wrangler 2.0.25 → 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.
Files changed (66) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +15 -3
  3. package/package.json +8 -6
  4. package/src/__tests__/configuration.test.ts +33 -29
  5. package/src/__tests__/dev.test.tsx +8 -6
  6. package/src/__tests__/generate.test.ts +2 -4
  7. package/src/__tests__/helpers/mock-cfetch.ts +33 -0
  8. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  9. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  10. package/src/__tests__/index.test.ts +30 -30
  11. package/src/__tests__/init.test.ts +537 -359
  12. package/src/__tests__/jest.setup.ts +7 -0
  13. package/src/__tests__/metrics.test.ts +1 -1
  14. package/src/__tests__/pages.test.ts +14 -0
  15. package/src/__tests__/publish.test.ts +59 -18
  16. package/src/__tests__/r2.test.ts +4 -3
  17. package/src/__tests__/tail.test.ts +53 -3
  18. package/src/__tests__/test-old-node-version.js +3 -3
  19. package/src/__tests__/user.test.ts +11 -0
  20. package/src/__tests__/worker-namespace.test.ts +37 -35
  21. package/src/api/dev.ts +1 -0
  22. package/src/bundle.ts +1 -1
  23. package/src/cfetch/internal.ts +118 -1
  24. package/src/config/environment.ts +1 -1
  25. package/src/config/index.ts +4 -4
  26. package/src/config/validation-helpers.ts +19 -6
  27. package/src/config/validation.ts +11 -5
  28. package/src/config-cache.ts +2 -1
  29. package/src/create-worker-upload-form.ts +29 -26
  30. package/src/dev/dev.tsx +4 -0
  31. package/src/dev/remote.tsx +10 -1
  32. package/src/dev.tsx +36 -8
  33. package/src/{worker-namespace.ts → dispatch-namespace.ts} +18 -18
  34. package/src/generate.ts +1 -1
  35. package/src/index.tsx +54 -8
  36. package/src/init.ts +111 -38
  37. package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
  38. package/src/metrics/metrics-config.ts +1 -1
  39. package/src/metrics/send-event.ts +5 -5
  40. package/src/miniflare-cli/assets.ts +8 -0
  41. package/src/miniflare-cli/index.ts +6 -3
  42. package/src/pages/build.tsx +41 -15
  43. package/src/pages/constants.ts +1 -0
  44. package/src/pages/dev.tsx +93 -37
  45. package/src/pages/errors.ts +22 -0
  46. package/src/pages/functions/routes-consolidation.test.ts +185 -1
  47. package/src/pages/functions/routes-consolidation.ts +46 -2
  48. package/src/pages/functions/routes-transformation.ts +0 -3
  49. package/src/pages/functions.tsx +96 -0
  50. package/src/pages/index.tsx +65 -55
  51. package/src/pages/publish.tsx +27 -16
  52. package/src/proxy.ts +10 -0
  53. package/src/publish.ts +19 -4
  54. package/src/r2.ts +4 -4
  55. package/src/tail/filters.ts +3 -1
  56. package/src/tail/printing.ts +2 -0
  57. package/src/user/user.tsx +6 -4
  58. package/src/whoami.tsx +5 -5
  59. package/src/worker.ts +3 -2
  60. package/src/zones.ts +91 -0
  61. package/templates/pages-template-plugin.ts +16 -4
  62. package/templates/pages-template-worker.ts +16 -5
  63. package/templates/service-bindings-module-facade.js +10 -7
  64. package/templates/service-bindings-sw-facade.js +10 -7
  65. package/wrangler-dist/cli.d.ts +8 -3
  66. package/wrangler-dist/cli.js +6757 -1639
@@ -1,7 +1,9 @@
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";
6
+ import { logger } from "../logger";
5
7
  import { ParseError, parseJSON } from "../parse";
6
8
  import { loginOrRefreshIfRequired, requireApiToken } from "../user";
7
9
  import type { ApiCredentials } from "../user";
