wrangler 0.0.0-e22f9d7 → 0.0.0-e2a26a0

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 (54) hide show
  1. package/bin/wrangler.js +2 -2
  2. package/package.json +15 -10
  3. package/pages/functions/buildWorker.ts +1 -1
  4. package/pages/functions/filepath-routing.test.ts +21 -13
  5. package/pages/functions/filepath-routing.ts +38 -28
  6. package/pages/functions/routes.ts +8 -6
  7. package/pages/functions/template-worker.ts +16 -24
  8. package/src/__tests__/dev.test.tsx +7 -3
  9. package/src/__tests__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
  10. package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
  11. package/src/__tests__/helpers/mock-account-id.ts +30 -0
  12. package/src/__tests__/helpers/mock-bin.ts +33 -0
  13. package/src/__tests__/{mock-cfetch.ts → helpers/mock-cfetch.ts} +49 -13
  14. package/src/__tests__/helpers/mock-console.ts +56 -0
  15. package/src/__tests__/{mock-dialogs.ts → helpers/mock-dialogs.ts} +1 -1
  16. package/src/__tests__/helpers/mock-kv.ts +40 -0
  17. package/src/__tests__/helpers/mock-user.ts +27 -0
  18. package/src/__tests__/helpers/run-in-tmp.ts +29 -0
  19. package/src/__tests__/helpers/run-wrangler.ts +14 -0
  20. package/src/__tests__/index.test.ts +312 -56
  21. package/src/__tests__/jest.setup.ts +17 -2
  22. package/src/__tests__/kv.test.ts +344 -316
  23. package/src/__tests__/logout.test.ts +50 -0
  24. package/src/__tests__/package-manager.test.ts +206 -0
  25. package/src/__tests__/publish.test.ts +1222 -0
  26. package/src/__tests__/secret.test.ts +210 -0
  27. package/src/__tests__/whoami.test.tsx +86 -0
  28. package/src/api/form_data.ts +10 -7
  29. package/src/api/preview.ts +2 -2
  30. package/src/api/worker.ts +3 -3
  31. package/src/cfetch/index.ts +14 -14
  32. package/src/cfetch/internal.ts +40 -8
  33. package/src/config.ts +162 -8
  34. package/src/dev.tsx +103 -53
  35. package/src/dialogs.tsx +2 -2
  36. package/src/index.tsx +438 -311
  37. package/src/inspect.ts +80 -23
  38. package/src/kv.tsx +9 -1
  39. package/src/module-collection.ts +5 -6
  40. package/src/package-manager.ts +120 -0
  41. package/src/pages.tsx +41 -26
  42. package/src/paths.ts +26 -0
  43. package/src/proxy.ts +78 -10
  44. package/src/publish.ts +98 -52
  45. package/src/sites.tsx +175 -53
  46. package/src/user.tsx +51 -59
  47. package/src/whoami.tsx +69 -0
  48. package/templates/new-worker.js +15 -0
  49. package/templates/new-worker.ts +15 -0
  50. package/{static-asset-facade.js → templates/static-asset-facade.js} +0 -0
  51. package/wrangler-dist/cli.js +111479 -110187
  52. package/wrangler-dist/cli.js.map +3 -3
  53. package/src/__tests__/run-in-tmp.ts +0 -19
  54. package/src/__tests__/run-wrangler.ts +0 -32
package/src/index.tsx CHANGED
@@ -1,22 +1,19 @@
1
- import React from "react";
1
+ import * as fs from "node:fs";
2
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { setTimeout } from "node:timers/promises";
5
+ import TOML from "@iarna/toml";
6
+ import { findUp } from "find-up";
2
7
  import { render } from "ink";
3
- import Dev from "./dev";
4
- import { readFile } from "node:fs/promises";
8
+ import React from "react";
9
+ import onExit from "signal-exit";
5
10
  import makeCLI from "yargs";
6
- import type Yargs from "yargs";
7
- import { findUp } from "find-up";
8
- import TOML from "@iarna/toml";
9
- import type { Config } from "./config";
10
- import { confirm, prompt } from "./dialogs";
11
11
  import { version as wranglerVersion } from "../package.json";
