wrangler 2.0.27 → 2.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ import { mockConsoleMethods } from "./helpers/mock-console";
4
4
  import { runInTempDir } from "./helpers/run-in-tmp";
5
5
  import { runWrangler } from "./helpers/run-wrangler";
6
6
 
7
- describe("worker-namespace", () => {
7
+ describe("dispatch-namespace", () => {
8
8
  runInTempDir();
9
9
  const std = mockConsoleMethods();
10
10
  mockAccountId();
@@ -14,8 +14,8 @@ describe("worker-namespace", () => {
14
14
  unsetAllMocks();
15
15
  });
16
16
 
17
- it("should should display a list of available subcommands, for worker-namespace with no subcommand", async () => {
18
- await runWrangler("worker-namespace");
17
+ it("should should display a list of available subcommands, for dispatch-namespace with no subcommand", async () => {
18
+ await runWrangler("dispatch-namespace");
19
19
 
20
20
  // wait a tick for the help menu to be printed
21
21
  await new Promise((resolve) => setImmediate(resolve));
@@ -24,16 +24,16 @@ describe("worker-namespace", () => {
24
24
  Object {
25
25
  "debug": "",
26
26
  "err": "",
27
- "out": "wrangler worker-namespace
27
+ "out": "wrangler dispatch-namespace
28
28
 
29
- 📦 Interact with a worker namespace
29
+ 📦 Interact with a dispatch namespace
30
30
 
31
31
  Commands:
32
- wrangler worker-namespace list List all Worker namespaces
33
- wrangler worker-namespace get <name> Get information about a Worker namespace
34
- wrangler worker-namespace create <name> Create a Worker namespace
35
- wrangler worker-namespace delete <name> Delete a Worker namespace
36
- wrangler worker-namespace rename <old-name> <new-name> Rename a Worker namespace
32
+ wrangler dispatch-namespace list List all dispatch namespaces
33
+ wrangler dispatch-namespace get <name> Get information about a dispatch namespace
34
+ wrangler dispatch-namespace create <name> Create a dispatch namespace
35
+ wrangler dispatch-namespace delete <name> Delete a dispatch namespace
36
+ wrangler dispatch-namespace rename <old-name> <new-name> Rename a dispatch namespace
37
37
 
38
38
  Flags:
39
39
  -c, --config Path to .toml configuration file [string]
@@ -73,19 +73,19 @@ describe("worker-namespace", () => {
73
73
 
74
74
  it("should display help for create", async () => {
75
75
  await expect(
76
- runWrangler("worker-namespace create")
76
+ runWrangler("dispatch-namespace create")
77
77
  ).rejects.toThrowErrorMatchingInlineSnapshot(
78
78
  `"Not enough non-option arguments: got 0, need at least 1"`
79
79
  );
80
80
 
81
81
  expect(std.out).toMatchInlineSnapshot(`
82
82
  "
83
- wrangler worker-namespace create <name>
83
+ wrangler dispatch-namespace create <name>
84
84
 
85
- Create a Worker namespace
85
+ Create a dispatch namespace
86
86
 
87
87
  Positionals:
88
- name Name of the Worker namespace [string] [required]
88
+ name Name of the dispatch namespace [string] [required]
89
89
 
90
90
  Flags:
91
91
  -c, --config Path to .toml configuration file [string]
@@ -97,11 +97,11 @@ describe("worker-namespace", () => {
97
97
  it("should attempt to create the given namespace", async () => {
98
98
  const namespaceName = "my-namespace";
99
99
  const requests = mockCreateRequest(namespaceName);
100
- await runWrangler(`worker-namespace create ${namespaceName}`);
100
+ await runWrangler(`dispatch-namespace create ${namespaceName}`);
101
101
  expect(requests.count).toEqual(1);
102
102
 
103
103
  expect(std.out).toMatchInlineSnapshot(
104
- `"Created Worker namespace \\"my-namespace\\" with ID \\"some-namespace-id\\""`
104
+ `"Created dispatch namespace \\"my-namespace\\" with ID \\"some-namespace-id\\""`
105
105
  );
106
106
  });
107
107
  });
@@ -125,19 +125,19 @@ describe("worker-namespace", () => {
125
125
 
126
126
  it("should display help for delete", async () => {
127
127
  await expect(
128
- runWrangler("worker-namespace create")
128
+ runWrangler("dispatch-namespace create")
129
129
  ).rejects.toThrowErrorMatchingInlineSnapshot(
130
130
  `"Not enough non-option arguments: got 0, need at least 1"`
131
131
  );
132
132
 
133
133
  expect(std.out).toMatchInlineSnapshot(`
134
134
  "
135
- wrangler worker-namespace create <name>
135
+ wrangler dispatch-namespace create <name>
136
136
 
137
- Create a Worker namespace
137
+ Create a dispatch namespace
138
138
 
139
139
  Positionals:
140
- name Name of the Worker namespace [string] [required]
140
+ name Name of the dispatch namespace [string] [required]
141
141
 
142
142
  Flags:
143
143
  -c, --config Path to .toml configuration file [string]
@@ -149,11 +149,11 @@ describe("worker-namespace", () => {
149
149
  it("should try to delete the given namespace", async () => {
150
150
  const namespaceName = "my-namespace";
151
151
  const requests = mockDeleteRequest(namespaceName);
152
- await runWrangler(`worker-namespace delete ${namespaceName}`);
152
+ await runWrangler(`dispatch-namespace delete ${namespaceName}`);
153
153
  expect(requests.count).toBe(1);
154
154
 
155
155
  expect(std.out).toMatchInlineSnapshot(
156
- `"Deleted Worker namespace \\"my-namespace\\""`
156
+ `"Deleted dispatch namespace \\"my-namespace\\""`
157
157
  );
158
158
  });
159
159
  });
@@ -183,19 +183,19 @@ describe("worker-namespace", () => {
183
183
 
184
184
  it("should display help for get", async () => {
185
185
  await expect(
186
- runWrangler("worker-namespace get")
186
+ runWrangler("dispatch-namespace get")
187
187
  ).rejects.toThrowErrorMatchingInlineSnapshot(
188
188
  `"Not enough non-option arguments: got 0, need at least 1"`
189
189
  );
190
190
 
191
191
  expect(std.out).toMatchInlineSnapshot(`
192
192
  "
193
- wrangler worker-namespace get <name>
193
+ wrangler dispatch-namespace get <name>
194
194
 
195
- Get information about a Worker namespace
195
+ Get information about a dispatch namespace
196
196
 
197
197
  Positionals:
198
- name Name of the Worker namespace [string] [required]
198
+ name Name of the dispatch namespace [string] [required]
199
199
 
200
200
  Flags:
201
201
  -c, --config Path to .toml configuration file [string]
@@ -207,7 +207,7 @@ describe("worker-namespace", () => {
207
207
  it("should attempt to get info for the given namespace", async () => {
208
208
  const namespaceName = "my-namespace";
209
209
  const requests = mockInfoRequest(namespaceName);
210
- await runWrangler(`worker-namespace get ${namespaceName}`);
210
+ await runWrangler(`dispatch-namespace get ${namespaceName}`);
211
211
  expect(requests.count).toBe(1);
212
212
 
213
213
  expect(std.out).toMatchInlineSnapshot(`
@@ -248,7 +248,7 @@ describe("worker-namespace", () => {
248
248
 
249
249
  it("should list all namespaces", async () => {
250
250
  const requests = mockListRequest();
251
- await runWrangler("worker-namespace list");
251
+ await runWrangler("dispatch-namespace list");
252
252
  expect(requests.count).toBe(1);
253
253
  expect(std.out).toMatchInlineSnapshot(`
254
254
  "[
@@ -291,20 +291,20 @@ describe("worker-namespace", () => {
291
291
 
292
292
  it("should display help for rename", async () => {
293
293
  await expect(
294
- runWrangler("worker-namespace rename")
294
+ runWrangler("dispatch-namespace rename")
295
295
  ).rejects.toThrowErrorMatchingInlineSnapshot(
296
296
  `"Not enough non-option arguments: got 0, need at least 2"`
297
297
  );
298
298
 
299
299
  expect(std.out).toMatchInlineSnapshot(`
300
300
  "
301
- wrangler worker-namespace rename <old-name> <new-name>
301
+ wrangler dispatch-namespace rename <old-name> <new-name>
302
302
 
303
- Rename a Worker namespace
303
+ Rename a dispatch namespace
304
304
 
305
305
  Positionals:
306
- old-name Name of the Worker namespace [string] [required]
307
- new-name New name of the Worker namespace [string] [required]
306
+ old-name Name of the dispatch namespace [string] [required]
307
+ new-name New name of the dispatch namespace [string] [required]
308
308
 
309
309
  Flags:
310
310
  -c, --config Path to .toml configuration file [string]
@@ -317,10 +317,12 @@ describe("worker-namespace", () => {
317
317
  const namespaceName = "my-namespace";
318
318
  const newName = "new-namespace";
319
319
  const requests = mockRenameRequest(namespaceName);
320
- await runWrangler(`worker-namespace rename ${namespaceName} ${newName}`);
320
+ await runWrangler(
321
+ `dispatch-namespace rename ${namespaceName} ${newName}`
322
+ );
321
323
  expect(requests.count).toBe(1);
322
324
  expect(std.out).toMatchInlineSnapshot(
323
- `"Renamed Worker namespace \\"my-namespace\\" to \\"new-namespace\\""`
325
+ `"Renamed dispatch namespace \\"my-namespace\\" to \\"new-namespace\\""`
324
326
  );
325
327
  });
326
328
  });
package/src/bundle.ts CHANGED
@@ -380,7 +380,7 @@ async function applyMultiWorkerDevFacade(
380
380
  services: Config["services"],
381
381
  workerDefinitions: WorkerRegistry
382
382
  ) {
383
- const targetPath = path.join(tmpDirPath, "serve-static-assets.entry.js");
383
+ const targetPath = path.join(tmpDirPath, "multiworker-dev-facade.entry.js");
384
384
  const serviceMap = Object.fromEntries(
385
385
  (services || []).map((serviceBinding) => [
386
386
  serviceBinding.binding,
@@ -1,5 +1,6 @@
1
1
  import assert from "node:assert";
2
- import { fetch, Headers } from "undici";
2
+ import Busboy from "busboy";
3
+ import { fetch, File, FormData, Headers } from "undici";
3
4
  import { version as wranglerVersion } from "../../package.json";
4
5
  import { getEnvironmentVariableFactory } from "../environment-variables";
5
6
  import { logger } from "../logger";
@@ -226,12 +227,72 @@ export async function fetchDashboardScript(
226
227
  ?.startsWith("multipart");
227
228
 
228
229
  if (usesModules) {
229
- const file = await response.text();
230
+ // Response from edge contains generic "name = worker.js" for dashboard created scripts
231
+ const form = await formData(response);
232
+ const entries = Array.from(form.entries());
233
+ if (entries.length > 1)
234
+ throw new RangeError("Expected only one entry in multipart response");
235
+ const [_, file] = entries[0];
236
+
237
+ if (file instanceof File) {
238
+ return await file.text();
239
+ }
240
+
241
+ return file ?? "";
230
242
 
231
243
  // Follow up on issue in Undici about multipart/form-data support & replace the workaround: https://github.com/nodejs/undici/issues/974
232
244
  // This should be using a builtin formData() parser pattern.
233
- return file.split("\n").slice(4, -4).join("\n");
234
245
  } else {
235
246
  return response.text();
236
247
  }
237
248
  }
249
+
250
+ async function formData({ headers, body }: Response): Promise<FormData> {
251
+ // undici doesn't include a multipart/form-data parser yet, so we parse
252
+ // form data with busboy instead
253
+ const contentType = headers.get("Content-Type") ?? "";
254
+ if (!/multipart\/form-data/.test(contentType))
255
+ throw Error("Need Content-Type for multipart/form-data");
256
+
257
+ const responseFormData = new FormData();
258
+
259
+ let busboy: Busboy.Busboy;
260
+
261
+ const parsedHeaders = Object.fromEntries(
262
+ Array.from(headers).map(([header, value]) => [header.toLowerCase(), value])
263
+ );
264
+ try {
265
+ busboy = Busboy({ headers: parsedHeaders });
266
+ } catch (err) {
267
+ // Error due to headers:
268
+ throw Object.assign(new TypeError(), { cause: err });
269
+ }
270
+
271
+ busboy.on("field", (name, value) => {
272
+ responseFormData.append(name, value);
273
+ });
274
+ busboy.on("file", (name, value, info) => {
275
+ const { filename, encoding, mimeType } = info;
276
+ const base64 = encoding.toLowerCase() === "base64";
277
+ const chunks: Buffer[] = [];
278
+ value.on("data", (chunk) => {
279
+ if (base64) chunk = Buffer.from(chunk.toString(), "base64");
280
+ chunks.push(chunk);
281
+ });
282
+ value.on("end", () => {
283
+ const file = new File(chunks, filename, { type: mimeType });
284
+ responseFormData.append(name, file);
285
+ });
286
+ });
287
+
288
+ const busboyResolve = new Promise((resolve, reject) => {
289
+ busboy.on("finish", resolve);
290
+ busboy.on("error", (err) => reject(err));
291
+ });
292
+
293
+ if (body !== null) for await (const chunk of body) busboy.write(chunk);
294
+ busboy.end();
295
+ await busboyResolve;
296
+
297
+ return responseFormData;
298
+ }
@@ -210,7 +210,7 @@ interface EnvironmentInheritable {
210
210
  * @default `[]`
211
211
  * @nonInheritable
212
212
  */
213
- worker_namespaces: {
213
+ dispatch_namespaces: {
214
214
  /** The binding name used to refer to the bound service. */
215
215
  binding: string;
216
216
  /** The namespace to bind to. */
@@ -91,7 +91,7 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
91
91
  unsafe,
92
92
  vars,
93
93
  wasm_modules,
94
- worker_namespaces,
94
+ dispatch_namespaces,
95
95
  } = bindings;
96
96
 
97
97
  if (data_blobs !== undefined && Object.keys(data_blobs).length > 0) {
@@ -219,10 +219,10 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
219
219
  });
220
220
  }
221
221
 
222
- if (worker_namespaces !== undefined && worker_namespaces.length > 0) {
222
+ if (dispatch_namespaces !== undefined && dispatch_namespaces.length > 0) {
223
223
  output.push({
224
- type: "Worker Namespaces",
225
- entries: worker_namespaces.map(({ binding, namespace }) => {
224
+ type: "dispatch namespaces",
225
+ entries: dispatch_namespaces.map(({ binding, namespace }) => {
226
226
  return {
227
227
  key: binding,
228
228
  value: namespace,
@@ -899,7 +899,7 @@ function normalizeAndValidateEnvironment(
899
899
 
900
900
  experimental(diagnostics, rawEnv, "unsafe");
901
901
  experimental(diagnostics, rawEnv, "services");
902
- experimental(diagnostics, rawEnv, "worker_namespaces");
902
+ experimental(diagnostics, rawEnv, "dispatch_namespaces");
903
903
 
904
904
  const route = normalizeAndValidateRoute(diagnostics, topLevelEnv, rawEnv);
905
905
 
@@ -1085,13 +1085,13 @@ function normalizeAndValidateEnvironment(
1085
1085
  validateBindingArray(envName, validateServiceBinding),
1086
1086
  []
1087
1087
  ),
1088
- worker_namespaces: notInheritable(
1088
+ dispatch_namespaces: notInheritable(
1089
1089
  diagnostics,
1090
1090
  topLevelEnv,
1091
1091
  rawConfig,
1092
1092
  rawEnv,
1093
1093
  envName,
1094
- "worker_namespaces",
1094
+ "dispatch_namespaces",
1095
1095
  validateBindingArray(envName, validateWorkerNamespaceBinding),
1096
1096
  []
1097
1097
  ),
@@ -23,6 +23,31 @@ export function toMimeType(type: CfModuleType): string {
23
23
  }
24
24
  }
25
25
 
26
+ type WorkerMetadataBinding =
27
+ // If you add any new binding types here, also add it to safeBindings
28
+ // under validateUnsafeBinding in config/validation.ts
29
+ | { type: "plain_text"; name: string; text: string }
30
+ | { type: "json"; name: string; json: unknown }
31
+ | { type: "wasm_module"; name: string; part: string }
32
+ | { type: "text_blob"; name: string; part: string }
33
+ | { type: "data_blob"; name: string; part: string }
34
+ | { type: "kv_namespace"; name: string; namespace_id: string }
35
+ | {
36
+ type: "durable_object_namespace";
37
+ name: string;
38
+ class_name: string;
39
+ script_name?: string;
40
+ environment?: string;
41
+ }
42
+ | { type: "r2_bucket"; name: string; bucket_name: string }
43
+ | { type: "service"; name: string; service: string; environment?: string }
44
+ | { type: "namespace"; name: string; namespace: string }
45
+ | {
46
+ type: "logfwdr";
47
+ name: string;
48
+ destination: string;
49
+ };
50
+
26
51
  export interface WorkerMetadata {
27
52
  /** The name of the entry point module. Only exists when the worker is in the ES module format */
28
53
  main_module?: string;
@@ -33,31 +58,8 @@ export interface WorkerMetadata {
33
58
  usage_model?: "bundled" | "unbound";
34
59
  migrations?: CfDurableObjectMigrations;
35
60
  capnp_schema?: string;
36
- // If you add any new binding types here, also add it to safeBindings
37
- // under validateUnsafeBinding in config/validation.ts
38
- bindings: (
39
- | { type: "plain_text"; name: string; text: string }
40
- | { type: "json"; name: string; json: unknown }
41
- | { type: "wasm_module"; name: string; part: string }
42
- | { type: "text_blob"; name: string; part: string }
43
- | { type: "data_blob"; name: string; part: string }
44
- | { type: "kv_namespace"; name: string; namespace_id: string }
45
- | {
46
- type: "durable_object_namespace";
47
- name: string;
48
- class_name: string;
49
- script_name?: string;
50
- environment?: string;
51
- }
52
- | { type: "r2_bucket"; name: string; bucket_name: string }
53
- | { type: "service"; name: string; service: string; environment?: string }
54
- | { type: "namespace"; name: string; namespace: string }
55
- | {
56
- type: "logfwdr";
57
- name: string;
58
- destination: string;
59
- }
60
- )[];
61
+ bindings: WorkerMetadataBinding[];
62
+ keep_bindings: WorkerMetadataBinding["type"][];
61
63
  }
62
64
 
63
65
  /**
@@ -123,7 +125,7 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
123
125
  });
124
126
  });
125
127
 
126
- bindings.worker_namespaces?.forEach(({ binding, namespace }) => {
128
+ bindings.dispatch_namespaces?.forEach(({ binding, namespace }) => {
127
129
  metadataBindings.push({
128
130
  name: binding,
129
131
  type: "namespace",
@@ -255,6 +257,7 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
255
257
  ...(usage_model && { usage_model }),
256
258
  ...(migrations && { migrations }),
257
259
  capnp_schema: bindings.logfwdr?.schema,
260
+ keep_bindings: ["plain_text", "json"],
258
261
  };
259
262
 
260
263
  formData.set("metadata", JSON.stringify(metadata));
@@ -182,7 +182,7 @@ export function useWorker(props: {
182
182
  } = props;
183
183
  const [session, setSession] = useState<CfPreviewSession | undefined>();
184
184
  const [token, setToken] = useState<CfPreviewToken | undefined>();
185
-
185
+ const [restartCounter, setRestartCounter] = useState<number>(0);
186
186
  // This is the most reliable way to detect whether
187
187
  // something's "happened" in our system; We make a ref and
188
188
  // mark it once we log our initial message. Refs are vars!
@@ -237,6 +237,7 @@ export function useWorker(props: {
237
237
  props.routes,
238
238
  props.zone,
239
239
  props.sendMetrics,
240
+ restartCounter,
240
241
  ]);
241
242
 
242
243
  // This effect uses the session to upload the worker and create a preview
@@ -314,6 +315,7 @@ export function useWorker(props: {
314
315
  compatibility_date: compatibilityDate,
315
316
  compatibility_flags: compatibilityFlags,
316
317
  usage_model: usageModel,
318
+ keep_bindings: true,
317
319
  };
318
320
 
319
321
  const workerAccount: CfAccount = {
@@ -379,6 +381,13 @@ export function useWorker(props: {
379
381
  logger.error(
380
382
  `${errorMessage}\n${solutionMessage}\n${onboardingLink}`
381
383
  );
384
+ } else if (err.code === 10049) {
385
+ logger.log("Preview token expired, fetching a new one");
386
+ // code 10049 happens when the preview token expires
387
+ // since we want a new preview token when this happens,
388
+ // lets increment the counter, and trigger a rerun of
389
+ // the useEffect above
390
+ setRestartCounter((prevCount) => prevCount + 1);
382
391
  } else {
383
392
  logger.error("Error on remote worker:", err);
384
393
  }
package/src/dev.tsx CHANGED
@@ -63,6 +63,8 @@ interface DevArgs {
63
63
  tsconfig?: string;
64
64
  local?: boolean;
65
65
  minify?: boolean;
66
+ var?: string[];
67
+ define?: string[];
66
68
  "node-compat"?: boolean;
67
69
  "experimental-enable-local-persistence"?: boolean;
68
70
  "live-reload"?: boolean;
@@ -129,7 +131,6 @@ export function devOptions(yargs: Argv): Argv<DevArgs> {
129
131
  .option("ip", {
130
132
  describe: "IP address to listen on",
131
133
  type: "string",
132
- default: "0.0.0.0",
133
134
  })
134
135
  .option("port", {
135
136
  describe: "Port to listen on",
@@ -196,6 +197,19 @@ export function devOptions(yargs: Argv): Argv<DevArgs> {
196
197
  describe: "Protocol to forward requests to host on, defaults to https.",
197
198
  choices: ["http", "https"] as const,
198
199
  })
200
+ .option("var", {
201
+ describe:
202
+ "A key-value pair to be injected into the script as a variable",
203
+ type: "string",
204
+ requiresArg: true,
205
+ array: true,
206
+ })
207
+ .option("define", {
208
+ describe: "A key-value pair to be substituted in the script",
209
+ type: "string",
210
+ requiresArg: true,
211
+ array: true,
212
+ })
199
213
  .option("jsx-factory", {
200
214
  describe: "The function that is called for each JSX element",
201
215
  type: "string",
@@ -427,22 +441,36 @@ export async function startDev(args: StartDevOptions) {
427
441
  const getLocalPort = memoizeGetPort(DEFAULT_LOCAL_PORT);
428
442
  const getInspectorPort = memoizeGetPort(DEFAULT_INSPECTOR_PORT);
429
443
 
444
+ const cliVars =
445
+ args.var?.reduce<Record<string, string>>((collectVars, v) => {
446
+ const [key, ...value] = v.split(":");
447
+ collectVars[key] = value.join("");
448
+ return collectVars;
449
+ }, {}) || {};
450
+
451
+ const cliDefines =
452
+ args.define?.reduce<Record<string, string>>((collectDefines, d) => {
453
+ const [key, ...value] = d.split(":");
454
+ collectDefines[key] = value.join("");
455
+ return collectDefines;
456
+ }, {}) || {};
457
+
430
458
  // eslint-disable-next-line no-inner-declarations
431
459
  async function getDevReactElement(configParam: Config) {
432
460
  // now log all available bindings into the terminal
433
461
  const bindings = await getBindings(configParam, {
434
462
  kv: args.kv,
435
- vars: args.vars,
463
+ vars: { ...args.vars, ...cliVars },
436
464
  durableObjects: args.durableObjects,
437
465
  r2: args.r2,
438
466
  });
439
467
 
440
- // mask anything that was overridden in .dev.vars
468
+ // mask anything that was overridden in .dev.vars or cli args
441
469
  // so that we don't log potential secrets into the terminal
442
470
  const maskedVars = { ...bindings.vars };
443
471
  for (const key of Object.keys(maskedVars)) {
444
472
  if (maskedVars[key] !== configParam.vars[key]) {
445
- // This means it was overridden in .dev.vars
473
+ // This means it was overridden in .dev.vars or cli args
446
474
  // so let's mask it
447
475
  maskedVars[key] = "(hidden)";
448
476
  }
@@ -477,7 +505,7 @@ export async function startDev(args: StartDevOptions) {
477
505
  minify={args.minify ?? config.minify}
478
506
  nodeCompat={nodeCompat}
479
507
  build={config.build || {}}
480
- define={config.define}
508
+ define={{ ...config.define, ...cliDefines }}
481
509
  initialMode={args.local ? "local" : "remote"}
482
510
  jsxFactory={args["jsx-factory"] || config.jsx_factory}
483
511
  jsxFragment={args["jsx-fragment"] || config.jsx_fragment}
@@ -615,7 +643,7 @@ async function getBindings(
615
643
  ) || []),
616
644
  ...(args.r2 || []),
617
645
  ],
618
- worker_namespaces: configParam.worker_namespaces,
646
+ dispatch_namespaces: configParam.dispatch_namespaces,
619
647
  services: configParam.services,
620
648
  unsafe: configParam.unsafe?.bindings,
621
649
  logfwdr: configParam.logfwdr,