wrangler 0.0.13 → 0.0.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "author": "wrangler@cloudflare.com",
5
5
  "description": "Command-line interface for all things Cloudflare Workers",
6
6
  "bin": {
@@ -72,6 +72,7 @@
72
72
  "ink-table": "^3.0.0",
73
73
  "ink-testing-library": "^2.1.0",
74
74
  "ink-text-input": "^4.0.2",
75
+ "jest-fetch-mock": "^3.0.3",
75
76
  "mime": "^3.0.0",
76
77
  "node-fetch": "3.1.1",
77
78
  "open": "^8.4.0",
@@ -44,6 +44,7 @@ function renderDev({
44
44
  compatibilityFlags,
45
45
  usageModel,
46
46
  buildCommand = {},
47
+ enableLocalPersistence = false,
47
48
  }: Partial<DevProps>) {
48
49
  return render(
49
50
  <Dev
@@ -62,6 +63,7 @@ function renderDev({
62
63
  compatibilityFlags={compatibilityFlags}
63
64
  usageModel={usageModel}
64
65
  bindings={bindings}
66
+ enableLocalPersistence={enableLocalPersistence}
65
67
  />
66
68
  );
67
69
  }
@@ -1,6 +1,13 @@
1
1
  import { mockFetchInternal } from "./mock-cfetch";
2
2
  import { confirm, prompt } from "../dialogs";
3
3
  import { fetchInternal } from "../cfetch/internal";
4
+ import fetchMock from "jest-fetch-mock";
5
+
6
+ jest.mock("node-fetch", () => jest.requireActual("jest-fetch-mock"));
7
+ fetchMock.doMock(() => {
8
+ // Any un-mocked fetches should throw
9
+ throw new Error("Unexpected fetch request");
10
+ });
4
11
 
5
12
  jest.mock("../cfetch/internal");
6
13
  (fetchInternal as jest.Mock).mockImplementation(mockFetchInternal);
@@ -0,0 +1,64 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import fetchMock from "jest-fetch-mock";
5
+ import { runWrangler } from "./run-wrangler";
6
+ import { runInTempDir } from "./run-in-tmp";
7
+ import { initialise } from "../user";
8
+ import { mockConsoleMethods } from "./mock-console";
9
+ import { writeUserConfig } from "./whoami.test";
10
+
11
+ const ORIGINAL_CF_API_TOKEN = process.env.CF_API_TOKEN;
12
+ const ORIGINAL_CF_ACCOUNT_ID = process.env.CF_ACCOUNT_ID;
13
+
14
+ describe("wrangler", () => {
15
+ runInTempDir({ homedir: "./home" });
16
+ const std = mockConsoleMethods();
17
+
18
+ beforeEach(() => {
19
+ delete process.env.CF_API_TOKEN;
20
+ delete process.env.CF_ACCOUNT_ID;
21
+ });
22
+
23
+ afterEach(() => {
24
+ // Reset any changes to the environment variables
25
+ process.env.CF_API_TOKEN = ORIGINAL_CF_API_TOKEN;
26
+ process.env.CF_ACCOUNT_ID = ORIGINAL_CF_ACCOUNT_ID;
27
+ });
28
+
29
+ describe("logout", () => {
30
+ it("should exit with a message stating the user is not logged in", async () => {
31
+ await initialise();
32
+ await runWrangler("logout");
33
+ expect(std.out).toMatchInlineSnapshot(`"Not logged in, exiting..."`);
34
+ });
35
+
36
+ it("should logout user that has been properly logged in", async () => {
37
+ writeUserConfig("some-oauth-tok", "some-refresh-tok");
38
+
39
+ // Mock out the response for a request to revoke the auth tokens,
40
+ // checking the form of the request is as expected.
41
+ fetchMock.mockResponseOnce(async (req) => {
42
+ expect(req.url).toEqual("https://dash.cloudflare.com/oauth2/revoke");
43
+ expect(req.method).toEqual("POST");
44
+ return "";
45
+ });
46
+
47
+ await initialise();
48
+ await runWrangler("logout");
49
+
50
+ expect(std.out).toMatchInlineSnapshot(`
51
+ "💁 Wrangler is configured with an OAuth token. The token has been successfully revoked
52
+ Removing ./home/.wrangler/config/default.toml.. success!"
53
+ `);
54
+
55
+ // Make sure that we made the request to logout.
56
+ expect(fetchMock).toHaveBeenCalledTimes(1);
57
+
58
+ // Make sure that logout removed the config file containing the auth tokens.
59
+ expect(
60
+ existsSync(path.join(os.homedir(), ".wrangler/config/default.toml"))
61
+ ).toBe(false);
62
+ });
63
+ });
64
+ });
@@ -748,6 +748,37 @@ describe("publish", () => {
748
748
  );
749
749
  });
750
750
  });
