wrangler 0.0.0-e7a0cd5b → 0.0.0-e87ad068

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 (255) hide show
  1. package/README.md +3 -3
  2. package/bin/wrangler.js +30 -10
  3. package/miniflare-dist/index.mjs +254 -128
  4. package/package.json +27 -19
  5. package/src/__tests__/api-dev.test.ts +65 -36
  6. package/src/__tests__/api-devregistry.test.ts +121 -0
  7. package/src/__tests__/api.test.ts +27 -5
  8. package/src/__tests__/configuration.test.ts +797 -98
  9. package/src/__tests__/constellation.test.ts +371 -0
  10. package/src/__tests__/d1/d1.test.ts +82 -0
  11. package/src/__tests__/d1/execute.test.ts +66 -0
  12. package/src/__tests__/d1/migrate.test.ts +257 -0
  13. package/src/__tests__/d1/splitter.test.ts +255 -0
  14. package/src/__tests__/delete.test.ts +91 -49
  15. package/src/__tests__/deployments.test.ts +330 -56
  16. package/src/__tests__/dev.test.tsx +198 -90
  17. package/src/__tests__/generate.test.ts +12 -10
  18. package/src/__tests__/guess-worker-format.test.ts +35 -0
  19. package/src/__tests__/helpers/end-event-loop.ts +6 -0
  20. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  21. package/src/__tests__/helpers/mock-console.ts +6 -0
  22. package/src/__tests__/helpers/mock-dialogs.ts +71 -85
  23. package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
  24. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -5
  25. package/src/__tests__/helpers/mock-known-routes.ts +7 -2
  26. package/src/__tests__/helpers/mock-kv.ts +29 -16
  27. package/src/__tests__/helpers/mock-oauth-flow.ts +103 -92
  28. package/src/__tests__/helpers/mock-process.ts +8 -13
  29. package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
  30. package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
  31. package/src/__tests__/helpers/msw/handlers/deployments.ts +128 -27
  32. package/src/__tests__/helpers/msw/handlers/namespaces.ts +18 -41
  33. package/src/__tests__/helpers/msw/handlers/oauth.ts +13 -18
  34. package/src/__tests__/helpers/msw/handlers/r2.ts +14 -34
  35. package/src/__tests__/helpers/msw/handlers/script.ts +9 -28
  36. package/src/__tests__/helpers/msw/handlers/user.ts +13 -24
  37. package/src/__tests__/helpers/msw/handlers/zones.ts +6 -8
  38. package/src/__tests__/helpers/msw/index.ts +32 -1
  39. package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
  40. package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
  41. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  42. package/src/__tests__/index.test.ts +92 -72
  43. package/src/__tests__/init.test.ts +1033 -631
  44. package/src/__tests__/jest.setup.ts +19 -42
  45. package/src/__tests__/kv.test.ts +355 -231
  46. package/src/__tests__/logger.test.ts +68 -2
  47. package/src/__tests__/logout.test.ts +47 -0
  48. package/src/__tests__/metrics.test.ts +94 -51
  49. package/src/__tests__/middleware.scheduled.test.ts +42 -32
  50. package/src/__tests__/middleware.test.ts +212 -122
  51. package/src/__tests__/mtls-certificates.test.ts +589 -0
  52. package/src/__tests__/pages/deployment-list.test.ts +80 -0
  53. package/src/__tests__/pages/functions-build.test.ts +529 -0
  54. package/src/__tests__/pages/pages.test.ts +81 -0
  55. package/src/__tests__/pages/project-create.test.ts +63 -0
  56. package/src/__tests__/pages/project-list.test.ts +110 -0
  57. package/src/__tests__/pages/project-upload.test.ts +500 -0
  58. package/src/__tests__/pages/publish.test.ts +2864 -0
  59. package/src/__tests__/pages-deployment-tail.test.ts +957 -0
  60. package/src/__tests__/parse.test.ts +106 -0
  61. package/src/__tests__/publish.test.ts +2227 -1005
  62. package/src/__tests__/pubsub.test.ts +226 -100
  63. package/src/__tests__/queues.test.ts +238 -77
  64. package/src/__tests__/r2.test.ts +55 -57
  65. package/src/__tests__/secret.test.ts +179 -130
  66. package/src/__tests__/tail.test.ts +313 -113
  67. package/src/__tests__/test-old-node-version.js +3 -3
  68. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  69. package/src/__tests__/tsconfig-sanity.ts +12 -0
  70. package/src/__tests__/tsconfig.json +8 -0
  71. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  72. package/src/__tests__/type-generation.test.ts +43 -26
  73. package/src/__tests__/unstableDev.test.ts +61 -0
  74. package/src/__tests__/user.test.ts +35 -72
  75. package/src/__tests__/whoami.test.tsx +8 -114
  76. package/src/__tests__/worker-namespace.test.ts +83 -69
  77. package/src/api/dev.ts +180 -60
  78. package/src/api/index.ts +10 -1
  79. package/src/api/mtls-certificate.ts +148 -0
  80. package/src/api/pages/create-worker-bundle-contents.ts +80 -0
  81. package/src/api/pages/index.ts +5 -0
  82. package/src/api/pages/publish.tsx +371 -0
  83. package/src/bundle.ts +315 -148
  84. package/src/cfetch/index.ts +0 -2
  85. package/src/cfetch/internal.ts +33 -33
  86. package/src/cli.ts +4 -4
  87. package/src/config/config.ts +14 -7
  88. package/src/config/environment.ts +120 -24
  89. package/src/config/index.ts +117 -35
  90. package/src/config/validation-helpers.ts +1 -1
  91. package/src/config/validation.ts +430 -19
  92. package/src/constellation/createProject.tsx +51 -0
  93. package/src/constellation/deleteProject.ts +51 -0
  94. package/src/constellation/deleteProjectModel.ts +76 -0
  95. package/src/constellation/index.ts +75 -0
  96. package/src/constellation/listCatalog.tsx +35 -0
  97. package/src/constellation/listModel.tsx +49 -0
  98. package/src/constellation/listProject.tsx +28 -0
  99. package/src/constellation/listRuntime.tsx +28 -0
  100. package/src/constellation/options.ts +17 -0
  101. package/src/constellation/types.ts +17 -0
  102. package/src/constellation/uploadModel.tsx +84 -0
  103. package/src/constellation/utils.ts +90 -0
  104. package/src/create-worker-preview.ts +19 -8
  105. package/src/create-worker-upload-form.ts +81 -18
  106. package/src/d1/backups.tsx +47 -46
  107. package/src/d1/constants.ts +5 -0
  108. package/src/d1/create.tsx +85 -37
  109. package/src/d1/{delete.tsx → delete.ts} +12 -15
  110. package/src/d1/execute.tsx +228 -156
  111. package/src/d1/index.ts +31 -7
  112. package/src/d1/list.tsx +27 -13
  113. package/src/d1/migrations/apply.tsx +235 -0
  114. package/src/d1/migrations/create.tsx +79 -0
  115. package/src/d1/migrations/helpers.ts +171 -0
  116. package/src/d1/migrations/index.ts +3 -0
  117. package/src/d1/migrations/list.tsx +95 -0
  118. package/src/d1/migrations/options.ts +23 -0
  119. package/src/d1/options.ts +12 -2
  120. package/src/d1/splitter.ts +161 -0
  121. package/src/d1/types.ts +32 -0
  122. package/src/d1/utils.ts +12 -2
  123. package/src/delete.ts +8 -16
  124. package/src/deployments.ts +340 -46
  125. package/src/deprecated/index.ts +8 -302
  126. package/src/dev/dev.tsx +66 -46
  127. package/src/dev/local.tsx +339 -104
  128. package/src/dev/remote.tsx +36 -3
  129. package/src/dev/start-server.ts +146 -101
  130. package/src/dev/use-esbuild.ts +82 -56
  131. package/src/dev/validate-dev-props.ts +9 -0
  132. package/src/{dev-registry.tsx → dev-registry.ts} +13 -1
  133. package/src/dev.tsx +202 -125
  134. package/src/dialogs.ts +136 -0
  135. package/src/dispatch-namespace.ts +21 -17
  136. package/src/docs/helpers.ts +50 -0
  137. package/src/docs/index.ts +54 -0
  138. package/src/entry.ts +26 -11
  139. package/src/environment-variables/factory.ts +89 -0
  140. package/src/environment-variables/misc-variables.ts +30 -0
  141. package/src/generate/index.ts +303 -0
  142. package/src/git-client.ts +15 -4
  143. package/src/{index.tsx → index.ts} +148 -63
  144. package/src/init.ts +301 -197
  145. package/src/inspect.ts +122 -6
  146. package/src/jest.d.ts +4 -0
  147. package/src/kv/helpers.ts +7 -4
  148. package/src/kv/index.ts +15 -17
  149. package/src/logger.ts +36 -5
  150. package/src/metrics/metrics-config.ts +3 -3
  151. package/src/metrics/send-event.ts +6 -1
  152. package/src/miniflare-cli/assets.ts +64 -28
  153. package/src/miniflare-cli/index.ts +6 -9
  154. package/src/miniflare-cli/tsconfig.json +9 -0
  155. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  156. package/src/miniflare-cli/types.ts +11 -0
  157. package/src/module-collection.ts +92 -26
  158. package/src/mtls-certificate/cli.ts +155 -0
  159. package/src/pages/build.ts +423 -0
  160. package/src/pages/buildFunctions.ts +140 -0
  161. package/src/pages/deployment-tails.ts +281 -0
  162. package/src/pages/deployments.tsx +11 -33
  163. package/src/pages/{dev.tsx → dev.ts} +192 -126
  164. package/src/pages/errors.ts +1 -0
  165. package/src/pages/functions/buildPlugin.ts +73 -69
  166. package/src/pages/functions/buildWorker.ts +342 -117
  167. package/src/pages/functions/tsconfig.json +8 -0
  168. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  169. package/src/pages/{functions.tsx → functions.ts} +8 -4
  170. package/src/pages/{index.tsx → index.ts} +11 -3
  171. package/src/pages/projects.tsx +12 -22
  172. package/src/pages/prompt-select-project.tsx +31 -0
  173. package/src/pages/publish.tsx +45 -214
  174. package/src/pages/types.ts +6 -9
  175. package/src/pages/upload.tsx +58 -14
  176. package/src/pages/utils.ts +14 -3
  177. package/src/parse.ts +23 -1
  178. package/src/paths.ts +1 -1
  179. package/src/proxy.ts +5 -0
  180. package/src/publish/index.ts +20 -16
  181. package/src/publish/publish.ts +81 -48
  182. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +19 -20
  183. package/src/queues/cli/commands/consumer/add.ts +24 -24
  184. package/src/queues/cli/commands/consumer/index.ts +3 -6
  185. package/src/queues/cli/commands/consumer/remove.ts +11 -18
  186. package/src/queues/cli/commands/create.ts +8 -8
  187. package/src/queues/cli/commands/delete.ts +8 -8
  188. package/src/queues/cli/commands/index.ts +6 -4
  189. package/src/queues/cli/commands/list.ts +8 -8
  190. package/src/queues/client.ts +1 -0
  191. package/src/queues/utils.ts +18 -0
  192. package/src/r2/constants.ts +4 -0
  193. package/src/r2/helpers.ts +1 -0
  194. package/src/r2/index.ts +40 -28
  195. package/src/secret/index.ts +18 -17
  196. package/src/{sites.tsx → sites.ts} +165 -53
  197. package/src/tail/createTail.ts +103 -3
  198. package/src/tail/filters.ts +1 -1
  199. package/src/tail/index.ts +8 -11
  200. package/src/tail/printing.ts +27 -0
  201. package/src/traverse-module-graph.ts +54 -0
  202. package/src/tsconfig-sanity.ts +16 -0
  203. package/src/type-generation.ts +85 -57
  204. package/src/user/access.ts +0 -1
  205. package/src/user/auth-variables.ts +113 -0
  206. package/src/user/choose-account.tsx +1 -31
  207. package/src/user/index.ts +0 -1
  208. package/src/user/{user.tsx → user.ts} +124 -82
  209. package/src/utils/render.ts +93 -0
  210. package/src/{whoami.tsx → whoami.ts} +37 -71
  211. package/src/worker.ts +61 -3
  212. package/src/yargs-types.ts +22 -5
  213. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  214. package/templates/__tests__/tsconfig.json +8 -0
  215. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  216. package/templates/checked-fetch.js +9 -3
  217. package/templates/d1-beta-facade.js +95 -25
  218. package/templates/facade.d.ts +14 -0
  219. package/templates/first-party-worker-module-facade.ts +4 -3
  220. package/templates/format-dev-errors.ts +8 -6
  221. package/templates/gitignore +1 -0
  222. package/templates/init-tests/test-jest-new-worker.js +3 -5
  223. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  224. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  225. package/templates/middleware/loader-modules.ts +2 -2
  226. package/templates/middleware/loader-sw.ts +51 -31
  227. package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
  228. package/templates/new-worker.ts +3 -0
  229. package/templates/pages-dev-pipeline.ts +4 -1
  230. package/templates/pages-dev-util.ts +4 -1
  231. package/templates/pages-shim.ts +4 -1
  232. package/templates/pages-template-plugin.ts +19 -10
  233. package/templates/serve-static-assets.ts +17 -14
  234. package/templates/service-bindings-module-facade.js +1 -0
  235. package/templates/tsconfig-sanity.ts +11 -0
  236. package/templates/tsconfig.init.json +105 -0
  237. package/templates/tsconfig.json +5 -103
  238. package/templates/tsconfig.tsbuildinfo +1 -0
  239. package/wrangler-dist/cli.d.ts +902 -77
  240. package/wrangler-dist/cli.js +131685 -140615
  241. package/wrangler-dist/wasm-sync.wasm +0 -0
  242. package/src/__tests__/api-devregistry.test.js +0 -57
  243. package/src/__tests__/d1.test.ts +0 -72
  244. package/src/__tests__/dialogs.test.tsx +0 -40
  245. package/src/__tests__/helpers/mock-cfetch.ts +0 -333
  246. package/src/__tests__/pages.test.ts +0 -2223
  247. package/src/d1/types.tsx +0 -14
  248. package/src/dialogs.tsx +0 -163
  249. package/src/environment-variables.ts +0 -50
  250. package/src/pages/build.tsx +0 -238
  251. package/src/user/env-vars.ts +0 -46
  252. package/templates/experimental-local-cache-stubs.js +0 -27
  253. /package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  254. /package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  255. /package/src/pages/{hash.tsx → hash.ts} +0 -0
