diff --git a/.changeset/funny-cobras-accept.md b/.changeset/funny-cobras-accept.md new file mode 100644 index 000000000..65805719c --- /dev/null +++ b/.changeset/funny-cobras-accept.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': minor +--- + +Introduces support for local KV bindings. Enhances development experience by allowing direct integration with `astro dev`. diff --git a/.changeset/hot-readers-live.md b/.changeset/hot-readers-live.md new file mode 100644 index 000000000..f510d77c1 --- /dev/null +++ b/.changeset/hot-readers-live.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': minor +--- + +Introduces support for local Durable Objects bindings. Enhances development experience by allowing direct integration with `astro dev`. diff --git a/.changeset/hungry-mails-boil.md b/.changeset/hungry-mails-boil.md new file mode 100644 index 000000000..851928e7a --- /dev/null +++ b/.changeset/hungry-mails-boil.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': minor +--- + +Introduces support for local D1 bindings. Enhances development experience by allowing direct integration with `astro dev`. diff --git a/.changeset/khaki-toes-exercise.md b/.changeset/khaki-toes-exercise.md new file mode 100644 index 000000000..f8daf864d --- /dev/null +++ b/.changeset/khaki-toes-exercise.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': minor +--- + +Introduces support for local R2 bindings. Enhances development experience by allowing direct integration with `astro dev`. diff --git a/.changeset/yellow-kiwis-pretend.md b/.changeset/yellow-kiwis-pretend.md new file mode 100644 index 000000000..cd5ee554b --- /dev/null +++ b/.changeset/yellow-kiwis-pretend.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': minor +--- + +Introduces support for local Caches bindings. Enhances development experience by allowing direct integration with `astro dev`. diff --git a/packages/integrations/cloudflare/.gitignore b/packages/integrations/cloudflare/.gitignore index 58b200bf6..0134f82df 100644 --- a/packages/integrations/cloudflare/.gitignore +++ b/packages/integrations/cloudflare/.gitignore @@ -1,2 +1,3 @@ # Astro cloudflare directory mode creates a function directory -functions \ No newline at end of file +functions +.mf diff --git a/packages/integrations/cloudflare/README.md b/packages/integrations/cloudflare/README.md index 7bfbd4b85..10a381a7b 100644 --- a/packages/integrations/cloudflare/README.md +++ b/packages/integrations/cloudflare/README.md @@ -212,7 +212,14 @@ export default defineConfig({ ## Cloudflare runtime -Gives you access to [environment variables](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables). +Gives you access to [environment variables](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables), and [Cloudflare bindings](https://developers.cloudflare.com/pages/platform/functions/bindings). + +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/) +- [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/) You can access the runtime from Astro components through `Astro.locals` inside any .astro` file. diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index bf4b41907..80f26b33b 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -36,6 +36,7 @@ "dependencies": { "@astrojs/underscore-redirects": "workspace:*", "@cloudflare/workers-types": "^4.20230821.0", + "miniflare": "^3.20230918.0", "@iarna/toml": "^2.2.5", "@miniflare/cache": "^2.14.1", "@miniflare/shared": "^2.14.1", diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index e0f055612..59cd92ce3 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -1,11 +1,9 @@ import type { AstroConfig, AstroIntegration, RouteData } from 'astro'; import { createRedirectsFromAstroRoutes } from '@astrojs/underscore-redirects'; -import { CacheStorage } from '@miniflare/cache'; -import { NoOpLog } from '@miniflare/shared'; -import { MemoryStorage } from '@miniflare/storage-memory'; import { AstroError } from 'astro/errors'; import esbuild from 'esbuild'; +import { Miniflare } from 'miniflare'; import * as fs from 'node:fs'; import * as os from 'node:os'; import { dirname, relative, sep } from 'node:path'; @@ -14,7 +12,13 @@ import glob from 'tiny-glob'; import { getAdapter } from './getAdapter.js'; import { deduplicatePatterns } from './utils/deduplicatePatterns.js'; import { getCFObject } from './utils/getCFObject.js'; -import { getEnvVars } from './utils/parser.js'; +import { + getD1Bindings, + getDOBindings, + 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'; @@ -55,20 +59,10 @@ interface BuildConfig { split?: boolean; } -class StorageFactory { - storages = new Map(); - - storage(namespace: string) { - let storage = this.storages.get(namespace); - if (storage) return storage; - this.storages.set(namespace, (storage = new MemoryStorage())); - return storage; - } -} - export default function createIntegration(args?: Options): AstroIntegration { let _config: AstroConfig; let _buildConfig: BuildConfig; + let _mf: Miniflare; let _entryPoints = new Map(); const SERVER_BUILD_FOLDER = '/$server_build/'; @@ -122,7 +116,55 @@ export default function createIntegration(args?: Options): AstroIntegration { try { const cf = await getCFObject(runtimeMode); const vars = await getEnvVars(); + const D1Bindings = await getD1Bindings(); + const R2Bindings = await getR2Bindings(); + const KVBindings = await getKVBindings(); + const DOBindings = await getDOBindings(); + let bindingsEnv = new Object({}); + // fix for the error "kj/filesystem-disk-unix.c++:1709: warning: PWD environment variable doesn't match current directory." + // note: This mismatch might be primarily due to the test runner. + const originalPWD = process.env.PWD; + process.env.PWD = process.cwd(); + + _mf = new Miniflare({ + modules: true, + script: '', + cache: true, + cachePersist: true, + cacheWarnUsage: true, + d1Databases: D1Bindings, + d1Persist: true, + r2Buckets: R2Bindings, + r2Persist: true, + kvNamespaces: KVBindings, + kvPersist: true, + durableObjects: DOBindings, + durableObjectsPersist: true, + }); + await _mf.ready; + + for (const D1Binding of D1Bindings) { + const db = await _mf.getD1Database(D1Binding); + Reflect.set(bindingsEnv, D1Binding, db); + } + for (const R2Binding of R2Bindings) { + 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); + } + for (const key in DOBindings) { + if (Object.prototype.hasOwnProperty.call(DOBindings, key)) { + const DO = await _mf.getDurableObjectNamespace(key); + Reflect.set(bindingsEnv, key, DO); + } + } + const mfCache = await _mf.getCaches(); + + process.env.PWD = originalPWD; const clientLocalsSymbol = Symbol.for('astro.locals'); Reflect.set(req, clientLocalsSymbol, { runtime: { @@ -136,18 +178,14 @@ export default function createIntegration(args?: Options): AstroIntegration { // will be fetched from git dynamically once we support mocking of bindings CF_PAGES_COMMIT_SHA: 'TBA', CF_PAGES_URL: `http://${req.headers.host}`, + ...bindingsEnv, ...vars, }, cf: cf, waitUntil: (_promise: Promise) => { return; }, - caches: new CacheStorage( - { cache: true, cachePersist: false }, - new NoOpLog(), - new StorageFactory(), - {} - ), + caches: mfCache, }, }); next(); @@ -157,6 +195,12 @@ export default function createIntegration(args?: Options): AstroIntegration { }); } }, + 'astro:server:done': async ({ logger }) => { + if (_mf) { + logger.info('Cleaning up the Miniflare instance, and shutting down the workerd server.'); + await _mf.dispose(); + } + }, 'astro:build:setup': ({ vite, target }) => { if (target === 'server') { vite.resolve ||= {}; diff --git a/packages/integrations/cloudflare/src/utils/parser.ts b/packages/integrations/cloudflare/src/utils/parser.ts index e9a9cdd00..de239a1ee 100644 --- a/packages/integrations/cloudflare/src/utils/parser.ts +++ b/packages/integrations/cloudflare/src/utils/parser.ts @@ -12,6 +12,8 @@ import dotenv from 'dotenv'; import { findUpSync } from 'find-up'; import * as fs from 'node:fs'; import { dirname, resolve } from 'node:path'; +import type {} from '@cloudflare/workers-types/experimental'; +let _wrangler: any; function findWranglerToml( referencePath: string = process.cwd(), @@ -119,7 +121,9 @@ function getVarsForDev(config: any, configPath: string | undefined): any { return config.vars; } } -export async function getEnvVars() { + +function parseConfig() { + if (_wrangler) return _wrangler; let rawConfig; const configPath = findWranglerToml(process.cwd(), false); // false = args.experimentalJsonConfig if (!configPath) { @@ -129,6 +133,59 @@ export async function getEnvVars() { if (configPath?.endsWith('toml')) { rawConfig = parseTOML(fs.readFileSync(configPath).toString(), configPath); } + _wrangler = { rawConfig, configPath }; + return { rawConfig, configPath }; +} + +export async function getEnvVars() { + const { rawConfig, configPath } = parseConfig(); const vars = getVarsForDev(rawConfig, configPath); return vars; } + +export async function getD1Bindings() { + const { rawConfig } = parseConfig(); + if (!rawConfig) return []; + if (!rawConfig?.d1_databases) return []; + const bindings = (rawConfig?.d1_databases as []).map( + (binding: { binding: string }) => binding.binding + ); + return bindings; +} + +export async function getR2Bindings() { + const { rawConfig } = parseConfig(); + if (!rawConfig) return []; + if (!rawConfig?.r2_buckets) return []; + const bindings = (rawConfig?.r2_buckets as []).map( + (binding: { binding: string }) => binding.binding + ); + 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; +} + +export function getDOBindings(): Record< + string, + { scriptName?: string | undefined; unsafeUniqueKey?: string | undefined; className: string } +> { + const { rawConfig } = parseConfig(); + if (!rawConfig) return {}; + if (!rawConfig?.durable_objects) return {}; + const output = new Object({}) as Record< + string, + { scriptName?: string | undefined; unsafeUniqueKey?: string | undefined; className: string } + >; + for (const binding of rawConfig?.durable_objects.bindings) { + Reflect.set(output, binding.name, { className: binding.class_name }); + } + return output; +} diff --git a/packages/integrations/cloudflare/test/cf.test.js b/packages/integrations/cloudflare/test/cf.test.js index 78a18dcdf..0078f3024 100644 --- a/packages/integrations/cloudflare/test/cf.test.js +++ b/packages/integrations/cloudflare/test/cf.test.js @@ -54,11 +54,6 @@ describe('Astro Cloudflare Runtime', () => { adapter: cloudflare({ runtime: 'local', }), - image: { - service: { - entrypoint: 'astro/assets/services/noop', - }, - }, }); process.chdir('./test/fixtures/cf'); devServer = await fixture.startDevServer(); @@ -68,12 +63,65 @@ describe('Astro Cloudflare Runtime', () => { await devServer?.stop(); }); - it('Populates CF, Vars & Bindings', async () => { + it('adds cf object', async () => { let res = await fixture.fetch('/'); expect(res.status).to.equal(200); let html = await res.text(); let $ = cheerio.load(html); - expect($('#hasRuntime').text()).to.equal('true'); - expect($('#hasCache').text()).to.equal('true'); + expect($('#hasCF').text()).to.equal('true'); + }); + + it('adds cache mocking', async () => { + let res = await fixture.fetch('/caches'); + expect(res.status).to.equal(200); + let html = await res.text(); + let $ = cheerio.load(html); + expect($('#hasCACHE').text()).to.equal('true'); + }); + + it('adds D1 mocking', async () => { + expect(await fixture.pathExists('../.mf/d1')).to.be.true; + + let res = await fixture.fetch('/d1'); + expect(res.status).to.equal(200); + let html = await res.text(); + let $ = cheerio.load(html); + expect($('#hasDB').text()).to.equal('true'); + expect($('#hasPRODDB').text()).to.equal('true'); + expect($('#hasACCESS').text()).to.equal('true'); + }); + + it('adds R2 mocking', async () => { + expect(await fixture.pathExists('../.mf/r2')).to.be.true; + + let res = await fixture.fetch('/r2'); + expect(res.status).to.equal(200); + let html = await res.text(); + let $ = cheerio.load(html); + expect($('#hasBUCKET').text()).to.equal('true'); + 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'); + }); + + it('adds DO mocking', async () => { + expect(await fixture.pathExists('../.mf/do')).to.be.true; + + let res = await fixture.fetch('/do'); + expect(res.status).to.equal(200); + let html = await res.text(); + let $ = cheerio.load(html); + expect($('#hasDO').text()).to.equal('true'); }); }); diff --git a/packages/integrations/cloudflare/test/fixtures/cf/src/pages/caches.astro b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/caches.astro new file mode 100644 index 000000000..743111721 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/caches.astro @@ -0,0 +1,15 @@ +--- +const runtime = Astro.locals.runtime; +--- + + + + + + + CACHES + + +
{!!runtime.caches}
+ + diff --git a/packages/integrations/cloudflare/test/fixtures/cf/src/pages/d1.astro b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/d1.astro new file mode 100644 index 000000000..a28940e9f --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/d1.astro @@ -0,0 +1,21 @@ +--- +const runtime = Astro.locals.runtime; +const db = runtime.env?.D1; +await db.exec("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)"); +await db.exec("INSERT INTO test (name) VALUES ('true')"); +const result = await db.prepare("SELECT * FROM test").all(); +--- + + + + + + + D1 + + +
{!!runtime.env?.D1}
+
{!!runtime.env?.D1_PROD}
+
{!!result.results[0].name}
+ + diff --git a/packages/integrations/cloudflare/test/fixtures/cf/src/pages/do.astro b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/do.astro new file mode 100644 index 000000000..e338c8e8f --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/do.astro @@ -0,0 +1,15 @@ +--- +const runtime = Astro.locals.runtime; +--- + + + + + + + DO + + +
{!!runtime.env.DO}
+ + diff --git a/packages/integrations/cloudflare/test/fixtures/cf/src/pages/index.astro b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/index.astro index 0e904752f..5ba11985f 100644 --- a/packages/integrations/cloudflare/test/fixtures/cf/src/pages/index.astro +++ b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/index.astro @@ -7,7 +7,6 @@ const runtime = Astro.locals.runtime;

Testing

-
{!!runtime.cf?.colo}
-
{!!runtime.caches}
+
{!!runtime.cf?.colo}
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 000000000..d21f163a0 --- /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/src/pages/r2.astro b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/r2.astro new file mode 100644 index 000000000..fbb9fc61b --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/cf/src/pages/r2.astro @@ -0,0 +1,20 @@ +--- +const runtime = Astro.locals.runtime; +const bucket = runtime.env?.R2; +await bucket.put("test", "true"); +const result = await (await bucket.get("test")).text() +--- + + + + + + + R2 + + +
{!!runtime.env?.R2}
+
{!!runtime.env?.R2_PROD}
+
{!!result}
+ + diff --git a/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml b/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml index ba0fa64c4..17fd88ea5 100644 --- a/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml +++ b/packages/integrations/cloudflare/test/fixtures/cf/wrangler.toml @@ -1,4 +1,37 @@ name = "test" +kv_namespaces = [ + { binding = "KV", id = "", preview_id = "" }, + { binding = "KV_PROD", id = "", preview_id = "" } +] + [vars] COOL = "ME" + +[[d1_databases]] +binding = "D1" # Should match preview_database_id, i.e. available in your Worker on env.DB +database_name = "" +database_id = "" +preview_database_id = "D1" # Required for Pages local development + +[[d1_databases]] +binding = "D1_PROD" # Should match preview_database_id +database_name = "" +database_id = "" +preview_database_id = "D1_PROD" # Required for Pages local development + +[[r2_buckets]] +binding = 'R2' # <~ valid JavaScript variable name +bucket_name = '' + +[[r2_buckets]] +binding = 'R2_PROD' # <~ valid JavaScript variable name +bucket_name = '' + +[[durable_objects.bindings]] +name = "DO" +class_name = "DurableObjectExample" + +[[durable_objects.bindings]] +name = "DO_PROD" +class_name = "DurableObjectProductionExample" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7af0f2954..0d8219cf0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3672,6 +3672,9 @@ importers: find-up: specifier: ^6.3.0 version: 6.3.0 + miniflare: + specifier: ^3.20230918.0 + version: 3.20230918.0 tiny-glob: specifier: ^0.2.9 version: 0.2.9 @@ -6974,6 +6977,15 @@ packages: dev: true optional: true + /@cloudflare/workerd-darwin-64@1.20230904.0: + resolution: {integrity: sha512-/GDlmxAFbDtrQwP4zOXFbqOfaPvkDxdsCoEa+KEBcAl5uR98+7WW5/b8naBHX+t26uS7p4bLlImM8J5F1ienRQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@cloudflare/workerd-darwin-arm64@1.20230814.1: resolution: {integrity: sha512-U2mcgi+AiuI/4EY5Wk/GmygiNoCNw/V2mcHmxESqe4r6XbJYOzBdEsjnqJ05rqd0JlEM8m64jRtE6/qBnQHygg==} engines: {node: '>=16'} @@ -6983,6 +6995,15 @@ packages: dev: true optional: true + /@cloudflare/workerd-darwin-arm64@1.20230904.0: + resolution: {integrity: sha512-x8WXNc2xnDqr5y1iirnNdyx8GZY3rL5xiF7ebK3mKQeB+jFjkhO71yuPTkDCzUWtOvw1Wfd4jbwy4wxacMX4mQ==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@cloudflare/workerd-linux-64@1.20230814.1: resolution: {integrity: sha512-Q4kITXLTCuG2i2Z01fbb5AjVRRIf3+lS4ZVsFbTbIwtcOOG4Ozcw7ee7tKsFES7hFqR4Eg9gMG4/aS0mmi+L2g==} engines: {node: '>=16'} @@ -6992,6 +7013,15 @@ packages: dev: true optional: true + /@cloudflare/workerd-linux-64@1.20230904.0: + resolution: {integrity: sha512-V58xyMS3oDpKO8Dpdh0r0BXm99OzoGgvWe9ufttVraj/1NTMGELwb6i9ySb8k3F1J9m/sO26+TV7pQc/bGC1VQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@cloudflare/workerd-linux-arm64@1.20230814.1: resolution: {integrity: sha512-BX5SaksXw+pkREVw3Rw2eSNXplqZw+14CcwW/5x/4oq/C6yn5qCvKxJfM7pukJGMI4wkJPOYops7B3g27FB/HA==} engines: {node: '>=16'} @@ -7001,6 +7031,15 @@ packages: dev: true optional: true + /@cloudflare/workerd-linux-arm64@1.20230904.0: + resolution: {integrity: sha512-VrDaW+pjb5IAKEnNWtEaFiG377kXKmk5Fu0Era4W+jKzPON2BW/qRb/4LNHXQ4yxg/2HLm7RiUTn7JZtt1qO6A==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@cloudflare/workerd-windows-64@1.20230814.1: resolution: {integrity: sha512-GWHqfyhsG/1wm2W8afkYX3q3fWXUWWD8NGtHfAs6ZVTHdW3mmYyMhKR0lc6ptBwz5i5aXRlP2S+CxxxwwDbKpw==} engines: {node: '>=16'} @@ -7010,6 +7049,15 @@ packages: dev: true optional: true + /@cloudflare/workerd-windows-64@1.20230904.0: + resolution: {integrity: sha512-/R/dE8uy+8J2YeXfDhI8/Bg7YUirdbbjH5/l/Vv00ZRE0lC3nPLcYeyBXSwXIQ6/Xht3gN+lksLQgKd0ZWRd+Q==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@cloudflare/workers-types@4.20230821.0: resolution: {integrity: sha512-lVQSyr5E4CEkQw7WIdsrMTj+kHjsm28mJ0B5AhNFByKR+16KTFsU/RW/nGLKHHW2jxT5lvYI+HjNQMzC9QR8Ng==} dev: false @@ -9691,7 +9739,6 @@ packages: resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} dependencies: printable-characters: 1.0.42 - dev: true /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -10160,7 +10207,6 @@ packages: tslib: 2.6.2 transitivePeerDependencies: - supports-color - dev: true /ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -10693,7 +10739,6 @@ packages: /data-uri-to-buffer@2.0.2: resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} - dev: true /data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} @@ -11575,7 +11620,6 @@ packages: /exit-hook@2.2.1: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} - dev: true /expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} @@ -11939,7 +11983,6 @@ packages: dependencies: data-uri-to-buffer: 2.0.2 source-map: 0.6.1 - dev: true /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} @@ -11992,7 +12035,6 @@ packages: /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: true /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} @@ -14055,6 +14097,28 @@ packages: - utf-8-validate dev: true + /miniflare@3.20230918.0: + resolution: {integrity: sha512-Dd29HB7ZlT1CXB2tPH8nW6fBOOXi/m7qFZHjKm2jGS+1OaGfrv0PkT5UspWW5jQi8rWI87xtordAUiIJkwWqRw==} + engines: {node: '>=16.13'} + dependencies: + acorn: 8.10.0 + acorn-walk: 8.2.0 + capnp-ts: 0.7.0 + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + source-map-support: 0.5.21 + stoppable: 1.1.0 + undici: 5.23.0 + workerd: 1.20230904.0 + ws: 8.13.0 + youch: 3.2.3 + zod: 3.21.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -14207,7 +14271,6 @@ packages: /mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true - dev: true /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -15329,7 +15392,6 @@ packages: /printable-characters@1.0.42: resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} - dev: true /prismjs@1.29.0: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} @@ -16372,7 +16434,6 @@ packages: dependencies: as-table: 1.0.55 get-source: 2.0.12 - dev: true /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} @@ -16392,7 +16453,6 @@ packages: /stoppable@1.1.0: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} - dev: true /stream-parser@0.3.1: resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} @@ -18235,6 +18295,19 @@ packages: '@cloudflare/workerd-windows-64': 1.20230814.1 dev: true + /workerd@1.20230904.0: + resolution: {integrity: sha512-t9znszH0rQGK4mJGvF9L3nN0qKEaObAGx0JkywFtAwH8OkSn+YfQbHNZE+YsJ4qa1hOz1DCNEk08UDFRBaYq4g==} + engines: {node: '>=16'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20230904.0 + '@cloudflare/workerd-darwin-arm64': 1.20230904.0 + '@cloudflare/workerd-linux-64': 1.20230904.0 + '@cloudflare/workerd-linux-arm64': 1.20230904.0 + '@cloudflare/workerd-windows-64': 1.20230904.0 + dev: false + /workerpool@6.2.1: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} dev: true @@ -18305,7 +18378,6 @@ packages: optional: true utf-8-validate: optional: true - dev: true /xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} @@ -18455,7 +18527,6 @@ packages: cookie: 0.5.0 mustache: 4.2.0 stacktracey: 2.1.8 - dev: true /zod@3.21.1: resolution: {integrity: sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==}