diff --git a/.changeset/funny-cobras-accept.md b/.changeset/funny-cobras-accept.md new file mode 100644 index 000000000000..8152913344d1 --- /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 fb60e0b01c09..29cf4b0d2d3b 100644 --- a/packages/integrations/cloudflare/README.md +++ b/packages/integrations/cloudflare/README.md @@ -217,6 +217,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 5e9e70fcdddc..6334e7eae06b 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 17598b38219b..af64e68c68aa 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 76045c7176b3..a9f5607373f5 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 000000000000..d21f163a092c --- /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") +--- + + + +
+ + +{!!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 b47382f74df6..a0fc8ddb5cd9 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 = "