diff --git a/.changeset/strange-geckos-shave.md b/.changeset/strange-geckos-shave.md new file mode 100644 index 000000000000..5d7d6e2ccdd0 --- /dev/null +++ b/.changeset/strange-geckos-shave.md @@ -0,0 +1,13 @@ +--- +"wrangler": patch +--- + +chore: rename `getBindingsProxy` to `getPlatformProxy` + +initially `getBindingsProxy` was supposed to only provide proxies for bindings, +the utility has however grown, including now `cf`, `ctx` and `caches`, to +clarify the increased scope the utility is getting renamed to `getPlatformProxy` +and its `bindings` field is getting renamed `env` + +_note_: `getBindingProxy` with its signature is still kept available, making this +a non breaking change diff --git a/fixtures/get-bindings-proxy/package.json b/fixtures/get-bindings-proxy/package.json index 838544b43098..34f9eaccadf9 100644 --- a/fixtures/get-bindings-proxy/package.json +++ b/fixtures/get-bindings-proxy/package.json @@ -1,7 +1,7 @@ { "name": "get-bindings-proxy-fixture", "private": true, - "description": "A test for the getBindingsProxy utility", + "description": "A test for the getBindingsProxy (deprecated) utility", "scripts": { "test": "vitest run", "test:watch": "vitest", diff --git a/fixtures/get-bindings-proxy/tests/get-bindings-proxy.bindings.test.ts b/fixtures/get-bindings-proxy/tests/get-bindings-proxy.bindings.test.ts index 77b6ebbffc17..3a354cc66c59 100644 --- a/fixtures/get-bindings-proxy/tests/get-bindings-proxy.bindings.test.ts +++ b/fixtures/get-bindings-proxy/tests/get-bindings-proxy.bindings.test.ts @@ -7,12 +7,10 @@ import { R2Bucket, } from "@cloudflare/workers-types"; import { describe, expect, it } from "vitest"; -import { - getBindingsProxy as originalGetBindingsProxy, - unstable_dev, -} from "wrangler"; +import { unstable_dev } from "wrangler"; +import { getBindingsProxy } from "./shared"; import type { KVNamespace } from "@cloudflare/workers-types"; -import type { GetBindingsProxyOptions, UnstableDevWorker } from "wrangler"; +import type { UnstableDevWorker } from "wrangler"; type Bindings = { MY_VAR: string; @@ -30,17 +28,6 @@ type Bindings = { const wranglerTomlFilePath = path.join(__dirname, "..", "wrangler.toml"); -// Here we wrap the actual original getBindingsProxy function and disable its persistance, this is to make sure -// that we don't implement any persistance during these tests (which would add unnecessary extra complexity) -function getBindingsProxy( - options: Omit -): ReturnType> { - return originalGetBindingsProxy({ - ...options, - persist: false, - }); -} - describe("getBindingsProxy - bindings", () => { let devWorkers: UnstableDevWorker[]; diff --git a/fixtures/get-platform-proxy/.dev.vars b/fixtures/get-platform-proxy/.dev.vars new file mode 100644 index 000000000000..32c5e4a65778 --- /dev/null +++ b/fixtures/get-platform-proxy/.dev.vars @@ -0,0 +1,3 @@ +MY_DEV_VAR = "my-dev-var-value" +MY_VAR_A = "my-dev-var-a" +MY_KV = "my-dev-kv" diff --git a/fixtures/get-platform-proxy/custom-toml/path/.dev.vars b/fixtures/get-platform-proxy/custom-toml/path/.dev.vars new file mode 100644 index 000000000000..50e8877a06c2 --- /dev/null +++ b/fixtures/get-platform-proxy/custom-toml/path/.dev.vars @@ -0,0 +1 @@ +MY_DEV_VAR = "my-dev-var-value-from-a-custom-location" diff --git a/fixtures/get-platform-proxy/custom-toml/path/test-toml b/fixtures/get-platform-proxy/custom-toml/path/test-toml new file mode 100644 index 000000000000..ef7778b9abb6 --- /dev/null +++ b/fixtures/get-platform-proxy/custom-toml/path/test-toml @@ -0,0 +1,7 @@ +name = "get-bindings-proxy-fixture" +main = "src/index.ts" +compatibility_date = "2023-11-21" + +[vars] +MY_VAR = "my-var-value-from-a-custom-toml" +MY_JSON_VAR = { test = true, customToml = true } diff --git a/fixtures/get-platform-proxy/package.json b/fixtures/get-platform-proxy/package.json new file mode 100644 index 000000000000..a87c8ca1bedf --- /dev/null +++ b/fixtures/get-platform-proxy/package.json @@ -0,0 +1,16 @@ +{ + "name": "get-platform-proxy-fixture", + "private": true, + "description": "A test for the getPlatformProxy utility", + "scripts": { + "test": "vitest run", + "test:watch": "vitest", + "type:tests": "tsc --noEmit" + }, + "devDependencies": { + "@cloudflare/workers-tsconfig": "workspace:*", + "@cloudflare/workers-types": "^4.20221111.1", + "wrangler": "workspace:*", + "undici": "^5.28.2" + } +} diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.caches.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.caches.test.ts new file mode 100644 index 000000000000..06e0b7b6fb6e --- /dev/null +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.caches.test.ts @@ -0,0 +1,34 @@ +import { Request, Response } from "undici"; +import { describe, expect, it } from "vitest"; +import { getPlatformProxy } from "./shared"; + +describe("getPlatformProxy - caches", () => { + (["default", "named"] as const).forEach((cacheType) => + it(`correctly obtains a no-op ${cacheType} cache`, async () => { + const { caches, dispose } = await getPlatformProxy(); + try { + const cache = + cacheType === "default" + ? caches.default + : await caches.open("my-cache"); + testNoOpCache(cache); + } finally { + await dispose(); + } + }) + ); +}); + +async function testNoOpCache( + cache: Awaited>["caches"]["default"] +) { + let match = await cache.match("http://0.0.0.0/test"); + expect(match).toBeUndefined(); + + const req = new Request("http://0.0.0.0/test"); + await cache.put(req, new Response("test")); + const resp = await cache.match(req); + expect(resp).toBeUndefined(); + const deleted = await cache.delete(req); + expect(deleted).toBe(false); +} diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.cf.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.cf.test.ts new file mode 100644 index 000000000000..352fe987a023 --- /dev/null +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.cf.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from "vitest"; +import { getPlatformProxy } from "./shared"; + +describe("getPlatformProxy - cf", () => { + it("should provide mock data", async () => { + const { cf, dispose } = await getPlatformProxy(); + try { + expect(cf).toMatchObject({ + colo: "DFW", + city: "Austin", + regionCode: "TX", + }); + } finally { + await dispose(); + } + }); + + it("should match the production runtime cf object", async () => { + const { cf, dispose } = await getPlatformProxy(); + try { + expect(cf.constructor.name).toBe("Object"); + + expect(() => { + cf.city = "test city"; + }).toThrowError( + "Cannot assign to read only property 'city' of object '#'" + ); + expect(cf.city).not.toBe("test city"); + + expect(() => { + cf.newField = "test new field"; + }).toThrowError("Cannot add property newField, object is not extensible"); + expect("newField" in cf).toBe(false); + + expect(cf.botManagement).toMatchObject({ + score: 99, + }); + expect(Object.isFrozen(cf.botManagement)).toBe(true); + } finally { + await dispose(); + } + }); +}); diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.ctx.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.ctx.test.ts new file mode 100644 index 000000000000..731546e560a1 --- /dev/null +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.ctx.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from "vitest"; +import { getPlatformProxy } from "./shared"; + +describe("getPlatformProxy - ctx", () => { + it("should provide a no-op waitUntil method", async () => { + const { ctx, dispose } = await getPlatformProxy(); + try { + let value = 4; + ctx.waitUntil( + new Promise((resolve) => { + value++; + resolve(value); + }) + ); + expect(value).toBe(5); + } finally { + await dispose(); + } + }); + + it("should provide a no-op passThroughOnException method", async () => { + const { ctx, dispose } = await getPlatformProxy(); + try { + expect(ctx.passThroughOnException()).toBe(undefined); + } finally { + await dispose(); + } + }); + + it("should match the production runtime ctx object", async () => { + const { ctx, dispose } = await getPlatformProxy(); + try { + expect(ctx.constructor.name).toBe("ExecutionContext"); + expect(typeof ctx.waitUntil).toBe("function"); + expect(typeof ctx.passThroughOnException).toBe("function"); + + ctx.waitUntil = ((str: string) => `- ${str} -`) as any; + expect(ctx.waitUntil("waitUntil can be overridden" as any)).toBe( + "- waitUntil can be overridden -" + ); + + ctx.passThroughOnException = ((str: string) => `_ ${str} _`) as any; + expect( + (ctx.passThroughOnException as any)( + "passThroughOnException can be overridden" + ) + ).toBe("_ passThroughOnException can be overridden _"); + + (ctx as any).text = "the ExecutionContext can be extended"; + expect((ctx as any).text).toBe("the ExecutionContext can be extended"); + } finally { + await dispose(); + } + }); +}); diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts new file mode 100644 index 000000000000..1f86b6191abe --- /dev/null +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts @@ -0,0 +1,257 @@ +import { readdir } from "fs/promises"; +import path from "path"; +import { + D1Database, + DurableObjectNamespace, + Fetcher, + R2Bucket, +} from "@cloudflare/workers-types"; +import { describe, expect, it } from "vitest"; +import { unstable_dev } from "wrangler"; +import { getPlatformProxy } from "./shared"; +import type { KVNamespace } from "@cloudflare/workers-types"; +import type { UnstableDevWorker } from "wrangler"; + +type Env = { + MY_VAR: string; + MY_VAR_A: string; + MY_JSON_VAR: Object; + MY_DEV_VAR: string; + MY_SERVICE_A: Fetcher; + MY_SERVICE_B: Fetcher; + MY_KV: KVNamespace; + MY_DO_A: DurableObjectNamespace; + MY_DO_B: DurableObjectNamespace; + MY_BUCKET: R2Bucket; + MY_D1: D1Database; +}; + +const wranglerTomlFilePath = path.join(__dirname, "..", "wrangler.toml"); + +describe("getPlatformProxy - bindings", () => { + let devWorkers: UnstableDevWorker[]; + + // Note: we're skipping the service workers and durable object tests + // so there's no need to start separate workers right now, the + // following beforeAll and afterAll should be un-commented when + // we reenable the tests + + // beforeAll(async () => { + // devWorkers = await startWorkers(); + // }); + + // afterAll(async () => { + // await Promise.allSettled(devWorkers.map((i) => i.stop())); + // }); + + describe("var bindings", () => { + it("correctly obtains var bindings from both wrangler.toml and .dev.vars", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; + expect(MY_VAR).toEqual("my-var-value"); + expect(MY_JSON_VAR).toEqual({ + test: true, + }); + expect(MY_DEV_VAR).toEqual("my-dev-var-value"); + } finally { + await dispose(); + } + }); + + it("correctly makes vars from .dev.vars override the ones in wrangler.toml", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_VAR_A } = env; + expect(MY_VAR_A).not.toEqual("my-var-a"); // if this fails, the value was read from wrangler.toml – not .dev.vars + expect(MY_VAR_A).toEqual("my-dev-var-a"); + } finally { + await dispose(); + } + }); + + it("correctly makes vars from .dev.vars not override bindings of the same name from wrangler.toml", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_KV } = env; + expect(MY_KV).not.toEqual("my-dev-kv"); + ["get", "delete", "list", "put", "getWithMetadata"].every( + (methodName) => expect(typeof MY_KV[methodName]).toBe("function") + ); + } finally { + await dispose(); + } + }); + + it("correctly reads a toml from a custom path alongside with its .dev.vars", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: path.join( + __dirname, + "..", + "custom-toml", + "path", + "test-toml" + ), + }); + try { + const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; + expect(MY_VAR).toEqual("my-var-value-from-a-custom-toml"); + expect(MY_JSON_VAR).toEqual({ + test: true, + customToml: true, + }); + expect(MY_DEV_VAR).toEqual("my-dev-var-value-from-a-custom-location"); + } finally { + await dispose(); + } + }); + }); + + it("correctly reads a json config file", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: path.join(__dirname, "..", "wrangler.json"), + }); + try { + const { MY_VAR, MY_JSON_VAR } = env; + expect(MY_VAR).toEqual("my-var-value-from-a-json-config-file"); + expect(MY_JSON_VAR).toEqual({ + test: true, + fromJson: true, + }); + } finally { + await dispose(); + } + }); + + // Note: the following test is skipped due to flakiness caused by the local registry not working reliably + // when we run all our fixtures together (possibly because of race condition issues) + it.skip("provides service bindings to external local workers", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_SERVICE_A, MY_SERVICE_B } = env; + await testServiceBinding(MY_SERVICE_A, "Hello World from hello-worker-a"); + await testServiceBinding(MY_SERVICE_B, "Hello World from hello-worker-b"); + } finally { + await dispose(); + } + }); + + it("correctly obtains functioning KV bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + const { MY_KV } = env; + let numOfKeys = (await MY_KV.list()).keys.length; + expect(numOfKeys).toBe(0); + await MY_KV.put("my-key", "my-value"); + numOfKeys = (await MY_KV.list()).keys.length; + expect(numOfKeys).toBe(1); + const value = await MY_KV.get("my-key"); + expect(value).toBe("my-value"); + await dispose(); + }); + + // Note: the following test is skipped due to flakiness caused by the local registry not working reliably + // when we run all our fixtures together (possibly because of race condition issues) + it.skip("correctly obtains functioning DO bindings (provided by external local workers)", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_DO_A, MY_DO_B } = env; + await testDoBinding(MY_DO_A, "Hello from DurableObject A"); + await testDoBinding(MY_DO_B, "Hello from DurableObject B"); + } finally { + await dispose(); + } + }); + + it("correctly obtains functioning R2 bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_BUCKET } = env; + let numOfObjects = (await MY_BUCKET.list()).objects.length; + expect(numOfObjects).toBe(0); + await MY_BUCKET.put("my-object", "my-value"); + numOfObjects = (await MY_BUCKET.list()).objects.length; + expect(numOfObjects).toBe(1); + const value = await MY_BUCKET.get("my-object"); + expect(await value?.text()).toBe("my-value"); + } finally { + await dispose(); + } + }); + + it("correctly obtains functioning D1 bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_D1 } = env; + await MY_D1.exec( + `CREATE TABLE IF NOT EXISTS users ( id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL )` + ); + const stmt = MY_D1.prepare("insert into users (name) values (?1)"); + await MY_D1.batch([ + stmt.bind("userA"), + stmt.bind("userB"), + stmt.bind("userC"), + ]); + const { results } = await MY_D1.prepare( + "SELECT name FROM users LIMIT 5" + ).all(); + expect(results).toEqual([ + { name: "userA" }, + { name: "userB" }, + { name: "userC" }, + ]); + } finally { + await dispose(); + } + }); +}); + +/** + * Starts all the workers present in the `workers` directory using `unstable_dev` + * + * @returns the workers' UnstableDevWorker instances + */ +async function startWorkers(): Promise { + const workersDirPath = path.join(__dirname, "..", "workers"); + const workers = await readdir(workersDirPath); + return await Promise.all( + workers.map((workerName) => { + const workerPath = path.join(workersDirPath, workerName); + return unstable_dev(path.join(workerPath, "index.ts"), { + config: path.join(workerPath, "wrangler.toml"), + }); + }) + ); +} + +async function testServiceBinding(binding: Fetcher, expectedResponse: string) { + const resp = await binding.fetch("http://0.0.0.0"); + const respText = await resp.text(); + expect(respText).toBe(expectedResponse); +} + +async function testDoBinding( + binding: DurableObjectNamespace, + expectedResponse: string +) { + const durableObjectId = binding.idFromName("__my-do__"); + const doStub = binding.get(durableObjectId); + const doResp = await doStub.fetch("http://0.0.0.0"); + const doRespText = await doResp.text(); + expect(doRespText).toBe(expectedResponse); +} diff --git a/fixtures/get-platform-proxy/tests/shared.ts b/fixtures/get-platform-proxy/tests/shared.ts new file mode 100644 index 000000000000..11156437eac5 --- /dev/null +++ b/fixtures/get-platform-proxy/tests/shared.ts @@ -0,0 +1,13 @@ +import { getPlatformProxy as originalGetPlatformProxy } from "wrangler"; +import type { GetPlatformProxyOptions } from "wrangler"; + +// Here we wrap the actual original getPlatformProxy function and disable its persistance, this is to make sure +// that we don't implement any persistance during these tests (which would add unnecessary extra complexity) +export function getPlatformProxy( + options: Omit = {} +): ReturnType> { + return originalGetPlatformProxy({ + ...options, + persist: false, + }); +} diff --git a/fixtures/get-platform-proxy/tsconfig.json b/fixtures/get-platform-proxy/tsconfig.json new file mode 100644 index 000000000000..b5bd7afe3b1f --- /dev/null +++ b/fixtures/get-platform-proxy/tsconfig.json @@ -0,0 +1,16 @@ +{ + "include": [ + "workers/hello-worker-a", + "module-worker-b", + "service-worker-a", + "module-worker-c", + "module-worker-d", + "pages-functions-app" + ], + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "lib": ["ES2020"], + "types": ["@cloudflare/workers-types"] + } +} diff --git a/fixtures/get-platform-proxy/vitest.config.ts b/fixtures/get-platform-proxy/vitest.config.ts new file mode 100644 index 000000000000..74c6ea85d13a --- /dev/null +++ b/fixtures/get-platform-proxy/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + testTimeout: 25_000, + hookTimeout: 25_000, + teardownTimeout: 25_000, + useAtomics: true, + }, +}); diff --git a/fixtures/get-platform-proxy/workers/do-worker-a/index.ts b/fixtures/get-platform-proxy/workers/do-worker-a/index.ts new file mode 100644 index 000000000000..5dcc1b07c161 --- /dev/null +++ b/fixtures/get-platform-proxy/workers/do-worker-a/index.ts @@ -0,0 +1,11 @@ +export default { + async fetch(): Promise { + return new Response("Hello World from do-worker-a"); + }, +}; + +export class DurableObjectClass { + async fetch() { + return new Response("Hello from DurableObject A"); + } +} diff --git a/fixtures/get-platform-proxy/workers/do-worker-a/wrangler.toml b/fixtures/get-platform-proxy/workers/do-worker-a/wrangler.toml new file mode 100644 index 000000000000..7dd727a5609d --- /dev/null +++ b/fixtures/get-platform-proxy/workers/do-worker-a/wrangler.toml @@ -0,0 +1,5 @@ +name = "do-worker-a" + +[[durable_objects.bindings]] +name = "MY_DO" +class_name = "DurableObjectClass" diff --git a/fixtures/get-platform-proxy/workers/do-worker-b/index.ts b/fixtures/get-platform-proxy/workers/do-worker-b/index.ts new file mode 100644 index 000000000000..695a3eaafd31 --- /dev/null +++ b/fixtures/get-platform-proxy/workers/do-worker-b/index.ts @@ -0,0 +1,11 @@ +export default { + async fetch(): Promise { + return new Response("Hello World from do-worker-a"); + }, +}; + +export class DurableObjectClass { + async fetch() { + return new Response("Hello from DurableObject B"); + } +} diff --git a/fixtures/get-platform-proxy/workers/do-worker-b/wrangler.toml b/fixtures/get-platform-proxy/workers/do-worker-b/wrangler.toml new file mode 100644 index 000000000000..efbd1e3fcf48 --- /dev/null +++ b/fixtures/get-platform-proxy/workers/do-worker-b/wrangler.toml @@ -0,0 +1,5 @@ +name = "do-worker-b" + +[[durable_objects.bindings]] +name = "MY_DO" +class_name = "DurableObjectClass" diff --git a/fixtures/get-platform-proxy/workers/hello-worker-a/index.ts b/fixtures/get-platform-proxy/workers/hello-worker-a/index.ts new file mode 100644 index 000000000000..882ae1188289 --- /dev/null +++ b/fixtures/get-platform-proxy/workers/hello-worker-a/index.ts @@ -0,0 +1,5 @@ +export default { + fetch() { + return new Response("Hello World from hello-worker-a"); + }, +}; diff --git a/fixtures/get-platform-proxy/workers/hello-worker-a/wrangler.toml b/fixtures/get-platform-proxy/workers/hello-worker-a/wrangler.toml new file mode 100644 index 000000000000..5e45dde6c83a --- /dev/null +++ b/fixtures/get-platform-proxy/workers/hello-worker-a/wrangler.toml @@ -0,0 +1 @@ +name = "hello-worker-a" diff --git a/fixtures/get-platform-proxy/workers/hello-worker-b/index.ts b/fixtures/get-platform-proxy/workers/hello-worker-b/index.ts new file mode 100644 index 000000000000..ecb5dc60ab93 --- /dev/null +++ b/fixtures/get-platform-proxy/workers/hello-worker-b/index.ts @@ -0,0 +1,5 @@ +export default { + fetch() { + return new Response("Hello World from hello-worker-b"); + }, +}; diff --git a/fixtures/get-platform-proxy/workers/hello-worker-b/wrangler.toml b/fixtures/get-platform-proxy/workers/hello-worker-b/wrangler.toml new file mode 100644 index 000000000000..bcc46b2ccf0c --- /dev/null +++ b/fixtures/get-platform-proxy/workers/hello-worker-b/wrangler.toml @@ -0,0 +1 @@ +name = "hello-worker-b" diff --git a/fixtures/get-platform-proxy/wrangler.json b/fixtures/get-platform-proxy/wrangler.json new file mode 100644 index 000000000000..092b75111fa8 --- /dev/null +++ b/fixtures/get-platform-proxy/wrangler.json @@ -0,0 +1,11 @@ +{ + "name": "get-bindings-proxy-fixture", + "main": "src/index.ts", + "vars": { + "MY_VAR": "my-var-value-from-a-json-config-file", + "MY_JSON_VAR": { + "test": true, + "fromJson": true + } + } +} diff --git a/fixtures/get-platform-proxy/wrangler.toml b/fixtures/get-platform-proxy/wrangler.toml new file mode 100644 index 000000000000..73ea9c16e16a --- /dev/null +++ b/fixtures/get-platform-proxy/wrangler.toml @@ -0,0 +1,32 @@ +name = "get-bindings-proxy-fixture" +main = "src/index.ts" +compatibility_date = "2023-11-21" + +services = [ + { binding = "MY_SERVICE_A", service = "hello-worker-a" }, + { binding = "MY_SERVICE_B", service = "hello-worker-b" } +] + +[vars] +MY_VAR = "my-var-value" +MY_VAR_A = "my-var-a" +MY_JSON_VAR = { test = true } + +[[kv_namespaces]] +binding = "MY_KV" +id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +[[r2_buckets]] +binding = "MY_BUCKET" +bucket_name = "my-bucket" + +[durable_objects] +bindings = [ + { name = "MY_DO_A", script_name = "do-worker-a", class_name = "DurableObjectClass" }, + { name = "MY_DO_B", script_name = "do-worker-b", class_name = "DurableObjectClass" } +] + +[[d1_databases]] +binding = "MY_D1" +database_name = "test-db" +database_id = "000000000-0000-0000-0000-000000000000" diff --git a/packages/wrangler/src/api/integrations/deprecated/getBindingsProxy.ts b/packages/wrangler/src/api/integrations/deprecated/getBindingsProxy.ts new file mode 100644 index 000000000000..faedb0a72fcd --- /dev/null +++ b/packages/wrangler/src/api/integrations/deprecated/getBindingsProxy.ts @@ -0,0 +1,45 @@ +import { getPlatformProxy } from "../platform/index"; +import type { GetPlatformProxyOptions, PlatformProxy } from "../platform/index"; +import type { IncomingRequestCfProperties } from "@cloudflare/workers-types/experimental"; + +/** Options for the `getBindingsProxy` utility */ +export type GetBindingsProxyOptions = GetPlatformProxyOptions; + +/** + * Result of the `getBindingsProxy` utility + */ +export type BindingsProxy< + Bindings = Record, + CfProperties extends Record = IncomingRequestCfProperties +> = Omit, "env"> & { + /** + * Object containing the various proxies + */ + bindings: Bindings; +}; + +/** + * By reading from a `wrangler.toml` file this function generates proxy binding objects that can be + * used to simulate the interaction with bindings during local development in a Node.js environment + * + * @deprecated use `getPlatformProxy` instead + * + * @param options The various options that can tweak this function's behavior + * @returns An Object containing the generated proxies alongside other related utilities + */ +export async function getBindingsProxy< + Bindings = Record, + CfProperties extends Record = IncomingRequestCfProperties +>( + options: GetBindingsProxyOptions = {} +): Promise> { + const { env, ...restOfPlatformProxy } = await getPlatformProxy< + Bindings, + CfProperties + >(options); + + return { + bindings: env, + ...restOfPlatformProxy, + }; +} diff --git a/packages/wrangler/src/api/integrations/deprecated/index.ts b/packages/wrangler/src/api/integrations/deprecated/index.ts new file mode 100644 index 000000000000..c5bf1a36e6c5 --- /dev/null +++ b/packages/wrangler/src/api/integrations/deprecated/index.ts @@ -0,0 +1 @@ +export * from "./getBindingsProxy"; diff --git a/packages/wrangler/src/api/integrations/index.ts b/packages/wrangler/src/api/integrations/index.ts index 9e592d79d6b8..7ee4de00d0d9 100644 --- a/packages/wrangler/src/api/integrations/index.ts +++ b/packages/wrangler/src/api/integrations/index.ts @@ -1 +1,2 @@ -export * from "./bindings"; +export * from "./platform"; +export * from "./deprecated"; diff --git a/packages/wrangler/src/api/integrations/bindings/caches.ts b/packages/wrangler/src/api/integrations/platform/caches.ts similarity index 98% rename from packages/wrangler/src/api/integrations/bindings/caches.ts rename to packages/wrangler/src/api/integrations/platform/caches.ts index b6a5858285c0..91ef58ef54ec 100644 --- a/packages/wrangler/src/api/integrations/bindings/caches.ts +++ b/packages/wrangler/src/api/integrations/platform/caches.ts @@ -8,7 +8,7 @@ * * We are not using miniflare's implementation because that would require the user to provide * miniflare-specific Request objects and they would receive back miniflare-specific Response - * objects, this (in particular the Request part) is not really suitable for `getBindingsProxy` + * objects, this (in particular the Request part) is not really suitable for `getPlatformProxy` * as people would ideally interact with their bindings in a very production-like manner and * requiring them to deal with miniflare-specific classes defeats a bit the purpose of the utility. * diff --git a/packages/wrangler/src/api/integrations/bindings/executionContext.ts b/packages/wrangler/src/api/integrations/platform/executionContext.ts similarity index 100% rename from packages/wrangler/src/api/integrations/bindings/executionContext.ts rename to packages/wrangler/src/api/integrations/platform/executionContext.ts diff --git a/packages/wrangler/src/api/integrations/bindings/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts similarity index 87% rename from packages/wrangler/src/api/integrations/bindings/index.ts rename to packages/wrangler/src/api/integrations/platform/index.ts index aefabfa24906..3dec29ce5712 100644 --- a/packages/wrangler/src/api/integrations/bindings/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -12,9 +12,9 @@ import type { IncomingRequestCfProperties } from "@cloudflare/workers-types/expe import type { MiniflareOptions } from "miniflare"; /** - * Options for the `getBindingsProxy` utility + * Options for the `getPlatformProxy` utility */ -export type GetBindingsProxyOptions = { +export type GetPlatformProxyOptions = { /** * The path to the config object to use (default `wrangler.toml`) */ @@ -35,16 +35,16 @@ export type GetBindingsProxyOptions = { }; /** - * Result of the `getBindingsProxy` utility + * Result of the `getPlatformProxy` utility */ -export type BindingsProxy< - Bindings = Record, +export type PlatformProxy< + Env = Record, CfProperties extends Record = IncomingRequestCfProperties > = { /** - * Object containing the various proxies + * Environment object containing the various Cloudflare bindings */ - bindings: Bindings; + env: Env; /** * Mock of the context object that Workers received in their request handler, all the object's methods are no-op */ @@ -64,18 +64,19 @@ export type BindingsProxy< }; /** - * By reading from a `wrangler.toml` file this function generates proxy binding objects that can be - * used to simulate the interaction with bindings during local development in a Node.js environment + * By reading from a `wrangler.toml` file this function generates proxy objects that can be + * used to simulate the interaction with the Cloudflare platform during local development + * in a Node.js environment * * @param options The various options that can tweak this function's behavior * @returns An Object containing the generated proxies alongside other related utilities */ -export async function getBindingsProxy< - Bindings = Record, +export async function getPlatformProxy< + Env = Record, CfProperties extends Record = IncomingRequestCfProperties >( - options: GetBindingsProxyOptions = {} -): Promise> { + options: GetPlatformProxyOptions = {} +): Promise> { const rawConfig = readConfig(options.configPath, { experimentalJsonConfig: options.experimentalJsonConfig, }); @@ -95,7 +96,7 @@ export async function getBindingsProxy< ...(miniflareOptions as Record), }); - const bindings: Bindings = await mf.getBindings(); + const bindings: Env = await mf.getBindings(); const vars = getVarsForDev(rawConfig, env); @@ -103,7 +104,7 @@ export async function getBindingsProxy< deepFreeze(cf); return { - bindings: { + env: { ...vars, ...bindings, }, @@ -117,7 +118,7 @@ export async function getBindingsProxy< async function getMiniflareOptionsFromConfig( rawConfig: Config, env: string | undefined, - options: GetBindingsProxyOptions + options: GetPlatformProxyOptions ): Promise> { const bindings = getBindings(rawConfig, env, true, {}); @@ -165,7 +166,7 @@ async function getMiniflareOptionsFromConfig( * @returns an object containing the properties to pass to miniflare */ function getMiniflarePersistOptions( - persist: GetBindingsProxyOptions["persist"] + persist: GetPlatformProxyOptions["persist"] ): Pick< MiniflareOptions, "kvPersist" | "durableObjectsPersist" | "r2Persist" | "d1Persist" diff --git a/packages/wrangler/src/api/integrations/bindings/services.ts b/packages/wrangler/src/api/integrations/platform/services.ts similarity index 100% rename from packages/wrangler/src/api/integrations/bindings/services.ts rename to packages/wrangler/src/api/integrations/platform/services.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e871f1e92399..f301c0ca20fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -216,6 +216,21 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/get-platform-proxy: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:* + version: link:../../packages/workers-tsconfig + '@cloudflare/workers-types': + specifier: ^4.20221111.1 + version: 4.20231218.0 + undici: + specifier: ^5.28.2 + version: 5.28.2 + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + fixtures/import-wasm-example: dependencies: import-wasm-static: