wrangler 0.0.0-e178d6fb → 0.0.0-e1c2f5b9

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 (239) hide show
  1. package/README.md +16 -2
  2. package/bin/wrangler.js +31 -11
  3. package/miniflare-dist/index.mjs +1340 -330
  4. package/package.json +40 -13
  5. package/src/__tests__/access.test.ts +25 -0
  6. package/src/__tests__/api-dev.test.ts +238 -0
  7. package/src/__tests__/api-devregistry.test.js +64 -0
  8. package/src/__tests__/api.test.ts +80 -0
  9. package/src/__tests__/configuration.test.ts +683 -470
  10. package/src/__tests__/d1.test.ts +123 -0
  11. package/src/__tests__/delete.test.ts +263 -0
  12. package/src/__tests__/deployments.test.ts +105 -0
  13. package/src/__tests__/dev.test.tsx +453 -70
  14. package/src/__tests__/dialogs.test.tsx +40 -0
  15. package/src/__tests__/generate.test.ts +235 -0
  16. package/src/__tests__/get-host-from-url.test.ts +16 -0
  17. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  18. package/src/__tests__/helpers/mock-cfetch.ts +92 -26
  19. package/src/__tests__/helpers/mock-console.ts +11 -2
  20. package/src/__tests__/helpers/mock-dialogs.ts +1 -1
  21. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  22. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  23. package/src/__tests__/helpers/mock-kv.ts +1 -1
  24. package/src/__tests__/helpers/mock-oauth-flow.ts +74 -53
  25. package/src/__tests__/helpers/mock-process.ts +8 -13
  26. package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
  27. package/src/__tests__/helpers/msw/handlers/deployments.ts +59 -0
  28. package/src/__tests__/helpers/msw/handlers/namespaces.ts +104 -0
  29. package/src/__tests__/helpers/msw/handlers/oauth.ts +31 -0
  30. package/src/__tests__/helpers/msw/handlers/r2.ts +80 -0
  31. package/src/__tests__/helpers/msw/handlers/script.ts +75 -0
  32. package/src/__tests__/helpers/msw/handlers/user.ts +63 -0
  33. package/src/__tests__/helpers/msw/handlers/zones.ts +22 -0
  34. package/src/__tests__/helpers/msw/index.ts +21 -0
  35. package/src/__tests__/helpers/worker-scripts/child-wrangler.toml +1 -0
  36. package/src/__tests__/helpers/worker-scripts/hello-world-worker.js +5 -0
  37. package/src/__tests__/helpers/worker-scripts/hello-world-wrangler.toml +1 -0
  38. package/src/__tests__/helpers/worker-scripts/parent-worker.js +8 -0
  39. package/src/__tests__/helpers/worker-scripts/parent-wrangler.toml +5 -0
  40. package/src/__tests__/index.test.ts +103 -97
  41. package/src/__tests__/init.test.ts +1484 -382
  42. package/src/__tests__/jest.setup.ts +88 -5
  43. package/src/__tests__/kv.test.ts +655 -540
  44. package/src/__tests__/logout.test.ts +47 -0
  45. package/src/__tests__/metrics.test.ts +95 -45
  46. package/src/__tests__/middleware.scheduled.test.ts +145 -0
  47. package/src/__tests__/middleware.test.ts +750 -0
  48. package/src/__tests__/pages-deployment-tail.test.ts +884 -0
  49. package/src/__tests__/pages.test.ts +1301 -119
  50. package/src/__tests__/paths.test.ts +39 -0
  51. package/src/__tests__/publish.test.ts +2266 -1180
  52. package/src/__tests__/pubsub.test.ts +211 -88
  53. package/src/__tests__/queues.test.ts +522 -0
  54. package/src/__tests__/r2.test.ts +363 -203
  55. package/src/__tests__/secret.test.ts +261 -59
  56. package/src/__tests__/tail.test.ts +352 -151
  57. package/src/__tests__/test-old-node-version.js +3 -3
  58. package/src/__tests__/tsconfig-sanity.ts +12 -0
  59. package/src/__tests__/tsconfig.json +8 -0
  60. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  61. package/src/__tests__/type-generation.test.ts +233 -0
  62. package/src/__tests__/user.test.ts +59 -73
  63. package/src/__tests__/utils-collectKeyValues.test.ts +47 -0
  64. package/src/__tests__/validate-dev-props.test.ts +56 -0
  65. package/src/__tests__/whoami.test.tsx +114 -66
  66. package/src/__tests__/worker-namespace.test.ts +154 -155
  67. package/src/api/dev.ts +170 -38
  68. package/src/api/index.ts +1 -0
  69. package/src/bundle-reporter.tsx +41 -2
  70. package/src/bundle.ts +668 -81
  71. package/src/cfetch/index.ts +40 -3
  72. package/src/cfetch/internal.ts +144 -32
  73. package/src/cli.ts +4 -3
  74. package/src/config/config.ts +27 -3
  75. package/src/config/environment.ts +131 -7
  76. package/src/config/index.ts +128 -8
  77. package/src/config/validation-helpers.ts +19 -6
  78. package/src/config/validation.ts +411 -14
  79. package/src/config-cache.ts +3 -2
  80. package/src/create-worker-preview.ts +31 -6
  81. package/src/create-worker-upload-form.ts +84 -22
  82. package/src/d1/backups.tsx +223 -0
  83. package/src/d1/constants.ts +2 -0
  84. package/src/d1/create.tsx +63 -0
  85. package/src/d1/delete.tsx +56 -0
  86. package/src/d1/execute.tsx +352 -0
  87. package/src/d1/formatTimeAgo.ts +14 -0
  88. package/src/d1/index.ts +101 -0
  89. package/src/d1/list.tsx +48 -0
  90. package/src/d1/migrations/apply.tsx +196 -0
  91. package/src/d1/migrations/create.tsx +77 -0
  92. package/src/d1/migrations/helpers.ts +147 -0
  93. package/src/d1/migrations/index.tsx +3 -0
  94. package/src/d1/migrations/list.tsx +79 -0
  95. package/src/d1/migrations/options.ts +18 -0
  96. package/src/d1/options.ts +22 -0
  97. package/src/d1/types.tsx +24 -0
  98. package/src/d1/utils.ts +48 -0
  99. package/src/delete.ts +108 -0
  100. package/src/deployments.ts +83 -0
  101. package/src/deprecated/index.ts +145 -0
  102. package/src/dev/dev-vars.ts +11 -8
  103. package/src/dev/dev.tsx +220 -58
  104. package/src/dev/get-local-persistence-path.tsx +31 -0
  105. package/src/dev/local.tsx +740 -181
  106. package/src/dev/remote.tsx +340 -123
  107. package/src/dev/start-server.ts +543 -0
  108. package/src/dev/use-esbuild.ts +61 -7
  109. package/src/dev/validate-dev-props.ts +31 -0
  110. package/src/dev-registry.tsx +201 -0
  111. package/src/dev.tsx +614 -258
  112. package/src/dialogs.tsx +41 -8
  113. package/src/{worker-namespace.ts → dispatch-namespace.ts} +23 -22
  114. package/src/docs/index.ts +97 -0
  115. package/src/entry.ts +3 -2
  116. package/src/environment-variables/factory.ts +88 -0
  117. package/src/environment-variables/misc-variables.ts +30 -0
  118. package/src/generate/index.ts +300 -0
  119. package/src/git-client.ts +100 -7
  120. package/src/index.tsx +249 -1560
  121. package/src/init.ts +626 -150
  122. package/src/inspect.ts +137 -32
  123. package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
  124. package/src/is-interactive.ts +4 -0
  125. package/src/jest.d.ts +4 -0
  126. package/src/{kv.ts → kv/helpers.ts} +3 -3
  127. package/src/kv/index.ts +596 -0
  128. package/src/logger.ts +27 -8
  129. package/src/metrics/index.ts +1 -0
  130. package/src/metrics/metrics-config.ts +4 -4
  131. package/src/metrics/metrics-dispatcher.ts +1 -0
  132. package/src/metrics/metrics-usage-headers.ts +24 -0
  133. package/src/metrics/send-event.ts +13 -8
  134. package/src/miniflare-cli/assets.ts +172 -465
  135. package/src/miniflare-cli/index.ts +149 -24
  136. package/src/miniflare-cli/tsconfig.json +9 -0
  137. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  138. package/src/miniflare-cli/types.ts +11 -0
  139. package/src/module-collection.ts +12 -3
  140. package/src/pages/build.tsx +108 -42
  141. package/src/pages/constants.ts +11 -0
  142. package/src/pages/deployment-tails.tsx +284 -0
  143. package/src/pages/deployments.tsx +9 -31
  144. package/src/pages/dev.tsx +417 -108
  145. package/src/pages/errors.ts +66 -0
  146. package/src/pages/functions/buildPlugin.ts +86 -84
  147. package/src/pages/functions/buildWorker.ts +121 -106
  148. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  149. package/src/pages/functions/routes-consolidation.ts +73 -0
  150. package/src/pages/functions/routes-transformation.test.ts +282 -0
  151. package/src/pages/functions/routes-transformation.ts +115 -0
  152. package/src/pages/functions/routes-validation.test.ts +403 -0
  153. package/src/pages/functions/routes-validation.ts +202 -0
  154. package/src/pages/functions/tsconfig.json +8 -0
  155. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  156. package/src/pages/functions.tsx +82 -0
  157. package/src/pages/hash.tsx +13 -0
  158. package/src/pages/index.tsx +73 -55
  159. package/src/pages/projects.tsx +9 -3
  160. package/src/pages/prompt-select-project.tsx +31 -0
  161. package/src/pages/publish.tsx +183 -60
  162. package/src/pages/types.ts +1 -0
  163. package/src/pages/upload.tsx +107 -56
  164. package/src/pages/utils.ts +13 -2
  165. package/src/paths.ts +49 -4
  166. package/src/proxy.ts +375 -157
  167. package/src/publish/index.ts +270 -0
  168. package/src/{publish.ts → publish/publish.ts} +431 -188
  169. package/src/pubsub/pubsub-commands.tsx +4 -3
  170. package/src/queues/cli/commands/consumer/add.ts +71 -0
  171. package/src/queues/cli/commands/consumer/index.ts +22 -0
  172. package/src/queues/cli/commands/consumer/remove.ts +38 -0
  173. package/src/queues/cli/commands/create.ts +25 -0
  174. package/src/queues/cli/commands/delete.ts +26 -0
  175. package/src/queues/cli/commands/index.ts +36 -0
  176. package/src/queues/cli/commands/list.ts +25 -0
  177. package/src/queues/client.ts +135 -0
  178. package/src/queues/utils.ts +18 -0
  179. package/src/r2/constants.ts +4 -0
  180. package/src/r2/helpers.ts +131 -0
  181. package/src/r2/index.ts +289 -0
  182. package/src/routes.ts +140 -0
  183. package/src/secret/index.ts +379 -0
  184. package/src/sites.tsx +3 -3
  185. package/src/tail/createTail.ts +379 -0
  186. package/src/tail/filters.ts +4 -6
  187. package/src/tail/index.ts +199 -284
  188. package/src/tail/printing.ts +43 -3
  189. package/src/tsconfig-sanity.ts +16 -0
  190. package/src/type-generation.ts +181 -0
  191. package/src/user/access.ts +68 -0
  192. package/src/user/auth-variables.ts +113 -0
  193. package/src/user/choose-account.tsx +1 -1
  194. package/src/user/index.ts +0 -1
  195. package/src/user/user.tsx +116 -49
  196. package/src/utils/collectKeyValues.ts +14 -0
  197. package/src/whoami.tsx +80 -2
  198. package/src/worker.ts +69 -9
  199. package/src/yargs-types.ts +24 -0
  200. package/src/zones.ts +124 -9
  201. package/templates/__tests__/pages-dev-util.test.ts +128 -0
  202. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  203. package/templates/__tests__/tsconfig.json +8 -0
  204. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  205. package/templates/d1-beta-facade.js +205 -0
  206. package/templates/facade.d.ts +14 -0
  207. package/templates/first-party-worker-module-facade.ts +19 -0
  208. package/templates/format-dev-errors.ts +33 -0
  209. package/templates/init-tests/test-jest-new-worker.js +23 -0
  210. package/templates/init-tests/test-vitest-new-worker.js +24 -0
  211. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  212. package/templates/middleware/common.ts +62 -0
  213. package/templates/middleware/loader-modules.ts +82 -0
  214. package/templates/middleware/loader-sw.ts +233 -0
  215. package/templates/middleware/middleware-miniflare3-json-error.ts +20 -0
  216. package/templates/middleware/middleware-pretty-error.ts +40 -0
  217. package/templates/middleware/middleware-scheduled.ts +15 -0
  218. package/templates/new-worker.js +1 -1
  219. package/templates/pages-dev-pipeline.ts +31 -0
  220. package/templates/pages-dev-util.ts +52 -0
  221. package/templates/pages-shim.ts +4 -1
  222. package/templates/pages-template-plugin.ts +21 -5
  223. package/templates/pages-template-worker.ts +37 -9
  224. package/templates/{static-asset-facade.js → serve-static-assets.ts} +23 -7
  225. package/templates/service-bindings-module-facade.js +54 -0
  226. package/templates/service-bindings-sw-facade.js +42 -0
  227. package/templates/tsconfig-sanity.ts +11 -0
  228. package/templates/tsconfig.init.json +106 -0
  229. package/templates/tsconfig.json +5 -102
  230. package/templates/tsconfig.tsbuildinfo +1 -0
  231. package/wrangler-dist/cli.d.ts +621 -42
  232. package/wrangler-dist/cli.js +144441 -102606
  233. package/src/environment-variables.ts +0 -35
  234. package/src/faye-websocket.d.ts +0 -6
  235. package/src/generate.ts +0 -33
  236. package/src/miniflare-cli/enum-keys.ts +0 -17
  237. package/src/preview.ts +0 -31
  238. package/src/r2.ts +0 -50
  239. package/src/user/env-vars.ts +0 -46