12
- import {
13
- login,
14
- logout,
15
- listScopes,
16
- initialise as initialiseUserConfig,
17
- loginOrRefreshIfRequired,
18
- getAccountId,
19
- } from "./user";
12
+ import { toFormData } from "./api/form_data";
13
+ import { fetchResult } from "./cfetch";
14
+ import { normaliseAndValidateEnvironmentsConfig } from "./config";
15
+ import Dev from "./dev";
16
+ import { confirm, prompt } from "./dialogs";
20
17
  import {
21
18
  getNamespaceId,
22
19
  listNamespaces,
@@ -26,22 +23,29 @@ import {
26
23
  deleteBulkKeyValue,
27
24
  createNamespace,
28
25
  isValidNamespaceBinding,
26
+ getKeyValue,
29
27
  } from "./kv";
30
-
28
+ import { getPackageManager } from "./package-manager";
31
29
  import { pages } from "./pages";
32
-
33
- import { fetchResult, fetchRaw } from "./cfetch";
34
-
35
30
  import publish from "./publish";
36
- import path from "path/posix";
37
- import { writeFile } from "node:fs/promises";
38
- import { toFormData } from "./api/form_data";
39
-
31
+ import { getAssetPaths } from "./sites";
40
32
  import { createTail } from "./tail";
41
- import onExit from "signal-exit";
42
- import { setTimeout } from "node:timers/promises";
43
- import * as fs from "node:fs";
44
- import { execa } from "execa";
33
+ import {
34
+ login,
35
+ logout,
36
+ listScopes,
37
+ initialise as initialiseUserConfig,
38
+ loginOrRefreshIfRequired,
39
+ getAccountId,
40
+ validateScopeKeys,
41
+ } from "./user";
42
+ import { whoami } from "./whoami";
43
+
44
+ import type { Config } from "./config";
45
+ import type Yargs from "yargs";
46
+
47
+ const resetColor = "\x1b[0m";
48
+ const fgGreenColor = "\x1b[32m";
45
49
 
46
50
  async function readConfig(configPath?: string): Promise<Config> {
47
51
  const config: Config = {};
@@ -56,48 +60,7 @@ async function readConfig(configPath?: string): Promise<Config> {
56
60
  Object.assign(config, parsed);
57
61
  }
58
62
 
59
- const inheritedFields = [
60
- "name",
61
- "account_id",
62
- "workers_dev",
63
- "compatibility_date",
64
- "compatibility_flags",
65
- "zone_id",
66
- "routes",
67
- "route",
68
- "jsx_factory",
69
- "jsx_fragment",
70
- "site",
71
- "triggers",
72
- "usage_model",
73
- ];
74
-
75
- Object.keys(config.env || {}).forEach((env) => {
76
- inheritedFields.forEach((field) => {
77
- if (config[field] !== undefined && config.env[env][field] === undefined) {
78
- config.env[env][field] = config[field]; // TODO: - shallow copy?
79
- }
80
- });
81
- });
82
-
83
- const mirroredFields = [
84
- "vars",
85
- "kv_namespaces",
86
- "durable_objects",
87
- "experimental_services",
88
- ];
89
- Object.keys(config.env || {}).forEach((env) => {
90
- mirroredFields.forEach((field) => {
91
- // if it exists on top level, it should exist on env definitions
92
- Object.keys(config[field] || {}).forEach((fieldKey) => {
93
- if (!(fieldKey in config.env[env][field])) {
94
- console.warn(
95
- `In your configuration, "${field}.${fieldKey}" exists at a top level, but not on "env.${env}". This is not what you probably want, since the field "${field}" is not inherited by environments. Please add "${field}.${fieldKey}" to "env.${env}".`
96
- );
97
- }
98
- });
99
- });
100
- });
63
+ normaliseAndValidateEnvironmentsConfig(config);
101
64
 
102
65
  if ("experimental_services" in config) {
103
66
  console.warn(
@@ -226,77 +189,103 @@ export async function main(argv: string[]): Promise<void> {
226
189
  throw new CommandLineArgsError(message);
227
190
  }
228
191
 
229
- const destination = path.join(process.cwd(), "wrangler.toml");
192
+ const packageManager = await getPackageManager(process.cwd());
193
+
194
+ const destination = "./wrangler.toml";
230
195
  if (fs.existsSync(destination)) {
231
196
  console.warn(`${destination} file already exists!`);
232
- const result = await confirm(
197
+ const shouldContinue = await confirm(
233
198
  "Do you want to continue initializing this project?"
234
199
  );
235
- if (!result) {
200
+ if (!shouldContinue) {
236
201
  return;
237
202
  }
203
+ } else {
204
+ const compatibilityDate = new Date().toISOString().substring(0, 10);
205
+ try {
206
+ await writeFile(
207
+ destination,
208
+ `compatibility_date = "${compatibilityDate}"` + "\n"
209
+ );
210
+ console.log(`✨ Successfully created wrangler.toml`);
211
+ // TODO: suggest next steps?
212
+ } catch (err) {
213
+ throw new Error(
214
+ `Failed to create wrangler.toml.\n${err.message ?? err}`
215
+ );
216
+ }
238
217
  }
239
218
 
240
- const compatibilityDate = new Date().toISOString().substring(0, 10);
241
- try {
242
- await writeFile(
243
- destination,
244
- `compatibility_date = "${compatibilityDate}"` + "\n"
245
- );
246
- console.log(`✨ Successfully created wrangler.toml`);
247
- // TODO: suggest next steps?
248
- } catch (err) {
249
- throw new Error(
250
- `Failed to create wrangler.toml.\n${err.message ?? err}`
251
- );
252
- }
253
-
254
- // if no package.json, ask, and if yes, create one
255
219
  let pathToPackageJson = await findUp("package.json");
256
-
257
220
  if (!pathToPackageJson) {
258
- if (
259
- await confirm("No package.json found. Would you like to create one?")
260
- ) {
221
+ // If no package.json exists, ask to create one
222
+ const shouldCreatePackageJson = await confirm(
223
+ "No package.json found. Would you like to create one?"
224
+ );
225
+ if (shouldCreatePackageJson) {
261
226
  await writeFile(
262
- path.join(process.cwd(), "package.json"),
227
+ "./package.json",
263
228
  JSON.stringify(
264
229
  {
265
230
  name: "worker",
266
- version: "0.0.1",
231
+ version: "0.0.0",
232
+ devDependencies: {
233
+ wrangler: wranglerVersion,
234
+ },
235
+ private: true,
267
236
  },
268
237
  null,
269
238
  " "
270
239
  ) + "\n"
271
240
  );
241
+ await packageManager.install();
272
242
  console.log(`✨ Created package.json`);
273
243
  pathToPackageJson = path.join(process.cwd(), "package.json");
274
244
  } else {
275
245
  return;
276
246
  }
247
+ } else {
248
+ // If package.json exists and wrangler isn't installed,
249
+ // then ask to add wrangler to devDependencies
250
+ const packageJson = JSON.parse(
251
+ await readFile(pathToPackageJson, "utf-8")
252
+ );
253
+ if (
254
+ !(
255
+ packageJson.devDependencies?.wrangler ||
256
+ packageJson.dependencies?.wrangler
257
+ )
258
+ ) {
259
+ const shouldInstall = await confirm(
260
+ "Would you like to install wrangler into your package.json?"
261
+ );
262
+ if (shouldInstall) {
263
+ await packageManager.addDevDeps(`wrangler@${wranglerVersion}`);
264
+ console.log(`✨ Installed wrangler`);
265
+ }
266
+ }
277
267
  }
278
268
 
279
- // if workers-types doesn't exist as a dependency
280
- // offer to install it
281
- // and make a tsconfig?
269
+ let isTypescriptProject = false;
282
270
  let pathToTSConfig = await findUp("tsconfig.json");
283
271
  if (!pathToTSConfig) {
284
- if (await confirm("Would you like to use typescript?")) {
272
+ // If there's no tsconfig, offer to create one
273
+ // and install @cloudflare/workers-types
274
+ if (await confirm("Would you like to use TypeScript?")) {
275
+ isTypescriptProject = true;
285
276
  await writeFile(
286
- path.join(process.cwd(), "tsconfig.json"),
277
+ "./tsconfig.json",
287
278
  JSON.stringify(
288
279
  {
289
280
  compilerOptions: {
290
- target: "esnext",
291
- module: "esnext",
281
+ target: "es2021",
282
+ module: "es2022",
292
283
  moduleResolution: "node",
293
- esModuleInterop: true,
294
284
  allowJs: true,
295
285
  allowSyntheticDefaultImports: true,
296
286
  isolatedModules: true,
297
287
  noEmit: true,
298
- lib: ["esnext"],
299
- jsx: "react",
288
+ lib: ["es2021"],
300
289
  resolveJsonModule: true,
301
290
  types: ["@cloudflare/workers-types"],
302
291
  },
@@ -305,16 +294,79 @@ export async function main(argv: string[]): Promise<void> {
305
294
  " "
306
295
  ) + "\n"
307
296
  );
308
- await execa("npm", [
309
- "install",
297
+ await packageManager.addDevDeps(
310
298
  "@cloudflare/workers-types",
311
- "--save-dev",
312
- ]);
299
+ "typescript"
300
+ );
301
+
313
302
  console.log(
314
303
  `✨ Created tsconfig.json, installed @cloudflare/workers-types into devDependencies`
315
304
  );
316
305
  pathToTSConfig = path.join(process.cwd(), "tsconfig.json");
317
306
  }
307
+ } else {
308
+ isTypescriptProject = true;
309
+ // If there's a tsconfig, check if @cloudflare/workers-types
310
+ // is already installed, and offer to install it if not
311
+ const packageJson = JSON.parse(
312
+ await readFile(pathToPackageJson, "utf-8")
313
+ );
314
+ if (
315
+ !(
316
+ packageJson.devDependencies?.["@cloudflare/workers-types"] ||
317
+ packageJson.dependencies?.["@cloudflare/workers-types"]
318
+ )
319
+ ) {
320
+ const shouldInstall = await confirm(
321
+ "Would you like to install the type definitions for Workers into your package.json?"
322
+ );
323
+ if (shouldInstall) {
324
+ await packageManager.addDevDeps("@cloudflare/workers-types");
325
+ // We don't update the tsconfig.json because
326
+ // it could be complicated in existing projects
327
+ // and we don't want to break them. Instead, we simply
328
+ // tell the user that they need to update their tsconfig.json
329
+ console.log(
330
+ `✨ Installed @cloudflare/workers-types.\nPlease add "@cloudflare/workers-types" to compilerOptions.types in your tsconfig.json`
331
+ );
332
+ }
333
+ }
334
+ }
335
+
336
+ if (isTypescriptProject) {
337
+ if (!fs.existsSync("./src/index.ts")) {
338
+ const shouldCreateSource = await confirm(
339
+ `Would you like to create a Worker at src/index.ts?`
340
+ );
341
+ if (shouldCreateSource) {
342
+ await mkdir("./src", { recursive: true });
343
+ await writeFile(
344
+ "./src/index.ts",
345
+ await readFile(
346
+ path.join(__dirname, "../templates/new-worker.ts"),
347
+ "utf-8"
348
+ )
349
+ );
350
+ console.log(`✨ Created src/index.ts`);
351
+ }
352
+ }
353
+ } else {
354
+ if (!fs.existsSync("./src/index.js")) {
355
+ const shouldCreateSource = await confirm(
356
+ `Would you like to create a Worker at src/index.js?`
357
+ );
358
+ if (shouldCreateSource) {
359
+ await mkdir("./src", { recursive: true });
360
+ await writeFile(
361
+ path.join("./src/index.js"),
362
+ await readFile(
363
+ path.join(__dirname, "../templates/new-worker.js"),
364
+ "utf-8"
365
+ )
366
+ );
367
+ console.log(`✨ Created src/index.js`);
368
+ }
369
+ }
318
370
  }
319
371
  }
320
372
  );
@@ -368,6 +420,11 @@ export async function main(argv: string[]): Promise<void> {
368
420
  listScopes();
369
421
  return;
370
422
  }
423
+ if (!validateScopeKeys(args.scopes)) {
424
+ throw new CommandLineArgsError(
425
+ `One of ${args.scopes} is not a valid authentication scope. Run "wrangler login --list-scopes" to see the valid scopes.`
426
+ );
427
+ }
371
428
  await login({ scopes: args.scopes });
372
429
  return;
373
430
  }
@@ -394,11 +451,10 @@ export async function main(argv: string[]): Promise<void> {
394
451
  // whoami
395
452
  wrangler.command(
396
453
  "whoami",
397
- false, // we don't need to show this the menu
398
- // "🕵️ Retrieve your user info and test your auth config",
454
+ "🕵️ Retrieve your user info and test your auth config",
399
455
  () => {},
400
- (args) => {
401
- console.log(":whoami", args);
456
+ async () => {
457
+ await whoami();
402
458
  }
403
459
  );
404
460
 
@@ -421,7 +477,11 @@ export async function main(argv: string[]): Promise<void> {
421
477
  "👂 Start a local server for developing your worker",
422
478
  (yargs) => {
423
479
  return yargs
424
- .positional("filename", { describe: "entry point", type: "string" })
480
+ .positional("filename", {
481
+ describe: "entry point",
482
+ type: "string",
483
+ demandOption: true,
484
+ })
425
485
  .option("name", {
426
486
  describe: "name of the script",
427
487
  type: "string",
@@ -477,6 +537,18 @@ export async function main(argv: string[]): Promise<void> {
477
537
  describe: "Root folder of static assets for Workers Sites",
478
538
  type: "string",
479
539
  })
540
+ .option("site-include", {
541
+ describe:
542
+ "Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.",
543
+ type: "string",
544
+ array: true,
545
+ })
546
+ .option("site-exclude", {
547
+ describe:
548
+ "Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.",
549
+ type: "string",
550
+ array: true,
551
+ })
480
552
  .option("upstream-protocol", {
481
553
  default: "https",
482
554
  describe:
@@ -490,6 +562,10 @@ export async function main(argv: string[]): Promise<void> {
490
562
  .option("jsx-fragment", {
491
563
  describe: "The function that is called for each JSX fragment",
492
564
  type: "string",
565
+ })
566
+ .option("experimental-enable-local-persistence", {
567
+ describe: "Enable persistence for this session (only for local mode)",
568
+ type: "boolean",
493
569
  });
494
570
  },
495
571
  async (args) => {
@@ -508,26 +584,34 @@ export async function main(argv: string[]): Promise<void> {
508
584
  );
509
585
  }
510
586
 
511
- // -- snip, extract --
587
+ if (config.site?.["entry-point"]) {
588
+ console.warn(
589
+ "Deprecation notice: The `site.entry-point` config field is no longer used.\n" +
590
+ "The entry-point is specified via the command line (e.g. `wrangler dev path/to/script`).\n" +
591
+ "Please remove the `site.entry-point` field from the `wrangler.toml` file."
592
+ );
593
+ }
512
594
 
513
595
  if (!args.local) {
596
+ // -- snip, extract --
514
597
  const loggedIn = await loginOrRefreshIfRequired();
515
598
  if (!loggedIn) {
516
599
  // didn't login, let's just quit
517
600
  console.log("Did not login, quitting...");
518
601
  return;
519
602
  }
603
+
520
604
  if (!config.account_id) {
521
605
  config.account_id = await getAccountId();
522
606
  if (!config.account_id) {
523
607
  throw new Error("No account id found, quitting...");
524
608
  }
525
609
  }
610
+ // -- snip, end --
526
611
  }
527
612
 
528
- // -- snip, end --
529
-
530
- const envRootObj = args.env ? config.env[args.env] || {} : config;
613
+ const environments = config.env ?? {};
614
+ const envRootObj = args.env ? environments[args.env] || {} : config;
531
615
 
532
616
  // TODO: this error shouldn't actually happen,
533
617
  // but we haven't fixed it internally yet
@@ -544,13 +628,22 @@ export async function main(argv: string[]): Promise<void> {
544
628
  <Dev
545
629
  name={args.name || config.name}
546
630
  entry={path.relative(process.cwd(), filename)}
631
+ env={args.env}
547
632
  buildCommand={config.build || {}}
548
633
  format={format}
549
634
  initialMode={args.local ? "local" : "remote"}
550
635
  jsxFactory={args["jsx-factory"] || envRootObj?.jsx_factory}
551
636
  jsxFragment={args["jsx-fragment"] || envRootObj?.jsx_fragment}
637
+ enableLocalPersistence={
638
+ args["experimental-enable-local-persistence"] || false
639
+ }
552
640
  accountId={config.account_id}
553
- site={args.site || config.site?.bucket}
641
+ assetPaths={getAssetPaths(
642
+ config,
643
+ args.site,
644
+ args.siteInclude,
645
+ args.siteExclude
646
+ )}
554
647
  port={args.port || config.dev?.port}
555
648
  public={args["experimental-public"]}
556
649
  compatibilityDate={
@@ -635,6 +728,18 @@ export async function main(argv: string[]): Promise<void> {
635
728
  describe: "Root folder of static assets for Workers Sites",
636
729
  type: "string",
637
730
  })
731
+ .option("site-include", {
732
+ describe:
733
+ "Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.",
734
+ type: "string",
735
+ array: true,
736
+ })
737
+ .option("site-exclude", {
738
+ describe:
739
+ "Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.",
740
+ type: "string",
741
+ array: true,
742
+ })
638
743
  .option("triggers", {
639
744
  describe: "cron schedules to attach",
640
745
  alias: ["schedule", "schedules"],
@@ -686,24 +791,30 @@ export async function main(argv: string[]): Promise<void> {
686
791
  );
687
792
  }
688
793
 
689
- // -- snip, extract --
690
794
  if (!args.local) {
795
+ // -- snip, extract --
691
796
  const loggedIn = await loginOrRefreshIfRequired();
692
797
  if (!loggedIn) {
693
798
  // didn't login, let's just quit
694
799
  console.log("Did not login, quitting...");
695
800
  return;
696
801
  }
802
+
697
803
  if (!config.account_id) {
698
804
  config.account_id = await getAccountId();
699
805
  if (!config.account_id) {
700
806
  throw new Error("No account id found, quitting...");
701
807
  }
702
808
  }
809
+ // -- snip, end --
703
810
  }
704
811
 
705
- // -- snip, end --
706
-
812
+ const assetPaths = getAssetPaths(
813
+ config,
814
+ args["experimental-public"] || args.site,
815
+ args.siteInclude,
816
+ args.siteExclude
817
+ );
707
818
  await publish({
708
819
  config: args.config as Config,
709
820
  name: args.name,
@@ -717,8 +828,10 @@ export async function main(argv: string[]): Promise<void> {
717
828
  jsxFactory: args["jsx-factory"],
718
829
  jsxFragment: args["jsx-fragment"],
719
830
  routes: args.routes,
720
- public: args["experimental-public"],
721
- site: args.site,
831
+ assetPaths,
832
+ format: undefined, // TODO: add args for this
833
+ legacyEnv: undefined, // TODO: get this from somewhere... config?
834
+ experimentalPublic: args["experimental-public"] !== undefined,
722
835
  });
723
836
  }
724
837
  );
@@ -768,6 +881,12 @@ export async function main(argv: string[]): Promise<void> {
768
881
  // TODO: filter by client ip, which can be 'self' or an ip address
769
882
  },
770
883
  async (args) => {
884
+ if (args.local) {
885
+ throw new NotImplementedError(
886
+ `local mode is not yet supported for this command`
887
+ );
888
+ }
889
+
771
890
  const config = args.config as Config;
772
891
 
773
892
  if (!(args.name || config.name)) {
@@ -778,22 +897,19 @@ export async function main(argv: string[]): Promise<void> {
778
897
  }`;
779
898
 
780
899
  // -- snip, extract --
900
+ const loggedIn = await loginOrRefreshIfRequired();
901
+ if (!loggedIn) {
902
+ // didn't login, let's just quit
903
+ console.log("Did not login, quitting...");
904
+ return;
905
+ }
781
906
 
782
- if (!args.local) {
783
- const loggedIn = await loginOrRefreshIfRequired();
784
- if (!loggedIn) {
785
- // didn't login, let's just quit
786
- console.log("Did not login, quitting...");
787
- return;
788
- }
907
+ if (!config.account_id) {
908
+ config.account_id = await getAccountId();
789
909
  if (!config.account_id) {
790
- config.account_id = await getAccountId();
791
- if (!config.account_id) {
792
- throw new Error("No account id found, quitting...");
793
- }
910
+ throw new Error("No account id found, quitting...");
794
911
  }
795
912
  }
796
-
797
913
  // -- snip, end --
798
914
 
799
915
  const accountId = config.account_id;
@@ -986,11 +1102,6 @@ export async function main(argv: string[]): Promise<void> {
986
1102
  });
987
1103
  },
988
1104
  async (args) => {
989
- if (args.local) {
990
- throw new NotImplementedError(
991
- "--local not implemented for this command yet"
992
- );
993
- }
994
1105
  const config = args.config as Config;
995
1106
 
996
1107
  // TODO: use environment (how does current wrangler do it?)
@@ -999,29 +1110,39 @@ export async function main(argv: string[]): Promise<void> {
999
1110
  throw new Error("Missing script name");
1000
1111
  }
1001
1112
 
1002
- // -- snip, extract --
1113
+ if (args.local) {
1114
+ console.warn("`wrangler secret put` is a no-op in --local mode");
1115
+ }
1003
1116
 
1004
1117
  if (!args.local) {
1118
+ // -- snip, extract --
1005
1119
  const loggedIn = await loginOrRefreshIfRequired();
1006
1120
  if (!loggedIn) {
1007
1121
  // didn't login, let's just quit
1008
1122
  console.log("Did not login, quitting...");
1009
1123
  return;
1010
1124
  }
1125
+
1011
1126
  if (!config.account_id) {
1012
1127
  config.account_id = await getAccountId();
1013
1128
  if (!config.account_id) {
1014
1129
  throw new Error("No account id found, quitting...");
1015
1130
  }
1016
1131
  }
1132
+ // -- snip, end --
1017
1133
  }
1018
1134
 
1019
- // -- snip, end --
1020
-
1021
1135
  const secretValue = await prompt(
1022
1136
  "Enter a secret value:",
1023
1137
  "password"
1024
1138
  );
1139
+
1140
+ if (args.local) {
1141
+ return;
1142
+ }
1143
+
1144
+ console.log(`🌀 Creating the secret for script ${scriptName}`);
1145
+
1025
1146
  async function submitSecret() {
1026
1147
  return await fetchResult(
1027
1148
  `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets/`,
@@ -1038,7 +1159,7 @@ export async function main(argv: string[]): Promise<void> {
1038
1159
  }
1039
1160
 
1040
1161
  try {
1041
- console.log(await submitSecret());
1162
+ await submitSecret();
1042
1163
  } catch (e) {
1043
1164
  if (e.code === 10007) {
1044
1165
  // upload a draft worker
@@ -1046,8 +1167,8 @@ export async function main(argv: string[]): Promise<void> {
1046
1167
  `/accounts/${config.account_id}/workers/scripts/${scriptName}`,
1047
1168
  {
1048
1169
  method: "PUT",
1049
- // @ts-expect-error TODO: fix this error!
1050
1170
  body: toFormData({
1171
+ name: scriptName,
1051
1172
  main: {
1052
1173
  name: scriptName,
1053
1174
  content: `export default { fetch() {} }`,
@@ -1059,15 +1180,20 @@ export async function main(argv: string[]): Promise<void> {
1059
1180
  durable_objects: { bindings: [] },
1060
1181
  },
1061
1182
  modules: [],
1183
+ migrations: undefined,
1184
+ compatibility_date: undefined,
1185
+ compatibility_flags: undefined,
1186
+ usage_model: undefined,
1062
1187
  }),
1063
1188
  }
1064
1189
  );
1065
1190
 
1066
1191
  // and then try again
1067
- console.log(await submitSecret());
1192
+ await submitSecret();
1068
1193
  // TODO: delete the draft worker if this failed too?
1069
1194
  }
1070
1195
  }
1196
+ console.log(`✨ Success! Uploaded secret ${args.key}`);
1071
1197
  }
1072
1198
  )
1073
1199
  .command(
@@ -1090,11 +1216,6 @@ export async function main(argv: string[]): Promise<void> {
1090
1216
  });
1091
1217
  },
1092
1218
  async (args) => {
1093
- if (args.local) {
1094
- throw new NotImplementedError(
1095
- "--local not implemented for this command yet"
1096
- );
1097
- }
1098
1219
  const config = args.config as Config;
1099
1220
 
1100
1221
  // TODO: use environment (how does current wrangler do it?)
@@ -1103,36 +1224,48 @@ export async function main(argv: string[]): Promise<void> {
1103
1224
  throw new Error("Missing script name");
1104
1225
  }
1105
1226
 
1106
- // -- snip, extract --
1227
+ if (args.local) {
1228
+ console.warn(
1229
+ "`wrangler secret delete` is a no-op in --local mode"
1230
+ );
1231
+ }
1107
1232
 
1108
1233
  if (!args.local) {
1234
+ // -- snip, extract --
1109
1235
  const loggedIn = await loginOrRefreshIfRequired();
1110
1236
  if (!loggedIn) {
1111
1237
  // didn't login, let's just quit
1112
1238
  console.log("Did not login, quitting...");
1113
1239
  return;
1114
1240
  }
1241
+
1115
1242
  if (!config.account_id) {
1116
1243
  config.account_id = await getAccountId();
1117
1244
  if (!config.account_id) {
1118
1245
  throw new Error("No account id found, quitting...");
1119
1246
  }
1120
1247
  }
1248
+ // -- snip, end --
1121
1249
  }
1122
1250
 
1123
- // -- snip, end --
1124
-
1125
- if (await confirm("Are you sure you want to delete this secret?")) {
1251
+ if (
1252
+ await confirm(
1253
+ `Are you sure you want to permanently delete the variable ${args.key} on the script ${scriptName}?`
1254
+ )
1255
+ ) {
1126
1256
  console.log(
1127
- `Deleting the secret ${args.key} on script ${scriptName}.`
1257
+ `🌀 Deleting the secret ${args.key} on script ${scriptName}.`
1128
1258
  );
1129
1259
 
1130
- console.log(
1131
- await fetchResult(
1132
- `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets/${args.key}`,
1133
- { method: "DELETE" }
1134
- )
1260
+ if (args.local) {
1261
+ return;
1262
+ }
1263
+
1264
+ await fetchResult(
1265
+ `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets/${args.key}`,
1266
+ { method: "DELETE" }
1135
1267
  );
1268
+ console.log(`✨ Success! Deleted secret ${args.key}`);
1136
1269
  }
1137
1270
  }
1138
1271
  )
@@ -1152,11 +1285,6 @@ export async function main(argv: string[]): Promise<void> {
1152
1285
  });
1153
1286
  },
1154
1287
  async (args) => {
1155
- if (args.local) {
1156
- throw new NotImplementedError(
1157
- "--local not implemented for this command yet"
1158
- );
1159
- }
1160
1288
  const config = args.config as Config;
1161
1289
 
1162
1290
  // TODO: use environment (how does current wrangler do it?)
@@ -1165,28 +1293,39 @@ export async function main(argv: string[]): Promise<void> {
1165
1293
  throw new Error("Missing script name");
1166
1294
  }
1167
1295
 
1168
- // -- snip, extract --
1296
+ if (args.local) {
1297
+ console.warn("`wrangler secret list` is a no-op in --local mode");
1298
+ }
1169
1299
 
1170
1300
  if (!args.local) {
1301
+ // -- snip, extract --
1171
1302
  const loggedIn = await loginOrRefreshIfRequired();
1172
1303
  if (!loggedIn) {
1173
1304
  // didn't login, let's just quit
1174
1305
  console.log("Did not login, quitting...");
1175
1306
  return;
1176
1307
  }
1308
+
1177
1309
  if (!config.account_id) {
1178
1310
  config.account_id = await getAccountId();
1179
1311
  if (!config.account_id) {
1180
1312
  throw new Error("No account id found, quitting...");
1181
1313
  }
1182
1314
  }
1315
+ // -- snip, end --
1183
1316
  }
1184
1317
 
1185
- // -- snip, end --
1318
+ if (args.local) {
1319
+ return;
1320
+ }
1186
1321
 
1187
1322
  console.log(
1188
- await fetchResult(
1189
- `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
1323
+ JSON.stringify(
1324
+ await fetchResult(
1325
+ `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
1326
+ ),
1327
+ null,
1328
+ " "
1190
1329
  )
1191
1330
  );
1192
1331
  }
@@ -1209,6 +1348,7 @@ export async function main(argv: string[]): Promise<void> {
1209
1348
  .positional("namespace", {
1210
1349
  describe: "The name of the new namespace",
1211
1350
  type: "string",
1351
+ demandOption: true,
1212
1352
  })
1213
1353
  .option("env", {
1214
1354
  type: "string",
@@ -1254,44 +1394,43 @@ export async function main(argv: string[]): Promise<void> {
1254
1394
  });
1255
1395
  await mf.getKVNamespace(title); // this should "create" the namespace
1256
1396
  console.log(`✨ Success! Created KV namespace ${title}`);
1257
- return;
1258
- }
1259
-
1260
- // -- snip, extract --
1261
-
1262
- if (!args.local) {
1397
+ } else {
1398
+ // -- snip, extract --
1263
1399
  const loggedIn = await loginOrRefreshIfRequired();
1264
1400
  if (!loggedIn) {
1265
1401
  // didn't login, let's just quit
1266
1402
  console.log("Did not login, quitting...");
1267
1403
  return;
1268
1404
  }
1405
+
1269
1406
  if (!config.account_id) {
1270
1407
  config.account_id = await getAccountId();
1271
1408
  if (!config.account_id) {
1272
1409
  throw new Error("No account id found, quitting...");
1273
1410
  }
1274
1411
  }
1275
- }
1276
-
1277
- // -- snip, end --
1412
+ // -- snip, end --
1278
1413
 
1279
- // TODO: generate a binding name stripping non alphanumeric chars
1414
+ // TODO: generate a binding name stripping non alphanumeric chars
1280
1415
 
1281
- console.log(`🌀 Creating namespace with title "${title}"`);
1282
- const namespaceId = await createNamespace(config.account_id, title);
1416
+ console.log(`🌀 Creating namespace with title "${title}"`);
1417
+ const namespaceId = await createNamespace(
1418
+ config.account_id,
1419
+ title
1420
+ );
1283
1421
 
1284
- console.log("✨ Success!");
1285
- const envString = args.env ? ` under [env.${args.env}]` : "";
1286
- const previewString = args.preview ? "preview_" : "";
1287
- console.log(
1288
- `Add the following to your configuration file in your kv_namespaces array${envString}:`
1289
- );
1290
- console.log(
1291
- `{ binding = "${args.namespace}", ${previewString}id = "${namespaceId}" }`
1292
- );
1422
+ console.log("✨ Success!");
1423
+ const envString = args.env ? ` under [env.${args.env}]` : "";
1424
+ const previewString = args.preview ? "preview_" : "";
1425
+ console.log(
1426
+ `Add the following to your configuration file in your kv_namespaces array${envString}:`
1427
+ );
1428
+ console.log(
1429
+ `{ binding = "${args.namespace}", ${previewString}id = "${namespaceId}" }`
1430
+ );
1293
1431
 
1294
- // TODO: automatically write this block to the wrangler.toml config file??
1432
+ // TODO: automatically write this block to the wrangler.toml config file??
1433
+ }
1295
1434
  }
1296
1435
  )
1297
1436
  .command(
@@ -1299,42 +1438,39 @@ export async function main(argv: string[]): Promise<void> {
1299
1438
  "Outputs a list of all KV namespaces associated with your account id.",
1300
1439
  {},
1301
1440
  async (args) => {
1441
+ const config = args.config as Config;
1442
+
1302
1443
  if (args.local) {
1303
1444
  throw new NotImplementedError(
1304
1445
  `local mode is not yet supported for this command`
1305
1446
  );
1306
- }
1307
-
1308
- const config = args.config as Config;
1309
-
1310
- // -- snip, extract --
1311
-
1312
- if (!args.local) {
1447
+ } else {
1448
+ // -- snip, extract --
1313
1449
  const loggedIn = await loginOrRefreshIfRequired();
1314
1450
  if (!loggedIn) {
1315
1451
  // didn't login, let's just quit
1316
1452
  console.log("Did not login, quitting...");
1317
1453
  return;
1318
1454
  }
1455
+
1319
1456
  if (!config.account_id) {
1320
1457
  config.account_id = await getAccountId();
1321
1458
  if (!config.account_id) {
1322
1459
  throw new Error("No account id found, quitting...");
1323
1460
  }
1324
1461
  }
1325
- }
1326
-
1327
- // -- snip, end --
1462
+ // -- snip, end --
1328
1463
 
1329
- // TODO: we should show bindings if they exist for given ids
1464
+ // TODO: we should show bindings if they exist for given ids
1330
1465
 
1331
- console.log(
1332
- JSON.stringify(
1333
- await listNamespaces(config.account_id),
1334
- null,
1335
- " "
1336
- )
1337
- );
1466
+ console.log(
1467
+ JSON.stringify(
1468
+ await listNamespaces(config.account_id),
1469
+ null,
1470
+ " "
1471
+ )
1472
+ );
1473
+ }
1338
1474
  }
1339
1475
  )
1340
1476
  .command(
@@ -1361,25 +1497,23 @@ export async function main(argv: string[]): Promise<void> {
1361
1497
  });
1362
1498
  },
1363
1499
  async (args) => {
1500
+ const config = args.config as Config;
1501
+
1364
1502
  if (args.local) {
1365
1503
  throw new NotImplementedError(
1366
1504
  `local mode is not yet supported for this command`
1367
1505
  );
1368
- }
1369
- const config = args.config as Config;
1370
-
1371
- let id;
1372
- try {
1373
- id = getNamespaceId(args);
1374
- } catch (e) {
1375
- throw new CommandLineArgsError(
1376
- "Not able to delete namespace.\n" + e.message
1377
- );
1378
- }
1379
-
1380
- // -- snip, extract --
1506
+ } else {
1507
+ let id;
1508
+ try {
1509
+ id = getNamespaceId(args);
1510
+ } catch (e) {
1511
+ throw new CommandLineArgsError(
1512
+ "Not able to delete namespace.\n" + e.message
1513
+ );
1514
+ }
1381
1515
 
1382
- if (!args.local) {
1516
+ // -- snip, extract --
1383
1517
  const loggedIn = await loginOrRefreshIfRequired();
1384
1518
  if (!loggedIn) {
1385
1519
  // didn't login, let's just quit
@@ -1393,32 +1527,31 @@ export async function main(argv: string[]): Promise<void> {
1393
1527
  throw new Error("No account id found, quitting...");
1394
1528
  }
1395
1529
  }
1396
- }
1397
-
1398
- // -- snip, end --
1530
+ // -- snip, end --
1399
1531
 
1400
- await fetchResult<{ id: string }>(
1401
- `/accounts/${config.account_id}/storage/kv/namespaces/${id}`,
1402
- { method: "DELETE" }
1403
- );
1532
+ await fetchResult<{ id: string }>(
1533
+ `/accounts/${config.account_id}/storage/kv/namespaces/${id}`,
1534
+ { method: "DELETE" }
1535
+ );
1404
1536
 
1405
- // TODO: recommend they remove it from wrangler.toml
1537
+ // TODO: recommend they remove it from wrangler.toml
1406
1538
 
1407
- // test-mf wrangler kv:namespace delete --namespace-id 2a7d3d8b23fc4159b5afa489d6cfd388
1408
- // Are you sure you want to delete namespace 2a7d3d8b23fc4159b5afa489d6cfd388? [y/n]
1409
- // n
1410
- // 💁 Not deleting namespace 2a7d3d8b23fc4159b5afa489d6cfd388
1411
- // ➜ test-mf wrangler kv:namespace delete --namespace-id 2a7d3d8b23fc4159b5afa489d6cfd388
1412
- // Are you sure you want to delete namespace 2a7d3d8b23fc4159b5afa489d6cfd388? [y/n]
1413
- // y
1414
- // 🌀 Deleting namespace 2a7d3d8b23fc4159b5afa489d6cfd388
1415
- // ✨ Success
1416
- // ⚠️ Make sure to remove this "kv-namespace" entry from your configuration file!
1417
- // ➜ test-mf
1539
+ // test-mf wrangler kv:namespace delete --namespace-id 2a7d3d8b23fc4159b5afa489d6cfd388
1540
+ // Are you sure you want to delete namespace 2a7d3d8b23fc4159b5afa489d6cfd388? [y/n]
1541
+ // n
1542
+ // 💁 Not deleting namespace 2a7d3d8b23fc4159b5afa489d6cfd388
1543
+ // ➜ test-mf wrangler kv:namespace delete --namespace-id 2a7d3d8b23fc4159b5afa489d6cfd388
1544
+ // Are you sure you want to delete namespace 2a7d3d8b23fc4159b5afa489d6cfd388? [y/n]
1545
+ // y
1546
+ // 🌀 Deleting namespace 2a7d3d8b23fc4159b5afa489d6cfd388
1547
+ // ✨ Success
1548
+ // ⚠️ Make sure to remove this "kv-namespace" entry from your configuration file!
1549
+ // ➜ test-mf
1418
1550
 
1419
- // TODO: do it automatically
1551
+ // TODO: do it automatically
1420
1552
 
1421
- // TODO: delete the preview namespace as well?
1553
+ // TODO: delete the preview namespace as well?
1554
+ }
1422
1555
  }
1423
1556
  );
1424
1557
  }
@@ -1438,6 +1571,7 @@ export async function main(argv: string[]): Promise<void> {
1438
1571
  .positional("key", {
1439
1572
  type: "string",
1440
1573
  describe: "The key to write to.",
1574
+ demandOption: true,
1441
1575
  })
1442
1576
  .positional("value", {
1443
1577
  type: "string",
@@ -1477,9 +1611,11 @@ export async function main(argv: string[]): Promise<void> {
1477
1611
  },
1478
1612
  async ({ key, ttl, expiration, ...args }) => {
1479
1613
  const namespaceId = getNamespaceId(args);
1614
+ // One of `args.path` and `args.value` must be defined
1480
1615
  const value = args.path
1481
1616
  ? await readFile(args.path, "utf-8")
1482
- : args.value;
1617
+ : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1618
+ args.value!;
1483
1619
  const config = args.config as Config;
1484
1620
 
1485
1621
  if (args.path) {
@@ -1501,11 +1637,8 @@ export async function main(argv: string[]): Promise<void> {
1501
1637
  });
1502
1638
  const ns = await mf.getKVNamespace(namespaceId);
1503
1639
  await ns.put(key, value, { expiration, expirationTtl: ttl });
1504
- return;
1505
- }
1506
- // -- snip, extract --
1507
-
1508
- if (!args.local) {
1640
+ } else {
1641
+ // -- snip, extract --
1509
1642
  const loggedIn = await loginOrRefreshIfRequired();
1510
1643
  if (!loggedIn) {
1511
1644
  // didn't login, let's just quit
@@ -1519,14 +1652,13 @@ export async function main(argv: string[]): Promise<void> {
1519
1652
  throw new Error("No account id found, quitting...");
1520
1653
  }
1521
1654
  }
1522
- }
1655
+ // -- snip, end --
1523
1656
 
1524
- // -- snip, end --
1525
-
1526
- await putKeyValue(config.account_id, namespaceId, key, value, {
1527
- expiration,
1528
- expiration_ttl: ttl,
1529
- });
1657
+ await putKeyValue(config.account_id, namespaceId, key, value, {
1658
+ expiration,
1659
+ expiration_ttl: ttl,
1660
+ });
1661
+ }
1530
1662
  }
1531
1663
  )
1532
1664
  .command(
@@ -1574,12 +1706,8 @@ export async function main(argv: string[]): Promise<void> {
1574
1706
  const ns = await mf.getKVNamespace(namespaceId);
1575
1707
  const listResponse = await ns.list({ prefix });
1576
1708
  console.log(JSON.stringify(listResponse.keys, null, " ")); // TODO: paginate, collate
1577
- return;
1578
- }
1579
-
1580
- // -- snip, extract --
1581
-
1582
- if (!args.local) {
1709
+ } else {
1710
+ // -- snip, extract --
1583
1711
  const loggedIn = await loginOrRefreshIfRequired();
1584
1712
  if (!loggedIn) {
1585
1713
  // didn't login, let's just quit
@@ -1593,13 +1721,15 @@ export async function main(argv: string[]): Promise<void> {
1593
1721
  throw new Error("No account id found, quitting...");
1594
1722
  }
1595
1723
  }
1596
- }
1597
-
1598
- // -- snip, end --
1724
+ // -- snip, end --
1599
1725
 
1600
- console.log(
1601
- await listNamespaceKeys(config.account_id, namespaceId, prefix)
1602
- );
1726
+ const results = await listNamespaceKeys(
1727
+ config.account_id,
1728
+ namespaceId,
1729
+ prefix
1730
+ );
1731
+ console.log(JSON.stringify(results, undefined, 2));
1732
+ }
1603
1733
  }
1604
1734
  )
1605
1735
  .command(
@@ -1610,6 +1740,7 @@ export async function main(argv: string[]): Promise<void> {
1610
1740
  .positional("key", {
1611
1741
  describe: "The key value to get.",
1612
1742
  type: "string",
1743
+ demandOption: true,
1613
1744
  })
1614
1745
  .option("binding", {
1615
1746
  type: "string",
@@ -1651,9 +1782,8 @@ export async function main(argv: string[]): Promise<void> {
1651
1782
  return;
1652
1783
  }
1653
1784
 
1654
- // -- snip, extract --
1655
-
1656
1785
  if (!args.local) {
1786
+ // -- snip, extract --
1657
1787
  const loggedIn = await loginOrRefreshIfRequired();
1658
1788
  if (!loggedIn) {
1659
1789
  // didn't login, let's just quit
@@ -1667,15 +1797,12 @@ export async function main(argv: string[]): Promise<void> {
1667
1797
  throw new Error("No account id found, quitting...");
1668
1798
  }
1669
1799
  }
1670
- }
1671
-
1672
- // -- snip, end --
1800
+ // -- snip, end --
1673
1801
 
1674
- console.log(
1675
- await fetchRaw(
1676
- `/accounts/${config.account_id}/storage/kv/namespaces/${namespaceId}/values/${key}`
1677
- )
1678
- );
1802
+ console.log(
1803
+ await getKeyValue(config.account_id, namespaceId, key)
1804
+ );
1805
+ }
1679
1806
  }
1680
1807
  )
1681
1808
  .command(
@@ -1686,6 +1813,7 @@ export async function main(argv: string[]): Promise<void> {
1686
1813
  .positional("key", {
1687
1814
  describe: "The key value to delete",
1688
1815
  type: "string",
1816
+ demandOption: true,
1689
1817
  })
1690
1818
  .option("binding", {
1691
1819
  type: "string",
@@ -1726,9 +1854,8 @@ export async function main(argv: string[]): Promise<void> {
1726
1854
 
1727
1855
  const config = args.config as Config;
1728
1856
 
1729
- // -- snip, extract --
1730
-
1731
1857
  if (!args.local) {
1858
+ // -- snip, extract --
1732
1859
  const loggedIn = await loginOrRefreshIfRequired();
1733
1860
  if (!loggedIn) {
1734
1861
  // didn't login, let's just quit
@@ -1742,10 +1869,9 @@ export async function main(argv: string[]): Promise<void> {
1742
1869
  throw new Error("No account id found, quitting...");
1743
1870
  }
1744
1871
  }
1872
+ // -- snip, end --
1745
1873
  }
1746
1874
 
1747
- // -- snip, end --
1748
-
1749
1875
  await fetchResult(
1750
1876
  `/accounts/${config.account_id}/storage/kv/namespaces/${namespaceId}/values/${key}`,
1751
1877
  { method: "DELETE" }
@@ -1769,6 +1895,7 @@ export async function main(argv: string[]): Promise<void> {
1769
1895
  .positional("filename", {
1770
1896
  describe: `The JSON file of key-value pairs to upload, in form [{"key":..., "value":...}"...]`,
1771
1897
  type: "string",
1898
+ demandOption: true,
1772
1899
  })
1773
1900
  .option("binding", {
1774
1901
  type: "string",
@@ -1824,13 +1951,8 @@ export async function main(argv: string[]): Promise<void> {
1824
1951
  expirationTtl: expiration_ttl,
1825
1952
  });
1826
1953
  }
1827
-
1828
- return;
1829
- }
1830
-
1831
- // -- snip, extract --
1832
-
1833
- if (!args.local) {
1954
+ } else {
1955
+ // -- snip, extract --
1834
1956
  const loggedIn = await loginOrRefreshIfRequired();
1835
1957
  if (!loggedIn) {
1836
1958
  // didn't login, let's just quit
@@ -1844,13 +1966,12 @@ export async function main(argv: string[]): Promise<void> {
1844
1966
  throw new Error("No account id found, quitting...");
1845
1967
  }
1846
1968
  }
1847
- }
1848
-
1849
- // -- snip, end --
1969
+ // -- snip, end --
1850
1970
 
1851
- console.log(
1852
- await putBulkKeyValue(config.account_id, namespaceId, content)
1853
- );
1971
+ console.log(
1972
+ await putBulkKeyValue(config.account_id, namespaceId, content)
1973
+ );
1974
+ }
1854
1975
  }
1855
1976
  )
1856
1977
  .command(
@@ -1861,6 +1982,7 @@ export async function main(argv: string[]): Promise<void> {
1861
1982
  .positional("filename", {
1862
1983
  describe: `The JSON file of keys to delete, in the form ["key1", "key2", ...]`,
1863
1984
  type: "string",
1985
+ demandOption: true,
1864
1986
  })
1865
1987
  .option("binding", {
1866
1988
  type: "string",
@@ -1904,13 +2026,8 @@ export async function main(argv: string[]): Promise<void> {
1904
2026
  for (const key of parsedContent) {
1905
2027
  await ns.delete(key);
1906
2028
  }
1907
-
1908
- return;
1909
- }
1910
-
1911
- // -- snip, extract --
1912
-
1913
- if (!args.local) {
2029
+ } else {
2030
+ // -- snip, extract --
1914
2031
  const loggedIn = await loginOrRefreshIfRequired();
1915
2032
  if (!loggedIn) {
1916
2033
  // didn't login, let's just quit
@@ -1924,13 +2041,16 @@ export async function main(argv: string[]): Promise<void> {
1924
2041
  throw new Error("No account id found, quitting...");
1925
2042
  }
1926
2043
  }
1927
- }
1928
-
1929
- // -- snip, end --
2044
+ // -- snip, end --
1930
2045
 
1931
- console.log(
1932
- await deleteBulkKeyValue(config.account_id, namespaceId, content)
1933
- );
2046
+ console.log(
2047
+ await deleteBulkKeyValue(
2048
+ config.account_id,
2049
+ namespaceId,
2050
+ content
2051
+ )
2052
+ );
2053
+ }
1934
2054
  }
1935
2055
  );
1936
2056
  }
@@ -1967,8 +2087,15 @@ export async function main(argv: string[]): Promise<void> {
1967
2087
  if (e instanceof CommandLineArgsError) {
1968
2088
  wrangler.showHelp("error");
1969
2089
  console.error(""); // Just adds a bit of space
2090
+ console.error(e.message);
2091
+ } else {
2092
+ console.error(e.message);
2093
+ console.error(""); // Just adds a bit of space
2094
+ console.error(
2095
+ `${fgGreenColor}%s${resetColor}`,
2096
+ "If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2097
+ );
1970
2098
  }
1971
- console.error(e.message);
1972
2099
  throw e;
1973
2100
  }
1974
2101
  }