wrangler 2.0.27 → 2.1.0

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 (65) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +1141 -369
  3. package/package.json +6 -4
  4. package/src/__tests__/api-dev.test.ts +19 -0
  5. package/src/__tests__/configuration.test.ts +27 -27
  6. package/src/__tests__/dev.test.tsx +8 -6
  7. package/src/__tests__/helpers/hello-world-worker.js +5 -0
  8. package/src/__tests__/helpers/mock-cfetch.ts +4 -4
  9. package/src/__tests__/helpers/mock-console.ts +11 -2
  10. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  11. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  12. package/src/__tests__/index.test.ts +37 -37
  13. package/src/__tests__/init.test.ts +356 -5
  14. package/src/__tests__/jest.setup.ts +13 -0
  15. package/src/__tests__/middleware.test.ts +768 -0
  16. package/src/__tests__/pages.test.ts +829 -104
  17. package/src/__tests__/paths.test.ts +17 -0
  18. package/src/__tests__/publish.test.ts +512 -445
  19. package/src/__tests__/tail.test.ts +79 -72
  20. package/src/__tests__/test-old-node-version.js +3 -3
  21. package/src/__tests__/worker-namespace.test.ts +37 -35
  22. package/src/api/dev.ts +93 -28
  23. package/src/bundle.ts +239 -12
  24. package/src/cfetch/internal.ts +64 -3
  25. package/src/cli.ts +1 -1
  26. package/src/config/environment.ts +1 -1
  27. package/src/config/index.ts +4 -4
  28. package/src/config/validation.ts +3 -3
  29. package/src/create-worker-upload-form.ts +29 -26
  30. package/src/dev/dev.tsx +3 -1
  31. package/src/dev/local.tsx +319 -171
  32. package/src/dev/remote.tsx +16 -4
  33. package/src/dev/start-server.ts +416 -0
  34. package/src/dev/use-esbuild.ts +4 -0
  35. package/src/dev.tsx +340 -166
  36. package/src/dialogs.tsx +12 -0
  37. package/src/{worker-namespace.ts → dispatch-namespace.ts} +18 -18
  38. package/src/entry.ts +2 -1
  39. package/src/index.tsx +59 -12
  40. package/src/init.ts +291 -16
  41. package/src/metrics/send-event.ts +6 -5
  42. package/src/miniflare-cli/assets.ts +130 -476
  43. package/src/miniflare-cli/index.ts +39 -33
  44. package/src/pages/constants.ts +3 -0
  45. package/src/pages/dev.tsx +8 -3
  46. package/src/pages/functions/buildPlugin.ts +2 -1
  47. package/src/pages/functions/buildWorker.ts +2 -1
  48. package/src/pages/functions/routes-transformation.test.ts +12 -1
  49. package/src/pages/functions/routes-transformation.ts +7 -1
  50. package/src/pages/hash.tsx +13 -0
  51. package/src/pages/publish.tsx +82 -38
  52. package/src/pages/upload.tsx +3 -18
  53. package/src/paths.ts +20 -1
  54. package/src/publish.ts +49 -8
  55. package/src/tail/filters.ts +1 -5
  56. package/src/tail/index.ts +6 -3
  57. package/src/worker.ts +10 -9
  58. package/src/zones.ts +91 -0
  59. package/templates/middleware/common.ts +62 -0
  60. package/templates/middleware/loader-modules.ts +84 -0
  61. package/templates/middleware/loader-sw.ts +213 -0
  62. package/templates/middleware/middleware-pretty-error.ts +40 -0
  63. package/templates/middleware/middleware-scheduled.ts +14 -0
  64. package/wrangler-dist/cli.d.ts +22 -8
  65. package/wrangler-dist/cli.js +71020 -65212
package/src/bundle.ts CHANGED
@@ -7,6 +7,7 @@ import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill";
7
7
  import * as esbuild from "esbuild";
8
8
  import tmp from "tmp-promise";
9
9
  import createModuleCollector from "./module-collection";
