From 031dd568845b74ab34d785a271bce5d575c302fa Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 31 Jan 2024 21:04:22 +0000 Subject: [PATCH] fix: ensure that the Pages dev proxy server does not change the Host header Previously, when configuring `wrangler pages dev` to use a proxy to a 3rd party dev server, the proxy would replace the Host header, resulting in problems at the dev server if it was checking for cross-site scripting attacks. Now the proxy server passes through the Host header unaltered making it invisible to the 3rd party dev server. Fixes #4799 --- .changeset/orange-emus-mate.md | 14 +++ fixtures/pages-proxy-app/package.json | 25 +++++ fixtures/pages-proxy-app/server/index.ts | 10 ++ fixtures/pages-proxy-app/tests/index.test.ts | 34 +++++++ fixtures/pages-proxy-app/tests/tsconfig.json | 7 ++ fixtures/pages-proxy-app/tsconfig.json | 13 +++ fixtures/pages-proxy-app/turbo.json | 9 ++ fixtures/pages-proxy-app/vitest.config.ts | 9 ++ .../shared/src/run-wrangler-long-lived.ts | 8 +- packages/wrangler/src/miniflare-cli/assets.ts | 44 ++++++++- pnpm-lock.yaml | 96 +++++++++++++------ 11 files changed, 237 insertions(+), 32 deletions(-) create mode 100644 .changeset/orange-emus-mate.md create mode 100644 fixtures/pages-proxy-app/package.json create mode 100644 fixtures/pages-proxy-app/server/index.ts create mode 100644 fixtures/pages-proxy-app/tests/index.test.ts create mode 100644 fixtures/pages-proxy-app/tests/tsconfig.json create mode 100644 fixtures/pages-proxy-app/tsconfig.json create mode 100644 fixtures/pages-proxy-app/turbo.json create mode 100644 fixtures/pages-proxy-app/vitest.config.ts diff --git a/.changeset/orange-emus-mate.md b/.changeset/orange-emus-mate.md new file mode 100644 index 000000000000..0825abd68b0d --- /dev/null +++ b/.changeset/orange-emus-mate.md @@ -0,0 +1,14 @@ +--- +"wrangler": patch +--- + +fix: ensure that the Pages dev proxy server does not change the Host header + +Previously, when configuring `wrangler pages dev` to use a proxy to a 3rd party dev server, +the proxy would replace the Host header, resulting in problems at the dev server if it was +checking for cross-site scripting attacks. + +Now the proxy server passes through the Host header unaltered making it invisible to the +3rd party dev server. + +Fixes #4799 diff --git a/fixtures/pages-proxy-app/package.json b/fixtures/pages-proxy-app/package.json new file mode 100644 index 000000000000..cd989ceb1eb6 --- /dev/null +++ b/fixtures/pages-proxy-app/package.json @@ -0,0 +1,25 @@ +{ + "name": "pages-proxy-app", + "version": "0.1.2", + "private": true, + "sideEffects": false, + "main": "server/index.js", + "scripts": { + "build": "esbuild --bundle --platform=node server/index.ts --outfile=dist/index.js", + "check:type": "tsc", + "dev": "npx wrangler pages dev --compatibility-date=2024-01-17 --port 8790 --proxy 8791 -- pnpm run server", + "server": "node dist/index.js", + "test": "vitest run", + "test:watch": "vitest", + "type:tests": "tsc -p ./tests/tsconfig.json" + }, + "devDependencies": { + "@cloudflare/workers-tsconfig": "workspace:*", + "miniflare": "workspace:*", + "undici": "^5.28.2", + "wrangler": "workspace:*" + }, + "engines": { + "node": ">=14" + } +} diff --git a/fixtures/pages-proxy-app/server/index.ts b/fixtures/pages-proxy-app/server/index.ts new file mode 100644 index 000000000000..e6efbc2ab5fa --- /dev/null +++ b/fixtures/pages-proxy-app/server/index.ts @@ -0,0 +1,10 @@ +import { createServer } from "http"; + +const server = createServer(); + +server.on("request", (req, res) => { + res.write("Host:" + req.headers.host); + res.end(); +}); + +server.listen(8791); diff --git a/fixtures/pages-proxy-app/tests/index.test.ts b/fixtures/pages-proxy-app/tests/index.test.ts new file mode 100644 index 000000000000..8333c7520841 --- /dev/null +++ b/fixtures/pages-proxy-app/tests/index.test.ts @@ -0,0 +1,34 @@ +import { fork } from "node:child_process"; +import { resolve } from "node:path"; +import { fetch } from "undici"; +import { afterAll, beforeAll, describe, it } from "vitest"; +import { runWranglerPagesDev } from "../../shared/src/run-wrangler-long-lived"; +import type { ChildProcess } from "node:child_process"; + +describe("pages-proxy-app", async () => { + let ip: string, port: number, stop: (() => Promise) | undefined; + let devServer: ChildProcess; + + beforeAll(async () => { + devServer = fork(resolve(__dirname, "../dist/index.js"), { + stdio: "ignore", + }); + + ({ ip, port, stop } = await runWranglerPagesDev( + resolve(__dirname, ".."), + undefined, + ["--port=0", "--inspector-port=0", "--proxy=8791"] + )); + }); + + afterAll(async () => { + await stop?.(); + devServer.kill(); + }); + + it("receives the correct Host header", async ({ expect }) => { + const response = await fetch(`http://${ip}:${port}/`); + const text = await response.text(); + expect(text).toContain(`Host:${ip}:${port}`); + }); +}); diff --git a/fixtures/pages-proxy-app/tests/tsconfig.json b/fixtures/pages-proxy-app/tests/tsconfig.json new file mode 100644 index 000000000000..d2ce7f144694 --- /dev/null +++ b/fixtures/pages-proxy-app/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/pages-proxy-app/tsconfig.json b/fixtures/pages-proxy-app/tsconfig.json new file mode 100644 index 000000000000..902b5311b2a8 --- /dev/null +++ b/fixtures/pages-proxy-app/tsconfig.json @@ -0,0 +1,13 @@ +{ + "include": ["server"], + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "lib": ["ES2020"], + "types": ["node"], + "moduleResolution": "node", + "esModuleInterop": true, + "noEmit": true, + "skipLibCheck": true + } +} diff --git a/fixtures/pages-proxy-app/turbo.json b/fixtures/pages-proxy-app/turbo.json new file mode 100644 index 000000000000..1a6c74c9def8 --- /dev/null +++ b/fixtures/pages-proxy-app/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "build": { + "outputs": ["dist/**"] + } + } +} diff --git a/fixtures/pages-proxy-app/vitest.config.ts b/fixtures/pages-proxy-app/vitest.config.ts new file mode 100644 index 000000000000..846cddc41995 --- /dev/null +++ b/fixtures/pages-proxy-app/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineProject, mergeConfig } from "vitest/config"; +import configShared from "../../vitest.shared"; + +export default mergeConfig( + configShared, + defineProject({ + test: {}, + }) +); diff --git a/fixtures/shared/src/run-wrangler-long-lived.ts b/fixtures/shared/src/run-wrangler-long-lived.ts index 0eab03135312..9d63214a8e65 100644 --- a/fixtures/shared/src/run-wrangler-long-lived.ts +++ b/fixtures/shared/src/run-wrangler-long-lived.ts @@ -16,10 +16,14 @@ export const wranglerEntryPath = path.resolve( */ export async function runWranglerPagesDev( cwd: string, - publicPath: string, + publicPath: string | undefined, options: string[] ) { - return runLongLivedWrangler(["pages", "dev", publicPath, ...options], cwd); + if (publicPath) { + return runLongLivedWrangler(["pages", "dev", publicPath, ...options], cwd); + } else { + return runLongLivedWrangler(["pages", "dev", ...options], cwd); + } } /** diff --git a/packages/wrangler/src/miniflare-cli/assets.ts b/packages/wrangler/src/miniflare-cli/assets.ts index 1da646944012..d6c8d5130fac 100644 --- a/packages/wrangler/src/miniflare-cli/assets.ts +++ b/packages/wrangler/src/miniflare-cli/assets.ts @@ -1,3 +1,4 @@ +import assert from "node:assert"; import { existsSync, lstatSync, readFileSync } from "node:fs"; import { join, resolve } from "node:path"; import { createMetadataObject } from "@cloudflare/pages-shared/metadata-generator/createMetadataObject"; @@ -6,6 +7,7 @@ import { parseRedirects } from "@cloudflare/pages-shared/metadata-generator/pars import { watch } from "chokidar"; import { getType } from "mime"; import { fetch, Request, Response } from "miniflare"; +import { Agent } from "undici"; import { hashFile } from "../pages/hash"; import type { Logger } from "../logger"; import type { Metadata } from "@cloudflare/pages-shared/asset-server/metadata"; @@ -15,6 +17,7 @@ import type { } from "@cloudflare/pages-shared/metadata-generator/types"; import type { Request as WorkersRequest } from "@cloudflare/workers-types/experimental"; import type { RequestInit } from "miniflare"; +import type { Dispatcher } from "undici"; export interface Options { log: Logger; @@ -38,7 +41,9 @@ export default async function generateASSETSBinding(options: Options) { proxyRequest.headers.delete("Sec-WebSocket-Accept"); proxyRequest.headers.delete("Sec-WebSocket-Key"); } - return await fetch(proxyRequest); + return await fetch(proxyRequest, { + dispatcher: new ProxyDispatcher(miniflareRequest.headers.get("Host")), + }); } catch (thrown) { options.log.error(new Error(`Could not proxy request: ${thrown}`)); @@ -63,6 +68,43 @@ export default async function generateASSETSBinding(options: Options) { }; } +/** + * An Undici custom Dispatcher that is used for the fetch requests + * of the Pages dev server proxy. + * + * Notably, this dispatcher will reinstate the Host header that is + * removed by the `fetch` machinery. This is removed as a security + * precaution, which is not relevant for this Proxy. + */ +class ProxyDispatcher extends Agent { + constructor(private host: string | null) { + super(); + } + + dispatch( + options: Agent.DispatchOptions, + handler: Dispatcher.DispatchHandlers + ): boolean { + if (this.host) { + const headers = options.headers; + assert(headers, "Expected all proxied requests to contain headers."); + if (Array.isArray(headers)) { + assert( + headers.every( + (h) => h !== "Host", + "Expected Host header to have been deleted." + ) + ); + headers.push("Host", this.host); + } else if (headers) { + assert(!headers["Host"], "Expected Host header to have been deleted."); + headers["Host"] = this.host; + } + } + return super.dispatch(options, handler); + } +} + async function generateAssetsFetch( directory: string, log: Logger diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bd9610d0b07..1669cf8141b1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -393,6 +393,21 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/pages-proxy-app: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:* + version: link:../../packages/workers-tsconfig + miniflare: + specifier: workspace:* + version: link:../../packages/miniflare + undici: + specifier: ^5.28.2 + version: 5.28.2 + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + fixtures/pages-simple-assets: devDependencies: '@cloudflare/workers-tsconfig': @@ -1048,7 +1063,7 @@ importers: version: 5.28.2 wrangler: specifier: ^3.24.0 - version: link:../wrangler + version: 3.26.0 packages/prerelease-registry: dependencies: @@ -1628,7 +1643,7 @@ importers: version: 6.5.1 wrangler: specifier: ^3.0.0 - version: link:../wrangler + version: 3.26.0 packages: @@ -3839,7 +3854,6 @@ packages: resolution: {integrity: sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==} dependencies: mime: 3.0.0 - dev: false /@cloudflare/kv-asset-handler@0.3.0: resolution: {integrity: sha512-9CB/MKf/wdvbfkUdfrj+OkEwZ5b7rws0eogJ4293h+7b6KX5toPwym+VQKmILafNB9YiehqY0DlNrDcDhdWHSQ==} @@ -3947,7 +3961,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@cloudflare/workerd-darwin-arm64@1.20240129.0: @@ -3956,7 +3969,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@cloudflare/workerd-linux-64@1.20240129.0: @@ -3965,7 +3977,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@cloudflare/workerd-linux-arm64@1.20240129.0: @@ -3974,7 +3985,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@cloudflare/workerd-windows-64@1.20240129.0: @@ -3983,7 +3993,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@cloudflare/workers-types@3.18.0: @@ -4054,7 +4063,6 @@ packages: esbuild: '*' dependencies: esbuild: 0.17.19 - dev: false /@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19): resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} @@ -4064,7 +4072,6 @@ packages: esbuild: 0.17.19 escape-string-regexp: 4.0.0 rollup-plugin-node-polyfills: 0.2.1 - dev: false /@esbuild/android-arm64@0.16.17: resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} @@ -8337,7 +8344,6 @@ packages: resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} dependencies: printable-characters: 1.0.42 - dev: false /assert@2.0.0: resolution: {integrity: sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==} @@ -8734,7 +8740,6 @@ packages: /blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - dev: false /blueimp-md5@2.19.0: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} @@ -9038,7 +9043,6 @@ packages: tslib: 2.5.3 transitivePeerDependencies: - supports-color - dev: false patched: true /capnpc-ts@0.7.0: @@ -9795,7 +9799,6 @@ packages: /data-uri-to-buffer@2.0.2: resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} - dev: false /data-uri-to-buffer@3.0.1: resolution: {integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==} @@ -11387,7 +11390,6 @@ packages: /estree-walker@0.6.1: resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - dev: false /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -12085,7 +12087,6 @@ packages: dependencies: data-uri-to-buffer: 2.0.2 source-map: 0.6.1 - dev: false /get-stream@4.1.0: resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} @@ -14432,7 +14433,6 @@ packages: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: sourcemap-codec: 1.4.8 - dev: false /magic-string@0.30.3: resolution: {integrity: sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==} @@ -15066,6 +15066,29 @@ packages: engines: {node: '>=4'} dev: false + /miniflare@3.20240129.0: + resolution: {integrity: sha512-27pDhlP2G/4gXmvnSt6LjMQ8KrkmbJElIQmn+BLjdiyIx+zXY4E8MSPJmi9flgf0dn3wtjuHO2ASenuopqqxrw==} + engines: {node: '>=16.13'} + hasBin: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + acorn: 8.10.0 + acorn-walk: 8.2.0 + capnp-ts: 0.7.0(patch_hash=l4yimnxyvkiyj6alnps2ec3sii) + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + stoppable: 1.1.0 + undici: 5.28.2 + workerd: 1.20240129.0 + ws: 8.14.2 + youch: 3.2.3 + zod: 3.22.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -15391,7 +15414,6 @@ packages: /node-forge@1.3.0: resolution: {integrity: sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==} engines: {node: '>= 6.13.0'} - dev: false /node-gyp@10.0.1: resolution: {integrity: sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==} @@ -16413,7 +16435,6 @@ packages: /printable-characters@1.0.42: resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} - dev: false /prism-react-renderer@1.3.5(react@18.2.0): resolution: {integrity: sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==} @@ -17321,19 +17342,16 @@ packages: estree-walker: 0.6.1 magic-string: 0.25.9 rollup-pluginutils: 2.8.2 - dev: false /rollup-plugin-node-polyfills@0.2.1: resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} dependencies: rollup-plugin-inject: 3.0.2 - dev: false /rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} dependencies: estree-walker: 0.6.1 - dev: false /rollup@3.25.1: resolution: {integrity: sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==} @@ -17472,7 +17490,6 @@ packages: engines: {node: '>=10'} dependencies: node-forge: 1.3.0 - dev: false /semiver@1.1.0: resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==} @@ -17855,7 +17872,6 @@ packages: /sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead - dev: false /space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -17943,7 +17959,6 @@ packages: dependencies: as-table: 1.0.55 get-source: 2.0.12 - dev: false /standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} @@ -17969,7 +17984,6 @@ packages: /stoppable@1.1.0: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} - dev: false /stream-shift@1.0.1: resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} @@ -19572,7 +19586,33 @@ packages: '@cloudflare/workerd-linux-64': 1.20240129.0 '@cloudflare/workerd-linux-arm64': 1.20240129.0 '@cloudflare/workerd-windows-64': 1.20240129.0 - dev: false + + /wrangler@3.26.0: + resolution: {integrity: sha512-2FKDyL0wV6ws+9AHkQl5/Yzn17kG9jlpgyT7wqCDkhb5q+TCL/I8N5IKVwXe8tRrTluBI1QQZRRymoA5nu0pHw==} + engines: {node: '>=16.17.0'} + hasBin: true + dependencies: + '@cloudflare/kv-asset-handler': 0.2.0 + '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) + '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) + blake3-wasm: 2.1.5 + chokidar: 3.5.3 + esbuild: 0.17.19 + miniflare: 3.20240129.0 + nanoid: 3.3.6 + path-to-regexp: 6.2.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + selfsigned: 2.1.1 + source-map: 0.6.1 + xxhash-wasm: 1.0.1 + optionalDependencies: + fsevents: 2.3.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} @@ -19736,7 +19776,6 @@ packages: /xxhash-wasm@1.0.1: resolution: {integrity: sha512-Lc9CTvDrH2vRoiaUzz25q7lRaviMhz90pkx6YxR9EPYtF99yOJnv2cB+CQ0hp/TLoqrUsk8z/W2EN31T568Azw==} - dev: false /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -19855,7 +19894,6 @@ packages: cookie: 0.5.0 mustache: 4.2.0 stacktracey: 2.1.8 - dev: false /z-schema@5.0.3: resolution: {integrity: sha512-sGvEcBOTNum68x9jCpCVGPFJ6mWnkD0YxOcddDlJHRx3tKdB2q8pCHExMVZo/AV/6geuVJXG7hljDaWG8+5GDw==}