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