10
+ import { getBasePath } from "./paths";
10
11
  import type { Config } from "./config";
11
12
  import type { WorkerRegistry } from "./dev-registry";
12
13
  import type { Entry } from "./entry";
@@ -71,9 +72,10 @@ export async function bundleWorker(
71
72
  nodeCompat: boolean | undefined;
72
73
  define: Config["define"];
73
74
  checkFetch: boolean;
74
- services: Config["services"];
75
+ services: Config["services"] | undefined;
75
76
  workerDefinitions: WorkerRegistry | undefined;
76
77
  firstPartyWorkerDevFacade: boolean | undefined;
78
+ targetConsumer: "dev" | "publish";
77
79
  }
78
80
  ): Promise<BundleResult> {
79
81
  const {
@@ -90,6 +92,7 @@ export async function bundleWorker(
90
92
  workerDefinitions,
91
93
  services,
92
94
  firstPartyWorkerDevFacade,
95
+ targetConsumer,
93
96
  } = options;
94
97
 
95
98
  // We create a temporary directory for any oneoff files we
@@ -129,7 +132,7 @@ export async function bundleWorker(
129
132
  });
130
133
  fs.writeFileSync(
131
134
  checkedFetchFileToInject,
132
- fs.readFileSync(path.resolve(__dirname, "../templates/checked-fetch.js"))
135
+ fs.readFileSync(path.resolve(getBasePath(), "templates/checked-fetch.js"))
133
136
  );
134
137
  }
135
138
 
