wrangler 0.0.0-fb43821 → 0.0.0-fbfc24d7

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 (221) hide show
  1. package/Cloudflare_CA.pem +18 -0
  2. package/README.md +51 -14
  3. package/bin/wrangler.js +160 -28
  4. package/kv-asset-handler.js +1 -0
  5. package/miniflare-dist/index.mjs +5542 -0
  6. package/package.json +172 -113
  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 +4026 -0
  10. package/src/__tests__/dev.test.tsx +1316 -0
  11. package/src/__tests__/generate.test.ts +91 -0
  12. package/src/__tests__/guess-worker-format.test.ts +85 -0
  13. package/src/__tests__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
  14. package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
  15. package/src/__tests__/helpers/mock-account-id.ts +48 -0
  16. package/src/__tests__/helpers/mock-bin.ts +36 -0
  17. package/src/__tests__/helpers/mock-cfetch.ts +296 -0
  18. package/src/__tests__/helpers/mock-console.ts +97 -0
  19. package/src/__tests__/helpers/mock-dialogs.ts +153 -0
  20. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  21. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  22. package/src/__tests__/helpers/mock-istty.ts +74 -0
  23. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  24. package/src/__tests__/helpers/mock-kv.ts +33 -0
  25. package/src/__tests__/helpers/mock-oauth-flow.ts +250 -0
  26. package/src/__tests__/helpers/mock-process.ts +39 -0
  27. package/src/__tests__/helpers/mock-stdin.ts +108 -0
  28. package/src/__tests__/helpers/mock-web-socket.ts +29 -0
  29. package/src/__tests__/helpers/run-in-tmp.ts +38 -0
  30. package/src/__tests__/helpers/run-wrangler.ts +16 -0
  31. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  32. package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
  33. package/src/__tests__/https-options.test.ts +163 -0
  34. package/src/__tests__/index.test.ts +242 -419
  35. package/src/__tests__/init.test.ts +2170 -0
  36. package/src/__tests__/jest.setup.ts +157 -0
  37. package/src/__tests__/kv.test.ts +1671 -0
  38. package/src/__tests__/logger.test.ts +141 -0
  39. package/src/__tests__/metrics.test.ts +450 -0
  40. package/src/__tests__/package-manager.test.ts +353 -0
  41. package/src/__tests__/pages.test.ts +1275 -0
  42. package/src/__tests__/parse.test.ts +330 -0
  43. package/src/__tests__/publish.test.ts +6903 -0
  44. package/src/__tests__/pubsub.test.ts +367 -0
  45. package/src/__tests__/r2.test.ts +336 -0
  46. package/src/__tests__/route.test.ts +45 -0
  47. package/src/__tests__/secret.test.ts +492 -0
  48. package/src/__tests__/tail.test.ts +802 -0
  49. package/src/__tests__/test-old-node-version.js +31 -0
  50. package/src/__tests__/user.test.ts +155 -0
  51. package/src/__tests__/validate-dev-props.test.ts +56 -0
  52. package/src/__tests__/version.test.ts +35 -0
  53. package/src/__tests__/whoami.test.tsx +289 -0
  54. package/src/__tests__/worker-namespace.test.ts +329 -0
  55. package/src/abort.d.ts +3 -0
  56. package/src/api/dev.ts +93 -0
  57. package/src/api/index.ts +1 -0
  58. package/src/bundle-reporter.tsx +29 -0
  59. package/src/bundle.ts +473 -0
  60. package/src/cfetch/index.ts +121 -0
  61. package/src/cfetch/internal.ts +237 -0
  62. package/src/cli.ts +25 -8
  63. package/src/config/README.md +107 -0
  64. package/src/config/config.ts +263 -0
  65. package/src/config/diagnostics.ts +80 -0
  66. package/src/config/environment.ts +485 -0
  67. package/src/config/index.ts +251 -0
  68. package/src/config/validation-helpers.ts +597 -0
  69. package/src/config/validation.ts +1862 -0
  70. package/src/config-cache.ts +85 -0
  71. package/src/create-worker-preview.ts +257 -0
  72. package/src/create-worker-upload-form.ts +288 -0
  73. package/src/dev/dev-vars.ts +36 -0
  74. package/src/dev/dev.tsx +545 -0
  75. package/src/dev/local.tsx +449 -0
  76. package/src/dev/remote.tsx +421 -0
  77. package/src/dev/use-esbuild.ts +178 -0
  78. package/src/dev/validate-dev-props.ts +31 -0
  79. package/src/dev-registry.tsx +160 -0
  80. package/src/dev.tsx +612 -764
  81. package/src/dialogs.tsx +117 -59
  82. package/src/dispatch-namespace.ts +206 -0
  83. package/src/durable.ts +102 -0
  84. package/src/entry.ts +328 -0
  85. package/src/environment-variables.ts +35 -0
  86. package/src/errors.ts +11 -0
  87. package/src/faye-websocket.d.ts +6 -0
  88. package/src/generate.ts +131 -0
  89. package/src/git-client.ts +42 -0
  90. package/src/global-wrangler-config-path.ts +26 -0
  91. package/src/https-options.ts +127 -0
  92. package/src/index.tsx +2213 -1857
  93. package/src/init.ts +622 -0
  94. package/src/inspect.ts +747 -0
  95. package/src/intl-polyfill.d.ts +139 -0
  96. package/src/is-ci.ts +14 -0
  97. package/src/is-interactive.ts +12 -0
  98. package/src/kv.ts +430 -0
  99. package/src/logger.ts +73 -0
  100. package/src/metrics/index.ts +5 -0
  101. package/src/metrics/metrics-config.ts +239 -0
  102. package/src/metrics/metrics-dispatcher.ts +96 -0
  103. package/src/metrics/metrics-usage-headers.ts +24 -0
  104. package/src/metrics/send-event.ts +92 -0
  105. package/src/miniflare-cli/README.md +30 -0
  106. package/src/miniflare-cli/assets.ts +554 -0
  107. package/src/miniflare-cli/enum-keys.ts +17 -0
  108. package/src/miniflare-cli/index.ts +207 -0
  109. package/src/miniflare-cli/request-context.ts +40 -0
  110. package/src/module-collection.ts +247 -53
  111. package/src/open-in-browser.ts +17 -0
  112. package/src/package-manager.ts +219 -0
  113. package/src/pages/build.tsx +238 -0
  114. package/src/pages/constants.ts +12 -0
  115. package/src/pages/deployments.tsx +106 -0
  116. package/src/pages/dev.tsx +528 -0
  117. package/src/pages/errors.ts +22 -0
  118. package/src/pages/functions/buildPlugin.ts +109 -0
  119. package/src/pages/functions/buildWorker.ts +155 -0
  120. package/src/pages/functions/filepath-routing.test.ts +234 -0
  121. package/src/pages/functions/filepath-routing.ts +189 -0
  122. package/src/pages/functions/identifiers.ts +78 -0
  123. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  124. package/src/pages/functions/routes-consolidation.ts +73 -0
  125. package/src/pages/functions/routes-transformation.test.ts +271 -0
  126. package/src/pages/functions/routes-transformation.ts +122 -0
  127. package/src/pages/functions/routes.ts +151 -0
  128. package/src/pages/functions.tsx +96 -0
  129. package/src/pages/index.tsx +94 -0
  130. package/src/pages/projects.tsx +169 -0
  131. package/src/pages/publish.tsx +391 -0
  132. package/src/pages/types.ts +49 -0
  133. package/src/pages/upload.tsx +413 -0
  134. package/src/pages/utils.ts +12 -0
  135. package/src/parse.ts +286 -0
  136. package/src/paths.ts +26 -0
  137. package/src/preview.ts +31 -0
  138. package/src/proxy.ts +486 -0
  139. package/src/publish.ts +796 -335
  140. package/src/pubsub/index.ts +286 -0
  141. package/src/pubsub/pubsub-commands.tsx +623 -0
  142. package/src/r2.ts +131 -0
  143. package/src/selfsigned.d.ts +29 -0
  144. package/src/sites.tsx +357 -100
  145. package/src/tail/filters.ts +281 -0
  146. package/src/tail/index.ts +312 -0
  147. package/src/tail/printing.ts +107 -0
  148. package/src/update-check.ts +19 -0
  149. package/src/user/choose-account.tsx +69 -0
  150. package/src/user/env-vars.ts +46 -0
  151. package/src/user/generate-auth-url.ts +33 -0
  152. package/src/user/generate-random-state.ts +16 -0
  153. package/src/user/index.ts +3 -0
  154. package/src/user/user.tsx +1191 -0
  155. package/src/whoami.tsx +169 -0
  156. package/src/worker.ts +203 -0
  157. package/src/zones.ts +167 -0
  158. package/templates/checked-fetch.js +17 -0
  159. package/templates/first-party-worker-module-facade.ts +18 -0
  160. package/templates/format-dev-errors.ts +32 -0
  161. package/templates/gitignore +171 -0
  162. package/templates/new-worker-scheduled.js +17 -0
  163. package/templates/new-worker-scheduled.ts +32 -0
  164. package/templates/new-worker.js +15 -0
  165. package/templates/new-worker.ts +30 -0
  166. package/templates/no-op-worker.js +10 -0
  167. package/templates/pages-shim.ts +9 -0
  168. package/templates/pages-template-plugin.ts +167 -0
  169. package/templates/pages-template-worker.ts +172 -0
  170. package/templates/serve-static-assets.ts +63 -0
  171. package/templates/service-bindings-module-facade.js +54 -0
  172. package/templates/service-bindings-sw-facade.js +42 -0
  173. package/templates/tsconfig.json +105 -0
  174. package/wrangler-dist/cli.d.ts +338 -0
  175. package/wrangler-dist/cli.js +127880 -101761
  176. package/src/__tests__/mock-cfetch.js +0 -42
  177. package/src/api/form_data.ts +0 -141
  178. package/src/api/inspect.ts +0 -430
  179. package/src/api/preview.ts +0 -128
  180. package/src/api/worker.ts +0 -161
  181. package/src/cfetch.ts +0 -72
  182. package/src/config.ts +0 -122
  183. package/src/kv.tsx +0 -211
  184. package/src/pages.tsx +0 -818
  185. package/src/tail.tsx +0 -71
  186. package/src/user.tsx +0 -1029
  187. package/static-asset-facade.js +0 -47
  188. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  189. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  190. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  191. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  192. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  193. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  194. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  195. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  196. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  197. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  198. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  199. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  200. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  201. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  202. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  203. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  204. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  205. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  206. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  207. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  208. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  209. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  210. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  211. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  212. package/vendor/wrangler-mime/LICENSE +0 -21
  213. package/vendor/wrangler-mime/Mime.js +0 -97
  214. package/vendor/wrangler-mime/README.md +0 -187
  215. package/vendor/wrangler-mime/cli.js +0 -46
  216. package/vendor/wrangler-mime/index.js +0 -4
  217. package/vendor/wrangler-mime/lite.js +0 -4
  218. package/vendor/wrangler-mime/package.json +0 -52
  219. package/vendor/wrangler-mime/types/other.js +0 -1
  220. package/vendor/wrangler-mime/types/standard.js +0 -1
  221. 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
+ }