From 42c2d235e0b0506575385b43dda731ff1bcaa995 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 00:27:09 +0100 Subject: [PATCH 01/15] add remote bindings support to `getPlatformProxy` --- .changeset/better-sheep-reply.md | 5 ++ .../index.test.js | 85 +++++++++++++++++++ .../package.json | 19 +++++ .../remote-worker.js | 7 ++ .../src/api/integrations/platform/index.ts | 54 ++++++++---- .../startDevWorker/LocalRuntimeController.ts | 3 +- .../MultiworkerRuntimeController.ts | 3 +- packages/wrangler/src/dev/miniflare.ts | 15 ++-- pnpm-lock.yaml | 12 +++ 9 files changed, 174 insertions(+), 29 deletions(-) create mode 100644 .changeset/better-sheep-reply.md create mode 100644 fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js create mode 100644 fixtures/get-platform-proxy-remote-bindings-node-test/package.json create mode 100644 fixtures/get-platform-proxy-remote-bindings-node-test/remote-worker.js diff --git a/.changeset/better-sheep-reply.md b/.changeset/better-sheep-reply.md new file mode 100644 index 000000000000..031932bcf687 --- /dev/null +++ b/.changeset/better-sheep-reply.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +add remote bindings support to `getPlatformProxy` diff --git a/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js new file mode 100644 index 000000000000..5585eb217960 --- /dev/null +++ b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js @@ -0,0 +1,85 @@ +import { execSync } from "child_process"; +import { randomUUID } from "crypto"; +import assert from "node:assert"; +import { mkdirSync, rmSync, writeFileSync } from "node:fs"; +import test, { after, before, describe } from "node:test"; +import { getPlatformProxy } from "wrangler"; + +if ( + !process.env.TEST_CLOUDFLARE_API_TOKEN || + !process.env.TEST_CLOUDFLARE_ACCOUNT_ID +) { + console.warn("No credentials provided, skipping test..."); + process.exit(0); +} + +const env = { + ...process.env, + CLOUDFLARE_API_TOKEN: process.env.TEST_CLOUDFLARE_API_TOKEN, + CLOUDFLARE_ACCOUNT_ID: process.env.TEST_CLOUDFLARE_ACCOUNT_ID, +}; + +describe("getPlatformProxy remote-bindings", () => { + const remoteWorkerName = `get-platform-proxy-remote-worker-test-${randomUUID().split("-")[0]}`; + + before(async () => { + const deployOut = execSync( + `pnpm dlx wrangler deploy remote-worker.js --name ${remoteWorkerName} --compatibility-date 2025-06-19`, + { + stdio: "pipe", + env, + } + ); + + if ( + !new RegExp(`Deployed\\s+${remoteWorkerName}\\b`).test(`${deployOut}`) + ) { + throw new Error(`Failed to deploy ${remoteWorkerName}`); + } + + rmSync("./.tmp", { recursive: true, force: true }); + + mkdirSync("./.tmp"); + + writeFileSync( + "./.tmp/wrangler.json", + JSON.stringify( + { + name: "get-platform-proxy-fixture-test", + compatibility_date: "2025-06-01", + services: [ + { + binding: "MY_WORKER", + service: remoteWorkerName, + experimental_remote: true, + }, + ], + }, + undefined, + 2 + ), + "utf8" + ); + }); + + test("getPlatformProxy works with remote bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: "./.tmp/wrangler.json", + experimental: { remoteBindings: true }, + }); + + try { + assert.strictEqual( + await (await env.MY_WORKER.fetch("http://example.com")).text(), + "Hello from a remote Worker part of the getPlatformProxy remote bindings fixture!" + ); + } finally { + await dispose(); + } + }); + + after(async () => { + execSync(`pnpm dlx wrangler delete --name ${remoteWorkerName}`, { env }); + rmSync("./.tmp", { recursive: true, force: true }); + }); +}); diff --git a/fixtures/get-platform-proxy-remote-bindings-node-test/package.json b/fixtures/get-platform-proxy-remote-bindings-node-test/package.json new file mode 100644 index 000000000000..02f5ef743b83 --- /dev/null +++ b/fixtures/get-platform-proxy-remote-bindings-node-test/package.json @@ -0,0 +1,19 @@ +{ + "name": "@fixture/get-platform-proxy-remote-bindings-node-test", + "private": true, + "description": "", + "license": "ISC", + "author": "", + "type": "module", + "scripts": { + "test:ci": "node --test" + }, + "devDependencies": { + "@cloudflare/workers-tsconfig": "workspace:*", + "@cloudflare/workers-types": "^4.20250617.0", + "wrangler": "workspace:*" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/fixtures/get-platform-proxy-remote-bindings-node-test/remote-worker.js b/fixtures/get-platform-proxy-remote-bindings-node-test/remote-worker.js new file mode 100644 index 000000000000..a88e54f0c7e0 --- /dev/null +++ b/fixtures/get-platform-proxy-remote-bindings-node-test/remote-worker.js @@ -0,0 +1,7 @@ +export default { + fetch() { + return new Response( + "Hello from a remote Worker part of the getPlatformProxy remote bindings fixture!" + ); + }, +}; diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index bce26b97bbc2..dc57b4529342 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -11,15 +11,16 @@ import { buildMiniflareBindingOptions, buildSitesOptions, } from "../../../dev/miniflare"; -import { run } from "../../../experimental-flags"; import { logger } from "../../../logger"; import { getSiteAssetPaths } from "../../../sites"; import { dedent } from "../../../utils/dedent"; +import { maybeStartOrUpdateRemoteProxySession } from "../../remoteBindings"; import { CacheStorage } from "./caches"; import { ExecutionContext } from "./executionContext"; import { getServiceBindings } from "./services"; import type { AssetsOptions } from "../../../assets"; import type { Config, RawConfig, RawEnvironment } from "../../../config"; +import type { RemoteProxySession } from "../../remoteBindings"; import type { IncomingRequestCfProperties } from "@cloudflare/workers-types/experimental"; import type { MiniflareOptions, @@ -58,6 +59,13 @@ export type GetPlatformProxyOptions = { * If `false` is specified no data is persisted on the filesystem. */ persist?: boolean | { path: string }; + /** + * Experimental flags (note: these can change at any time and are not version-controlled use at your own risk) + */ + experimental?: { + /** whether access to remove bindings should be enabled */ + remoteBindings?: boolean; + }; }; /** @@ -103,6 +111,8 @@ export async function getPlatformProxy< >( options: GetPlatformProxyOptions = {} ): Promise> { + const experimentalRemoteBindings = !!options.experimental?.remoteBindings; + const env = options.environment; const rawConfig = readConfig({ @@ -110,20 +120,28 @@ export async function getPlatformProxy< env, }); - const miniflareOptions = await run( - { - MULTIWORKER: false, - RESOURCES_PROVISION: false, - // TODO: when possible remote bindings should be made available for getPlatformProxy - REMOTE_BINDINGS: false, - }, - () => getMiniflareOptionsFromConfig(rawConfig, env, options) + let remoteProxySession: RemoteProxySession | undefined = undefined; + if (experimentalRemoteBindings && rawConfig.configPath) { + const a = await maybeStartOrUpdateRemoteProxySession( + rawConfig.configPath, + null + ); + remoteProxySession = a?.session; + } + + const miniflareOptions = await getMiniflareOptionsFromConfig( + rawConfig, + env, + options, + remoteProxySession?.remoteProxyConnectionString ); const mf = new Miniflare({ script: "", + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore modules: true, - ...(miniflareOptions as Record), + ...miniflareOptions, }); const bindings: Env = await mf.getBindings(); @@ -136,7 +154,10 @@ export async function getPlatformProxy< cf: cf as CfProperties, ctx: new ExecutionContext(), caches: new CacheStorage(), - dispose: () => mf.dispose(), + dispose: async () => { + await remoteProxySession?.dispose(); + await mf.dispose(); + }, }; } @@ -144,7 +165,8 @@ export async function getPlatformProxy< async function getMiniflareOptionsFromConfig( rawConfig: Config, env: string | undefined, - options: GetPlatformProxyOptions + options: GetPlatformProxyOptions, + remoteProxyConnectionString?: RemoteProxyConnectionString ): Promise> { const bindings = getBindings(rawConfig, env, true, {}); @@ -183,8 +205,7 @@ async function getMiniflareOptionsFromConfig( containers: undefined, containerBuildId: undefined, }, - undefined, - false + remoteProxyConnectionString ); const defaultPersistRoot = getMiniflarePersistRoot(options.persist); @@ -320,8 +341,9 @@ export function unstable_getMiniflareWorkerOptions( containers: undefined, containerBuildId: undefined, }, - options?.remoteProxyConnectionString, - options?.remoteBindingsEnabled ?? false + options?.remoteBindingsEnabled + ? options?.remoteProxyConnectionString + : undefined ); // This function is currently only exported for the Workers Vitest pool. diff --git a/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts b/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts index 949749f504d5..d0db3c30ecef 100644 --- a/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts +++ b/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts @@ -234,8 +234,7 @@ export class LocalRuntimeController extends RuntimeController { this.#log, configBundle, this.#proxyToUserWorkerAuthenticationSecret, - this.#remoteProxySessionData?.session?.remoteProxyConnectionString, - !!experimentalRemoteBindings + this.#remoteProxySessionData?.session?.remoteProxyConnectionString ); options.liveReload = false; // TODO: set in buildMiniflareOptions once old code path is removed if (this.#mf === undefined) { diff --git a/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts b/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts index 5320df1c2d79..7bc8c6c5b9aa 100644 --- a/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts +++ b/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts @@ -134,8 +134,7 @@ export class MultiworkerRuntimeController extends LocalRuntimeController { await convertToConfigBundle(data), this.#proxyToUserWorkerAuthenticationSecret, this.#remoteProxySessionsData.get(data.config.name)?.session - ?.remoteProxyConnectionString, - !!experimentalRemoteBindings + ?.remoteProxyConnectionString ); this.#options.set(data.config.name, { diff --git a/packages/wrangler/src/dev/miniflare.ts b/packages/wrangler/src/dev/miniflare.ts index 22b96414dcc7..172892ed6ef1 100644 --- a/packages/wrangler/src/dev/miniflare.ts +++ b/packages/wrangler/src/dev/miniflare.ts @@ -535,13 +535,14 @@ type MiniflareBindingsConfig = Pick< // each plugin options schema and use those export function buildMiniflareBindingOptions( config: MiniflareBindingsConfig, - remoteProxyConnectionString: RemoteProxyConnectionString | undefined, - remoteBindingsEnabled: boolean + remoteProxyConnectionString: RemoteProxyConnectionString | undefined ): { bindingOptions: WorkerOptionsBindings; internalObjects: CfDurableObject[]; externalWorkers: WorkerOptions[]; } { + const remoteBindingsEnabled = !!remoteProxyConnectionString; + const bindings = config.bindings; // Setup blob and module bindings @@ -1289,8 +1290,7 @@ export async function buildMiniflareOptions( log: Log, config: Omit, proxyToUserWorkerAuthenticationSecret: UUID, - remoteProxyConnectionString: RemoteProxyConnectionString | undefined, - remoteBindingsEnabled: boolean + remoteProxyConnectionString: RemoteProxyConnectionString | undefined ): Promise<{ options: Options; internalObjects: CfDurableObject[]; @@ -1305,6 +1305,7 @@ export async function buildMiniflareOptions( } } + const remoteBindingsEnabled = !!remoteProxyConnectionString; if (!remoteBindingsEnabled) { if (config.bindings.ai) { if (!didWarnAiAccountUsage) { @@ -1339,11 +1340,7 @@ export async function buildMiniflareOptions( const { sourceOptions, entrypointNames } = await buildSourceOptions(config); const { bindingOptions, internalObjects, externalWorkers } = - buildMiniflareBindingOptions( - config, - remoteProxyConnectionString, - remoteBindingsEnabled - ); + buildMiniflareBindingOptions(config, remoteProxyConnectionString); const sitesOptions = buildSitesOptions(config); const defaultPersistRoot = getDefaultPersistRoot(config.localPersistencePath); const assetOptions = buildAssetOptions(config); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98cf3a79e003..87d83266b633 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -329,6 +329,18 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/get-platform-proxy-remote-bindings-node-test: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:* + version: link:../../packages/workers-tsconfig + '@cloudflare/workers-types': + specifier: ^4.20250617.0 + version: 4.20250617.0 + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + fixtures/import-npm: {} fixtures/import-wasm-example: From 10e7f6602fd0b6a25ef21bbd9afb14c4674e6d9f Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 01:02:44 +0100 Subject: [PATCH 02/15] fixup! add remote bindings support to `getPlatformProxy` put back explicit `remoteBindingsEnabled` --- .../src/api/integrations/platform/index.ts | 14 ++++++++------ .../api/startDevWorker/LocalRuntimeController.ts | 3 ++- .../MultiworkerRuntimeController.ts | 3 ++- packages/wrangler/src/dev/miniflare.ts | 15 +++++++++------ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index dc57b4529342..a9a455347e92 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -133,7 +133,8 @@ export async function getPlatformProxy< rawConfig, env, options, - remoteProxySession?.remoteProxyConnectionString + remoteProxySession?.remoteProxyConnectionString, + experimentalRemoteBindings ); const mf = new Miniflare({ @@ -166,7 +167,8 @@ async function getMiniflareOptionsFromConfig( rawConfig: Config, env: string | undefined, options: GetPlatformProxyOptions, - remoteProxyConnectionString?: RemoteProxyConnectionString + remoteProxyConnectionString?: RemoteProxyConnectionString, + remoteBindingsEnabled = false ): Promise> { const bindings = getBindings(rawConfig, env, true, {}); @@ -205,7 +207,8 @@ async function getMiniflareOptionsFromConfig( containers: undefined, containerBuildId: undefined, }, - remoteProxyConnectionString + remoteProxyConnectionString, + remoteBindingsEnabled ); const defaultPersistRoot = getMiniflarePersistRoot(options.persist); @@ -341,9 +344,8 @@ export function unstable_getMiniflareWorkerOptions( containers: undefined, containerBuildId: undefined, }, - options?.remoteBindingsEnabled - ? options?.remoteProxyConnectionString - : undefined + options?.remoteProxyConnectionString, + options?.remoteBindingsEnabled ?? false ); // This function is currently only exported for the Workers Vitest pool. diff --git a/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts b/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts index d0db3c30ecef..949749f504d5 100644 --- a/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts +++ b/packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts @@ -234,7 +234,8 @@ export class LocalRuntimeController extends RuntimeController { this.#log, configBundle, this.#proxyToUserWorkerAuthenticationSecret, - this.#remoteProxySessionData?.session?.remoteProxyConnectionString + this.#remoteProxySessionData?.session?.remoteProxyConnectionString, + !!experimentalRemoteBindings ); options.liveReload = false; // TODO: set in buildMiniflareOptions once old code path is removed if (this.#mf === undefined) { diff --git a/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts b/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts index 7bc8c6c5b9aa..5320df1c2d79 100644 --- a/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts +++ b/packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts @@ -134,7 +134,8 @@ export class MultiworkerRuntimeController extends LocalRuntimeController { await convertToConfigBundle(data), this.#proxyToUserWorkerAuthenticationSecret, this.#remoteProxySessionsData.get(data.config.name)?.session - ?.remoteProxyConnectionString + ?.remoteProxyConnectionString, + !!experimentalRemoteBindings ); this.#options.set(data.config.name, { diff --git a/packages/wrangler/src/dev/miniflare.ts b/packages/wrangler/src/dev/miniflare.ts index 172892ed6ef1..22b96414dcc7 100644 --- a/packages/wrangler/src/dev/miniflare.ts +++ b/packages/wrangler/src/dev/miniflare.ts @@ -535,14 +535,13 @@ type MiniflareBindingsConfig = Pick< // each plugin options schema and use those export function buildMiniflareBindingOptions( config: MiniflareBindingsConfig, - remoteProxyConnectionString: RemoteProxyConnectionString | undefined + remoteProxyConnectionString: RemoteProxyConnectionString | undefined, + remoteBindingsEnabled: boolean ): { bindingOptions: WorkerOptionsBindings; internalObjects: CfDurableObject[]; externalWorkers: WorkerOptions[]; } { - const remoteBindingsEnabled = !!remoteProxyConnectionString; - const bindings = config.bindings; // Setup blob and module bindings @@ -1290,7 +1289,8 @@ export async function buildMiniflareOptions( log: Log, config: Omit, proxyToUserWorkerAuthenticationSecret: UUID, - remoteProxyConnectionString: RemoteProxyConnectionString | undefined + remoteProxyConnectionString: RemoteProxyConnectionString | undefined, + remoteBindingsEnabled: boolean ): Promise<{ options: Options; internalObjects: CfDurableObject[]; @@ -1305,7 +1305,6 @@ export async function buildMiniflareOptions( } } - const remoteBindingsEnabled = !!remoteProxyConnectionString; if (!remoteBindingsEnabled) { if (config.bindings.ai) { if (!didWarnAiAccountUsage) { @@ -1340,7 +1339,11 @@ export async function buildMiniflareOptions( const { sourceOptions, entrypointNames } = await buildSourceOptions(config); const { bindingOptions, internalObjects, externalWorkers } = - buildMiniflareBindingOptions(config, remoteProxyConnectionString); + buildMiniflareBindingOptions( + config, + remoteProxyConnectionString, + remoteBindingsEnabled + ); const sitesOptions = buildSitesOptions(config); const defaultPersistRoot = getDefaultPersistRoot(config.localPersistencePath); const assetOptions = buildAssetOptions(config); From d3bcc9015e084f1528cd6442c7f852bd913a04a8 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 01:04:42 +0100 Subject: [PATCH 03/15] fixup! add remote bindings support to `getPlatformProxy` replace @ts-ignore to the more appropriate @ts-expect-error --- packages/wrangler/src/api/integrations/platform/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index a9a455347e92..a22b2255ba6f 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -139,8 +139,7 @@ export async function getPlatformProxy< const mf = new Miniflare({ script: "", - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore + // @ts-expect-error TS doesn't like the spreading of miniflareConfig modules: true, ...miniflareOptions, }); From d9f0a7f10c68c2b62bf8f04215a3527bf66bcde3 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 01:06:43 +0100 Subject: [PATCH 04/15] fixup! add remote bindings support to `getPlatformProxy` replace variable `a` --- packages/wrangler/src/api/integrations/platform/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index a22b2255ba6f..420cbdb9d3a1 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -122,11 +122,9 @@ export async function getPlatformProxy< let remoteProxySession: RemoteProxySession | undefined = undefined; if (experimentalRemoteBindings && rawConfig.configPath) { - const a = await maybeStartOrUpdateRemoteProxySession( - rawConfig.configPath, - null - ); - remoteProxySession = a?.session; + const maybeRemoteProxySessionWrap = + await maybeStartOrUpdateRemoteProxySession(rawConfig.configPath, null); + remoteProxySession = maybeRemoteProxySessionWrap?.session; } const miniflareOptions = await getMiniflareOptionsFromConfig( From b44fad4cbb8f2c82570904d8763975d9f3090467 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 01:11:35 +0100 Subject: [PATCH 05/15] fixup! add remote bindings support to `getPlatformProxy` make `preExistingRemoteProxySessionData` param optional --- packages/wrangler/src/api/integrations/platform/index.ts | 2 +- packages/wrangler/src/api/remoteBindings/index.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 420cbdb9d3a1..9ca75e083863 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -123,7 +123,7 @@ export async function getPlatformProxy< let remoteProxySession: RemoteProxySession | undefined = undefined; if (experimentalRemoteBindings && rawConfig.configPath) { const maybeRemoteProxySessionWrap = - await maybeStartOrUpdateRemoteProxySession(rawConfig.configPath, null); + await maybeStartOrUpdateRemoteProxySession(rawConfig.configPath); remoteProxySession = maybeRemoteProxySessionWrap?.session; } diff --git a/packages/wrangler/src/api/remoteBindings/index.ts b/packages/wrangler/src/api/remoteBindings/index.ts index 564ff1c4472a..9fa9b2748fbf 100644 --- a/packages/wrangler/src/api/remoteBindings/index.ts +++ b/packages/wrangler/src/api/remoteBindings/index.ts @@ -106,7 +106,8 @@ export function pickRemoteBindings( * * @param configPathOrWorkerConfig either a file path to a wrangler configuration file or an object containing the name of * the target worker alongside its bindings. - * @param preExistingRemoteProxySessionData the data of a pre-existing remote proxy session if there was one null otherwise + * @param preExistingRemoteProxySessionData the optional data of a pre-existing remote proxy session if there was one, this + * argument can be omitted or set to null if there is no pre-existing remote proxy session * @returns null if no existing remote proxy session was provided and one should not be created (because the worker is not * defining any remote bindings), the data associated to the created/updated remote proxy session otherwise. */ @@ -117,7 +118,7 @@ export async function maybeStartOrUpdateRemoteProxySession( name?: string; bindings: NonNullable; }, - preExistingRemoteProxySessionData: { + preExistingRemoteProxySessionData?: { session: RemoteProxySession; remoteBindings: Record; } | null From 0e1b23ca44c4debe8eeb1b5a7c73af96eca59052 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 01:53:21 +0100 Subject: [PATCH 06/15] fixup! add remote bindings support to `getPlatformProxy` set the process.env cloudflare id and token so that getPlatformProxy can inherit them --- .../get-platform-proxy-remote-bindings-node-test/index.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js index 5585eb217960..b9f303435cba 100644 --- a/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js +++ b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js @@ -23,6 +23,9 @@ describe("getPlatformProxy remote-bindings", () => { const remoteWorkerName = `get-platform-proxy-remote-worker-test-${randomUUID().split("-")[0]}`; before(async () => { + process.env.CLOUDFLARE_ACCOUNT_ID = process.env.TEST_CLOUDFLARE_ACCOUNT_ID; + process.env.CLOUDFLARE_API_TOKEN = process.env.TEST_CLOUDFLARE_API_TOKEN; + const deployOut = execSync( `pnpm dlx wrangler deploy remote-worker.js --name ${remoteWorkerName} --compatibility-date 2025-06-19`, { From 41ed67571fd520f49a02f656d1653da1eca36558 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 02:10:08 +0100 Subject: [PATCH 07/15] fixup! add remote bindings support to `getPlatformProxy` add helpful comment --- .../index.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js index b9f303435cba..9bff28ca32a3 100644 --- a/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js +++ b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js @@ -23,6 +23,10 @@ describe("getPlatformProxy remote-bindings", () => { const remoteWorkerName = `get-platform-proxy-remote-worker-test-${randomUUID().split("-")[0]}`; before(async () => { + // Note: ideally we pass the auth data to `getPlatformProxy`, that currently is not + // possible (DEVX-1857) so we need to make sure that the CLOUDFLARE_ACCOUNT_ID + // and CLOUDFLARE_API_TOKEN env variables are set so that `getPlatformProxy` + // can establish the remote proxy connection process.env.CLOUDFLARE_ACCOUNT_ID = process.env.TEST_CLOUDFLARE_ACCOUNT_ID; process.env.CLOUDFLARE_API_TOKEN = process.env.TEST_CLOUDFLARE_API_TOKEN; From 2a248aedbb6b93d736be484f8bb15166bc2ebaac Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 10:20:31 +0100 Subject: [PATCH 08/15] fixup! add remote bindings support to `getPlatformProxy` refactor `getMiniflareOptionsFromConfig` --- .../src/api/integrations/platform/index.ts | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 9ca75e083863..4220b40a4ef9 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -113,11 +113,11 @@ export async function getPlatformProxy< ): Promise> { const experimentalRemoteBindings = !!options.experimental?.remoteBindings; - const env = options.environment; + const targetEnvironment = options.environment; const rawConfig = readConfig({ config: options.configPath, - env, + env: targetEnvironment, }); let remoteProxySession: RemoteProxySession | undefined = undefined; @@ -129,18 +129,13 @@ export async function getPlatformProxy< const miniflareOptions = await getMiniflareOptionsFromConfig( rawConfig, - env, + targetEnvironment, options, remoteProxySession?.remoteProxyConnectionString, experimentalRemoteBindings ); - const mf = new Miniflare({ - script: "", - // @ts-expect-error TS doesn't like the spreading of miniflareConfig - modules: true, - ...miniflareOptions, - }); + const mf = new Miniflare(miniflareOptions); const bindings: Env = await mf.getBindings(); @@ -159,15 +154,23 @@ export async function getPlatformProxy< }; } -// this is only used by getPlatformProxy +/** + * Builds an options configuration object for the `getPlatformProxy` functionality that + * can be then passed to the Miniflare constructor + * + * @param rawConfig The raw configuration to base the options from + * @param targetEnvironment The target environment from which to get the binding configuration options + * @param options The user provided `getPlatformProxy` options + * @returns an object ready to be passed to the Miniflare constructor + */ async function getMiniflareOptionsFromConfig( rawConfig: Config, - env: string | undefined, + targetEnvironment: string | undefined, options: GetPlatformProxyOptions, remoteProxyConnectionString?: RemoteProxyConnectionString, remoteBindingsEnabled = false -): Promise> { - const bindings = getBindings(rawConfig, env, true, {}); +): Promise { + const bindings = getBindings(rawConfig, targetEnvironment, true, {}); if (rawConfig["durable_objects"]) { const { localBindings } = partitionDurableObjectBindings(rawConfig); @@ -229,7 +232,11 @@ async function getMiniflareOptionsFromConfig( defaultPersistRoot, }; - return miniflareOptions; + return { + script: "", + modules: true, + ...miniflareOptions, + }; } /** From b67b22f5529bf6d72daac85dd844edce20c7d09a Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 10:26:27 +0100 Subject: [PATCH 09/15] fixup! add remote bindings support to `getPlatformProxy` pass an args object to `getMiniflareOptionsFromConfig` --- .../src/api/integrations/platform/index.ts | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 4220b40a4ef9..c471aba8f5a4 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -127,13 +127,14 @@ export async function getPlatformProxy< remoteProxySession = maybeRemoteProxySessionWrap?.session; } - const miniflareOptions = await getMiniflareOptionsFromConfig( + const miniflareOptions = await getMiniflareOptionsFromConfig({ rawConfig, targetEnvironment, options, - remoteProxySession?.remoteProxyConnectionString, - experimentalRemoteBindings - ); + remoteProxyConnectionString: + remoteProxySession?.remoteProxyConnectionString, + remoteBindingsEnabled: experimentalRemoteBindings, + }); const mf = new Miniflare(miniflareOptions); @@ -158,18 +159,28 @@ export async function getPlatformProxy< * Builds an options configuration object for the `getPlatformProxy` functionality that * can be then passed to the Miniflare constructor * - * @param rawConfig The raw configuration to base the options from - * @param targetEnvironment The target environment from which to get the binding configuration options - * @param options The user provided `getPlatformProxy` options + * @param args.rawConfig The raw configuration to base the options from + * @param args.targetEnvironment The target environment from which to get the binding configuration options + * @param args.options The user provided `getPlatformProxy` options + * @param args.remoteProxyConnectionString The potential remote proxy connection string to be used to connect the remote bindings + * @param args.remoteBindingsEnabled Whether remote bindings are enabled * @returns an object ready to be passed to the Miniflare constructor */ -async function getMiniflareOptionsFromConfig( - rawConfig: Config, - targetEnvironment: string | undefined, - options: GetPlatformProxyOptions, - remoteProxyConnectionString?: RemoteProxyConnectionString, - remoteBindingsEnabled = false -): Promise { +async function getMiniflareOptionsFromConfig(args: { + rawConfig: Config; + targetEnvironment: string | undefined; + options: GetPlatformProxyOptions; + remoteProxyConnectionString?: RemoteProxyConnectionString; + remoteBindingsEnabled: boolean; +}): Promise { + const { + rawConfig, + targetEnvironment, + options, + remoteProxyConnectionString, + remoteBindingsEnabled, + } = args; + const bindings = getBindings(rawConfig, targetEnvironment, true, {}); if (rawConfig["durable_objects"]) { From 3684fa70229a42fdd16a4b28f46966bd56359c4d Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 10:38:12 +0100 Subject: [PATCH 10/15] fixup! add remote bindings support to `getPlatformProxy` add example to changelog --- .changeset/better-sheep-reply.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.changeset/better-sheep-reply.md b/.changeset/better-sheep-reply.md index 031932bcf687..702b3842eca4 100644 --- a/.changeset/better-sheep-reply.md +++ b/.changeset/better-sheep-reply.md @@ -3,3 +3,32 @@ --- add remote bindings support to `getPlatformProxy` + +Example: + +```json +// wrangler.jsonc +{ + "name": "get-platform-proxy-test", + "services": [ + { + "binding": "MY_WORKER", + "service": "my-worker", + "experimental_remote": true + } + ] +} +``` + +```js +// index.mjs +import { getPlatformProxy } from "wrangler"; + +const { env } = await getPlatformProxy({ + experimental: { + remoteBindings: true, + }, +}); + +// env.MY_WORKER.fetch() fetches from the remote my-worker service +``` From 90aed0aa3a46f76388d1a01b2c0f5d7e73dda61a Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 16:12:57 +0100 Subject: [PATCH 11/15] fixup! add remote bindings support to `getPlatformProxy` remove unnecessary `env` object --- .../index.test.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js index 9bff28ca32a3..ef3152dfedb2 100644 --- a/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js +++ b/fixtures/get-platform-proxy-remote-bindings-node-test/index.test.js @@ -13,12 +13,6 @@ if ( process.exit(0); } -const env = { - ...process.env, - CLOUDFLARE_API_TOKEN: process.env.TEST_CLOUDFLARE_API_TOKEN, - CLOUDFLARE_ACCOUNT_ID: process.env.TEST_CLOUDFLARE_ACCOUNT_ID, -}; - describe("getPlatformProxy remote-bindings", () => { const remoteWorkerName = `get-platform-proxy-remote-worker-test-${randomUUID().split("-")[0]}`; @@ -34,7 +28,6 @@ describe("getPlatformProxy remote-bindings", () => { `pnpm dlx wrangler deploy remote-worker.js --name ${remoteWorkerName} --compatibility-date 2025-06-19`, { stdio: "pipe", - env, } ); @@ -86,7 +79,7 @@ describe("getPlatformProxy remote-bindings", () => { }); after(async () => { - execSync(`pnpm dlx wrangler delete --name ${remoteWorkerName}`, { env }); + execSync(`pnpm dlx wrangler delete --name ${remoteWorkerName}`); rmSync("./.tmp", { recursive: true, force: true }); }); }); From e78b859475cfaac939229959d9a07be2ef2b46f1 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 16:17:11 +0100 Subject: [PATCH 12/15] fixup! add remote bindings support to `getPlatformProxy` remove unnecessary intermediary variable --- packages/wrangler/src/api/integrations/platform/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index c471aba8f5a4..a1f6454ecb56 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -122,9 +122,9 @@ export async function getPlatformProxy< let remoteProxySession: RemoteProxySession | undefined = undefined; if (experimentalRemoteBindings && rawConfig.configPath) { - const maybeRemoteProxySessionWrap = - await maybeStartOrUpdateRemoteProxySession(rawConfig.configPath); - remoteProxySession = maybeRemoteProxySessionWrap?.session; + remoteProxySession = ( + (await maybeStartOrUpdateRemoteProxySession(rawConfig.configPath)) ?? {} + ).session; } const miniflareOptions = await getMiniflareOptionsFromConfig({ From 5f1d3521b27e0a056a5ace34f33cd3c58a7cd61f Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 16:20:25 +0100 Subject: [PATCH 13/15] revert targetEnvironment variable renaming --- .../src/api/integrations/platform/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index a1f6454ecb56..90ebc1ea945f 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -113,11 +113,11 @@ export async function getPlatformProxy< ): Promise> { const experimentalRemoteBindings = !!options.experimental?.remoteBindings; - const targetEnvironment = options.environment; + const env = options.environment; const rawConfig = readConfig({ config: options.configPath, - env: targetEnvironment, + env, }); let remoteProxySession: RemoteProxySession | undefined = undefined; @@ -129,7 +129,7 @@ export async function getPlatformProxy< const miniflareOptions = await getMiniflareOptionsFromConfig({ rawConfig, - targetEnvironment, + env, options, remoteProxyConnectionString: remoteProxySession?.remoteProxyConnectionString, @@ -160,7 +160,7 @@ export async function getPlatformProxy< * can be then passed to the Miniflare constructor * * @param args.rawConfig The raw configuration to base the options from - * @param args.targetEnvironment The target environment from which to get the binding configuration options + * @param args.env The target environment from which to get the binding configuration options * @param args.options The user provided `getPlatformProxy` options * @param args.remoteProxyConnectionString The potential remote proxy connection string to be used to connect the remote bindings * @param args.remoteBindingsEnabled Whether remote bindings are enabled @@ -168,20 +168,20 @@ export async function getPlatformProxy< */ async function getMiniflareOptionsFromConfig(args: { rawConfig: Config; - targetEnvironment: string | undefined; + env: string | undefined; options: GetPlatformProxyOptions; remoteProxyConnectionString?: RemoteProxyConnectionString; remoteBindingsEnabled: boolean; }): Promise { const { rawConfig, - targetEnvironment, + env, options, remoteProxyConnectionString, remoteBindingsEnabled, } = args; - const bindings = getBindings(rawConfig, targetEnvironment, true, {}); + const bindings = getBindings(rawConfig, env, true, {}); if (rawConfig["durable_objects"]) { const { localBindings } = partitionDurableObjectBindings(rawConfig); From 869a6fdbb68901b6f5aead966e399882527386d6 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 16:22:31 +0100 Subject: [PATCH 14/15] remove extra env passing --- packages/wrangler/src/api/integrations/platform/index.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 90ebc1ea945f..25b56e329024 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -129,7 +129,6 @@ export async function getPlatformProxy< const miniflareOptions = await getMiniflareOptionsFromConfig({ rawConfig, - env, options, remoteProxyConnectionString: remoteProxySession?.remoteProxyConnectionString, @@ -160,7 +159,6 @@ export async function getPlatformProxy< * can be then passed to the Miniflare constructor * * @param args.rawConfig The raw configuration to base the options from - * @param args.env The target environment from which to get the binding configuration options * @param args.options The user provided `getPlatformProxy` options * @param args.remoteProxyConnectionString The potential remote proxy connection string to be used to connect the remote bindings * @param args.remoteBindingsEnabled Whether remote bindings are enabled @@ -168,20 +166,18 @@ export async function getPlatformProxy< */ async function getMiniflareOptionsFromConfig(args: { rawConfig: Config; - env: string | undefined; options: GetPlatformProxyOptions; remoteProxyConnectionString?: RemoteProxyConnectionString; remoteBindingsEnabled: boolean; }): Promise { const { rawConfig, - env, options, remoteProxyConnectionString, remoteBindingsEnabled, } = args; - const bindings = getBindings(rawConfig, env, true, {}); + const bindings = getBindings(rawConfig, options.environment, true, {}); if (rawConfig["durable_objects"]) { const { localBindings } = partitionDurableObjectBindings(rawConfig); From 86f2189251069679840662e2d929aeb82b25bc1e Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 20 Jun 2025 16:27:17 +0100 Subject: [PATCH 15/15] rename rawConfig to just config --- .../src/api/integrations/platform/index.ts | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 25b56e329024..1f4ef6f2da87 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -115,20 +115,20 @@ export async function getPlatformProxy< const env = options.environment; - const rawConfig = readConfig({ + const config = readConfig({ config: options.configPath, env, }); let remoteProxySession: RemoteProxySession | undefined = undefined; - if (experimentalRemoteBindings && rawConfig.configPath) { + if (experimentalRemoteBindings && config.configPath) { remoteProxySession = ( - (await maybeStartOrUpdateRemoteProxySession(rawConfig.configPath)) ?? {} + (await maybeStartOrUpdateRemoteProxySession(config.configPath)) ?? {} ).session; } const miniflareOptions = await getMiniflareOptionsFromConfig({ - rawConfig, + config, options, remoteProxyConnectionString: remoteProxySession?.remoteProxyConnectionString, @@ -158,29 +158,29 @@ export async function getPlatformProxy< * Builds an options configuration object for the `getPlatformProxy` functionality that * can be then passed to the Miniflare constructor * - * @param args.rawConfig The raw configuration to base the options from + * @param args.config The wrangler configuration to base the options from * @param args.options The user provided `getPlatformProxy` options * @param args.remoteProxyConnectionString The potential remote proxy connection string to be used to connect the remote bindings * @param args.remoteBindingsEnabled Whether remote bindings are enabled * @returns an object ready to be passed to the Miniflare constructor */ async function getMiniflareOptionsFromConfig(args: { - rawConfig: Config; + config: Config; options: GetPlatformProxyOptions; remoteProxyConnectionString?: RemoteProxyConnectionString; remoteBindingsEnabled: boolean; }): Promise { const { - rawConfig, + config, options, remoteProxyConnectionString, remoteBindingsEnabled, } = args; - const bindings = getBindings(rawConfig, options.environment, true, {}); + const bindings = getBindings(config, options.environment, true, {}); - if (rawConfig["durable_objects"]) { - const { localBindings } = partitionDurableObjectBindings(rawConfig); + if (config["durable_objects"]) { + const { localBindings } = partitionDurableObjectBindings(config); if (localBindings.length > 0) { logger.warn(dedent` You have defined bindings to the following internal Durable Objects: @@ -193,22 +193,22 @@ async function getMiniflareOptionsFromConfig(args: { } } const workerDefinitions = await getBoundRegisteredWorkers({ - name: rawConfig.name, + name: config.name, services: bindings.services, - durableObjects: rawConfig["durable_objects"], + durableObjects: config["durable_objects"], tailConsumers: [], }); const { bindingOptions, externalWorkers } = buildMiniflareBindingOptions( { - name: rawConfig.name, - complianceRegion: rawConfig.compliance_region, + name: config.name, + complianceRegion: config.compliance_region, bindings, workerDefinitions, queueConsumers: undefined, - services: rawConfig.services, + services: config.services, serviceBindings: {}, - migrations: rawConfig.migrations, + migrations: config.migrations, imagesLocalMode: false, tails: [], containers: undefined, @@ -227,7 +227,7 @@ async function getMiniflareOptionsFromConfig(args: { { script: "", modules: true, - name: rawConfig.name, + name: config.name, ...bindingOptions, serviceBindings: { ...serviceBindings,