wrangler 2.0.21 → 2.0.24

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 (65) hide show
  1. package/README.md +20 -2
  2. package/bin/wrangler.js +1 -1
  3. package/miniflare-dist/index.mjs +527 -5
  4. package/package.json +18 -5
  5. package/src/__tests__/configuration.test.ts +88 -16
  6. package/src/__tests__/dev.test.tsx +95 -4
  7. package/src/__tests__/generate.test.ts +93 -0
  8. package/src/__tests__/helpers/mock-cfetch.ts +54 -2
  9. package/src/__tests__/index.test.ts +10 -27
  10. package/src/__tests__/jest.setup.ts +31 -1
  11. package/src/__tests__/kv.test.ts +82 -61
  12. package/src/__tests__/metrics.test.ts +35 -0
  13. package/src/__tests__/publish.test.ts +573 -254
  14. package/src/__tests__/r2.test.ts +155 -71
  15. package/src/__tests__/user.test.ts +1 -0
  16. package/src/__tests__/validate-dev-props.test.ts +56 -0
  17. package/src/__tests__/version.test.ts +35 -0
  18. package/src/__tests__/whoami.test.tsx +60 -1
  19. package/src/api/dev.ts +43 -9
  20. package/src/bundle.ts +297 -37
  21. package/src/cfetch/internal.ts +34 -2
  22. package/src/config/config.ts +14 -2
  23. package/src/config/environment.ts +40 -8
  24. package/src/config/index.ts +13 -0
  25. package/src/config/validation.ts +110 -8
  26. package/src/create-worker-preview.ts +3 -1
  27. package/src/create-worker-upload-form.ts +25 -0
  28. package/src/dev/dev.tsx +135 -31
  29. package/src/dev/local.tsx +48 -20
  30. package/src/dev/remote.tsx +39 -12
  31. package/src/dev/use-esbuild.ts +25 -0
  32. package/src/dev/validate-dev-props.ts +31 -0
  33. package/src/dev-registry.tsx +157 -0
  34. package/src/dev.tsx +137 -65
  35. package/src/generate.ts +112 -14
  36. package/src/index.tsx +222 -7
  37. package/src/inspect.ts +93 -5
  38. package/src/metrics/index.ts +1 -0
  39. package/src/metrics/is-ci.ts +14 -0
  40. package/src/metrics/metrics-config.ts +19 -2
  41. package/src/metrics/metrics-dispatcher.ts +1 -0
  42. package/src/metrics/metrics-usage-headers.ts +24 -0
  43. package/src/metrics/send-event.ts +2 -2
  44. package/src/miniflare-cli/assets.ts +543 -0
  45. package/src/miniflare-cli/index.ts +36 -4
  46. package/src/module-collection.ts +3 -3
  47. package/src/pages/constants.ts +1 -0
  48. package/src/pages/deployments.tsx +1 -1
  49. package/src/pages/dev.tsx +85 -639
  50. package/src/pages/publish.tsx +1 -1
  51. package/src/pages/upload.tsx +32 -13
  52. package/src/publish.ts +139 -112
  53. package/src/r2.ts +68 -0
  54. package/src/user/choose-account.tsx +20 -11
  55. package/src/user/user.tsx +20 -2
  56. package/src/whoami.tsx +79 -1
  57. package/src/worker.ts +12 -0
  58. package/templates/first-party-worker-module-facade.ts +18 -0
  59. package/templates/format-dev-errors.ts +32 -0
  60. package/templates/pages-shim.ts +9 -0
  61. package/templates/{static-asset-facade.js → serve-static-assets.ts} +21 -7
  62. package/templates/service-bindings-module-facade.js +51 -0
  63. package/templates/service-bindings-sw-facade.js +39 -0
  64. package/wrangler-dist/cli.d.ts +32 -3
  65. package/wrangler-dist/cli.js +45257 -25209
package/src/index.tsx CHANGED
@@ -1,4 +1,6 @@
1
+ import * as fs from "node:fs";
1
2
  import path from "node:path";
3
+ import * as stream from "node:stream";
2
4
  import { StringDecoder } from "node:string_decoder";
3
5
  import { setTimeout } from "node:timers/promises";
4
6
  import TOML from "@iarna/toml";
