wrangler 0.0.0-e2b7352 → 0.0.0-e305903a

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 (264) hide show
  1. package/Cloudflare_CA.pem +18 -0
  2. package/README.md +51 -14
  3. package/bin/wrangler.js +154 -31
  4. package/kv-asset-handler.js +1 -0
  5. package/miniflare-dist/index.mjs +6244 -21
  6. package/package.json +185 -141
  7. package/src/__tests__/api-dev.test.ts +209 -0
  8. package/src/__tests__/api-devregistry.test.js +56 -0
  9. package/src/__tests__/api.test.ts +80 -0
  10. package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
  11. package/src/__tests__/config-cache.test.ts +42 -0
  12. package/src/__tests__/configuration.test.ts +4122 -2810
  13. package/src/__tests__/dev.test.tsx +1341 -527
  14. package/src/__tests__/dialogs.test.tsx +40 -0
  15. package/src/__tests__/generate.test.ts +91 -0
  16. package/src/__tests__/guess-worker-format.test.ts +74 -57
  17. package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
  18. package/src/__tests__/helpers/mock-account-id.ts +24 -24
  19. package/src/__tests__/helpers/mock-bin.ts +20 -20
  20. package/src/__tests__/helpers/mock-cfetch.ts +202 -93
  21. package/src/__tests__/helpers/mock-console.ts +68 -32
  22. package/src/__tests__/helpers/mock-dialogs.ts +121 -33
  23. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  24. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  25. package/src/__tests__/helpers/mock-istty.ts +74 -0
  26. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  27. package/src/__tests__/helpers/mock-kv.ts +26 -26
  28. package/src/__tests__/helpers/mock-oauth-flow.ts +252 -0
  29. package/src/__tests__/helpers/mock-process.ts +39 -0
  30. package/src/__tests__/helpers/mock-stdin.ts +82 -77
  31. package/src/__tests__/helpers/mock-web-socket.ts +21 -21
  32. package/src/__tests__/helpers/msw/handlers/index.ts +13 -0
  33. package/src/__tests__/helpers/msw/handlers/namespaces.ts +104 -0
  34. package/src/__tests__/helpers/msw/handlers/oauth.ts +36 -0
  35. package/src/__tests__/helpers/msw/handlers/r2.ts +80 -0
  36. package/src/__tests__/helpers/msw/handlers/user.ts +63 -0
  37. package/src/__tests__/helpers/msw/index.ts +4 -0
  38. package/src/__tests__/helpers/run-in-tmp.ts +28 -22
  39. package/src/__tests__/helpers/run-wrangler.ts +8 -8
  40. package/src/__tests__/helpers/worker-scripts/child-wrangler.toml +1 -0
  41. package/src/__tests__/helpers/worker-scripts/hello-world-worker.js +5 -0
  42. package/src/__tests__/helpers/worker-scripts/hello-world-wrangler.toml +1 -0
  43. package/src/__tests__/helpers/worker-scripts/parent-worker.js +8 -0
  44. package/src/__tests__/helpers/worker-scripts/parent-wrangler.toml +5 -0
  45. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  46. package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
  47. package/src/__tests__/https-options.test.ts +144 -108
  48. package/src/__tests__/index.test.ts +233 -967
  49. package/src/__tests__/init.test.ts +2717 -0
  50. package/src/__tests__/jest.setup.ts +151 -34
  51. package/src/__tests__/kv.test.ts +1376 -1085
  52. package/src/__tests__/logger.test.ts +141 -0
  53. package/src/__tests__/metrics.test.ts +450 -0
  54. package/src/__tests__/middleware.scheduled.test.ts +135 -0
  55. package/src/__tests__/middleware.test.ts +726 -0
  56. package/src/__tests__/package-manager.test.ts +312 -165
  57. package/src/__tests__/pages.test.ts +1990 -77
  58. package/src/__tests__/parse.test.ts +253 -245
  59. package/src/__tests__/paths.test.ts +39 -0
  60. package/src/__tests__/publish.test.ts +6989 -3411
  61. package/src/__tests__/pubsub.test.ts +367 -0
  62. package/src/__tests__/r2.test.ts +363 -190
  63. package/src/__tests__/route.test.ts +22 -22
  64. package/src/__tests__/secret.test.ts +626 -407
  65. package/src/__tests__/tail.test.ts +653 -516
  66. package/src/__tests__/test-old-node-version.js +31 -0
  67. package/src/__tests__/user.test.ts +155 -0
  68. package/src/__tests__/validate-dev-props.test.ts +56 -0
  69. package/src/__tests__/version.test.ts +35 -0
  70. package/src/__tests__/whoami.test.tsx +261 -88
  71. package/src/__tests__/worker-namespace.test.ts +319 -0
  72. package/src/abort.d.ts +3 -0
  73. package/src/api/dev.ts +206 -0
  74. package/src/api/index.ts +2 -0
  75. package/src/bundle-reporter.tsx +29 -0
  76. package/src/bundle.ts +723 -122
  77. package/src/cfetch/index.ts +83 -66
  78. package/src/cfetch/internal.ts +267 -92
  79. package/src/cli.ts +24 -14
  80. package/src/config/README.md +1 -1
  81. package/src/config/config.ts +236 -179
  82. package/src/config/diagnostics.ts +61 -61
  83. package/src/config/environment.ts +450 -316
  84. package/src/config/index.ts +259 -38
  85. package/src/config/validation-helpers.ts +385 -342
  86. package/src/config/validation.ts +1797 -1099
  87. package/src/config-cache.ts +85 -0
  88. package/src/create-worker-preview.ts +233 -124
  89. package/src/create-worker-upload-form.ts +285 -201
  90. package/src/d1/backups.tsx +212 -0
  91. package/src/d1/create.tsx +54 -0
  92. package/src/d1/delete.tsx +56 -0
  93. package/src/d1/execute.tsx +294 -0
  94. package/src/d1/formatTimeAgo.ts +14 -0
  95. package/src/d1/index.ts +75 -0
  96. package/src/d1/list.tsx +48 -0
  97. package/src/d1/options.ts +12 -0
  98. package/src/d1/types.tsx +14 -0
  99. package/src/d1/utils.ts +39 -0
  100. package/src/dev/dev-vars.ts +36 -0
  101. package/src/dev/dev.tsx +501 -328
  102. package/src/dev/get-local-persistence-path.tsx +31 -0
  103. package/src/dev/local.tsx +629 -211
  104. package/src/dev/remote.tsx +398 -188
  105. package/src/dev/start-server.ts +443 -0
  106. package/src/dev/use-esbuild.ts +175 -82
  107. package/src/dev/validate-dev-props.ts +31 -0
  108. package/src/dev-registry.tsx +190 -0
  109. package/src/dev.tsx +869 -0
  110. package/src/dialogs.tsx +138 -57
  111. package/src/dispatch-namespace.ts +206 -0
  112. package/src/durable.ts +102 -0
  113. package/src/entry.ts +260 -171
  114. package/src/environment-variables.ts +40 -23
  115. package/src/errors.ts +11 -0
  116. package/src/faye-websocket.d.ts +6 -0
  117. package/src/generate.ts +131 -0
  118. package/src/git-client.ts +42 -0
  119. package/src/global-wrangler-config-path.ts +26 -0
  120. package/src/https-options.ts +85 -80
  121. package/src/index.tsx +2295 -2315
  122. package/src/init.ts +967 -0
  123. package/src/inspect.ts +687 -557
  124. package/src/intl-polyfill.d.ts +123 -123
  125. package/src/is-ci.ts +14 -0
  126. package/src/is-interactive.ts +12 -0
  127. package/src/kv.ts +353 -242
  128. package/src/logger.ts +80 -0
  129. package/src/metrics/index.ts +5 -0
  130. package/src/metrics/metrics-config.ts +239 -0
  131. package/src/metrics/metrics-dispatcher.ts +96 -0
  132. package/src/metrics/metrics-usage-headers.ts +24 -0
  133. package/src/metrics/send-event.ts +93 -0
  134. package/src/miniflare-cli/assets.ts +215 -0
  135. package/src/miniflare-cli/index.ts +201 -30
  136. package/src/miniflare-cli/request-context.ts +40 -0
  137. package/src/module-collection.ts +213 -213
  138. package/src/open-in-browser.ts +8 -16
  139. package/src/package-manager.ts +183 -90
  140. package/src/pages/build.tsx +238 -0
  141. package/src/pages/constants.ts +16 -0
  142. package/src/pages/deployments.tsx +106 -0
  143. package/src/pages/dev.tsx +684 -0
  144. package/src/pages/errors.ts +66 -0
  145. package/src/pages/functions/buildPlugin.ts +110 -0
  146. package/src/pages/functions/buildWorker.ts +156 -0
  147. package/src/pages/functions/filepath-routing.test.ts +234 -0
  148. package/src/pages/functions/filepath-routing.ts +189 -0
  149. package/src/pages/functions/identifiers.ts +78 -0
  150. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  151. package/src/pages/functions/routes-consolidation.ts +73 -0
  152. package/src/pages/functions/routes-transformation.test.ts +282 -0
  153. package/src/pages/functions/routes-transformation.ts +115 -0
  154. package/src/pages/functions/routes-validation.test.ts +403 -0
  155. package/src/pages/functions/routes-validation.ts +202 -0
  156. package/src/pages/functions/routes.ts +151 -0
  157. package/src/pages/functions.tsx +82 -0
  158. package/src/pages/hash.tsx +13 -0
  159. package/src/pages/index.tsx +94 -0
  160. package/src/pages/projects.tsx +169 -0
  161. package/src/pages/publish.tsx +419 -0
  162. package/src/pages/types.ts +49 -0
  163. package/src/pages/upload.tsx +398 -0
  164. package/src/pages/utils.ts +12 -0
  165. package/src/parse.ts +224 -121
  166. package/src/paths.ts +53 -8
  167. package/src/preview.ts +31 -0
  168. package/src/proxy.ts +436 -370
  169. package/src/publish.ts +839 -324
  170. package/src/pubsub/index.ts +286 -0
  171. package/src/pubsub/pubsub-commands.tsx +623 -0
  172. package/src/r2.ts +100 -19
  173. package/src/selfsigned.d.ts +23 -23
  174. package/src/sites.tsx +281 -189
  175. package/src/tail/filters.ts +108 -110
  176. package/src/tail/index.ts +234 -218
  177. package/src/tail/printing.ts +92 -47
  178. package/src/update-check.ts +19 -0
  179. package/src/user/choose-account.tsx +69 -0
  180. package/src/user/env-vars.ts +46 -0
  181. package/src/user/generate-auth-url.ts +33 -0
  182. package/src/user/generate-random-state.ts +16 -0
  183. package/src/user/index.ts +3 -0
  184. package/src/user/user.tsx +1192 -0
  185. package/src/whoami.tsx +142 -42
  186. package/src/worker.ts +171 -100
  187. package/src/zones.ts +167 -0
  188. package/templates/checked-fetch.js +17 -0
  189. package/templates/d1-beta-facade.js +174 -0
  190. package/templates/experimental-local-cache-stubs.js +27 -0
  191. package/templates/first-party-worker-module-facade.ts +18 -0
  192. package/templates/format-dev-errors.ts +32 -0
  193. package/templates/gitignore +171 -0
  194. package/templates/init-tests/test-jest-new-worker.js +25 -0
  195. package/templates/init-tests/test-vitest-new-worker.js +26 -0
  196. package/templates/middleware/common.ts +62 -0
  197. package/templates/middleware/loader-modules.ts +84 -0
  198. package/templates/middleware/loader-sw.ts +213 -0
  199. package/templates/middleware/middleware-pretty-error.ts +40 -0
  200. package/templates/middleware/middleware-scheduled.ts +15 -0
  201. package/templates/new-worker-scheduled.js +17 -0
  202. package/templates/new-worker-scheduled.ts +32 -0
  203. package/templates/new-worker.js +3 -3
  204. package/templates/new-worker.ts +18 -3
  205. package/templates/no-op-worker.js +10 -0
  206. package/templates/pages-dev-pipeline.ts +35 -0
  207. package/templates/pages-shim.ts +9 -0
  208. package/templates/pages-template-plugin.ts +167 -0
  209. package/templates/pages-template-worker.ts +172 -0
  210. package/templates/serve-static-assets.ts +63 -0
  211. package/templates/service-bindings-module-facade.js +54 -0
  212. package/templates/service-bindings-sw-facade.js +42 -0
  213. package/templates/tsconfig.json +95 -95
  214. package/wrangler-dist/cli.d.ts +841 -0
  215. package/wrangler-dist/cli.js +129492 -108210
  216. package/miniflare-dist/index.mjs.map +0 -7
  217. package/pages/functions/buildWorker.ts +0 -62
  218. package/pages/functions/filepath-routing.test.ts +0 -223
  219. package/pages/functions/filepath-routing.ts +0 -181
  220. package/pages/functions/identifiers.ts +0 -78
  221. package/pages/functions/routes.ts +0 -151
  222. package/pages/functions/template-worker.ts +0 -130
  223. package/src/__tests__/helpers/faye-websocket.d.ts +0 -6
  224. package/src/__tests__/logout.test.ts +0 -52
  225. package/src/__tests__/sentry.test.ts +0 -146
  226. package/src/miniflare-cli/enum-keys.ts +0 -17
  227. package/src/pages.tsx +0 -1061
  228. package/src/reporting.ts +0 -131
  229. package/src/user.tsx +0 -1127
  230. package/templates/static-asset-facade.js +0 -47
  231. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  232. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  233. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  234. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  235. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  236. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  237. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  238. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  239. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  240. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  241. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  242. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  243. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  244. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  245. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  246. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  247. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  248. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  249. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  250. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  251. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  252. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  253. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  254. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  255. package/vendor/wrangler-mime/LICENSE +0 -21
  256. package/vendor/wrangler-mime/Mime.js +0 -97
  257. package/vendor/wrangler-mime/README.md +0 -187
  258. package/vendor/wrangler-mime/cli.js +0 -46
  259. package/vendor/wrangler-mime/index.js +0 -4
  260. package/vendor/wrangler-mime/lite.js +0 -4
  261. package/vendor/wrangler-mime/package.json +0 -52
  262. package/vendor/wrangler-mime/types/other.js +0 -1
  263. package/vendor/wrangler-mime/types/standard.js +0 -1
  264. package/wrangler-dist/cli.js.map +0 -7