@@ -44,6 +46,13 @@ export async function fetchInternal<ResponseType>(
44
46
 
45
47
  const queryString = queryParams ? `?${queryParams.toString()}` : "";
46
48
  const method = init.method ?? "GET";
49
+
50
+ logger.debug(
51
+ `-- START CF API REQUEST: ${method} ${getCloudflareAPIBaseURL()}${resource}${queryString}`
52
+ );
53
+ logger.debug("HEADERS:", JSON.stringify(headers, null, 2));
54
+ logger.debug("INIT:", JSON.stringify(init, null, 2));
55
+ logger.debug("-- END CF API REQUEST");
47
56
  const response = await fetch(
48
57
  `${getCloudflareAPIBaseURL()}${resource}${queryString}`,
49
58
  {
@@ -54,6 +63,15 @@ export async function fetchInternal<ResponseType>(
54
63
  }
55
64
  );
56
65
  const jsonText = await response.text();
66
+ logger.debug(
67
+ "-- START CF API RESPONSE:",
68
+ response.statusText,
69
+ response.status
70
+ );
71
+ logger.debug("HEADERS:", JSON.stringify(response.headers, null, 2));
72
+ logger.debug("RESPONSE:", jsonText);
73
+ logger.debug("-- END CF API RESPONSE");
74
+
57
75
  try {
58
76
  return parseJSON<ResponseType>(jsonText);
59
77
  } catch (err) {
@@ -179,3 +197,102 @@ export async function fetchR2Objects(
179
197
  );
180
198
  }
181
199
  }
200
+
201
+ /**
202
+ * This is a wrapper STOPGAP for getting the script which returns a raw text response.
203
+ */
204
+ export async function fetchDashboardScript(
205
+ resource: string,
206
+ bodyInit: RequestInit = {}
207
+ ): Promise<string> {
208
+ await requireLoggedIn();
209
+ const auth = requireApiToken();
210
+ const headers = cloneHeaders(bodyInit.headers);
211
+ addAuthorizationHeaderIfUnspecified(headers, auth);
212
+ addUserAgent(headers);
213
+
214
+ const response = await fetch(`${getCloudflareAPIBaseURL()}${resource}`, {
215
+ ...bodyInit,
216
+ headers,
217
+ });
218
+
219
+ if (!response.ok || !response.body) {
220
+ throw new Error(
221
+ `Failed to fetch ${resource} - ${response.status}: ${response.statusText});`
222
+ );
223
+ }
224
+
225
+ const usesModules = response.headers
226
+ .get("content-type")
227
+ ?.startsWith("multipart");
228
+
229
+ if (usesModules) {
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 ?? "";
242
+
243
+ // Follow up on issue in Undici about multipart/form-data support & replace the workaround: https://github.com/nodejs/undici/issues/974
244
+ // This should be using a builtin formData() parser pattern.
245
+ } else {
246
+ return response.text();
247
+ }
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,
@@ -383,7 +383,7 @@ export const validateRequiredProperty = (
383
383
  container: string,
384
384
  key: string,
385
385
  value: unknown,
386
- type: string,
386
+ type: TypeofType,
387
387
  choices?: unknown[]
388
388
  ): boolean => {
389
389
  if (container) {
@@ -417,7 +417,7 @@ export const validateOptionalProperty = (
417
417
  container: string,
418
418
  key: string,
419
419
  value: unknown,
420
- type: string,
420
+ type: TypeofType,
421
421
  choices?: unknown[]
422
422
  ): boolean => {
423
423
  if (value !== undefined) {
@@ -440,7 +440,7 @@ export const validateTypedArray = (
440
440
  diagnostics: Diagnostics,
441
441
  container: string,
442
442
  value: unknown,
443
- type: string
443
+ type: TypeofType
444
444
  ): boolean => {
445
445
  let isValid = true;
446
446
  if (!Array.isArray(value)) {
@@ -472,7 +472,7 @@ export const validateOptionalTypedArray = (
472
472
  diagnostics: Diagnostics,
473
473
  container: string,
474
474
  value: unknown,
475
- type: string
475
+ type: TypeofType
476
476
  ) => {
477
477
  if (value !== undefined) {
478
478
  return validateTypedArray(diagnostics, container, value, type);
@@ -486,7 +486,7 @@ export const validateOptionalTypedArray = (
486
486
  export const isRequiredProperty = <T extends object>(
487
487
  obj: object,
488
488
  prop: keyof T,
489
- type: string,
489
+ type: TypeofType,
490
490
  choices?: unknown[]
491
491
  ): obj is T =>
492
492
  hasProperty<T>(obj, prop) &&
@@ -499,7 +499,7 @@ export const isRequiredProperty = <T extends object>(
499
499
  export const isOptionalProperty = <T extends object>(
500
500
  obj: object,
501
501
  prop: keyof T,
502
- type: string
502
+ type: TypeofType
503
503
  ): obj is T => !hasProperty<T>(obj, prop) || typeof obj[prop] === type;
504
504
 
505
505
  /**
@@ -582,3 +582,16 @@ const isRecord = (
582
582
  value: unknown
583
583
  ): value is Record<string | number | symbol, unknown> =>
584
584
  typeof value === "object" && value !== null && !Array.isArray(value);
585
+
586
+ /**
587
+ * JavaScript `typeof` operator return values.
588
+ */
589
+ type TypeofType =
590
+ | "string"
591
+ | "number"
592
+ | "bigint"
593
+ | "boolean"
594
+ | "symbol"
595
+ | "undefined"
596
+ | "object"
597
+ | "function";
@@ -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
  ),
@@ -1630,7 +1630,10 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
1630
1630
  );
1631
1631
  isValid = false;
1632
1632
  }
1633
- if (!isRequiredProperty(value, "id", "string")) {
1633
+ if (
1634
+ !isRequiredProperty(value, "id", "string") ||
1635
+ (value as { id: string }).id.length === 0
1636
+ ) {
1634
1637
  diagnostics.errors.push(
1635
1638
  `"${field}" bindings should have a string "id" field but got ${JSON.stringify(
1636
1639
  value
@@ -1668,7 +1671,10 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
1668
1671
  );
1669
1672
  isValid = false;
1670
1673
  }
1671
- if (!isRequiredProperty(value, "bucket_name", "string")) {
1674
+ if (
1675
+ !isRequiredProperty(value, "bucket_name", "string") ||
1676
+ (value as { bucket_name: string }).bucket_name.length === 0
1677
+ ) {
1672
1678
  diagnostics.errors.push(
1673
1679
  `"${field}" bindings should have a string "bucket_name" field but got ${JSON.stringify(
1674
1680
  value
@@ -1,6 +1,7 @@
1
1
  import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
2
2
  import * as path from "path";
3
3
  import { findUpSync } from "find-up";
4
+ import { CI } from "./is-ci";
4
5
  import isInteractive from "./is-interactive";
5
6
  import { logger } from "./logger";
6
7
 
@@ -29,7 +30,7 @@ const arrayFormatter = new Intl.ListFormat("en", {
29
30
  });
30
31
 
31
32
  function showCacheMessage(fields: string[], folder: string) {
32
- if (!cacheMessageShown && isInteractive()) {
33
+ if (!cacheMessageShown && isInteractive() && !CI.isCI()) {
33
34
  if (fields.length > 0) {
34
35
  logger.log(
35
36
  `Retrieving cached values for ${arrayFormatter.format(
@@ -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));
package/src/dev/dev.tsx CHANGED
@@ -493,6 +493,10 @@ function useHotkeys(props: {
493
493
  break;
494
494
  // open browser
495
495
  case "b": {
496
+ if (ip === "0.0.0.0") {
497
+ await openInBrowser(`${localProtocol}://127.0.0.1:${port}`);
498
+ return;
499
+ }
496
500
  await openInBrowser(`${localProtocol}://${ip}:${port}`);
497
501
  break;
498
502
  }
@@ -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}
@@ -502,10 +530,10 @@ export async function startDev(args: StartDevOptions) {
502
530
  isWorkersSite={Boolean(args.site || config.site)}
503
531
  compatibilityDate={getDevCompatibilityDate(
504
532
  config,
505
- args["compatibility-date"]
533
+ args.compatibilityDate
506
534
  )}
507
535
  compatibilityFlags={
508
- args["compatibility-flags"] || config.compatibility_flags
536
+ args.compatibilityFlags || config.compatibility_flags
509
537
  }
510
538
  usageModel={config.usage_model}
511
539
  bindings={bindings}
@@ -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,
@@ -34,7 +34,7 @@ async function createWorkerNamespace(accountId: string, name: string) {
34
34
  }
35
35
  );
36
36
  logger.log(
37
- `Created Worker namespace "${name}" with ID "${namespace.namespace_id}"`
37
+ `Created dispatch namespace "${name}" with ID "${namespace.namespace_id}"`
38
38
  );
39
39
  }
40
40
 
@@ -46,7 +46,7 @@ async function deleteWorkerNamespace(accountId: string, name: string) {
46
46
  `/accounts/${accountId}/workers/dispatch/namespaces/${name}`,
47
47
  { method: "DELETE" }
48
48
  );
49
- logger.log(`Deleted Worker namespace "${name}"`);
49
+ logger.log(`Deleted dispatch namespace "${name}"`);
50
50
  }
51
51
 
52
52
  /**
@@ -101,7 +101,7 @@ async function renameWorkerNamespace(
101
101
  body: JSON.stringify({ name: newName }),
102
102
  }
103
103
  );
104
- logger.log(`Renamed Worker namespace "${oldName}" to "${newName}"`);
104
+ logger.log(`Renamed dispatch namespace "${oldName}" to "${newName}"`);
105
105
  }
106
106
 
107
107
  export function workerNamespaceCommands(
@@ -110,20 +110,20 @@ export function workerNamespaceCommands(
110
110
  ): Argv {
111
111
  return workerNamespaceYargs
112
112
  .command(subHelp)
113
- .command("list", "List all Worker namespaces", {}, async (args) => {
113
+ .command("list", "List all dispatch namespaces", {}, async (args) => {
114
114
  const config = readConfig(args.config as ConfigPath, args);
115
115
  const accountId = await requireAuth(config);
116
116
  await listWorkerNamespaces(accountId);
117
- await metrics.sendMetricsEvent("list worker namespaces", {
117
+ await metrics.sendMetricsEvent("list dispatch namespaces", {
118
118
  sendMetrics: config.send_metrics,
119
119
  });
120
120
  })
121
121
  .command(
122
122
  "get <name>",
123
- "Get information about a Worker namespace",
123
+ "Get information about a dispatch namespace",
124
124
  (yargs) => {
125
125
  return yargs.positional("name", {
126
- describe: "Name of the Worker namespace",
126
+ describe: "Name of the dispatch namespace",
127
127
  type: "string",
128
128
  demandOption: true,
129
129
  });
@@ -132,17 +132,17 @@ export function workerNamespaceCommands(
132
132
  const config = readConfig(args.config as ConfigPath, args);
133
133
  const accountId = await requireAuth(config);
134
134
  await getWorkerNamespaceInfo(accountId, args.name);
135
- await metrics.sendMetricsEvent("view worker namespace", {
135
+ await metrics.sendMetricsEvent("view dispatch namespace", {
136
136
  sendMetrics: config.send_metrics,
137
137
  });
138
138
  }
139
139
  )
140
140
  .command(
141
141
  "create <name>",
142
- "Create a Worker namespace",
142
+ "Create a dispatch namespace",
143
143
  (yargs) => {
144
144
  return yargs.positional("name", {
145
- describe: "Name of the Worker namespace",
145
+ describe: "Name of the dispatch namespace",
146
146
  type: "string",
147
147
  demandOption: true,
148
148
  });
@@ -152,17 +152,17 @@ export function workerNamespaceCommands(
152
152
  const config = readConfig(args.config as ConfigPath, args);
153
153
  const accountId = await requireAuth(config);
154
154
  await createWorkerNamespace(accountId, args.name);
155
- await metrics.sendMetricsEvent("create worker namespace", {
155
+ await metrics.sendMetricsEvent("create dispatch namespace", {
156
156
  sendMetrics: config.send_metrics,
157
157
  });
158
158
  }
159
159
  )
160
160
  .command(
161
161
  "delete <name>",
162
- "Delete a Worker namespace",
162
+ "Delete a dispatch namespace",
163
163
  (yargs) => {
164
164
  return yargs.positional("name", {
165
- describe: "Name of the Worker namespace",
165
+ describe: "Name of the dispatch namespace",
166
166
  type: "string",
167
167
  demandOption: true,
168
168
  });
@@ -172,23 +172,23 @@ export function workerNamespaceCommands(
172
172
  const config = readConfig(args.config as ConfigPath, args);
173
173
  const accountId = await requireAuth(config);
174
174
  await deleteWorkerNamespace(accountId, args.name);
175
- await metrics.sendMetricsEvent("delete worker namespace", {
175
+ await metrics.sendMetricsEvent("delete dispatch namespace", {
176
176
  sendMetrics: config.send_metrics,
177
177
  });
178
178
  }
179
179
  )
180
180
  .command(
181
181
  "rename <old-name> <new-name>",
182
- "Rename a Worker namespace",
182
+ "Rename a dispatch namespace",
183
183
  (yargs) => {
184
184
  return yargs
185
185
  .positional("old-name", {
186
- describe: "Name of the Worker namespace",
186
+ describe: "Name of the dispatch namespace",
187
187
  type: "string",
188
188
  demandOption: true,
189
189
  })
190
190
  .positional("new-name", {
191
- describe: "New name of the Worker namespace",
191
+ describe: "New name of the dispatch namespace",
192
192
  type: "string",
193
193
  demandOption: true,
194
194
  });
@@ -198,7 +198,7 @@ export function workerNamespaceCommands(
198
198
  const config = readConfig(args.config as ConfigPath, args);
199
199
  const accountId = await requireAuth(config);
200
200
  await renameWorkerNamespace(accountId, args.oldName, args.newName);
201
- await metrics.sendMetricsEvent("rename worker namespace", {
201
+ await metrics.sendMetricsEvent("rename dispatch namespace", {
202
202
  sendMetrics: config.send_metrics,
203
203
  });
204
204
  }