From a1f212e6423fd251612b1b3c2ac9f254daa8fa4c Mon Sep 17 00:00:00 2001 From: Daniel Walsh Date: Thu, 19 Oct 2023 14:32:51 +0100 Subject: [PATCH] Service bindings in Pages (#2162) * Service bindings in Pages * Add env support + test * run prettify * update workers-types dependency in external service bindings fixture * update pnpm-lock file * fix copy-pasta in external-service-bindings fixture * fix and improve external-service-bindings-app fixture * add test for service environments * fix types in external-service-bindings-app fixture * add environment to service flag description * add changeset * Update fixtures/external-service-bindings-app/package.json Co-authored-by: Greg Brimble * add missing newlines * tweak flag description * improve changeset * add warning about service binding env being experimental * only print the env warning once * fix bad wording * add comment for SERVICE_BINDING_REGEXP * remove unneeded jest section in package.json --------- Co-authored-by: Daniel Walsh Co-authored-by: Dario Piotrowicz Co-authored-by: Greg Brimble --- .changeset/three-dolphins-float.md | 19 +++ .../module-worker-a/index.ts | 5 + .../module-worker-a/wrangler.toml | 1 + .../module-worker-b/index.ts | 9 ++ .../module-worker-b/wrangler.toml | 5 + .../module-worker-c/index.ts | 5 + .../module-worker-c/wrangler.toml | 7 + .../module-worker-d/index.ts | 5 + .../module-worker-d/wrangler.toml | 7 + .../package.json | 25 +++ .../pages-functions-app/functions/env.ts | 9 ++ .../pages-functions-app/functions/index.ts | 10 ++ .../pages-functions-app/package.json | 4 + .../pages-functions-app/public/index.html | 1 + .../service-worker-a/index.ts | 3 + .../service-worker-a/wrangler.toml | 2 + .../tests/index.test.ts | 75 +++++++++ .../tsconfig.json | 16 ++ packages/wrangler/src/api/dev.ts | 5 + packages/wrangler/src/dev.tsx | 8 +- packages/wrangler/src/pages/dev.ts | 51 ++++++ pnpm-lock.yaml | 150 ++++++++++++------ 22 files changed, 376 insertions(+), 46 deletions(-) create mode 100644 .changeset/three-dolphins-float.md create mode 100644 fixtures/external-service-bindings-app/module-worker-a/index.ts create mode 100644 fixtures/external-service-bindings-app/module-worker-a/wrangler.toml create mode 100644 fixtures/external-service-bindings-app/module-worker-b/index.ts create mode 100644 fixtures/external-service-bindings-app/module-worker-b/wrangler.toml create mode 100644 fixtures/external-service-bindings-app/module-worker-c/index.ts create mode 100644 fixtures/external-service-bindings-app/module-worker-c/wrangler.toml create mode 100644 fixtures/external-service-bindings-app/module-worker-d/index.ts create mode 100644 fixtures/external-service-bindings-app/module-worker-d/wrangler.toml create mode 100644 fixtures/external-service-bindings-app/package.json create mode 100644 fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts create mode 100644 fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts create mode 100644 fixtures/external-service-bindings-app/pages-functions-app/package.json create mode 100644 fixtures/external-service-bindings-app/pages-functions-app/public/index.html create mode 100644 fixtures/external-service-bindings-app/service-worker-a/index.ts create mode 100644 fixtures/external-service-bindings-app/service-worker-a/wrangler.toml create mode 100644 fixtures/external-service-bindings-app/tests/index.test.ts create mode 100644 fixtures/external-service-bindings-app/tsconfig.json diff --git a/.changeset/three-dolphins-float.md b/.changeset/three-dolphins-float.md new file mode 100644 index 00000000000..91b4453a263 --- /dev/null +++ b/.changeset/three-dolphins-float.md @@ -0,0 +1,19 @@ +--- +"wrangler": minor +--- + +add support for service bindings in `wrangler pages dev` by providing the +new `--service`|`-s` flag which accepts an array of `BINDING_NAME=SCRIPT_NAME` +where `BINDING_NAME` is the name of the binding and `SCRIPT_NAME` is the name +of the worker (as defined in its `wrangler.toml`), such workers need to be +running locally with with `wrangler dev`. + +For example if a user has a worker named `worker-a`, in order to locally bind +to that they'll need to open two different terminals, in each navigate to the +respective worker/pages application and then run respectively `wrangler dev` and +`wrangler pages ./publicDir --service MY_SERVICE=worker-a` this will add the +`MY_SERVICE` binding to pages' worker `env` object. + +Note: additionally after the `SCRIPT_NAME` the name of an environment can be specified, +prefixed by an `@` (as in: `MY_SERVICE=SCRIPT_NAME@PRODUCTION`), this behavior is however +experimental and not fully properly defined. diff --git a/fixtures/external-service-bindings-app/module-worker-a/index.ts b/fixtures/external-service-bindings-app/module-worker-a/index.ts new file mode 100644 index 00000000000..7267d55e833 --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-a/index.ts @@ -0,0 +1,5 @@ +export default { + fetch() { + return new Response("Hello from module worker a"); + }, +}; diff --git a/fixtures/external-service-bindings-app/module-worker-a/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-a/wrangler.toml new file mode 100644 index 00000000000..c2259034a1d --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-a/wrangler.toml @@ -0,0 +1 @@ +name = "module-worker-a" diff --git a/fixtures/external-service-bindings-app/module-worker-b/index.ts b/fixtures/external-service-bindings-app/module-worker-b/index.ts new file mode 100644 index 00000000000..a8f66a028a4 --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-b/index.ts @@ -0,0 +1,9 @@ +export default { + async fetch(request: Request, env: { SERVICE: Fetcher }) { + const serviceResp = await env.SERVICE.fetch(request); + const serviceRespTxt = await serviceResp.text(); + return new Response( + `Hello from module worker b and also: ${serviceRespTxt}` + ); + }, +}; diff --git a/fixtures/external-service-bindings-app/module-worker-b/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-b/wrangler.toml new file mode 100644 index 00000000000..92507006818 --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-b/wrangler.toml @@ -0,0 +1,5 @@ +name = "module-worker-b" + +services = [ + { binding = "SERVICE", service = "module-worker-a" } +] diff --git a/fixtures/external-service-bindings-app/module-worker-c/index.ts b/fixtures/external-service-bindings-app/module-worker-c/index.ts new file mode 100644 index 00000000000..1f44afc9230 --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-c/index.ts @@ -0,0 +1,5 @@ +export default { + fetch(req, env) { + return new Response(`Hello from module worker c (${env.MY_ENV})`); + }, +}; diff --git a/fixtures/external-service-bindings-app/module-worker-c/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-c/wrangler.toml new file mode 100644 index 00000000000..835bb309a66 --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-c/wrangler.toml @@ -0,0 +1,7 @@ +name = "module-worker-c" + +[env.staging.vars] +MY_ENV = "staging" + +[env.production.vars] +MY_ENV = "prod" diff --git a/fixtures/external-service-bindings-app/module-worker-d/index.ts b/fixtures/external-service-bindings-app/module-worker-d/index.ts new file mode 100644 index 00000000000..0cbcb85a5d1 --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-d/index.ts @@ -0,0 +1,5 @@ +export default { + fetch(req, env) { + return new Response(`Hello from module worker d (${env.MY_ENV})`); + }, +}; diff --git a/fixtures/external-service-bindings-app/module-worker-d/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-d/wrangler.toml new file mode 100644 index 00000000000..2805074ddb2 --- /dev/null +++ b/fixtures/external-service-bindings-app/module-worker-d/wrangler.toml @@ -0,0 +1,7 @@ +name = "module-worker-d" + +[env.staging.vars] +MY_ENV = "staging" + +[env.production.vars] +MY_ENV = "prod" diff --git a/fixtures/external-service-bindings-app/package.json b/fixtures/external-service-bindings-app/package.json new file mode 100644 index 00000000000..57b56511f9c --- /dev/null +++ b/fixtures/external-service-bindings-app/package.json @@ -0,0 +1,25 @@ +{ + "name": "external-service-bindings-app", + "private": true, + "description": "A test for external service bindings", + "scripts": { + "mod-a-dev": "wrangler dev module-worker-a/index.ts --local --port 8500", + "mod-b-dev": "wrangler dev module-worker-b/index.ts --local --port 8501", + "ser-a-dev": "wrangler dev service-worker-a/index.ts --local --port 8502", + "mod-c-dev": "wrangler dev module-worker-c/index.ts --local --port 8503 --env staging", + "mod-d-dev": "wrangler dev module-worker-d/index.ts --local --port 8504 --env production", + "pages-dev": "cd pages-functions-app && npx wrangler pages dev public --port 8505 --service MODULE_A_SERVICE=module-worker-a MODULE_B_SERVICE=module-worker-b SERVICE_A_SERVICE=service-worker-a STAGING_MODULE_C_SERVICE=module-worker-c@staging STAGING_MODULE_D_SERVICE=module-worker-d@staging", + "dev": "npx concurrently -s first -k 'npm run mod-a-dev' 'npm run mod-b-dev' 'npm run ser-a-dev' 'npm run mod-c-dev' 'npm run mod-d-dev' 'npm run pages-dev'", + "test": "npx vitest run", + "test:ci": "npx vitest run", + "test:watch": "npx vitest", + "type:tests": "tsc --noEmit" + }, + "devDependencies": { + "undici": "^5.23.0", + "concurrently": "^8.2.1", + "@cloudflare/workers-tsconfig": "workspace:*", + "@cloudflare/workers-types": "^4.20221111.1", + "wrangler": "workspace:*" + } +} diff --git a/fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts b/fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts new file mode 100644 index 00000000000..0b65d762c22 --- /dev/null +++ b/fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts @@ -0,0 +1,9 @@ +export const onRequest = async ({ env, request }) => { + const getTextFrom = (fetcher: Fetcher) => + fetcher.fetch(request).then((resp) => resp.text()); + + return Response.json({ + moduleWorkerCResponse: await getTextFrom(env.STAGING_MODULE_C_SERVICE), + moduleWorkerDResponse: await getTextFrom(env.STAGING_MODULE_D_SERVICE), + }); +}; diff --git a/fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts b/fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts new file mode 100644 index 00000000000..7efeceacdaf --- /dev/null +++ b/fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts @@ -0,0 +1,10 @@ +export const onRequest = async ({ env, request }) => { + const getTextFrom = (fetcher: Fetcher) => + fetcher.fetch(request).then((resp) => resp.text()); + + return Response.json({ + moduleWorkerAResponse: await getTextFrom(env.MODULE_A_SERVICE), + moduleWorkerBResponse: await getTextFrom(env.MODULE_B_SERVICE), + serviceWorkerAResponse: await getTextFrom(env.SERVICE_A_SERVICE), + }); +}; diff --git a/fixtures/external-service-bindings-app/pages-functions-app/package.json b/fixtures/external-service-bindings-app/pages-functions-app/package.json new file mode 100644 index 00000000000..62b679f9e5d --- /dev/null +++ b/fixtures/external-service-bindings-app/pages-functions-app/package.json @@ -0,0 +1,4 @@ +{ + "name": "pages-functions-app", + "private": true +} diff --git a/fixtures/external-service-bindings-app/pages-functions-app/public/index.html b/fixtures/external-service-bindings-app/pages-functions-app/public/index.html new file mode 100644 index 00000000000..dfa041fb456 --- /dev/null +++ b/fixtures/external-service-bindings-app/pages-functions-app/public/index.html @@ -0,0 +1 @@ +

This will never be served.

diff --git a/fixtures/external-service-bindings-app/service-worker-a/index.ts b/fixtures/external-service-bindings-app/service-worker-a/index.ts new file mode 100644 index 00000000000..fcb0547caa9 --- /dev/null +++ b/fixtures/external-service-bindings-app/service-worker-a/index.ts @@ -0,0 +1,3 @@ +addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello from service worker a")); +}); diff --git a/fixtures/external-service-bindings-app/service-worker-a/wrangler.toml b/fixtures/external-service-bindings-app/service-worker-a/wrangler.toml new file mode 100644 index 00000000000..26a69a5f8f5 --- /dev/null +++ b/fixtures/external-service-bindings-app/service-worker-a/wrangler.toml @@ -0,0 +1,2 @@ +name = "service-worker-a" +main = "src/index.ts" diff --git a/fixtures/external-service-bindings-app/tests/index.test.ts b/fixtures/external-service-bindings-app/tests/index.test.ts new file mode 100644 index 00000000000..6b05e00748d --- /dev/null +++ b/fixtures/external-service-bindings-app/tests/index.test.ts @@ -0,0 +1,75 @@ +import { spawn } from "child_process"; +import * as path from "path"; +import type { ChildProcess } from "child_process"; +import { describe, expect, it, beforeAll, afterAll } from "vitest"; +import { fetch, type Response } from "undici"; + +const waitUntilReady = async (url: string): Promise => { + let response: Response | undefined = undefined; + + while (response === undefined) { + await new Promise((resolvePromise) => setTimeout(resolvePromise, 500)); + + try { + response = await fetch(url); + } catch {} + } + + return response as Response; +}; + +const isWindows = process.platform === "win32"; + +describe("Pages Functions", () => { + let wranglerProcess: ChildProcess; + + beforeAll(() => { + wranglerProcess = spawn("npm", ["run", "dev"], { + shell: isWindows, + cwd: path.resolve(__dirname, "../"), + env: { BROWSER: "none", ...process.env }, + }); + wranglerProcess.stdout?.on("data", (chunk) => { + console.log(chunk.toString()); + }); + wranglerProcess.stderr?.on("data", (chunk) => { + console.log(chunk.toString()); + }); + }); + + afterAll(async () => { + await new Promise((resolve, reject) => { + wranglerProcess.once("exit", (code) => { + if (!code) { + resolve(code); + } else { + reject(code); + } + }); + wranglerProcess.kill("SIGTERM"); + }); + }); + + it("connects up Workers (both module and service ones) and fetches from them", async () => { + const combinedResponse = await waitUntilReady("http://localhost:8505/"); + const json = await combinedResponse.json(); + expect(json).toMatchInlineSnapshot(` + { + "moduleWorkerAResponse": "Hello from module worker a", + "moduleWorkerBResponse": "Hello from module worker b and also: Hello from module worker a", + "serviceWorkerAResponse": "Hello from service worker a", + } + `); + }); + + it("respects the environments specified for the service bindings (and doesn't connect if the env doesn't match)", async () => { + const combinedResponse = await waitUntilReady("http://localhost:8505/env"); + const json = await combinedResponse.json(); + expect(json).toMatchInlineSnapshot(` + { + "moduleWorkerCResponse": "Hello from module worker c (staging)", + "moduleWorkerDResponse": "You should start up wrangler dev --local on the STAGING_MODULE_D_SERVICE worker", + } + `); + }); +}); diff --git a/fixtures/external-service-bindings-app/tsconfig.json b/fixtures/external-service-bindings-app/tsconfig.json new file mode 100644 index 00000000000..4dbc853e530 --- /dev/null +++ b/fixtures/external-service-bindings-app/tsconfig.json @@ -0,0 +1,16 @@ +{ + "include": [ + "module-worker-a", + "module-worker-b", + "service-worker-a", + "module-worker-c", + "module-worker-d", + "pages-functions-app" + ], + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "lib": ["ES2020"], + "types": ["@cloudflare/workers-types"] + } +} diff --git a/packages/wrangler/src/api/dev.ts b/packages/wrangler/src/api/dev.ts index 6c88d555495..628aa06ad63 100644 --- a/packages/wrangler/src/api/dev.ts +++ b/packages/wrangler/src/api/dev.ts @@ -39,6 +39,11 @@ export interface UnstableDevOptions { script_name?: string | undefined; environment?: string | undefined; }[]; + services?: { + binding: string; + service: string; + environment?: string | undefined; + }[]; r2?: { binding: string; bucket_name: string; diff --git a/packages/wrangler/src/dev.tsx b/packages/wrangler/src/dev.tsx index ffc930179f3..28bf91392a3 100644 --- a/packages/wrangler/src/dev.tsx +++ b/packages/wrangler/src/dev.tsx @@ -314,6 +314,11 @@ export type AdditionalDevProps = { script_name?: string | undefined; environment?: string | undefined; }[]; + services?: { + binding: string; + service: string; + environment?: string; + }[]; r2?: { binding: string; bucket_name: string; @@ -819,6 +824,7 @@ function getBindingsAndAssetPaths(args: StartDevOptions, configParam: Config) { vars: { ...args.vars, ...cliVars }, durableObjects: args.durableObjects, r2: args.r2, + services: args.services, d1Databases: args.d1Databases, }); @@ -915,7 +921,7 @@ function getBindings( ], dispatch_namespaces: configParam.dispatch_namespaces, mtls_certificates: configParam.mtls_certificates, - services: configParam.services, + services: [...(configParam.services || []), ...(args.services || [])], analytics_engine_datasets: configParam.analytics_engine_datasets, unsafe: { bindings: configParam.unsafe.bindings, diff --git a/packages/wrangler/src/pages/dev.ts b/packages/wrangler/src/pages/dev.ts index a0eb5acf952..c5500983dc4 100644 --- a/packages/wrangler/src/pages/dev.ts +++ b/packages/wrangler/src/pages/dev.ts @@ -56,6 +56,16 @@ const DURABLE_OBJECTS_BINDING_REGEXP = new RegExp( */ const BINDING_REGEXP = new RegExp(/^(?[^=]+)(?:=(?[^\s]+))?$/); +/* SERVICE_BINDING_REGEXP matches strings like: + * - "binding=service" + * - "binding=service@environment" + * This is used to capture both the binding name (how the binding is used in JS) alongside the name of the service it needs to bind to. + * Additionally it can also accept an environment which indicates what environment the service has to be running for. + */ +const SERVICE_BINDING_REGEXP = new RegExp( + /^(?[^=]+)=(?[^@\s]+)(@(?.*)$)?$/ +); + export function Options(yargs: CommonYargsArgv) { return yargs .positional("directory", { @@ -144,6 +154,11 @@ export function Options(yargs: CommonYargsArgv) { type: "array", description: "R2 bucket to bind (--r2 R2_BINDING)", }, + service: { + type: "array", + description: "Service to bind (--service SERVICE=SCRIPT_NAME)", + alia: "s", + }, "live-reload": { type: "boolean", default: false, @@ -199,6 +214,7 @@ export const Handler = async ({ do: durableObjects = [], d1: d1s = [], r2: r2s = [], + service: requestedServices = [], liveReload, localProtocol, persistTo, @@ -544,6 +560,40 @@ export const Handler = async ({ } } + const services = requestedServices + .map((serviceBinding) => { + const { binding, service, environment } = + SERVICE_BINDING_REGEXP.exec(serviceBinding.toString())?.groups || {}; + + if (!binding || !service) { + logger.warn( + "Could not parse Service binding:", + serviceBinding.toString() + ); + return; + } + + // Envs get appended to the end of the name + let serviceName = service; + if (environment) { + serviceName = `${service}-${environment}`; + } + + return { + binding, + service: serviceName, + environment, + }; + }) + .filter(Boolean) as NonNullable; + + if (services.find(({ environment }) => !!environment)) { + // We haven't yet properly defined how environments of service bindings should + // work, so if the user is using an environment for any of their service + // bindings we warn them that they are experimental + logger.warn("Support for service binding environments is experimental."); + } + const { stop, waitUntilExit } = await unstable_dev(entrypoint, { ip, port, @@ -557,6 +607,7 @@ export const Handler = async ({ .map((binding) => binding.toString().split("=")) .map(([key, ...values]) => [key, values.join("=")]) ), + services, kv: kvs .map((kv) => { const { binding, ref } = diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7246abe329a..0ccaddb8f60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,6 +117,24 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/external-service-bindings-app: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:* + version: link:../../packages/workers-tsconfig + '@cloudflare/workers-types': + specifier: ^4.20221111.1 + version: registry.npmjs.org/@cloudflare/workers-types@4.20230914.0 + concurrently: + specifier: ^8.2.1 + version: 8.2.1 + undici: + specifier: ^5.23.0 + version: 5.23.0 + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + fixtures/isomorphic-random-example: {} fixtures/legacy-site-app: {} @@ -3404,46 +3422,6 @@ packages: marked: 0.3.19 dev: false - /@cloudflare/workerd-darwin-64@1.20231016.0: - resolution: {integrity: sha512-rPAnF8Q25+eHEsAopihWeftPW/P0QapY9d7qaUmtOXztWdd6YPQ7JuiWVj4Nvjphge1BleehxAbo4I3Z4L2H1g==} - engines: {node: '>=16'} - cpu: [x64] - os: [darwin] - requiresBuild: true - optional: true - - /@cloudflare/workerd-darwin-arm64@1.20231016.0: - resolution: {integrity: sha512-MvydDdiLXt+jy57vrVZ2lU6EQwCdpieyZoN8uBXSWzfG3zR/6dxU1+okvPQPlHN0jtlufqPeHrpJyAqqgLHUKA==} - engines: {node: '>=16'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - optional: true - - /@cloudflare/workerd-linux-64@1.20231016.0: - resolution: {integrity: sha512-y6Sj37yTzM8QbAghG9LRqoSBrsREnQz8NkcmpjSxeK6KMc2g0L5A/OemCdugNlIiv+zRv9BYX1aosaoxY5JbeQ==} - engines: {node: '>=16'} - cpu: [x64] - os: [linux] - requiresBuild: true - optional: true - - /@cloudflare/workerd-linux-arm64@1.20231016.0: - resolution: {integrity: sha512-LqMIRUHD1YeRg2TPIfIQEhapSKMFSq561RypvJoXZvTwSbaROxGdW6Ku+PvButqTkEvuAtfzN/kGje7fvfQMHg==} - engines: {node: '>=16'} - cpu: [arm64] - os: [linux] - requiresBuild: true - optional: true - - /@cloudflare/workerd-windows-64@1.20231016.0: - resolution: {integrity: sha512-96ojBwIHyiUAbsWlzBqo9P/cvH8xUh8SuBboFXtwAeXcJ6/urwKN2AqPa/QzOGUTCdsurWYiieARHT5WWWPhKw==} - engines: {node: '>=16'} - cpu: [x64] - os: [win32] - requiresBuild: true - optional: true - /@cloudflare/workers-types@3.18.0: resolution: {integrity: sha512-ehKOJVLMeR+tZkYhWEaLYQxl0TaIZu/kE86HF3/RidR8Xv5LuQxpbh+XXAoKVqsaphWLhIgBhgnlN5HGdheXSQ==} @@ -7902,6 +7880,22 @@ packages: yargs: 17.7.1 dev: true + /concurrently@8.2.1: + resolution: {integrity: sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ==} + engines: {node: ^14.13.0 || >=16.0.0} + hasBin: true + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.1 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + dev: true + /connect-history-api-fallback@1.6.0: resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} engines: {node: '>=0.8'} @@ -15102,6 +15096,12 @@ packages: tslib: 2.5.3 dev: true + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.5.3 + dev: true + /sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -15569,6 +15569,10 @@ packages: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} dev: true + /spawn-command@0.0.2: + resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + dev: true + /spawn-command@0.0.2-1: resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==} dev: true @@ -17316,11 +17320,11 @@ packages: hasBin: true requiresBuild: true optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20231016.0 - '@cloudflare/workerd-darwin-arm64': 1.20231016.0 - '@cloudflare/workerd-linux-64': 1.20231016.0 - '@cloudflare/workerd-linux-arm64': 1.20231016.0 - '@cloudflare/workerd-windows-64': 1.20231016.0 + '@cloudflare/workerd-darwin-64': registry.npmjs.org/@cloudflare/workerd-darwin-64@1.20231016.0 + '@cloudflare/workerd-darwin-arm64': registry.npmjs.org/@cloudflare/workerd-darwin-arm64@1.20231016.0 + '@cloudflare/workerd-linux-64': registry.npmjs.org/@cloudflare/workerd-linux-64@1.20231016.0 + '@cloudflare/workerd-linux-arm64': registry.npmjs.org/@cloudflare/workerd-linux-arm64@1.20231016.0 + '@cloudflare/workerd-windows-64': registry.npmjs.org/@cloudflare/workerd-windows-64@1.20231016.0 /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} @@ -17608,3 +17612,59 @@ packages: name: yoga-layout version: 2.0.0-beta.1 dev: true + + registry.npmjs.org/@cloudflare/workerd-darwin-64@1.20231016.0: + resolution: {integrity: sha512-rPAnF8Q25+eHEsAopihWeftPW/P0QapY9d7qaUmtOXztWdd6YPQ7JuiWVj4Nvjphge1BleehxAbo4I3Z4L2H1g==, registry: https://registry-gateway.cloudflare-ui.workers.dev/, tarball: https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20231016.0.tgz} + name: '@cloudflare/workerd-darwin-64' + version: 1.20231016.0 + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + registry.npmjs.org/@cloudflare/workerd-darwin-arm64@1.20231016.0: + resolution: {integrity: sha512-MvydDdiLXt+jy57vrVZ2lU6EQwCdpieyZoN8uBXSWzfG3zR/6dxU1+okvPQPlHN0jtlufqPeHrpJyAqqgLHUKA==, registry: https://registry-gateway.cloudflare-ui.workers.dev/, tarball: https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20231016.0.tgz} + name: '@cloudflare/workerd-darwin-arm64' + version: 1.20231016.0 + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + registry.npmjs.org/@cloudflare/workerd-linux-64@1.20231016.0: + resolution: {integrity: sha512-y6Sj37yTzM8QbAghG9LRqoSBrsREnQz8NkcmpjSxeK6KMc2g0L5A/OemCdugNlIiv+zRv9BYX1aosaoxY5JbeQ==, registry: https://registry-gateway.cloudflare-ui.workers.dev/, tarball: https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20231016.0.tgz} + name: '@cloudflare/workerd-linux-64' + version: 1.20231016.0 + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + registry.npmjs.org/@cloudflare/workerd-linux-arm64@1.20231016.0: + resolution: {integrity: sha512-LqMIRUHD1YeRg2TPIfIQEhapSKMFSq561RypvJoXZvTwSbaROxGdW6Ku+PvButqTkEvuAtfzN/kGje7fvfQMHg==, registry: https://registry-gateway.cloudflare-ui.workers.dev/, tarball: https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20231016.0.tgz} + name: '@cloudflare/workerd-linux-arm64' + version: 1.20231016.0 + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + registry.npmjs.org/@cloudflare/workerd-windows-64@1.20231016.0: + resolution: {integrity: sha512-96ojBwIHyiUAbsWlzBqo9P/cvH8xUh8SuBboFXtwAeXcJ6/urwKN2AqPa/QzOGUTCdsurWYiieARHT5WWWPhKw==, registry: https://registry-gateway.cloudflare-ui.workers.dev/, tarball: https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20231016.0.tgz} + name: '@cloudflare/workerd-windows-64' + version: 1.20231016.0 + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + + registry.npmjs.org/@cloudflare/workers-types@4.20230914.0: + resolution: {integrity: sha512-OVeN4lFVu1O0PJGZ2d0FwpK8lelFcr33qYOgCh77ErEYmEBO4adwnIxcIsdQbFbhF0ffN6joiVcljD4zakdaeQ==, registry: https://registry-gateway.cloudflare-ui.workers.dev/, tarball: https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20230914.0.tgz} + name: '@cloudflare/workers-types' + version: 4.20230914.0 + dev: true