wrangler 0.0.0-e88a54e → 0.0.0-e8e684c7

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 (222) hide show
  1. package/Cloudflare_CA.pem +18 -0
  2. package/README.md +51 -14
  3. package/bin/wrangler.js +161 -29
  4. package/kv-asset-handler.js +1 -0
  5. package/miniflare-dist/index.mjs +5484 -21
  6. package/package.json +173 -143
  7. package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
  8. package/src/__tests__/config-cache.test.ts +42 -0
  9. package/src/__tests__/configuration.test.ts +4016 -2786
  10. package/src/__tests__/dev.test.tsx +1305 -483
  11. package/src/__tests__/generate.test.ts +91 -0
  12. package/src/__tests__/guess-worker-format.test.ts +75 -48
  13. package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
  14. package/src/__tests__/helpers/mock-account-id.ts +24 -24
  15. package/src/__tests__/helpers/mock-bin.ts +20 -20
  16. package/src/__tests__/helpers/mock-cfetch.ts +182 -93
  17. package/src/__tests__/helpers/mock-console.ts +59 -32
  18. package/src/__tests__/helpers/mock-dialogs.ts +121 -33
  19. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  20. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  21. package/src/__tests__/helpers/mock-istty.ts +74 -0
  22. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  23. package/src/__tests__/helpers/mock-kv.ts +26 -26
  24. package/src/__tests__/helpers/mock-oauth-flow.ts +250 -0
  25. package/src/__tests__/helpers/mock-process.ts +39 -0
  26. package/src/__tests__/helpers/mock-stdin.ts +82 -77
  27. package/src/__tests__/helpers/mock-web-socket.ts +21 -21
  28. package/src/__tests__/helpers/run-in-tmp.ts +28 -22
  29. package/src/__tests__/helpers/run-wrangler.ts +8 -8
  30. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  31. package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
  32. package/src/__tests__/https-options.test.ts +144 -108
  33. package/src/__tests__/index.test.ts +229 -975
  34. package/src/__tests__/init.test.ts +2170 -0
  35. package/src/__tests__/jest.setup.ts +122 -34
  36. package/src/__tests__/kv.test.ts +1376 -1087
  37. package/src/__tests__/logger.test.ts +141 -0
  38. package/src/__tests__/metrics.test.ts +450 -0
  39. package/src/__tests__/package-manager.test.ts +312 -165
  40. package/src/__tests__/pages.test.ts +1270 -39
  41. package/src/__tests__/parse.test.ts +253 -245
  42. package/src/__tests__/publish.test.ts +6878 -2627
  43. package/src/__tests__/pubsub.test.ts +367 -0
  44. package/src/__tests__/r2.test.ts +328 -190
  45. package/src/__tests__/route.test.ts +22 -22
  46. package/src/__tests__/secret.test.ts +474 -407
  47. package/src/__tests__/tail.test.ts +679 -441
  48. package/src/__tests__/test-old-node-version.js +31 -0
  49. package/src/__tests__/user.test.ts +155 -0
  50. package/src/__tests__/validate-dev-props.test.ts +56 -0
  51. package/src/__tests__/version.test.ts +35 -0
  52. package/src/__tests__/whoami.test.tsx +276 -87
  53. package/src/__tests__/worker-namespace.test.ts +329 -0
  54. package/src/abort.d.ts +3 -0
  55. package/src/api/dev.ts +93 -0
  56. package/src/api/index.ts +1 -0
  57. package/src/bundle-reporter.tsx +29 -0
  58. package/src/bundle.ts +441 -110
  59. package/src/cfetch/index.ts +83 -66
  60. package/src/cfetch/internal.ts +251 -92
  61. package/src/cli.ts +22 -14
  62. package/src/config/README.md +1 -1
  63. package/src/config/config.ts +224 -179
  64. package/src/config/diagnostics.ts +61 -61
  65. package/src/config/environment.ts +430 -311
  66. package/src/config/index.ts +227 -38
  67. package/src/config/validation-helpers.ts +414 -303
  68. package/src/config/validation.ts +1745 -973
  69. package/src/config-cache.ts +85 -0
  70. package/src/create-worker-preview.ts +209 -118
  71. package/src/create-worker-upload-form.ts +275 -201
  72. package/src/dev/dev-vars.ts +36 -0
  73. package/src/dev/dev.tsx +488 -307
  74. package/src/dev/local.tsx +427 -210
  75. package/src/dev/remote.tsx +407 -188
  76. package/src/dev/use-esbuild.ts +156 -78
  77. package/src/dev/validate-dev-props.ts +31 -0
  78. package/src/dev-registry.tsx +160 -0
  79. package/src/dev.tsx +696 -0
  80. package/src/dialogs.tsx +115 -57
  81. package/src/dispatch-namespace.ts +206 -0
  82. package/src/durable.ts +102 -0
  83. package/src/entry.ts +267 -147
  84. package/src/environment-variables.ts +25 -23
  85. package/src/errors.ts +11 -0
  86. package/src/faye-websocket.d.ts +6 -0
  87. package/src/generate.ts +131 -0
  88. package/src/git-client.ts +42 -0
  89. package/src/global-wrangler-config-path.ts +26 -0
  90. package/src/https-options.ts +85 -80
  91. package/src/index.tsx +2191 -2304
  92. package/src/init.ts +622 -0
  93. package/src/inspect.ts +687 -557
  94. package/src/intl-polyfill.d.ts +139 -0
  95. package/src/is-ci.ts +14 -0
  96. package/src/is-interactive.ts +12 -0
  97. package/src/kv.ts +353 -242
  98. package/src/logger.ts +73 -0
  99. package/src/metrics/index.ts +5 -0
  100. package/src/metrics/metrics-config.ts +239 -0
  101. package/src/metrics/metrics-dispatcher.ts +96 -0
  102. package/src/metrics/metrics-usage-headers.ts +24 -0
  103. package/src/metrics/send-event.ts +92 -0
  104. package/src/miniflare-cli/assets.ts +554 -0
  105. package/src/miniflare-cli/enum-keys.ts +8 -8
  106. package/src/miniflare-cli/index.ts +199 -29
  107. package/src/miniflare-cli/request-context.ts +40 -0
  108. package/src/module-collection.ts +213 -213
  109. package/src/open-in-browser.ts +8 -16
  110. package/src/package-manager.ts +183 -90
  111. package/src/pages/build.tsx +238 -0
  112. package/src/pages/constants.ts +12 -0
  113. package/src/pages/deployments.tsx +106 -0
  114. package/src/pages/dev.tsx +528 -0
  115. package/src/pages/errors.ts +22 -0
  116. package/src/pages/functions/buildPlugin.ts +109 -0
  117. package/src/pages/functions/buildWorker.ts +155 -0
  118. package/src/pages/functions/filepath-routing.test.ts +234 -0
  119. package/src/pages/functions/filepath-routing.ts +189 -0
  120. package/src/pages/functions/identifiers.ts +78 -0
  121. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  122. package/src/pages/functions/routes-consolidation.ts +73 -0
  123. package/src/pages/functions/routes-transformation.test.ts +271 -0
  124. package/src/pages/functions/routes-transformation.ts +122 -0
  125. package/src/pages/functions/routes.ts +151 -0
  126. package/src/pages/functions.tsx +96 -0
  127. package/src/pages/index.tsx +94 -0
  128. package/src/pages/projects.tsx +169 -0
  129. package/src/pages/publish.tsx +391 -0
  130. package/src/pages/types.ts +49 -0
  131. package/src/pages/upload.tsx +413 -0
  132. package/src/pages/utils.ts +12 -0
  133. package/src/parse.ts +224 -121
  134. package/src/paths.ts +6 -6
  135. package/src/preview.ts +31 -0
  136. package/src/proxy.ts +416 -370
  137. package/src/publish.ts +796 -321
  138. package/src/pubsub/index.ts +286 -0
  139. package/src/pubsub/pubsub-commands.tsx +623 -0
  140. package/src/r2.ts +100 -19
  141. package/src/selfsigned.d.ts +23 -23
  142. package/src/sites.tsx +281 -189
  143. package/src/tail/filters.ts +111 -109
  144. package/src/tail/index.ts +230 -217
  145. package/src/tail/printing.ts +92 -47
  146. package/src/update-check.ts +19 -0
  147. package/src/user/choose-account.tsx +69 -0
  148. package/src/user/env-vars.ts +46 -0
  149. package/src/user/generate-auth-url.ts +33 -0
  150. package/src/user/generate-random-state.ts +16 -0
  151. package/src/user/index.ts +3 -0
  152. package/src/user/user.tsx +1191 -0
  153. package/src/whoami.tsx +142 -42
  154. package/src/worker.ts +135 -94
  155. package/src/zones.ts +167 -0
  156. package/templates/checked-fetch.js +17 -0
  157. package/templates/first-party-worker-module-facade.ts +18 -0
  158. package/templates/format-dev-errors.ts +32 -0
  159. package/templates/gitignore +171 -0
  160. package/templates/new-worker-scheduled.js +17 -0
  161. package/templates/new-worker-scheduled.ts +32 -0
  162. package/templates/new-worker.js +3 -3
  163. package/templates/new-worker.ts +18 -3
  164. package/templates/no-op-worker.js +10 -0
  165. package/templates/pages-shim.ts +9 -0
  166. package/templates/pages-template-plugin.ts +167 -0
  167. package/templates/pages-template-worker.ts +172 -0
  168. package/templates/serve-static-assets.ts +63 -0
  169. package/templates/service-bindings-module-facade.js +54 -0
  170. package/templates/service-bindings-sw-facade.js +42 -0
  171. package/templates/tsconfig.json +95 -95
  172. package/wrangler-dist/cli.d.ts +338 -0
  173. package/wrangler-dist/cli.js +124611 -112403
  174. package/miniflare-dist/index.mjs.map +0 -7
  175. package/pages/functions/buildWorker.ts +0 -62
  176. package/pages/functions/filepath-routing.test.ts +0 -223
  177. package/pages/functions/filepath-routing.ts +0 -181
  178. package/pages/functions/identifiers.ts +0 -78
  179. package/pages/functions/routes.ts +0 -151
  180. package/pages/functions/template-worker.ts +0 -130
  181. package/src/__tests__/dev2.test.tsx +0 -154
  182. package/src/__tests__/helpers/faye-websocket.d.ts +0 -6
  183. package/src/__tests__/logout.test.ts +0 -52
  184. package/src/__tests__/sentry.test.ts +0 -146
  185. package/src/pages.tsx +0 -1047
  186. package/src/reporting.ts +0 -131
  187. package/src/user.tsx +0 -1118
  188. package/templates/static-asset-facade.js +0 -47
  189. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  190. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  191. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  192. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  193. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  194. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  195. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  196. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  197. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  198. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  199. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  200. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  201. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  202. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  203. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  204. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  205. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  206. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  207. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  208. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  209. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  210. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  211. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  212. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  213. package/vendor/wrangler-mime/LICENSE +0 -21
  214. package/vendor/wrangler-mime/Mime.js +0 -97
  215. package/vendor/wrangler-mime/README.md +0 -187
  216. package/vendor/wrangler-mime/cli.js +0 -46
  217. package/vendor/wrangler-mime/index.js +0 -4
  218. package/vendor/wrangler-mime/lite.js +0 -4
  219. package/vendor/wrangler-mime/package.json +0 -52
  220. package/vendor/wrangler-mime/types/other.js +0 -1
  221. package/vendor/wrangler-mime/types/standard.js +0 -1
  222. package/wrangler-dist/cli.js.map +0 -7
