From 8f1590d3b0705b41daf8c49d6d1049a7e26f0456 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 13 Oct 2023 12:54:25 +0100 Subject: [PATCH 01/34] Revert "Revert "startDevWorker - Milestone 1" (#4171)" This reverts commit 88f15f61cad2a69c07e26203cc84ddb2da42deb3. --- fixtures/dev-env/.gitignore | 1 + fixtures/dev-env/package.json | 25 + fixtures/dev-env/tests/index.test.ts | 552 +++++++++++++++ fixtures/dev-env/tests/tsconfig.json | 12 + .../tests/index.test.ts | 11 +- packages/wrangler/.eslintrc.js | 1 + packages/wrangler/e2e/tsconfig.json | 2 +- packages/wrangler/package.json | 2 +- packages/wrangler/scripts/bundle.ts | 63 +- .../src/__tests__/api-devregistry.test.ts | 48 +- packages/wrangler/src/__tests__/dev.test.tsx | 2 + packages/wrangler/src/__tests__/jest.setup.ts | 40 +- packages/wrangler/src/api/dev.ts | 18 +- packages/wrangler/src/api/index.ts | 1 + .../src/api/startDevWorker/BaseController.ts | 40 ++ .../api/startDevWorker/BundlerController.ts | 44 ++ .../api/startDevWorker/ConfigController.ts | 42 ++ .../wrangler/src/api/startDevWorker/DevEnv.ts | 148 ++++ .../startDevWorker/LocalRuntimeController.ts | 41 ++ .../api/startDevWorker/NotImplementedError.ts | 15 + .../src/api/startDevWorker/ProxyController.ts | 527 ++++++++++++++ .../startDevWorker/RemoteRuntimeController.ts | 41 ++ .../startDevWorker/bundle-allowed-paths.ts | 99 +++ .../src/api/startDevWorker/devtools.ts | 41 ++ .../wrangler/src/api/startDevWorker/events.ts | 138 ++++ .../wrangler/src/api/startDevWorker/index.ts | 12 + .../wrangler/src/api/startDevWorker/types.ts | 197 ++++++ .../wrangler/src/api/startDevWorker/utils.ts | 43 ++ packages/wrangler/src/cli.ts | 4 +- packages/wrangler/src/dev.tsx | 3 +- packages/wrangler/src/dev/dev.tsx | 119 +++- packages/wrangler/src/dev/inspect.ts | 659 +----------------- packages/wrangler/src/dev/local.tsx | 88 +-- packages/wrangler/src/dev/miniflare.ts | 43 +- packages/wrangler/src/dev/remote.tsx | 77 +- packages/wrangler/src/dev/start-server.ts | 115 ++- packages/wrangler/src/dev/use-esbuild.ts | 6 + packages/wrangler/src/https-options.ts | 14 +- packages/wrangler/src/worker.d.ts | 4 + .../startDevWorker/InspectorProxyWorker.ts | 526 ++++++++++++++ .../templates/startDevWorker/ProxyWorker.ts | 260 +++++++ pnpm-lock.yaml | 145 +++- 42 files changed, 3437 insertions(+), 832 deletions(-) create mode 100644 fixtures/dev-env/.gitignore create mode 100644 fixtures/dev-env/package.json create mode 100644 fixtures/dev-env/tests/index.test.ts create mode 100644 fixtures/dev-env/tests/tsconfig.json create mode 100644 packages/wrangler/src/api/startDevWorker/BaseController.ts create mode 100644 packages/wrangler/src/api/startDevWorker/BundlerController.ts create mode 100644 packages/wrangler/src/api/startDevWorker/ConfigController.ts create mode 100644 packages/wrangler/src/api/startDevWorker/DevEnv.ts create mode 100644 packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts create mode 100644 packages/wrangler/src/api/startDevWorker/NotImplementedError.ts create mode 100644 packages/wrangler/src/api/startDevWorker/ProxyController.ts create mode 100644 packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts create mode 100644 packages/wrangler/src/api/startDevWorker/bundle-allowed-paths.ts create mode 100644 packages/wrangler/src/api/startDevWorker/devtools.ts create mode 100644 packages/wrangler/src/api/startDevWorker/events.ts create mode 100644 packages/wrangler/src/api/startDevWorker/index.ts create mode 100644 packages/wrangler/src/api/startDevWorker/types.ts create mode 100644 packages/wrangler/src/api/startDevWorker/utils.ts create mode 100644 packages/wrangler/src/worker.d.ts create mode 100644 packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts create mode 100644 packages/wrangler/templates/startDevWorker/ProxyWorker.ts diff --git a/fixtures/dev-env/.gitignore b/fixtures/dev-env/.gitignore new file mode 100644 index 000000000000..1521c8b7652b --- /dev/null +++ b/fixtures/dev-env/.gitignore @@ -0,0 +1 @@ +dist diff --git a/fixtures/dev-env/package.json b/fixtures/dev-env/package.json new file mode 100644 index 000000000000..5502c9d0e0b8 --- /dev/null +++ b/fixtures/dev-env/package.json @@ -0,0 +1,25 @@ +{ + "name": "dev-env", + "version": "1.0.1", + "private": true, + "description": "", + "license": "ISC", + "author": "", + "main": "src/index.js", + "scripts": { + "test": "npx vitest run", + "test:ci": "npx vitest run", + "test:watch": "npx vitest", + "type:tests": "tsc -p ./tests/tsconfig.json" + }, + "devDependencies": { + "@types/ws": "^8.5.7", + "@cloudflare/workers-tsconfig": "workspace:^", + "get-port": "^7.0.0", + "miniflare": "3.20231002.1", + "undici": "^5.23.0", + "wrangler": "workspace:*", + "ws": "^8.14.2" + }, + "dependencies": {} +} diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts new file mode 100644 index 000000000000..83e7baa04b83 --- /dev/null +++ b/fixtures/dev-env/tests/index.test.ts @@ -0,0 +1,552 @@ +import assert from "node:assert"; +import getPort from "get-port"; +import { + Miniflare, + type Response as MiniflareResponse, + type MiniflareOptions, + Log, +} from "miniflare"; +import * as undici from "undici"; +import { WebSocket } from "ws"; +import { beforeEach, afterEach, describe, test, expect, vi } from "vitest"; +import { unstable_DevEnv as DevEnv } from "wrangler"; +import type { ProxyData } from "wrangler/src/api"; +import type { StartDevWorkerOptions } from "wrangler/src/api/startDevWorker/types"; +import type { EsbuildBundle } from "wrangler/src/dev/use-esbuild"; + +const fakeBundle = {} as EsbuildBundle; + +let devEnv: DevEnv; +let mf: Miniflare | undefined; +let res: MiniflareResponse | undici.Response | undefined; +let ws: WebSocket | undefined; + +type OptionalKeys = Omit & Partial>; + +beforeEach(() => { + devEnv = new DevEnv(); + mf = undefined; + res = undefined; + ws = undefined; +}); +afterEach(async () => { + await devEnv?.teardown(); + await mf?.dispose(); + await ws?.close(); + + vi.resetAllMocks(); +}); + +async function fakeStartUserWorker(options: { + script: string; + name?: string; + mfOpts?: Partial; + config?: OptionalKeys; +}) { + const config: StartDevWorkerOptions = { + ...options.config, + name: options.name ?? "test-worker", + script: { contents: options.script }, + }; + const mfOpts: MiniflareOptions = Object.assign( + { + port: 0, + inspectorPort: 0, + modules: true, + compatibilityDate: "2023-08-01", + name: config.name, + script: options.script, + log: Object.assign(new Log(), { error() {} }), // TODO: remove when this bug is fixed https://jira.cfdata.org/browse/DEVX-983 + }, + options.mfOpts + ); + + assert("script" in mfOpts); + + fakeConfigUpdate(config); + fakeReloadStart(config); + + const worker = devEnv.startWorker(config); + const { proxyWorker, inspectorProxyWorker } = await devEnv.proxy.ready + .promise; + const proxyWorkerUrl = await proxyWorker.ready; + const inspectorProxyWorkerUrl = await inspectorProxyWorker.ready; + + mf = new Miniflare(mfOpts); + + const userWorkerUrl = await mf.ready; + const userWorkerInspectorUrl = await mf.getInspectorURL(); + fakeReloadComplete(config, mfOpts, userWorkerUrl, userWorkerInspectorUrl); + + return { + worker, + mf, + mfOpts, + config, + userWorkerUrl, + userWorkerInspectorUrl, + proxyWorkerUrl, + inspectorProxyWorkerUrl, + }; +} + +async function fakeUserWorkerChanges({ + script, + mfOpts, + config, +}: { + script?: string; + mfOpts: MiniflareOptions; + config: StartDevWorkerOptions; +}) { + assert(mf); + assert("script" in mfOpts); + + config = { + ...config, + script: { + ...config.script, + ...(script ? { contents: script } : undefined), + }, + }; + mfOpts = { + ...mfOpts, + script: script ?? mfOpts.script, + }; + + fakeReloadStart(config); + + await mf.setOptions(mfOpts); + + const userWorkerUrl = await mf.ready; + const userWorkerInspectorUrl = await mf.getInspectorURL(); + fakeReloadComplete( + config, + mfOpts, + userWorkerUrl, + userWorkerInspectorUrl, + 1000 + ); + + return { mfOpts, config, mf, userWorkerUrl, userWorkerInspectorUrl }; +} + +function fireAndForgetFakeUserWorkerChanges( + ...args: Parameters +) { + // fire and forget the reload -- this let's us test request buffering + void fakeUserWorkerChanges(...args); +} + +function fakeConfigUpdate(config: StartDevWorkerOptions) { + devEnv.proxy.onConfigUpdate({ + type: "configUpdate", + config, + }); + + return config; // convenience to allow calling and defining new config inline but also store the new object +} +function fakeReloadStart(config: StartDevWorkerOptions) { + devEnv.proxy.onReloadStart({ + type: "reloadStart", + config, + bundle: fakeBundle, + }); + + return config; +} +function fakeReloadComplete( + config: StartDevWorkerOptions, + mfOpts: MiniflareOptions, + userWorkerUrl: URL, + userWorkerInspectorUrl: URL, + delay = 100 +) { + const proxyData: ProxyData = { + userWorkerUrl: { + protocol: userWorkerUrl.protocol, + hostname: userWorkerUrl.hostname, + port: userWorkerUrl.port, + }, + userWorkerInspectorUrl: { + protocol: userWorkerInspectorUrl.protocol, + hostname: userWorkerInspectorUrl.hostname, + port: userWorkerInspectorUrl.port, + pathname: `/core:user:${config.name}`, + }, + userWorkerInnerUrlOverrides: { + protocol: config?.dev?.urlOverrides?.secure ? "https:" : "http:", + hostname: config?.dev?.urlOverrides?.hostname, + }, + headers: {}, + liveReload: config.dev?.liveReload, + }; + + setTimeout(() => { + devEnv.proxy.onReloadComplete({ + type: "reloadComplete", + config, + bundle: fakeBundle, + proxyData, + }); + }, delay); + + return { config, mfOpts }; // convenience to allow calling and defining new config/mfOpts inline but also store the new objects +} + +describe("startDevWorker: ProxyController", () => { + test("ProxyWorker buffers requests while runtime reloads", async () => { + const run = await fakeStartUserWorker({ + script: ` + export default { + fetch() { + return new Response("body:1"); + } + } + `, + }); + + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:1"); + + fireAndForgetFakeUserWorkerChanges({ + mfOpts: run.mfOpts, + config: run.config, + script: run.mfOpts.script.replace("1", "2"), + }); + + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:2"); + }); + + test("InspectorProxyWorker discovery endpoints + devtools websocket connection", async () => { + const run = await fakeStartUserWorker({ + script: ` + export default { + fetch() { + console.log('Inside mock user worker'); + + return new Response("body:1"); + } + } + `, + }); + + await devEnv.proxy.ready; + res = await undici.fetch(`http://${run.inspectorProxyWorkerUrl.host}/json`); + + await expect(res.json()).resolves.toBeInstanceOf(Array); + + ws = new WebSocket( + `ws://${run.inspectorProxyWorkerUrl.host}/core:user:${run.config.name}` + ); + const openPromise = new Promise((resolve) => { + ws?.addEventListener("open", resolve); + }); + const consoleAPICalledPromise = new Promise((resolve) => { + ws?.addEventListener("message", (event) => { + assert(typeof event.data === "string"); + if (event.data.includes("Runtime.consoleAPICalled")) { + resolve(JSON.parse(event.data)); + } + }); + }); + const executionContextCreatedPromise = new Promise((resolve) => { + ws?.addEventListener("message", (event) => { + assert(typeof event.data === "string"); + if (event.data.includes("Runtime.executionContextCreated")) { + resolve(JSON.parse(event.data)); + } + }); + }); + + await openPromise; + await run.worker.fetch("http://localhost"); + + await expect(consoleAPICalledPromise).resolves.toMatchObject({ + method: "Runtime.consoleAPICalled", + params: { + args: expect.arrayContaining([ + { type: "string", value: "Inside mock user worker" }, + ]), + }, + }); + await expect(executionContextCreatedPromise).resolves.toMatchObject({ + method: "Runtime.executionContextCreated", + params: { + context: { id: expect.any(Number) }, + }, + }); + }); + + test("User worker exception", async () => { + const consoleErrorSpy = vi.spyOn(console, "error"); + + const run = await fakeStartUserWorker({ + script: ` + export default { + fetch() { + throw new Error('Boom!'); + + return new Response("body:1"); + } + } + `, + }); + + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("Error: Boom!"); + + await new Promise((r) => setTimeout(r, 100)); // allow some time for the error to be logged (TODO: replace with retry/waitUntil helper) + expect(consoleErrorSpy).toBeCalledWith( + expect.stringContaining("Error: Boom!") + ); + + // test changes causing a new error cause the new error to propogate + fireAndForgetFakeUserWorkerChanges({ + script: ` + export default { + fetch() { + throw new Error('Boom 2!'); + + return new Response("body:2"); + } + } + `, + mfOpts: run.mfOpts, + config: run.config, + }); + + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("Error: Boom 2!"); + + await new Promise((r) => setTimeout(r, 100)); // allow some time for the error to be logged (TODO: replace with retry/waitUntil helper) + expect(consoleErrorSpy).toBeCalledWith( + expect.stringContaining("Error: Boom 2!") + ); + + // test eyeball requests receive the pretty error page + fireAndForgetFakeUserWorkerChanges({ + script: ` + export default { + fetch() { + const e = new Error('Boom 3!'); + + // this is how errors are serialised after they are caught by wrangler/miniflare3 middlewares + const error = { name: e.name, message: e.message, stack: e.stack }; + return Response.json(error, { + status: 500, + headers: { "MF-Experimental-Error-Stack": "true" }, + }); + } + } + `, + mfOpts: run.mfOpts, + config: run.config, + }); + + const proxyWorkerUrl = await devEnv.proxy.proxyWorker?.ready; + assert(proxyWorkerUrl); + res = await undici.fetch(proxyWorkerUrl, { + headers: { Accept: "text/html" }, + }); + await expect(res.text()).resolves.toEqual( + expect.stringContaining(`

Boom 3!

`) // pretty error page html snippet + ); + + // test further changes that fix the code + fireAndForgetFakeUserWorkerChanges({ + script: ` + export default { + fetch() { + return new Response("body:3"); + } + } + `, + mfOpts: run.mfOpts, + config: run.config, + }); + + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:3"); + + consoleErrorSpy.mockReset(); + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:3"); + + await new Promise((r) => setTimeout(r, 100)); // allow some time for the error to be logged (TODO: replace with retry/waitUntil helper) + expect(consoleErrorSpy).not.toHaveBeenCalled(); + }); + + test("config.dev.{server,inspector} changes, restart the server instance", async () => { + const run = await fakeStartUserWorker({ + script: ` + export default { + fetch() { + return new Response("body:1"); + } + } + `, + config: { + dev: { + server: { port: await getPort() }, + inspector: { port: await getPort() }, + }, + }, + }); + + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:1"); + + const oldPort = run.config.dev?.server?.port; + res = await undici.fetch(`http://127.0.0.1:${oldPort}`); + await expect(res.text()).resolves.toBe("body:1"); + + const config2 = fakeConfigUpdate({ + ...run.config, + dev: { + server: { port: await getPort() }, + inspector: { port: await getPort() }, + }, + }); + fakeReloadStart(config2); + fakeReloadComplete( + config2, + run.mfOpts, + run.userWorkerUrl, + run.userWorkerInspectorUrl + ); + + const newPort = config2.dev?.server?.port; + + res = await run.worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:1"); + + res = await undici.fetch(`http://127.0.0.1:${newPort}`); + await expect(res.text()).resolves.toBe("body:1"); + + await expect( + undici.fetch(`http://127.0.0.1:${oldPort}`).then((r) => r.text()) + ).rejects.toMatchInlineSnapshot("[TypeError: fetch failed]"); + }); + + test("liveReload", async () => { + let resText: string; + const scriptRegex = / + `, + { html: true } + ); + } + }, + }); + + return htmlRewriter.transform(response); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ed90ec67a05..9e1933b629b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,6 +102,30 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/dev-env: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:^ + version: link:../../packages/workers-tsconfig + '@types/ws': + specifier: ^8.5.7 + version: 8.5.7 + get-port: + specifier: ^7.0.0 + version: 7.0.0 + miniflare: + specifier: 3.20231002.1 + version: 3.20231002.1 + undici: + specifier: ^5.23.0 + version: 5.23.0 + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + ws: + specifier: ^8.14.2 + version: 8.14.2 + fixtures/external-durable-objects-app: devDependencies: '@cloudflare/workers-tsconfig': @@ -687,7 +711,7 @@ importers: version: 8.49.0 eslint-config-turbo: specifier: latest - version: 1.10.15(eslint@8.49.0) + version: 1.10.16(eslint@8.49.0) eslint-plugin-import: specifier: 2.26.x version: 2.26.0(@typescript-eslint/parser@6.7.2)(eslint@8.49.0) @@ -3479,6 +3503,15 @@ packages: marked: 0.3.19 dev: false + /@cloudflare/workerd-darwin-64@1.20231002.0: + resolution: {integrity: sha512-sgtjzVO/wtI/6S7O0bk4zQAv2xlvqOxB18AXzlit6uXgbYFGeQedRHjhKVMOacGmWEnM4C3ir/fxJGsc3Pyxng==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@cloudflare/workerd-darwin-64@1.20231025.0: resolution: {integrity: sha512-MYRYTbSl+tjGg6su7savlLIb8cOcKJfdGpA+WdtgqT2OF7O+89Lag0l1SA/iyVlUkT31Jc6OLHqvzsXgmg+niQ==} engines: {node: '>=16'} @@ -3487,6 +3520,15 @@ packages: requiresBuild: true optional: true + /@cloudflare/workerd-darwin-arm64@1.20231002.0: + resolution: {integrity: sha512-dv8nztYFaTYYgBpyy80vc4hdMYv9mhyNbvBsZywm8S7ivcIpzogi0UKkGU4E/G0lYK6W3WtwTBqwRe+pXJ1+Ww==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@cloudflare/workerd-darwin-arm64@1.20231025.0: resolution: {integrity: sha512-BszjtBDR84TVa6oWe74dePJSAukWlTmLw9zR4KeWuwZLJGV7RMm6AmwGStetjnwZrecZaaOFELfBCAHtsebV0Q==} engines: {node: '>=16'} @@ -3495,6 +3537,15 @@ packages: requiresBuild: true optional: true + /@cloudflare/workerd-linux-64@1.20231002.0: + resolution: {integrity: sha512-UG8SlLcGzaQDSSw6FR4+Zf408925wkLOCAi8w5qEoFYu3g4Ef7ZenstesCOsyWL7qBDKx0/iwk6+a76W5IHI0Q==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@cloudflare/workerd-linux-64@1.20231025.0: resolution: {integrity: sha512-AT9dxgKXOa9xZxZ3k2a432axPJJ58KpoNWnPiPYGpuAuLoWnfcYwwh6mr9sZVcTdAdTAK9Xu9c81tp0YABanUw==} engines: {node: '>=16'} @@ -3503,6 +3554,15 @@ packages: requiresBuild: true optional: true + /@cloudflare/workerd-linux-arm64@1.20231002.0: + resolution: {integrity: sha512-GPaa66ZSq1gK09r87c5CJbHIApcIU//LVHz3rnUxK0//00YCwUuGUUK1dn/ylg+fVqDQxIDmH+ABnobBanvcDA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@cloudflare/workerd-linux-arm64@1.20231025.0: resolution: {integrity: sha512-EIjex5o2k80YZWPix1btGybL/vNZ3o6vqKX9ptS0JcFkHV5aFX5/kcMwSBRjiIC+w04zVjmGQx3N1Vh3njuncg==} engines: {node: '>=16'} @@ -3511,6 +3571,15 @@ packages: requiresBuild: true optional: true + /@cloudflare/workerd-windows-64@1.20231002.0: + resolution: {integrity: sha512-ybIy+sCme0VO0RscndXvqWNBaRMUOc8vhi+1N2h/KDsKfNLsfEQph+XWecfKzJseUy1yE2rV1xei3BaNmaa6vg==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@cloudflare/workerd-windows-64@1.20231025.0: resolution: {integrity: sha512-7vtq0mO22A2v0OOsKXa760r9a84Gg8CK0gDu5uNWlj6hojmt011iz7jJt76I7oo/XrVwVlVfu69GnA3ljx6U8w==} engines: {node: '>=16'} @@ -6035,6 +6104,12 @@ packages: '@types/node': 20.1.7 dev: true + /@types/ws@8.5.7: + resolution: {integrity: sha512-6UrLjiDUvn40CMrAubXuIVtj2PEfKDffJS7ychvnPU44j+KVeXmdHHTgqcM/dxLUTHxlXHiFM8Skmb8ozGdTnQ==} + dependencies: + '@types/node': 20.1.7 + dev: true + /@types/yargs-parser@20.2.1: resolution: {integrity: sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==} dev: true @@ -6901,14 +6976,6 @@ packages: dependencies: acorn: 8.10.0 - /acorn-jsx@5.3.2(acorn@8.8.2): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.8.2 - dev: true - /acorn-walk@8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} @@ -9132,13 +9199,13 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-turbo@1.10.15(eslint@8.49.0): - resolution: {integrity: sha512-76mpx2x818JZE26euen14utYcFDxOahZ9NaWA+6Xa4pY2ezVKVschuOxS96EQz3o3ZRSmcgBOapw/gHbN+EKxQ==} + /eslint-config-turbo@1.10.16(eslint@8.49.0): + resolution: {integrity: sha512-O3NQI72bQHV7FvSC6lWj66EGx8drJJjuT1kuInn6nbMLOHdMBhSUX/8uhTAlHRQdlxZk2j9HtgFCIzSc93w42g==} peerDependencies: eslint: '>6.6.0' dependencies: eslint: 8.49.0 - eslint-plugin-turbo: 1.10.15(eslint@8.49.0) + eslint-plugin-turbo: 1.10.16(eslint@8.49.0) dev: false /eslint-import-resolver-node@0.3.7: @@ -9473,8 +9540,8 @@ packages: - typescript dev: true - /eslint-plugin-turbo@1.10.15(eslint@8.49.0): - resolution: {integrity: sha512-Tv4QSKV/U56qGcTqS/UgOvb9HcKFmWOQcVh3HEaj7of94lfaENgfrtK48E2CckQf7amhKs1i+imhCsNCKjkQyA==} + /eslint-plugin-turbo@1.10.16(eslint@8.49.0): + resolution: {integrity: sha512-ZjrR88MTN64PNGufSEcM0tf+V1xFYVbeiMeuIqr0aiABGomxFLo4DBkQ7WI4WzkZtWQSIA2sP+yxqSboEfL9MQ==} peerDependencies: eslint: '>6.6.0' dependencies: @@ -9647,8 +9714,8 @@ packages: resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.8.2 - acorn-jsx: 5.3.2(acorn@8.8.2) + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) eslint-visitor-keys: 3.4.1 dev: true @@ -10377,6 +10444,11 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true + /get-port@7.0.0: + resolution: {integrity: sha512-mDHFgApoQd+azgMdwylJrv2DX47ywGq1i5VFJE7fZ0dttNq3iQMfsU4IvEgBHojA3KqEudyu7Vq+oN8kNaNkWw==} + engines: {node: '>=16'} + dev: true + /get-source@2.0.12: resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} dependencies: @@ -13176,6 +13248,28 @@ packages: engines: {node: '>=4'} dev: false + /miniflare@3.20231002.1: + resolution: {integrity: sha512-4xJ8FezJkQqHzCm71lovb9L/wJ0VV/odMFf5CIxfLTunsx97kTIlZnhS6aHuvcbzdztbWp1RR71K/1qFUHdpdQ==} + engines: {node: '>=16.13'} + dependencies: + acorn: 8.10.0 + acorn-walk: 8.2.0 + capnp-ts: 0.7.0(supports-color@9.2.2) + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + source-map-support: 0.5.21 + stoppable: 1.1.0 + undici: 5.23.0 + workerd: 1.20231002.0 + ws: 8.14.2 + youch: 3.2.3 + zod: 3.22.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /miniflare@3.20231025.0(supports-color@9.2.2): resolution: {integrity: sha512-pFcr2BRaGIQ26UfdDo8BMJ6kkd/Jo/FkQ/4K7UG/eORlDepsLrR/sTJddcSSIGl07MA+MGjhzopFTPpFskkS+g==} engines: {node: '>=16.13'} @@ -13189,7 +13283,7 @@ packages: stoppable: 1.1.0 undici: 5.23.0 workerd: 1.20231025.0 - ws: 8.13.0 + ws: 8.14.2 youch: 3.2.3 zod: 3.22.2 transitivePeerDependencies: @@ -17524,6 +17618,19 @@ packages: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true + /workerd@1.20231002.0: + resolution: {integrity: sha512-NFuUQBj30ZguDoPZ6bL40hINiu8aP2Pvxr/3xAdhWOwVFLuObPOiSdQ8qm4JYZ7jovxWjWE4Z7VR2avjIzEksQ==} + engines: {node: '>=16'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20231002.0 + '@cloudflare/workerd-darwin-arm64': 1.20231002.0 + '@cloudflare/workerd-linux-64': 1.20231002.0 + '@cloudflare/workerd-linux-arm64': 1.20231002.0 + '@cloudflare/workerd-windows-64': 1.20231002.0 + dev: true + /workerd@1.20231025.0: resolution: {integrity: sha512-W1PFtpMFfvmm+ozBf+u70TE3Pviv7WA4qzDeejHDC4z+PFDq4+3KJCkgffaGBO86h+akWO0hSsc0uXL2zAqofQ==} engines: {node: '>=16'} @@ -17606,8 +17713,8 @@ packages: optional: true dev: true - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + /ws@8.14.2: + resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 From 61b3cbba76a0604e3f9612203e5a30b8c82477f7 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:31:22 +0100 Subject: [PATCH 02/34] fix: don't show logs to ProxyWorker(s) unless log level is debug change ProxyControllerLogger info override to log override change WranglerLog info override to log override -- this worksaround an internal Miniflare change --- packages/wrangler/src/api/startDevWorker/ProxyController.ts | 6 +++--- packages/wrangler/src/dev/miniflare.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 849fa4db21bf..8f70454d5a1c 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -492,12 +492,12 @@ export class ProxyController extends EventEmitter { } export class ProxyControllerLogger extends WranglerLog { - info(message: string) { + log(message: string) { // filter out request logs being handled by the ProxyWorker // the requests log remaining are handled by the UserWorker // keep the ProxyWorker request logs if we're in debug mode - if (message.includes("/cdn-cgi/") && this.level !== LogLevel.DEBUG) return; - super.info(message); + if (message.includes("/cdn-cgi/") && this.level < LogLevel.DEBUG) return; + super.log(message); } // TODO: remove this override when miniflare is fixed https://jira.cfdata.org/browse/DEVX-983 diff --git a/packages/wrangler/src/dev/miniflare.ts b/packages/wrangler/src/dev/miniflare.ts index 7ea00de63bf1..beecf38f0f93 100644 --- a/packages/wrangler/src/dev/miniflare.ts +++ b/packages/wrangler/src/dev/miniflare.ts @@ -108,10 +108,10 @@ export interface ConfigBundle { export class WranglerLog extends Log { #warnedCompatibilityDateFallback = false; - info(message: string) { + log(message: string) { // Hide request logs for external Durable Objects proxy worker if (message.includes(EXTERNAL_DURABLE_OBJECTS_WORKER_NAME)) return; - super.info(message); + super.log(message); } warn(message: string) { From b1b65442af0b32d632f241885c5b9b3a0a0ad785 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:55:19 +0100 Subject: [PATCH 03/34] fix: show console.log's in remote mode remote inspector websocket upgrade request required auth headers so use `fetch` with `Upgrade: websocket` header instead of `new WebSocket` --- .../startDevWorker/InspectorProxyWorker.ts | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts index 7bc70ffce761..30e5dd987508 100644 --- a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts +++ b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts @@ -239,20 +239,49 @@ export class InspectorProxyWorker implements DurableObject { }; runtimeKeepAliveInterval: number | null = null; - reconnectRuntimeWebSocket() { + + // TODO: add abort signal + runtimeAbortController = new AbortController(); + async reconnectRuntimeWebSocket() { assert(this.proxyData, "Expected this.proxyData to be defined"); this.sendDebugLog("reconnectRuntimeWebSocket"); + this.runtimeAbortController.abort(); + this.runtimeAbortController = new AbortController(); this.websockets.runtimeDeferred = createDeferred( this.websockets.runtimeDeferred ); const runtimeWebSocketUrl = urlFromParts( this.proxyData.userWorkerInspectorUrl - ).href; + ); + runtimeWebSocketUrl.protocol = this.proxyData.userWorkerUrl.protocol; // http: or https: + this.sendDebugLog("NEW RUNTIME WEBSOCKET", runtimeWebSocketUrl); - const runtime = new WebSocket(runtimeWebSocketUrl); + + const upgrade = await fetch(runtimeWebSocketUrl, { + headers: { + ...this.proxyData.headers, + Upgrade: "websocket", + }, + signal: this.runtimeAbortController.signal, + }); + + const runtime = upgrade.webSocket; + if (!runtime) { + const error = new Error( + `Failed to establish the WebSocket connection: expected server to reply with HTTP status code 101 (switching protocols), but received ${upgrade.status} instead.` + ); + + this.websockets.runtimeDeferred.reject(error); + this.sendProxyControllerRequest({ + type: "runtime-websocket-error", + error: serialiseError(error), + }); + + return; + } this.websockets.runtime?.close(); this.websockets.runtime = runtime; @@ -293,9 +322,11 @@ export class InspectorProxyWorker implements DurableObject { // wait for a new proxy-data message or manual restart }); - runtime.addEventListener("open", () => { - this.handleRuntimeWebSocketOpen(runtime); - }); + runtime.accept(); + + // fetch(Upgrade: websocket) resolves when the websocket is open + // therefore the open event will not fire, so just trigger the handler + this.handleRuntimeWebSocketOpen(runtime); } #runtimeMessageCounter = 1e8; From d34fc4cdd7ef6a199fc8853f605b0d2506a751a8 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:01:04 +0100 Subject: [PATCH 04/34] use miniflare verbose mode only if debug log level --- packages/wrangler/src/api/startDevWorker/ProxyController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 8f70454d5a1c..da0eba85137c 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -60,7 +60,7 @@ export class ProxyController extends EventEmitter { : undefined; const proxyWorkerOptions: MiniflareOptions = { - verbose: true, + verbose: logger.loggerLevel === "debug", compatibilityFlags: ["nodejs_compat"], modulesRoot: path.dirname(proxyWorkerPath), modules: [{ type: "ESModule", path: proxyWorkerPath }], @@ -94,7 +94,7 @@ export class ProxyController extends EventEmitter { }), }; const inspectorProxyWorkerOptions: MiniflareOptions = { - verbose: true, + verbose: logger.loggerLevel === "debug", compatibilityFlags: ["nodejs_compat"], modulesRoot: path.dirname(inspectorProxyWorkerPath), modules: [{ type: "ESModule", path: inspectorProxyWorkerPath }], From cd9be393356f189ea50a9b14e91c38a87dbb30a1 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:16:40 +0100 Subject: [PATCH 05/34] register ProxyWorker with DevRegistry instead of UserWorker --- .../src/api/startDevWorker/ProxyController.ts | 33 +++++++++++++++++-- packages/wrangler/src/dev/local.tsx | 2 -- packages/wrangler/src/dev/start-server.ts | 2 -- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index da0eba85137c..ec1a0243e496 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -10,7 +10,8 @@ import { logConsoleMessage, maybeHandleNetworkLoadResource, } from "../../dev/inspect"; -import { WranglerLog, castLogLevel } from "../../dev/miniflare"; +import { maybeRegisterLocalWorker } from "../../dev/local"; +import { ReloadedEvent, WranglerLog, castLogLevel } from "../../dev/miniflare"; import { getHttpsOptions } from "../../https-options"; import { logger } from "../../logger"; import { getSourceMappedStack } from "../../sourcemap"; @@ -177,10 +178,13 @@ export class ProxyController extends EventEmitter { } // store the non-null versions for callbacks - const { proxyWorker, inspectorProxyWorker } = this; + const { proxyWorker, inspectorProxyWorker, latestConfig: config } = this; void Promise.all([proxyWorker.ready, this.reconnectInspectorProxyWorker()]) - .then(() => { + .then(async ([proxyWorkerUrl]) => { + // wait for registration to complete before emitting ready event + await maybeRegisterProxyWorkerWithDevRegistry(proxyWorkerUrl, config); + this.emitReadyEvent(proxyWorker, inspectorProxyWorker); }) .catch((error) => { @@ -525,3 +529,26 @@ function didMiniflareOptionsChange( // otherwise, if they're not deeply equal, they've changed return !deepEquality(prev, next); } + +async function maybeRegisterProxyWorkerWithDevRegistry( + proxyWorkerUrl: URL, + config: StartDevWorkerOptions +) { + const reloadedEvent = new ReloadedEvent("reloaded", { + url: proxyWorkerUrl, + internalDurableObjects: Object.entries(config.bindings ?? {}).flatMap( + ([bindingName, binding]) => { + const isInternalDurableObject = + binding.type === "durable-object" && + (binding.service?.name === undefined || + binding.service?.name === config.name); + + if (!isInternalDurableObject) return []; + + return [{ name: bindingName, class_name: binding.className }]; + } + ), + }); + + await maybeRegisterLocalWorker(reloadedEvent, config.name); +} diff --git a/packages/wrangler/src/dev/local.tsx b/packages/wrangler/src/dev/local.tsx index da51ec68c0a0..df813012c01c 100644 --- a/packages/wrangler/src/dev/local.tsx +++ b/packages/wrangler/src/dev/local.tsx @@ -157,8 +157,6 @@ function useLocalWorker(props: LocalProps) { const newServer = new MiniflareServer(); miniflareServerRef.current = server = newServer; server.addEventListener("reloaded", async (event) => { - await maybeRegisterLocalWorker(event, props.name); - const proxyData: ProxyData = { userWorkerUrl: { protocol: event.url.protocol, diff --git a/packages/wrangler/src/dev/start-server.ts b/packages/wrangler/src/dev/start-server.ts index 1898b35e446f..0f8aa4854ab4 100644 --- a/packages/wrangler/src/dev/start-server.ts +++ b/packages/wrangler/src/dev/start-server.ts @@ -396,8 +396,6 @@ export async function startLocalServer(props: LocalProps) { return new Promise<{ stop: () => void }>((resolve, reject) => { const server = new MiniflareServer(); server.addEventListener("reloaded", async (event) => { - await maybeRegisterLocalWorker(event, props.name); - const proxyData: ProxyData = { userWorkerUrl: { protocol: event.url.protocol, From e106aa66ceaefef249837a7ee6a540faf45d377d Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:34:06 +0100 Subject: [PATCH 06/34] Revert "register ProxyWorker with DevRegistry" This reverts commit 1e6879b7acb4d168356950045ff31379648ec2a2. This commit will be reapplied in the Milestone 2 PR. --- .../src/api/startDevWorker/ProxyController.ts | 33 ++----------------- packages/wrangler/src/dev/local.tsx | 2 ++ packages/wrangler/src/dev/start-server.ts | 2 ++ 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index ec1a0243e496..da0eba85137c 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -10,8 +10,7 @@ import { logConsoleMessage, maybeHandleNetworkLoadResource, } from "../../dev/inspect"; -import { maybeRegisterLocalWorker } from "../../dev/local"; -import { ReloadedEvent, WranglerLog, castLogLevel } from "../../dev/miniflare"; +import { WranglerLog, castLogLevel } from "../../dev/miniflare"; import { getHttpsOptions } from "../../https-options"; import { logger } from "../../logger"; import { getSourceMappedStack } from "../../sourcemap"; @@ -178,13 +177,10 @@ export class ProxyController extends EventEmitter { } // store the non-null versions for callbacks - const { proxyWorker, inspectorProxyWorker, latestConfig: config } = this; + const { proxyWorker, inspectorProxyWorker } = this; void Promise.all([proxyWorker.ready, this.reconnectInspectorProxyWorker()]) - .then(async ([proxyWorkerUrl]) => { - // wait for registration to complete before emitting ready event - await maybeRegisterProxyWorkerWithDevRegistry(proxyWorkerUrl, config); - + .then(() => { this.emitReadyEvent(proxyWorker, inspectorProxyWorker); }) .catch((error) => { @@ -529,26 +525,3 @@ function didMiniflareOptionsChange( // otherwise, if they're not deeply equal, they've changed return !deepEquality(prev, next); } - -async function maybeRegisterProxyWorkerWithDevRegistry( - proxyWorkerUrl: URL, - config: StartDevWorkerOptions -) { - const reloadedEvent = new ReloadedEvent("reloaded", { - url: proxyWorkerUrl, - internalDurableObjects: Object.entries(config.bindings ?? {}).flatMap( - ([bindingName, binding]) => { - const isInternalDurableObject = - binding.type === "durable-object" && - (binding.service?.name === undefined || - binding.service?.name === config.name); - - if (!isInternalDurableObject) return []; - - return [{ name: bindingName, class_name: binding.className }]; - } - ), - }); - - await maybeRegisterLocalWorker(reloadedEvent, config.name); -} diff --git a/packages/wrangler/src/dev/local.tsx b/packages/wrangler/src/dev/local.tsx index df813012c01c..da51ec68c0a0 100644 --- a/packages/wrangler/src/dev/local.tsx +++ b/packages/wrangler/src/dev/local.tsx @@ -157,6 +157,8 @@ function useLocalWorker(props: LocalProps) { const newServer = new MiniflareServer(); miniflareServerRef.current = server = newServer; server.addEventListener("reloaded", async (event) => { + await maybeRegisterLocalWorker(event, props.name); + const proxyData: ProxyData = { userWorkerUrl: { protocol: event.url.protocol, diff --git a/packages/wrangler/src/dev/start-server.ts b/packages/wrangler/src/dev/start-server.ts index 0f8aa4854ab4..1898b35e446f 100644 --- a/packages/wrangler/src/dev/start-server.ts +++ b/packages/wrangler/src/dev/start-server.ts @@ -396,6 +396,8 @@ export async function startLocalServer(props: LocalProps) { return new Promise<{ stop: () => void }>((resolve, reject) => { const server = new MiniflareServer(); server.addEventListener("reloaded", async (event) => { + await maybeRegisterLocalWorker(event, props.name); + const proxyData: ProxyData = { userWorkerUrl: { protocol: event.url.protocol, From b272636ee77f6e5f69b7cb3e69216d1710d38d05 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 25 Oct 2023 12:59:29 +0100 Subject: [PATCH 07/34] use single Miniflare instance for (Inspector)ProxyWorker --- fixtures/dev-env/tests/index.test.ts | 11 +- .../src/api/startDevWorker/ProxyController.ts | 174 +++++++----------- .../wrangler/src/api/startDevWorker/events.ts | 1 - .../startDevWorker/InspectorProxyWorker.ts | 8 + pnpm-lock.yaml | 43 +++-- 5 files changed, 113 insertions(+), 124 deletions(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index 83e7baa04b83..a9c323fa8740 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -18,7 +18,7 @@ const fakeBundle = {} as EsbuildBundle; let devEnv: DevEnv; let mf: Miniflare | undefined; -let res: MiniflareResponse | undici.Response | undefined; +let res: MiniflareResponse | undici.Response; let ws: WebSocket | undefined; type OptionalKeys = Omit & Partial>; @@ -26,7 +26,7 @@ type OptionalKeys = Omit & Partial>; beforeEach(() => { devEnv = new DevEnv(); mf = undefined; - res = undefined; + res = undefined as any; ws = undefined; }); afterEach(async () => { @@ -67,10 +67,11 @@ async function fakeStartUserWorker(options: { fakeReloadStart(config); const worker = devEnv.startWorker(config); - const { proxyWorker, inspectorProxyWorker } = await devEnv.proxy.ready - .promise; + const { proxyWorker } = await devEnv.proxy.ready.promise; const proxyWorkerUrl = await proxyWorker.ready; - const inspectorProxyWorkerUrl = await inspectorProxyWorker.ready; + const inspectorProxyWorkerUrl = await proxyWorker.unsafeGetDirectURL( + "InspectorProxyWorker" + ); mf = new Miniflare(mfOpts); diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index da0eba85137c..26d72dbab58b 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -40,9 +40,7 @@ export class ProxyController extends EventEmitter { public ready = createDeferred(); public proxyWorker?: Miniflare; - public inspectorProxyWorker?: Miniflare; proxyWorkerOptions?: MiniflareOptions; - inspectorProxyWorkerOptions?: MiniflareOptions; inspectorProxyWorkerWebSocket?: DeferredPromise; protected latestConfig?: StartDevWorkerOptions; @@ -60,32 +58,64 @@ export class ProxyController extends EventEmitter { : undefined; const proxyWorkerOptions: MiniflareOptions = { - verbose: logger.loggerLevel === "debug", - compatibilityFlags: ["nodejs_compat"], - modulesRoot: path.dirname(proxyWorkerPath), - modules: [{ type: "ESModule", path: proxyWorkerPath }], - durableObjects: { - DURABLE_OBJECT: "ProxyWorker", - }, - serviceBindings: { - PROXY_CONTROLLER: async (req): Promise => { - const message = (await req.json()) as ProxyWorkerOutgoingRequestBody; - - this.onProxyWorkerMessage(message); - - return new Response(null, { status: 204 }); - }, - }, - bindings: { - PROXY_CONTROLLER_AUTH_SECRET: this.secret, - }, - host: this.latestConfig.dev?.server?.hostname, port: this.latestConfig.dev?.server?.port, https: this.latestConfig.dev?.server?.secure, httpsCert: cert?.cert, httpsKey: cert?.key, + workers: [ + { + name: "ProxyWorker", + compatibilityFlags: ["nodejs_compat"], + modulesRoot: path.dirname(proxyWorkerPath), + modules: [{ type: "ESModule", path: proxyWorkerPath }], + durableObjects: { + DURABLE_OBJECT: "ProxyWorker", + }, + serviceBindings: { + PROXY_CONTROLLER: async (req): Promise => { + const message = + (await req.json()) as ProxyWorkerOutgoingRequestBody; + + this.onProxyWorkerMessage(message); + + return new Response(null, { status: 204 }); + }, + }, + bindings: { + PROXY_CONTROLLER_AUTH_SECRET: this.secret, + }, + }, + { + name: "InspectorProxyWorker", + compatibilityFlags: ["nodejs_compat"], + modulesRoot: path.dirname(inspectorProxyWorkerPath), + modules: [{ type: "ESModule", path: inspectorProxyWorkerPath }], + durableObjects: { + DURABLE_OBJECT: "InspectorProxyWorker", + }, + serviceBindings: { + PROXY_CONTROLLER: async (req): Promise => { + const body = + (await req.json()) as InspectorProxyWorkerOutgoingRequestBody; + + return this.onInspectorProxyWorkerRequest(body); + }, + }, + bindings: { + PROXY_CONTROLLER_AUTH_SECRET: this.secret, + }, + + unsafeDirectHost: this.latestConfig.dev?.inspector?.hostname, + unsafeDirectPort: this.latestConfig.dev?.inspector?.port, + }, + ], + + verbose: logger.loggerLevel === "debug", + cache: false, + unsafeEphemeralDurableObjects: true, + // log requests into the ProxyWorker (for local + remote mode) log: new ProxyControllerLogger(castLogLevel(logger.loggerLevel), { prefix: @@ -93,95 +123,31 @@ export class ProxyController extends EventEmitter { logger.loggerLevel === "debug" ? "wrangler-ProxyWorker" : "wrangler", }), }; - const inspectorProxyWorkerOptions: MiniflareOptions = { - verbose: logger.loggerLevel === "debug", - compatibilityFlags: ["nodejs_compat"], - modulesRoot: path.dirname(inspectorProxyWorkerPath), - modules: [{ type: "ESModule", path: inspectorProxyWorkerPath }], - durableObjects: { - DURABLE_OBJECT: "InspectorProxyWorker", - }, - serviceBindings: { - PROXY_CONTROLLER: async (req): Promise => { - const body = - (await req.json()) as InspectorProxyWorkerOutgoingRequestBody; - - return this.onInspectorProxyWorkerRequest(body); - }, - }, - bindings: { - PROXY_CONTROLLER_AUTH_SECRET: this.secret, - }, - - host: this.latestConfig.dev?.inspector?.hostname, - port: this.latestConfig.dev?.inspector?.port, - https: this.latestConfig.dev?.inspector?.secure, - httpsCert: cert?.cert, - httpsKey: cert?.key, - - // only if debugging, log requests to InspectorProxyWorker - log: - logger.loggerLevel === "debug" - ? new ProxyControllerLogger(LogLevel.DEBUG, { - prefix: "wrangler-InspectorProxyWorker", - }) - : undefined, - }; const proxyWorkerOptionsChanged = didMiniflareOptionsChange( this.proxyWorkerOptions, proxyWorkerOptions ); - const inspectorProxyWorkerOptionsChanged = didMiniflareOptionsChange( - this.inspectorProxyWorkerOptions, - inspectorProxyWorkerOptions - ); - if (this.proxyWorker === undefined) { - this.proxyWorker = new Miniflare(proxyWorkerOptions); - this.proxyWorkerOptions = proxyWorkerOptions; - } - if (this.inspectorProxyWorker === undefined) { - this.inspectorProxyWorker = new Miniflare(inspectorProxyWorkerOptions); - this.inspectorProxyWorkerOptions = inspectorProxyWorkerOptions; - } + this.proxyWorker ??= new Miniflare(proxyWorkerOptions); + this.proxyWorkerOptions = proxyWorkerOptions; + + if (proxyWorkerOptionsChanged) { + logger.debug("ProxyWorker miniflare options changed, reinstantiating..."); + + void this.proxyWorker.setOptions(proxyWorkerOptions); - if (proxyWorkerOptionsChanged || inspectorProxyWorkerOptionsChanged) { // this creates a new .ready promise that will be resolved when both ProxyWorkers are ready // it also respects any await-ers of the existing .ready promise this.ready = createDeferred(this.ready); } - if (proxyWorkerOptionsChanged) { - logger.debug("ProxyWorker miniflare options changed, reinstantiating..."); - // TODO: ideally we'd use the same miniflare instance via .setOptions but bug: it doesn't respect port changes (easy fix incoming) - // Ideally we'd do: - // void this.proxyWorker.setOptions(proxyWorkerOptions); - // this.proxyWorkerOptions = proxyWorkerOptions; - // Instead, for now, we do: - void this.proxyWorker.dispose(); - this.proxyWorker = new Miniflare(proxyWorkerOptions); - this.proxyWorkerOptions = proxyWorkerOptions; - } - if (inspectorProxyWorkerOptionsChanged) { - logger.debug( - "InspectorProxyWorker miniflare options changed, reinstantiating..." - ); - // TODO: ideally we'd use the same miniflare instance via .setOptions but bug: it doesn't respect port changes (easy fix incoming) - // Ideally we'd do: - // void this.inspectorProxyWorker.setOptions(inspectorProxyWorkerOptions); - // this.inspectorProxyWorkerOptions = inspectorProxyWorkerOptions; - // Instead, for now, we do: - void this.inspectorProxyWorker.dispose(); - this.inspectorProxyWorker = new Miniflare(inspectorProxyWorkerOptions); - this.inspectorProxyWorkerOptions = inspectorProxyWorkerOptions; - } // store the non-null versions for callbacks - const { proxyWorker, inspectorProxyWorker } = this; + const { proxyWorker } = this; void Promise.all([proxyWorker.ready, this.reconnectInspectorProxyWorker()]) .then(() => { - this.emitReadyEvent(proxyWorker, inspectorProxyWorker); + this.emitReadyEvent(proxyWorker); }) .catch((error) => { this.emitErrorEvent( @@ -204,10 +170,15 @@ export class ProxyController extends EventEmitter { let webSocket: WebSocket | null = null; try { - assert(this.inspectorProxyWorker); - ({ webSocket } = await this.inspectorProxyWorker.dispatchFetch( + assert(this.proxyWorker); + const inspectorProxyWorker = await this.proxyWorker.getWorker( + "InspectorProxyWorker" + ); + ({ webSocket } = await inspectorProxyWorker.fetch( "http://dummy/cdn-cgi/InspectorProxyWorker/websocket", - { headers: { Authorization: this.secret, Upgrade: "websocket" } } + { + headers: { Authorization: this.secret, Upgrade: "websocket" }, + } )); } catch (cause) { if (this._torndown) return; @@ -437,13 +408,11 @@ export class ProxyController extends EventEmitter { logger.debug("ProxyController teardown"); this._torndown = true; - const { proxyWorker, inspectorProxyWorker } = this; + const { proxyWorker } = this; this.proxyWorker = undefined; - this.inspectorProxyWorker = undefined; await Promise.all([ proxyWorker?.dispose(), - inspectorProxyWorker?.dispose(), this.inspectorProxyWorkerWebSocket?.promise .then((ws) => ws.close()) .catch(() => { @@ -456,11 +425,10 @@ export class ProxyController extends EventEmitter { // Event Dispatchers // ********************* - emitReadyEvent(proxyWorker: Miniflare, inspectorProxyWorker: Miniflare) { + emitReadyEvent(proxyWorker: Miniflare) { const data: ReadyEvent = { type: "ready", proxyWorker, - inspectorProxyWorker, }; this.emit("ready", data); diff --git a/packages/wrangler/src/api/startDevWorker/events.ts b/packages/wrangler/src/api/startDevWorker/events.ts index e6b806d2b129..f71202cd7eb9 100644 --- a/packages/wrangler/src/api/startDevWorker/events.ts +++ b/packages/wrangler/src/api/startDevWorker/events.ts @@ -74,7 +74,6 @@ export type ReadyEvent = { type: "ready"; proxyWorker: Miniflare; - inspectorProxyWorker: Miniflare; }; // ProxyWorker diff --git a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts index 30e5dd987508..22abd4ce5fde 100644 --- a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts +++ b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts @@ -71,6 +71,14 @@ export class InspectorProxyWorker implements DurableObject { runtimeMessageBuffer: (DevToolsCommandResponses | DevToolsEvents)[] = []; async fetch(req: Request) { + const url = new URL(req.url); + + // temp: respond with the origin until miniflare supports mf.getWorker(...).getUrl() + if (url.pathname === "/cdn-cgi/get-url") { + this.sendDebugLog("InspectorProxyWorker.ts:", url.href); + return new Response(url.origin); + } + if ( req.headers.get("Authorization") === this.env.PROXY_CONTROLLER_AUTH_SECRET ) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e1933b629b6..030101edac38 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -812,7 +812,7 @@ importers: version: 0.31.4 wrangler: specifier: ^3.5.1 - version: link:../wrangler + version: 3.14.0 packages/prerelease-registry: dependencies: @@ -1380,7 +1380,7 @@ importers: version: 6.5.1 wrangler: specifier: ^3.0.0 - version: link:../wrangler + version: 3.14.0 packages: @@ -3407,7 +3407,6 @@ packages: resolution: {integrity: sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==} dependencies: mime: 3.0.0 - dev: false /@cloudflare/style-const@5.7.3(react@18.2.0): resolution: {integrity: sha512-N9Y8bcFXoO7htm+sSVsBmQOVbjLeEY2hy1CBmvt0AoH1zWvs3izwJrnlL0ee4kJ6DkyjaY6SIAkUGUtTOApF3Q==} @@ -3653,7 +3652,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==} @@ -3663,7 +3661,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.3: resolution: {integrity: sha512-RolFVeinkeraDvN/OoRf1F/lP0KUfGNb5jxy/vkIMeRRChkrX/HTYN6TYZosRJs3a1+8wqpxAo5PI5hFmxyPRg==} @@ -7530,7 +7527,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==} @@ -9791,7 +9787,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==} @@ -12658,7 +12653,6 @@ packages: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: sourcemap-codec: 1.4.8 - dev: false /magic-string@0.30.0: resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==} @@ -13581,7 +13575,6 @@ packages: /node-forge@1.3.0: resolution: {integrity: sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==} engines: {node: '>= 6.13.0'} - dev: false /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -15357,19 +15350,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==} @@ -15504,7 +15494,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==} @@ -15880,7 +15869,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==} @@ -17643,6 +17631,32 @@ packages: '@cloudflare/workerd-linux-arm64': 1.20231025.0 '@cloudflare/workerd-windows-64': 1.20231025.0 + /wrangler@3.14.0: + resolution: {integrity: sha512-4vzw11yG1/KXpYKbumvRJ61Iyhm/yKXb/ayOw/2xiIRdKdpsfN9/796d2l525+CDaGwZWswpLENe6ZMS0p/Ghg==} + engines: {node: '>=16.13.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.20231016.0(supports-color@9.2.2) + nanoid: 3.3.6 + path-to-regexp: 6.2.0 + selfsigned: 2.1.1 + source-map: 0.6.1 + source-map-support: 0.5.21 + 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==} engines: {node: '>=8'} @@ -17784,7 +17798,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==} From 6ce1f9271ed9ab5d2ca716ead5b0b58d6ffc8238 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 25 Oct 2023 13:30:35 +0100 Subject: [PATCH 08/34] port: clear remote runtime logs upon UserWorker restarts --- .../src/api/startDevWorker/ProxyController.ts | 1 + .../wrangler/src/api/startDevWorker/events.ts | 12 ++- .../startDevWorker/InspectorProxyWorker.ts | 76 ++++++++++--------- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 26d72dbab58b..cb50c9d10ad4 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -301,6 +301,7 @@ export class ProxyController extends EventEmitter { this.latestConfig = data.config; void this.sendMessageToProxyWorker({ type: "pause" }); + void this.sendMessageToInspectorProxyWorker({ type: "reloadStart" }); } onReloadComplete(data: ReloadCompleteEvent) { this.latestConfig = data.config; diff --git a/packages/wrangler/src/api/startDevWorker/events.ts b/packages/wrangler/src/api/startDevWorker/events.ts index f71202cd7eb9..3230009c3746 100644 --- a/packages/wrangler/src/api/startDevWorker/events.ts +++ b/packages/wrangler/src/api/startDevWorker/events.ts @@ -87,10 +87,14 @@ export type ProxyWorkerOutgoingRequestBody = // InspectorProxyWorker export * from "./devtools"; -export type InspectorProxyWorkerIncomingWebSocketMessage = { - type: ReloadCompleteEvent["type"]; - proxyData: ProxyData; -}; +export type InspectorProxyWorkerIncomingWebSocketMessage = + | { + type: ReloadStartEvent["type"]; + } + | { + type: ReloadCompleteEvent["type"]; + proxyData: ProxyData; + }; export type InspectorProxyWorkerOutgoingWebsocketMessage = // Relayed Chrome DevTools Protocol Messages | DevToolsEvent<"Runtime.consoleAPICalled"> diff --git a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts index 22abd4ce5fde..69796a1a1ee8 100644 --- a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts +++ b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts @@ -71,14 +71,6 @@ export class InspectorProxyWorker implements DurableObject { runtimeMessageBuffer: (DevToolsCommandResponses | DevToolsEvents)[] = []; async fetch(req: Request) { - const url = new URL(req.url); - - // temp: respond with the origin until miniflare supports mf.getWorker(...).getUrl() - if (url.pathname === "/cdn-cgi/get-url") { - this.sendDebugLog("InspectorProxyWorker.ts:", url.href); - return new Response(url.origin); - } - if ( req.headers.get("Authorization") === this.env.PROXY_CONTROLLER_AUTH_SECRET ) { @@ -133,6 +125,37 @@ export class InspectorProxyWorker implements DurableObject { }); } + handleProxyControllerIncomingMessage = (event: MessageEvent) => { + assert( + typeof event.data === "string", + "Expected event.data from proxy controller to be string" + ); + + const message: InspectorProxyWorkerIncomingWebSocketMessage = JSON.parse( + event.data + ); + + this.sendDebugLog("handleProxyControllerIncomingMessage", event.data); + + switch (message.type) { + case "reloadStart": { + this.sendRuntimeDiscardConsoleEntries(); + + break; + } + case "reloadComplete": { + this.proxyData = message.proxyData; + + this.reconnectRuntimeWebSocket(); + + break; + } + default: { + assertNever(message); + } + } + }; + sendProxyControllerMessage( message: string | InspectorProxyWorkerOutgoingWebsocketMessage ) { @@ -220,36 +243,8 @@ export class InspectorProxyWorker implements DurableObject { } }; - handleProxyControllerIncomingMessage = (event: MessageEvent) => { - assert( - typeof event.data === "string", - "Expected event.data from proxy controller to be string" - ); - - const message: InspectorProxyWorkerIncomingWebSocketMessage = JSON.parse( - event.data - ); - - this.sendDebugLog("handleProxyControllerIncomingMessage", event.data); - - switch (message.type) { - case "reloadComplete": { - this.proxyData = message.proxyData; - - this.reconnectRuntimeWebSocket(); - - break; - } - default: { - assertNever(message.type); - } - } - }; - - runtimeKeepAliveInterval: number | null = null; - - // TODO: add abort signal runtimeAbortController = new AbortController(); + runtimeKeepAliveInterval: number | null = null; async reconnectRuntimeWebSocket() { assert(this.proxyData, "Expected this.proxyData to be defined"); @@ -368,6 +363,13 @@ export class InspectorProxyWorker implements DurableObject { this.websockets.runtimeDeferred.resolve(runtime); } + sendRuntimeDiscardConsoleEntries() { + this.sendRuntimeMessage({ + method: "Runtime.discardConsoleEntries", + id: this.nextCounter(), + }); + } + async sendRuntimeMessage( message: string | DevToolsCommandRequests, runtime: MaybePromise = this.websockets.runtimeDeferred.promise From f2c8c97750b78adec35e870803d35fb754963f05 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:54:11 +0100 Subject: [PATCH 09/34] default unstable_dev inspectorPort to 0 --- packages/wrangler/src/api/dev.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/src/api/dev.ts b/packages/wrangler/src/api/dev.ts index fc4ca218947e..d65d49eab54e 100644 --- a/packages/wrangler/src/api/dev.ts +++ b/packages/wrangler/src/api/dev.ts @@ -170,7 +170,7 @@ export async function unstable_dev( compatibilityDate: options?.compatibilityDate, compatibilityFlags: options?.compatibilityFlags, ip: options?.ip, - inspectorPort: options?.inspectorPort, + inspectorPort: options?.inspectorPort ?? 0, v: undefined, localProtocol: options?.localProtocol, assets: options?.assets, From 6749fbacc49b9155edecb32bd3a48ce1e34c718c Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:11:31 +0100 Subject: [PATCH 10/34] parallelise cleanup to minimise chance of hanging previously, sequential cleanups fail to fully cleanup if earlier steps in the sequence fail --- packages/wrangler/src/dev/start-server.ts | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/wrangler/src/dev/start-server.ts b/packages/wrangler/src/dev/start-server.ts index 1898b35e446f..3611607be4e8 100644 --- a/packages/wrangler/src/dev/start-server.ts +++ b/packages/wrangler/src/dev/start-server.ts @@ -196,9 +196,11 @@ export async function startDevServer( return { stop: async () => { - stop(); - await stopWorkerRegistry(); - await devEnv.teardown(); + await Promise.allSettled([ + stop(), + stopWorkerRegistry(), + devEnv.teardown(), + ]); }, // TODO: inspectorUrl, }; @@ -247,9 +249,11 @@ export async function startDevServer( }); return { stop: async () => { - stop(); - await stopWorkerRegistry(); - await devEnv.teardown(); + await Promise.allSettled([ + stop(), + stopWorkerRegistry(), + devEnv.teardown(), + ]); }, // TODO: inspectorUrl, }; @@ -373,7 +377,7 @@ async function runEsbuild({ } export async function startLocalServer(props: LocalProps) { - if (!props.bundle || !props.format) return Promise.resolve({ stop() {} }); + if (!props.bundle || !props.format) return { async stop() {} }; // Log warnings for experimental dev-registry-dependent options if (props.bindings.services && props.bindings.services.length > 0) { @@ -393,7 +397,7 @@ export async function startLocalServer(props: LocalProps) { logger.log(chalk.dim("⎔ Starting local server...")); const config = await localPropsToConfigBundle(props); - return new Promise<{ stop: () => void }>((resolve, reject) => { + return new Promise<{ stop: () => Promise }>((resolve, reject) => { const server = new MiniflareServer(); server.addEventListener("reloaded", async (event) => { await maybeRegisterLocalWorker(event, props.name); @@ -421,12 +425,12 @@ export async function startLocalServer(props: LocalProps) { props.onReady?.(event.url.hostname, parseInt(event.url.port), proxyData); // Note `unstable_dev` doesn't do anything with the inspector URL yet resolve({ - stop: () => { + stop: async () => { abortController.abort(); logger.log("⎔ Shutting down local server..."); // Initialization errors are also thrown asynchronously by dispose(). // The `addEventListener("error")` above should've caught them though. - server.onDispose().catch(() => {}); + await server.onDispose().catch(() => {}); removeMiniflareServerExitListener(); }, }); From 827613897f07ee6b53d417f22ab56a63c662d101 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:14:30 +0100 Subject: [PATCH 11/34] ensure InspectorProxyWorker unsafeDirectPort is set --- packages/wrangler/src/api/startDevWorker/ProxyController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index cb50c9d10ad4..6e3e71f323db 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -108,7 +108,7 @@ export class ProxyController extends EventEmitter { }, unsafeDirectHost: this.latestConfig.dev?.inspector?.hostname, - unsafeDirectPort: this.latestConfig.dev?.inspector?.port, + unsafeDirectPort: this.latestConfig.dev?.inspector?.port ?? 0, }, ], From 9b403a5b20de4794197ee9792c756cfbd8d08529 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 25 Oct 2023 17:32:02 +0100 Subject: [PATCH 12/34] don't use file-system for (Inspector)ProxyWorker DOs --- .../wrangler/src/api/startDevWorker/ProxyController.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 6e3e71f323db..91150accc7eb 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -86,6 +86,10 @@ export class ProxyController extends EventEmitter { bindings: { PROXY_CONTROLLER_AUTH_SECRET: this.secret, }, + + // no need to use file-system, so don't + cache: false, + unsafeEphemeralDurableObjects: true, }, { name: "InspectorProxyWorker", @@ -109,12 +113,14 @@ export class ProxyController extends EventEmitter { unsafeDirectHost: this.latestConfig.dev?.inspector?.hostname, unsafeDirectPort: this.latestConfig.dev?.inspector?.port ?? 0, + + // no need to use file-system, so don't + cache: false, + unsafeEphemeralDurableObjects: true, }, ], verbose: logger.loggerLevel === "debug", - cache: false, - unsafeEphemeralDurableObjects: true, // log requests into the ProxyWorker (for local + remote mode) log: new ProxyControllerLogger(castLogLevel(logger.loggerLevel), { From 7813a2689514b0b56184655f17aa8ceee839ad50 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:18:56 +0000 Subject: [PATCH 13/34] prevent eviction of the Durable Objects with (Inspector)ProxyWorker --- packages/wrangler/package.json | 2 +- .../src/api/startDevWorker/ProxyController.ts | 10 ++- pnpm-lock.yaml | 75 +++++++++++-------- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index bb02d2892355..edc62743a5f3 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -107,7 +107,7 @@ "blake3-wasm": "^2.1.5", "chokidar": "^3.5.3", "esbuild": "0.17.19", - "miniflare": "3.20231025.0", + "miniflare": "3.20231025.1", "nanoid": "^3.3.3", "path-to-regexp": "^6.2.0", "resolve.exports": "^2.0.2", diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 91150accc7eb..0fee064010c5 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -71,7 +71,10 @@ export class ProxyController extends EventEmitter { modulesRoot: path.dirname(proxyWorkerPath), modules: [{ type: "ESModule", path: proxyWorkerPath }], durableObjects: { - DURABLE_OBJECT: "ProxyWorker", + DURABLE_OBJECT: { + className: "ProxyWorker", + unsafePreventEviction: true, + }, }, serviceBindings: { PROXY_CONTROLLER: async (req): Promise => { @@ -97,7 +100,10 @@ export class ProxyController extends EventEmitter { modulesRoot: path.dirname(inspectorProxyWorkerPath), modules: [{ type: "ESModule", path: inspectorProxyWorkerPath }], durableObjects: { - DURABLE_OBJECT: "InspectorProxyWorker", + DURABLE_OBJECT: { + className: "InspectorProxyWorker", + unsafePreventEviction: true, + }, }, serviceBindings: { PROXY_CONTROLLER: async (req): Promise => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 030101edac38..afbceb8dd1f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -390,7 +390,7 @@ importers: version: link:../../packages/workers-tsconfig miniflare: specifier: 3.20231025.0 - version: 3.20231025.0(supports-color@9.2.2) + version: 3.20231025.0 wrangler: specifier: workspace:* version: link:../../packages/wrangler @@ -759,7 +759,7 @@ importers: dependencies: miniflare: specifier: 3.20231025.0 - version: 3.20231025.0(supports-color@9.2.2) + version: 3.20231025.0 devDependencies: '@cloudflare/workers-tsconfig': specifier: workspace:* @@ -812,7 +812,7 @@ importers: version: 0.31.4 wrangler: specifier: ^3.5.1 - version: 3.14.0 + version: link:../wrangler packages/prerelease-registry: dependencies: @@ -1086,8 +1086,8 @@ importers: specifier: 0.17.19 version: 0.17.19 miniflare: - specifier: 3.20231025.0 - version: 3.20231025.0(supports-color@9.2.2) + specifier: 3.20231025.1 + version: 3.20231025.1(supports-color@9.2.2) nanoid: specifier: ^3.3.3 version: 3.3.6 @@ -1380,7 +1380,7 @@ importers: version: 6.5.1 wrangler: specifier: ^3.0.0 - version: 3.14.0 + version: link:../wrangler packages: @@ -3407,6 +3407,7 @@ packages: resolution: {integrity: sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==} dependencies: mime: 3.0.0 + dev: false /@cloudflare/style-const@5.7.3(react@18.2.0): resolution: {integrity: sha512-N9Y8bcFXoO7htm+sSVsBmQOVbjLeEY2hy1CBmvt0AoH1zWvs3izwJrnlL0ee4kJ6DkyjaY6SIAkUGUtTOApF3Q==} @@ -3652,6 +3653,7 @@ 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==} @@ -3661,6 +3663,7 @@ 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.3: resolution: {integrity: sha512-RolFVeinkeraDvN/OoRf1F/lP0KUfGNb5jxy/vkIMeRRChkrX/HTYN6TYZosRJs3a1+8wqpxAo5PI5hFmxyPRg==} @@ -7527,6 +7530,7 @@ 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==} @@ -9787,6 +9791,7 @@ 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==} @@ -12653,6 +12658,7 @@ packages: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: sourcemap-codec: 1.4.8 + dev: false /magic-string@0.30.0: resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==} @@ -13264,7 +13270,7 @@ packages: - utf-8-validate dev: true - /miniflare@3.20231025.0(supports-color@9.2.2): + /miniflare@3.20231025.0: resolution: {integrity: sha512-pFcr2BRaGIQ26UfdDo8BMJ6kkd/Jo/FkQ/4K7UG/eORlDepsLrR/sTJddcSSIGl07MA+MGjhzopFTPpFskkS+g==} engines: {node: '>=16.13'} dependencies: @@ -13285,6 +13291,28 @@ packages: - supports-color - utf-8-validate + /miniflare@3.20231025.1(supports-color@9.2.2): + resolution: {integrity: sha512-zwvu/f6eivBBF2shuom5DibnZjGSxt6FiC8sZlj+CcqTRss1D2ZHYD09odhAZLY9DYXE0orBFkJKnIDx/QmYdQ==} + engines: {node: '>=16.13'} + dependencies: + acorn: 8.10.0 + acorn-walk: 8.2.0 + capnp-ts: 0.7.0(supports-color@9.2.2) + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + source-map-support: 0.5.21 + stoppable: 1.1.0 + undici: 5.23.0 + workerd: 1.20231025.0 + ws: 8.14.2 + youch: 3.2.3 + zod: 3.22.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -13575,6 +13603,7 @@ packages: /node-forge@1.3.0: resolution: {integrity: sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==} engines: {node: '>= 6.13.0'} + dev: false /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -15350,16 +15379,19 @@ 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==} @@ -15494,6 +15526,7 @@ 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==} @@ -15869,6 +15902,7 @@ 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==} @@ -17631,32 +17665,6 @@ packages: '@cloudflare/workerd-linux-arm64': 1.20231025.0 '@cloudflare/workerd-windows-64': 1.20231025.0 - /wrangler@3.14.0: - resolution: {integrity: sha512-4vzw11yG1/KXpYKbumvRJ61Iyhm/yKXb/ayOw/2xiIRdKdpsfN9/796d2l525+CDaGwZWswpLENe6ZMS0p/Ghg==} - engines: {node: '>=16.13.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.20231016.0(supports-color@9.2.2) - nanoid: 3.3.6 - path-to-regexp: 6.2.0 - selfsigned: 2.1.1 - source-map: 0.6.1 - source-map-support: 0.5.21 - 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==} engines: {node: '>=8'} @@ -17798,6 +17806,7 @@ 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==} From ba1418faa66f266833e3bf78b250393c96a119a8 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:15:02 +0100 Subject: [PATCH 14/34] ready event should await proxyWorker.setOptions --- .../wrangler/src/api/startDevWorker/ProxyController.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 0fee064010c5..94641c629e7a 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -144,10 +144,11 @@ export class ProxyController extends EventEmitter { this.proxyWorker ??= new Miniflare(proxyWorkerOptions); this.proxyWorkerOptions = proxyWorkerOptions; + let setOptionsPromise: Promise | undefined; if (proxyWorkerOptionsChanged) { logger.debug("ProxyWorker miniflare options changed, reinstantiating..."); - void this.proxyWorker.setOptions(proxyWorkerOptions); + setOptionsPromise = this.proxyWorker.setOptions(proxyWorkerOptions); // this creates a new .ready promise that will be resolved when both ProxyWorkers are ready // it also respects any await-ers of the existing .ready promise @@ -157,7 +158,11 @@ export class ProxyController extends EventEmitter { // store the non-null versions for callbacks const { proxyWorker } = this; - void Promise.all([proxyWorker.ready, this.reconnectInspectorProxyWorker()]) + void Promise.all([ + setOptionsPromise, // TODO: should this be awaited internally by mf.ready? + proxyWorker.ready, + this.reconnectInspectorProxyWorker(), + ]) .then(() => { this.emitReadyEvent(proxyWorker); }) From 0311273e06e0174a11e07605871c24d40787d1b2 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Mon, 30 Oct 2023 13:18:16 +0000 Subject: [PATCH 15/34] remove unused import from rebase --- packages/wrangler/src/dev/start-server.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/wrangler/src/dev/start-server.ts b/packages/wrangler/src/dev/start-server.ts index 3611607be4e8..3c19d6a19ff3 100644 --- a/packages/wrangler/src/dev/start-server.ts +++ b/packages/wrangler/src/dev/start-server.ts @@ -2,7 +2,6 @@ import * as path from "node:path"; import * as util from "node:util"; import chalk from "chalk"; import onExit from "signal-exit"; -import tmp from "tmp-promise"; import { DevEnv, type StartDevWorkerOptions } from "../api"; import { bundleWorker } from "../deployment-bundle/bundle"; import { getBundleType } from "../deployment-bundle/bundle-type"; From c456de24b395cb6109ea1ad0e54785747ac10cc4 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Mon, 30 Oct 2023 15:38:44 +0000 Subject: [PATCH 16/34] Make external-service-bindings-app mork locally --- .../external-service-bindings-app/tests/index.test.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fixtures/external-service-bindings-app/tests/index.test.ts b/fixtures/external-service-bindings-app/tests/index.test.ts index d71fe7bb9880..2ccd7308b021 100644 --- a/fixtures/external-service-bindings-app/tests/index.test.ts +++ b/fixtures/external-service-bindings-app/tests/index.test.ts @@ -3,16 +3,17 @@ import * as path from "path"; import type { ChildProcess } from "child_process"; import { describe, expect, it, beforeAll, afterAll, beforeEach } from "vitest"; import { fetch, type Response } from "undici"; +import { setTimeout } from "node:timers/promises"; const waitUntilReady = async (url: string): Promise => { let response: Response | undefined = undefined; while (response === undefined) { - await new Promise((resolvePromise) => setTimeout(resolvePromise, 500)); + await setTimeout(500); try { response = await fetch(url); - } catch {} + } catch (e) {} } return response as Response; @@ -73,7 +74,7 @@ describe("Pages Functions", () => { it("connects up Workers (both module and service ones) and fetches from them", async () => { const combinedResponse = await waitUntilReady( - `http://localhost:${pagesAppPort}/` + `http://127.0.0.1:${pagesAppPort}/` ); const json = await combinedResponse.json(); expect(json).toMatchInlineSnapshot(` @@ -87,7 +88,7 @@ describe("Pages Functions", () => { 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:${pagesAppPort}/env` + `http://127.0.0.1:${pagesAppPort}/env` ); const json = await combinedResponse.json(); expect(json).toMatchInlineSnapshot(` From 2fd84def1d90383deaca838096a035ddfa15e8d9 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:54:40 +0000 Subject: [PATCH 17/34] tmp: disable fail-fast on unit-test matrix so i can see if the failures on windows are platform-specific --- .github/workflows/pullrequests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pullrequests.yml b/.github/workflows/pullrequests.yml index 70cbc46c839c..4721fa3786ce 100644 --- a/.github/workflows/pullrequests.yml +++ b/.github/workflows/pullrequests.yml @@ -59,6 +59,7 @@ jobs: test: name: "Tests" strategy: + fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} From 8622c366942e1a88d7ca92d111c5bdb84feed6aa Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 12:21:21 +0000 Subject: [PATCH 18/34] tmp: test debugging --- fixtures/dev-env/tests/index.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index a9c323fa8740..1d60e16c0a9c 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -56,7 +56,10 @@ async function fakeStartUserWorker(options: { compatibilityDate: "2023-08-01", name: config.name, script: options.script, - log: Object.assign(new Log(), { error() {} }), // TODO: remove when this bug is fixed https://jira.cfdata.org/browse/DEVX-983 + // TODO: remove when this bug is fixed https://jira.cfdata.org/browse/DEVX-983 + log: Object.assign(new Log(undefined, { prefix: "FakeUserWorker" }), { + error() {}, + }), }, options.mfOpts ); @@ -396,9 +399,11 @@ describe("startDevWorker: ProxyController", () => { }, }); + // worker.fetch should wait for the ProxyWorker instance to be ready res = await run.worker.fetch("http://dummy"); await expect(res.text()).resolves.toBe("body:1"); + // test eyeball fetches with undici.fetch (we already confirmed the ProxyWorker instance is ready, above) const oldPort = run.config.dev?.server?.port; res = await undici.fetch(`http://127.0.0.1:${oldPort}`); await expect(res.text()).resolves.toBe("body:1"); @@ -419,13 +424,18 @@ describe("startDevWorker: ProxyController", () => { ); const newPort = config2.dev?.server?.port; + expect(newPort).not.toBe(oldPort); + console.log({ oldPort, newPort }); + // worker.fetch should wait for the new ProxyWorker instance to be ready res = await run.worker.fetch("http://dummy"); await expect(res.text()).resolves.toBe("body:1"); + // test eyeball fetches with undici.fetch (we already confirmed the new ProxyWorker instance is ready, above) res = await undici.fetch(`http://127.0.0.1:${newPort}`); await expect(res.text()).resolves.toBe("body:1"); + // assuming the old server should shutdown by the time the new server is up await expect( undici.fetch(`http://127.0.0.1:${oldPort}`).then((r) => r.text()) ).rejects.toMatchInlineSnapshot("[TypeError: fetch failed]"); From f4e55d005974fd15c3150d4237133ebf9c5a6cbd Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:28:59 +0000 Subject: [PATCH 19/34] tmp: more test debugging --- packages/wrangler/src/api/startDevWorker/DevEnv.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/wrangler/src/api/startDevWorker/DevEnv.ts b/packages/wrangler/src/api/startDevWorker/DevEnv.ts index 85ee7002e62b..6f97fde11df8 100644 --- a/packages/wrangler/src/api/startDevWorker/DevEnv.ts +++ b/packages/wrangler/src/api/startDevWorker/DevEnv.ts @@ -119,11 +119,22 @@ export function createWorkerObject(devEnv: DevEnv): DevWorker { return devEnv.config.updateOptions(options); }, async fetch(...args) { + const start = performance.now(); + console.log("DevEnv.worker.fetch"); const { proxyWorker } = await devEnv.proxy.ready.promise; + console.log( + "DevEnv.worker.fetch devEnv.proxy.ready", + performance.now() - start + ); // return proxyWorker.dispatchFetch(...args); // ^ bug: Miniflare#dispatchFetch uses one HTTP/1.1 connection, preventing parallel requests (pause/play requests + buffered eyeball requests) // workaround: use undici.fetch const proxyWorkerUrl = await proxyWorker.ready; + console.log( + "DevEnv.worker.fetch proxyWorker.ready", + performance.now() - start + ); + console.log({ proxyWorkerUrl: proxyWorkerUrl.href }); const req = new Request(...args); const url = new URL(req.url); url.protocol = proxyWorkerUrl.protocol; From e49c8c814a46db0e6876914be9328054648773ee Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:58:54 +0000 Subject: [PATCH 20/34] temp: more test debugging --- fixtures/dev-env/tests/index.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index 1d60e16c0a9c..a765042a4545 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -408,6 +408,7 @@ describe("startDevWorker: ProxyController", () => { res = await undici.fetch(`http://127.0.0.1:${oldPort}`); await expect(res.text()).resolves.toBe("body:1"); + const oldProxyWorkerInstance = devEnv.proxy.proxyWorker; const config2 = fakeConfigUpdate({ ...run.config, dev: { @@ -427,6 +428,10 @@ describe("startDevWorker: ProxyController", () => { expect(newPort).not.toBe(oldPort); console.log({ oldPort, newPort }); + // temp + expect(oldProxyWorkerInstance).not.toBe(devEnv.proxy.proxyWorker); + await devEnv.proxy.proxyWorker.ready; + // worker.fetch should wait for the new ProxyWorker instance to be ready res = await run.worker.fetch("http://dummy"); await expect(res.text()).resolves.toBe("body:1"); From 2bf4d4604a3108b893fb8002e52ca4ec686ad662 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 15:15:33 +0000 Subject: [PATCH 21/34] temp: run only dev-env tests --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4c02840be264..52f2b4c9e451 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "fix": "pnpm run prettify && dotenv -- turbo check:lint -- --fix", "prettify": "prettier . --write --ignore-unknown", "test": "dotenv -- turbo test --concurrency=1", - "test:ci": "dotenv -- turbo test:ci --filter=!local-mode-tests --filter=!playground-preview-worker --filter=!no-bundle-import --filter=!pages-functions-app --filter=!pages-plugin-mounted-on-root-app --filter=!workers.new --concurrency=1", + "test:ci": "dotenv -- turbo test:ci --filter=dev-env --concurrency=1", "test:ci:quarantine": "dotenv -- turbo test:ci --filter=local-mode-tests --filter=pages-functions-app --filter=pages-plugin-mounted-on-root-app --filter=playground-preview-worker --filter=no-bundle-import --filter=workers.new --concurrency=1", "test:watch": "turbo test:watch", "type:tests": "dotenv -- turbo type:tests", From e8836d9c36b9b2958c87804bb4c9e5c95e303af0 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 15:45:56 +0000 Subject: [PATCH 22/34] temp: more test debugging remove assertion proxyWorker miniflare instance is different --- fixtures/dev-env/tests/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index a765042a4545..f08a67956a13 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -408,7 +408,6 @@ describe("startDevWorker: ProxyController", () => { res = await undici.fetch(`http://127.0.0.1:${oldPort}`); await expect(res.text()).resolves.toBe("body:1"); - const oldProxyWorkerInstance = devEnv.proxy.proxyWorker; const config2 = fakeConfigUpdate({ ...run.config, dev: { @@ -429,8 +428,9 @@ describe("startDevWorker: ProxyController", () => { console.log({ oldPort, newPort }); // temp - expect(oldProxyWorkerInstance).not.toBe(devEnv.proxy.proxyWorker); + console.log("awaiting devEnv.proxy.proxyWorker.ready"); await devEnv.proxy.proxyWorker.ready; + console.log("devEnv.proxy.proxyWorker.ready"); // worker.fetch should wait for the new ProxyWorker instance to be ready res = await run.worker.fetch("http://dummy"); From 7cf90699f7ec4d819145df2827a06f5b6dad24a4 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 15:49:49 +0000 Subject: [PATCH 23/34] temp: more test debugging --- fixtures/dev-env/tests/index.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index f08a67956a13..6bbde099e614 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -429,8 +429,9 @@ describe("startDevWorker: ProxyController", () => { // temp console.log("awaiting devEnv.proxy.proxyWorker.ready"); - await devEnv.proxy.proxyWorker.ready; + const { proxyWorker } = await devEnv.proxy.proxyWorker.ready.promise; console.log("devEnv.proxy.proxyWorker.ready"); + console.log({ proxyWorkerUrl: await proxyWorker.url }); // worker.fetch should wait for the new ProxyWorker instance to be ready res = await run.worker.fetch("http://dummy"); From bc11f06eda921b243f2571419694049371972b31 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:08:34 +0000 Subject: [PATCH 24/34] temp: more test debugging --- fixtures/dev-env/tests/index.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index 6bbde099e614..498ccbd261e4 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -408,6 +408,7 @@ describe("startDevWorker: ProxyController", () => { res = await undici.fetch(`http://127.0.0.1:${oldPort}`); await expect(res.text()).resolves.toBe("body:1"); + const oldReadyDeferred = devEnv.proxy.ready; const config2 = fakeConfigUpdate({ ...run.config, dev: { @@ -428,8 +429,9 @@ describe("startDevWorker: ProxyController", () => { console.log({ oldPort, newPort }); // temp + expect(oldReadyDeferred).not.toBe(devEnv.proxy.ready); console.log("awaiting devEnv.proxy.proxyWorker.ready"); - const { proxyWorker } = await devEnv.proxy.proxyWorker.ready.promise; + const { proxyWorker } = await devEnv.proxy.ready.promise; console.log("devEnv.proxy.proxyWorker.ready"); console.log({ proxyWorkerUrl: await proxyWorker.url }); From 10b73b755d8ec6534c5db4108b74f966113b966f Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:28:41 +0000 Subject: [PATCH 25/34] await setOptionsPromise before accessing mf.ready promise --- fixtures/dev-env/tests/index.test.ts | 4 ++-- .../wrangler/src/api/startDevWorker/ProxyController.ts | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index 498ccbd261e4..ac9347aacbbc 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -430,9 +430,9 @@ describe("startDevWorker: ProxyController", () => { // temp expect(oldReadyDeferred).not.toBe(devEnv.proxy.ready); - console.log("awaiting devEnv.proxy.proxyWorker.ready"); + console.log("awaiting devEnv.proxy.ready.promise"); const { proxyWorker } = await devEnv.proxy.ready.promise; - console.log("devEnv.proxy.proxyWorker.ready"); + console.log("awaiting proxyWorker.ready"); console.log({ proxyWorkerUrl: await proxyWorker.url }); // worker.fetch should wait for the new ProxyWorker instance to be ready diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 94641c629e7a..a57c709bef02 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -158,11 +158,9 @@ export class ProxyController extends EventEmitter { // store the non-null versions for callbacks const { proxyWorker } = this; - void Promise.all([ - setOptionsPromise, // TODO: should this be awaited internally by mf.ready? - proxyWorker.ready, - this.reconnectInspectorProxyWorker(), - ]) + Promise.resolve(setOptionsPromise) + .then(() => proxyWorker!.ready) + .then(() => this.reconnectInspectorProxyWorker()) .then(() => { this.emitReadyEvent(proxyWorker); }) From 9cc55163cd5454b28c7c25260daefe6f8fb2a701 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:45:25 +0000 Subject: [PATCH 26/34] workaround for Miniflare bug setOptions/ready https://jira.cfdata.org/browse/DEVX-1016 --- .../src/api/startDevWorker/ProxyController.ts | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index a57c709bef02..662b9f696406 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -42,6 +42,7 @@ export class ProxyController extends EventEmitter { public proxyWorker?: Miniflare; proxyWorkerOptions?: MiniflareOptions; inspectorProxyWorkerWebSocket?: DeferredPromise; + setOptionsPromise: Promise | undefined; protected latestConfig?: StartDevWorkerOptions; protected latestBundle?: EsbuildBundle; @@ -144,25 +145,24 @@ export class ProxyController extends EventEmitter { this.proxyWorker ??= new Miniflare(proxyWorkerOptions); this.proxyWorkerOptions = proxyWorkerOptions; - let setOptionsPromise: Promise | undefined; if (proxyWorkerOptionsChanged) { logger.debug("ProxyWorker miniflare options changed, reinstantiating..."); - setOptionsPromise = this.proxyWorker.setOptions(proxyWorkerOptions); + this.setOptionsPromise = this.proxyWorker.setOptions(proxyWorkerOptions); // this creates a new .ready promise that will be resolved when both ProxyWorkers are ready // it also respects any await-ers of the existing .ready promise this.ready = createDeferred(this.ready); } - // store the non-null versions for callbacks - const { proxyWorker } = this; - - Promise.resolve(setOptionsPromise) - .then(() => proxyWorker!.ready) - .then(() => this.reconnectInspectorProxyWorker()) + void Promise.all([ + Promise.resolve(this.setOptionsPromise).then( + () => this.proxyWorker!.ready + ), + this.reconnectInspectorProxyWorker(), + ]) .then(() => { - this.emitReadyEvent(proxyWorker); + this.emitReadyEvent(this.proxyWorker!); }) .catch((error) => { this.emitErrorEvent( @@ -186,6 +186,10 @@ export class ProxyController extends EventEmitter { try { assert(this.proxyWorker); + // workaround for https://jira.cfdata.org/browse/DEVX-1016 + await this.setOptionsPromise; + await this.proxyWorker.ready; + // end workaround const inspectorProxyWorker = await this.proxyWorker.getWorker( "InspectorProxyWorker" ); From e2544c65f169be1c7fcc97381030b66518c8abdb Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Tue, 31 Oct 2023 18:23:32 +0000 Subject: [PATCH 27/34] Add logging --- packages/wrangler/src/api/startDevWorker/ProxyController.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 662b9f696406..1a9070574c7e 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -241,6 +241,7 @@ export class ProxyController extends EventEmitter { if (this._torndown) return; assert(this.proxyWorker, "proxyWorker should already be instantiated"); + await this.proxyWorker.ready; try { await this.proxyWorker.dispatchFetch( `http://dummy/cdn-cgi/ProxyWorker/${message.type}`, @@ -250,6 +251,7 @@ export class ProxyController extends EventEmitter { } ); } catch (cause) { + console.error("ProxyWorker connection error", cause); if (this._torndown) return; const error = castErrorCause(cause); From db2cf68e585df3bf45b189bb553e65eb02cae076 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 1 Nov 2023 12:26:45 +0000 Subject: [PATCH 28/34] remove miniflare workaround for parallel requests --- .../wrangler/src/api/startDevWorker/DevEnv.ts | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/DevEnv.ts b/packages/wrangler/src/api/startDevWorker/DevEnv.ts index 6f97fde11df8..e11ccfd89ffa 100644 --- a/packages/wrangler/src/api/startDevWorker/DevEnv.ts +++ b/packages/wrangler/src/api/startDevWorker/DevEnv.ts @@ -119,30 +119,8 @@ export function createWorkerObject(devEnv: DevEnv): DevWorker { return devEnv.config.updateOptions(options); }, async fetch(...args) { - const start = performance.now(); - console.log("DevEnv.worker.fetch"); const { proxyWorker } = await devEnv.proxy.ready.promise; - console.log( - "DevEnv.worker.fetch devEnv.proxy.ready", - performance.now() - start - ); - // return proxyWorker.dispatchFetch(...args); - // ^ bug: Miniflare#dispatchFetch uses one HTTP/1.1 connection, preventing parallel requests (pause/play requests + buffered eyeball requests) - // workaround: use undici.fetch - const proxyWorkerUrl = await proxyWorker.ready; - console.log( - "DevEnv.worker.fetch proxyWorker.ready", - performance.now() - start - ); - console.log({ proxyWorkerUrl: proxyWorkerUrl.href }); - const req = new Request(...args); - const url = new URL(req.url); - url.protocol = proxyWorkerUrl.protocol; - url.hostname = proxyWorkerUrl.hostname; - url.port = proxyWorkerUrl.port; - // /workaround - - return fetch(url, req as RequestInit); + return proxyWorker.dispatchFetch(...args); }, async queue(..._args) { // const { worker } = await devEnv.proxy.ready; From eecccd736016db9d1fc1824f45ea0d4f87a22607 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 1 Nov 2023 12:40:16 +0000 Subject: [PATCH 29/34] ensure miniflare version is consistent across all packages/fixtures --- fixtures/dev-env/package.json | 2 +- fixtures/pages-ws-app/package.json | 2 +- packages/pages-shared/package.json | 2 +- pnpm-lock.yaml | 114 ++--------------------------- 4 files changed, 9 insertions(+), 111 deletions(-) diff --git a/fixtures/dev-env/package.json b/fixtures/dev-env/package.json index 5502c9d0e0b8..11103f0de5a0 100644 --- a/fixtures/dev-env/package.json +++ b/fixtures/dev-env/package.json @@ -16,7 +16,7 @@ "@types/ws": "^8.5.7", "@cloudflare/workers-tsconfig": "workspace:^", "get-port": "^7.0.0", - "miniflare": "3.20231002.1", + "miniflare": "3.20231025.1", "undici": "^5.23.0", "wrangler": "workspace:*", "ws": "^8.14.2" diff --git a/fixtures/pages-ws-app/package.json b/fixtures/pages-ws-app/package.json index 25f6304f86a0..e4db99b1cd0f 100644 --- a/fixtures/pages-ws-app/package.json +++ b/fixtures/pages-ws-app/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@cloudflare/workers-tsconfig": "workspace:*", - "miniflare": "3.20231025.0", + "miniflare": "3.20231025.1", "wrangler": "workspace:*", "ws": "^8.8.0" }, diff --git a/packages/pages-shared/package.json b/packages/pages-shared/package.json index 2528f62d1065..4634434438df 100644 --- a/packages/pages-shared/package.json +++ b/packages/pages-shared/package.json @@ -18,7 +18,7 @@ "test:ci": "vitest run" }, "dependencies": { - "miniflare": "3.20231025.0" + "miniflare": "3.20231025.1" }, "devDependencies": { "@cloudflare/workers-tsconfig": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index afbceb8dd1f9..0ab20853d0ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,8 +114,8 @@ importers: specifier: ^7.0.0 version: 7.0.0 miniflare: - specifier: 3.20231002.1 - version: 3.20231002.1 + specifier: 3.20231025.1 + version: 3.20231025.1(supports-color@9.2.2) undici: specifier: ^5.23.0 version: 5.23.0 @@ -389,8 +389,8 @@ importers: specifier: workspace:* version: link:../../packages/workers-tsconfig miniflare: - specifier: 3.20231025.0 - version: 3.20231025.0 + specifier: 3.20231025.1 + version: 3.20231025.1(supports-color@9.2.2) wrangler: specifier: workspace:* version: link:../../packages/wrangler @@ -758,8 +758,8 @@ importers: packages/pages-shared: dependencies: miniflare: - specifier: 3.20231025.0 - version: 3.20231025.0 + specifier: 3.20231025.1 + version: 3.20231025.1(supports-color@9.2.2) devDependencies: '@cloudflare/workers-tsconfig': specifier: workspace:* @@ -3503,15 +3503,6 @@ packages: marked: 0.3.19 dev: false - /@cloudflare/workerd-darwin-64@1.20231002.0: - resolution: {integrity: sha512-sgtjzVO/wtI/6S7O0bk4zQAv2xlvqOxB18AXzlit6uXgbYFGeQedRHjhKVMOacGmWEnM4C3ir/fxJGsc3Pyxng==} - engines: {node: '>=16'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@cloudflare/workerd-darwin-64@1.20231025.0: resolution: {integrity: sha512-MYRYTbSl+tjGg6su7savlLIb8cOcKJfdGpA+WdtgqT2OF7O+89Lag0l1SA/iyVlUkT31Jc6OLHqvzsXgmg+niQ==} engines: {node: '>=16'} @@ -3520,15 +3511,6 @@ packages: requiresBuild: true optional: true - /@cloudflare/workerd-darwin-arm64@1.20231002.0: - resolution: {integrity: sha512-dv8nztYFaTYYgBpyy80vc4hdMYv9mhyNbvBsZywm8S7ivcIpzogi0UKkGU4E/G0lYK6W3WtwTBqwRe+pXJ1+Ww==} - engines: {node: '>=16'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@cloudflare/workerd-darwin-arm64@1.20231025.0: resolution: {integrity: sha512-BszjtBDR84TVa6oWe74dePJSAukWlTmLw9zR4KeWuwZLJGV7RMm6AmwGStetjnwZrecZaaOFELfBCAHtsebV0Q==} engines: {node: '>=16'} @@ -3537,15 +3519,6 @@ packages: requiresBuild: true optional: true - /@cloudflare/workerd-linux-64@1.20231002.0: - resolution: {integrity: sha512-UG8SlLcGzaQDSSw6FR4+Zf408925wkLOCAi8w5qEoFYu3g4Ef7ZenstesCOsyWL7qBDKx0/iwk6+a76W5IHI0Q==} - engines: {node: '>=16'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@cloudflare/workerd-linux-64@1.20231025.0: resolution: {integrity: sha512-AT9dxgKXOa9xZxZ3k2a432axPJJ58KpoNWnPiPYGpuAuLoWnfcYwwh6mr9sZVcTdAdTAK9Xu9c81tp0YABanUw==} engines: {node: '>=16'} @@ -3554,15 +3527,6 @@ packages: requiresBuild: true optional: true - /@cloudflare/workerd-linux-arm64@1.20231002.0: - resolution: {integrity: sha512-GPaa66ZSq1gK09r87c5CJbHIApcIU//LVHz3rnUxK0//00YCwUuGUUK1dn/ylg+fVqDQxIDmH+ABnobBanvcDA==} - engines: {node: '>=16'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@cloudflare/workerd-linux-arm64@1.20231025.0: resolution: {integrity: sha512-EIjex5o2k80YZWPix1btGybL/vNZ3o6vqKX9ptS0JcFkHV5aFX5/kcMwSBRjiIC+w04zVjmGQx3N1Vh3njuncg==} engines: {node: '>=16'} @@ -3571,15 +3535,6 @@ packages: requiresBuild: true optional: true - /@cloudflare/workerd-windows-64@1.20231002.0: - resolution: {integrity: sha512-ybIy+sCme0VO0RscndXvqWNBaRMUOc8vhi+1N2h/KDsKfNLsfEQph+XWecfKzJseUy1yE2rV1xei3BaNmaa6vg==} - engines: {node: '>=16'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@cloudflare/workerd-windows-64@1.20231025.0: resolution: {integrity: sha512-7vtq0mO22A2v0OOsKXa760r9a84Gg8CK0gDu5uNWlj6hojmt011iz7jJt76I7oo/XrVwVlVfu69GnA3ljx6U8w==} engines: {node: '>=16'} @@ -13248,49 +13203,6 @@ packages: engines: {node: '>=4'} dev: false - /miniflare@3.20231002.1: - resolution: {integrity: sha512-4xJ8FezJkQqHzCm71lovb9L/wJ0VV/odMFf5CIxfLTunsx97kTIlZnhS6aHuvcbzdztbWp1RR71K/1qFUHdpdQ==} - engines: {node: '>=16.13'} - dependencies: - acorn: 8.10.0 - acorn-walk: 8.2.0 - capnp-ts: 0.7.0(supports-color@9.2.2) - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - source-map-support: 0.5.21 - stoppable: 1.1.0 - undici: 5.23.0 - workerd: 1.20231002.0 - ws: 8.14.2 - youch: 3.2.3 - zod: 3.22.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /miniflare@3.20231025.0: - resolution: {integrity: sha512-pFcr2BRaGIQ26UfdDo8BMJ6kkd/Jo/FkQ/4K7UG/eORlDepsLrR/sTJddcSSIGl07MA+MGjhzopFTPpFskkS+g==} - engines: {node: '>=16.13'} - dependencies: - acorn: 8.10.0 - acorn-walk: 8.2.0 - capnp-ts: 0.7.0(supports-color@9.2.2) - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - source-map-support: 0.5.21 - stoppable: 1.1.0 - undici: 5.23.0 - workerd: 1.20231025.0 - ws: 8.14.2 - youch: 3.2.3 - zod: 3.22.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - /miniflare@3.20231025.1(supports-color@9.2.2): resolution: {integrity: sha512-zwvu/f6eivBBF2shuom5DibnZjGSxt6FiC8sZlj+CcqTRss1D2ZHYD09odhAZLY9DYXE0orBFkJKnIDx/QmYdQ==} engines: {node: '>=16.13'} @@ -13311,7 +13223,6 @@ packages: - bufferutil - supports-color - utf-8-validate - dev: false /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -17640,19 +17551,6 @@ packages: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true - /workerd@1.20231002.0: - resolution: {integrity: sha512-NFuUQBj30ZguDoPZ6bL40hINiu8aP2Pvxr/3xAdhWOwVFLuObPOiSdQ8qm4JYZ7jovxWjWE4Z7VR2avjIzEksQ==} - engines: {node: '>=16'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20231002.0 - '@cloudflare/workerd-darwin-arm64': 1.20231002.0 - '@cloudflare/workerd-linux-64': 1.20231002.0 - '@cloudflare/workerd-linux-arm64': 1.20231002.0 - '@cloudflare/workerd-windows-64': 1.20231002.0 - dev: true - /workerd@1.20231025.0: resolution: {integrity: sha512-W1PFtpMFfvmm+ozBf+u70TE3Pviv7WA4qzDeejHDC4z+PFDq4+3KJCkgffaGBO86h+akWO0hSsc0uXL2zAqofQ==} engines: {node: '>=16'} From c61bdb43a2b31cc811097a8953ab5da403f9137a Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 1 Nov 2023 12:49:45 +0000 Subject: [PATCH 30/34] apply miniflare patch for Mutex#drained bug --- package.json | 3 ++- patches/miniflare@3.20231025.1.patch | 13 +++++++++++++ pnpm-lock.yaml | 14 +++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 patches/miniflare@3.20231025.1.patch diff --git a/package.json b/package.json index 52f2b4c9e451..3bac84c8c6f7 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,8 @@ "patchedDependencies": { "ink@3.2.0": "patches/ink@3.2.0.patch", "toucan-js@3.2.2": "patches/toucan-js@3.2.2.patch", - "@cloudflare/component-listbox@1.10.6": "patches/@cloudflare__component-listbox@1.10.6.patch" + "@cloudflare/component-listbox@1.10.6": "patches/@cloudflare__component-listbox@1.10.6.patch", + "miniflare@3.20231025.1": "patches/miniflare@3.20231025.1.patch" } } } diff --git a/patches/miniflare@3.20231025.1.patch b/patches/miniflare@3.20231025.1.patch new file mode 100644 index 000000000000..92eb3402ec40 --- /dev/null +++ b/patches/miniflare@3.20231025.1.patch @@ -0,0 +1,13 @@ +diff --git a/dist/src/index.js b/dist/src/index.js +index e9825f77c63e24abeacf13b6255e5a9d9673f2f7..79621864da441d90ca1113fb5e61b24a1912b799 100644 +--- a/dist/src/index.js ++++ b/dist/src/index.js +@@ -3340,7 +3340,7 @@ var Mutex = class { + } + } + async drained() { +- if (this.resolveQueue.length === 0) ++ if (this.resolveQueue.length === 0 && !this.locked) + return; + return new Promise((resolve) => this.drainQueue.push(resolve)); + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ab20853d0ec..470208015621 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ patchedDependencies: ink@3.2.0: hash: iiwbcf44d6ccmi6a27ljqs7qce path: patches/ink@3.2.0.patch + miniflare@3.20231025.1: + hash: hir75yp2jy3vlvmeaiwdyrrpf4 + path: patches/miniflare@3.20231025.1.patch toucan-js@3.2.2: hash: dxprwy4mawdnq3drjhp7shhm2m path: patches/toucan-js@3.2.2.patch @@ -115,7 +118,7 @@ importers: version: 7.0.0 miniflare: specifier: 3.20231025.1 - version: 3.20231025.1(supports-color@9.2.2) + version: 3.20231025.1(patch_hash=hir75yp2jy3vlvmeaiwdyrrpf4)(supports-color@9.2.2) undici: specifier: ^5.23.0 version: 5.23.0 @@ -390,7 +393,7 @@ importers: version: link:../../packages/workers-tsconfig miniflare: specifier: 3.20231025.1 - version: 3.20231025.1(supports-color@9.2.2) + version: 3.20231025.1(patch_hash=hir75yp2jy3vlvmeaiwdyrrpf4)(supports-color@9.2.2) wrangler: specifier: workspace:* version: link:../../packages/wrangler @@ -759,7 +762,7 @@ importers: dependencies: miniflare: specifier: 3.20231025.1 - version: 3.20231025.1(supports-color@9.2.2) + version: 3.20231025.1(patch_hash=hir75yp2jy3vlvmeaiwdyrrpf4)(supports-color@9.2.2) devDependencies: '@cloudflare/workers-tsconfig': specifier: workspace:* @@ -1087,7 +1090,7 @@ importers: version: 0.17.19 miniflare: specifier: 3.20231025.1 - version: 3.20231025.1(supports-color@9.2.2) + version: 3.20231025.1(patch_hash=hir75yp2jy3vlvmeaiwdyrrpf4)(supports-color@9.2.2) nanoid: specifier: ^3.3.3 version: 3.3.6 @@ -13203,7 +13206,7 @@ packages: engines: {node: '>=4'} dev: false - /miniflare@3.20231025.1(supports-color@9.2.2): + /miniflare@3.20231025.1(patch_hash=hir75yp2jy3vlvmeaiwdyrrpf4)(supports-color@9.2.2): resolution: {integrity: sha512-zwvu/f6eivBBF2shuom5DibnZjGSxt6FiC8sZlj+CcqTRss1D2ZHYD09odhAZLY9DYXE0orBFkJKnIDx/QmYdQ==} engines: {node: '>=16.13'} dependencies: @@ -13223,6 +13226,7 @@ packages: - bufferutil - supports-color - utf-8-validate + patched: true /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} From 2909265d19f40e985d5f96fade59177c4e7eadb3 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Wed, 1 Nov 2023 13:20:15 +0000 Subject: [PATCH 31/34] considerations for race between control messages and user fetches --- fixtures/dev-env/tests/index.test.ts | 5 ++++- .../wrangler/src/api/startDevWorker/DevEnv.ts | 2 ++ .../src/api/startDevWorker/ProxyController.ts | 22 +++++++++++-------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index ac9347aacbbc..bffdccb0c6ab 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -20,6 +20,7 @@ let devEnv: DevEnv; let mf: Miniflare | undefined; let res: MiniflareResponse | undici.Response; let ws: WebSocket | undefined; +let fireAndForgetPromises: Promise[] = []; type OptionalKeys = Omit & Partial>; @@ -30,6 +31,7 @@ beforeEach(() => { ws = undefined; }); afterEach(async () => { + await Promise.allSettled(fireAndForgetPromises); await devEnv?.teardown(); await mf?.dispose(); await ws?.close(); @@ -139,7 +141,8 @@ function fireAndForgetFakeUserWorkerChanges( ...args: Parameters ) { // fire and forget the reload -- this let's us test request buffering - void fakeUserWorkerChanges(...args); + const promise = fakeUserWorkerChanges(...args); + fireAndForgetPromises.push(promise); } function fakeConfigUpdate(config: StartDevWorkerOptions) { diff --git a/packages/wrangler/src/api/startDevWorker/DevEnv.ts b/packages/wrangler/src/api/startDevWorker/DevEnv.ts index e11ccfd89ffa..1838322824ce 100644 --- a/packages/wrangler/src/api/startDevWorker/DevEnv.ts +++ b/packages/wrangler/src/api/startDevWorker/DevEnv.ts @@ -120,6 +120,8 @@ export function createWorkerObject(devEnv: DevEnv): DevWorker { }, async fetch(...args) { const { proxyWorker } = await devEnv.proxy.ready.promise; + await devEnv.proxy.runtimeMessageMutex.drained(); + return proxyWorker.dispatchFetch(...args); }, async queue(..._args) { diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 1a9070574c7e..0207a4d54d26 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -34,7 +34,7 @@ import type { SerializedError, } from "./events"; import type { StartDevWorkerOptions } from "./types"; -import type { MiniflareOptions } from "miniflare"; +import { MiniflareOptions, Mutex } from "miniflare"; export class ProxyController extends EventEmitter { public ready = createDeferred(); @@ -234,6 +234,7 @@ export class ProxyController extends EventEmitter { return webSocket; } + runtimeMessageMutex = new Mutex(); async sendMessageToProxyWorker( message: ProxyWorkerIncomingRequestBody, retries = 3 @@ -241,15 +242,18 @@ export class ProxyController extends EventEmitter { if (this._torndown) return; assert(this.proxyWorker, "proxyWorker should already be instantiated"); - await this.proxyWorker.ready; try { - await this.proxyWorker.dispatchFetch( - `http://dummy/cdn-cgi/ProxyWorker/${message.type}`, - { - headers: { Authorization: this.secret }, - cf: { hostMetadata: message }, - } - ); + await this.runtimeMessageMutex.runWith(async () => { + await this.proxyWorker!.ready; + + return this.proxyWorker!.dispatchFetch( + `http://dummy/cdn-cgi/ProxyWorker/${message.type}`, + { + headers: { Authorization: this.secret }, + cf: { hostMetadata: message }, + } + ); + }); } catch (cause) { console.error("ProxyWorker connection error", cause); if (this._torndown) return; From 6b99cabc17166ce61b7b1ce1d88be4822ae6b8b0 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:28:16 +0000 Subject: [PATCH 32/34] use port: undefined vs 0 for UserWorker to force different port across reloads to workaround workerd bug on Windows --- fixtures/dev-env/tests/index.test.ts | 2 +- packages/wrangler/src/dev/dev.tsx | 2 +- packages/wrangler/src/dev/local.tsx | 2 +- packages/wrangler/src/dev/miniflare.ts | 7 ++++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/fixtures/dev-env/tests/index.test.ts b/fixtures/dev-env/tests/index.test.ts index bffdccb0c6ab..fcd541b2bd3d 100644 --- a/fixtures/dev-env/tests/index.test.ts +++ b/fixtures/dev-env/tests/index.test.ts @@ -52,7 +52,7 @@ async function fakeStartUserWorker(options: { }; const mfOpts: MiniflareOptions = Object.assign( { - port: 0, + port: undefined, inspectorPort: 0, modules: true, compatibilityDate: "2023-08-01", diff --git a/packages/wrangler/src/dev/dev.tsx b/packages/wrangler/src/dev/dev.tsx index bb5764e606c8..96813682ef41 100644 --- a/packages/wrangler/src/dev/dev.tsx +++ b/packages/wrangler/src/dev/dev.tsx @@ -421,7 +421,7 @@ function DevSession(props: DevSessionProps) { bindings={props.bindings} workerDefinitions={workerDefinitions} assetPaths={props.assetPaths} - initialPort={0} // hard-code for userworker, DevEnv-ProxyWorker now uses this prop value + 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} inspectorPort={props.inspectorPort} diff --git a/packages/wrangler/src/dev/local.tsx b/packages/wrangler/src/dev/local.tsx index da51ec68c0a0..08bfc86ca7a9 100644 --- a/packages/wrangler/src/dev/local.tsx +++ b/packages/wrangler/src/dev/local.tsx @@ -25,7 +25,7 @@ export interface LocalProps { bindings: CfWorkerInit["bindings"]; workerDefinitions: WorkerRegistry | undefined; assetPaths: AssetPaths | undefined; - initialPort: number; + initialPort: number | undefined; initialIp: string; rules: Config["rules"]; inspectorPort: number; diff --git a/packages/wrangler/src/dev/miniflare.ts b/packages/wrangler/src/dev/miniflare.ts index beecf38f0f93..005f86b01e27 100644 --- a/packages/wrangler/src/dev/miniflare.ts +++ b/packages/wrangler/src/dev/miniflare.ts @@ -80,6 +80,11 @@ export default { } `; +type SpecificPort = Exclude; +type RandomConsistentPort = 0; // random port, but consistent across reloads +type RandomDifferentPort = undefined; // random port, but different across reloads +type Port = SpecificPort | RandomConsistentPort | RandomDifferentPort; + export interface ConfigBundle { // TODO(soon): maybe rename some of these options, check proposed API Google Docs name: string | undefined; @@ -91,7 +96,7 @@ export interface ConfigBundle { bindings: CfWorkerInit["bindings"]; workerDefinitions: WorkerRegistry | undefined; assetPaths: AssetPaths | undefined; - initialPort: number; + initialPort: Port; initialIp: string; rules: Config["rules"]; inspectorPort: number; From 42fcf89ec6248763240cdfee393856427131b2aa Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 2 Nov 2023 18:12:20 +0000 Subject: [PATCH 33/34] Don't try to parse node internals --- .../templates/startDevWorker/InspectorProxyWorker.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts index 69796a1a1ee8..23fbc1f8f344 100644 --- a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts +++ b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts @@ -218,9 +218,13 @@ export class InspectorProxyWorker implements DurableObject { if ( !this.websockets.devtoolsHasFileSystemAccess && - msg.params.sourceMapURL !== undefined + msg.params.sourceMapURL !== undefined && + // Don't try to find a sourcemap for e.g. node-internal: scripts + msg.params.url.startsWith("file:") ) { const url = new URL(msg.params.sourceMapURL, msg.params.url); + // Check for file: in case msg.params.sourceMapURL has a different + // protocol (e.g. data). In that case we should ignore this file if (url.protocol === "file:") { msg.params.sourceMapURL = url.href.replace("file:", "wrangler-file:"); } From b55a13a443c5131f2fbdc66df009c649ef9e852d Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 3 Nov 2023 11:50:43 +0000 Subject: [PATCH 34/34] improve InspectorProxyWorker debug logs --- .../src/api/startDevWorker/ProxyController.ts | 5 ++- .../wrangler/src/api/startDevWorker/events.ts | 2 +- .../startDevWorker/InspectorProxyWorker.ts | 37 +++++++++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ProxyController.ts b/packages/wrangler/src/api/startDevWorker/ProxyController.ts index 0207a4d54d26..7ba5bec2d992 100644 --- a/packages/wrangler/src/api/startDevWorker/ProxyController.ts +++ b/packages/wrangler/src/api/startDevWorker/ProxyController.ts @@ -389,7 +389,10 @@ export class ProxyController extends EventEmitter { switch (message.type) { case "runtime-websocket-error": // TODO: consider sending proxyData again to trigger the InspectorProxyWorker to reconnect to the runtime - logger.error(message.error); + logger.error( + "[InspectorProxyWorker] 'runtime websocket' error", + message.error + ); break; case "error": diff --git a/packages/wrangler/src/api/startDevWorker/events.ts b/packages/wrangler/src/api/startDevWorker/events.ts index 3230009c3746..25eb8931da55 100644 --- a/packages/wrangler/src/api/startDevWorker/events.ts +++ b/packages/wrangler/src/api/startDevWorker/events.ts @@ -119,7 +119,7 @@ export function serialiseError(e: unknown): SerializedError { message: e.message, name: e.name, stack: e.stack, - cause: serialiseError(e.cause), + cause: e.cause && serialiseError(e.cause), }; } else { return { message: String(e) }; diff --git a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts index 23fbc1f8f344..70ef234be9e0 100644 --- a/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts +++ b/packages/wrangler/templates/startDevWorker/InspectorProxyWorker.ts @@ -96,18 +96,27 @@ export class InspectorProxyWorker implements DurableObject { const { 0: response, 1: proxyController } = new WebSocketPair(); proxyController.accept(); - proxyController.addEventListener("close", () => { + proxyController.addEventListener("close", (event) => { // don't reconnect the proxyController websocket // ProxyController can detect this event and reconnect itself + this.sendDebugLog( + "PROXY CONTROLLER WEBSOCKET CLOSED", + event.code, + event.reason + ); + if (this.websockets.proxyController === proxyController) { this.websockets.proxyController = undefined; } }); - proxyController.addEventListener("error", () => { + proxyController.addEventListener("error", (event) => { // don't reconnect the proxyController websocket // ProxyController can detect this event and reconnect itself + const error = serialiseError(event.error); + this.sendDebugLog("PROXY CONTROLLER WEBSOCKET ERROR", error); + if (this.websockets.proxyController === proxyController) { this.websockets.proxyController = undefined; } @@ -310,6 +319,9 @@ export class InspectorProxyWorker implements DurableObject { }); runtime.addEventListener("error", (event) => { + const error = serialiseError(event.error); + this.sendDebugLog("RUNTIME WEBSOCKET ERROR", error); + clearInterval(this.runtimeKeepAliveInterval); if (this.websockets.runtime === runtime) { @@ -318,10 +330,7 @@ export class InspectorProxyWorker implements DurableObject { this.sendProxyControllerRequest({ type: "runtime-websocket-error", - error: { - message: event.message, - cause: event.error, - }, + error, }); // don't reconnect the runtime websocket @@ -452,12 +461,21 @@ export class InspectorProxyWorker implements DurableObject { ); } else { devtools.addEventListener("message", this.handleDevToolsIncomingMessage); - devtools.addEventListener("close", () => { + devtools.addEventListener("close", (event) => { + this.sendDebugLog( + "DEVTOOLS WEBSOCKET CLOSED", + event.code, + event.reason + ); + if (this.websockets.devtools === devtools) { this.websockets.devtools = undefined; } }); devtools.addEventListener("error", (event) => { + const error = serialiseError(event.error); + this.sendDebugLog("DEVTOOLS WEBSOCKET ERROR", error); + if (this.websockets.devtools === devtools) { this.websockets.devtools = undefined; } @@ -546,6 +564,11 @@ export class InspectorProxyWorker implements DurableObject { url: message.params.url, }); if (response === undefined) { + this.sendDebugLog( + `ProxyController could not resolve Network.loadNetworkResource for "${message.params.url}"` + ); + + // When the ProxyController cannot resolve a resource, let the runtime handle the request this.sendRuntimeMessage(JSON.stringify(message)); } else { // this.websockets.devtools can be undefined here