package/src/dev/local.tsx CHANGED
@@ -1,232 +1,650 @@
1
- import { spawn } from "node:child_process";
1
+ import { fork } from "node:child_process";
2
2
  import { realpathSync } from "node:fs";
3
3
  import { writeFile } from "node:fs/promises";
4
4
  import path from "node:path";
5
+ import { npxImport } from "npx-import";
5
6
  import { useState, useEffect, useRef } from "react";
6
7
  import onExit from "signal-exit";
8
+ import { registerWorker } from "../dev-registry";
7
9
  import useInspector from "../inspect";
10
+ import { logger } from "../logger";
8
11
  import { DEFAULT_MODULE_RULES } from "../module-collection";
12
+ import { getBasePath } from "../paths";
9
13
  import { waitForPortToBeAvailable } from "../proxy";
10
14
  import type { Config } from "../config";
15
+ import type { WorkerRegistry } from "../dev-registry";
16
+ import type { EnablePagesAssetsServiceBindingOptions } from "../miniflare-cli";
11
17
  import type { AssetPaths } from "../sites";
12
- import type { CfWorkerInit, CfScriptFormat } from "../worker";
18
+ import type {
19
+ CfWorkerInit,
20
+ CfScriptFormat,
21
+ CfWasmModuleBindings,
22
+ CfTextBlobBindings,
23
+ CfDataBlobBindings,
24
+ CfDurableObject,
25
+ CfKvNamespace,
26
+ CfR2Bucket,
27
+ CfVars,
28
+ CfD1Database,
29
+ } from "../worker";
13
30
  import type { EsbuildBundle } from "./use-esbuild";
