wrangler 2.1.2 → 2.1.4

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.
package/src/init.ts CHANGED
@@ -21,6 +21,7 @@ import type { RawConfig } from "./config";
21
21
  import type { Route, SimpleRoute } from "./config/environment";
22
22
  import type { WorkerMetadata } from "./create-worker-upload-form";
23
23
  import type { ConfigPath } from "./index";
24
+ import type { PackageManager } from "./package-manager";
24
25
  import type { Argv, ArgumentsCamelCase } from "yargs";
25
26
 
26
27
  export async function initOptions(yargs: Argv) {
@@ -234,6 +235,8 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
234
235
  "package.json"
235
236
  );
236
237
  let shouldCreatePackageJson = false;
238
+ let shouldCreateTests = false;
239
+ let newWorkerTestType: "jest" | "vitest" = "jest";
237
240
 
238
241
  if (!pathToPackageJson) {
239
242
  // If no package.json exists, ask to create one
@@ -355,48 +358,26 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
355
358
  !packageJsonContent.scripts?.publish &&
356
359
  shouldCreatePackageJson;
357
360
 
358
- /*
359
- * Passes the array of accumulated devDeps to install through to
360
- * the package manager. Also generates a human-readable list
361
- * of packages it installed.
362
- * If there are no devDeps to install, optionally runs
363
- * the package manager's install command.
364
- */
365
- async function installPackages(
366
- shouldRunInstall: boolean,
367
- depsToInstall: string[]
368
- ) {
369
- //lets install the devDeps they asked for
370
- //and run their package manager's install command if needed
371
- if (depsToInstall.length > 0) {
372
- const formatter = new Intl.ListFormat("en", {
373
- style: "long",
374
- type: "conjunction",
375
- });
376
- await packageManager.addDevDeps(...depsToInstall);
377
- const versionlessPackages = depsToInstall.map((dep) =>
378
- dep === `wrangler@${wranglerVersion}` ? "wrangler" : dep
379
- );
380
-
381
- logger.log(
382
- `✨ Installed ${formatter.format(
383
- versionlessPackages
384
- )} into devDependencies`
385
- );
386
- } else {
387
- if (shouldRunInstall) {
388
- await packageManager.install();
389
- }
361
+ async function writePackageJsonScriptsAndUpdateWranglerToml({
362
+ isWritingScripts,
363
+ isAddingTests,
364
+ testRunner,
365
+ isCreatingWranglerToml,
366
+ packagePath,
367
+ scriptPath,
368
+ extraToml,
369
+ }: {
370
+ isWritingScripts: boolean;
371
+ isAddingTests?: boolean;
372
+ testRunner?: "jest" | "vitest";
373
+ isCreatingWranglerToml: boolean;
374
+ packagePath: string;
375
+ scriptPath: string;
376
+ extraToml: TOML.JsonMap;
377
+ }) {
378
+ if (isAddingTests && !testRunner) {
379
+ logger.error("testRunner is required if isAddingTests");
390
380
  }
391
- }
392
-
393
- async function writePackageJsonScriptsAndUpdateWranglerToml(
394
- isWritingScripts: boolean,
395
- isCreatingWranglerToml: boolean,
396
- packagePath: string,
397
- scriptPath: string,
398
- extraToml: TOML.JsonMap
399
- ) {
400
381
  if (isCreatingWranglerToml) {
401
382
  // rewrite wrangler.toml with main = "path/to/script" and any additional config specified in `extraToml`
402
383
  const parsedWranglerToml = parseTOML(
@@ -412,7 +393,8 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
412
393
  }
413
394
  const isNamedWorker =
414
395
  isCreatingWranglerToml && path.dirname(packagePath) !== process.cwd();
415
-
396
+ const isAddingTestScripts =
397
+ isAddingTests && !packageJsonContent.scripts?.test;
416
398
  if (isWritingScripts) {
417
399
  await writeFile(
418
400
  packagePath,
@@ -427,6 +409,7 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
427
409
  deploy: isCreatingWranglerToml
428
410
  ? `wrangler publish`
429
411
  : `wrangler publish ${scriptPath}`,
412
+ ...(isAddingTestScripts && { test: testRunner }),
430
413
  },
431
414
  },
432
415
  null,
@@ -438,6 +421,9 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
438
421
  isNamedWorker ? `cd ${args.name} && ` : ""
439
422
  }npm start\``
440
423
  );
424
+ if (isAddingTestScripts) {
425
+ instructions.push(`To start testing your Worker, run \`npm test\``);
426
+ }
441
427
  instructions.push(
442
428
  `To publish your Worker to the Internet, run \`npm run deploy\``
443
429
  );
@@ -455,53 +441,6 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
455
441
  }
456
442
  }
457
443
 
458
- async function getNewWorkerType(newWorkerFilename: string) {
459
- return select(
460
- `Would you like to create a Worker at ${newWorkerFilename}?`,
461
- [
462
- {
463
- value: "none",
464
- label: "None",
465
- },
466
- {
467
- value: "fetch",
468
- label: "Fetch handler",
469
- },
470
- {
471
- value: "scheduled",
472
- label: "Scheduled handler",
473
- },
474
- ],
475
- 1
476
- ) as Promise<"none" | "fetch" | "scheduled">;
477
- }
478
-
479
- function getNewWorkerTemplate(
480
- lang: "js" | "ts",
481
- workerType: "fetch" | "scheduled"
482
- ) {
483
- const templates = {
484
- "js-fetch": "new-worker.js",
485
- "js-scheduled": "new-worker-scheduled.js",
486
- "ts-fetch": "new-worker.ts",
487
- "ts-scheduled": "new-worker-scheduled.ts",
488
- };
489
-
490
- return templates[`${lang}-${workerType}`];
491
- }
492
-
493
- function getNewWorkerToml(workerType: "fetch" | "scheduled"): TOML.JsonMap {
494
- if (workerType === "scheduled") {
495
- return {
496
- triggers: {
497
- crons: ["1 * * * *"],
498
- },
499
- };
500
- }
501
-
502
- return {};
503
- }
504
-
505
444
  if (isTypescriptProject) {
506
445
  if (!fs.existsSync(path.join(creationDirectory, "./src/index.ts"))) {
507
446
  const newWorkerFilename = path.relative(
@@ -533,17 +472,16 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
533
472
  dashScript
534
473
  );
535
474
 
536
- await writePackageJsonScriptsAndUpdateWranglerToml(
537
- shouldWritePackageJsonScripts,
538
- justCreatedWranglerToml,
539
- pathToPackageJson,
540
- "src/index.ts",
541
-
542
- (await getWorkerConfig(accountId, fromDashScriptName, {
475
+ await writePackageJsonScriptsAndUpdateWranglerToml({
476
+ isWritingScripts: shouldWritePackageJsonScripts,
477
+ isCreatingWranglerToml: justCreatedWranglerToml,
478
+ packagePath: pathToPackageJson,
479
+ scriptPath: "src/index.ts",
480
+ extraToml: (await getWorkerConfig(accountId, fromDashScriptName, {
543
481
  defaultEnvironment,
544
482
  environments: serviceMetaData.environments,
545
- })) as TOML.JsonMap
546
- );
483
+ })) as TOML.JsonMap,
484
+ });
547
485
  } else {
548
486
  const newWorkerType = yesFlag
549
487
  ? "fetch"
@@ -567,13 +505,13 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
567
505
  )}`
568
506
  );
569
507
 
570
- await writePackageJsonScriptsAndUpdateWranglerToml(
571
- shouldWritePackageJsonScripts,
572
- justCreatedWranglerToml,
573
- pathToPackageJson,
574
- "src/index.ts",
575
- getNewWorkerToml(newWorkerType)
576
- );
508
+ await writePackageJsonScriptsAndUpdateWranglerToml({
509
+ isWritingScripts: shouldWritePackageJsonScripts,
510
+ isCreatingWranglerToml: justCreatedWranglerToml,
511
+ packagePath: pathToPackageJson,
512
+ scriptPath: "src/index.ts",
513
+ extraToml: getNewWorkerToml(newWorkerType),
514
+ });
577
515
  }
578
516
  }
579
517
  }
@@ -611,17 +549,17 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
611
549
  dashScript
612
550
  );
613
551
 
614
- await writePackageJsonScriptsAndUpdateWranglerToml(
615
- shouldWritePackageJsonScripts,
616
- justCreatedWranglerToml,
617
- pathToPackageJson,
618
- "src/index.ts",
552
+ await writePackageJsonScriptsAndUpdateWranglerToml({
553
+ isWritingScripts: shouldWritePackageJsonScripts,
554
+ isCreatingWranglerToml: justCreatedWranglerToml,
555
+ packagePath: pathToPackageJson,
556
+ scriptPath: "src/index.ts",
619
557
  //? Should we have Environment argument for `wrangler init --from-dash` - Jacob
620
- (await getWorkerConfig(accountId, fromDashScriptName, {
558
+ extraToml: (await getWorkerConfig(accountId, fromDashScriptName, {
621
559
  defaultEnvironment,
622
560
  environments: serviceMetaData.environments,
623
- })) as TOML.JsonMap
624
- );
561
+ })) as TOML.JsonMap,
562
+ });
625
563
  } else {
626
564
  const newWorkerType = yesFlag
627
565
  ? "fetch"
@@ -645,20 +583,50 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
645
583
  )}`
646
584
  );