package/src/inspect.ts CHANGED
@@ -1,9 +1,10 @@
1
+ import { readFileSync } from "fs";
1
2
  import { readFile } from "fs/promises";
2
3
  import assert from "node:assert";
3
4
  import { createServer } from "node:http";
4
5
  import os from "node:os";
5
6
  import { URL } from "node:url";
6
-
7
+ import path from "path";
7
8
  import open from "open";
8
9
  import { useEffect, useRef, useState } from "react";
9
10
  import { SourceMapConsumer } from "source-map";
@@ -40,6 +41,13 @@ import type { MessageEvent } from "ws";
40
41
  * - handle more methods from console
41
42
  */
42
43
 
44
+ // Information about Wrangler's bundling process that needs passsed through
45
+ // for DevTools sourcemap transformation
46
+ export interface SourceMapMetadata {
47
+ tmpDir: string;
48
+ entryDirectory: string;
49
+ }
50
+
43
51
  interface InspectorProps {
44
52
  /**
45
53
  * The port that the local proxy server should listen on.
@@ -58,9 +66,13 @@ interface InspectorProps {
58
66
  /**
59
67
  * Sourcemap path, so that stacktraces can be interpretted
60
68
  */
61
- sourceMapPath?: string | undefined;
69
+ sourceMapPath: string | undefined;
70
+
71
+ sourceMapMetadata: SourceMapMetadata | undefined;
62
72
 
63
73
  host?: string;
74
+
75
+ name?: string;
64
76
  }
