@qwik.dev/router 2.0.0-beta.4 → 2.0.0-beta.40

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 (87) 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 +44 -58
  4. package/lib/adapters/bun-server/vite/index.d.ts +2 -2
  5. package/lib/adapters/bun-server/vite/index.mjs +16 -23
  6. package/lib/adapters/cloud-run/vite/index.d.ts +2 -2
  7. package/lib/adapters/cloud-run/vite/index.mjs +15 -20
  8. package/lib/adapters/cloudflare-pages/vite/index.d.ts +2 -2
  9. package/lib/adapters/cloudflare-pages/vite/index.mjs +45 -77
  10. package/lib/adapters/deno-server/vite/index.d.ts +2 -2
  11. package/lib/adapters/deno-server/vite/index.mjs +25 -35
  12. package/lib/adapters/netlify-edge/vite/index.d.ts +2 -2
  13. package/lib/adapters/netlify-edge/vite/index.mjs +49 -89
  14. package/lib/adapters/node-server/vite/index.d.ts +2 -2
  15. package/lib/adapters/node-server/vite/index.mjs +16 -23
  16. package/lib/adapters/shared/vite/index.d.ts +9 -22
  17. package/lib/adapters/shared/vite/index.mjs +273 -333
  18. package/lib/adapters/ssg/vite/index.d.ts +13 -0
  19. package/lib/adapters/ssg/vite/index.mjs +13 -0
  20. package/lib/adapters/vercel-edge/vite/index.d.ts +3 -3
  21. package/lib/adapters/vercel-edge/vite/index.mjs +73 -80
  22. package/lib/chunks/dev-preloaded-route-loader.mjs +2 -0
  23. package/lib/chunks/format.mjs +24 -0
  24. package/lib/chunks/fs.mjs +133 -0
  25. package/lib/chunks/head.qwik.mjs +1217 -0
  26. package/lib/chunks/http-error.qwik.mjs +27 -0
  27. package/lib/chunks/pathname.mjs +57 -0
  28. package/lib/chunks/request-body-limit.mjs +27 -0
  29. package/lib/chunks/request-path.mjs +49 -0
  30. package/lib/chunks/routes.mjs +26 -0
  31. package/lib/chunks/server-error.mjs +16 -0
  32. package/lib/chunks/system.mjs +265 -0
  33. package/lib/chunks/url.mjs +59 -0
  34. package/lib/chunks/user-response.mjs +1707 -0
  35. package/lib/chunks/worker-thread.mjs +264 -0
  36. package/lib/index.d.ts +626 -170
  37. package/lib/index.qwik.mjs +1649 -1964
  38. package/lib/middleware/aws-lambda/index.d.ts +15 -16
  39. package/lib/middleware/aws-lambda/index.mjs +45 -54
  40. package/lib/middleware/azure-swa/index.mjs +85 -295
  41. package/lib/middleware/bun/index.d.ts +20 -5
  42. package/lib/middleware/bun/index.mjs +119 -205
  43. package/lib/middleware/cloudflare-pages/index.mjs +83 -105
  44. package/lib/middleware/deno/index.d.ts +22 -5
  45. package/lib/middleware/deno/index.mjs +105 -192
  46. package/lib/middleware/firebase/index.mjs +22 -35
  47. package/lib/middleware/netlify-edge/index.mjs +63 -81
  48. package/lib/middleware/node/index.d.ts +17 -5
  49. package/lib/middleware/node/index.mjs +299 -273
  50. package/lib/middleware/request-handler/index.d.ts +206 -99
  51. package/lib/middleware/request-handler/index.mjs +117 -1648
  52. package/lib/middleware/vercel-edge/index.mjs +76 -101
  53. package/lib/modules.d.ts +11 -16
  54. package/lib/service-worker/index.mjs +13 -0
  55. package/lib/{static → ssg}/index.d.ts +46 -22
  56. package/lib/ssg/index.mjs +257 -0
  57. package/lib/vite/index.d.ts +58 -10
  58. package/lib/vite/index.mjs +2459 -27446
  59. package/modules.d.ts +11 -16
  60. package/package.json +63 -67
  61. package/ssg.d.ts +2 -0
  62. package/static.d.ts +1 -1
  63. package/lib/adapters/azure-swa/vite/index.cjs +0 -96
  64. package/lib/adapters/bun-server/vite/index.cjs +0 -50
  65. package/lib/adapters/cloud-run/vite/index.cjs +0 -47
  66. package/lib/adapters/cloudflare-pages/vite/index.cjs +0 -115
  67. package/lib/adapters/deno-server/vite/index.cjs +0 -62
  68. package/lib/adapters/netlify-edge/vite/index.cjs +0 -129
  69. package/lib/adapters/node-server/vite/index.cjs +0 -50
  70. package/lib/adapters/shared/vite/index.cjs +0 -378
  71. package/lib/adapters/static/vite/index.cjs +0 -368
  72. package/lib/adapters/static/vite/index.d.ts +0 -10
  73. package/lib/adapters/static/vite/index.mjs +0 -331
  74. package/lib/adapters/vercel-edge/vite/index.cjs +0 -118
  75. package/lib/index.qwik.cjs +0 -2022
  76. package/lib/middleware/node/index.cjs +0 -314
  77. package/lib/middleware/request-handler/index.cjs +0 -1691
  78. package/lib/service-worker.cjs +0 -17
  79. package/lib/service-worker.mjs +0 -15
  80. package/lib/static/deno.mjs +0 -8
  81. package/lib/static/index.cjs +0 -67
  82. package/lib/static/index.mjs +0 -48
  83. package/lib/static/node.cjs +0 -1126
  84. package/lib/static/node.mjs +0 -1088
  85. package/lib/vite/index.cjs +0 -27525
  86. package/middleware/request-handler/generated/not-found-paths.ts +0 -7
  87. package/middleware/request-handler/generated/static-paths.ts +0 -35