647
585
 
648
- await writePackageJsonScriptsAndUpdateWranglerToml(
649
- shouldWritePackageJsonScripts,
650
- justCreatedWranglerToml,
651
- pathToPackageJson,
652
- "src/index.js",
653
- getNewWorkerToml(newWorkerType)
654
- );
586
+ shouldCreateTests =
587
+ yesFlag ||
588
+ (await confirm("Would you like us to write your first test?"));
589
+
590
+ if (shouldCreateTests) {
591
+ newWorkerTestType = await getNewWorkerTestType();
592
+ devDepsToInstall.push(newWorkerTestType);
593
+ await writeFile(
594
+ path.join(creationDirectory, "./src/index.test.js"),
595
+ readFileSync(
596
+ path.join(
597
+ getBasePath(),
598
+ `templates/init-tests/test-${newWorkerTestType}-new-worker.js`
599
+ )
600
+ )
601
+ );
602
+ logger.log(
603
+ `✨ Created ${path.relative(
604
+ process.cwd(),
605
+ path.join(creationDirectory, "./src/index.test.js")
606
+ )}`
607
+ );
608
+ }
609
+
610
+ await writePackageJsonScriptsAndUpdateWranglerToml({
611
+ isWritingScripts: shouldWritePackageJsonScripts,
612
+ isAddingTests: shouldCreateTests,
613
+ testRunner: newWorkerTestType,
614
+ isCreatingWranglerToml: justCreatedWranglerToml,
615
+ packagePath: pathToPackageJson,
616
+ scriptPath: "src/index.js",
617
+ extraToml: getNewWorkerToml(newWorkerType),
618
+ });
655
619
  }
