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