wrangler 2.0.16 → 2.0.19

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.
Files changed (51) hide show
  1. package/bin/wrangler.js +42 -8
  2. package/miniflare-dist/index.mjs +1 -0
  3. package/package.json +65 -63
  4. package/src/__tests__/configuration.test.ts +11 -7
  5. package/src/__tests__/helpers/run-in-tmp.ts +22 -23
  6. package/src/__tests__/https-options.test.ts +51 -18
  7. package/src/__tests__/index.test.ts +13 -13
  8. package/src/__tests__/jest.setup.ts +13 -0
  9. package/src/__tests__/kv.test.ts +33 -2
  10. package/src/__tests__/metrics.test.ts +415 -0
  11. package/src/__tests__/pages.test.ts +15 -8
  12. package/src/__tests__/publish.test.ts +49 -23
  13. package/src/__tests__/secret.test.ts +84 -78
  14. package/src/__tests__/tail.test.ts +8 -0
  15. package/src/__tests__/test-old-node-version.js +31 -0
  16. package/src/__tests__/user.test.ts +7 -7
  17. package/src/__tests__/whoami.test.tsx +11 -1
  18. package/src/api/dev.ts +4 -1
  19. package/src/cli.ts +1 -1
  20. package/src/config/config.ts +8 -0
  21. package/src/config/validation.ts +9 -0
  22. package/src/config-cache.ts +2 -1
  23. package/src/dev/local.tsx +31 -25
  24. package/src/dev/remote.tsx +2 -2
  25. package/src/dev.tsx +6 -0
  26. package/src/entry.ts +1 -1
  27. package/src/{__tests__/helpers/faye-websocket.d.ts → faye-websocket.d.ts} +0 -0
  28. package/src/global-wrangler-config-path.ts +26 -0
  29. package/src/https-options.ts +8 -4
  30. package/src/index.tsx +120 -22
  31. package/src/kv.ts +23 -1
  32. package/src/metrics/index.ts +4 -0
  33. package/src/metrics/metrics-config.ts +222 -0
  34. package/src/metrics/metrics-dispatcher.ts +93 -0
  35. package/src/metrics/send-event.ts +80 -0
  36. package/src/miniflare-cli/index.ts +1 -0
  37. package/src/package-manager.ts +45 -0
  38. package/src/pages/build.tsx +2 -0
  39. package/src/pages/deployments.tsx +2 -0
  40. package/src/pages/dev.tsx +4 -0
  41. package/src/pages/projects.tsx +3 -0
  42. package/src/pages/publish.tsx +3 -0
  43. package/src/pages/upload.tsx +26 -14
  44. package/src/publish.ts +28 -15
  45. package/src/pubsub/pubsub-commands.tsx +43 -0
  46. package/src/user/user.tsx +29 -20
  47. package/src/worker-namespace.ts +16 -0
  48. package/templates/static-asset-facade.js +11 -5
  49. package/templates/tsconfig.json +2 -2
  50. package/wrangler-dist/cli.d.ts +298 -0
  51. package/wrangler-dist/cli.js +2589 -1659
package/src/publish.ts CHANGED
@@ -469,21 +469,34 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
469
469
  if (!props.dryRun) {
470
470
  // Upload the script so it has time to propagate.
471
471
  // We can also now tell whether available_on_subdomain is set
472
- available_on_subdomain = (
473
- await fetchResult<{ available_on_subdomain: boolean }>(
474
- workerUrl,
475
- {
476
- method: "PUT",
477
- body: createWorkerUploadForm(worker),
478
- },
479
- new URLSearchParams({
480
- include_subdomain_availability: "true",
481
- // pass excludeScript so the whole body of the
482
- // script doesn't get included in the response
483
- excludeScript: "true",
484
- })
485
- )
486
- ).available_on_subdomain;
472
+ const result = await fetchResult<{
473
+ available_on_subdomain: boolean;
474
+ id: string | null;
475
+ etag: string | null;
476
+ pipeline_hash: string | null;
477
+ }>(
478
+ workerUrl,
479
+ {
480
+ method: "PUT",
481
+ body: createWorkerUploadForm(worker),
482
+ },
483
+ new URLSearchParams({
484
+ include_subdomain_availability: "true",
485
+ // pass excludeScript so the whole body of the
486
+ // script doesn't get included in the response
487
+ excludeScript: "true",
488
+ })
489
+ );
490
+
491
+ available_on_subdomain = result.available_on_subdomain;
492
+
493
+ // Print some useful information returned after publishing
494
+ // Not all fields will be populated for every worker
495
+ // These fields are likely to be scraped by tools, so do not rename
496
+ if (result.id) logger.log("Worker ID: ", result.id);
497
+ if (result.etag) logger.log("Worker ETag: ", result.etag);
498
+ if (result.pipeline_hash)
499
+ logger.log("Worker PipelineHash: ", result.pipeline_hash);
487
500
  }
