wrangler 2.0.26 → 2.0.29

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 (62) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +54 -46
  3. package/package.json +6 -4
  4. package/src/__tests__/api-dev.test.ts +19 -0
  5. package/src/__tests__/configuration.test.ts +33 -29
  6. package/src/__tests__/dev.test.tsx +8 -6
  7. package/src/__tests__/generate.test.ts +2 -4
  8. package/src/__tests__/helpers/hello-world-worker.js +5 -0
  9. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  10. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  11. package/src/__tests__/index.test.ts +30 -30
  12. package/src/__tests__/jest.setup.ts +17 -0
  13. package/src/__tests__/metrics.test.ts +1 -1
  14. package/src/__tests__/pages.test.ts +829 -103
  15. package/src/__tests__/paths.test.ts +17 -0
  16. package/src/__tests__/publish.test.ts +59 -18
  17. package/src/__tests__/r2.test.ts +4 -3
  18. package/src/__tests__/tail.test.ts +34 -0
  19. package/src/__tests__/test-old-node-version.js +3 -3
  20. package/src/__tests__/user.test.ts +11 -0
  21. package/src/__tests__/worker-namespace.test.ts +37 -35
  22. package/src/api/dev.ts +74 -28
  23. package/src/bundle.ts +14 -11
  24. package/src/cfetch/internal.ts +81 -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-helpers.ts +19 -6
  29. package/src/config/validation.ts +11 -5
  30. package/src/config-cache.ts +2 -1
  31. package/src/create-worker-upload-form.ts +29 -26
  32. package/src/dev/local.tsx +317 -169
  33. package/src/dev/remote.tsx +10 -1
  34. package/src/dev/start-server.ts +412 -0
  35. package/src/dev.tsx +341 -157
  36. package/src/{worker-namespace.ts → dispatch-namespace.ts} +18 -18
  37. package/src/entry.ts +2 -1
  38. package/src/generate.ts +1 -1
  39. package/src/index.tsx +54 -8
  40. package/src/init.ts +5 -5
  41. package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
  42. package/src/metrics/metrics-config.ts +1 -1
  43. package/src/metrics/send-event.ts +6 -5
  44. package/src/miniflare-cli/assets.ts +4 -65
  45. package/src/miniflare-cli/index.ts +36 -32
  46. package/src/pages/constants.ts +3 -0
  47. package/src/pages/dev.tsx +10 -15
  48. package/src/pages/functions/buildPlugin.ts +2 -1
  49. package/src/pages/functions/buildWorker.ts +2 -1
  50. package/src/pages/functions/routes-transformation.test.ts +12 -1
  51. package/src/pages/functions/routes-transformation.ts +7 -1
  52. package/src/pages/publish.tsx +82 -38
  53. package/src/paths.ts +20 -1
  54. package/src/proxy.ts +10 -0
  55. package/src/publish.ts +19 -4
  56. package/src/r2.ts +4 -4
  57. package/src/user/user.tsx +6 -4
  58. package/src/whoami.tsx +5 -5
  59. package/src/worker.ts +10 -9
  60. package/src/zones.ts +91 -0
  61. package/wrangler-dist/cli.d.ts +22 -8
  62. package/wrangler-dist/cli.js +7757 -2315
package/src/dev/local.tsx CHANGED
@@ -8,16 +8,27 @@ import { registerWorker } from "../dev-registry";
8
8
  import useInspector from "../inspect";
9
9
  import { logger } from "../logger";
10
10
  import { DEFAULT_MODULE_RULES } from "../module-collection";
11
+ import { getBasePath } from "../paths";
11
12
  import { waitForPortToBeAvailable } from "../proxy";
12
13
  import type { Config } from "../config";
13
14
  import type { WorkerRegistry } from "../dev-registry";
14
15
  import type { EnablePagesAssetsServiceBindingOptions } from "../miniflare-cli";
15
16
  import type { AssetPaths } from "../sites";
