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