From 913c8f56a9aa6140e44a7e0fa3830fb8d7a121b3 Mon Sep 17 00:00:00 2001 From: Alexander Niebuhr Date: Sat, 23 Sep 2023 10:53:49 +0200 Subject: [PATCH] feat(cloudflare): Add KV Bindings --- .changeset/funny-cobras-accept.md | 5 +++++ packages/integrations/cloudflare/README.md | 1 + packages/integrations/cloudflare/src/index.ts | 9 ++++++++- .../cloudflare/src/utils/parser.ts | 10 ++++++++++ .../integrations/cloudflare/test/cf.test.js | 12 +++++++++++ .../test/fixtures/cf/src/pages/kv.astro | 20 +++++++++++++++++++ .../cloudflare/test/fixtures/cf/wrangler.toml | 6 ++++++ 7 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 .changeset/funny-cobras-accept.md create mode 100644 packages/integrations/cloudflare/test/fixtures/cf/src/pages/kv.astro diff --git a/.changeset/funny-cobras-accept.md b/.changeset/funny-cobras-accept.md new file mode 100644 index 0000000000000..8152913344d1a --- /dev/null +++ b/.changeset/funny-cobras-accept.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': minor +--- + +Introduce support for local KV bindings. Enhance development experience by allowing direct integration with `astro dev`. diff --git a/packages/integrations/cloudflare/README.md b/packages/integrations/cloudflare/README.md index 837b7c1bfd801..b1200d696c77f 100644 --- a/packages/integrations/cloudflare/README.md +++ b/packages/integrations/cloudflare/README.md @@ -218,6 +218,7 @@ Currently supported bindings: - [Cloudflare D1](https://developers.cloudflare.com/d1/) - [Cloudflare R2](https://developers.cloudflare.com/r2/) +- [Cloudflare Workers KV](https://developers.cloudflare.com/kv/) You can access the runtime from Astro components through `Astro.locals` inside any .astro` file. diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index 987e89ea91f7c..82bab441f5a9e 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -15,7 +15,7 @@ import glob from 'tiny-glob'; import { getAdapter } from './getAdapter.js'; import { deduplicatePatterns } from './utils/deduplicatePatterns.js'; import { getCFObject } from './utils/getCFObject.js'; -import { getD1Bindings, getEnvVars, getR2Bindings } from './utils/parser.js'; +import { getD1Bindings, getEnvVars, getKVBindings, getR2Bindings } from './utils/parser.js'; import { prependForwardSlash } from './utils/prependForwardSlash.js'; import { rewriteWasmImportPath } from './utils/rewriteWasmImportPath.js'; import { wasmModuleLoader } from './utils/wasm-module-loader.js'; @@ -126,6 +126,7 @@ export default function createIntegration(args?: Options): AstroIntegration { const vars = await getEnvVars(); const D1Bindings = await getD1Bindings(); const R2Bindings = await getR2Bindings(); + const KVBindings = await getKVBindings(); let bindingsEnv = new Object({}); @@ -143,6 +144,8 @@ export default function createIntegration(args?: Options): AstroIntegration { d1Persist: true, r2Buckets: R2Bindings, r2Persist: true, + kvNamespaces: KVBindings, + kvPersist: true, }); await _mf.ready; @@ -154,6 +157,10 @@ export default function createIntegration(args?: Options): AstroIntegration { const bucket = await _mf.getR2Bucket(R2Binding); Reflect.set(bindingsEnv, R2Binding, bucket); } + for (const KVBinding of KVBindings) { + const namespace = await _mf.getKVNamespace(KVBinding); + Reflect.set(bindingsEnv, KVBinding, namespace); + } process.env.PWD = originalPWD; const clientLocalsSymbol = Symbol.for('astro.locals'); diff --git a/packages/integrations/cloudflare/src/utils/parser.ts b/packages/integrations/cloudflare/src/utils/parser.ts index 17598b38219b0..af64e68c68aa9 100644 --- a/packages/integrations/cloudflare/src/utils/parser.ts +++ b/packages/integrations/cloudflare/src/utils/parser.ts @@ -162,3 +162,13 @@ export async function getR2Bindings() { ); return bindings; } + +export async function getKVBindings() { + const { rawConfig } = parseConfig(); + if (!rawConfig) return []; + if (!rawConfig?.kv_namespaces) return []; + const bindings = (rawConfig?.kv_namespaces as []).map( + (binding: { binding: string }) => binding.binding + ); + return bindings; +} diff --git a/packages/integrations/cloudflare/test/cf.test.js b/packages/integrations/cloudflare/test/cf.test.js index 76045c7176b35..a9f5607373f58 100644 --- a/packages/integrations/cloudflare/test/cf.test.js +++ b/packages/integrations/cloudflare/test/cf.test.js @@ -95,4 +95,16 @@ describe('Astro Cloudflare Runtime', () => { expect($('#hasPRODBUCKET').text()).to.equal('true'); expect($('#hasACCESS').text()).to.equal('true'); }); + + it('adds KV mocking', async () => { + expect(await fixture.pathExists('../.mf/kv')).to.be.true; + + let res = await fixture.fetch('/kv'); + expect(res.status).to.equal(200); + let html = await res.text(); + let $ = cheerio.load(html); + expect($('#hasKV').text()).to.equal('true'); + expect($('#hasPRODKV').text()).to.equal('true'); + expect($('#hasACCESS').text()).to.equal('true'); + }); }); diff --git a/packages/integrations/cloudflare/test/fixtures/cf/src/pages/kv.astro b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/kv.astro new file mode 100644 index 0000000000000..d21f163a092cb --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/kv.astro @@ -0,0 +1,20 @@ +--- +const runtime = Astro.locals.runtime; +const kv = runtime.env?.KV; +await kv.put("test", "true"); +const result = await kv.get("test") +--- + + + + + + + KV + + +
{!!runtime.env?.KV}
+
{!!runtime.env?.KV_PROD}
+
{!!result}
+ + diff --git a/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml b/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml index b47382f74df6c..a0fc8ddb5cd93 100644 --- a/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml +++ b/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml @@ -1,5 +1,10 @@ name = "test" +kv_namespaces = [ + { binding = "KV", id = "", preview_id = "" }, + { binding = "KV_PROD", id = "", preview_id = "" } +] + [vars] COOL = "ME" @@ -22,3 +27,4 @@ bucket_name = '' [[r2_buckets]] binding = 'R2_PROD' # <~ valid JavaScript variable name bucket_name = '' +