wrangler 0.0.0-e3cab74 → 0.0.0-e3d46ab3

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 (158) hide show
  1. package/README.md +47 -16
  2. package/bin/wrangler.js +95 -32
  3. package/config-schema.json +2939 -0
  4. package/kv-asset-handler.js +1 -0
  5. package/package.json +135 -84
  6. package/templates/__tests__/pages-dev-util.test.ts +128 -0
  7. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  8. package/templates/__tests__/tsconfig.json +8 -0
  9. package/templates/checked-fetch.js +30 -0
  10. package/templates/facade.d.ts +19 -0
  11. package/templates/gitignore +167 -0
  12. package/templates/init-tests/test-jest-new-worker.js +23 -0
  13. package/templates/init-tests/test-vitest-new-worker.js +24 -0
  14. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  15. package/templates/middleware/common.ts +67 -0
  16. package/templates/middleware/loader-modules.ts +134 -0
  17. package/templates/middleware/loader-sw.ts +229 -0
  18. package/templates/middleware/middleware-ensure-req-body-drained.ts +18 -0
  19. package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
  20. package/templates/middleware/middleware-pretty-error.ts +40 -0
  21. package/templates/middleware/middleware-scheduled.ts +15 -0
  22. package/templates/middleware/middleware-serve-static-assets.d.ts +6 -0
  23. package/templates/middleware/middleware-serve-static-assets.ts +56 -0
  24. package/templates/modules-watch-stub.js +4 -0
  25. package/templates/new-worker-scheduled.js +17 -0
  26. package/templates/new-worker-scheduled.ts +32 -0
  27. package/templates/new-worker.js +3 -3
  28. package/templates/new-worker.ts +22 -4
  29. package/templates/no-op-worker.js +10 -0
  30. package/templates/pages-dev-pipeline.ts +32 -0
  31. package/templates/pages-dev-util.ts +55 -0
  32. package/templates/pages-shim.ts +9 -0
  33. package/templates/pages-template-plugin.ts +190 -0
  34. package/templates/pages-template-worker.ts +198 -0
  35. package/templates/startDevWorker/InspectorProxyWorker.ts +664 -0
  36. package/templates/startDevWorker/ProxyWorker.ts +334 -0
  37. package/templates/tsconfig-sanity.ts +11 -0
  38. package/templates/tsconfig.init.json +105 -0
  39. package/templates/tsconfig.json +6 -103
  40. package/wrangler-dist/InspectorProxyWorker.js +464 -0
  41. package/wrangler-dist/InspectorProxyWorker.js.map +6 -0
  42. package/wrangler-dist/ProxyWorker.js +240 -0
  43. package/wrangler-dist/ProxyWorker.js.map +6 -0
  44. package/wrangler-dist/cli.d.ts +24056 -0
  45. package/wrangler-dist/cli.js +199391 -131806
  46. package/wrangler-dist/wasm-sync.wasm +0 -0
  47. package/import_meta_url.js +0 -3
  48. package/miniflare-config-stubs/.env.empty +0 -0
  49. package/miniflare-config-stubs/package.empty.json +0 -1
  50. package/miniflare-config-stubs/wrangler.empty.toml +0 -0
  51. package/pages/functions/buildWorker.ts +0 -62
  52. package/pages/functions/filepath-routing.test.ts +0 -123
  53. package/pages/functions/filepath-routing.ts +0 -178
  54. package/pages/functions/identifiers.ts +0 -78
  55. package/pages/functions/routes.ts +0 -151
  56. package/pages/functions/template-worker.ts +0 -130
  57. package/src/__tests__/configuration.test.ts +0 -2185
  58. package/src/__tests__/dev.test.tsx +0 -113
  59. package/src/__tests__/guess-worker-format.test.ts +0 -66
  60. package/src/__tests__/helpers/clipboardy-mock.js +0 -4
  61. package/src/__tests__/helpers/cmd-shim.d.ts +0 -11
  62. package/src/__tests__/helpers/faye-websocket.d.ts +0 -6
  63. package/src/__tests__/helpers/mock-account-id.ts +0 -30
  64. package/src/__tests__/helpers/mock-bin.ts +0 -36
  65. package/src/__tests__/helpers/mock-cfetch.ts +0 -207
  66. package/src/__tests__/helpers/mock-console.ts +0 -62
  67. package/src/__tests__/helpers/mock-dialogs.ts +0 -65
  68. package/src/__tests__/helpers/mock-kv.ts +0 -40
  69. package/src/__tests__/helpers/mock-user.ts +0 -27
  70. package/src/__tests__/helpers/mock-web-socket.ts +0 -29
  71. package/src/__tests__/helpers/run-in-tmp.ts +0 -29
  72. package/src/__tests__/helpers/run-wrangler.ts +0 -16
  73. package/src/__tests__/helpers/write-wrangler-toml.ts +0 -17
  74. package/src/__tests__/index.test.ts +0 -866
  75. package/src/__tests__/jest.setup.ts +0 -57
  76. package/src/__tests__/kv.test.ts +0 -1141
  77. package/src/__tests__/logout.test.ts +0 -50
  78. package/src/__tests__/package-manager.test.ts +0 -206
  79. package/src/__tests__/parse.test.ts +0 -322
  80. package/src/__tests__/publish.test.ts +0 -2406
  81. package/src/__tests__/r2.test.ts +0 -198
  82. package/src/__tests__/secret.test.ts +0 -326
  83. package/src/__tests__/sentry.test.ts +0 -146
  84. package/src/__tests__/tail.test.ts +0 -564
  85. package/src/__tests__/whoami.test.tsx +0 -86
  86. package/src/api/form_data.ts +0 -217
  87. package/src/api/preview.ts +0 -147
  88. package/src/api/worker.ts +0 -186
  89. package/src/bundle.ts +0 -133
  90. package/src/cfetch/index.ts +0 -104
  91. package/src/cfetch/internal.ts +0 -133
  92. package/src/cli.ts +0 -19
  93. package/src/config/README.md +0 -107
  94. package/src/config/config.ts +0 -265
  95. package/src/config/diagnostics.ts +0 -80
  96. package/src/config/environment.ts +0 -305
  97. package/src/config/index.ts +0 -52
  98. package/src/config/validation-helpers.ts +0 -370
  99. package/src/config/validation.ts +0 -1017
  100. package/src/dev.tsx +0 -961
  101. package/src/dialogs.tsx +0 -77
  102. package/src/entry.ts +0 -57
  103. package/src/environment-variables.ts +0 -33
  104. package/src/guess-worker-format.ts +0 -68
  105. package/src/index.tsx +0 -2327
  106. package/src/inspect.ts +0 -609
  107. package/src/kv.tsx +0 -275
  108. package/src/module-collection.ts +0 -170
  109. package/src/open-in-browser.ts +0 -13
  110. package/src/package-manager.ts +0 -126
  111. package/src/pages.tsx +0 -1045
  112. package/src/parse.ts +0 -183
  113. package/src/paths.ts +0 -26
  114. package/src/proxy.ts +0 -376
  115. package/src/publish.ts +0 -368
  116. package/src/r2.ts +0 -50
  117. package/src/reporting.ts +0 -115
  118. package/src/sites.tsx +0 -241
  119. package/src/tail/filters.ts +0 -279
  120. package/src/tail/index.ts +0 -299
  121. package/src/tail/printing.ts +0 -62
  122. package/src/user.tsx +0 -1049
  123. package/src/whoami.tsx +0 -69
  124. package/templates/static-asset-facade.js +0 -47
  125. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  126. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  127. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  128. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  129. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  130. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  131. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  132. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  133. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  134. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  135. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  136. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  137. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  138. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  139. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  140. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  141. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  142. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  143. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  144. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  145. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  146. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  147. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  148. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  149. package/vendor/wrangler-mime/LICENSE +0 -21
  150. package/vendor/wrangler-mime/Mime.js +0 -97
  151. package/vendor/wrangler-mime/README.md +0 -187
  152. package/vendor/wrangler-mime/cli.js +0 -46
  153. package/vendor/wrangler-mime/index.js +0 -4
  154. package/vendor/wrangler-mime/lite.js +0 -4
  155. package/vendor/wrangler-mime/package.json +0 -52
  156. package/vendor/wrangler-mime/types/other.js +0 -1
  157. package/vendor/wrangler-mime/types/standard.js +0 -1
  158. package/wrangler-dist/cli.js.map +0 -7