65
77
 
66
78
  export default function useInspector(props: InspectorProps) {
@@ -151,6 +163,18 @@ export default function useInspector(props: InspectorProps) {
151
163
  );
152
164
  ws.close(1013, "Too many clients; only one can be connected at a time");
153
165
  } else {
166
+ // Since Wrangler proxies the inspector, reloading Chrome DevTools won't trigger debugger initialisation events (because it's connecting to an extant session).
167
+ // This sends a `Debugger.disable` message to the remote when a new WebSocket connection is initialised,
168
+ // with the assumption that the new connection will shortly send a `Debugger.enable` event and trigger re-initialisation.
169
+ // The key initialisation messages that are needed are the `Debugger.scriptParsed events`.
170
+ remoteWebSocket?.send(
171
+ JSON.stringify({
172
+ // This number is arbitrary, and is chosen to be high so as not to conflict with messages that DevTools might actually send.
173
+ // For completeness, these options don't work: 0, -1, or Number.MAX_SAFE_INTEGER
174
+ id: 100_000_000,
175
+ method: "Debugger.disable",
176
+ })
177
+ );
154
178
  // As promised, save the created websocket in a state hook
155
179
  setLocalWebSocket(ws);
156
180
 
@@ -481,6 +505,65 @@ export default function useInspector(props: InspectorProps) {
481
505
 
482
506
  /** Send a message from the local websocket to the remote websocket */
483
507
  function sendMessageToRemoteWebSocket(event: MessageEvent) {
508
+ try {
509
+ // Intercept Network.loadNetworkResource to load sourcemaps
510
+ const message = JSON.parse(event.data as string);
511
+ if (
512
+ message.method === "Network.loadNetworkResource" &&
513
+ props.sourceMapPath !== undefined &&
514
+ props.sourceMapMetadata !== undefined
515
+ ) {
516
+ // Read the generated source map from esbuild
517
+ const sourceMap = JSON.parse(
518
+ readFileSync(props.sourceMapPath, "utf-8")
519
+ );
520
+
521
+ // The source root is a temporary directory (`tmpDir`), and so shouldn't be user-visible
522
+ // It provides no useful info to the user
523
+ sourceMap.sourceRoot = "";
524
+
525
+ const tmpDir = props.sourceMapMetadata.tmpDir;
526
+
527
+ // See https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.mt2g20loc2ct
528
+ // The above link documents the x_google_ignoreList property, which is intended to mark code that shouldn't be visible in DevTools
529
+ // Here we use it to indicate specifically Wrangler-injected code (facades & middleware)
530
+ sourceMap.x_google_ignoreList = sourceMap.sources
531
+ // Filter anything in the generated tmpDir, and anything from Wrangler's templates
532
+ // This should cover facades and middleware, but intentionally doesn't include all non-user code e.g. node_modules
533
+ .map((s: string, idx: number) =>
534
+ s.includes(tmpDir) || s.includes("wrangler/templates")
535
+ ? idx
536
+ : null
537
+ )
538
+ .filter((i: number | null) => i !== null);
539
+
540
+ const entryDirectory = props.sourceMapMetadata.entryDirectory;
541
+
542
+ sourceMap.sources = sourceMap.sources.map(
543
+ (s: string) =>
544
+ // These are never loaded by Wrangler or DevTools. However, the presence of a scheme is required for DevTools to show the path as folders in the Sources view
545
+ // The scheme is intentially not the same as for the sourceMappingURL
546
+ // Without this difference in scheme, DevTools will not strip prefix `../` path elements from top level folders (../node_modules -> node_modules, for instance)
547
+ `worker://${props.name}/${path.relative(entryDirectory, s)}`
548
+ );
549
+
550
+ sendMessageToLocalWebSocket({
551
+ data: JSON.stringify({
552
+ id: message.id,
553
+ result: {
554
+ resource: {
555
+ success: true,
556
+ text: JSON.stringify(sourceMap),
557
+ },
558
+ },
559
+ }),
560
+ });
561
+ return;
562
+ }
563
+ } catch (e) {
564
+ logger.debug(e);
565
+ // Ignore errors, fallthrough to the remote inspector
566
+ }
484
567
  try {
485
568
  assert(
486
569
  remoteWebSocket,
@@ -505,11 +588,28 @@ export default function useInspector(props: InspectorProps) {
505
588
  }
506
589
 
507
590
  /** Send a message from the local websocket to the remote websocket */
508
- function sendMessageToLocalWebSocket(event: MessageEvent) {
591
+ function sendMessageToLocalWebSocket(event: Pick<MessageEvent, "data">) {
509
592
  assert(
510
593
  localWebSocket,
511
594
  "Trying to send a message to an undefined `localWebSocket`"
512
595
  );
596
+ try {
597
+ // Intercept Debugger.scriptParsed responses to inject URL schemes
598
+ const message = JSON.parse(event.data as string);
599
+ if (message.method === "Debugger.scriptParsed") {
600
+ // Add the worker:// scheme conditionally, since some module types already have schemes (e.g. wasm)
601
+ message.params.url = new URL(
602
+ message.params.url,
603
+ `worker://${props.name}`
604
+ ).href;
605
+ localWebSocket.send(JSON.stringify(message));
606
+ return;
607
+ }
608
+ } catch (e) {
609
+ logger.debug(e);
610
+ // Ignore errors, fallthrough to the local websocket
611
+ }
612
+
513
613
  localWebSocket.send(event.data);
514
614
  }
515
615
 
@@ -543,7 +643,13 @@ export default function useInspector(props: InspectorProps) {
543
643
  );
544
644
  }
545
645
  };
546
- }, [localWebSocket, remoteWebSocket]);
646
+ }, [
647
+ localWebSocket,
648
+ remoteWebSocket,
649
+ props.name,
650
+ props.sourceMapMetadata,
651
+ props.sourceMapPath,
652
+ ]);
547
653
  }