@@ -11,9 +11,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
11
11
  return require.apply(this, arguments);
12
12
  throw new Error('Dynamic require of "' + x + '" is not supported');
13
13
  });
14
+ var __esm = (fn, res) => function __init() {
15
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
16
+ };
14
17
  var __commonJS = (cb, mod) => function __require2() {
15
18
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
19
  };
20
+ var __export = (target, all) => {
21
+ for (var name in all)
22
+ __defProp(target, name, { get: all[name], enumerable: true });
23
+ };
17
24
  var __copyProps = (to, from, except, desc) => {
18
25
  if (from && typeof from === "object" || typeof from === "function") {
19
26
  for (let key of __getOwnPropNames(from))
@@ -22,7 +29,10 @@ var __copyProps = (to, from, except, desc) => {
22
29
  }
23
30
  return to;
24
31
  };
25
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
32
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
26
36
 
27
37
  // ../../node_modules/mime/Mime.js
28
38
  var require_Mime = __commonJS({
@@ -50,7 +60,9 @@ var require_Mime = __commonJS({
50
60
  continue;
51
61
  }
52
62
  if (!force && ext in this._types) {
53
- throw new Error('Attempt to change mapping for "' + ext + '" extension from "' + this._types[ext] + '" to "' + type + '". Pass `force=true` to allow this, otherwise remove "' + ext + '" from the list of extensions for "' + type + '".');
63
+ throw new Error(
64
+ 'Attempt to change mapping for "' + ext + '" extension from "' + this._types[ext] + '" to "' + type + '". Pass `force=true` to allow this, otherwise remove "' + ext + '" from the list of extensions for "' + type + '".'
65
+ );
54
66
  }
55
67
  this._types[ext] = type;
56
68
  }
@@ -99,8 +111,686 @@ var require_mime = __commonJS({
99
111
  }
100
112
  });
101
113
 
114
+ // ../pages-shared/environment-polyfills/index.ts
115
+ var polyfill;
116
+ var init_environment_polyfills = __esm({
117
+ "../pages-shared/environment-polyfills/index.ts"() {
118
+ polyfill = (environment) => {
119
+ Object.entries(environment).map(([name, value]) => {
120
+ Object.defineProperty(globalThis, name, {
121
+ value,
122
+ configurable: true,
123
+ enumerable: true,
124
+ writable: true
125
+ });
126
+ });
127
+ };
128
+ }
129
+ });
130
+
131
+ // ../pages-shared/environment-polyfills/miniflare-tre.ts
132
+ var miniflare_tre_exports = {};
133
+ __export(miniflare_tre_exports, {
134
+ default: () => miniflare_tre_default
135
+ });
136
+ var miniflare_tre_default;
137
+ var init_miniflare_tre = __esm({
138
+ "../pages-shared/environment-polyfills/miniflare-tre.ts"() {
139
+ init_environment_polyfills();
140
+ miniflare_tre_default = async () => {
141
+ const mf = await import("@miniflare/tre");
142
+ polyfill({
143
+ fetch: mf.fetch,
144
+ Headers: mf.Headers,
145
+ Request: mf.Request,
146
+ Response: mf.Response
147
+ });
148
+ };
149
+ }
150
+ });
151
+
152
+ // ../pages-shared/environment-polyfills/miniflare.ts
153
+ var miniflare_exports = {};
154
+ __export(miniflare_exports, {
155
+ default: () => miniflare_default
156
+ });
157
+ var miniflare_default;
158
+ var init_miniflare = __esm({
159
+ "../pages-shared/environment-polyfills/miniflare.ts"() {
160
+ init_environment_polyfills();
161
+ miniflare_default = async () => {
162
+ const mf = await import("@miniflare/core");
163
+ polyfill({
164
+ fetch: mf.fetch,
165
+ Headers: mf.Headers,
166
+ Request: mf.Request,
167
+ Response: mf.Response
168
+ });
169
+ };
170
+ }
171
+ });
172
+
173
+ // ../pages-shared/asset-server/responses.ts
174
+ function mergeHeaders(base, extra) {
175
+ base = new Headers(base ?? {});
176
+ extra = new Headers(extra ?? {});
177
+ return new Headers({
178
+ ...Object.fromEntries(base.entries()),
179
+ ...Object.fromEntries(extra.entries())
180
+ });
181
+ }
182
+ var OkResponse, MovedPermanentlyResponse, FoundResponse, NotModifiedResponse, PermanentRedirectResponse, NotFoundResponse, MethodNotAllowedResponse, NotAcceptableResponse, InternalServerErrorResponse, SeeOtherResponse, TemporaryRedirectResponse;
183
+ var init_responses = __esm({
184
+ "../pages-shared/asset-server/responses.ts"() {
185
+ OkResponse = class extends Response {
186
+ constructor(...[body, init]) {
187
+ super(body, {
188
+ ...init,
189
+ status: 200,
190
+ statusText: "OK"
191
+ });
192
+ }
193
+ };
194
+ MovedPermanentlyResponse = class extends Response {
195
+ constructor(location, init) {
196
+ super(`Redirecting to ${location}`, {
197
+ ...init,
198
+ status: 301,
199
+ statusText: "Moved Permanently",
200
+ headers: mergeHeaders(init?.headers, {
201
+ location
202
+ })
203
+ });
204
+ }
205
+ };
206
+ FoundResponse = class extends Response {
207
+ constructor(location, init) {
208
+ super(`Redirecting to ${location}`, {
209
+ ...init,
210
+ status: 302,
211
+ statusText: "Found",
212
+ headers: mergeHeaders(init?.headers, {
213
+ location
214
+ })
215
+ });
216
+ }
217
+ };
218
+ NotModifiedResponse = class extends Response {
219
+ constructor(...[_body, _init]) {
220
+ super(void 0, {
221
+ status: 304,
222
+ statusText: "Not Modified"
223
+ });
224
+ }
225
+ };
226
+ PermanentRedirectResponse = class extends Response {
227
+ constructor(location, init) {
228
+ super(void 0, {
229
+ ...init,
230
+ status: 308,
231
+ statusText: "Permanent Redirect",
232
+ headers: mergeHeaders(init?.headers, {
233
+ location
234
+ })
235
+ });
236
+ }
237
+ };
238
+ NotFoundResponse = class extends Response {
239
+ constructor(...[body, init]) {
240
+ super(body, {
241
+ ...init,
242
+ status: 404,
243
+ statusText: "Not Found"
244
+ });
245
+ }
246
+ };
247
+ MethodNotAllowedResponse = class extends Response {
248
+ constructor(...[body, init]) {
249
+ super(body, {
250
+ ...init,
251
+ status: 405,
252
+ statusText: "Method Not Allowed"
253
+ });
254
+ }
255
+ };
256
+ NotAcceptableResponse = class extends Response {
257
+ constructor(...[body, init]) {
258
+ super(body, {
259
+ ...init,
260
+ status: 406,
261
+ statusText: "Not Acceptable"
262
+ });
263
+ }
264
+ };
265
+ InternalServerErrorResponse = class extends Response {
266
+ constructor(err, init) {
267
+ let body = void 0;
268
+ if (globalThis.DEBUG) {
269
+ body = `${err.message}
270
+
271
+ ${err.stack}`;
272
+ }
273
+ super(body, {
274
+ ...init,
275
+ status: 500,
276
+ statusText: "Internal Server Error"
277
+ });
278
+ }
279
+ };
280
+ SeeOtherResponse = class extends Response {
281
+ constructor(location, init) {
282
+ super(`Redirecting to ${location}`, {
283
+ ...init,
284
+ status: 303,
285
+ statusText: "See Other",
286
+ headers: mergeHeaders(init?.headers, { location })
287
+ });
288
+ }
289
+ };
290
+ TemporaryRedirectResponse = class extends Response {
291
+ constructor(location, init) {
292
+ super(`Redirecting to ${location}`, {
293
+ ...init,
294
+ status: 307,
295
+ statusText: "Temporary Redirect",
296
+ headers: mergeHeaders(init?.headers, { location })
297
+ });
298
+ }
299
+ };
300
+ }
301
+ });
302
+
303
+ // ../pages-shared/asset-server/rulesEngine.ts
304
+ var ESCAPE_REGEX_CHARACTERS, escapeRegex, HOST_PLACEHOLDER_REGEX, PLACEHOLDER_REGEX2, replacer, generateRulesMatcher;
305
+ var init_rulesEngine = __esm({
306
+ "../pages-shared/asset-server/rulesEngine.ts"() {
307
+ ESCAPE_REGEX_CHARACTERS = /[-/\\^$*+?.()|[\]{}]/g;
308
+ escapeRegex = (str) => {
309
+ return str.replace(ESCAPE_REGEX_CHARACTERS, "\\$&");
310
+ };
311
+ HOST_PLACEHOLDER_REGEX = /(?<=^https:\\\/\\\/[^/]*?):([^\\]+)(?=\\)/g;
312
+ PLACEHOLDER_REGEX2 = /:(\w+)/g;
313
+ replacer = (str, replacements) => {
314
+ for (const [replacement, value] of Object.entries(replacements)) {
315
+ str = str.replaceAll(`:${replacement}`, value);
316
+ }
317
+ return str;
318
+ };
319
+ generateRulesMatcher = (rules, replacerFn = (match) => match) => {
320
+ if (!rules)
321
+ return () => [];
322
+ const compiledRules = Object.entries(rules).map(([rule, match]) => {
323
+ const crossHost = rule.startsWith("https://");
324
+ rule = rule.split("*").map(escapeRegex).join("(?<splat>.*)");
325
+ const host_matches = rule.matchAll(HOST_PLACEHOLDER_REGEX);
326
+ for (const host_match of host_matches) {
327
+ rule = rule.split(host_match[0]).join(`(?<${host_match[1]}>[^/.]+)`);
328
+ }
329
+ const path_matches = rule.matchAll(PLACEHOLDER_REGEX2);
330
+ for (const path_match of path_matches) {
331
+ rule = rule.split(path_match[0]).join(`(?<${path_match[1]}>[^/]+)`);
332
+ }
333
+ rule = "^" + rule + "$";
334
+ try {
335
+ const regExp = new RegExp(rule);
336
+ return [{ crossHost, regExp }, match];
337
+ } catch {
338
+ }
339
+ }).filter((value) => value !== void 0);
340
+ return ({ request }) => {
341
+ const { pathname, host } = new URL(request.url);
342
+ return compiledRules.map(([{ crossHost, regExp }, match]) => {
343
+ const test = crossHost ? `https://${host}${pathname}` : pathname;
344
+ const result = regExp.exec(test);
345
+ if (result) {
346
+ return replacerFn(match, result.groups || {});
347
+ }
348
+ }).filter((value) => value !== void 0);
349
+ };
350
+ };
351
+ }
352
+ });
353
+
354
+ // ../pages-shared/asset-server/url.ts
355
+ function stringifyURLToRootRelativePathname(url) {
356
+ return `${url.pathname}${url.search}${url.hash}`;
357
+ }
358
+ var init_url = __esm({
359
+ "../pages-shared/asset-server/url.ts"() {
360
+ }
361
+ });
362
+
363
+ // ../pages-shared/asset-server/handler.ts
364
+ var handler_exports = {};
365
+ __export(handler_exports, {
366
+ ANALYTICS_VERSION: () => ANALYTICS_VERSION2,
367
+ ASSET_PRESERVATION_CACHE: () => ASSET_PRESERVATION_CACHE,
368
+ CACHE_CONTROL_BROWSER: () => CACHE_CONTROL_BROWSER,
369
+ HEADERS_VERSION: () => HEADERS_VERSION2,
370
+ HEADERS_VERSION_V1: () => HEADERS_VERSION_V1,
371
+ REDIRECTS_VERSION: () => REDIRECTS_VERSION2,
372
+ generateHandler: () => generateHandler,
373
+ getResponseFromMatch: () => getResponseFromMatch,
374
+ normaliseHeaders: () => normaliseHeaders,
375
+ parseQualityWeightedList: () => parseQualityWeightedList
376
+ });
377
+ function normaliseHeaders(headers) {
378
+ if (headers.version === HEADERS_VERSION2) {
379
+ return headers.rules;
380
+ } else if (headers.version === HEADERS_VERSION_V1) {
381
+ return Object.keys(headers.rules).reduce(
382
+ (acc, key) => {
383
+ acc[key] = {
384
+ set: headers.rules[key]
385
+ };
386
+ return acc;
387
+ },
388
+ {}
389
+ );
390
+ } else {
391
+ return {};
392
+ }
393
+ }
394
+ async function generateHandler({
395
+ request,
396
+ metadata,
397
+ xServerEnvHeader,
398
+ logError,
399
+ findAssetEntryForPath,
400
+ getAssetKey,
401
+ negotiateContent,
402
+ fetchAsset,
403
+ generateNotFoundResponse = async (notFoundRequest, notFoundFindAssetEntryForPath, notFoundServeAsset) => {
404
+ let assetEntry;
405
+ if (assetEntry = await notFoundFindAssetEntryForPath("/index.html")) {
406
+ return notFoundServeAsset(assetEntry, { preserve: false });
407
+ }
408
+ return new NotFoundResponse();
409
+ },
410
+ attachAdditionalHeaders = () => {
411
+ },
412
+ caches,
413
+ waitUntil
414
+ }) {
415
+ const url = new URL(request.url);
416
+ const { protocol, host, search } = url;
417
+ let { pathname } = url;
418
+ const earlyHintsCache = metadata.deploymentId ? await caches?.open(`eh:${metadata.deploymentId}`) : void 0;
419
+ const headerRules = metadata.headers ? normaliseHeaders(metadata.headers) : {};
420
+ const staticRules = metadata.redirects?.version === REDIRECTS_VERSION2 ? metadata.redirects.staticRules || {} : {};
421
+ const staticRedirectsMatcher = () => {
422
+ const withHostMatch = staticRules[`https://${host}${pathname}`];
423
+ const withoutHostMatch = staticRules[pathname];
424
+ if (withHostMatch && withoutHostMatch) {
425
+ if (withHostMatch.lineNumber < withoutHostMatch.lineNumber) {
426
+ return withHostMatch;
427
+ } else {
428
+ return withoutHostMatch;
429
+ }
430
+ }
431
+ return withHostMatch || withoutHostMatch;
432
+ };
433
+ const generateRedirectsMatcher = () => generateRulesMatcher(
434
+ metadata.redirects?.version === REDIRECTS_VERSION2 ? metadata.redirects.rules : {},
435
+ ({ status, to }, replacements) => ({
436
+ status,
437
+ to: replacer(to, replacements)
438
+ })
439
+ );
440
+ let assetEntry;
441
+ async function generateResponse() {
442
+ const match = staticRedirectsMatcher() || generateRedirectsMatcher()({ request })[0];
443
+ if (match) {
444
+ return getResponseFromMatch(match, url);
445
+ }
446
+ if (!request.method.match(/^(get|head)$/i)) {
447
+ return new MethodNotAllowedResponse();
448
+ }
449
+ try {
450
+ pathname = globalThis.decodeURIComponent(pathname);
451
+ } catch (err) {
452
+ }
453
+ if (pathname.endsWith("/")) {
454
+ if (assetEntry = await findAssetEntryForPath(`${pathname}index.html`)) {
455
+ return serveAsset(assetEntry);
456
+ } else if (pathname.endsWith("/index/")) {
457
+ return new PermanentRedirectResponse(
458
+ `/${pathname.slice(1, -"index/".length)}${search}`
459
+ );
460
+ } else if (assetEntry = await findAssetEntryForPath(
461
+ `${pathname.replace(/\/$/, ".html")}`
462
+ )) {
463
+ return new PermanentRedirectResponse(
464
+ `/${pathname.slice(1, -1)}${search}`
465
+ );
466
+ } else {
467
+ return notFound();
468
+ }
469
+ }
470
+ if (assetEntry = await findAssetEntryForPath(pathname)) {
471
+ if (pathname.endsWith(".html")) {
472
+ const extensionlessPath = pathname.slice(0, -".html".length);
473
+ if (extensionlessPath.endsWith("/index")) {
474
+ return new PermanentRedirectResponse(
475
+ `${extensionlessPath.replace(/\/index$/, "/")}${search}`
476
+ );
477
+ } else if (await findAssetEntryForPath(extensionlessPath) || extensionlessPath === "/") {
478
+ return serveAsset(assetEntry);
479
+ } else {
480
+ return new PermanentRedirectResponse(`${extensionlessPath}${search}`);
481
+ }
482
+ } else {
483
+ return serveAsset(assetEntry);
484
+ }
485
+ } else if (pathname.endsWith("/index")) {
486
+ return new PermanentRedirectResponse(
487
+ `/${pathname.slice(1, -"index".length)}${search}`
488
+ );
489
+ } else if (assetEntry = await findAssetEntryForPath(`${pathname}.html`)) {
490
+ return serveAsset(assetEntry);
491
+ } else if (hasFileExtension(pathname)) {
492
+ return notFound();
493
+ }
494
+ if (assetEntry = await findAssetEntryForPath(`${pathname}/index.html`)) {
495
+ return new PermanentRedirectResponse(`${pathname}/${search}`);
496
+ } else {
497
+ return notFound();
498
+ }
499
+ }
500
+ async function attachHeaders(response) {
501
+ const existingHeaders = new Headers(response.headers);
502
+ const extraHeaders = new Headers({
503
+ "access-control-allow-origin": "*",
504
+ "referrer-policy": "strict-origin-when-cross-origin",
505
+ ...existingHeaders.has("content-type") ? { "x-content-type-options": "nosniff" } : {}
506
+ });
507
+ const headers = new Headers({
508
+ ...Object.fromEntries(existingHeaders.entries()),
509
+ ...Object.fromEntries(extraHeaders.entries())
510
+ });
511
+ if (earlyHintsCache) {
512
+ const preEarlyHintsHeaders = new Headers(headers);
513
+ const earlyHintsCacheKey = `${protocol}//${host}${pathname}`;
514
+ const earlyHintsResponse = await earlyHintsCache.match(
515
+ earlyHintsCacheKey
516
+ );
517
+ if (earlyHintsResponse) {
518
+ const earlyHintsLinkHeader = earlyHintsResponse.headers.get("Link");
519
+ if (earlyHintsLinkHeader) {
520
+ headers.set("Link", earlyHintsLinkHeader);
521
+ }
522
+ }
523
+ const clonedResponse = response.clone();
524
+ if (waitUntil) {
525
+ waitUntil(
526
+ (async () => {
527
+ try {
528
+ const links = [];
529
+ const transformedResponse = new HTMLRewriter().on("link[rel~=preconnect],link[rel~=preload]", {
530
+ element(element) {
531
+ for (const [attributeName] of element.attributes) {
532
+ if (!ALLOWED_EARLY_HINT_LINK_ATTRIBUTES.includes(
533
+ attributeName.toLowerCase()
534
+ )) {
535
+ return;
536
+ }
537
+ }
538
+ const href = element.getAttribute("href") || void 0;
539
+ const rel = element.getAttribute("rel") || void 0;
540
+ const as = element.getAttribute("as") || void 0;
541
+ if (href && !href.startsWith("data:") && rel) {
542
+ links.push({ href, rel, as });
543
+ }
544
+ }
545
+ }).transform(clonedResponse);
546
+ await transformedResponse.text();
547
+ links.forEach(({ href, rel, as }) => {
548
+ let link = `<${href}>; rel="${rel}"`;
549
+ if (as) {
550
+ link += `; as=${as}`;
551
+ }
552
+ preEarlyHintsHeaders.append("Link", link);
553
+ });
554
+ const linkHeader = preEarlyHintsHeaders.get("Link");
555
+ if (linkHeader) {
556
+ await earlyHintsCache.put(
557
+ earlyHintsCacheKey,
558
+ new Response(null, { headers: { Link: linkHeader } })
559
+ );
560
+ }
561
+ } catch (err) {
562
+ }
563
+ })()
564
+ );
565
+ }
566
+ }
567
+ const headersMatcher = generateRulesMatcher(
568
+ headerRules,
569
+ ({ set = {}, unset = [] }, replacements) => {
570
+ const replacedSet = {};
571
+ Object.keys(set).forEach((key) => {
572
+ replacedSet[key] = replacer(set[key], replacements);
573
+ });
574
+ return {
575
+ set: replacedSet,
576
+ unset
577
+ };
578
+ }
579
+ );
580
+ const matches = headersMatcher({ request });
581
+ const setMap = /* @__PURE__ */ new Set();
582
+ matches.forEach(({ set = {}, unset = [] }) => {
583
+ unset.forEach((key) => {
584
+ headers.delete(key);
585
+ });
586
+ Object.keys(set).forEach((key) => {
587
+ if (setMap.has(key.toLowerCase())) {
588
+ headers.append(key, set[key]);
589
+ } else {
590
+ headers.set(key, set[key]);
591
+ setMap.add(key.toLowerCase());
592
+ }
593
+ });
594
+ });
595
+ return new Response(
596
+ [101, 204, 205, 304].includes(response.status) ? null : response.body,
597
+ {
598
+ headers,
599
+ status: response.status,
600
+ statusText: response.statusText
601
+ }
602
+ );
603
+ }
604
+ return await attachHeaders(await generateResponse());
605
+ async function serveAsset(servingAssetEntry, options = { preserve: true }) {
606
+ let content;
607
+ try {
608
+ content = negotiateContent(request, servingAssetEntry);
609
+ } catch (err) {
610
+ return new NotAcceptableResponse();
611
+ }
612
+ const assetKey = getAssetKey(servingAssetEntry, content);
613
+ const etag = `"${assetKey}"`;
614
+ const weakEtag = `W/${etag}`;
615
+ const ifNoneMatch = request.headers.get("if-none-match");
616
+ if (ifNoneMatch === weakEtag || ifNoneMatch === etag) {
617
+ return new NotModifiedResponse();
618
+ }
619
+ try {
620
+ const asset = await fetchAsset(assetKey);
621
+ const headers = {
622
+ etag,
623
+ "content-type": asset.contentType
624
+ };
625
+ let encodeBody = "automatic";
626
+ if (xServerEnvHeader) {
627
+ headers["x-server-env"] = xServerEnvHeader;
628
+ }
629
+ if (content.encoding) {
630
+ encodeBody = "manual";
631
+ headers["cache-control"] = "no-transform";
632
+ headers["content-encoding"] = content.encoding;
633
+ }
634
+ const response = new OkResponse(
635
+ request.method === "HEAD" ? null : asset.body,
636
+ {
637
+ headers,
638
+ encodeBody
639
+ }
640
+ );
641
+ if (isCacheable(request)) {
642
+ response.headers.append("cache-control", CACHE_CONTROL_BROWSER);
643
+ }
644
+ attachAdditionalHeaders(response, content, servingAssetEntry, asset);
645
+ if (isPreview(new URL(request.url))) {
646
+ response.headers.set("x-robots-tag", "noindex");
647
+ }
648
+ if (options.preserve) {
649
+ const preservedResponse = new Response(
650
+ [101, 204, 205, 304].includes(response.status) ? null : response.clone().body,
651
+ response
652
+ );
653
+ preservedResponse.headers.set(
654
+ "cache-control",
655
+ CACHE_CONTROL_PRESERVATION
656
+ );
657
+ preservedResponse.headers.set("x-robots-tag", "noindex");
658
+ if (waitUntil && caches) {
659
+ waitUntil(
660
+ caches.open(ASSET_PRESERVATION_CACHE).then(
661
+ (assetPreservationCache) => assetPreservationCache.put(request.url, preservedResponse)
662
+ ).catch((err) => {
663
+ logError(err);
664
+ })
665
+ );
666
+ }
667
+ }
668
+ if (asset.contentType.startsWith("text/html") && metadata.analytics?.version === ANALYTICS_VERSION2) {
669
+ return new HTMLRewriter().on("body", {
670
+ element(e) {
671
+ e.append(
672
+ `<!-- Cloudflare Pages Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "${metadata.analytics?.token}"}'><\/script><!-- Cloudflare Pages Analytics -->`,
673
+ { html: true }
674
+ );
675
+ }
676
+ }).transform(response);
677
+ }
678
+ return response;
679
+ } catch (err) {
680
+ logError(err);
681
+ return new InternalServerErrorResponse(err);
682
+ }
683
+ }
684
+ async function notFound() {
685
+ if (caches) {
686
+ const assetPreservationCache = await caches.open(
687
+ ASSET_PRESERVATION_CACHE
688
+ );
689
+ const preservedResponse = await assetPreservationCache.match(request.url);
690
+ if (preservedResponse) {
691
+ return preservedResponse;
692
+ }
693
+ }
694
+ let cwd = pathname;
695
+ while (cwd) {
696
+ cwd = cwd.slice(0, cwd.lastIndexOf("/"));
697
+ if (assetEntry = await findAssetEntryForPath(`${cwd}/404.html`)) {
698
+ let content;
699
+ try {
700
+ content = negotiateContent(request, assetEntry);
701
+ } catch (err) {
702
+ return new NotAcceptableResponse();
703
+ }
704
+ const assetKey = getAssetKey(assetEntry, content);
705
+ try {
706
+ const { body, contentType } = await fetchAsset(assetKey);
707
+ const response = new NotFoundResponse(body);
708
+ response.headers.set("content-type", contentType);
709
+ return response;
710
+ } catch (err) {
711
+ logError(err);
712
+ return new InternalServerErrorResponse(err);
713
+ }
714
+ }
715
+ }
716
+ return await generateNotFoundResponse(
717
+ request,
718
+ findAssetEntryForPath,
719
+ serveAsset
720
+ );
721
+ }
722
+ }
723
+ function getResponseFromMatch({
724
+ status,
725
+ to
726
+ }, requestUrl) {
727
+ const destination = new URL(to, requestUrl);
728
+ destination.search = destination.search || requestUrl.search;
729
+ const location = destination.origin === requestUrl.origin ? stringifyURLToRootRelativePathname(destination) : destination.toString();
730
+ switch (status) {
731
+ case 301:
732
+ return new MovedPermanentlyResponse(location);
733
+ case 303:
734
+ return new SeeOtherResponse(location);
735
+ case 307:
736
+ return new TemporaryRedirectResponse(location);
737
+ case 308:
738
+ return new PermanentRedirectResponse(location);
739
+ case 302:
740
+ default:
741
+ return new FoundResponse(location);
742
+ }
743
+ }
744
+ function parseQualityWeightedList(list = "") {
745
+ const items = {};
746
+ list.replace(/\s/g, "").split(",").forEach((el) => {
747
+ const [item, weight] = el.split(";q=");
748
+ items[item] = weight ? parseFloat(weight) : 1;
749
+ });
750
+ return items;
751
+ }
752
+ function isCacheable(request) {
753
+ return !request.headers.has("authorization") && !request.headers.has("range");
754
+ }
755
+ function hasFileExtension(path) {
756
+ return /\/.+\.[a-z0-9]+$/i.test(path);
757
+ }
758
+ function isPreview(url) {
759
+ if (url.hostname.endsWith(".pages.dev")) {
760
+ return url.hostname.split(".").length > 3 ? true : false;
761
+ }
762
+ return false;
763
+ }
764
+ var ASSET_PRESERVATION_CACHE, CACHE_CONTROL_PRESERVATION, CACHE_CONTROL_BROWSER, REDIRECTS_VERSION2, HEADERS_VERSION2, HEADERS_VERSION_V1, ANALYTICS_VERSION2, ALLOWED_EARLY_HINT_LINK_ATTRIBUTES;
765
+ var init_handler = __esm({
766
+ "../pages-shared/asset-server/handler.ts"() {
767
+ init_responses();
768
+ init_rulesEngine();
769
+ init_url();
770
+ ASSET_PRESERVATION_CACHE = "assetPreservationCache";
771
+ CACHE_CONTROL_PRESERVATION = "public, s-maxage=604800";
772
+ CACHE_CONTROL_BROWSER = "public, max-age=0, must-revalidate";
773
+ REDIRECTS_VERSION2 = 1;
774
+ HEADERS_VERSION2 = 2;
775
+ HEADERS_VERSION_V1 = 1;
776
+ ANALYTICS_VERSION2 = 1;
777
+ ALLOWED_EARLY_HINT_LINK_ATTRIBUTES = ["rel", "as", "href"];
778
+ }
779
+ });
780
+
102
781
  // src/miniflare-cli/index.ts
103
- import { Log, LogLevel, Miniflare } from "miniflare";
782
+ import { fetch } from "@miniflare/core";
783
+ import {
784
+ DurableObjectNamespace,
785
+ DurableObjectStub
786
+ } from "@miniflare/durable-objects";
787
+ import {
788
+ Log as MiniflareLog,
789
+ LogLevel as MiniflareLogLevel,
790
+ Miniflare,
791
+ Request as MiniflareRequest,
792
+ Response as MiniflareResponse
793
+ } from "miniflare";
104
794
 
105
795
  // ../../node_modules/yargs/lib/platform-shims/esm.mjs
106
796
  import { notStrictEqual, strictEqual } from "assert";
@@ -4909,365 +5599,580 @@ function isYargsInstance(y) {
4909
5599
  var Yargs = YargsFactory(esm_default);
4910
5600
  var yargs_default = Yargs;
4911
5601
 
5602
+ // src/errors.ts
5603
+ var FatalError = class extends Error {
5604
+ constructor(message, code) {
5605
+ super(message);
5606
+ this.code = code;
5607
+ }
5608
+ };
5609
+
4912
5610
  // src/miniflare-cli/assets.ts
4913
- var import_mime = __toESM(require_mime());
4914
- import { existsSync, lstatSync, readFileSync as readFileSync4 } from "node:fs";
5611
+ import { existsSync, lstatSync, readFileSync as readFileSync5 } from "node:fs";
4915
5612
  import { join } from "node:path";
4916
- import { fetch as miniflareFetch } from "@miniflare/core";
4917
- import { watch } from "chokidar";
4918
- import { Response } from "miniflare";
4919
- async function generateASSETSBinding(options) {
4920
- const assetsFetch = options.directory !== void 0 ? await generateAssetsFetch(options.directory, options.log) : invalidAssetsFetch;
4921
- return async function(request) {
4922
- if (options.proxyPort) {
4923
- try {
4924
- const url = new URL(request.url);
4925
- url.host = `localhost:${options.proxyPort}`;
4926
- return await miniflareFetch(url, request);
4927
- } catch (thrown) {
4928
- options.log.error(new Error(`Could not proxy request: ${thrown}`));
4929
- return new Response(`[wrangler] Could not proxy request: ${thrown}`, {
4930
- status: 502
4931
- });
4932
- }
4933
- } else {
4934
- try {
4935
- return await assetsFetch(request);
4936
- } catch (thrown) {
4937
- options.log.error(new Error(`Could not serve static asset: ${thrown}`));
4938
- return new Response(`[wrangler] Could not serve static asset: ${thrown}`, { status: 502 });
4939
- }
4940
- }
4941
- };
4942
- }
4943
- function escapeRegex(str) {
4944
- return str.replace(/[-/\\^$*+?.()|[]{}]/g, "\\$&");
4945
- }
4946
- function replacer(str, replacements) {
4947
- for (const [replacement, value] of Object.entries(replacements)) {
4948
- str = str.replace(`:${replacement}`, value);
5613
+
5614
+ // ../pages-shared/metadata-generator/constants.ts
5615
+ var REDIRECTS_VERSION = 1;
5616
+ var HEADERS_VERSION = 2;
5617
+ var ANALYTICS_VERSION = 1;
5618
+ var PERMITTED_STATUS_CODES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
5619
+ var HEADER_SEPARATOR = ":";
5620
+ var MAX_LINE_LENGTH = 2e3;
5621
+ var MAX_HEADER_RULES = 100;
5622
+ var MAX_DYNAMIC_REDIRECT_RULES = 100;
5623
+ var MAX_STATIC_REDIRECT_RULES = 2e3;
5624
+ var UNSET_OPERATOR = "! ";
5625
+ var SPLAT_REGEX = /\*/g;
5626
+ var PLACEHOLDER_REGEX = /:\w+/g;
5627
+
5628
+ // ../pages-shared/metadata-generator/createMetadataObject.ts
5629
+ function createMetadataObject({
5630
+ redirects,
5631
+ headers,
5632
+ webAnalyticsToken,
5633
+ deploymentId,
5634
+ failOpen,
5635
+ logger = (_message) => {
4949
5636
  }
4950
- return str;
4951
- }
4952
- function generateRulesMatcher(rules, replacerFn = (match) => match) {
4953
- if (!rules)
4954
- return () => [];
4955
- const compiledRules = Object.entries(rules).map(([rule, match]) => {
4956
- const crossHost = rule.startsWith("https://");
4957
- rule = rule.split("*").map(escapeRegex).join("(?<splat>.*)");
4958
- const host_matches = rule.matchAll(/(?<=^https:\\\/\\\/[^/]*?):([^\\]+)(?=\\)/g);
4959
- for (const hostMatch of host_matches) {
4960
- rule = rule.split(hostMatch[0]).join(`(?<${hostMatch[1]}>[^/.]+)`);
4961
- }
4962
- const path_matches = rule.matchAll(/:(\w+)/g);
4963
- for (const pathMatch of path_matches) {
4964
- rule = rule.split(pathMatch[0]).join(`(?<${pathMatch[1]}>[^/]+)`);
4965
- }
4966
- rule = "^" + rule + "$";
4967
- try {
4968
- const regExp = new RegExp(rule);
4969
- return [{ crossHost, regExp }, match];
4970
- } catch {
4971
- }
4972
- }).filter((value) => value !== void 0);
4973
- return ({ request }) => {
4974
- const { pathname, host } = new URL(request.url);
4975
- return compiledRules.map(([{ crossHost, regExp }, match]) => {
4976
- const test = crossHost ? `https://${host}${pathname}` : pathname;
4977
- const result = regExp.exec(test);
4978
- if (result) {
4979
- return replacerFn(match, result.groups || {});
4980
- }
4981
- }).filter((value) => value !== void 0);
5637
+ }) {
5638
+ return {
5639
+ ...constructRedirects({ redirects, logger }),
5640
+ ...constructHeaders({ headers, logger }),
5641
+ ...constructWebAnalytics({ webAnalyticsToken, logger }),
5642
+ deploymentId,
5643
+ failOpen
4982
5644
  };
4983
5645
  }
4984
- function generateHeadersMatcher(headersFile) {
4985
- if (existsSync(headersFile)) {
4986
- const contents = readFileSync4(headersFile).toString();
4987
- const lines = contents.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("#") && line !== "");
4988
- const rules = {};
4989
- let rule = void 0;
4990
- for (const line of lines) {
4991
- if (/^([^\s]+:\/\/|^\/)/.test(line)) {
4992
- if (rule && Object.keys(rule.headers).length > 0) {
4993
- rules[rule.path] = rule.headers;
4994
- }
4995
- const path = validateURL(line);
4996
- if (path) {
4997
- rule = {
4998
- path,
4999
- headers: {}
5000
- };
5001
- continue;
5002
- }
5003
- }
5004
- if (!line.includes(":"))
5005
- continue;
5006
- const [rawName, ...rawValue] = line.split(":");
5007
- const name = rawName.trim().toLowerCase();
5008
- const value = rawValue.join(":").trim();
5009
- if (name === "")
5010
- continue;
5011
- if (!rule)
5646
+ function constructRedirects({
5647
+ redirects,
5648
+ logger
5649
+ }) {
5650
+ if (!redirects)
5651
+ return {};
5652
+ const num_valid = redirects.rules.length;
5653
+ const num_invalid = redirects.invalid.length;
5654
+ logger(
5655
+ `Parsed ${num_valid} valid redirect rule${num_valid === 1 ? "" : "s"}.`
5656
+ );
5657
+ if (num_invalid > 0) {
5658
+ logger(`Found invalid redirect lines:`);
5659
+ for (const { line, lineNumber, message } of redirects.invalid) {
5660
+ if (line)
5661
+ logger(` - ${lineNumber ? `#${lineNumber}: ` : ""}${line}`);
5662
+ logger(` ${message}`);
5663
+ }
5664
+ }
5665
+ if (num_valid === 0) {
5666
+ return {};
5667
+ }
5668
+ const staticRedirects = {};
5669
+ const dynamicRedirects = {};
5670
+ let canCreateStaticRule = true;
5671
+ for (const rule of redirects.rules) {
5672
+ if (!rule.from.match(SPLAT_REGEX) && !rule.from.match(PLACEHOLDER_REGEX)) {
5673
+ if (canCreateStaticRule) {
5674
+ staticRedirects[rule.from] = {
5675
+ status: rule.status,
5676
+ to: rule.to,
5677
+ lineNumber: rule.lineNumber
5678
+ };
5012
5679
  continue;
5013
- const existingValues = rule.headers[name];
5014
- rule.headers[name] = existingValues ? `${existingValues}, ${value}` : value;
5015
- }
5016
- if (rule && Object.keys(rule.headers).length > 0) {
5017
- rules[rule.path] = rule.headers;
5018
- }
5019
- const rulesMatcher = generateRulesMatcher(rules, (match, replacements) => Object.fromEntries(Object.entries(match).map(([name, value]) => [
5020
- name,
5021
- replacer(value, replacements)
5022
- ])));
5023
- return (request) => {
5024
- const matches = rulesMatcher({
5025
- request
5026
- });
5027
- if (matches)
5028
- return matches;
5029
- };
5030
- } else {
5031
- return () => void 0;
5680
+ } else {
5681
+ logger(
5682
+ `Info: the redirect rule ${rule.from} \u2192 ${rule.status} ${rule.to} could be made more performant by bringing it above any lines with splats or placeholders.`
5683
+ );
5684
+ }
5685
+ }
5686
+ dynamicRedirects[rule.from] = { status: rule.status, to: rule.to };
5687
+ canCreateStaticRule = false;
5032
5688
  }
5689
+ return {
5690
+ redirects: {
5691
+ version: REDIRECTS_VERSION,
5692
+ staticRules: staticRedirects,
5693
+ rules: dynamicRedirects
5694
+ }
5695
+ };
5033
5696
  }
5034
- function generateRedirectsMatcher(redirectsFile) {
5035
- if (existsSync(redirectsFile)) {
5036
- const contents = readFileSync4(redirectsFile).toString();
5037
- const lines = contents.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("#") && line !== "");
5038
- const rules = Object.fromEntries(lines.map((line) => line.split(" ")).filter((tokens) => tokens.length === 2 || tokens.length === 3).map((tokens) => {
5039
- const from = validateURL(tokens[0], true, false, false);
5040
- const to = validateURL(tokens[1], false, true, true);
5041
- let status = parseInt(tokens[2]) || 302;
5042
- status = [301, 302, 303, 307, 308].includes(status) ? status : void 0;
5043
- return from && to && status ? [from, { to, status }] : void 0;
5044
- }).filter((rule) => rule !== void 0));
5045
- const rulesMatcher = generateRulesMatcher(rules, ({ status, to }, replacements) => ({
5046
- status,
5047
- to: replacer(to, replacements)
5048
- }));
5049
- return (request) => {
5050
- const match = rulesMatcher({
5051
- request
5052
- })[0];
5053
- if (match)
5054
- return match;
5055
- };
5056
- } else {
5057
- return () => void 0;
5697
+ function constructHeaders({
5698
+ headers,
5699
+ logger
5700
+ }) {
5701
+ if (!headers)
5702
+ return {};
5703
+ const num_valid = headers.rules.length;
5704
+ const num_invalid = headers.invalid.length;
5705
+ logger(`Parsed ${num_valid} valid header rule${num_valid === 1 ? "" : "s"}.`);
5706
+ if (num_invalid > 0) {
5707
+ logger(`Found invalid header lines:`);
5708
+ for (const { line, lineNumber, message } of headers.invalid) {
5709
+ if (line)
5710
+ logger(` - ${lineNumber ? `#${lineNumber}: ` : ""} ${line}`);
5711
+ logger(` ${message}`);
5712
+ }
5713
+ }
5714
+ if (num_valid === 0) {
5715
+ return {};
5716
+ }
5717
+ const rules = {};
5718
+ for (const rule of headers.rules) {
5719
+ rules[rule.path] = {};
5720
+ if (Object.keys(rule.headers).length) {
5721
+ rules[rule.path].set = rule.headers;
5722
+ }
5723
+ if (rule.unsetHeaders.length) {
5724
+ rules[rule.path].unset = rule.unsetHeaders;
5725
+ }
5058
5726
  }
5727
+ return {
5728
+ headers: {
5729
+ version: HEADERS_VERSION,
5730
+ rules
5731
+ }
5732
+ };
5733
+ }
5734
+ function constructWebAnalytics({
5735
+ webAnalyticsToken
5736
+ }) {
5737
+ if (!webAnalyticsToken)
5738
+ return {};
5739
+ return {
5740
+ analytics: {
5741
+ version: ANALYTICS_VERSION,
5742
+ token: webAnalyticsToken
5743
+ }
5744
+ };
5059
5745
  }
5060
- function extractPathname(path = "/", includeSearch, includeHash) {
5746
+
5747
+ // ../pages-shared/metadata-generator/validateURL.ts
5748
+ var extractPathname = (path = "/", includeSearch, includeHash) => {
5061
5749
  if (!path.startsWith("/"))
5062
5750
  path = `/${path}`;
5063
5751
  const url = new URL(`//${path}`, "relative://");
5064
5752
  return `${url.pathname}${includeSearch ? url.search : ""}${includeHash ? url.hash : ""}`;
5065
- }
5066
- function validateURL(token, onlyRelative = false, includeSearch = false, includeHash = false) {
5067
- const host = /^https:\/\/+(?<host>[^/]+)\/?(?<path>.*)/.exec(token);
5753
+ };
5754
+ var URL_REGEX = /^https:\/\/+(?<host>[^/]+)\/?(?<path>.*)/;
5755
+ var PATH_REGEX = /^\//;
5756
+ var validateUrl = (token, onlyRelative = false, includeSearch = false, includeHash = false) => {
5757
+ const host = URL_REGEX.exec(token);
5068
5758
  if (host && host.groups && host.groups.host) {
5069
5759
  if (onlyRelative)
5070
- return;
5071
- return `https://${host.groups.host}${extractPathname(host.groups.path, includeSearch, includeHash)}`;
5760
+ return [
5761
+ void 0,
5762
+ `Only relative URLs are allowed. Skipping absolute URL ${token}.`
5763
+ ];
5764
+ return [
5765
+ `https://${host.groups.host}${extractPathname(
5766
+ host.groups.path,
5767
+ includeSearch,
5768
+ includeHash
5769
+ )}`,
5770
+ void 0
5771
+ ];
5072
5772
  } else {
5073
5773
  if (!token.startsWith("/") && onlyRelative)
5074
5774
  token = `/${token}`;
5075
- const path = /^\//.exec(token);
5775
+ const path = PATH_REGEX.exec(token);
5076
5776
  if (path) {
5077
5777
  try {
5078
- return extractPathname(token, includeSearch, includeHash);
5778
+ return [extractPathname(token, includeSearch, includeHash), void 0];
5079
5779
  } catch {
5780
+ return [void 0, `Error parsing URL segment ${token}. Skipping.`];
5080
5781
  }
5081
5782
  }
5082
5783
  }
5083
- return "";
5084
- }
5085
- function hasFileExtension(pathname) {
5086
- return /\/.+\.[a-z0-9]+$/i.test(pathname);
5087
- }
5088
- async function generateAssetsFetch(directory, log) {
5089
- const { Headers, Request } = await import("@miniflare/core");
5090
- const headersFile = join(directory, "_headers");
5091
- const redirectsFile = join(directory, "_redirects");
5092
- const workerFile = join(directory, "_worker.js");
5093
- const ignoredFiles = [headersFile, redirectsFile, workerFile];
5094
- const assetExists = (path) => {
5095
- path = join(directory, path);
5096
- return existsSync(path) && lstatSync(path).isFile() && !ignoredFiles.includes(path);
5097
- };
5098
- const getAsset = (path) => {
5099
- if (assetExists(path)) {
5100
- return join(directory, path);
5784
+ return [
5785
+ void 0,
5786
+ onlyRelative ? "URLs should begin with a forward-slash." : 'URLs should either be relative (e.g. begin with a forward-slash), or use HTTPS (e.g. begin with "https://").'
5787
+ ];
5788
+ };
5789
+
5790
+ // ../pages-shared/metadata-generator/parseHeaders.ts
5791
+ var LINE_IS_PROBABLY_A_PATH = new RegExp(/^([^\s]+:\/\/|^\/)/);
5792
+ function parseHeaders(input) {
5793
+ const lines = input.split("\n");
5794
+ const rules = [];
5795
+ const invalid = [];
5796
+ let rule = void 0;
5797
+ for (let i = 0; i < lines.length; i++) {
5798
+ const line = lines[i].trim();
5799
+ if (line.length === 0 || line.startsWith("#"))
5800
+ continue;
5801
+ if (line.length > MAX_LINE_LENGTH) {
5802
+ invalid.push({
5803
+ message: `Ignoring line ${i + 1} as it exceeds the maximum allowed length of ${MAX_LINE_LENGTH}.`
5804
+ });
5805
+ continue;
5101
5806
  }
5102
- };
5103
- let redirectsMatcher = generateRedirectsMatcher(redirectsFile);
5104
- let headersMatcher = generateHeadersMatcher(headersFile);
5105
- watch([headersFile, redirectsFile], {
5106
- persistent: true
5107
- }).on("change", (path) => {
5108
- switch (path) {
5109
- case headersFile: {
5110
- log.log("_headers modified. Re-evaluating...");
5111
- headersMatcher = generateHeadersMatcher(headersFile);
5807
+ if (LINE_IS_PROBABLY_A_PATH.test(line)) {
5808
+ if (rules.length >= MAX_HEADER_RULES) {
5809
+ invalid.push({
5810
+ message: `Maximum number of rules supported is ${MAX_HEADER_RULES}. Skipping remaining ${lines.length - i} lines of file.`
5811
+ });
5112
5812
  break;
5113
5813
  }
5114
- case redirectsFile: {
5115
- log.log("_redirects modified. Re-evaluating...");
5116
- redirectsMatcher = generateRedirectsMatcher(redirectsFile);
5117
- break;
5814
+ if (rule) {
5815
+ if (isValidRule(rule)) {
5816
+ rules.push({
5817
+ path: rule.path,
5818
+ headers: rule.headers,
5819
+ unsetHeaders: rule.unsetHeaders
5820
+ });
5821
+ } else {
5822
+ invalid.push({
5823
+ line: rule.line,
5824
+ lineNumber: i + 1,
5825
+ message: "No headers specified"
5826
+ });
5827
+ }
5118
5828
  }
5119
- }
5120
- });
5121
- const serveAsset = (file) => {
5122
- return readFileSync4(file);
5123
- };
5124
- const generateResponse = (request) => {
5125
- const url = new URL(request.url);
5126
- const deconstructedResponse = {
5127
- status: 200,
5128
- headers: new Headers(),
5129
- body: void 0
5130
- };
5131
- const match = redirectsMatcher(request);
5132
- if (match) {
5133
- const { status, to } = match;
5134
- let location = to;
5135
- let search;
5136
- if (to.startsWith("/")) {
5137
- search = new URL(location, "http://fakehost").search;
5138
- } else {
5139
- search = new URL(location).search;
5829
+ const [path, pathError] = validateUrl(line);
5830
+ if (pathError) {
5831
+ invalid.push({
5832
+ line,
5833
+ lineNumber: i + 1,
5834
+ message: pathError
5835
+ });
5836
+ rule = void 0;
5837
+ continue;
5140
5838
  }
5141
- location = `${location}${search ? "" : url.search}`;
5142
- if (status && [301, 302, 303, 307, 308].includes(status)) {
5143
- deconstructedResponse.status = status;
5839
+ rule = {
5840
+ path,
5841
+ line,
5842
+ headers: {},
5843
+ unsetHeaders: []
5844
+ };
5845
+ continue;
5846
+ }
5847
+ if (!line.includes(HEADER_SEPARATOR)) {
5848
+ if (!rule) {
5849
+ invalid.push({
5850
+ line,
5851
+ lineNumber: i + 1,
5852
+ message: "Expected a path beginning with at least one forward-slash"
5853
+ });
5144
5854
  } else {
5145
- deconstructedResponse.status = 302;
5146
- }
5147
- deconstructedResponse.headers.set("Location", location);
5148
- return deconstructedResponse;
5149
- }
5150
- if (!request.method?.match(/^(get|head)$/i)) {
5151
- deconstructedResponse.status = 405;
5152
- return deconstructedResponse;
5153
- }
5154
- const notFound = () => {
5155
- let cwd = url.pathname;
5156
- while (cwd) {
5157
- cwd = cwd.slice(0, cwd.lastIndexOf("/"));
5158
- if (asset = getAsset(`${cwd}/404.html`)) {
5159
- deconstructedResponse.status = 404;
5160
- deconstructedResponse.body = serveAsset(asset);
5161
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5162
- return deconstructedResponse;
5855
+ if (line.trim().startsWith(UNSET_OPERATOR)) {
5856
+ rule.unsetHeaders.push(line.trim().replace(UNSET_OPERATOR, ""));
5857
+ } else {
5858
+ invalid.push({
5859
+ line,
5860
+ lineNumber: i + 1,
5861
+ message: "Expected a colon-separated header pair (e.g. name: value)"
5862
+ });
5163
5863
  }
5164
5864
  }
5165
- if (asset = getAsset(`/index.html`)) {
5166
- deconstructedResponse.body = serveAsset(asset);
5167
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5168
- return deconstructedResponse;
5865
+ continue;
5866
+ }
5867
+ const [rawName, ...rawValue] = line.split(HEADER_SEPARATOR);
5868
+ const name = rawName.trim().toLowerCase();
5869
+ if (name.includes(" ")) {
5870
+ invalid.push({
5871
+ line,
5872
+ lineNumber: i + 1,
5873
+ message: "Header name cannot include spaces"
5874
+ });
5875
+ continue;
5876
+ }
5877
+ const value = rawValue.join(HEADER_SEPARATOR).trim();
5878
+ if (name === "") {
5879
+ invalid.push({
5880
+ line,
5881
+ lineNumber: i + 1,
5882
+ message: "No header name specified"
5883
+ });
5884
+ continue;
5885
+ }
5886
+ if (value === "") {
5887
+ invalid.push({
5888
+ line,
5889
+ lineNumber: i + 1,
5890
+ message: "No header value specified"
5891
+ });
5892
+ continue;
5893
+ }
5894
+ if (!rule) {
5895
+ invalid.push({
5896
+ line,
5897
+ lineNumber: i + 1,
5898
+ message: `Path should come before header (${name}: ${value})`
5899
+ });
5900
+ continue;
5901
+ }
5902
+ const existingValues = rule.headers[name];
5903
+ rule.headers[name] = existingValues ? `${existingValues}, ${value}` : value;
5904
+ }
5905
+ if (rule) {
5906
+ if (isValidRule(rule)) {
5907
+ rules.push({
5908
+ path: rule.path,
5909
+ headers: rule.headers,
5910
+ unsetHeaders: rule.unsetHeaders
5911
+ });
5912
+ } else {
5913
+ invalid.push({ line: rule.line, message: "No headers specified" });
5914
+ }
5915
+ }
5916
+ return {
5917
+ rules,
5918
+ invalid
5919
+ };
5920
+ }
5921
+ function isValidRule(rule) {
5922
+ return Object.keys(rule.headers).length > 0 || rule.unsetHeaders.length > 0;
5923
+ }
5924
+
5925
+ // ../pages-shared/metadata-generator/parseRedirects.ts
5926
+ function parseRedirects(input) {
5927
+ const lines = input.split("\n");
5928
+ const rules = [];
5929
+ const seen_paths = /* @__PURE__ */ new Set();
5930
+ const invalid = [];
5931
+ let staticRules = 0;
5932
+ let dynamicRules = 0;
5933
+ let canCreateStaticRule = true;
5934
+ for (let i = 0; i < lines.length; i++) {
5935
+ const line = lines[i].trim();
5936
+ if (line.length === 0 || line.startsWith("#"))
5937
+ continue;
5938
+ if (line.length > MAX_LINE_LENGTH) {
5939
+ invalid.push({
5940
+ message: `Ignoring line ${i + 1} as it exceeds the maximum allowed length of ${MAX_LINE_LENGTH}.`
5941
+ });
5942
+ continue;
5943
+ }
5944
+ const tokens = line.split(/\s+/);
5945
+ if (tokens.length < 2 || tokens.length > 3) {
5946
+ invalid.push({
5947
+ line,
5948
+ lineNumber: i + 1,
5949
+ message: `Expected exactly 2 or 3 whitespace-separated tokens. Got ${tokens.length}.`
5950
+ });
5951
+ continue;
5952
+ }
5953
+ const [str_from, str_to, str_status = "302"] = tokens;
5954
+ const fromResult = validateUrl(str_from, true, false, false);
5955
+ if (fromResult[0] === void 0) {
5956
+ invalid.push({
5957
+ line,
5958
+ lineNumber: i + 1,
5959
+ message: fromResult[1]
5960
+ });
5961
+ continue;
5962
+ }
5963
+ const from = fromResult[0];
5964
+ if (canCreateStaticRule && !from.match(SPLAT_REGEX) && !from.match(PLACEHOLDER_REGEX)) {
5965
+ staticRules += 1;
5966
+ if (staticRules > MAX_STATIC_REDIRECT_RULES) {
5967
+ invalid.push({
5968
+ message: `Maximum number of static rules supported is ${MAX_STATIC_REDIRECT_RULES}. Skipping line.`
5969
+ });
5970
+ continue;
5169
5971
  }
5170
- deconstructedResponse.status = 404;
5171
- return deconstructedResponse;
5172
- };
5173
- let asset;
5174
- if (url.pathname.endsWith("/")) {
5175
- if (asset = getAsset(`${url.pathname}/index.html`)) {
5176
- deconstructedResponse.body = serveAsset(asset);
5177
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5178
- return deconstructedResponse;
5179
- } else if (asset = getAsset(`${url.pathname.replace(/\/$/, ".html")}`)) {
5180
- deconstructedResponse.status = 301;
5181
- deconstructedResponse.headers.set("Location", `${url.pathname.slice(0, -1)}${url.search}`);
5182
- return deconstructedResponse;
5183
- }
5184
- }
5185
- if (url.pathname.endsWith("/index")) {
5186
- deconstructedResponse.status = 301;
5187
- deconstructedResponse.headers.set("Location", `${url.pathname.slice(0, -"index".length)}${url.search}`);
5188
- return deconstructedResponse;
5189
- }
5190
- if (asset = getAsset(url.pathname)) {
5191
- if (url.pathname.endsWith(".html")) {
5192
- const extensionlessPath = url.pathname.slice(0, -".html".length);
5193
- if (getAsset(extensionlessPath) || extensionlessPath === "/") {
5194
- deconstructedResponse.body = serveAsset(asset);
5195
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5196
- return deconstructedResponse;
5197
- } else {
5198
- deconstructedResponse.status = 301;
5199
- deconstructedResponse.headers.set("Location", `${extensionlessPath}${url.search}`);
5200
- return deconstructedResponse;
5972
+ } else {
5973
+ dynamicRules += 1;
5974
+ canCreateStaticRule = false;
5975
+ if (dynamicRules > MAX_DYNAMIC_REDIRECT_RULES) {
5976
+ invalid.push({
5977
+ message: `Maximum number of dynamic rules supported is ${MAX_DYNAMIC_REDIRECT_RULES}. Skipping remaining ${lines.length - i} lines of file.`
5978
+ });
5979
+ break;
5980
+ }
5981
+ }
5982
+ const toResult = validateUrl(str_to, false, true, true);
5983
+ if (toResult[0] === void 0) {
5984
+ invalid.push({
5985
+ line,
5986
+ lineNumber: i + 1,
5987
+ message: toResult[1]
5988
+ });
5989
+ continue;
5990
+ }
5991
+ const to = toResult[0];
5992
+ const status = Number(str_status);
5993
+ if (isNaN(status) || !PERMITTED_STATUS_CODES.has(status)) {
5994
+ invalid.push({
5995
+ line,
5996
+ lineNumber: i + 1,
5997
+ message: `Valid status codes are 301, 302 (default), 303, 307, or 308. Got ${str_status}.`
5998
+ });
5999
+ continue;
6000
+ }
6001
+ if (seen_paths.has(from)) {
6002
+ invalid.push({
6003
+ line,
6004
+ lineNumber: i + 1,
6005
+ message: `Ignoring duplicate rule for path ${from}.`
6006
+ });
6007
+ continue;
6008
+ }
6009
+ seen_paths.add(from);
6010
+ rules.push({ from, to, status, lineNumber: i + 1 });
6011
+ }
6012
+ return {
6013
+ rules,
6014
+ invalid
6015
+ };
6016
+ }
6017
+
6018
+ // src/miniflare-cli/assets.ts
6019
+ var import_mime = __toESM(require_mime());
6020
+ import { watch } from "chokidar";
6021
+
6022
+ // src/pages/hash.tsx
6023
+ import { readFileSync as readFileSync4 } from "node:fs";
6024
+ import { extname as extname2 } from "node:path";
6025
+ import { hash as blake3hash } from "blake3-wasm";
6026
+ var hashFile = (filepath) => {
6027
+ const contents = readFileSync4(filepath);
6028
+ const base64Contents = contents.toString("base64");
6029
+ const extension = extname2(filepath).substring(1);
6030
+ return blake3hash(base64Contents + extension).toString("hex").slice(0, 32);
6031
+ };
6032
+
6033
+ // src/miniflare-cli/assets.ts
6034
+ async function generateASSETSBinding(options) {
6035
+ const assetsFetch = options.directory !== void 0 ? await generateAssetsFetch(options.directory, options.log, options.tre) : invalidAssetsFetch;
6036
+ const miniflare = options.tre ? await import("@miniflare/tre") : await import("@miniflare/core");
6037
+ const Request = miniflare.Request;
6038
+ const Response2 = miniflare.Response;
6039
+ const fetch2 = options.tre ? miniflare.fetch : (await import("@miniflare/web-sockets")).upgradingFetch;
6040
+ return async function(miniflareRequest) {
6041
+ if (options.proxyPort) {
6042
+ try {
6043
+ const url = new URL(miniflareRequest.url);
6044
+ url.host = `localhost:${options.proxyPort}`;
6045
+ const proxyRequest = new Request(url, miniflareRequest);
6046
+ if (proxyRequest.headers.get("Upgrade") === "websocket") {
6047
+ proxyRequest.headers.delete("Sec-WebSocket-Accept");
6048
+ proxyRequest.headers.delete("Sec-WebSocket-Key");
5201
6049
  }
5202
- } else {
5203
- deconstructedResponse.body = serveAsset(asset);
5204
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5205
- return deconstructedResponse;
5206
- }
5207
- } else if (hasFileExtension(url.pathname)) {
5208
- notFound();
5209
- return deconstructedResponse;
5210
- }
5211
- if (asset = getAsset(`${url.pathname}.html`)) {
5212
- deconstructedResponse.body = serveAsset(asset);
5213
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5214
- return deconstructedResponse;
5215
- }
5216
- if (asset = getAsset(`${url.pathname}/index.html`)) {
5217
- deconstructedResponse.status = 301;
5218
- deconstructedResponse.headers.set("Location", `${url.pathname}/${url.search}`);
5219
- return deconstructedResponse;
6050
+ return await fetch2(proxyRequest);
6051
+ } catch (thrown) {
6052
+ options.log.error(new Error(`Could not proxy request: ${thrown}`));
6053
+ return new Response2(`[wrangler] Could not proxy request: ${thrown}`, {
6054
+ status: 502
6055
+ });
6056
+ }
5220
6057
  } else {
5221
- notFound();
5222
- return deconstructedResponse;
6058
+ try {
6059
+ return await assetsFetch(miniflareRequest);
6060
+ } catch (thrown) {
6061
+ options.log.error(new Error(`Could not serve static asset: ${thrown}`));
6062
+ return new Response2(
6063
+ `[wrangler] Could not serve static asset: ${thrown}`,
6064
+ { status: 502 }
6065
+ );
6066
+ }
5223
6067
  }
5224
6068
  };
5225
- const attachHeaders = (request, deconstructedResponse) => {
5226
- const headers = deconstructedResponse.headers;
5227
- const newHeaders = new Headers({});
5228
- const matches = headersMatcher(request) || [];
5229
- matches.forEach((match) => {
5230
- Object.entries(match).forEach(([name, value]) => {
5231
- newHeaders.append(name, `${value}`);
6069
+ }
6070
+ async function generateAssetsFetch(directory, log, tre) {
6071
+ const polyfill2 = tre ? (await Promise.resolve().then(() => (init_miniflare_tre(), miniflare_tre_exports))).default : (await Promise.resolve().then(() => (init_miniflare(), miniflare_exports))).default;
6072
+ await polyfill2();
6073
+ const miniflare = tre ? await import("@miniflare/tre") : await import("@miniflare/core");
6074
+ const Request = miniflare.Request;
6075
+ const { generateHandler: generateHandler2, parseQualityWeightedList: parseQualityWeightedList2 } = await Promise.resolve().then(() => (init_handler(), handler_exports));
6076
+ const headersFile = join(directory, "_headers");
6077
+ const redirectsFile = join(directory, "_redirects");
6078
+ const workerFile = join(directory, "_worker.js");
6079
+ const ignoredFiles = [headersFile, redirectsFile, workerFile];
6080
+ let redirects;
6081
+ if (existsSync(redirectsFile)) {
6082
+ const contents = readFileSync5(redirectsFile, "utf-8");
6083
+ redirects = parseRedirects(contents);
6084
+ }
6085
+ let headers;
6086
+ if (existsSync(headersFile)) {
6087
+ const contents = readFileSync5(headersFile, "utf-8");
6088
+ headers = parseHeaders(contents);
6089
+ }
6090
+ let metadata = createMetadataObject({
6091
+ redirects,
6092
+ headers,
6093
+ logger: log.warn.bind(log)
6094
+ });
6095
+ watch([headersFile, redirectsFile], { persistent: true }).on(
6096
+ "change",
6097
+ (path) => {
6098
+ switch (path) {
6099
+ case headersFile: {
6100
+ log.log("_headers modified. Re-evaluating...");
6101
+ const contents = readFileSync5(headersFile).toString();
6102
+ headers = parseHeaders(contents);
6103
+ break;
6104
+ }
6105
+ case redirectsFile: {
6106
+ log.log("_redirects modified. Re-evaluating...");
6107
+ const contents = readFileSync5(redirectsFile).toString();
6108
+ redirects = parseRedirects(contents);
6109
+ break;
6110
+ }
6111
+ }
6112
+ metadata = createMetadataObject({
6113
+ redirects,
6114
+ headers,
6115
+ logger: log.warn
5232
6116
  });
5233
- });
5234
- const combinedHeaders = {
5235
- ...Object.fromEntries(headers.entries()),
5236
- ...Object.fromEntries(newHeaders.entries())
5237
- };
5238
- deconstructedResponse.headers = new Headers({});
5239
- Object.entries(combinedHeaders).forEach(([name, value]) => {
5240
- if (value)
5241
- deconstructedResponse.headers.set(name, value);
6117
+ }
6118
+ );
6119
+ const generateResponse = async (request) => {
6120
+ const assetKeyEntryMap = /* @__PURE__ */ new Map();
6121
+ return await generateHandler2({
6122
+ request,
6123
+ metadata,
6124
+ xServerEnvHeader: "dev",
6125
+ logError: console.error,
6126
+ findAssetEntryForPath: async (path) => {
6127
+ const filepath = join(directory, path);
6128
+ if (existsSync(filepath) && lstatSync(filepath).isFile() && !ignoredFiles.includes(filepath)) {
6129
+ const hash = hashFile(filepath);
6130
+ assetKeyEntryMap.set(hash, filepath);
6131
+ return hash;
6132
+ }
6133
+ return null;
6134
+ },
6135
+ getAssetKey: (assetEntry) => {
6136
+ return assetEntry;
6137
+ },
6138
+ negotiateContent: (contentRequest) => {
6139
+ let rawAcceptEncoding;
6140
+ if (contentRequest.cf && "clientAcceptEncoding" in contentRequest.cf && contentRequest.cf.clientAcceptEncoding) {
6141
+ rawAcceptEncoding = contentRequest.cf.clientAcceptEncoding;
6142
+ } else {
6143
+ rawAcceptEncoding = contentRequest.headers.get("Accept-Encoding") || void 0;
6144
+ }
6145
+ const acceptEncoding = parseQualityWeightedList2(rawAcceptEncoding);
6146
+ if (acceptEncoding["identity"] === 0 || acceptEncoding["*"] === 0 && acceptEncoding["identity"] === void 0) {
6147
+ throw new Error("No acceptable encodings available");
6148
+ }
6149
+ return { encoding: null };
6150
+ },
6151
+ fetchAsset: async (assetKey) => {
6152
+ const filepath = assetKeyEntryMap.get(assetKey);
6153
+ if (!filepath) {
6154
+ throw new Error(
6155
+ "Could not fetch asset. Please file an issue on GitHub (https://github.com/cloudflare/wrangler2/issues/new/choose) with reproduction steps."
6156
+ );
6157
+ }
6158
+ const body = readFileSync5(filepath);
6159
+ let contentType = (0, import_mime.getType)(filepath) || "application/octet-stream";
6160
+ if (contentType.startsWith("text/") && !contentType.includes("charset")) {
6161
+ contentType = `${contentType}; charset=utf-8`;
6162
+ }
6163
+ return { body, contentType };
6164
+ }
5242
6165
  });
5243
6166
  };
5244
6167
  return async (input, init) => {
5245
6168
  const request = new Request(input, init);
5246
- const deconstructedResponse = generateResponse(request);
5247
- attachHeaders(request, deconstructedResponse);
5248
- const headers = new Headers();
5249
- [...deconstructedResponse.headers.entries()].forEach(([name, value]) => {
5250
- if (value)
5251
- headers.set(name, value);
5252
- });
5253
- return new Response(deconstructedResponse.body, {
5254
- headers,
5255
- status: deconstructedResponse.status
5256
- });
6169
+ return await generateResponse(request);
5257
6170
  };
5258
6171
  }
5259
6172
  var invalidAssetsFetch = () => {
5260
- throw new Error("Trying to fetch assets directly when there is no `directory` option specified.");
5261
- };
5262
-
5263
- // src/miniflare-cli/enum-keys.ts
5264
- var enumObject = (e) => {
5265
- const copy = { ...e };
5266
- Object.values(e).forEach((value) => typeof value === "number" && delete copy[value]);
5267
- return copy;
5268
- };
5269
- var enumKeys = (e) => {
5270
- return Object.keys(enumObject(e));
6173
+ throw new Error(
6174
+ "Trying to fetch assets directly when there is no `directory` option specified."
6175
+ );
5271
6176
  };
5272
6177
 
5273
6178
  // src/miniflare-cli/request-context.ts
@@ -5290,7 +6195,7 @@ var getRequestContextCheckOptions = async () => {
5290
6195
  };
5291
6196
 
5292
6197
  // src/miniflare-cli/index.ts
5293
- var NoOpLog = class extends Log {
6198
+ var MiniflareNoOpLog = class extends MiniflareLog {
5294
6199
  log() {
5295
6200
  }
5296
6201
  error(message) {
@@ -5298,30 +6203,76 @@ var NoOpLog = class extends Log {
5298
6203
  }
5299
6204
  };
5300
6205
  async function main() {
5301
- const args = await yargs_default(hideBin(process.argv)).help(false).version(false).option("log", {
5302
- choices: enumKeys(LogLevel)
5303
- }).argv;
5304
- const logLevel = LogLevel[args.log ?? "INFO"];
6206
+ const args = await yargs_default(hideBin(process.argv)).help(false).version(false).argv;
5305
6207
  const requestContextCheckOptions = await getRequestContextCheckOptions();
5306
6208
  const config = {
5307
6209
  ...JSON.parse(args._[0] ?? "{}"),
5308
6210
  ...requestContextCheckOptions
5309
6211
  };
5310
- config.log = config.disableLogs ? new NoOpLog() : new Log(logLevel, config.logOptions);
5311
- if (logLevel > LogLevel.INFO) {
5312
- console.log("OPTIONS:\n", JSON.stringify(config, null, 2));
5313
- }
6212
+ let logLevelString = config.logLevel.toUpperCase();
6213
+ if (logLevelString === "LOG")
6214
+ logLevelString = "INFO";
6215
+ const logLevel = MiniflareLogLevel[logLevelString];
6216
+ config.log = logLevel === MiniflareLogLevel.NONE ? new MiniflareNoOpLog() : new MiniflareLog(logLevel, config.logOptions);
6217
+ if (logLevel === MiniflareLogLevel.DEBUG) {
6218
+ console.log("MINIFLARE OPTIONS:\n", JSON.stringify(config, null, 2));
6219
+ }
6220
+ config.bindings = {
6221
+ ...config.bindings,
6222
+ ...config.externalDurableObjects && Object.fromEntries(
6223
+ Object.entries(
6224
+ config.externalDurableObjects
6225
+ ).map(([binding, { name, host, port }]) => {
6226
+ const factory = () => {
6227
+ throw new FatalError(
6228
+ "An external Durable Object instance's state has somehow been attempted to be accessed.",
6229
+ 1
6230
+ );
6231
+ };
6232
+ const namespace = new DurableObjectNamespace(name, factory);
6233
+ namespace.get = (id) => {
6234
+ const stub = new DurableObjectStub(factory, id);
6235
+ stub.fetch = (...reqArgs) => {
6236
+ const requestFromArgs = new MiniflareRequest(...reqArgs);
6237
+ const url = new URL(requestFromArgs.url);
6238
+ url.host = host;
6239
+ if (port !== void 0)
6240
+ url.port = port.toString();
6241
+ const request = new MiniflareRequest(
6242
+ url.toString(),
6243
+ requestFromArgs
6244
+ );
6245
+ request.headers.set("x-miniflare-durable-object-name", name);
6246
+ request.headers.set(
6247
+ "x-miniflare-durable-object-id",
6248
+ id.toString()
6249
+ );
6250
+ return fetch(request);
6251
+ };
6252
+ return stub;
6253
+ };
6254
+ return [binding, namespace];
6255
+ })
6256
+ )
6257
+ };
5314
6258
  let mf;
6259
+ let durableObjectsMf = void 0;
6260
+ let durableObjectsMfPort = void 0;
5315
6261
  try {
5316
6262
  if (args._[1]) {
5317
- const opts = JSON.parse(args._[1]);
6263
+ const opts = JSON.parse(
6264
+ args._[1]
6265
+ );
5318
6266
  if (isNaN(opts.proxyPort || NaN) && !opts.directory) {
5319
- throw new Error("MiniflareCLIOptions: built in service bindings set to true, but no port or directory provided");
6267
+ throw new Error(
6268
+ "MiniflareCLIOptions: built in service bindings set to true, but no port or directory provided"
6269
+ );
5320
6270
  }
5321
6271
  const options = {
5322
6272
  log: config.log,
5323
6273
  proxyPort: opts.proxyPort,
5324
- directory: opts.directory
6274
+ directory: opts.directory,
6275
+ tre: false
5325
6276
  };
5326
6277
  config.serviceBindings = {
5327
6278
  ...config.serviceBindings,
@@ -5329,13 +6280,72 @@ async function main() {
5329
6280
  };
5330
6281
  }
5331
6282
  mf = new Miniflare(config);
5332
- await mf.startServer();
6283
+ const mfServer = await mf.startServer();
6284
+ const mfPort = mfServer.address().port;
5333
6285
  await mf.startScheduler();
5334
- process.send && process.send("ready");
6286
+ const internalDurableObjectClassNames = Object.values(
6287
+ config.durableObjects
6288
+ );
6289
+ if (internalDurableObjectClassNames.length > 0) {
6290
+ durableObjectsMf = new Miniflare({
6291
+ host: config.host,
6292
+ port: 0,
6293
+ script: `
6294
+ export default {
6295
+ fetch(request, env) {
6296
+ return env.DO.fetch(request)
6297
+ }
6298
+ }`,
6299
+ serviceBindings: {
6300
+ DO: async (request) => {
6301
+ request = new MiniflareRequest(request);
6302
+ const name = request.headers.get("x-miniflare-durable-object-name");
6303
+ const idString = request.headers.get(
6304
+ "x-miniflare-durable-object-id"
6305
+ );
6306
+ request.headers.delete("x-miniflare-durable-object-name");
6307
+ request.headers.delete("x-miniflare-durable-object-id");
6308
+ if (!name || !idString) {
6309
+ return new MiniflareResponse(
6310
+ "[durable-object-proxy-err] Missing `x-miniflare-durable-object-name` or `x-miniflare-durable-object-id` headers.",
6311
+ { status: 400 }
6312
+ );
6313
+ }
6314
+ const namespace = await mf?.getDurableObjectNamespace(name);
6315
+ const id = namespace?.idFromString(idString);
6316
+ if (!id) {
6317
+ return new MiniflareResponse(
6318
+ "[durable-object-proxy-err] Could not generate an ID. Possibly due to a mismatched DO name and ID?",
6319
+ { status: 500 }
6320
+ );
6321
+ }
6322
+ const stub = namespace?.get(id);
6323
+ if (!stub) {
6324
+ return new MiniflareResponse(
6325
+ "[durable-object-proxy-err] Could not generate a stub. Possibly due to a mismatched DO name and ID?",
6326
+ { status: 500 }
6327
+ );
6328
+ }
6329
+ return stub.fetch(request);
6330
+ }
6331
+ },
6332
+ modules: true
6333
+ });
6334
+ const server = await durableObjectsMf.startServer();
6335
+ durableObjectsMfPort = server.address().port;
6336
+ }
6337
+ process.send && process.send(
6338
+ JSON.stringify({
6339
+ port: mfPort,
6340
+ ready: true,
6341
+ durableObjectsPort: durableObjectsMfPort
6342
+ })
6343
+ );
5335
6344
  } catch (e) {
5336
6345
  mf?.log.error(e);
5337
6346
  process.exitCode = 1;
5338
6347
  await mf?.dispose();
6348
+ await durableObjectsMf?.dispose();
5339
6349
  }
5340
6350
  }
5341
6351
  await main();