488
501
  } finally {
489
502
  if (typeof destination !== "string") {
@@ -3,6 +3,7 @@ import { readConfig } from "../config";
3
3
  import { confirm } from "../dialogs";
4
4
  import { CommandLineArgsError } from "../index";
5
5
  import { logger } from "../logger";
6
+ import * as metrics from "../metrics";
6
7
  import { parseHumanDuration } from "../parse";
7
8
  import { requireAuth } from "../user";
8
9
  import * as pubsub from ".";
@@ -50,6 +51,9 @@ export function pubSubCommands(
50
51
  logger.log(`Creating Pub/SubNamespace ${args.name}...`);
51
52
  await pubsub.createPubSubNamespace(accountId, namespace);
52
53
  logger.log(`Success! Created Pub/Sub Namespace ${args.name}`);
54
+ metrics.sendMetricsEvent("create pubsub namespace", {
55
+ sendMetrics: config.send_metrics,
56
+ });
53
57
  }
54
58
  )
55
59
  .command(
@@ -63,6 +67,9 @@ export function pubSubCommands(
63
67
  const accountId = await requireAuth(config);
64
68
 
65
69
  logger.log(await pubsub.listPubSubNamespaces(accountId));
70
+ metrics.sendMetricsEvent("list pubsub namespaces", {
71
+ sendMetrics: config.send_metrics,
72
+ });
66
73
  }
67
74
  )
68
75
  .command(
@@ -89,6 +96,9 @@ export function pubSubCommands(
89
96
  logger.log(`Deleting namespace ${args.name}...`);
90
97
  await pubsub.deletePubSubNamespace(accountId, args.name);
91
98
  logger.log(`Deleted namespace ${args.name}.`);
99
+ metrics.sendMetricsEvent("delete pubsub namespace", {
100
+ sendMetrics: config.send_metrics,
101
+ });
92
102
  }
93
103
  }
94
104
  )
@@ -111,6 +121,9 @@ export function pubSubCommands(
111
121
  logger.log(
112
122
  await pubsub.describePubSubNamespace(accountId, args.name)
113
123
  );
124
+ metrics.sendMetricsEvent("view pubsub namespace", {
125
+ sendMetrics: config.send_metrics,
126
+ });
114
127
  }
115
128
  )
116
129
  .epilogue(pubsub.pubSubBetaWarning);
@@ -178,6 +191,9 @@ export function pubSubCommands(
178
191
  logger.log(
179
192
  await pubsub.createPubSubBroker(accountId, args.namespace, broker)
180
193
  );
194
+ metrics.sendMetricsEvent("create pubsub broker", {
195
+ sendMetrics: config.send_metrics,
196
+ });
181
197
  }
182
198
  );
183
199
 
@@ -247,6 +263,9 @@ export function pubSubCommands(
247
263
  )
248
264
  );
249
265
  logger.log(`Successfully updated Pub/Sub Broker ${args.name}`);
266
+ metrics.sendMetricsEvent("update pubsub broker", {
267
+ sendMetrics: config.send_metrics,
268
+ });
250
269
  }
251
270
  );
252
271
 
@@ -268,6 +287,9 @@ export function pubSubCommands(
268
287
  const accountId = await requireAuth(config);
269
288
 
270
289
  logger.log(await pubsub.listPubSubBrokers(accountId, args.namespace));
290
+ metrics.sendMetricsEvent("list pubsub brokers", {
291
+ sendMetrics: config.send_metrics,
292
+ });
271
293
  }
272
294
  );
273
295
 
@@ -306,6 +328,9 @@ export function pubSubCommands(
306
328
  args.name
307
329
  );
308
330
  logger.log(`Deleted Pub/Sub Broker ${args.name}.`);
