diff --git a/fixtures/worker-ts/wrangler.toml b/fixtures/worker-ts/wrangler.toml index 0404b911ae95..7da01f05203d 100644 --- a/fixtures/worker-ts/wrangler.toml +++ b/fixtures/worker-ts/wrangler.toml @@ -1,3 +1,5 @@ name = "worker-ts" main = "src/index.ts" compatibility_date = "2023-05-04" + +account_id = "a67e14daa5f8dceeb91fe5449ba496eb" \ No newline at end of file diff --git a/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts b/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts index ae4abd05adc7..6e0dd9049c50 100644 --- a/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts +++ b/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts @@ -19,134 +19,143 @@ async function waitForConfigUpdate( describe("ConfigController", () => { runInTempDir(); mockConsoleMethods(); - mockAccountId(); - mockApiToken(); - it("should emit configUpdate events with defaults applied", async () => { - const controller = new ConfigController(); - const event = waitForConfigUpdate(controller); - await seed({ - "src/index.ts": dedent/* javascript */ ` + describe("with mocked auth env vars", () => { + mockAccountId(); + mockApiToken(); + + it("should emit configUpdate events with defaults applied", async () => { + const controller = new ConfigController(); + const event = waitForConfigUpdate(controller); + await seed({ + "src/index.ts": dedent/* javascript */ ` export default { fetch(request, env, ctx) { return new Response("hello world") } } satisfies ExportedHandler `, - }); - const config: StartDevWorkerInput = { - entrypoint: "src/index.ts", - }; + }); + const config: StartDevWorkerInput = { + entrypoint: "src/index.ts", + }; - await controller.set(config); + await controller.set(config); - await expect(event).resolves.toMatchObject({ - type: "configUpdate", - config: { - build: { - additionalModules: [], - define: {}, - format: "modules", - moduleRoot: path.join(process.cwd(), "src"), - moduleRules: [], + await expect(event).resolves.toMatchObject({ + type: "configUpdate", + config: { + build: { + additionalModules: [], + define: {}, + format: "modules", + moduleRoot: path.join(process.cwd(), "src"), + moduleRules: [], + }, + directory: process.cwd(), + entrypoint: path.join(process.cwd(), "src/index.ts"), }, - directory: process.cwd(), - entrypoint: path.join(process.cwd(), "src/index.ts"), - }, + }); }); - }); - it("should shallow merge patched config", async () => { - const controller = new ConfigController(); - const event1 = waitForConfigUpdate(controller); - await seed({ - "src/index.ts": dedent/* javascript */ ` + it("should shallow merge patched config", async () => { + const controller = new ConfigController(); + const event1 = waitForConfigUpdate(controller); + await seed({ + "src/index.ts": dedent/* javascript */ ` export default { fetch(request, env, ctx) { return new Response("hello world") } } satisfies ExportedHandler `, - }); - const config: StartDevWorkerInput = { - entrypoint: "src/index.ts", - }; + }); + const config: StartDevWorkerInput = { + entrypoint: "src/index.ts", + }; - await controller.set(config); + await controller.set(config); - await expect(event1).resolves.toMatchObject({ - type: "configUpdate", - config: { - entrypoint: path.join(process.cwd(), "src/index.ts"), - directory: process.cwd(), - build: { - additionalModules: [], - define: {}, - format: "modules", - moduleRoot: path.join(process.cwd(), "src"), - moduleRules: [], + await expect(event1).resolves.toMatchObject({ + type: "configUpdate", + config: { + entrypoint: path.join(process.cwd(), "src/index.ts"), + directory: process.cwd(), + build: { + additionalModules: [], + define: {}, + format: "modules", + moduleRoot: path.join(process.cwd(), "src"), + moduleRules: [], + }, }, - }, - }); + }); - const event2 = waitForConfigUpdate(controller); - await controller.patch({ - dev: { - remote: true, - liveReload: true, - server: { port: 1234 }, - }, - }); - // expect `dev` field to be added and all other config to remain intact - await expect(event2).resolves.toMatchObject({ - type: "configUpdate", - config: { - entrypoint: path.join(process.cwd(), "src/index.ts"), - directory: process.cwd(), - build: { - additionalModules: [], - define: {}, - format: "modules", - moduleRoot: path.join(process.cwd(), "src"), - moduleRules: [], - }, + const event2 = waitForConfigUpdate(controller); + await controller.patch({ dev: { remote: true, liveReload: true, server: { port: 1234 }, }, - }, - }); - - const event3 = waitForConfigUpdate(controller); - await controller.patch({ - dev: { - origin: { hostname: "myexample.com" }, - }, - build: { - alias: { foo: "bar" }, - }, - }); - // expect `dev` and `build.alias` fields to be overwritten and all other config to remain intact - await expect(event3).resolves.toMatchObject({ - type: "configUpdate", - config: { - entrypoint: path.join(process.cwd(), "src/index.ts"), - directory: process.cwd(), - build: { - alias: { - foo: "bar", + }); + // expect `dev` field to be added and all other config to remain intact + await expect(event2).resolves.toMatchObject({ + type: "configUpdate", + config: { + entrypoint: path.join(process.cwd(), "src/index.ts"), + directory: process.cwd(), + build: { + additionalModules: [], + define: {}, + format: "modules", + moduleRoot: path.join(process.cwd(), "src"), + moduleRules: [], + }, + dev: { + remote: true, + liveReload: true, + server: { port: 1234 }, }, - additionalModules: [], - define: {}, - format: "modules", - moduleRoot: path.join(process.cwd(), "src"), - moduleRules: [], }, + }); + + const event3 = waitForConfigUpdate(controller); + await controller.patch({ dev: { origin: { hostname: "myexample.com" }, }, - }, + build: { + alias: { foo: "bar" }, + }, + }); + // expect `dev` and `build.alias` fields to be overwritten and all other config to remain intact + await expect(event3).resolves.toMatchObject({ + type: "configUpdate", + config: { + entrypoint: path.join(process.cwd(), "src/index.ts"), + directory: process.cwd(), + build: { + alias: { + foo: "bar", + }, + additionalModules: [], + define: {}, + format: "modules", + moduleRoot: path.join(process.cwd(), "src"), + moduleRules: [], + }, + dev: { + origin: { hostname: "myexample.com" }, + }, + }, + }); + }); + }); + + describe("without mocked auth env vars", () => { + it("should use account_id from config file before env var or prompting", async () => { + // TODO }); }); }); diff --git a/packages/wrangler/src/api/startDevWorker/ConfigController.ts b/packages/wrangler/src/api/startDevWorker/ConfigController.ts index 3278c3cfe4d8..1d45e701bb76 100644 --- a/packages/wrangler/src/api/startDevWorker/ConfigController.ts +++ b/packages/wrangler/src/api/startDevWorker/ConfigController.ts @@ -53,14 +53,16 @@ async function resolveDevConfig( config: Config, input: StartDevWorkerInput ): Promise { - const auth = - input.dev?.auth ?? - (async () => { - return { - accountId: await getAccountId(), - apiToken: requireApiToken(), - }; - }); + const auth = async () => { + if (input.dev?.auth) { + return unwrapHook(input.dev.auth, config); + } + + return { + accountId: config.account_id ?? (await getAccountId()), + apiToken: requireApiToken(), + }; + }; const localPersistencePath = getLocalPersistencePath( input.dev?.persist, @@ -85,7 +87,7 @@ async function resolveDevConfig( // Because it's a non-recoverable user error, we want it to exit the Wrangler process early to allow the user to fix it. // Calling it here forces the error to be thrown where it will correctly exit the Wrangler process. if (input.dev?.remote) { - const { accountId } = await unwrapHook(auth); + const { accountId } = await unwrapHook(auth, config); assert(accountId, "Account ID must be provided for remote dev"); await getZoneIdForPreview({ host, routes, accountId }); } diff --git a/packages/wrangler/src/api/startDevWorker/types.ts b/packages/wrangler/src/api/startDevWorker/types.ts index 71ec5526e8f3..868b6e44d24a 100644 --- a/packages/wrangler/src/api/startDevWorker/types.ts +++ b/packages/wrangler/src/api/startDevWorker/types.ts @@ -129,7 +129,7 @@ export interface StartDevWorkerInput { /** Whether the worker runs on the edge or locally. */ remote?: boolean; /** Cloudflare Account credentials. Can be provided upfront or as a function which will be called only when required. */ - auth?: AsyncHook; + auth?: AsyncHook]>; // provide config.account_id as a hook param /** Whether local storage (KV, Durable Objects, R2, D1, etc) is persisted. You can also specify the directory to persist data to. */ persist?: string; /** Controls which logs are logged 🤙. */ @@ -187,6 +187,7 @@ export type StartDevWorkerOptions = Omit & { }; dev: StartDevWorkerInput["dev"] & { persist: string; + auth?: AsyncHook; // redefine without config.account_id hook param (can only be provided by ConfigController with access to wrangler.toml, not by other controllers eg RemoteRuntimeContoller) }; entrypoint: string; assets?: AssetsOptions; diff --git a/packages/wrangler/src/dev.tsx b/packages/wrangler/src/dev.tsx index aa390c510a51..1f6e2653b04d 100644 --- a/packages/wrangler/src/dev.tsx +++ b/packages/wrangler/src/dev.tsx @@ -711,11 +711,11 @@ export async function startDev(args: StartDevOptions) { }), }, dev: { - auth: async () => { + auth: async (config) => { let accountId = args.accountId; if (!accountId) { unregisterHotKeys?.(); - accountId = await requireAuth({}); + accountId = await requireAuth(config); unregisterHotKeys = registerDevHotKeys(devEnv, args); } return {