From 8a3c6c00105a3420e46da660bd3f317b26f1c6d4 Mon Sep 17 00:00:00 2001 From: Carmen Popoviciu Date: Fri, 2 Aug 2024 11:52:22 +0200 Subject: [PATCH] feat: Create very basic Asset Worker and plumb it into wrangler dev (#6370) This commit does the ground work needed in order to add Assets support for Workers in `wrangler dev`. Amongst others, it implements the following: - it creates a new package called `workers-shared` that hosts the `Asset Server Worker`, and the `Router Worker`in the future - it scaffolds the `Asset Server Worker` in some very basic form, with basic configuration. Further behaviour implementation will follow in a subsequent PR - it does the ground work of plumbing ASW into Miniflare --- .changeset/orange-icons-build.md | 12 + fixtures/workers-with-assets/README.md | 23 ++ fixtures/workers-with-assets/package.json | 20 ++ .../workers-with-assets/public/index.html | 1 + .../workers-with-assets/tests/index.test.ts | 26 ++ .../workers-with-assets/tests/tsconfig.json | 7 + fixtures/workers-with-assets/tsconfig.json | 13 + fixtures/workers-with-assets/wrangler.toml | 5 + packages/workers-shared/README.md | 13 + .../asset-server-worker/README.md | 3 + .../asset-server-worker/src/index.ts | 5 + .../asset-server-worker/wrangler.toml | 12 + packages/workers-shared/package.json | 17 ++ packages/workers-shared/turbo.json | 9 + packages/wrangler/package.json | 1 + packages/wrangler/scripts/deps.ts | 1 + .../wrangler/src/__tests__/deploy.test.ts | 2 +- packages/wrangler/src/__tests__/dev.test.tsx | 83 +++++- packages/wrangler/src/api/dev.ts | 2 +- .../api/startDevWorker/ConfigController.ts | 7 + .../startDevWorker/LocalRuntimeController.ts | 1 + .../wrangler/src/api/startDevWorker/types.ts | 7 +- .../wrangler/src/deployment-bundle/entry.ts | 12 +- packages/wrangler/src/dev.tsx | 61 +++-- packages/wrangler/src/dev/dev.tsx | 8 +- packages/wrangler/src/dev/local.tsx | 3 + packages/wrangler/src/dev/miniflare.ts | 52 +++- packages/wrangler/src/dev/start-server.ts | 1 + .../wrangler/templates/no-op-assets-worker.ts | 33 +++ pnpm-lock.yaml | 252 +++++++++++++----- 30 files changed, 582 insertions(+), 110 deletions(-) create mode 100644 .changeset/orange-icons-build.md create mode 100644 fixtures/workers-with-assets/README.md create mode 100644 fixtures/workers-with-assets/package.json create mode 100644 fixtures/workers-with-assets/public/index.html create mode 100644 fixtures/workers-with-assets/tests/index.test.ts create mode 100644 fixtures/workers-with-assets/tests/tsconfig.json create mode 100644 fixtures/workers-with-assets/tsconfig.json create mode 100644 fixtures/workers-with-assets/wrangler.toml create mode 100644 packages/workers-shared/README.md create mode 100644 packages/workers-shared/asset-server-worker/README.md create mode 100644 packages/workers-shared/asset-server-worker/src/index.ts create mode 100644 packages/workers-shared/asset-server-worker/wrangler.toml create mode 100644 packages/workers-shared/package.json create mode 100644 packages/workers-shared/turbo.json create mode 100644 packages/wrangler/templates/no-op-assets-worker.ts diff --git a/.changeset/orange-icons-build.md b/.changeset/orange-icons-build.md new file mode 100644 index 000000000000..40677b029a94 --- /dev/null +++ b/.changeset/orange-icons-build.md @@ -0,0 +1,12 @@ +--- +"@cloudflare/workers-shared": minor +"wrangler": minor +--- + +feat: Create very basic Asset Server Worker and plumb it into `wrangler dev` + +These changes do the ground work needed in order to add Assets support for Workers in `wrangler dev`. They implement the following: + +- it creates a new package called `workers-shared` that hosts the `Asset Server Worker`, and the `Router Worker`in the future +- it scaffolds the `Asset Server Worker` in some very basic form, with basic configuration. Further behaviour implementation will follow in a subsequent PR +- it does the ground work of plumbing ASW into Miniflare diff --git a/fixtures/workers-with-assets/README.md b/fixtures/workers-with-assets/README.md new file mode 100644 index 000000000000..3cddc512a6a6 --- /dev/null +++ b/fixtures/workers-with-assets/README.md @@ -0,0 +1,23 @@ +# workers-with-assets + +`workers-with-assets` is a test fixture that showcases Workers with Assets. This particular fixture sets up an assets-only Workers project. + +## dev + +To start a dev session you can run + +``` +wrangler dev +``` + +or + +``` +wrangler dev --experimental-assets=./public +``` + +## Run tests + +``` +npm run test +``` diff --git a/fixtures/workers-with-assets/package.json b/fixtures/workers-with-assets/package.json new file mode 100644 index 000000000000..771021f2e01c --- /dev/null +++ b/fixtures/workers-with-assets/package.json @@ -0,0 +1,20 @@ +{ + "name": "assets-worker", + "private": true, + "scripts": { + "check:type": "tsc", + "dev": "npx wrangler dev", + "test:ci": "vitest run", + "test:watch": "vitest", + "type:tests": "tsc -p ./tests/tsconfig.json" + }, + "devDependencies": { + "@cloudflare/workers-tsconfig": "workspace:*", + "@cloudflare/workers-types": "^4.20240725.0", + "undici": "^5.28.4", + "wrangler": "workspace:*" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/fixtures/workers-with-assets/public/index.html b/fixtures/workers-with-assets/public/index.html new file mode 100644 index 000000000000..de28c4adee5c --- /dev/null +++ b/fixtures/workers-with-assets/public/index.html @@ -0,0 +1 @@ +

Hello Workers + Assets World!

diff --git a/fixtures/workers-with-assets/tests/index.test.ts b/fixtures/workers-with-assets/tests/index.test.ts new file mode 100644 index 000000000000..cc0d36bb02b9 --- /dev/null +++ b/fixtures/workers-with-assets/tests/index.test.ts @@ -0,0 +1,26 @@ +import { resolve } from "node:path"; +import { fetch } from "undici"; +import { afterAll, beforeAll, describe, it } from "vitest"; +import { runWranglerDev } from "../../shared/src/run-wrangler-long-lived"; + +describe("[Workers + Assets] `wrangler dev`", () => { + let ip: string, port: number, stop: (() => Promise) | undefined; + + beforeAll(async () => { + ({ ip, port, stop } = await runWranglerDev(resolve(__dirname, ".."), [ + "--port=0", + "--inspector-port=0", + ])); + }); + + afterAll(async () => { + await stop?.(); + }); + + it("renders ", async ({ expect }) => { + const response = await fetch(`http://${ip}:${port}/`); + const text = await response.text(); + expect(response.status).toBe(200); + expect(text).toContain(`Hello from Asset Server Worker 🚀`); + }); +}); diff --git a/fixtures/workers-with-assets/tests/tsconfig.json b/fixtures/workers-with-assets/tests/tsconfig.json new file mode 100644 index 000000000000..d2ce7f144694 --- /dev/null +++ b/fixtures/workers-with-assets/tests/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@cloudflare/workers-tsconfig/tsconfig.json", + "compilerOptions": { + "types": ["node"] + }, + "include": ["**/*.ts", "../../../node-types.d.ts"] +} diff --git a/fixtures/workers-with-assets/tsconfig.json b/fixtures/workers-with-assets/tsconfig.json new file mode 100644 index 000000000000..874dec6ac33a --- /dev/null +++ b/fixtures/workers-with-assets/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "esModuleInterop": true, + "module": "CommonJS", + "lib": ["ES2020"], + "types": ["node"], + "moduleResolution": "node", + "noEmit": true, + "skipLibCheck": true + }, + "include": ["tests", "../../node-types.d.ts"] +} diff --git a/fixtures/workers-with-assets/wrangler.toml b/fixtures/workers-with-assets/wrangler.toml new file mode 100644 index 000000000000..74950a4d0992 --- /dev/null +++ b/fixtures/workers-with-assets/wrangler.toml @@ -0,0 +1,5 @@ +name = "assets-worker" +compatibility_date = "2024-01-01" + +[experimental_assets] +directory = "./public" diff --git a/packages/workers-shared/README.md b/packages/workers-shared/README.md new file mode 100644 index 000000000000..c42b57532b77 --- /dev/null +++ b/packages/workers-shared/README.md @@ -0,0 +1,13 @@ +# `@cloudflare/workers-shared` + +This is a package that is used at Cloudflare to power some internal features of [Cloudflare Workers](https://developers.cloudflare.com/workers/), as well as their open-source equivalents here in workers-sdk and Wrangler. + +## `asset-server` + +The Asset Server Worker. + +For more details please refer to the dedicated README file. + +> [!NOTE] +> Since code in this package is used by the Workers infrastructure, it is important that PRs are given careful review with regards to how they could cause a failure in production. +> Ideally, there should be comprehensive tests for changes being made to give extra confidence about the behavior. diff --git a/packages/workers-shared/asset-server-worker/README.md b/packages/workers-shared/asset-server-worker/README.md new file mode 100644 index 000000000000..88a6e0d953e5 --- /dev/null +++ b/packages/workers-shared/asset-server-worker/README.md @@ -0,0 +1,3 @@ +# `asset-server` + +The Asset Server is a [Cloudflare Worker](https://developers.cloudflare.com/workers/) that is responsible of serving assets for Workers deployed on the edge, that contain static assets as well. diff --git a/packages/workers-shared/asset-server-worker/src/index.ts b/packages/workers-shared/asset-server-worker/src/index.ts new file mode 100644 index 000000000000..3249a340c471 --- /dev/null +++ b/packages/workers-shared/asset-server-worker/src/index.ts @@ -0,0 +1,5 @@ +export default { + async fetch(request, env) { + return new Response("Hello from Asset Server Worker 🚀"); + }, +}; diff --git a/packages/workers-shared/asset-server-worker/wrangler.toml b/packages/workers-shared/asset-server-worker/wrangler.toml new file mode 100644 index 000000000000..5c312ad0e107 --- /dev/null +++ b/packages/workers-shared/asset-server-worker/wrangler.toml @@ -0,0 +1,12 @@ +## +# Configuration file for the Asset Server Worker +# +# Please note that wrangler has a dependency on this file, and will +# attempt to read it as part of setting up a new Miniflare instance +# in developemnt mode. We should ensure that any configuration changes +# to this file are persisted in wrangler as well, when necessary. +# (see packages/wrangler/src/dev/miniflare.ts -> buildMiniflareOptions()) +## +name = "asset-server" +main = "src/index.ts" +compatibility_date = "2024-07-31" diff --git a/packages/workers-shared/package.json b/packages/workers-shared/package.json new file mode 100644 index 000000000000..2d2c9345d715 --- /dev/null +++ b/packages/workers-shared/package.json @@ -0,0 +1,17 @@ +{ + "name": "@cloudflare/workers-shared", + "version": "0.0.1", + "description": "Package that is used at Cloudflare to power some internal features of Cloudflare Workers.", + "scripts": { + "build": "pnpm run clean && pnpm run bundle:asset-server", + "bundle:asset-server": "esbuild asset-server-worker/src/index.ts --format=esm --bundle --outfile=dist/asset-server-worker.mjs --sourcemap=external", + "clean": "rimraf dist", + "dev": "pnpm run clean && concurrently -n bundle:asset-server -c blue \"pnpm run bundle:asset-server --watch\"" + }, + "devDependencies": { + "concurrently": "^8.2.2", + "esbuild": "0.17.19", + "rimraf": "^6.0.1", + "typescript": "^5.5.4" + } +} diff --git a/packages/workers-shared/turbo.json b/packages/workers-shared/turbo.json new file mode 100644 index 000000000000..1a6c74c9def8 --- /dev/null +++ b/packages/workers-shared/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "build": { + "outputs": ["dist/**"] + } + } +} diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index 00b374bc3c02..d48326f63234 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -92,6 +92,7 @@ "@cloudflare/eslint-config-worker": "workspace:*", "@cloudflare/pages-shared": "workspace:^", "@cloudflare/types": "^6.18.4", + "@cloudflare/workers-shared": "workspace:*", "@cloudflare/workers-tsconfig": "workspace:*", "@cloudflare/workers-types": "^4.20240725.0", "@cspotcode/source-map-support": "0.8.1", diff --git a/packages/wrangler/scripts/deps.ts b/packages/wrangler/scripts/deps.ts index 4c6ed1409263..874df64b2740 100644 --- a/packages/wrangler/scripts/deps.ts +++ b/packages/wrangler/scripts/deps.ts @@ -22,6 +22,7 @@ export const EXTERNAL_DEPENDENCIES = [ // and read when we are bundling the worker application "unenv", "workerd/worker.mjs", + "@cloudflare/workers-shared", ]; const pathToPackageJson = path.resolve(__dirname, "..", "package.json"); diff --git a/packages/wrangler/src/__tests__/deploy.test.ts b/packages/wrangler/src/__tests__/deploy.test.ts index 0928001eb071..6a1109ee44e5 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -4363,7 +4363,7 @@ addEventListener('fetch', event => {});` }); writeWorkerSource(); mockUploadWorkerRequest({ - expectedMainModule: "no-op-worker.js", + expectedMainModule: "no-op-assets-worker.js", }); mockSubDomainRequest(); await runWrangler("deploy"); diff --git a/packages/wrangler/src/__tests__/dev.test.tsx b/packages/wrangler/src/__tests__/dev.test.tsx index 1a96ed5c64c5..c0e9376e07cf 100644 --- a/packages/wrangler/src/__tests__/dev.test.tsx +++ b/packages/wrangler/src/__tests__/dev.test.tsx @@ -1303,7 +1303,7 @@ describe("wrangler dev", () => { await expect( runWrangler("dev --legacy-assets abc --site xyz") ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Cannot use Assets and Workers Sites in the same Worker.]` + `[Error: Cannot use Legacy Assets and Workers Sites in the same Worker.]` ); }); @@ -1318,7 +1318,7 @@ describe("wrangler dev", () => { await expect( runWrangler("dev --legacy-assets abc") ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Cannot use Assets and Workers Sites in the same Worker.]` + `[Error: Cannot use Legacy Assets and Workers Sites in the same Worker.]` ); }); @@ -1331,7 +1331,7 @@ describe("wrangler dev", () => { await expect( runWrangler("dev --site xyz") ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Cannot use Assets and Workers Sites in the same Worker.]` + `[Error: Cannot use Legacy Assets and Workers Sites in the same Worker.]` ); }); @@ -1347,7 +1347,7 @@ describe("wrangler dev", () => { await expect( runWrangler("dev --legacy-assets abc") ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Cannot use Assets and Workers Sites in the same Worker.]` + `[Error: Cannot use Legacy Assets and Workers Sites in the same Worker.]` ); }); @@ -1441,11 +1441,11 @@ describe("wrangler dev", () => { await expect( runWrangler("dev") ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Cannot use Assets and Workers Sites in the same Worker.]` + `[Error: Cannot use Experimental Assets and Workers Sites in the same Worker.]` ); }); - it("should error if --experimental-assets and config.site are used together", async () => { + it("should error if config.site and --experimental-assets are used together", async () => { writeWranglerToml({ main: "./index.js", site: { @@ -1457,7 +1457,74 @@ describe("wrangler dev", () => { await expect( runWrangler("dev --experimental-assets assets") ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Cannot use Assets and Workers Sites in the same Worker.]` + `[Error: Cannot use Experimental Assets and Workers Sites in the same Worker.]` + ); + }); + + it("should error if config.experimental_assets and config.legacy_assets are used together", async () => { + writeWranglerToml({ + main: "./index.js", + experimental_assets: { directory: "assets" }, + legacy_assets: { + bucket: "xyz", + include: [], + exclude: [], + browser_TTL: undefined, + serve_single_page_app: true, + }, + }); + fs.writeFileSync("index.js", `export default {};`); + fs.openSync("assets", "w"); + await expect( + runWrangler("dev") + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Cannot use Legacy Assets and Experimental Assets in the same Worker.]` + ); + }); + + it("should error if --experimental-assets and --legacy-assets are used together", async () => { + fs.writeFileSync("index.js", `export default {};`); + fs.openSync("assets", "w"); + await expect( + runWrangler("dev --experimental-assets assets --legacy-assets assets") + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Cannot use Legacy Assets and Experimental Assets in the same Worker.]` + ); + }); + + it("should error if --experimental-assets and config.legacy_assets are used together", async () => { + writeWranglerToml({ + main: "./index.js", + legacy_assets: { + bucket: "xyz", + include: [], + exclude: [], + browser_TTL: undefined, + serve_single_page_app: true, + }, + }); + fs.writeFileSync("index.js", `export default {};`); + fs.openSync("assets", "w"); + await expect( + runWrangler("dev --experimental-assets assets") + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Cannot use Legacy Assets and Experimental Assets in the same Worker.]` + ); + }); + + it("should error if config.experimental_assets and --legacy-assets are used together", async () => { + writeWranglerToml({ + main: "./index.js", + experimental_assets: { + directory: "xyz", + }, + }); + fs.writeFileSync("index.js", `export default {};`); + fs.openSync("xyz", "w"); + await expect( + runWrangler("dev --legacy-assets xyz") + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Cannot use Legacy Assets and Experimental Assets in the same Worker.]` ); }); @@ -1475,7 +1542,7 @@ describe("wrangler dev", () => { ); }); - it("should error if directory specified by 'experimental_assets' configuration key does not exist", async () => { + it("should error if directory specified by '[experimental_assets]' configuration key does not exist", async () => { writeWranglerToml({ main: "./index.js", experimental_assets: { diff --git a/packages/wrangler/src/api/dev.ts b/packages/wrangler/src/api/dev.ts index a9dde89e61d1..dc43a863c6a8 100644 --- a/packages/wrangler/src/api/dev.ts +++ b/packages/wrangler/src/api/dev.ts @@ -189,7 +189,7 @@ export async function unstable_dev( localProtocol: options?.localProtocol, httpsKeyPath: options?.httpsKeyPath, httpsCertPath: options?.httpsCertPath, - experimentalAssets: options?.experimentalAssets, + experimentalAssets: undefined, legacyAssets: options?.legacyAssets, site: options?.site, // Root folder of static assets for Workers Sites siteInclude: options?.siteInclude, // Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded. diff --git a/packages/wrangler/src/api/startDevWorker/ConfigController.ts b/packages/wrangler/src/api/startDevWorker/ConfigController.ts index 6ec2e5b75f40..874f505da207 100644 --- a/packages/wrangler/src/api/startDevWorker/ConfigController.ts +++ b/packages/wrangler/src/api/startDevWorker/ConfigController.ts @@ -204,6 +204,10 @@ async function resolveConfig( legacyAssets: Boolean(legacyAssets), script: input.entrypoint, moduleRoot: input.build?.moduleRoot, + // getEntry only needs to know if experimental_assets was specified. + // The actualy value is not relevant here, which is why not passing + // the entire ExperimentalAssets object is fine. + experimentalAssets: input?.experimental?.assets?.directory, }, config, "dev" @@ -257,6 +261,9 @@ async function resolveConfig( capnp: input.unsafe?.capnp ?? unsafe?.capnp, metadata: input.unsafe?.metadata ?? unsafe?.metadata, }, + experimental: { + assets: input?.experimental?.assets, + }, } satisfies StartDevWorkerOptions; if (resolved.legacy.legacyAssets && resolved.legacy.site) { diff --git a/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts b/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts index 1fc406fc233e..22bd9aab3bed 100644 --- a/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts +++ b/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts @@ -100,6 +100,7 @@ async function convertToConfigBundle( includePatterns: event.config.legacy?.site?.include ?? [], } : undefined, + experimentalAssets: event.config.experimental?.assets, initialPort: undefined, initialIp: "127.0.0.1", rules: [], diff --git a/packages/wrangler/src/api/startDevWorker/types.ts b/packages/wrangler/src/api/startDevWorker/types.ts index aa45767a92b3..9f8c0ecd0b0c 100644 --- a/packages/wrangler/src/api/startDevWorker/types.ts +++ b/packages/wrangler/src/api/startDevWorker/types.ts @@ -1,6 +1,7 @@ import type { Config } from "../../config"; import type { CustomDomainRoute, + ExperimentalAssets, Rule, ZoneIdRoute, ZoneNameRoute, @@ -161,6 +162,9 @@ export interface StartDevWorkerInput { enableServiceEnvironments?: boolean; }; unsafe?: Omit; + experimental?: { + assets?: Omit; + }; } export type StartDevWorkerOptions = StartDevWorkerInput & { @@ -258,7 +262,8 @@ export type Binding = | ({ type: "dispatch_namespace" } & Omit) | ({ type: "mtls_certificate" } & Omit) | ({ type: "logfwdr" } & Omit) - | { type: `unsafe_${string}` }; + | { type: `unsafe_${string}` } + | { type: "assets" }; export type ServiceFetch = (request: Request) => Promise | Response; diff --git a/packages/wrangler/src/deployment-bundle/entry.ts b/packages/wrangler/src/deployment-bundle/entry.ts index 8eef2c9e8088..3fe5d022efa9 100644 --- a/packages/wrangler/src/deployment-bundle/entry.ts +++ b/packages/wrangler/src/deployment-bundle/entry.ts @@ -38,13 +38,14 @@ export async function getEntry( format?: CfScriptFormat | undefined; legacyAssets?: string | undefined | boolean; moduleRoot?: string; - experimentalAssets?: string; + experimentalAssets?: string | undefined; }, config: Config, command: "dev" | "deploy" | "versions upload" | "types" ): Promise { let file: string; let directory = process.cwd(); + if (args.script) { // If the script name comes from the command line it is relative to the current working directory. file = path.resolve(args.script); @@ -55,13 +56,10 @@ export async function getEntry( ? path.resolve(config.site?.["entry-point"]) : // site.entry-point could be a directory path.resolve(config.site?.["entry-point"], "index.js"); - } else if ( - args.legacyAssets || - config.legacy_assets || - args.experimentalAssets || - config.experimental_assets - ) { + } else if (args.legacyAssets || config.legacy_assets) { file = path.resolve(getBasePath(), "templates/no-op-worker.js"); + } else if (args.experimentalAssets || config.experimental_assets) { + file = path.resolve(getBasePath(), "templates/no-op-assets-worker.ts"); } else { throw new UserError( `Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler ${command} path/to/script\`) or the \`main\` config field.` diff --git a/packages/wrangler/src/dev.tsx b/packages/wrangler/src/dev.tsx index 2fa09c157275..286833ef6bdf 100644 --- a/packages/wrangler/src/dev.tsx +++ b/packages/wrangler/src/dev.tsx @@ -562,6 +562,7 @@ export async function startDev(args: StartDevOptions) { "--local is no longer required and will be removed in a future version.\n`wrangler dev` now uses the local Cloudflare Workers runtime by default. 🎉" ); } + if (args.experimentalLocal) { logger.warn( "--experimental-local is no longer required and will be removed in a future version.\n`wrangler dev` now uses the local Cloudflare Workers runtime by default. 🎉" @@ -574,6 +575,7 @@ export async function startDev(args: StartDevOptions) { "Passing --inspect is unnecessary, now you can always connect to devtools." ); } + if (args.experimentalPublic) { throw new UserError( "The --experimental-public field has been deprecated, try --legacy-assets instead." @@ -594,6 +596,21 @@ export async function startDev(args: StartDevOptions) { ); } + const experimentalAssets = processExperimentalAssetsArg(args, config); + if (experimentalAssets) { + args.forceLocal = true; + } + + /* + * - `config.legacy_assets` conflates `legacy_assets` and `assets` + * - `args.legacyAssets` conflates `legacy-assets` and `assets` + */ + if ((args.legacyAssets || config.legacy_assets) && experimentalAssets) { + throw new UserError( + "Cannot use Legacy Assets and Experimental Assets in the same Worker." + ); + } + const projectRoot = configPath && path.dirname(configPath); const devEnv = new DevEnv(); @@ -770,6 +787,9 @@ export async function startDev(args: StartDevOptions) { legacyAssets: (configParam) => configParam.legacy_assets, enableServiceEnvironments: !(args.legacyEnv ?? true), }, + experimental: { + assets: experimentalAssets, + }, } satisfies StartDevWorkerInput); void metrics.sendMetricsEvent( @@ -803,11 +823,6 @@ export async function startDev(args: StartDevOptions) { }); } - const experimentalAssets = processExperimentalAssetsArg(args, config); - if (experimentalAssets) { - args.forceLocal = true; - } - const { entry, upstreamProtocol, @@ -882,6 +897,7 @@ export async function startDev(args: StartDevOptions) { } legacyAssetPaths={legacyAssetPaths} legacyAssetsConfig={configParam.legacy_assets} + experimentalAssets={experimentalAssets} initialPort={ args.port ?? configParam.dev.port ?? (await getLocalPort()) } @@ -1044,6 +1060,7 @@ export async function startApiDev(args: StartDevOptions) { args.accountId ?? configParam.account_id ?? getAccountFromCache()?.id, legacyAssetPaths: legacyAssetPaths, legacyAssetsConfig: configParam.legacy_assets, + experimentalAssets: undefined, //port can be 0, which means to use a random port initialPort: args.port ?? configParam.dev.port ?? (await getLocalPort()), initialIp: args.ip ?? configParam.dev.ip, @@ -1181,6 +1198,28 @@ export async function validateDevServerSettings( args: StartDevOptions, config: Config ) { + /* + * - `args.legacyAssets` conflates `legacy-assets` and `assets` + * - `config.legacy_assets` conflates `legacy_assets` and `assets` + */ + if ( + (args.legacyAssets || config.legacy_assets) && + (args.site || config.site) + ) { + throw new UserError( + "Cannot use Legacy Assets and Workers Sites in the same Worker." + ); + } + + if ( + (args.experimentalAssets || config.experimental_assets) && + (args.site || config.site) + ) { + throw new UserError( + "Cannot use Experimental Assets and Workers Sites in the same Worker." + ); + } + const entry = await getEntry( { legacyAssets: args.legacyAssets, @@ -1231,18 +1270,6 @@ export async function validateDevServerSettings( ); } - if ( - (args.legacyAssets || - config.legacy_assets || - args.experimentalAssets || - config.experimental_assets) && - (args.site || config.site) - ) { - throw new UserError( - "Cannot use Assets and Workers Sites in the same Worker." - ); - } - const upstreamProtocol = args.upstreamProtocol ?? config.dev.upstream_protocol; if (upstreamProtocol === "http" && args.remote) { diff --git a/packages/wrangler/src/dev/dev.tsx b/packages/wrangler/src/dev/dev.tsx index a6da138b7e56..0c7dcceac2a7 100644 --- a/packages/wrangler/src/dev/dev.tsx +++ b/packages/wrangler/src/dev/dev.tsx @@ -42,7 +42,7 @@ import type { Trigger, } from "../api"; import type { Config } from "../config"; -import type { Route } from "../config/environment"; +import type { ExperimentalAssets, Route } from "../config/environment"; import type { Entry } from "../deployment-bundle/entry"; import type { NodeJSCompatMode } from "../deployment-bundle/node-compat"; import type { CfModule, CfWorkerInit } from "../deployment-bundle/worker"; @@ -233,6 +233,7 @@ export type DevProps = { isWorkersSite: boolean; legacyAssetPaths: LegacyAssetPaths | undefined; legacyAssetsConfig: Config["legacy_assets"]; + experimentalAssets: ExperimentalAssets | undefined; compatibilityDate: string; compatibilityFlags: string[] | undefined; usageModel: "bundled" | "unbound" | undefined; @@ -479,6 +480,9 @@ function DevSession(props: DevSessionProps) { capnp: props.bindings.unsafe?.capnp, metadata: props.bindings.unsafe?.metadata, }, + experimental: { + assets: props.experimentalAssets, + }, } satisfies StartDevWorkerOptions; }, [ props.routes, @@ -493,6 +497,7 @@ function DevSession(props: DevSessionProps) { props.isWorkersSite, props.local, props.legacyAssetsConfig, + props.experimentalAssets, props.processEntrypoint, props.additionalModules, props.env, @@ -684,6 +689,7 @@ function DevSession(props: DevSessionProps) { bindings={props.bindings} workerDefinitions={workerDefinitions} legacyAssetPaths={props.legacyAssetPaths} + experimentalAssets={props.experimentalAssets} initialPort={undefined} // hard-code for userworker, DevEnv-ProxyWorker now uses this prop value initialIp={"127.0.0.1"} // hard-code for userworker, DevEnv-ProxyWorker now uses this prop value rules={props.rules} diff --git a/packages/wrangler/src/dev/local.tsx b/packages/wrangler/src/dev/local.tsx index 612ce77b4459..66e428bc32bf 100644 --- a/packages/wrangler/src/dev/local.tsx +++ b/packages/wrangler/src/dev/local.tsx @@ -7,6 +7,7 @@ import { logger } from "../logger"; import { DEFAULT_WORKER_NAME, MiniflareServer } from "./miniflare"; import type { ProxyData } from "../api"; import type { Config } from "../config"; +import type { ExperimentalAssets } from "../config/environment"; import type { CfDurableObject, CfScriptFormat, @@ -31,6 +32,7 @@ export interface LocalProps { bindings: CfWorkerInit["bindings"]; workerDefinitions: WorkerRegistry | undefined; legacyAssetPaths: LegacyAssetPaths | undefined; + experimentalAssets: ExperimentalAssets | undefined; initialPort: number | undefined; initialIp: string; rules: Config["rules"]; @@ -90,6 +92,7 @@ export async function localPropsToConfigBundle( bindings: props.bindings, workerDefinitions: props.workerDefinitions, legacyAssetPaths: props.legacyAssetPaths, + experimentalAssets: props.experimentalAssets, initialPort: props.initialPort, initialIp: props.initialIp, rules: props.rules, diff --git a/packages/wrangler/src/dev/miniflare.ts b/packages/wrangler/src/dev/miniflare.ts index c3bb37498900..674cc8fd5404 100644 --- a/packages/wrangler/src/dev/miniflare.ts +++ b/packages/wrangler/src/dev/miniflare.ts @@ -1,6 +1,6 @@ import assert from "node:assert"; import { randomUUID } from "node:crypto"; -import path from "node:path"; +import path, { dirname } from "node:path"; import * as esmLexer from "es-module-lexer"; import { CoreHeaders, @@ -16,6 +16,7 @@ import { EXTERNAL_AI_WORKER_NAME, EXTERNAL_AI_WORKER_SCRIPT, } from "../ai/fetcher"; +import { readConfig } from "../config"; import { ModuleTypeToRuleType } from "../deployment-bundle/module-collection"; import { withSourceURLs } from "../deployment-bundle/source-url"; import { UserError } from "../errors"; @@ -24,6 +25,7 @@ import { getSourceMappedString } from "../sourcemap"; import { updateCheck } from "../update-check"; import type { ServiceFetch } from "../api"; import type { Config } from "../config"; +import type { ExperimentalAssets } from "../config/environment"; import type { CfD1Database, CfDurableObject, @@ -172,6 +174,7 @@ export interface ConfigBundle { bindings: CfWorkerInit["bindings"]; workerDefinitions: WorkerRegistry | undefined; legacyAssetPaths: LegacyAssetPaths | undefined; + experimentalAssets: ExperimentalAssets | undefined; initialPort: Port; initialIp: string; rules: Config["rules"]; @@ -374,7 +377,7 @@ type MiniflareBindingsConfig = Pick< | "services" | "serviceBindings" > & - Partial>; + Partial>; // TODO(someday): would be nice to type these methods more, can we export types for // each plugin options schema and use those @@ -408,7 +411,9 @@ export function buildMiniflareBindingOptions(config: MiniflareBindingsConfig): { // Setup service bindings to external services const serviceBindings: NonNullable = { ...config.serviceBindings, + ...(config.experimentalAssets ? { ASSET_SERVER: "asset-server" } : {}), }; + const notFoundServices = new Set(); for (const service of config.services ?? []) { if (service.service === config.name) { @@ -837,6 +842,43 @@ export async function buildMiniflareOptions( } } + const assetServerModulePath = require.resolve( + "@cloudflare/workers-shared/dist/asset-server-worker.mjs" + ); + const assetServerConfigPath = require.resolve( + "@cloudflare/workers-shared/asset-server-worker/wrangler.toml" + ); + let assetServerConfig: Config | undefined; + + try { + assetServerConfig = readConfig(assetServerConfigPath, {}); + } catch (err) { + throw new UserError( + "Failed to read the Asset Server Worker configuration file.\n" + `${err}` + ); + } + + const assetServerWorker: WorkerOptions | undefined = config.experimentalAssets + ? { + name: assetServerConfig?.name, + compatibilityDate: assetServerConfig?.compatibility_date, + compatibilityFlags: assetServerConfig?.compatibility_flags, + modulesRoot: dirname(assetServerModulePath), + modules: [ + { + type: "ESModule", + path: assetServerModulePath, + }, + ], + unsafeDirectSockets: [ + { + host: "127.0.0.1", + port: 0, + }, + ], + } + : undefined; + const upstream = typeof config.localUpstream === "string" ? `${config.upstreamProtocol}://${config.localUpstream}` @@ -879,6 +921,9 @@ export async function buildMiniflareOptions( proxy: true, })), }, + ...(config.experimentalAssets + ? [assetServerWorker as WorkerOptions] + : []), ...externalWorkers, ], }; @@ -947,9 +992,11 @@ export class MiniflareServer extends TypedEventTarget { config, this.#proxyToUserWorkerAuthenticationSecret ); + if (opts?.signal?.aborted) { return; } + if (this.#mf === undefined) { this.#mf = new Miniflare(options); } else { @@ -981,6 +1028,7 @@ export class MiniflareServer extends TypedEventTarget { this.dispatchEvent(new ErrorEvent("error", { error })); } } + onBundleUpdate(config: ConfigBundle, opts?: Abortable): Promise { return this.#mutex.runWith(() => this.#onBundleUpdate(config, opts)); } diff --git a/packages/wrangler/src/dev/start-server.ts b/packages/wrangler/src/dev/start-server.ts index 831ecc523f1e..92ca4e693b58 100644 --- a/packages/wrangler/src/dev/start-server.ts +++ b/packages/wrangler/src/dev/start-server.ts @@ -266,6 +266,7 @@ export async function startDevServer( compatibilityFlags: props.compatibilityFlags, bindings: props.bindings, legacyAssetPaths: props.legacyAssetPaths, + experimentalAssets: props.experimentalAssets, initialPort: undefined, // hard-code for userworker, DevEnv-ProxyWorker now uses this prop value initialIp: "127.0.0.1", // hard-code for userworker, DevEnv-ProxyWorker now uses this prop value rules: props.rules, diff --git a/packages/wrangler/templates/no-op-assets-worker.ts b/packages/wrangler/templates/no-op-assets-worker.ts new file mode 100644 index 000000000000..7f9a0636d0dc --- /dev/null +++ b/packages/wrangler/templates/no-op-assets-worker.ts @@ -0,0 +1,33 @@ +/** + * This Worker is used as a default entry-point for Assets-only + * Workers. It proxies the request directly on to the Asset Sever + * Worker service binding. + * + * In an Assets-only Workers world, we want to enable users + * to deploy a Worker with Assets without ever having to provide + * a User Worker. + * + * ```bash + * wrangler dev --experimental-assets dist + * wrangler deploy --experimental-assets dist + * ``` + * + * ```toml + * name = "assets-only-worker" + * compatibility_date = "2024-01-01" + * ``` + * + * Without a user-defined Worker, which usually serves as the entry + * point in the bundling process, wrangler needs to default to some + * other entry-point Worker for all intents and purposes. This is what + * this Worker is. + */ +type Env = { + ASSET_SERVER: Fetcher; +}; + +export default { + async fetch(request: Request, env: Env) { + return env.ASSET_SERVER.fetch(request); + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 59bfcecec8bd..0870a2a4c89b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -668,6 +668,21 @@ importers: fixtures/workers-chat-demo: {} + fixtures/workers-with-assets: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:* + version: link:../../packages/workers-tsconfig + '@cloudflare/workers-types': + specifier: ^4.20240725.0 + version: 4.20240725.0 + undici: + specifier: ^5.28.4 + version: 5.28.4 + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + packages/cli: devDependencies: '@clack/core': @@ -684,10 +699,10 @@ importers: version: link:../workers-tsconfig '@typescript-eslint/eslint-plugin': specifier: ^6.9.0 - version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': specifier: ^6.9.0 - version: 6.10.0(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(eslint@8.57.0)(typescript@5.5.4) chalk: specifier: ^5.2.0 version: 5.3.0 @@ -759,10 +774,10 @@ importers: version: 17.0.24 '@typescript-eslint/eslint-plugin': specifier: ^6.9.0 - version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': specifier: ^6.9.0 - version: 6.10.0(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(eslint@8.57.0)(typescript@5.5.4) chalk: specifier: ^5.2.0 version: 5.2.0 @@ -816,7 +831,7 @@ importers: version: 5.28.4 vite-tsconfig-paths: specifier: ^4.0.8 - version: 4.2.0(typescript@5.5.2)(vite@5.0.12(@types/node@20.8.3)) + version: 4.2.0(typescript@5.5.4)(vite@5.0.12(@types/node@20.8.3)) which-pm-runs: specifier: ^1.1.0 version: 1.1.0 @@ -870,7 +885,7 @@ importers: dependencies: '@typescript-eslint/parser': specifier: ^6.9.0 - version: 6.10.0(eslint@8.49.0)(typescript@5.5.2) + version: 6.10.0(eslint@8.49.0)(typescript@5.5.4) eslint: specifier: ^8.49.0 version: 8.49.0 @@ -879,7 +894,7 @@ importers: version: 2.0.10(eslint@8.49.0) eslint-plugin-import: specifier: 2.26.x - version: 2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0) + version: 2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0) eslint-plugin-no-only-tests: specifier: ^3.1.0 version: 3.1.0 @@ -891,11 +906,11 @@ importers: version: 4.6.0(eslint@8.49.0) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.0.0(@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0) + version: 3.0.0(@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0) devDependencies: '@typescript-eslint/eslint-plugin': specifier: ^6.9.0 - version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0)(typescript@5.5.2) + version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0)(typescript@5.5.4) packages/format-errors: devDependencies: @@ -1032,10 +1047,10 @@ importers: version: 8.5.10 '@typescript-eslint/eslint-plugin': specifier: ^6.9.0 - version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': specifier: ^6.9.0 - version: 6.10.0(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(eslint@8.57.0)(typescript@5.5.4) ava: specifier: ^6.0.1 version: 6.1.1(@ava/typescript@4.1.0)(encoding@0.1.13) @@ -1065,7 +1080,7 @@ importers: version: 4.1.0(eslint@8.57.0) eslint-plugin-import: specifier: 2.26.x - version: 2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0) + version: 2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.0.1 version: 5.0.1(eslint-config-prettier@9.0.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5) @@ -1419,10 +1434,10 @@ importers: version: 9.0.4 '@typescript-eslint/eslint-plugin': specifier: ^6.9.0 - version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': specifier: ^6.9.0 - version: 6.10.0(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(eslint@8.57.0)(typescript@5.5.4) '@vitejs/plugin-react': specifier: ^4.0.1 version: 4.0.4(vite@5.0.12(@types/node@20.12.12)) @@ -1448,6 +1463,21 @@ importers: specifier: workspace:^ version: link:../wrangler + packages/workers-shared: + devDependencies: + concurrently: + specifier: ^8.2.2 + version: 8.2.2 + esbuild: + specifier: 0.17.19 + version: 0.17.19 + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + typescript: + specifier: ^5.5.4 + version: 5.5.4 + packages/workers-tsconfig: {} packages/workers.new: @@ -1544,6 +1574,9 @@ importers: '@cloudflare/types': specifier: ^6.18.4 version: 6.18.4(react@18.2.0) + '@cloudflare/workers-shared': + specifier: workspace:* + version: link:../workers-shared '@cloudflare/workers-tsconfig': specifier: workspace:* version: link:../workers-tsconfig @@ -1711,7 +1744,7 @@ importers: version: 9.3.1 msw: specifier: ^2.3.0 - version: 2.3.0(typescript@5.5.2) + version: 2.3.0(typescript@5.5.4) open: specifier: ^8.4.0 version: 8.4.0 @@ -1810,10 +1843,10 @@ importers: version: link:../packages/workers-tsconfig '@typescript-eslint/eslint-plugin': specifier: ^6.9.0 - version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': specifier: ^6.9.0 - version: 6.10.0(eslint@8.57.0)(typescript@5.5.2) + version: 6.10.0(eslint@8.57.0)(typescript@5.5.4) find-up: specifier: ^6.3.0 version: 6.3.0 @@ -5443,6 +5476,11 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -5988,6 +6026,10 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} + jackspeak@4.0.1: + resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} + engines: {node: 20 || >=22} + javascript-time-ago@2.5.7: resolution: {integrity: sha512-EGvh6K4hpJz0S0aZinbW2EfXDqT/JBB84HfMOFDTzGg7yjpjql9feSgtlG1JQ6b6/NkIxl+PoKSUTEMsatTuTg==} @@ -6226,6 +6268,10 @@ packages: resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} engines: {node: 14 || >=16.14} + lru-cache@11.0.0: + resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==} + engines: {node: 20 || >=22} + lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -6368,6 +6414,10 @@ packages: engines: {node: '>=16.13'} hasBin: true + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + minimatch@3.0.8: resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} @@ -6405,6 +6455,10 @@ packages: resolution: {integrity: sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} @@ -6766,6 +6820,9 @@ packages: resolution: {integrity: sha512-GYTTew2slBcYdvRHqjhwaaydVMvn/qrGC323+nKclYioNSLTDUM/lGgtGTgyHVtYcozb+XkE8CNhwcraOmZ9Mg==} engines: {node: '>=18'} + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + package-json@8.1.1: resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} engines: {node: '>=14.16'} @@ -6855,6 +6912,10 @@ packages: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -7402,6 +7463,11 @@ packages: engines: {node: '>=14'} hasBin: true + rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + roarr@7.11.0: resolution: {integrity: sha512-DKiMaEYHoOZ0JyD4Ohr5KRnqybQ162s3ZL/WNO9oy6EUszYvpp0eLYJErc/U4NI96HYnHsbROhFaH4LYuJPnDg==} engines: {node: '>=12.0'} @@ -8132,6 +8198,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + ufo@1.5.3: resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} @@ -10796,13 +10867,13 @@ snapshots: '@types/yoga-layout@1.9.2': {} - '@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0)(typescript@5.5.2)': + '@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0)(typescript@5.5.4)': dependencies: '@eslint-community/regexpp': 4.10.1 - '@typescript-eslint/parser': 6.10.0(eslint@8.49.0)(typescript@5.5.2) + '@typescript-eslint/parser': 6.10.0(eslint@8.49.0)(typescript@5.5.4) '@typescript-eslint/scope-manager': 6.10.0 - '@typescript-eslint/type-utils': 6.10.0(eslint@8.49.0)(typescript@5.5.2) - '@typescript-eslint/utils': 6.10.0(eslint@8.49.0)(typescript@5.5.2) + '@typescript-eslint/type-utils': 6.10.0(eslint@8.49.0)(typescript@5.5.4) + '@typescript-eslint/utils': 6.10.0(eslint@8.49.0)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 6.10.0 debug: 4.3.5(supports-color@9.2.2) eslint: 8.49.0 @@ -10810,19 +10881,19 @@ snapshots: ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.5.2) + ts-api-utils: 1.0.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2)': + '@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': dependencies: '@eslint-community/regexpp': 4.10.1 - '@typescript-eslint/parser': 6.10.0(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/parser': 6.10.0(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/scope-manager': 6.10.0 - '@typescript-eslint/type-utils': 6.10.0(eslint@8.57.0)(typescript@5.5.2) - '@typescript-eslint/utils': 6.10.0(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/type-utils': 6.10.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/utils': 6.10.0(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 6.10.0 debug: 4.3.5(supports-color@9.2.2) eslint: 8.57.0 @@ -10830,35 +10901,35 @@ snapshots: ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.5.2) + ts-api-utils: 1.0.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2)': + '@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4)': dependencies: '@typescript-eslint/scope-manager': 6.10.0 '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 6.10.0 debug: 4.3.5(supports-color@9.2.2) eslint: 8.49.0 optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2)': + '@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4)': dependencies: '@typescript-eslint/scope-manager': 6.10.0 '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 6.10.0 debug: 4.3.5(supports-color@9.2.2) eslint: 8.57.0 optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 transitivePeerDependencies: - supports-color @@ -10867,33 +10938,33 @@ snapshots: '@typescript-eslint/types': 6.10.0 '@typescript-eslint/visitor-keys': 6.10.0 - '@typescript-eslint/type-utils@6.10.0(eslint@8.49.0)(typescript@5.5.2)': + '@typescript-eslint/type-utils@6.10.0(eslint@8.49.0)(typescript@5.5.4)': dependencies: - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.2) - '@typescript-eslint/utils': 6.10.0(eslint@8.49.0)(typescript@5.5.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.4) + '@typescript-eslint/utils': 6.10.0(eslint@8.49.0)(typescript@5.5.4) debug: 4.3.5(supports-color@9.2.2) eslint: 8.49.0 - ts-api-utils: 1.0.3(typescript@5.5.2) + ts-api-utils: 1.0.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@6.10.0(eslint@8.57.0)(typescript@5.5.2)': + '@typescript-eslint/type-utils@6.10.0(eslint@8.57.0)(typescript@5.5.4)': dependencies: - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.2) - '@typescript-eslint/utils': 6.10.0(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.4) + '@typescript-eslint/utils': 6.10.0(eslint@8.57.0)(typescript@5.5.4) debug: 4.3.5(supports-color@9.2.2) eslint: 8.57.0 - ts-api-utils: 1.0.3(typescript@5.5.2) + ts-api-utils: 1.0.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 transitivePeerDependencies: - supports-color '@typescript-eslint/types@6.10.0': {} - '@typescript-eslint/typescript-estree@6.10.0(typescript@5.5.2)': + '@typescript-eslint/typescript-estree@6.10.0(typescript@5.5.4)': dependencies: '@typescript-eslint/types': 6.10.0 '@typescript-eslint/visitor-keys': 6.10.0 @@ -10901,34 +10972,34 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.5.2) + ts-api-utils: 1.0.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.10.0(eslint@8.49.0)(typescript@5.5.2)': + '@typescript-eslint/utils@6.10.0(eslint@8.49.0)(typescript@5.5.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.1 '@typescript-eslint/scope-manager': 6.10.0 '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.4) eslint: 8.49.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@6.10.0(eslint@8.57.0)(typescript@5.5.2)': + '@typescript-eslint/utils@6.10.0(eslint@8.57.0)(typescript@5.5.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.1 '@typescript-eslint/scope-manager': 6.10.0 '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.5.4) eslint: 8.57.0 semver: 7.5.4 transitivePeerDependencies: @@ -12375,21 +12446,21 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.7)(eslint@8.49.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint@8.49.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.10.0(eslint@8.49.0)(typescript@5.5.2) + '@typescript-eslint/parser': 6.10.0(eslint@8.49.0)(typescript@5.5.4) eslint: 8.49.0 eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.7)(eslint@8.57.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.10.0(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/parser': 6.10.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: @@ -12401,7 +12472,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0): + eslint-plugin-import@2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0): dependencies: array-includes: 3.1.6 array.prototype.flat: 1.3.1 @@ -12409,7 +12480,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.49.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.7)(eslint@8.49.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint@8.49.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -12418,13 +12489,13 @@ snapshots: resolve: 1.22.2 tsconfig-paths: 3.14.1 optionalDependencies: - '@typescript-eslint/parser': 6.10.0(eslint@8.49.0)(typescript@5.5.2) + '@typescript-eslint/parser': 6.10.0(eslint@8.49.0)(typescript@5.5.4) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0): + eslint-plugin-import@2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0): dependencies: array-includes: 3.1.6 array.prototype.flat: 1.3.1 @@ -12432,7 +12503,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.7)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.7)(eslint@8.57.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -12441,7 +12512,7 @@ snapshots: resolve: 1.22.2 tsconfig-paths: 3.14.1 optionalDependencies: - '@typescript-eslint/parser': 6.10.0(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/parser': 6.10.0(eslint@8.57.0)(typescript@5.5.4) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -12495,12 +12566,12 @@ snapshots: dotenv: 16.0.3 eslint: 8.49.0 - eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0): + eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0): dependencies: eslint: 8.49.0 eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.2))(eslint@8.49.0)(typescript@5.5.2) + '@typescript-eslint/eslint-plugin': 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.49.0)(typescript@5.5.4))(eslint@8.49.0)(typescript@5.5.4) eslint-rule-composer@0.3.0: {} @@ -13066,6 +13137,15 @@ snapshots: minipass: 6.0.2 path-scurry: 1.10.1 + glob@11.0.0: + dependencies: + foreground-child: 3.1.1 + jackspeak: 4.0.1 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 2.0.0 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -13639,6 +13719,12 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@4.0.1: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + javascript-time-ago@2.5.7: dependencies: relative-time-format: 1.1.4 @@ -13862,6 +13948,8 @@ snapshots: lru-cache@10.1.0: {} + lru-cache@11.0.0: {} + lru-cache@4.1.5: dependencies: pseudomap: 1.0.2 @@ -13992,6 +14080,10 @@ snapshots: - supports-color - utf-8-validate + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + minimatch@3.0.8: dependencies: brace-expansion: 1.1.11 @@ -14030,6 +14122,8 @@ snapshots: minipass@6.0.2: {} + minipass@7.1.2: {} + minizlib@2.1.2: dependencies: minipass: 3.3.6 @@ -14069,7 +14163,7 @@ snapshots: ms@2.1.3: {} - msw@2.3.0(typescript@5.5.2): + msw@2.3.0(typescript@5.5.4): dependencies: '@bundled-es-modules/cookie': 2.0.0 '@bundled-es-modules/statuses': 1.0.1 @@ -14089,7 +14183,7 @@ snapshots: type-fest: 4.18.2 yargs: 17.7.2 optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 mustache@4.2.0: {} @@ -14425,6 +14519,8 @@ snapshots: find-up-simple: 1.0.0 load-json-file: 7.0.1 + package-json-from-dist@1.0.0: {} + package-json@8.1.1: dependencies: got: 12.6.1 @@ -14513,6 +14609,11 @@ snapshots: lru-cache: 10.1.0 minipass: 6.0.2 + path-scurry@2.0.0: + dependencies: + lru-cache: 11.0.0 + minipass: 7.1.2 + path-to-regexp@0.1.7: {} path-to-regexp@6.2.0: {} @@ -15073,6 +15174,11 @@ snapshots: dependencies: glob: 10.3.10 + rimraf@6.0.1: + dependencies: + glob: 11.0.0 + package-json-from-dist: 1.0.0 + roarr@7.11.0: dependencies: boolean: 3.2.0 @@ -15658,9 +15764,9 @@ snapshots: trim-newlines@3.0.1: {} - ts-api-utils@1.0.3(typescript@5.5.2): + ts-api-utils@1.0.3(typescript@5.5.4): dependencies: - typescript: 5.5.2 + typescript: 5.5.4 ts-dedent@2.2.0: {} @@ -15697,9 +15803,9 @@ snapshots: lodash: 4.17.21 prettier: 2.7.1 - tsconfck@2.1.1(typescript@5.5.2): + tsconfck@2.1.1(typescript@5.5.4): optionalDependencies: - typescript: 5.5.2 + typescript: 5.5.4 tsconfig-paths@3.14.1: dependencies: @@ -15846,6 +15952,8 @@ snapshots: typescript@5.5.2: {} + typescript@5.5.4: {} + ufo@1.5.3: {} uglify-js@3.17.4: @@ -16028,11 +16136,11 @@ snapshots: connect-history-api-fallback: 1.6.0 vite: 5.0.12(@types/node@20.12.12) - vite-tsconfig-paths@4.2.0(typescript@5.5.2)(vite@5.0.12(@types/node@20.8.3)): + vite-tsconfig-paths@4.2.0(typescript@5.5.4)(vite@5.0.12(@types/node@20.8.3)): dependencies: debug: 4.3.4(supports-color@9.2.2) globrex: 0.1.2 - tsconfck: 2.1.1(typescript@5.5.2) + tsconfck: 2.1.1(typescript@5.5.4) optionalDependencies: vite: 5.0.12(@types/node@20.8.3) transitivePeerDependencies: