wrangler 2.0.3 → 2.0.7

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/index.tsx CHANGED
@@ -11,6 +11,7 @@ import { render } from "ink";
11
11
  import React from "react";
12
12
  import onExit from "signal-exit";
13
13
  import supportsColor from "supports-color";
14
+ import { setGlobalDispatcher, ProxyAgent } from "undici";
14
15
  import makeCLI from "yargs";
15
16
  import { version as wranglerVersion } from "../package.json";
16
17
  import { fetchResult } from "./cfetch";
@@ -22,17 +23,19 @@ import { confirm, prompt } from "./dialogs";
22
23
  import { getEntry } from "./entry";
23
24
  import { DeprecationError } from "./errors";
24
25
  import {
25
- getNamespaceId,
26
- listNamespaces,
27
- listNamespaceKeys,
28
- putKeyValue,
29
- putBulkKeyValue,
30
- deleteBulkKeyValue,
31
- createNamespace,
32
- isValidNamespaceBinding,
33
- getKeyValue,
34
- isKeyValue,
35
- unexpectedKeyValueProps,
26
+ getKVNamespaceId,
27
+ listKVNamespaces,
28
+ listKVNamespaceKeys,
29
+ putKVKeyValue,
30
+ putKVBulkKeyValue,
31
+ deleteKVBulkKeyValue,
32
+ createKVNamespace,
33
+ isValidKVNamespaceBinding,
34
+ getKVKeyValue,
35
+ isKVKeyValue,
36
+ unexpectedKVKeyValueProps,
37
+ deleteKVNamespace,
38
+ deleteKVKeyValue,
36
39
  } from "./kv";
37
40
  import { logger } from "./logger";
38
41
  import { getPackageManager } from "./package-manager";
@@ -41,6 +44,7 @@ import {
41
44
  formatMessage,
42
45
  ParseError,
43
46
  parseJSON,
47
+ parsePackageJSON,
44
48
  parseTOML,
45
49
  readFileSync,
46
50
  } from "./parse";
@@ -75,6 +79,17 @@ const resetColor = "\x1b[0m";
75
79
  const fgGreenColor = "\x1b[32m";
76
80
  const DEFAULT_LOCAL_PORT = 8787;
77
81
 
82
+ const proxy =
83
+ process.env.https_proxy ||
84
+ process.env.HTTPS_PROXY ||
85
+ process.env.http_proxy ||
86
+ process.env.HTTP_PROXY ||
87
+ undefined;
88
+
89
+ if (proxy) {
90
+ setGlobalDispatcher(new ProxyAgent(proxy));
91
+ }
92
+
78
93
  function getRules(config: Config): Config["rules"] {
79
94
  const rules = config.rules ?? config.build?.upload?.rules ?? [];
80
95
 
@@ -204,9 +219,17 @@ function demandOneOfOption(...options: string[]) {
204
219
  };
205
220
  }
206
221
 
222
+ /**
223
+ * Remove trailing white space from inputs.
224
+ * Matching Wrangler legacy behavior with handling inputs
225
+ */
226
+ function trimTrailingWhitespace(str: string) {
227
+ return str.trimEnd();
228
+ }
229
+
207
230
  class CommandLineArgsError extends Error {}
208
231
 