548
654
 
549
655
  // Credit: https://stackoverflow.com/a/2117523
@@ -732,8 +838,15 @@ function logConsoleMessage(evt: Protocol.Runtime.ConsoleAPICalledEvent): void {
732
838
  /**
733
839
  * Opens the chrome debugger
734
840
  */
735
- export const openInspector = async (inspectorPort: number) => {
736
- const url = `https://built-devtools.pages.dev/js_app?experiments=true&v8only=true&ws=localhost:${inspectorPort}/ws`;
841
+ export const openInspector = async (
842
+ inspectorPort: number,
843
+ worker: string | undefined
844
+ ) => {
845
+ const query = new URLSearchParams();
846
+ query.set("theme", "systemPreferred");
847
+ query.set("ws", `localhost:${inspectorPort}/ws`);
848
+ if (worker) query.set("domain", worker);
849
+ const url = `https://devtools.devprod.cloudflare.dev/js_app?${query.toString()}`;
737
850
  const errorMessage =
738
851
  "Failed to open inspector.\nInspector depends on having a Chromium-based browser installed, maybe you need to install one?";
739
852
 
@@ -759,6 +872,9 @@ export const openInspector = async (inspectorPort: number) => {
759
872
  {
760
873
  name: open.apps.edge,
761
874
  },
875
+ {
876
+ name: open.apps.firefox,
877
+ },
762
878
  ],
763
879
  });
764
880
  childProcess.on("error", () => {
package/src/jest.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare global {
2
+ const jest: unknown;
3
+ }
4
+ export {};
package/src/kv/helpers.ts CHANGED
@@ -8,7 +8,7 @@ import type { Config } from "../config";
8
8
  const API_MAX = 10000;
9
9
  // The const below are halved from the API's true capacity to help avoid
10
10
  // hammering it with large requests.
11
- const BATCH_KEY_MAX = API_MAX / 2;
11
+ export const BATCH_KEY_MAX = API_MAX / 2;
12
12
 
13
13
  type KvArgs = {
14
14
  binding?: string;
@@ -256,7 +256,7 @@ export async function deleteKVKeyValue(
256
256
  /**
257
257
  * Formatter for converting e.g. 5328 --> 5,328
258
258
  */
259
- const formatNumber = new Intl.NumberFormat("en-US", {
259
+ export const formatNumber = new Intl.NumberFormat("en-US", {
260
260
  notation: "standard",
261
261
  }).format;
262
262
 
@@ -279,7 +279,8 @@ export async function putKVBulkKeyValue(
279
279
  accountId: string,
280
280
  namespaceId: string,
281
281
  keyValues: KeyValue[],
282
- quiet = false
282
+ quiet = false,
283
+ abortSignal?: AbortSignal
283
284
  ) {
284
285
  for (let index = 0; index < keyValues.length; index += BATCH_KEY_MAX) {
285
286
  if (!quiet && keyValues.length > BATCH_KEY_MAX) {
@@ -292,7 +293,9 @@ export async function putKVBulkKeyValue(
292
293
  method: "PUT",
293
294
  body: JSON.stringify(keyValues.slice(index, index + BATCH_KEY_MAX)),
294
295
  headers: { "Content-Type": "application/json" },
295
- }
296
+ },
297
+ undefined,
298
+ abortSignal
296
299
  );
297
300
  }
298
301
 
package/src/kv/index.ts CHANGED
@@ -25,12 +25,10 @@ import {
25
25
  putKVKeyValue,
26
26
  unexpectedKVKeyValueProps,
27
27
  } from "./helpers";
28
- import type { ConfigPath } from "../index";
29
- import type { CommonYargsOptions } from "../yargs-types";
28
+ import type { CommonYargsArgv } from "../yargs-types";
30
29
  import type { KeyValue } from "./helpers";
31
- import type { Argv } from "yargs";
32
30
 
33
- export const kvNamespace = (kvYargs: Argv<CommonYargsOptions>) => {
31
+ export function kvNamespace(kvYargs: CommonYargsArgv) {
34
32
  return kvYargs
35
33
  .command(
36
34
  "create <namespace>",
@@ -56,7 +54,7 @@ export const kvNamespace = (kvYargs: Argv<CommonYargsOptions>) => {
56
54
  );
57
55
  }
58
56
 
59
- const config = readConfig(args.config as ConfigPath, args);
57
+ const config = readConfig(args.config, args);
60
58
  if (!config.name) {
61
59
  logger.warn(
62
60
  "No configured name present, using `worker` as a prefix for the title"
@@ -94,9 +92,9 @@ export const kvNamespace = (kvYargs: Argv<CommonYargsOptions>) => {
94
92
  .command(
95
93
  "list",
96
94
  "Outputs a list of all KV namespaces associated with your account id.",
97
- {},
95
+ (listArgs) => listArgs,
98
96
  async (args) => {
99
- const config = readConfig(args.config as ConfigPath, args);
97
+ const config = readConfig(args.config, args);
100
98
 
101
99
  const accountId = await requireAuth(config);
102
100
 
@@ -133,7 +131,7 @@ export const kvNamespace = (kvYargs: Argv<CommonYargsOptions>) => {
133
131
  },
134
132
  async (args) => {
135
133
  await printWranglerBanner();
136
- const config = readConfig(args.config as ConfigPath, args);
134
+ const config = readConfig(args.config, args);
137
135
 
138
136
  let id;
139
137
  try {
@@ -172,9 +170,9 @@ export const kvNamespace = (kvYargs: Argv<CommonYargsOptions>) => {
172
170
  // TODO: delete the preview namespace as well?
173
171
  }
174
172
  );
175
- };
173
+ }
176
174
 
177
- export const kvKey = (kvYargs: Argv<CommonYargsOptions>) => {
175
+ export const kvKey = (kvYargs: CommonYargsArgv) => {
178
176
  return kvYargs
179
177
  .command(
180
178
  "put <key> [value]",
@@ -231,7 +229,7 @@ export const kvKey = (kvYargs: Argv<CommonYargsOptions>) => {
231
229
  },
232
230
  async ({ key, ttl, expiration, metadata, ...args }) => {
233
231
  await printWranglerBanner();
234
- const config = readConfig(args.config as ConfigPath, args);
232
+ const config = readConfig(args.config, args);
235
233
  const namespaceId = getKVNamespaceId(args, config);
236
234
  // One of `args.path` and `args.value` must be defined
237
235
  const value = args.path
@@ -297,7 +295,7 @@ export const kvKey = (kvYargs: Argv<CommonYargsOptions>) => {
297
295
  },
298
296
  async ({ prefix, ...args }) => {
299
297
  // TODO: support for limit+cursor (pagination)
300
- const config = readConfig(args.config as ConfigPath, args);
298
+ const config = readConfig(args.config, args);
301
299
  const namespaceId = getKVNamespaceId(args, config);
302
300
 
303
301
  const accountId = await requireAuth(config);
@@ -351,7 +349,7 @@ export const kvKey = (kvYargs: Argv<CommonYargsOptions>) => {
351
349
  });
352
350
  },
353
351
  async ({ key, ...args }) => {
354
- const config = readConfig(args.config as ConfigPath, args);
352
+ const config = readConfig(args.config, args);
355
353
  const namespaceId = getKVNamespaceId(args, config);
356
354
 
357
355
  const accountId = await requireAuth(config);
@@ -398,7 +396,7 @@ export const kvKey = (kvYargs: Argv<CommonYargsOptions>) => {
398
396
  },
399
397
  async ({ key, ...args }) => {
400
398
  await printWranglerBanner();
401
- const config = readConfig(args.config as ConfigPath, args);
399
+ const config = readConfig(args.config, args);
402
400
  const namespaceId = getKVNamespaceId(args, config);
403
401
 
404
402
  logger.log(`Deleting the key "${key}" on namespace ${namespaceId}.`);
@@ -413,7 +411,7 @@ export const kvKey = (kvYargs: Argv<CommonYargsOptions>) => {
413
411
  );
414
412
  };
415
413
 
416
- export const kvBulk = (kvYargs: Argv<CommonYargsOptions>) => {
414
+ export const kvBulk = (kvYargs: CommonYargsArgv) => {
417
415
  return kvYargs
418
416
  .command(
419
417
  "put <filename>",
@@ -447,7 +445,7 @@ export const kvBulk = (kvYargs: Argv<CommonYargsOptions>) => {
447
445
  // This could be made more efficient with a streaming parser/uploader
448
446
  // but we'll do that in the future if needed.
449
447
 
450
- const config = readConfig(args.config as ConfigPath, args);
448
+ const config = readConfig(args.config, args);
451
449
  const namespaceId = getKVNamespaceId(args, config);
452
450
  const content = parseJSON(readFileSync(filename), filename);
453
451
 
@@ -541,7 +539,7 @@ export const kvBulk = (kvYargs: Argv<CommonYargsOptions>) => {
541
539
  },
542
540
  async ({ filename, ...args }) => {
543
541
  await printWranglerBanner();
544
- const config = readConfig(args.config as ConfigPath, args);
542
+ const config = readConfig(args.config, args);
545
543
  const namespaceId = getKVNamespaceId(args, config);
546
544
 
547
545
  if (!args.force) {
package/src/logger.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { format } from "node:util";
2
+ import chalk from "chalk";
3
+ import CLITable from "cli-table3";
2
4
  import { formatMessagesSync } from "esbuild";
3
- import { getEnvironmentVariableFactory } from "./environment-variables";
5
+ import { getEnvironmentVariableFactory } from "./environment-variables/factory";
4
6
  import type { BuildFailure } from "esbuild";
5
-
6
7
  export const LOGGER_LEVELS = {
7
8
  none: -1,
8
9
  error: 0,
@@ -25,13 +26,30 @@ const LOGGER_LEVEL_FORMAT_TYPE_MAP = {
25
26
 
26
27
  const getLogLevelFromEnv = getEnvironmentVariableFactory({
27
28
  variableName: "WRANGLER_LOG",
28
- defaultValue: "log",
29
29
  });
30
30
 
31
- class Logger {
31
+ function getLoggerLevel(): LoggerLevel {
32
+ const fromEnv = getLogLevelFromEnv()?.toLowerCase();
33
+ if (fromEnv !== undefined) {
34
+ if (fromEnv in LOGGER_LEVELS) return fromEnv as LoggerLevel;
35
+ const expected = Object.keys(LOGGER_LEVELS)
36
+ .map((level) => `"${level}"`)
37
+ .join(" | ");
38
+ console.warn(
39
+ `Unrecognised WRANGLER_LOG value ${JSON.stringify(
40
+ fromEnv
41
+ )}, expected ${expected}, defaulting to "log"...`
42
+ );
43
+ }
44
+ return "log";
45
+ }
46
+
47
+ export type TableRow<Keys extends string> = Record<Keys, string>;
48
+
49
+ export class Logger {
32
50
  constructor() {}
33
51
 
34
- loggerLevel: LoggerLevel = (getLogLevelFromEnv() as LoggerLevel) ?? "log";
52
+ loggerLevel = getLoggerLevel();
35
53
  columns = process.stdout.columns;
36
54
 
37
55
  debug = (...args: unknown[]) => this.doLog("debug", args);
@@ -39,6 +57,19 @@ class Logger {
39
57
  log = (...args: unknown[]) => this.doLog("log", args);
40
58
  warn = (...args: unknown[]) => this.doLog("warn", args);
41
59
  error = (...args: unknown[]) => this.doLog("error", args);
60
+ table<Keys extends string>(data: TableRow<Keys>[]) {
61
+ const keys: Keys[] =
62
+ data.length === 0 ? [] : (Object.keys(data[0]) as Keys[]);
63
+ const t = new CLITable({
64
+ head: keys,
65
+ style: {
66
+ head: chalk.level ? ["blue"] : [],
67
+ border: chalk.level ? ["gray"] : [],
68
+ },
69
+ });
70
+ t.push(...data.map((row) => keys.map((k) => row[k])));
71
+ return this.doLog("log", [t.toString()]);
72
+ }
42
73
 
43
74
  private doLog(messageLevel: Exclude<LoggerLevel, "none">, args: unknown[]) {
44
75
  if (LOGGER_LEVELS[this.loggerLevel] >= LOGGER_LEVELS[messageLevel]) {
@@ -1,11 +1,11 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
3
- import os from "node:os";
4
3
  import path from "node:path";
5
4
  import { fetchResult } from "../cfetch";
6
5
  import { getConfigCache, saveToConfigCache } from "../config-cache";
7
6
  import { confirm } from "../dialogs";
8
- import { getEnvironmentVariableFactory } from "../environment-variables";
7
+ import { getEnvironmentVariableFactory } from "../environment-variables/factory";
8
+ import { getGlobalWranglerConfigPath } from "../global-wrangler-config-path";
9
9
  import { CI } from "../is-ci";
10
10
  import isInteractive from "../is-interactive";
11
11
  import { logger } from "../logger";
@@ -167,7 +167,7 @@ export function readMetricsConfig(): MetricsConfigFile {
167
167
  * Get the path to the metrics config file.
168
168
  */
169
169
  function getMetricsConfigPath(): string {
170
- return path.resolve(os.homedir(), ".wrangler/config/metrics.json");
170
+ return path.resolve(getGlobalWranglerConfigPath(), "metrics.json");
171
171
  }
172
172
 
173
173
  /**
@@ -10,6 +10,8 @@ export type EventNames =
10
10
  | "delete worker script"
11
11
  | "begin log stream"
12
12
  | "end log stream"
13
+ | "begin pages log stream"
14
+ | "end pages log stream"
13
15
  | "create encrypted variable"
14
16
  | "delete encrypted variable"
15
17
  | "list encrypted variables"
@@ -53,7 +55,10 @@ export type EventNames =
53
55
  | "build pages functions"
54
56
  | "run dev"
55
57
  | "run dev (api)"
56
- | "run pages dev";
58
+ | "run pages dev"
59
+ | "view docs"
60
+ | "view deployments"
61
+ | "rollback deployments";
57
62
 
58
63
  /**
59
64
  * Send a metrics event, with no extra properties, to Cloudflare, if usage tracking is enabled.
@@ -3,54 +3,70 @@ import { join } from "node:path";
3
3
  import { createMetadataObject } from "@cloudflare/pages-shared/metadata-generator/createMetadataObject";
4
4
  import { parseHeaders } from "@cloudflare/pages-shared/metadata-generator/parseHeaders";
5
5
  import { parseRedirects } from "@cloudflare/pages-shared/metadata-generator/parseRedirects";
6
- import { fetch as miniflareFetch } from "@miniflare/core";
7
- import {
8
- Response as MiniflareResponse,
9
- Request as MiniflareRequest,
10
- } from "@miniflare/core";
11
6
  import { watch } from "chokidar";
12
7
  import { getType } from "mime";
13
8
  import { hashFile } from "../pages/hash";
14
9
  import type { Metadata } from "@cloudflare/pages-shared/asset-server/metadata";
15
- import type {
16
- fetch,
17
- Request,
18
- } from "@cloudflare/pages-shared/environment-polyfills/types";
19
10
  import type {
20
11
  ParsedRedirects,
21
12
  ParsedHeaders,
22
13
  } from "@cloudflare/pages-shared/metadata-generator/types";
23
- import type { RequestInfo, RequestInit, FetcherFetch } from "@miniflare/core";
24
- import type { Log } from "miniflare";
14
+ import type {
15
+ Request as MiniflareRequest,
16
+ RequestInfo as MiniflareRequestInfo,
17
+ RequestInit as MiniflareRequestInit,
18
+ } from "@miniflare/core";
19
+
20
+ interface Logger {
21
+ log: (message: string) => void;
22
+ warn: (message: string) => void;
23
+ error: (error: Error) => void;
24
+ }
25
25
 
26
26
  export interface Options {
27
- log: Log;
27
+ log: Logger;
28
28
  proxyPort?: number;
29
29
  directory?: string;
30
+ tre: boolean;
30
31
  }
31
32
 
32
33
  export default async function generateASSETSBinding(options: Options) {
33
34
  const assetsFetch =
34
35
  options.directory !== undefined
35
- ? await generateAssetsFetch(options.directory, options.log)
36
+ ? await generateAssetsFetch(options.directory, options.log, options.tre)
36
37
  : invalidAssetsFetch;
37
38
 
38
- return async function (miniflareRequest: MiniflareRequest) {
39
+ const miniflare = options.tre
40
+ ? await import("@miniflare/tre")
41
+ : await import("@miniflare/core");
42
+
43
+ const Request = miniflare.Request as typeof MiniflareRequest;
44
+ const Response = miniflare.Response;
45
+ // WebSockets won't work with `--experimental-local` until we expose something like `upgradingFetch` from `@miniflare/tre`.
46
+ const fetch = (
47
+ options.tre
48
+ ? miniflare.fetch
49
+ : (await import("@miniflare/web-sockets")).upgradingFetch
50
+ ) as (request: Request) => Promise<Response>;
51
+
52
+ return async function (miniflareRequest: Request) {
39
53
  if (options.proxyPort) {
40
54
  try {
41
55
  const url = new URL(miniflareRequest.url);
42
56
  url.host = `localhost:${options.proxyPort}`;
43
- return await miniflareFetch(url, miniflareRequest);
57
+ const proxyRequest = new Request(url, miniflareRequest);
58
+ if (proxyRequest.headers.get("Upgrade") === "websocket") {
59
+ proxyRequest.headers.delete("Sec-WebSocket-Accept");
60
+ proxyRequest.headers.delete("Sec-WebSocket-Key");
61
+ }
62
+ return await fetch(proxyRequest as Request);
44
63
  } catch (thrown) {
45
64
  options.log.error(new Error(`Could not proxy request: ${thrown}`));
46
65
 
47
66
  // TODO: Pretty error page
48
- return new MiniflareResponse(
49
- `[wrangler] Could not proxy request: ${thrown}`,
50
- {
51
- status: 502,
52
- }
53
- );
67
+ return new Response(`[wrangler] Could not proxy request: ${thrown}`, {
68
+ status: 502,
69
+ });
54
70
  }
55
71
  } else {
56
72
  try {
@@ -59,21 +75,41 @@ export default async function generateASSETSBinding(options: Options) {
59
75
  options.log.error(new Error(`Could not serve static asset: ${thrown}`));
60
76
 
61
77
  // TODO: Pretty error page
62
- return new MiniflareResponse(
78
+ return new Response(
63
79
  `[wrangler] Could not serve static asset: ${thrown}`,
64
80
  { status: 502 }
65
81
  );
66
82
  }
67
83
  }
68
- } as FetcherFetch;
84
+ };
69
85
  }
70
86
 
71
87
  async function generateAssetsFetch(
72
88
  directory: string,
73
- log: Log
89
+ log: Logger,
90
+ tre: boolean
74
91
  ): Promise<typeof fetch> {
75
92
  // Defer importing miniflare until we really need it
76
- await import("@cloudflare/pages-shared/environment-polyfills/miniflare");
93
+
94
+ // NOTE: These dynamic imports bring in `global` type augmentations from
95
+ // `@cloudflare/pages-shared/environment-polyfills/types.ts`, allowing us to
96
+ // use `fetch`, `Headers`, `Request` and `Response` as globals in this file
97
+ // and the *entire* `miniflare-cli` TypeScript project.
98
+ const polyfill = tre
99
+ ? (
100
+ await import(
101
+ "@cloudflare/pages-shared/environment-polyfills/miniflare-tre"
102
+ )
103
+ ).default
104
+ : (await import("@cloudflare/pages-shared/environment-polyfills/miniflare"))
105
+ .default;
106
+
107
+ await polyfill();
108
+
109
+ const miniflare = tre
110
+ ? await import("@miniflare/tre")
111
+ : await import("@miniflare/core");
112
+ const Request = miniflare.Request as typeof MiniflareRequest;
77
113
 
78
114
  const { generateHandler, parseQualityWeightedList } = await import(
79
115
  "@cloudflare/pages-shared/asset-server/handler"
@@ -184,7 +220,7 @@ async function generateAssetsFetch(
184
220
  const filepath = assetKeyEntryMap.get(assetKey);
185
221
  if (!filepath) {
186
222
  throw new Error(
187
- "Could not fetch asset. Please file an issue on GitHub (https://github.com/cloudflare/wrangler2/issues/new/choose) with reproduction steps."
223
+ "Could not fetch asset. Please file an issue on GitHub (https://github.com/cloudflare/workers-sdk/issues/new/choose) with reproduction steps."
188
224
  );
189
225
  }
190
226
  const body = readFileSync(filepath) as unknown as ReadableStream;
@@ -202,8 +238,8 @@ async function generateAssetsFetch(
202
238
  });
203
239
  };
204
240
 
205
- return async (input: RequestInfo, init?: RequestInit) => {
206
- const request = new MiniflareRequest(input, init);
241
+ return async (input: MiniflareRequestInfo, init?: MiniflareRequestInit) => {
242
+ const request = new Request(input, init);
207
243
  return await generateResponse(request as unknown as Request);
208
244
  };
209
245
  }
@@ -1,8 +1,8 @@
1
- import { fetch } from "@miniflare/core";
2
1
  import {
3
2
  DurableObjectNamespace,
4
3
  DurableObjectStub,
5
4
  } from "@miniflare/durable-objects";
5
+ import { upgradingFetch } from "@miniflare/web-sockets";
6
6
  import {
7
7
  Log as MiniflareLog,
8
8
  LogLevel as MiniflareLogLevel,
@@ -17,13 +17,9 @@ import generateASSETSBinding from "./assets";
17
17
  import { getRequestContextCheckOptions } from "./request-context";
18
18
  import type { LoggerLevel } from "../logger";
19
19
  import type { Options } from "./assets";
20
+ import type { EnablePagesAssetsServiceBindingOptions } from "./types";
20
21
  import type { AddressInfo } from "net";
21
22
 
22
- export interface EnablePagesAssetsServiceBindingOptions {
23
- proxyPort?: number;
24
- directory?: string;
25
- }
26
-
27
23
  // miniflare defines this but importing it throws:
28
24
  // Dynamic require of "path" is not supported
29
25
  class MiniflareNoOpLog extends MiniflareLog {
@@ -51,7 +47,7 @@ async function main() {
51
47
  config.log =
52
48
  logLevel === MiniflareLogLevel.NONE
53
49
  ? new MiniflareNoOpLog()
54
- : new MiniflareLog(logLevel, config.logOptions);
50
+ : new MiniflareLog(logLevel);
55
51
 
56
52
  if (logLevel === MiniflareLogLevel.DEBUG) {
57
53
  console.log("MINIFLARE OPTIONS:\n", JSON.stringify(config, null, 2));
@@ -91,7 +87,7 @@ async function main() {
91
87
  id.toString()
92
88
  );
93
89
 
94
- return fetch(request);
90
+ return upgradingFetch(request);
95
91
  };
96
92
  return stub;
97
93
  };
@@ -120,6 +116,7 @@ async function main() {
120
116
  log: config.log,
121
117
  proxyPort: opts.proxyPort,
122
118
  directory: opts.directory,
119
+ tre: false,
123
120
  };
124
121
 
125
122
  config.serviceBindings = {
@@ -196,7 +193,7 @@ async function main() {
196
193
  process.send &&
197
194
  process.send(
198
195
  JSON.stringify({
199
- mfPort: mfPort,
196
+ port: mfPort,
200
197
  ready: true,
201
198
  durableObjectsPort: durableObjectsMfPort,
202
199
  })