331
+ metrics.sendMetricsEvent("delete pubsub broker", {
332
+ sendMetrics: config.send_metrics,
333
+ });
309
334
  }
310
335
  }
311
336
  )
@@ -338,6 +363,9 @@ export function pubSubCommands(
338
363
  args.name
339
364
  )
340
365
  );
366
+ metrics.sendMetricsEvent("view pubsub broker", {
367
+ sendMetrics: config.send_metrics,
368
+ });
341
369
  }
342
370
  );
343
371
 
@@ -413,6 +441,9 @@ export function pubSubCommands(
413
441
  parsedExpiration
414
442
  )
415
443
  );
444
+ metrics.sendMetricsEvent("issue pubsub broker credentials", {
445
+ sendMetrics: config.send_metrics,
446
+ });
416
447
  }
417
448
  );
418
449
 
@@ -458,6 +489,9 @@ export function pubSubCommands(
458
489
  );
459
490
 
460
491
  logger.log(`Revoked ${args.jti.length} credential(s).`);
492
+ metrics.sendMetricsEvent("revoke pubsub broker credentials", {
493
+ sendMetrics: config.send_metrics,
494
+ });
461
495
  }
462
496
  );
463
497
 
@@ -502,6 +536,9 @@ export function pubSubCommands(
502
536
  );
503
537
 
504
538
  logger.log(`Unrevoked ${numTokens} credential(s)`);
539
+ metrics.sendMetricsEvent("unrevoke pubsub broker credentials", {
540
+ sendMetrics: config.send_metrics,
541
+ });
505
542
  }
506
543
  );
507
544
 
@@ -535,6 +572,9 @@ export function pubSubCommands(
535
572
  args.name
536
573
  )
537
574
  );
575
+ metrics.sendMetricsEvent("list pubsub broker revoked credentials", {
576
+ sendMetrics: config.send_metrics,
577
+ });
538
578
  }
539
579
  );
540
580
 
@@ -567,6 +607,9 @@ export function pubSubCommands(
567
607
  args.name
568
608
  )
569
609
  );
610
+ metrics.sendMetricsEvent("list pubsub broker public-keys", {
611
+ sendMetrics: config.send_metrics,
612
+ });
570
613
  }
571
614
  );
572
615
 
package/src/user/user.tsx CHANGED
@@ -209,7 +209,6 @@ import assert from "node:assert";
209
209
  import { webcrypto as crypto } from "node:crypto";
210
210
  import { mkdirSync, rmSync, writeFileSync } from "node:fs";
211
211
  import http from "node:http";
212
- import os from "node:os";
213
212
  import path from "node:path";
214
213
  import url from "node:url";
215
214
  import { TextEncoder } from "node:util";
@@ -224,6 +223,7 @@ import {
224
223
  purgeConfigCaches,
225
224
  saveToConfigCache,
226
225
  } from "../config-cache";
226
+ import { getGlobalWranglerConfigPath } from "../global-wrangler-config-path";
227
227
  import isInteractive from "../is-interactive";
228
228
  import { logger } from "../logger";
229
229
  import openInBrowser from "../open-in-browser";
