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