wrangler 0.0.0-e0d2f35 → 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 +48 -4
- package/kv-asset-handler.js +1 -0
- package/miniflare-dist/index.mjs +4886 -0
- package/package.json +58 -31
- package/pages/functions/buildPlugin.ts +105 -0
- package/pages/functions/buildWorker.ts +93 -4
- package/pages/functions/filepath-routing.test.ts +223 -28
- package/pages/functions/filepath-routing.ts +92 -131
- package/pages/functions/routes.ts +16 -18
- 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__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
- package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
- package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
- package/src/__tests__/helpers/mock-account-id.ts +48 -0
- package/src/__tests__/helpers/mock-bin.ts +36 -0
- package/src/__tests__/{mock-cfetch.ts → helpers/mock-cfetch.ts} +50 -12
- package/src/__tests__/helpers/mock-console.ts +87 -0
- package/src/__tests__/helpers/mock-dialogs.ts +153 -0
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +27 -0
- package/src/__tests__/{mock-kv.ts → 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__/{run-in-tmp.ts → helpers/run-in-tmp.ts} +11 -1
- package/src/__tests__/helpers/run-wrangler.ts +16 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
- package/src/__tests__/https-options.test.ts +130 -0
- package/src/__tests__/index.test.ts +171 -338
- package/src/__tests__/init.test.ts +1992 -0
- package/src/__tests__/jest.setup.ts +86 -8
- package/src/__tests__/kv.test.ts +745 -449
- 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 +5631 -903
- package/src/__tests__/r2.test.ts +233 -0
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +370 -95
- package/src/__tests__/tail.test.ts +690 -0
- package/src/__tests__/user.test.ts +132 -0
- package/src/__tests__/whoami.test.tsx +58 -20
- package/src/abort.d.ts +3 -0
- package/src/bundle.ts +204 -0
- package/src/cfetch/index.ts +30 -20
- package/src/cfetch/internal.ts +101 -30
- 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 +66 -8
- 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 +1848 -1019
- package/src/inspect.ts +87 -20
- 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 +229 -34
- package/src/open-in-browser.ts +17 -0
- package/src/package-manager.ts +174 -0
- package/src/pages.tsx +1145 -95
- package/src/parse.ts +222 -0
- package/src/paths.ts +26 -0
- package/src/proxy.ts +180 -74
- package/src/publish.ts +626 -310
- package/src/r2.ts +50 -0
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +187 -59
- package/src/tail/filters.ts +279 -0
- package/src/tail/index.ts +299 -0
- package/src/tail/printing.ts +67 -0
- package/src/update-check.ts +19 -0
- package/src/user.tsx +359 -176
- package/src/whoami.tsx +5 -3
- package/src/{api/worker.ts → worker.ts} +66 -40
- 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 +112889 -110835
- package/src/__tests__/logout.test.ts +0 -64
- package/src/__tests__/mock-console.ts +0 -34
- package/src/__tests__/mock-dialogs.ts +0 -65
- package/src/__tests__/mock-user.ts +0 -27
- package/src/__tests__/run-wrangler.ts +0 -8
- package/src/api/form_data.ts +0 -135
- package/src/api/preview.ts +0 -128
- package/src/config.ts +0 -641
- package/src/dev.tsx +0 -830
- 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,83 +1,200 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { setTimeout } from "node:timers/promises";
|
|
5
|
+
import TOML from "@iarna/toml";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { watch } from "chokidar";
|
|
8
|
+
import { execa } from "execa";
|
|
9
|
+
import { findUp } from "find-up";
|
|
10
|
+
import getPort from "get-port";
|
|
2
11
|
import { render } from "ink";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
12
|
+
import React from "react";
|
|
13
|
+
import onExit from "signal-exit";
|
|
14
|
+
import supportsColor from "supports-color";
|
|
15
|
+
import { setGlobalDispatcher, ProxyAgent } from "undici";
|
|
5
16
|
import makeCLI from "yargs";
|
|
6
|
-
import type Yargs from "yargs";
|
|
7
|
-
import { findUp } from "find-up";
|
|
8
|
-
import TOML from "@iarna/toml";
|
|
9
|
-
import { normaliseAndValidateEnvironmentsConfig } from "./config";
|
|
10
|
-
import type { Config } from "./config";
|
|
11
|
-
import { getAssetPaths } from "./sites";
|
|
12
|
-
import { confirm, prompt } from "./dialogs";
|
|
13
17
|
import { version as wranglerVersion } from "../package.json";
|
|
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";
|
|
26
|
+
import {
|
|
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,
|
|
40
|
+
} from "./kv";
|
|
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";
|
|
53
|
+
import publish from "./publish";
|
|
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";
|
|
14
63
|
import {
|
|
15
64
|
login,
|
|
16
65
|
logout,
|
|
17
66
|
listScopes,
|
|
18
|
-
initialise as initialiseUserConfig,
|
|
19
|
-
loginOrRefreshIfRequired,
|
|
20
|
-
getAccountId,
|
|
21
67
|
validateScopeKeys,
|
|
68
|
+
requireAuth,
|
|
22
69
|
} from "./user";
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
listNamespaces,
|
|
26
|
-
listNamespaceKeys,
|
|
27
|
-
putKeyValue,
|
|
28
|
-
putBulkKeyValue,
|
|
29
|
-
deleteBulkKeyValue,
|
|
30
|
-
createNamespace,
|
|
31
|
-
isValidNamespaceBinding,
|
|
32
|
-
} from "./kv";
|
|
70
|
+
import { whoami } from "./whoami";
|
|
71
|
+
import { getZoneIdFromHost, getZoneForRoute } from "./zones";
|
|
33
72
|
|
|
34
|
-
import {
|
|
73
|
+
import type { Config } from "./config";
|
|
74
|
+
import type { TailCLIFilters } from "./tail";
|
|
75
|
+
import type { RawData } from "ws";
|
|
76
|
+
import type { CommandModule } from "yargs";
|
|
77
|
+
import type Yargs from "yargs";
|
|
35
78
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
import publish from "./publish";
|
|
39
|
-
import path from "path/posix";
|
|
40
|
-
import { writeFile } from "node:fs/promises";
|
|
41
|
-
import { toFormData } from "./api/form_data";
|
|
42
|
-
|
|
43
|
-
import { createTail } from "./tail";
|
|
44
|
-
import onExit from "signal-exit";
|
|
45
|
-
import { setTimeout } from "node:timers/promises";
|
|
46
|
-
import * as fs from "node:fs";
|
|
47
|
-
import { execa } from "execa";
|
|
48
|
-
import { whoami } from "./whoami";
|
|
79
|
+
type ConfigPath = string | undefined;
|
|
49
80
|
|
|
50
81
|
const resetColor = "\x1b[0m";
|
|
51
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;
|
|
52
91
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
+
);
|
|
58
103
|
}
|
|
59
104
|
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return rules;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function printWranglerBanner() {
|
|
116
|
+
// Let's not print this in tests
|
|
117
|
+
if (typeof jest !== "undefined") {
|
|
118
|
+
return;
|
|
64
119
|
}
|
|
65
120
|
|
|
66
|
-
|
|
121
|
+
const text = ` ⛅️ wrangler ${wranglerVersion} ${await updateCheck()}`;
|
|
67
122
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
123
|
+
logger.log(
|
|
124
|
+
text +
|
|
125
|
+
"\n" +
|
|
126
|
+
(supportsColor.stdout
|
|
127
|
+
? chalk.hex("#FF8800")("-".repeat(text.length))
|
|
128
|
+
: "-".repeat(text.length))
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
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
|
+
`
|
|
71
149
|
);
|
|
72
150
|
}
|
|
73
151
|
|
|
74
|
-
|
|
75
|
-
|
|
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
|
+
}
|
|
166
|
+
|
|
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
|
+
});
|
|
76
186
|
|
|
77
|
-
|
|
78
|
-
|
|
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
|
+
});
|
|
79
192
|
|
|
80
|
-
|
|
193
|
+
// If there is an `error` event then the handler will reject the promise.
|
|
194
|
+
stdin.on("error", (err) => {
|
|
195
|
+
reject(err);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
81
198
|
}
|
|
82
199
|
|
|
83
200
|
// a helper to demand one of a set of options
|
|
@@ -105,19 +222,27 @@ function demandOneOfOption(...options: string[]) {
|
|
|
105
222
|
};
|
|
106
223
|
}
|
|
107
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
|
+
|
|
108
233
|
class CommandLineArgsError extends Error {}
|
|
109
|
-
class DeprecationError extends Error {}
|
|
110
|
-
class NotImplementedError extends Error {}
|
|
111
234
|
|
|
112
|
-
|
|
235
|
+
function createCLIParser(argv: string[]) {
|
|
113
236
|
const wrangler = makeCLI(argv)
|
|
237
|
+
.strict()
|
|
114
238
|
// We handle errors ourselves in a try-catch around `yargs.parse`.
|
|
115
239
|
// If you want the "help info" to be displayed then throw an instance of `CommandLineArgsError`.
|
|
116
240
|
// Otherwise we just log the error that was thrown without any "help info".
|
|
117
241
|
.showHelpOnFail(false)
|
|
118
242
|
.fail((msg, error) => {
|
|
119
|
-
if (!error) {
|
|
120
|
-
// 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.
|
|
121
246
|
error = new CommandLineArgsError(msg);
|
|
122
247
|
}
|
|
123
248
|
throw error;
|
|
@@ -125,7 +250,15 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
125
250
|
.scriptName("wrangler")
|
|
126
251
|
.wrap(null);
|
|
127
252
|
|
|
128
|
-
//
|
|
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
|
+
};
|
|
129
262
|
wrangler.command(
|
|
130
263
|
["*"],
|
|
131
264
|
false,
|
|
@@ -159,14 +292,19 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
159
292
|
default: "worker",
|
|
160
293
|
})
|
|
161
294
|
.positional("template", {
|
|
162
|
-
describe: "
|
|
295
|
+
describe: "The URL of a GitHub template",
|
|
163
296
|
default: "https://github.com/cloudflare/worker-template",
|
|
164
297
|
});
|
|
165
298
|
},
|
|
166
|
-
() => {
|
|
299
|
+
(generateArgs) => {
|
|
167
300
|
// "👯 [DEPRECATED]. Scaffold a Cloudflare Workers project from a public GitHub repository.",
|
|
168
301
|
throw new DeprecationError(
|
|
169
|
-
"`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."
|
|
170
308
|
);
|
|
171
309
|
}
|
|
172
310
|
);
|
|
@@ -176,13 +314,32 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
176
314
|
"init [name]",
|
|
177
315
|
"📥 Create a wrangler.toml configuration file",
|
|
178
316
|
(yargs) => {
|
|
179
|
-
return yargs
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
+
});
|
|
183
339
|
},
|
|
184
340
|
async (args) => {
|
|
185
|
-
|
|
341
|
+
await printWranglerBanner();
|
|
342
|
+
if (args.type) {
|
|
186
343
|
let message = "The --type option is no longer supported.";
|
|
187
344
|
if (args.type === "webpack") {
|
|
188
345
|
message +=
|
|
@@ -192,9 +349,52 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
192
349
|
throw new CommandLineArgsError(message);
|
|
193
350
|
}
|
|
194
351
|
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
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
|
+
);
|
|
198
398
|
const shouldContinue = await confirm(
|
|
199
399
|
"Do you want to continue initializing this project?"
|
|
200
400
|
);
|
|
@@ -202,55 +402,119 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
202
402
|
return;
|
|
203
403
|
}
|
|
204
404
|
} else {
|
|
405
|
+
await mkdir(creationDirectory, { recursive: true });
|
|
205
406
|
const compatibilityDate = new Date().toISOString().substring(0, 10);
|
|
407
|
+
|
|
206
408
|
try {
|
|
207
409
|
await writeFile(
|
|
208
|
-
|
|
209
|
-
|
|
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
|
+
)}`
|
|
210
422
|
);
|
|
211
|
-
|
|
212
|
-
// TODO: suggest next steps?
|
|
423
|
+
justCreatedWranglerToml = true;
|
|
213
424
|
} catch (err) {
|
|
214
425
|
throw new Error(
|
|
215
|
-
`Failed to create
|
|
426
|
+
`Failed to create ${path.relative(
|
|
427
|
+
process.cwd(),
|
|
428
|
+
wranglerTomlDestination
|
|
429
|
+
)}.\n${(err as Error).message ?? err}`
|
|
216
430
|
);
|
|
217
431
|
}
|
|
218
432
|
}
|
|
219
433
|
|
|
220
|
-
|
|
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
|
+
|
|
221
479
|
if (!pathToPackageJson) {
|
|
222
480
|
// If no package.json exists, ask to create one
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
481
|
+
shouldCreatePackageJson =
|
|
482
|
+
yesFlag ||
|
|
483
|
+
(await confirm(
|
|
484
|
+
"No package.json found. Would you like to create one?"
|
|
485
|
+
));
|
|
486
|
+
|
|
226
487
|
if (shouldCreatePackageJson) {
|
|
227
488
|
await writeFile(
|
|
228
|
-
path.join(
|
|
489
|
+
path.join(creationDirectory, "./package.json"),
|
|
229
490
|
JSON.stringify(
|
|
230
491
|
{
|
|
231
|
-
name:
|
|
232
|
-
version: "0.0.
|
|
492
|
+
name: workerName,
|
|
493
|
+
version: "0.0.0",
|
|
233
494
|
devDependencies: {
|
|
234
495
|
wrangler: wranglerVersion,
|
|
235
496
|
},
|
|
497
|
+
private: true,
|
|
236
498
|
},
|
|
237
499
|
null,
|
|
238
500
|
" "
|
|
239
501
|
) + "\n"
|
|
240
502
|
);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
503
|
+
|
|
504
|
+
shouldRunPackageManagerInstall = true;
|
|
505
|
+
pathToPackageJson = path.join(creationDirectory, "package.json");
|
|
506
|
+
logger.log(
|
|
507
|
+
`✨ Created ${path.relative(process.cwd(), pathToPackageJson)}`
|
|
508
|
+
);
|
|
246
509
|
} else {
|
|
247
510
|
return;
|
|
248
511
|
}
|
|
249
512
|
} else {
|
|
250
513
|
// If package.json exists and wrangler isn't installed,
|
|
251
514
|
// then ask to add wrangler to devDependencies
|
|
252
|
-
const packageJson =
|
|
253
|
-
|
|
515
|
+
const packageJson = parsePackageJSON(
|
|
516
|
+
readFileSync(pathToPackageJson),
|
|
517
|
+
pathToPackageJson
|
|
254
518
|
);
|
|
255
519
|
if (
|
|
256
520
|
!(
|
|
@@ -258,65 +522,49 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
258
522
|
packageJson.dependencies?.wrangler
|
|
259
523
|
)
|
|
260
524
|
) {
|
|
261
|
-
const shouldInstall =
|
|
262
|
-
|
|
263
|
-
|
|
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
|
+
));
|
|
264
533
|
if (shouldInstall) {
|
|
265
|
-
|
|
266
|
-
"npm",
|
|
267
|
-
["install", `wrangler@${wranglerVersion}`, "--save-dev"],
|
|
268
|
-
{
|
|
269
|
-
stdio: "inherit",
|
|
270
|
-
}
|
|
271
|
-
);
|
|
272
|
-
console.log(`✨ Installed wrangler`);
|
|
534
|
+
devDepsToInstall.push(`wrangler@${wranglerVersion}`);
|
|
273
535
|
}
|
|
274
536
|
}
|
|
275
537
|
}
|
|
276
538
|
|
|
277
|
-
let
|
|
539
|
+
let isTypescriptProject = false;
|
|
540
|
+
let pathToTSConfig = await findPath(
|
|
541
|
+
isolatedInit,
|
|
542
|
+
creationDirectory,
|
|
543
|
+
"tsconfig.json"
|
|
544
|
+
);
|
|
278
545
|
if (!pathToTSConfig) {
|
|
279
546
|
// If there's no tsconfig, offer to create one
|
|
280
547
|
// and install @cloudflare/workers-types
|
|
281
|
-
if (await confirm("Would you like to use
|
|
548
|
+
if (yesFlag || (await confirm("Would you like to use TypeScript?"))) {
|
|
549
|
+
isTypescriptProject = true;
|
|
282
550
|
await writeFile(
|
|
283
|
-
path.join(
|
|
284
|
-
|
|
285
|
-
{
|
|
286
|
-
compilerOptions: {
|
|
287
|
-
target: "esnext",
|
|
288
|
-
module: "esnext",
|
|
289
|
-
moduleResolution: "node",
|
|
290
|
-
esModuleInterop: true,
|
|
291
|
-
allowJs: true,
|
|
292
|
-
allowSyntheticDefaultImports: true,
|
|
293
|
-
isolatedModules: true,
|
|
294
|
-
noEmit: true,
|
|
295
|
-
lib: ["esnext"],
|
|
296
|
-
jsx: "react",
|
|
297
|
-
resolveJsonModule: true,
|
|
298
|
-
types: ["@cloudflare/workers-types"],
|
|
299
|
-
},
|
|
300
|
-
},
|
|
301
|
-
null,
|
|
302
|
-
" "
|
|
303
|
-
) + "\n"
|
|
304
|
-
);
|
|
305
|
-
await execa(
|
|
306
|
-
"npm",
|
|
307
|
-
["install", "@cloudflare/workers-types", "--save-dev"],
|
|
308
|
-
{ stdio: "inherit" }
|
|
551
|
+
path.join(creationDirectory, "./tsconfig.json"),
|
|
552
|
+
readFileSync(path.join(__dirname, "../templates/tsconfig.json"))
|
|
309
553
|
);
|
|
310
|
-
|
|
311
|
-
|
|
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)}`
|
|
312
559
|
);
|
|
313
|
-
pathToTSConfig = path.join(process.cwd(), "tsconfig.json");
|
|
314
560
|
}
|
|
315
561
|
} else {
|
|
562
|
+
isTypescriptProject = true;
|
|
316
563
|
// If there's a tsconfig, check if @cloudflare/workers-types
|
|
317
564
|
// is already installed, and offer to install it if not
|
|
318
|
-
const packageJson =
|
|
319
|
-
|
|
565
|
+
const packageJson = parsePackageJSON(
|
|
566
|
+
readFileSync(pathToPackageJson),
|
|
567
|
+
pathToPackageJson
|
|
320
568
|
);
|
|
321
569
|
if (
|
|
322
570
|
!(
|
|
@@ -328,25 +576,271 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
328
576
|
"Would you like to install the type definitions for Workers into your package.json?"
|
|
329
577
|
);
|
|
330
578
|
if (shouldInstall) {
|
|
331
|
-
|
|
332
|
-
"npm",
|
|
333
|
-
["install", "@cloudflare/workers-types", "--save-dev"],
|
|
334
|
-
{
|
|
335
|
-
stdio: "inherit",
|
|
336
|
-
}
|
|
337
|
-
);
|
|
579
|
+
devDepsToInstall.push("@cloudflare/workers-types");
|
|
338
580
|
// We don't update the tsconfig.json because
|
|
339
581
|
// it could be complicated in existing projects
|
|
340
582
|
// and we don't want to break them. Instead, we simply
|
|
341
583
|
// tell the user that they need to update their tsconfig.json
|
|
342
|
-
|
|
343
|
-
|
|
584
|
+
instructions.push(
|
|
585
|
+
`🚨 Please add "@cloudflare/workers-types" to compilerOptions.types in ${path.relative(
|
|
586
|
+
process.cwd(),
|
|
587
|
+
pathToTSConfig
|
|
588
|
+
)}`
|
|
344
589
|
);
|
|
345
|
-
} else {
|
|
346
|
-
return;
|
|
347
590
|
}
|
|
348
591
|
}
|
|
349
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)
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
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));
|
|
350
844
|
}
|
|
351
845
|
);
|
|
352
846
|
|
|
@@ -357,83 +851,34 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
357
851
|
(yargs) => {
|
|
358
852
|
return yargs.option("env", {
|
|
359
853
|
describe: "Perform on a specific environment",
|
|
854
|
+
type: "string",
|
|
360
855
|
});
|
|
361
856
|
},
|
|
362
|
-
() => {
|
|
857
|
+
async (buildArgs) => {
|
|
363
858
|
// "[DEPRECATED] 🦀 Build your project (if applicable)",
|
|
364
|
-
throw new DeprecationError(
|
|
365
|
-
"`wrangler build` has been deprecated, please refer to TODO://some/path for alternatives"
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
);
|
|
369
859
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
+
],
|
|
382
873
|
})
|
|
383
|
-
|
|
384
|
-
describe: "allows to choose your set of OAuth scopes.",
|
|
385
|
-
array: true,
|
|
386
|
-
type: "string",
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// TODO: scopes
|
|
390
|
-
},
|
|
391
|
-
async (args) => {
|
|
392
|
-
if (args["scopes-list"]) {
|
|
393
|
-
listScopes();
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
if (args.scopes) {
|
|
397
|
-
if (args.scopes.length === 0) {
|
|
398
|
-
// don't allow no scopes to be passed, that would be weird
|
|
399
|
-
listScopes();
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
if (!validateScopeKeys(args.scopes)) {
|
|
403
|
-
throw new CommandLineArgsError(
|
|
404
|
-
`One of ${args.scopes} is not a valid authentication scope. Run "wrangler login --list-scopes" to see the valid scopes.`
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
await login({ scopes: args.scopes });
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
await login();
|
|
411
|
-
|
|
412
|
-
// TODO: would be nice if it optionally saved login
|
|
413
|
-
// credentials inside node_modules/.cache or something
|
|
414
|
-
// this way you could have multiple users on a single machine
|
|
415
|
-
}
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
// logout
|
|
419
|
-
wrangler.command(
|
|
420
|
-
// this needs scopes as an option?
|
|
421
|
-
"logout",
|
|
422
|
-
false, // we don't need to show this in the menu
|
|
423
|
-
// "🚪 Logout from Cloudflare",
|
|
424
|
-
() => {},
|
|
425
|
-
async () => {
|
|
426
|
-
await logout();
|
|
427
|
-
}
|
|
428
|
-
);
|
|
874
|
+
);
|
|
429
875
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
await whoami();
|
|
876
|
+
await createCLIParser([
|
|
877
|
+
"publish",
|
|
878
|
+
"--dry-run",
|
|
879
|
+
"--outdir=dist",
|
|
880
|
+
...(buildArgs.env ? ["--env", buildArgs.env] : []),
|
|
881
|
+
]).parse();
|
|
437
882
|
}
|
|
438
883
|
);
|
|
439
884
|
|
|
@@ -445,43 +890,48 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
445
890
|
() => {
|
|
446
891
|
// "🕵️ Authenticate Wrangler with a Cloudflare API Token",
|
|
447
892
|
throw new DeprecationError(
|
|
448
|
-
"`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"
|
|
449
894
|
);
|
|
450
895
|
}
|
|
451
896
|
);
|
|
452
897
|
|
|
453
898
|
// dev
|
|
454
899
|
wrangler.command(
|
|
455
|
-
"dev
|
|
900
|
+
"dev [script]",
|
|
456
901
|
"👂 Start a local server for developing your worker",
|
|
457
902
|
(yargs) => {
|
|
458
903
|
return yargs
|
|
459
|
-
.positional("
|
|
460
|
-
describe: "entry point",
|
|
904
|
+
.positional("script", {
|
|
905
|
+
describe: "The path to an entry point for your worker",
|
|
461
906
|
type: "string",
|
|
462
|
-
demandOption: true,
|
|
463
907
|
})
|
|
464
908
|
.option("name", {
|
|
465
|
-
describe: "
|
|
909
|
+
describe: "Name of the worker",
|
|
466
910
|
type: "string",
|
|
911
|
+
requiresArg: true,
|
|
467
912
|
})
|
|
468
913
|
.option("format", {
|
|
469
914
|
choices: ["modules", "service-worker"] as const,
|
|
470
915
|
describe: "Choose an entry type",
|
|
916
|
+
deprecated: true,
|
|
471
917
|
})
|
|
472
918
|
.option("env", {
|
|
473
919
|
describe: "Perform on a specific environment",
|
|
474
920
|
type: "string",
|
|
475
|
-
|
|
921
|
+
requiresArg: true,
|
|
922
|
+
alias: "e",
|
|
476
923
|
})
|
|
477
924
|
.option("compatibility-date", {
|
|
478
925
|
describe: "Date to use for compatibility checks",
|
|
479
926
|
type: "string",
|
|
927
|
+
requiresArg: true,
|
|
480
928
|
})
|
|
481
929
|
.option("compatibility-flags", {
|
|
482
930
|
describe: "Flags to use for compatibility checks",
|
|
483
|
-
type: "array",
|
|
484
931
|
alias: "compatibility-flag",
|
|
932
|
+
type: "string",
|
|
933
|
+
requiresArg: true,
|
|
934
|
+
array: true,
|
|
485
935
|
})
|
|
486
936
|
.option("latest", {
|
|
487
937
|
describe: "Use the latest version of the worker runtime",
|
|
@@ -489,154 +939,218 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
489
939
|
default: true,
|
|
490
940
|
})
|
|
491
941
|
.option("ip", {
|
|
492
|
-
describe: "IP address to listen on",
|
|
942
|
+
describe: "IP address to listen on, defaults to `localhost`",
|
|
493
943
|
type: "string",
|
|
494
|
-
|
|
944
|
+
requiresArg: true,
|
|
495
945
|
})
|
|
496
946
|
.option("port", {
|
|
497
|
-
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",
|
|
498
952
|
type: "number",
|
|
499
|
-
|
|
953
|
+
})
|
|
954
|
+
.option("routes", {
|
|
955
|
+
describe: "Routes to upload",
|
|
956
|
+
alias: "route",
|
|
957
|
+
type: "string",
|
|
958
|
+
requiresArg: true,
|
|
959
|
+
array: true,
|
|
500
960
|
})
|
|
501
961
|
.option("host", {
|
|
502
962
|
type: "string",
|
|
963
|
+
requiresArg: true,
|
|
503
964
|
describe:
|
|
504
965
|
"Host to forward requests to, defaults to the zone of project",
|
|
505
966
|
})
|
|
506
967
|
.option("local-protocol", {
|
|
507
|
-
default: "http",
|
|
508
968
|
describe: "Protocol to listen to requests on, defaults to http.",
|
|
509
|
-
choices: ["http", "https"],
|
|
969
|
+
choices: ["http", "https"] as const,
|
|
510
970
|
})
|
|
511
971
|
.option("experimental-public", {
|
|
512
972
|
describe: "Static assets to be served",
|
|
513
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,
|
|
514
982
|
})
|
|
515
983
|
.option("site", {
|
|
516
984
|
describe: "Root folder of static assets for Workers Sites",
|
|
517
985
|
type: "string",
|
|
986
|
+
requiresArg: true,
|
|
518
987
|
})
|
|
519
988
|
.option("site-include", {
|
|
520
989
|
describe:
|
|
521
990
|
"Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.",
|
|
522
991
|
type: "string",
|
|
992
|
+
requiresArg: true,
|
|
523
993
|
array: true,
|
|
524
994
|
})
|
|
525
995
|
.option("site-exclude", {
|
|
526
996
|
describe:
|
|
527
997
|
"Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.",
|
|
528
998
|
type: "string",
|
|
999
|
+
requiresArg: true,
|
|
529
1000
|
array: true,
|
|
530
1001
|
})
|
|
531
1002
|
.option("upstream-protocol", {
|
|
532
|
-
default: "https",
|
|
533
1003
|
describe:
|
|
534
1004
|
"Protocol to forward requests to host on, defaults to https.",
|
|
535
|
-
choices: ["http", "https"],
|
|
1005
|
+
choices: ["http", "https"] as const,
|
|
536
1006
|
})
|
|
537
1007
|
.option("jsx-factory", {
|
|
538
1008
|
describe: "The function that is called for each JSX element",
|
|
539
1009
|
type: "string",
|
|
1010
|
+
requiresArg: true,
|
|
540
1011
|
})
|
|
541
1012
|
.option("jsx-fragment", {
|
|
542
1013
|
describe: "The function that is called for each JSX fragment",
|
|
543
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",
|
|
544
1035
|
})
|
|
545
1036
|
.option("experimental-enable-local-persistence", {
|
|
546
1037
|
describe: "Enable persistence for this session (only for local mode)",
|
|
547
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,
|
|
548
1049
|
});
|
|
549
1050
|
},
|
|
550
1051
|
async (args) => {
|
|
551
|
-
|
|
552
|
-
|
|
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
|
+
}
|
|
553
1074
|
|
|
554
|
-
|
|
555
|
-
console.warn(
|
|
556
|
-
"🚨 The --experimental-public field is experimental and will change in the future."
|
|
557
|
-
);
|
|
558
|
-
}
|
|
1075
|
+
const entry = await getEntry(args, config, "dev");
|
|
559
1076
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
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
|
+
}
|
|
565
1089
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
);
|
|
572
|
-
}
|
|
1090
|
+
if (args.inspect) {
|
|
1091
|
+
logger.warn(
|
|
1092
|
+
"Passing --inspect is unnecessary, now you can always connect to devtools."
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
573
1095
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
// didn't login, let's just quit
|
|
579
|
-
console.log("Did not login, quitting...");
|
|
580
|
-
return;
|
|
1096
|
+
if (args["experimental-public"]) {
|
|
1097
|
+
throw new Error(
|
|
1098
|
+
"The --experimental-public field has been renamed to --assets"
|
|
1099
|
+
);
|
|
581
1100
|
}
|
|
582
1101
|
|
|
583
|
-
if (
|
|
584
|
-
|
|
585
|
-
if (!config.account_id) {
|
|
586
|
-
throw new Error("No account id found, quitting...");
|
|
587
|
-
}
|
|
1102
|
+
if (args.public) {
|
|
1103
|
+
throw new Error("The --public field has been renamed to --assets");
|
|
588
1104
|
}
|
|
589
|
-
// -- snip, end --
|
|
590
|
-
}
|
|
591
1105
|
|
|
592
|
-
|
|
593
|
-
|
|
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
|
+
}
|
|
594
1111
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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."
|
|
601
1119
|
);
|
|
602
1120
|
}
|
|
603
|
-
// TODO: if not already published, publish a draft worker
|
|
604
|
-
}
|
|
605
1121
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
jsxFragment={args["jsx-fragment"] || envRootObj?.jsx_fragment}
|
|
616
|
-
enableLocalPersistence={
|
|
617
|
-
args["experimental-enable-local-persistence"] || false
|
|
618
|
-
}
|
|
619
|
-
accountId={config.account_id}
|
|
620
|
-
assetPaths={getAssetPaths(
|
|
621
|
-
config,
|
|
622
|
-
args.site,
|
|
623
|
-
args.siteInclude,
|
|
624
|
-
args.siteExclude
|
|
625
|
-
)}
|
|
626
|
-
port={args.port || config.dev?.port}
|
|
627
|
-
public={args["experimental-public"]}
|
|
628
|
-
compatibilityDate={
|
|
629
|
-
args["compatibility-date"] ||
|
|
630
|
-
config.compatibility_date ||
|
|
631
|
-
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);
|
|
632
1131
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
+
}
|
|
636
1140
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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(
|
|
640
1154
|
({ binding, preview_id, id: _id }) => {
|
|
641
1155
|
// In `dev`, we make folks use a separate kv namespace called
|
|
642
1156
|
// `preview_id` instead of `id` so that they don't
|
|
@@ -657,13 +1171,116 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
657
1171
|
};
|
|
658
1172
|
}
|
|
659
1173
|
),
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
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
|
+
}
|
|
667
1284
|
}
|
|
668
1285
|
);
|
|
669
1286
|
|
|
@@ -675,24 +1292,41 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
675
1292
|
return yargs
|
|
676
1293
|
.option("env", {
|
|
677
1294
|
type: "string",
|
|
1295
|
+
requiresArg: true,
|
|
678
1296
|
describe: "Perform on a specific environment",
|
|
1297
|
+
alias: "e",
|
|
679
1298
|
})
|
|
680
1299
|
.positional("script", {
|
|
681
|
-
describe: "
|
|
1300
|
+
describe: "The path to an entry point for your worker",
|
|
682
1301
|
type: "string",
|
|
1302
|
+
requiresArg: true,
|
|
683
1303
|
})
|
|
684
1304
|
.option("name", {
|
|
685
|
-
describe: "
|
|
1305
|
+
describe: "Name of the worker",
|
|
1306
|
+
type: "string",
|
|
1307
|
+
requiresArg: true,
|
|
1308
|
+
})
|
|
1309
|
+
.option("outdir", {
|
|
1310
|
+
describe: "Output directory for the bundled worker",
|
|
686
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,
|
|
687
1318
|
})
|
|
688
1319
|
.option("compatibility-date", {
|
|
689
1320
|
describe: "Date to use for compatibility checks",
|
|
690
1321
|
type: "string",
|
|
1322
|
+
requiresArg: true,
|
|
691
1323
|
})
|
|
692
1324
|
.option("compatibility-flags", {
|
|
693
1325
|
describe: "Flags to use for compatibility checks",
|
|
694
|
-
type: "array",
|
|
695
1326
|
alias: "compatibility-flag",
|
|
1327
|
+
type: "string",
|
|
1328
|
+
requiresArg: true,
|
|
1329
|
+
array: true,
|
|
696
1330
|
})
|
|
697
1331
|
.option("latest", {
|
|
698
1332
|
describe: "Use the latest version of the worker runtime",
|
|
@@ -702,115 +1336,146 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
702
1336
|
.option("experimental-public", {
|
|
703
1337
|
describe: "Static assets to be served",
|
|
704
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,
|
|
705
1347
|
})
|
|
706
1348
|
.option("site", {
|
|
707
1349
|
describe: "Root folder of static assets for Workers Sites",
|
|
708
1350
|
type: "string",
|
|
1351
|
+
requiresArg: true,
|
|
709
1352
|
})
|
|
710
1353
|
.option("site-include", {
|
|
711
1354
|
describe:
|
|
712
1355
|
"Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.",
|
|
713
1356
|
type: "string",
|
|
1357
|
+
requiresArg: true,
|
|
714
1358
|
array: true,
|
|
715
1359
|
})
|
|
716
1360
|
.option("site-exclude", {
|
|
717
1361
|
describe:
|
|
718
1362
|
"Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.",
|
|
719
1363
|
type: "string",
|
|
1364
|
+
requiresArg: true,
|
|
720
1365
|
array: true,
|
|
721
1366
|
})
|
|
722
1367
|
.option("triggers", {
|
|
723
1368
|
describe: "cron schedules to attach",
|
|
724
1369
|
alias: ["schedule", "schedules"],
|
|
725
|
-
type: "
|
|
1370
|
+
type: "string",
|
|
1371
|
+
requiresArg: true,
|
|
1372
|
+
array: true,
|
|
726
1373
|
})
|
|
727
1374
|
.option("routes", {
|
|
728
|
-
describe: "
|
|
1375
|
+
describe: "Routes to upload",
|
|
729
1376
|
alias: "route",
|
|
730
|
-
type: "
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
describe: "experimental support for services",
|
|
734
|
-
type: "boolean",
|
|
735
|
-
default: "false",
|
|
736
|
-
hidden: true,
|
|
1377
|
+
type: "string",
|
|
1378
|
+
requiresArg: true,
|
|
1379
|
+
array: true,
|
|
737
1380
|
})
|
|
738
1381
|
.option("jsx-factory", {
|
|
739
1382
|
describe: "The function that is called for each JSX element",
|
|
740
1383
|
type: "string",
|
|
1384
|
+
requiresArg: true,
|
|
741
1385
|
})
|
|
742
1386
|
.option("jsx-fragment", {
|
|
743
1387
|
describe: "The function that is called for each JSX fragment",
|
|
744
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,
|
|
745
1412
|
});
|
|
746
1413
|
},
|
|
747
1414
|
async (args) => {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
)
|
|
752
|
-
|
|
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");
|
|
753
1422
|
|
|
1423
|
+
if (args.public) {
|
|
1424
|
+
throw new Error("The --public field has been renamed to --assets");
|
|
1425
|
+
}
|
|
754
1426
|
if (args["experimental-public"]) {
|
|
755
|
-
|
|
756
|
-
"
|
|
1427
|
+
throw new Error(
|
|
1428
|
+
"The --experimental-public field has been renamed to --assets"
|
|
757
1429
|
);
|
|
758
1430
|
}
|
|
759
|
-
|
|
1431
|
+
|
|
1432
|
+
if ((args.assets || config.assets) && (args.site || config.site)) {
|
|
760
1433
|
throw new Error(
|
|
761
|
-
"
|
|
1434
|
+
"Cannot use Assets and Workers Sites in the same Worker."
|
|
762
1435
|
);
|
|
763
1436
|
}
|
|
764
1437
|
|
|
765
|
-
const config = args.config as Config;
|
|
766
|
-
|
|
767
1438
|
if (args.latest) {
|
|
768
|
-
|
|
769
|
-
"
|
|
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"
|
|
770
1441
|
);
|
|
771
1442
|
}
|
|
772
1443
|
|
|
773
|
-
|
|
774
|
-
// -- snip, extract --
|
|
775
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
776
|
-
if (!loggedIn) {
|
|
777
|
-
// didn't login, let's just quit
|
|
778
|
-
console.log("Did not login, quitting...");
|
|
779
|
-
return;
|
|
780
|
-
}
|
|
1444
|
+
const accountId = args.dryRun ? undefined : await requireAuth(config);
|
|
781
1445
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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
|
+
);
|
|
790
1455
|
|
|
791
|
-
const assetPaths = getAssetPaths(
|
|
792
|
-
config,
|
|
793
|
-
args["experimental-public"] || args.site,
|
|
794
|
-
args.siteInclude,
|
|
795
|
-
args.siteExclude
|
|
796
|
-
);
|
|
797
1456
|
await publish({
|
|
798
|
-
config
|
|
799
|
-
|
|
800
|
-
|
|
1457
|
+
config,
|
|
1458
|
+
accountId,
|
|
1459
|
+
name: getScriptName(args, config),
|
|
1460
|
+
rules: getRules(config),
|
|
1461
|
+
entry,
|
|
801
1462
|
env: args.env,
|
|
802
1463
|
compatibilityDate: args.latest
|
|
803
1464
|
? new Date().toISOString().substring(0, 10)
|
|
804
1465
|
: args["compatibility-date"],
|
|
805
|
-
compatibilityFlags: args["compatibility-flags"]
|
|
1466
|
+
compatibilityFlags: args["compatibility-flags"],
|
|
806
1467
|
triggers: args.triggers,
|
|
807
1468
|
jsxFactory: args["jsx-factory"],
|
|
808
1469
|
jsxFragment: args["jsx-fragment"],
|
|
1470
|
+
tsconfig: args.tsconfig,
|
|
809
1471
|
routes: args.routes,
|
|
810
1472
|
assetPaths,
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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,
|
|
814
1479
|
});
|
|
815
1480
|
}
|
|
816
1481
|
);
|
|
@@ -818,119 +1483,147 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
818
1483
|
// tail
|
|
819
1484
|
wrangler.command(
|
|
820
1485
|
"tail [name]",
|
|
821
|
-
"🦚 Starts a log tailing session for a
|
|
1486
|
+
"🦚 Starts a log tailing session for a published Worker.",
|
|
822
1487
|
(yargs) => {
|
|
823
|
-
return
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
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
|
+
});
|
|
861
1548
|
},
|
|
862
1549
|
async (args) => {
|
|
863
|
-
if (args.
|
|
864
|
-
|
|
865
|
-
`local mode is not yet supported for this command`
|
|
866
|
-
);
|
|
1550
|
+
if (args.format === "pretty") {
|
|
1551
|
+
await printWranglerBanner();
|
|
867
1552
|
}
|
|
1553
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
868
1554
|
|
|
869
|
-
const
|
|
1555
|
+
const scriptName = getLegacyScriptName(args, config);
|
|
870
1556
|
|
|
871
|
-
if (!
|
|
1557
|
+
if (!scriptName) {
|
|
872
1558
|
throw new Error("Missing script name");
|
|
873
1559
|
}
|
|
874
|
-
const scriptName = `${args.name || config.name}${
|
|
875
|
-
args.env ? `-${args.env}` : ""
|
|
876
|
-
}`;
|
|
877
|
-
|
|
878
|
-
// -- snip, extract --
|
|
879
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
880
|
-
if (!loggedIn) {
|
|
881
|
-
// didn't login, let's just quit
|
|
882
|
-
console.log("Did not login, quitting...");
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
if (!config.account_id) {
|
|
887
|
-
config.account_id = await getAccountId();
|
|
888
|
-
if (!config.account_id) {
|
|
889
|
-
throw new Error("No account id found, quitting...");
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
// -- snip, end --
|
|
893
1560
|
|
|
894
|
-
const accountId = config
|
|
1561
|
+
const accountId = await requireAuth(config);
|
|
895
1562
|
|
|
896
|
-
const
|
|
897
|
-
status: args.status as "ok" | "error" | "canceled",
|
|
1563
|
+
const cliFilters: TailCLIFilters = {
|
|
1564
|
+
status: args.status as ("ok" | "error" | "canceled")[] | undefined,
|
|
898
1565
|
header: args.header,
|
|
899
1566
|
method: args.method,
|
|
900
|
-
|
|
1567
|
+
samplingRate: args["sampling-rate"],
|
|
901
1568
|
search: args.search,
|
|
1569
|
+
clientIp: args.ip,
|
|
902
1570
|
};
|
|
903
1571
|
|
|
904
|
-
const
|
|
905
|
-
|
|
1572
|
+
const filters = translateCLICommandToFilterMessage(
|
|
1573
|
+
cliFilters,
|
|
1574
|
+
args.debug
|
|
1575
|
+
);
|
|
906
1576
|
|
|
907
|
-
|
|
908
|
-
|
|
1577
|
+
const { tail, expiration, deleteTail } = await createTail(
|
|
1578
|
+
accountId,
|
|
1579
|
+
scriptName,
|
|
1580
|
+
filters,
|
|
1581
|
+
!isLegacyEnv(config) ? args.env : undefined
|
|
909
1582
|
);
|
|
910
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
|
+
|
|
911
1594
|
onExit(async () => {
|
|
912
1595
|
tail.terminate();
|
|
913
1596
|
await deleteTail();
|
|
914
1597
|
});
|
|
915
1598
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1599
|
+
const printLog: (data: RawData) => void =
|
|
1600
|
+
args.format === "pretty" ? prettyPrintLogs : jsonPrintLogs;
|
|
1601
|
+
|
|
1602
|
+
tail.on("message", printLog);
|
|
919
1603
|
|
|
920
1604
|
while (tail.readyState !== tail.OPEN) {
|
|
921
1605
|
switch (tail.readyState) {
|
|
922
1606
|
case tail.CONNECTING:
|
|
923
|
-
await setTimeout(
|
|
1607
|
+
await setTimeout(100);
|
|
924
1608
|
break;
|
|
925
1609
|
case tail.CLOSING:
|
|
926
|
-
await setTimeout(
|
|
1610
|
+
await setTimeout(100);
|
|
927
1611
|
break;
|
|
928
1612
|
case tail.CLOSED:
|
|
929
|
-
|
|
1613
|
+
throw new Error(
|
|
1614
|
+
`Connection to ${scriptDisplayName} closed unexpectedly.`
|
|
1615
|
+
);
|
|
930
1616
|
}
|
|
931
1617
|
}
|
|
932
1618
|
|
|
933
|
-
|
|
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
|
+
});
|
|
934
1627
|
}
|
|
935
1628
|
);
|
|
936
1629
|
|
|
@@ -941,17 +1634,16 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
941
1634
|
(yargs) => {
|
|
942
1635
|
return yargs
|
|
943
1636
|
.positional("method", {
|
|
1637
|
+
type: "string",
|
|
944
1638
|
describe: "Type of request to preview your worker",
|
|
945
|
-
choices: ["GET", "POST"],
|
|
946
|
-
default: ["GET"],
|
|
947
1639
|
})
|
|
948
1640
|
.positional("body", {
|
|
949
1641
|
type: "string",
|
|
950
1642
|
describe: "Body string to post to your preview worker request.",
|
|
951
|
-
default: "Null",
|
|
952
1643
|
})
|
|
953
1644
|
.option("env", {
|
|
954
1645
|
type: "string",
|
|
1646
|
+
requiresArg: true,
|
|
955
1647
|
describe: "Perform on a specific environment",
|
|
956
1648
|
})
|
|
957
1649
|
.option("watch", {
|
|
@@ -960,15 +1652,110 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
960
1652
|
type: "boolean",
|
|
961
1653
|
});
|
|
962
1654
|
},
|
|
963
|
-
() => {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
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
|
+
/>
|
|
967
1753
|
);
|
|
1754
|
+
await waitUntilExit();
|
|
968
1755
|
}
|
|
969
1756
|
);
|
|
970
1757
|
|
|
971
|
-
// route
|
|
1758
|
+
// [DEPRECATED] route
|
|
972
1759
|
wrangler.command(
|
|
973
1760
|
"route",
|
|
974
1761
|
false, // I think we want to hide this command
|
|
@@ -977,35 +1764,39 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
977
1764
|
return routeYargs
|
|
978
1765
|
.command(
|
|
979
1766
|
"list",
|
|
980
|
-
"List
|
|
1767
|
+
"List the routes associated with a zone",
|
|
981
1768
|
(yargs) => {
|
|
982
1769
|
return yargs
|
|
983
1770
|
.option("env", {
|
|
984
1771
|
type: "string",
|
|
1772
|
+
requiresArg: true,
|
|
985
1773
|
describe: "Perform on a specific environment",
|
|
986
1774
|
})
|
|
987
1775
|
.option("zone", {
|
|
988
1776
|
type: "string",
|
|
989
|
-
|
|
1777
|
+
requiresArg: true,
|
|
1778
|
+
describe: "Zone id",
|
|
990
1779
|
})
|
|
991
1780
|
.positional("zone", {
|
|
992
|
-
describe: "
|
|
1781
|
+
describe: "Zone id",
|
|
993
1782
|
type: "string",
|
|
994
1783
|
});
|
|
995
1784
|
},
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
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
|
+
);
|
|
1005
1796
|
}
|
|
1006
1797
|
)
|
|
1007
1798
|
.command(
|
|
1008
|
-
"delete
|
|
1799
|
+
"delete [id]",
|
|
1009
1800
|
"Delete a route associated with a zone",
|
|
1010
1801
|
(yargs) => {
|
|
1011
1802
|
return yargs
|
|
@@ -1015,28 +1806,31 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1015
1806
|
})
|
|
1016
1807
|
.option("zone", {
|
|
1017
1808
|
type: "string",
|
|
1809
|
+
requiresArg: true,
|
|
1018
1810
|
describe: "zone id",
|
|
1019
1811
|
})
|
|
1020
1812
|
.option("env", {
|
|
1021
1813
|
type: "string",
|
|
1814
|
+
requiresArg: true,
|
|
1022
1815
|
describe: "Perform on a specific environment",
|
|
1023
1816
|
});
|
|
1024
1817
|
},
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
console.log(
|
|
1034
|
-
await fetchResult(`/zones/${zone}/workers/routes/${args.id}`, {
|
|
1035
|
-
method: "DELETE",
|
|
1036
|
-
})
|
|
1037
|
-
);
|
|
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}`);
|
|
1038
1825
|
}
|
|
1039
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}`);
|
|
1040
1834
|
}
|
|
1041
1835
|
);
|
|
1042
1836
|
|
|
@@ -1050,7 +1844,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1050
1844
|
},
|
|
1051
1845
|
() => {
|
|
1052
1846
|
throw new DeprecationError(
|
|
1053
|
-
"`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"
|
|
1054
1848
|
);
|
|
1055
1849
|
}
|
|
1056
1850
|
);
|
|
@@ -1061,186 +1855,190 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1061
1855
|
"🤫 Generate a secret that can be referenced in the worker script",
|
|
1062
1856
|
(secretYargs) => {
|
|
1063
1857
|
return secretYargs
|
|
1858
|
+
.command(subHelp)
|
|
1859
|
+
.option("legacy-env", {
|
|
1860
|
+
type: "boolean",
|
|
1861
|
+
describe: "Use legacy environments",
|
|
1862
|
+
hidden: true,
|
|
1863
|
+
})
|
|
1064
1864
|
.command(
|
|
1065
1865
|
"put <key>",
|
|
1066
1866
|
"Create or update a secret variable for a script",
|
|
1067
1867
|
(yargs) => {
|
|
1068
1868
|
return yargs
|
|
1069
1869
|
.positional("key", {
|
|
1070
|
-
describe: "The variable name to be accessible in the script
|
|
1870
|
+
describe: "The variable name to be accessible in the script",
|
|
1071
1871
|
type: "string",
|
|
1072
1872
|
})
|
|
1073
1873
|
.option("name", {
|
|
1074
|
-
describe: "
|
|
1874
|
+
describe: "Name of the worker",
|
|
1075
1875
|
type: "string",
|
|
1876
|
+
requiresArg: true,
|
|
1076
1877
|
})
|
|
1077
1878
|
.option("env", {
|
|
1078
1879
|
type: "string",
|
|
1880
|
+
requiresArg: true,
|
|
1079
1881
|
describe:
|
|
1080
|
-
"Binds the secret to the
|
|
1882
|
+
"Binds the secret to the Worker of the specific environment",
|
|
1883
|
+
alias: "e",
|
|
1081
1884
|
});
|
|
1082
1885
|
},
|
|
1083
1886
|
async (args) => {
|
|
1084
|
-
|
|
1887
|
+
await printWranglerBanner();
|
|
1888
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
1085
1889
|
|
|
1086
|
-
|
|
1087
|
-
const scriptName = args.name || config.name;
|
|
1890
|
+
const scriptName = getLegacyScriptName(args, config);
|
|
1088
1891
|
if (!scriptName) {
|
|
1089
1892
|
throw new Error("Missing script name");
|
|
1090
1893
|
}
|
|
1091
1894
|
|
|
1092
|
-
|
|
1093
|
-
console.warn("`wrangler secret put` is a no-op in --local mode");
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
if (!args.local) {
|
|
1097
|
-
// -- snip, extract --
|
|
1098
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1099
|
-
if (!loggedIn) {
|
|
1100
|
-
// didn't login, let's just quit
|
|
1101
|
-
console.log("Did not login, quitting...");
|
|
1102
|
-
return;
|
|
1103
|
-
}
|
|
1895
|
+
const accountId = await requireAuth(config);
|
|
1104
1896
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
// -- snip, end --
|
|
1112
|
-
}
|
|
1897
|
+
const isInteractive = process.stdin.isTTY;
|
|
1898
|
+
const secretValue = trimTrailingWhitespace(
|
|
1899
|
+
isInteractive
|
|
1900
|
+
? await prompt("Enter a secret value:", "password")
|
|
1901
|
+
: await readFromStdin()
|
|
1902
|
+
);
|
|
1113
1903
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1904
|
+
logger.log(
|
|
1905
|
+
`🌀 Creating the secret for script ${scriptName} ${
|
|
1906
|
+
args.env && !isLegacyEnv(config) ? `(${args.env})` : ""
|
|
1907
|
+
}`
|
|
1117
1908
|
);
|
|
1118
1909
|
|
|
1119
|
-
|
|
1120
|
-
|
|
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
|
+
});
|
|
1121
1925
|
}
|
|
1122
1926
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
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}`,
|
|
1128
1933
|
{
|
|
1129
1934
|
method: "PUT",
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
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,
|
|
1135
1958
|
}),
|
|
1136
1959
|
}
|
|
1137
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
|
+
);
|
|
1138
1969
|
}
|
|
1139
1970
|
|
|
1140
1971
|
try {
|
|
1141
1972
|
await submitSecret();
|
|
1142
1973
|
} catch (e) {
|
|
1143
|
-
if (e
|
|
1144
|
-
//
|
|
1145
|
-
await
|
|
1146
|
-
`/accounts/${config.account_id}/workers/scripts/${scriptName}`,
|
|
1147
|
-
{
|
|
1148
|
-
method: "PUT",
|
|
1149
|
-
// @ts-expect-error TODO: fix this error!
|
|
1150
|
-
body: toFormData({
|
|
1151
|
-
main: {
|
|
1152
|
-
name: scriptName,
|
|
1153
|
-
content: `export default { fetch() {} }`,
|
|
1154
|
-
type: "esm",
|
|
1155
|
-
},
|
|
1156
|
-
bindings: {
|
|
1157
|
-
kv_namespaces: [],
|
|
1158
|
-
vars: {},
|
|
1159
|
-
durable_objects: { bindings: [] },
|
|
1160
|
-
},
|
|
1161
|
-
modules: [],
|
|
1162
|
-
}),
|
|
1163
|
-
}
|
|
1164
|
-
);
|
|
1165
|
-
|
|
1166
|
-
// and then try again
|
|
1974
|
+
if (isMissingWorkerError(e)) {
|
|
1975
|
+
// create a draft worker and try again
|
|
1976
|
+
await createDraftWorker();
|
|
1167
1977
|
await submitSecret();
|
|
1168
1978
|
// TODO: delete the draft worker if this failed too?
|
|
1979
|
+
} else {
|
|
1980
|
+
throw e;
|
|
1169
1981
|
}
|
|
1170
1982
|
}
|
|
1171
|
-
|
|
1983
|
+
|
|
1984
|
+
logger.log(`✨ Success! Uploaded secret ${args.key}`);
|
|
1172
1985
|
}
|
|
1173
1986
|
)
|
|
1174
1987
|
.command(
|
|
1175
1988
|
"delete <key>",
|
|
1176
1989
|
"Delete a secret variable from a script",
|
|
1177
|
-
(yargs) => {
|
|
1990
|
+
async (yargs) => {
|
|
1991
|
+
await printWranglerBanner();
|
|
1178
1992
|
return yargs
|
|
1179
1993
|
.positional("key", {
|
|
1180
|
-
describe: "The variable name to be accessible in the script
|
|
1994
|
+
describe: "The variable name to be accessible in the script",
|
|
1181
1995
|
type: "string",
|
|
1182
1996
|
})
|
|
1183
1997
|
.option("name", {
|
|
1184
|
-
describe: "
|
|
1998
|
+
describe: "Name of the worker",
|
|
1185
1999
|
type: "string",
|
|
2000
|
+
requiresArg: true,
|
|
1186
2001
|
})
|
|
1187
2002
|
.option("env", {
|
|
1188
2003
|
type: "string",
|
|
2004
|
+
requiresArg: true,
|
|
1189
2005
|
describe:
|
|
1190
|
-
"Binds the secret to the
|
|
2006
|
+
"Binds the secret to the Worker of the specific environment",
|
|
2007
|
+
alias: "e",
|
|
1191
2008
|
});
|
|
1192
2009
|
},
|
|
1193
2010
|
async (args) => {
|
|
1194
|
-
const config = args.config as
|
|
2011
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
1195
2012
|
|
|
1196
|
-
|
|
1197
|
-
const scriptName = args.name || config.name;
|
|
2013
|
+
const scriptName = getLegacyScriptName(args, config);
|
|
1198
2014
|
if (!scriptName) {
|
|
1199
2015
|
throw new Error("Missing script name");
|
|
1200
2016
|
}
|
|
1201
2017
|
|
|
1202
|
-
|
|
1203
|
-
console.warn(
|
|
1204
|
-
"`wrangler secret delete` is a no-op in --local mode"
|
|
1205
|
-
);
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
if (!args.local) {
|
|
1209
|
-
// -- snip, extract --
|
|
1210
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1211
|
-
if (!loggedIn) {
|
|
1212
|
-
// didn't login, let's just quit
|
|
1213
|
-
console.log("Did not login, quitting...");
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
if (!config.account_id) {
|
|
1218
|
-
config.account_id = await getAccountId();
|
|
1219
|
-
if (!config.account_id) {
|
|
1220
|
-
throw new Error("No account id found, quitting...");
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
// -- snip, end --
|
|
1224
|
-
}
|
|
2018
|
+
const accountId = await requireAuth(config);
|
|
1225
2019
|
|
|
1226
2020
|
if (
|
|
1227
2021
|
await confirm(
|
|
1228
|
-
`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
|
+
}?`
|
|
1229
2027
|
)
|
|
1230
2028
|
) {
|
|
1231
|
-
|
|
1232
|
-
`🌀 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
|
+
}`
|
|
1233
2033
|
);
|
|
1234
2034
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
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`;
|
|
1238
2039
|
|
|
1239
|
-
await fetchResult(
|
|
1240
|
-
|
|
1241
|
-
{ method: "DELETE" }
|
|
1242
|
-
);
|
|
1243
|
-
console.log(`✨ Success! Deleted secret ${args.key}`);
|
|
2040
|
+
await fetchResult(`${url}/${args.key}`, { method: "DELETE" });
|
|
2041
|
+
logger.log(`✨ Success! Deleted secret ${args.key}`);
|
|
1244
2042
|
}
|
|
1245
2043
|
}
|
|
1246
2044
|
)
|
|
@@ -1250,59 +2048,34 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1250
2048
|
(yargs) => {
|
|
1251
2049
|
return yargs
|
|
1252
2050
|
.option("name", {
|
|
1253
|
-
describe: "
|
|
2051
|
+
describe: "Name of the worker",
|
|
1254
2052
|
type: "string",
|
|
2053
|
+
requiresArg: true,
|
|
1255
2054
|
})
|
|
1256
2055
|
.option("env", {
|
|
1257
2056
|
type: "string",
|
|
2057
|
+
requiresArg: true,
|
|
1258
2058
|
describe:
|
|
1259
|
-
"Binds the secret to the
|
|
2059
|
+
"Binds the secret to the Worker of the specific environment.",
|
|
2060
|
+
alias: "e",
|
|
1260
2061
|
});
|
|
1261
2062
|
},
|
|
1262
2063
|
async (args) => {
|
|
1263
|
-
const config = args.config as
|
|
2064
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
1264
2065
|
|
|
1265
|
-
|
|
1266
|
-
const scriptName = args.name || config.name;
|
|
2066
|
+
const scriptName = getLegacyScriptName(args, config);
|
|
1267
2067
|
if (!scriptName) {
|
|
1268
2068
|
throw new Error("Missing script name");
|
|
1269
2069
|
}
|
|
1270
2070
|
|
|
1271
|
-
|
|
1272
|
-
console.warn("`wrangler secret list` is a no-op in --local mode");
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
if (!args.local) {
|
|
1276
|
-
// -- snip, extract --
|
|
1277
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1278
|
-
if (!loggedIn) {
|
|
1279
|
-
// didn't login, let's just quit
|
|
1280
|
-
console.log("Did not login, quitting...");
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
if (!config.account_id) {
|
|
1285
|
-
config.account_id = await getAccountId();
|
|
1286
|
-
if (!config.account_id) {
|
|
1287
|
-
throw new Error("No account id found, quitting...");
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
// -- snip, end --
|
|
1291
|
-
}
|
|
2071
|
+
const accountId = await requireAuth(config);
|
|
1292
2072
|
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
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`;
|
|
1296
2077
|
|
|
1297
|
-
|
|
1298
|
-
JSON.stringify(
|
|
1299
|
-
await fetchResult(
|
|
1300
|
-
`/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
|
|
1301
|
-
),
|
|
1302
|
-
null,
|
|
1303
|
-
" "
|
|
1304
|
-
)
|
|
1305
|
-
);
|
|
2078
|
+
logger.log(JSON.stringify(await fetchResult(url), null, " "));
|
|
1306
2079
|
}
|
|
1307
2080
|
);
|
|
1308
2081
|
}
|
|
@@ -1315,6 +2088,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1315
2088
|
"🗂️ Interact with your Workers KV Namespaces",
|
|
1316
2089
|
(namespaceYargs) => {
|
|
1317
2090
|
return namespaceYargs
|
|
2091
|
+
.command(subHelp)
|
|
1318
2092
|
.command(
|
|
1319
2093
|
"create <namespace>",
|
|
1320
2094
|
"Create a new namespace",
|
|
@@ -1327,7 +2101,9 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1327
2101
|
})
|
|
1328
2102
|
.option("env", {
|
|
1329
2103
|
type: "string",
|
|
2104
|
+
requiresArg: true,
|
|
1330
2105
|
describe: "Perform on a specific environment",
|
|
2106
|
+
alias: "e",
|
|
1331
2107
|
})
|
|
1332
2108
|
.option("preview", {
|
|
1333
2109
|
type: "boolean",
|
|
@@ -1335,22 +2111,17 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1335
2111
|
});
|
|
1336
2112
|
},
|
|
1337
2113
|
async (args) => {
|
|
1338
|
-
|
|
1339
|
-
const extraArgs = args._.slice(2).join(" ");
|
|
1340
|
-
throw new CommandLineArgsError(
|
|
1341
|
-
`Unexpected additional positional arguments "${extraArgs}".`
|
|
1342
|
-
);
|
|
1343
|
-
}
|
|
2114
|
+
await printWranglerBanner();
|
|
1344
2115
|
|
|
1345
|
-
if (!
|
|
2116
|
+
if (!isValidKVNamespaceBinding(args.namespace)) {
|
|
1346
2117
|
throw new CommandLineArgsError(
|
|
1347
2118
|
`The namespace binding name "${args.namespace}" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number.`
|
|
1348
2119
|
);
|
|
1349
2120
|
}
|
|
1350
2121
|
|
|
1351
|
-
const config = args.config as
|
|
2122
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
1352
2123
|
if (!config.name) {
|
|
1353
|
-
|
|
2124
|
+
logger.warn(
|
|
1354
2125
|
"No configured name present, using `worker` as a prefix for the title"
|
|
1355
2126
|
);
|
|
1356
2127
|
}
|
|
@@ -1360,52 +2131,24 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1360
2131
|
const preview = args.preview ? "_preview" : "";
|
|
1361
2132
|
const title = `${name}${environment}-${args.namespace}${preview}`;
|
|
1362
2133
|
|
|
1363
|
-
|
|
1364
|
-
const { Miniflare } = await import("miniflare");
|
|
1365
|
-
const mf = new Miniflare({
|
|
1366
|
-
kvPersist: (args.kvPersist as string) || true,
|
|
1367
|
-
// TODO: these options shouldn't be required
|
|
1368
|
-
script: ` `, // has to be a string with at least one char
|
|
1369
|
-
});
|
|
1370
|
-
await mf.getKVNamespace(title); // this should "create" the namespace
|
|
1371
|
-
console.log(`✨ Success! Created KV namespace ${title}`);
|
|
1372
|
-
} else {
|
|
1373
|
-
// -- snip, extract --
|
|
1374
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1375
|
-
if (!loggedIn) {
|
|
1376
|
-
// didn't login, let's just quit
|
|
1377
|
-
console.log("Did not login, quitting...");
|
|
1378
|
-
return;
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
if (!config.account_id) {
|
|
1382
|
-
config.account_id = await getAccountId();
|
|
1383
|
-
if (!config.account_id) {
|
|
1384
|
-
throw new Error("No account id found, quitting...");
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
// -- snip, end --
|
|
2134
|
+
const accountId = await requireAuth(config);
|
|
1388
2135
|
|
|
1389
|
-
|
|
2136
|
+
// TODO: generate a binding name stripping non alphanumeric chars
|
|
1390
2137
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
config.account_id,
|
|
1394
|
-
title
|
|
1395
|
-
);
|
|
2138
|
+
logger.log(`🌀 Creating namespace with title "${title}"`);
|
|
2139
|
+
const namespaceId = await createKVNamespace(accountId, title);
|
|
1396
2140
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
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
|
+
);
|
|
1406
2150
|
|
|
1407
|
-
|
|
1408
|
-
}
|
|
2151
|
+
// TODO: automatically write this block to the wrangler.toml config file??
|
|
1409
2152
|
}
|
|
1410
2153
|
)
|
|
1411
2154
|
.command(
|
|
@@ -1413,39 +2156,15 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1413
2156
|
"Outputs a list of all KV namespaces associated with your account id.",
|
|
1414
2157
|
{},
|
|
1415
2158
|
async (args) => {
|
|
1416
|
-
const config = args.config as
|
|
1417
|
-
|
|
1418
|
-
if (args.local) {
|
|
1419
|
-
throw new NotImplementedError(
|
|
1420
|
-
`local mode is not yet supported for this command`
|
|
1421
|
-
);
|
|
1422
|
-
} else {
|
|
1423
|
-
// -- snip, extract --
|
|
1424
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1425
|
-
if (!loggedIn) {
|
|
1426
|
-
// didn't login, let's just quit
|
|
1427
|
-
console.log("Did not login, quitting...");
|
|
1428
|
-
return;
|
|
1429
|
-
}
|
|
2159
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
1430
2160
|
|
|
1431
|
-
|
|
1432
|
-
config.account_id = await getAccountId();
|
|
1433
|
-
if (!config.account_id) {
|
|
1434
|
-
throw new Error("No account id found, quitting...");
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
// -- snip, end --
|
|
2161
|
+
const accountId = await requireAuth(config);
|
|
1438
2162
|
|
|
1439
|
-
|
|
2163
|
+
// TODO: we should show bindings if they exist for given ids
|
|
1440
2164
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
null,
|
|
1445
|
-
" "
|
|
1446
|
-
)
|
|
1447
|
-
);
|
|
1448
|
-
}
|
|
2165
|
+
logger.log(
|
|
2166
|
+
JSON.stringify(await listKVNamespaces(accountId), null, " ")
|
|
2167
|
+
);
|
|
1449
2168
|
}
|
|
1450
2169
|
)
|
|
1451
2170
|
.command(
|
|
@@ -1455,16 +2174,20 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1455
2174
|
return yargs
|
|
1456
2175
|
.option("binding", {
|
|
1457
2176
|
type: "string",
|
|
2177
|
+
requiresArg: true,
|
|
1458
2178
|
describe: "The name of the namespace to delete",
|
|
1459
2179
|
})
|
|
1460
2180
|
.option("namespace-id", {
|
|
1461
2181
|
type: "string",
|
|
2182
|
+
requiresArg: true,
|
|
1462
2183
|
describe: "The id of the namespace to delete",
|
|
1463
2184
|
})
|
|
1464
2185
|
.check(demandOneOfOption("binding", "namespace-id"))
|
|
1465
2186
|
.option("env", {
|
|
1466
2187
|
type: "string",
|
|
2188
|
+
requiresArg: true,
|
|
1467
2189
|
describe: "Perform on a specific environment",
|
|
2190
|
+
alias: "e",
|
|
1468
2191
|
})
|
|
1469
2192
|
.option("preview", {
|
|
1470
2193
|
type: "boolean",
|
|
@@ -1472,61 +2195,39 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1472
2195
|
});
|
|
1473
2196
|
},
|
|
1474
2197
|
async (args) => {
|
|
1475
|
-
|
|
2198
|
+
await printWranglerBanner();
|
|
2199
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
1476
2200
|
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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)
|
|
1480
2207
|
);
|
|
1481
|
-
}
|
|
1482
|
-
let id;
|
|
1483
|
-
try {
|
|
1484
|
-
id = getNamespaceId(args);
|
|
1485
|
-
} catch (e) {
|
|
1486
|
-
throw new CommandLineArgsError(
|
|
1487
|
-
"Not able to delete namespace.\n" + e.message
|
|
1488
|
-
);
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
// -- snip, extract --
|
|
1492
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1493
|
-
if (!loggedIn) {
|
|
1494
|
-
// didn't login, let's just quit
|
|
1495
|
-
console.log("Did not login, quitting...");
|
|
1496
|
-
return;
|
|
1497
|
-
}
|
|
2208
|
+
}
|
|
1498
2209
|
|
|
1499
|
-
|
|
1500
|
-
config.account_id = await getAccountId();
|
|
1501
|
-
if (!config.account_id) {
|
|
1502
|
-
throw new Error("No account id found, quitting...");
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
// -- snip, end --
|
|
2210
|
+
const accountId = await requireAuth(config);
|
|
1506
2211
|
|
|
1507
|
-
|
|
1508
|
-
`/accounts/${config.account_id}/storage/kv/namespaces/${id}`,
|
|
1509
|
-
{ method: "DELETE" }
|
|
1510
|
-
);
|
|
2212
|
+
await deleteKVNamespace(accountId, id);
|
|
1511
2213
|
|
|
1512
|
-
|
|
2214
|
+
// TODO: recommend they remove it from wrangler.toml
|
|
1513
2215
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
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
|
|
1525
2227
|
|
|
1526
|
-
|
|
2228
|
+
// TODO: do it automatically
|
|
1527
2229
|
|
|
1528
|
-
|
|
1529
|
-
}
|
|
2230
|
+
// TODO: delete the preview namespace as well?
|
|
1530
2231
|
}
|
|
1531
2232
|
);
|
|
1532
2233
|
}
|
|
@@ -1538,6 +2239,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1538
2239
|
"🔑 Individually manage Workers KV key-value pairs",
|
|
1539
2240
|
(kvKeyYargs) => {
|
|
1540
2241
|
return kvKeyYargs
|
|
2242
|
+
.command(subHelp)
|
|
1541
2243
|
.command(
|
|
1542
2244
|
"put <key> [value]",
|
|
1543
2245
|
"Writes a single key/value pair to the given namespace.",
|
|
@@ -1545,25 +2247,29 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1545
2247
|
return yargs
|
|
1546
2248
|
.positional("key", {
|
|
1547
2249
|
type: "string",
|
|
1548
|
-
describe: "The key to write to
|
|
2250
|
+
describe: "The key to write to",
|
|
1549
2251
|
demandOption: true,
|
|
1550
2252
|
})
|
|
1551
2253
|
.positional("value", {
|
|
1552
2254
|
type: "string",
|
|
1553
|
-
describe: "The value to write
|
|
2255
|
+
describe: "The value to write",
|
|
1554
2256
|
})
|
|
1555
2257
|
.option("binding", {
|
|
1556
2258
|
type: "string",
|
|
1557
|
-
|
|
2259
|
+
requiresArg: true,
|
|
2260
|
+
describe: "The binding of the namespace to write to",
|
|
1558
2261
|
})
|
|
1559
2262
|
.option("namespace-id", {
|
|
1560
2263
|
type: "string",
|
|
1561
|
-
|
|
2264
|
+
requiresArg: true,
|
|
2265
|
+
describe: "The id of the namespace to write to",
|
|
1562
2266
|
})
|
|
1563
2267
|
.check(demandOneOfOption("binding", "namespace-id"))
|
|
1564
2268
|
.option("env", {
|
|
1565
2269
|
type: "string",
|
|
2270
|
+
requiresArg: true,
|
|
1566
2271
|
describe: "Perform on a specific environment",
|
|
2272
|
+
alias: "e",
|
|
1567
2273
|
})
|
|
1568
2274
|
.option("preview", {
|
|
1569
2275
|
type: "boolean",
|
|
@@ -1571,7 +2277,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1571
2277
|
})
|
|
1572
2278
|
.option("ttl", {
|
|
1573
2279
|
type: "number",
|
|
1574
|
-
describe: "Time for which the entries should be visible
|
|
2280
|
+
describe: "Time for which the entries should be visible",
|
|
1575
2281
|
})
|
|
1576
2282
|
.option("expiration", {
|
|
1577
2283
|
type: "number",
|
|
@@ -1580,60 +2286,39 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1580
2286
|
})
|
|
1581
2287
|
.option("path", {
|
|
1582
2288
|
type: "string",
|
|
1583
|
-
|
|
2289
|
+
requiresArg: true,
|
|
2290
|
+
describe: "Read value from the file at a given path",
|
|
1584
2291
|
})
|
|
1585
2292
|
.check(demandOneOfOption("value", "path"));
|
|
1586
2293
|
},
|
|
1587
2294
|
async ({ key, ttl, expiration, ...args }) => {
|
|
1588
|
-
|
|
2295
|
+
await printWranglerBanner();
|
|
2296
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
2297
|
+
const namespaceId = getKVNamespaceId(args, config);
|
|
1589
2298
|
// One of `args.path` and `args.value` must be defined
|
|
1590
2299
|
const value = args.path
|
|
1591
|
-
?
|
|
2300
|
+
? readFileSyncToBuffer(args.path)
|
|
1592
2301
|
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1593
2302
|
args.value!;
|
|
1594
|
-
const config = args.config as Config;
|
|
1595
2303
|
|
|
1596
2304
|
if (args.path) {
|
|
1597
|
-
|
|
1598
|
-
`
|
|
2305
|
+
logger.log(
|
|
2306
|
+
`Writing the contents of ${args.path} to the key "${key}" on namespace ${namespaceId}.`
|
|
1599
2307
|
);
|
|
1600
2308
|
} else {
|
|
1601
|
-
|
|
1602
|
-
`
|
|
2309
|
+
logger.log(
|
|
2310
|
+
`Writing the value "${value}" to key "${key}" on namespace ${namespaceId}.`
|
|
1603
2311
|
);
|
|
1604
2312
|
}
|
|
1605
2313
|
|
|
1606
|
-
|
|
1607
|
-
const { Miniflare } = await import("miniflare");
|
|
1608
|
-
const mf = new Miniflare({
|
|
1609
|
-
kvPersist: (args.kvPersist as string) || true,
|
|
1610
|
-
// TODO: these options shouldn't be required
|
|
1611
|
-
script: ` `, // has to be a string with at least one char
|
|
1612
|
-
});
|
|
1613
|
-
const ns = await mf.getKVNamespace(namespaceId);
|
|
1614
|
-
await ns.put(key, value, { expiration, expirationTtl: ttl });
|
|
1615
|
-
} else {
|
|
1616
|
-
// -- snip, extract --
|
|
1617
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1618
|
-
if (!loggedIn) {
|
|
1619
|
-
// didn't login, let's just quit
|
|
1620
|
-
console.log("Did not login, quitting...");
|
|
1621
|
-
return;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
if (!config.account_id) {
|
|
1625
|
-
config.account_id = await getAccountId();
|
|
1626
|
-
if (!config.account_id) {
|
|
1627
|
-
throw new Error("No account id found, quitting...");
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
// -- snip, end --
|
|
2314
|
+
const accountId = await requireAuth(config);
|
|
1631
2315
|
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
2316
|
+
await putKVKeyValue(accountId, namespaceId, {
|
|
2317
|
+
key,
|
|
2318
|
+
value,
|
|
2319
|
+
expiration,
|
|
2320
|
+
expiration_ttl: ttl,
|
|
2321
|
+
});
|
|
1637
2322
|
}
|
|
1638
2323
|
)
|
|
1639
2324
|
.command(
|
|
@@ -1643,16 +2328,20 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1643
2328
|
return yargs
|
|
1644
2329
|
.option("binding", {
|
|
1645
2330
|
type: "string",
|
|
2331
|
+
requiresArg: true,
|
|
1646
2332
|
describe: "The name of the namespace to list",
|
|
1647
2333
|
})
|
|
1648
2334
|
.option("namespace-id", {
|
|
1649
2335
|
type: "string",
|
|
2336
|
+
requiresArg: true,
|
|
1650
2337
|
describe: "The id of the namespace to list",
|
|
1651
2338
|
})
|
|
1652
2339
|
.check(demandOneOfOption("binding", "namespace-id"))
|
|
1653
2340
|
.option("env", {
|
|
1654
2341
|
type: "string",
|
|
2342
|
+
requiresArg: true,
|
|
1655
2343
|
describe: "Perform on a specific environment",
|
|
2344
|
+
alias: "e",
|
|
1656
2345
|
})
|
|
1657
2346
|
.option("preview", {
|
|
1658
2347
|
type: "boolean",
|
|
@@ -1662,49 +2351,23 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1662
2351
|
})
|
|
1663
2352
|
.option("prefix", {
|
|
1664
2353
|
type: "string",
|
|
2354
|
+
requiresArg: true,
|
|
1665
2355
|
describe: "A prefix to filter listed keys",
|
|
1666
2356
|
});
|
|
1667
2357
|
},
|
|
1668
2358
|
async ({ prefix, ...args }) => {
|
|
1669
2359
|
// TODO: support for limit+cursor (pagination)
|
|
2360
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
2361
|
+
const namespaceId = getKVNamespaceId(args, config);
|
|
1670
2362
|
|
|
1671
|
-
const
|
|
1672
|
-
const config = args.config as Config;
|
|
2363
|
+
const accountId = await requireAuth(config);
|
|
1673
2364
|
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
});
|
|
1681
|
-
const ns = await mf.getKVNamespace(namespaceId);
|
|
1682
|
-
const listResponse = await ns.list({ prefix });
|
|
1683
|
-
console.log(JSON.stringify(listResponse.keys, null, " ")); // TODO: paginate, collate
|
|
1684
|
-
} else {
|
|
1685
|
-
// -- snip, extract --
|
|
1686
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1687
|
-
if (!loggedIn) {
|
|
1688
|
-
// didn't login, let's just quit
|
|
1689
|
-
console.log("Did not login, quitting...");
|
|
1690
|
-
return;
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
if (!config.account_id) {
|
|
1694
|
-
config.account_id = await getAccountId();
|
|
1695
|
-
if (!config.account_id) {
|
|
1696
|
-
throw new Error("No account id found, quitting...");
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
// -- snip, end --
|
|
1700
|
-
|
|
1701
|
-
const results = await listNamespaceKeys(
|
|
1702
|
-
config.account_id,
|
|
1703
|
-
namespaceId,
|
|
1704
|
-
prefix
|
|
1705
|
-
);
|
|
1706
|
-
console.log(JSON.stringify(results, undefined, 2));
|
|
1707
|
-
}
|
|
2365
|
+
const results = await listKVNamespaceKeys(
|
|
2366
|
+
accountId,
|
|
2367
|
+
namespaceId,
|
|
2368
|
+
prefix
|
|
2369
|
+
);
|
|
2370
|
+
logger.log(JSON.stringify(results, undefined, 2));
|
|
1708
2371
|
}
|
|
1709
2372
|
)
|
|
1710
2373
|
.command(
|
|
@@ -1719,16 +2382,20 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1719
2382
|
})
|
|
1720
2383
|
.option("binding", {
|
|
1721
2384
|
type: "string",
|
|
2385
|
+
requiresArg: true,
|
|
1722
2386
|
describe: "The name of the namespace to get from",
|
|
1723
2387
|
})
|
|
1724
2388
|
.option("namespace-id", {
|
|
1725
2389
|
type: "string",
|
|
2390
|
+
requiresArg: true,
|
|
1726
2391
|
describe: "The id of the namespace to get from",
|
|
1727
2392
|
})
|
|
1728
2393
|
.check(demandOneOfOption("binding", "namespace-id"))
|
|
1729
2394
|
.option("env", {
|
|
1730
2395
|
type: "string",
|
|
2396
|
+
requiresArg: true,
|
|
1731
2397
|
describe: "Perform on a specific environment",
|
|
2398
|
+
alias: "e",
|
|
1732
2399
|
})
|
|
1733
2400
|
.option("preview", {
|
|
1734
2401
|
type: "boolean",
|
|
@@ -1742,43 +2409,13 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1742
2409
|
});
|
|
1743
2410
|
},
|
|
1744
2411
|
async ({ key, ...args }) => {
|
|
1745
|
-
const
|
|
1746
|
-
const
|
|
1747
|
-
|
|
1748
|
-
if (args.local) {
|
|
1749
|
-
const { Miniflare } = await import("miniflare");
|
|
1750
|
-
const mf = new Miniflare({
|
|
1751
|
-
kvPersist: (args.kvPersist as string) || true,
|
|
1752
|
-
// TODO: these options shouldn't be required
|
|
1753
|
-
script: ` `, // has to be a string with at least one char
|
|
1754
|
-
});
|
|
1755
|
-
const ns = await mf.getKVNamespace(namespaceId);
|
|
1756
|
-
console.log(await ns.get(key));
|
|
1757
|
-
return;
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
if (!args.local) {
|
|
1761
|
-
// -- snip, extract --
|
|
1762
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1763
|
-
if (!loggedIn) {
|
|
1764
|
-
// didn't login, let's just quit
|
|
1765
|
-
console.log("Did not login, quitting...");
|
|
1766
|
-
return;
|
|
1767
|
-
}
|
|
2412
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
2413
|
+
const namespaceId = getKVNamespaceId(args, config);
|
|
1768
2414
|
|
|
1769
|
-
|
|
1770
|
-
config.account_id = await getAccountId();
|
|
1771
|
-
if (!config.account_id) {
|
|
1772
|
-
throw new Error("No account id found, quitting...");
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
// -- snip, end --
|
|
1776
|
-
}
|
|
2415
|
+
const accountId = await requireAuth(config);
|
|
1777
2416
|
|
|
1778
|
-
|
|
1779
|
-
await
|
|
1780
|
-
`/accounts/${config.account_id}/storage/kv/namespaces/${namespaceId}/values/${key}`
|
|
1781
|
-
)
|
|
2417
|
+
process.stdout.write(
|
|
2418
|
+
Buffer.from(await getKVKeyValue(accountId, namespaceId, key))
|
|
1782
2419
|
);
|
|
1783
2420
|
}
|
|
1784
2421
|
)
|
|
@@ -1794,16 +2431,20 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1794
2431
|
})
|
|
1795
2432
|
.option("binding", {
|
|
1796
2433
|
type: "string",
|
|
2434
|
+
requiresArg: true,
|
|
1797
2435
|
describe: "The name of the namespace to delete from",
|
|
1798
2436
|
})
|
|
1799
2437
|
.option("namespace-id", {
|
|
1800
2438
|
type: "string",
|
|
2439
|
+
requiresArg: true,
|
|
1801
2440
|
describe: "The id of the namespace to delete from",
|
|
1802
2441
|
})
|
|
1803
2442
|
.check(demandOneOfOption("binding", "namespace-id"))
|
|
1804
2443
|
.option("env", {
|
|
1805
2444
|
type: "string",
|
|
2445
|
+
requiresArg: true,
|
|
1806
2446
|
describe: "Perform on a specific environment",
|
|
2447
|
+
alias: "e",
|
|
1807
2448
|
})
|
|
1808
2449
|
.option("preview", {
|
|
1809
2450
|
type: "boolean",
|
|
@@ -1811,48 +2452,17 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1811
2452
|
});
|
|
1812
2453
|
},
|
|
1813
2454
|
async ({ key, ...args }) => {
|
|
1814
|
-
|
|
2455
|
+
await printWranglerBanner();
|
|
2456
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
2457
|
+
const namespaceId = getKVNamespaceId(args, config);
|
|
1815
2458
|
|
|
1816
|
-
|
|
1817
|
-
`
|
|
2459
|
+
logger.log(
|
|
2460
|
+
`Deleting the key "${key}" on namespace ${namespaceId}.`
|
|
1818
2461
|
);
|
|
1819
2462
|
|
|
1820
|
-
|
|
1821
|
-
const { Miniflare } = await import("miniflare");
|
|
1822
|
-
const mf = new Miniflare({
|
|
1823
|
-
kvPersist: (args.kvPersist as string) || true,
|
|
1824
|
-
// TODO: these options shouldn't be required
|
|
1825
|
-
script: ` `, // has to be a string with at least one char
|
|
1826
|
-
});
|
|
1827
|
-
const ns = await mf.getKVNamespace(namespaceId);
|
|
1828
|
-
console.log(await ns.delete(key));
|
|
1829
|
-
return;
|
|
1830
|
-
}
|
|
1831
|
-
|
|
1832
|
-
const config = args.config as Config;
|
|
1833
|
-
|
|
1834
|
-
if (!args.local) {
|
|
1835
|
-
// -- snip, extract --
|
|
1836
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1837
|
-
if (!loggedIn) {
|
|
1838
|
-
// didn't login, let's just quit
|
|
1839
|
-
console.log("Did not login, quitting...");
|
|
1840
|
-
return;
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
if (!config.account_id) {
|
|
1844
|
-
config.account_id = await getAccountId();
|
|
1845
|
-
if (!config.account_id) {
|
|
1846
|
-
throw new Error("No account id found, quitting...");
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
// -- snip, end --
|
|
1850
|
-
}
|
|
2463
|
+
const accountId = await requireAuth(config);
|
|
1851
2464
|
|
|
1852
|
-
await
|
|
1853
|
-
`/accounts/${config.account_id}/storage/kv/namespaces/${namespaceId}/values/${key}`,
|
|
1854
|
-
{ method: "DELETE" }
|
|
1855
|
-
);
|
|
2465
|
+
await deleteKVKeyValue(accountId, namespaceId, key);
|
|
1856
2466
|
}
|
|
1857
2467
|
);
|
|
1858
2468
|
}
|
|
@@ -1864,6 +2474,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1864
2474
|
"💪 Interact with multiple Workers KV key-value pairs at once",
|
|
1865
2475
|
(kvBulkYargs) => {
|
|
1866
2476
|
return kvBulkYargs
|
|
2477
|
+
.command(subHelp)
|
|
1867
2478
|
.command(
|
|
1868
2479
|
"put <filename>",
|
|
1869
2480
|
"Upload multiple key-value pairs to a namespace",
|
|
@@ -1876,16 +2487,20 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1876
2487
|
})
|
|
1877
2488
|
.option("binding", {
|
|
1878
2489
|
type: "string",
|
|
1879
|
-
|
|
2490
|
+
requiresArg: true,
|
|
2491
|
+
describe: "The name of the namespace to insert values into",
|
|
1880
2492
|
})
|
|
1881
2493
|
.option("namespace-id", {
|
|
1882
2494
|
type: "string",
|
|
1883
|
-
|
|
2495
|
+
requiresArg: true,
|
|
2496
|
+
describe: "The id of the namespace to insert values into",
|
|
1884
2497
|
})
|
|
1885
2498
|
.check(demandOneOfOption("binding", "namespace-id"))
|
|
1886
2499
|
.option("env", {
|
|
1887
2500
|
type: "string",
|
|
2501
|
+
requiresArg: true,
|
|
1888
2502
|
describe: "Perform on a specific environment",
|
|
2503
|
+
alias: "e",
|
|
1889
2504
|
})
|
|
1890
2505
|
.option("preview", {
|
|
1891
2506
|
type: "boolean",
|
|
@@ -1893,62 +2508,67 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1893
2508
|
});
|
|
1894
2509
|
},
|
|
1895
2510
|
async ({ filename, ...args }) => {
|
|
2511
|
+
await printWranglerBanner();
|
|
1896
2512
|
// The simplest implementation I could think of.
|
|
1897
2513
|
// This could be made more efficient with a streaming parser/uploader
|
|
1898
2514
|
// but we'll do that in the future if needed.
|
|
1899
2515
|
|
|
1900
|
-
const
|
|
1901
|
-
const
|
|
1902
|
-
const content =
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
parsedContent = JSON.parse(content);
|
|
1906
|
-
} 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)) {
|
|
1907
2521
|
throw new Error(
|
|
1908
|
-
`
|
|
2522
|
+
`Unexpected JSON input from "${filename}".\n` +
|
|
2523
|
+
`Expected an array of key-value objects but got type "${typeof content}".`
|
|
1909
2524
|
);
|
|
1910
2525
|
}
|
|
1911
2526
|
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
expirationTtl: expiration_ttl,
|
|
1929
|
-
});
|
|
1930
|
-
}
|
|
1931
|
-
} else {
|
|
1932
|
-
// -- snip, extract --
|
|
1933
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
1934
|
-
if (!loggedIn) {
|
|
1935
|
-
// didn't login, let's just quit
|
|
1936
|
-
console.log("Did not login, quitting...");
|
|
1937
|
-
return;
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
if (!config.account_id) {
|
|
1941
|
-
config.account_id = await getAccountId();
|
|
1942
|
-
if (!config.account_id) {
|
|
1943
|
-
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
|
+
);
|
|
1944
2543
|
}
|
|
1945
2544
|
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
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")
|
|
1950
2565
|
);
|
|
1951
2566
|
}
|
|
2567
|
+
|
|
2568
|
+
const accountId = await requireAuth(config);
|
|
2569
|
+
await putKVBulkKeyValue(accountId, namespaceId, content);
|
|
2570
|
+
|
|
2571
|
+
logger.log("Success!");
|
|
1952
2572
|
}
|
|
1953
2573
|
)
|
|
1954
2574
|
.command(
|
|
@@ -1963,116 +2583,325 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1963
2583
|
})
|
|
1964
2584
|
.option("binding", {
|
|
1965
2585
|
type: "string",
|
|
2586
|
+
requiresArg: true,
|
|
1966
2587
|
describe: "The name of the namespace to delete from",
|
|
1967
2588
|
})
|
|
1968
2589
|
.option("namespace-id", {
|
|
1969
2590
|
type: "string",
|
|
2591
|
+
requiresArg: true,
|
|
1970
2592
|
describe: "The id of the namespace to delete from",
|
|
1971
2593
|
})
|
|
1972
2594
|
.check(demandOneOfOption("binding", "namespace-id"))
|
|
1973
2595
|
.option("env", {
|
|
1974
2596
|
type: "string",
|
|
2597
|
+
requiresArg: true,
|
|
1975
2598
|
describe: "Perform on a specific environment",
|
|
2599
|
+
alias: "e",
|
|
1976
2600
|
})
|
|
1977
2601
|
.option("preview", {
|
|
1978
2602
|
type: "boolean",
|
|
1979
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",
|
|
1980
2609
|
});
|
|
1981
2610
|
},
|
|
1982
2611
|
async ({ filename, ...args }) => {
|
|
1983
|
-
|
|
1984
|
-
const config = args.config as
|
|
1985
|
-
const
|
|
1986
|
-
let parsedContent;
|
|
1987
|
-
try {
|
|
1988
|
-
parsedContent = JSON.parse(content);
|
|
1989
|
-
} catch (err) {
|
|
1990
|
-
throw new Error(
|
|
1991
|
-
`Could not parse json from ${filename}.\n${err.message ?? err}`
|
|
1992
|
-
);
|
|
1993
|
-
}
|
|
2612
|
+
await printWranglerBanner();
|
|
2613
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
2614
|
+
const namespaceId = getKVNamespaceId(args, config);
|
|
1994
2615
|
|
|
1995
|
-
if (args.
|
|
1996
|
-
const
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
});
|
|
2002
|
-
const ns = await mf.getKVNamespace(namespaceId);
|
|
2003
|
-
for (const key of parsedContent) {
|
|
2004
|
-
await ns.delete(key);
|
|
2005
|
-
}
|
|
2006
|
-
} else {
|
|
2007
|
-
// -- snip, extract --
|
|
2008
|
-
const loggedIn = await loginOrRefreshIfRequired();
|
|
2009
|
-
if (!loggedIn) {
|
|
2010
|
-
// didn't login, let's just quit
|
|
2011
|
-
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}".`);
|
|
2012
2622
|
return;
|
|
2013
2623
|
}
|
|
2624
|
+
}
|
|
2014
2625
|
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
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
|
+
);
|
|
2020
2647
|
}
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
content
|
|
2028
|
-
)
|
|
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")
|
|
2029
2654
|
);
|
|
2030
2655
|
}
|
|
2656
|
+
|
|
2657
|
+
const accountId = await requireAuth(config);
|
|
2658
|
+
|
|
2659
|
+
await deleteKVBulkKeyValue(accountId, namespaceId, content);
|
|
2660
|
+
|
|
2661
|
+
logger.log("Success!");
|
|
2031
2662
|
}
|
|
2032
2663
|
);
|
|
2033
2664
|
}
|
|
2034
2665
|
);
|
|
2035
2666
|
|
|
2036
|
-
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);
|
|
2037
2693
|
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
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
|
+
});
|
|
2053
2818
|
|
|
2054
2819
|
wrangler.group(["config", "help", "version"], "Flags:");
|
|
2055
2820
|
wrangler.help().alias("h", "help");
|
|
2056
2821
|
wrangler.version(wranglerVersion).alias("v", "version");
|
|
2057
2822
|
wrangler.exitProcess(false);
|
|
2058
2823
|
|
|
2059
|
-
|
|
2824
|
+
return wrangler;
|
|
2825
|
+
}
|
|
2060
2826
|
|
|
2827
|
+
export async function main(argv: string[]): Promise<void> {
|
|
2828
|
+
const wrangler = createCLIParser(argv);
|
|
2061
2829
|
try {
|
|
2062
2830
|
await wrangler.parse();
|
|
2063
2831
|
} catch (e) {
|
|
2832
|
+
logger.log(""); // Just adds a bit of space
|
|
2064
2833
|
if (e instanceof CommandLineArgsError) {
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
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));
|
|
2068
2844
|
} else {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
console.error(
|
|
2845
|
+
logger.error(e instanceof Error ? e.message : e);
|
|
2846
|
+
logger.log(
|
|
2072
2847
|
`${fgGreenColor}%s${resetColor}`,
|
|
2073
|
-
"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"
|
|
2074
2849
|
);
|
|
2075
2850
|
}
|
|
2076
2851
|
throw e;
|
|
2077
2852
|
}
|
|
2078
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
|
+
}
|