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