@@ -0,0 +1,1707 @@
1
+ import { t as ensureSlash } from "./pathname.mjs";
2
+ import { C as getRouteLoaderValues, D as loadRouteLoader, G as QACTION_KEY, J as Q_ROUTE, K as QDATA_KEY, N as setRouteLoaders, O as matchesRouteLoaderId, S as getRouteLoaderResponse, Y as _asyncRequestStore, a as isPromise, f as FULLPATH_HEADER, h as clearRouteLoaderData, k as resolveRouteLoaderByHash, q as QFN_KEY, r as resolveRouteConfig, v as getLoaderRequestEvent, x as getRouteLoaderCtx } from "./head.qwik.mjs";
3
+ import { a as QLoaderId, c as resolveValidInternalFullPathname, i as QActionId, s as recognizeRequest, t as IsQAction, u as trimRecognizedInternalPathname } from "./request-path.mjs";
4
+ import { i as RedirectMessage, n as throwIfControlFlowSignal, r as AbortMessage, t as ServerError } from "./server-error.mjs";
5
+ import { inlinedQrl, isDev } from "@qwik.dev/core";
6
+ import { _deserialize, _serialize, _verifySerializable, isDev as isDev$1 } from "@qwik.dev/core/internal";
7
+ /**
8
+ * FNV-1a 32-bit hash for generating eTags from response data. Cheap to compute, sufficient
9
+ * collision resistance for cache validation (not cryptographic).
10
+ */ function hash(str) {
11
+ let hash = 2166136261;
12
+ for (let i = 0; i < str.length; i++) {
13
+ hash ^= str.charCodeAt(i);
14
+ hash = hash * 16777619 | 0;
15
+ }
16
+ return (hash >>> 0).toString(36);
17
+ }
18
+ /**
19
+ * Normalize an ETag header value (or a single `If-None-Match` entry) into a canonical form so byte
20
+ * equality compares the same logical tag. Strips weak ETag syntax (`W/"..."`), quotes, and any
21
+ * character outside RFC 7232's `etagc` grammar (printable ASCII except DQUOTE — no escape mechanism
22
+ * exists, and non-ASCII bytes are mangled by many HTTP stacks even though `obs-text` technically
23
+ * permits them). Idempotent.
24
+ */ function normalizeETag(raw) {
25
+ let tag = raw.trim();
26
+ if (tag.endsWith("\"") && tag.startsWith("W/\"")) tag = tag.slice(3);
27
+ tag = tag.replace(/[^!#-~]/g, "");
28
+ return tag;
29
+ }
30
+ function setETagHeader(requestEv, normalizedETag) {
31
+ const headerETag = `"${normalizedETag}"`;
32
+ requestEv.headers.set("ETag", headerETag);
33
+ }
34
+ /**
35
+ * Set the strong ETag header on the response and check the request's `If-None-Match` against it.
36
+ * The eTag argument must already be normalized. Returns true if a 304 was sent (caller should stop
37
+ * processing).
38
+ */ function performETagMatch(requestEv, normalizedETag) {
39
+ setETagHeader(requestEv, normalizedETag);
40
+ const ifNoneMatch = requestEv.request.headers.get("If-None-Match");
41
+ if (ifNoneMatch) {
42
+ let found = ifNoneMatch.trim() === "*";
43
+ if (!found) {
44
+ for (const entry of ifNoneMatch.split(",")) if (normalizeETag(entry) === normalizedETag) {
45
+ found = true;
46
+ break;
47
+ }
48
+ }
49
+ if (found) {
50
+ requestEv.status(304);
51
+ requestEv.send(304, "");
52
+ return true;
53
+ }
54
+ }
55
+ return false;
56
+ }
57
+ function createCacheControl(cacheControl) {
58
+ const controls = [];
59
+ if (cacheControl === "day") cacheControl = 86400;
60
+ else if (cacheControl === "week") cacheControl = 604800;
61
+ else if (cacheControl === "month") cacheControl = 2592e3;
62
+ else if (cacheControl === "year") cacheControl = 31536e3;
63
+ else if (cacheControl === "private") cacheControl = {
64
+ private: true,
65
+ noCache: true
66
+ };
67
+ else if (cacheControl === "immutable") cacheControl = {
68
+ public: true,
69
+ immutable: true,
70
+ maxAge: 31536e3
71
+ };
72
+ else if (cacheControl === "no-cache") cacheControl = { noCache: true };
73
+ if (typeof cacheControl === "number") cacheControl = {
74
+ maxAge: cacheControl,
75
+ sMaxAge: cacheControl
76
+ };
77
+ if (cacheControl.immutable) controls.push("immutable");
78
+ if (cacheControl.maxAge) controls.push(`max-age=${cacheControl.maxAge}`);
79
+ if (cacheControl.sMaxAge) controls.push(`s-maxage=${cacheControl.sMaxAge}`);
80
+ if (cacheControl.noStore) controls.push("no-store");
81
+ if (cacheControl.noCache) controls.push("no-cache");
82
+ if (cacheControl.private) controls.push("private");
83
+ if (cacheControl.public) controls.push("public");
84
+ if (cacheControl.staleWhileRevalidate) controls.push(`stale-while-revalidate=${cacheControl.staleWhileRevalidate}`);
85
+ if (cacheControl.staleIfError) controls.push(`stale-if-error=${cacheControl.staleIfError}`);
86
+ return controls.join(", ");
87
+ }
88
+ var SAMESITE = {
89
+ lax: "Lax",
90
+ Lax: "Lax",
91
+ None: "None",
92
+ none: "None",
93
+ strict: "Strict",
94
+ Strict: "Strict"
95
+ };
96
+ var UNIT = {
97
+ seconds: 1,
98
+ minutes: 60,
99
+ hours: 3600,
100
+ days: 86400,
101
+ weeks: 604800
102
+ };
103
+ function tryDecodeUriComponent(str) {
104
+ try {
105
+ return decodeURIComponent(str);
106
+ } catch {
107
+ return str;
108
+ }
109
+ }
110
+ var parseCookieString = (cookieString) => {
111
+ const cookie = {};
112
+ if (typeof cookieString === "string" && cookieString !== "") {
113
+ const cookieSegments = cookieString.split(";");
114
+ for (const cookieSegment of cookieSegments) {
115
+ const separatorIndex = cookieSegment.indexOf("=");
116
+ if (separatorIndex !== -1) cookie[tryDecodeUriComponent(cookieSegment.slice(0, separatorIndex).trim())] = tryDecodeUriComponent(cookieSegment.slice(separatorIndex + 1).trim());
117
+ }
118
+ }
119
+ return cookie;
120
+ };
121
+ function resolveSameSite(sameSite) {
122
+ if (sameSite === true) return "Strict";
123
+ if (sameSite === false) return "None";
124
+ if (sameSite) return SAMESITE[sameSite];
125
+ }
126
+ var createSetCookieValue = (cookieName, cookieValue, options) => {
127
+ const c = [`${cookieName}=${cookieValue}`];
128
+ if (typeof options.domain === "string") c.push(`Domain=${options.domain}`);
129
+ if (typeof options.maxAge === "number") c.push(`Max-Age=${options.maxAge}`);
130
+ else if (Array.isArray(options.maxAge)) c.push(`Max-Age=${options.maxAge[0] * UNIT[options.maxAge[1]]}`);
131
+ else if (typeof options.expires === "number" || typeof options.expires == "string") c.push(`Expires=${options.expires}`);
132
+ else if (options.expires instanceof Date) c.push(`Expires=${options.expires.toUTCString()}`);
133
+ if (options.httpOnly) c.push("HttpOnly");
134
+ if (typeof options.path === "string") c.push(`Path=${options.path}`);
135
+ const sameSite = resolveSameSite(options.sameSite);
136
+ if (sameSite) c.push(`SameSite=${sameSite}`);
137
+ if (options.secure) c.push("Secure");
138
+ return c.join("; ");
139
+ };
140
+ var REQ_COOKIE = Symbol("request-cookies");
141
+ var RES_COOKIE = Symbol("response-cookies");
142
+ var LIVE_COOKIE = Symbol("live-cookies");
143
+ var Cookie = class {
144
+ [REQ_COOKIE];
145
+ [RES_COOKIE] = {};
146
+ [LIVE_COOKIE] = {};
147
+ appendCounter = 0;
148
+ constructor(cookieString) {
149
+ this[REQ_COOKIE] = parseCookieString(cookieString);
150
+ this[LIVE_COOKIE] = { ...this[REQ_COOKIE] };
151
+ }
152
+ get(cookieName, live = true) {
153
+ const value = this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
154
+ if (!value) return null;
155
+ return {
156
+ value,
157
+ json() {
158
+ return JSON.parse(value);
159
+ },
160
+ number() {
161
+ return Number(value);
162
+ }
163
+ };
164
+ }
165
+ getAll(live = true) {
166
+ return Object.keys(this[live ? LIVE_COOKIE : REQ_COOKIE]).reduce((cookies, cookieName) => {
167
+ cookies[cookieName] = this.get(cookieName);
168
+ return cookies;
169
+ }, {});
170
+ }
171
+ has(cookieName, live = true) {
172
+ return !!this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
173
+ }
174
+ set(cookieName, cookieValue, options = {}) {
175
+ this[LIVE_COOKIE][cookieName] = typeof cookieValue === "string" ? cookieValue : JSON.stringify(cookieValue);
176
+ const resolvedValue = typeof cookieValue === "string" ? cookieValue : encodeURIComponent(JSON.stringify(cookieValue));
177
+ this[RES_COOKIE][cookieName] = createSetCookieValue(cookieName, resolvedValue, options);
178
+ }
179
+ append(cookieName, cookieValue, options = {}) {
180
+ this[LIVE_COOKIE][cookieName] = typeof cookieValue === "string" ? cookieValue : JSON.stringify(cookieValue);
181
+ const resolvedValue = typeof cookieValue === "string" ? cookieValue : encodeURIComponent(JSON.stringify(cookieValue));
182
+ this[RES_COOKIE][++this.appendCounter] = createSetCookieValue(cookieName, resolvedValue, options);
183
+ }
184
+ delete(name, options) {
185
+ this.set(name, "deleted", {
186
+ ...options,
187
+ maxAge: 0
188
+ });
189
+ this[LIVE_COOKIE][name] = null;
190
+ }
191
+ headers() {
192
+ return Object.values(this[RES_COOKIE]);
193
+ }
194
+ };
195
+ /** @public */ var mergeHeadersCookies = (headers, cookies) => {
196
+ const cookieHeaders = cookies.headers();
197
+ if (cookieHeaders.length > 0) {
198
+ const newHeaders = new Headers(headers);
199
+ for (const cookie of cookieHeaders) newHeaders.append("Set-Cookie", cookie);
200
+ return newHeaders;
201
+ }
202
+ return headers;
203
+ };
204
+ /** @public */ var RewriteMessage = class extends AbortMessage {
205
+ pathname;
206
+ constructor(pathname) {
207
+ super(), this.pathname = pathname;
208
+ }
209
+ };
210
+ var encoder = /*#__PURE__*/ new TextEncoder();
211
+ function getContentType(headers) {
212
+ return (headers.get("content-type")?.split(/[;,]/, 1)[0].trim() ?? "").toLowerCase();
213
+ }
214
+ function isContentType(headers, ...types) {
215
+ const type = getContentType(headers);
216
+ for (let i = 0; i < types.length; i++) if (types[i].toLowerCase() === type) return true;
217
+ return false;
218
+ }
219
+ var RequestEvMode = Symbol("RequestEvMode");
220
+ var RequestEvRoute = Symbol("RequestEvRoute");
221
+ var RequestRouteName = "@routeName";
222
+ var RequestEvSharedActionId = "@actionId";
223
+ var RequestEvSharedActionFormData = "@actionFormData";
224
+ var RequestEvSharedNonce = "@nonce";
225
+ var RequestEvIsRewrite = "@rewrite";
226
+ var RequestEvShareServerTiming = "@serverTiming";
227
+ var RequestEvETagCacheKey = "@eTagCacheKey";
228
+ var RequestEvHttpStatusMessage = "@httpStatusMessage";
229
+ function getRequestRoute(requestEv) {
230
+ return requestEv[RequestEvRoute];
231
+ }
232
+ function getRequestMode(requestEv) {
233
+ return requestEv[RequestEvMode];
234
+ }
235
+ var ABORT_INDEX = Number.MAX_SAFE_INTEGER;
236
+ var isDangerousKey = (k) => k === "__proto__" || k === "constructor" || k === "prototype";
237
+ var isArrayIndexKey = (k) => /^(0|[1-9]\d*)$/.test(k);
238
+ var createFormPathNode = () => ({
239
+ children: /* @__PURE__ */ new Map(),
240
+ isArray: true
241
+ });
242
+ var getFormPathTree = (formData) => {
243
+ const root = createFormPathNode();
244
+ for (const [name] of formData) {
245
+ const keys = name.split(".");
246
+ let hasDangerousKey = false;
247
+ for (const key of keys) if (isDangerousKey(key)) {
248
+ hasDangerousKey = true;
249
+ break;
250
+ }
251
+ if (hasDangerousKey) continue;
252
+ let pathNode = root;
253
+ for (let i = 0; i < keys.length - 1; i++) {
254
+ const key = keys[i];
255
+ if (key.endsWith("[]")) break;
256
+ let childNode = pathNode.children.get(key);
257
+ if (!childNode) {
258
+ childNode = createFormPathNode();
259
+ pathNode.children.set(key, childNode);
260
+ }
261
+ if (!isArrayIndexKey(keys[i + 1])) childNode.isArray = false;
262
+ pathNode = childNode;
263
+ }
264
+ }
265
+ return root;
266
+ };
267
+ var formToObj = (formData) => {
268
+ /**
269
+ * Convert FormData to object Handle nested form input using dot notation Handle array input using
270
+ * indexed dot notation (name.0, name.0) or bracket notation (name[]), the later is needed for
271
+ * multiselects Create values object by form data entries
272
+ */ const values = Object.create(null);
273
+ const pathTree = getFormPathTree(formData);
274
+ for (const [name, value] of formData) {
275
+ const keys = name.split(".");
276
+ let hasDangerousKey = false;
277
+ for (let i = 0; i < keys.length; i++) if (isDangerousKey(keys[i])) {
278
+ hasDangerousKey = true;
279
+ break;
280
+ }
281
+ if (hasDangerousKey) continue;
282
+ let object = values;
283
+ let pathNode = pathTree;
284
+ for (let i = 0; i < keys.length; i++) {
285
+ const key = keys[i];
286
+ if (key.endsWith("[]")) {
287
+ const arrayKey = key.slice(0, -2);
288
+ if (isDangerousKey(arrayKey)) break;
289
+ const existingValue = object[arrayKey];
290
+ if (existingValue !== void 0 && !Array.isArray(existingValue)) break;
291
+ object[arrayKey] = existingValue || [];
292
+ object[arrayKey].push(value);
293
+ break;
294
+ }
295
+ if (Array.isArray(object) && !isArrayIndexKey(key)) break;
296
+ if (i < keys.length - 1) {
297
+ const childNode = pathNode.children.get(key);
298
+ const nextValue = object[key];
299
+ if (nextValue !== void 0) {
300
+ object = nextValue;
301
+ pathNode = childNode;
302
+ continue;
303
+ }
304
+ object = object[key] = childNode.isArray ? [] : Object.create(null);
305
+ pathNode = childNode;
306
+ } else object[key] = value;
307
+ }
308
+ }
309
+ return values;
310
+ };
311
+ var parseRequest = async ({ request, method, query }, sharedMap) => {
312
+ const type = getContentType(request.headers);
313
+ if (type === "application/x-www-form-urlencoded" || type === "multipart/form-data") {
314
+ const formData = await request.formData();
315
+ sharedMap.set(RequestEvSharedActionFormData, formData);
316
+ return formToObj(formData);
317
+ } else if (type === "application/json") return await request.json();
318
+ else if (type === "application/qwik-json") {
319
+ if (method === "GET" && query.has("qdata")) {
320
+ const data = query.get(QDATA_KEY);
321
+ if (data) try {
322
+ return await _deserialize(decodeURIComponent(data));
323
+ } catch {}
324
+ }
325
+ return await _deserialize(await request.text());
326
+ }
327
+ };
328
+ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, basePathname, resolved) {
329
+ const { request, platform, env } = serverRequestEv;
330
+ const sharedMap = /* @__PURE__ */ new Map();
331
+ const cookie = new Cookie(request.headers.get("cookie"));
332
+ const headers = new Headers();
333
+ const url = new URL(request.url);
334
+ let internalRequest = false;
335
+ const recognized = recognizeRequest(url.pathname);
336
+ if (recognized) {
337
+ url.pathname = trimRecognizedInternalPathname(url.pathname, recognized);
338
+ sharedMap.set(recognized.type, true);
339
+ internalRequest = "loader";
340
+ if (recognized.data?.loaderId) sharedMap.set(QLoaderId, recognized.data.loaderId);
341
+ }
342
+ const actionId = url.searchParams.get(QACTION_KEY);
343
+ if (actionId) {
344
+ sharedMap.set(IsQAction, true);
345
+ sharedMap.set(QActionId, actionId);
346
+ if (request.method === "POST" && request.headers.get("accept")?.includes("application/json")) internalRequest = "action";
347
+ }
348
+ let routeModuleIndex = -1;
349
+ let writableStream = null;
350
+ let requestData = void 0;
351
+ let locale = serverRequestEv.locale;
352
+ let status = loadedRoute?.$notFound$ ? 404 : 200;
353
+ const next = async () => {
354
+ routeModuleIndex++;
355
+ while (routeModuleIndex < requestHandlers.length) {
356
+ const moduleRequestHandler = requestHandlers[routeModuleIndex];
357
+ const result = moduleRequestHandler(requestEv);
358
+ throwIfControlFlowSignal(isPromise(result) ? await result : result);
359
+ routeModuleIndex++;
360
+ }
361
+ };
362
+ const resetRoute = (_loadedRoute, _requestHandlers, _url = url) => {
363
+ loadedRoute = _loadedRoute;
364
+ status = loadedRoute?.$notFound$ ? 404 : 200;
365
+ requestHandlers = _requestHandlers;
366
+ url.pathname = _url.pathname;
367
+ url.search = _url.search;
368
+ routeModuleIndex = -1;
369
+ };
370
+ const check = () => {
371
+ if (writableStream !== null) throw new Error("Response already sent");
372
+ };
373
+ const send = (statusOrResponse, body) => {
374
+ check();
375
+ if (typeof statusOrResponse === "number") {
376
+ status = statusOrResponse;
377
+ const writer = requestEv.getWritableStream().getWriter();
378
+ writer.write(typeof body === "string" ? encoder.encode(body) : body);
379
+ writer.close();
380
+ } else {
381
+ status = statusOrResponse.status;
382
+ statusOrResponse.headers.forEach((value, key) => {
383
+ if (key.toLowerCase() === "set-cookie") return;
384
+ headers.append(key, value);
385
+ });
386
+ statusOrResponse.headers.getSetCookie().forEach((ck) => {
387
+ const index = ck.indexOf("=");
388
+ if (index === -1) return;
389
+ const key = ck.slice(0, index).trim();
390
+ const value = ck.slice(index + 1).trim();
391
+ cookie.set(key, value);
392
+ });
393
+ if (statusOrResponse.body) {
394
+ const writableStream = requestEv.getWritableStream();
395
+ statusOrResponse.body.pipeTo(writableStream);
396
+ } else requestEv.getWritableStream().getWriter().close();
397
+ }
398
+ return exit();
399
+ };
400
+ const exit = (message = new AbortMessage()) => {
401
+ routeModuleIndex = ABORT_INDEX;
402
+ return message;
403
+ };
404
+ const requestEv = {
405
+ [RequestEvMode]: serverRequestEv.mode,
406
+ get [RequestEvRoute]() {
407
+ return loadedRoute;
408
+ },
409
+ cookie,
410
+ headers,
411
+ env,
412
+ method: request.method,
413
+ signal: request.signal,
414
+ originalUrl: new URL(url),
415
+ get params() {
416
+ return loadedRoute?.$params$ ?? {};
417
+ },
418
+ get pathname() {
419
+ return url.pathname;
420
+ },
421
+ platform,
422
+ get query() {
423
+ return url.searchParams;
424
+ },
425
+ request,
426
+ url,
427
+ internalRequest,
428
+ basePathname,
429
+ sharedMap,
430
+ get headersSent() {
431
+ return writableStream !== null;
432
+ },
433
+ get exited() {
434
+ return routeModuleIndex >= ABORT_INDEX;
435
+ },
436
+ get clientConn() {
437
+ return serverRequestEv.getClientConn();
438
+ },
439
+ next,
440
+ resetRoute,
441
+ exit,
442
+ cacheControl: (cacheControl, target = "Cache-Control") => {
443
+ check();
444
+ headers.set(target, createCacheControl(cacheControl));
445
+ },
446
+ resolveValue: async (loaderOrAction) => {
447
+ if (loaderOrAction.__brand === "server_loader") {
448
+ const loaderValues = getRouteLoaderValues(requestEv);
449
+ if (loaderOrAction.__id in loaderValues) return loaderValues[loaderOrAction.__id];
450
+ return loadRouteLoader(loaderOrAction, requestEv);
451
+ }
452
+ },
453
+ status: (statusCode) => {
454
+ if (typeof statusCode === "number") {
455
+ check();
456
+ status = statusCode;
457
+ return statusCode;
458
+ }
459
+ return status;
460
+ },
461
+ locale: (_locale) => {
462
+ if (typeof _locale === "string") locale = _locale;
463
+ return locale || "";
464
+ },
465
+ error: (statusCode, message) => {
466
+ status = statusCode;
467
+ headers.delete("Cache-Control");
468
+ return new ServerError(statusCode, message);
469
+ },
470
+ redirect: (statusCode, url) => {
471
+ check();
472
+ status = statusCode;
473
+ if (url) {
474
+ if (/^\/\//.test(url) || /([^:])\/\/+/.test(url)) {
475
+ const fixedURL = url.replace(/^\/\/+/, "/").replace(/([^:])\/\/+/g, "$1/");
476
+ console.warn(`Redirect URL ${url} is invalid, fixing to ${fixedURL}`);
477
+ url = fixedURL;
478
+ }
479
+ headers.set("Location", url);
480
+ }
481
+ headers.delete("Cache-Control");
482
+ if (statusCode > 301) headers.set("Cache-Control", "no-store");
483
+ if (internalRequest === "loader") return new RedirectMessage();
484
+ return exit(new RedirectMessage());
485
+ },
486
+ rewrite: (pathname) => {
487
+ check();
488
+ if (pathname.startsWith("http")) throw new ServerError(400, isDev$1 ? "Rewrite does not support absolute urls" : "Bad Request");
489
+ sharedMap.set(RequestEvIsRewrite, true);
490
+ return exit(new RewriteMessage(pathname.replace(/\/+/g, "/")));
491
+ },
492
+ defer: (returnData) => {
493
+ return typeof returnData === "function" ? returnData : () => returnData;
494
+ },
495
+ fail: (statusCode, data) => {
496
+ check();
497
+ status = statusCode;
498
+ headers.delete("Cache-Control");
499
+ return {
500
+ failed: true,
501
+ ...data
502
+ };
503
+ },
504
+ text: (statusCode, text) => {
505
+ headers.set("Content-Type", "text/plain; charset=utf-8");
506
+ return send(statusCode, text);
507
+ },
508
+ html: (statusCode, html) => {
509
+ headers.set("Content-Type", "text/html; charset=utf-8");
510
+ return send(statusCode, html);
511
+ },
512
+ parseBody: async () => {
513
+ if (requestData !== void 0) return requestData;
514
+ return requestData = parseRequest(requestEv, sharedMap);
515
+ },
516
+ json: (statusCode, data) => {
517
+ headers.set("Content-Type", "application/json; charset=utf-8");
518
+ return send(statusCode, JSON.stringify(data));
519
+ },
520
+ send,
521
+ isDirty: () => {
522
+ return writableStream !== null;
523
+ },
524
+ getWritableStream: () => {
525
+ if (writableStream === null) {
526
+ if (isDev$1) {
527
+ const serverTiming = sharedMap.get(RequestEvShareServerTiming);
528
+ if (serverTiming) headers.set("Server-Timing", serverTiming.map(([name, duration]) => `${name};dur=${duration}`).join(","));
529
+ }
530
+ writableStream = serverRequestEv.getWritableStream(status, headers, cookie, resolved, requestEv);
531
+ }
532
+ return writableStream;
533
+ }
534
+ };
535
+ return requestEv;
536
+ }
537
+ var MAX_CACHE_SIZE = typeof globalThis.__SSR_CACHE_SIZE__ === "number" ? globalThis.__SSR_CACHE_SIZE__ : 50;
538
+ function createLruCache() {
539
+ const cache = /* @__PURE__ */ new Map();
540
+ return {
541
+ get(key) {
542
+ const entry = cache.get(key);
543
+ if (entry !== void 0) {
544
+ cache.delete(key);
545
+ cache.set(key, entry);
546
+ }
547
+ return entry;
548
+ },
549
+ set(key, entry) {
550
+ if (MAX_CACHE_SIZE <= 0) return;
551
+ if (cache.size >= MAX_CACHE_SIZE) {
552
+ const firstKey = cache.keys().next().value;
553
+ cache.delete(firstKey);
554
+ }
555
+ cache.set(key, entry);
556
+ },
557
+ clear(key) {
558
+ if (key != null) cache.delete(key);
559
+ else cache.clear();
560
+ }
561
+ };
562
+ }
563
+ var ssrCache = createLruCache();
564
+ var loaderCache = createLruCache();
565
+ /**
566
+ * Resolve an eTag value from a ContentModuleETag (string, function, or undefined). Returns the eTag
567
+ * string or null.
568
+ */ function resolveETag(eTagExport, headProps) {
569
+ if (eTagExport === void 0) return null;
570
+ if (typeof eTagExport === "function") return eTagExport(headProps);
571
+ return eTagExport;
572
+ }
573
+ /**
574
+ * Resolve a cache key from a CacheKeyFn. The default key callback is only called when `cacheKey ===
575
+ * true`.
576
+ */ function resolveCacheKey(cacheKeyExport, defaultKey, requestEv, eTag) {
577
+ if (cacheKeyExport === true) return defaultKey(requestEv, eTag);
578
+ if (typeof cacheKeyExport !== "function") return "";
579
+ return cacheKeyExport(requestEv, eTag) || "";
580
+ }
581
+ /** Build the default SSR cache key. eTag slot is dropped when no eTag was resolved. */ function defaultSsrCacheKey(requestEv, eTag) {
582
+ const status = requestEv.status();
583
+ const pathname = requestEv.url.pathname;
584
+ return eTag ? `${status}|${eTag}|${pathname}` : `${status}|${pathname}`;
585
+ }
586
+ /** Build the default loader cache key. eTag slot is dropped when no eTag was resolved. */ function defaultLoaderCacheKey(requestEv, eTag) {
587
+ const loaderId = requestEv.sharedMap.get(QLoaderId);
588
+ const base = `${requestEv.url.pathname}|${requestEv.url.search}|${loaderId}`;
589
+ return eTag ? `${base}|${eTag}` : base;
590
+ }
591
+ /** Get a cached SSR entry by key (LRU touch). */ function getCachedSsr(key) {
592
+ return ssrCache.get(key);
593
+ }
594
+ /** Cache an SSR entry by key, evicting the least recently used entry if at capacity. */ function setCachedSsr(key, entry) {
595
+ ssrCache.set(key, entry);
596
+ }
597
+ /** Get a cached loader entry by key (LRU touch). */ function getCachedLoader(key) {
598
+ return loaderCache.get(key);
599
+ }
600
+ /** Cache a loader entry by key, evicting the least recently used entry if at capacity. */ function setCachedLoader(key, entry) {
601
+ loaderCache.set(key, entry);
602
+ }
603
+ /**
604
+ * Clear the in-memory SSR cache. Call after deployments or data changes.
605
+ *
606
+ * When `cacheKey` is provided, only that single entry is removed; otherwise the entire cache is
607
+ * cleared.
608
+ *
609
+ * @public
610
+ */ function clearSsrCache(cacheKey) {
611
+ ssrCache.clear(cacheKey);
612
+ }
613
+ /**
614
+ * Clear the in-memory loader cache. Call after deployments or data changes.
615
+ *
616
+ * When `cacheKey` is provided, only that single entry is removed; otherwise the entire cache is
617
+ * cleared.
618
+ *
619
+ * @public
620
+ */ function clearLoaderCache(cacheKey) {
621
+ loaderCache.clear(cacheKey);
622
+ }
623
+ /**
624
+ * Create per-loader request event views. Loader-specific URL/search data is scoped to the view,
625
+ * while request-wide state (headers, cookies, loader value maps, etc.) still delegates to the
626
+ * original request event.
627
+ */ function createLoaderRequestEventFactory(requestEv) {
628
+ return (loader) => getLoaderRequestEvent(loader, requestEv);
629
+ }
630
+ /**
631
+ * Resolve the loader's cacheControl option. Loaders default to `no-cache` so the browser always
632
+ * revalidates; pair with `eTag` for cheap 304s. A function form may return `null` to skip the
633
+ * header entirely.
634
+ */ function resolveLoaderCacheControl(option, requestEv) {
635
+ const value = typeof option === "function" ? option(requestEv) : option;
636
+ return value === void 0 ? "no-cache" : value;
637
+ }
638
+ async function runBlockingLoadersBeforeTarget(routeLoaders, targetLoader, requestEv) {
639
+ for (const loader of routeLoaders) {
640
+ if (loader === targetLoader) return;
641
+ if (loader.__blockSSR) await loadRouteLoader(loader, requestEv);
642
+ }
643
+ }
644
+ function setLoaderData(requestEv, routeLoaders, loaderPaths) {
645
+ if (loaderPaths) Object.assign(getRouteLoaderCtx(requestEv).loaderPaths, loaderPaths);
646
+ setRouteLoaders(requestEv, routeLoaders);
647
+ }
648
+ /** Resolve eTag from a static string or function (before running the loader). */ function resolvePreETag(eTagOption, requestEv) {
649
+ if (typeof eTagOption === "string") return normalizeETag(eTagOption);
650
+ const result = eTagOption(requestEv);
651
+ return result ? normalizeETag(result) : "";
652
+ }
653
+ function addVaryHeader(requestEv, value) {
654
+ const vary = requestEv.headers.get("Vary");
655
+ if (!vary) {
656
+ requestEv.headers.set("Vary", value);
657
+ return;
658
+ }
659
+ if (!vary.split(",").map((item) => item.trim().toLowerCase()).includes(value.toLowerCase())) requestEv.headers.set("Vary", `${vary}, ${value}`);
660
+ }
661
+ async function sendLoaderResponse(requestEv, data, cacheControl) {
662
+ requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
663
+ addVaryHeader(requestEv, FULLPATH_HEADER);
664
+ if (cacheControl !== null && !requestEv.headers.has("Cache-Control")) requestEv.cacheControl(cacheControl);
665
+ requestEv.send(200, data);
666
+ }
667
+ /**
668
+ * Handler that executes the requested loader and returns the result as JSON. Runs AFTER
669
+ * plugin/route middleware, so middleware redirects/errors are handled by `jsonRequestWrapper`. The
670
+ * loader function's own redirects/errors are caught by getRouteLoaderResponse and serialized in the
671
+ * LoaderResponse envelope ({ d, r, e }).
672
+ */ function loaderHandler(routeLoaders, loaderPaths) {
673
+ return async (requestEvent) => {
674
+ const requestEv = requestEvent;
675
+ if (!requestEv.sharedMap.has("@isQLoader")) return;
676
+ if (requestEv.headersSent || requestEv.exited) return;
677
+ const loaderId = requestEv.sharedMap.get(QLoaderId);
678
+ const loader = resolveRouteLoaderByHash(routeLoaders, loaderId);
679
+ if (!loader) {
680
+ requestEv.json(404, { error: "Loader not found" });
681
+ return;
682
+ }
683
+ setLoaderData(requestEv, routeLoaders, loaderPaths);
684
+ await runBlockingLoadersBeforeTarget(routeLoaders, loader, requestEv);
685
+ const loaderRequestEv = createLoaderRequestEventFactory(requestEv)(loader);
686
+ const cacheControl = resolveLoaderCacheControl(loader.__cacheControl, loaderRequestEv);
687
+ const normalizedETag = loader.__eTag !== void 0 ? resolvePreETag(loader.__eTag, loaderRequestEv) : "";
688
+ if (normalizedETag && performETagMatch(loaderRequestEv, normalizedETag)) return;
689
+ let cacheKey = "";
690
+ if (loader.__cacheKey) cacheKey = resolveCacheKey(loader.__cacheKey, defaultLoaderCacheKey, loaderRequestEv, normalizedETag);
691
+ if (cacheKey) {
692
+ const cached = getCachedLoader(cacheKey);
693
+ if (cached) {
694
+ if (!normalizedETag) {
695
+ if (performETagMatch(loaderRequestEv, cached.eTag)) return;
696
+ } else setETagHeader(loaderRequestEv, cached.eTag);
697
+ await sendLoaderResponse(requestEv, cached.body, cacheControl);
698
+ return;
699
+ }
700
+ }
701
+ const responseData = await getRouteLoaderResponse(loader.__qrl, loader.__validators, loaderRequestEv);
702
+ const data = await _serialize(responseData);
703
+ const failed = responseData.d && typeof responseData.d === "object" && responseData.d.failed;
704
+ const cacheable = cacheKey && !responseData.r && !responseData.e && !failed;
705
+ const finalETag = normalizedETag || (cacheable ? hash(data) : "");
706
+ if (cacheable && finalETag) setCachedLoader(cacheKey, {
707
+ eTag: finalETag,
708
+ body: data
709
+ });
710
+ if (!normalizedETag && finalETag && performETagMatch(loaderRequestEv, finalETag)) return;
711
+ await sendLoaderResponse(requestEv, data, cacheControl);
712
+ };
713
+ }
714
+ /** Serialize and send a JSON response (used by error/redirect paths in jsonRequestWrapper). */ async function sendJsonResponse(requestEv, responseData, status = 200) {
715
+ const data = await _serialize(responseData);
716
+ requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
717
+ requestEv.send(status, data);
718
+ }
719
+ async function sendActionResponse(requestEv, responseData) {
720
+ const data = await _serialize(responseData);
721
+ requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
722
+ requestEv.send(responseData.s || 200, data);
723
+ }
724
+ /**
725
+ * Early handler that wraps `next()` for JSON API requests (q-loader and q-action).
726
+ *
727
+ * For `IsQLoader` requests, it also rewrites the URL using the `X-Qwik-fullpath` header so that
728
+ * downstream middleware sees the real page URL.
729
+ *
730
+ * By calling `await next()` inside a try/catch, middleware redirects and errors are captured and
731
+ * returned as JSON envelopes instead of HTTP redirects/error pages. This keeps SPA navigation
732
+ * intact on the client.
733
+ */ function jsonRequestWrapper() {
734
+ return async (requestEvent) => {
735
+ const requestEv = requestEvent;
736
+ const isLoader = requestEv.internalRequest === "loader";
737
+ const isActionJson = requestEv.internalRequest === "action";
738
+ if (!isLoader && !isActionJson) return;
739
+ if (isLoader) {
740
+ addVaryHeader(requestEv, FULLPATH_HEADER);
741
+ const pagePath = requestEv.request.headers.get(FULLPATH_HEADER);
742
+ const pagePathname = resolveValidInternalFullPathname(requestEv.url.pathname, pagePath);
743
+ if (pagePathname) requestEv.url.pathname = pagePathname;
744
+ }
745
+ try {
746
+ await requestEv.next();
747
+ } catch (err) {
748
+ if (requestEv.headersSent) return;
749
+ if (err instanceof RedirectMessage) {
750
+ const location = requestEv.headers.get("Location") || "/";
751
+ requestEv.headers.delete("Location");
752
+ if (isLoader) await sendJsonResponse(requestEv, { r: location });
753
+ else await sendActionResponse(requestEv, { redirect: location });
754
+ } else if (err instanceof ServerError) {
755
+ if (isLoader) await sendJsonResponse(requestEv, { e: err });
756
+ else await sendActionResponse(requestEv, {
757
+ e: err,
758
+ s: err.status
759
+ });
760
+ } else if (err instanceof Error) {
761
+ console.error("JSON request error:", err);
762
+ const message = isDev ? `${err.message}\n(this is only visible in dev mode)` : "Internal Server Error";
763
+ const se = new ServerError(500, message);
764
+ if (isLoader) await sendJsonResponse(requestEv, { e: se });
765
+ else await sendActionResponse(requestEv, {
766
+ e: se,
767
+ s: 500
768
+ });
769
+ } else throw err;
770
+ }
771
+ };
772
+ }
773
+ function verifySerializable$1(data, qrl) {
774
+ try {
775
+ _verifySerializable(data, void 0);
776
+ } catch (e) {
777
+ if (e instanceof Error && qrl.dev) e.loc = qrl.dev;
778
+ throw e;
779
+ }
780
+ }
781
+ async function measure$1(requestEv, name, fn) {
782
+ const start = performance.now();
783
+ try {
784
+ return await fn();
785
+ } finally {
786
+ const duration = performance.now() - start;
787
+ let measurements = requestEv.sharedMap.get("@serverTiming");
788
+ if (!measurements) requestEv.sharedMap.set("@serverTiming", measurements = []);
789
+ measurements.push([name, duration]);
790
+ }
791
+ }
792
+ async function runValidators(requestEv, validators, data, devMode) {
793
+ let lastResult = {
794
+ success: true,
795
+ data
796
+ };
797
+ if (validators) for (const validator of validators) {
798
+ if (devMode) lastResult = await measure$1(requestEv, `validator$`, () => validator.validate(requestEv, data));
799
+ else lastResult = await validator.validate(requestEv, data);
800
+ if (!lastResult.success) return lastResult;
801
+ else data = lastResult.data;
802
+ }
803
+ return lastResult;
804
+ }
805
+ /**
806
+ * Handler for action requests (`?qaction={actionId}`).
807
+ *
808
+ * When the request has `Accept: application/json`, returns the action result as JSON. Otherwise,
809
+ * falls through to let the page render (progressive enhancement for forms).
810
+ *
811
+ * If the action has no `invalidate` list, the client invalidates all current route loaders unless
812
+ * strict loaders mode treats it as `invalidate: []`. If `invalidate` is specified, only those
813
+ * loader hashes are sent for the client to re-fetch.
814
+ */ function actionHandler(routeActions) {
815
+ return async (requestEvent) => {
816
+ const requestEv = requestEvent;
817
+ if (!requestEv.sharedMap.has("@isQAction")) return;
818
+ if (!requestEv.request.headers.get("accept")?.includes("application/json")) return;
819
+ if (requestEv.headersSent || requestEv.exited) return;
820
+ const actionId = requestEv.sharedMap.get(QActionId);
821
+ const method = requestEv.method;
822
+ const devMode = isDev$1;
823
+ if (devMode && method === "GET") console.warn("Seems like you are submitting a Qwik Action via GET request. Qwik Actions should be submitted via POST request.\nMake sure your <form> has method=\"POST\" attribute, like this: <form method=\"POST\">");
824
+ if (method !== "POST") return;
825
+ let action;
826
+ for (const routeAction of routeActions) if (routeAction.__id === actionId) action = routeAction;
827
+ if (!action) action = globalThis._qwikActionsMap?.get(actionId);
828
+ if (!action) {
829
+ requestEv.json(404, { error: "Action not found" });
830
+ return;
831
+ }
832
+ const data = await requestEv.parseBody();
833
+ if (!data || typeof data !== "object") throw new Error(`Expected request data for the action id ${actionId} to be an object`);
834
+ let actionResult;
835
+ const result = await runValidators(requestEv, action.__validators, data, devMode);
836
+ if (!result.success) actionResult = requestEv.fail(result.status ?? 500, result.error);
837
+ else {
838
+ const actionResolved = devMode ? await measure$1(requestEv, action.__qrl.getHash(), () => action.__qrl.call(requestEv, result.data, requestEv)) : await action.__qrl.call(requestEv, result.data, requestEv);
839
+ throwIfControlFlowSignal(actionResolved);
840
+ if (devMode) verifySerializable$1(actionResolved, action.__qrl);
841
+ actionResult = actionResolved;
842
+ }
843
+ if (requestEv.headers.has("Location")) throw new RedirectMessage();
844
+ const responseData = { result: actionResult };
845
+ requestEv.sharedMap.set(RequestEvSharedActionId, actionId);
846
+ requestEv.sharedMap.set("@actionResult", actionResult);
847
+ if (action.__invalidate) responseData.loaderHashes = action.__invalidate;
848
+ else if (globalThis.__STRICT_LOADERS__) responseData.loaderHashes = [];
849
+ const serialized = await _serialize(responseData);
850
+ requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
851
+ requestEv.send(requestEv.status(), serialized);
852
+ };
853
+ }
854
+ /**
855
+ * Hypertext Transfer Protocol (HTTP) response status codes.
856
+ *
857
+ * @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes}
858
+ */ var HttpStatus = /*#__PURE__*/ function(HttpStatus) {
859
+ /**
860
+ * The server has received the request headers and the client should proceed to send the request
861
+ * body (in the case of a request for which a body needs to be sent; for example, a POST request).
862
+ * Sending a large request body to a server after a request has been rejected for inappropriate
863
+ * headers would be inefficient. To have a server check the request's headers, a client must send
864
+ * Expect: 100-continue as a header in its initial request and receive a 100 Continue status code
865
+ * in response before sending the body. The response 417 Expectation Failed indicates the request
866
+ * should not be continued.
867
+ */ HttpStatus[HttpStatus["Continue"] = 100] = "Continue";
868
+ /** The requester has asked the server to switch protocols and the server has agreed to do so. */ HttpStatus[HttpStatus["SwitchingProtocols"] = 101] = "SwitchingProtocols";
869
+ /**
870
+ * A WebDAV request may contain many sub-requests involving file operations, requiring a long time
871
+ * to complete the request. This code indicates that the server has received and is processing the
872
+ * request, but no response is available yet. This prevents the client from timing out and
873
+ * assuming the request was lost.
874
+ */ HttpStatus[HttpStatus["Processing"] = 102] = "Processing";
875
+ /**
876
+ * Standard response for successful HTTP requests. The actual response will depend on the request
877
+ * method used. In a GET request, the response will contain an entity corresponding to the
878
+ * requested resource. In a POST request, the response will contain an entity describing or
879
+ * containing the result of the action.
880
+ */ HttpStatus[HttpStatus["Ok"] = 200] = "Ok";
881
+ /** The request has been fulfilled, resulting in the creation of a new resource. */ HttpStatus[HttpStatus["Created"] = 201] = "Created";
882
+ /**
883
+ * The request has been accepted for processing, but the processing has not been completed. The
884
+ * request might or might not be eventually acted upon, and may be disallowed when processing
885
+ * occurs.
886
+ */ HttpStatus[HttpStatus["Accepted"] = 202] = "Accepted";
887
+ /**
888
+ * SINCE HTTP/1.1 The server is a transforming proxy that received a 200 OK from its origin, but
889
+ * is returning a modified version of the origin's response.
890
+ */ HttpStatus[HttpStatus["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
891
+ /** The server successfully processed the request and is not returning any content. */ HttpStatus[HttpStatus["NoContent"] = 204] = "NoContent";
892
+ /**
893
+ * The server successfully processed the request, but is not returning any content. Unlike a 204
894
+ * response, this response requires that the requester reset the document view.
895
+ */ HttpStatus[HttpStatus["ResetContent"] = 205] = "ResetContent";
896
+ /**
897
+ * The server is delivering only part of the resource (byte serving) due to a range header sent by
898
+ * the client. The range header is used by HTTP clients to enable resuming of interrupted
899
+ * downloads, or split a download into multiple simultaneous streams.
900
+ */ HttpStatus[HttpStatus["PartialContent"] = 206] = "PartialContent";
901
+ /**
902
+ * The message body that follows is an XML message and can contain a number of separate response
903
+ * codes, depending on how many sub-requests were made.
904
+ */ HttpStatus[HttpStatus["MultiStatus"] = 207] = "MultiStatus";
905
+ /**
906
+ * The members of a DAV binding have already been enumerated in a preceding part of the
907
+ * (multistatus) response, and are not being included again.
908
+ */ HttpStatus[HttpStatus["AlreadyReported"] = 208] = "AlreadyReported";
909
+ /**
910
+ * The server has fulfilled a request for the resource, and the response is a representation of
911
+ * the result of one or more instance-manipulations applied to the current instance.
912
+ */ HttpStatus[HttpStatus["ImUsed"] = 226] = "ImUsed";
913
+ /**
914
+ * Indicates multiple options for the resource from which the client may choose (via agent-driven
915
+ * content negotiation). For example, this code could be used to present multiple video format
916
+ * options, to list files with different filename extensions, or to suggest word-sense
917
+ * disambiguation.
918
+ */ HttpStatus[HttpStatus["MultipleChoices"] = 300] = "MultipleChoices";
919
+ /** This and all future requests should be directed to the given URI. */ HttpStatus[HttpStatus["MovedPermanently"] = 301] = "MovedPermanently";
920
+ /**
921
+ * This is an example of industry practice contradicting the standard. The HTTP/1.0 specification
922
+ * (RFC 1945) required the client to perform a temporary redirect (the original describing phrase
923
+ * was "Moved Temporarily"), but popular browsers implemented 302 with the functionality of a 303
924
+ * See Other. Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the two
925
+ * behaviors. However, some Web applications and frameworks use the 302 status code as if it were
926
+ * the 303.
927
+ */ HttpStatus[HttpStatus["Found"] = 302] = "Found";
928
+ /**
929
+ * SINCE HTTP/1.1 The response to the request can be found under another URI using a GET method.
930
+ * When received in response to a POST (or PUT/DELETE), the client should presume that the server
931
+ * has received the data and should issue a redirect with a separate GET message.
932
+ */ HttpStatus[HttpStatus["SeeOther"] = 303] = "SeeOther";
933
+ /**
934
+ * Indicates that the resource has not been modified since the version specified by the request
935
+ * headers If-Modified-Since or If-None-Match. In such case, there is no need to retransmit the
936
+ * resource since the client still has a previously-downloaded copy.
937
+ */ HttpStatus[HttpStatus["NotModified"] = 304] = "NotModified";
938
+ /**
939
+ * SINCE HTTP/1.1 The requested resource is available only through a proxy, the address for which
940
+ * is provided in the response. Many HTTP clients (such as Mozilla and Internet Explorer) do not
941
+ * correctly handle responses with this status code, primarily for security reasons.
942
+ */ HttpStatus[HttpStatus["UseProxy"] = 305] = "UseProxy";
943
+ /** No longer used. Originally meant "Subsequent requests should use the specified proxy." */ HttpStatus[HttpStatus["SwitchProxy"] = 306] = "SwitchProxy";
944
+ /**
945
+ * SINCE HTTP/1.1 In this case, the request should be repeated with another URI; however, future
946
+ * requests should still use the original URI. In contrast to how 302 was historically
947
+ * implemented, the request method is not allowed to be changed when reissuing the original
948
+ * request. For example, a POST request should be repeated using another POST request.
949
+ */ HttpStatus[HttpStatus["TemporaryRedirect"] = 307] = "TemporaryRedirect";
950
+ /**
951
+ * The request and all future requests should be repeated using another URI. 307 and 308 parallel
952
+ * the behaviors of 302 and 301, but do not allow the HTTP method to change. So, for example,
953
+ * submitting a form to a permanently redirected resource may continue smoothly.
954
+ */ HttpStatus[HttpStatus["PermanentRedirect"] = 308] = "PermanentRedirect";
955
+ /**
956
+ * The server cannot or will not process the request due to an apparent client error (e.g.,
957
+ * malformed request syntax, too large size, invalid request message framing, or deceptive request
958
+ * routing).
959
+ */ HttpStatus[HttpStatus["BadRequest"] = 400] = "BadRequest";
960
+ /**
961
+ * Similar to 403 Forbidden, but specifically for use when authentication is required and has
962
+ * failed or has not yet been provided. The response must include a WWW-Authenticate header field
963
+ * containing a challenge applicable to the requested resource. See Basic access authentication
964
+ * and Digest access authentication. 401 semantically means "unauthenticated",i.e. the user does
965
+ * not have the necessary credentials.
966
+ */ HttpStatus[HttpStatus["Unauthorized"] = 401] = "Unauthorized";
967
+ /**
968
+ * Reserved for future use. The original intention was that this code might be used as part of
969
+ * some form of digital cash or micro payment scheme, but that has not happened, and this code is
970
+ * not usually used. Google Developers API uses this status if a particular developer has exceeded
971
+ * the daily limit on requests.
972
+ */ HttpStatus[HttpStatus["PaymentRequired"] = 402] = "PaymentRequired";
973
+ /**
974
+ * The request was valid, but the server is refusing action. The user might not have the necessary
975
+ * permissions for a resource.
976
+ */ HttpStatus[HttpStatus["Forbidden"] = 403] = "Forbidden";
977
+ /**
978
+ * The requested resource could not be found but may be available in the future. Subsequent
979
+ * requests by the client are permissible.
980
+ */ HttpStatus[HttpStatus["NotFound"] = 404] = "NotFound";
981
+ /**
982
+ * A request method is not supported for the requested resource; for example, a GET request on a
983
+ * form that requires data to be presented via POST, or a PUT request on a read-only resource.
984
+ */ HttpStatus[HttpStatus["MethodNotAllowed"] = 405] = "MethodNotAllowed";
985
+ /**
986
+ * The requested resource is capable of generating only content not acceptable according to the
987
+ * Accept headers sent in the request.
988
+ */ HttpStatus[HttpStatus["NotAcceptable"] = 406] = "NotAcceptable";
989
+ /** The client must first authenticate itself with the proxy. */ HttpStatus[HttpStatus["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
990
+ /**
991
+ * The server timed out waiting for the request. According to HTTP specifications: "The client did
992
+ * not produce a request within the time that the server was prepared to wait. The client MAY
993
+ * repeat the request without modifications at any later time."
994
+ */ HttpStatus[HttpStatus["RequestTimeout"] = 408] = "RequestTimeout";
995
+ /**
996
+ * Indicates that the request could not be processed because of conflict in the request, such as
997
+ * an edit conflict between multiple simultaneous updates.
998
+ */ HttpStatus[HttpStatus["Conflict"] = 409] = "Conflict";
999
+ /**
1000
+ * Indicates that the resource requested is no longer available and will not be available again.
1001
+ * This should be used when a resource has been intentionally removed and the resource should be
1002
+ * purged. Upon receiving a 410 status code, the client should not request the resource in the
1003
+ * future. Clients such as search engines should remove the resource from their indices. Most use
1004
+ * cases do not require clients and search engines to purge the resource, and a "404 Not Found"
1005
+ * may be used instead.
1006
+ */ HttpStatus[HttpStatus["Gone"] = 410] = "Gone";
1007
+ /**
1008
+ * The request did not specify the length of its content, which is required by the requested
1009
+ * resource.
1010
+ */ HttpStatus[HttpStatus["LengthRequired"] = 411] = "LengthRequired";
1011
+ /** The server does not meet one of the preconditions that the requester put on the request. */ HttpStatus[HttpStatus["PreconditionFailed"] = 412] = "PreconditionFailed";
1012
+ /**
1013
+ * The request is larger than the server is willing or able to process. Previously called "Request
1014
+ * Entity Too Large".
1015
+ */ HttpStatus[HttpStatus["PayloadTooLarge"] = 413] = "PayloadTooLarge";
1016
+ /**
1017
+ * The URI provided was too long for the server to process. Often the result of too much data
1018
+ * being encoded as a query-string of a GET request, in which case it should be converted to a
1019
+ * POST request. Called "Request-URI Too Long" previously.
1020
+ */ HttpStatus[HttpStatus["UriTooLong"] = 414] = "UriTooLong";
1021
+ /**
1022
+ * The request entity has a media type which the server or resource does not support. For example,
1023
+ * the client uploads an image as image/svg+xml, but the server requires that images use a
1024
+ * different format.
1025
+ */ HttpStatus[HttpStatus["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
1026
+ /**
1027
+ * The client has asked for a portion of the file (byte serving), but the server cannot supply
1028
+ * that portion. For example, if the client asked for a part of the file that lies beyond the end
1029
+ * of the file. Called "Requested Range Not Satisfiable" previously.
1030
+ */ HttpStatus[HttpStatus["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
1031
+ /** The server cannot meet the requirements of the Expect request-header field. */ HttpStatus[HttpStatus["ExpectationFailed"] = 417] = "ExpectationFailed";
1032
+ /**
1033
+ * This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324,
1034
+ * Hyper Text Coffee Pot Control Protocol, and is not expected to be implemented by actual HTTP
1035
+ * servers. The RFC specifies this code should be returned by teapots requested to brew coffee.
1036
+ * This HTTP status is used as an Easter egg in some websites, including Google.com.
1037
+ */ HttpStatus[HttpStatus["IAmATeapot"] = 418] = "IAmATeapot";
1038
+ /**
1039
+ * The request was directed at a server that is not able to produce a response (for example
1040
+ * because a connection reuse).
1041
+ */ HttpStatus[HttpStatus["MisdirectedRequest"] = 421] = "MisdirectedRequest";
1042
+ /** The request was well-formed but was unable to be followed due to semantic errors. */ HttpStatus[HttpStatus["UnprocessableEntity"] = 422] = "UnprocessableEntity";
1043
+ /** The resource that is being accessed is locked. */ HttpStatus[HttpStatus["Locked"] = 423] = "Locked";
1044
+ /** The request failed due to failure of a previous request (e.g., a PROPPATCH). */ HttpStatus[HttpStatus["FailedDependency"] = 424] = "FailedDependency";
1045
+ /**
1046
+ * The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header
1047
+ * field.
1048
+ */ HttpStatus[HttpStatus["UpgradeRequired"] = 426] = "UpgradeRequired";
1049
+ /**
1050
+ * The origin server requires the request to be conditional. Intended to prevent "the 'lost
1051
+ * update' problem, where a client GETs a resource's state, modifies it, and PUTs it back to the
1052
+ * server, when meanwhile a third party has modified the state on the server, leading to a
1053
+ * conflict."
1054
+ */ HttpStatus[HttpStatus["PreconditionRequired"] = 428] = "PreconditionRequired";
1055
+ /**
1056
+ * The user has sent too many requests in a given amount of time. Intended for use with
1057
+ * rate-limiting schemes.
1058
+ */ HttpStatus[HttpStatus["TooManyRequests"] = 429] = "TooManyRequests";
1059
+ /**
1060
+ * The server is unwilling to process the request because either an individual header field, or
1061
+ * all the header fields collectively, are too large.
1062
+ */ HttpStatus[HttpStatus["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
1063
+ /**
1064
+ * A server operator has received a legal demand to deny access to a resource or to a set of
1065
+ * resources that includes the requested resource. The code 451 was chosen as a reference to the
1066
+ * novel Fahrenheit 451.
1067
+ */ HttpStatus[HttpStatus["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
1068
+ /**
1069
+ * A generic error message, given when an unexpected condition was encountered and no more
1070
+ * specific message is suitable.
1071
+ */ HttpStatus[HttpStatus["InternalServerError"] = 500] = "InternalServerError";
1072
+ /**
1073
+ * The server either does not recognize the request method, or it lacks the ability to fulfill the
1074
+ * request. Usually this implies future availability (e.g., a new feature of a web-service API).
1075
+ */ HttpStatus[HttpStatus["NotImplemented"] = 501] = "NotImplemented";
1076
+ /**
1077
+ * The server was acting as a gateway or proxy and received an invalid response from the upstream
1078
+ * server.
1079
+ */ HttpStatus[HttpStatus["BadGateway"] = 502] = "BadGateway";
1080
+ /**
1081
+ * The server is currently unavailable (because it is overloaded or down for maintenance).
1082
+ * Generally, this is a temporary state.
1083
+ */ HttpStatus[HttpStatus["ServiceUnavailable"] = 503] = "ServiceUnavailable";
1084
+ /**
1085
+ * The server was acting as a gateway or proxy and did not receive a timely response from the
1086
+ * upstream server.
1087
+ */ HttpStatus[HttpStatus["GatewayTimeout"] = 504] = "GatewayTimeout";
1088
+ /** The server does not support the HTTP protocol version used in the request */ HttpStatus[HttpStatus["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
1089
+ /** Transparent content negotiation for the request results in a circular reference. */ HttpStatus[HttpStatus["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
1090
+ /** The server is unable to store the representation needed to complete the request. */ HttpStatus[HttpStatus["InsufficientStorage"] = 507] = "InsufficientStorage";
1091
+ /** The server detected an infinite loop while processing the request. */ HttpStatus[HttpStatus["LoopDetected"] = 508] = "LoopDetected";
1092
+ /** Further extensions to the request are required for the server to fulfill it. */ HttpStatus[HttpStatus["NotExtended"] = 510] = "NotExtended";
1093
+ /**
1094
+ * The client needs to authenticate to gain network access. Intended for use by intercepting
1095
+ * proxies used to control access to the network (e.g., "captive portals" used to require
1096
+ * agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot).
1097
+ */ HttpStatus[HttpStatus["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
1098
+ return HttpStatus;
1099
+ }({});
1100
+ function getQwikRouterServerData(requestEv) {
1101
+ const { params, request, status, locale, originalUrl } = requestEv;
1102
+ const requestHeaders = {};
1103
+ request.headers.forEach((value, key) => requestHeaders[key] = value);
1104
+ const action = requestEv.sharedMap.get(RequestEvSharedActionId);
1105
+ const actionResult = requestEv.sharedMap.get("@actionResult");
1106
+ const formData = requestEv.sharedMap.get(RequestEvSharedActionFormData);
1107
+ const routeName = requestEv.sharedMap.get(RequestRouteName);
1108
+ const nonce = requestEv.sharedMap.get(RequestEvSharedNonce);
1109
+ const headers = requestEv.request.headers;
1110
+ const reconstructedUrl = new URL(originalUrl.pathname + originalUrl.search, originalUrl);
1111
+ const host = headers.get("X-Forwarded-Host");
1112
+ const protocol = headers.get("X-Forwarded-Proto");
1113
+ if (host) {
1114
+ reconstructedUrl.port = "";
1115
+ reconstructedUrl.host = host;
1116
+ }
1117
+ if (protocol) reconstructedUrl.protocol = protocol;
1118
+ const routeLoaderCtx = getRouteLoaderCtx(requestEv);
1119
+ const loaderValues = getRouteLoaderValues(requestEv);
1120
+ return {
1121
+ url: reconstructedUrl.href,
1122
+ requestHeaders,
1123
+ renderMode: getRequestMode(requestEv),
1124
+ locale: locale(),
1125
+ nonce,
1126
+ containerAttributes: { [Q_ROUTE]: routeName },
1127
+ qwikrouter: {
1128
+ routeName,
1129
+ ev: requestEv,
1130
+ params: { ...params },
1131
+ loadedRoute: getRequestRoute(requestEv),
1132
+ routeLoaderCtx,
1133
+ loaderValues,
1134
+ response: {
1135
+ status: status(),
1136
+ statusMessage: requestEv.sharedMap.get(RequestEvHttpStatusMessage),
1137
+ action,
1138
+ actionResult,
1139
+ formData
1140
+ }
1141
+ }
1142
+ };
1143
+ }
1144
+ var loadHttpError = () => import("./http-error.qwik.mjs");
1145
+ function createResolveRequestHandlers() {
1146
+ const resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler) => {
1147
+ const routeLoaders = [];
1148
+ const routeActions = [];
1149
+ const requestHandlers = [];
1150
+ const isPageRoute = !!isLastModulePageRoute(route.$mods$);
1151
+ if (isPageRoute) {
1152
+ /**
1153
+ * JSON request wrapper must be before all middleware so it can rewrite the URL and catch
1154
+ * redirects/errors from plugin/route middleware via try/catch on next()
1155
+ */ requestHandlers.push(jsonRequestWrapper());
1156
+ requestHandlers.push(serverErrorMiddleware(route, renderHandler));
1157
+ }
1158
+ if (serverPlugins) _resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, serverPlugins, isPageRoute, method);
1159
+ if (!route.$notFound$ && isPageRoute && (method === "POST" || method === "GET")) requestHandlers.push(runServerFunction);
1160
+ const routeModules = route.$mods$;
1161
+ _resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, routeModules, isPageRoute, method, isPageRoute);
1162
+ const routeName = route.$routeName$;
1163
+ if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
1164
+ if (checkOrigin === "lax-proto") requestHandlers.unshift(csrfLaxProtoCheckMiddleware);
1165
+ else requestHandlers.unshift(csrfCheckMiddleware);
1166
+ }
1167
+ if (isPageRoute) {
1168
+ requestHandlers.push(loaderHandler(routeLoaders, route.$loaderPaths$));
1169
+ requestHandlers.push(actionHandler(routeActions));
1170
+ if (!route.$notFound$) requestHandlers.push(fixTrailingSlash);
1171
+ }
1172
+ if (isPageRoute) {
1173
+ requestHandlers.push((ev) => {
1174
+ ev.sharedMap.set(RequestRouteName, routeName);
1175
+ });
1176
+ requestHandlers.push(actionsMiddleware(routeActions));
1177
+ requestHandlers.push(loadersMiddleware(routeLoaders, route));
1178
+ requestHandlers.push(eTagMiddleware(route));
1179
+ requestHandlers.push(renderHandler);
1180
+ }
1181
+ return requestHandlers;
1182
+ };
1183
+ function _resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, routeModules, collectActions, method, guardPageHandlersForLoader = false) {
1184
+ for (let i = 0; i < routeModules.length; i++) {
1185
+ const routeModule = routeModules[i];
1186
+ const moduleHandlers = getModuleRequestHandlers(routeModule, method);
1187
+ const shouldGuardPageHandlers = guardPageHandlersForLoader && i === routeModules.length - 1;
1188
+ requestHandlers.push(...shouldGuardPageHandlers ? moduleHandlers.map((handler) => guardPageHandlerForLoader(routeModule, handler)) : moduleHandlers);
1189
+ if (collectActions) {
1190
+ for (const module of Object.values(routeModule)) if (typeof module === "function") {
1191
+ if (module.__brand === "server_loader") routeLoaders.push(module);
1192
+ else if (module.__brand === "server_action") routeActions.push(module);
1193
+ }
1194
+ }
1195
+ }
1196
+ }
1197
+ function getModuleRequestHandlers(routeModule, method) {
1198
+ const handlers = [];
1199
+ addRequestHandlers(handlers, routeModule.onRequest);
1200
+ let methodReqHandler;
1201
+ switch (method) {
1202
+ case "GET":
1203
+ methodReqHandler = routeModule.onGet;
1204
+ break;
1205
+ case "POST":
1206
+ methodReqHandler = routeModule.onPost;
1207
+ break;
1208
+ case "PUT":
1209
+ methodReqHandler = routeModule.onPut;
1210
+ break;
1211
+ case "PATCH":
1212
+ methodReqHandler = routeModule.onPatch;
1213
+ break;
1214
+ case "DELETE":
1215
+ methodReqHandler = routeModule.onDelete;
1216
+ break;
1217
+ case "OPTIONS":
1218
+ methodReqHandler = routeModule.onOptions;
1219
+ break;
1220
+ case "HEAD": methodReqHandler = routeModule.onHead;
1221
+ }
1222
+ addRequestHandlers(handlers, methodReqHandler);
1223
+ return handlers;
1224
+ }
1225
+ function addRequestHandlers(handlers, handler) {
1226
+ if (typeof handler === "function") handlers.push(handler);
1227
+ else if (Array.isArray(handler)) handlers.push(...handler);
1228
+ }
1229
+ function guardPageHandlerForLoader(routeModule, handler) {
1230
+ return (requestEv) => {
1231
+ if (requestEv.sharedMap.has("@isQLoader")) {
1232
+ if (!moduleHasLoader(routeModule, requestEv.sharedMap.get("@loaderId"))) return;
1233
+ }
1234
+ return handler(requestEv);
1235
+ };
1236
+ }
1237
+ function moduleHasLoader(routeModule, loaderId) {
1238
+ if (typeof loaderId !== "string") return false;
1239
+ for (const value of Object.values(routeModule)) if (checkBrand(value, "server_loader") && matchesRouteLoaderId(value, loaderId)) return true;
1240
+ return false;
1241
+ }
1242
+ const checkBrand = (obj, brand) => {
1243
+ return obj && typeof obj === "function" && obj.__brand === brand;
1244
+ };
1245
+ function actionsMiddleware(routeActions) {
1246
+ return async (requestEvent) => {
1247
+ const requestEv = requestEvent;
1248
+ if (requestEv.headersSent) {
1249
+ requestEv.exit();
1250
+ return;
1251
+ }
1252
+ const { method } = requestEv;
1253
+ if (isDev && method === "GET") {
1254
+ if (requestEv.query.has("qaction")) console.warn("Seems like you are submitting a Qwik Action via GET request. Qwik Actions should be submitted via POST request.\nMake sure your <form> has method=\"POST\" attribute, like this: <form method=\"POST\">");
1255
+ }
1256
+ if (method === "POST") {
1257
+ const selectedActionId = requestEv.query.get(QACTION_KEY);
1258
+ if (selectedActionId) {
1259
+ const serverActionsMap = globalThis._qwikActionsMap;
1260
+ const action = routeActions.find((action) => action.__id === selectedActionId) ?? serverActionsMap?.get(selectedActionId);
1261
+ if (action) {
1262
+ requestEv.sharedMap.set(RequestEvSharedActionId, selectedActionId);
1263
+ const data = await requestEv.parseBody();
1264
+ if (!data || typeof data !== "object") throw new Error(`Expected request data for the action id ${selectedActionId} to be an object`);
1265
+ const result = await runValidators(requestEv, action.__validators, data);
1266
+ let actionResult;
1267
+ if (!result.success) actionResult = requestEv.fail(result.status ?? 500, result.error);
1268
+ else {
1269
+ const actionResolved = isDev ? await measure(requestEv, action.__qrl.getHash(), () => action.__qrl.call(requestEv, result.data, requestEv)) : await action.__qrl.call(requestEv, result.data, requestEv);
1270
+ throwIfControlFlowSignal(actionResolved);
1271
+ if (isDev) verifySerializable(actionResolved, action.__qrl);
1272
+ actionResult = actionResolved;
1273
+ }
1274
+ requestEv.sharedMap.set("@actionResult", actionResult);
1275
+ }
1276
+ }
1277
+ }
1278
+ };
1279
+ }
1280
+ function loadersMiddleware(routeLoaders, route) {
1281
+ return (requestEvent) => {
1282
+ if (requestEvent.headersSent) {
1283
+ requestEvent.exit();
1284
+ return;
1285
+ }
1286
+ if (routeLoaders.length === 0) return;
1287
+ setLoaderData(requestEvent, routeLoaders, route);
1288
+ let allBlockSSRLoaders;
1289
+ for (let i = 0; i < routeLoaders.length; i++) {
1290
+ const loader = routeLoaders[i];
1291
+ const promise = loadRouteLoader(loader, requestEvent);
1292
+ promise.catch(() => {});
1293
+ if (loader.__blockSSR) allBlockSSRLoaders = allBlockSSRLoaders ? allBlockSSRLoaders.then(() => promise) : promise;
1294
+ }
1295
+ return allBlockSSRLoaders;
1296
+ };
1297
+ }
1298
+ function setLoaderData(requestEv, routeLoaders, route) {
1299
+ if (routeLoaders.length === 0) return;
1300
+ const routeLoaderCtx = getRouteLoaderCtx(requestEv);
1301
+ if (route.$loaderPaths$) Object.assign(routeLoaderCtx.loaderPaths, route.$loaderPaths$);
1302
+ setRouteLoaders(requestEv, routeLoaders);
1303
+ }
1304
+ function eTagMiddleware(route) {
1305
+ return (requestEv) => {
1306
+ if (requestEv.headersSent) return;
1307
+ if (requestEv.method !== "GET") return;
1308
+ const mods = route.$mods$;
1309
+ if (!mods.some((m) => {
1310
+ if (!m) return false;
1311
+ if (m.routeConfig) return typeof m.routeConfig === "function" || m.routeConfig.eTag !== void 0 || m.routeConfig.cacheKey !== void 0;
1312
+ return m.eTag !== void 0 || m.cacheKey !== void 0;
1313
+ })) return;
1314
+ const loaderValues = getRouteLoaderValues(requestEv);
1315
+ const getData = (loaderOrAction) => {
1316
+ const id = loaderOrAction.__id;
1317
+ if (loaderOrAction.__brand === "server_loader") {
1318
+ if (!(id in loaderValues)) throw new Error("Loader not executed for this request.");
1319
+ return loaderValues[id];
1320
+ }
1321
+ return requestEv.sharedMap.get("@actionId") === id ? requestEv.sharedMap.get("@actionResult") : void 0;
1322
+ };
1323
+ const routeLocation = {
1324
+ params: requestEv.params,
1325
+ url: requestEv.url,
1326
+ isNavigating: false,
1327
+ prevUrl: void 0
1328
+ };
1329
+ const status = requestEv.status();
1330
+ const config = resolveRouteConfig(getData, routeLocation, mods, "", status);
1331
+ const headProps = {
1332
+ head: config.head,
1333
+ status,
1334
+ withLocale: (fn) => fn(),
1335
+ resolveValue: getData,
1336
+ ...routeLocation
1337
+ };
1338
+ const resolvedETag = resolveETag(config.eTag, headProps);
1339
+ const normalizedETag = resolvedETag !== null ? normalizeETag(resolvedETag) : "";
1340
+ if (normalizedETag && performETagMatch(requestEv, normalizedETag)) return;
1341
+ if (MAX_CACHE_SIZE <= 0) return;
1342
+ const cacheKey = resolveCacheKey(config.cacheKey, defaultSsrCacheKey, requestEv, normalizedETag);
1343
+ if (!cacheKey) return;
1344
+ const cached = getCachedSsr(cacheKey);
1345
+ if (cached) {
1346
+ requestEv.headers.set("Content-Type", "text/html; charset=utf-8");
1347
+ requestEv.headers.set("X-SSR-Cache", "HIT");
1348
+ if (!normalizedETag) {
1349
+ if (performETagMatch(requestEv, cached.eTag)) return;
1350
+ } else setETagHeader(requestEv, cached.eTag);
1351
+ requestEv.send(status, cached.body);
1352
+ return;
1353
+ }
1354
+ requestEv.sharedMap.set(RequestEvETagCacheKey, {
1355
+ key: cacheKey,
1356
+ eTag: normalizedETag
1357
+ });
1358
+ };
1359
+ }
1360
+ function serverErrorMiddleware(route, renderHandler) {
1361
+ return async (requestEv) => {
1362
+ try {
1363
+ await requestEv.next();
1364
+ } catch (e) {
1365
+ if (!(e instanceof ServerError) || requestEv.headersSent) throw e;
1366
+ const accept = requestEv.request.headers.get("Accept");
1367
+ if (accept && !accept.includes("text/html")) throw e;
1368
+ const status = e.status;
1369
+ requestEv.status(status);
1370
+ const errorLoader = route.$errorLoader$;
1371
+ route.$mods$ = errorLoader ? await Promise.all(errorLoader.map((load) => load())) : [await loadHttpError()];
1372
+ requestEv.sharedMap.set(RequestEvHttpStatusMessage, typeof e.data === "string" ? e.data : "Server Error");
1373
+ clearErrorResponseData(requestEv);
1374
+ await renderHandler(requestEv);
1375
+ }
1376
+ };
1377
+ }
1378
+ function clearErrorResponseData(requestEv) {
1379
+ clearRouteLoaderData(requestEv);
1380
+ requestEv.sharedMap.delete(RequestEvSharedActionId);
1381
+ requestEv.sharedMap.delete(RequestEvSharedActionFormData);
1382
+ requestEv.sharedMap.delete("@actionResult");
1383
+ }
1384
+ async function runValidators(requestEv, validators, data) {
1385
+ let lastResult = {
1386
+ success: true,
1387
+ data
1388
+ };
1389
+ if (validators) for (const validator of validators) {
1390
+ if (isDev) lastResult = await measure(requestEv, `validator$`, () => validator.validate(requestEv, data));
1391
+ else lastResult = await validator.validate(requestEv, data);
1392
+ if (!lastResult.success) return lastResult;
1393
+ else data = lastResult.data;
1394
+ }
1395
+ return lastResult;
1396
+ }
1397
+ function isAsyncIterator(obj) {
1398
+ return obj ? typeof obj === "object" && Symbol.asyncIterator in obj : false;
1399
+ }
1400
+ async function runServerFunction(ev) {
1401
+ const serverFnHash = ev.query.get(QFN_KEY);
1402
+ if (serverFnHash && ev.request.headers.get("X-QRL") === serverFnHash && ev.request.headers.get("Content-Type") === "application/qwik-json") {
1403
+ ev.exit();
1404
+ const data = await ev.parseBody();
1405
+ if (!Array.isArray(data) || !(Array.isArray(data[0]) || data[0] === void 0)) throw ev.error(500, "Invalid request");
1406
+ const qrl = inlinedQrl(null, serverFnHash, data.slice(1));
1407
+ let result;
1408
+ try {
1409
+ if (isDev) result = await measure(ev, `server_${serverFnHash}`, () => qrl.apply(ev, data[0]));
1410
+ else result = await qrl.apply(ev, data[0]);
1411
+ } catch (err) {
1412
+ if (err instanceof ServerError) throw ev.error(err.status, err.data);
1413
+ console.error(`Server function ${serverFnHash} failed:`, err);
1414
+ throw ev.error(500, "Invalid request");
1415
+ }
1416
+ throwIfControlFlowSignal(result);
1417
+ if (isAsyncIterator(result)) await streamServerFunctionResult(ev, result, qrl);
1418
+ else {
1419
+ verifySerializable(result, qrl);
1420
+ ev.headers.set("Content-Type", "application/qwik-json");
1421
+ const message = await _serialize(result);
1422
+ ev.send(200, message);
1423
+ }
1424
+ return;
1425
+ }
1426
+ }
1427
+ async function streamServerFunctionResult(ev, result, qrl) {
1428
+ ev.headers.set("Content-Type", "text/qwik-json-stream");
1429
+ const stream = ev.getWritableStream().getWriter();
1430
+ for await (const item of result) {
1431
+ if (isDev) verifySerializable(item, qrl);
1432
+ const message = await _serialize(item);
1433
+ if (ev.signal.aborted) break;
1434
+ await stream.write(encoder.encode(`${message}\n`)).catch((err) => {
1435
+ if (isDev) console.error(`Server function ${qrl.getSymbol()} stream write failed:`, err);
1436
+ });
1437
+ }
1438
+ await stream.close().catch((err) => {
1439
+ if (isDev) console.error(`Server function ${qrl.getSymbol()} stream close failed:`, err);
1440
+ });
1441
+ }
1442
+ function fixTrailingSlash(ev) {
1443
+ const { basePathname, originalUrl } = ev;
1444
+ const { pathname, search } = originalUrl;
1445
+ if (!pathname.startsWith("/") || pathname.startsWith("//")) return;
1446
+ if (pathname !== basePathname && !pathname.endsWith(".html")) {
1447
+ if (!globalThis.__NO_TRAILING_SLASH__) {
1448
+ if (!pathname.endsWith("/")) throw ev.redirect(HttpStatus.MovedPermanently, ensureSlash(pathname) + search);
1449
+ } else if (pathname.endsWith("/")) throw ev.redirect(HttpStatus.MovedPermanently, pathname.slice(0, pathname.length - 1) + search);
1450
+ }
1451
+ }
1452
+ function verifySerializable(data, qrl) {
1453
+ try {
1454
+ _verifySerializable(data, void 0);
1455
+ } catch (e) {
1456
+ if (e instanceof Error && qrl.dev) e.loc = qrl.dev;
1457
+ throw e;
1458
+ }
1459
+ }
1460
+ const isQrl = (value) => {
1461
+ return typeof value === "function" && typeof value.getSymbol === "function";
1462
+ };
1463
+ function isLastModulePageRoute(routeModules) {
1464
+ const lastRouteModule = routeModules[routeModules.length - 1];
1465
+ return lastRouteModule && typeof lastRouteModule.default === "function";
1466
+ }
1467
+ function getPathname(url) {
1468
+ url = new URL(url);
1469
+ if (!globalThis.__NO_TRAILING_SLASH__) {
1470
+ if (!url.pathname.endsWith("/")) url.pathname = ensureSlash(url.pathname);
1471
+ } else if (url.pathname.endsWith("/")) url.pathname = url.pathname.slice(0, -1);
1472
+ const search = url.search.slice(1).replaceAll(/&?q(action|data|func|loaders)=[^&]+/g, "");
1473
+ return `${url.pathname}${search ? `?${search}` : ""}${url.hash}`;
1474
+ }
1475
+ function csrfLaxProtoCheckMiddleware(requestEv) {
1476
+ checkCSRF(requestEv, "lax-proto");
1477
+ }
1478
+ function csrfCheckMiddleware(requestEv) {
1479
+ checkCSRF(requestEv);
1480
+ }
1481
+ function checkCSRF(requestEv, laxProto) {
1482
+ if (!requestEv.request.headers.get("content-type") || isContentType(requestEv.request.headers, "application/x-www-form-urlencoded", "multipart/form-data", "text/plain")) {
1483
+ const inputOrigin = requestEv.request.headers.get("origin");
1484
+ const origin = requestEv.url.origin;
1485
+ let forbidden = inputOrigin !== origin;
1486
+ if (forbidden && laxProto && inputOrigin?.replace(/^http(s)?/g, "") === origin.replace(/^http(s)?/g, "")) forbidden = false;
1487
+ if (forbidden) throw requestEv.error(403, `CSRF check failed. Cross-site ${requestEv.method} form submissions are forbidden.
1488
+ The request origin "${inputOrigin}" does not match the server origin "${origin}".`);
1489
+ }
1490
+ }
1491
+ function renderQwikMiddleware(render) {
1492
+ return async (requestEv) => {
1493
+ if (requestEv.headersSent) return;
1494
+ const responseHeaders = requestEv.headers;
1495
+ if (!responseHeaders.has("Content-Type")) responseHeaders.set("Content-Type", "text/html; charset=utf-8");
1496
+ const cachePlan = requestEv.sharedMap.get(RequestEvETagCacheKey);
1497
+ const { readable, writable } = new TextEncoderStream();
1498
+ const writableStream = requestEv.getWritableStream();
1499
+ let cacheChunks;
1500
+ let pipeSource = readable;
1501
+ if (cachePlan) {
1502
+ cacheChunks = [];
1503
+ const capture = new TransformStream({ transform(chunk, controller) {
1504
+ cacheChunks.push(chunk);
1505
+ controller.enqueue(chunk);
1506
+ } });
1507
+ pipeSource = readable.pipeThrough(capture);
1508
+ }
1509
+ let pipeError;
1510
+ const pipe = pipeSource.pipeTo(writableStream, { preventClose: true }).catch((error) => {
1511
+ pipeError = error;
1512
+ });
1513
+ const stream = writable.getWriter();
1514
+ try {
1515
+ const isStatic = getRequestMode(requestEv) === "static";
1516
+ const serverData = getQwikRouterServerData(requestEv);
1517
+ const result = await render({
1518
+ base: requestEv.basePathname + "build/",
1519
+ stream,
1520
+ streaming: isStatic ? { outOfOrder: false } : void 0,
1521
+ serverData,
1522
+ containerAttributes: {
1523
+ ["q:render"]: isStatic ? "static" : "",
1524
+ ...serverData.containerAttributes
1525
+ }
1526
+ });
1527
+ if (typeof result.html === "string") await stream.write(result.html);
1528
+ } finally {
1529
+ await stream.ready;
1530
+ await stream.close();
1531
+ await pipe;
1532
+ }
1533
+ if (pipeError) throw pipeError;
1534
+ if (cachePlan && cacheChunks && cacheChunks.length > 0) {
1535
+ const totalLength = cacheChunks.reduce((sum, chunk) => sum + chunk.length, 0);
1536
+ const combined = new Uint8Array(totalLength);
1537
+ let offset = 0;
1538
+ for (const chunk of cacheChunks) {
1539
+ combined.set(chunk, offset);
1540
+ offset += chunk.length;
1541
+ }
1542
+ const html = new TextDecoder().decode(combined);
1543
+ const cachedETag = cachePlan.eTag || hash(html);
1544
+ setCachedSsr(cachePlan.key, {
1545
+ eTag: cachedETag,
1546
+ body: html
1547
+ });
1548
+ }
1549
+ await writableStream.close();
1550
+ };
1551
+ }
1552
+ function now() {
1553
+ return typeof performance !== "undefined" ? performance.now() : 0;
1554
+ }
1555
+ async function measure(requestEv, name, fn) {
1556
+ const start = now();
1557
+ try {
1558
+ return await fn();
1559
+ } finally {
1560
+ const duration = now() - start;
1561
+ let measurements = requestEv.sharedMap.get(RequestEvShareServerTiming);
1562
+ if (!measurements) requestEv.sharedMap.set(RequestEvShareServerTiming, measurements = []);
1563
+ measurements.push([name, duration]);
1564
+ }
1565
+ }
1566
+ return {
1567
+ actionsMiddleware,
1568
+ checkBrand,
1569
+ checkCSRF,
1570
+ fixTrailingSlash,
1571
+ getPathname,
1572
+ isLastModulePageRoute,
1573
+ isQrl,
1574
+ loadersMiddleware,
1575
+ measure,
1576
+ renderQwikMiddleware,
1577
+ resolveRequestHandlers,
1578
+ streamServerFunctionResult,
1579
+ verifySerializable
1580
+ };
1581
+ }
1582
+ var { actionsMiddleware, checkBrand, checkCSRF, fixTrailingSlash, getPathname, isLastModulePageRoute, isQrl, loadersMiddleware, measure, renderQwikMiddleware, resolveRequestHandlers, streamServerFunctionResult, verifySerializable } = createResolveRequestHandlers();
1583
+ /** @public */ var ESCAPE_HTML = /[&<>]/g;
1584
+ var escapeHtml = (s) => {
1585
+ return s.replace(ESCAPE_HTML, (c) => {
1586
+ switch (c) {
1587
+ case "&": return "&amp;";
1588
+ case "<": return "&lt;";
1589
+ case ">": return "&gt;";
1590
+ default: return "";
1591
+ }
1592
+ });
1593
+ };
1594
+ var COLOR_400 = "#006ce9";
1595
+ var COLOR_500 = "#713fc2";
1596
+ function minimalHtmlResponse(status, message) {
1597
+ if (typeof status !== "number") status = 500;
1598
+ if (typeof message === "string") message = escapeHtml(message);
1599
+ else message = "";
1600
+ const width = typeof message === "string" ? "600px" : "300px";
1601
+ const color = status >= 500 ? COLOR_500 : COLOR_400;
1602
+ return `
1603
+ <head>
1604
+ <meta charset="utf-8">
1605
+ <meta http-equiv="Status" content="${status}">
1606
+ <title>${status} ${message}</title>
1607
+ <meta name="viewport" content="width=device-width,initial-scale=1">
1608
+ <style>
1609
+ body { color: ${color}; background-color: #fafafa; padding: 30px; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Roboto, sans-serif; }
1610
+ p { max-width: ${width}; margin: 60px auto 30px auto; background: white; border-radius: 4px; box-shadow: 0px 0px 50px -20px ${color}; overflow: hidden; }
1611
+ strong { display: inline-block; padding: 15px; background: ${color}; color: white; }
1612
+ span { display: inline-block; padding: 15px; }
1613
+ </style>
1614
+ </head>
1615
+ <body><p><strong>${status}</strong> <span>${message}</span></p></body>
1616
+ `;
1617
+ }
1618
+ function getErrorHtml(status, e) {
1619
+ let message = "Server Error";
1620
+ if (e != null) {
1621
+ if (typeof e.message === "string") message = e.message;
1622
+ else message = String(e);
1623
+ }
1624
+ return `<html>` + minimalHtmlResponse(status, message) + `</html>`;
1625
+ }
1626
+ var ensureError = (e) => e instanceof Error || typeof e === "object" && e !== null ? e : new Error(String(e));
1627
+ async function runNext(requestEv, rebuildRouteInfo, resolve) {
1628
+ try {
1629
+ const isValidURL = (url) => new URL(url.pathname + url.search, url);
1630
+ isValidURL(requestEv.originalUrl);
1631
+ } catch {
1632
+ const status = 404;
1633
+ const message = "Resource Not Found";
1634
+ requestEv.status(status);
1635
+ requestEv.html(status, getErrorHtml(status, message));
1636
+ return new ServerError(status, message);
1637
+ }
1638
+ let rewriteAttempt = 1;
1639
+ async function runOnce() {
1640
+ try {
1641
+ await requestEv.next();
1642
+ } catch (e) {
1643
+ if (e instanceof RedirectMessage) {
1644
+ await requestEv.getWritableStream().close();
1645
+ return e;
1646
+ } else if (e instanceof RewriteMessage) {
1647
+ if (rewriteAttempt > 50) return /* @__PURE__ */ new Error(`Infinite rewrite loop`);
1648
+ rewriteAttempt += 1;
1649
+ const url = new URL(requestEv.url);
1650
+ url.pathname = e.pathname;
1651
+ const { loadedRoute, requestHandlers } = await rebuildRouteInfo(url);
1652
+ requestEv.resetRoute(loadedRoute, requestHandlers, url);
1653
+ return await runOnce();
1654
+ } else if (e instanceof AbortMessage) return;
1655
+ else if (e instanceof ServerError && !requestEv.headersSent) {
1656
+ const status = e.status;
1657
+ const accept = requestEv.request.headers.get("Accept");
1658
+ if (accept && !accept.includes("text/html")) {
1659
+ requestEv.headers.set("Content-Type", "application/qwik-json");
1660
+ requestEv.send(status, await _serialize(e.data));
1661
+ } else requestEv.html(status, getErrorHtml(status, e.data));
1662
+ return e;
1663
+ }
1664
+ if (!isDev$1) try {
1665
+ if (!requestEv.headersSent) {
1666
+ requestEv.headers.set("content-type", "text/html; charset=utf-8");
1667
+ requestEv.cacheControl({ noCache: true });
1668
+ requestEv.status(500);
1669
+ }
1670
+ const stream = requestEv.getWritableStream();
1671
+ if (!stream.locked) {
1672
+ const writer = stream.getWriter();
1673
+ await writer.write(encoder.encode(getErrorHtml(500, "Internal Server Error")));
1674
+ await writer.close();
1675
+ }
1676
+ } catch {
1677
+ console.error("Unable to render error page");
1678
+ }
1679
+ return e instanceof Error || typeof e === "object" && e !== null ? e : new Error(String(e));
1680
+ }
1681
+ }
1682
+ try {
1683
+ return await runOnce();
1684
+ } finally {
1685
+ if (!requestEv.isDirty()) resolve(null);
1686
+ }
1687
+ }
1688
+ function runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, basePathname = "/") {
1689
+ let resolve;
1690
+ const responsePromise = new Promise((r) => resolve = r);
1691
+ try {
1692
+ const requestEv = createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, basePathname, resolve);
1693
+ return {
1694
+ response: responsePromise,
1695
+ requestEv,
1696
+ completion: _asyncRequestStore ? _asyncRequestStore.run(requestEv, runNext, requestEv, rebuildRouteInfo, resolve) : runNext(requestEv, rebuildRouteInfo, resolve)
1697
+ };
1698
+ } catch (e) {
1699
+ resolve(null);
1700
+ return {
1701
+ response: responsePromise,
1702
+ requestEv: { headersSent: false },
1703
+ completion: Promise.resolve(ensureError(e))
1704
+ };
1705
+ }
1706
+ }
1707
+ export { clearLoaderCache as a, mergeHeadersCookies as c, resolveRequestHandlers as i, getErrorHtml as n, clearSsrCache as o, renderQwikMiddleware as r, RewriteMessage as s, runQwikRouter as t };