656
620
  }
657
621
  }
658
622
  }
659
623
  // install packages as the final step of init
660
624
  try {
661
- await installPackages(shouldRunPackageManagerInstall, devDepsToInstall);
625
+ await installPackages(
626
+ shouldRunPackageManagerInstall,
627
+ devDepsToInstall,
628
+ packageManager
629
+ );
662
630
  } catch (e) {
663
631
  // fetching packages could fail due to loss of internet, etc
664
632
  // we should let folks know we failed to fetch, but their
@@ -673,6 +641,106 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
673
641
  instructions.forEach((instruction) => logger.log(instruction));
674
642
  }
675
643
 
644
+ /*
645
+ * Passes the array of accumulated devDeps to install through to
646
+ * the package manager. Also generates a human-readable list
647
+ * of packages it installed.
648
+ * If there are no devDeps to install, optionally runs
649
+ * the package manager's install command.
650
+ */
651
+ async function installPackages(
652
+ shouldRunInstall: boolean,
653
+ depsToInstall: string[],
654
+ packageManager: PackageManager
655
+ ) {
656
+ //lets install the devDeps they asked for
657
+ //and run their package manager's install command if needed
658
+ if (depsToInstall.length > 0) {
659
+ const formatter = new Intl.ListFormat("en", {
660
+ style: "long",
661
+ type: "conjunction",
662
+ });
663
+ await packageManager.addDevDeps(...depsToInstall);
664
+ const versionlessPackages = depsToInstall.map((dep) =>
665
+ dep === `wrangler@${wranglerVersion}` ? "wrangler" : dep
666
+ );
667
+
668
+ logger.log(
669
+ `✨ Installed ${formatter.format(
670
+ versionlessPackages
671
+ )} into devDependencies`
672
+ );
673
+ } else {
674
+ if (shouldRunInstall) {
675
+ await packageManager.install();
676
+ }
677
+ }
678
+ }
679
+
680
+ async function getNewWorkerType(newWorkerFilename: string) {
681
+ return select(
682
+ `Would you like to create a Worker at ${newWorkerFilename}?`,
683
+ [
684
+ {
685
+ value: "none",
686
+ label: "None",
687
+ },
688
+ {
689
+ value: "fetch",
690
+ label: "Fetch handler",
691
+ },
692
+ {
693
+ value: "scheduled",
694
+ label: "Scheduled handler",
695
+ },
696
+ ],
697
+ 1
698
+ ) as Promise<"none" | "fetch" | "scheduled">;
699
+ }
700
+
701
+ async function getNewWorkerTestType() {
702
+ return select(
703
+ `Which test runner would you like to use?`,
704
+ [
705
+ {
706
+ value: "vitest",
707
+ label: "Vitest",
708
+ },
709
+ {
710
+ value: "jest",
711
+ label: "Jest",
712
+ },
713
+ ],
714
+ 1
715
+ ) as Promise<"jest" | "vitest">;
716
+ }
717
+
718
+ function getNewWorkerTemplate(
719
+ lang: "js" | "ts",
720
+ workerType: "fetch" | "scheduled"
721
+ ) {
722
+ const templates = {
723
+ "js-fetch": "new-worker.js",
724
+ "js-scheduled": "new-worker-scheduled.js",
725
+ "ts-fetch": "new-worker.ts",
726
+ "ts-scheduled": "new-worker-scheduled.ts",
727
+ };
728
+
729
+ return templates[`${lang}-${workerType}`];
730
+ }
731
+
732
+ function getNewWorkerToml(workerType: "fetch" | "scheduled"): TOML.JsonMap {
733
+ if (workerType === "scheduled") {
734
+ return {
735
+ triggers: {
736
+ crons: ["1 * * * *"],
737
+ },
738
+ };
739
+ }
740
+
741
+ return {};
742
+ }
743
+
676
744
  /**
677
745
  * Find the path to the given `basename` file from the `cwd`.
678
746
  *
package/src/pages/dev.tsx CHANGED
@@ -116,9 +116,22 @@ export function Options(yargs: Argv) {
116
116
  choices: ["http", "https"] as const,
117
117
  },
118
118
  "experimental-enable-local-persistence": {
119
+ describe:
120
+ "Enable persistence for local mode (deprecated, use --persist)",
119
121
  type: "boolean",
120
- default: false,
121
- describe: "Enable persistence for this session (only for local mode)",
122
+ deprecated: true,
123
+ hidden: true,
124
+ },
125
+ persist: {
126
+ describe:
127
+ "Enable persistence for local mode, using default path: .wrangler/state",
128
+ type: "boolean",
129
+ },
130
+ "persist-to": {
131
+ describe:
132
+ "Specify directory to use for local persistence (implies --persist)",
133
+ type: "string",
134
+ requiresArg: true,
122
135
  },
123
136
  "node-compat": {
124
137
  describe: "Enable node.js compatibility",
@@ -151,7 +164,9 @@ export const Handler = async ({
151
164
  r2: r2s = [],
152
165
  "live-reload": liveReload,
153
166
  "local-protocol": localProtocol,
154
- "experimental-enable-local-persistence": experimentalEnableLocalPersistence,
167
+ experimentalEnableLocalPersistence,
168
+ persist,
169
+ persistTo,
155
170
  "node-compat": nodeCompat,
156
171
  config: config,
157
172
  _: [_pages, _dev, ...remaining],
@@ -189,6 +204,14 @@ export const Handler = async ({
189
204
  directory = resolve(directory);
190
205
  }
191
206
 
207
+ if (experimentalEnableLocalPersistence) {
208
+ logger.warn(
209
+ `--experimental-enable-local-persistence is deprecated.\n` +
210
+ `Move any existing data to .wrangler/state and use --persist, or\n` +
211
+ `use --persist-to=./wrangler-local-state to keep using the old path.`
212
+ );
213
+ }
214
+
192
215
  let scriptReadyResolve: () => void;
193
216
  const scriptReadyPromise = new Promise<void>(
194
217
  (promiseResolve) => (scriptReadyResolve = promiseResolve)
@@ -358,7 +381,8 @@ export const Handler = async ({
358
381
  directory,
359
382
  },
360
383
  forceLocal: true,
361
- experimentalEnableLocalPersistence,
384
+ persist,
385
+ persistTo,
362
386
  showInteractiveDevSession: undefined,
363
387
  inspect: true,
364
388
  logLevel: "error",
@@ -0,0 +1,25 @@
1
+ const { unstable_dev } = require("wrangler");
2
+
3
+ describe("Worker", () => {
4
+ let worker;
5
+
6
+ beforeAll(async () => {
7
+ worker = await unstable_dev(
8
+ "src/index.js",
9
+ {},
10
+ { disableExperimentalWarning: true }
11
+ );
12
+ });
13
+
14
+ afterAll(async () => {
15
+ await worker.stop();
16
+ });
17
+
18
+ it("should return Hello World", async () => {
19
+ const resp = await worker.fetch();
20
+ if (resp) {
21
+ const text = await resp.text();
22
+ expect(text).toMatchInlineSnapshot(`"Hello World!"`);
23
+ }
24
+ });
25
+ });
@@ -0,0 +1,26 @@
1
+ import { unstable_dev } from "wrangler";
2
+ import { describe, expect, it, beforeAll, afterAll } from "vitest";
3
+
4
+ describe("Worker", () => {
5
+ let worker;
6
+
7
+ beforeAll(async () => {
8
+ worker = await unstable_dev(
9
+ "src/index.js",
10
+ {},
11
+ { disableExperimentalWarning: true }
12
+ );
13
+ });
14
+
15
+ afterAll(async () => {
16
+ await worker.stop();
17
+ });
18
+
19
+ it("should return Hello World", async () => {
20
+ const resp = await worker.fetch();
21
+ if (resp) {
22
+ const text = await resp.text();
23
+ expect(text).toMatchInlineSnapshot(`"Hello World!"`);
24
+ }
25
+ });
26
+ });
@@ -52,7 +52,8 @@ declare interface DevOptions {
52
52
  nodeCompat?: boolean;
53
53
  compatibilityDate?: string;
54
54
  compatibilityFlags?: string[];
55
- experimentalEnableLocalPersistence?: boolean;
55
+ persist?: boolean;
56
+ persistTo?: string;
56
57
  liveReload?: boolean;
57
58
  watch?: boolean;
58
59
  vars?: {
@@ -253,8 +254,67 @@ declare type ReferrerPolicy =
253
254
  | 'strict-origin-when-cross-origin'
254
255
  | 'unsafe-url';
255
256
 
257
+ declare class Request implements BodyMixin {
258
+ constructor (input: RequestInfo, init?: RequestInit)
259
+
260
+ readonly cache: RequestCache
261
+ readonly credentials: RequestCredentials
262
+ readonly destination: RequestDestination
263
+ readonly headers: Headers
264
+ readonly integrity: string
265
+ readonly method: string
266
+ readonly mode: RequestMode
267
+ readonly redirect: RequestRedirect
268
+ readonly referrerPolicy: string
269
+ readonly url: string
270
+
271
+ readonly keepalive: boolean
272
+ readonly signal: AbortSignal
273
+
274
+ readonly body: ReadableStream | null
275
+ readonly bodyUsed: boolean
276
+
277
+ readonly arrayBuffer: () => Promise<ArrayBuffer>
278
+ readonly blob: () => Promise<Blob_2>
279
+ readonly formData: () => Promise<FormData>
280
+ readonly json: () => Promise<unknown>
281
+ readonly text: () => Promise<string>
282
+
283
+ readonly clone: () => Request
284
+ }
285
+
286
+ declare type RequestCache =
287
+ | 'default'
288
+ | 'force-cache'
289
+ | 'no-cache'
290
+ | 'no-store'
291
+ | 'only-if-cached'
292
+ | 'reload'
293
+
256
294
  declare type RequestCredentials = 'omit' | 'include' | 'same-origin'
257
295
 
296
+ declare type RequestDestination =
297
+ | ''
298
+ | 'audio'
299
+ | 'audioworklet'
300
+ | 'document'
301
+ | 'embed'
302
+ | 'font'
303
+ | 'image'
304
+ | 'manifest'
305
+ | 'object'
306
+ | 'paintworklet'
307
+ | 'report'
308
+ | 'script'
309
+ | 'sharedworker'
310
+ | 'style'
311
+ | 'track'
312
+ | 'video'
313
+ | 'worker'
314
+ | 'xslt'
315
+
316
+ declare type RequestInfo = string | URL_2 | Request
317
+
258
318
  declare interface RequestInit {
259
319
  method?: string
260
320
  keepalive?: boolean
@@ -337,11 +397,11 @@ declare interface SpecIterator<T, TReturn = any, TNext = undefined> {
337
397
  * @param {DevApiOptions} apiOptions
338
398
  * @returns {Promise<UnstableDev>}
339
399
  */
340
- export declare function unstable_dev(script: string, options?: DevOptions, apiOptions?: DevApiOptions): Promise<UnstableDev>;
400
+ export declare function unstable_dev(script: string, options?: DevOptions, apiOptions?: DevApiOptions): Promise<UnstableDevWorker>;
341
401
 
342
- declare interface UnstableDev {
402
+ export declare interface UnstableDevWorker {
343
403
  stop: () => Promise<void>;
344
- fetch: (init?: RequestInit) => Promise<Response | undefined>;
404
+ fetch: (input?: RequestInfo, init?: RequestInit) => Promise<Response | undefined>;
345
405
  waitUntilExit: () => Promise<void>;
346
406
  }
347
407