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/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;
@@ -37,7 +48,7 @@ interface LocalProps {
37
48
  localProtocol: "http" | "https";
38
49
  localUpstream: string | undefined;
39
50
  inspect: boolean;
40
- onReady: (() => void) | undefined;
51
+ onReady: ((ip: string, port: number) => void) | undefined;
41
52
  logLevel: "none" | "error" | "log" | "warn" | "debug" | undefined;
42
53
  logPrefix?: string;
43
54
  enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
@@ -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),
@@ -348,7 +228,7 @@ function useLocalWorker({
348
228
  : {}),
349
229
  });
350
230
  }
351
- onReady?.();
231
+ onReady?.(ip, message.mfPort);
352
232
  }
353
233
  });
354
234
 
@@ -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
+ }
@@ -54,7 +54,7 @@ export function Remote(props: {
54
54
  zone: string | undefined;
55
55
  host: string | undefined;
56
56
  routes: Route[] | undefined;
57
- onReady?: (() => void) | undefined;
57
+ onReady?: ((ip: string, port: number) => void) | undefined;
58
58
  sourceMapPath: string | undefined;
59
59
  sendMetrics: boolean | undefined;
60
60
  }) {
@@ -81,6 +81,7 @@ export function Remote(props: {
81
81
  routes: props.routes,
82
82
  onReady: props.onReady,
83
83
  sendMetrics: props.sendMetrics,
84
+ port: props.port,
84
85
  });
85
86
 
86
87
  usePreviewServer({
@@ -164,8 +165,9 @@ export function useWorker(props: {
164
165
  zone: string | undefined;
165
166
  host: string | undefined;
166
167
  routes: Route[] | undefined;
167
- onReady: (() => void) | undefined;
168
+ onReady: ((ip: string, port: number) => void) | undefined;
168
169
  sendMetrics: boolean | undefined;
170
+ port: number;
169
171
  }): CfPreviewToken | undefined {
170
172
  const {
171
173
  name,
@@ -182,7 +184,7 @@ export function useWorker(props: {
182
184
  } = props;
183
185
  const [session, setSession] = useState<CfPreviewSession | undefined>();
184
186
  const [token, setToken] = useState<CfPreviewToken | undefined>();
185
-
187
+ const [restartCounter, setRestartCounter] = useState<number>(0);
186
188
  // This is the most reliable way to detect whether
187
189
  // something's "happened" in our system; We make a ref and
188
190
  // mark it once we log our initial message. Refs are vars!
@@ -237,6 +239,7 @@ export function useWorker(props: {
237
239
  props.routes,
238
240
  props.zone,
239
241
  props.sendMetrics,
242
+ restartCounter,
240
243
  ]);
241
244
 
242
245
  // This effect uses the session to upload the worker and create a preview
@@ -314,6 +317,7 @@ export function useWorker(props: {
314
317
  compatibility_date: compatibilityDate,
315
318
  compatibility_flags: compatibilityFlags,
316
319
  usage_model: usageModel,
320
+ keep_bindings: true,
317
321
  };
318
322
 
319
323
  const workerAccount: CfAccount = {
@@ -361,7 +365,7 @@ export function useWorker(props: {
361
365
  }
362
366
  */
363
367
 
364
- onReady?.();
368
+ onReady?.(props.host || "localhost", props.port);
365
369
  }
366
370
  start().catch((err) => {
367
371
  // we want to log the error, but not end the process
@@ -379,6 +383,13 @@ export function useWorker(props: {
379
383
  logger.error(
380
384
  `${errorMessage}\n${solutionMessage}\n${onboardingLink}`
381
385
  );
386
+ } else if (err.code === 10049) {
387
+ logger.log("Preview token expired, fetching a new one");
388
+ // code 10049 happens when the preview token expires
389
+ // since we want a new preview token when this happens,
390
+ // lets increment the counter, and trigger a rerun of
391
+ // the useEffect above
392
+ setRestartCounter((prevCount) => prevCount + 1);
382
393
  } else {
383
394
  logger.error("Error on remote worker:", err);
384
395
  }
@@ -408,6 +419,7 @@ export function useWorker(props: {
408
419
  session,
409
420
  onReady,
410
421
  props.sendMetrics,
422
+ props.port,
411
423
  ]);
412
424
  return token;
413
425
  }