@@ -270,7 +270,7 @@ interface AuthTokens {
270
270
  * The path to the config file that holds user authentication data,
271
271
  * relative to the user's home directory.
272
272
  */
273
- export const USER_AUTH_CONFIG_FILE = ".wrangler/config/default.toml";
273
+ export const USER_AUTH_CONFIG_FILE = "config/default.toml";
274
274
 
275
275
  /**
276
276
  * The data that may be read from the `USER_CONFIG_FILE`.
@@ -368,6 +368,11 @@ function getAuthTokens(config?: UserAuthConfig): AuthTokens | undefined {
368
368
  refreshToken: { value: refresh_token ?? "" },
369
369
  };
370
370
  } else if (api_token) {
371
+ logger.warn(
372
+ "It looks like you have used Wrangler 1's `config` command to login with an API token.\n" +
373
+ "This is no longer supported in the current version of Wrangler.\n" +
374
+ "If you wish to authenticate via an API token then please set the `CLOUDFLARE_API_TOKEN` environment variable."
375
+ );
371
376
  return { apiToken: api_token };
372
377
  }
373
378
  } catch {
@@ -396,12 +401,8 @@ export function reinitialiseAuthTokens(config?: UserAuthConfig): void {
396
401
  }
397
402
 
398
403
  export function getAPIToken(): ApiCredentials | undefined {
399
- if ("apiToken" in LocalState) {
400
- logger.warn(
401
- "It looks like you have used Wrangler 1's `config` command to login with an API token.\n" +
402
- "This is no longer supported in the current version of Wrangler.\n" +
403
- "If you wish to authenticate via an API token then please set the `CLOUDFLARE_API_TOKEN` environment variable."
404
- );
404
+ if (LocalState.apiToken) {
405
+ return { apiToken: LocalState.apiToken };
405
406
  }
406
407
 
407
408
  const localAPIToken = getAuthFromEnv();
@@ -410,11 +411,7 @@ export function getAPIToken(): ApiCredentials | undefined {
410
411
  const storedAccessToken = LocalState.accessToken?.value;
411
412
  if (storedAccessToken) return { apiToken: storedAccessToken };
412
413
 
413
- if (!process.stdout.isTTY) {
414
- throw new Error(
415
- "In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/tokens/create/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."
416
- );
417
- }
414
+ return undefined;
418
415
  }
419
416
 
420
417
  interface AccessContext {
@@ -846,11 +843,15 @@ async function generatePKCECodes(): Promise<PKCECodes> {
846
843
  * and updates the user auth state with the new credentials.
847
844
  */
848
845
  export function writeAuthConfigFile(config: UserAuthConfig) {
849
- mkdirSync(path.join(os.homedir(), ".wrangler/config/"), {
846
+ const authConfigFilePath = path.join(
847
+ getGlobalWranglerConfigPath(),
848
+ USER_AUTH_CONFIG_FILE
849
+ );
850
+ mkdirSync(path.dirname(authConfigFilePath), {
850
851
  recursive: true,
851
852
  });
852
853
  writeFileSync(
853
- path.join(os.homedir(), USER_AUTH_CONFIG_FILE),
854
+ path.join(authConfigFilePath),
854
855
  TOML.stringify(config as TOML.JsonMap),
855
856
  { encoding: "utf-8" }
856
857
  );
@@ -859,9 +860,11 @@ export function writeAuthConfigFile(config: UserAuthConfig) {
859
860
  }
860
861
 
861
862
  export function readAuthConfigFile(): UserAuthConfig {
862
- const toml = parseTOML(
863
- readFileSync(path.join(os.homedir(), USER_AUTH_CONFIG_FILE))
863
+ const authConfigFilePath = path.join(
864
+ getGlobalWranglerConfigPath(),
865
+ USER_AUTH_CONFIG_FILE
864
866
  );
867
+ const toml = parseTOML(readFileSync(authConfigFilePath));
865
868
  return toml;
866
869
  }
867
870
 
@@ -1045,7 +1048,7 @@ export async function logout(): Promise<void> {
1045
1048
  },
1046
1049
  });
1047
1050
  await response.text(); // blank text? would be nice if it was something meaningful
1048
- rmSync(path.join(os.homedir(), USER_AUTH_CONFIG_FILE));
1051
+ rmSync(path.join(getGlobalWranglerConfigPath(), USER_AUTH_CONFIG_FILE));
1049
1052
  logger.log(`Successfully logged out.`);
1050
1053
  }
1051
1054
 
@@ -1114,8 +1117,14 @@ export async function requireAuth(config: {
1114
1117
  }): Promise<string> {
1115
1118
  const loggedIn = await loginOrRefreshIfRequired();
1116
1119
  if (!loggedIn) {
1117
- // didn't login, let's just quit
1118
- throw new Error("Did not login, quitting...");
1120
+ if (!isInteractive()) {
1121
+ throw new Error(
1122
+ "In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/tokens/create/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."
1123
+ );
1124
+ } else {
1125
+ // didn't login, let's just quit
1126
+ throw new Error("Did not login, quitting...");
1127
+ }
1119
1128
  }
1120
1129
  const accountId = config.account_id || (await getAccountId());
1121
1130
  if (!accountId) {
@@ -1,6 +1,7 @@
1
1
  import { fetchResult } from "./cfetch";
2
2
  import { readConfig } from "./config";
3
3
  import { logger } from "./logger";
4
+ import * as metrics from "./metrics";
4
5
  import { requireAuth } from "./user";
5
6
  import { printWranglerBanner } from ".";
6
7
  import type { ConfigPath } from ".";
@@ -113,6 +114,9 @@ export function workerNamespaceCommands(
113
114
  const config = readConfig(args.config as ConfigPath, args);
114
115
  const accountId = await requireAuth(config);
115
116
  await listWorkerNamespaces(accountId);
117
+ metrics.sendMetricsEvent("list worker namespaces", {
118
+ sendMetrics: config.send_metrics,
119
+ });
116
120
  })
117
121
  .command(
118
122
  "get <name>",
@@ -128,6 +132,9 @@ export function workerNamespaceCommands(
128
132
  const config = readConfig(args.config as ConfigPath, args);
129
133
  const accountId = await requireAuth(config);
130
134
  await getWorkerNamespaceInfo(accountId, args.name);
135
+ metrics.sendMetricsEvent("view worker namespace", {
136
+ sendMetrics: config.send_metrics,
137
+ });
131
138
  }
132
139
  )
133
140
  .command(
@@ -145,6 +152,9 @@ export function workerNamespaceCommands(
145
152
  const config = readConfig(args.config as ConfigPath, args);
146
153
  const accountId = await requireAuth(config);
147
154
  await createWorkerNamespace(accountId, args.name);
155
+ metrics.sendMetricsEvent("create worker namespace", {
156
+ sendMetrics: config.send_metrics,
157
+ });
148
158
  }
149
159
  )
150
160
  .command(
@@ -162,6 +172,9 @@ export function workerNamespaceCommands(
162
172
  const config = readConfig(args.config as ConfigPath, args);
163
173
  const accountId = await requireAuth(config);
164
174
  await deleteWorkerNamespace(accountId, args.name);
175
+ metrics.sendMetricsEvent("delete worker namespace", {
176
+ sendMetrics: config.send_metrics,
177
+ });
165
178
  }
166
179
  )
167
180
  .command(
@@ -185,6 +198,9 @@ export function workerNamespaceCommands(
185
198
  const config = readConfig(args.config as ConfigPath, args);
186
199
  const accountId = await requireAuth(config);
187
200
  await renameWorkerNamespace(accountId, args.oldName, args.newName);
201
+ metrics.sendMetricsEvent("rename worker namespace", {
202
+ sendMetrics: config.send_metrics,
203
+ });
188
204
  }
189
205
  );
190
206
  }
@@ -1,6 +1,10 @@
1
1
  // DO NOT IMPORT THIS DIRECTLY
2
2
  import worker from "__ENTRY_POINT__";
3
- import { getAssetFromKV } from "__KV_ASSET_HANDLER__";
3
+ import {
4
+ getAssetFromKV,
5
+ NotFoundError,
6
+ MethodNotAllowedError,
7
+ } from "__KV_ASSET_HANDLER__";
4
8
  import manifest from "__STATIC_CONTENT_MANIFEST";
5
9
  const ASSET_MANIFEST = JSON.parse(manifest);
6
10
 
@@ -33,11 +37,13 @@ export default {
33
37
 
34
38
  return response;
35
39
  } catch (e) {
40
+ if (e instanceof NotFoundError || e instanceof MethodNotAllowedError) {
41
+ // if a known error is thrown then serve from actual worker
42
+ return worker.fetch(request, env, ctx);
43
+ }
44
+ // otherwise it's a real error, so throw it
36
45
  console.error(e);
37
- // if an error is thrown then serve from actual worker
38
- return worker.fetch(request, env, ctx);
39
- // TODO: throw here if worker is not available
40
- // (which implies it may be a service-worker)
46
+ return new Response(e.message, { status: 500 });
41
47
  }
42
48
  },
43
49
  };
@@ -15,7 +15,7 @@
15
15
  "lib": [
16
16
  "es2021"
17
17
  ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
18
- // "jsx": "preserve", /* Specify what JSX code is generated. */
18
+ "jsx": "react" /* Specify what JSX code is generated. */,
19
19
  // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
20
20
  // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
21
21
  // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
@@ -42,7 +42,7 @@
42
42
 
43
43
  /* JavaScript Support */
44
44
  "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */,
45
- "checkJs": true /* Enable error reporting in type-checked JavaScript files. */,
45
+ "checkJs": false /* Enable error reporting in type-checked JavaScript files. */,
46
46
  // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
47
47
 
48
48
  /* Emit */