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