751
+
752
+ describe("custom builds", () => {
753
+ it("should run a custom build before publishing", async () => {
754
+ writeWranglerToml({
755
+ build: {
756
+ command: `echo "custom build" && echo "export default { fetch(){ return new Response(123)} }" > index.js`,
757
+ },
758
+ });
759
+
760
+ mockUploadWorkerRequest({
761
+ expectedBody: "return new Response(123)",
762
+ });
763
+ mockSubDomainRequest();
764
+
765
+ await runWrangler("publish index.js");
766
+ expect(stripTimings(std.out)).toMatchInlineSnapshot(`
767
+ "running:
768
+ echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123)} }\\" > index.js
769
+ Uploaded
770
+ test-name
771
+ (TIMINGS)
772
+ Deployed
773
+ test-name
774
+ (TIMINGS)
775
+
776
+ test-name.test-sub-domain.workers.dev"
777
+ `);
778
+ expect(std.err).toMatchInlineSnapshot(`""`);
779
+ expect(std.warn).toMatchInlineSnapshot(`""`);
780
+ });
781
+ });
751
782
  });
752
783
 
753
784
  /** Write a mock wrangler.toml file to disk. */
@@ -0,0 +1,206 @@
1
+ import { setMockResponse, unsetAllMocks } from "./mock-cfetch";
2
+ import { runWrangler } from "./run-wrangler";
3
+ import { runInTempDir } from "./run-in-tmp";
4
+ import { mockConfirm, mockPrompt } from "./mock-dialogs";
5
+ import { mockConsoleMethods } from "./mock-console";
6
+
7
+ describe("wrangler secret", () => {
8
+ const std = mockConsoleMethods();
9
+ runInTempDir();
10
+ afterEach(() => {
11
+ unsetAllMocks();
12
+ });
13
+
14
+ describe("put", () => {
15
+ function mockPutRequest(input: { name: string; text: string }) {
16
+ setMockResponse(
17
+ "/accounts/:accountId/workers/scripts/:scriptName/secrets",
18
+ "PUT",
19
+ ([_url, accountId], { body }) => {
20
+ expect(accountId).toEqual("some-account-id");
21
+ const { name, text, type } = JSON.parse(body as string);
22
+ expect(type).toEqual("secret_text");
23
+ expect(name).toEqual(input.name);
24
+ expect(text).toEqual(input.text);
25
+
26
+ return { name, type };
27
+ }
28
+ );
29
+ }
30
+
31
+ it("should create a secret", async () => {
32
+ mockPrompt({
33
+ text: "Enter a secret value:",
34
+ type: "password",
35
+ result: "the-secret",
36
+ });
37
+
38
+ mockPutRequest({ name: "the-secret-name", text: "the-secret" });
39
+ await runWrangler("secret put the-key --name script-name");
40
+
41
+ expect(std.out).toMatchInlineSnapshot(`
42
+ "🌀 Creating the secret for script script-name
43
+ ✨ Success! Uploaded secret the-key"
44
+ `);
45
+ expect(std.err).toMatchInlineSnapshot(`""`);
46
+ });
47
+
48
+ it("should error without a script name", async () => {
49
+ let error: Error | undefined;
50
+ try {
51
+ await runWrangler("secret put the-key");
52
+ } catch (e) {
53
+ error = e;
54
+ }
55
+ expect(std.out).toMatchInlineSnapshot(`""`);
56
+ expect(std.err).toMatchInlineSnapshot(`
57
+ "Missing script name
58
+
59
+ %s
60
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
61
+ `);
62
+ expect(error).toMatchInlineSnapshot(`[Error: Missing script name]`);
63
+ });
64
+
65
+ it("warns about being a no-op in local mode", async () => {
66
+ mockPrompt({
67
+ text: "Enter a secret value:",
68
+ type: "password",
69
+ result: "the-secret",
70
+ });
71
+
72
+ mockPutRequest({ name: "the-secret-name", text: "the-secret" });
73
+ await runWrangler("secret put the-key --name script-name --local");
74
+ expect(std.out).toMatchInlineSnapshot(`""`);
75
+ expect(std.err).toMatchInlineSnapshot(`""`);
76
+ expect(std.warn).toMatchInlineSnapshot(
77
+ `"\`wrangler secret put\` is a no-op in --local mode"`
78
+ );
79
+ });
80
+ });
81
+
82
+ describe("delete", () => {
83
+ function mockDeleteRequest(input: {
84
+ scriptName: string;
85
+ secretName: string;
86
+ }) {
87
+ setMockResponse(
88
+ "/accounts/:accountId/workers/scripts/:scriptName/secrets/:secretName",
89
+ "DELETE",
90
+ ([_url, accountId, scriptName, secretName]) => {
91
+ expect(accountId).toEqual("some-account-id");
92
+ expect(scriptName).toEqual(input.scriptName);
93
+ expect(secretName).toEqual(input.secretName);
94
+
95
+ return null;
96
+ }
97
+ );
98
+ }
99
+ it("should delete a secret", async () => {
100
+ mockDeleteRequest({ scriptName: "script-name", secretName: "the-key" });
101
+ mockConfirm({
102
+ text: "Are you sure you want to permanently delete the variable the-key on the script script-name?",
103
+ result: true,
104
+ });
105
+ await runWrangler("secret delete the-key --name script-name");
106
+ expect(std.out).toMatchInlineSnapshot(`
107
+ "🌀 Deleting the secret the-key on script script-name.
108
+ ✨ Success! Deleted secret the-key"
109
+ `);
110
+ expect(std.err).toMatchInlineSnapshot(`""`);
111
+ });
112
+
113
+ it("should error without a script name", async () => {
114
+ let error: Error | undefined;
115
+
116
+ try {
117
+ await runWrangler("secret delete the-key");
118
+ } catch (e) {
119
+ error = e;
120
+ }
121
+ expect(std.out).toMatchInlineSnapshot(`""`);
122
+ expect(std.err).toMatchInlineSnapshot(`
123
+ "Missing script name
124
+
125
+ %s
126
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
127
+ `);
128
+ expect(error).toMatchInlineSnapshot(`[Error: Missing script name]`);
129
+ });
130
+
131
+ it("warns about being a no-op in local mode", async () => {
132
+ mockConfirm({
133
+ text: "Are you sure you want to permanently delete the variable the-key on the script script-name?",
134
+ result: true,
135
+ });
136
+ await runWrangler("secret delete the-key --name script-name --local");
137
+ expect(std.out).toMatchInlineSnapshot(
138
+ `"🌀 Deleting the secret the-key on script script-name."`
139
+ );
140
+ expect(std.err).toMatchInlineSnapshot(`""`);
141
+ expect(std.warn).toMatchInlineSnapshot(
142
+ `"\`wrangler secret delete\` is a no-op in --local mode"`
143
+ );
144
+ });
145
+ });
146
+
147
+ describe("list", () => {
148
+ function mockListRequest(input: { scriptName: string }) {
149
+ setMockResponse(
150
+ "/accounts/:accountId/workers/scripts/:scriptName/secrets",
151
+ "GET",
152
+ ([_url, accountId, scriptName]) => {
153
+ expect(accountId).toEqual("some-account-id");
154
+ expect(scriptName).toEqual(input.scriptName);
155
+
156
+ return [
157
+ {
158
+ name: "the-secret-name",
159
+ type: "secret_text",
160
+ },
161
+ ];
162
+ }
163
+ );
164
+ }
165
+
166
+ it("should list secrets", async () => {
167
+ mockListRequest({ scriptName: "script-name" });
168
+ await runWrangler("secret list --name script-name");
169
+ expect(std.out).toMatchInlineSnapshot(`
170
+ "[
171
+ {
172
+ \\"name\\": \\"the-secret-name\\",
173
+ \\"type\\": \\"secret_text\\"
174
+ }
175
+ ]"
176
+ `);
177
+ expect(std.err).toMatchInlineSnapshot(`""`);
178
+ });
179
+
180
+ it("should error without a script name", async () => {
181
+ let error: Error | undefined;
182
+ try {
183
+ await runWrangler("secret list");
184
+ } catch (e) {
185
+ error = e;
186
+ }
187
+ expect(std.out).toMatchInlineSnapshot(`""`);
188
+ expect(std.err).toMatchInlineSnapshot(`
189
+ "Missing script name
190
+
191
+ %s
192
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
193
+ `);
194
+ expect(error).toMatchInlineSnapshot(`[Error: Missing script name]`);
195
+ });
196
+
197
+ it("warns about being a no-op in local mode", async () => {
198
+ await runWrangler("secret list --name script-name --local");
199
+ expect(std.out).toMatchInlineSnapshot(`""`);
200
+ expect(std.err).toMatchInlineSnapshot(`""`);
201
+ expect(std.warn).toMatchInlineSnapshot(
202
+ `"\`wrangler secret list\` is a no-op in --local mode"`
203
+ );
204
+ });
205
+ });
206
+ });
@@ -102,7 +102,7 @@ describe("WhoAmI component", () => {
102
102
  });