package/src/index.tsx DELETED
@@ -1,2327 +0,0 @@
1
- import * as fs from "node:fs";
2
- import { 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";
7
- import getPort from "get-port";
8
- import { render } from "ink";
9
- import React from "react";
10
- import onExit from "signal-exit";
11
- import makeCLI from "yargs";
12
- import { version as wranglerVersion } from "../package.json";
13
- import { toFormData } from "./api/form_data";
14
- import { fetchResult } from "./cfetch";
15
- import { findWranglerToml, readConfig } from "./config";
16
- import Dev from "./dev";
17
- import { confirm, prompt } from "./dialogs";
18
- import { getEntry } from "./entry";
19
- import {
20
- getNamespaceId,
21
- listNamespaces,
22
- listNamespaceKeys,
23
- putKeyValue,
24
- putBulkKeyValue,
25
- deleteBulkKeyValue,
26
- createNamespace,
27
- isValidNamespaceBinding,
28
- getKeyValue,
29
- } from "./kv";
30
- import { getPackageManager } from "./package-manager";
31
- import { pages } from "./pages";
32
- import { formatMessage, ParseError, parseJSON, readFileSync } from "./parse";
33
- import publish from "./publish";
34
- import { createR2Bucket, deleteR2Bucket, listR2Buckets } from "./r2";
35
- import { getAssetPaths } from "./sites";
36
- import {
37
- createTail,
38
- jsonPrintLogs,
39
- prettyPrintLogs,
40
- translateCLICommandToFilterMessage,
41
- } from "./tail";
42
- import {
43
- login,
44
- logout,
45
- listScopes,
46
- initialise as initialiseUserConfig,
47
- loginOrRefreshIfRequired,
48
- getAccountId,
49
- validateScopeKeys,
50
- } from "./user";
51
- import { whoami } from "./whoami";
52
-
53
- import type { Config } from "./config";
54
- import type { TailCLIFilters } from "./tail";
55
- import type { RawData } from "ws";
56
- import type Yargs from "yargs";
57
-
58
- type ConfigPath = string | undefined;
59
-
60
- const resetColor = "\x1b[0m";
61
- const fgGreenColor = "\x1b[32m";
62
-
63
- function getRules(config: Config): Config["rules"] {
64
- const rules = config.rules ?? config.build?.upload?.rules ?? [];
65
-
66
- if (config.rules && config.build?.upload?.rules) {
67
- throw new Error(
68
- `You cannot configure both [rules] and [build.upload.rules] in your wrangler.toml. Delete the \`build.upload\` section.`
69
- );
70
- }
71
-
72
- if (config.build?.upload?.rules) {
73
- console.warn(
74
- `Deprecation notice: The \`build.upload.rules\` config field is no longer used, the rules should be specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration file, and add this:
75
-
76
- ${TOML.stringify({ rules: config.build.upload.rules })}`
77
- );
78
- }
79
- return rules;
80
- }
81
-
82
- function isLegacyEnv(args: unknown, config: Config): boolean {
83
- return (
84
- (args as { "legacy-env": boolean | undefined })["legacy-env"] ??
85
- config.legacy_env
86
- );
87
- }
88
-
89
- function getScriptName(
90
- args: { name: string | undefined; env: string | undefined },
91
- config: Config
92
- ): string | undefined {
93
- const shortScriptName = args.name ?? config.name;
94
- if (!shortScriptName) {
95
- return;
96
- }
97
-
98
- return isLegacyEnv(args, config)
99
- ? `${shortScriptName}${args.env ? `-${args.env}` : ""}`
100
- : shortScriptName;
101
- }
102
-
103
- // a helper to demand one of a set of options
104
- // via https://github.com/yargs/yargs/issues/1093#issuecomment-491299261
105
- function demandOneOfOption(...options: string[]) {
106
- return function (argv: Yargs.Arguments) {
107
- const count = options.filter((option) => argv[option]).length;
108
- const lastOption = options.pop();
109
-
110
- if (count === 0) {
111
- throw new CommandLineArgsError(
112
- `Exactly one of the arguments ${options.join(
113
- ", "
114
- )} and ${lastOption} is required`
115
- );
116
- } else if (count > 1) {
117
- throw new CommandLineArgsError(
118
- `Arguments ${options.join(
119
- ", "
120
- )} and ${lastOption} are mutually exclusive`
121
- );
122
- }
123
-
124
- return true;
125
- };
126
- }
127
-
128
- class CommandLineArgsError extends Error {}
129
- class DeprecationError extends Error {
130
- constructor(message: string) {
131
- super(`DEPRECATION WARNING:\n${message}`);
132
- }
133
- }
134
-
135
- export async function main(argv: string[]): Promise<void> {
136
- const wrangler = makeCLI(argv)
137
- // We handle errors ourselves in a try-catch around `yargs.parse`.
138
- // If you want the "help info" to be displayed then throw an instance of `CommandLineArgsError`.
139
- // Otherwise we just log the error that was thrown without any "help info".
140
- .showHelpOnFail(false)
141
- .fail((msg, error) => {
142
- if (!error) {
143
- // If there is only a `msg` then this came from yargs own validation, so wrap in a `CommandLineArgsError`.
144
- error = new CommandLineArgsError(msg);
145
- }
146
- throw error;
147
- })
148
- .scriptName("wrangler")
149
- .wrap(null);
150
-
151
- // the default is to simply print the help menu
152
- wrangler.command(
153
- ["*"],
154
- false,
155
- () => {},
156
- (args) => {
157
- if (args._.length > 0) {
158
- throw new CommandLineArgsError(`Unknown command: ${args._}.`);
159
- } else {
160
- wrangler.showHelp("log");
161
- }
162
- }
163
- );
164
-
165
- // You will note that we use the form for all commands where we use the builder function
166
- // to define options and subcommands.
167
- // Further we return the result of this builder even though it's not completely necessary.
168
- // The reason is that it's required for type inference of the args in the handle function.
169
- // I wish we could enforce this pattern, but this comment will have to do for now.
170
- // (It's also annoying that choices[] doesn't get inferred as an enum. 🤷‍♂.)
171
-
172
- // [DEPRECATED] generate
173
- wrangler.command(
174
- // we definitely want to move away from us cloning github templates
175
- // we can do something better here, let's see
176
- "generate [name] [template]",
177
- false,
178
- (yargs) => {
179
- return yargs
180
- .positional("name", {
181
- describe: "Name of the Workers project",
182
- default: "worker",
183
- })
184
- .positional("template", {
185
- describe: "a link to a GitHub template",
186
- default: "https://github.com/cloudflare/worker-template",
187
- });
188
- },
189
- () => {
190
- // "👯 [DEPRECATED]. Scaffold a Cloudflare Workers project from a public GitHub repository.",
191
- throw new DeprecationError(
192
- "`wrangler generate` has been deprecated, please refer to TODO://some/path for alternatives"
193
- );
194
- }
195
- );
196
-
197
- // init
198
- wrangler.command(
199
- "init [name]",
200
- "📥 Create a wrangler.toml configuration file",
201
- (yargs) => {
202
- return yargs
203
- .positional("name", {
204
- describe: "The name of your worker",
205
- type: "string",
206
- })
207
- .option("yes", {
208
- describe: 'Answer "yes" to any prompts for new projects',
209
- type: "boolean",
210
- alias: "y",
211
- });
212
- },
213
- async (args) => {
214
- if ("type" in args) {
215
- let message = "The --type option is no longer supported.";
216
- if (args.type === "webpack") {
217
- message +=
218
- "\nIf you wish to use webpack then you will need to create a custom build.";
219
- // TODO: Add a link to docs
220
- }
221
- throw new CommandLineArgsError(message);
222
- }
223
-
224
- // TODO: make sure args.name is a valid identifier for a worker name
225
-
226
- const creationDirectory = path.join(process.cwd(), args.name ?? "");
227
-
228
- const packageManager = await getPackageManager(creationDirectory);
229
-
230
- // TODO: ask which directory to make the worker in (defaults to args.name)
231
- // TODO: if args.name isn't provided, ask what to name the worker
232
-
233
- const wranglerTomlDestination = path.join(
234
- creationDirectory,
235
- "./wrangler.toml"
236
- );
237
- let justCreatedWranglerToml = false;
238
- const workerName =
239
- args.name || path.basename(path.resolve(process.cwd()));
240
- if (fs.existsSync(wranglerTomlDestination)) {
241
- console.warn(`${wranglerTomlDestination} file already exists!`);
242
- const shouldContinue = await confirm(
243
- "Do you want to continue initializing this project?"
244
- );
245
- if (!shouldContinue) {
246
- return;
247
- }
248
- } else {
249
- await mkdir(creationDirectory, { recursive: true });
250
- const compatibilityDate = new Date().toISOString().substring(0, 10);
251
- try {
252
- await writeFile(
253
- wranglerTomlDestination,
254
- TOML.stringify({
255
- name: workerName,
256
- compatibility_date: compatibilityDate,
257
- }) + "\n"
258
- );
259
- console.log(`✨ Successfully created wrangler.toml`);
260
- justCreatedWranglerToml = true;
261
- } catch (err) {
262
- throw new Error(
263
- `Failed to create wrangler.toml.\n${(err as Error).message ?? err}`
264
- );
265
- }
266
- }
267
-
268
- let pathToPackageJson = await findUp("package.json");
269
- let shouldCreatePackageJson = false;
270
- const yesFlag = args.yes ?? false;
271
- if (!pathToPackageJson) {
272
- // If no package.json exists, ask to create one
273
- shouldCreatePackageJson =
274
- yesFlag ||
275
- (await confirm(
276
- "No package.json found. Would you like to create one?"
277
- ));
278
-
279
- if (shouldCreatePackageJson) {
280
- await writeFile(
281
- path.join(creationDirectory, "./package.json"),
282
- JSON.stringify(
283
- {
284
- name: workerName,
285
- version: "0.0.0",
286
- devDependencies: {
287
- wrangler: wranglerVersion,
288
- },
289
- private: true,
290
- },
291
- null,
292
- " "
293
- ) + "\n"
294
- );
295
- await packageManager.install();
296
- console.log(`✨ Created package.json`);
297
- pathToPackageJson = path.join(creationDirectory, "package.json");
298
- } else {
299
- return;
300
- }
301
- } else {
302
- // If package.json exists and wrangler isn't installed,
303
- // then ask to add wrangler to devDependencies
304
- const packageJson = parseJSON(
305
- readFileSync(pathToPackageJson),
306
- pathToPackageJson
307
- );
308
- if (
309
- !(
310
- packageJson.devDependencies?.wrangler ||
311
- packageJson.dependencies?.wrangler
312
- )
313
- ) {
314
- const shouldInstall =
315
- yesFlag ||
316
- (await confirm(
317
- "Would you like to install wrangler into your package.json?"
318
- ));
319
- if (shouldInstall) {
320
- await packageManager.addDevDeps(`wrangler@${wranglerVersion}`);
321
- console.log(`✨ Installed wrangler`);
322
- }
323
- }
324
- }
325
-
326
- let isTypescriptProject = false;
327
- let pathToTSConfig = await findUp("tsconfig.json");
328
- if (!pathToTSConfig) {
329
- // If there's no tsconfig, offer to create one
330
- // and install @cloudflare/workers-types
331
- if (yesFlag || (await confirm("Would you like to use TypeScript?"))) {
332
- isTypescriptProject = true;
333
- await writeFile(
334
- path.join(creationDirectory, "./tsconfig.json"),
335
- readFileSync(path.join(__dirname, "../templates/tsconfig.json"))
336
- );
337
- await packageManager.addDevDeps(
338
- "@cloudflare/workers-types",
339
- "typescript"
340
- );
341
-
342
- console.log(
343
- `✨ Created tsconfig.json, installed @cloudflare/workers-types into devDependencies`
344
- );
345
- pathToTSConfig = path.join(creationDirectory, "tsconfig.json");
346
- }
347
- } else {
348
- isTypescriptProject = true;
349
- // If there's a tsconfig, check if @cloudflare/workers-types
350
- // is already installed, and offer to install it if not
351
- const packageJson = parseJSON(
352
- readFileSync(pathToPackageJson),
353
- pathToPackageJson
354
- );
355
- if (
356
- !(
357
- packageJson.devDependencies?.["@cloudflare/workers-types"] ||
358
- packageJson.dependencies?.["@cloudflare/workers-types"]
359
- )
360
- ) {
361
- const shouldInstall = await confirm(
362
- "Would you like to install the type definitions for Workers into your package.json?"
363
- );
364
- if (shouldInstall) {
365
- await packageManager.addDevDeps("@cloudflare/workers-types");
366
- // We don't update the tsconfig.json because
367
- // it could be complicated in existing projects
368
- // and we don't want to break them. Instead, we simply
369
- // tell the user that they need to update their tsconfig.json
370
- console.log(
371
- `✨ Installed @cloudflare/workers-types.\nPlease add "@cloudflare/workers-types" to compilerOptions.types in your tsconfig.json`
372
- );
373
- }
374
- }
375
- }
376
-
377
- const packageJsonContent = parseJSON(
378
- readFileSync(pathToPackageJson),
379
- pathToPackageJson
380
- );
381
- const shouldWritePackageJsonScripts =
382
- !packageJsonContent.scripts?.start &&
383
- !packageJsonContent.scripts?.publish &&
384
- shouldCreatePackageJson;
385
-
386
- async function writePackageJsonScriptsAndUpdateWranglerToml(
387
- isWritingScripts: boolean,
388
- isCreatingWranglerToml: boolean,
389
- packagePath: string,
390
- scriptPath: string
391
- ) {
392
- if (isCreatingWranglerToml) {
393
- // rewrite wrangler.toml with main = "path/to/script"
394
- const parsedWranglerToml = TOML.parse(
395
- readFileSync(wranglerTomlDestination)
396
- );
397
- fs.writeFileSync(
398
- wranglerTomlDestination,
399
- TOML.stringify({
400
- name: parsedWranglerToml.name,
401
- main: scriptPath,
402
- compatibility_date: parsedWranglerToml.compatibility_date,
403
- })
404
- );
405
- }
406
- const isNamedWorker =
407
- isCreatingWranglerToml && path.dirname(packagePath) !== process.cwd();
408
-
409
- if (isWritingScripts) {
410
- await writeFile(
411
- packagePath,
412
- JSON.stringify(
413
- {
414
- ...packageJsonContent,
415
- scripts: {
416
- ...packageJsonContent.scripts,
417
- start: isCreatingWranglerToml
418
- ? `wrangler dev`
419
- : `wrangler dev ${scriptPath}`,
420
- publish: isCreatingWranglerToml
421
- ? `wrangler publish`
422
- : `wrangler publish ${scriptPath}`,
423
- },
424
- },
425
- null,
426
- 2
427
- ) + "\n"
428
- );
429
- console.log(
430
- `\nTo start developing your Worker, run \`${
431
- isNamedWorker ? `cd ${args.name} && ` : ""
432
- }npm start\``
433
- );
434
- console.log(
435
- `To publish your Worker to the Internet, run \`npm run publish\``
436
- );
437
- } else {
438
- console.log(
439
- `\nTo start developing your Worker, run \`npx wrangler dev\`${
440
- isCreatingWranglerToml ? "" : ` ${scriptPath}`
441
- }`
442
- );
443
- console.log(
444
- `To publish your Worker to the Internet, run \`npx wrangler publish\`${
445
- isCreatingWranglerToml ? "" : ` ${scriptPath}`
446
- }`
447
- );
448
- }
449
- }
450
-
451
- if (isTypescriptProject) {
452
- if (!fs.existsSync(path.join(creationDirectory, "./src/index.ts"))) {
453
- let shouldCreateSource = false;
454
-
455
- shouldCreateSource =
456
- yesFlag ||
457
- (await confirm(
458
- `Would you like to create a Worker at src/index.ts?`
459
- ));
460
-
461
- if (shouldCreateSource) {
462
- await mkdir(path.join(creationDirectory, "./src"), {
463
- recursive: true,
464
- });
465
- await writeFile(
466
- path.join(creationDirectory, "./src/index.ts"),
467
- readFileSync(path.join(__dirname, "../templates/new-worker.ts"))
468
- );
469
-
470
- console.log(`✨ Created src/index.ts`);
471
-
472
- await writePackageJsonScriptsAndUpdateWranglerToml(
473
- shouldWritePackageJsonScripts,
474
- justCreatedWranglerToml,
475
- pathToPackageJson,
476
- "src/index.ts"
477
- );
478
- }
479
- }
480
- } else {
481
- if (!fs.existsSync("./src/index.js")) {
482
- const shouldCreateSource = await confirm(
483
- `Would you like to create a Worker at src/index.js?`
484
- );
485
- if (shouldCreateSource) {
486
- await mkdir(path.join(creationDirectory, "./src"), {
487
- recursive: true,
488
- });
489
- await writeFile(
490
- path.join(path.join(creationDirectory, "./src/index.js")),
491
- readFileSync(path.join(__dirname, "../templates/new-worker.js"))
492
- );
493
-
494
- console.log(`✨ Created src/index.js`);
495
-
496
- await writePackageJsonScriptsAndUpdateWranglerToml(
497
- shouldWritePackageJsonScripts,
498
- justCreatedWranglerToml,
499
- pathToPackageJson,
500
- "src/index.js"
501
- );
502
- }
503
- }
504
- }
505
- }
506
- );
507
-
508
- // build
509
- wrangler.command(
510
- "build",
511
- false,
512
- (yargs) => {
513
- return yargs.option("env", {
514
- describe: "Perform on a specific environment",
515
- });
516
- },
517
- () => {
518
- // "[DEPRECATED] 🦀 Build your project (if applicable)",
519
- throw new DeprecationError(
520
- "`wrangler build` has been deprecated, please refer to TODO://some/path for alternatives"
521
- );
522
- }
523
- );
524
-
525
- // login
526
- wrangler.command(
527
- // this needs scopes as an option?
528
- "login",
529
- false, // we don't need to show this in the menu
530
- // "🔓 Login to Cloudflare",
531
- (yargs) => {
532
- // TODO: This needs some copy editing
533
- // I mean, this entire app does, but this too.
534
- return yargs
535
- .option("scopes-list", {
536
- describe: "List all the available OAuth scopes with descriptions",
537
- })
538
- .option("scopes", {
539
- describe: "Pick the set of applicable OAuth scopes when logging in",
540
- array: true,
541
- type: "string",
542
- });
543
-
544
- // TODO: scopes
545
- },
546
- async (args) => {
547
- if (args["scopes-list"]) {
548
- listScopes();
549
- return;
550
- }
551
- if (args.scopes) {
552
- if (args.scopes.length === 0) {
553
- // don't allow no scopes to be passed, that would be weird
554
- listScopes();
555
- return;
556
- }
557
- if (!validateScopeKeys(args.scopes)) {
558
- throw new CommandLineArgsError(
559
- `One of ${args.scopes} is not a valid authentication scope. Run "wrangler login --list-scopes" to see the valid scopes.`
560
- );
561
- }
562
- await login({ scopes: args.scopes });
563
- return;
564
- }
565
- await login();
566
-
567
- // TODO: would be nice if it optionally saved login
568
- // credentials inside node_modules/.cache or something
569
- // this way you could have multiple users on a single machine
570
- }
571
- );
572
-
573
- // logout
574
- wrangler.command(
575
- // this needs scopes as an option?
576
- "logout",
577
- false, // we don't need to show this in the menu
578
- // "🚪 Logout from Cloudflare",
579
- () => {},
580
- async () => {
581
- await logout();
582
- }
583
- );
584
-
585
- // whoami
586
- wrangler.command(
587
- "whoami",
588
- "🕵️ Retrieve your user info and test your auth config",
589
- () => {},
590
- async () => {
591
- await whoami();
592
- }
593
- );
594
-
595
- // config
596
- wrangler.command(
597
- "config",
598
- false,
599
- () => {},
600
- () => {
601
- // "🕵️ Authenticate Wrangler with a Cloudflare API Token",
602
- throw new DeprecationError(
603
- "`wrangler config` has been deprecated, please refer to TODO://some/path for alternatives"
604
- );
605
- }
606
- );
607
-
608
- // dev
609
- wrangler.command(
610
- "dev [script]",
611
- "👂 Start a local server for developing your worker",
612
- (yargs) => {
613
- return yargs
614
- .positional("script", {
615
- describe: "The path to an entry point for your worker",
616
- type: "string",
617
- })
618
- .option("name", {
619
- describe: "Name of the worker",
620
- type: "string",
621
- })
622
- .option("format", {
623
- choices: ["modules", "service-worker"] as const,
624
- describe: "Choose an entry type",
625
- })
626
- .option("env", {
627
- describe: "Perform on a specific environment",
628
- type: "string",
629
- })
630
- .option("compatibility-date", {
631
- describe: "Date to use for compatibility checks",
632
- type: "string",
633
- })
634
- .option("compatibility-flags", {
635
- describe: "Flags to use for compatibility checks",
636
- type: "array",
637
- alias: "compatibility-flag",
638
- })
639
- .option("latest", {
640
- describe: "Use the latest version of the worker runtime",
641
- type: "boolean",
642
- default: true,
643
- })
644
- .option("ip", {
645
- describe: "IP address to listen on",
646
- type: "string",
647
- default: "127.0.0.1",
648
- })
649
- .option("port", {
650
- describe: "Port to listen on",
651
- type: "number",
652
- })
653
- .option("inspector-port", {
654
- describe: "Port for devtools to connect to",
655
- type: "number",
656
- })
657
- .option("host", {
658
- type: "string",
659
- describe:
660
- "Host to forward requests to, defaults to the zone of project",
661
- })
662
- .option("local-protocol", {
663
- default: "http",
664
- describe: "Protocol to listen to requests on, defaults to http.",
665
- choices: ["http", "https"],
666
- })
667
- .option("experimental-public", {
668
- describe: "Static assets to be served",
669
- type: "string",
670
- })
671
- .option("site", {
672
- describe: "Root folder of static assets for Workers Sites",
673
- type: "string",
674
- })
675
- .option("site-include", {
676
- describe:
677
- "Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.",
678
- type: "string",
679
- array: true,
680
- })
681
- .option("site-exclude", {
682
- describe:
683
- "Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.",
684
- type: "string",
685
- array: true,
686
- })
687
- .option("upstream-protocol", {
688
- default: "https",
689
- describe:
690
- "Protocol to forward requests to host on, defaults to https.",
691
- choices: ["http", "https"],
692
- })
693
- .option("jsx-factory", {
694
- describe: "The function that is called for each JSX element",
695
- type: "string",
696
- })
697
- .option("jsx-fragment", {
698
- describe: "The function that is called for each JSX fragment",
699
- type: "string",
700
- })
701
- .option("local", {
702
- alias: "l",
703
- describe: "Run on my machine",
704
- type: "boolean",
705
- default: false, // I bet this will a point of contention. We'll revisit it.
706
- })
707
- .option("experimental-enable-local-persistence", {
708
- describe: "Enable persistence for this session (only for local mode)",
709
- type: "boolean",
710
- });
711
- },
712
- async (args) => {
713
- const config = readConfig(
714
- (args.config as ConfigPath) ||
715
- (args.script && findWranglerToml(path.dirname(args.script)))
716
- );
717
- const entry = getEntry(config, "dev", args.script);
718
-
719
- if (args["experimental-public"]) {
720
- console.warn(
721
- "🚨 The --experimental-public field is experimental and will change in the future."
722
- );
723
- }
724
-
725
- if (args.public) {
726
- throw new Error(
727
- "🚨 The --public field has been renamed to --experimental-public, and will change behaviour in the future."
728
- );
729
- }
730
-
731
- if (config.site?.["entry-point"]) {
732
- console.warn(
733
- "Deprecation notice: The `site.entry-point` config field is no longer used.\n" +
734
- "The entry-point is specified via the command line (e.g. `wrangler dev path/to/script`).\n" +
735
- "Please remove the `site.entry-point` field from the `wrangler.toml` file."
736
- );
737
- }
738
-
739
- if (!args.local) {
740
- // -- snip, extract --
741
- const loggedIn = await loginOrRefreshIfRequired();
742
- if (!loggedIn) {
743
- // didn't login, let's just quit
744
- console.log("Did not login, quitting...");
745
- return;
746
- }
747
-
748
- if (!config.account_id) {
749
- config.account_id = await getAccountId();
750
- if (!config.account_id) {
751
- throw new Error("No account id found, quitting...");
752
- }
753
- }
754
- // -- snip, end --
755
- }
756
-
757
- const environments = config.env ?? {};
758
- const envRootObj = args.env ? environments[args.env] || {} : config;
759
-
760
- const { waitUntilExit } = render(
761
- <Dev
762
- name={getScriptName(args, config)}
763
- entry={entry}
764
- env={args.env}
765
- zone={undefined}
766
- rules={getRules(config)}
767
- legacyEnv={isLegacyEnv(args, config)}
768
- buildCommand={config.build || {}}
769
- format={args.format || config.build?.upload?.format}
770
- initialMode={args.local ? "local" : "remote"}
771
- jsxFactory={args["jsx-factory"] || envRootObj?.jsx_factory}
772
- jsxFragment={args["jsx-fragment"] || envRootObj?.jsx_fragment}
773
- enableLocalPersistence={
774
- args["experimental-enable-local-persistence"] || false
775
- }
776
- accountId={config.account_id}
777
- assetPaths={getAssetPaths(
778
- config,
779
- args.site,
780
- args.siteInclude,
781
- args.siteExclude
782
- )}
783
- port={
784
- args.port || config.dev?.port || (await getPort({ port: 8787 }))
785
- }
786
- inspectorPort={
787
- args["inspector-port"] ?? (await getPort({ port: 9229 }))
788
- }
789
- public={args["experimental-public"]}
790
- compatibilityDate={
791
- args["compatibility-date"] ||
792
- config.compatibility_date ||
793
- new Date().toISOString().substring(0, 10)
794
- }
795
- compatibilityFlags={
796
- (args["compatibility-flags"] as string[]) ||
797
- config.compatibility_flags
798
- }
799
- usageModel={envRootObj.usage_model}
800
- bindings={{
801
- kv_namespaces: envRootObj.kv_namespaces?.map(
802
- ({ binding, preview_id, id: _id }) => {
803
- // In `dev`, we make folks use a separate kv namespace called
804
- // `preview_id` instead of `id` so that they don't
805
- // break production data. So here we check that a `preview_id`
806
- // has actually been configured.
807
- // This whole block of code will be obsoleted in the future
808
- // when we have copy-on-write for previews on edge workers.
809
- if (!preview_id) {
810
- // TODO: This error has to be a _lot_ better, ideally just asking
811
- // to create a preview namespace for the user automatically
812
- throw new Error(
813
- `In development, you should use a separate kv namespace than the one you'd use in production. Please create a new kv namespace with "wrangler kv:namespace create <name> --preview" and add its id as preview_id to the kv_namespace "${binding}" in your wrangler.toml`
814
- ); // Ugh, I really don't like this message very much
815
- }
816
- return {
817
- binding,
818
- id: preview_id,
819
- };
820
- }
821
- ),
822
- vars: envRootObj.vars,
823
- wasm_modules: config.wasm_modules,
824
- text_blobs: config.text_blobs,
825
- durable_objects: envRootObj.durable_objects,
826
- r2_buckets: envRootObj.r2_buckets,
827
- unsafe: envRootObj.unsafe?.bindings,
828
- }}
829
- />
830
- );
831
- await waitUntilExit();
832
- }
833
- );
834
-
835
- // publish
836
- wrangler.command(
837
- "publish [script]",
838
- "🆙 Publish your Worker to Cloudflare.",
839
- (yargs) => {
840
- return yargs
841
- .option("env", {
842
- type: "string",
843
- describe: "Perform on a specific environment",
844
- })
845
- .positional("script", {
846
- describe: "The path to an entry point for your worker",
847
- type: "string",
848
- })
849
- .option("name", {
850
- describe: "Name of the worker",
851
- type: "string",
852
- })
853
- .option("format", {
854
- choices: ["modules", "service-worker"] as const,
855
- describe: "Choose an entry type",
856
- })
857
- .option("compatibility-date", {
858
- describe: "Date to use for compatibility checks",
859
- type: "string",
860
- })
861
- .option("compatibility-flags", {
862
- describe: "Flags to use for compatibility checks",
863
- type: "array",
864
- alias: "compatibility-flag",
865
- })
866
- .option("latest", {
867
- describe: "Use the latest version of the worker runtime",
868
- type: "boolean",
869
- default: false,
870
- })
871
- .option("experimental-public", {
872
- describe: "Static assets to be served",
873
- type: "string",
874
- })
875
- .option("site", {
876
- describe: "Root folder of static assets for Workers Sites",
877
- type: "string",
878
- })
879
- .option("site-include", {
880
- describe:
881
- "Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.",
882
- type: "string",
883
- array: true,
884
- })
885
- .option("site-exclude", {
886
- describe:
887
- "Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.",
888
- type: "string",
889
- array: true,
890
- })
891
- .option("triggers", {
892
- describe: "cron schedules to attach",
893
- alias: ["schedule", "schedules"],
894
- type: "array",
895
- })
896
- .option("routes", {
897
- describe: "Routes to upload",
898
- alias: "route",
899
- type: "array",
900
- })
901
- .option("jsx-factory", {
902
- describe: "The function that is called for each JSX element",
903
- type: "string",
904
- })
905
- .option("jsx-fragment", {
906
- describe: "The function that is called for each JSX fragment",
907
- type: "string",
908
- });
909
- },
910
- async (args) => {
911
- if (args["experimental-public"]) {
912
- console.warn(
913
- "🚨 The --experimental-public field is experimental and will change in the future."
914
- );
915
- }
916
- if (args.public) {
917
- throw new Error(
918
- "🚨 The --public field has been renamed to --experimental-public, and will change behaviour in the future."
919
- );
920
- }
921
-
922
- const config = readConfig(
923
- (args.config as ConfigPath) ||
924
- (args.script && findWranglerToml(path.dirname(args.script)))
925
- );
926
- const entry = getEntry(config, "publish", args.script);
927
-
928
- if (args.latest) {
929
- console.warn(
930
- "⚠️ Using the latest version of the Workers runtime. To silence this warning, please choose a specific version of the runtime with --compatibility-date, or add a compatibility_date to your wrangler.toml.\n"
931
- );
932
- }
933
-
934
- // -- snip, extract --
935
- const loggedIn = await loginOrRefreshIfRequired();
936
- if (!loggedIn) {
937
- // didn't login, let's just quit
938
- console.log("Did not login, quitting...");
939
- return;
940
- }
941
-
942
- if (!config.account_id) {
943
- config.account_id = await getAccountId();
944
- if (!config.account_id) {
945
- throw new Error("No account id found, quitting...");
946
- }
947
- }
948
- // -- snip, end --
949
-
950
- const assetPaths = getAssetPaths(
951
- config,
952
- args["experimental-public"] || args.site,
953
- args.siteInclude,
954
- args.siteExclude
955
- );
956
- await publish({
957
- config,
958
- name: getScriptName(args, config),
959
- rules: getRules(config),
960
- format: args.format || config.build?.upload?.format,
961
- entry,
962
- env: args.env,
963
- compatibilityDate: args.latest
964
- ? new Date().toISOString().substring(0, 10)
965
- : args["compatibility-date"],
966
- compatibilityFlags: args["compatibility-flags"] as string[],
967
- triggers: args.triggers,
968
- jsxFactory: args["jsx-factory"],
969
- jsxFragment: args["jsx-fragment"],
970
- routes: args.routes,
971
- assetPaths,
972
- legacyEnv: isLegacyEnv(args, config),
973
- experimentalPublic: args["experimental-public"] !== undefined,
974
- });
975
- }
976
- );
977
-
978
- // tail
979
- wrangler.command(
980
- "tail [name]",
981
- "🦚 Starts a log tailing session for a published Worker.",
982
- (yargs) => {
983
- return (
984
- yargs
985
- .positional("name", {
986
- describe: "Name of the worker",
987
- type: "string",
988
- })
989
- // TODO: auto-detect if this should be json or pretty based on atty
990
- .option("format", {
991
- default: "json",
992
- choices: ["json", "pretty"],
993
- describe: "The format of log entries",
994
- })
995
- .option("status", {
996
- choices: ["ok", "error", "canceled"],
997
- describe: "Filter by invocation status",
998
- array: true,
999
- })
1000
- .option("header", {
1001
- type: "string",
1002
- describe: "Filter by HTTP header",
1003
- })
1004
- .option("method", {
1005
- type: "string",
1006
- describe: "Filter by HTTP method",
1007
- array: true,
1008
- })
1009
- .option("sampling-rate", {
1010
- type: "number",
1011
- describe: "Adds a percentage of requests to log sampling rate",
1012
- })
1013
- .option("search", {
1014
- type: "string",
1015
- describe: "Filter by a text match in console.log messages",
1016
- })
1017
- .option("ip", {
1018
- type: "string",
1019
- describe:
1020
- 'Filter by the IP address the request originates from. Use "self" to filter for your own IP',
1021
- array: true,
1022
- })
1023
- .option("env", {
1024
- type: "string",
1025
- describe: "Perform on a specific environment",
1026
- })
1027
- .option("debug", {
1028
- type: "boolean",
1029
- hidden: true,
1030
- default: false,
1031
- describe:
1032
- "If a log would have been filtered out, send it through anyway alongside the filter which would have blocked it.",
1033
- })
1034
- );
1035
- },
1036
- async (args) => {
1037
- const config = readConfig(args.config as ConfigPath);
1038
-
1039
- const scriptName = getScriptName(args, config);
1040
-
1041
- if (!scriptName) {
1042
- throw new Error("Missing script name");
1043
- }
1044
-
1045
- // -- snip, extract --
1046
- const loggedIn = await loginOrRefreshIfRequired();
1047
- if (!loggedIn) {
1048
- // didn't login, let's just quit
1049
- console.log("Did not login, quitting...");
1050
- return;
1051
- }
1052
-
1053
- if (!config.account_id) {
1054
- config.account_id = await getAccountId();
1055
- if (!config.account_id) {
1056
- throw new Error("No account id found, quitting...");
1057
- }
1058
- }
1059
- // -- snip, end --
1060
-
1061
- const accountId = config.account_id;
1062
-
1063
- const cliFilters: TailCLIFilters = {
1064
- status: args.status as ("ok" | "error" | "canceled")[],
1065
- header: args.header,
1066
- method: args.method,
1067
- samplingRate: args["sampling-rate"],
1068
- search: args.search,
1069
- clientIp: args.ip,
1070
- };
1071
-
1072
- const filters = translateCLICommandToFilterMessage(
1073
- cliFilters,
1074
- args.debug
1075
- );
1076
-
1077
- const { tail, expiration, deleteTail } = await createTail(
1078
- accountId,
1079
- scriptName,
1080
- filters,
1081
- !isLegacyEnv(args, config) ? args.env : undefined
1082
- );
1083
-
1084
- const scriptDisplayName = `${scriptName}${
1085
- args.env && !isLegacyEnv(args, config) ? ` (${args.env})` : ""
1086
- }`;
1087
-
1088
- console.log(
1089
- `successfully created tail, expires at ${expiration.toLocaleString()}`
1090
- );
1091
-
1092
- onExit(async () => {
1093
- tail.terminate();
1094
- await deleteTail();
1095
- });
1096
-
1097
- const printLog: (data: RawData) => void =
1098
- args.format === "pretty" ? prettyPrintLogs : jsonPrintLogs;
1099
-
1100
- tail.on("message", printLog);
1101
-
1102
- while (tail.readyState !== tail.OPEN) {
1103
- switch (tail.readyState) {
1104
- case tail.CONNECTING:
1105
- await setTimeout(100);
1106
- break;
1107
- case tail.CLOSING:
1108
- await setTimeout(100);
1109
- break;
1110
- case tail.CLOSED:
1111
- throw new Error(
1112
- `Connection to ${scriptDisplayName} closed unexpectedly.`
1113
- );
1114
- }
1115
- }
1116
-
1117
- console.log(`Connected to ${scriptDisplayName}, waiting for logs...`);
1118
-
1119
- tail.on("close", async () => {
1120
- tail.terminate();
1121
- await deleteTail();
1122
- });
1123
- }
1124
- );
1125
-
1126
- // preview
1127
- wrangler.command(
1128
- "preview [method] [body]",
1129
- false,
1130
- (yargs) => {
1131
- return yargs
1132
- .positional("method", {
1133
- type: "string",
1134
- describe: "Type of request to preview your worker",
1135
- })
1136
- .positional("body", {
1137
- type: "string",
1138
- describe: "Body string to post to your preview worker request.",
1139
- })
1140
- .option("env", {
1141
- type: "string",
1142
- describe: "Perform on a specific environment",
1143
- })
1144
- .option("watch", {
1145
- default: true,
1146
- describe: "Enable live preview",
1147
- type: "boolean",
1148
- });
1149
- },
1150
- async (args) => {
1151
- if (args.method || args.body) {
1152
- throw new DeprecationError(
1153
- "The `wrangler preview` command has been deprecated.\n" +
1154
- "Try using `wrangler dev` to to try out a worker during development.\n"
1155
- );
1156
- }
1157
-
1158
- // Delegate to `wrangler dev`
1159
- console.warn(
1160
- "***************************************************\n" +
1161
- "The `wrangler preview` command has been deprecated.\n" +
1162
- "Attempting to run `wrangler dev` instead.\n" +
1163
- "***************************************************\n"
1164
- );
1165
-
1166
- const config = readConfig(args.config as ConfigPath);
1167
- const entry = getEntry(config, "dev");
1168
-
1169
- // -- snip, extract --
1170
- const loggedIn = await loginOrRefreshIfRequired();
1171
- if (!loggedIn) {
1172
- // didn't login, let's just quit
1173
- console.log("Did not login, quitting...");
1174
- return;
1175
- }
1176
-
1177
- if (!config.account_id) {
1178
- config.account_id = await getAccountId();
1179
- if (!config.account_id) {
1180
- throw new Error("No account id found, quitting...");
1181
- }
1182
- }
1183
- // -- snip, end --
1184
-
1185
- const environments = config.env ?? {};
1186
- const envRootObj = args.env ? environments[args.env] || {} : config;
1187
-
1188
- const { waitUntilExit } = render(
1189
- <Dev
1190
- name={config.name}
1191
- entry={entry}
1192
- rules={getRules(config)}
1193
- env={args.env}
1194
- zone={undefined}
1195
- legacyEnv={isLegacyEnv(args, config)}
1196
- buildCommand={config.build || {}}
1197
- format={config.build?.upload?.format}
1198
- initialMode={args.local ? "local" : "remote"}
1199
- jsxFactory={envRootObj?.jsx_factory}
1200
- jsxFragment={envRootObj?.jsx_fragment}
1201
- enableLocalPersistence={false}
1202
- accountId={config.account_id}
1203
- assetPaths={undefined}
1204
- port={config.dev?.port}
1205
- public={undefined}
1206
- compatibilityDate={
1207
- config.compatibility_date ||
1208
- new Date().toISOString().substring(0, 10)
1209
- }
1210
- compatibilityFlags={
1211
- (args["compatibility-flags"] as string[]) ||
1212
- config.compatibility_flags
1213
- }
1214
- usageModel={config.usage_model}
1215
- bindings={{
1216
- kv_namespaces: envRootObj.kv_namespaces?.map(
1217
- ({ binding, preview_id, id: _id }) => {
1218
- // In `dev`, we make folks use a separate kv namespace called
1219
- // `preview_id` instead of `id` so that they don't
1220
- // break production data. So here we check that a `preview_id`
1221
- // has actually been configured.
1222
- // This whole block of code will be obsoleted in the future
1223
- // when we have copy-on-write for previews on edge workers.
1224
- if (!preview_id) {
1225
- // TODO: This error has to be a _lot_ better, ideally just asking
1226
- // to create a preview namespace for the user automatically
1227
- throw new Error(
1228
- `In development, you should use a separate kv namespace than the one you'd use in production. Please create a new kv namespace with "wrangler kv:namespace create <name> --preview" and add its id as preview_id to the kv_namespace "${binding}" in your wrangler.toml`
1229
- ); // Ugh, I really don't like this message very much
1230
- }
1231
- return {
1232
- binding,
1233
- id: preview_id,
1234
- };
1235
- }
1236
- ),
1237
- vars: envRootObj.vars,
1238
- wasm_modules: config.wasm_modules,
1239
- text_blobs: config.text_blobs,
1240
- durable_objects: envRootObj.durable_objects,
1241
- r2_buckets: envRootObj.r2_buckets,
1242
- unsafe: envRootObj.unsafe?.bindings,
1243
- }}
1244
- inspectorPort={await getPort({ port: 9229 })}
1245
- />
1246
- );
1247
- await waitUntilExit();
1248
- }
1249
- );
1250
-
1251
- // route
1252
- wrangler.command(
1253
- "route",
1254
- false, // I think we want to hide this command
1255
- // "➡️ List or delete worker routes",
1256
- (routeYargs) => {
1257
- return routeYargs
1258
- .command(
1259
- "list",
1260
- "List the routes associated with a zone",
1261
- (yargs) => {
1262
- return yargs
1263
- .option("env", {
1264
- type: "string",
1265
- describe: "Perform on a specific environment",
1266
- })
1267
- .option("zone", {
1268
- type: "string",
1269
- describe: "Zone id",
1270
- })
1271
- .positional("zone", {
1272
- describe: "Zone id",
1273
- type: "string",
1274
- });
1275
- },
1276
- async (args) => {
1277
- console.log(":route list", args);
1278
- // TODO: use environment (current wrangler doesn't do so?)
1279
- // TODO: don't get `zone_id` from config at all and require the command line arg `--zone`.
1280
- const config = readConfig(args.config as ConfigPath);
1281
- const zone = args.zone || config.zone_id;
1282
- if (!zone) {
1283
- throw new Error("missing zone id");
1284
- }
1285
-
1286
- console.log(await fetchResult(`/zones/${zone}/workers/routes`));
1287
- }
1288
- )
1289
- .command(
1290
- "delete <id>",
1291
- "Delete a route associated with a zone",
1292
- (yargs) => {
1293
- return yargs
1294
- .positional("id", {
1295
- describe: "The hash of the route ID to delete.",
1296
- type: "string",
1297
- })
1298
- .option("zone", {
1299
- type: "string",
1300
- describe: "zone id",
1301
- })
1302
- .option("env", {
1303
- type: "string",
1304
- describe: "Perform on a specific environment",
1305
- });
1306
- },
1307
- async (args) => {
1308
- console.log(":route delete", args);
1309
- // TODO: use environment (current wrangler doesn't do so?)
1310
- const config = readConfig(args.config as ConfigPath);
1311
- const zone = args.zone || config.zone_id;
1312
- if (!zone) {
1313
- throw new Error("missing zone id");
1314
- }
1315
-
1316
- console.log(
1317
- await fetchResult(`/zones/${zone}/workers/routes/${args.id}`, {
1318
- method: "DELETE",
1319
- })
1320
- );
1321
- }
1322
- );
1323
- }
1324
- );
1325
-
1326
- // subdomain
1327
- wrangler.command(
1328
- "subdomain [name]",
1329
- false,
1330
- // "👷 Create or change your workers.dev subdomain.",
1331
- (yargs) => {
1332
- return yargs.positional("name", { type: "string" });
1333
- },
1334
- () => {
1335
- throw new DeprecationError(
1336
- "`wrangler subdomain` has been deprecated, please refer to TODO://some/path for alternatives"
1337
- );
1338
- }
1339
- );
1340
-
1341
- // secret
1342
- wrangler.command(
1343
- "secret",
1344
- "🤫 Generate a secret that can be referenced in the worker script",
1345
- (secretYargs) => {
1346
- return secretYargs
1347
- .command(
1348
- "put <key>",
1349
- "Create or update a secret variable for a script",
1350
- (yargs) => {
1351
- return yargs
1352
- .positional("key", {
1353
- describe: "The variable name to be accessible in the script",
1354
- type: "string",
1355
- })
1356
- .option("name", {
1357
- describe: "Name of the worker",
1358
- type: "string",
1359
- })
1360
- .option("env", {
1361
- type: "string",
1362
- describe:
1363
- "Binds the secret to the Worker of the specific environment",
1364
- });
1365
- },
1366
- async (args) => {
1367
- const config = readConfig(args.config as ConfigPath);
1368
-
1369
- const scriptName = getScriptName(args, config);
1370
- if (!scriptName) {
1371
- throw new Error("Missing script name");
1372
- }
1373
-
1374
- // -- snip, extract --
1375
- const loggedIn = await loginOrRefreshIfRequired();
1376
- if (!loggedIn) {
1377
- // didn't login, let's just quit
1378
- console.log("Did not login, quitting...");
1379
- return;
1380
- }
1381
-
1382
- if (!config.account_id) {
1383
- config.account_id = await getAccountId();
1384
- if (!config.account_id) {
1385
- throw new Error("No account id found, quitting...");
1386
- }
1387
- }
1388
- // -- snip, end --
1389
-
1390
- const secretValue = await prompt(
1391
- "Enter a secret value:",
1392
- "password"
1393
- );
1394
-
1395
- console.log(
1396
- `🌀 Creating the secret for script ${scriptName} ${
1397
- args.env && !isLegacyEnv(args, config) ? `(${args.env})` : ""
1398
- }`
1399
- );
1400
-
1401
- async function submitSecret() {
1402
- const url =
1403
- !args.env || isLegacyEnv(args, config)
1404
- ? `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
1405
- : `/accounts/${config.account_id}/workers/services/${scriptName}/environments/${args.env}/secrets`;
1406
-
1407
- return await fetchResult(url, {
1408
- method: "PUT",
1409
- headers: { "Content-Type": "application/json" },
1410
- body: JSON.stringify({
1411
- name: args.key,
1412
- text: secretValue,
1413
- type: "secret_text",
1414
- }),
1415
- });
1416
- }
1417
-
1418
- try {
1419
- await submitSecret();
1420
- } catch (e) {
1421
- // @ts-expect-error non-standard property on Error
1422
- if (e.code === 10007) {
1423
- // upload a draft worker
1424
- // TODO: log a warning
1425
- await fetchResult(
1426
- !args["legacy-env"] && args.env
1427
- ? `/accounts/${config.account_id}/workers/services/${scriptName}/environments/${args.env}`
1428
- : `/accounts/${config.account_id}/workers/scripts/${scriptName}`,
1429
- {
1430
- method: "PUT",
1431
- body: toFormData({
1432
- name: scriptName,
1433
- main: {
1434
- name: scriptName,
1435
- content: `export default { fetch() {} }`,
1436
- type: "esm",
1437
- },
1438
- bindings: {
1439
- kv_namespaces: [],
1440
- vars: {},
1441
- durable_objects: { bindings: [] },
1442
- r2_buckets: [],
1443
- wasm_modules: {},
1444
- text_blobs: {},
1445
- unsafe: [],
1446
- },
1447
- modules: [],
1448
- migrations: undefined,
1449
- compatibility_date: undefined,
1450
- compatibility_flags: undefined,
1451
- usage_model: undefined,
1452
- }),
1453
- }
1454
- );
1455
-
1456
- // and then try again
1457
- await submitSecret();
1458
- // TODO: delete the draft worker if this failed too?
1459
- }
1460
- }
1461
- console.log(`✨ Success! Uploaded secret ${args.key}`);
1462
- }
1463
- )
1464
- .command(
1465
- "delete <key>",
1466
- "Delete a secret variable from a script",
1467
- (yargs) => {
1468
- return yargs
1469
- .positional("key", {
1470
- describe: "The variable name to be accessible in the script",
1471
- type: "string",
1472
- })
1473
- .option("name", {
1474
- describe: "Name of the worker",
1475
- type: "string",
1476
- })
1477
- .option("env", {
1478
- type: "string",
1479
- describe:
1480
- "Binds the secret to the Worker of the specific environment",
1481
- });
1482
- },
1483
- async (args) => {
1484
- const config = readConfig(args.config as ConfigPath);
1485
-
1486
- const scriptName = getScriptName(args, config);
1487
- if (!scriptName) {
1488
- throw new Error("Missing script name");
1489
- }
1490
-
1491
- // -- snip, extract --
1492
- const loggedIn = await loginOrRefreshIfRequired();
1493
- if (!loggedIn) {
1494
- // didn't login, let's just quit
1495
- console.log("Did not login, quitting...");
1496
- return;
1497
- }
1498
-
1499
- if (!config.account_id) {
1500
- config.account_id = await getAccountId();
1501
- if (!config.account_id) {
1502
- throw new Error("No account id found, quitting...");
1503
- }
1504
- }
1505
- // -- snip, end --
1506
-
1507
- if (
1508
- await confirm(
1509
- `Are you sure you want to permanently delete the variable ${
1510
- args.key
1511
- } on the script ${scriptName}${
1512
- args.env && !isLegacyEnv(args, config) ? ` (${args.env})` : ""
1513
- }?`
1514
- )
1515
- ) {
1516
- console.log(
1517
- `🌀 Deleting the secret ${args.key} on script ${scriptName}${
1518
- args.env && !isLegacyEnv(args, config) ? ` (${args.env})` : ""
1519
- }`
1520
- );
1521
-
1522
- const url =
1523
- !args.env || isLegacyEnv(args, config)
1524
- ? `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
1525
- : `/accounts/${config.account_id}/workers/services/${scriptName}/environments/${args.env}/secrets`;
1526
-
1527
- await fetchResult(`${url}/${args.key}`, { method: "DELETE" });
1528
- console.log(`✨ Success! Deleted secret ${args.key}`);
1529
- }
1530
- }
1531
- )
1532
- .command(
1533
- "list",
1534
- "List all secrets for a script",
1535
- (yargs) => {
1536
- return yargs
1537
- .option("name", {
1538
- describe: "Name of the worker",
1539
- type: "string",
1540
- })
1541
- .option("env", {
1542
- type: "string",
1543
- describe:
1544
- "Binds the secret to the Worker of the specific environment.",
1545
- });
1546
- },
1547
- async (args) => {
1548
- const config = readConfig(args.config as ConfigPath);
1549
-
1550
- const scriptName = getScriptName(args, config);
1551
- if (!scriptName) {
1552
- throw new Error("Missing script name");
1553
- }
1554
-
1555
- // -- snip, extract --
1556
- const loggedIn = await loginOrRefreshIfRequired();
1557
- if (!loggedIn) {
1558
- // didn't login, let's just quit
1559
- console.log("Did not login, quitting...");
1560
- return;
1561
- }
1562
-
1563
- if (!config.account_id) {
1564
- config.account_id = await getAccountId();
1565
- if (!config.account_id) {
1566
- throw new Error("No account id found, quitting...");
1567
- }
1568
- }
1569
- // -- snip, end --
1570
-
1571
- const url =
1572
- !args.env || isLegacyEnv(args, config)
1573
- ? `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
1574
- : `/accounts/${config.account_id}/workers/services/${scriptName}/environments/${args.env}/secrets`;
1575
-
1576
- console.log(JSON.stringify(await fetchResult(url), null, " "));
1577
- }
1578
- );
1579
- }
1580
- );
1581
-
1582
- // kv
1583
- // :namespace
1584
- wrangler.command(
1585
- "kv:namespace",
1586
- "🗂️ Interact with your Workers KV Namespaces",
1587
- (namespaceYargs) => {
1588
- return namespaceYargs
1589
- .command(
1590
- "create <namespace>",
1591
- "Create a new namespace",
1592
- (yargs) => {
1593
- return yargs
1594
- .positional("namespace", {
1595
- describe: "The name of the new namespace",
1596
- type: "string",
1597
- demandOption: true,
1598
- })
1599
- .option("env", {
1600
- type: "string",
1601
- describe: "Perform on a specific environment",
1602
- })
1603
- .option("preview", {
1604
- type: "boolean",
1605
- describe: "Interact with a preview namespace",
1606
- });
1607
- },
1608
- async (args) => {
1609
- if (args._.length > 2) {
1610
- const extraArgs = args._.slice(2).join(" ");
1611
- throw new CommandLineArgsError(
1612
- `Unexpected additional positional arguments "${extraArgs}".`
1613
- );
1614
- }
1615
-
1616
- if (!isValidNamespaceBinding(args.namespace)) {
1617
- throw new CommandLineArgsError(
1618
- `The namespace binding name "${args.namespace}" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number.`
1619
- );
1620
- }
1621
-
1622
- const config = readConfig(args.config as ConfigPath);
1623
- if (!config.name) {
1624
- console.warn(
1625
- "No configured name present, using `worker` as a prefix for the title"
1626
- );
1627
- }
1628
-
1629
- const name = config.name || "worker";
1630
- const environment = args.env ? `-${args.env}` : "";
1631
- const preview = args.preview ? "_preview" : "";
1632
- const title = `${name}${environment}-${args.namespace}${preview}`;
1633
-
1634
- // -- snip, extract --
1635
- const loggedIn = await loginOrRefreshIfRequired();
1636
- if (!loggedIn) {
1637
- // didn't login, let's just quit
1638
- console.log("Did not login, quitting...");
1639
- return;
1640
- }
1641
-
1642
- if (!config.account_id) {
1643
- config.account_id = await getAccountId();
1644
- if (!config.account_id) {
1645
- throw new Error("No account id found, quitting...");
1646
- }
1647
- }
1648
- // -- snip, end --
1649
-
1650
- // TODO: generate a binding name stripping non alphanumeric chars
1651
-
1652
- console.log(`🌀 Creating namespace with title "${title}"`);
1653
- const namespaceId = await createNamespace(config.account_id, title);
1654
-
1655
- console.log("✨ Success!");
1656
- const envString = args.env ? ` under [env.${args.env}]` : "";
1657
- const previewString = args.preview ? "preview_" : "";
1658
- console.log(
1659
- `Add the following to your configuration file in your kv_namespaces array${envString}:`
1660
- );
1661
- console.log(
1662
- `{ binding = "${args.namespace}", ${previewString}id = "${namespaceId}" }`
1663
- );
1664
-
1665
- // TODO: automatically write this block to the wrangler.toml config file??
1666
- }
1667
- )
1668
- .command(
1669
- "list",
1670
- "Outputs a list of all KV namespaces associated with your account id.",
1671
- {},
1672
- async (args) => {
1673
- const config = readConfig(args.config as ConfigPath);
1674
-
1675
- // -- snip, extract --
1676
- const loggedIn = await loginOrRefreshIfRequired();
1677
- if (!loggedIn) {
1678
- // didn't login, let's just quit
1679
- console.log("Did not login, quitting...");
1680
- return;
1681
- }
1682
-
1683
- if (!config.account_id) {
1684
- config.account_id = await getAccountId();
1685
- if (!config.account_id) {
1686
- throw new Error("No account id found, quitting...");
1687
- }
1688
- }
1689
- // -- snip, end --
1690
-
1691
- // TODO: we should show bindings if they exist for given ids
1692
-
1693
- console.log(
1694
- JSON.stringify(
1695
- await listNamespaces(config.account_id),
1696
- null,
1697
- " "
1698
- )
1699
- );
1700
- }
1701
- )
1702
- .command(
1703
- "delete",
1704
- "Deletes a given namespace.",
1705
- (yargs) => {
1706
- return yargs
1707
- .option("binding", {
1708
- type: "string",
1709
- describe: "The name of the namespace to delete",
1710
- })
1711
- .option("namespace-id", {
1712
- type: "string",
1713
- describe: "The id of the namespace to delete",
1714
- })
1715
- .check(demandOneOfOption("binding", "namespace-id"))
1716
- .option("env", {
1717
- type: "string",
1718
- describe: "Perform on a specific environment",
1719
- })
1720
- .option("preview", {
1721
- type: "boolean",
1722
- describe: "Interact with a preview namespace",
1723
- });
1724
- },
1725
- async (args) => {
1726
- const config = readConfig(args.config as ConfigPath);
1727
-
1728
- let id;
1729
- try {
1730
- id = getNamespaceId(args, config);
1731
- } catch (e) {
1732
- throw new CommandLineArgsError(
1733
- "Not able to delete namespace.\n" + ((e as Error).message ?? e)
1734
- );
1735
- }
1736
-
1737
- // -- snip, extract --
1738
- const loggedIn = await loginOrRefreshIfRequired();
1739
- if (!loggedIn) {
1740
- // didn't login, let's just quit
1741
- console.log("Did not login, quitting...");
1742
- return;
1743
- }
1744
-
1745
- if (!config.account_id) {
1746
- config.account_id = await getAccountId();
1747
- if (!config.account_id) {
1748
- throw new Error("No account id found, quitting...");
1749
- }
1750
- }
1751
- // -- snip, end --
1752
-
1753
- await fetchResult<{ id: string }>(
1754
- `/accounts/${config.account_id}/storage/kv/namespaces/${id}`,
1755
- { method: "DELETE" }
1756
- );
1757
-
1758
- // TODO: recommend they remove it from wrangler.toml
1759
-
1760
- // test-mf wrangler kv:namespace delete --namespace-id 2a7d3d8b23fc4159b5afa489d6cfd388
1761
- // Are you sure you want to delete namespace 2a7d3d8b23fc4159b5afa489d6cfd388? [y/n]
1762
- // n
1763
- // 💁 Not deleting namespace 2a7d3d8b23fc4159b5afa489d6cfd388
1764
- // ➜ test-mf wrangler kv:namespace delete --namespace-id 2a7d3d8b23fc4159b5afa489d6cfd388
1765
- // Are you sure you want to delete namespace 2a7d3d8b23fc4159b5afa489d6cfd388? [y/n]
1766
- // y
1767
- // 🌀 Deleting namespace 2a7d3d8b23fc4159b5afa489d6cfd388
1768
- // ✨ Success
1769
- // ⚠️ Make sure to remove this "kv-namespace" entry from your configuration file!
1770
- // ➜ test-mf
1771
-
1772
- // TODO: do it automatically
1773
-
1774
- // TODO: delete the preview namespace as well?
1775
- }
1776
- );
1777
- }
1778
- );
1779
-
1780
- // :key
1781
- wrangler.command(
1782
- "kv:key",
1783
- "🔑 Individually manage Workers KV key-value pairs",
1784
- (kvKeyYargs) => {
1785
- return kvKeyYargs
1786
- .command(
1787
- "put <key> [value]",
1788
- "Writes a single key/value pair to the given namespace.",
1789
- (yargs) => {
1790
- return yargs
1791
- .positional("key", {
1792
- type: "string",
1793
- describe: "The key to write to",
1794
- demandOption: true,
1795
- })
1796
- .positional("value", {
1797
- type: "string",
1798
- describe: "The value to write",
1799
- })
1800
- .option("binding", {
1801
- type: "string",
1802
- describe: "The binding of the namespace to write to",
1803
- })
1804
- .option("namespace-id", {
1805
- type: "string",
1806
- describe: "The id of the namespace to write to",
1807
- })
1808
- .check(demandOneOfOption("binding", "namespace-id"))
1809
- .option("env", {
1810
- type: "string",
1811
- describe: "Perform on a specific environment",
1812
- })
1813
- .option("preview", {
1814
- type: "boolean",
1815
- describe: "Interact with a preview namespace",
1816
- })
1817
- .option("ttl", {
1818
- type: "number",
1819
- describe: "Time for which the entries should be visible",
1820
- })
1821
- .option("expiration", {
1822
- type: "number",
1823
- describe:
1824
- "Time since the UNIX epoch after which the entry expires",
1825
- })
1826
- .option("path", {
1827
- type: "string",
1828
- describe: "Read value from the file at a given path",
1829
- })
1830
- .check(demandOneOfOption("value", "path"));
1831
- },
1832
- async ({ key, ttl, expiration, ...args }) => {
1833
- const config = readConfig(args.config as ConfigPath);
1834
- const namespaceId = getNamespaceId(args, config);
1835
- // One of `args.path` and `args.value` must be defined
1836
- const value = args.path
1837
- ? readFileSync(args.path)
1838
- : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1839
- args.value!;
1840
-
1841
- if (args.path) {
1842
- console.log(
1843
- `writing the contents of ${args.path} to the key "${key}" on namespace ${namespaceId}`
1844
- );
1845
- } else {
1846
- console.log(
1847
- `writing the value "${value}" to key "${key}" on namespace ${namespaceId}`
1848
- );
1849
- }
1850
-
1851
- // -- snip, extract --
1852
- const loggedIn = await loginOrRefreshIfRequired();
1853
- if (!loggedIn) {
1854
- // didn't login, let's just quit
1855
- console.log("Did not login, quitting...");
1856
- return;
1857
- }
1858
-
1859
- if (!config.account_id) {
1860
- config.account_id = await getAccountId();
1861
- if (!config.account_id) {
1862
- throw new Error("No account id found, quitting...");
1863
- }
1864
- }
1865
- // -- snip, end --
1866
-
1867
- await putKeyValue(config.account_id, namespaceId, key, value, {
1868
- expiration,
1869
- expiration_ttl: ttl,
1870
- });
1871
- }
1872
- )
1873
- .command(
1874
- "list",
1875
- "Outputs a list of all keys in a given namespace.",
1876
- (yargs) => {
1877
- return yargs
1878
- .option("binding", {
1879
- type: "string",
1880
- describe: "The name of the namespace to list",
1881
- })
1882
- .option("namespace-id", {
1883
- type: "string",
1884
- describe: "The id of the namespace to list",
1885
- })
1886
- .check(demandOneOfOption("binding", "namespace-id"))
1887
- .option("env", {
1888
- type: "string",
1889
- describe: "Perform on a specific environment",
1890
- })
1891
- .option("preview", {
1892
- type: "boolean",
1893
- // In the case of listing keys we will default to non-preview mode
1894
- default: false,
1895
- describe: "Interact with a preview namespace",
1896
- })
1897
- .option("prefix", {
1898
- type: "string",
1899
- describe: "A prefix to filter listed keys",
1900
- });
1901
- },
1902
- async ({ prefix, ...args }) => {
1903
- // TODO: support for limit+cursor (pagination)
1904
- const config = readConfig(args.config as ConfigPath);
1905
- const namespaceId = getNamespaceId(args, config);
1906
-
1907
- // -- snip, extract --
1908
- const loggedIn = await loginOrRefreshIfRequired();
1909
- if (!loggedIn) {
1910
- // didn't login, let's just quit
1911
- console.log("Did not login, quitting...");
1912
- return;
1913
- }
1914
-
1915
- if (!config.account_id) {
1916
- config.account_id = await getAccountId();
1917
- if (!config.account_id) {
1918
- throw new Error("No account id found, quitting...");
1919
- }
1920
- }
1921
- // -- snip, end --
1922
-
1923
- const results = await listNamespaceKeys(
1924
- config.account_id,
1925
- namespaceId,
1926
- prefix
1927
- );
1928
- console.log(JSON.stringify(results, undefined, 2));
1929
- }
1930
- )
1931
- .command(
1932
- "get <key>",
1933
- "Reads a single value by key from the given namespace.",
1934
- (yargs) => {
1935
- return yargs
1936
- .positional("key", {
1937
- describe: "The key value to get.",
1938
- type: "string",
1939
- demandOption: true,
1940
- })
1941
- .option("binding", {
1942
- type: "string",
1943
- describe: "The name of the namespace to get from",
1944
- })
1945
- .option("namespace-id", {
1946
- type: "string",
1947
- describe: "The id of the namespace to get from",
1948
- })
1949
- .check(demandOneOfOption("binding", "namespace-id"))
1950
- .option("env", {
1951
- type: "string",
1952
- describe: "Perform on a specific environment",
1953
- })
1954
- .option("preview", {
1955
- type: "boolean",
1956
- describe: "Interact with a preview namespace",
1957
- })
1958
- .option("preview", {
1959
- type: "boolean",
1960
- // In the case of getting key values we will default to non-preview mode
1961
- default: false,
1962
- describe: "Interact with a preview namespace",
1963
- });
1964
- },
1965
- async ({ key, ...args }) => {
1966
- const config = readConfig(args.config as ConfigPath);
1967
- const namespaceId = getNamespaceId(args, config);
1968
-
1969
- // -- snip, extract --
1970
- const loggedIn = await loginOrRefreshIfRequired();
1971
- if (!loggedIn) {
1972
- // didn't login, let's just quit
1973
- console.log("Did not login, quitting...");
1974
- return;
1975
- }
1976
-
1977
- if (!config.account_id) {
1978
- config.account_id = await getAccountId();
1979
- if (!config.account_id) {
1980
- throw new Error("No account id found, quitting...");
1981
- }
1982
- }
1983
- // -- snip, end --
1984
-
1985
- console.log(await getKeyValue(config.account_id, namespaceId, key));
1986
- }
1987
- )
1988
- .command(
1989
- "delete <key>",
1990
- "Removes a single key value pair from the given namespace.",
1991
- (yargs) => {
1992
- return yargs
1993
- .positional("key", {
1994
- describe: "The key value to delete",
1995
- type: "string",
1996
- demandOption: true,
1997
- })
1998
- .option("binding", {
1999
- type: "string",
2000
- describe: "The name of the namespace to delete from",
2001
- })
2002
- .option("namespace-id", {
2003
- type: "string",
2004
- describe: "The id of the namespace to delete from",
2005
- })
2006
- .check(demandOneOfOption("binding", "namespace-id"))
2007
- .option("env", {
2008
- type: "string",
2009
- describe: "Perform on a specific environment",
2010
- })
2011
- .option("preview", {
2012
- type: "boolean",
2013
- describe: "Interact with a preview namespace",
2014
- });
2015
- },
2016
- async ({ key, ...args }) => {
2017
- const config = readConfig(args.config as ConfigPath);
2018
- const namespaceId = getNamespaceId(args, config);
2019
-
2020
- console.log(
2021
- `deleting the key "${key}" on namespace ${namespaceId}`
2022
- );
2023
-
2024
- // -- snip, extract --
2025
- const loggedIn = await loginOrRefreshIfRequired();
2026
- if (!loggedIn) {
2027
- // didn't login, let's just quit
2028
- console.log("Did not login, quitting...");
2029
- return;
2030
- }
2031
-
2032
- if (!config.account_id) {
2033
- config.account_id = await getAccountId();
2034
- if (!config.account_id) {
2035
- throw new Error("No account id found, quitting...");
2036
- }
2037
- }
2038
- // -- snip, end --
2039
-
2040
- await fetchResult(
2041
- `/accounts/${config.account_id}/storage/kv/namespaces/${namespaceId}/values/${key}`,
2042
- { method: "DELETE" }
2043
- );
2044
- }
2045
- );
2046
- }
2047
- );
2048
-
2049
- // :bulk
2050
- wrangler.command(
2051
- "kv:bulk",
2052
- "💪 Interact with multiple Workers KV key-value pairs at once",
2053
- (kvBulkYargs) => {
2054
- return kvBulkYargs
2055
- .command(
2056
- "put <filename>",
2057
- "Upload multiple key-value pairs to a namespace",
2058
- (yargs) => {
2059
- return yargs
2060
- .positional("filename", {
2061
- describe: `The JSON file of key-value pairs to upload, in form [{"key":..., "value":...}"...]`,
2062
- type: "string",
2063
- demandOption: true,
2064
- })
2065
- .option("binding", {
2066
- type: "string",
2067
- describe: "The name of the namespace to insert values into",
2068
- })
2069
- .option("namespace-id", {
2070
- type: "string",
2071
- describe: "The id of the namespace to insert values into",
2072
- })
2073
- .check(demandOneOfOption("binding", "namespace-id"))
2074
- .option("env", {
2075
- type: "string",
2076
- describe: "Perform on a specific environment",
2077
- })
2078
- .option("preview", {
2079
- type: "boolean",
2080
- describe: "Interact with a preview namespace",
2081
- });
2082
- },
2083
- async ({ filename, ...args }) => {
2084
- // The simplest implementation I could think of.
2085
- // This could be made more efficient with a streaming parser/uploader
2086
- // but we'll do that in the future if needed.
2087
-
2088
- const config = readConfig(args.config as ConfigPath);
2089
- const namespaceId = getNamespaceId(args, config);
2090
- const content = parseJSON(readFileSync(filename), filename);
2091
-
2092
- // -- snip, extract --
2093
- const loggedIn = await loginOrRefreshIfRequired();
2094
- if (!loggedIn) {
2095
- // didn't login, let's just quit
2096
- console.log("Did not login, quitting...");
2097
- return;
2098
- }
2099
-
2100
- if (!config.account_id) {
2101
- config.account_id = await getAccountId();
2102
- if (!config.account_id) {
2103
- throw new Error("No account id found, quitting...");
2104
- }
2105
- }
2106
- // -- snip, end --
2107
-
2108
- console.log(
2109
- await putBulkKeyValue(config.account_id, namespaceId, content)
2110
- );
2111
- }
2112
- )
2113
- .command(
2114
- "delete <filename>",
2115
- "Delete multiple key-value pairs from a namespace",
2116
- (yargs) => {
2117
- return yargs
2118
- .positional("filename", {
2119
- describe: `The JSON file of keys to delete, in the form ["key1", "key2", ...]`,
2120
- type: "string",
2121
- demandOption: true,
2122
- })
2123
- .option("binding", {
2124
- type: "string",
2125
- describe: "The name of the namespace to delete from",
2126
- })
2127
- .option("namespace-id", {
2128
- type: "string",
2129
- describe: "The id of the namespace to delete from",
2130
- })
2131
- .check(demandOneOfOption("binding", "namespace-id"))
2132
- .option("env", {
2133
- type: "string",
2134
- describe: "Perform on a specific environment",
2135
- })
2136
- .option("preview", {
2137
- type: "boolean",
2138
- describe: "Interact with a preview namespace",
2139
- });
2140
- },
2141
- async ({ filename, ...args }) => {
2142
- const config = readConfig(args.config as ConfigPath);
2143
- const namespaceId = getNamespaceId(args, config);
2144
- const content = parseJSON(readFileSync(filename), filename);
2145
-
2146
- // -- snip, extract --
2147
- const loggedIn = await loginOrRefreshIfRequired();
2148
- if (!loggedIn) {
2149
- // didn't login, let's just quit
2150
- console.log("Did not login, quitting...");
2151
- return;
2152
- }
2153
-
2154
- if (!config.account_id) {
2155
- config.account_id = await getAccountId();
2156
- if (!config.account_id) {
2157
- throw new Error("No account id found, quitting...");
2158
- }
2159
- }
2160
- // -- snip, end --
2161
-
2162
- console.log(
2163
- await deleteBulkKeyValue(config.account_id, namespaceId, content)
2164
- );
2165
- }
2166
- );
2167
- }
2168
- );
2169
-
2170
- wrangler.command("pages", "⚡️ Configure Cloudflare Pages", pages);
2171
-
2172
- wrangler.command("r2", "📦 Interact with an R2 store", (r2Yargs) => {
2173
- return r2Yargs.command("bucket", "Manage R2 buckets", (r2BucketYargs) => {
2174
- r2BucketYargs.command(
2175
- "create <name>",
2176
- "Create a new R2 bucket",
2177
- (yargs) => {
2178
- return yargs.positional("name", {
2179
- describe: "The name of the new bucket",
2180
- type: "string",
2181
- demandOption: true,
2182
- });
2183
- },
2184
- async (args) => {
2185
- // We expect three values in `_`: `r2`, `bucket`, `create`.
2186
- if (args._.length > 3) {
2187
- const extraArgs = args._.slice(3).join(" ");
2188
- throw new CommandLineArgsError(
2189
- `Unexpected additional positional arguments "${extraArgs}".`
2190
- );
2191
- }
2192
-
2193
- const config = readConfig(args.config as ConfigPath);
2194
-
2195
- // -- snip, extract --
2196
- const loggedIn = await loginOrRefreshIfRequired();
2197
- if (!loggedIn) {
2198
- // didn't login, let's just quit
2199
- console.log("Did not login, quitting...");
2200
- return;
2201
- }
2202
-
2203
- if (!config.account_id) {
2204
- config.account_id = await getAccountId();
2205
- if (!config.account_id) {
2206
- throw new Error("No account id found, quitting...");
2207
- }
2208
- }
2209
- // -- snip, end --
2210
-
2211
- console.log(`Creating bucket ${args.name}.`);
2212
- await createR2Bucket(config.account_id, args.name);
2213
- console.log(`Created bucket ${args.name}.`);
2214
- }
2215
- );
2216
-
2217
- r2BucketYargs.command("list", "List R2 buckets", {}, async (args) => {
2218
- const config = readConfig(args.config as ConfigPath);
2219
-
2220
- // -- snip, extract --
2221
- const loggedIn = await loginOrRefreshIfRequired();
2222
- if (!loggedIn) {
2223
- // didn't login, let's just quit
2224
- console.log("Did not login, quitting...");
2225
- return;
2226
- }
2227
-
2228
- if (!config.account_id) {
2229
- config.account_id = await getAccountId();
2230
- if (!config.account_id) {
2231
- throw new Error("No account id found, quitting...");
2232
- }
2233
- }
2234
- // -- snip, end --
2235
-
2236
- console.log(
2237
- JSON.stringify(await listR2Buckets(config.account_id), null, 2)
2238
- );
2239
- });
2240
-
2241
- r2BucketYargs.command(
2242
- "delete <name>",
2243
- "Delete an R2 bucket",
2244
- (yargs) => {
2245
- return yargs.positional("name", {
2246
- describe: "The name of the bucket to delete",
2247
- type: "string",
2248
- demandOption: true,
2249
- });
2250
- },
2251
- async (args) => {
2252
- // We expect three values in `_`: `r2`, `bucket`, `delete`.
2253
- if (args._.length > 3) {
2254
- const extraArgs = args._.slice(3).join(" ");
2255
- throw new CommandLineArgsError(
2256
- `Unexpected additional positional arguments "${extraArgs}".`
2257
- );
2258
- }
2259
-
2260
- const config = readConfig(args.config as ConfigPath);
2261
-
2262
- // -- snip, extract --
2263
- const loggedIn = await loginOrRefreshIfRequired();
2264
- if (!loggedIn) {
2265
- // didn't login, let's just quit
2266
- console.log("Did not login, quitting...");
2267
- return;
2268
- }
2269
-
2270
- if (!config.account_id) {
2271
- config.account_id = await getAccountId();
2272
- if (!config.account_id) {
2273
- throw new Error("No account id found, quitting...");
2274
- }
2275
- }
2276
- // -- snip, end --
2277
-
2278
- console.log(`Deleting bucket ${args.name}.`);
2279
- await deleteR2Bucket(config.account_id, args.name);
2280
- console.log(`Deleted bucket ${args.name}.`);
2281
- }
2282
- );
2283
- return r2BucketYargs;
2284
- });
2285
- });
2286
-
2287
- wrangler
2288
- .option("legacy-env", {
2289
- type: "boolean",
2290
- describe: "Use legacy environments",
2291
- })
2292
- .option("config", {
2293
- alias: "c",
2294
- describe: "Path to .toml configuration file",
2295
- type: "string",
2296
- });
2297
-
2298
- wrangler.group(["config", "help", "version", "legacy-env"], "Flags:");
2299
- wrangler.help().alias("h", "help");
2300
- wrangler.version(wranglerVersion).alias("v", "version");
2301
- wrangler.exitProcess(false);
2302
-
2303
- try {
2304
- await initialiseUserConfig();
2305
- await wrangler.parse();
2306
- } catch (e) {
2307
- if (e instanceof CommandLineArgsError) {
2308
- wrangler.showHelp("error");
2309
- console.error(""); // Just adds a bit of space
2310
- console.error(e.message);
2311
- } else if (e instanceof ParseError) {
2312
- console.error("");
2313
- e.notes.push({
2314
- text: "\nIf you think this is a bug, please open an issue at: https://github.com/cloudflare/wrangler2/issues/new",
2315
- });
2316
- console.error(formatMessage(e));
2317
- } else {
2318
- console.error(e instanceof Error ? e.message : e);
2319
- console.error(""); // Just adds a bit of space
2320
- console.error(
2321
- `${fgGreenColor}%s${resetColor}`,
2322
- "If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2323
- );
2324
- }
2325
- throw e;
2326
- }
2327
- }