@qwik.dev/router 2.0.0-beta.3 → 2.0.0-beta.30
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.
- package/adapters/static/vite.d.ts +1 -1
- package/lib/adapters/azure-swa/vite/index.d.ts +2 -2
- package/lib/adapters/azure-swa/vite/index.mjs +39 -44
- package/lib/adapters/bun-server/vite/index.d.ts +2 -2
- package/lib/adapters/bun-server/vite/index.mjs +6 -7
- package/lib/adapters/cloud-run/vite/index.d.ts +2 -2
- package/lib/adapters/cloud-run/vite/index.mjs +6 -7
- package/lib/adapters/cloudflare-pages/vite/index.d.ts +2 -2
- package/lib/adapters/cloudflare-pages/vite/index.mjs +23 -32
- package/lib/adapters/deno-server/vite/index.d.ts +2 -2
- package/lib/adapters/deno-server/vite/index.mjs +13 -9
- package/lib/adapters/netlify-edge/vite/index.d.ts +2 -2
- package/lib/adapters/netlify-edge/vite/index.mjs +22 -36
- package/lib/adapters/node-server/vite/index.d.ts +2 -2
- package/lib/adapters/node-server/vite/index.mjs +6 -7
- package/lib/adapters/shared/vite/index.d.ts +7 -19
- package/lib/adapters/shared/vite/index.mjs +244 -233
- package/lib/adapters/ssg/vite/index.d.ts +13 -0
- package/lib/adapters/ssg/vite/index.mjs +17 -0
- package/lib/adapters/vercel-edge/vite/index.d.ts +3 -3
- package/lib/adapters/vercel-edge/vite/index.mjs +33 -19
- package/lib/chunks/deepFreeze.qwik.mjs +18 -0
- package/lib/chunks/error-handler.mjs +57 -0
- package/lib/chunks/fs.mjs +144 -0
- package/lib/chunks/http-error.qwik.mjs +35 -0
- package/lib/chunks/mime-types.mjs +52 -0
- package/lib/chunks/not-found-wrapper.qwik.mjs +25 -0
- package/lib/chunks/pathname.mjs +105 -0
- package/lib/chunks/redirect-handler.mjs +6 -0
- package/lib/chunks/routing.qwik.mjs +820 -0
- package/lib/chunks/system.mjs +333 -0
- package/lib/chunks/use-functions.qwik.mjs +35 -0
- package/lib/chunks/worker-thread.qwik.mjs +2572 -0
- package/lib/index.d.ts +358 -141
- package/lib/index.qwik.mjs +865 -1156
- package/lib/middleware/aws-lambda/index.d.ts +3 -2
- package/lib/middleware/aws-lambda/index.mjs +15 -13
- package/lib/middleware/azure-swa/index.mjs +17 -218
- package/lib/middleware/bun/index.d.ts +11 -0
- package/lib/middleware/bun/index.mjs +51 -94
- package/lib/middleware/cloudflare-pages/index.mjs +23 -28
- package/lib/middleware/deno/index.d.ts +11 -0
- package/lib/middleware/deno/index.mjs +50 -94
- package/lib/middleware/firebase/index.mjs +7 -11
- package/lib/middleware/netlify-edge/index.mjs +23 -29
- package/lib/middleware/node/index.mjs +31 -100
- package/lib/middleware/request-handler/index.d.ts +161 -83
- package/lib/middleware/request-handler/index.mjs +1458 -1257
- package/lib/middleware/vercel-edge/index.mjs +28 -33
- package/lib/modules.d.ts +11 -16
- package/lib/service-worker/index.mjs +4 -0
- package/lib/{static → ssg}/index.d.ts +45 -13
- package/lib/ssg/index.mjs +336 -0
- package/lib/vite/index.d.ts +38 -10
- package/lib/vite/index.mjs +2067 -26841
- package/modules.d.ts +11 -16
- package/package.json +62 -67
- package/ssg.d.ts +2 -0
- package/static.d.ts +1 -1
- package/lib/adapters/azure-swa/vite/index.cjs +0 -96
- package/lib/adapters/bun-server/vite/index.cjs +0 -50
- package/lib/adapters/cloud-run/vite/index.cjs +0 -47
- package/lib/adapters/cloudflare-pages/vite/index.cjs +0 -115
- package/lib/adapters/deno-server/vite/index.cjs +0 -62
- package/lib/adapters/netlify-edge/vite/index.cjs +0 -129
- package/lib/adapters/node-server/vite/index.cjs +0 -50
- package/lib/adapters/shared/vite/index.cjs +0 -378
- package/lib/adapters/static/vite/index.cjs +0 -368
- package/lib/adapters/static/vite/index.d.ts +0 -10
- package/lib/adapters/static/vite/index.mjs +0 -331
- package/lib/adapters/vercel-edge/vite/index.cjs +0 -118
- package/lib/index.qwik.cjs +0 -1947
- package/lib/middleware/node/index.cjs +0 -314
- package/lib/middleware/request-handler/index.cjs +0 -1614
- package/lib/service-worker.cjs +0 -17
- package/lib/service-worker.mjs +0 -15
- package/lib/static/deno.mjs +0 -8
- package/lib/static/index.cjs +0 -67
- package/lib/static/index.mjs +0 -48
- package/lib/static/node.cjs +0 -1124
- package/lib/static/node.mjs +0 -1086
- package/lib/vite/index.cjs +0 -27445
- package/middleware/request-handler/generated/not-found-paths.ts +0 -7
- package/middleware/request-handler/generated/static-paths.ts +0 -35
|
@@ -1,652 +1,292 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { Q as Q_ROUTE, m as resolveRouteConfig, n as QLOADER_KEY, h as QFN_KEY, j as QACTION_KEY, o as isPromise, k as QDATA_KEY, e as loadRoute } from '../../chunks/routing.qwik.mjs';
|
|
2
|
+
import { isDev, _UNINITIALIZED, _deserialize, _verifySerializable, _serialize } from '@qwik.dev/core/internal';
|
|
3
|
+
import { inlinedQrl } from '@qwik.dev/core';
|
|
4
|
+
import { R as RedirectMessage, A as AbortMessage } from '../../chunks/redirect-handler.mjs';
|
|
5
|
+
import { isServer } from '@qwik.dev/core/build';
|
|
6
|
+
import { g as getErrorHtml, m as minimalHtmlResponse } from '../../chunks/error-handler.mjs';
|
|
7
|
+
|
|
8
|
+
const IsQData = "@isQData";
|
|
9
|
+
const QDATA_JSON = "/q-data.json";
|
|
10
|
+
function getRouteMatchPathname(pathname) {
|
|
11
|
+
const isInternal = pathname.endsWith(QDATA_JSON);
|
|
12
|
+
if (isInternal) {
|
|
13
|
+
const trimEnd = pathname.length - QDATA_JSON.length + (globalThis.__NO_TRAILING_SLASH__ ? 0 : 1);
|
|
14
|
+
pathname = pathname.slice(0, trimEnd);
|
|
15
|
+
if (pathname === "") {
|
|
16
|
+
pathname = "/";
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
status = 500;
|
|
23
|
-
}
|
|
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
|
-
`;
|
|
19
|
+
return {
|
|
20
|
+
pathname,
|
|
21
|
+
isInternal
|
|
22
|
+
};
|
|
46
23
|
}
|
|
47
|
-
var ESCAPE_HTML = /[&<>]/g;
|
|
48
|
-
var escapeHtml = (s) => {
|
|
49
|
-
return s.replace(ESCAPE_HTML, (c) => {
|
|
50
|
-
switch (c) {
|
|
51
|
-
case "&":
|
|
52
|
-
return "&";
|
|
53
|
-
case "<":
|
|
54
|
-
return "<";
|
|
55
|
-
case ">":
|
|
56
|
-
return ">";
|
|
57
|
-
default:
|
|
58
|
-
return "";
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
var COLOR_400 = "#006ce9";
|
|
63
|
-
var COLOR_500 = "#713fc2";
|
|
64
24
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
none: "None",
|
|
71
|
-
strict: "Strict",
|
|
72
|
-
Strict: "Strict"
|
|
73
|
-
};
|
|
74
|
-
var UNIT = {
|
|
75
|
-
seconds: 1,
|
|
76
|
-
minutes: 1 * 60,
|
|
77
|
-
hours: 1 * 60 * 60,
|
|
78
|
-
days: 1 * 60 * 60 * 24,
|
|
79
|
-
weeks: 1 * 60 * 60 * 24 * 7
|
|
80
|
-
};
|
|
81
|
-
var createSetCookieValue = (cookieName, cookieValue, options) => {
|
|
82
|
-
const c = [`${cookieName}=${cookieValue}`];
|
|
83
|
-
if (typeof options.domain === "string") {
|
|
84
|
-
c.push(`Domain=${options.domain}`);
|
|
85
|
-
}
|
|
86
|
-
if (typeof options.maxAge === "number") {
|
|
87
|
-
c.push(`Max-Age=${options.maxAge}`);
|
|
88
|
-
} else if (Array.isArray(options.maxAge)) {
|
|
89
|
-
c.push(`Max-Age=${options.maxAge[0] * UNIT[options.maxAge[1]]}`);
|
|
90
|
-
} else if (typeof options.expires === "number" || typeof options.expires == "string") {
|
|
91
|
-
c.push(`Expires=${options.expires}`);
|
|
92
|
-
} else if (options.expires instanceof Date) {
|
|
93
|
-
c.push(`Expires=${options.expires.toUTCString()}`);
|
|
94
|
-
}
|
|
95
|
-
if (options.httpOnly) {
|
|
96
|
-
c.push("HttpOnly");
|
|
97
|
-
}
|
|
98
|
-
if (typeof options.path === "string") {
|
|
99
|
-
c.push(`Path=${options.path}`);
|
|
100
|
-
}
|
|
101
|
-
const sameSite = resolveSameSite(options.sameSite);
|
|
102
|
-
if (sameSite) {
|
|
103
|
-
c.push(`SameSite=${sameSite}`);
|
|
104
|
-
}
|
|
105
|
-
if (options.secure) {
|
|
106
|
-
c.push("Secure");
|
|
25
|
+
const MAX_CACHE_SIZE = typeof globalThis.__SSR_CACHE_SIZE__ === "number" ? globalThis.__SSR_CACHE_SIZE__ : 50;
|
|
26
|
+
const ssrCache = /* @__PURE__ */ new Map();
|
|
27
|
+
function resolveETag(eTagExport, headProps) {
|
|
28
|
+
if (eTagExport === void 0) {
|
|
29
|
+
return null;
|
|
107
30
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
function tryDecodeUriComponent(str) {
|
|
111
|
-
try {
|
|
112
|
-
return decodeURIComponent(str);
|
|
113
|
-
} catch {
|
|
114
|
-
return str;
|
|
31
|
+
if (typeof eTagExport === "function") {
|
|
32
|
+
return eTagExport(headProps);
|
|
115
33
|
}
|
|
34
|
+
return eTagExport;
|
|
116
35
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const cookieSegments = cookieString.split(";");
|
|
121
|
-
for (const cookieSegment of cookieSegments) {
|
|
122
|
-
const separatorIndex = cookieSegment.indexOf("=");
|
|
123
|
-
if (separatorIndex !== -1) {
|
|
124
|
-
cookie[tryDecodeUriComponent(cookieSegment.slice(0, separatorIndex).trim())] = tryDecodeUriComponent(cookieSegment.slice(separatorIndex + 1).trim());
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return cookie;
|
|
129
|
-
};
|
|
130
|
-
function resolveSameSite(sameSite) {
|
|
131
|
-
if (sameSite === true) {
|
|
132
|
-
return "Strict";
|
|
36
|
+
function resolveCacheKey(cacheKeyExport, status, eTag, pathname) {
|
|
37
|
+
if (cacheKeyExport === true) {
|
|
38
|
+
return `${status}|${eTag}|${pathname}`;
|
|
133
39
|
}
|
|
134
|
-
if (
|
|
135
|
-
return
|
|
136
|
-
}
|
|
137
|
-
if (sameSite) {
|
|
138
|
-
return SAMESITE[sameSite];
|
|
40
|
+
if (typeof cacheKeyExport !== "function") {
|
|
41
|
+
return null;
|
|
139
42
|
}
|
|
140
|
-
return
|
|
43
|
+
return cacheKeyExport(status, eTag, pathname);
|
|
141
44
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
[RES_COOKIE] = {};
|
|
148
|
-
[LIVE_COOKIE] = {};
|
|
149
|
-
appendCounter = 0;
|
|
150
|
-
constructor(cookieString) {
|
|
151
|
-
this[REQ_COOKIE] = parseCookieString(cookieString);
|
|
152
|
-
this[LIVE_COOKIE] = { ...this[REQ_COOKIE] };
|
|
153
|
-
}
|
|
154
|
-
get(cookieName, live = true) {
|
|
155
|
-
const value = this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
|
|
156
|
-
if (!value) {
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
value,
|
|
161
|
-
json() {
|
|
162
|
-
return JSON.parse(value);
|
|
163
|
-
},
|
|
164
|
-
number() {
|
|
165
|
-
return Number(value);
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
getAll(live = true) {
|
|
170
|
-
return Object.keys(this[live ? LIVE_COOKIE : REQ_COOKIE]).reduce(
|
|
171
|
-
(cookies, cookieName) => {
|
|
172
|
-
cookies[cookieName] = this.get(cookieName);
|
|
173
|
-
return cookies;
|
|
174
|
-
},
|
|
175
|
-
{}
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
has(cookieName, live = true) {
|
|
179
|
-
return !!this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
|
|
180
|
-
}
|
|
181
|
-
set(cookieName, cookieValue, options = {}) {
|
|
182
|
-
this[LIVE_COOKIE][cookieName] = typeof cookieValue === "string" ? cookieValue : JSON.stringify(cookieValue);
|
|
183
|
-
const resolvedValue = typeof cookieValue === "string" ? cookieValue : encodeURIComponent(JSON.stringify(cookieValue));
|
|
184
|
-
this[RES_COOKIE][cookieName] = createSetCookieValue(cookieName, resolvedValue, options);
|
|
185
|
-
}
|
|
186
|
-
append(cookieName, cookieValue, options = {}) {
|
|
187
|
-
this[LIVE_COOKIE][cookieName] = typeof cookieValue === "string" ? cookieValue : JSON.stringify(cookieValue);
|
|
188
|
-
const resolvedValue = typeof cookieValue === "string" ? cookieValue : encodeURIComponent(JSON.stringify(cookieValue));
|
|
189
|
-
this[RES_COOKIE][++this.appendCounter] = createSetCookieValue(
|
|
190
|
-
cookieName,
|
|
191
|
-
resolvedValue,
|
|
192
|
-
options
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
delete(name, options) {
|
|
196
|
-
this.set(name, "deleted", { ...options, maxAge: 0 });
|
|
197
|
-
this[LIVE_COOKIE][name] = null;
|
|
198
|
-
}
|
|
199
|
-
headers() {
|
|
200
|
-
return Object.values(this[RES_COOKIE]);
|
|
45
|
+
function getCachedHtml(key) {
|
|
46
|
+
const html = ssrCache.get(key);
|
|
47
|
+
if (html !== void 0) {
|
|
48
|
+
ssrCache.delete(key);
|
|
49
|
+
ssrCache.set(key, html);
|
|
201
50
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
for (const cookie of cookieHeaders) {
|
|
208
|
-
newHeaders.append("Set-Cookie", cookie);
|
|
209
|
-
}
|
|
210
|
-
return newHeaders;
|
|
51
|
+
return html;
|
|
52
|
+
}
|
|
53
|
+
function setCachedHtml(key, html) {
|
|
54
|
+
if (MAX_CACHE_SIZE <= 0) {
|
|
55
|
+
return;
|
|
211
56
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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;
|
|
57
|
+
if (ssrCache.size >= MAX_CACHE_SIZE) {
|
|
58
|
+
const firstKey = ssrCache.keys().next().value;
|
|
59
|
+
ssrCache.delete(firstKey);
|
|
226
60
|
}
|
|
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);
|
|
61
|
+
ssrCache.set(key, html);
|
|
242
62
|
}
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
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 || {};
|
|
63
|
+
function clearSsrCache(cacheKey) {
|
|
64
|
+
if (cacheKey != null) {
|
|
65
|
+
ssrCache.delete(cacheKey);
|
|
290
66
|
} else {
|
|
291
|
-
|
|
67
|
+
ssrCache.clear();
|
|
292
68
|
}
|
|
293
69
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
70
|
+
|
|
71
|
+
var HttpStatus = /* @__PURE__ */ (function(HttpStatus2) {
|
|
72
|
+
HttpStatus2[HttpStatus2["Continue"] = 100] = "Continue";
|
|
73
|
+
HttpStatus2[HttpStatus2["SwitchingProtocols"] = 101] = "SwitchingProtocols";
|
|
74
|
+
HttpStatus2[HttpStatus2["Processing"] = 102] = "Processing";
|
|
75
|
+
HttpStatus2[HttpStatus2["Ok"] = 200] = "Ok";
|
|
76
|
+
HttpStatus2[HttpStatus2["Created"] = 201] = "Created";
|
|
77
|
+
HttpStatus2[HttpStatus2["Accepted"] = 202] = "Accepted";
|
|
78
|
+
HttpStatus2[HttpStatus2["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
|
|
79
|
+
HttpStatus2[HttpStatus2["NoContent"] = 204] = "NoContent";
|
|
80
|
+
HttpStatus2[HttpStatus2["ResetContent"] = 205] = "ResetContent";
|
|
81
|
+
HttpStatus2[HttpStatus2["PartialContent"] = 206] = "PartialContent";
|
|
82
|
+
HttpStatus2[HttpStatus2["MultiStatus"] = 207] = "MultiStatus";
|
|
83
|
+
HttpStatus2[HttpStatus2["AlreadyReported"] = 208] = "AlreadyReported";
|
|
84
|
+
HttpStatus2[HttpStatus2["ImUsed"] = 226] = "ImUsed";
|
|
85
|
+
HttpStatus2[HttpStatus2["MultipleChoices"] = 300] = "MultipleChoices";
|
|
86
|
+
HttpStatus2[HttpStatus2["MovedPermanently"] = 301] = "MovedPermanently";
|
|
87
|
+
HttpStatus2[HttpStatus2["Found"] = 302] = "Found";
|
|
88
|
+
HttpStatus2[HttpStatus2["SeeOther"] = 303] = "SeeOther";
|
|
89
|
+
HttpStatus2[HttpStatus2["NotModified"] = 304] = "NotModified";
|
|
90
|
+
HttpStatus2[HttpStatus2["UseProxy"] = 305] = "UseProxy";
|
|
91
|
+
HttpStatus2[HttpStatus2["SwitchProxy"] = 306] = "SwitchProxy";
|
|
92
|
+
HttpStatus2[HttpStatus2["TemporaryRedirect"] = 307] = "TemporaryRedirect";
|
|
93
|
+
HttpStatus2[HttpStatus2["PermanentRedirect"] = 308] = "PermanentRedirect";
|
|
94
|
+
HttpStatus2[HttpStatus2["BadRequest"] = 400] = "BadRequest";
|
|
95
|
+
HttpStatus2[HttpStatus2["Unauthorized"] = 401] = "Unauthorized";
|
|
96
|
+
HttpStatus2[HttpStatus2["PaymentRequired"] = 402] = "PaymentRequired";
|
|
97
|
+
HttpStatus2[HttpStatus2["Forbidden"] = 403] = "Forbidden";
|
|
98
|
+
HttpStatus2[HttpStatus2["NotFound"] = 404] = "NotFound";
|
|
99
|
+
HttpStatus2[HttpStatus2["MethodNotAllowed"] = 405] = "MethodNotAllowed";
|
|
100
|
+
HttpStatus2[HttpStatus2["NotAcceptable"] = 406] = "NotAcceptable";
|
|
101
|
+
HttpStatus2[HttpStatus2["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
|
|
102
|
+
HttpStatus2[HttpStatus2["RequestTimeout"] = 408] = "RequestTimeout";
|
|
103
|
+
HttpStatus2[HttpStatus2["Conflict"] = 409] = "Conflict";
|
|
104
|
+
HttpStatus2[HttpStatus2["Gone"] = 410] = "Gone";
|
|
105
|
+
HttpStatus2[HttpStatus2["LengthRequired"] = 411] = "LengthRequired";
|
|
106
|
+
HttpStatus2[HttpStatus2["PreconditionFailed"] = 412] = "PreconditionFailed";
|
|
107
|
+
HttpStatus2[HttpStatus2["PayloadTooLarge"] = 413] = "PayloadTooLarge";
|
|
108
|
+
HttpStatus2[HttpStatus2["UriTooLong"] = 414] = "UriTooLong";
|
|
109
|
+
HttpStatus2[HttpStatus2["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
|
|
110
|
+
HttpStatus2[HttpStatus2["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
|
|
111
|
+
HttpStatus2[HttpStatus2["ExpectationFailed"] = 417] = "ExpectationFailed";
|
|
112
|
+
HttpStatus2[HttpStatus2["IAmATeapot"] = 418] = "IAmATeapot";
|
|
113
|
+
HttpStatus2[HttpStatus2["MisdirectedRequest"] = 421] = "MisdirectedRequest";
|
|
114
|
+
HttpStatus2[HttpStatus2["UnprocessableEntity"] = 422] = "UnprocessableEntity";
|
|
115
|
+
HttpStatus2[HttpStatus2["Locked"] = 423] = "Locked";
|
|
116
|
+
HttpStatus2[HttpStatus2["FailedDependency"] = 424] = "FailedDependency";
|
|
117
|
+
HttpStatus2[HttpStatus2["UpgradeRequired"] = 426] = "UpgradeRequired";
|
|
118
|
+
HttpStatus2[HttpStatus2["PreconditionRequired"] = 428] = "PreconditionRequired";
|
|
119
|
+
HttpStatus2[HttpStatus2["TooManyRequests"] = 429] = "TooManyRequests";
|
|
120
|
+
HttpStatus2[HttpStatus2["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
|
|
121
|
+
HttpStatus2[HttpStatus2["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
|
|
122
|
+
HttpStatus2[HttpStatus2["InternalServerError"] = 500] = "InternalServerError";
|
|
123
|
+
HttpStatus2[HttpStatus2["NotImplemented"] = 501] = "NotImplemented";
|
|
124
|
+
HttpStatus2[HttpStatus2["BadGateway"] = 502] = "BadGateway";
|
|
125
|
+
HttpStatus2[HttpStatus2["ServiceUnavailable"] = 503] = "ServiceUnavailable";
|
|
126
|
+
HttpStatus2[HttpStatus2["GatewayTimeout"] = 504] = "GatewayTimeout";
|
|
127
|
+
HttpStatus2[HttpStatus2["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
|
|
128
|
+
HttpStatus2[HttpStatus2["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
|
|
129
|
+
HttpStatus2[HttpStatus2["InsufficientStorage"] = 507] = "InsufficientStorage";
|
|
130
|
+
HttpStatus2[HttpStatus2["LoopDetected"] = 508] = "LoopDetected";
|
|
131
|
+
HttpStatus2[HttpStatus2["NotExtended"] = 510] = "NotExtended";
|
|
132
|
+
HttpStatus2[HttpStatus2["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
|
|
133
|
+
return HttpStatus2;
|
|
134
|
+
})({});
|
|
135
|
+
|
|
136
|
+
const RequestEvLoaders = /* @__PURE__ */ Symbol("RequestEvLoaders");
|
|
137
|
+
const RequestEvMode = /* @__PURE__ */ Symbol("RequestEvMode");
|
|
138
|
+
const RequestEvRoute = /* @__PURE__ */ Symbol("RequestEvRoute");
|
|
139
|
+
const RequestEvLoaderSerializationStrategyMap = /* @__PURE__ */ Symbol("RequestEvLoaderSerializationStrategyMap");
|
|
140
|
+
const RequestRouteName = "@routeName";
|
|
141
|
+
const RequestEvSharedActionId = "@actionId";
|
|
142
|
+
const RequestEvSharedActionFormData = "@actionFormData";
|
|
143
|
+
const RequestEvSharedNonce = "@nonce";
|
|
144
|
+
const RequestEvIsRewrite = "@rewrite";
|
|
145
|
+
const RequestEvShareServerTiming = "@serverTiming";
|
|
146
|
+
const RequestEvETagCacheKey = "@eTagCacheKey";
|
|
147
|
+
const RequestEvHttpStatusMessage = "@httpStatusMessage";
|
|
148
|
+
const RequestEvShareQData = "qData";
|
|
149
|
+
function getRequestLoaders(requestEv) {
|
|
150
|
+
return requestEv[RequestEvLoaders];
|
|
300
151
|
}
|
|
301
|
-
function
|
|
302
|
-
|
|
303
|
-
return idx >= length || idx == length - 1 && text.charCodeAt(idx) === 47 /* SLASH */;
|
|
152
|
+
function getRequestLoaderSerializationStrategyMap(requestEv) {
|
|
153
|
+
return requestEv[RequestEvLoaderSerializationStrategyMap];
|
|
304
154
|
}
|
|
305
|
-
function
|
|
306
|
-
return
|
|
155
|
+
function getRequestRoute(requestEv) {
|
|
156
|
+
return requestEv[RequestEvRoute];
|
|
307
157
|
}
|
|
308
|
-
function
|
|
309
|
-
return
|
|
158
|
+
function getRequestMode(requestEv) {
|
|
159
|
+
return requestEv[RequestEvMode];
|
|
310
160
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const
|
|
316
|
-
for (
|
|
317
|
-
|
|
318
|
-
|
|
161
|
+
const ABORT_INDEX = Number.MAX_SAFE_INTEGER;
|
|
162
|
+
const isDangerousKey = (k) => k === "__proto__" || k === "constructor" || k === "prototype";
|
|
163
|
+
const isArrayIndexKey = (k) => /^(0|[1-9]\d*)$/.test(k);
|
|
164
|
+
const getArrayPaths = (formData) => {
|
|
165
|
+
const arrayCandidates = /* @__PURE__ */ new Map();
|
|
166
|
+
for (const [name] of formData) {
|
|
167
|
+
const keys = name.split(".");
|
|
168
|
+
let hasDangerousKey = false;
|
|
169
|
+
for (const key of keys) {
|
|
170
|
+
if (isDangerousKey(key)) {
|
|
171
|
+
hasDangerousKey = true;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
319
174
|
}
|
|
320
|
-
|
|
321
|
-
|
|
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;
|
|
175
|
+
if (hasDangerousKey) {
|
|
176
|
+
continue;
|
|
338
177
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
178
|
+
let path = "";
|
|
179
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
180
|
+
const key = keys[i];
|
|
181
|
+
if (key.endsWith("[]")) {
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
path = path ? `${path}.${key}` : key;
|
|
185
|
+
if (!arrayCandidates.has(path)) {
|
|
186
|
+
arrayCandidates.set(path, true);
|
|
187
|
+
}
|
|
188
|
+
if (!isArrayIndexKey(keys[i + 1])) {
|
|
189
|
+
arrayCandidates.set(path, false);
|
|
190
|
+
}
|
|
342
191
|
}
|
|
343
|
-
pathIdx = newPathIdx;
|
|
344
192
|
}
|
|
345
|
-
return
|
|
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";
|
|
193
|
+
return new Set(Array.from(arrayCandidates.entries()).filter(([, isArrayPath]) => isArrayPath).map(([path]) => path));
|
|
358
194
|
};
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
195
|
+
const formToObj = (formData) => {
|
|
196
|
+
const values = /* @__PURE__ */ Object.create(null);
|
|
197
|
+
const arrayPaths = getArrayPaths(formData);
|
|
198
|
+
for (const [name, value] of formData) {
|
|
199
|
+
const keys = name.split(".");
|
|
200
|
+
let hasDangerousKey = false;
|
|
201
|
+
for (let i = 0; i < keys.length; i++) {
|
|
202
|
+
if (isDangerousKey(keys[i])) {
|
|
203
|
+
hasDangerousKey = true;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
367
206
|
}
|
|
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) {
|
|
207
|
+
if (hasDangerousKey) {
|
|
381
208
|
continue;
|
|
382
209
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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);
|
|
210
|
+
let object = values;
|
|
211
|
+
let path = "";
|
|
212
|
+
for (let i = 0; i < keys.length; i++) {
|
|
213
|
+
const key = keys[i];
|
|
214
|
+
if (key.endsWith("[]")) {
|
|
215
|
+
const arrayKey = key.slice(0, -2);
|
|
216
|
+
if (isDangerousKey(arrayKey)) {
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
const existingValue = object[arrayKey];
|
|
220
|
+
if (existingValue !== void 0 && !Array.isArray(existingValue)) {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
object[arrayKey] = existingValue || [];
|
|
224
|
+
object[arrayKey].push(value);
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
if (Array.isArray(object) && !isArrayIndexKey(key)) {
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
if (i < keys.length - 1) {
|
|
231
|
+
path = path ? `${path}.${key}` : key;
|
|
232
|
+
const nextValue = object[key];
|
|
233
|
+
if (nextValue !== void 0) {
|
|
234
|
+
object = nextValue;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
object = object[key] = arrayPaths.has(path) ? [] : /* @__PURE__ */ Object.create(null);
|
|
238
|
+
} else {
|
|
239
|
+
object[key] = value;
|
|
428
240
|
}
|
|
429
241
|
}
|
|
430
242
|
}
|
|
243
|
+
return values;
|
|
431
244
|
};
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
);
|
|
438
|
-
|
|
439
|
-
|
|
245
|
+
const parseRequest = async (deps, { request, method, query }, sharedMap) => {
|
|
246
|
+
const type = deps.getContentType(request.headers);
|
|
247
|
+
if (type === "application/x-www-form-urlencoded" || type === "multipart/form-data") {
|
|
248
|
+
const formData = await request.formData();
|
|
249
|
+
sharedMap.set(RequestEvSharedActionFormData, formData);
|
|
250
|
+
return formToObj(formData);
|
|
251
|
+
} else if (type === "application/json") {
|
|
252
|
+
const data = await request.json();
|
|
253
|
+
return data;
|
|
254
|
+
} else if (type === "application/qwik-json") {
|
|
255
|
+
if (method === "GET" && query.has(deps.QDATA_KEY)) {
|
|
256
|
+
const data = query.get(deps.QDATA_KEY);
|
|
257
|
+
if (data) {
|
|
258
|
+
try {
|
|
259
|
+
return _deserialize(decodeURIComponent(data));
|
|
260
|
+
} catch {
|
|
261
|
+
}
|
|
262
|
+
}
|
|
440
263
|
}
|
|
264
|
+
return _deserialize(await request.text());
|
|
441
265
|
}
|
|
266
|
+
return void 0;
|
|
442
267
|
};
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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) {
|
|
520
|
-
let resolve;
|
|
521
|
-
const responsePromise = new Promise((r) => resolve = r);
|
|
522
|
-
const requestEv = createRequestEvent(
|
|
523
|
-
serverRequestEv,
|
|
524
|
-
loadedRoute,
|
|
525
|
-
requestHandlers,
|
|
526
|
-
trailingSlash,
|
|
527
|
-
basePathname,
|
|
528
|
-
qwikSerializer,
|
|
529
|
-
resolve
|
|
530
|
-
);
|
|
531
|
-
return {
|
|
532
|
-
response: responsePromise,
|
|
533
|
-
requestEv,
|
|
534
|
-
completion: asyncStore ? asyncStore.run(requestEv, runNext, requestEv, rebuildRouteInfo, resolve) : runNext(requestEv, rebuildRouteInfo, resolve)
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
async function runNext(requestEv, rebuildRouteInfo, resolve) {
|
|
538
|
-
let rewriteAttempt = 1;
|
|
539
|
-
async function _runNext() {
|
|
540
|
-
try {
|
|
541
|
-
await requestEv.next();
|
|
542
|
-
} catch (e) {
|
|
543
|
-
if (e instanceof RedirectMessage) {
|
|
544
|
-
const stream = requestEv.getWritableStream();
|
|
545
|
-
await stream.close();
|
|
546
|
-
} else if (e instanceof RewriteMessage) {
|
|
547
|
-
if (rewriteAttempt > 50) {
|
|
548
|
-
throw new Error(`Infinite rewrite loop`);
|
|
549
|
-
}
|
|
550
|
-
rewriteAttempt += 1;
|
|
551
|
-
const url = new URL(requestEv.url);
|
|
552
|
-
url.pathname = e.pathname;
|
|
553
|
-
const { loadedRoute, requestHandlers } = await rebuildRouteInfo(url);
|
|
554
|
-
requestEv.resetRoute(loadedRoute, requestHandlers, url);
|
|
555
|
-
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
|
-
}
|
|
568
|
-
}
|
|
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");
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
return e;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
return void 0;
|
|
591
|
-
}
|
|
592
|
-
try {
|
|
593
|
-
return await _runNext();
|
|
594
|
-
} finally {
|
|
595
|
-
if (!requestEv.isDirty()) {
|
|
596
|
-
resolve(null);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
function getRouteMatchPathname(pathname, trailingSlash) {
|
|
601
|
-
if (pathname.endsWith(QDATA_JSON)) {
|
|
602
|
-
const trimEnd = pathname.length - QDATA_JSON_LEN + (trailingSlash ? 1 : 0);
|
|
603
|
-
pathname = pathname.slice(0, trimEnd);
|
|
604
|
-
if (pathname === "") {
|
|
605
|
-
pathname = "/";
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
return pathname;
|
|
609
|
-
}
|
|
610
|
-
var IsQData = "@isQData";
|
|
611
|
-
var QDATA_JSON = "/q-data.json";
|
|
612
|
-
var QDATA_JSON_LEN = QDATA_JSON.length;
|
|
613
|
-
|
|
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) {
|
|
626
|
-
const { request, platform, env } = serverRequestEv;
|
|
627
|
-
const sharedMap = /* @__PURE__ */ new Map();
|
|
628
|
-
const cookie = new Cookie(request.headers.get("cookie"));
|
|
629
|
-
const headers = new Headers();
|
|
630
|
-
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
|
-
}
|
|
636
|
-
sharedMap.set(IsQData, true);
|
|
268
|
+
function createRequestEventWithDeps(deps, serverRequestEv, loadedRoute, requestHandlers, basePathname, resolved) {
|
|
269
|
+
const { request, platform, env } = serverRequestEv;
|
|
270
|
+
const sharedMap = /* @__PURE__ */ new Map();
|
|
271
|
+
const cookie = new deps.Cookie(request.headers.get("cookie"));
|
|
272
|
+
const headers = new Headers();
|
|
273
|
+
const url = new URL(request.url);
|
|
274
|
+
const { pathname, isInternal } = deps.getRouteMatchPathname(url.pathname);
|
|
275
|
+
if (isInternal) {
|
|
276
|
+
url.pathname = pathname;
|
|
277
|
+
sharedMap.set(deps.IsQData, true);
|
|
637
278
|
}
|
|
638
279
|
let routeModuleIndex = -1;
|
|
639
280
|
let writableStream = null;
|
|
640
281
|
let requestData = void 0;
|
|
641
282
|
let locale = serverRequestEv.locale;
|
|
642
|
-
let status = 200;
|
|
283
|
+
let status = loadedRoute?.$notFound$ ? 404 : 200;
|
|
643
284
|
const next = async () => {
|
|
644
285
|
routeModuleIndex++;
|
|
645
286
|
while (routeModuleIndex < requestHandlers.length) {
|
|
646
287
|
const moduleRequestHandler = requestHandlers[routeModuleIndex];
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
if (isPromise(result)) {
|
|
288
|
+
const result = moduleRequestHandler(requestEv);
|
|
289
|
+
if (deps.isPromise(result)) {
|
|
650
290
|
await result;
|
|
651
291
|
}
|
|
652
292
|
routeModuleIndex++;
|
|
@@ -654,6 +294,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
654
294
|
};
|
|
655
295
|
const resetRoute = (_loadedRoute, _requestHandlers, _url = url) => {
|
|
656
296
|
loadedRoute = _loadedRoute;
|
|
297
|
+
status = loadedRoute?.$notFound$ ? 404 : 200;
|
|
657
298
|
requestHandlers = _requestHandlers;
|
|
658
299
|
url.pathname = _url.pathname;
|
|
659
300
|
url.search = _url.search;
|
|
@@ -670,7 +311,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
670
311
|
status = statusOrResponse;
|
|
671
312
|
const writableStream2 = requestEv.getWritableStream();
|
|
672
313
|
const writer = writableStream2.getWriter();
|
|
673
|
-
writer.write(typeof body === "string" ? encoder.encode(body) : body);
|
|
314
|
+
writer.write(typeof body === "string" ? deps.encoder.encode(body) : body);
|
|
674
315
|
writer.close();
|
|
675
316
|
} else {
|
|
676
317
|
status = statusOrResponse.status;
|
|
@@ -698,19 +339,18 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
698
339
|
}
|
|
699
340
|
return exit();
|
|
700
341
|
};
|
|
701
|
-
const exit = () => {
|
|
342
|
+
const exit = (message = new deps.AbortMessage()) => {
|
|
702
343
|
routeModuleIndex = ABORT_INDEX;
|
|
703
|
-
return
|
|
344
|
+
return message;
|
|
704
345
|
};
|
|
705
346
|
const loaders = {};
|
|
706
347
|
const requestEv = {
|
|
707
348
|
[RequestEvLoaders]: loaders,
|
|
349
|
+
[RequestEvLoaderSerializationStrategyMap]: /* @__PURE__ */ new Map(),
|
|
708
350
|
[RequestEvMode]: serverRequestEv.mode,
|
|
709
|
-
[RequestEvTrailingSlash]: trailingSlash,
|
|
710
351
|
get [RequestEvRoute]() {
|
|
711
352
|
return loadedRoute;
|
|
712
353
|
},
|
|
713
|
-
[RequestEvQwikSerializer]: qwikSerializer,
|
|
714
354
|
cookie,
|
|
715
355
|
headers,
|
|
716
356
|
env,
|
|
@@ -718,7 +358,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
718
358
|
signal: request.signal,
|
|
719
359
|
originalUrl: new URL(url),
|
|
720
360
|
get params() {
|
|
721
|
-
return
|
|
361
|
+
return loadedRoute?.$params$ ?? {};
|
|
722
362
|
},
|
|
723
363
|
get pathname() {
|
|
724
364
|
return url.pathname;
|
|
@@ -745,15 +385,16 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
745
385
|
exit,
|
|
746
386
|
cacheControl: (cacheControl, target = "Cache-Control") => {
|
|
747
387
|
check();
|
|
748
|
-
headers.set(target, createCacheControl(cacheControl));
|
|
388
|
+
headers.set(target, deps.createCacheControl(cacheControl));
|
|
749
389
|
},
|
|
750
390
|
resolveValue: async (loaderOrAction) => {
|
|
751
391
|
const id = loaderOrAction.__id;
|
|
752
392
|
if (loaderOrAction.__brand === "server_loader") {
|
|
753
393
|
if (!(id in loaders)) {
|
|
754
|
-
throw new Error(
|
|
755
|
-
|
|
756
|
-
|
|
394
|
+
throw new Error("You can not get the returned data of a loader that has not been executed for this request.");
|
|
395
|
+
}
|
|
396
|
+
if (loaders[id] === _UNINITIALIZED) {
|
|
397
|
+
await deps.getRouteLoaderPromise(loaderOrAction, loaders, requestEv[RequestEvLoaderSerializationStrategyMap], requestEv);
|
|
757
398
|
}
|
|
758
399
|
}
|
|
759
400
|
return loaders[id];
|
|
@@ -774,31 +415,37 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
774
415
|
},
|
|
775
416
|
error: (statusCode, message) => {
|
|
776
417
|
status = statusCode;
|
|
777
|
-
|
|
418
|
+
headers.delete("Cache-Control");
|
|
419
|
+
return new deps.ServerError(statusCode, message);
|
|
778
420
|
},
|
|
779
421
|
redirect: (statusCode, url2) => {
|
|
780
422
|
check();
|
|
781
423
|
status = statusCode;
|
|
782
424
|
if (url2) {
|
|
783
|
-
|
|
784
|
-
|
|
425
|
+
if (
|
|
426
|
+
// //test.com
|
|
427
|
+
/^\/\//.test(url2) || // /test//path
|
|
428
|
+
/([^:])\/\/+/.test(url2)
|
|
429
|
+
) {
|
|
430
|
+
const fixedURL = url2.replace(/^\/\/+/, "/").replace(/([^:])\/\/+/g, "$1/");
|
|
785
431
|
console.warn(`Redirect URL ${url2} is invalid, fixing to ${fixedURL}`);
|
|
432
|
+
url2 = fixedURL;
|
|
786
433
|
}
|
|
787
|
-
headers.set("Location",
|
|
434
|
+
headers.set("Location", url2);
|
|
788
435
|
}
|
|
789
|
-
|
|
436
|
+
headers.delete("Cache-Control");
|
|
437
|
+
if (statusCode > 301) {
|
|
790
438
|
headers.set("Cache-Control", "no-store");
|
|
791
439
|
}
|
|
792
|
-
exit();
|
|
793
|
-
return new RedirectMessage();
|
|
440
|
+
return exit(new deps.RedirectMessage());
|
|
794
441
|
},
|
|
795
|
-
rewrite: (
|
|
442
|
+
rewrite: (pathname2) => {
|
|
796
443
|
check();
|
|
797
|
-
if (
|
|
798
|
-
throw new
|
|
444
|
+
if (pathname2.startsWith("http")) {
|
|
445
|
+
throw new deps.ServerError(400, isDev ? "Rewrite does not support absolute urls" : "Bad Request");
|
|
799
446
|
}
|
|
800
447
|
sharedMap.set(RequestEvIsRewrite, true);
|
|
801
|
-
return new RewriteMessage(
|
|
448
|
+
return exit(new deps.RewriteMessage(pathname2.replace(/\/+/g, "/")));
|
|
802
449
|
},
|
|
803
450
|
defer: (returnData) => {
|
|
804
451
|
return typeof returnData === "function" ? returnData : () => returnData;
|
|
@@ -806,6 +453,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
806
453
|
fail: (statusCode, data) => {
|
|
807
454
|
check();
|
|
808
455
|
status = statusCode;
|
|
456
|
+
headers.delete("Cache-Control");
|
|
809
457
|
return {
|
|
810
458
|
failed: true,
|
|
811
459
|
...data
|
|
@@ -823,7 +471,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
823
471
|
if (requestData !== void 0) {
|
|
824
472
|
return requestData;
|
|
825
473
|
}
|
|
826
|
-
return requestData = parseRequest(requestEv, sharedMap
|
|
474
|
+
return requestData = parseRequest(deps, requestEv, sharedMap);
|
|
827
475
|
},
|
|
828
476
|
json: (statusCode, data) => {
|
|
829
477
|
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
@@ -835,678 +483,1235 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
|
|
|
835
483
|
},
|
|
836
484
|
getWritableStream: () => {
|
|
837
485
|
if (writableStream === null) {
|
|
838
|
-
if (
|
|
839
|
-
const serverTiming = sharedMap.get(
|
|
486
|
+
if (isDev) {
|
|
487
|
+
const serverTiming = sharedMap.get(RequestEvShareServerTiming);
|
|
840
488
|
if (serverTiming) {
|
|
841
|
-
headers.set("Server-Timing", serverTiming.map((
|
|
489
|
+
headers.set("Server-Timing", serverTiming.map(([name, duration]) => `${name};dur=${duration}`).join(","));
|
|
842
490
|
}
|
|
843
491
|
}
|
|
844
|
-
writableStream = serverRequestEv.getWritableStream(
|
|
845
|
-
status,
|
|
846
|
-
headers,
|
|
847
|
-
cookie,
|
|
848
|
-
resolved,
|
|
849
|
-
requestEv
|
|
850
|
-
);
|
|
492
|
+
writableStream = serverRequestEv.getWritableStream(status, headers, cookie, resolved, requestEv);
|
|
851
493
|
}
|
|
852
494
|
return writableStream;
|
|
853
495
|
}
|
|
854
496
|
};
|
|
855
|
-
return
|
|
497
|
+
return requestEv;
|
|
856
498
|
}
|
|
857
|
-
|
|
858
|
-
|
|
499
|
+
|
|
500
|
+
function verifySerializable(data, qrl) {
|
|
501
|
+
try {
|
|
502
|
+
_verifySerializable(data, void 0);
|
|
503
|
+
} catch (e) {
|
|
504
|
+
if (e instanceof Error && qrl.dev) {
|
|
505
|
+
e.loc = qrl.dev;
|
|
506
|
+
}
|
|
507
|
+
throw e;
|
|
508
|
+
}
|
|
859
509
|
}
|
|
860
|
-
function
|
|
861
|
-
return
|
|
510
|
+
function now() {
|
|
511
|
+
return typeof performance !== "undefined" ? performance.now() : 0;
|
|
862
512
|
}
|
|
863
|
-
function
|
|
864
|
-
|
|
513
|
+
async function measure(requestEv, name, fn) {
|
|
514
|
+
const start = now();
|
|
515
|
+
try {
|
|
516
|
+
return await fn();
|
|
517
|
+
} finally {
|
|
518
|
+
const duration = now() - start;
|
|
519
|
+
let measurements = requestEv.sharedMap.get("@serverTiming");
|
|
520
|
+
if (!measurements) {
|
|
521
|
+
requestEv.sharedMap.set("@serverTiming", measurements = []);
|
|
522
|
+
}
|
|
523
|
+
measurements.push([
|
|
524
|
+
name,
|
|
525
|
+
duration
|
|
526
|
+
]);
|
|
527
|
+
}
|
|
865
528
|
}
|
|
866
|
-
function
|
|
867
|
-
|
|
529
|
+
async function runValidators(requestEv, validators, data) {
|
|
530
|
+
let lastResult = {
|
|
531
|
+
success: true,
|
|
532
|
+
data
|
|
533
|
+
};
|
|
534
|
+
if (validators) {
|
|
535
|
+
for (const validator of validators) {
|
|
536
|
+
if (isDev) {
|
|
537
|
+
lastResult = await measure(requestEv, `validator$`, () => validator.validate(requestEv, data));
|
|
538
|
+
} else {
|
|
539
|
+
lastResult = await validator.validate(requestEv, data);
|
|
540
|
+
}
|
|
541
|
+
if (!lastResult.success) {
|
|
542
|
+
return lastResult;
|
|
543
|
+
} else {
|
|
544
|
+
data = lastResult.data;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return lastResult;
|
|
868
549
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
550
|
+
async function getRouteLoaderPromise(loader, loaders, loadersSerializationStrategy, requestEv) {
|
|
551
|
+
const loaderId = loader.__id;
|
|
552
|
+
loaders[loaderId] = runValidators(
|
|
553
|
+
requestEv,
|
|
554
|
+
loader.__validators,
|
|
555
|
+
void 0
|
|
556
|
+
// data
|
|
557
|
+
).then((res) => {
|
|
558
|
+
if (res.success) {
|
|
559
|
+
if (isDev) {
|
|
560
|
+
return measure(requestEv, loader.__qrl.getHash(), () => loader.__qrl.call(requestEv, requestEv));
|
|
561
|
+
} else {
|
|
562
|
+
return loader.__qrl.call(requestEv, requestEv);
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
return requestEv.fail(res.status ?? 500, res.error);
|
|
566
|
+
}
|
|
567
|
+
}).then((resolvedLoader) => {
|
|
568
|
+
if (typeof resolvedLoader === "function") {
|
|
569
|
+
loaders[loaderId] = resolvedLoader();
|
|
570
|
+
} else {
|
|
571
|
+
if (isDev) {
|
|
572
|
+
verifySerializable(resolvedLoader, loader.__qrl);
|
|
573
|
+
}
|
|
574
|
+
loaders[loaderId] = resolvedLoader;
|
|
575
|
+
}
|
|
576
|
+
return resolvedLoader;
|
|
577
|
+
});
|
|
578
|
+
loadersSerializationStrategy.set(loaderId, loader.__serializationStrategy);
|
|
579
|
+
return loaders[loaderId];
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function getQwikRouterServerDataWithDeps(deps, requestEv) {
|
|
583
|
+
const { params, request, status, locale, originalUrl } = requestEv;
|
|
584
|
+
const requestHeaders = {};
|
|
585
|
+
request.headers.forEach((value, key) => requestHeaders[key] = value);
|
|
586
|
+
const action = requestEv.sharedMap.get(deps.RequestEvSharedActionId);
|
|
587
|
+
const formData = requestEv.sharedMap.get(deps.RequestEvSharedActionFormData);
|
|
588
|
+
const routeName = requestEv.sharedMap.get(deps.RequestRouteName);
|
|
589
|
+
const nonce = requestEv.sharedMap.get(deps.RequestEvSharedNonce);
|
|
590
|
+
const headers = requestEv.request.headers;
|
|
591
|
+
const reconstructedUrl = new URL(originalUrl.pathname + originalUrl.search, originalUrl);
|
|
592
|
+
const host = headers.get("X-Forwarded-Host");
|
|
593
|
+
const protocol = headers.get("X-Forwarded-Proto");
|
|
594
|
+
if (host) {
|
|
595
|
+
reconstructedUrl.port = "";
|
|
596
|
+
reconstructedUrl.host = host;
|
|
597
|
+
}
|
|
598
|
+
if (protocol) {
|
|
599
|
+
reconstructedUrl.protocol = protocol;
|
|
600
|
+
}
|
|
601
|
+
const loaders = deps.getRequestLoaders(requestEv);
|
|
602
|
+
const loadersSerializationStrategy = deps.getRequestLoaderSerializationStrategyMap(requestEv);
|
|
603
|
+
return {
|
|
604
|
+
url: reconstructedUrl.href,
|
|
605
|
+
requestHeaders,
|
|
606
|
+
locale: locale(),
|
|
607
|
+
nonce,
|
|
608
|
+
containerAttributes: {
|
|
609
|
+
[deps.Q_ROUTE]: routeName
|
|
610
|
+
},
|
|
611
|
+
qwikrouter: {
|
|
612
|
+
routeName,
|
|
613
|
+
ev: requestEv,
|
|
614
|
+
params: {
|
|
615
|
+
...params
|
|
616
|
+
},
|
|
617
|
+
loadedRoute: deps.getRequestRoute(requestEv),
|
|
618
|
+
response: {
|
|
619
|
+
status: status(),
|
|
620
|
+
statusMessage: requestEv.sharedMap.get(deps.RequestEvHttpStatusMessage),
|
|
621
|
+
loaders,
|
|
622
|
+
loadersSerializationStrategy,
|
|
623
|
+
action,
|
|
624
|
+
formData
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const responsePageDeps = {
|
|
631
|
+
Q_ROUTE,
|
|
632
|
+
RequestEvHttpStatusMessage,
|
|
633
|
+
RequestEvSharedActionFormData,
|
|
634
|
+
RequestEvSharedActionId,
|
|
635
|
+
RequestEvSharedNonce,
|
|
636
|
+
RequestRouteName,
|
|
637
|
+
getRequestLoaders,
|
|
638
|
+
getRequestLoaderSerializationStrategyMap,
|
|
639
|
+
getRequestRoute
|
|
640
|
+
};
|
|
641
|
+
function getQwikRouterServerData(...args) {
|
|
642
|
+
return getQwikRouterServerDataWithDeps(responsePageDeps, ...args);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function createResolveRequestHandlers(deps) {
|
|
646
|
+
const resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler, isInternal) => {
|
|
647
|
+
const routeLoaders = [];
|
|
648
|
+
const routeActions = [];
|
|
649
|
+
const requestHandlers = [];
|
|
650
|
+
const isPageRoute = !!(route && isLastModulePageRoute(route.$mods$));
|
|
651
|
+
if (isInternal) {
|
|
652
|
+
requestHandlers.push(handleQDataRedirect);
|
|
653
|
+
}
|
|
654
|
+
if (isPageRoute) {
|
|
655
|
+
requestHandlers.push(serverErrorMiddleware(route, renderHandler));
|
|
656
|
+
}
|
|
657
|
+
if (serverPlugins) {
|
|
658
|
+
_resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, serverPlugins, isPageRoute, method);
|
|
659
|
+
}
|
|
660
|
+
if (route) {
|
|
661
|
+
const routeModules = route.$mods$;
|
|
662
|
+
_resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, routeModules, isPageRoute, method);
|
|
663
|
+
const routeName = route.$routeName$;
|
|
664
|
+
if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
|
|
665
|
+
if (checkOrigin === "lax-proto") {
|
|
666
|
+
requestHandlers.unshift(csrfLaxProtoCheckMiddleware);
|
|
667
|
+
} else {
|
|
668
|
+
requestHandlers.unshift(csrfCheckMiddleware);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (isPageRoute) {
|
|
672
|
+
if (method === "POST" || method === "GET") {
|
|
673
|
+
requestHandlers.push(runServerFunction);
|
|
674
|
+
}
|
|
675
|
+
requestHandlers.push(fixTrailingSlash);
|
|
676
|
+
if (isInternal) {
|
|
677
|
+
requestHandlers.push(renderQData);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (isPageRoute) {
|
|
681
|
+
requestHandlers.push((ev) => {
|
|
682
|
+
ev.sharedMap.set(deps.RequestRouteName, routeName);
|
|
683
|
+
});
|
|
684
|
+
requestHandlers.push(actionsMiddleware(routeActions));
|
|
685
|
+
requestHandlers.push(loadersMiddleware(routeLoaders));
|
|
686
|
+
requestHandlers.push(eTagMiddleware(route));
|
|
687
|
+
requestHandlers.push(renderHandler);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return requestHandlers;
|
|
691
|
+
};
|
|
692
|
+
const _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, routeModules, collectActions, method) => {
|
|
693
|
+
for (const routeModule of routeModules) {
|
|
694
|
+
if (typeof routeModule.onRequest === "function") {
|
|
695
|
+
requestHandlers.push(routeModule.onRequest);
|
|
696
|
+
} else if (Array.isArray(routeModule.onRequest)) {
|
|
697
|
+
requestHandlers.push(...routeModule.onRequest);
|
|
698
|
+
}
|
|
699
|
+
let methodReqHandler;
|
|
700
|
+
switch (method) {
|
|
701
|
+
case "GET": {
|
|
702
|
+
methodReqHandler = routeModule.onGet;
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
case "POST": {
|
|
706
|
+
methodReqHandler = routeModule.onPost;
|
|
707
|
+
break;
|
|
708
|
+
}
|
|
709
|
+
case "PUT": {
|
|
710
|
+
methodReqHandler = routeModule.onPut;
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
713
|
+
case "PATCH": {
|
|
714
|
+
methodReqHandler = routeModule.onPatch;
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
case "DELETE": {
|
|
718
|
+
methodReqHandler = routeModule.onDelete;
|
|
719
|
+
break;
|
|
720
|
+
}
|
|
721
|
+
case "OPTIONS": {
|
|
722
|
+
methodReqHandler = routeModule.onOptions;
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
case "HEAD": {
|
|
726
|
+
methodReqHandler = routeModule.onHead;
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (typeof methodReqHandler === "function") {
|
|
731
|
+
requestHandlers.push(methodReqHandler);
|
|
732
|
+
} else if (Array.isArray(methodReqHandler)) {
|
|
733
|
+
requestHandlers.push(...methodReqHandler);
|
|
734
|
+
}
|
|
735
|
+
if (collectActions) {
|
|
736
|
+
for (const module of Object.values(routeModule)) {
|
|
737
|
+
if (typeof module === "function") {
|
|
738
|
+
if (module.__brand === "server_loader") {
|
|
739
|
+
routeLoaders.push(module);
|
|
740
|
+
} else if (module.__brand === "server_action") {
|
|
741
|
+
routeActions.push(module);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
887
744
|
}
|
|
888
745
|
}
|
|
889
746
|
}
|
|
890
|
-
|
|
747
|
+
};
|
|
748
|
+
const checkBrand = (obj, brand) => {
|
|
749
|
+
return obj && typeof obj === "function" && obj.__brand === brand;
|
|
750
|
+
};
|
|
751
|
+
function actionsMiddleware(routeActions) {
|
|
752
|
+
return async (requestEvent) => {
|
|
753
|
+
const requestEv = requestEvent;
|
|
754
|
+
if (requestEv.headersSent) {
|
|
755
|
+
requestEv.exit();
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
const { method } = requestEv;
|
|
759
|
+
const loaders = deps.getRequestLoaders(requestEv);
|
|
760
|
+
if (isDev && method === "GET") {
|
|
761
|
+
if (requestEv.query.has(deps.QACTION_KEY)) {
|
|
762
|
+
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">');
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
if (method === "POST") {
|
|
766
|
+
const selectedActionId = requestEv.query.get(deps.QACTION_KEY);
|
|
767
|
+
if (selectedActionId) {
|
|
768
|
+
const serverActionsMap = globalThis._qwikActionsMap;
|
|
769
|
+
const action = routeActions.find((action2) => action2.__id === selectedActionId) ?? serverActionsMap?.get(selectedActionId);
|
|
770
|
+
if (action) {
|
|
771
|
+
requestEv.sharedMap.set(deps.RequestEvSharedActionId, selectedActionId);
|
|
772
|
+
const data = await requestEv.parseBody();
|
|
773
|
+
if (!data || typeof data !== "object") {
|
|
774
|
+
throw new Error(`Expected request data for the action id ${selectedActionId} to be an object`);
|
|
775
|
+
}
|
|
776
|
+
const result = await runValidators(requestEv, action.__validators, data);
|
|
777
|
+
if (!result.success) {
|
|
778
|
+
loaders[selectedActionId] = requestEv.fail(result.status ?? 500, result.error);
|
|
779
|
+
} else {
|
|
780
|
+
const actionResolved = isDev ? await measure(requestEv, action.__qrl.getHash(), () => action.__qrl.call(requestEv, result.data, requestEv)) : await action.__qrl.call(requestEv, result.data, requestEv);
|
|
781
|
+
if (isDev) {
|
|
782
|
+
verifySerializable(actionResolved, action.__qrl);
|
|
783
|
+
}
|
|
784
|
+
loaders[selectedActionId] = actionResolved;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
function loadersMiddleware(routeLoaders) {
|
|
792
|
+
return async (requestEvent) => {
|
|
793
|
+
const requestEv = requestEvent;
|
|
794
|
+
if (requestEv.headersSent) {
|
|
795
|
+
requestEv.exit();
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
const loaders = deps.getRequestLoaders(requestEv);
|
|
799
|
+
const loadersSerializationStrategy = deps.getRequestLoaderSerializationStrategyMap(requestEv);
|
|
800
|
+
if (routeLoaders.length > 0) {
|
|
801
|
+
const resolvedLoadersPromises = routeLoaders.map((loader) => deps.getRouteLoaderPromise(loader, loaders, loadersSerializationStrategy, requestEv));
|
|
802
|
+
await Promise.all(resolvedLoadersPromises);
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
function eTagMiddleware(route) {
|
|
807
|
+
return (requestEv) => {
|
|
808
|
+
if (requestEv.headersSent) {
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (requestEv.method !== "GET" || requestEv.sharedMap.has(deps.IsQData)) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
const mods = route.$mods$;
|
|
815
|
+
const hasETag = mods.some((m) => {
|
|
816
|
+
if (!m) {
|
|
817
|
+
return false;
|
|
818
|
+
}
|
|
819
|
+
if (m.routeConfig) {
|
|
820
|
+
return typeof m.routeConfig === "function" || m.routeConfig.eTag !== void 0;
|
|
821
|
+
}
|
|
822
|
+
return m.eTag !== void 0;
|
|
823
|
+
});
|
|
824
|
+
if (!hasETag) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const loaders = deps.getRequestLoaders(requestEv);
|
|
828
|
+
const getData = (loaderOrAction) => {
|
|
829
|
+
const id = loaderOrAction.__id;
|
|
830
|
+
if (loaderOrAction.__brand === "server_loader" && !(id in loaders)) {
|
|
831
|
+
throw new Error("Loader not executed for this request.");
|
|
832
|
+
}
|
|
833
|
+
if (loaders[id] instanceof Promise) {
|
|
834
|
+
throw new Error("Loaders returning a promise cannot be resolved for the eTag function.");
|
|
835
|
+
}
|
|
836
|
+
return loaders[id];
|
|
837
|
+
};
|
|
838
|
+
const routeLocation = {
|
|
839
|
+
params: requestEv.params,
|
|
840
|
+
url: requestEv.url,
|
|
841
|
+
isNavigating: false,
|
|
842
|
+
prevUrl: void 0
|
|
843
|
+
};
|
|
844
|
+
const status = requestEv.status();
|
|
845
|
+
const config = deps.resolveRouteConfig(getData, routeLocation, mods, "", status);
|
|
846
|
+
const headProps = {
|
|
847
|
+
head: config.head,
|
|
848
|
+
status,
|
|
849
|
+
withLocale: (fn) => fn(),
|
|
850
|
+
resolveValue: getData,
|
|
851
|
+
...routeLocation
|
|
852
|
+
};
|
|
853
|
+
const eTag = deps.resolveETag(config.eTag, headProps);
|
|
854
|
+
if (!eTag) {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
requestEv.headers.set("ETag", eTag);
|
|
858
|
+
const ifNoneMatch = requestEv.request.headers.get("If-None-Match");
|
|
859
|
+
if (ifNoneMatch && (ifNoneMatch === eTag || ifNoneMatch === `W/${eTag}` || `W/${ifNoneMatch}` === eTag)) {
|
|
860
|
+
requestEv.status(304);
|
|
861
|
+
requestEv.send(304, "");
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
if (deps.MAX_CACHE_SIZE <= 0) {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
const cacheKey = deps.resolveCacheKey(config.cacheKey, status, eTag, requestEv.url.pathname);
|
|
868
|
+
if (!cacheKey) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const cachedHtml = deps.getCachedHtml(cacheKey);
|
|
872
|
+
if (cachedHtml) {
|
|
873
|
+
requestEv.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
874
|
+
requestEv.headers.set("X-SSR-Cache", "HIT");
|
|
875
|
+
requestEv.send(status, cachedHtml);
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
requestEv.sharedMap.set(deps.RequestEvETagCacheKey, cacheKey);
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
function serverErrorMiddleware(route, renderHandler) {
|
|
882
|
+
return async (requestEv) => {
|
|
883
|
+
try {
|
|
884
|
+
await requestEv.next();
|
|
885
|
+
} catch (e) {
|
|
886
|
+
if (!(e instanceof deps.ServerError) || requestEv.headersSent) {
|
|
887
|
+
throw e;
|
|
888
|
+
}
|
|
889
|
+
if (requestEv.sharedMap.has(deps.IsQData)) {
|
|
890
|
+
throw e;
|
|
891
|
+
}
|
|
892
|
+
const accept = requestEv.request.headers.get("Accept");
|
|
893
|
+
if (accept && !accept.includes("text/html")) {
|
|
894
|
+
throw e;
|
|
895
|
+
}
|
|
896
|
+
const status = e.status;
|
|
897
|
+
requestEv.status(status);
|
|
898
|
+
const errorLoader = route.$errorLoader$;
|
|
899
|
+
const errorModule = errorLoader ? await errorLoader() : await deps.loadHttpError();
|
|
900
|
+
route.$mods$ = [
|
|
901
|
+
errorModule
|
|
902
|
+
];
|
|
903
|
+
requestEv.sharedMap.set(deps.RequestEvHttpStatusMessage, typeof e.data === "string" ? e.data : "Server Error");
|
|
904
|
+
await renderHandler(requestEv);
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
async function runValidators(requestEv, validators, data) {
|
|
909
|
+
let lastResult = {
|
|
910
|
+
success: true,
|
|
911
|
+
data
|
|
912
|
+
};
|
|
913
|
+
if (validators) {
|
|
914
|
+
for (const validator of validators) {
|
|
915
|
+
if (isDev) {
|
|
916
|
+
lastResult = await measure(requestEv, `validator$`, () => validator.validate(requestEv, data));
|
|
917
|
+
} else {
|
|
918
|
+
lastResult = await validator.validate(requestEv, data);
|
|
919
|
+
}
|
|
920
|
+
if (!lastResult.success) {
|
|
921
|
+
return lastResult;
|
|
922
|
+
} else {
|
|
923
|
+
data = lastResult.data;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
return lastResult;
|
|
928
|
+
}
|
|
929
|
+
function isAsyncIterator(obj) {
|
|
930
|
+
return obj ? typeof obj === "object" && Symbol.asyncIterator in obj : false;
|
|
931
|
+
}
|
|
932
|
+
async function runServerFunction(ev) {
|
|
933
|
+
const serverFnHash = ev.query.get(deps.QFN_KEY);
|
|
934
|
+
if (serverFnHash && ev.request.headers.get("X-QRL") === serverFnHash && ev.request.headers.get("Content-Type") === "application/qwik-json") {
|
|
935
|
+
ev.exit();
|
|
936
|
+
const data = await ev.parseBody();
|
|
937
|
+
if (!Array.isArray(data) || !(Array.isArray(data[0]) || data[0] === void 0)) {
|
|
938
|
+
throw ev.error(500, "Invalid request");
|
|
939
|
+
}
|
|
940
|
+
const qrl = inlinedQrl(null, serverFnHash, data.slice(1));
|
|
941
|
+
let result;
|
|
942
|
+
try {
|
|
943
|
+
if (isDev) {
|
|
944
|
+
result = await measure(ev, `server_${serverFnHash}`, () => qrl.apply(ev, data[0]));
|
|
945
|
+
} else {
|
|
946
|
+
result = await qrl.apply(ev, data[0]);
|
|
947
|
+
}
|
|
948
|
+
} catch (err) {
|
|
949
|
+
if (err instanceof deps.ServerError) {
|
|
950
|
+
throw ev.error(err.status, err.data);
|
|
951
|
+
}
|
|
952
|
+
console.error(`Server function ${serverFnHash} failed:`, err);
|
|
953
|
+
throw ev.error(500, "Invalid request");
|
|
954
|
+
}
|
|
955
|
+
if (isAsyncIterator(result)) {
|
|
956
|
+
ev.headers.set("Content-Type", "text/qwik-json-stream");
|
|
957
|
+
const writable = ev.getWritableStream();
|
|
958
|
+
const stream = writable.getWriter();
|
|
959
|
+
for await (const item of result) {
|
|
960
|
+
if (isDev) {
|
|
961
|
+
verifySerializable(item, qrl);
|
|
962
|
+
}
|
|
963
|
+
const message = await _serialize(item);
|
|
964
|
+
if (ev.signal.aborted) {
|
|
965
|
+
break;
|
|
966
|
+
}
|
|
967
|
+
await stream.write(deps.encoder.encode(`${message}
|
|
968
|
+
`));
|
|
969
|
+
}
|
|
970
|
+
stream.close();
|
|
971
|
+
} else {
|
|
972
|
+
verifySerializable(result, qrl);
|
|
973
|
+
ev.headers.set("Content-Type", "application/qwik-json");
|
|
974
|
+
const message = await _serialize(result);
|
|
975
|
+
ev.send(200, message);
|
|
976
|
+
}
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
function fixTrailingSlash(ev) {
|
|
981
|
+
const { basePathname, originalUrl, sharedMap } = ev;
|
|
982
|
+
const { pathname, search } = originalUrl;
|
|
983
|
+
const isQData = sharedMap.has(deps.IsQData);
|
|
984
|
+
if (!pathname.startsWith("/") || pathname.startsWith("//")) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (!isQData && pathname !== basePathname && !pathname.endsWith(".html")) {
|
|
988
|
+
if (!globalThis.__NO_TRAILING_SLASH__) {
|
|
989
|
+
if (!pathname.endsWith("/")) {
|
|
990
|
+
throw ev.redirect(deps.HttpStatus.MovedPermanently, pathname + "/" + search);
|
|
991
|
+
}
|
|
992
|
+
} else {
|
|
993
|
+
if (pathname.endsWith("/")) {
|
|
994
|
+
throw ev.redirect(deps.HttpStatus.MovedPermanently, pathname.slice(0, pathname.length - 1) + search);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
function verifySerializable(data, qrl) {
|
|
1000
|
+
try {
|
|
1001
|
+
_verifySerializable(data, void 0);
|
|
1002
|
+
} catch (e) {
|
|
1003
|
+
if (e instanceof Error && qrl.dev) {
|
|
1004
|
+
e.loc = qrl.dev;
|
|
1005
|
+
}
|
|
1006
|
+
throw e;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
const isQrl = (value) => {
|
|
1010
|
+
return typeof value === "function" && typeof value.getSymbol === "function";
|
|
1011
|
+
};
|
|
1012
|
+
function isLastModulePageRoute(routeModules) {
|
|
1013
|
+
const lastRouteModule = routeModules[routeModules.length - 1];
|
|
1014
|
+
return lastRouteModule && typeof lastRouteModule.default === "function";
|
|
1015
|
+
}
|
|
1016
|
+
function getPathname(url) {
|
|
1017
|
+
url = new URL(url);
|
|
1018
|
+
if (url.pathname.endsWith(deps.QDATA_JSON)) {
|
|
1019
|
+
url.pathname = url.pathname.slice(0, -deps.QDATA_JSON.length);
|
|
1020
|
+
}
|
|
1021
|
+
if (!globalThis.__NO_TRAILING_SLASH__) {
|
|
1022
|
+
if (!url.pathname.endsWith("/")) {
|
|
1023
|
+
url.pathname += "/";
|
|
1024
|
+
}
|
|
1025
|
+
} else {
|
|
1026
|
+
if (url.pathname.endsWith("/")) {
|
|
1027
|
+
url.pathname = url.pathname.slice(0, -1);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
const search = url.search.slice(1).replaceAll(/&?q(action|data|func|loaders)=[^&]+/g, "");
|
|
1031
|
+
return `${url.pathname}${search ? `?${search}` : ""}${url.hash}`;
|
|
1032
|
+
}
|
|
1033
|
+
function csrfLaxProtoCheckMiddleware(requestEv) {
|
|
1034
|
+
checkCSRF(requestEv, "lax-proto");
|
|
1035
|
+
}
|
|
1036
|
+
function csrfCheckMiddleware(requestEv) {
|
|
1037
|
+
checkCSRF(requestEv);
|
|
1038
|
+
}
|
|
1039
|
+
function checkCSRF(requestEv, laxProto) {
|
|
1040
|
+
const contentType = requestEv.request.headers.get("content-type");
|
|
1041
|
+
const isSimpleRequest = !contentType || deps.isContentType(requestEv.request.headers, "application/x-www-form-urlencoded", "multipart/form-data", "text/plain");
|
|
1042
|
+
if (isSimpleRequest) {
|
|
1043
|
+
const inputOrigin = requestEv.request.headers.get("origin");
|
|
1044
|
+
const origin = requestEv.url.origin;
|
|
1045
|
+
let forbidden = inputOrigin !== origin;
|
|
1046
|
+
if (forbidden && laxProto && inputOrigin?.replace(/^http(s)?/g, "") === origin.replace(/^http(s)?/g, "")) {
|
|
1047
|
+
forbidden = false;
|
|
1048
|
+
}
|
|
1049
|
+
if (forbidden) {
|
|
1050
|
+
throw requestEv.error(403, `CSRF check failed. Cross-site ${requestEv.method} form submissions are forbidden.
|
|
1051
|
+
The request origin "${inputOrigin}" does not match the server origin "${origin}".`);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
function renderQwikMiddleware(render) {
|
|
1056
|
+
return async (requestEv) => {
|
|
1057
|
+
if (requestEv.headersSent) {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
if (requestEv.sharedMap.has(deps.IsQData)) {
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
const responseHeaders = requestEv.headers;
|
|
1064
|
+
if (!responseHeaders.has("Content-Type")) {
|
|
1065
|
+
responseHeaders.set("Content-Type", "text/html; charset=utf-8");
|
|
1066
|
+
}
|
|
1067
|
+
const eTagCacheKey = requestEv.sharedMap.get(deps.RequestEvETagCacheKey);
|
|
1068
|
+
const { readable, writable } = new TextEncoderStream();
|
|
1069
|
+
const writableStream = requestEv.getWritableStream();
|
|
1070
|
+
let cacheChunks;
|
|
1071
|
+
let pipeSource = readable;
|
|
1072
|
+
if (eTagCacheKey) {
|
|
1073
|
+
cacheChunks = [];
|
|
1074
|
+
const capture = new TransformStream({
|
|
1075
|
+
transform(chunk, controller) {
|
|
1076
|
+
cacheChunks.push(chunk);
|
|
1077
|
+
controller.enqueue(chunk);
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
pipeSource = readable.pipeThrough(capture);
|
|
1081
|
+
}
|
|
1082
|
+
const pipe = pipeSource.pipeTo(writableStream, {
|
|
1083
|
+
preventClose: true
|
|
1084
|
+
});
|
|
1085
|
+
const stream = writable.getWriter();
|
|
1086
|
+
const status = requestEv.status();
|
|
1087
|
+
try {
|
|
1088
|
+
const isStatic = deps.getRequestMode(requestEv) === "static";
|
|
1089
|
+
const serverData = deps.getQwikRouterServerData(requestEv);
|
|
1090
|
+
const result = await render({
|
|
1091
|
+
base: requestEv.basePathname + "build/",
|
|
1092
|
+
stream,
|
|
1093
|
+
serverData,
|
|
1094
|
+
containerAttributes: {
|
|
1095
|
+
["q:render"]: isStatic ? "static" : "",
|
|
1096
|
+
...serverData.containerAttributes
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
const qData = {
|
|
1100
|
+
loaders: deps.getRequestLoaders(requestEv),
|
|
1101
|
+
action: requestEv.sharedMap.get(deps.RequestEvSharedActionId),
|
|
1102
|
+
status: status !== 200 ? status : 200,
|
|
1103
|
+
href: getPathname(requestEv.url)
|
|
1104
|
+
};
|
|
1105
|
+
if (typeof result.html === "string") {
|
|
1106
|
+
await stream.write(result.html);
|
|
1107
|
+
}
|
|
1108
|
+
requestEv.sharedMap.set(deps.RequestEvShareQData, qData);
|
|
1109
|
+
} finally {
|
|
1110
|
+
await stream.ready;
|
|
1111
|
+
await stream.close();
|
|
1112
|
+
await pipe;
|
|
1113
|
+
}
|
|
1114
|
+
if (eTagCacheKey && cacheChunks && cacheChunks.length > 0) {
|
|
1115
|
+
const totalLength = cacheChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
1116
|
+
const combined = new Uint8Array(totalLength);
|
|
1117
|
+
let offset = 0;
|
|
1118
|
+
for (const chunk of cacheChunks) {
|
|
1119
|
+
combined.set(chunk, offset);
|
|
1120
|
+
offset += chunk.length;
|
|
1121
|
+
}
|
|
1122
|
+
deps.setCachedHtml(eTagCacheKey, new TextDecoder().decode(combined));
|
|
1123
|
+
}
|
|
1124
|
+
await writableStream.close();
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
async function handleQDataRedirect(requestEv) {
|
|
1128
|
+
try {
|
|
1129
|
+
await requestEv.next();
|
|
1130
|
+
} catch (err) {
|
|
1131
|
+
if (!(err instanceof deps.RedirectMessage)) {
|
|
1132
|
+
throw err;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
if (requestEv.headersSent) {
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
const status = requestEv.status();
|
|
1139
|
+
const location = requestEv.headers.get("Location");
|
|
1140
|
+
const isRedirect = status >= 301 && status <= 308 && location;
|
|
1141
|
+
if (isRedirect) {
|
|
1142
|
+
const adaptedLocation = makeQDataPath(location);
|
|
1143
|
+
if (adaptedLocation) {
|
|
1144
|
+
requestEv.headers.set("Location", adaptedLocation);
|
|
1145
|
+
requestEv.getWritableStream().close();
|
|
1146
|
+
return;
|
|
1147
|
+
} else {
|
|
1148
|
+
requestEv.status(200);
|
|
1149
|
+
requestEv.headers.delete("Location");
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
async function renderQData(requestEv) {
|
|
1154
|
+
await requestEv.next();
|
|
1155
|
+
if (requestEv.headersSent || requestEv.exited) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
const status = requestEv.status();
|
|
1159
|
+
const redirectLocation = requestEv.headers.get("Location");
|
|
1160
|
+
requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
|
|
1161
|
+
let loaders = deps.getRequestLoaders(requestEv);
|
|
1162
|
+
const selectedLoaderIds = requestEv.query.getAll(deps.QLOADER_KEY);
|
|
1163
|
+
const hasCustomLoaders = selectedLoaderIds.length > 0;
|
|
1164
|
+
if (hasCustomLoaders) {
|
|
1165
|
+
const selectedLoaders = {};
|
|
1166
|
+
for (const loaderId of selectedLoaderIds) {
|
|
1167
|
+
const loader = loaders[loaderId];
|
|
1168
|
+
selectedLoaders[loaderId] = loader;
|
|
1169
|
+
}
|
|
1170
|
+
loaders = selectedLoaders;
|
|
1171
|
+
}
|
|
1172
|
+
const qData = hasCustomLoaders ? {
|
|
1173
|
+
loaders,
|
|
1174
|
+
status: status !== 200 ? status : 200,
|
|
1175
|
+
href: getPathname(requestEv.url)
|
|
1176
|
+
} : {
|
|
1177
|
+
loaders,
|
|
1178
|
+
action: requestEv.sharedMap.get(deps.RequestEvSharedActionId),
|
|
1179
|
+
status: status !== 200 ? status : 200,
|
|
1180
|
+
href: getPathname(requestEv.url),
|
|
1181
|
+
redirect: redirectLocation ?? void 0,
|
|
1182
|
+
isRewrite: requestEv.sharedMap.get(deps.RequestEvIsRewrite)
|
|
1183
|
+
};
|
|
1184
|
+
const writer = requestEv.getWritableStream().getWriter();
|
|
1185
|
+
const data = await _serialize(qData);
|
|
1186
|
+
writer.write(deps.encoder.encode(data));
|
|
1187
|
+
requestEv.sharedMap.set(deps.RequestEvShareQData, qData);
|
|
1188
|
+
writer.close();
|
|
1189
|
+
}
|
|
1190
|
+
function makeQDataPath(href) {
|
|
1191
|
+
if (href.startsWith("/")) {
|
|
1192
|
+
if (!href.includes(deps.QDATA_JSON)) {
|
|
1193
|
+
const url = new URL(href, "http://localhost");
|
|
1194
|
+
const pathname = url.pathname.endsWith("/") ? url.pathname.slice(0, -1) : url.pathname;
|
|
1195
|
+
return pathname + deps.QDATA_JSON + url.search;
|
|
1196
|
+
}
|
|
1197
|
+
return href;
|
|
1198
|
+
} else {
|
|
1199
|
+
return void 0;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
function now() {
|
|
1203
|
+
return typeof performance !== "undefined" ? performance.now() : 0;
|
|
1204
|
+
}
|
|
1205
|
+
async function measure(requestEv, name, fn) {
|
|
1206
|
+
const start = now();
|
|
1207
|
+
try {
|
|
1208
|
+
return await fn();
|
|
1209
|
+
} finally {
|
|
1210
|
+
const duration = now() - start;
|
|
1211
|
+
let measurements = requestEv.sharedMap.get(deps.RequestEvShareServerTiming);
|
|
1212
|
+
if (!measurements) {
|
|
1213
|
+
requestEv.sharedMap.set(deps.RequestEvShareServerTiming, measurements = []);
|
|
1214
|
+
}
|
|
1215
|
+
measurements.push([
|
|
1216
|
+
name,
|
|
1217
|
+
duration
|
|
1218
|
+
]);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
actionsMiddleware,
|
|
1223
|
+
checkBrand,
|
|
1224
|
+
checkCSRF,
|
|
1225
|
+
fixTrailingSlash,
|
|
1226
|
+
getPathname,
|
|
1227
|
+
isLastModulePageRoute,
|
|
1228
|
+
isQrl,
|
|
1229
|
+
loadersMiddleware,
|
|
1230
|
+
measure,
|
|
1231
|
+
renderQwikMiddleware,
|
|
1232
|
+
resolveRequestHandlers,
|
|
1233
|
+
verifySerializable
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const encoder = /* @__PURE__ */ new TextEncoder();
|
|
1238
|
+
function getContentType(headers) {
|
|
1239
|
+
return (headers.get("content-type")?.split(/[;,]/, 1)[0].trim() ?? "").toLowerCase();
|
|
1240
|
+
}
|
|
1241
|
+
function isContentType(headers, ...types) {
|
|
1242
|
+
const type = getContentType(headers);
|
|
1243
|
+
for (let i = 0; i < types.length; i++) {
|
|
1244
|
+
if (types[i].toLowerCase() === type) {
|
|
1245
|
+
return true;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
class ServerError extends Error {
|
|
1252
|
+
status;
|
|
1253
|
+
data;
|
|
1254
|
+
constructor(status, data) {
|
|
1255
|
+
super(typeof data === "string" ? data : void 0), this.status = status, this.data = data;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
const requestHandlers = createResolveRequestHandlers({
|
|
1260
|
+
QACTION_KEY,
|
|
1261
|
+
QFN_KEY,
|
|
1262
|
+
QLOADER_KEY,
|
|
1263
|
+
QDATA_JSON,
|
|
1264
|
+
IsQData,
|
|
1265
|
+
RequestEvETagCacheKey,
|
|
1266
|
+
RequestEvHttpStatusMessage,
|
|
1267
|
+
RequestEvIsRewrite,
|
|
1268
|
+
RequestEvShareQData,
|
|
1269
|
+
RequestEvShareServerTiming,
|
|
1270
|
+
RequestEvSharedActionId,
|
|
1271
|
+
RequestRouteName,
|
|
1272
|
+
RedirectMessage,
|
|
1273
|
+
ServerError,
|
|
1274
|
+
HttpStatus,
|
|
1275
|
+
encoder,
|
|
1276
|
+
isContentType,
|
|
1277
|
+
getCachedHtml,
|
|
1278
|
+
getQwikRouterServerData,
|
|
1279
|
+
getRequestLoaderSerializationStrategyMap,
|
|
1280
|
+
getRequestLoaders,
|
|
1281
|
+
getRequestMode,
|
|
1282
|
+
getRouteLoaderPromise,
|
|
1283
|
+
loadHttpError: () => import('../../chunks/http-error.qwik.mjs'),
|
|
1284
|
+
MAX_CACHE_SIZE,
|
|
1285
|
+
resolveCacheKey,
|
|
1286
|
+
resolveETag,
|
|
1287
|
+
resolveRouteConfig,
|
|
1288
|
+
setCachedHtml
|
|
1289
|
+
});
|
|
1290
|
+
const { renderQwikMiddleware, resolveRequestHandlers} = requestHandlers;
|
|
1291
|
+
|
|
1292
|
+
let _asyncRequestStore;
|
|
1293
|
+
if (isServer) {
|
|
1294
|
+
import('node:async_hooks').then((module) => {
|
|
1295
|
+
_asyncRequestStore = new module.AsyncLocalStorage();
|
|
1296
|
+
}).catch((err) => {
|
|
1297
|
+
console.warn("\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", err);
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
function createCacheControl(cacheControl) {
|
|
1302
|
+
const controls = [];
|
|
1303
|
+
if (cacheControl === "day") {
|
|
1304
|
+
cacheControl = 60 * 60 * 24;
|
|
1305
|
+
} else if (cacheControl === "week") {
|
|
1306
|
+
cacheControl = 60 * 60 * 24 * 7;
|
|
1307
|
+
} else if (cacheControl === "month") {
|
|
1308
|
+
cacheControl = 60 * 60 * 24 * 30;
|
|
1309
|
+
} else if (cacheControl === "year") {
|
|
1310
|
+
cacheControl = 60 * 60 * 24 * 365;
|
|
1311
|
+
} else if (cacheControl === "private") {
|
|
1312
|
+
cacheControl = {
|
|
1313
|
+
private: true,
|
|
1314
|
+
noCache: true
|
|
1315
|
+
};
|
|
1316
|
+
} else if (cacheControl === "immutable") {
|
|
1317
|
+
cacheControl = {
|
|
1318
|
+
public: true,
|
|
1319
|
+
immutable: true,
|
|
1320
|
+
maxAge: 60 * 60 * 24 * 365
|
|
1321
|
+
};
|
|
1322
|
+
} else if (cacheControl === "no-cache") {
|
|
1323
|
+
cacheControl = {
|
|
1324
|
+
noCache: true
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
if (typeof cacheControl === "number") {
|
|
1328
|
+
cacheControl = {
|
|
1329
|
+
maxAge: cacheControl,
|
|
1330
|
+
sMaxAge: cacheControl
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
if (cacheControl.immutable) {
|
|
1334
|
+
controls.push("immutable");
|
|
1335
|
+
}
|
|
1336
|
+
if (cacheControl.maxAge) {
|
|
1337
|
+
controls.push(`max-age=${cacheControl.maxAge}`);
|
|
1338
|
+
}
|
|
1339
|
+
if (cacheControl.sMaxAge) {
|
|
1340
|
+
controls.push(`s-maxage=${cacheControl.sMaxAge}`);
|
|
1341
|
+
}
|
|
1342
|
+
if (cacheControl.noStore) {
|
|
1343
|
+
controls.push("no-store");
|
|
1344
|
+
}
|
|
1345
|
+
if (cacheControl.noCache) {
|
|
1346
|
+
controls.push("no-cache");
|
|
1347
|
+
}
|
|
1348
|
+
if (cacheControl.private) {
|
|
1349
|
+
controls.push("private");
|
|
1350
|
+
}
|
|
1351
|
+
if (cacheControl.public) {
|
|
1352
|
+
controls.push("public");
|
|
1353
|
+
}
|
|
1354
|
+
if (cacheControl.staleWhileRevalidate) {
|
|
1355
|
+
controls.push(`stale-while-revalidate=${cacheControl.staleWhileRevalidate}`);
|
|
1356
|
+
}
|
|
1357
|
+
if (cacheControl.staleIfError) {
|
|
1358
|
+
controls.push(`stale-if-error=${cacheControl.staleIfError}`);
|
|
1359
|
+
}
|
|
1360
|
+
return controls.join(", ");
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
const SAMESITE = {
|
|
1364
|
+
lax: "Lax",
|
|
1365
|
+
Lax: "Lax",
|
|
1366
|
+
None: "None",
|
|
1367
|
+
none: "None",
|
|
1368
|
+
strict: "Strict",
|
|
1369
|
+
Strict: "Strict"
|
|
1370
|
+
};
|
|
1371
|
+
const UNIT = {
|
|
1372
|
+
seconds: 1,
|
|
1373
|
+
minutes: 1 * 60,
|
|
1374
|
+
hours: 1 * 60 * 60,
|
|
1375
|
+
days: 1 * 60 * 60 * 24,
|
|
1376
|
+
weeks: 1 * 60 * 60 * 24 * 7
|
|
1377
|
+
};
|
|
1378
|
+
function tryDecodeUriComponent(str) {
|
|
1379
|
+
try {
|
|
1380
|
+
return decodeURIComponent(str);
|
|
1381
|
+
} catch {
|
|
1382
|
+
return str;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
const parseCookieString = (cookieString) => {
|
|
1386
|
+
const cookie = {};
|
|
1387
|
+
if (typeof cookieString === "string" && cookieString !== "") {
|
|
1388
|
+
const cookieSegments = cookieString.split(";");
|
|
1389
|
+
for (const cookieSegment of cookieSegments) {
|
|
1390
|
+
const separatorIndex = cookieSegment.indexOf("=");
|
|
1391
|
+
if (separatorIndex !== -1) {
|
|
1392
|
+
cookie[tryDecodeUriComponent(cookieSegment.slice(0, separatorIndex).trim())] = tryDecodeUriComponent(cookieSegment.slice(separatorIndex + 1).trim());
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
return cookie;
|
|
1397
|
+
};
|
|
1398
|
+
function resolveSameSite(sameSite) {
|
|
1399
|
+
if (sameSite === true) {
|
|
1400
|
+
return "Strict";
|
|
1401
|
+
}
|
|
1402
|
+
if (sameSite === false) {
|
|
1403
|
+
return "None";
|
|
1404
|
+
}
|
|
1405
|
+
if (sameSite) {
|
|
1406
|
+
return SAMESITE[sameSite];
|
|
1407
|
+
}
|
|
1408
|
+
return void 0;
|
|
1409
|
+
}
|
|
1410
|
+
const createSetCookieValue = (cookieName, cookieValue, options) => {
|
|
1411
|
+
const c = [
|
|
1412
|
+
`${cookieName}=${cookieValue}`
|
|
1413
|
+
];
|
|
1414
|
+
if (typeof options.domain === "string") {
|
|
1415
|
+
c.push(`Domain=${options.domain}`);
|
|
1416
|
+
}
|
|
1417
|
+
if (typeof options.maxAge === "number") {
|
|
1418
|
+
c.push(`Max-Age=${options.maxAge}`);
|
|
1419
|
+
} else if (Array.isArray(options.maxAge)) {
|
|
1420
|
+
c.push(`Max-Age=${options.maxAge[0] * UNIT[options.maxAge[1]]}`);
|
|
1421
|
+
} else if (typeof options.expires === "number" || typeof options.expires == "string") {
|
|
1422
|
+
c.push(`Expires=${options.expires}`);
|
|
1423
|
+
} else if (options.expires instanceof Date) {
|
|
1424
|
+
c.push(`Expires=${options.expires.toUTCString()}`);
|
|
1425
|
+
}
|
|
1426
|
+
if (options.httpOnly) {
|
|
1427
|
+
c.push("HttpOnly");
|
|
1428
|
+
}
|
|
1429
|
+
if (typeof options.path === "string") {
|
|
1430
|
+
c.push(`Path=${options.path}`);
|
|
1431
|
+
}
|
|
1432
|
+
const sameSite = resolveSameSite(options.sameSite);
|
|
1433
|
+
if (sameSite) {
|
|
1434
|
+
c.push(`SameSite=${sameSite}`);
|
|
1435
|
+
}
|
|
1436
|
+
if (options.secure) {
|
|
1437
|
+
c.push("Secure");
|
|
1438
|
+
}
|
|
1439
|
+
return c.join("; ");
|
|
1440
|
+
};
|
|
1441
|
+
const REQ_COOKIE = /* @__PURE__ */ Symbol("request-cookies");
|
|
1442
|
+
const RES_COOKIE = /* @__PURE__ */ Symbol("response-cookies");
|
|
1443
|
+
const LIVE_COOKIE = /* @__PURE__ */ Symbol("live-cookies");
|
|
1444
|
+
class Cookie {
|
|
1445
|
+
[REQ_COOKIE];
|
|
1446
|
+
[RES_COOKIE] = {};
|
|
1447
|
+
[LIVE_COOKIE] = {};
|
|
1448
|
+
appendCounter = 0;
|
|
1449
|
+
constructor(cookieString) {
|
|
1450
|
+
this[REQ_COOKIE] = parseCookieString(cookieString);
|
|
1451
|
+
this[LIVE_COOKIE] = {
|
|
1452
|
+
...this[REQ_COOKIE]
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
get(cookieName, live = true) {
|
|
1456
|
+
const value = this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
|
|
1457
|
+
if (!value) {
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
return {
|
|
1461
|
+
value,
|
|
1462
|
+
json() {
|
|
1463
|
+
return JSON.parse(value);
|
|
1464
|
+
},
|
|
1465
|
+
number() {
|
|
1466
|
+
return Number(value);
|
|
1467
|
+
}
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
getAll(live = true) {
|
|
1471
|
+
return Object.keys(this[live ? LIVE_COOKIE : REQ_COOKIE]).reduce((cookies, cookieName) => {
|
|
1472
|
+
cookies[cookieName] = this.get(cookieName);
|
|
1473
|
+
return cookies;
|
|
1474
|
+
}, {});
|
|
1475
|
+
}
|
|
1476
|
+
has(cookieName, live = true) {
|
|
1477
|
+
return !!this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
|
|
1478
|
+
}
|
|
1479
|
+
set(cookieName, cookieValue, options = {}) {
|
|
1480
|
+
this[LIVE_COOKIE][cookieName] = typeof cookieValue === "string" ? cookieValue : JSON.stringify(cookieValue);
|
|
1481
|
+
const resolvedValue = typeof cookieValue === "string" ? cookieValue : encodeURIComponent(JSON.stringify(cookieValue));
|
|
1482
|
+
this[RES_COOKIE][cookieName] = createSetCookieValue(cookieName, resolvedValue, options);
|
|
1483
|
+
}
|
|
1484
|
+
append(cookieName, cookieValue, options = {}) {
|
|
1485
|
+
this[LIVE_COOKIE][cookieName] = typeof cookieValue === "string" ? cookieValue : JSON.stringify(cookieValue);
|
|
1486
|
+
const resolvedValue = typeof cookieValue === "string" ? cookieValue : encodeURIComponent(JSON.stringify(cookieValue));
|
|
1487
|
+
this[RES_COOKIE][++this.appendCounter] = createSetCookieValue(cookieName, resolvedValue, options);
|
|
891
1488
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
const arrayKey = key.slice(0, -2);
|
|
899
|
-
object[arrayKey] = object[arrayKey] || [];
|
|
900
|
-
return object[arrayKey] = [...object[arrayKey], value];
|
|
901
|
-
}
|
|
902
|
-
if (index < keys.length - 1) {
|
|
903
|
-
return object[key] = object[key] || (Number.isNaN(+keys[index + 1]) ? {} : []);
|
|
904
|
-
}
|
|
905
|
-
return object[key] = value;
|
|
906
|
-
}, values2);
|
|
907
|
-
return values2;
|
|
908
|
-
}, {});
|
|
909
|
-
return values;
|
|
910
|
-
};
|
|
911
|
-
|
|
912
|
-
// packages/qwik-router/src/middleware/request-handler/response-page.ts
|
|
913
|
-
function getQwikRouterServerData(requestEv) {
|
|
914
|
-
const { params, request, status, locale, originalUrl } = requestEv;
|
|
915
|
-
const requestHeaders = {};
|
|
916
|
-
request.headers.forEach((value, key) => requestHeaders[key] = value);
|
|
917
|
-
const action = requestEv.sharedMap.get(RequestEvSharedActionId);
|
|
918
|
-
const formData = requestEv.sharedMap.get(RequestEvSharedActionFormData);
|
|
919
|
-
const routeName = requestEv.sharedMap.get(RequestRouteName);
|
|
920
|
-
const nonce = requestEv.sharedMap.get(RequestEvSharedNonce);
|
|
921
|
-
const headers = requestEv.request.headers;
|
|
922
|
-
const reconstructedUrl = new URL(originalUrl.pathname + originalUrl.search, originalUrl);
|
|
923
|
-
const host = headers.get("X-Forwarded-Host");
|
|
924
|
-
const protocol = headers.get("X-Forwarded-Proto");
|
|
925
|
-
if (host) {
|
|
926
|
-
reconstructedUrl.port = "";
|
|
927
|
-
reconstructedUrl.host = host;
|
|
1489
|
+
delete(name, options) {
|
|
1490
|
+
this.set(name, "deleted", {
|
|
1491
|
+
...options,
|
|
1492
|
+
maxAge: 0
|
|
1493
|
+
});
|
|
1494
|
+
this[LIVE_COOKIE][name] = null;
|
|
928
1495
|
}
|
|
929
|
-
|
|
930
|
-
|
|
1496
|
+
headers() {
|
|
1497
|
+
return Object.values(this[RES_COOKIE]);
|
|
931
1498
|
}
|
|
932
|
-
return {
|
|
933
|
-
url: reconstructedUrl.href,
|
|
934
|
-
requestHeaders,
|
|
935
|
-
locale: locale(),
|
|
936
|
-
nonce,
|
|
937
|
-
containerAttributes: {
|
|
938
|
-
"q:route": routeName
|
|
939
|
-
},
|
|
940
|
-
qwikrouter: {
|
|
941
|
-
routeName,
|
|
942
|
-
ev: requestEv,
|
|
943
|
-
params: { ...params },
|
|
944
|
-
loadedRoute: getRequestRoute(requestEv),
|
|
945
|
-
response: {
|
|
946
|
-
status: status(),
|
|
947
|
-
loaders: getRequestLoaders(requestEv),
|
|
948
|
-
action,
|
|
949
|
-
formData
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
};
|
|
953
1499
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
const isPageRoute = !!(route && isLastModulePageRoute(route[2]));
|
|
961
|
-
if (serverPlugins) {
|
|
962
|
-
_resolveRequestHandlers(
|
|
963
|
-
routeLoaders,
|
|
964
|
-
routeActions,
|
|
965
|
-
requestHandlers,
|
|
966
|
-
serverPlugins,
|
|
967
|
-
isPageRoute,
|
|
968
|
-
method
|
|
969
|
-
);
|
|
970
|
-
}
|
|
971
|
-
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);
|
|
985
|
-
_resolveRequestHandlers(
|
|
986
|
-
routeLoaders,
|
|
987
|
-
routeActions,
|
|
988
|
-
requestHandlers,
|
|
989
|
-
routeModules,
|
|
990
|
-
isPageRoute,
|
|
991
|
-
method
|
|
992
|
-
);
|
|
993
|
-
if (isPageRoute) {
|
|
994
|
-
requestHandlers.push((ev) => {
|
|
995
|
-
ev.sharedMap.set(RequestRouteName, routeName);
|
|
996
|
-
});
|
|
997
|
-
requestHandlers.push(actionsMiddleware(routeActions, routeLoaders));
|
|
998
|
-
requestHandlers.push(renderHandler);
|
|
1500
|
+
const mergeHeadersCookies = (headers, cookies) => {
|
|
1501
|
+
const cookieHeaders = cookies.headers();
|
|
1502
|
+
if (cookieHeaders.length > 0) {
|
|
1503
|
+
const newHeaders = new Headers(headers);
|
|
1504
|
+
for (const cookie of cookieHeaders) {
|
|
1505
|
+
newHeaders.append("Set-Cookie", cookie);
|
|
999
1506
|
}
|
|
1507
|
+
return newHeaders;
|
|
1000
1508
|
}
|
|
1001
|
-
return
|
|
1509
|
+
return headers;
|
|
1002
1510
|
};
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
requestHandlers.push(...routeModule.onRequest);
|
|
1009
|
-
}
|
|
1010
|
-
let methodReqHandler;
|
|
1011
|
-
switch (method) {
|
|
1012
|
-
case "GET": {
|
|
1013
|
-
methodReqHandler = routeModule.onGet;
|
|
1014
|
-
break;
|
|
1015
|
-
}
|
|
1016
|
-
case "POST": {
|
|
1017
|
-
methodReqHandler = routeModule.onPost;
|
|
1018
|
-
break;
|
|
1019
|
-
}
|
|
1020
|
-
case "PUT": {
|
|
1021
|
-
methodReqHandler = routeModule.onPut;
|
|
1022
|
-
break;
|
|
1023
|
-
}
|
|
1024
|
-
case "PATCH": {
|
|
1025
|
-
methodReqHandler = routeModule.onPatch;
|
|
1026
|
-
break;
|
|
1027
|
-
}
|
|
1028
|
-
case "DELETE": {
|
|
1029
|
-
methodReqHandler = routeModule.onDelete;
|
|
1030
|
-
break;
|
|
1031
|
-
}
|
|
1032
|
-
case "OPTIONS": {
|
|
1033
|
-
methodReqHandler = routeModule.onOptions;
|
|
1034
|
-
break;
|
|
1035
|
-
}
|
|
1036
|
-
case "HEAD": {
|
|
1037
|
-
methodReqHandler = routeModule.onHead;
|
|
1038
|
-
break;
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
if (typeof methodReqHandler === "function") {
|
|
1042
|
-
requestHandlers.push(methodReqHandler);
|
|
1043
|
-
} else if (Array.isArray(methodReqHandler)) {
|
|
1044
|
-
requestHandlers.push(...methodReqHandler);
|
|
1045
|
-
}
|
|
1046
|
-
if (collectActions) {
|
|
1047
|
-
for (const module of Object.values(routeModule)) {
|
|
1048
|
-
if (typeof module === "function") {
|
|
1049
|
-
if (module.__brand === "server_loader") {
|
|
1050
|
-
routeLoaders.push(module);
|
|
1051
|
-
} else if (module.__brand === "server_action") {
|
|
1052
|
-
routeActions.push(module);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1511
|
+
|
|
1512
|
+
class RewriteMessage extends AbortMessage {
|
|
1513
|
+
pathname;
|
|
1514
|
+
constructor(pathname) {
|
|
1515
|
+
super(), this.pathname = pathname;
|
|
1057
1516
|
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
const requestEventDeps = {
|
|
1520
|
+
QDATA_KEY,
|
|
1521
|
+
isPromise,
|
|
1522
|
+
createCacheControl,
|
|
1523
|
+
Cookie,
|
|
1524
|
+
AbortMessage,
|
|
1525
|
+
RedirectMessage,
|
|
1526
|
+
RewriteMessage,
|
|
1527
|
+
ServerError,
|
|
1528
|
+
getRouteLoaderPromise,
|
|
1529
|
+
getRouteMatchPathname,
|
|
1530
|
+
IsQData,
|
|
1531
|
+
encoder,
|
|
1532
|
+
getContentType
|
|
1058
1533
|
};
|
|
1059
|
-
function
|
|
1060
|
-
return
|
|
1061
|
-
if (requestEv.headersSent) {
|
|
1062
|
-
requestEv.exit();
|
|
1063
|
-
return;
|
|
1064
|
-
}
|
|
1065
|
-
const { method } = requestEv;
|
|
1066
|
-
const loaders = getRequestLoaders(requestEv);
|
|
1067
|
-
const isDev = getRequestMode(requestEv) === "dev";
|
|
1068
|
-
const qwikSerializer = requestEv[RequestEvQwikSerializer];
|
|
1069
|
-
if (isDev && method === "GET") {
|
|
1070
|
-
if (requestEv.query.has(QACTION_KEY)) {
|
|
1071
|
-
console.warn(
|
|
1072
|
-
'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">'
|
|
1073
|
-
);
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
if (method === "POST") {
|
|
1077
|
-
const selectedActionId = requestEv.query.get(QACTION_KEY);
|
|
1078
|
-
if (selectedActionId) {
|
|
1079
|
-
const serverActionsMap = globalThis._qwikActionsMap;
|
|
1080
|
-
const action = routeActions.find((action2) => action2.__id === selectedActionId) ?? (serverActionsMap == null ? void 0 : serverActionsMap.get(selectedActionId));
|
|
1081
|
-
if (action) {
|
|
1082
|
-
requestEv.sharedMap.set(RequestEvSharedActionId, selectedActionId);
|
|
1083
|
-
const data = await requestEv.parseBody();
|
|
1084
|
-
if (!data || typeof data !== "object") {
|
|
1085
|
-
throw new Error(
|
|
1086
|
-
`Expected request data for the action id ${selectedActionId} to be an object`
|
|
1087
|
-
);
|
|
1088
|
-
}
|
|
1089
|
-
const result = await runValidators(requestEv, action.__validators, data, isDev);
|
|
1090
|
-
if (!result.success) {
|
|
1091
|
-
loaders[selectedActionId] = requestEv.fail(result.status ?? 500, result.error);
|
|
1092
|
-
} else {
|
|
1093
|
-
const actionResolved = isDev ? await measure(
|
|
1094
|
-
requestEv,
|
|
1095
|
-
action.__qrl.getSymbol().split("_", 1)[0],
|
|
1096
|
-
() => action.__qrl.call(requestEv, result.data, requestEv)
|
|
1097
|
-
) : await action.__qrl.call(requestEv, result.data, requestEv);
|
|
1098
|
-
if (isDev) {
|
|
1099
|
-
verifySerializable(qwikSerializer, actionResolved, action.__qrl);
|
|
1100
|
-
}
|
|
1101
|
-
loaders[selectedActionId] = actionResolved;
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
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
|
-
});
|
|
1142
|
-
await Promise.all(resolvedLoadersPromises);
|
|
1143
|
-
}
|
|
1144
|
-
};
|
|
1534
|
+
function createRequestEvent(...args) {
|
|
1535
|
+
return createRequestEventWithDeps(requestEventDeps, ...args);
|
|
1145
1536
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
() => validator.validate(requestEv, data)
|
|
1158
|
-
);
|
|
1159
|
-
} else {
|
|
1160
|
-
lastResult = await validator.validate(requestEv, data);
|
|
1161
|
-
}
|
|
1162
|
-
if (!lastResult.success) {
|
|
1163
|
-
return lastResult;
|
|
1164
|
-
} else {
|
|
1165
|
-
data = lastResult.data;
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1537
|
+
|
|
1538
|
+
async function runNextWithDeps(requestEv, rebuildRouteInfo, resolve, deps) {
|
|
1539
|
+
try {
|
|
1540
|
+
const isValidURL = (url) => new URL(url.pathname + url.search, url);
|
|
1541
|
+
isValidURL(requestEv.originalUrl);
|
|
1542
|
+
} catch {
|
|
1543
|
+
const status = 404;
|
|
1544
|
+
const message = "Resource Not Found";
|
|
1545
|
+
requestEv.status(status);
|
|
1546
|
+
requestEv.html(status, deps.getErrorHtml(status, message));
|
|
1547
|
+
return new deps.ServerError(status, message);
|
|
1168
1548
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
if (Array.isArray(data)) {
|
|
1182
|
-
const [qrl, ...args] = data;
|
|
1183
|
-
if (isQrl(qrl) && qrl.getHash() === fn) {
|
|
1184
|
-
let result;
|
|
1185
|
-
try {
|
|
1186
|
-
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);
|
|
1194
|
-
}
|
|
1195
|
-
} catch (err) {
|
|
1196
|
-
if (err instanceof ServerError) {
|
|
1197
|
-
throw ev.error(err.status, err.data);
|
|
1198
|
-
}
|
|
1199
|
-
throw ev.error(500, "Invalid request");
|
|
1549
|
+
let rewriteAttempt = 1;
|
|
1550
|
+
async function runOnce() {
|
|
1551
|
+
try {
|
|
1552
|
+
await requestEv.next();
|
|
1553
|
+
} catch (e) {
|
|
1554
|
+
if (e instanceof deps.RedirectMessage) {
|
|
1555
|
+
const stream = requestEv.getWritableStream();
|
|
1556
|
+
await stream.close();
|
|
1557
|
+
return e;
|
|
1558
|
+
} else if (e instanceof deps.RewriteMessage) {
|
|
1559
|
+
if (rewriteAttempt > 50) {
|
|
1560
|
+
return new Error(`Infinite rewrite loop`);
|
|
1200
1561
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
}
|
|
1216
|
-
stream.close();
|
|
1562
|
+
rewriteAttempt += 1;
|
|
1563
|
+
const url = new URL(requestEv.url);
|
|
1564
|
+
url.pathname = e.pathname;
|
|
1565
|
+
const { loadedRoute, requestHandlers } = await rebuildRouteInfo(url);
|
|
1566
|
+
requestEv.resetRoute(loadedRoute, requestHandlers, url);
|
|
1567
|
+
return await runOnce();
|
|
1568
|
+
} else if (e instanceof deps.AbortMessage) {
|
|
1569
|
+
return;
|
|
1570
|
+
} else if (e instanceof deps.ServerError && !requestEv.headersSent) {
|
|
1571
|
+
const status = e.status;
|
|
1572
|
+
const accept = requestEv.request.headers.get("Accept");
|
|
1573
|
+
if (accept && !accept.includes("text/html")) {
|
|
1574
|
+
requestEv.headers.set("Content-Type", "application/qwik-json");
|
|
1575
|
+
requestEv.send(status, await _serialize(e.data));
|
|
1217
1576
|
} else {
|
|
1218
|
-
|
|
1219
|
-
ev.headers.set("Content-Type", "application/qwik-json");
|
|
1220
|
-
const message = await qwikSerializer._serialize([result]);
|
|
1221
|
-
ev.send(200, message);
|
|
1577
|
+
requestEv.html(status, deps.getErrorHtml(status, e.data));
|
|
1222
1578
|
}
|
|
1223
|
-
return;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
throw ev.error(500, "Invalid request");
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
function fixTrailingSlash(ev) {
|
|
1230
|
-
const trailingSlash = getRequestTrailingSlash(ev);
|
|
1231
|
-
const { basePathname, originalUrl, sharedMap } = ev;
|
|
1232
|
-
const { pathname, search } = originalUrl;
|
|
1233
|
-
const isQData = sharedMap.has(IsQData);
|
|
1234
|
-
if (!isQData && pathname !== basePathname && !pathname.endsWith(".html")) {
|
|
1235
|
-
if (trailingSlash) {
|
|
1236
|
-
if (!pathname.endsWith("/")) {
|
|
1237
|
-
throw ev.redirect(301 /* MovedPermanently */, pathname + "/" + search);
|
|
1579
|
+
return e;
|
|
1238
1580
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1581
|
+
if (!isDev) {
|
|
1582
|
+
try {
|
|
1583
|
+
if (!requestEv.headersSent) {
|
|
1584
|
+
requestEv.headers.set("content-type", "text/html; charset=utf-8");
|
|
1585
|
+
requestEv.cacheControl({
|
|
1586
|
+
noCache: true
|
|
1587
|
+
});
|
|
1588
|
+
requestEv.status(500);
|
|
1589
|
+
}
|
|
1590
|
+
const stream = requestEv.getWritableStream();
|
|
1591
|
+
if (!stream.locked) {
|
|
1592
|
+
const writer = stream.getWriter();
|
|
1593
|
+
await writer.write(deps.encoder.encode(deps.getErrorHtml(500, "Internal Server Error")));
|
|
1594
|
+
await writer.close();
|
|
1595
|
+
}
|
|
1596
|
+
} catch {
|
|
1597
|
+
console.error("Unable to render error page");
|
|
1598
|
+
}
|
|
1245
1599
|
}
|
|
1600
|
+
return e instanceof Error || typeof e === "object" && e !== null ? e : new Error(String(e));
|
|
1246
1601
|
}
|
|
1247
1602
|
}
|
|
1248
|
-
}
|
|
1249
|
-
function verifySerializable(qwikSerializer, data, qrl) {
|
|
1250
1603
|
try {
|
|
1251
|
-
|
|
1252
|
-
}
|
|
1253
|
-
if (
|
|
1254
|
-
|
|
1604
|
+
return await runOnce();
|
|
1605
|
+
} finally {
|
|
1606
|
+
if (!requestEv.isDirty()) {
|
|
1607
|
+
resolve(null);
|
|
1255
1608
|
}
|
|
1256
|
-
throw e;
|
|
1257
1609
|
}
|
|
1258
1610
|
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
if (url.pathname.endsWith(QDATA_JSON)) {
|
|
1269
|
-
url.pathname = url.pathname.slice(0, -QDATA_JSON.length);
|
|
1270
|
-
}
|
|
1271
|
-
if (trailingSlash) {
|
|
1272
|
-
if (!url.pathname.endsWith("/")) {
|
|
1273
|
-
url.pathname += "/";
|
|
1274
|
-
}
|
|
1275
|
-
} else {
|
|
1276
|
-
if (url.pathname.endsWith("/")) {
|
|
1277
|
-
url.pathname = url.pathname.slice(0, -1);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
const search = url.search.slice(1).replaceAll(/&?q(action|data|func)=[^&]+/g, "");
|
|
1281
|
-
return `${url.pathname}${search ? `?${search}` : ""}${url.hash}`;
|
|
1611
|
+
function runQwikRouterWithDeps(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, basePathname, deps) {
|
|
1612
|
+
let resolve;
|
|
1613
|
+
const responsePromise = new Promise((r) => resolve = r);
|
|
1614
|
+
const requestEv = deps.createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, basePathname, resolve);
|
|
1615
|
+
return {
|
|
1616
|
+
response: responsePromise,
|
|
1617
|
+
requestEv,
|
|
1618
|
+
completion: deps.asyncRequestStore ? deps.asyncRequestStore.run(requestEv, runNextWithDeps, requestEv, rebuildRouteInfo, resolve, deps) : runNextWithDeps(requestEv, rebuildRouteInfo, resolve, deps)
|
|
1619
|
+
};
|
|
1282
1620
|
}
|
|
1283
|
-
|
|
1284
|
-
function
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
if (forbidden) {
|
|
1296
|
-
throw requestEv.error(
|
|
1297
|
-
403,
|
|
1298
|
-
`CSRF check failed. Cross-site ${requestEv.method} form submissions are forbidden.
|
|
1299
|
-
The request origin "${inputOrigin}" does not match the server origin "${origin}".`
|
|
1300
|
-
);
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1621
|
+
|
|
1622
|
+
function runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, basePathname = "/") {
|
|
1623
|
+
return runQwikRouterWithDeps(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, basePathname, {
|
|
1624
|
+
AbortMessage,
|
|
1625
|
+
RedirectMessage,
|
|
1626
|
+
RewriteMessage,
|
|
1627
|
+
ServerError,
|
|
1628
|
+
asyncRequestStore: _asyncRequestStore,
|
|
1629
|
+
createRequestEvent,
|
|
1630
|
+
encoder,
|
|
1631
|
+
getErrorHtml
|
|
1632
|
+
});
|
|
1303
1633
|
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
const requestHeaders = {};
|
|
1314
|
-
requestEv.request.headers.forEach((value, key) => requestHeaders[key] = value);
|
|
1315
|
-
const responseHeaders = requestEv.headers;
|
|
1316
|
-
if (!responseHeaders.has("Content-Type")) {
|
|
1317
|
-
responseHeaders.set("Content-Type", "text/html; charset=utf-8");
|
|
1318
|
-
}
|
|
1319
|
-
const trailingSlash = getRequestTrailingSlash(requestEv);
|
|
1320
|
-
const { readable, writable } = new TextEncoderStream();
|
|
1321
|
-
const writableStream = requestEv.getWritableStream();
|
|
1322
|
-
const pipe = readable.pipeTo(writableStream, { preventClose: true });
|
|
1323
|
-
const stream = writable.getWriter();
|
|
1324
|
-
const status = requestEv.status();
|
|
1325
|
-
try {
|
|
1326
|
-
const isStatic = getRequestMode(requestEv) === "static";
|
|
1327
|
-
const serverData = getQwikRouterServerData(requestEv);
|
|
1328
|
-
const result = await render({
|
|
1329
|
-
base: requestEv.basePathname + "build/",
|
|
1330
|
-
stream,
|
|
1331
|
-
serverData,
|
|
1332
|
-
containerAttributes: {
|
|
1333
|
-
["q:render"]: isStatic ? "static" : "",
|
|
1334
|
-
...serverData.containerAttributes
|
|
1335
|
-
}
|
|
1336
|
-
});
|
|
1337
|
-
const qData = {
|
|
1338
|
-
loaders: getRequestLoaders(requestEv),
|
|
1339
|
-
action: requestEv.sharedMap.get(RequestEvSharedActionId),
|
|
1340
|
-
status: status !== 200 ? status : 200,
|
|
1341
|
-
href: getPathname(requestEv.url, trailingSlash)
|
|
1342
|
-
};
|
|
1343
|
-
if (typeof result.html === "string") {
|
|
1344
|
-
await stream.write(result.html);
|
|
1345
|
-
}
|
|
1346
|
-
requestEv.sharedMap.set("qData", qData);
|
|
1347
|
-
} finally {
|
|
1348
|
-
await stream.ready;
|
|
1349
|
-
await stream.close();
|
|
1350
|
-
await pipe;
|
|
1351
|
-
}
|
|
1352
|
-
await writableStream.close();
|
|
1634
|
+
|
|
1635
|
+
let qwikRouterConfigActual;
|
|
1636
|
+
async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrigin, renderFn, isInternal) {
|
|
1637
|
+
const { routes, serverPlugins, cacheModules } = qwikRouterConfig;
|
|
1638
|
+
const loadedRoute = await loadRoute(routes, cacheModules, pathname, isInternal);
|
|
1639
|
+
const requestHandlers = resolveRequestHandlers(serverPlugins, loadedRoute, method, checkOrigin, renderQwikMiddleware(renderFn), isInternal);
|
|
1640
|
+
return {
|
|
1641
|
+
loadedRoute,
|
|
1642
|
+
requestHandlers
|
|
1353
1643
|
};
|
|
1354
1644
|
}
|
|
1355
|
-
async function
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
await requestEv.next();
|
|
1362
|
-
} catch (err) {
|
|
1363
|
-
if (!(err instanceof RedirectMessage)) {
|
|
1364
|
-
throw err;
|
|
1645
|
+
async function requestHandler(serverRequestEv, opts) {
|
|
1646
|
+
const { render, checkOrigin } = opts;
|
|
1647
|
+
let { qwikRouterConfig } = opts;
|
|
1648
|
+
if (!qwikRouterConfig) {
|
|
1649
|
+
if (!qwikRouterConfigActual) {
|
|
1650
|
+
qwikRouterConfigActual = await import('@qwik-router-config');
|
|
1365
1651
|
}
|
|
1652
|
+
qwikRouterConfig = qwikRouterConfigActual;
|
|
1366
1653
|
}
|
|
1367
|
-
if (
|
|
1368
|
-
|
|
1369
|
-
}
|
|
1370
|
-
const status = requestEv.status();
|
|
1371
|
-
const location = requestEv.headers.get("Location");
|
|
1372
|
-
const isRedirect = status >= 301 && status <= 308 && location;
|
|
1373
|
-
if (isRedirect) {
|
|
1374
|
-
const adaptedLocation = makeQDataPath(location);
|
|
1375
|
-
if (adaptedLocation) {
|
|
1376
|
-
requestEv.headers.set("Location", adaptedLocation);
|
|
1377
|
-
requestEv.getWritableStream().close();
|
|
1378
|
-
return;
|
|
1379
|
-
} else {
|
|
1380
|
-
requestEv.status(200);
|
|
1381
|
-
requestEv.headers.delete("Location");
|
|
1382
|
-
}
|
|
1654
|
+
if (!qwikRouterConfig) {
|
|
1655
|
+
throw new Error("qwikRouterConfig is required.");
|
|
1383
1656
|
}
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
if (!isPageDataReq) {
|
|
1388
|
-
return;
|
|
1657
|
+
const { pathname, isInternal } = getRouteMatchPathname(serverRequestEv.url.pathname);
|
|
1658
|
+
if (pathname === "/.well-known" || pathname.startsWith("/.well-known/")) {
|
|
1659
|
+
return null;
|
|
1389
1660
|
}
|
|
1390
|
-
await
|
|
1391
|
-
if (
|
|
1392
|
-
return;
|
|
1661
|
+
const { loadedRoute, requestHandlers } = await loadRequestHandlers(qwikRouterConfig, pathname, serverRequestEv.request.method, checkOrigin ?? true, render, isInternal);
|
|
1662
|
+
if (qwikRouterConfig.fallthrough && loadedRoute.$notFound$) {
|
|
1663
|
+
return null;
|
|
1393
1664
|
}
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
const requestHeaders = {};
|
|
1398
|
-
requestEv.request.headers.forEach((value, key) => requestHeaders[key] = value);
|
|
1399
|
-
requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
|
|
1400
|
-
const qData = {
|
|
1401
|
-
loaders: getRequestLoaders(requestEv),
|
|
1402
|
-
action: requestEv.sharedMap.get(RequestEvSharedActionId),
|
|
1403
|
-
status: status !== 200 ? status : 200,
|
|
1404
|
-
href: getPathname(requestEv.url, trailingSlash),
|
|
1405
|
-
redirect: redirectLocation ?? void 0,
|
|
1406
|
-
isRewrite: requestEv.sharedMap.get(RequestEvIsRewrite)
|
|
1665
|
+
const rebuildRouteInfo = async (url) => {
|
|
1666
|
+
const { pathname: pathname2 } = getRouteMatchPathname(url.pathname);
|
|
1667
|
+
return loadRequestHandlers(qwikRouterConfig, pathname2, serverRequestEv.request.method, checkOrigin ?? true, render, isInternal);
|
|
1407
1668
|
};
|
|
1408
|
-
|
|
1409
|
-
const qwikSerializer = requestEv[RequestEvQwikSerializer];
|
|
1410
|
-
const data = await qwikSerializer._serialize([qData]);
|
|
1411
|
-
writer.write(encoder.encode(data));
|
|
1412
|
-
requestEv.sharedMap.set("qData", qData);
|
|
1413
|
-
writer.close();
|
|
1414
|
-
}
|
|
1415
|
-
function makeQDataPath(href) {
|
|
1416
|
-
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;
|
|
1421
|
-
} else {
|
|
1422
|
-
return void 0;
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
function now() {
|
|
1426
|
-
return typeof performance !== "undefined" ? performance.now() : 0;
|
|
1669
|
+
return runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, qwikRouterConfig.basePathname);
|
|
1427
1670
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
if (
|
|
1436
|
-
|
|
1671
|
+
|
|
1672
|
+
const notFounds = [
|
|
1673
|
+
// Will be replaced in post-build with the 404s generated by SSG
|
|
1674
|
+
"__QWIK_ROUTER_NOT_FOUND_ARRAY__"
|
|
1675
|
+
];
|
|
1676
|
+
function getNotFound(prefix) {
|
|
1677
|
+
for (const [path, html] of notFounds) {
|
|
1678
|
+
if (prefix.startsWith(path)) {
|
|
1679
|
+
return html;
|
|
1437
1680
|
}
|
|
1438
|
-
measurements.push([name, duration]);
|
|
1439
1681
|
}
|
|
1440
|
-
|
|
1441
|
-
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);
|
|
1682
|
+
return minimalHtmlResponse(404, "Resource Not Found");
|
|
1445
1683
|
}
|
|
1446
1684
|
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1685
|
+
const staticPaths = /* @__PURE__ */ new Set([
|
|
1686
|
+
"__QWIK_ROUTER_STATIC_PATHS_ARRAY__"
|
|
1687
|
+
]);
|
|
1688
|
+
function isStaticPath(method, url) {
|
|
1689
|
+
if (method.toUpperCase() !== "GET") {
|
|
1690
|
+
return false;
|
|
1691
|
+
}
|
|
1692
|
+
const p = url.pathname;
|
|
1693
|
+
if (p.startsWith("/" + (globalThis.__QWIK_BUILD_DIR__ || "build") + "/")) {
|
|
1694
|
+
return true;
|
|
1695
|
+
}
|
|
1696
|
+
if (p.startsWith("/" + (globalThis.__QWIK_ASSETS_DIR__ || "assets") + "/")) {
|
|
1697
|
+
return true;
|
|
1698
|
+
}
|
|
1699
|
+
if (staticPaths.has(p)) {
|
|
1700
|
+
return true;
|
|
1701
|
+
}
|
|
1702
|
+
if (p.endsWith("/q-data.json")) {
|
|
1703
|
+
const pWithoutQdata = p.replace(/\/q-data.json$/, "");
|
|
1704
|
+
if (staticPaths.has(pWithoutQdata + "/")) {
|
|
1705
|
+
return true;
|
|
1706
|
+
}
|
|
1707
|
+
if (staticPaths.has(pWithoutQdata)) {
|
|
1708
|
+
return true;
|
|
1709
|
+
}
|
|
1452
1710
|
}
|
|
1453
|
-
|
|
1454
|
-
const matchPathname = getRouteMatchPathname(pathname, qwikRouterConfig.trailingSlash);
|
|
1455
|
-
const routeAndHandlers = await loadRequestHandlers(
|
|
1456
|
-
qwikRouterConfig,
|
|
1457
|
-
matchPathname,
|
|
1458
|
-
serverRequestEv.request.method,
|
|
1459
|
-
checkOrigin ?? true,
|
|
1460
|
-
render
|
|
1461
|
-
);
|
|
1462
|
-
if (routeAndHandlers) {
|
|
1463
|
-
const [route, requestHandlers] = routeAndHandlers;
|
|
1464
|
-
const rebuildRouteInfo = async (url) => {
|
|
1465
|
-
const matchPathname2 = getRouteMatchPathname(url.pathname, qwikRouterConfig.trailingSlash);
|
|
1466
|
-
const routeAndHandlers2 = await loadRequestHandlers(
|
|
1467
|
-
qwikRouterConfig,
|
|
1468
|
-
matchPathname2,
|
|
1469
|
-
serverRequestEv.request.method,
|
|
1470
|
-
checkOrigin ?? true,
|
|
1471
|
-
render
|
|
1472
|
-
);
|
|
1473
|
-
if (routeAndHandlers2) {
|
|
1474
|
-
const [loadedRoute, requestHandlers2] = routeAndHandlers2;
|
|
1475
|
-
return { loadedRoute, requestHandlers: requestHandlers2 };
|
|
1476
|
-
} else {
|
|
1477
|
-
return { loadedRoute: null, requestHandlers: [] };
|
|
1478
|
-
}
|
|
1479
|
-
};
|
|
1480
|
-
return runQwikRouter(
|
|
1481
|
-
serverRequestEv,
|
|
1482
|
-
route,
|
|
1483
|
-
requestHandlers,
|
|
1484
|
-
rebuildRouteInfo,
|
|
1485
|
-
qwikRouterConfig.trailingSlash,
|
|
1486
|
-
qwikRouterConfig.basePathname,
|
|
1487
|
-
qwikSerializer
|
|
1488
|
-
);
|
|
1489
|
-
}
|
|
1490
|
-
return null;
|
|
1491
|
-
}
|
|
1492
|
-
async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrigin, renderFn) {
|
|
1493
|
-
const { routes, serverPlugins, menus, cacheModules } = qwikRouterConfig;
|
|
1494
|
-
const route = await loadRoute(routes, menus, cacheModules, pathname);
|
|
1495
|
-
const requestHandlers = resolveRequestHandlers(
|
|
1496
|
-
serverPlugins,
|
|
1497
|
-
route,
|
|
1498
|
-
method,
|
|
1499
|
-
checkOrigin,
|
|
1500
|
-
renderQwikMiddleware(renderFn)
|
|
1501
|
-
);
|
|
1502
|
-
if (requestHandlers.length > 0) {
|
|
1503
|
-
return [route, requestHandlers];
|
|
1504
|
-
}
|
|
1505
|
-
return null;
|
|
1711
|
+
return false;
|
|
1506
1712
|
}
|
|
1507
1713
|
|
|
1508
|
-
|
|
1509
|
-
var _TextEncoderStream_polyfill = class {
|
|
1714
|
+
class _TextEncoderStream_polyfill {
|
|
1510
1715
|
#pendingHighSurrogate = null;
|
|
1511
1716
|
#handle = new TextEncoder();
|
|
1512
1717
|
#transform = new TransformStream({
|
|
@@ -1523,14 +1728,14 @@ var _TextEncoderStream_polyfill = class {
|
|
|
1523
1728
|
finalChunk += highSurrogate + item;
|
|
1524
1729
|
continue;
|
|
1525
1730
|
}
|
|
1526
|
-
finalChunk += "
|
|
1731
|
+
finalChunk += "�";
|
|
1527
1732
|
}
|
|
1528
1733
|
if (55296 <= codeUnit && codeUnit <= 56319) {
|
|
1529
1734
|
this.#pendingHighSurrogate = item;
|
|
1530
1735
|
continue;
|
|
1531
1736
|
}
|
|
1532
1737
|
if (56320 <= codeUnit && codeUnit <= 57343) {
|
|
1533
|
-
finalChunk += "
|
|
1738
|
+
finalChunk += "�";
|
|
1534
1739
|
continue;
|
|
1535
1740
|
}
|
|
1536
1741
|
finalChunk += item;
|
|
@@ -1541,7 +1746,11 @@ var _TextEncoderStream_polyfill = class {
|
|
|
1541
1746
|
},
|
|
1542
1747
|
flush: (controller) => {
|
|
1543
1748
|
if (this.#pendingHighSurrogate !== null) {
|
|
1544
|
-
controller.enqueue(new Uint8Array([
|
|
1749
|
+
controller.enqueue(new Uint8Array([
|
|
1750
|
+
239,
|
|
1751
|
+
191,
|
|
1752
|
+
189
|
|
1753
|
+
]));
|
|
1545
1754
|
}
|
|
1546
1755
|
}
|
|
1547
1756
|
});
|
|
@@ -1557,14 +1766,6 @@ var _TextEncoderStream_polyfill = class {
|
|
|
1557
1766
|
get [Symbol.toStringTag]() {
|
|
1558
1767
|
return "TextEncoderStream";
|
|
1559
1768
|
}
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
RedirectMessage,
|
|
1564
|
-
RewriteMessage,
|
|
1565
|
-
ServerError,
|
|
1566
|
-
_TextEncoderStream_polyfill,
|
|
1567
|
-
getErrorHtml,
|
|
1568
|
-
mergeHeadersCookies,
|
|
1569
|
-
requestHandler
|
|
1570
|
-
};
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
export { AbortMessage, RedirectMessage, RequestEvShareQData, RewriteMessage, ServerError, _TextEncoderStream_polyfill, _asyncRequestStore, clearSsrCache, getErrorHtml, getNotFound, isStaticPath, mergeHeadersCookies, requestHandler };
|