diff --git a/.changeset/open-points-speak.md b/.changeset/open-points-speak.md new file mode 100644 index 000000000000..7ce8d2001371 --- /dev/null +++ b/.changeset/open-points-speak.md @@ -0,0 +1,5 @@ +--- +"wrangler": minor +--- + +Allow users to provide an `account_id` as part of the `WorkerConfigObject` they pass to `maybeStartOrUpdateRemoteProxySession` diff --git a/.changeset/tough-crabs-tap.md b/.changeset/tough-crabs-tap.md new file mode 100644 index 000000000000..84d7fedcffcf --- /dev/null +++ b/.changeset/tough-crabs-tap.md @@ -0,0 +1,5 @@ +--- +"@cloudflare/vite-plugin": patch +--- + +Make sure that the `account_id` present in the user's config file is used for remote bindings diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json index 2c0ec94c20f0..41219bf70b72 100644 --- a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.node.json", "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo", - "types": ["@cloudflare/workers-types/2023-07-01", "vite/client", "node"] + "types": ["@cloudflare/workers-types", "vite/client", "node"] }, "include": ["api"] } diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/dynamic/tsconfig.worker.json b/packages/vite-plugin-cloudflare/e2e/fixtures/dynamic/tsconfig.worker.json index ff69f9652d65..de623f44bd0b 100644 --- a/packages/vite-plugin-cloudflare/e2e/fixtures/dynamic/tsconfig.worker.json +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/dynamic/tsconfig.worker.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.node.json", "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo", - "types": ["@cloudflare/workers-types/2023-07-01", "vite/client"] + "types": ["@cloudflare/workers-types", "vite/client"] }, "include": ["src"] } diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/package.json b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/package.json new file mode 100644 index 000000000000..09a73f7ae51b --- /dev/null +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/package.json @@ -0,0 +1,27 @@ +{ + "name": "@cloudflare/vite-plugin-e2e-remote-bindings-config-account-id", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "buildAndPreview": "vite build && vite preview", + "dev": "vite", + "lint": "eslint .", + "preview": "vite preview" + }, + "devDependencies": { + "@cloudflare/vite-plugin": "*", + "@cloudflare/workers-types": "^4.20250204.0", + "@eslint/js": "^9.19.0", + "eslint": "^9.19.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.18", + "globals": "^15.14.0", + "miniflare": "*", + "typescript": "~5.7.2", + "typescript-eslint": "^8.22.0", + "vite": "^6.1.0", + "wrangler": "*" + } +} diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/src/index.ts b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/src/index.ts new file mode 100644 index 000000000000..9bd4c9e9b36e --- /dev/null +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/src/index.ts @@ -0,0 +1,5 @@ +export default { + async fetch() { + return new Response("Hello world"); + }, +}; diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.json b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.json new file mode 100644 index 000000000000..b52af703bdc2 --- /dev/null +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.node.json" }, + { "path": "./tsconfig.worker.json" } + ] +} diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.node.json b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.node.json new file mode 100644 index 000000000000..50130b3a269b --- /dev/null +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.worker.json b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.worker.json new file mode 100644 index 000000000000..de623f44bd0b --- /dev/null +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/tsconfig.worker.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.node.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo", + "types": ["@cloudflare/workers-types", "vite/client"] + }, + "include": ["src"] +} diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/vite.config.ts b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/vite.config.ts new file mode 100644 index 000000000000..db6baac9bbea --- /dev/null +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/vite.config.ts @@ -0,0 +1,12 @@ +import { cloudflare } from "@cloudflare/vite-plugin"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [ + cloudflare({ + configPath: "./wrangler.jsonc", + inspectorPort: false, + persistState: false, + }), + ], +}); diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/wrangler.jsonc b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/wrangler.jsonc new file mode 100644 index 000000000000..a0ac2b26ca08 --- /dev/null +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-config-account-id/wrangler.jsonc @@ -0,0 +1,14 @@ +{ + "name": "cloudflare-vite-e2e-remote-bindings-config-account-id-worker", + "main": "./src/index.ts", + "compatibility_date": "2024-12-30", + "compatibility_flags": ["nodejs_compat"], + "account_id": "not-a-valid-account-id-abc", + "services": [ + { + "binding": "REMOTE_WORKER", + "service": "MY_REMOTE_WORKER", + "remote": true, + }, + ], +} diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-disabled/tsconfig.worker.json b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-disabled/tsconfig.worker.json index ff69f9652d65..de623f44bd0b 100644 --- a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-disabled/tsconfig.worker.json +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings-disabled/tsconfig.worker.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.node.json", "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo", - "types": ["@cloudflare/workers-types/2023-07-01", "vite/client"] + "types": ["@cloudflare/workers-types", "vite/client"] }, "include": ["src"] } diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings/tsconfig.worker.json b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings/tsconfig.worker.json index 1fdb92436597..fbc236b0f8bb 100644 --- a/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings/tsconfig.worker.json +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/remote-bindings/tsconfig.worker.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.node.json", "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo", - "types": ["@cloudflare/workers-types/2023-07-01", "vite/client"] + "types": ["@cloudflare/workers-types", "vite/client"] }, "include": ["entry-worker/src", "auxiliary-worker/src"] } diff --git a/packages/vite-plugin-cloudflare/e2e/helpers.ts b/packages/vite-plugin-cloudflare/e2e/helpers.ts index 3e21e49577b8..2bdd81f3ce77 100644 --- a/packages/vite-plugin-cloudflare/e2e/helpers.ts +++ b/packages/vite-plugin-cloudflare/e2e/helpers.ts @@ -14,6 +14,7 @@ import { onTestFinished, vi, } from "vitest"; +import wranglerPackage from "../../wrangler/package.json"; import vitePluginPackage from "../package.json"; const debuglog = util.debuglog("vite-plugin:test"); @@ -52,7 +53,7 @@ export function seed( errorOnExist: true, }); debuglog("Fixture copied to " + projectPath); - await updateVitePluginVersion(projectPath); + await updateVitePluginAndWranglerVersion(projectPath); debuglog("Fixing up replacements in seeded files"); await fixupReplacements(projectPath, replacements); debuglog("Updated vite-plugin version in package.json"); @@ -169,7 +170,7 @@ function wrap(proc: childProcess.ChildProcess): Process { return wrappedProc; } -async function updateVitePluginVersion(projectPath: string) { +async function updateVitePluginAndWranglerVersion(projectPath: string) { const pkg = JSON.parse( await fs.readFile(path.resolve(projectPath, "package.json"), "utf8") ); @@ -178,6 +179,9 @@ async function updateVitePluginVersion(projectPath: string) { if (pkg[field]?.["@cloudflare/vite-plugin"]) { pkg[field]["@cloudflare/vite-plugin"] = vitePluginPackage.version; } + if (pkg[field]?.["wrangler"]) { + pkg[field]["wrangler"] = wranglerPackage.version; + } } await fs.writeFile( path.resolve(projectPath, "package.json"), diff --git a/packages/vite-plugin-cloudflare/e2e/remote-bindings.test.ts b/packages/vite-plugin-cloudflare/e2e/remote-bindings.test.ts index d73b73a573d6..32718a27a500 100644 --- a/packages/vite-plugin-cloudflare/e2e/remote-bindings.test.ts +++ b/packages/vite-plugin-cloudflare/e2e/remote-bindings.test.ts @@ -163,3 +163,25 @@ describe("remote bindings disabled", () => { ); }); }); + +describe("remote bindings without actually establishing a remote connection", () => { + const projectPath = seed("remote-bindings-config-account-id", "pnpm"); + + test("for connection to remote bindings during dev the account_id present in the wrangler config file is used", async ({ + expect, + }) => { + const proc = await runLongLived("pnpm", "dev", projectPath); + await vi.waitFor( + async () => { + expect(proc.stderr).toMatch( + // Note: this error message shows that we're attempting to establish the remote proxy connection + // using the "not-a-valid-account-id-abc" account id + /A request to the Cloudflare API \(\/accounts\/not-a-valid-account-id-abc\/.*?\) failed/ + ); + }, + { + timeout: 10_000, + } + ); + }); +}); diff --git a/packages/vite-plugin-cloudflare/src/miniflare-options.ts b/packages/vite-plugin-cloudflare/src/miniflare-options.ts index 8490d512edf7..6d998d74033c 100644 --- a/packages/vite-plugin-cloudflare/src/miniflare-options.ts +++ b/packages/vite-plugin-cloudflare/src/miniflare-options.ts @@ -400,6 +400,7 @@ export async function getDevMiniflareOptions( { name: workerConfig.name, bindings: bindings ?? {}, + account_id: workerConfig.account_id, }, preExistingRemoteProxySession ?? null ); @@ -724,6 +725,7 @@ export async function getPreviewMiniflareOptions( { name: workerConfig.name, bindings: bindings ?? {}, + account_id: workerConfig.account_id, }, preExistingRemoteProxySessionData ?? null ); diff --git a/packages/wrangler/src/api/remoteBindings/index.ts b/packages/wrangler/src/api/remoteBindings/index.ts index 03dac61c8eda..96be69db8562 100644 --- a/packages/wrangler/src/api/remoteBindings/index.ts +++ b/packages/wrangler/src/api/remoteBindings/index.ts @@ -49,6 +49,8 @@ type WorkerConfigObject = { bindings: NonNullable; /** If running in a non-public compliance region, set this here. */ complianceRegion?: Config["compliance_region"]; + /** Id of the account owning the worker */ + account_id?: Config["account_id"]; }; /** @@ -110,7 +112,14 @@ export async function maybeStartOrUpdateRemoteProxySession( remoteProxySession = await startRemoteProxySession(remoteBindings, { workerName: workerConfigObject.name, complianceRegion: workerConfigObject.complianceRegion, - auth: getAuthHook(auth, config), + auth: getAuthHook( + auth, + workerConfigObject.account_id + ? { + account_id: workerConfigObject.account_id, + } + : config + ), }); } else { // The auth values haven't changed so we can reuse the pre-existing session @@ -127,7 +136,14 @@ export async function maybeStartOrUpdateRemoteProxySession( remoteProxySession = await startRemoteProxySession(remoteBindings, { workerName: workerConfigObject.name, complianceRegion: workerConfigObject.complianceRegion, - auth: getAuthHook(auth, config), + auth: getAuthHook( + auth, + workerConfigObject.account_id + ? { + account_id: workerConfigObject.account_id, + } + : config + ), }); } } else { @@ -160,7 +176,7 @@ export async function maybeStartOrUpdateRemoteProxySession( */ function getAuthHook( auth: CfAccount | undefined, - config: Config | undefined + config: Pick | undefined ): AsyncHook]> | undefined { if (auth) { return auth;