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