@qwik.dev/router 2.0.0-beta.2 → 2.0.0-beta.21

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 (78) hide show
  1. package/adapters/static/vite.d.ts +1 -1
  2. package/lib/adapters/azure-swa/vite/index.d.ts +2 -2
  3. package/lib/adapters/azure-swa/vite/index.mjs +9 -9
  4. package/lib/adapters/bun-server/vite/index.d.ts +2 -2
  5. package/lib/adapters/bun-server/vite/index.mjs +9 -7
  6. package/lib/adapters/cloud-run/vite/index.d.ts +2 -2
  7. package/lib/adapters/cloud-run/vite/index.mjs +9 -7
  8. package/lib/adapters/cloudflare-pages/vite/index.d.ts +2 -2
  9. package/lib/adapters/cloudflare-pages/vite/index.mjs +9 -24
  10. package/lib/adapters/deno-server/vite/index.d.ts +2 -2
  11. package/lib/adapters/deno-server/vite/index.mjs +9 -7
  12. package/lib/adapters/netlify-edge/vite/index.d.ts +2 -2
  13. package/lib/adapters/netlify-edge/vite/index.mjs +10 -14
  14. package/lib/adapters/node-server/vite/index.d.ts +2 -2
  15. package/lib/adapters/node-server/vite/index.mjs +9 -7
  16. package/lib/adapters/shared/vite/index.d.ts +13 -19
  17. package/lib/adapters/shared/vite/index.mjs +107 -139
  18. package/lib/adapters/ssg/vite/index.d.ts +13 -0
  19. package/lib/adapters/ssg/vite/index.mjs +18 -0
  20. package/lib/adapters/vercel-edge/vite/index.d.ts +3 -3
  21. package/lib/adapters/vercel-edge/vite/index.mjs +9 -11
  22. package/lib/chunks/error-handler.mjs +57 -0
  23. package/lib/chunks/format-error.mjs +137 -0
  24. package/lib/chunks/fs.mjs +254 -0
  25. package/lib/{static/node.mjs → chunks/index.mjs} +361 -563
  26. package/lib/chunks/mime-types.mjs +52 -0
  27. package/lib/chunks/routing.qwik.mjs +429 -0
  28. package/lib/chunks/types.qwik.mjs +22 -0
  29. package/lib/index.d.ts +240 -60
  30. package/lib/index.qwik.mjs +698 -983
  31. package/lib/middleware/aws-lambda/index.d.ts +3 -2
  32. package/lib/middleware/aws-lambda/index.mjs +8 -12
  33. package/lib/middleware/azure-swa/index.mjs +10 -216
  34. package/lib/middleware/bun/index.d.ts +11 -0
  35. package/lib/middleware/bun/index.mjs +24 -83
  36. package/lib/middleware/cloudflare-pages/index.mjs +10 -22
  37. package/lib/middleware/deno/index.d.ts +11 -0
  38. package/lib/middleware/deno/index.mjs +24 -83
  39. package/lib/middleware/firebase/index.mjs +7 -11
  40. package/lib/middleware/netlify-edge/index.mjs +10 -23
  41. package/lib/middleware/node/index.mjs +22 -87
  42. package/lib/middleware/request-handler/index.d.ts +89 -70
  43. package/lib/middleware/request-handler/index.mjs +584 -659
  44. package/lib/middleware/vercel-edge/index.mjs +15 -27
  45. package/lib/modules.d.ts +4 -12
  46. package/lib/service-worker/index.mjs +4 -0
  47. package/lib/{static → ssg}/index.d.ts +17 -17
  48. package/lib/ssg/index.mjs +14 -0
  49. package/lib/vite/index.d.ts +32 -10
  50. package/lib/vite/index.mjs +1524 -26934
  51. package/modules.d.ts +4 -12
  52. package/package.json +62 -68
  53. package/ssg.d.ts +2 -0
  54. package/static.d.ts +1 -1
  55. package/lib/adapters/azure-swa/vite/index.cjs +0 -96
  56. package/lib/adapters/bun-server/vite/index.cjs +0 -50
  57. package/lib/adapters/cloud-run/vite/index.cjs +0 -47
  58. package/lib/adapters/cloudflare-pages/vite/index.cjs +0 -115
  59. package/lib/adapters/deno-server/vite/index.cjs +0 -62
  60. package/lib/adapters/netlify-edge/vite/index.cjs +0 -129
  61. package/lib/adapters/node-server/vite/index.cjs +0 -50
  62. package/lib/adapters/shared/vite/index.cjs +0 -378
  63. package/lib/adapters/static/vite/index.cjs +0 -368
  64. package/lib/adapters/static/vite/index.d.ts +0 -10
  65. package/lib/adapters/static/vite/index.mjs +0 -331
  66. package/lib/adapters/vercel-edge/vite/index.cjs +0 -118
  67. package/lib/index.qwik.cjs +0 -1947
  68. package/lib/middleware/node/index.cjs +0 -314
  69. package/lib/middleware/request-handler/index.cjs +0 -1614
  70. package/lib/service-worker.cjs +0 -17
  71. package/lib/service-worker.mjs +0 -15
  72. package/lib/static/deno.mjs +0 -8
  73. package/lib/static/index.cjs +0 -67
  74. package/lib/static/index.mjs +0 -48
  75. package/lib/static/node.cjs +0 -1124
  76. package/lib/vite/index.cjs +0 -27445
  77. package/middleware/request-handler/generated/not-found-paths.ts +0 -7
  78. package/middleware/request-handler/generated/static-paths.ts +0 -35