@@ -139,6 +142,19 @@ export async function bundleWorker(
139
142
  // a new entry point, that we call "middleware" or "facades".
140
143
  // Look at implementations of these functions to learn more.
141
144
 
145
+ // We also have middleware that uses a more "traditional" middleware stack,
146
+ // which is all loaded as one in a stack.
147
+ const middlewareToLoad: MiddlewareLoader[] = [
148
+ // {
149
+ // path: "templates/middleware/middleware-pretty-error.ts",
150
+ // publish: true,
151
+ // dev: false,
152
+ // },
153
+ // {
154
+ // path: "../templates/middleware/middleware-scheduled.ts",
155
+ // },
156
+ ];
157
+
142
158
  type MiddlewareFn = (arg0: Entry) => Promise<Entry>;
143
159
  const middleware: (false | undefined | MiddlewareFn)[] = [
144
160
  // serve static assets
@@ -172,6 +188,32 @@ export async function bundleWorker(
172
188
  ((currentEntry: Entry) => {
173
189
  return applyFirstPartyWorkerDevFacade(currentEntry, tmpDir.path);
174
190
  }),
191
+
192
+ // Middleware loader: to add middleware, we add the path to the middleware
193
+ // Currently for demonstration purposes we have two example middlewares
194
+ // Middlewares are togglable by changing the `publish` (default=false) and `dev` (default=true) options
195
+ // As we are not yet supporting user created middlewares yet, if no wrangler applied middleware
196
+ // are found, we will not load any middleware. We also need to check if there are middlewares compatible with
197
+ // the target consumer (dev / publish).
198
+ (middlewareToLoad.filter(
199
+ (m) =>
200
+ (m.publish && targetConsumer === "publish") ||
201
+ (m.dev !== false && targetConsumer === "dev")
202
+ ).length > 0 ||
203
+ process.env.EXPERIMENTAL_MIDDLEWARE === "true") &&
204
+ ((currentEntry: Entry) => {
205
+ return applyMiddlewareLoaderFacade(
206
+ currentEntry,
207
+ tmpDir.path,
208
+ middlewareToLoad.filter(
209
+ // We dynamically filter the middleware depending on where we are bundling for
210
+ (m) =>
211
+ (targetConsumer === "dev" && m.dev !== false) ||
212
+ (m.publish && targetConsumer === "publish")
213
+ ),
214
+ moduleCollector.plugin
215
+ );
216
+ }),
175
217
  ].filter(Boolean);
176
218
 
177
219
  let inputEntry = entry;
@@ -214,7 +256,11 @@ export async function bundleWorker(
214
256
  ".cjs": "jsx",
215
257
  },
216
258
  plugins: [
217
- moduleCollector.plugin,
259
+ // We run the moduleCollector plugin for service workers as part of the middleware loader
260
+ // so we only run here for modules or with no middleware to load
261
+ ...(entry.format === "modules" || middlewareToLoad.length === 0
262
+ ? [moduleCollector.plugin]
263
+ : []),
218
264
  ...(nodeCompat
219
265
  ? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
220
266
  : // we use checkForNodeBuiltinsPlugin to throw a nicer error
@@ -302,7 +348,9 @@ async function applyFormatDevErrorsFacade(
302
348
  ): Promise<Entry> {
303
349
  const targetPath = path.join(tmpDirPath, "format-dev-errors.entry.js");
304
350
  await esbuild.build({
305
- entryPoints: [path.resolve(__dirname, "../templates/format-dev-errors.ts")],
351
+ entryPoints: [
352
+ path.resolve(getBasePath(), "templates/format-dev-errors.ts"),
353
+ ],
306
354
  bundle: true,
307
355
  sourcemap: true,
308
356
  format: "esm",
@@ -320,6 +368,185 @@ async function applyFormatDevErrorsFacade(
320
368
  };
321
369
  }
322
370
 
371
+ /**
372
+ * A facade that acts as a "middleware loader".
373
+ * Instead of needing to apply a facade for each individual middleware, this allows
374
+ * middleware to be written in a more traditional manner and then be applied all
375
+ * at once, requiring just two esbuild steps, rather than 1 per middleware.
376
+ */
377
+
378
+ interface MiddlewareLoader {
379
+ path: string;
380
+ // By default all middleware will run on dev, but will not be run when published
381
+ publish?: boolean;
382
+ dev?: boolean;
383
+ }
384
+
385
+ async function applyMiddlewareLoaderFacade(
386
+ entry: Entry,
387
+ tmpDirPath: string,
388
+ middleware: MiddlewareLoader[], // a list of paths to middleware files
389
+ moduleCollectorPlugin: esbuild.Plugin
390
+ ): Promise<Entry> {
391
+ // Firstly we need to insert the middleware array into the project,
392
+ // and then we load the middleware - this insertion and loading is
393
+ // different for each format.
394
+
395
+ // STEP 1: Insert the middleware
396
+ const targetPathInsertion = path.join(
397
+ tmpDirPath,
398
+ "middleware-insertion.entry.js"
399
+ );
400
+
401
+ // We need to import each of the middlewares, so we need to generate a
402
+ // random, unique identifier that we can use for the import.
403
+ // Middlewares are required to be default exports so we can import to any name.
404
+ const middlewareIdentifiers = middleware.map(
405
+ (_, index) => `__MIDDLEWARE_${index}__`
406
+ );
407
+
408
+ const dynamicFacadePath = path.join(
409
+ tmpDirPath,
410
+ "middleware-insertion-facade.js"
411
+ );
412
+
413
+ if (entry.format === "modules") {
414
+ // We use a facade to expose the required middleware alongside any user defined
415
+ // middleware on the worker object
416
+
417
+ const imports = middlewareIdentifiers
418
+ .map((m) => `import ${m} from "${m}";`)
419
+ .join("\n");
420
+
421
+ // write a file with all of the imports required
422
+ fs.writeFileSync(
423
+ dynamicFacadePath,
424
+ `import worker from "__ENTRY_POINT__";
425
+ ${imports}
426
+ const facade = {
427
+ ...worker,
428
+ middleware: [
429
+ ${middlewareIdentifiers.join(",")}${middlewareIdentifiers.length > 0 ? "," : ""}
430
+ ...(worker.middleware ? worker.middleware : []),
431
+ ]
432
+ }
433
+ export * from "__ENTRY_POINT__";
434
+ export default facade;`
435
+ );
436
+
437
+ await esbuild.build({
438
+ entryPoints: [path.resolve(getBasePath(), dynamicFacadePath)],
439
+ bundle: true,
440
+ sourcemap: true,
441
+ format: "esm",
442
+ plugins: [
443
+ esbuildAliasExternalPlugin({
444
+ __ENTRY_POINT__: entry.file,
445
+ ...Object.fromEntries(
446
+ middleware.map((val, index) => [
447
+ middlewareIdentifiers[index],
448
+ path.resolve(getBasePath(), val.path),
449
+ ])
450
+ ),
451
+ }),
452
+ ],
453
+ outfile: targetPathInsertion,
454
+ });
455
+ } else {
456
+ // We handle service workers slightly differently as we have to overwrite
457
+ // the event listeners and reimplement them
458
+
459
+ await esbuild.build({
460
+ entryPoints: [entry.file],
461
+ bundle: true,
462
+ sourcemap: true,
463
+ define: {
464
+ "process.env.NODE_ENV": `"${process.env["NODE_ENV" + ""]}"`,
465
+ },
466
+ format: "esm",
467
+ outfile: targetPathInsertion,
468
+ plugins: [moduleCollectorPlugin],
469
+ });
470
+
471
+ const imports = middlewareIdentifiers
472
+ .map(
473
+ (m, i) =>
474
+ `import ${m} from "${path.resolve(
475
+ getBasePath(),
476
+ middleware[i].path
477
+ )}";`
478
+ )
479
+ .join("\n");
480
+
481
+ // We add the new modules with imports and then register using the
482
+ // addMiddleware function (which gets rewritten in the next build step)
483
+
484
+ // We choose to run middleware inserted in wrangler before user inserted
485
+ // middleware in the stack
486
+ // To do this, we either need to execute the addMiddleware function first
487
+ // before any user middleware, or use a separate handling function.
488
+ // We choose to do the latter as to prepend, we would have to load the entire
489
+ // script into memory as a prepend function doesn't exist or work in the same
490
+ // way that an append function does.
491
+
492
+ fs.copyFileSync(targetPathInsertion, dynamicFacadePath);
493
+ fs.appendFileSync(
494
+ dynamicFacadePath,
495
+ `
496
+ ${imports}
497
+ addMiddlewareInternal([${middlewareIdentifiers.join(",")}])
498
+ `
499
+ );
500
+ }
501
+
502
+ // STEP 2: Load the middleware
503
+ // We want to get the filename of the orginal entry point
504
+ let targetPathLoader = path.join(tmpDirPath, path.basename(entry.file));
505
+ if (path.extname(entry.file) === "") targetPathLoader += ".js";
506
+
507
+ const loaderPath =
508
+ entry.format === "modules"
509
+ ? path.resolve(getBasePath(), "templates/middleware/loader-modules.ts")
510
+ : dynamicFacadePath;
511
+
512
+ await esbuild.build({
513
+ entryPoints: [loaderPath],
514
+ bundle: true,
515
+ sourcemap: true,
516
+ format: "esm",
517
+ ...(entry.format === "service-worker"
518
+ ? {
519
+ inject: [
520
+ path.resolve(getBasePath(), "templates/middleware/loader-sw.ts"),
521
+ ],
522
+ define: {
523
+ addEventListener: "__facade_addEventListener__",
524
+ removeEventListener: "__facade_removeEventListener__",
525
+ dispatchEvent: "__facade_dispatchEvent__",
526
+ addMiddleware: "__facade_register__",
527
+ addMiddlewareInternal: "__facade_registerInternal__",
528
+ },
529
+ }
530
+ : {
531
+ plugins: [
532
+ esbuildAliasExternalPlugin({
533
+ __ENTRY_POINT__: targetPathInsertion,
534
+ "./common": path.resolve(
535
+ getBasePath(),
536
+ "templates/middleware/common.ts"
537
+ ),
538
+ }),
539
+ ],
540
+ }),
541
+ outfile: targetPathLoader,
542
+ });
543
+
544
+ return {
545
+ ...entry,
546
+ file: targetPathLoader,
547
+ };
548
+ }
549
+
323
550
  /**
324
551
  * A middleware that serves static assets from a worker.
325
552
  * This powers --assets / config.assets
@@ -334,7 +561,7 @@ async function applyStaticAssetFacade(
334
561
 
335
562
  await esbuild.build({
336
563
  entryPoints: [
337
- path.resolve(__dirname, "../templates/serve-static-assets.ts"),
564
+ path.resolve(getBasePath(), "templates/serve-static-assets.ts"),
338
565
  ],
339
566
  bundle: true,
340
567
  format: "esm",
@@ -342,7 +569,7 @@ async function applyStaticAssetFacade(
342
569
  plugins: [
343
570
  esbuildAliasExternalPlugin({
344
571
  __ENTRY_POINT__: entry.file,
345
- __KV_ASSET_HANDLER__: path.join(__dirname, "../kv-asset-handler.js"),
572
+ __KV_ASSET_HANDLER__: path.join(getBasePath(), "kv-asset-handler.js"),
346
573
  __STATIC_CONTENT_MANIFEST: "__STATIC_CONTENT_MANIFEST",
347
574
  }),
348
575
  ],
@@ -380,7 +607,7 @@ async function applyMultiWorkerDevFacade(
380
607
  services: Config["services"],
381
608
  workerDefinitions: WorkerRegistry
382
609
  ) {
383
- const targetPath = path.join(tmpDirPath, "serve-static-assets.entry.js");
610
+ const targetPath = path.join(tmpDirPath, "multiworker-dev-facade.entry.js");
384
611
  const serviceMap = Object.fromEntries(
385
612
  (services || []).map((serviceBinding) => [
386
613
  serviceBinding.binding,
@@ -391,10 +618,10 @@ async function applyMultiWorkerDevFacade(
391
618
  await esbuild.build({
392
619
  entryPoints: [
393
620
  path.join(
394
- __dirname,
621
+ getBasePath(),
395
622
  entry.format === "modules"
396
- ? "../templates/service-bindings-module-facade.js"
397
- : "../templates/service-bindings-sw-facade.js"
623
+ ? "templates/service-bindings-module-facade.js"
624
+ : "templates/service-bindings-sw-facade.js"
398
625
  ),
399
626
  ],
400
627
  bundle: true,
@@ -440,8 +667,8 @@ async function applyFirstPartyWorkerDevFacade(
440
667
  await esbuild.build({
441
668
  entryPoints: [
442
669
  path.resolve(
443
- __dirname,
444
- "../templates/first-party-worker-module-facade.ts"
670
+ getBasePath(),
671
+ "templates/first-party-worker-module-facade.ts"
445
672
  ),
446
673
  ],
447
674
  bundle: true,
@@ -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
+ }
package/src/cli.ts CHANGED
@@ -24,4 +24,4 @@ if (typeof jest === "undefined" && require.main) {
24
24
  * It makes it possible to import wrangler from 'wrangler',
25
25
  * and call wrangler.unstable_dev().
26
26
  */
27
- export default { unstable_dev };
27
+ export { unstable_dev };
@@ -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));
package/src/dev/dev.tsx CHANGED
@@ -158,7 +158,7 @@ export type DevProps = {
158
158
  inspect: boolean;
159
159
  logLevel: "none" | "error" | "log" | "warn" | "debug" | undefined;
160
160
  logPrefix?: string;
161
- onReady: (() => void) | undefined;
161
+ onReady: ((ip: string, port: number) => void) | undefined;
162
162
  showInteractiveDevSession: boolean | undefined;
163
163
  forceLocal: boolean | undefined;
164
164
  enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
@@ -257,6 +257,8 @@ function DevSession(props: DevSessionProps) {
257
257
  services: props.bindings.services,
258
258
  durableObjects: props.bindings.durable_objects || { bindings: [] },
259
259
  firstPartyWorkerDevFacade: props.firstPartyWorker,
260
+ // Enable the bundling to know whether we are using dev or publish
261
+ targetConsumer: "dev",
260
262
  });
261
263
 
262
264
  return props.local ? (