31
+ import type {
32
+ Miniflare as Miniflare3Type,
33
+ MiniflareOptions as Miniflare3Options,
34
+ } from "@miniflare/tre";
14
35
  import type { MiniflareOptions } from "miniflare";
36
+ import type { ChildProcess } from "node:child_process";
15
37
 
16
- interface LocalProps {
17
- name: undefined | string;
18
- bundle: EsbuildBundle | undefined;
19
- format: CfScriptFormat | undefined;
20
- compatibilityDate: string | undefined;
21
- compatibilityFlags: undefined | string[];
22
- bindings: CfWorkerInit["bindings"];
23
- assetPaths: undefined | AssetPaths;
24
- public: undefined | string;
25
- port: number;
26
- ip: string;
27
- rules: Config["rules"];
28
- inspectorPort: number;
29
- enableLocalPersistence: boolean;
38
+ // caching of the miniflare package
39
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
40
+ let Miniflare: typeof import("@miniflare/tre")["Miniflare"];
41
+
42
+ export interface LocalProps {
43
+ name: string | undefined;
44
+ bundle: EsbuildBundle | undefined;
45
+ format: CfScriptFormat | undefined;
46
+ compatibilityDate: string;
47
+ compatibilityFlags: string[] | undefined;
48
+ usageModel: "bundled" | "unbound" | undefined;
49
+ bindings: CfWorkerInit["bindings"];
50
+ workerDefinitions: WorkerRegistry | undefined;
51
+ assetPaths: AssetPaths | undefined;
52
+ port: number;
53
+ ip: string;
54
+ rules: Config["rules"];
55
+ inspectorPort: number;
56
+ localPersistencePath: string | null;
57
+ liveReload: boolean;
58
+ crons: Config["triggers"]["crons"];
59
+ localProtocol: "http" | "https";
60
+ localUpstream: string | undefined;
61
+ inspect: boolean;
62
+ onReady: ((ip: string, port: number) => void) | undefined;
63
+ logPrefix?: string;
64
+ enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
65
+ testScheduled?: boolean;
66
+ experimentalLocal?: boolean;
30
67
  }
31
68
 
32
69
  export function Local(props: LocalProps) {
33
- const { inspectorUrl } = useLocalWorker(props);
34
- useInspector({
35
- inspectorUrl,
36
- port: props.inspectorPort,
37
- logToTerminal: false,
38
- });
39
- return null;
70
+ const { inspectorUrl } = useLocalWorker(props);
71
+ useInspector({
72
+ inspectorUrl,
73
+ port: props.inspectorPort,
74
+ logToTerminal: false,
75
+ });
76
+ return null;
77
+ }
78
+
79
+ function arrayToObject(values: string[] = []): Record<string, string> {
80
+ return Object.fromEntries(values.map((value) => [value, value]));
40
81
  }
41
82
 
42
83
  function useLocalWorker({
43
- name: workerName,
44
- bundle,
45
- format,
46
- compatibilityDate,
47
- compatibilityFlags,
48
- bindings,
49
- assetPaths,
50
- public: publicDirectory,
51
- port,
52
- rules,
53
- enableLocalPersistence,
54
- ip,
84
+ name: workerName,
85
+ bundle,
86
+ format,
87
+ compatibilityDate,
88
+ compatibilityFlags,
89
+ usageModel,
90
+ bindings,
91
+ workerDefinitions,
92
+ assetPaths,
93
+ port,
94
+ inspectorPort,
95
+ rules,
96
+ localPersistencePath,
97
+ liveReload,
98
+ ip,
99
+ crons,
100
+ localProtocol,
101
+ localUpstream,
102
+ inspect,
103
+ onReady,
104
+ logPrefix,
105
+ enablePagesAssetsServiceBinding,
106
+ experimentalLocal,
55
107
  }: LocalProps) {
56
- // TODO: pass vars via command line
57
- const local = useRef<ReturnType<typeof spawn>>();
58
- const removeSignalExitListener = useRef<() => void>();
59
- const [inspectorUrl, setInspectorUrl] = useState<string | undefined>();
60
- useEffect(() => {
61
- async function startLocalWorker() {
62
- if (!bundle || !format) return;
63
-
64
- // port for the worker
65
- await waitForPortToBeAvailable(port, { retryPeriod: 200, timeout: 2000 });
66
-
67
- if (publicDirectory) {
68
- throw new Error(
69
- '⎔ A "public" folder is not yet supported in local mode.'
70
- );
71
- }
72
-
73
- // In local mode, we want to copy all referenced modules into
74
- // the output bundle directory before starting up
75
- for (const module of bundle.modules) {
76
- await writeFile(
77
- path.join(path.dirname(bundle.path), module.name),
78
- module.content
79
- );
80
- }
81
-
82
- const scriptPath = realpathSync(bundle.path);
83
-
84
- const wasmBindings = { ...bindings.wasm_modules };
85
- if (format === "service-worker") {
86
- for (const { type, name } of bundle.modules) {
87
- if (type === "compiled-wasm") {
88
- // In service-worker format, .wasm modules are referenced by global identifiers,
89
- // so we convert it here.
90
- // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
91
- // characters with an underscore.
92
- const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
93
- wasmBindings[identifier] = name;
94
- }
95
- }
96
- }
97
-
98
- const options: MiniflareOptions = {
99
- name: workerName,
100
- port,
101
- scriptPath,
102
- host: ip,
103
- modules: format === "modules",
104
- modulesRules: (rules || [])
105
- .concat(DEFAULT_MODULE_RULES)
106
- .map(({ type, globs: include, fallthrough }) => ({
107
- type,
108
- include,
109
- fallthrough,
110
- })),
111
- compatibilityDate,
112
- compatibilityFlags,
113
- kvNamespaces: bindings.kv_namespaces?.map((kv) => kv.binding),
114
- kvPersist: enableLocalPersistence,
115
- durableObjects: Object.fromEntries(
116
- (bindings.durable_objects?.bindings ?? []).map<[string, string]>(
117
- (value) => [value.name, value.class_name]
118
- )
119
- ),
120
- durableObjectsPersist: enableLocalPersistence,
121
- cachePersist: enableLocalPersistence,
122
- sitePath: assetPaths?.assetDirectory
123
- ? path.join(assetPaths.baseDirectory, assetPaths.assetDirectory)
124
- : undefined,
125
- siteInclude: assetPaths?.includePatterns.length
126
- ? assetPaths?.includePatterns
127
- : undefined,
128
- siteExclude: assetPaths?.excludePatterns.length
129
- ? assetPaths.excludePatterns
130
- : undefined,
131
- bindings: bindings.vars,
132
- wasmBindings,
133
- sourceMap: true,
134
- logUnhandledRejections: true,
135
- };
136
-
137
- // The path to the Miniflare CLI assumes that this file is being run from
138
- // `wrangler-dist` and that the CLI is found in `miniflare-dist`.
139
- // If either of those paths change this line needs updating.
140
- const miniflareCLIPath = path.resolve(
141
- __dirname,
142
- "../miniflare-dist/index.mjs"
143
- );
144
- const optionsArg = JSON.stringify(options, null);
145
-
146
- console.log("⎔ Starting a local server...");
147
- local.current = spawn(
148
- "node",
149
- [
150
- "--experimental-vm-modules", // ensures that Miniflare can run ESM Workers
151
- "--no-warnings", // hide annoying Node warnings
152
- "--inspect", // start Miniflare listening for a debugger to attach
153
- miniflareCLIPath,
154
- optionsArg,
155
- // "--log=VERBOSE", // uncomment this to Miniflare to log "everything"!
156
- ],
157
- {
158
- cwd: path.dirname(scriptPath),
159
- }
160
- );
161
-
162
- local.current.on("close", (code) => {
163
- if (code) {
164
- console.log(`Miniflare process exited with code ${code}`);
165
- }
166
- });
167
-
168
- local.current.stdout?.on("data", (data: Buffer) => {
169
- console.log(`${data.toString()}`);
170
- });
171
-
172
- local.current.stderr?.on("data", (data: Buffer) => {
173
- console.error(`${data.toString()}`);
174
- const matches =
175
- /Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)/.exec(
176
- data.toString()
177
- );
178
- if (matches) {
179
- setInspectorUrl(matches[1]);
180
- }
181
- });
182
-
183
- local.current.on("exit", (code) => {
184
- if (code) {
185
- console.error(`Miniflare process exited with code ${code}`);
186
- }
187
- });
188
-
189
- local.current.on("error", (error: Error) => {
190
- console.error(`Miniflare process failed to spawn`);
191
- console.error(error);
192
- });
193
-
194
- removeSignalExitListener.current = onExit((_code, _signal) => {
195
- console.log("⎔ Shutting down local server.");
196
- local.current?.kill();
197
- local.current = undefined;
198
- });
199
- }
200
-
201
- startLocalWorker().catch((err) => {
202
- console.error("local worker:", err);
203
- });
204
-
205
- return () => {
206
- if (local.current) {
207
- console.log("⎔ Shutting down local server.");
208
- local.current?.kill();
209
- local.current = undefined;
210
- removeSignalExitListener.current && removeSignalExitListener.current();
211
- removeSignalExitListener.current = undefined;
212
- }
213
- };
214
- }, [
215
- bundle,
216
- workerName,
217
- format,
218
- port,
219
- ip,
220
- bindings.durable_objects?.bindings,
221
- bindings.kv_namespaces,
222
- bindings.vars,
223
- compatibilityDate,
224
- compatibilityFlags,
225
- enableLocalPersistence,
226
- assetPaths,
227
- publicDirectory,
228
- rules,
229
- bindings.wasm_modules,
230
- ]);
231
- return { inspectorUrl };
108
+ // TODO: pass vars via command line
109
+ const local = useRef<ChildProcess>();
110
+ const experimentalLocalRef = useRef<Miniflare3Type>();
111
+ const removeSignalExitListener = useRef<() => void>();
112
+ const [inspectorUrl, setInspectorUrl] = useState<string | undefined>();
113
+
114
+ useEffect(() => {
115
+ if (bindings.services && bindings.services.length > 0) {
116
+ logger.warn(
117
+ "⎔ Support for service bindings in local mode is experimental and may change."
118
+ );
119
+ }
120
+ }, [bindings.services]);
121
+
122
+ useEffect(() => {
123
+ const externalDurableObjects = (
124
+ bindings.durable_objects?.bindings || []
125
+ ).filter((binding) => binding.script_name);
126
+
127
+ if (externalDurableObjects.length > 0) {
128
+ logger.warn(
129
+ "⎔ Support for external Durable Objects in local mode is experimental and may change."
130
+ );
131
+ }
132
+ }, [bindings.durable_objects?.bindings]);
133
+
134
+ useEffect(() => {
135
+ const abortController = new AbortController();
136
+ async function startLocalWorker() {
137
+ if (!bundle || !format) return;
138
+
139
+ // port for the worker
140
+ await waitForPortToBeAvailable(port, {
141
+ retryPeriod: 200,
142
+ timeout: 2000,
143
+ abortSignal: abortController.signal,
144
+ });
145
+
146
+ // In local mode, we want to copy all referenced modules into
147
+ // the output bundle directory before starting up
148
+ for (const module of bundle.modules) {
149
+ await writeFile(
150
+ path.join(path.dirname(bundle.path), module.name),
151
+ module.content
152
+ );
153
+ }
154
+
155
+ const scriptPath = realpathSync(bundle.path);
156
+
157
+ const upstream =
158
+ typeof localUpstream === "string"
159
+ ? `${localProtocol}://${localUpstream}`
160
+ : undefined;
161
+
162
+ const {
163
+ externalDurableObjects,
164
+ internalDurableObjects,
165
+ wasmBindings,
166
+ textBlobBindings,
167
+ dataBlobBindings,
168
+ } = setupBindings({
169
+ wasm_modules: bindings.wasm_modules,
170
+ text_blobs: bindings.text_blobs,
171
+ data_blobs: bindings.data_blobs,
172
+ durable_objects: bindings.durable_objects,
173
+ format,
174
+ bundle,
175
+ });
176
+
177
+ const { forkOptions, miniflareCLIPath } = setupMiniflareOptions({
178
+ workerName,
179
+ port,
180
+ scriptPath,
181
+ localProtocol,
182
+ ip,
183
+ format,
184
+ rules,
185
+ compatibilityDate,
186
+ compatibilityFlags,
187
+ usageModel,
188
+ kv_namespaces: bindings?.kv_namespaces,
189
+ r2_buckets: bindings?.r2_buckets,
190
+ d1_databases: bindings?.d1_databases,
191
+ internalDurableObjects,
192
+ externalDurableObjects,
193
+ localPersistencePath,
194
+ liveReload,
195
+ assetPaths,
196
+ vars: bindings?.vars,
197
+ wasmBindings,
198
+ textBlobBindings,
199
+ dataBlobBindings,
200
+ crons,
201
+ upstream,
202
+ logPrefix,
203
+ workerDefinitions,
204
+ enablePagesAssetsServiceBinding,
205
+ });
206
+
207
+ if (experimentalLocal) {
208
+ // TODO: refactor setupMiniflareOptions so we don't need to parse here
209
+ const miniflare2Options: MiniflareOptions = JSON.parse(forkOptions[0]);
210
+ const options: Miniflare3Options = {
211
+ ...miniflare2Options,
212
+ // Miniflare 3 distinguishes between binding name and namespace/bucket
213
+ // IDs. For now, just use the same value as we did in Miniflare 2.
214
+ // TODO: use defined KV preview ID if any
215
+ kvNamespaces: arrayToObject(miniflare2Options.kvNamespaces),
216
+ r2Buckets: arrayToObject(miniflare2Options.r2Buckets),
217
+ // TODO: pass-through collected modules instead of getting Miniflare
218
+ // to collect them again
219
+ };
220
+
221
+ logger.log("⎔ Starting an experimental local server...");
222
+
223
+ if (Miniflare === undefined) {
224
+ ({ Miniflare } = await npxImport<
225
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
226
+ typeof import("@miniflare/tre")
227
+ >("@miniflare/tre"));
228
+ }
229
+
230
+ const mf = new Miniflare(options);
231
+ experimentalLocalRef.current = mf;
232
+ removeSignalExitListener.current = onExit((_code, _signal) => {
233
+ logger.log("⎔ Shutting down experimental local server.");
234
+ mf.dispose();
235
+ experimentalLocalRef.current = undefined;
236
+ });
237
+ await mf.ready;
238
+ return;
239
+ }
240
+
241
+ const nodeOptions = setupNodeOptions({ inspect, ip, inspectorPort });
242
+ logger.log("⎔ Starting a local server...");
243
+
244
+ const child = (local.current = fork(miniflareCLIPath, forkOptions, {
245
+ cwd: path.dirname(scriptPath),
246
+ execArgv: nodeOptions,
247
+ stdio: "pipe",
248
+ }));
249
+
250
+ child.on("message", async (messageString) => {
251
+ const message = JSON.parse(messageString as string);
252
+ if (message.ready) {
253
+ // Let's register our presence in the dev registry
254
+ if (workerName) {
255
+ await registerWorker(workerName, {
256
+ protocol: localProtocol,
257
+ mode: "local",
258
+ port,
259
+ host: ip,
260
+ durableObjects: internalDurableObjects.map((binding) => ({
261
+ name: binding.name,
262
+ className: binding.class_name,
263
+ })),
264
+ ...(message.durableObjectsPort
265
+ ? {
266
+ durableObjectsHost: ip,
267
+ durableObjectsPort: message.durableObjectsPort,
268
+ }
269
+ : {}),
270
+ });
271
+ }
272
+ onReady?.(ip, message.mfPort);
273
+ }
274
+ });
275
+
276
+ child.on("close", (code) => {
277
+ if (code) {
278
+ logger.log(`Miniflare process exited with code ${code}`);
279
+ }
280
+ });
281
+
282
+ child.stdout?.on("data", (data: Buffer) => {
283
+ process.stdout.write(data);
284
+ });
285
+
286
+ // parse the node inspector url (which may be received in chunks) from stderr
287
+ let stderrData = "";
288
+ let inspectorUrlFound = false;
289
+ child.stderr?.on("data", (data: Buffer) => {
290
+ if (!inspectorUrlFound) {
291
+ stderrData += data.toString();
292
+ const matches =
293
+ /Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)[\r|\n]/.exec(
294
+ stderrData
295
+ );
296
+ if (matches) {
297
+ inspectorUrlFound = true;
298
+ setInspectorUrl(matches[1]);
299
+ }
300
+ }
301
+
302
+ process.stderr.write(data);
303
+ });
304
+
305
+ child.on("exit", (code) => {
306
+ if (code) {
307
+ logger.error(`Miniflare process exited with code ${code}`);
308
+ }
309
+ });
310
+
311
+ child.on("error", (error: Error) => {
312
+ logger.error(`Miniflare process failed to spawn`);
313
+ logger.error(error);
314
+ });
315
+
316
+ removeSignalExitListener.current = onExit((_code, _signal) => {
317
+ logger.log("⎔ Shutting down local server.");
318
+ child.kill();
319
+ local.current = undefined;
320
+ });
321
+ }
322
+
323
+ startLocalWorker().catch((err) => {
324
+ logger.error("local worker:", err);
325
+ });
326
+
327
+ return () => {
328
+ abortController.abort();
329
+ if (local.current) {
330
+ logger.log("⎔ Shutting down local server.");
331
+ local.current?.kill();
332
+ local.current = undefined;
333
+ }
334
+ if (experimentalLocalRef.current) {
335
+ logger.log("⎔ Shutting down experimental local server.");
336
+ // Initialisation errors are also thrown asynchronously by dispose().
337
+ // The catch() above should've caught them though.
338
+ experimentalLocalRef.current?.dispose().catch(() => {});
339
+ experimentalLocalRef.current = undefined;
340
+ }
341
+ removeSignalExitListener.current?.();
342
+ removeSignalExitListener.current = undefined;
343
+ };
344
+ }, [
345
+ bundle,
346
+ workerName,
347
+ format,
348
+ port,
349
+ inspectorPort,
350
+ ip,
351
+ bindings.durable_objects,
352
+ bindings.kv_namespaces,
353
+ bindings.r2_buckets,
354
+ bindings.d1_databases,
355
+ bindings.vars,
356
+ bindings.services,
357
+ workerDefinitions,
358
+ compatibilityDate,
359
+ compatibilityFlags,
360
+ usageModel,
361
+ localPersistencePath,
362
+ liveReload,
363
+ assetPaths,
364
+ rules,
365
+ bindings.wasm_modules,
366
+ bindings.text_blobs,
367
+ bindings.data_blobs,
368
+ crons,
369
+ localProtocol,
370
+ localUpstream,
371
+ inspect,
372
+ logPrefix,
373
+ onReady,
374
+ enablePagesAssetsServiceBinding,
375
+ experimentalLocal,
376
+ ]);
377
+ return { inspectorUrl };
378
+ }
379
+
380
+ interface SetupBindingsProps {
381
+ wasm_modules: CfWasmModuleBindings | undefined;
382
+ text_blobs: CfTextBlobBindings | undefined;
383
+ data_blobs: CfDataBlobBindings | undefined;
384
+ durable_objects: { bindings: CfDurableObject[] } | undefined;
385
+ bundle: EsbuildBundle;
386
+ format: CfScriptFormat;
387
+ }
388
+
389
+ export function setupBindings({
390
+ wasm_modules,
391
+ text_blobs,
392
+ data_blobs,
393
+ durable_objects,
394
+ format,
395
+ bundle,
396
+ }: SetupBindingsProps) {
397
+ // the wasm_modules/text_blobs/data_blobs bindings are
398
+ // relative to process.cwd(), but the actual worker bundle
399
+ // is in the temp output directory; so we rewrite the paths to be absolute,
400
+ // letting miniflare resolve them correctly
401
+
402
+ // wasm
403
+ const wasmBindings: Record<string, string> = {};
404
+ for (const [name, filePath] of Object.entries(wasm_modules || {})) {
405
+ wasmBindings[name] = path.join(process.cwd(), filePath);
406
+ }
407
+
408
+ // text
409
+ const textBlobBindings: Record<string, string> = {};
410
+ for (const [name, filePath] of Object.entries(text_blobs || {})) {
411
+ textBlobBindings[name] = path.join(process.cwd(), filePath);
412
+ }
413
+
414
+ // data
415
+ const dataBlobBindings: Record<string, string> = {};
416
+ for (const [name, filePath] of Object.entries(data_blobs || {})) {
417
+ dataBlobBindings[name] = path.join(process.cwd(), filePath);
418
+ }
419
+
420
+ if (format === "service-worker") {
421
+ for (const { type, name } of bundle.modules) {
422
+ if (type === "compiled-wasm") {
423
+ // In service-worker format, .wasm modules are referenced by global identifiers,
424
+ // so we convert it here.
425
+ // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
426
+ // characters with an underscore.
427
+ const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
428
+ wasmBindings[identifier] = name;
429
+ } else if (type === "text") {
430
+ // In service-worker format, text modules are referenced by global identifiers,
431
+ // so we convert it here.
432
+ // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
433
+ // characters with an underscore.
434
+ const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
435
+ textBlobBindings[identifier] = name;
436
+ } else if (type === "buffer") {
437
+ // In service-worker format, data blobs are referenced by global identifiers,
438
+ // so we convert it here.
439
+ // This identifier has to be a valid JS identifier, so we replace all non alphanumeric
440
+ // characters with an underscore.
441
+ const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
442
+ dataBlobBindings[identifier] = name;
443
+ }
444
+ }
445
+ }
446
+
447
+ const internalDurableObjects = (durable_objects?.bindings || []).filter(
448
+ (binding) => !binding.script_name
449
+ );
450
+ const externalDurableObjects = (durable_objects?.bindings || []).filter(
451
+ (binding) => binding.script_name
452
+ );
453
+ return {
454
+ internalDurableObjects,
455
+ externalDurableObjects,
456
+ wasmBindings,
457
+ textBlobBindings,
458
+ dataBlobBindings,
459
+ };
460
+ }
461
+
462
+ interface SetupMiniflareOptionsProps {
463
+ workerName: string | undefined;
464
+ port: number;
465
+ scriptPath: string;
466
+ localProtocol: "http" | "https";
467
+ ip: string;
468
+ format: CfScriptFormat;
469
+ rules: Config["rules"];
470
+ compatibilityDate: string;
471
+ compatibilityFlags: string[] | undefined;
472
+ usageModel: "bundled" | "unbound" | undefined;
473
+ kv_namespaces: CfKvNamespace[] | undefined;
474
+ r2_buckets: CfR2Bucket[] | undefined;
475
+ d1_databases: CfD1Database[] | undefined;
476
+ internalDurableObjects: CfDurableObject[];
477
+ externalDurableObjects: CfDurableObject[];
478
+ localPersistencePath: string | null;
479
+ liveReload: boolean;
480
+ assetPaths: AssetPaths | undefined;
481
+ vars: CfVars | undefined;
482
+ wasmBindings: Record<string, string>;
483
+ textBlobBindings: Record<string, string>;
484
+ dataBlobBindings: Record<string, string>;
485
+ crons: Config["triggers"]["crons"];
486
+ upstream: string | undefined;
487
+ logPrefix: string | undefined;
488
+ workerDefinitions: WorkerRegistry | undefined;
489
+ enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
490
+ }
491
+
492
+ export function setupMiniflareOptions({
493
+ workerName,
494
+ port,
495
+ scriptPath,
496
+ localProtocol,
497
+ ip,
498
+ format,
499
+ rules,
500
+ compatibilityDate,
501
+ compatibilityFlags,
502
+ usageModel,
503
+ kv_namespaces,
504
+ r2_buckets,
505
+ d1_databases,
506
+ internalDurableObjects,
507
+ externalDurableObjects,
508
+ localPersistencePath,
509
+ liveReload,
510
+ assetPaths,
511
+ vars,
512
+ wasmBindings,
513
+ textBlobBindings,
514
+ dataBlobBindings,
515
+ crons,
516
+ upstream,
517
+ logPrefix,
518
+ workerDefinitions,
519
+ enablePagesAssetsServiceBinding,
520
+ }: SetupMiniflareOptionsProps): {
521
+ miniflareCLIPath: string;
522
+ forkOptions: string[];
523
+ } {
524
+ // It's now getting _really_ messy now with Pages ASSETS binding outside and the external Durable Objects inside.
525
+ const options = {
526
+ name: workerName,
527
+ port,
528
+ scriptPath,
529
+ https: localProtocol === "https",
530
+ host: ip,
531
+ modules: format === "modules",
532
+ modulesRules: (rules || [])
533
+ .concat(DEFAULT_MODULE_RULES)
534
+ .map(({ type, globs: include, fallthrough }) => ({
535
+ type,
536
+ include,
537
+ fallthrough,
538
+ })),
539
+ compatibilityDate,
540
+ compatibilityFlags,
541
+ usageModel,
542
+ kvNamespaces: kv_namespaces?.map((kv) => kv.binding),
543
+ r2Buckets: r2_buckets?.map((r2) => r2.binding),
544
+ durableObjects: Object.fromEntries(
545
+ internalDurableObjects.map((binding) => [
546
+ binding.name,
547
+ binding.class_name,
548
+ ])
549
+ ),
550
+ externalDurableObjects: Object.fromEntries(
551
+ externalDurableObjects
552
+ .map((binding) => {
553
+ const service =
554
+ workerDefinitions &&
555
+ workerDefinitions[binding.script_name as string];
556
+ if (!service) return [binding.name, undefined];
557
+
558
+ const name = service.durableObjects.find(
559
+ (durableObject) => durableObject.className === binding.class_name
560
+ )?.name;
561
+ if (!name) return [binding.name, undefined];
562
+
563
+ return [
564
+ binding.name,
565
+ {
566
+ name,
567
+ host: service.durableObjectsHost,
568
+ port: service.durableObjectsPort,
569
+ },
570
+ ];
571
+ })
572
+ .filter(([_, details]) => !!details)
573
+ ),
574
+ d1Databases: d1_databases?.map((db) => db.binding),
575
+ ...(localPersistencePath
576
+ ? {
577
+ cachePersist: path.join(localPersistencePath, "cache"),
578
+ durableObjectsPersist: path.join(localPersistencePath, "do"),
579
+ kvPersist: path.join(localPersistencePath, "kv"),
580
+ r2Persist: path.join(localPersistencePath, "r2"),
581
+ d1Persist: path.join(localPersistencePath, "d1"),
582
+ }
583
+ : {
584
+ // We mark these as true, so that they'll
585
+ // persist in the temp directory.
586
+ // This means they'll persist across a dev session,
587
+ // even if we change source and reload,
588
+ // and be deleted when the dev session ends
589
+ cachePersist: true,
590
+ durableObjectsPersist: true,
591
+ kvPersist: true,
592
+ r2Persist: true,
593
+ }),
594
+
595
+ liveReload,
596
+ sitePath: assetPaths?.assetDirectory
597
+ ? path.join(assetPaths.baseDirectory, assetPaths.assetDirectory)
598
+ : undefined,
599
+ siteInclude: assetPaths?.includePatterns.length
600
+ ? assetPaths?.includePatterns
601
+ : undefined,
602
+ siteExclude: assetPaths?.excludePatterns.length
603
+ ? assetPaths.excludePatterns
604
+ : undefined,
605
+ bindings: vars,
606
+ wasmBindings,
607
+ textBlobBindings,
608
+ dataBlobBindings,
609
+ sourceMap: true,
610
+ logUnhandledRejections: true,
611
+ crons,
612
+ upstream,
613
+ logLevel: logger.loggerLevel,
614
+ logOptions: logPrefix ? { prefix: logPrefix } : undefined,
615
+ enablePagesAssetsServiceBinding,
616
+ };
617
+ // The path to the Miniflare CLI assumes that this file is being run from
618
+ // `wrangler-dist` and that the CLI is found in `miniflare-dist`.
619
+ // If either of those paths change this line needs updating.
620
+ const miniflareCLIPath = path.resolve(
621
+ getBasePath(),
622
+ "miniflare-dist/index.mjs"
623
+ );
624
+ const miniflareOptions = JSON.stringify(options, null);
625
+ const forkOptions = [miniflareOptions];
626
+ if (enablePagesAssetsServiceBinding) {
627
+ forkOptions.push(JSON.stringify(enablePagesAssetsServiceBinding));
628
+ }
629
+ return { miniflareCLIPath, forkOptions };
630
+ }
631
+
632
+ export function setupNodeOptions({
633
+ inspect,
634
+ ip,
635
+ inspectorPort,
636
+ }: {
637
+ inspect: boolean;
638
+ ip: string;
639
+ inspectorPort: number;
640
+ }) {
641
+ const nodeOptions = [
642
+ "--experimental-vm-modules", // ensures that Miniflare can run ESM Workers
643
+ "--no-warnings", // hide annoying Node warnings
644
+ // "--log=VERBOSE", // uncomment this to Miniflare to log "everything"!
645
+ ];
646
+ if (inspect) {
647
+ nodeOptions.push("--inspect=" + `${ip}:${inspectorPort}`); // start Miniflare listening for a debugger to attach
648
+ }
649
+ return nodeOptions;
232
650
  }