209
- export async function main(argv: string[]): Promise<void> {
232
+ function createCLIParser(argv: string[]) {
210
233
  const wrangler = makeCLI(argv)
211
234
  .strict()
212
235
  // We handle errors ourselves in a try-catch around `yargs.parse`.
@@ -323,6 +346,9 @@ export async function main(argv: string[]): Promise<void> {
323
346
  throw new CommandLineArgsError(message);
324
347
  }
325
348
 
349
+ const devDepsToInstall: string[] = [];
350
+ const instructions: string[] = [];
351
+ let shouldRunPackageManagerInstall = false;
326
352
  const creationDirectory = path.resolve(process.cwd(), args.name ?? "");
327
353
 
328
354
  if (args.site) {
@@ -411,19 +437,16 @@ export async function main(argv: string[]): Promise<void> {
411
437
  try {
412
438
  isGitInstalled = (await execa("git", ["--version"])).exitCode === 0;
413
439
  } catch (err) {
414
- if ((err as { code: string | undefined }).code !== "ENOENT") {
415
- // only throw if the error is not because git is not installed
416
- throw err;
417
- } else {
418
- isGitInstalled = false;
419
- }
440
+ isGitInstalled = false;
420
441
  }
421
442
  if (!isInsideGitProject && isGitInstalled) {
422
443
  const shouldInitGit =
423
444
  yesFlag ||
424
445
  (await confirm("Would you like to use git to manage this Worker?"));
425
446
  if (shouldInitGit) {
426
- await execa("git", ["init"], { cwd: creationDirectory });
447
+ await execa("git", ["init", "--initial-branch=main"], {
448
+ cwd: creationDirectory,
449
+ });
427
450
  await writeFile(
428
451
  path.join(creationDirectory, ".gitignore"),
429
452
  readFileSync(path.join(__dirname, "../templates/gitignore"))
@@ -469,7 +492,7 @@ export async function main(argv: string[]): Promise<void> {
469
492
  ) + "\n"
470
493
  );
471
494
 
472
- await packageManager.install();
495
+ shouldRunPackageManagerInstall = true;
473
496
  pathToPackageJson = path.join(creationDirectory, "package.json");
474
497
  logger.log(
475
498
  `✨ Created ${path.relative(process.cwd(), pathToPackageJson)}`
@@ -480,7 +503,7 @@ export async function main(argv: string[]): Promise<void> {
480
503
  } else {
481
504
  // If package.json exists and wrangler isn't installed,
482
505
  // then ask to add wrangler to devDependencies
483
- const packageJson = parseJSON(
506
+ const packageJson = parsePackageJSON(
484
507
  readFileSync(pathToPackageJson),
485
508
  pathToPackageJson
486
509
  );
@@ -499,8 +522,7 @@ export async function main(argv: string[]): Promise<void> {
499
522
  )}?`
500
523
  ));
501
524
  if (shouldInstall) {
502
- await packageManager.addDevDeps(`wrangler@${wranglerVersion}`);
503
- logger.log(`✨ Installed wrangler`);
525
+ devDepsToInstall.push(`wrangler@${wranglerVersion}`);
504
526
  }
505
527
  }
506
528
  }
@@ -518,23 +540,18 @@ export async function main(argv: string[]): Promise<void> {
518
540
  path.join(creationDirectory, "./tsconfig.json"),
519
541
  readFileSync(path.join(__dirname, "../templates/tsconfig.json"))
520
542
  );
521
- await packageManager.addDevDeps(
522
- "@cloudflare/workers-types",
523
- "typescript"
524
- );
543
+ devDepsToInstall.push("@cloudflare/workers-types");
544
+ devDepsToInstall.push("typescript");
525
545
  pathToTSConfig = path.join(creationDirectory, "tsconfig.json");
526
546
  logger.log(
527
- `✨ Created ${path.relative(
528
- process.cwd(),
529
- pathToTSConfig
530
- )}, installed @cloudflare/workers-types into devDependencies`
547
+ `✨ Created ${path.relative(process.cwd(), pathToTSConfig)}`
531
548
  );
532
549
  }
533
550
  } else {
534
551
  isTypescriptProject = true;
535
552
  // If there's a tsconfig, check if @cloudflare/workers-types
536
553
  // is already installed, and offer to install it if not
537
- const packageJson = parseJSON(
554
+ const packageJson = parsePackageJSON(
538
555
  readFileSync(pathToPackageJson),
539
556
  pathToPackageJson
540
557
  );
@@ -548,13 +565,13 @@ export async function main(argv: string[]): Promise<void> {
548
565
  "Would you like to install the type definitions for Workers into your package.json?"
549
566
  );
550
567
  if (shouldInstall) {
551
- await packageManager.addDevDeps("@cloudflare/workers-types");
568
+ devDepsToInstall.push("@cloudflare/workers-types");
552
569
  // We don't update the tsconfig.json because
553
570
  // it could be complicated in existing projects
554
571
  // and we don't want to break them. Instead, we simply
555
572
  // tell the user that they need to update their tsconfig.json
556
- logger.log(
557
- `✨ Installed @cloudflare/workers-types.\nPlease add "@cloudflare/workers-types" to compilerOptions.types in ${path.relative(
573
+ instructions.push(
574
+ `🚨 Please add "@cloudflare/workers-types" to compilerOptions.types in ${path.relative(
558
575
  process.cwd(),
559
576
  pathToTSConfig
560
577
  )}`
@@ -563,7 +580,7 @@ export async function main(argv: string[]): Promise<void> {
563
580
  }
564
581
  }
565
582
 
566
- const packageJsonContent = parseJSON(
583
+ const packageJsonContent = parsePackageJSON(
567
584
  readFileSync(pathToPackageJson),
568
585
  pathToPackageJson
569
586
  );
@@ -572,6 +589,41 @@ export async function main(argv: string[]): Promise<void> {
572
589
  !packageJsonContent.scripts?.publish &&
573
590
  shouldCreatePackageJson;
574
591
 
592
+ /*
593
+ * Passes the array of accumulated devDeps to install through to
594
+ * the package manager. Also generates a human-readable list
595
+ * of packages it installed.
596
+ * If there are no devDeps to install, optionally runs
597
+ * the package manager's install command.
598
+ */
599
+ async function installPackages(
600
+ shouldRunInstall: boolean,
601
+ depsToInstall: string[]
602
+ ) {
603
+ //lets install the devDeps they asked for
604
+ //and run their package manager's install command if needed
605
+ if (depsToInstall.length > 0) {
606
+ const formatter = new Intl.ListFormat("en", {
607
+ style: "long",
608
+ type: "conjunction",
609
+ });
610
+ await packageManager.addDevDeps(...depsToInstall);
611
+ const versionlessPackages = depsToInstall.map((dep) =>
612
+ dep === `wrangler@${wranglerVersion}` ? "wrangler" : dep
613
+ );
614
+
615
+ logger.log(
616
+ `✨ Installed ${formatter.format(
617
+ versionlessPackages
618
+ )} into devDependencies`
619
+ );
620
+ } else {
621
+ if (shouldRunInstall) {
622
+ await packageManager.install();
623
+ }
624
+ }
625
+ }
626
+
575
627
  async function writePackageJsonScriptsAndUpdateWranglerToml(
576
628
  isWritingScripts: boolean,
577
629
  isCreatingWranglerToml: boolean,
@@ -615,21 +667,21 @@ export async function main(argv: string[]): Promise<void> {
615
667
  2
616
668
  ) + "\n"
617
669
  );
618
- logger.log(
670
+ instructions.push(
619
671
  `\nTo start developing your Worker, run \`${
620
672
  isNamedWorker ? `cd ${args.name} && ` : ""
621
673
  }npm start\``
622
674
  );
623
- logger.log(
675
+ instructions.push(
624
676
  `To publish your Worker to the Internet, run \`npm run publish\``
625
677
  );
626
678
  } else {
627
- logger.log(
679
+ instructions.push(
628
680
  `\nTo start developing your Worker, run \`npx wrangler dev\`${
629
681
  isCreatingWranglerToml ? "" : ` ${scriptPath}`
630
682
  }`
631
683
  );
632
- logger.log(
684
+ instructions.push(
633
685
  `To publish your Worker to the Internet, run \`npx wrangler publish\`${
634
686
  isCreatingWranglerToml ? "" : ` ${scriptPath}`
635
687
  }`
@@ -708,6 +760,21 @@ export async function main(argv: string[]): Promise<void> {
708
760
  }
709
761
  }
710
762
  }
763
+ // install packages as the final step of init
764
+ try {
765
+ await installPackages(shouldRunPackageManagerInstall, devDepsToInstall);
766
+ } catch (e) {
767
+ // fetching packages could fail due to loss of internet, etc
768
+ // we should let folks know we failed to fetch, but their
769
+ // workers project is still ready to go
770
+ logger.error(e instanceof Error ? e.message : e);
771
+ instructions.push(
772
+ "\n🚨 wrangler was unable to fetch your npm packages, but your project is ready to go"
773
+ );
774
+ }
775
+
776
+ // let users know what to do now
777
+ instructions.forEach((instruction) => logger.log(instruction));
711
778
  }
712
779
  );
713
780
 
@@ -718,13 +785,34 @@ export async function main(argv: string[]): Promise<void> {
718
785
  (yargs) => {
719
786
  return yargs.option("env", {
720
787
  describe: "Perform on a specific environment",
788
+ type: "string",
721
789
  });
722
790
  },
723
- () => {
791
+ async (buildArgs) => {
724
792
  // "[DEPRECATED] 🦀 Build your project (if applicable)",
725
- throw new DeprecationError(
726
- "`wrangler build` has been deprecated, please refer to https://developers.cloudflare.com/workers/wrangler/migration/deprecations/#build for alternatives"
793
+
794
+ const envFlag = buildArgs.env ? ` --env=${buildArgs.env}` : "";
795
+ logger.log(
796
+ formatMessage({
797
+ kind: "warning",
798
+ text: "Deprecation: `wrangler build` has been deprecated.",
799
+ notes: [
800
+ {
801
+ text: "Please refer to https://developers.cloudflare.com/workers/wrangler/migration/deprecations/#build for more information.",
802
+ },
803
+ {
804
+ text: `Attempting to run \`wrangler publish --dry-run --outdir=dist${envFlag}\` for you instead:`,
805
+ },
806
+ ],
807
+ })
727
808
  );
809
+
810
+ await createCLIParser([
811
+ "publish",
812
+ "--dry-run",
813
+ "--outdir=dist",
814
+ ...(buildArgs.env ? ["--env", buildArgs.env] : []),
815
+ ]).parse();
728
816
  }
729
817
  );
730
818
 
@@ -895,6 +983,19 @@ export async function main(argv: string[]): Promise<void> {
895
983
  const config = readConfig(configPath, args);
896
984
  const entry = await getEntry(args, config, "dev");
897
985
 
986
+ if (config.services && config.services.length > 0) {
987
+ logger.warn(
988
+ `This worker is bound to live services: ${config.services
989
+ .map(
990
+ (service) =>
991
+ `${service.binding} (${service.service}${
992
+ service.environment ? `@${service.environment}` : ""
993
+ })`
994
+ )
995
+ .join(", ")}`
996
+ );
997
+ }
998
+
898
999
  if (args.inspect) {
899
1000
  logger.warn(
900
1001
  "Passing --inspect is unnecessary, now you can always connect to devtools."
@@ -932,6 +1033,9 @@ export async function main(argv: string[]): Promise<void> {
932
1033
  * try to extract a host from it
933
1034
  */
934
1035
  function getHost(urlLike: string): string | undefined {
1036
+ // strip leading * / *.
1037
+ urlLike = urlLike.replace(/^\*(\.)?/g, "");
1038
+
935
1039
  if (
936
1040
  !(urlLike.startsWith("http://") || urlLike.startsWith("https://"))
937
1041
  ) {
@@ -1102,6 +1206,7 @@ export async function main(argv: string[]): Promise<void> {
1102
1206
  };
1103
1207
  }
1104
1208
  ),
1209
+ services: config.services,
1105
1210
  unsafe: config.unsafe?.bindings,
1106
1211
  }}
1107
1212
  crons={config.triggers.crons}
@@ -1256,7 +1361,7 @@ export async function main(argv: string[]): Promise<void> {
1256
1361
  );
1257
1362
  }
1258
1363
 
1259
- const accountId = await requireAuth(config);
1364
+ const accountId = args.dryRun ? undefined : await requireAuth(config);
1260
1365
 
1261
1366
  const assetPaths = getAssetPaths(
1262
1367
  config,
@@ -1264,6 +1369,7 @@ export async function main(argv: string[]): Promise<void> {
1264
1369
  args.siteInclude,
1265
1370
  args.siteExclude
1266
1371
  );
1372
+
1267
1373
  await publish({
1268
1374
  config,
1269
1375
  accountId,
@@ -1554,6 +1660,7 @@ export async function main(argv: string[]): Promise<void> {
1554
1660
  };
1555
1661
  }
1556
1662
  ),
1663
+ services: config.services,
1557
1664
  unsafe: config.unsafe?.bindings,
1558
1665
  }}
1559
1666
  crons={config.triggers.crons}
@@ -1704,9 +1811,11 @@ export async function main(argv: string[]): Promise<void> {
1704
1811
  const accountId = await requireAuth(config);
1705
1812
 
1706
1813
  const isInteractive = process.stdin.isTTY;
1707
- const secretValue = isInteractive
1708
- ? await prompt("Enter a secret value:", "password")
1709
- : await readFromStdin();
1814
+ const secretValue = trimTrailingWhitespace(
1815
+ isInteractive
1816
+ ? await prompt("Enter a secret value:", "password")
1817
+ : await readFromStdin()
1818
+ );
1710
1819
 
1711
1820
  logger.log(
1712
1821
  `🌀 Creating the secret for script ${scriptName} ${
@@ -1751,6 +1860,7 @@ export async function main(argv: string[]): Promise<void> {
1751
1860
  vars: {},
1752
1861
  durable_objects: { bindings: [] },
1753
1862
  r2_buckets: [],
1863
+ services: [],
1754
1864
  wasm_modules: {},
1755
1865
  text_blobs: {},
1756
1866
  data_blobs: {},
@@ -1919,7 +2029,7 @@ export async function main(argv: string[]): Promise<void> {
1919
2029
  async (args) => {
1920
2030
  await printWranglerBanner();
1921
2031
 
1922
- if (!isValidNamespaceBinding(args.namespace)) {
2032
+ if (!isValidKVNamespaceBinding(args.namespace)) {
1923
2033
  throw new CommandLineArgsError(
1924
2034
  `The namespace binding name "${args.namespace}" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number.`
1925
2035
  );
@@ -1942,7 +2052,7 @@ export async function main(argv: string[]): Promise<void> {
1942
2052
  // TODO: generate a binding name stripping non alphanumeric chars
1943
2053
 
1944
2054
  logger.log(`🌀 Creating namespace with title "${title}"`);
1945
- const namespaceId = await createNamespace(accountId, title);
2055
+ const namespaceId = await createKVNamespace(accountId, title);
1946
2056
 
1947
2057
  logger.log("✨ Success!");
1948
2058
  const envString = args.env ? ` under [env.${args.env}]` : "";
@@ -1969,7 +2079,7 @@ export async function main(argv: string[]): Promise<void> {
1969
2079
  // TODO: we should show bindings if they exist for given ids
1970
2080
 
1971
2081
  logger.log(
1972
- JSON.stringify(await listNamespaces(accountId), null, " ")
2082
+ JSON.stringify(await listKVNamespaces(accountId), null, " ")
1973
2083
  );
1974
2084
  }
1975
2085
  )
@@ -2006,7 +2116,7 @@ export async function main(argv: string[]): Promise<void> {
2006
2116
 
2007
2117
  let id;
2008
2118
  try {
2009
- id = getNamespaceId(args, config);
2119
+ id = getKVNamespaceId(args, config);
2010
2120
  } catch (e) {
2011
2121
  throw new CommandLineArgsError(
2012
2122
  "Not able to delete namespace.\n" + ((e as Error).message ?? e)
@@ -2015,12 +2125,7 @@ export async function main(argv: string[]): Promise<void> {
2015
2125
 
2016
2126
  const accountId = await requireAuth(config);
2017
2127
 
2018
- await fetchResult<{ id: string }>(
2019
- `/accounts/${accountId}/storage/kv/namespaces/${encodeURIComponent(
2020
- id
2021
- )}`,
2022
- { method: "DELETE" }
2023
- );
2128
+ await deleteKVNamespace(accountId, id);
2024
2129
 
2025
2130
  // TODO: recommend they remove it from wrangler.toml
2026
2131
 
@@ -2105,7 +2210,7 @@ export async function main(argv: string[]): Promise<void> {
2105
2210
  async ({ key, ttl, expiration, ...args }) => {
2106
2211
  await printWranglerBanner();
2107
2212
  const config = readConfig(args.config as ConfigPath, args);
2108
- const namespaceId = getNamespaceId(args, config);
2213
+ const namespaceId = getKVNamespaceId(args, config);
2109
2214
  // One of `args.path` and `args.value` must be defined
2110
2215
  const value = args.path
2111
2216
  ? readFileSync(args.path)
@@ -2124,7 +2229,7 @@ export async function main(argv: string[]): Promise<void> {
2124
2229
 
2125
2230
  const accountId = await requireAuth(config);
2126
2231
 
2127
- await putKeyValue(accountId, namespaceId, {
2232
+ await putKVKeyValue(accountId, namespaceId, {
2128
2233
  key,
2129
2234
  value,
2130
2235
  expiration,
@@ -2169,11 +2274,11 @@ export async function main(argv: string[]): Promise<void> {
2169
2274
  async ({ prefix, ...args }) => {
2170
2275
  // TODO: support for limit+cursor (pagination)
2171
2276
  const config = readConfig(args.config as ConfigPath, args);
2172
- const namespaceId = getNamespaceId(args, config);
2277
+ const namespaceId = getKVNamespaceId(args, config);
2173
2278
 
2174
2279
  const accountId = await requireAuth(config);
2175
2280
 
2176
- const results = await listNamespaceKeys(
2281
+ const results = await listKVNamespaceKeys(
2177
2282
  accountId,
2178
2283
  namespaceId,
2179
2284
  prefix
@@ -2221,11 +2326,11 @@ export async function main(argv: string[]): Promise<void> {
2221
2326
  },
2222
2327
  async ({ key, ...args }) => {
2223
2328
  const config = readConfig(args.config as ConfigPath, args);
2224
- const namespaceId = getNamespaceId(args, config);
2329
+ const namespaceId = getKVNamespaceId(args, config);
2225
2330
 
2226
2331
  const accountId = await requireAuth(config);
2227
2332
 
2228
- logger.log(await getKeyValue(accountId, namespaceId, key));
2333
+ logger.log(await getKVKeyValue(accountId, namespaceId, key));
2229
2334
  }
2230
2335
  )
2231
2336
  .command(
@@ -2263,7 +2368,7 @@ export async function main(argv: string[]): Promise<void> {
2263
2368
  async ({ key, ...args }) => {
2264
2369
  await printWranglerBanner();
2265
2370
  const config = readConfig(args.config as ConfigPath, args);
2266
- const namespaceId = getNamespaceId(args, config);
2371
+ const namespaceId = getKVNamespaceId(args, config);
2267
2372
 
2268
2373
  logger.log(
2269
2374
  `Deleting the key "${key}" on namespace ${namespaceId}.`
@@ -2271,12 +2376,7 @@ export async function main(argv: string[]): Promise<void> {
2271
2376
 
2272
2377
  const accountId = await requireAuth(config);
2273
2378
 
2274
- await fetchResult(
2275
- `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${encodeURIComponent(
2276
- key
2277
- )}`,
2278
- { method: "DELETE" }
2279
- );
2379
+ await deleteKVKeyValue(accountId, namespaceId, key);
2280
2380
  }
2281
2381
  );
2282
2382
  }
@@ -2328,7 +2428,7 @@ export async function main(argv: string[]): Promise<void> {
2328
2428
  // but we'll do that in the future if needed.
2329
2429
 
2330
2430
  const config = readConfig(args.config as ConfigPath, args);
2331
- const namespaceId = getNamespaceId(args, config);
2431
+ const namespaceId = getKVNamespaceId(args, config);
2332
2432
  const content = parseJSON(readFileSync(filename), filename);
2333
2433
 
2334
2434
  if (!Array.isArray(content)) {
@@ -2342,18 +2442,12 @@ export async function main(argv: string[]): Promise<void> {
2342
2442
  const warnings: string[] = [];
2343
2443
  for (let i = 0; i < content.length; i++) {
2344
2444
  const keyValue = content[i];
2345
- if (typeof keyValue !== "object") {
2346
- errors.push(
2347
- `The item at index ${i} is type: "${typeof keyValue}" - ${JSON.stringify(
2348
- keyValue
2349
- )}`
2350
- );
2351
- } else if (!isKeyValue(keyValue)) {
2445
+ if (!isKVKeyValue(keyValue)) {
2352
2446
  errors.push(
2353
2447
  `The item at index ${i} is ${JSON.stringify(keyValue)}`
2354
2448
  );
2355
2449
  } else {
2356
- const props = unexpectedKeyValueProps(keyValue);
2450
+ const props = unexpectedKVKeyValueProps(keyValue);
2357
2451
  if (props.length > 0) {
2358
2452
  warnings.push(
2359
2453
  `The item at index ${i} contains unexpected properties: ${JSON.stringify(
@@ -2386,14 +2480,7 @@ export async function main(argv: string[]): Promise<void> {
2386
2480
  }
2387
2481
 
2388
2482
  const accountId = await requireAuth(config);
2389
- await putBulkKeyValue(
2390
- accountId,
2391
- namespaceId,
2392
- content,
2393
- (index, total) => {
2394
- logger.log(`Uploaded ${index} of ${total}.`);
2395
- }
2396
- );
2483
+ await putKVBulkKeyValue(accountId, namespaceId, content);
2397
2484
 
2398
2485
  logger.log("Success!");
2399
2486
  }
@@ -2438,7 +2525,7 @@ export async function main(argv: string[]): Promise<void> {
2438
2525
  async ({ filename, ...args }) => {
2439
2526
  await printWranglerBanner();
2440
2527
  const config = readConfig(args.config as ConfigPath, args);
2441
- const namespaceId = getNamespaceId(args, config);
2528
+ const namespaceId = getKVNamespaceId(args, config);
2442
2529
 
2443
2530
  if (!args.force) {
2444
2531
  const result = await confirm(
@@ -2483,14 +2570,7 @@ export async function main(argv: string[]): Promise<void> {
2483
2570
 
2484
2571
  const accountId = await requireAuth(config);
2485
2572
 
2486
- await deleteBulkKeyValue(
2487
- accountId,
2488
- namespaceId,
2489
- content,
2490
- (index, total) => {
2491
- logger.log(`Deleted ${index} of ${total}.`);
2492
- }
2493
- );
2573
+ await deleteKVBulkKeyValue(accountId, namespaceId, content);
2494
2574
 
2495
2575
  logger.log("Success!");
2496
2576
  }
@@ -2655,14 +2735,21 @@ export async function main(argv: string[]): Promise<void> {
2655
2735
  wrangler.version(wranglerVersion).alias("v", "version");
2656
2736
  wrangler.exitProcess(false);
2657
2737
 
2738
+ return wrangler;
2739
+ }
2740
+
2741
+ export async function main(argv: string[]): Promise<void> {
2742
+ const wrangler = createCLIParser(argv);
2658
2743
  try {
2659
2744
  await wrangler.parse();
2660
2745
  } catch (e) {
2661
2746
  logger.log(""); // Just adds a bit of space
2662
2747
  if (e instanceof CommandLineArgsError) {
2663
- wrangler.showHelp("error");
2664
- logger.log(""); // Add a bit of space.
2665
2748
  logger.error(e.message);
2749
+ // We are not able to ask the `wrangler` CLI parser to show help for a subcommand programmatically.
2750
+ // The workaround is to re-run the parsing with an additional `--help` flag, which will result in the correct help message being displayed.
2751
+ // The `wrangler` object is "frozen"; we cannot reuse that with different args, so we must create a new CLI parser to generate the help message.
2752
+ await createCLIParser([...argv, "--help"]).parse();
2666
2753
  } else if (e instanceof ParseError) {
2667
2754
  e.notes.push({
2668
2755
  text: "\nIf you think this is a bug, please open an issue at: https://github.com/cloudflare/wrangler2/issues/new",
package/src/inspect.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import assert from "node:assert";
2
2
  import { createServer } from "node:http";
3
+ import os from "node:os";
3
4
  import { URL } from "node:url";
4
5
 
6
+ import open from "open";
5
7
  import { useEffect, useRef, useState } from "react";
6
8
  import WebSocket, { WebSocketServer } from "ws";
7
9
  import { version } from "../package.json";
@@ -621,3 +623,40 @@ function logConsoleMessage(evt: Protocol.Runtime.ConsoleAPICalledEvent): void {
621
623
  logger.warn("console event:", evt);
622
624
  }
623
625
  }
626
+
627
+ /**
628
+ * Opens the chrome debugger
629
+ */
630
+ export const openInspector = async (inspectorPort: number) => {
631
+ const url = `https://built-devtools.pages.dev/js_app?experiments=true&v8only=true&ws=localhost:${inspectorPort}/ws`;
632
+ const errorMessage =
633
+ "Failed to open inspector.\nInspector depends on having a Chromium-based browser installed, maybe you need to install one?";
634
+
635
+ // see: https://github.com/sindresorhus/open/issues/177#issue-610016699
636
+ let braveBrowser: string;
637
+ switch (os.platform()) {
638
+ case "darwin":
639
+ case "win32":
640
+ braveBrowser = "Brave";
641
+ break;
642
+ default:
643
+ braveBrowser = "brave";
644
+ }
645
+
646
+ const childProcess = await open(url, {
647
+ app: [
648
+ {
649
+ name: open.apps.chrome,
650
+ },
651
+ {
652
+ name: braveBrowser,
653
+ },
654
+ {
655
+ name: open.apps.edge,
656
+ },
657
+ ],
658
+ });
659
+ childProcess.on("error", () => {
660
+ logger.warn(errorMessage);
661
+ });
662
+ };