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