@@ -0,0 +1,528 @@
1
+ import { execSync, spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { homedir, tmpdir } from "node:os";
4
+ import { join, resolve } from "node:path";
5
+ import { watch } from "chokidar";
6
+ import { build as workerJsBuild } from "esbuild";
7
+ import { unstable_dev } from "../api";
8
+ import { FatalError } from "../errors";
9
+ import { logger } from "../logger";
10
+ import * as metrics from "../metrics";
11
+ import { buildFunctions } from "./build";
12
+ import { SECONDS_TO_WAIT_FOR_PROXY } from "./constants";
13
+ import { FunctionsNoRoutesError, getFunctionsNoRoutesWarning } from "./errors";
14
+ import { CLEANUP, CLEANUP_CALLBACKS, pagesBetaWarning } from "./utils";
15
+ import type { AdditionalDevProps } from "../dev";
16
+ import type { YargsOptionsToInterface } from "./types";
17
+ import type { Plugin } from "esbuild";
18
+ import type { Argv } from "yargs";
19
+
20
+ const DURABLE_OBJECTS_BINDING_REGEXP = new RegExp(
21
+ /^(?<binding>[^=]+)=(?<className>[^@\s]+)(@(?<scriptName>.*)$)?$/
22
+ );
23
+
24
+ type PagesDevArgs = YargsOptionsToInterface<typeof Options>;
25
+
26
+ export function Options(yargs: Argv) {
27
+ return yargs
28
+ .positional("directory", {
29
+ type: "string",
30
+ demandOption: undefined,
31
+ description: "The directory of static assets to serve",
32
+ })
33
+ .positional("command", {
34
+ type: "string",
35
+ demandOption: undefined,
36
+ description: "The proxy command to run",
37
+ })
38
+ .options({
39
+ local: {
40
+ type: "boolean",
41
+ default: true,
42
+ description: "Run on my machine",
43
+ },
44
+ "compatibility-date": {
45
+ describe: "Date to use for compatibility checks",
46
+ type: "string",
47
+ },
48
+ "compatibility-flags": {
49
+ describe: "Flags to use for compatibility checks",
50
+ alias: "compatibility-flag",
51
+ type: "string",
52
+ array: true,
53
+ },
54
+
55
+ // TODO
56
+ // For now, all Pages projects are set to 2021-11-02. We're adding compat date soon, and we can then adopt `wrangler dev`'s `default: true`.
57
+ // However, it looks like it isn't actually connected up properly in `wrangler dev` at the moment, hence commenting this out for now.
58
+
59
+ // latest: {
60
+ // describe: "Use the latest version of the worker runtime",
61
+ // type: "boolean",
62
+ // default: false,
63
+ // },
64
+
65
+ ip: {
66
+ type: "string",
67
+ default: "0.0.0.0",
68
+ description: "The IP address to listen on",
69
+ },
70
+ port: {
71
+ type: "number",
72
+ default: 8788,
73
+ description: "The port to listen on (serve from)",
74
+ },
75
+ "inspector-port": {
76
+ type: "number",
77
+ describe: "Port for devtools to connect to",
78
+ },
79
+ proxy: {
80
+ type: "number",
81
+ description: "The port to proxy (where the static assets are served)",
82
+ },
83
+ "script-path": {
84
+ type: "string",
85
+ default: "_worker.js",
86
+ description:
87
+ "The location of the single Worker script if not using functions",
88
+ },
89
+ binding: {
90
+ type: "array",
91
+ description: "Bind variable/secret (KEY=VALUE)",
92
+ alias: "b",
93
+ },
94
+ kv: {
95
+ type: "array",
96
+ description: "KV namespace to bind (--kv KV_BINDING)",
97
+ alias: "k",
98
+ },
99
+ do: {
100
+ type: "array",
101
+ description: "Durable Object to bind (--do NAME=CLASS)",
102
+ alias: "o",
103
+ },
104
+ r2: {
105
+ type: "array",
106
+ description: "R2 bucket to bind (--r2 R2_BINDING)",
107
+ },
108
+ "live-reload": {
109
+ type: "boolean",
110
+ default: false,
111
+ description: "Auto reload HTML pages when change is detected",
112
+ },
113
+ "local-protocol": {
114
+ describe: "Protocol to listen to requests on, defaults to http.",
115
+ choices: ["http", "https"] as const,
116
+ },
117
+ "experimental-enable-local-persistence": {
118
+ type: "boolean",
119
+ default: false,
120
+ describe: "Enable persistence for this session (only for local mode)",
121
+ },
122
+ "node-compat": {
123
+ describe: "Enable node.js compatibility",
124
+ default: false,
125
+ type: "boolean",
126
+ hidden: true,
127
+ },
128
+ config: {
129
+ describe: "Pages does not support wrangler.toml",
130
+ type: "string",
131
+ hidden: true,
132
+ },
133
+ })
134
+ .epilogue(pagesBetaWarning);
135
+ }
136
+
137
+ export const Handler = async ({
138
+ local,
139
+ directory,
140
+ "compatibility-date": compatibilityDate = "2021-11-02",
141
+ "compatibility-flags": compatibilityFlags,
142
+ ip,
143
+ port,
144
+ "inspector-port": inspectorPort,
145
+ proxy: requestedProxyPort,
146
+ "script-path": singleWorkerScriptPath,
147
+ binding: bindings = [],
148
+ kv: kvs = [],
149
+ do: durableObjects = [],
150
+ r2: r2s = [],
151
+ "live-reload": liveReload,
152
+ "local-protocol": localProtocol,
153
+ "experimental-enable-local-persistence": experimentalEnableLocalPersistence,
154
+ "node-compat": nodeCompat,
155
+ config: config,
156
+ _: [_pages, _dev, ...remaining],
157
+ }: PagesDevArgs) => {
158
+ // Beta message for `wrangler pages <commands>` usage
159
+ logger.log(pagesBetaWarning);
160
+
161
+ if (!local) {
162
+ throw new FatalError("Only local mode is supported at the moment.", 1);
163
+ }
164
+
165
+ if (config) {
166
+ throw new FatalError("Pages does not support wrangler.toml", 1);
167
+ }
168
+
169
+ const functionsDirectory = "./functions";
170
+ let usingFunctions = existsSync(functionsDirectory);
171
+
172
+ const command = remaining;
173
+
174
+ let proxyPort: number | undefined;
175
+
176
+ if (directory !== undefined && command.length > 0) {
177
+ throw new FatalError(
178
+ "Specify either a directory OR a proxy command, not both.",
179
+ 1
180
+ );
181
+ } else if (directory === undefined) {
182
+ proxyPort = await spawnProxyProcess({
183
+ port: requestedProxyPort,
184
+ command,
185
+ });
186
+ if (proxyPort === undefined) return undefined;
187
+ } else {
188
+ directory = resolve(directory);
189
+ }
190
+
191
+ let scriptReadyResolve: () => void;
192
+ const scriptReadyPromise = new Promise<void>(
193
+ (promiseResolve) => (scriptReadyResolve = promiseResolve)
194
+ );
195
+
196
+ let scriptPath = "";
197
+
198
+ // Try to use Functions
199
+ if (usingFunctions) {
200
+ const outfile = join(tmpdir(), `./functionsWorker-${Math.random()}.js`);
201
+ scriptPath = outfile;
202
+
203
+ if (nodeCompat) {
204
+ console.warn(
205
+ "Enabling node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details."
206
+ );
207
+ }
208
+
209
+ logger.log(`Compiling worker to "${outfile}"...`);
210
+ const onEnd = () => scriptReadyResolve();
211
+ try {
212
+ await buildFunctions({
213
+ outfile,
214
+ functionsDirectory,
215
+ sourcemap: true,
216
+ watch: true,
217
+ onEnd,
218
+ buildOutputDirectory: directory,
219
+ nodeCompat,
220
+ });
221
+ await metrics.sendMetricsEvent("build pages functions");
222
+
223
+ // If Functions found routes, continue using Functions
224
+ watch([functionsDirectory], {
225
+ persistent: true,
226
+ ignoreInitial: true,
227
+ }).on("all", async () => {
228
+ try {
229
+ await buildFunctions({
230
+ outfile,
231
+ functionsDirectory,
232
+ sourcemap: true,
233
+ watch: true,
234
+ onEnd,
235
+ buildOutputDirectory: directory,
236
+ nodeCompat,
237
+ });
238
+ await metrics.sendMetricsEvent("build pages functions");
239
+ } catch (e) {
240
+ if (e instanceof FunctionsNoRoutesError) {
241
+ logger.warn(
242
+ getFunctionsNoRoutesWarning(functionsDirectory, "skipping")
243
+ );
244
+ } else {
245
+ throw e;
246
+ }
247
+ }
248
+ });
249
+ } catch (e) {
250
+ // If there are no Functions, then Pages will only serve assets.
251
+ if (e instanceof FunctionsNoRoutesError) {
252
+ logger.warn(
253
+ getFunctionsNoRoutesWarning(functionsDirectory, "skipping")
254
+ );
255
+ // Resolve anyway and run without Functions
256
+ onEnd();
257
+ // Turn off Functions
258
+ usingFunctions = false;
259
+ } else {
260
+ throw e;
261
+ }
262
+ }
263
+ }
264
+ // Depending on the result of building Functions, we may not actually be using
265
+ // Functions even if the directory exists.
266
+ if (!usingFunctions) {
267
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
268
+ scriptReadyResolve!();
269
+
270
+ scriptPath =
271
+ directory !== undefined
272
+ ? join(directory, singleWorkerScriptPath)
273
+ : singleWorkerScriptPath;
274
+
275
+ if (!existsSync(scriptPath)) {
276
+ logger.log("No functions. Shimming...");
277
+ scriptPath = resolve(__dirname, "../templates/pages-shim.ts");
278
+ } else {
279
+ const runBuild = async () => {
280
+ try {
281
+ await workerJsBuild({
282
+ entryPoints: [scriptPath],
283
+ write: false,
284
+ plugins: [blockWorkerJsImports],
285
+ });
286
+ } catch {}
287
+ };
288
+ await runBuild();
289
+ watch([scriptPath], {
290
+ persistent: true,
291
+ ignoreInitial: true,
292
+ }).on("all", async () => {
293
+ await runBuild();
294
+ });
295
+ }
296
+ }
297
+
298
+ await scriptReadyPromise;
299
+
300
+ if (scriptPath === "") {
301
+ // Failed to get a script with or without Functions,
302
+ // something really bad must have happend.
303
+ throw new FatalError(
304
+ "Failed to start wrangler pages dev due to an unknown error",
305
+ 1
306
+ );
307
+ }
308
+
309
+ const { stop, waitUntilExit } = await unstable_dev(
310
+ scriptPath,
311
+ {
312
+ ip,
313
+ port,
314
+ inspectorPort,
315
+ watch: true,
316
+ localProtocol,
317
+ liveReload,
318
+ compatibilityDate,
319
+ compatibilityFlags,
320
+ nodeCompat,
321
+ vars: Object.fromEntries(
322
+ bindings
323
+ .map((binding) => binding.toString().split("="))
324
+ .map(([key, ...values]) => [key, values.join("=")])
325
+ ),
326
+ kv: kvs.map((val) => ({
327
+ binding: val.toString(),
328
+ id: "",
329
+ })),
330
+ durableObjects: durableObjects
331
+ .map((durableObject) => {
332
+ const { binding, className, scriptName } =
333
+ DURABLE_OBJECTS_BINDING_REGEXP.exec(durableObject.toString())
334
+ ?.groups || {};
335
+
336
+ if (!binding || !className) {
337
+ logger.warn(
338
+ "Could not parse Durable Object binding:",
339
+ durableObject.toString()
340
+ );
341
+ return;
342
+ }
343
+
344
+ return {
345
+ name: binding,
346
+ class_name: className,
347
+ script_name: scriptName,
348
+ };
349
+ })
350
+ .filter(Boolean) as AdditionalDevProps["durableObjects"],
351
+ r2: r2s.map((binding) => {
352
+ return { binding: binding.toString(), bucket_name: "" };
353
+ }),
354
+
355
+ enablePagesAssetsServiceBinding: {
356
+ proxyPort,
357
+ directory,
358
+ },
359
+ forceLocal: true,
360
+ experimentalEnableLocalPersistence,
361
+ showInteractiveDevSession: undefined,
362
+ inspect: true,
363
+ logLevel: "error",
364
+ logPrefix: "pages",
365
+ },
366
+ true
367
+ );
368
+ await metrics.sendMetricsEvent("run pages dev");
369
+
370
+ CLEANUP_CALLBACKS.push(stop);
371
+
372
+ waitUntilExit().then(() => {
373
+ CLEANUP();
374
+ process.exit(0);
375
+ });
376
+
377
+ process.on("exit", CLEANUP);
378
+ process.on("SIGINT", CLEANUP);
379
+ process.on("SIGTERM", CLEANUP);
380
+ };
381
+
382
+ function isWindows() {
383
+ return process.platform === "win32";
384
+ }
385
+
386
+ async function sleep(ms: number) {
387
+ await new Promise((promiseResolve) => setTimeout(promiseResolve, ms));
388
+ }
389
+
390
+ function getPids(pid: number) {
391
+ const pids: number[] = [pid];
392
+ let command: string, regExp: RegExp;
393
+
394
+ if (isWindows()) {
395
+ command = `wmic process where (ParentProcessId=${pid}) get ProcessId`;
396
+ regExp = new RegExp(/(\d+)/);
397
+ } else {
398
+ command = `pgrep -P ${pid}`;
399
+ regExp = new RegExp(/(\d+)/);
400
+ }
401
+
402
+ try {
403
+ const newPids = (
404
+ execSync(command)
405
+ .toString()
406
+ .split("\n")
407
+ .map((line) => line.match(regExp))
408
+ .filter((line) => line !== null) as RegExpExecArray[]
409
+ ).map((match) => parseInt(match[1]));
410
+
411
+ pids.push(...newPids.map(getPids).flat());
412
+ } catch {}
413
+
414
+ return pids;
415
+ }
416
+
417
+ function getPort(pid: number) {
418
+ let command: string, regExp: RegExp;
419
+
420
+ if (isWindows()) {
421
+ const drive = homedir().split(":\\")[0];
422
+ command = drive + ":\\windows\\system32\\netstat.exe -nao";
423
+ regExp = new RegExp(`TCP\\s+.*:(\\d+)\\s+.*:\\d+\\s+LISTENING\\s+${pid}`);
424
+ } else {
425
+ command = "lsof -nPi";
426
+ regExp = new RegExp(`${pid}\\s+.*TCP\\s+.*:(\\d+)\\s+\\(LISTEN\\)`);
427
+ }
428
+
429
+ try {
430
+ const matches = execSync(command)
431
+ .toString()
432
+ .split("\n")
433
+ .map((line) => line.match(regExp))
434
+ .filter((line) => line !== null) as RegExpExecArray[];
435
+
436
+ const match = matches[0];
437
+ if (match) return parseInt(match[1]);
438
+ } catch (thrown) {
439
+ logger.error(
440
+ `Error scanning for ports of process with PID ${pid}: ${thrown}`
441
+ );
442
+ }
443
+ }
444
+
445
+ async function spawnProxyProcess({
446
+ port,
447
+ command,
448
+ }: {
449
+ port?: number;
450
+ command: (string | number)[];
451
+ }): Promise<undefined | number> {
452
+ if (command.length === 0) {
453
+ CLEANUP();
454
+ throw new FatalError(
455
+ "Must specify a directory of static assets to serve or a command to run.",
456
+ 1
457
+ );
458
+ }
459
+
460
+ logger.log(`Running ${command.join(" ")}...`);
461
+ const proxy = spawn(
462
+ command[0].toString(),
463
+ command.slice(1).map((value) => value.toString()),
464
+ {
465
+ shell: isWindows(),
466
+ env: {
467
+ BROWSER: "none",
468
+ ...process.env,
469
+ },
470
+ }
471
+ );
472
+ CLEANUP_CALLBACKS.push(() => {
473
+ proxy.kill();
474
+ });
475
+
476
+ proxy.stdout.on("data", (data) => {
477
+ logger.log(`[proxy]: ${data}`);
478
+ });
479
+
480
+ proxy.stderr.on("data", (data) => {
481
+ logger.error(`[proxy]: ${data}`);
482
+ });
483
+
484
+ proxy.on("close", (code) => {
485
+ logger.error(`Proxy exited with status ${code}.`);
486
+ CLEANUP();
487
+ process.exitCode = code ?? 0;
488
+ });
489
+
490
+ // Wait for proxy process to start...
491
+ while (!proxy.pid) {}
492
+
493
+ if (port === undefined) {
494
+ logger.log(
495
+ `Sleeping ${SECONDS_TO_WAIT_FOR_PROXY} seconds to allow proxy process to start before attempting to automatically determine port...`
496
+ );
497
+ logger.log("To skip, specify the proxy port with --proxy.");
498
+ await sleep(SECONDS_TO_WAIT_FOR_PROXY * 1000);
499
+
500
+ port = getPids(proxy.pid)
501
+ .map(getPort)
502
+ .filter((nr) => nr !== undefined)[0];
503
+
504
+ if (port === undefined) {
505
+ CLEANUP();
506
+ throw new FatalError(
507
+ "Could not automatically determine proxy port. Please specify the proxy port with --proxy.",
508
+ 1
509
+ );
510
+ } else {
511
+ logger.log(`Automatically determined the proxy port to be ${port}.`);
512
+ }
513
+ }
514
+
515
+ return port;
516
+ }
517
+
518
+ const blockWorkerJsImports: Plugin = {
519
+ name: "block-worker-js-imports",
520
+ setup(build) {
521
+ build.onResolve({ filter: /.*/g }, (_args) => {
522
+ logger.error(
523
+ `_worker.js is importing from another file. This will throw an error if deployed.\nYou should bundle your Worker or remove the import if it is unused.`
524
+ );
525
+ return null;
526
+ });
527
+ },
528
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Pages error when no routes are found in the functions directory
3
+ */
4
+ export class FunctionsNoRoutesError extends Error {
5
+ constructor(message: string) {
6
+ super(message);
7
+ }
8
+ }
9
+ /**
10
+ * Exit code for `pages functions build` when no routes are found.
11
+ */
12
+ export const EXIT_CODE_FUNCTIONS_NO_ROUTES_ERROR = 156;
13
+
14
+ /** Warning message for when buildFunctions throws FunctionsNoRoutesError */
15
+ export function getFunctionsNoRoutesWarning(
16
+ functionsDirectory: string,
17
+ suffix?: string
18
+ ) {
19
+ return `No routes found when building Functions directory: ${functionsDirectory}${
20
+ suffix ? " - " + suffix : ""
21
+ }`;
22
+ }
@@ -0,0 +1,109 @@
1
+ import { access, lstat } from "node:fs/promises";
2
+ import { dirname, relative, resolve } from "node:path";
3
+ import NodeGlobalsPolyfills from "@esbuild-plugins/node-globals-polyfill";
4
+ import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill";
5
+ import { build } from "esbuild";
6
+
7
+ type Options = {
8
+ routesModule: string;
9
+ outfile: string;
10
+ minify?: boolean;
11
+ sourcemap?: boolean;
12
+ watch?: boolean;
13
+ nodeCompat?: boolean;
14
+ onEnd?: () => void;
15
+ };
16
+
17
+ export function buildPlugin({
18
+ routesModule,
19
+ outfile = "bundle.js",
20
+ minify = false,
21
+ sourcemap = false,
22
+ watch = false,
23
+ nodeCompat,
24
+ onEnd = () => {},
25
+ }: Options) {
26
+ return build({
27
+ entryPoints: [resolve(__dirname, "../templates/pages-template-plugin.ts")],
28
+ inject: [routesModule],
29
+ bundle: true,
30
+ format: "esm",
31
+ target: "esnext",
32
+ loader: {
33
+ ".html": "text",
34
+ ".txt": "text",
35
+ },
36
+ outfile,
37
+ minify,
38
+ sourcemap,
39
+ watch,
40
+ allowOverwrite: true,
41
+ define: { ...(nodeCompat ? { global: "globalThis" } : {}) },
42
+ plugins: [
43
+ {
44
+ name: "wrangler notifier and monitor",
45
+ setup(pluginBuild) {
46
+ pluginBuild.onEnd((result) => {
47
+ if (result.errors.length > 0) {
48
+ console.error(
49
+ `${result.errors.length} error(s) and ${result.warnings.length} warning(s) when compiling Worker.`
50
+ );
51
+ } else if (result.warnings.length > 0) {
52
+ console.warn(
53
+ `${result.warnings.length} warning(s) when compiling Worker.`
54
+ );
55
+ onEnd();
56
+ } else {
57
+ console.log("Compiled Worker successfully.");
58
+ onEnd();
59
+ }
60
+ });
61
+ },
62
+ },
63
+ {
64
+ name: "Assets",
65
+ setup(pluginBuild) {
66
+ if (pluginBuild.initialOptions.outfile) {
67
+ const outdir = dirname(pluginBuild.initialOptions.outfile);
68
+
69
+ pluginBuild.onResolve({ filter: /^assets:/ }, async (args) => {
70
+ const directory = resolve(
71
+ args.resolveDir,
72
+ args.path.slice("assets:".length)
73
+ );
74
+
75
+ const exists = await access(directory)
76
+ .then(() => true)
77
+ .catch(() => false);
78
+
79
+ const isDirectory =
80
+ exists && (await lstat(directory)).isDirectory();
81
+
82
+ if (!isDirectory) {
83
+ return {
84
+ errors: [
85
+ {
86
+ text: `'${directory}' does not exist or is not a directory.`,
87
+ },
88
+ ],
89
+ };
90
+ }
91
+
92
+ const path = `assets:./${relative(outdir, directory)}`;
93
+
94
+ return { path, external: true, namespace: "assets" };
95
+ });
96
+ }
97
+ },
98
+ },
99
+ ...(nodeCompat
100
+ ? [
101
+ NodeGlobalsPolyfills({
102
+ buffer: true,
103
+ }),
104
+ NodeModulesPolyfills(),
105
+ ]
106
+ : []),
107
+ ],
108
+ });
109
+ }