@@ -45,7 +47,14 @@ import {
45
47
  import { previewHandler, previewOptions } from "./preview";
46
48
  import publish from "./publish";
47
49
  import { pubSubCommands } from "./pubsub/pubsub-commands";
48
- import { createR2Bucket, deleteR2Bucket, listR2Buckets } from "./r2";
50
+ import {
51
+ bucketAndKeyFromObjectPath,
52
+ createR2Bucket,
53
+ deleteR2Bucket,
54
+ getR2Object,
55
+ listR2Buckets,
56
+ putR2Object,
57
+ } from "./r2";
49
58
  import { getAssetPaths, getSiteAssetPaths } from "./sites";
50
59
  import {
51
60
  createTail,
@@ -67,6 +76,7 @@ import { workerNamespaceCommands } from "./worker-namespace";
67
76
  import type { Config } from "./config";
68
77
  import type { KeyValue } from "./kv";
69
78
  import type { TailCLIFilters } from "./tail";
79
+ import type { Readable } from "node:stream";
70
80
  import type { RawData } from "ws";
71
81
  import type { CommandModule } from "yargs";
72
82
  import type Yargs from "yargs";
@@ -76,6 +86,7 @@ export type ConfigPath = string | undefined;
76
86
  const resetColor = "\x1b[0m";
77
87
  const fgGreenColor = "\x1b[32m";
78
88
  export const DEFAULT_LOCAL_PORT = 8787;
89
+ export const DEFAULT_INSPECTOR_PORT = 9229;
79
90
 
80
91
  const proxy =
81
92
  process.env.https_proxy ||
@@ -258,11 +269,22 @@ function createCLIParser(argv: string[]) {
258
269
  ["*"],
259
270
  false,
260
271
  () => {},
261
- (args) => {
272
+ async (args) => {
262
273
  if (args._.length > 0) {
263
274
  throw new CommandLineArgsError(`Unknown command: ${args._}.`);
264
275
  } else {
265
- wrangler.showHelp("log");
276
+ // args.v will exist and be true in the case that no command is called, and the -v
277
+ // option is present. This is to allow for running asynchronous printWranglerBanner
278
+ // in the version command.
279
+ if (args.v) {
280
+ if (process.stdout.isTTY) {
281
+ await printWranglerBanner();
282
+ } else {
283
+ logger.log(wranglerVersion);
284
+ }
285
+ } else {
286
+ wrangler.showHelp("log");
287
+ }
266
288
  }
267
289
  }
268
290
  );
@@ -501,10 +523,16 @@ function createCLIParser(argv: string[]) {
501
523
  (args.config as ConfigPath) ||
502
524
  (args.script && findWranglerToml(path.dirname(args.script)));
503
525
  const config = readConfig(configPath, args);
504
- await metrics.sendMetricsEvent("deploy worker script", {
505
- sendMetrics: config.send_metrics,
506
- });
507
526
  const entry = await getEntry(args, config, "publish");
527
+ await metrics.sendMetricsEvent(
528
+ "deploy worker script",
529
+ {
530
+ usesTypeScript: /\.tsx?$/.test(entry.file),
531
+ },
532
+ {
533
+ sendMetrics: config.send_metrics,
534
+ }
535
+ );
508
536
 
509
537
  if (args.public) {
510
538
  throw new Error("The --public field has been renamed to --assets");
@@ -938,6 +966,7 @@ function createCLIParser(argv: string[]) {
938
966
  text_blobs: {},
939
967
  data_blobs: {},
940
968
  worker_namespaces: [],
969
+ logfwdr: { schema: undefined, bindings: [] },
941
970
  unsafe: [],
942
971
  },
943
972
  modules: [],
@@ -1220,7 +1249,9 @@ function createCLIParser(argv: string[]) {
1220
1249
 
1221
1250
  const accountId = await requireAuth(config);
1222
1251
 
1252
+ logger.log(`Deleting KV namespace ${id}.`);
1223
1253
  await deleteKVNamespace(accountId, id);
1254
+ logger.log(`Deleted KV namespace ${id}.`);
1224
1255
  await metrics.sendMetricsEvent("delete kv namespace", {
1225
1256
  sendMetrics: config.send_metrics,
1226
1257
  });
@@ -1732,6 +1763,167 @@ function createCLIParser(argv: string[]) {
1732
1763
  wrangler.command("r2", "📦 Interact with an R2 store", (r2Yargs) => {
1733
1764
  return r2Yargs
1734
1765
  .command(subHelp)
1766
+ .command("object", "Manage R2 objects", (r2ObjectYargs) => {
1767
+ return r2ObjectYargs
1768
+ .command(
1769
+ "get <objectPath>",
1770
+ "Fetch an object from an R2 bucket",
1771
+ (yargs) => {
1772
+ return yargs
1773
+ .positional("objectPath", {
1774
+ describe:
1775
+ "The source object path in the form of {bucket}/{key}",
1776
+ type: "string",
1777
+ })
1778
+ .option("file", {
1779
+ describe: "The destination file to create",
1780
+ alias: "f",
1781
+ conflicts: "pipe",
1782
+ requiresArg: true,
1783
+ type: "string",
1784
+ })
1785
+ .option("pipe", {
1786
+ describe:
1787
+ "Enables the file to be piped to a destination, rather than specified with the --file option",
1788
+ alias: "p",
1789
+ conflicts: "file",
1790
+ type: "boolean",
1791
+ });
1792
+ },
1793
+ async (args) => {
1794
+ const config = readConfig(args.config as ConfigPath, args);
1795
+ const accountId = await requireAuth(config);
1796
+ const { objectPath, pipe } = args;
1797
+ const { bucket, key } = bucketAndKeyFromObjectPath(objectPath);
1798
+
1799
+ let file = args.file;
1800
+ if (!file && !pipe) {
1801
+ file = key;
1802
+ }
1803
+ if (!pipe) {
1804
+ await printWranglerBanner();
1805
+ logger.log(`Downloading "${key}" from "${bucket}".`);
1806
+ }
1807
+ const input = await getR2Object(accountId, bucket, key);
1808
+ const output = file ? fs.createWriteStream(file) : process.stdout;
1809
+ await new Promise<void>((resolve, reject) => {
1810
+ stream.pipeline(input, output, (err: unknown) => {
1811
+ err ? reject(err) : resolve();
1812
+ });
1813
+ });
1814
+ if (!pipe) logger.log("Download complete.");
1815
+ }
1816
+ )
1817
+ .command(
1818
+ "put <objectPath>",
1819
+ "Create an object in an R2 bucket",
1820
+ (yargs) => {
1821
+ return yargs
1822
+ .positional("objectPath", {
1823
+ describe:
1824
+ "The destination object path in the form of {bucket}/{key}",
1825
+ type: "string",
1826
+ })
1827
+ .option("file", {
1828
+ describe: "The path of the file to upload",
1829
+ alias: "f",
1830
+ conflicts: "pipe",
1831
+ requiresArg: true,
1832
+ type: "string",
1833
+ })
1834
+ .option("pipe", {
1835
+ describe:
1836
+ "Enables the file to be piped in, rather than specified with the --file option",
1837
+ alias: "p",
1838
+ conflicts: "file",
1839
+ type: "boolean",
1840
+ })
1841
+ .option("content-type", {
1842
+ describe:
1843
+ "A standard MIME type describing the format of the object data",
1844
+ alias: "ct",
1845
+ requiresArg: true,
1846
+ type: "string",
1847
+ })
1848
+ .option("content-disposition", {
1849
+ describe:
1850
+ "Specifies presentational information for the object",
1851
+ alias: "cd",
1852
+ requiresArg: true,
1853
+ type: "string",
1854
+ })
1855
+ .option("content-encoding", {
1856
+ describe:
1857
+ "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",
1858
+ alias: "ce",
1859
+ requiresArg: true,
1860
+ type: "string",
1861
+ })
1862
+ .option("content-language", {
1863
+ describe: "The language the content is in",
1864
+ alias: "cl",
1865
+ requiresArg: true,
1866
+ type: "string",
1867
+ })
1868
+ .option("cache-control", {
1869
+ describe:
1870
+ "Specifies caching behavior along the request/reply chain",
1871
+ alias: "cc",
1872
+ requiresArg: true,
1873
+ type: "string",
1874
+ })
1875
+ .option("expires", {
1876
+ describe:
1877
+ "The date and time at which the object is no longer cacheable",
1878
+ alias: "e",
1879
+ requiresArg: true,
1880
+ type: "string",
1881
+ });
1882
+ },
1883
+ async (args) => {
1884
+ await printWranglerBanner();
1885
+
1886
+ const config = readConfig(args.config as ConfigPath, args);
1887
+ const accountId = await requireAuth(config);
1888
+ const { objectPath, file, pipe, ...options } = args;
1889
+ const { bucket, key } = bucketAndKeyFromObjectPath(objectPath);
1890
+ if (!file && !pipe) {
1891
+ throw new CommandLineArgsError(
1892
+ "Either the --file or --pipe options are required."
1893
+ );
1894
+ }
1895
+ let object: Readable | Buffer;
1896
+ let objectSize: number;
1897
+ if (file) {
1898
+ object = fs.createReadStream(file);
1899
+ const stats = fs.statSync(file);
1900
+ objectSize = stats.size;
1901
+ } else {
1902
+ object = await new Promise<Buffer>((resolve, reject) => {
1903
+ const stdin = process.stdin;
1904
+ const chunks = Array<Buffer>();
1905
+ stdin.on("data", (chunk) => chunks.push(chunk));
1906
+ stdin.on("end", () => resolve(Buffer.concat(chunks)));
1907
+ stdin.on("error", (err) =>
1908
+ reject(
1909
+ new CommandLineArgsError(
1910
+ `Could not pipe. Reason: "${err.message}"`
1911
+ )
1912
+ )
1913
+ );
1914
+ });
1915
+ objectSize = object.byteLength;
1916
+ }
1917
+
1918
+ logger.log(`Creating object "${key}" in bucket "${bucket}".`);
1919
+ await putR2Object(accountId, bucket, key, object, {
1920
+ ...options,
1921
+ "content-length": `${objectSize}`,
1922
+ });
1923
+ logger.log("Upload complete.");
1924
+ }
1925
+ );
1926
+ })
1735
1927
  .command("bucket", "Manage R2 buckets", (r2BucketYargs) => {
1736
1928
  r2BucketYargs.command(
1737
1929
  "create <name>",
@@ -1903,6 +2095,29 @@ function createCLIParser(argv: string[]) {
1903
2095
  }
1904
2096
  );
1905
2097
 
2098
+ // This set to false to allow overwrite of default behaviour
2099
+ wrangler.version(false);
2100
+
2101
+ // version
2102
+ wrangler.command(
2103
+ "version",
2104
+ false,
2105
+ () => {},
2106
+ async () => {
2107
+ if (process.stdout.isTTY) {
2108
+ await printWranglerBanner();
2109
+ } else {
2110
+ logger.log(wranglerVersion);
2111
+ }
2112
+ }
2113
+ );
2114
+
2115
+ wrangler.option("v", {
2116
+ describe: "Show version number",
2117
+ alias: "version",
2118
+ type: "boolean",
2119
+ });
2120
+
1906
2121
  wrangler.option("config", {
1907
2122
  alias: "c",
1908
2123
  describe: "Path to .toml configuration file",
@@ -1912,7 +2127,7 @@ function createCLIParser(argv: string[]) {
1912
2127
 
1913
2128
  wrangler.group(["config", "help", "version"], "Flags:");
1914
2129
  wrangler.help().alias("h", "help");
1915
- wrangler.version(wranglerVersion).alias("v", "version");
2130
+
1916
2131
  wrangler.exitProcess(false);
1917
2132
 
1918
2133
  return wrangler;
package/src/inspect.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { readFile } from "fs/promises";
1
2
  import assert from "node:assert";
2
3
  import { createServer } from "node:http";
3
4
  import os from "node:os";
@@ -5,6 +6,7 @@ import { URL } from "node:url";
5
6
 
6
7
  import open from "open";
7
8
  import { useEffect, useRef, useState } from "react";
9
+ import { SourceMapConsumer } from "source-map";
8
10
  import WebSocket, { WebSocketServer } from "ws";
9
11
  import { version } from "../package.json";
10
12
  import { logger } from "./logger";
@@ -52,6 +54,10 @@ interface InspectorProps {
52
54
  * logged to the terminal by nature of them actually running in node locally.)
53
55
  */
54
56
  logToTerminal: boolean;
57
+ /**
58
+ * Sourcemap path, so that stacktraces can be interpretted
59
+ */
60
+ sourceMapPath?: string | undefined;
55
61
  }
56
62
 
57
63
  export default function useInspector(props: InspectorProps) {
@@ -252,15 +258,96 @@ export default function useInspector(props: InspectorProps) {
252
258
  * without having to open the devtools).
253
259
  */
254
260
  if (props.logToTerminal) {
255
- ws.addEventListener("message", (event: MessageEvent) => {
261
+ ws.addEventListener("message", async (event: MessageEvent) => {
256
262
  if (typeof event.data === "string") {
257
263
  const evt = JSON.parse(event.data);
258
264
  if (evt.method === "Runtime.exceptionThrown") {
259
265
  const params = evt.params as Protocol.Runtime.ExceptionThrownEvent;
260
- logger.error(
261
- params.exceptionDetails.text,
262
- params.exceptionDetails.exception?.description ?? ""
263
- );
266
+
267
+ // Parse stack trace with source map.
268
+ if (props.sourceMapPath) {
269
+ // Parse in the sourcemap
270
+ const mapContent = JSON.parse(
271
+ await readFile(props.sourceMapPath, "utf-8")
272
+ );
273
+
274
+ // Create the lines for the exception details log
275
+ const exceptionLines = [
276
+ params.exceptionDetails.exception?.description?.split("\n")[0],
277
+ ];
278
+
279
+ await SourceMapConsumer.with(
280
+ mapContent,
281
+ null,
282
+ async (consumer) => {
283
+ // Pass each of the callframes into the consumer, and format the error
284
+ const stack = params.exceptionDetails.stackTrace?.callFrames;
285
+
286
+ stack?.forEach(
287
+ ({ functionName, lineNumber, columnNumber }, i) => {
288
+ try {
289
+ if (lineNumber) {
290
+ // The line and column numbers in the stackTrace are zero indexed,
291
+ // whereas the sourcemap consumer indexes from one.
292
+ const pos = consumer.originalPositionFor({
293
+ line: lineNumber + 1,
294
+ column: columnNumber + 1,
295
+ });
296
+
297
+ // Print out line which caused error:
298
+ if (i === 0 && pos.source && pos.line) {
299
+ const fileSource = consumer.sourceContentFor(
300
+ pos.source
301
+ );
302
+ const fileSourceLine =
303
+ fileSource?.split("\n")[pos.line - 1] || "";
304
+ exceptionLines.push(fileSourceLine.trim());
305
+
306
+ // If we have a column, we can mark the position underneath
307
+ if (pos.column) {
308
+ exceptionLines.push(
309
+ `${" ".repeat(
310
+ pos.column - fileSourceLine.search(/\S/)
311
+ )}^`
312
+ );
313
+ }
314
+ }
315
+
316
+ // From the way esbuild implements the "names" field:
317
+ // > To save space, the original name is only recorded when it's different from the final name.
318
+ // however, source-map consumer does not handle this
319
+ if (pos && pos.line != null) {
320
+ const convertedFnName =
321
+ pos.name || functionName || "";
322
+ exceptionLines.push(
323
+ ` at ${convertedFnName} (${pos.source?.replace(
324
+ `${mapContent.sourceRoot}/`,
325
+ ""
326
+ )}:${pos.line}:${pos.column})`
327
+ );
328
+ }
329
+ }
330
+ } catch {
331
+ // Line failed to parse through the sourcemap consumer
332
+ // We should handle this better
333
+ }
334
+ }
335
+ );
336
+ }
337
+ );
338
+
339
+ // Log the parsed stacktrace
340
+ logger.error(
341
+ params.exceptionDetails.text,
342
+ exceptionLines.join("\n")
343
+ );
344
+ } else {
345
+ // We log the stacktrace to the terminal
346
+ logger.error(
347
+ params.exceptionDetails.text,
348
+ params.exceptionDetails.exception?.description ?? ""
349
+ );
350
+ }
264
351
  }
265
352
  if (evt.method === "Runtime.consoleAPICalled") {
266
353
  logConsoleMessage(
@@ -333,6 +420,7 @@ export default function useInspector(props: InspectorProps) {
333
420
  }, [
334
421
  props.inspectorUrl,
335
422
  props.logToTerminal,
423
+ props.sourceMapPath,
336
424
  wsServer,
337
425
  // We use a state value as a sigil to trigger a retry of the
338
426
  // remote websocket connection. It's not used inside the effect,
@@ -2,3 +2,4 @@ export { getMetricsDispatcher } from "./metrics-dispatcher";
2
2
  export type { Properties } from "./metrics-dispatcher";
3
3
  export { getMetricsConfig } from "./metrics-config";
4
4
  export * from "./send-event";
5
+ export { getMetricsUsageHeaders } from "./metrics-usage-headers";
@@ -0,0 +1,14 @@
1
+ import isCI from "is-ci";
2
+
3
+ /**
4
+ * Use this object to find out if we are currently running in a continuous integration environment.
5
+ *
6
+ * The isCI constant imported above cannot be easily mocked for testing.
7
+ * By wrapping this up in a method on an object, it results in clean and testable code.
8
+ */
9
+ export const CI = {
10
+ /** Is Wrangler currently running in a CI? */
11
+ isCI() {
12
+ return isCI;
13
+ },
14
+ };
@@ -5,9 +5,11 @@ import path from "node:path";
5
5
  import { fetchResult } from "../cfetch";
6
6
  import { getConfigCache, saveToConfigCache } from "../config-cache";
7
7
  import { confirm } from "../dialogs";
8
+ import { getEnvironmentVariableFactory } from "../environment-variables";
8
9
  import isInteractive from "../is-interactive";
9
10
  import { logger } from "../logger";
10
11
  import { getAPIToken } from "../user";
12
+ import { CI } from "./is-ci";
11
13
 
12
14
  /**
13
15
  * The date that the metrics being gathered was last updated in a way that would require
@@ -21,6 +23,10 @@ import { getAPIToken } from "../user";
21
23
  export const CURRENT_METRICS_DATE = new Date(2022, 6, 4);
22
24
  export const USER_ID_CACHE_PATH = "user-id.json";
23
25
 
26
+ export const getWranglerSendMetricsFromEnv = getEnvironmentVariableFactory({
27
+ variableName: "WRANGLER_SEND_METRICS",
28
+ });
29
+
24
30
  export interface MetricsConfigOptions {
25
31
  /**
26
32
  * Defines whether to send metrics to Cloudflare:
@@ -70,6 +76,17 @@ export async function getMetricsConfig({
70
76
  const deviceId = getDeviceId(config);
71
77
  const userId = await getUserId(offline);
72
78
 
79
+ // If the WRANGLER_SEND_METRICS environment variable has been set use that
80
+ // and ignore everything else.
81
+ const sendMetricsEnv = getWranglerSendMetricsFromEnv();
82
+ if (sendMetricsEnv !== undefined) {
83
+ return {
84
+ enabled: sendMetricsEnv.toLowerCase() === "true",
85
+ deviceId,
86
+ userId,
87
+ };
88
+ }
89
+
73
90
  // If the project is explicitly set the `send_metrics` options in `wrangler.toml`
74
91
  // then use that and ignore any user preference.
75
92
  if (sendMetrics !== undefined) {
@@ -89,8 +106,8 @@ export async function getMetricsConfig({
89
106
  }
90
107
 
91
108
  // We couldn't get the metrics permission from the project-level nor the user-level config.
92
- // If we are not interactive then just bail out.
93
- if (!isInteractive()) {
109
+ // If we are not interactive or in a CI build then just bail out.
110
+ if (!isInteractive() || CI.isCI()) {
94
111
  return { enabled: false, deviceId, userId };
95
112
  }
96
113
 
@@ -67,6 +67,7 @@ export async function getMetricsDispatcher(options: MetricsConfigOptions) {
67
67
  properties: {
68
68
  category: "Workers",
69
69
  wranglerVersion,
70
+ os: process.platform + ":" + process.arch,
70
71
  ...event.properties,
71
72
  },
72
73
  });
@@ -0,0 +1,24 @@
1
+ import { getMetricsConfig } from "./metrics-config";
2
+
3
+ /**
4
+ * Add an additional header to publish requests if the user has opted into sending usage metrics.
5
+ *
6
+ * This allows us to estimate the number of instances of Wrangler that have opted-in
7
+ * without breaking our agreement not to send stuff if you have not opted-in.
8
+ */
9
+ export async function getMetricsUsageHeaders(
10
+ sendMetrics: boolean | undefined
11
+ ): Promise<Record<string, string> | undefined> {
12
+ const metricsEnabled = (
13
+ await getMetricsConfig({
14
+ sendMetrics,
15
+ })
16
+ ).enabled;
17
+ if (metricsEnabled) {
18
+ return {
19
+ metricsEnabled: "true",
20
+ };
21
+ } else {
22
+ return undefined;
23
+ }
24
+ }
@@ -47,8 +47,8 @@ export type EventNames =
47
47
  | "rename worker namespace"
48
48
  | "create pages project"
49
49
  | "list pages projects"
50
- | "deploy pages project"
51
- | "list pages projects deployments"
50
+ | "create pages deployment"
51
+ | "list pages deployments"
52
52
  | "build pages functions"
53
53
  | "run dev"
54
54
  | "run pages dev";