103
103
  });
104
104
 
105
- function writeUserConfig(
105
+ export function writeUserConfig(
106
106
  oauth_token?: string,
107
107
  refresh_token?: string,
108
108
  expiration_time?: string
package/src/dev.tsx CHANGED
@@ -8,7 +8,7 @@ import { Box, Text, useApp, useInput } from "ink";
8
8
  import { watch } from "chokidar";
9
9
  import clipboardy from "clipboardy";
10
10
  import commandExists from "command-exists";
11
- import { execa } from "execa";
11
+ import { execaCommand } from "execa";
12
12
  import fetch from "node-fetch";
13
13
  import open from "open";
14
14
  import React, { useState, useEffect, useRef } from "react";
@@ -40,6 +40,7 @@ export type DevProps = {
40
40
  initialMode: "local" | "remote";
41
41
  jsxFactory: undefined | string;
42
42
  jsxFragment: undefined | string;
43
+ enableLocalPersistence: boolean;
43
44
  bindings: CfWorkerInit["bindings"];
44
45
  public: undefined | string;
45
46
  assetPaths: undefined | AssetPaths;
@@ -102,6 +103,7 @@ function Dev(props: DevProps): JSX.Element {
102
103
  site={props.assetPaths}
103
104
  public={props.public}
104
105
  port={port}
106
+ enableLocalPersistence={props.enableLocalPersistence}
105
107
  />
106
108
  ) : (
107
109
  <Remote
@@ -184,6 +186,7 @@ function Local(props: {
184
186
  public: undefined | string;
185
187
  site: undefined | AssetPaths;
186
188
  port: number;
189
+ enableLocalPersistence: boolean;
187
190
  }) {
188
191
  const { inspectorUrl } = useLocalWorker({
189
192
  name: props.name,
@@ -191,6 +194,7 @@ function Local(props: {
191
194
  format: props.format,
192
195
  bindings: props.bindings,
193
196
  port: props.port,
197
+ enableLocalPersistence: props.enableLocalPersistence,
194
198
  });
195
199
  useInspector({ inspectorUrl, port: 9229, logToTerminal: false });
196
200
  return null;
@@ -202,6 +206,7 @@ function useLocalWorker(props: {
202
206
  format: CfScriptFormat;
203
207
  bindings: CfWorkerInit["bindings"];
204
208
  port: number;
209
+ enableLocalPersistence: boolean;
205
210
  }) {
206
211
  // TODO: pass vars via command line
207
212
  const { bundle, format, bindings, port } = props;
@@ -238,9 +243,9 @@ function useLocalWorker(props: {
238
243
  path.join(__dirname, "../miniflare-config-stubs/package.empty.json"),
239
244
  "--port",
240
245
  port.toString(),
241
- "--kv-persist",
242
- "--cache-persist",
243
- "--do-persist",
246
+ ...(props.enableLocalPersistence
247
+ ? ["--kv-persist", "--cache-persist", "--do-persist"]
248
+ : []),
244
249
  ...Object.entries(bindings.vars || {}).flatMap(([key, value]) => {
245
250
  return ["--binding", `${key}=${value}`];
246
251
  }),
@@ -371,20 +376,21 @@ function useCustomBuild(
371
376
  if (!command) return;
372
377
  let cmd, interval;
373
378
  console.log("running:", command);
374
- const commandPieces = command.split(" ");
375
- cmd = execa(commandPieces[0], commandPieces.slice(1), {
379
+ cmd = execaCommand(command, {
376
380
  ...(cwd && { cwd }),
381
+ shell: true,
377
382
  stderr: "inherit",
378
383
  stdout: "inherit",
379
384
  });
380
385
  if (watch_dir) {
381
386
  watch(watch_dir, { persistent: true, ignoreInitial: true }).on(
382
387
  "all",
383
- (_event, _path) => {
384
- console.log(`The file ${path} changed, restarting build...`);
388
+ (_event, filePath) => {
389
+ console.log(`The file ${filePath} changed, restarting build...`);
385
390
  cmd.kill();
386
- cmd = execa(commandPieces[0], commandPieces.slice(1), {
391
+ cmd = execaCommand(command, {
387
392
  ...(cwd && { cwd }),
393
+ shell: true,
388
394
  stderr: "inherit",
389
395
  stdout: "inherit",
390
396
  });
package/src/index.tsx CHANGED
@@ -238,7 +238,7 @@ export async function main(argv: string[]): Promise<void> {
238
238
  " "
239
239
  ) + "\n"
240
240
  );
241
- await execa("npm", ["install", "--prefer-offline"], {
241
+ await execa("npm", ["install"], {
242
242
  stdio: "inherit",
243
243
  });
244
244
  console.log(`✨ Created package.json`);
@@ -264,12 +264,7 @@ export async function main(argv: string[]): Promise<void> {
264
264
  if (shouldInstall) {
265
265
  await execa(
266
266
  "npm",
267
- [
268
- "install",
269
- `wrangler@${wranglerVersion}`,
270
- "--save-dev",
271
- "--prefer-offline",
272
- ],
267
+ ["install", `wrangler@${wranglerVersion}`, "--save-dev"],
273
268
  {
274
269
  stdio: "inherit",
275
270
  }
@@ -309,12 +304,7 @@ export async function main(argv: string[]): Promise<void> {
309
304
  );
310
305
  await execa(
311
306
  "npm",
312
- [
313
- "install",
314
- "@cloudflare/workers-types",
315
- "--save-dev",
316
- "--prefer-offline",
317
- ],
307
+ ["install", "@cloudflare/workers-types", "--save-dev"],
318
308
  { stdio: "inherit" }
319
309
  );
320
310
  console.log(
@@ -340,12 +330,7 @@ export async function main(argv: string[]): Promise<void> {
340
330
  if (shouldInstall) {
341
331
  await execa(
342
332
  "npm",
343
- [
344
- "install",
345
- "@cloudflare/workers-types",
346
- "--save-dev",
347
- "--prefer-offline",
348
- ],
333
+ ["install", "@cloudflare/workers-types", "--save-dev"],
349
334
  {
350
335
  stdio: "inherit",
351
336
  }
@@ -556,6 +541,10 @@ export async function main(argv: string[]): Promise<void> {
556
541
  .option("jsx-fragment", {
557
542
  describe: "The function that is called for each JSX fragment",
558
543
  type: "string",
544
+ })
545
+ .option("experimental-enable-local-persistence", {
546
+ describe: "Enable persistence for this session (only for local mode)",
547
+ type: "boolean",
559
548
  });
560
549
  },
561
550
  async (args) => {
@@ -623,6 +612,9 @@ export async function main(argv: string[]): Promise<void> {
623
612
  initialMode={args.local ? "local" : "remote"}
624
613
  jsxFactory={args["jsx-factory"] || envRootObj?.jsx_factory}
625
614
  jsxFragment={args["jsx-fragment"] || envRootObj?.jsx_fragment}
615
+ enableLocalPersistence={
616
+ args["experimental-enable-local-persistence"] || false
617
+ }
626
618
  accountId={config.account_id}
627
619
  assetPaths={getAssetPaths(
628
620
  config,
@@ -1088,11 +1080,6 @@ export async function main(argv: string[]): Promise<void> {
1088
1080
  });
1089
1081
  },
1090
1082
  async (args) => {
1091
- if (args.local) {
1092
- throw new NotImplementedError(
1093
- "--local not implemented for this command yet"
1094
- );
1095
- }
1096
1083
  const config = args.config as Config;
1097
1084
 
1098
1085
  // TODO: use environment (how does current wrangler do it?)
@@ -1101,6 +1088,10 @@ export async function main(argv: string[]): Promise<void> {
1101
1088
  throw new Error("Missing script name");
1102
1089
  }
1103
1090
 
1091
+ if (args.local) {
1092
+ console.warn("`wrangler secret put` is a no-op in --local mode");
1093
+ }
1094
+
1104
1095
  if (!args.local) {
1105
1096
  // -- snip, extract --
1106
1097
  const loggedIn = await loginOrRefreshIfRequired();
@@ -1123,6 +1114,13 @@ export async function main(argv: string[]): Promise<void> {
1123
1114
  "Enter a secret value:",
1124
1115
  "password"
1125
1116
  );
1117
+
1118
+ if (args.local) {
1119
+ return;
1120
+ }
1121
+
1122
+ console.log(`🌀 Creating the secret for script ${scriptName}`);
1123
+
1126
1124
  async function submitSecret() {
1127
1125
  return await fetchResult(
1128
1126
  `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets/`,
@@ -1139,7 +1137,7 @@ export async function main(argv: string[]): Promise<void> {
1139
1137
  }
1140
1138
 
1141
1139
  try {
1142
- console.log(await submitSecret());
1140
+ await submitSecret();
1143
1141
  } catch (e) {
1144
1142
  if (e.code === 10007) {
1145
1143
  // upload a draft worker
@@ -1165,10 +1163,11 @@ export async function main(argv: string[]): Promise<void> {
1165
1163
  );
1166
1164
 
1167
1165
  // and then try again
1168
- console.log(await submitSecret());
1166
+ await submitSecret();
1169
1167
  // TODO: delete the draft worker if this failed too?
1170
1168
  }
1171
1169
  }
1170
+ console.log(`✨ Success! Uploaded secret ${args.key}`);
1172
1171
  }
1173
1172
  )
1174
1173
  .command(
@@ -1191,11 +1190,6 @@ export async function main(argv: string[]): Promise<void> {
1191
1190
  });
1192
1191
  },
1193
1192
  async (args) => {
1194
- if (args.local) {
1195
- throw new NotImplementedError(
1196
- "--local not implemented for this command yet"
1197
- );
1198
- }
1199
1193
  const config = args.config as Config;
1200
1194
 
1201
1195
  // TODO: use environment (how does current wrangler do it?)
@@ -1204,6 +1198,12 @@ export async function main(argv: string[]): Promise<void> {
1204
1198
  throw new Error("Missing script name");
1205
1199
  }
1206
1200
 
1201
+ if (args.local) {
1202
+ console.warn(
1203
+ "`wrangler secret delete` is a no-op in --local mode"
1204
+ );
1205
+ }
1206
+
1207
1207
  if (!args.local) {
1208
1208
  // -- snip, extract --
1209
1209
  const loggedIn = await loginOrRefreshIfRequired();
@@ -1222,17 +1222,24 @@ export async function main(argv: string[]): Promise<void> {
1222
1222
  // -- snip, end --
1223
1223
  }
1224
1224
 
1225
- if (await confirm("Are you sure you want to delete this secret?")) {
1225
+ if (
1226
+ await confirm(
1227
+ `Are you sure you want to permanently delete the variable ${args.key} on the script ${scriptName}?`
1228
+ )
1229
+ ) {
1226
1230
  console.log(
1227
- `Deleting the secret ${args.key} on script ${scriptName}.`
1231
+ `🌀 Deleting the secret ${args.key} on script ${scriptName}.`
1228
1232
  );
1229
1233
 
1230
- console.log(
1231
- await fetchResult(
1232
- `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets/${args.key}`,
1233
- { method: "DELETE" }
1234
- )
1234
+ if (args.local) {
1235
+ return;
1236
+ }
1237
+
1238
+ await fetchResult(
1239
+ `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets/${args.key}`,
1240
+ { method: "DELETE" }
1235
1241
  );
1242
+ console.log(`✨ Success! Deleted secret ${args.key}`);
1236
1243
  }
1237
1244
  }
1238
1245
  )
@@ -1252,11 +1259,6 @@ export async function main(argv: string[]): Promise<void> {
1252
1259
  });
1253
1260
  },
1254
1261
  async (args) => {
1255
- if (args.local) {
1256
- throw new NotImplementedError(
1257
- "--local not implemented for this command yet"
1258
- );
1259
- }
1260
1262
  const config = args.config as Config;
1261
1263
 
1262
1264
  // TODO: use environment (how does current wrangler do it?)
@@ -1265,6 +1267,10 @@ export async function main(argv: string[]): Promise<void> {
1265
1267
  throw new Error("Missing script name");
1266
1268
  }
1267
1269
 
1270
+ if (args.local) {
1271
+ console.warn("`wrangler secret list` is a no-op in --local mode");
1272
+ }
1273
+
1268
1274
  if (!args.local) {
1269
1275
  // -- snip, extract --
1270
1276
  const loggedIn = await loginOrRefreshIfRequired();
@@ -1283,9 +1289,17 @@ export async function main(argv: string[]): Promise<void> {
1283
1289
  // -- snip, end --
1284
1290
  }
1285
1291
 
1292
+ if (args.local) {
1293
+ return;
1294
+ }
1295
+
1286
1296
  console.log(
1287
- await fetchResult(
1288
- `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
1297
+ JSON.stringify(
1298
+ await fetchResult(
1299
+ `/accounts/${config.account_id}/workers/scripts/${scriptName}/secrets`
1300
+ ),
1301
+ null,
1302
+ " "
1289
1303
  )
1290
1304
  );
1291
1305
  }