16
- import type { CfWorkerInit, CfScriptFormat } from "../worker";
17
+ import type {
18
+ CfWorkerInit,
19
+ CfScriptFormat,
20
+ CfWasmModuleBindings,
21
+ CfTextBlobBindings,
22
+ CfDataBlobBindings,
23
+ CfDurableObject,
24
+ CfKvNamespace,
25
+ CfR2Bucket,
26
+ CfVars,
27
+ } from "../worker";
17
28
  import type { EsbuildBundle } from "./use-esbuild";
18
29
  import type { MiniflareOptions } from "miniflare";
19
30
  import type { ChildProcess } from "node:child_process";
20
- interface LocalProps {
31
+ export interface LocalProps {
21
32
  name: string | undefined;
22
33
  bundle: EsbuildBundle | undefined;
23
34
  format: CfScriptFormat | undefined;
@@ -25,7 +36,7 @@ interface LocalProps {
25
36
  compatibilityFlags: string[] | undefined;
26
37
  usageModel: "bundled" | "unbound" | undefined;
27
38
  bindings: CfWorkerInit["bindings"];
28
- workerDefinitions: WorkerRegistry;
39
+ workerDefinitions: WorkerRegistry | undefined;
29
40
  assetPaths: AssetPaths | undefined;
30
41
  port: number;
31
42
  ip: string;
@@ -136,189 +147,58 @@ function useLocalWorker({
136
147
 
137
148
  const scriptPath = realpathSync(bundle.path);
138
149
 
139
- // the wasm_modules/text_blobs/data_blobs bindings are
140
- // relative to process.cwd(), but the actual worker bundle
141
- // is in the temp output directory; so we rewrite the paths to be absolute,
142
- // letting miniflare resolve them correctly
143
-
144
- // wasm
145
- const wasmBindings: Record<string, string> = {};
146
- for (const [name, filePath] of Object.entries(
147
- bindings.wasm_modules || {}
148
- )) {
149
- wasmBindings[name] = path.join(process.cwd(), filePath);
150
- }
151
-
152
- // text
153
- const textBlobBindings: Record<string, string> = {};
154
- for (const [name, filePath] of Object.entries(
155
- bindings.text_blobs || {}
156
- )) {
157
- textBlobBindings[name] = path.join(process.cwd(), filePath);
158
- }
159
-
160
- // data
161
- const dataBlobBindings: Record<string, string> = {};
162
- for (const [name, filePath] of Object.entries(
163
- bindings.data_blobs || {}
164
- )) {
165
- dataBlobBindings[name] = path.join(process.cwd(), filePath);
166
- }
167
-
168
- if (format === "service-worker") {
169
- for (const { type, name } of bundle.modules) {
170
- if (type === "compiled-wasm") {
171
- // In service-worker format, .wasm modules are referenced by global identifiers,
172
- // so we convert it here.
173
- // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
174
- // characters with an underscore.
175
- const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
176
- wasmBindings[identifier] = name;
177
- } else if (type === "text") {
178
- // In service-worker format, text modules are referenced by global identifiers,
179
- // so we convert it here.
180
- // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
181
- // characters with an underscore.
182
- const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
183
- textBlobBindings[identifier] = name;
184
- } else if (type === "buffer") {
185
- // In service-worker format, data blobs are referenced by global identifiers,
186
- // so we convert it here.
187
- // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
188
- // characters with an underscore.
189
- const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
190
- dataBlobBindings[identifier] = name;
191
- }
192
- }
193
- }
194
-
195
150
  const upstream =
196
151
  typeof localUpstream === "string"
197
152
  ? `${localProtocol}://${localUpstream}`
198
153
  : undefined;
199
154
 
200
- const internalDurableObjects = (
201
- bindings.durable_objects?.bindings || []
202
- ).filter((binding) => !binding.script_name);
203
- const externalDurableObjects = (
204
- bindings.durable_objects?.bindings || []
205
- ).filter((binding) => binding.script_name);
206
-
207
- // TODO: This was already messy with the custom `disableLogs` and `logOptions`.
208
- // It's now getting _really_ messy now with Pages ASSETS binding outside and the external Durable Objects inside.
209
- const options: MiniflareOptions = {
210
- name: workerName,
155
+ const {
156
+ externalDurableObjects,
157
+ internalDurableObjects,
158
+ wasmBindings,
159
+ textBlobBindings,
160
+ dataBlobBindings,
161
+ } = setupBindings({
162
+ wasm_modules: bindings.wasm_modules,
163
+ text_blobs: bindings.text_blobs,
164
+ data_blobs: bindings.data_blobs,
165
+ durable_objects: bindings.durable_objects,
166
+ format,
167
+ bundle,
168
+ });
169
+
170
+ const { forkOptions, miniflareCLIPath } = setupMiniflareOptions({
171
+ workerName,
211
172
  port,
212
173
  scriptPath,
213
- https: localProtocol === "https",
214
- host: ip,
215
- modules: format === "modules",
216
- modulesRules: (rules || [])
217
- .concat(DEFAULT_MODULE_RULES)
218
- .map(({ type, globs: include, fallthrough }) => ({
219
- type,
220
- include,
221
- fallthrough,
222
- })),
174
+ localProtocol,
175
+ ip,
176
+ format,
177
+ rules,
223
178
  compatibilityDate,
224
179
  compatibilityFlags,
225
180
  usageModel,
226
- kvNamespaces: bindings.kv_namespaces?.map((kv) => kv.binding),
227
- r2Buckets: bindings.r2_buckets?.map((r2) => r2.binding),
228
- durableObjects: Object.fromEntries(
229
- internalDurableObjects.map((binding) => [
230
- binding.name,
231
- binding.class_name,
232
- ])
233
- ),
234
- externalDurableObjects: Object.fromEntries(
235
- externalDurableObjects
236
- .map((binding) => {
237
- const service = workerDefinitions[binding.script_name as string];
238
- if (!service) return [binding.name, undefined];
239
-
240
- const name = service.durableObjects.find(
241
- (durableObject) =>
242
- durableObject.className === binding.class_name
243
- )?.name;
244
- if (!name) return [binding.name, undefined];
245
-
246
- return [
247
- binding.name,
248
- {
249
- name,
250
- host: service.durableObjectsHost,
251
- port: service.durableObjectsPort,
252
- },
253
- ];
254
- })
255
- .filter(([_, details]) => !!details)
256
- ),
257
- ...(localPersistencePath
258
- ? {
259
- cachePersist: path.join(localPersistencePath, "cache"),
260
- durableObjectsPersist: path.join(localPersistencePath, "do"),
261
- kvPersist: path.join(localPersistencePath, "kv"),
262
- r2Persist: path.join(localPersistencePath, "r2"),
263
- }
264
- : {
265
- // We mark these as true, so that they'll
266
- // persist in the temp directory.
267
- // This means they'll persist across a dev session,
268
- // even if we change source and reload,
269
- // and be deleted when the dev session ends
270
- cachePersist: true,
271
- durableObjectsPersist: true,
272
- kvPersist: true,
273
- r2Persist: true,
274
- }),
275
-
181
+ kv_namespaces: bindings?.kv_namespaces,
182
+ r2_buckets: bindings?.r2_buckets,
183
+ internalDurableObjects,
184
+ externalDurableObjects,
185
+ localPersistencePath,
276
186
  liveReload,
277
- sitePath: assetPaths?.assetDirectory
278
- ? path.join(assetPaths.baseDirectory, assetPaths.assetDirectory)
279
- : undefined,
280
- siteInclude: assetPaths?.includePatterns.length
281
- ? assetPaths?.includePatterns
282
- : undefined,
283
- siteExclude: assetPaths?.excludePatterns.length
284
- ? assetPaths.excludePatterns
285
- : undefined,
286
- bindings: bindings.vars,
187
+ assetPaths,
188
+ vars: bindings?.vars,
287
189
  wasmBindings,
288
190
  textBlobBindings,
289
191
  dataBlobBindings,
290
- sourceMap: true,
291
- logUnhandledRejections: true,
292
192
  crons,
293
193
  upstream,
294
- disableLogs: logLevel === "none",
295
- logOptions: logPrefix ? { prefix: logPrefix } : undefined,
296
- };
297
-
298
- // The path to the Miniflare CLI assumes that this file is being run from
299
- // `wrangler-dist` and that the CLI is found in `miniflare-dist`.
300
- // If either of those paths change this line needs updating.
301
- const miniflareCLIPath = path.resolve(
302
- __dirname,
303
- "../miniflare-dist/index.mjs"
304
- );
305
- const miniflareOptions = JSON.stringify(options, null);
194
+ logLevel,
195
+ logPrefix,
196
+ workerDefinitions,
197
+ enablePagesAssetsServiceBinding,
198
+ });
306
199
 
200
+ const nodeOptions = setupNodeOptions({ inspect, ip, inspectorPort });
307
201
  logger.log("⎔ Starting a local server...");
308
- const nodeOptions = [
309
- "--experimental-vm-modules", // ensures that Miniflare can run ESM Workers
310
- "--no-warnings", // hide annoying Node warnings
311
- // "--log=VERBOSE", // uncomment this to Miniflare to log "everything"!
312
- ];
313
- if (inspect) {
314
- nodeOptions.push("--inspect=" + `${ip}:${inspectorPort}`); // start Miniflare listening for a debugger to attach
315
- }
316
-
317
- const forkOptions = [miniflareOptions];
318
-
319
- if (enablePagesAssetsServiceBinding) {
320
- forkOptions.push(JSON.stringify(enablePagesAssetsServiceBinding));
321
- }
322
202
 
323
203
  const child = (local.current = fork(miniflareCLIPath, forkOptions, {
324
204
  cwd: path.dirname(scriptPath),
@@ -420,7 +300,7 @@ function useLocalWorker({
420
300
  port,
421
301
  inspectorPort,
422
302
  ip,
423
- bindings.durable_objects?.bindings,
303
+ bindings.durable_objects,
424
304
  bindings.kv_namespaces,
425
305
  bindings.r2_buckets,
426
306
  bindings.vars,
@@ -447,3 +327,271 @@ function useLocalWorker({
447
327
  ]);
448
328
  return { inspectorUrl };
449
329
  }
330
+
331
+ interface SetupBindingsProps {
332
+ wasm_modules: CfWasmModuleBindings | undefined;
333
+ text_blobs: CfTextBlobBindings | undefined;
334
+ data_blobs: CfDataBlobBindings | undefined;
335
+ durable_objects: { bindings: CfDurableObject[] } | undefined;
336
+ bundle: EsbuildBundle;
337
+ format: CfScriptFormat;
338
+ }
339
+
340
+ export function setupBindings({
341
+ wasm_modules,
342
+ text_blobs,
343
+ data_blobs,
344
+ durable_objects,
345
+ format,
346
+ bundle,
347
+ }: SetupBindingsProps) {
348
+ // the wasm_modules/text_blobs/data_blobs bindings are
349
+ // relative to process.cwd(), but the actual worker bundle
350
+ // is in the temp output directory; so we rewrite the paths to be absolute,
351
+ // letting miniflare resolve them correctly
352
+
353
+ // wasm
354
+ const wasmBindings: Record<string, string> = {};
355
+ for (const [name, filePath] of Object.entries(wasm_modules || {})) {
356
+ wasmBindings[name] = path.join(process.cwd(), filePath);
357
+ }
358
+
359
+ // text
360
+ const textBlobBindings: Record<string, string> = {};
361
+ for (const [name, filePath] of Object.entries(text_blobs || {})) {
362
+ textBlobBindings[name] = path.join(process.cwd(), filePath);
363
+ }
364
+
365
+ // data
366
+ const dataBlobBindings: Record<string, string> = {};
367
+ for (const [name, filePath] of Object.entries(data_blobs || {})) {
368
+ dataBlobBindings[name] = path.join(process.cwd(), filePath);
369
+ }
370
+
371
+ if (format === "service-worker") {
372
+ for (const { type, name } of bundle.modules) {
373
+ if (type === "compiled-wasm") {
374
+ // In service-worker format, .wasm modules are referenced by global identifiers,
375
+ // so we convert it here.
376
+ // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
377
+ // characters with an underscore.
378
+ const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
379
+ wasmBindings[identifier] = name;
380
+ } else if (type === "text") {
381
+ // In service-worker format, text modules are referenced by global identifiers,
382
+ // so we convert it here.
383
+ // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
384
+ // characters with an underscore.
385
+ const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
386
+ textBlobBindings[identifier] = name;
387
+ } else if (type === "buffer") {
388
+ // In service-worker format, data blobs are referenced by global identifiers,
389
+ // so we convert it here.
390
+ // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
391
+ // characters with an underscore.
392
+ const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
393
+ dataBlobBindings[identifier] = name;
394
+ }
395
+ }
396
+ }
397
+
398
+ const internalDurableObjects = (durable_objects?.bindings || []).filter(
399
+ (binding) => !binding.script_name
400
+ );
401
+ const externalDurableObjects = (durable_objects?.bindings || []).filter(
402
+ (binding) => binding.script_name
403
+ );
404
+ return {
405
+ internalDurableObjects,
406
+ externalDurableObjects,
407
+ wasmBindings,
408
+ textBlobBindings,
409
+ dataBlobBindings,
410
+ };
411
+ }
412
+
413
+ interface SetupMiniflareOptionsProps {
414
+ workerName: string | undefined;
415
+ port: number;
416
+ scriptPath: string;
417
+ localProtocol: "http" | "https";
418
+ ip: string;
419
+ format: CfScriptFormat;
420
+ rules: Config["rules"];
421
+ compatibilityDate: string;
422
+ compatibilityFlags: string[] | undefined;
423
+ usageModel: "bundled" | "unbound" | undefined;
424
+ kv_namespaces: CfKvNamespace[] | undefined;
425
+ r2_buckets: CfR2Bucket[] | undefined;
426
+ internalDurableObjects: CfDurableObject[];
427
+ externalDurableObjects: CfDurableObject[];
428
+ localPersistencePath: string | null;
429
+ liveReload: boolean;
430
+ assetPaths: AssetPaths | undefined;
431
+ vars: CfVars | undefined;
432
+ wasmBindings: Record<string, string>;
433
+ textBlobBindings: Record<string, string>;
434
+ dataBlobBindings: Record<string, string>;
435
+ crons: Config["triggers"]["crons"];
436
+ upstream: string | undefined;
437
+ logLevel: "none" | "error" | "log" | "warn" | "debug" | undefined;
438
+ logPrefix: string | undefined;
439
+ workerDefinitions: WorkerRegistry | undefined;
440
+ enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
441
+ }
442
+
443
+ export function setupMiniflareOptions({
444
+ workerName,
445
+ port,
446
+ scriptPath,
447
+ localProtocol,
448
+ ip,
449
+ format,
450
+ rules,
451
+ compatibilityDate,
452
+ compatibilityFlags,
453
+ usageModel,
454
+ kv_namespaces,
455
+ r2_buckets,
456
+ internalDurableObjects,
457
+ externalDurableObjects,
458
+ localPersistencePath,
459
+ liveReload,
460
+ assetPaths,
461
+ vars,
462
+ wasmBindings,
463
+ textBlobBindings,
464
+ dataBlobBindings,
465
+ crons,
466
+ upstream,
467
+ logLevel,
468
+ logPrefix,
469
+ workerDefinitions,
470
+ enablePagesAssetsServiceBinding,
471
+ }: SetupMiniflareOptionsProps): MiniflareOptions {
472
+ // TODO: This was already messy with the custom `disableLogs` and `logOptions`.
473
+ // It's now getting _really_ messy now with Pages ASSETS binding outside and the external Durable Objects inside.
474
+ const options = {
475
+ name: workerName,
476
+ port,
477
+ scriptPath,
478
+ https: localProtocol === "https",
479
+ host: ip,
480
+ modules: format === "modules",
481
+ modulesRules: (rules || [])
482
+ .concat(DEFAULT_MODULE_RULES)
483
+ .map(({ type, globs: include, fallthrough }) => ({
484
+ type,
485
+ include,
486
+ fallthrough,
487
+ })),
488
+ compatibilityDate,
489
+ compatibilityFlags,
490
+ usageModel,
491
+ kvNamespaces: kv_namespaces?.map((kv) => kv.binding),
492
+ r2Buckets: r2_buckets?.map((r2) => r2.binding),
493
+ durableObjects: Object.fromEntries(
494
+ internalDurableObjects.map((binding) => [
495
+ binding.name,
496
+ binding.class_name,
497
+ ])
498
+ ),
499
+ externalDurableObjects: Object.fromEntries(
500
+ externalDurableObjects
501
+ .map((binding) => {
502
+ const service =
503
+ workerDefinitions &&
504
+ workerDefinitions[binding.script_name as string];
505
+ if (!service) return [binding.name, undefined];
506
+
507
+ const name = service.durableObjects.find(
508
+ (durableObject) => durableObject.className === binding.class_name
509
+ )?.name;
510
+ if (!name) return [binding.name, undefined];
511
+
512
+ return [
513
+ binding.name,
514
+ {
515
+ name,
516
+ host: service.durableObjectsHost,
517
+ port: service.durableObjectsPort,
518
+ },
519
+ ];
520
+ })
521
+ .filter(([_, details]) => !!details)
522
+ ),
523
+ ...(localPersistencePath
524
+ ? {
525
+ cachePersist: path.join(localPersistencePath, "cache"),
526
+ durableObjectsPersist: path.join(localPersistencePath, "do"),
527
+ kvPersist: path.join(localPersistencePath, "kv"),
528
+ r2Persist: path.join(localPersistencePath, "r2"),
529
+ }
530
+ : {
531
+ // We mark these as true, so that they'll
532
+ // persist in the temp directory.
533
+ // This means they'll persist across a dev session,
534
+ // even if we change source and reload,
535
+ // and be deleted when the dev session ends
536
+ cachePersist: true,
537
+ durableObjectsPersist: true,
538
+ kvPersist: true,
539
+ r2Persist: true,
540
+ }),
541
+
542
+ liveReload,
543
+ sitePath: assetPaths?.assetDirectory
544
+ ? path.join(assetPaths.baseDirectory, assetPaths.assetDirectory)
545
+ : undefined,
546
+ siteInclude: assetPaths?.includePatterns.length
547
+ ? assetPaths?.includePatterns
548
+ : undefined,
549
+ siteExclude: assetPaths?.excludePatterns.length
550
+ ? assetPaths.excludePatterns
551
+ : undefined,
552
+ bindings: vars,
553
+ wasmBindings,
554
+ textBlobBindings,
555
+ dataBlobBindings,
556
+ sourceMap: true,
557
+ logUnhandledRejections: true,
558
+ crons,
559
+ upstream,
560
+ disableLogs: logLevel === "none",
561
+ logOptions: logPrefix ? { prefix: logPrefix } : undefined,
562
+ enablePagesAssetsServiceBinding,
563
+ };
564
+ // The path to the Miniflare CLI assumes that this file is being run from
565
+ // `wrangler-dist` and that the CLI is found in `miniflare-dist`.
566
+ // If either of those paths change this line needs updating.
567
+ const miniflareCLIPath = path.resolve(
568
+ getBasePath(),
569
+ "miniflare-dist/index.mjs"
570
+ );
571
+ const miniflareOptions = JSON.stringify(options, null);
572
+ const forkOptions = [miniflareOptions];
573
+ if (enablePagesAssetsServiceBinding) {
574
+ forkOptions.push(JSON.stringify(enablePagesAssetsServiceBinding));
575
+ }
576
+ return { miniflareCLIPath, forkOptions };
577
+ }
578
+
579
+ export function setupNodeOptions({
580
+ inspect,
581
+ ip,
582
+ inspectorPort,
583
+ }: {
584
+ inspect: boolean;
585
+ ip: string;
586
+ inspectorPort: number;
587
+ }) {
588
+ const nodeOptions = [
589
+ "--experimental-vm-modules", // ensures that Miniflare can run ESM Workers
590
+ "--no-warnings", // hide annoying Node warnings
591
+ // "--log=VERBOSE", // uncomment this to Miniflare to log "everything"!
592
+ ];
593
+ if (inspect) {
594
+ nodeOptions.push("--inspect=" + `${ip}:${inspectorPort}`); // start Miniflare listening for a debugger to attach
595
+ }
596
+ return nodeOptions;
597
+ }
@@ -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
  }