@@ -1,69 +1,140 @@
1
- // packages/qwik-router/src/middleware/request-handler/error-handler.ts
2
- var ServerError = class extends Error {
3
- constructor(status, data) {
4
- super(typeof data === "string" ? data : void 0);
5
- this.status = status;
6
- this.data = data;
1
+ import { isServer } from '@qwik.dev/core/build';
2
+ import { i as isPromise, k as QDATA_KEY, Q as Q_ROUTE, h as QFN_KEY, m as QLOADER_KEY, j as QACTION_KEY, d as loadRoute } from '../../chunks/routing.qwik.mjs';
3
+ import { inlinedQrl } from '@qwik.dev/core';
4
+ import { _serialize, _UNINITIALIZED, _deserialize, _verifySerializable } from '@qwik.dev/core/internal';
5
+ import { L as LoadedRouteProp } from '../../chunks/types.qwik.mjs';
6
+ import { _asyncRequestStore as _asyncRequestStore$1, ServerError as ServerError$1, RedirectMessage as RedirectMessage$1, RewriteMessage as RewriteMessage$1, AbortMessage as AbortMessage$1 } from '@qwik.dev/router/middleware/request-handler';
7
+ import { g as getErrorHtml, m as minimalHtmlResponse } from '../../chunks/error-handler.mjs';
8
+ import '@qwik.dev/core/preloader';
9
+
10
+ var HttpStatus = /* @__PURE__ */ ((HttpStatus2) => {
11
+ HttpStatus2[HttpStatus2["Continue"] = 100] = "Continue";
12
+ HttpStatus2[HttpStatus2["SwitchingProtocols"] = 101] = "SwitchingProtocols";
13
+ HttpStatus2[HttpStatus2["Processing"] = 102] = "Processing";
14
+ HttpStatus2[HttpStatus2["Ok"] = 200] = "Ok";
15
+ HttpStatus2[HttpStatus2["Created"] = 201] = "Created";
16
+ HttpStatus2[HttpStatus2["Accepted"] = 202] = "Accepted";
17
+ HttpStatus2[HttpStatus2["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
18
+ HttpStatus2[HttpStatus2["NoContent"] = 204] = "NoContent";
19
+ HttpStatus2[HttpStatus2["ResetContent"] = 205] = "ResetContent";
20
+ HttpStatus2[HttpStatus2["PartialContent"] = 206] = "PartialContent";
21
+ HttpStatus2[HttpStatus2["MultiStatus"] = 207] = "MultiStatus";
22
+ HttpStatus2[HttpStatus2["AlreadyReported"] = 208] = "AlreadyReported";
23
+ HttpStatus2[HttpStatus2["ImUsed"] = 226] = "ImUsed";
24
+ HttpStatus2[HttpStatus2["MultipleChoices"] = 300] = "MultipleChoices";
25
+ HttpStatus2[HttpStatus2["MovedPermanently"] = 301] = "MovedPermanently";
26
+ HttpStatus2[HttpStatus2["Found"] = 302] = "Found";
27
+ HttpStatus2[HttpStatus2["SeeOther"] = 303] = "SeeOther";
28
+ HttpStatus2[HttpStatus2["NotModified"] = 304] = "NotModified";
29
+ HttpStatus2[HttpStatus2["UseProxy"] = 305] = "UseProxy";
30
+ HttpStatus2[HttpStatus2["SwitchProxy"] = 306] = "SwitchProxy";
31
+ HttpStatus2[HttpStatus2["TemporaryRedirect"] = 307] = "TemporaryRedirect";
32
+ HttpStatus2[HttpStatus2["PermanentRedirect"] = 308] = "PermanentRedirect";
33
+ HttpStatus2[HttpStatus2["BadRequest"] = 400] = "BadRequest";
34
+ HttpStatus2[HttpStatus2["Unauthorized"] = 401] = "Unauthorized";
35
+ HttpStatus2[HttpStatus2["PaymentRequired"] = 402] = "PaymentRequired";
36
+ HttpStatus2[HttpStatus2["Forbidden"] = 403] = "Forbidden";
37
+ HttpStatus2[HttpStatus2["NotFound"] = 404] = "NotFound";
38
+ HttpStatus2[HttpStatus2["MethodNotAllowed"] = 405] = "MethodNotAllowed";
39
+ HttpStatus2[HttpStatus2["NotAcceptable"] = 406] = "NotAcceptable";
40
+ HttpStatus2[HttpStatus2["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
41
+ HttpStatus2[HttpStatus2["RequestTimeout"] = 408] = "RequestTimeout";
42
+ HttpStatus2[HttpStatus2["Conflict"] = 409] = "Conflict";
43
+ HttpStatus2[HttpStatus2["Gone"] = 410] = "Gone";
44
+ HttpStatus2[HttpStatus2["LengthRequired"] = 411] = "LengthRequired";
45
+ HttpStatus2[HttpStatus2["PreconditionFailed"] = 412] = "PreconditionFailed";
46
+ HttpStatus2[HttpStatus2["PayloadTooLarge"] = 413] = "PayloadTooLarge";
47
+ HttpStatus2[HttpStatus2["UriTooLong"] = 414] = "UriTooLong";
48
+ HttpStatus2[HttpStatus2["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
49
+ HttpStatus2[HttpStatus2["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
50
+ HttpStatus2[HttpStatus2["ExpectationFailed"] = 417] = "ExpectationFailed";
51
+ HttpStatus2[HttpStatus2["IAmATeapot"] = 418] = "IAmATeapot";
52
+ HttpStatus2[HttpStatus2["MisdirectedRequest"] = 421] = "MisdirectedRequest";
53
+ HttpStatus2[HttpStatus2["UnprocessableEntity"] = 422] = "UnprocessableEntity";
54
+ HttpStatus2[HttpStatus2["Locked"] = 423] = "Locked";
55
+ HttpStatus2[HttpStatus2["FailedDependency"] = 424] = "FailedDependency";
56
+ HttpStatus2[HttpStatus2["UpgradeRequired"] = 426] = "UpgradeRequired";
57
+ HttpStatus2[HttpStatus2["PreconditionRequired"] = 428] = "PreconditionRequired";
58
+ HttpStatus2[HttpStatus2["TooManyRequests"] = 429] = "TooManyRequests";
59
+ HttpStatus2[HttpStatus2["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
60
+ HttpStatus2[HttpStatus2["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
61
+ HttpStatus2[HttpStatus2["InternalServerError"] = 500] = "InternalServerError";
62
+ HttpStatus2[HttpStatus2["NotImplemented"] = 501] = "NotImplemented";
63
+ HttpStatus2[HttpStatus2["BadGateway"] = 502] = "BadGateway";
64
+ HttpStatus2[HttpStatus2["ServiceUnavailable"] = 503] = "ServiceUnavailable";
65
+ HttpStatus2[HttpStatus2["GatewayTimeout"] = 504] = "GatewayTimeout";
66
+ HttpStatus2[HttpStatus2["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
67
+ HttpStatus2[HttpStatus2["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
68
+ HttpStatus2[HttpStatus2["InsufficientStorage"] = 507] = "InsufficientStorage";
69
+ HttpStatus2[HttpStatus2["LoopDetected"] = 508] = "LoopDetected";
70
+ HttpStatus2[HttpStatus2["NotExtended"] = 510] = "NotExtended";
71
+ HttpStatus2[HttpStatus2["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
72
+ return HttpStatus2;
73
+ })(HttpStatus || {});
74
+
75
+ function createCacheControl(cacheControl) {
76
+ const controls = [];
77
+ if (cacheControl === "day") {
78
+ cacheControl = 60 * 60 * 24;
79
+ } else if (cacheControl === "week") {
80
+ cacheControl = 60 * 60 * 24 * 7;
81
+ } else if (cacheControl === "month") {
82
+ cacheControl = 60 * 60 * 24 * 30;
83
+ } else if (cacheControl === "year") {
84
+ cacheControl = 60 * 60 * 24 * 365;
85
+ } else if (cacheControl === "private") {
86
+ cacheControl = {
87
+ private: true,
88
+ noCache: true
89
+ };
90
+ } else if (cacheControl === "immutable") {
91
+ cacheControl = {
92
+ public: true,
93
+ immutable: true,
94
+ maxAge: 60 * 60 * 24 * 365
95
+ };
96
+ } else if (cacheControl === "no-cache") {
97
+ cacheControl = {
98
+ noCache: true
99
+ };
7
100
  }
8
- };
9
- function getErrorHtml(status, e) {
10
- let message = "Server Error";
11
- if (e != null) {
12
- if (typeof e.message === "string") {
13
- message = e.message;
14
- } else {
15
- message = String(e);
16
- }
101
+ if (typeof cacheControl === "number") {
102
+ cacheControl = {
103
+ maxAge: cacheControl,
104
+ sMaxAge: cacheControl
105
+ };
17
106
  }
18
- return `<html>` + minimalHtmlResponse(status, message) + `</html>`;
19
- }
20
- function minimalHtmlResponse(status, message) {
21
- if (typeof status !== "number") {
22
- status = 500;
107
+ if (cacheControl.immutable) {
108
+ controls.push("immutable");
23
109
  }
24
- if (typeof message === "string") {
25
- message = escapeHtml(message);
26
- } else {
27
- message = "";
28
- }
29
- const width = typeof message === "string" ? "600px" : "300px";
30
- const color = status >= 500 ? COLOR_500 : COLOR_400;
31
- return `
32
- <head>
33
- <meta charset="utf-8">
34
- <meta http-equiv="Status" content="${status}">
35
- <title>${status} ${message}</title>
36
- <meta name="viewport" content="width=device-width,initial-scale=1">
37
- <style>
38
- body { color: ${color}; background-color: #fafafa; padding: 30px; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Roboto, sans-serif; }
39
- p { max-width: ${width}; margin: 60px auto 30px auto; background: white; border-radius: 4px; box-shadow: 0px 0px 50px -20px ${color}; overflow: hidden; }
40
- strong { display: inline-block; padding: 15px; background: ${color}; color: white; }
41
- span { display: inline-block; padding: 15px; }
42
- </style>
43
- </head>
44
- <body><p><strong>${status}</strong> <span>${message}</span></p></body>
45
- `;
110
+ if (cacheControl.maxAge) {
111
+ controls.push(`max-age=${cacheControl.maxAge}`);
112
+ }
113
+ if (cacheControl.sMaxAge) {
114
+ controls.push(`s-maxage=${cacheControl.sMaxAge}`);
115
+ }
116
+ if (cacheControl.noStore) {
117
+ controls.push("no-store");
118
+ }
119
+ if (cacheControl.noCache) {
120
+ controls.push("no-cache");
121
+ }
122
+ if (cacheControl.private) {
123
+ controls.push("private");
124
+ }
125
+ if (cacheControl.public) {
126
+ controls.push("public");
127
+ }
128
+ if (cacheControl.staleWhileRevalidate) {
129
+ controls.push(`stale-while-revalidate=${cacheControl.staleWhileRevalidate}`);
130
+ }
131
+ if (cacheControl.staleIfError) {
132
+ controls.push(`stale-if-error=${cacheControl.staleIfError}`);
133
+ }
134
+ return controls.join(", ");
46
135
  }
47
- var ESCAPE_HTML = /[&<>]/g;
48
- var escapeHtml = (s) => {
49
- return s.replace(ESCAPE_HTML, (c) => {
50
- switch (c) {
51
- case "&":
52
- return "&amp;";
53
- case "<":
54
- return "&lt;";
55
- case ">":
56
- return "&gt;";
57
- default:
58
- return "";
59
- }
60
- });
61
- };
62
- var COLOR_400 = "#006ce9";
63
- var COLOR_500 = "#713fc2";
64
136
 
65
- // packages/qwik-router/src/middleware/request-handler/cookie.ts
66
- var SAMESITE = {
137
+ const SAMESITE = {
67
138
  lax: "Lax",
68
139
  Lax: "Lax",
69
140
  None: "None",
@@ -71,14 +142,14 @@ var SAMESITE = {
71
142
  strict: "Strict",
72
143
  Strict: "Strict"
73
144
  };
74
- var UNIT = {
145
+ const UNIT = {
75
146
  seconds: 1,
76
147
  minutes: 1 * 60,
77
148
  hours: 1 * 60 * 60,
78
149
  days: 1 * 60 * 60 * 24,
79
150
  weeks: 1 * 60 * 60 * 24 * 7
80
151
  };
81
- var createSetCookieValue = (cookieName, cookieValue, options) => {
152
+ const createSetCookieValue = (cookieName, cookieValue, options) => {
82
153
  const c = [`${cookieName}=${cookieValue}`];
83
154
  if (typeof options.domain === "string") {
84
155
  c.push(`Domain=${options.domain}`);
@@ -114,7 +185,7 @@ function tryDecodeUriComponent(str) {
114
185
  return str;
115
186
  }
116
187
  }
117
- var parseCookieString = (cookieString) => {
188
+ const parseCookieString = (cookieString) => {
118
189
  const cookie = {};
119
190
  if (typeof cookieString === "string" && cookieString !== "") {
120
191
  const cookieSegments = cookieString.split(";");
@@ -139,10 +210,10 @@ function resolveSameSite(sameSite) {
139
210
  }
140
211
  return void 0;
141
212
  }
142
- var REQ_COOKIE = Symbol("request-cookies");
143
- var RES_COOKIE = Symbol("response-cookies");
144
- var LIVE_COOKIE = Symbol("live-cookies");
145
- var Cookie = class {
213
+ const REQ_COOKIE = /* @__PURE__ */ Symbol("request-cookies");
214
+ const RES_COOKIE = /* @__PURE__ */ Symbol("response-cookies");
215
+ const LIVE_COOKIE = /* @__PURE__ */ Symbol("live-cookies");
216
+ class Cookie {
146
217
  [REQ_COOKIE];
147
218
  [RES_COOKIE] = {};
148
219
  [LIVE_COOKIE] = {};
@@ -199,8 +270,8 @@ var Cookie = class {
199
270
  headers() {
200
271
  return Object.values(this[RES_COOKIE]);
201
272
  }
202
- };
203
- var mergeHeadersCookies = (headers, cookies) => {
273
+ }
274
+ const mergeHeadersCookies = (headers, cookies) => {
204
275
  const cookieHeaders = cookies.headers();
205
276
  if (cookieHeaders.length > 0) {
206
277
  const newHeaders = new Headers(headers);
@@ -212,340 +283,46 @@ var mergeHeadersCookies = (headers, cookies) => {
212
283
  return headers;
213
284
  };
214
285
 
215
- // packages/qwik-router/src/middleware/request-handler/redirect-handler.ts
216
- var AbortMessage = class {
217
- };
218
- var RedirectMessage = class extends AbortMessage {
219
- };
220
-
221
- // packages/qwik-router/src/middleware/request-handler/rewrite-handler.ts
222
- var RewriteMessage = class extends AbortMessage {
223
- constructor(pathname) {
224
- super();
225
- this.pathname = pathname;
226
- }
227
- };
228
-
229
- // packages/qwik-router/src/runtime/src/constants.ts
230
- var MODULE_CACHE = /* @__PURE__ */ new WeakMap();
231
- var QACTION_KEY = "qaction";
232
- var QFN_KEY = "qfunc";
233
- var QDATA_KEY = "qdata";
234
-
235
- // packages/qwik-router/src/runtime/src/route-matcher.ts
236
- function matchRoute(route, path) {
237
- const routeIdx = startIdxSkipSlash(route);
238
- const routeLength = lengthNoTrailingSlash(route);
239
- const pathIdx = startIdxSkipSlash(path);
240
- const pathLength = lengthNoTrailingSlash(path);
241
- return matchRoutePart(route, routeIdx, routeLength, path, pathIdx, pathLength);
242
- }
243
- function matchRoutePart(route, routeIdx, routeLength, path, pathIdx, pathLength) {
244
- let params = null;
245
- while (routeIdx < routeLength) {
246
- const routeCh = route.charCodeAt(routeIdx++);
247
- const pathCh = path.charCodeAt(pathIdx++);
248
- if (routeCh === 91 /* OPEN_BRACKET */) {
249
- const isMany = isThreeDots(route, routeIdx);
250
- const paramNameStart = routeIdx + (isMany ? 3 : 0);
251
- const paramNameEnd = scan(route, paramNameStart, routeLength, 93 /* CLOSE_BRACKET */);
252
- const paramName = route.substring(paramNameStart, paramNameEnd);
253
- const paramSuffixEnd = scan(route, paramNameEnd + 1, routeLength, 47 /* SLASH */);
254
- const suffix = route.substring(paramNameEnd + 1, paramSuffixEnd);
255
- routeIdx = paramNameEnd + 1;
256
- const paramValueStart = pathIdx - 1;
257
- if (isMany) {
258
- const match = recursiveScan(
259
- paramName,
260
- suffix,
261
- path,
262
- paramValueStart,
263
- pathLength,
264
- route,
265
- routeIdx + suffix.length + 1,
266
- routeLength
267
- );
268
- if (match) {
269
- return Object.assign(params || (params = {}), match);
270
- }
271
- }
272
- const paramValueEnd = scan(path, paramValueStart, pathLength, 47 /* SLASH */, suffix);
273
- if (paramValueEnd == -1) {
274
- return null;
275
- }
276
- const paramValue = path.substring(paramValueStart, paramValueEnd);
277
- if (!isMany && !suffix && !paramValue) {
278
- return null;
279
- }
280
- pathIdx = paramValueEnd;
281
- (params || (params = {}))[paramName] = decodeURIComponent(paramValue);
282
- } else if (routeCh !== pathCh) {
283
- if (!(isNaN(pathCh) && isRestParameter(route, routeIdx))) {
284
- return null;
285
- }
286
- }
287
- }
288
- if (allConsumed(route, routeIdx) && allConsumed(path, pathIdx)) {
289
- return params || {};
290
- } else {
291
- return null;
292
- }
293
- }
294
- function isRestParameter(text, idx) {
295
- return text.charCodeAt(idx) === 91 /* OPEN_BRACKET */ && isThreeDots(text, idx + 1);
296
- }
297
- function lengthNoTrailingSlash(text) {
298
- const length = text.length;
299
- return length > 1 && text.charCodeAt(length - 1) === 47 /* SLASH */ ? length - 1 : length;
300
- }
301
- function allConsumed(text, idx) {
302
- const length = text.length;
303
- return idx >= length || idx == length - 1 && text.charCodeAt(idx) === 47 /* SLASH */;
304
- }
305
- function startIdxSkipSlash(text) {
306
- return text.charCodeAt(0) === 47 /* SLASH */ ? 1 : 0;
307
- }
308
- function isThreeDots(text, idx) {
309
- return text.charCodeAt(idx) === 46 /* DOT */ && text.charCodeAt(idx + 1) === 46 /* DOT */ && text.charCodeAt(idx + 2) === 46 /* DOT */;
310
- }
311
- function scan(text, idx, end, ch, suffix = "") {
312
- while (idx < end && text.charCodeAt(idx) !== ch) {
313
- idx++;
314
- }
315
- const suffixLength = suffix.length;
316
- for (let i = 0; i < suffixLength; i++) {
317
- if (text.charCodeAt(idx - suffixLength + i) !== suffix.charCodeAt(i)) {
318
- return -1;
319
- }
320
- }
321
- return idx - suffixLength;
322
- }
323
- function recursiveScan(paramName, suffix, path, pathStart, pathLength, route, routeStart, routeLength) {
324
- if (path.charCodeAt(pathStart) === 47 /* SLASH */) {
325
- pathStart++;
326
- }
327
- let pathIdx = pathLength;
328
- const sep = suffix + "/";
329
- while (pathIdx >= pathStart) {
330
- const match = matchRoutePart(route, routeStart, routeLength, path, pathIdx, pathLength);
331
- if (match) {
332
- let value = path.substring(pathStart, Math.min(pathIdx, pathLength));
333
- if (value.endsWith(sep)) {
334
- value = value.substring(0, value.length - sep.length);
335
- }
336
- match[paramName] = decodeURIComponent(value);
337
- return match;
338
- }
339
- const newPathIdx = lastIndexOf(path, pathStart, sep, pathIdx, pathStart - 1) + sep.length;
340
- if (pathIdx === newPathIdx) {
341
- break;
342
- }
343
- pathIdx = newPathIdx;
344
- }
345
- return null;
346
- }
347
- function lastIndexOf(text, start, match, searchIdx, notFoundIdx) {
348
- let idx = text.lastIndexOf(match, searchIdx);
349
- if (idx == searchIdx - match.length) {
350
- idx = text.lastIndexOf(match, searchIdx - match.length - 1);
351
- }
352
- return idx > start ? idx : notFoundIdx;
353
- }
354
-
355
- // packages/qwik-router/src/runtime/src/utils.ts
356
- var isPromise = (value) => {
357
- return value && typeof value.then === "function";
358
- };
359
- var deepFreeze = (obj) => {
360
- if (obj == null) {
361
- return obj;
362
- }
363
- Object.getOwnPropertyNames(obj).forEach((prop) => {
364
- const value = obj[prop];
365
- if (value && typeof value === "object" && !Object.isFrozen(value)) {
366
- deepFreeze(value);
367
- }
368
- });
369
- return Object.freeze(obj);
370
- };
371
-
372
- // packages/qwik-router/src/runtime/src/routing.ts
373
- var loadRoute = async (routes, menus, cacheModules, pathname) => {
374
- if (!Array.isArray(routes)) {
375
- return null;
376
- }
377
- for (const routeData of routes) {
378
- const routeName = routeData[0];
379
- const params = matchRoute(routeName, pathname);
380
- if (!params) {
381
- continue;
382
- }
383
- const loaders = routeData[1];
384
- const routeBundleNames = routeData[3];
385
- const modules = new Array(loaders.length);
386
- const pendingLoads = [];
387
- loaders.forEach((moduleLoader, i) => {
388
- loadModule(
389
- moduleLoader,
390
- pendingLoads,
391
- (routeModule) => modules[i] = routeModule,
392
- cacheModules
393
- );
394
- });
395
- const menuLoader = getMenuLoader(menus, pathname);
396
- let menu = void 0;
397
- loadModule(
398
- menuLoader,
399
- pendingLoads,
400
- (menuModule) => menu = menuModule == null ? void 0 : menuModule.default,
401
- cacheModules
402
- );
403
- if (pendingLoads.length > 0) {
404
- await Promise.all(pendingLoads);
405
- }
406
- return [routeName, params, modules, deepFreeze(menu), routeBundleNames];
407
- }
408
- return null;
409
- };
410
- var loadModule = (moduleLoader, pendingLoads, moduleSetter, cacheModules) => {
411
- if (typeof moduleLoader === "function") {
412
- const loadedModule = MODULE_CACHE.get(moduleLoader);
413
- if (loadedModule) {
414
- moduleSetter(loadedModule);
415
- } else {
416
- const moduleOrPromise = moduleLoader();
417
- if (typeof moduleOrPromise.then === "function") {
418
- pendingLoads.push(
419
- moduleOrPromise.then((loadedModule2) => {
420
- if (cacheModules !== false) {
421
- MODULE_CACHE.set(moduleLoader, loadedModule2);
422
- }
423
- moduleSetter(loadedModule2);
424
- })
425
- );
426
- } else if (moduleOrPromise) {
427
- moduleSetter(moduleOrPromise);
428
- }
429
- }
430
- }
431
- };
432
- var getMenuLoader = (menus, pathname) => {
433
- if (menus) {
434
- pathname = pathname.endsWith("/") ? pathname : pathname + "/";
435
- const menu = menus.find(
436
- (m) => m[0] === pathname || pathname.startsWith(m[0] + (pathname.endsWith("/") ? "" : "/"))
437
- );
438
- if (menu) {
439
- return menu[1];
440
- }
441
- }
442
- };
443
-
444
- // packages/qwik-router/src/middleware/request-handler/cache-control.ts
445
- function createCacheControl(cacheControl) {
446
- const controls = [];
447
- if (cacheControl === "day") {
448
- cacheControl = 60 * 60 * 24;
449
- } else if (cacheControl === "week") {
450
- cacheControl = 60 * 60 * 24 * 7;
451
- } else if (cacheControl === "month") {
452
- cacheControl = 60 * 60 * 24 * 30;
453
- } else if (cacheControl === "year") {
454
- cacheControl = 60 * 60 * 24 * 365;
455
- } else if (cacheControl === "private") {
456
- cacheControl = {
457
- private: true,
458
- noCache: true
459
- };
460
- } else if (cacheControl === "immutable") {
461
- cacheControl = {
462
- public: true,
463
- immutable: true,
464
- maxAge: 60 * 60 * 24 * 365
465
- };
466
- } else if (cacheControl === "no-cache") {
467
- cacheControl = {
468
- noCache: true
469
- };
470
- }
471
- if (typeof cacheControl === "number") {
472
- cacheControl = {
473
- maxAge: cacheControl,
474
- sMaxAge: cacheControl
475
- };
476
- }
477
- if (cacheControl.immutable) {
478
- controls.push("immutable");
479
- }
480
- if (cacheControl.maxAge) {
481
- controls.push(`max-age=${cacheControl.maxAge}`);
482
- }
483
- if (cacheControl.sMaxAge) {
484
- controls.push(`s-maxage=${cacheControl.sMaxAge}`);
485
- }
486
- if (cacheControl.noStore) {
487
- controls.push("no-store");
488
- }
489
- if (cacheControl.noCache) {
490
- controls.push("no-cache");
491
- }
492
- if (cacheControl.private) {
493
- controls.push("private");
494
- }
495
- if (cacheControl.public) {
496
- controls.push("public");
497
- }
498
- if (cacheControl.staleWhileRevalidate) {
499
- controls.push(`stale-while-revalidate=${cacheControl.staleWhileRevalidate}`);
500
- }
501
- if (cacheControl.staleIfError) {
502
- controls.push(`stale-if-error=${cacheControl.staleIfError}`);
503
- }
504
- return controls.join(", ");
505
- }
506
-
507
- // packages/qwik-router/src/middleware/request-handler/user-response.ts
508
- var asyncStore;
509
- import("node:async_hooks").then((module) => {
510
- const AsyncLocalStorage = module.AsyncLocalStorage;
511
- asyncStore = new AsyncLocalStorage();
512
- globalThis.qcAsyncRequestStore = asyncStore;
513
- }).catch((err) => {
514
- console.warn(
515
- "AsyncLocalStorage not available, continuing without it. This might impact concurrent server calls.",
516
- err
517
- );
518
- });
519
- function runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, trailingSlash = true, basePathname = "/", qwikSerializer) {
286
+ function runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, basePathname = "/") {
520
287
  let resolve;
521
288
  const responsePromise = new Promise((r) => resolve = r);
522
289
  const requestEv = createRequestEvent(
523
290
  serverRequestEv,
524
291
  loadedRoute,
525
292
  requestHandlers,
526
- trailingSlash,
527
293
  basePathname,
528
- qwikSerializer,
529
294
  resolve
530
295
  );
531
296
  return {
532
297
  response: responsePromise,
533
298
  requestEv,
534
- completion: asyncStore ? asyncStore.run(requestEv, runNext, requestEv, rebuildRouteInfo, resolve) : runNext(requestEv, rebuildRouteInfo, resolve)
299
+ completion: _asyncRequestStore$1 ? _asyncRequestStore$1.run(requestEv, runNext, requestEv, rebuildRouteInfo, resolve) : runNext(requestEv, rebuildRouteInfo, resolve)
535
300
  };
536
301
  }
537
302
  async function runNext(requestEv, rebuildRouteInfo, resolve) {
303
+ try {
304
+ const isValidURL = (url) => new URL(url.pathname + url.search, url);
305
+ isValidURL(requestEv.originalUrl);
306
+ } catch {
307
+ const status = 404;
308
+ const message = "Resource Not Found";
309
+ requestEv.status(status);
310
+ const html = getErrorHtml(status, message);
311
+ requestEv.html(status, html);
312
+ return new ServerError$1(status, message);
313
+ }
538
314
  let rewriteAttempt = 1;
539
315
  async function _runNext() {
540
316
  try {
541
317
  await requestEv.next();
542
318
  } catch (e) {
543
- if (e instanceof RedirectMessage) {
319
+ if (e instanceof RedirectMessage$1) {
544
320
  const stream = requestEv.getWritableStream();
545
321
  await stream.close();
546
- } else if (e instanceof RewriteMessage) {
322
+ return e;
323
+ } else if (e instanceof RewriteMessage$1) {
547
324
  if (rewriteAttempt > 50) {
548
- throw new Error(`Infinite rewrite loop`);
325
+ return new Error(`Infinite rewrite loop`);
549
326
  }
550
327
  rewriteAttempt += 1;
551
328
  const url = new URL(requestEv.url);
@@ -553,41 +330,38 @@ async function runNext(requestEv, rebuildRouteInfo, resolve) {
553
330
  const { loadedRoute, requestHandlers } = await rebuildRouteInfo(url);
554
331
  requestEv.resetRoute(loadedRoute, requestHandlers, url);
555
332
  return await _runNext();
556
- } else if (e instanceof ServerError) {
557
- if (!requestEv.headersSent) {
558
- const status = e.status;
559
- const accept = requestEv.request.headers.get("Accept");
560
- if (accept && !accept.includes("text/html")) {
561
- const qwikSerializer = requestEv[RequestEvQwikSerializer];
562
- requestEv.headers.set("Content-Type", "application/qwik-json");
563
- requestEv.send(status, await qwikSerializer._serialize([e.data]));
564
- } else {
565
- const html = getErrorHtml(e.status, e.data);
566
- requestEv.html(status, html);
567
- }
333
+ } else if (e instanceof AbortMessage$1) {
334
+ return;
335
+ } else if (e instanceof ServerError$1 && !requestEv.headersSent) {
336
+ const status = e.status;
337
+ const accept = requestEv.request.headers.get("Accept");
338
+ if (accept && !accept.includes("text/html")) {
339
+ requestEv.headers.set("Content-Type", "application/qwik-json");
340
+ requestEv.send(status, await _serialize([e.data]));
341
+ } else {
342
+ requestEv.html(status, getErrorHtml(status, e.data));
568
343
  }
569
- } else if (!(e instanceof AbortMessage)) {
570
- if (getRequestMode(requestEv) !== "dev") {
571
- try {
572
- if (!requestEv.headersSent) {
573
- requestEv.headers.set("content-type", "text/html; charset=utf-8");
574
- requestEv.cacheControl({ noCache: true });
575
- requestEv.status(500);
576
- }
577
- const stream = requestEv.getWritableStream();
578
- if (!stream.locked) {
579
- const writer = stream.getWriter();
580
- await writer.write(encoder.encode(minimalHtmlResponse(500, "Internal Server Error")));
581
- await writer.close();
582
- }
583
- } catch {
584
- console.error("Unable to render error page");
344
+ return e;
345
+ }
346
+ if (getRequestMode(requestEv) !== "dev") {
347
+ try {
348
+ if (!requestEv.headersSent) {
349
+ requestEv.headers.set("content-type", "text/html; charset=utf-8");
350
+ requestEv.cacheControl({ noCache: true });
351
+ requestEv.status(500);
352
+ }
353
+ const stream = requestEv.getWritableStream();
354
+ if (!stream.locked) {
355
+ const writer = stream.getWriter();
356
+ await writer.write(encoder.encode(getErrorHtml(500, "Internal Server Error")));
357
+ await writer.close();
585
358
  }
359
+ } catch {
360
+ console.error("Unable to render error page");
586
361
  }
587
- return e;
588
362
  }
363
+ return e;
589
364
  }
590
- return void 0;
591
365
  }
592
366
  try {
593
367
  return await _runNext();
@@ -597,42 +371,42 @@ async function runNext(requestEv, rebuildRouteInfo, resolve) {
597
371
  }
598
372
  }
599
373
  }
600
- function getRouteMatchPathname(pathname, trailingSlash) {
601
- if (pathname.endsWith(QDATA_JSON)) {
602
- const trimEnd = pathname.length - QDATA_JSON_LEN + (trailingSlash ? 1 : 0);
374
+ function getRouteMatchPathname(pathname) {
375
+ const isInternal = pathname.endsWith(QDATA_JSON);
376
+ if (isInternal) {
377
+ const trimEnd = pathname.length - QDATA_JSON.length + (globalThis.__NO_TRAILING_SLASH__ ? 0 : 1);
603
378
  pathname = pathname.slice(0, trimEnd);
604
379
  if (pathname === "") {
605
380
  pathname = "/";
606
381
  }
607
382
  }
608
- return pathname;
383
+ return { pathname, isInternal };
609
384
  }
610
- var IsQData = "@isQData";
611
- var QDATA_JSON = "/q-data.json";
612
- var QDATA_JSON_LEN = QDATA_JSON.length;
385
+ const IsQData = "@isQData";
386
+ const QDATA_JSON = "/q-data.json";
613
387
 
614
- // packages/qwik-router/src/middleware/request-handler/request-event.ts
615
- var RequestEvLoaders = Symbol("RequestEvLoaders");
616
- var RequestEvMode = Symbol("RequestEvMode");
617
- var RequestEvRoute = Symbol("RequestEvRoute");
618
- var RequestEvQwikSerializer = Symbol("RequestEvQwikSerializer");
619
- var RequestEvTrailingSlash = Symbol("RequestEvTrailingSlash");
620
- var RequestRouteName = "@routeName";
621
- var RequestEvSharedActionId = "@actionId";
622
- var RequestEvSharedActionFormData = "@actionFormData";
623
- var RequestEvSharedNonce = "@nonce";
624
- var RequestEvIsRewrite = "@rewrite";
625
- function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trailingSlash, basePathname, qwikSerializer, resolved) {
388
+ const RequestEvLoaders = /* @__PURE__ */ Symbol("RequestEvLoaders");
389
+ const RequestEvMode = /* @__PURE__ */ Symbol("RequestEvMode");
390
+ const RequestEvRoute = /* @__PURE__ */ Symbol("RequestEvRoute");
391
+ const RequestEvLoaderSerializationStrategyMap = /* @__PURE__ */ Symbol(
392
+ "RequestEvLoaderSerializationStrategyMap"
393
+ );
394
+ const RequestRouteName = "@routeName";
395
+ const RequestEvSharedActionId = "@actionId";
396
+ const RequestEvSharedActionFormData = "@actionFormData";
397
+ const RequestEvSharedNonce = "@nonce";
398
+ const RequestEvIsRewrite = "@rewrite";
399
+ const RequestEvShareServerTiming = "@serverTiming";
400
+ const RequestEvShareQData = "qData";
401
+ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, basePathname, resolved) {
626
402
  const { request, platform, env } = serverRequestEv;
627
403
  const sharedMap = /* @__PURE__ */ new Map();
628
404
  const cookie = new Cookie(request.headers.get("cookie"));
629
405
  const headers = new Headers();
630
406
  const url = new URL(request.url);
631
- if (url.pathname.endsWith(QDATA_JSON)) {
632
- url.pathname = url.pathname.slice(0, -QDATA_JSON_LEN);
633
- if (trailingSlash && !url.pathname.endsWith("/")) {
634
- url.pathname += "/";
635
- }
407
+ const { pathname, isInternal } = getRouteMatchPathname(url.pathname);
408
+ if (isInternal) {
409
+ url.pathname = pathname;
636
410
  sharedMap.set(IsQData, true);
637
411
  }
638
412
  let routeModuleIndex = -1;
@@ -644,8 +418,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
644
418
  routeModuleIndex++;
645
419
  while (routeModuleIndex < requestHandlers.length) {
646
420
  const moduleRequestHandler = requestHandlers[routeModuleIndex];
647
- const asyncStore2 = globalThis.qcAsyncRequestStore;
648
- const result = (asyncStore2 == null ? void 0 : asyncStore2.run) ? asyncStore2.run(requestEv, moduleRequestHandler, requestEv) : moduleRequestHandler(requestEv);
421
+ const result = moduleRequestHandler(requestEv);
649
422
  if (isPromise(result)) {
650
423
  await result;
651
424
  }
@@ -698,19 +471,18 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
698
471
  }
699
472
  return exit();
700
473
  };
701
- const exit = () => {
474
+ const exit = (message = new AbortMessage$1()) => {
702
475
  routeModuleIndex = ABORT_INDEX;
703
- return new AbortMessage();
476
+ return message;
704
477
  };
705
478
  const loaders = {};
706
479
  const requestEv = {
707
480
  [RequestEvLoaders]: loaders,
481
+ [RequestEvLoaderSerializationStrategyMap]: /* @__PURE__ */ new Map(),
708
482
  [RequestEvMode]: serverRequestEv.mode,
709
- [RequestEvTrailingSlash]: trailingSlash,
710
483
  get [RequestEvRoute]() {
711
484
  return loadedRoute;
712
485
  },
713
- [RequestEvQwikSerializer]: qwikSerializer,
714
486
  cookie,
715
487
  headers,
716
488
  env,
@@ -718,7 +490,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
718
490
  signal: request.signal,
719
491
  originalUrl: new URL(url),
720
492
  get params() {
721
- return (loadedRoute == null ? void 0 : loadedRoute[1]) ?? {};
493
+ return loadedRoute?.[LoadedRouteProp.Params] ?? {};
722
494
  },
723
495
  get pathname() {
724
496
  return url.pathname;
@@ -747,7 +519,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
747
519
  check();
748
520
  headers.set(target, createCacheControl(cacheControl));
749
521
  },
750
- resolveValue: async (loaderOrAction) => {
522
+ resolveValue: (async (loaderOrAction) => {
751
523
  const id = loaderOrAction.__id;
752
524
  if (loaderOrAction.__brand === "server_loader") {
753
525
  if (!(id in loaders)) {
@@ -755,9 +527,13 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
755
527
  "You can not get the returned data of a loader that has not been executed for this request."
756
528
  );
757
529
  }
530
+ if (loaders[id] === _UNINITIALIZED) {
531
+ const isDev = getRequestMode(requestEv) === "dev";
532
+ await getRouteLoaderPromise(loaderOrAction, loaders, requestEv, isDev);
533
+ }
758
534
  }
759
535
  return loaders[id];
760
- },
536
+ }),
761
537
  status: (statusCode) => {
762
538
  if (typeof statusCode === "number") {
763
539
  check();
@@ -774,31 +550,37 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
774
550
  },
775
551
  error: (statusCode, message) => {
776
552
  status = statusCode;
777
- return new ServerError(statusCode, message);
553
+ headers.delete("Cache-Control");
554
+ return new ServerError$1(statusCode, message);
778
555
  },
779
556
  redirect: (statusCode, url2) => {
780
557
  check();
781
558
  status = statusCode;
782
559
  if (url2) {
783
- const fixedURL = url2.replace(/([^:])\/{2,}/g, "$1/");
784
- if (url2 !== fixedURL) {
560
+ if (
561
+ // //test.com
562
+ /^\/\//.test(url2) || // /test//path
563
+ /([^:])\/\/+/.test(url2)
564
+ ) {
565
+ const fixedURL = url2.replace(/^\/\/+/, "/").replace(/([^:])\/\/+/g, "$1/");
785
566
  console.warn(`Redirect URL ${url2} is invalid, fixing to ${fixedURL}`);
567
+ url2 = fixedURL;
786
568
  }
787
- headers.set("Location", fixedURL);
569
+ headers.set("Location", url2);
788
570
  }
789
- if (statusCode > 301 && !headers.get("Cache-Control")) {
571
+ headers.delete("Cache-Control");
572
+ if (statusCode > 301) {
790
573
  headers.set("Cache-Control", "no-store");
791
574
  }
792
- exit();
793
- return new RedirectMessage();
575
+ return exit(new RedirectMessage$1());
794
576
  },
795
- rewrite: (pathname) => {
577
+ rewrite: (pathname2) => {
796
578
  check();
797
- if (pathname.startsWith("http")) {
579
+ if (pathname2.startsWith("http")) {
798
580
  throw new Error("Rewrite does not support absolute urls");
799
581
  }
800
582
  sharedMap.set(RequestEvIsRewrite, true);
801
- return new RewriteMessage(pathname.replace(/\/+/g, "/"));
583
+ return exit(new RewriteMessage$1(pathname2.replace(/\/+/g, "/")));
802
584
  },
803
585
  defer: (returnData) => {
804
586
  return typeof returnData === "function" ? returnData : () => returnData;
@@ -806,6 +588,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
806
588
  fail: (statusCode, data) => {
807
589
  check();
808
590
  status = statusCode;
591
+ headers.delete("Cache-Control");
809
592
  return {
810
593
  failed: true,
811
594
  ...data
@@ -823,7 +606,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
823
606
  if (requestData !== void 0) {
824
607
  return requestData;
825
608
  }
826
- return requestData = parseRequest(requestEv, sharedMap, qwikSerializer);
609
+ return requestData = parseRequest(requestEv, sharedMap);
827
610
  },
828
611
  json: (statusCode, data) => {
829
612
  headers.set("Content-Type", "application/json; charset=utf-8");
@@ -836,9 +619,12 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
836
619
  getWritableStream: () => {
837
620
  if (writableStream === null) {
838
621
  if (serverRequestEv.mode === "dev") {
839
- const serverTiming = sharedMap.get("@serverTiming");
622
+ const serverTiming = sharedMap.get(RequestEvShareServerTiming);
840
623
  if (serverTiming) {
841
- headers.set("Server-Timing", serverTiming.map((a) => `${a[0]};dur=${a[1]}`).join(","));
624
+ headers.set(
625
+ "Server-Timing",
626
+ serverTiming.map(([name, duration]) => `${name};dur=${duration}`).join(",")
627
+ );
842
628
  }
843
629
  }
844
630
  writableStream = serverRequestEv.getWritableStream(
@@ -852,13 +638,13 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
852
638
  return writableStream;
853
639
  }
854
640
  };
855
- return Object.freeze(requestEv);
641
+ return requestEv;
856
642
  }
857
643
  function getRequestLoaders(requestEv) {
858
644
  return requestEv[RequestEvLoaders];
859
645
  }
860
- function getRequestTrailingSlash(requestEv) {
861
- return requestEv[RequestEvTrailingSlash];
646
+ function getRequestLoaderSerializationStrategyMap(requestEv) {
647
+ return requestEv[RequestEvLoaderSerializationStrategyMap];
862
648
  }
863
649
  function getRequestRoute(requestEv) {
864
650
  return requestEv[RequestEvRoute];
@@ -866,10 +652,9 @@ function getRequestRoute(requestEv) {
866
652
  function getRequestMode(requestEv) {
867
653
  return requestEv[RequestEvMode];
868
654
  }
869
- var ABORT_INDEX = Number.MAX_SAFE_INTEGER;
870
- var parseRequest = async ({ request, method, query }, sharedMap, qwikSerializer) => {
871
- var _a;
872
- const type = ((_a = request.headers.get("content-type")) == null ? void 0 : _a.split(/[;,]/, 1)[0].trim()) ?? "";
655
+ const ABORT_INDEX = Number.MAX_SAFE_INTEGER;
656
+ const parseRequest = async ({ request, method, query }, sharedMap) => {
657
+ const type = getContentType(request.headers);
873
658
  if (type === "application/x-www-form-urlencoded" || type === "multipart/form-data") {
874
659
  const formData = await request.formData();
875
660
  sharedMap.set(RequestEvSharedActionFormData, formData);
@@ -882,34 +667,52 @@ var parseRequest = async ({ request, method, query }, sharedMap, qwikSerializer)
882
667
  const data = query.get(QDATA_KEY);
883
668
  if (data) {
884
669
  try {
885
- return qwikSerializer._deserialize(decodeURIComponent(data));
670
+ return _deserialize(decodeURIComponent(data));
886
671
  } catch {
887
672
  }
888
673
  }
889
674
  }
890
- return qwikSerializer._deserialize(await request.text());
675
+ return _deserialize(await request.text());
891
676
  }
892
677
  return void 0;
893
678
  };
894
- var formToObj = (formData) => {
895
- const values = [...formData.entries()].reduce((values2, [name, value]) => {
896
- name.split(".").reduce((object, key, index, keys) => {
679
+ const isDangerousKey = (k) => k === "__proto__" || k === "constructor" || k === "prototype";
680
+ const formToObj = (formData) => {
681
+ const values = /* @__PURE__ */ Object.create(null);
682
+ for (const [name, value] of formData) {
683
+ const keys = name.split(".");
684
+ let hasDangerousKey = false;
685
+ for (let i = 0; i < keys.length; i++) {
686
+ if (isDangerousKey(keys[i])) {
687
+ hasDangerousKey = true;
688
+ break;
689
+ }
690
+ }
691
+ if (hasDangerousKey) {
692
+ continue;
693
+ }
694
+ let object = values;
695
+ for (let i = 0; i < keys.length; i++) {
696
+ const key = keys[i];
897
697
  if (key.endsWith("[]")) {
898
698
  const arrayKey = key.slice(0, -2);
699
+ if (isDangerousKey(arrayKey)) {
700
+ break;
701
+ }
899
702
  object[arrayKey] = object[arrayKey] || [];
900
- return object[arrayKey] = [...object[arrayKey], value];
703
+ object[arrayKey].push(value);
704
+ break;
901
705
  }
902
- if (index < keys.length - 1) {
903
- return object[key] = object[key] || (Number.isNaN(+keys[index + 1]) ? {} : []);
706
+ if (i < keys.length - 1) {
707
+ object = object[key] = object[key] || (Number.isNaN(+keys[i + 1]) ? /* @__PURE__ */ Object.create(null) : []);
708
+ } else {
709
+ object[key] = value;
904
710
  }
905
- return object[key] = value;
906
- }, values2);
907
- return values2;
908
- }, {});
711
+ }
712
+ }
909
713
  return values;
910
714
  };
911
715
 
912
- // packages/qwik-router/src/middleware/request-handler/response-page.ts
913
716
  function getQwikRouterServerData(requestEv) {
914
717
  const { params, request, status, locale, originalUrl } = requestEv;
915
718
  const requestHeaders = {};
@@ -929,13 +732,15 @@ function getQwikRouterServerData(requestEv) {
929
732
  if (protocol) {
930
733
  reconstructedUrl.protocol = protocol;
931
734
  }
735
+ const loaders = getRequestLoaders(requestEv);
736
+ const loadersSerializationStrategy = getRequestLoaderSerializationStrategyMap(requestEv);
932
737
  return {
933
738
  url: reconstructedUrl.href,
934
739
  requestHeaders,
935
740
  locale: locale(),
936
741
  nonce,
937
742
  containerAttributes: {
938
- "q:route": routeName
743
+ [Q_ROUTE]: routeName
939
744
  },
940
745
  qwikrouter: {
941
746
  routeName,
@@ -944,7 +749,8 @@ function getQwikRouterServerData(requestEv) {
944
749
  loadedRoute: getRequestRoute(requestEv),
945
750
  response: {
946
751
  status: status(),
947
- loaders: getRequestLoaders(requestEv),
752
+ loaders,
753
+ loadersSerializationStrategy,
948
754
  action,
949
755
  formData
950
756
  }
@@ -952,12 +758,14 @@ function getQwikRouterServerData(requestEv) {
952
758
  };
953
759
  }
954
760
 
955
- // packages/qwik-router/src/middleware/request-handler/resolve-request-handlers.ts
956
- var resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler) => {
761
+ const resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler, isInternal) => {
957
762
  const routeLoaders = [];
958
763
  const routeActions = [];
959
764
  const requestHandlers = [];
960
- const isPageRoute = !!(route && isLastModulePageRoute(route[2]));
765
+ const isPageRoute = !!(route && isLastModulePageRoute(route[LoadedRouteProp.Mods]));
766
+ if (isInternal) {
767
+ requestHandlers.push(handleQDataRedirect);
768
+ }
961
769
  if (serverPlugins) {
962
770
  _resolveRequestHandlers(
963
771
  routeLoaders,
@@ -969,19 +777,7 @@ var resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderH
969
777
  );
970
778
  }
971
779
  if (route) {
972
- const routeName = route[0];
973
- if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
974
- requestHandlers.unshift(csrfCheckMiddleware);
975
- }
976
- if (isPageRoute) {
977
- if (method === "POST" || method === "GET") {
978
- requestHandlers.push(pureServerFunction);
979
- }
980
- requestHandlers.push(fixTrailingSlash);
981
- requestHandlers.push(renderQData);
982
- }
983
- const routeModules = route[2];
984
- requestHandlers.push(handleRedirect);
780
+ const routeModules = route[LoadedRouteProp.Mods];
985
781
  _resolveRequestHandlers(
986
782
  routeLoaders,
987
783
  routeActions,
@@ -990,17 +786,35 @@ var resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderH
990
786
  isPageRoute,
991
787
  method
992
788
  );
789
+ const routeName = route[LoadedRouteProp.RouteName];
790
+ if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
791
+ if (checkOrigin === "lax-proto") {
792
+ requestHandlers.unshift(csrfLaxProtoCheckMiddleware);
793
+ } else {
794
+ requestHandlers.unshift(csrfCheckMiddleware);
795
+ }
796
+ }
797
+ if (isPageRoute) {
798
+ if (method === "POST" || method === "GET") {
799
+ requestHandlers.push(runServerFunction);
800
+ }
801
+ requestHandlers.push(fixTrailingSlash);
802
+ if (isInternal) {
803
+ requestHandlers.push(renderQData);
804
+ }
805
+ }
993
806
  if (isPageRoute) {
994
807
  requestHandlers.push((ev) => {
995
808
  ev.sharedMap.set(RequestRouteName, routeName);
996
809
  });
997
- requestHandlers.push(actionsMiddleware(routeActions, routeLoaders));
810
+ requestHandlers.push(actionsMiddleware(routeActions));
811
+ requestHandlers.push(loadersMiddleware(routeLoaders));
998
812
  requestHandlers.push(renderHandler);
999
813
  }
1000
814
  }
1001
815
  return requestHandlers;
1002
816
  };
1003
- var _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, routeModules, collectActions, method) => {
817
+ const _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, routeModules, collectActions, method) => {
1004
818
  for (const routeModule of routeModules) {
1005
819
  if (typeof routeModule.onRequest === "function") {
1006
820
  requestHandlers.push(routeModule.onRequest);
@@ -1056,8 +870,9 @@ var _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, rout
1056
870
  }
1057
871
  }
1058
872
  };
1059
- function actionsMiddleware(routeActions, routeLoaders) {
1060
- return async (requestEv) => {
873
+ function actionsMiddleware(routeActions) {
874
+ return async (requestEvent) => {
875
+ const requestEv = requestEvent;
1061
876
  if (requestEv.headersSent) {
1062
877
  requestEv.exit();
1063
878
  return;
@@ -1065,7 +880,6 @@ function actionsMiddleware(routeActions, routeLoaders) {
1065
880
  const { method } = requestEv;
1066
881
  const loaders = getRequestLoaders(requestEv);
1067
882
  const isDev = getRequestMode(requestEv) === "dev";
1068
- const qwikSerializer = requestEv[RequestEvQwikSerializer];
1069
883
  if (isDev && method === "GET") {
1070
884
  if (requestEv.query.has(QACTION_KEY)) {
1071
885
  console.warn(
@@ -1077,7 +891,7 @@ function actionsMiddleware(routeActions, routeLoaders) {
1077
891
  const selectedActionId = requestEv.query.get(QACTION_KEY);
1078
892
  if (selectedActionId) {
1079
893
  const serverActionsMap = globalThis._qwikActionsMap;
1080
- const action = routeActions.find((action2) => action2.__id === selectedActionId) ?? (serverActionsMap == null ? void 0 : serverActionsMap.get(selectedActionId));
894
+ const action = routeActions.find((action2) => action2.__id === selectedActionId) ?? serverActionsMap?.get(selectedActionId);
1081
895
  if (action) {
1082
896
  requestEv.sharedMap.set(RequestEvSharedActionId, selectedActionId);
1083
897
  const data = await requestEv.parseBody();
@@ -1092,57 +906,73 @@ function actionsMiddleware(routeActions, routeLoaders) {
1092
906
  } else {
1093
907
  const actionResolved = isDev ? await measure(
1094
908
  requestEv,
1095
- action.__qrl.getSymbol().split("_", 1)[0],
909
+ action.__qrl.getHash(),
1096
910
  () => action.__qrl.call(requestEv, result.data, requestEv)
1097
911
  ) : await action.__qrl.call(requestEv, result.data, requestEv);
1098
912
  if (isDev) {
1099
- verifySerializable(qwikSerializer, actionResolved, action.__qrl);
913
+ verifySerializable(actionResolved, action.__qrl);
1100
914
  }
1101
915
  loaders[selectedActionId] = actionResolved;
1102
916
  }
1103
917
  }
1104
918
  }
1105
919
  }
920
+ };
921
+ }
922
+ function loadersMiddleware(routeLoaders) {
923
+ return async (requestEvent) => {
924
+ const requestEv = requestEvent;
925
+ if (requestEv.headersSent) {
926
+ requestEv.exit();
927
+ return;
928
+ }
929
+ const loaders = getRequestLoaders(requestEv);
930
+ const isDev = getRequestMode(requestEv) === "dev";
1106
931
  if (routeLoaders.length > 0) {
1107
- const resolvedLoadersPromises = routeLoaders.map((loader) => {
1108
- const loaderId = loader.__id;
1109
- loaders[loaderId] = runValidators(
1110
- requestEv,
1111
- loader.__validators,
1112
- void 0,
1113
- // data
1114
- isDev
1115
- ).then((res) => {
1116
- if (res.success) {
1117
- if (isDev) {
1118
- return measure(
1119
- requestEv,
1120
- loader.__qrl.getSymbol().split("_", 1)[0],
1121
- () => loader.__qrl.call(requestEv, requestEv)
1122
- );
1123
- } else {
1124
- return loader.__qrl.call(requestEv, requestEv);
1125
- }
1126
- } else {
1127
- return requestEv.fail(res.status ?? 500, res.error);
1128
- }
1129
- }).then((resolvedLoader) => {
1130
- if (typeof resolvedLoader === "function") {
1131
- loaders[loaderId] = resolvedLoader();
1132
- } else {
1133
- if (isDev) {
1134
- verifySerializable(qwikSerializer, resolvedLoader, loader.__qrl);
1135
- }
1136
- loaders[loaderId] = resolvedLoader;
1137
- }
1138
- return resolvedLoader;
1139
- });
1140
- return loaders[loaderId];
1141
- });
932
+ const resolvedLoadersPromises = routeLoaders.map(
933
+ (loader) => getRouteLoaderPromise(loader, loaders, requestEv, isDev)
934
+ );
1142
935
  await Promise.all(resolvedLoadersPromises);
1143
936
  }
1144
937
  };
1145
938
  }
939
+ async function getRouteLoaderPromise(loader, loaders, requestEv, isDev) {
940
+ const loaderId = loader.__id;
941
+ loaders[loaderId] = runValidators(
942
+ requestEv,
943
+ loader.__validators,
944
+ void 0,
945
+ // data
946
+ isDev
947
+ ).then((res) => {
948
+ if (res.success) {
949
+ if (isDev) {
950
+ return measure(
951
+ requestEv,
952
+ loader.__qrl.getHash(),
953
+ () => loader.__qrl.call(requestEv, requestEv)
954
+ );
955
+ } else {
956
+ return loader.__qrl.call(requestEv, requestEv);
957
+ }
958
+ } else {
959
+ return requestEv.fail(res.status ?? 500, res.error);
960
+ }
961
+ }).then((resolvedLoader) => {
962
+ if (typeof resolvedLoader === "function") {
963
+ loaders[loaderId] = resolvedLoader();
964
+ } else {
965
+ if (isDev) {
966
+ verifySerializable(resolvedLoader, loader.__qrl);
967
+ }
968
+ loaders[loaderId] = resolvedLoader;
969
+ }
970
+ return resolvedLoader;
971
+ });
972
+ const loadersSerializationStrategy = getRequestLoaderSerializationStrategyMap(requestEv);
973
+ loadersSerializationStrategy.set(loaderId, loader.__serializationStrategy);
974
+ return loaders[loaderId];
975
+ }
1146
976
  async function runValidators(requestEv, validators, data, isDev) {
1147
977
  let lastResult = {
1148
978
  success: true,
@@ -1171,84 +1001,88 @@ async function runValidators(requestEv, validators, data, isDev) {
1171
1001
  function isAsyncIterator(obj) {
1172
1002
  return obj ? typeof obj === "object" && Symbol.asyncIterator in obj : false;
1173
1003
  }
1174
- async function pureServerFunction(ev) {
1175
- const fn = ev.query.get(QFN_KEY);
1176
- if (fn && ev.request.headers.get("X-QRL") === fn && ev.request.headers.get("Content-Type") === "application/qwik-json") {
1004
+ async function runServerFunction(ev) {
1005
+ const serverFnHash = ev.query.get(QFN_KEY);
1006
+ if (serverFnHash && ev.request.headers.get("X-QRL") === serverFnHash && ev.request.headers.get("Content-Type") === "application/qwik-json") {
1177
1007
  ev.exit();
1178
1008
  const isDev = getRequestMode(ev) === "dev";
1179
- const qwikSerializer = ev[RequestEvQwikSerializer];
1180
1009
  const data = await ev.parseBody();
1181
1010
  if (Array.isArray(data)) {
1182
- const [qrl, ...args] = data;
1183
- if (isQrl(qrl) && qrl.getHash() === fn) {
1184
- let result;
1185
- try {
1011
+ const qrl = inlinedQrl(null, serverFnHash, data[1]);
1012
+ let result;
1013
+ try {
1014
+ if (isDev) {
1015
+ result = await measure(
1016
+ ev,
1017
+ `server_${serverFnHash}`,
1018
+ () => qrl.apply(ev, data[0])
1019
+ );
1020
+ } else {
1021
+ result = await qrl.apply(ev, data[0]);
1022
+ }
1023
+ } catch (err) {
1024
+ if (err instanceof ServerError$1) {
1025
+ throw ev.error(err.status, err.data);
1026
+ }
1027
+ console.error(`Server function ${serverFnHash} failed:`, err);
1028
+ throw ev.error(500, "Invalid request");
1029
+ }
1030
+ if (isAsyncIterator(result)) {
1031
+ ev.headers.set("Content-Type", "text/qwik-json-stream");
1032
+ const writable = ev.getWritableStream();
1033
+ const stream = writable.getWriter();
1034
+ for await (const item of result) {
1186
1035
  if (isDev) {
1187
- result = await measure(
1188
- ev,
1189
- `server_${qrl.getSymbol()}`,
1190
- () => qrl.apply(ev, args)
1191
- );
1192
- } else {
1193
- result = await qrl.apply(ev, args);
1036
+ verifySerializable(item, qrl);
1194
1037
  }
1195
- } catch (err) {
1196
- if (err instanceof ServerError) {
1197
- throw ev.error(err.status, err.data);
1038
+ const message = await _serialize([item]);
1039
+ if (ev.signal.aborted) {
1040
+ break;
1198
1041
  }
1199
- throw ev.error(500, "Invalid request");
1200
- }
1201
- if (isAsyncIterator(result)) {
1202
- ev.headers.set("Content-Type", "text/qwik-json-stream");
1203
- const writable = ev.getWritableStream();
1204
- const stream = writable.getWriter();
1205
- for await (const item of result) {
1206
- if (isDev) {
1207
- verifySerializable(qwikSerializer, item, qrl);
1208
- }
1209
- const message = await qwikSerializer._serialize([item]);
1210
- if (ev.signal.aborted) {
1211
- break;
1212
- }
1213
- await stream.write(encoder.encode(`${message}
1042
+ await stream.write(encoder.encode(`${message}
1214
1043
  `));
1215
- }
1216
- stream.close();
1217
- } else {
1218
- verifySerializable(qwikSerializer, result, qrl);
1219
- ev.headers.set("Content-Type", "application/qwik-json");
1220
- const message = await qwikSerializer._serialize([result]);
1221
- ev.send(200, message);
1222
1044
  }
1223
- return;
1045
+ stream.close();
1046
+ } else {
1047
+ verifySerializable(result, qrl);
1048
+ ev.headers.set("Content-Type", "application/qwik-json");
1049
+ const message = await _serialize([result]);
1050
+ ev.send(200, message);
1224
1051
  }
1052
+ return;
1225
1053
  }
1226
1054
  throw ev.error(500, "Invalid request");
1227
1055
  }
1228
1056
  }
1229
1057
  function fixTrailingSlash(ev) {
1230
- const trailingSlash = getRequestTrailingSlash(ev);
1231
1058
  const { basePathname, originalUrl, sharedMap } = ev;
1232
1059
  const { pathname, search } = originalUrl;
1233
1060
  const isQData = sharedMap.has(IsQData);
1061
+ if (
1062
+ // all valid pathnames must start with a single slash
1063
+ !pathname.startsWith("/") || // protocol-relative URLs are not allowed like: //test.com, ///bad.com
1064
+ pathname.startsWith("//")
1065
+ ) {
1066
+ return;
1067
+ }
1234
1068
  if (!isQData && pathname !== basePathname && !pathname.endsWith(".html")) {
1235
- if (trailingSlash) {
1069
+ if (!globalThis.__NO_TRAILING_SLASH__) {
1236
1070
  if (!pathname.endsWith("/")) {
1237
- throw ev.redirect(301 /* MovedPermanently */, pathname + "/" + search);
1071
+ throw ev.redirect(HttpStatus.MovedPermanently, pathname + "/" + search);
1238
1072
  }
1239
1073
  } else {
1240
1074
  if (pathname.endsWith("/")) {
1241
1075
  throw ev.redirect(
1242
- 301 /* MovedPermanently */,
1076
+ HttpStatus.MovedPermanently,
1243
1077
  pathname.slice(0, pathname.length - 1) + search
1244
1078
  );
1245
1079
  }
1246
1080
  }
1247
1081
  }
1248
1082
  }
1249
- function verifySerializable(qwikSerializer, data, qrl) {
1083
+ function verifySerializable(data, qrl) {
1250
1084
  try {
1251
- qwikSerializer._verifySerializable(data, void 0);
1085
+ _verifySerializable(data, void 0);
1252
1086
  } catch (e) {
1253
1087
  if (e instanceof Error && qrl.dev) {
1254
1088
  e.loc = qrl.dev;
@@ -1256,19 +1090,16 @@ function verifySerializable(qwikSerializer, data, qrl) {
1256
1090
  throw e;
1257
1091
  }
1258
1092
  }
1259
- var isQrl = (value) => {
1260
- return typeof value === "function" && typeof value.getSymbol === "function";
1261
- };
1262
1093
  function isLastModulePageRoute(routeModules) {
1263
1094
  const lastRouteModule = routeModules[routeModules.length - 1];
1264
1095
  return lastRouteModule && typeof lastRouteModule.default === "function";
1265
1096
  }
1266
- function getPathname(url, trailingSlash) {
1097
+ function getPathname(url) {
1267
1098
  url = new URL(url);
1268
1099
  if (url.pathname.endsWith(QDATA_JSON)) {
1269
1100
  url.pathname = url.pathname.slice(0, -QDATA_JSON.length);
1270
1101
  }
1271
- if (trailingSlash) {
1102
+ if (!globalThis.__NO_TRAILING_SLASH__) {
1272
1103
  if (!url.pathname.endsWith("/")) {
1273
1104
  url.pathname += "/";
1274
1105
  }
@@ -1277,21 +1108,31 @@ function getPathname(url, trailingSlash) {
1277
1108
  url.pathname = url.pathname.slice(0, -1);
1278
1109
  }
1279
1110
  }
1280
- const search = url.search.slice(1).replaceAll(/&?q(action|data|func)=[^&]+/g, "");
1111
+ const search = url.search.slice(1).replaceAll(/&?q(action|data|func|loaders)=[^&]+/g, "");
1281
1112
  return `${url.pathname}${search ? `?${search}` : ""}${url.hash}`;
1282
1113
  }
1283
- var encoder = /* @__PURE__ */ new TextEncoder();
1114
+ const encoder = /* @__PURE__ */ new TextEncoder();
1115
+ function csrfLaxProtoCheckMiddleware(requestEv) {
1116
+ checkCSRF(requestEv, "lax-proto");
1117
+ }
1284
1118
  function csrfCheckMiddleware(requestEv) {
1285
- const isForm = isContentType(
1119
+ checkCSRF(requestEv);
1120
+ }
1121
+ function checkCSRF(requestEv, laxProto) {
1122
+ const contentType = requestEv.request.headers.get("content-type");
1123
+ const isSimpleRequest = !contentType || isContentType(
1286
1124
  requestEv.request.headers,
1287
1125
  "application/x-www-form-urlencoded",
1288
1126
  "multipart/form-data",
1289
1127
  "text/plain"
1290
1128
  );
1291
- if (isForm) {
1129
+ if (isSimpleRequest) {
1292
1130
  const inputOrigin = requestEv.request.headers.get("origin");
1293
1131
  const origin = requestEv.url.origin;
1294
- const forbidden = inputOrigin !== origin;
1132
+ let forbidden = inputOrigin !== origin;
1133
+ if (forbidden && laxProto && inputOrigin?.replace(/^http(s)?/g, "") === origin.replace(/^http(s)?/g, "")) {
1134
+ forbidden = false;
1135
+ }
1295
1136
  if (forbidden) {
1296
1137
  throw requestEv.error(
1297
1138
  403,
@@ -1310,13 +1151,11 @@ function renderQwikMiddleware(render) {
1310
1151
  if (isPageDataReq) {
1311
1152
  return;
1312
1153
  }
1313
- const requestHeaders = {};
1314
- requestEv.request.headers.forEach((value, key) => requestHeaders[key] = value);
1154
+ requestEv.request.headers.forEach((value, key) => value);
1315
1155
  const responseHeaders = requestEv.headers;
1316
1156
  if (!responseHeaders.has("Content-Type")) {
1317
1157
  responseHeaders.set("Content-Type", "text/html; charset=utf-8");
1318
1158
  }
1319
- const trailingSlash = getRequestTrailingSlash(requestEv);
1320
1159
  const { readable, writable } = new TextEncoderStream();
1321
1160
  const writableStream = requestEv.getWritableStream();
1322
1161
  const pipe = readable.pipeTo(writableStream, { preventClose: true });
@@ -1338,12 +1177,12 @@ function renderQwikMiddleware(render) {
1338
1177
  loaders: getRequestLoaders(requestEv),
1339
1178
  action: requestEv.sharedMap.get(RequestEvSharedActionId),
1340
1179
  status: status !== 200 ? status : 200,
1341
- href: getPathname(requestEv.url, trailingSlash)
1180
+ href: getPathname(requestEv.url)
1342
1181
  };
1343
1182
  if (typeof result.html === "string") {
1344
1183
  await stream.write(result.html);
1345
1184
  }
1346
- requestEv.sharedMap.set("qData", qData);
1185
+ requestEv.sharedMap.set(RequestEvShareQData, qData);
1347
1186
  } finally {
1348
1187
  await stream.ready;
1349
1188
  await stream.close();
@@ -1352,15 +1191,11 @@ function renderQwikMiddleware(render) {
1352
1191
  await writableStream.close();
1353
1192
  };
1354
1193
  }
1355
- async function handleRedirect(requestEv) {
1356
- const isPageDataReq = requestEv.sharedMap.has(IsQData);
1357
- if (!isPageDataReq) {
1358
- return;
1359
- }
1194
+ async function handleQDataRedirect(requestEv) {
1360
1195
  try {
1361
1196
  await requestEv.next();
1362
1197
  } catch (err) {
1363
- if (!(err instanceof RedirectMessage)) {
1198
+ if (!(err instanceof RedirectMessage$1)) {
1364
1199
  throw err;
1365
1200
  }
1366
1201
  }
@@ -1383,41 +1218,52 @@ async function handleRedirect(requestEv) {
1383
1218
  }
1384
1219
  }
1385
1220
  async function renderQData(requestEv) {
1386
- const isPageDataReq = requestEv.sharedMap.has(IsQData);
1387
- if (!isPageDataReq) {
1388
- return;
1389
- }
1390
1221
  await requestEv.next();
1391
1222
  if (requestEv.headersSent || requestEv.exited) {
1392
1223
  return;
1393
1224
  }
1394
1225
  const status = requestEv.status();
1395
1226
  const redirectLocation = requestEv.headers.get("Location");
1396
- const trailingSlash = getRequestTrailingSlash(requestEv);
1397
- const requestHeaders = {};
1398
- requestEv.request.headers.forEach((value, key) => requestHeaders[key] = value);
1227
+ requestEv.request.headers.forEach((value, key) => value);
1399
1228
  requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
1400
- const qData = {
1401
- loaders: getRequestLoaders(requestEv),
1229
+ let loaders = getRequestLoaders(requestEv);
1230
+ const selectedLoaderIds = requestEv.query.getAll(QLOADER_KEY);
1231
+ const hasCustomLoaders = selectedLoaderIds.length > 0;
1232
+ if (hasCustomLoaders) {
1233
+ const selectedLoaders = {};
1234
+ for (const loaderId of selectedLoaderIds) {
1235
+ const loader = loaders[loaderId];
1236
+ selectedLoaders[loaderId] = loader;
1237
+ }
1238
+ loaders = selectedLoaders;
1239
+ }
1240
+ const qData = hasCustomLoaders ? {
1241
+ // send minimal data to the client
1242
+ loaders,
1243
+ status: status !== 200 ? status : 200,
1244
+ href: getPathname(requestEv.url)
1245
+ } : {
1246
+ loaders,
1402
1247
  action: requestEv.sharedMap.get(RequestEvSharedActionId),
1403
1248
  status: status !== 200 ? status : 200,
1404
- href: getPathname(requestEv.url, trailingSlash),
1249
+ href: getPathname(requestEv.url),
1405
1250
  redirect: redirectLocation ?? void 0,
1406
1251
  isRewrite: requestEv.sharedMap.get(RequestEvIsRewrite)
1407
1252
  };
1408
1253
  const writer = requestEv.getWritableStream().getWriter();
1409
- const qwikSerializer = requestEv[RequestEvQwikSerializer];
1410
- const data = await qwikSerializer._serialize([qData]);
1254
+ const data = await _serialize([qData]);
1411
1255
  writer.write(encoder.encode(data));
1412
- requestEv.sharedMap.set("qData", qData);
1256
+ requestEv.sharedMap.set(RequestEvShareQData, qData);
1413
1257
  writer.close();
1414
1258
  }
1415
1259
  function makeQDataPath(href) {
1416
1260
  if (href.startsWith("/")) {
1417
- const append = QDATA_JSON;
1418
- const url = new URL(href, "http://localhost");
1419
- const pathname = url.pathname.endsWith("/") ? url.pathname.slice(0, -1) : url.pathname;
1420
- return pathname + (append.startsWith("/") ? "" : "/") + append + url.search;
1261
+ if (!href.includes(QDATA_JSON)) {
1262
+ const url = new URL(href, "http://localhost");
1263
+ const pathname = url.pathname.endsWith("/") ? url.pathname.slice(0, -1) : url.pathname;
1264
+ return pathname + QDATA_JSON + url.search;
1265
+ }
1266
+ return href;
1421
1267
  } else {
1422
1268
  return void 0;
1423
1269
  }
@@ -1431,44 +1277,73 @@ async function measure(requestEv, name, fn) {
1431
1277
  return await fn();
1432
1278
  } finally {
1433
1279
  const duration = now() - start;
1434
- let measurements = requestEv.sharedMap.get("@serverTiming");
1280
+ let measurements = requestEv.sharedMap.get(RequestEvShareServerTiming);
1435
1281
  if (!measurements) {
1436
- requestEv.sharedMap.set("@serverTiming", measurements = []);
1282
+ requestEv.sharedMap.set(RequestEvShareServerTiming, measurements = []);
1437
1283
  }
1438
1284
  measurements.push([name, duration]);
1439
1285
  }
1440
1286
  }
1287
+ function getContentType(headers) {
1288
+ return (headers.get("content-type")?.split(/[;,]/, 1)[0].trim() ?? "").toLowerCase();
1289
+ }
1441
1290
  function isContentType(headers, ...types) {
1442
- var _a;
1443
- const type = ((_a = headers.get("content-type")) == null ? void 0 : _a.split(/;/, 1)[0].trim()) ?? "";
1444
- return types.includes(type);
1291
+ const type = getContentType(headers);
1292
+ for (let i = 0; i < types.length; i++) {
1293
+ if (types[i].toLowerCase() === type) {
1294
+ return true;
1295
+ }
1296
+ }
1297
+ return false;
1445
1298
  }
1446
1299
 
1447
- // packages/qwik-router/src/middleware/request-handler/request-handler.ts
1448
- async function requestHandler(serverRequestEv, opts, qwikSerializer) {
1449
- const { render, qwikRouterConfig, checkOrigin } = opts;
1300
+ let _asyncRequestStore;
1301
+ if (isServer) {
1302
+ import('node:async_hooks').then((module) => {
1303
+ _asyncRequestStore = new module.AsyncLocalStorage();
1304
+ }).catch((err) => {
1305
+ console.warn(
1306
+ "\n=====================\n Qwik Router Warning:\n AsyncLocalStorage is not available, continuing without it.\n This impacts concurrent async server calls, where they lose access to the ServerRequestEv object.\n=====================\n\n",
1307
+ err
1308
+ );
1309
+ });
1310
+ }
1311
+ let qwikRouterConfigActual;
1312
+ async function requestHandler(serverRequestEv, opts) {
1313
+ const { render, checkOrigin } = opts;
1314
+ let { qwikRouterConfig } = opts;
1315
+ if (!qwikRouterConfig) {
1316
+ if (!qwikRouterConfigActual) {
1317
+ qwikRouterConfigActual = await import('@qwik-router-config');
1318
+ }
1319
+ qwikRouterConfig = qwikRouterConfigActual;
1320
+ }
1450
1321
  if (!qwikRouterConfig) {
1451
1322
  throw new Error("qwikRouterConfig is required.");
1452
1323
  }
1453
- const pathname = serverRequestEv.url.pathname;
1454
- const matchPathname = getRouteMatchPathname(pathname, qwikRouterConfig.trailingSlash);
1324
+ const { pathname, isInternal } = getRouteMatchPathname(serverRequestEv.url.pathname);
1325
+ if (pathname === "/.well-known" || pathname.startsWith("/.well-known/")) {
1326
+ return null;
1327
+ }
1455
1328
  const routeAndHandlers = await loadRequestHandlers(
1456
1329
  qwikRouterConfig,
1457
- matchPathname,
1330
+ pathname,
1458
1331
  serverRequestEv.request.method,
1459
1332
  checkOrigin ?? true,
1460
- render
1333
+ render,
1334
+ isInternal
1461
1335
  );
1462
1336
  if (routeAndHandlers) {
1463
1337
  const [route, requestHandlers] = routeAndHandlers;
1464
1338
  const rebuildRouteInfo = async (url) => {
1465
- const matchPathname2 = getRouteMatchPathname(url.pathname, qwikRouterConfig.trailingSlash);
1339
+ const { pathname: pathname2 } = getRouteMatchPathname(url.pathname);
1466
1340
  const routeAndHandlers2 = await loadRequestHandlers(
1467
1341
  qwikRouterConfig,
1468
- matchPathname2,
1342
+ pathname2,
1469
1343
  serverRequestEv.request.method,
1470
1344
  checkOrigin ?? true,
1471
- render
1345
+ render,
1346
+ isInternal
1472
1347
  );
1473
1348
  if (routeAndHandlers2) {
1474
1349
  const [loadedRoute, requestHandlers2] = routeAndHandlers2;
@@ -1482,22 +1357,21 @@ async function requestHandler(serverRequestEv, opts, qwikSerializer) {
1482
1357
  route,
1483
1358
  requestHandlers,
1484
1359
  rebuildRouteInfo,
1485
- qwikRouterConfig.trailingSlash,
1486
- qwikRouterConfig.basePathname,
1487
- qwikSerializer
1360
+ qwikRouterConfig.basePathname
1488
1361
  );
1489
1362
  }
1490
1363
  return null;
1491
1364
  }
1492
- async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrigin, renderFn) {
1365
+ async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrigin, renderFn, isInternal) {
1493
1366
  const { routes, serverPlugins, menus, cacheModules } = qwikRouterConfig;
1494
- const route = await loadRoute(routes, menus, cacheModules, pathname);
1367
+ const route = await loadRoute(routes, menus, cacheModules, pathname, isInternal);
1495
1368
  const requestHandlers = resolveRequestHandlers(
1496
1369
  serverPlugins,
1497
1370
  route,
1498
1371
  method,
1499
1372
  checkOrigin,
1500
- renderQwikMiddleware(renderFn)
1373
+ renderQwikMiddleware(renderFn),
1374
+ isInternal
1501
1375
  );
1502
1376
  if (requestHandlers.length > 0) {
1503
1377
  return [route, requestHandlers];
@@ -1505,8 +1379,67 @@ async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrig
1505
1379
  return null;
1506
1380
  }
1507
1381
 
1508
- // packages/qwik-router/src/middleware/request-handler/polyfill.ts
1509
- var _TextEncoderStream_polyfill = class {
1382
+ const notFounds = [
1383
+ // Will be replaced in post-build with the 404s generated by SSG
1384
+ "__QWIK_ROUTER_NOT_FOUND_ARRAY__"
1385
+ ];
1386
+ function getNotFound(prefix) {
1387
+ for (const [path, html] of notFounds) {
1388
+ if (prefix.startsWith(path)) {
1389
+ return html;
1390
+ }
1391
+ }
1392
+ return minimalHtmlResponse(404, "Resource Not Found");
1393
+ }
1394
+
1395
+ const staticPaths = /* @__PURE__ */ new Set(["__QWIK_ROUTER_STATIC_PATHS_ARRAY__"]);
1396
+ function isStaticPath(method, url) {
1397
+ if (method.toUpperCase() !== "GET") {
1398
+ return false;
1399
+ }
1400
+ const p = url.pathname;
1401
+ if (p.startsWith("/" + (globalThis.__QWIK_BUILD_DIR__ || "build") + "/")) {
1402
+ return true;
1403
+ }
1404
+ if (p.startsWith("/" + (globalThis.__QWIK_ASSETS_DIR__ || "assets") + "/")) {
1405
+ return true;
1406
+ }
1407
+ if (staticPaths.has(p)) {
1408
+ return true;
1409
+ }
1410
+ if (p.endsWith("/q-data.json")) {
1411
+ const pWithoutQdata = p.replace(/\/q-data.json$/, "");
1412
+ if (staticPaths.has(pWithoutQdata + "/")) {
1413
+ return true;
1414
+ }
1415
+ if (staticPaths.has(pWithoutQdata)) {
1416
+ return true;
1417
+ }
1418
+ }
1419
+ return false;
1420
+ }
1421
+
1422
+ class ServerError extends Error {
1423
+ constructor(status, data) {
1424
+ super(typeof data === "string" ? data : void 0);
1425
+ this.status = status;
1426
+ this.data = data;
1427
+ }
1428
+ }
1429
+
1430
+ class AbortMessage {
1431
+ }
1432
+ class RedirectMessage extends AbortMessage {
1433
+ }
1434
+
1435
+ class RewriteMessage extends AbortMessage {
1436
+ constructor(pathname) {
1437
+ super();
1438
+ this.pathname = pathname;
1439
+ }
1440
+ }
1441
+
1442
+ class _TextEncoderStream_polyfill {
1510
1443
  #pendingHighSurrogate = null;
1511
1444
  #handle = new TextEncoder();
1512
1445
  #transform = new TransformStream({
@@ -1523,14 +1456,14 @@ var _TextEncoderStream_polyfill = class {
1523
1456
  finalChunk += highSurrogate + item;
1524
1457
  continue;
1525
1458
  }
1526
- finalChunk += "\uFFFD";
1459
+ finalChunk += "";
1527
1460
  }
1528
1461
  if (55296 <= codeUnit && codeUnit <= 56319) {
1529
1462
  this.#pendingHighSurrogate = item;
1530
1463
  continue;
1531
1464
  }
1532
1465
  if (56320 <= codeUnit && codeUnit <= 57343) {
1533
- finalChunk += "\uFFFD";
1466
+ finalChunk += "";
1534
1467
  continue;
1535
1468
  }
1536
1469
  finalChunk += item;
@@ -1557,14 +1490,6 @@ var _TextEncoderStream_polyfill = class {
1557
1490
  get [Symbol.toStringTag]() {
1558
1491
  return "TextEncoderStream";
1559
1492
  }
1560
- };
1561
- export {
1562
- AbortMessage,
1563
- RedirectMessage,
1564
- RewriteMessage,
1565
- ServerError,
1566
- _TextEncoderStream_polyfill,
1567
- getErrorHtml,
1568
- mergeHeadersCookies,
1569
- requestHandler
1570
- };
1493
+ }
1494
+
1495
+ export { AbortMessage, RedirectMessage, RequestEvShareQData, RewriteMessage, ServerError, _TextEncoderStream_polyfill, _asyncRequestStore, getErrorHtml, getNotFound, isStaticPath, mergeHeadersCookies, requestHandler };