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