@qwik.dev/router 2.0.0-beta.27 → 2.0.0-beta.29
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/lib/adapters/azure-swa/vite/index.mjs +31 -36
- package/lib/adapters/bun-server/vite/index.mjs +0 -3
- package/lib/adapters/cloud-run/vite/index.mjs +0 -3
- package/lib/adapters/cloudflare-pages/vite/index.mjs +15 -9
- package/lib/adapters/deno-server/vite/index.mjs +7 -5
- package/lib/adapters/netlify-edge/vite/index.mjs +13 -23
- package/lib/adapters/node-server/vite/index.mjs +0 -3
- package/lib/adapters/shared/vite/index.d.ts +1 -7
- package/lib/adapters/shared/vite/index.mjs +171 -157
- package/lib/adapters/ssg/vite/index.mjs +3 -4
- package/lib/adapters/vercel-edge/vite/index.mjs +25 -9
- package/lib/chunks/error-handler.mjs +26 -26
- package/lib/chunks/fs.mjs +28 -138
- package/lib/chunks/http-error.qwik.mjs +27 -0
- package/lib/chunks/not-found-wrapper.qwik.mjs +25 -0
- package/lib/chunks/pathname.mjs +105 -0
- package/lib/chunks/routing.qwik.mjs +592 -216
- package/lib/chunks/system.mjs +328 -0
- package/lib/chunks/use-functions.qwik.mjs +35 -0
- package/lib/chunks/worker-thread.mjs +271 -0
- package/lib/index.d.ts +136 -102
- package/lib/index.qwik.mjs +699 -751
- package/lib/middleware/aws-lambda/index.mjs +7 -1
- package/lib/middleware/azure-swa/index.mjs +7 -2
- package/lib/middleware/bun/index.mjs +24 -8
- package/lib/middleware/cloudflare-pages/index.mjs +10 -3
- package/lib/middleware/deno/index.mjs +23 -8
- package/lib/middleware/netlify-edge/index.mjs +10 -3
- package/lib/middleware/node/index.mjs +10 -14
- package/lib/middleware/request-handler/index.d.ts +82 -12
- package/lib/middleware/request-handler/index.mjs +661 -524
- package/lib/middleware/vercel-edge/index.mjs +10 -3
- package/lib/modules.d.ts +7 -4
- package/lib/ssg/index.d.ts +48 -16
- package/lib/ssg/index.mjs +320 -7
- package/lib/vite/index.d.ts +6 -0
- package/lib/vite/index.mjs +1106 -630
- package/modules.d.ts +7 -4
- package/package.json +9 -9
- package/lib/chunks/format-error.mjs +0 -137
- package/lib/chunks/index.mjs +0 -884
- package/lib/chunks/types.qwik.mjs +0 -22
|
@@ -1,13 +1,57 @@
|
|
|
1
1
|
import { isServer } from '@qwik.dev/core/build';
|
|
2
|
-
import {
|
|
2
|
+
import { k as isPromise, j as QDATA_KEY, Q as Q_ROUTE, f as QFN_KEY, m as QLOADER_KEY, h as QACTION_KEY, n as resolveRouteConfig, d as loadRoute } from '../../chunks/routing.qwik.mjs';
|
|
3
3
|
import { inlinedQrl } from '@qwik.dev/core';
|
|
4
4
|
import { _serialize, isDev, _UNINITIALIZED, _deserialize, _verifySerializable } from '@qwik.dev/core/internal';
|
|
5
|
-
import { L as LoadedRouteProp } from '../../chunks/types.qwik.mjs';
|
|
6
5
|
import { _asyncRequestStore as _asyncRequestStore$1, ServerError as ServerError$1, RedirectMessage as RedirectMessage$1, RewriteMessage as RewriteMessage$1, AbortMessage as AbortMessage$1 } from '@qwik.dev/router/middleware/request-handler';
|
|
7
6
|
import { g as getErrorHtml, m as minimalHtmlResponse } from '../../chunks/error-handler.mjs';
|
|
8
|
-
import '@qwik.dev/core/preloader';
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
const MAX_CACHE_SIZE = typeof globalThis.__SSR_CACHE_SIZE__ === "number" ? globalThis.__SSR_CACHE_SIZE__ : 50;
|
|
9
|
+
const ssrCache = /* @__PURE__ */ new Map();
|
|
10
|
+
function resolveETag(eTagExport, headProps) {
|
|
11
|
+
if (eTagExport === void 0) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
if (typeof eTagExport === "function") {
|
|
15
|
+
return eTagExport(headProps);
|
|
16
|
+
}
|
|
17
|
+
return eTagExport;
|
|
18
|
+
}
|
|
19
|
+
function resolveCacheKey(cacheKeyExport, status, eTag, pathname) {
|
|
20
|
+
if (cacheKeyExport === true) {
|
|
21
|
+
return `${status}|${eTag}|${pathname}`;
|
|
22
|
+
}
|
|
23
|
+
if (typeof cacheKeyExport !== "function") {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return cacheKeyExport(status, eTag, pathname);
|
|
27
|
+
}
|
|
28
|
+
function getCachedHtml(key) {
|
|
29
|
+
const html = ssrCache.get(key);
|
|
30
|
+
if (html !== void 0) {
|
|
31
|
+
ssrCache.delete(key);
|
|
32
|
+
ssrCache.set(key, html);
|
|
33
|
+
}
|
|
34
|
+
return html;
|
|
35
|
+
}
|
|
36
|
+
function setCachedHtml(key, html) {
|
|
37
|
+
if (MAX_CACHE_SIZE <= 0) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (ssrCache.size >= MAX_CACHE_SIZE) {
|
|
41
|
+
const firstKey = ssrCache.keys().next().value;
|
|
42
|
+
ssrCache.delete(firstKey);
|
|
43
|
+
}
|
|
44
|
+
ssrCache.set(key, html);
|
|
45
|
+
}
|
|
46
|
+
function clearSsrCache(cacheKey) {
|
|
47
|
+
if (cacheKey != null) {
|
|
48
|
+
ssrCache.delete(cacheKey);
|
|
49
|
+
} else {
|
|
50
|
+
ssrCache.clear();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
var HttpStatus = /* @__PURE__ */ (function(HttpStatus2) {
|
|
11
55
|
HttpStatus2[HttpStatus2["Continue"] = 100] = "Continue";
|
|
12
56
|
HttpStatus2[HttpStatus2["SwitchingProtocols"] = 101] = "SwitchingProtocols";
|
|
13
57
|
HttpStatus2[HttpStatus2["Processing"] = 102] = "Processing";
|
|
@@ -70,7 +114,7 @@ var HttpStatus = /* @__PURE__ */ ((HttpStatus2) => {
|
|
|
70
114
|
HttpStatus2[HttpStatus2["NotExtended"] = 510] = "NotExtended";
|
|
71
115
|
HttpStatus2[HttpStatus2["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
|
|
72
116
|
return HttpStatus2;
|
|
73
|
-
})(
|
|
117
|
+
})({});
|
|
74
118
|
|
|
75
119
|
function createCacheControl(cacheControl) {
|
|
76
120
|
const controls = [];
|
|
@@ -149,35 +193,6 @@ const UNIT = {
|
|
|
149
193
|
days: 1 * 60 * 60 * 24,
|
|
150
194
|
weeks: 1 * 60 * 60 * 24 * 7
|
|
151
195
|
};
|
|
152
|
-
const createSetCookieValue = (cookieName, cookieValue, options) => {
|
|
153
|
-
const c = [`${cookieName}=${cookieValue}`];
|
|
154
|
-
if (typeof options.domain === "string") {
|
|
155
|
-
c.push(`Domain=${options.domain}`);
|
|
156
|
-
}
|
|
157
|
-
if (typeof options.maxAge === "number") {
|
|
158
|
-
c.push(`Max-Age=${options.maxAge}`);
|
|
159
|
-
} else if (Array.isArray(options.maxAge)) {
|
|
160
|
-
c.push(`Max-Age=${options.maxAge[0] * UNIT[options.maxAge[1]]}`);
|
|
161
|
-
} else if (typeof options.expires === "number" || typeof options.expires == "string") {
|
|
162
|
-
c.push(`Expires=${options.expires}`);
|
|
163
|
-
} else if (options.expires instanceof Date) {
|
|
164
|
-
c.push(`Expires=${options.expires.toUTCString()}`);
|
|
165
|
-
}
|
|
166
|
-
if (options.httpOnly) {
|
|
167
|
-
c.push("HttpOnly");
|
|
168
|
-
}
|
|
169
|
-
if (typeof options.path === "string") {
|
|
170
|
-
c.push(`Path=${options.path}`);
|
|
171
|
-
}
|
|
172
|
-
const sameSite = resolveSameSite(options.sameSite);
|
|
173
|
-
if (sameSite) {
|
|
174
|
-
c.push(`SameSite=${sameSite}`);
|
|
175
|
-
}
|
|
176
|
-
if (options.secure) {
|
|
177
|
-
c.push("Secure");
|
|
178
|
-
}
|
|
179
|
-
return c.join("; ");
|
|
180
|
-
};
|
|
181
196
|
function tryDecodeUriComponent(str) {
|
|
182
197
|
try {
|
|
183
198
|
return decodeURIComponent(str);
|
|
@@ -210,6 +225,37 @@ function resolveSameSite(sameSite) {
|
|
|
210
225
|
}
|
|
211
226
|
return void 0;
|
|
212
227
|
}
|
|
228
|
+
const createSetCookieValue = (cookieName, cookieValue, options) => {
|
|
229
|
+
const c = [
|
|
230
|
+
`${cookieName}=${cookieValue}`
|
|
231
|
+
];
|
|
232
|
+
if (typeof options.domain === "string") {
|
|
233
|
+
c.push(`Domain=${options.domain}`);
|
|
234
|
+
}
|
|
235
|
+
if (typeof options.maxAge === "number") {
|
|
236
|
+
c.push(`Max-Age=${options.maxAge}`);
|
|
237
|
+
} else if (Array.isArray(options.maxAge)) {
|
|
238
|
+
c.push(`Max-Age=${options.maxAge[0] * UNIT[options.maxAge[1]]}`);
|
|
239
|
+
} else if (typeof options.expires === "number" || typeof options.expires == "string") {
|
|
240
|
+
c.push(`Expires=${options.expires}`);
|
|
241
|
+
} else if (options.expires instanceof Date) {
|
|
242
|
+
c.push(`Expires=${options.expires.toUTCString()}`);
|
|
243
|
+
}
|
|
244
|
+
if (options.httpOnly) {
|
|
245
|
+
c.push("HttpOnly");
|
|
246
|
+
}
|
|
247
|
+
if (typeof options.path === "string") {
|
|
248
|
+
c.push(`Path=${options.path}`);
|
|
249
|
+
}
|
|
250
|
+
const sameSite = resolveSameSite(options.sameSite);
|
|
251
|
+
if (sameSite) {
|
|
252
|
+
c.push(`SameSite=${sameSite}`);
|
|
253
|
+
}
|
|
254
|
+
if (options.secure) {
|
|
255
|
+
c.push("Secure");
|
|
256
|
+
}
|
|
257
|
+
return c.join("; ");
|
|
258
|
+
};
|
|
213
259
|
const REQ_COOKIE = /* @__PURE__ */ Symbol("request-cookies");
|
|
214
260
|
const RES_COOKIE = /* @__PURE__ */ Symbol("response-cookies");
|
|
215
261
|
const LIVE_COOKIE = /* @__PURE__ */ Symbol("live-cookies");
|
|
@@ -220,7 +266,9 @@ class Cookie {
|
|
|
220
266
|
appendCounter = 0;
|
|
221
267
|
constructor(cookieString) {
|
|
222
268
|
this[REQ_COOKIE] = parseCookieString(cookieString);
|
|
223
|
-
this[LIVE_COOKIE] = {
|
|
269
|
+
this[LIVE_COOKIE] = {
|
|
270
|
+
...this[REQ_COOKIE]
|
|
271
|
+
};
|
|
224
272
|
}
|
|
225
273
|
get(cookieName, live = true) {
|
|
226
274
|
const value = this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
|
|
@@ -238,13 +286,10 @@ class Cookie {
|
|
|
238
286
|
};
|
|
239
287
|
}
|
|
240
288
|
getAll(live = true) {
|
|
241
|
-
return Object.keys(this[live ? LIVE_COOKIE : REQ_COOKIE]).reduce(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
},
|
|
246
|
-
{}
|
|
247
|
-
);
|
|
289
|
+
return Object.keys(this[live ? LIVE_COOKIE : REQ_COOKIE]).reduce((cookies, cookieName) => {
|
|
290
|
+
cookies[cookieName] = this.get(cookieName);
|
|
291
|
+
return cookies;
|
|
292
|
+
}, {});
|
|
248
293
|
}
|
|
249
294
|
has(cookieName, live = true) {
|
|
250
295
|
return !!this[live ? LIVE_COOKIE : REQ_COOKIE][cookieName];
|
|
@@ -257,14 +302,13 @@ class Cookie {
|
|
|
257
302
|
append(cookieName, cookieValue, options = {}) {
|
|
258
303
|
this[LIVE_COOKIE][cookieName] = typeof cookieValue === "string" ? cookieValue : JSON.stringify(cookieValue);
|
|
259
304
|
const resolvedValue = typeof cookieValue === "string" ? cookieValue : encodeURIComponent(JSON.stringify(cookieValue));
|
|
260
|
-
this[RES_COOKIE][++this.appendCounter] = createSetCookieValue(
|
|
261
|
-
cookieName,
|
|
262
|
-
resolvedValue,
|
|
263
|
-
options
|
|
264
|
-
);
|
|
305
|
+
this[RES_COOKIE][++this.appendCounter] = createSetCookieValue(cookieName, resolvedValue, options);
|
|
265
306
|
}
|
|
266
307
|
delete(name, options) {
|
|
267
|
-
this.set(name, "deleted", {
|
|
308
|
+
this.set(name, "deleted", {
|
|
309
|
+
...options,
|
|
310
|
+
maxAge: 0
|
|
311
|
+
});
|
|
268
312
|
this[LIVE_COOKIE][name] = null;
|
|
269
313
|
}
|
|
270
314
|
headers() {
|
|
@@ -283,22 +327,6 @@ const mergeHeadersCookies = (headers, cookies) => {
|
|
|
283
327
|
return headers;
|
|
284
328
|
};
|
|
285
329
|
|
|
286
|
-
function runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, basePathname = "/") {
|
|
287
|
-
let resolve;
|
|
288
|
-
const responsePromise = new Promise((r) => resolve = r);
|
|
289
|
-
const requestEv = createRequestEvent(
|
|
290
|
-
serverRequestEv,
|
|
291
|
-
loadedRoute,
|
|
292
|
-
requestHandlers,
|
|
293
|
-
basePathname,
|
|
294
|
-
resolve
|
|
295
|
-
);
|
|
296
|
-
return {
|
|
297
|
-
response: responsePromise,
|
|
298
|
-
requestEv,
|
|
299
|
-
completion: _asyncRequestStore$1 ? _asyncRequestStore$1.run(requestEv, runNext, requestEv, rebuildRouteInfo, resolve) : runNext(requestEv, rebuildRouteInfo, resolve)
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
330
|
async function runNext(requestEv, rebuildRouteInfo, resolve) {
|
|
303
331
|
try {
|
|
304
332
|
const isValidURL = (url) => new URL(url.pathname + url.search, url);
|
|
@@ -347,7 +375,9 @@ async function runNext(requestEv, rebuildRouteInfo, resolve) {
|
|
|
347
375
|
try {
|
|
348
376
|
if (!requestEv.headersSent) {
|
|
349
377
|
requestEv.headers.set("content-type", "text/html; charset=utf-8");
|
|
350
|
-
requestEv.cacheControl({
|
|
378
|
+
requestEv.cacheControl({
|
|
379
|
+
noCache: true
|
|
380
|
+
});
|
|
351
381
|
requestEv.status(500);
|
|
352
382
|
}
|
|
353
383
|
const stream = requestEv.getWritableStream();
|
|
@@ -371,6 +401,18 @@ async function runNext(requestEv, rebuildRouteInfo, resolve) {
|
|
|
371
401
|
}
|
|
372
402
|
}
|
|
373
403
|
}
|
|
404
|
+
function runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, basePathname = "/") {
|
|
405
|
+
let resolve;
|
|
406
|
+
const responsePromise = new Promise((r) => resolve = r);
|
|
407
|
+
const requestEv = createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, basePathname, resolve);
|
|
408
|
+
return {
|
|
409
|
+
response: responsePromise,
|
|
410
|
+
requestEv,
|
|
411
|
+
completion: _asyncRequestStore$1 ? _asyncRequestStore$1.run(requestEv, runNext, requestEv, rebuildRouteInfo, resolve) : runNext(requestEv, rebuildRouteInfo, resolve)
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const IsQData = "@isQData";
|
|
415
|
+
const QDATA_JSON = "/q-data.json";
|
|
374
416
|
function getRouteMatchPathname(pathname) {
|
|
375
417
|
const isInternal = pathname.endsWith(QDATA_JSON);
|
|
376
418
|
if (isInternal) {
|
|
@@ -380,24 +422,144 @@ function getRouteMatchPathname(pathname) {
|
|
|
380
422
|
pathname = "/";
|
|
381
423
|
}
|
|
382
424
|
}
|
|
383
|
-
return {
|
|
425
|
+
return {
|
|
426
|
+
pathname,
|
|
427
|
+
isInternal
|
|
428
|
+
};
|
|
384
429
|
}
|
|
385
|
-
const IsQData = "@isQData";
|
|
386
|
-
const QDATA_JSON = "/q-data.json";
|
|
387
430
|
|
|
388
431
|
const RequestEvLoaders = /* @__PURE__ */ Symbol("RequestEvLoaders");
|
|
389
432
|
const RequestEvMode = /* @__PURE__ */ Symbol("RequestEvMode");
|
|
390
433
|
const RequestEvRoute = /* @__PURE__ */ Symbol("RequestEvRoute");
|
|
391
|
-
const RequestEvLoaderSerializationStrategyMap = /* @__PURE__ */ Symbol(
|
|
392
|
-
"RequestEvLoaderSerializationStrategyMap"
|
|
393
|
-
);
|
|
434
|
+
const RequestEvLoaderSerializationStrategyMap = /* @__PURE__ */ Symbol("RequestEvLoaderSerializationStrategyMap");
|
|
394
435
|
const RequestRouteName = "@routeName";
|
|
395
436
|
const RequestEvSharedActionId = "@actionId";
|
|
396
437
|
const RequestEvSharedActionFormData = "@actionFormData";
|
|
397
438
|
const RequestEvSharedNonce = "@nonce";
|
|
398
439
|
const RequestEvIsRewrite = "@rewrite";
|
|
399
440
|
const RequestEvShareServerTiming = "@serverTiming";
|
|
441
|
+
const RequestEvETagCacheKey = "@eTagCacheKey";
|
|
442
|
+
const RequestEvHttpStatusMessage = "@httpStatusMessage";
|
|
400
443
|
const RequestEvShareQData = "qData";
|
|
444
|
+
function getRequestLoaders(requestEv) {
|
|
445
|
+
return requestEv[RequestEvLoaders];
|
|
446
|
+
}
|
|
447
|
+
function getRequestLoaderSerializationStrategyMap(requestEv) {
|
|
448
|
+
return requestEv[RequestEvLoaderSerializationStrategyMap];
|
|
449
|
+
}
|
|
450
|
+
function getRequestRoute(requestEv) {
|
|
451
|
+
return requestEv[RequestEvRoute];
|
|
452
|
+
}
|
|
453
|
+
function getRequestMode(requestEv) {
|
|
454
|
+
return requestEv[RequestEvMode];
|
|
455
|
+
}
|
|
456
|
+
const ABORT_INDEX = Number.MAX_SAFE_INTEGER;
|
|
457
|
+
const isDangerousKey = (k) => k === "__proto__" || k === "constructor" || k === "prototype";
|
|
458
|
+
const isArrayIndexKey = (k) => /^(0|[1-9]\d*)$/.test(k);
|
|
459
|
+
const getArrayPaths = (formData) => {
|
|
460
|
+
const arrayCandidates = /* @__PURE__ */ new Map();
|
|
461
|
+
for (const [name] of formData) {
|
|
462
|
+
const keys = name.split(".");
|
|
463
|
+
let hasDangerousKey = false;
|
|
464
|
+
for (const key of keys) {
|
|
465
|
+
if (isDangerousKey(key)) {
|
|
466
|
+
hasDangerousKey = true;
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (hasDangerousKey) {
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
let path = "";
|
|
474
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
475
|
+
const key = keys[i];
|
|
476
|
+
if (key.endsWith("[]")) {
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
path = path ? `${path}.${key}` : key;
|
|
480
|
+
if (!arrayCandidates.has(path)) {
|
|
481
|
+
arrayCandidates.set(path, true);
|
|
482
|
+
}
|
|
483
|
+
if (!isArrayIndexKey(keys[i + 1])) {
|
|
484
|
+
arrayCandidates.set(path, false);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return new Set(Array.from(arrayCandidates.entries()).filter(([, isArrayPath]) => isArrayPath).map(([path]) => path));
|
|
489
|
+
};
|
|
490
|
+
const formToObj = (formData) => {
|
|
491
|
+
const values = /* @__PURE__ */ Object.create(null);
|
|
492
|
+
const arrayPaths = getArrayPaths(formData);
|
|
493
|
+
for (const [name, value] of formData) {
|
|
494
|
+
const keys = name.split(".");
|
|
495
|
+
let hasDangerousKey = false;
|
|
496
|
+
for (let i = 0; i < keys.length; i++) {
|
|
497
|
+
if (isDangerousKey(keys[i])) {
|
|
498
|
+
hasDangerousKey = true;
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
if (hasDangerousKey) {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
let object = values;
|
|
506
|
+
let path = "";
|
|
507
|
+
for (let i = 0; i < keys.length; i++) {
|
|
508
|
+
const key = keys[i];
|
|
509
|
+
if (key.endsWith("[]")) {
|
|
510
|
+
const arrayKey = key.slice(0, -2);
|
|
511
|
+
if (isDangerousKey(arrayKey)) {
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
const existingValue = object[arrayKey];
|
|
515
|
+
if (existingValue !== void 0 && !Array.isArray(existingValue)) {
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
object[arrayKey] = existingValue || [];
|
|
519
|
+
object[arrayKey].push(value);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
if (Array.isArray(object) && !isArrayIndexKey(key)) {
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
if (i < keys.length - 1) {
|
|
526
|
+
path = path ? `${path}.${key}` : key;
|
|
527
|
+
const nextValue = object[key];
|
|
528
|
+
if (nextValue !== void 0) {
|
|
529
|
+
object = nextValue;
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
object = object[key] = arrayPaths.has(path) ? [] : /* @__PURE__ */ Object.create(null);
|
|
533
|
+
} else {
|
|
534
|
+
object[key] = value;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return values;
|
|
539
|
+
};
|
|
540
|
+
const parseRequest = async ({ request, method, query }, sharedMap) => {
|
|
541
|
+
const type = getContentType(request.headers);
|
|
542
|
+
if (type === "application/x-www-form-urlencoded" || type === "multipart/form-data") {
|
|
543
|
+
const formData = await request.formData();
|
|
544
|
+
sharedMap.set(RequestEvSharedActionFormData, formData);
|
|
545
|
+
return formToObj(formData);
|
|
546
|
+
} else if (type === "application/json") {
|
|
547
|
+
const data = await request.json();
|
|
548
|
+
return data;
|
|
549
|
+
} else if (type === "application/qwik-json") {
|
|
550
|
+
if (method === "GET" && query.has(QDATA_KEY)) {
|
|
551
|
+
const data = query.get(QDATA_KEY);
|
|
552
|
+
if (data) {
|
|
553
|
+
try {
|
|
554
|
+
return _deserialize(decodeURIComponent(data));
|
|
555
|
+
} catch {
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return _deserialize(await request.text());
|
|
560
|
+
}
|
|
561
|
+
return void 0;
|
|
562
|
+
};
|
|
401
563
|
function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, basePathname, resolved) {
|
|
402
564
|
const { request, platform, env } = serverRequestEv;
|
|
403
565
|
const sharedMap = /* @__PURE__ */ new Map();
|
|
@@ -413,7 +575,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, baseP
|
|
|
413
575
|
let writableStream = null;
|
|
414
576
|
let requestData = void 0;
|
|
415
577
|
let locale = serverRequestEv.locale;
|
|
416
|
-
let status = 200;
|
|
578
|
+
let status = loadedRoute?.$notFound$ ? 404 : 200;
|
|
417
579
|
const next = async () => {
|
|
418
580
|
routeModuleIndex++;
|
|
419
581
|
while (routeModuleIndex < requestHandlers.length) {
|
|
@@ -427,6 +589,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, baseP
|
|
|
427
589
|
};
|
|
428
590
|
const resetRoute = (_loadedRoute, _requestHandlers, _url = url) => {
|
|
429
591
|
loadedRoute = _loadedRoute;
|
|
592
|
+
status = loadedRoute?.$notFound$ ? 404 : 200;
|
|
430
593
|
requestHandlers = _requestHandlers;
|
|
431
594
|
url.pathname = _url.pathname;
|
|
432
595
|
url.search = _url.search;
|
|
@@ -490,7 +653,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, baseP
|
|
|
490
653
|
signal: request.signal,
|
|
491
654
|
originalUrl: new URL(url),
|
|
492
655
|
get params() {
|
|
493
|
-
return loadedRoute
|
|
656
|
+
return loadedRoute?.$params$ ?? {};
|
|
494
657
|
},
|
|
495
658
|
get pathname() {
|
|
496
659
|
return url.pathname;
|
|
@@ -519,20 +682,18 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, baseP
|
|
|
519
682
|
check();
|
|
520
683
|
headers.set(target, createCacheControl(cacheControl));
|
|
521
684
|
},
|
|
522
|
-
resolveValue:
|
|
685
|
+
resolveValue: async (loaderOrAction) => {
|
|
523
686
|
const id = loaderOrAction.__id;
|
|
524
687
|
if (loaderOrAction.__brand === "server_loader") {
|
|
525
688
|
if (!(id in loaders)) {
|
|
526
|
-
throw new Error(
|
|
527
|
-
"You can not get the returned data of a loader that has not been executed for this request."
|
|
528
|
-
);
|
|
689
|
+
throw new Error("You can not get the returned data of a loader that has not been executed for this request.");
|
|
529
690
|
}
|
|
530
691
|
if (loaders[id] === _UNINITIALIZED) {
|
|
531
692
|
await getRouteLoaderPromise(loaderOrAction, loaders, requestEv);
|
|
532
693
|
}
|
|
533
694
|
}
|
|
534
695
|
return loaders[id];
|
|
535
|
-
}
|
|
696
|
+
},
|
|
536
697
|
status: (statusCode) => {
|
|
537
698
|
if (typeof statusCode === "number") {
|
|
538
699
|
check();
|
|
@@ -576,10 +737,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, baseP
|
|
|
576
737
|
rewrite: (pathname2) => {
|
|
577
738
|
check();
|
|
578
739
|
if (pathname2.startsWith("http")) {
|
|
579
|
-
throw new ServerError$1(
|
|
580
|
-
400,
|
|
581
|
-
isDev ? "Rewrite does not support absolute urls" : "Bad Request"
|
|
582
|
-
);
|
|
740
|
+
throw new ServerError$1(400, isDev ? "Rewrite does not support absolute urls" : "Bad Request");
|
|
583
741
|
}
|
|
584
742
|
sharedMap.set(RequestEvIsRewrite, true);
|
|
585
743
|
return exit(new RewriteMessage$1(pathname2.replace(/\/+/g, "/")));
|
|
@@ -623,113 +781,32 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, baseP
|
|
|
623
781
|
if (isDev) {
|
|
624
782
|
const serverTiming = sharedMap.get(RequestEvShareServerTiming);
|
|
625
783
|
if (serverTiming) {
|
|
626
|
-
headers.set(
|
|
627
|
-
"Server-Timing",
|
|
628
|
-
serverTiming.map(([name, duration]) => `${name};dur=${duration}`).join(",")
|
|
629
|
-
);
|
|
784
|
+
headers.set("Server-Timing", serverTiming.map(([name, duration]) => `${name};dur=${duration}`).join(","));
|
|
630
785
|
}
|
|
631
786
|
}
|
|
632
|
-
writableStream = serverRequestEv.getWritableStream(
|
|
633
|
-
status,
|
|
634
|
-
headers,
|
|
635
|
-
cookie,
|
|
636
|
-
resolved,
|
|
637
|
-
requestEv
|
|
638
|
-
);
|
|
787
|
+
writableStream = serverRequestEv.getWritableStream(status, headers, cookie, resolved, requestEv);
|
|
639
788
|
}
|
|
640
789
|
return writableStream;
|
|
641
790
|
}
|
|
642
791
|
};
|
|
643
792
|
return requestEv;
|
|
644
793
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
const
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
const formData = await request.formData();
|
|
662
|
-
sharedMap.set(RequestEvSharedActionFormData, formData);
|
|
663
|
-
return formToObj(formData);
|
|
664
|
-
} else if (type === "application/json") {
|
|
665
|
-
const data = await request.json();
|
|
666
|
-
return data;
|
|
667
|
-
} else if (type === "application/qwik-json") {
|
|
668
|
-
if (method === "GET" && query.has(QDATA_KEY)) {
|
|
669
|
-
const data = query.get(QDATA_KEY);
|
|
670
|
-
if (data) {
|
|
671
|
-
try {
|
|
672
|
-
return _deserialize(decodeURIComponent(data));
|
|
673
|
-
} catch {
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
return _deserialize(await request.text());
|
|
678
|
-
}
|
|
679
|
-
return void 0;
|
|
680
|
-
};
|
|
681
|
-
const isDangerousKey = (k) => k === "__proto__" || k === "constructor" || k === "prototype";
|
|
682
|
-
const formToObj = (formData) => {
|
|
683
|
-
const values = /* @__PURE__ */ Object.create(null);
|
|
684
|
-
for (const [name, value] of formData) {
|
|
685
|
-
const keys = name.split(".");
|
|
686
|
-
let hasDangerousKey = false;
|
|
687
|
-
for (let i = 0; i < keys.length; i++) {
|
|
688
|
-
if (isDangerousKey(keys[i])) {
|
|
689
|
-
hasDangerousKey = true;
|
|
690
|
-
break;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
if (hasDangerousKey) {
|
|
694
|
-
continue;
|
|
695
|
-
}
|
|
696
|
-
let object = values;
|
|
697
|
-
for (let i = 0; i < keys.length; i++) {
|
|
698
|
-
const key = keys[i];
|
|
699
|
-
if (key.endsWith("[]")) {
|
|
700
|
-
const arrayKey = key.slice(0, -2);
|
|
701
|
-
if (isDangerousKey(arrayKey)) {
|
|
702
|
-
break;
|
|
703
|
-
}
|
|
704
|
-
object[arrayKey] = object[arrayKey] || [];
|
|
705
|
-
object[arrayKey].push(value);
|
|
706
|
-
break;
|
|
707
|
-
}
|
|
708
|
-
if (i < keys.length - 1) {
|
|
709
|
-
object = object[key] = object[key] || (Number.isNaN(+keys[i + 1]) ? /* @__PURE__ */ Object.create(null) : []);
|
|
710
|
-
} else {
|
|
711
|
-
object[key] = value;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
return values;
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
function getQwikRouterServerData(requestEv) {
|
|
719
|
-
const { params, request, status, locale, originalUrl } = requestEv;
|
|
720
|
-
const requestHeaders = {};
|
|
721
|
-
request.headers.forEach((value, key) => requestHeaders[key] = value);
|
|
722
|
-
const action = requestEv.sharedMap.get(RequestEvSharedActionId);
|
|
723
|
-
const formData = requestEv.sharedMap.get(RequestEvSharedActionFormData);
|
|
724
|
-
const routeName = requestEv.sharedMap.get(RequestRouteName);
|
|
725
|
-
const nonce = requestEv.sharedMap.get(RequestEvSharedNonce);
|
|
726
|
-
const headers = requestEv.request.headers;
|
|
727
|
-
const reconstructedUrl = new URL(originalUrl.pathname + originalUrl.search, originalUrl);
|
|
728
|
-
const host = headers.get("X-Forwarded-Host");
|
|
729
|
-
const protocol = headers.get("X-Forwarded-Proto");
|
|
730
|
-
if (host) {
|
|
731
|
-
reconstructedUrl.port = "";
|
|
732
|
-
reconstructedUrl.host = host;
|
|
794
|
+
|
|
795
|
+
function getQwikRouterServerData(requestEv) {
|
|
796
|
+
const { params, request, status, locale, originalUrl } = requestEv;
|
|
797
|
+
const requestHeaders = {};
|
|
798
|
+
request.headers.forEach((value, key) => requestHeaders[key] = value);
|
|
799
|
+
const action = requestEv.sharedMap.get(RequestEvSharedActionId);
|
|
800
|
+
const formData = requestEv.sharedMap.get(RequestEvSharedActionFormData);
|
|
801
|
+
const routeName = requestEv.sharedMap.get(RequestRouteName);
|
|
802
|
+
const nonce = requestEv.sharedMap.get(RequestEvSharedNonce);
|
|
803
|
+
const headers = requestEv.request.headers;
|
|
804
|
+
const reconstructedUrl = new URL(originalUrl.pathname + originalUrl.search, originalUrl);
|
|
805
|
+
const host = headers.get("X-Forwarded-Host");
|
|
806
|
+
const protocol = headers.get("X-Forwarded-Proto");
|
|
807
|
+
if (host) {
|
|
808
|
+
reconstructedUrl.port = "";
|
|
809
|
+
reconstructedUrl.host = host;
|
|
733
810
|
}
|
|
734
811
|
if (protocol) {
|
|
735
812
|
reconstructedUrl.protocol = protocol;
|
|
@@ -747,10 +824,13 @@ function getQwikRouterServerData(requestEv) {
|
|
|
747
824
|
qwikrouter: {
|
|
748
825
|
routeName,
|
|
749
826
|
ev: requestEv,
|
|
750
|
-
params: {
|
|
827
|
+
params: {
|
|
828
|
+
...params
|
|
829
|
+
},
|
|
751
830
|
loadedRoute: getRequestRoute(requestEv),
|
|
752
831
|
response: {
|
|
753
832
|
status: status(),
|
|
833
|
+
statusMessage: requestEv.sharedMap.get(RequestEvHttpStatusMessage),
|
|
754
834
|
loaders,
|
|
755
835
|
loadersSerializationStrategy,
|
|
756
836
|
action,
|
|
@@ -760,62 +840,6 @@ function getQwikRouterServerData(requestEv) {
|
|
|
760
840
|
};
|
|
761
841
|
}
|
|
762
842
|
|
|
763
|
-
const resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler, isInternal) => {
|
|
764
|
-
const routeLoaders = [];
|
|
765
|
-
const routeActions = [];
|
|
766
|
-
const requestHandlers = [];
|
|
767
|
-
const isPageRoute = !!(route && isLastModulePageRoute(route[LoadedRouteProp.Mods]));
|
|
768
|
-
if (isInternal) {
|
|
769
|
-
requestHandlers.push(handleQDataRedirect);
|
|
770
|
-
}
|
|
771
|
-
if (serverPlugins) {
|
|
772
|
-
_resolveRequestHandlers(
|
|
773
|
-
routeLoaders,
|
|
774
|
-
routeActions,
|
|
775
|
-
requestHandlers,
|
|
776
|
-
serverPlugins,
|
|
777
|
-
isPageRoute,
|
|
778
|
-
method
|
|
779
|
-
);
|
|
780
|
-
}
|
|
781
|
-
if (route) {
|
|
782
|
-
const routeModules = route[LoadedRouteProp.Mods];
|
|
783
|
-
_resolveRequestHandlers(
|
|
784
|
-
routeLoaders,
|
|
785
|
-
routeActions,
|
|
786
|
-
requestHandlers,
|
|
787
|
-
routeModules,
|
|
788
|
-
isPageRoute,
|
|
789
|
-
method
|
|
790
|
-
);
|
|
791
|
-
const routeName = route[LoadedRouteProp.RouteName];
|
|
792
|
-
if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
|
|
793
|
-
if (checkOrigin === "lax-proto") {
|
|
794
|
-
requestHandlers.unshift(csrfLaxProtoCheckMiddleware);
|
|
795
|
-
} else {
|
|
796
|
-
requestHandlers.unshift(csrfCheckMiddleware);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
if (isPageRoute) {
|
|
800
|
-
if (method === "POST" || method === "GET") {
|
|
801
|
-
requestHandlers.push(runServerFunction);
|
|
802
|
-
}
|
|
803
|
-
requestHandlers.push(fixTrailingSlash);
|
|
804
|
-
if (isInternal) {
|
|
805
|
-
requestHandlers.push(renderQData);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
if (isPageRoute) {
|
|
809
|
-
requestHandlers.push((ev) => {
|
|
810
|
-
ev.sharedMap.set(RequestRouteName, routeName);
|
|
811
|
-
});
|
|
812
|
-
requestHandlers.push(actionsMiddleware(routeActions));
|
|
813
|
-
requestHandlers.push(loadersMiddleware(routeLoaders));
|
|
814
|
-
requestHandlers.push(renderHandler);
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
return requestHandlers;
|
|
818
|
-
};
|
|
819
843
|
const _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, routeModules, collectActions, method) => {
|
|
820
844
|
for (const routeModule of routeModules) {
|
|
821
845
|
if (typeof routeModule.onRequest === "function") {
|
|
@@ -872,185 +896,111 @@ const _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, ro
|
|
|
872
896
|
}
|
|
873
897
|
}
|
|
874
898
|
};
|
|
875
|
-
function
|
|
876
|
-
return
|
|
877
|
-
const requestEv = requestEvent;
|
|
899
|
+
function eTagMiddleware(route) {
|
|
900
|
+
return (requestEv) => {
|
|
878
901
|
if (requestEv.headersSent) {
|
|
879
|
-
requestEv.exit();
|
|
880
902
|
return;
|
|
881
903
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
904
|
+
if (requestEv.method !== "GET" || requestEv.sharedMap.has(IsQData)) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
const mods = route.$mods$;
|
|
908
|
+
const hasETag = mods.some((m) => {
|
|
909
|
+
if (!m) {
|
|
910
|
+
return false;
|
|
911
|
+
}
|
|
912
|
+
if (m.routeConfig) {
|
|
913
|
+
return typeof m.routeConfig === "function" || m.routeConfig.eTag !== void 0;
|
|
889
914
|
}
|
|
915
|
+
return m.eTag !== void 0;
|
|
916
|
+
});
|
|
917
|
+
if (!hasETag) {
|
|
918
|
+
return;
|
|
890
919
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
throw new Error(
|
|
901
|
-
`Expected request data for the action id ${selectedActionId} to be an object`
|
|
902
|
-
);
|
|
903
|
-
}
|
|
904
|
-
const result = await runValidators(requestEv, action.__validators, data);
|
|
905
|
-
if (!result.success) {
|
|
906
|
-
loaders[selectedActionId] = requestEv.fail(result.status ?? 500, result.error);
|
|
907
|
-
} else {
|
|
908
|
-
const actionResolved = isDev ? await measure(
|
|
909
|
-
requestEv,
|
|
910
|
-
action.__qrl.getHash(),
|
|
911
|
-
() => action.__qrl.call(requestEv, result.data, requestEv)
|
|
912
|
-
) : await action.__qrl.call(requestEv, result.data, requestEv);
|
|
913
|
-
if (isDev) {
|
|
914
|
-
verifySerializable(actionResolved, action.__qrl);
|
|
915
|
-
}
|
|
916
|
-
loaders[selectedActionId] = actionResolved;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
920
|
+
const loaders = getRequestLoaders(requestEv);
|
|
921
|
+
const getData = (loaderOrAction) => {
|
|
922
|
+
const id = loaderOrAction.__id;
|
|
923
|
+
if (loaderOrAction.__brand === "server_loader" && !(id in loaders)) {
|
|
924
|
+
throw new Error("Loader not executed for this request.");
|
|
925
|
+
}
|
|
926
|
+
const data = loaders[id];
|
|
927
|
+
if (data instanceof Promise) {
|
|
928
|
+
throw new Error("Loaders returning a promise cannot be resolved for the eTag function.");
|
|
919
929
|
}
|
|
930
|
+
return data;
|
|
931
|
+
};
|
|
932
|
+
const routeLocation = {
|
|
933
|
+
params: requestEv.params,
|
|
934
|
+
url: requestEv.url,
|
|
935
|
+
isNavigating: false,
|
|
936
|
+
prevUrl: void 0
|
|
937
|
+
};
|
|
938
|
+
const status = requestEv.status();
|
|
939
|
+
const config = resolveRouteConfig(getData, routeLocation, mods, "", status);
|
|
940
|
+
const headProps = {
|
|
941
|
+
head: config.head,
|
|
942
|
+
status,
|
|
943
|
+
withLocale: (fn) => fn(),
|
|
944
|
+
resolveValue: getData,
|
|
945
|
+
...routeLocation
|
|
946
|
+
};
|
|
947
|
+
const eTag = resolveETag(config.eTag, headProps);
|
|
948
|
+
if (!eTag) {
|
|
949
|
+
return;
|
|
920
950
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
if (requestEv.headersSent) {
|
|
927
|
-
requestEv.exit();
|
|
951
|
+
requestEv.headers.set("ETag", eTag);
|
|
952
|
+
const ifNoneMatch = requestEv.request.headers.get("If-None-Match");
|
|
953
|
+
if (ifNoneMatch && (ifNoneMatch === eTag || ifNoneMatch === `W/${eTag}` || `W/${ifNoneMatch}` === eTag)) {
|
|
954
|
+
requestEv.status(304);
|
|
955
|
+
requestEv.send(304, "");
|
|
928
956
|
return;
|
|
929
957
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
const resolvedLoadersPromises = routeLoaders.map(
|
|
933
|
-
(loader) => getRouteLoaderPromise(loader, loaders, requestEv)
|
|
934
|
-
);
|
|
935
|
-
await Promise.all(resolvedLoadersPromises);
|
|
958
|
+
if (MAX_CACHE_SIZE <= 0) {
|
|
959
|
+
return;
|
|
936
960
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
const loaderId = loader.__id;
|
|
941
|
-
loaders[loaderId] = runValidators(
|
|
942
|
-
requestEv,
|
|
943
|
-
loader.__validators,
|
|
944
|
-
void 0
|
|
945
|
-
// data
|
|
946
|
-
).then((res) => {
|
|
947
|
-
if (res.success) {
|
|
948
|
-
if (isDev) {
|
|
949
|
-
return measure(
|
|
950
|
-
requestEv,
|
|
951
|
-
loader.__qrl.getHash(),
|
|
952
|
-
() => loader.__qrl.call(requestEv, requestEv)
|
|
953
|
-
);
|
|
954
|
-
} else {
|
|
955
|
-
return loader.__qrl.call(requestEv, requestEv);
|
|
956
|
-
}
|
|
957
|
-
} else {
|
|
958
|
-
return requestEv.fail(res.status ?? 500, res.error);
|
|
961
|
+
const cacheKey = resolveCacheKey(config.cacheKey, status, eTag, requestEv.url.pathname);
|
|
962
|
+
if (!cacheKey) {
|
|
963
|
+
return;
|
|
959
964
|
}
|
|
960
|
-
|
|
961
|
-
if (
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}
|
|
967
|
-
loaders[loaderId] = resolvedLoader;
|
|
965
|
+
const cachedHtml = getCachedHtml(cacheKey);
|
|
966
|
+
if (cachedHtml) {
|
|
967
|
+
requestEv.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
968
|
+
requestEv.headers.set("X-SSR-Cache", "HIT");
|
|
969
|
+
requestEv.send(status, cachedHtml);
|
|
970
|
+
return;
|
|
968
971
|
}
|
|
969
|
-
|
|
970
|
-
});
|
|
971
|
-
const loadersSerializationStrategy = getRequestLoaderSerializationStrategyMap(requestEv);
|
|
972
|
-
loadersSerializationStrategy.set(loaderId, loader.__serializationStrategy);
|
|
973
|
-
return loaders[loaderId];
|
|
974
|
-
}
|
|
975
|
-
async function runValidators(requestEv, validators, data) {
|
|
976
|
-
let lastResult = {
|
|
977
|
-
success: true,
|
|
978
|
-
data
|
|
972
|
+
requestEv.sharedMap.set(RequestEvETagCacheKey, cacheKey);
|
|
979
973
|
};
|
|
980
|
-
if (validators) {
|
|
981
|
-
for (const validator of validators) {
|
|
982
|
-
if (isDev) {
|
|
983
|
-
lastResult = await measure(
|
|
984
|
-
requestEv,
|
|
985
|
-
`validator$`,
|
|
986
|
-
() => validator.validate(requestEv, data)
|
|
987
|
-
);
|
|
988
|
-
} else {
|
|
989
|
-
lastResult = await validator.validate(requestEv, data);
|
|
990
|
-
}
|
|
991
|
-
if (!lastResult.success) {
|
|
992
|
-
return lastResult;
|
|
993
|
-
} else {
|
|
994
|
-
data = lastResult.data;
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
return lastResult;
|
|
999
|
-
}
|
|
1000
|
-
function isAsyncIterator(obj) {
|
|
1001
|
-
return obj ? typeof obj === "object" && Symbol.asyncIterator in obj : false;
|
|
1002
974
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
if (serverFnHash && ev.request.headers.get("X-QRL") === serverFnHash && ev.request.headers.get("Content-Type") === "application/qwik-json") {
|
|
1006
|
-
ev.exit();
|
|
1007
|
-
const data = await ev.parseBody();
|
|
1008
|
-
if (!Array.isArray(data) || !(Array.isArray(data[0]) || data[0] === void 0)) {
|
|
1009
|
-
throw ev.error(500, "Invalid request");
|
|
1010
|
-
}
|
|
1011
|
-
const qrl = inlinedQrl(null, serverFnHash, data.slice(1));
|
|
1012
|
-
let result;
|
|
975
|
+
function serverErrorMiddleware(route, renderHandler) {
|
|
976
|
+
return async (requestEv) => {
|
|
1013
977
|
try {
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
() => qrl.apply(ev, data[0])
|
|
1019
|
-
);
|
|
1020
|
-
} else {
|
|
1021
|
-
result = await qrl.apply(ev, data[0]);
|
|
978
|
+
await requestEv.next();
|
|
979
|
+
} catch (e) {
|
|
980
|
+
if (!(e instanceof ServerError$1) || requestEv.headersSent) {
|
|
981
|
+
throw e;
|
|
1022
982
|
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
throw ev.error(err.status, err.data);
|
|
983
|
+
if (requestEv.sharedMap.has(IsQData)) {
|
|
984
|
+
throw e;
|
|
1026
985
|
}
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
if (isAsyncIterator(result)) {
|
|
1031
|
-
ev.headers.set("Content-Type", "text/qwik-json-stream");
|
|
1032
|
-
const writable = ev.getWritableStream();
|
|
1033
|
-
const stream = writable.getWriter();
|
|
1034
|
-
for await (const item of result) {
|
|
1035
|
-
if (isDev) {
|
|
1036
|
-
verifySerializable(item, qrl);
|
|
1037
|
-
}
|
|
1038
|
-
const message = await _serialize(item);
|
|
1039
|
-
if (ev.signal.aborted) {
|
|
1040
|
-
break;
|
|
1041
|
-
}
|
|
1042
|
-
await stream.write(encoder.encode(`${message}
|
|
1043
|
-
`));
|
|
986
|
+
const accept = requestEv.request.headers.get("Accept");
|
|
987
|
+
if (accept && !accept.includes("text/html")) {
|
|
988
|
+
throw e;
|
|
1044
989
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
990
|
+
const status = e.status;
|
|
991
|
+
requestEv.status(status);
|
|
992
|
+
const errorLoader = route.$errorLoader$;
|
|
993
|
+
const errorModule = errorLoader ? await errorLoader() : await import('../../chunks/http-error.qwik.mjs');
|
|
994
|
+
route.$mods$ = [
|
|
995
|
+
errorModule
|
|
996
|
+
];
|
|
997
|
+
requestEv.sharedMap.set(RequestEvHttpStatusMessage, typeof e.data === "string" ? e.data : "Server Error");
|
|
998
|
+
await renderHandler(requestEv);
|
|
1051
999
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
function isAsyncIterator(obj) {
|
|
1003
|
+
return obj ? typeof obj === "object" && Symbol.asyncIterator in obj : false;
|
|
1054
1004
|
}
|
|
1055
1005
|
function fixTrailingSlash(ev) {
|
|
1056
1006
|
const { basePathname, originalUrl, sharedMap } = ev;
|
|
@@ -1070,10 +1020,7 @@ function fixTrailingSlash(ev) {
|
|
|
1070
1020
|
}
|
|
1071
1021
|
} else {
|
|
1072
1022
|
if (pathname.endsWith("/")) {
|
|
1073
|
-
throw ev.redirect(
|
|
1074
|
-
HttpStatus.MovedPermanently,
|
|
1075
|
-
pathname.slice(0, pathname.length - 1) + search
|
|
1076
|
-
);
|
|
1023
|
+
throw ev.redirect(HttpStatus.MovedPermanently, pathname.slice(0, pathname.length - 1) + search);
|
|
1077
1024
|
}
|
|
1078
1025
|
}
|
|
1079
1026
|
}
|
|
@@ -1110,36 +1057,6 @@ function getPathname(url) {
|
|
|
1110
1057
|
return `${url.pathname}${search ? `?${search}` : ""}${url.hash}`;
|
|
1111
1058
|
}
|
|
1112
1059
|
const encoder = /* @__PURE__ */ new TextEncoder();
|
|
1113
|
-
function csrfLaxProtoCheckMiddleware(requestEv) {
|
|
1114
|
-
checkCSRF(requestEv, "lax-proto");
|
|
1115
|
-
}
|
|
1116
|
-
function csrfCheckMiddleware(requestEv) {
|
|
1117
|
-
checkCSRF(requestEv);
|
|
1118
|
-
}
|
|
1119
|
-
function checkCSRF(requestEv, laxProto) {
|
|
1120
|
-
const contentType = requestEv.request.headers.get("content-type");
|
|
1121
|
-
const isSimpleRequest = !contentType || isContentType(
|
|
1122
|
-
requestEv.request.headers,
|
|
1123
|
-
"application/x-www-form-urlencoded",
|
|
1124
|
-
"multipart/form-data",
|
|
1125
|
-
"text/plain"
|
|
1126
|
-
);
|
|
1127
|
-
if (isSimpleRequest) {
|
|
1128
|
-
const inputOrigin = requestEv.request.headers.get("origin");
|
|
1129
|
-
const origin = requestEv.url.origin;
|
|
1130
|
-
let forbidden = inputOrigin !== origin;
|
|
1131
|
-
if (forbidden && laxProto && inputOrigin?.replace(/^http(s)?/g, "") === origin.replace(/^http(s)?/g, "")) {
|
|
1132
|
-
forbidden = false;
|
|
1133
|
-
}
|
|
1134
|
-
if (forbidden) {
|
|
1135
|
-
throw requestEv.error(
|
|
1136
|
-
403,
|
|
1137
|
-
`CSRF check failed. Cross-site ${requestEv.method} form submissions are forbidden.
|
|
1138
|
-
The request origin "${inputOrigin}" does not match the server origin "${origin}".`
|
|
1139
|
-
);
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
1060
|
function renderQwikMiddleware(render) {
|
|
1144
1061
|
return async (requestEv) => {
|
|
1145
1062
|
if (requestEv.headersSent) {
|
|
@@ -1154,10 +1071,25 @@ function renderQwikMiddleware(render) {
|
|
|
1154
1071
|
if (!responseHeaders.has("Content-Type")) {
|
|
1155
1072
|
responseHeaders.set("Content-Type", "text/html; charset=utf-8");
|
|
1156
1073
|
}
|
|
1074
|
+
const eTagCacheKey = requestEv.sharedMap.get(RequestEvETagCacheKey);
|
|
1157
1075
|
const { readable, writable } = new TextEncoderStream();
|
|
1158
1076
|
const writableStream = requestEv.getWritableStream();
|
|
1159
|
-
|
|
1160
|
-
|
|
1077
|
+
let cacheChunks;
|
|
1078
|
+
let pipeSource = readable;
|
|
1079
|
+
if (eTagCacheKey) {
|
|
1080
|
+
cacheChunks = [];
|
|
1081
|
+
const capture = new TransformStream({
|
|
1082
|
+
transform(chunk, controller) {
|
|
1083
|
+
cacheChunks.push(chunk);
|
|
1084
|
+
controller.enqueue(chunk);
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
pipeSource = readable.pipeThrough(capture);
|
|
1088
|
+
}
|
|
1089
|
+
const pipe = pipeSource.pipeTo(writableStream, {
|
|
1090
|
+
preventClose: true
|
|
1091
|
+
});
|
|
1092
|
+
const stream = writable.getWriter();
|
|
1161
1093
|
const status = requestEv.status();
|
|
1162
1094
|
try {
|
|
1163
1095
|
const isStatic = getRequestMode(requestEv) === "static";
|
|
@@ -1186,35 +1118,19 @@ function renderQwikMiddleware(render) {
|
|
|
1186
1118
|
await stream.close();
|
|
1187
1119
|
await pipe;
|
|
1188
1120
|
}
|
|
1121
|
+
if (eTagCacheKey && cacheChunks && cacheChunks.length > 0) {
|
|
1122
|
+
const totalLength = cacheChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
1123
|
+
const combined = new Uint8Array(totalLength);
|
|
1124
|
+
let offset = 0;
|
|
1125
|
+
for (const chunk of cacheChunks) {
|
|
1126
|
+
combined.set(chunk, offset);
|
|
1127
|
+
offset += chunk.length;
|
|
1128
|
+
}
|
|
1129
|
+
setCachedHtml(eTagCacheKey, new TextDecoder().decode(combined));
|
|
1130
|
+
}
|
|
1189
1131
|
await writableStream.close();
|
|
1190
1132
|
};
|
|
1191
1133
|
}
|
|
1192
|
-
async function handleQDataRedirect(requestEv) {
|
|
1193
|
-
try {
|
|
1194
|
-
await requestEv.next();
|
|
1195
|
-
} catch (err) {
|
|
1196
|
-
if (!(err instanceof RedirectMessage$1)) {
|
|
1197
|
-
throw err;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
if (requestEv.headersSent) {
|
|
1201
|
-
return;
|
|
1202
|
-
}
|
|
1203
|
-
const status = requestEv.status();
|
|
1204
|
-
const location = requestEv.headers.get("Location");
|
|
1205
|
-
const isRedirect = status >= 301 && status <= 308 && location;
|
|
1206
|
-
if (isRedirect) {
|
|
1207
|
-
const adaptedLocation = makeQDataPath(location);
|
|
1208
|
-
if (adaptedLocation) {
|
|
1209
|
-
requestEv.headers.set("Location", adaptedLocation);
|
|
1210
|
-
requestEv.getWritableStream().close();
|
|
1211
|
-
return;
|
|
1212
|
-
} else {
|
|
1213
|
-
requestEv.status(200);
|
|
1214
|
-
requestEv.headers.delete("Location");
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
1134
|
async function renderQData(requestEv) {
|
|
1219
1135
|
await requestEv.next();
|
|
1220
1136
|
if (requestEv.headersSent || requestEv.exited) {
|
|
@@ -1266,6 +1182,32 @@ function makeQDataPath(href) {
|
|
|
1266
1182
|
return void 0;
|
|
1267
1183
|
}
|
|
1268
1184
|
}
|
|
1185
|
+
async function handleQDataRedirect(requestEv) {
|
|
1186
|
+
try {
|
|
1187
|
+
await requestEv.next();
|
|
1188
|
+
} catch (err) {
|
|
1189
|
+
if (!(err instanceof RedirectMessage$1)) {
|
|
1190
|
+
throw err;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
if (requestEv.headersSent) {
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
const status = requestEv.status();
|
|
1197
|
+
const location = requestEv.headers.get("Location");
|
|
1198
|
+
const isRedirect = status >= 301 && status <= 308 && location;
|
|
1199
|
+
if (isRedirect) {
|
|
1200
|
+
const adaptedLocation = makeQDataPath(location);
|
|
1201
|
+
if (adaptedLocation) {
|
|
1202
|
+
requestEv.headers.set("Location", adaptedLocation);
|
|
1203
|
+
requestEv.getWritableStream().close();
|
|
1204
|
+
return;
|
|
1205
|
+
} else {
|
|
1206
|
+
requestEv.status(200);
|
|
1207
|
+
requestEv.headers.delete("Location");
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1269
1211
|
function now() {
|
|
1270
1212
|
return typeof performance !== "undefined" ? performance.now() : 0;
|
|
1271
1213
|
}
|
|
@@ -1279,7 +1221,165 @@ async function measure(requestEv, name, fn) {
|
|
|
1279
1221
|
if (!measurements) {
|
|
1280
1222
|
requestEv.sharedMap.set(RequestEvShareServerTiming, measurements = []);
|
|
1281
1223
|
}
|
|
1282
|
-
measurements.push([
|
|
1224
|
+
measurements.push([
|
|
1225
|
+
name,
|
|
1226
|
+
duration
|
|
1227
|
+
]);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
async function runValidators(requestEv, validators, data) {
|
|
1231
|
+
let lastResult = {
|
|
1232
|
+
success: true,
|
|
1233
|
+
data
|
|
1234
|
+
};
|
|
1235
|
+
if (validators) {
|
|
1236
|
+
for (const validator of validators) {
|
|
1237
|
+
if (isDev) {
|
|
1238
|
+
lastResult = await measure(requestEv, `validator$`, () => validator.validate(requestEv, data));
|
|
1239
|
+
} else {
|
|
1240
|
+
lastResult = await validator.validate(requestEv, data);
|
|
1241
|
+
}
|
|
1242
|
+
if (!lastResult.success) {
|
|
1243
|
+
return lastResult;
|
|
1244
|
+
} else {
|
|
1245
|
+
data = lastResult.data;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
return lastResult;
|
|
1250
|
+
}
|
|
1251
|
+
function actionsMiddleware(routeActions) {
|
|
1252
|
+
return async (requestEvent) => {
|
|
1253
|
+
const requestEv = requestEvent;
|
|
1254
|
+
if (requestEv.headersSent) {
|
|
1255
|
+
requestEv.exit();
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
const { method } = requestEv;
|
|
1259
|
+
const loaders = getRequestLoaders(requestEv);
|
|
1260
|
+
if (isDev && method === "GET") {
|
|
1261
|
+
if (requestEv.query.has(QACTION_KEY)) {
|
|
1262
|
+
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">');
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
if (method === "POST") {
|
|
1266
|
+
const selectedActionId = requestEv.query.get(QACTION_KEY);
|
|
1267
|
+
if (selectedActionId) {
|
|
1268
|
+
const serverActionsMap = globalThis._qwikActionsMap;
|
|
1269
|
+
const action = routeActions.find((action2) => action2.__id === selectedActionId) ?? serverActionsMap?.get(selectedActionId);
|
|
1270
|
+
if (action) {
|
|
1271
|
+
requestEv.sharedMap.set(RequestEvSharedActionId, selectedActionId);
|
|
1272
|
+
const data = await requestEv.parseBody();
|
|
1273
|
+
if (!data || typeof data !== "object") {
|
|
1274
|
+
throw new Error(`Expected request data for the action id ${selectedActionId} to be an object`);
|
|
1275
|
+
}
|
|
1276
|
+
const result = await runValidators(requestEv, action.__validators, data);
|
|
1277
|
+
if (!result.success) {
|
|
1278
|
+
loaders[selectedActionId] = requestEv.fail(result.status ?? 500, result.error);
|
|
1279
|
+
} else {
|
|
1280
|
+
const actionResolved = isDev ? await measure(requestEv, action.__qrl.getHash(), () => action.__qrl.call(requestEv, result.data, requestEv)) : await action.__qrl.call(requestEv, result.data, requestEv);
|
|
1281
|
+
if (isDev) {
|
|
1282
|
+
verifySerializable(actionResolved, action.__qrl);
|
|
1283
|
+
}
|
|
1284
|
+
loaders[selectedActionId] = actionResolved;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
async function getRouteLoaderPromise(loader, loaders, requestEv) {
|
|
1292
|
+
const loaderId = loader.__id;
|
|
1293
|
+
loaders[loaderId] = runValidators(
|
|
1294
|
+
requestEv,
|
|
1295
|
+
loader.__validators,
|
|
1296
|
+
void 0
|
|
1297
|
+
// data
|
|
1298
|
+
).then((res) => {
|
|
1299
|
+
if (res.success) {
|
|
1300
|
+
if (isDev) {
|
|
1301
|
+
return measure(requestEv, loader.__qrl.getHash(), () => loader.__qrl.call(requestEv, requestEv));
|
|
1302
|
+
} else {
|
|
1303
|
+
return loader.__qrl.call(requestEv, requestEv);
|
|
1304
|
+
}
|
|
1305
|
+
} else {
|
|
1306
|
+
return requestEv.fail(res.status ?? 500, res.error);
|
|
1307
|
+
}
|
|
1308
|
+
}).then((resolvedLoader) => {
|
|
1309
|
+
if (typeof resolvedLoader === "function") {
|
|
1310
|
+
loaders[loaderId] = resolvedLoader();
|
|
1311
|
+
} else {
|
|
1312
|
+
if (isDev) {
|
|
1313
|
+
verifySerializable(resolvedLoader, loader.__qrl);
|
|
1314
|
+
}
|
|
1315
|
+
loaders[loaderId] = resolvedLoader;
|
|
1316
|
+
}
|
|
1317
|
+
return resolvedLoader;
|
|
1318
|
+
});
|
|
1319
|
+
const loadersSerializationStrategy = getRequestLoaderSerializationStrategyMap(requestEv);
|
|
1320
|
+
loadersSerializationStrategy.set(loaderId, loader.__serializationStrategy);
|
|
1321
|
+
return loaders[loaderId];
|
|
1322
|
+
}
|
|
1323
|
+
function loadersMiddleware(routeLoaders) {
|
|
1324
|
+
return async (requestEvent) => {
|
|
1325
|
+
const requestEv = requestEvent;
|
|
1326
|
+
if (requestEv.headersSent) {
|
|
1327
|
+
requestEv.exit();
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
const loaders = getRequestLoaders(requestEv);
|
|
1331
|
+
if (routeLoaders.length > 0) {
|
|
1332
|
+
const resolvedLoadersPromises = routeLoaders.map((loader) => getRouteLoaderPromise(loader, loaders, requestEv));
|
|
1333
|
+
await Promise.all(resolvedLoadersPromises);
|
|
1334
|
+
}
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
async function runServerFunction(ev) {
|
|
1338
|
+
const serverFnHash = ev.query.get(QFN_KEY);
|
|
1339
|
+
if (serverFnHash && ev.request.headers.get("X-QRL") === serverFnHash && ev.request.headers.get("Content-Type") === "application/qwik-json") {
|
|
1340
|
+
ev.exit();
|
|
1341
|
+
const data = await ev.parseBody();
|
|
1342
|
+
if (!Array.isArray(data) || !(Array.isArray(data[0]) || data[0] === void 0)) {
|
|
1343
|
+
throw ev.error(500, "Invalid request");
|
|
1344
|
+
}
|
|
1345
|
+
const qrl = inlinedQrl(null, serverFnHash, data.slice(1));
|
|
1346
|
+
let result;
|
|
1347
|
+
try {
|
|
1348
|
+
if (isDev) {
|
|
1349
|
+
result = await measure(ev, `server_${serverFnHash}`, () => qrl.apply(ev, data[0]));
|
|
1350
|
+
} else {
|
|
1351
|
+
result = await qrl.apply(ev, data[0]);
|
|
1352
|
+
}
|
|
1353
|
+
} catch (err) {
|
|
1354
|
+
if (err instanceof ServerError$1) {
|
|
1355
|
+
throw ev.error(err.status, err.data);
|
|
1356
|
+
}
|
|
1357
|
+
console.error(`Server function ${serverFnHash} failed:`, err);
|
|
1358
|
+
throw ev.error(500, "Invalid request");
|
|
1359
|
+
}
|
|
1360
|
+
if (isAsyncIterator(result)) {
|
|
1361
|
+
ev.headers.set("Content-Type", "text/qwik-json-stream");
|
|
1362
|
+
const writable = ev.getWritableStream();
|
|
1363
|
+
const stream = writable.getWriter();
|
|
1364
|
+
for await (const item of result) {
|
|
1365
|
+
if (isDev) {
|
|
1366
|
+
verifySerializable(item, qrl);
|
|
1367
|
+
}
|
|
1368
|
+
const message = await _serialize(item);
|
|
1369
|
+
if (ev.signal.aborted) {
|
|
1370
|
+
break;
|
|
1371
|
+
}
|
|
1372
|
+
await stream.write(encoder.encode(`${message}
|
|
1373
|
+
`));
|
|
1374
|
+
}
|
|
1375
|
+
stream.close();
|
|
1376
|
+
} else {
|
|
1377
|
+
verifySerializable(result, qrl);
|
|
1378
|
+
ev.headers.set("Content-Type", "application/qwik-json");
|
|
1379
|
+
const message = await _serialize(result);
|
|
1380
|
+
ev.send(200, message);
|
|
1381
|
+
}
|
|
1382
|
+
return;
|
|
1283
1383
|
}
|
|
1284
1384
|
}
|
|
1285
1385
|
function getContentType(headers) {
|
|
@@ -1294,19 +1394,93 @@ function isContentType(headers, ...types) {
|
|
|
1294
1394
|
}
|
|
1295
1395
|
return false;
|
|
1296
1396
|
}
|
|
1397
|
+
function checkCSRF(requestEv, laxProto) {
|
|
1398
|
+
const contentType = requestEv.request.headers.get("content-type");
|
|
1399
|
+
const isSimpleRequest = !contentType || isContentType(requestEv.request.headers, "application/x-www-form-urlencoded", "multipart/form-data", "text/plain");
|
|
1400
|
+
if (isSimpleRequest) {
|
|
1401
|
+
const inputOrigin = requestEv.request.headers.get("origin");
|
|
1402
|
+
const origin = requestEv.url.origin;
|
|
1403
|
+
let forbidden = inputOrigin !== origin;
|
|
1404
|
+
if (forbidden && laxProto && inputOrigin?.replace(/^http(s)?/g, "") === origin.replace(/^http(s)?/g, "")) {
|
|
1405
|
+
forbidden = false;
|
|
1406
|
+
}
|
|
1407
|
+
if (forbidden) {
|
|
1408
|
+
throw requestEv.error(403, `CSRF check failed. Cross-site ${requestEv.method} form submissions are forbidden.
|
|
1409
|
+
The request origin "${inputOrigin}" does not match the server origin "${origin}".`);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
function csrfLaxProtoCheckMiddleware(requestEv) {
|
|
1414
|
+
checkCSRF(requestEv, "lax-proto");
|
|
1415
|
+
}
|
|
1416
|
+
function csrfCheckMiddleware(requestEv) {
|
|
1417
|
+
checkCSRF(requestEv);
|
|
1418
|
+
}
|
|
1419
|
+
const resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler, isInternal) => {
|
|
1420
|
+
const routeLoaders = [];
|
|
1421
|
+
const routeActions = [];
|
|
1422
|
+
const requestHandlers = [];
|
|
1423
|
+
const isPageRoute = !!(route && isLastModulePageRoute(route.$mods$));
|
|
1424
|
+
if (isInternal) {
|
|
1425
|
+
requestHandlers.push(handleQDataRedirect);
|
|
1426
|
+
}
|
|
1427
|
+
if (isPageRoute) {
|
|
1428
|
+
requestHandlers.push(serverErrorMiddleware(route, renderHandler));
|
|
1429
|
+
}
|
|
1430
|
+
if (serverPlugins) {
|
|
1431
|
+
_resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, serverPlugins, isPageRoute, method);
|
|
1432
|
+
}
|
|
1433
|
+
if (route) {
|
|
1434
|
+
const routeModules = route.$mods$;
|
|
1435
|
+
_resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, routeModules, isPageRoute, method);
|
|
1436
|
+
const routeName = route.$routeName$;
|
|
1437
|
+
if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
|
|
1438
|
+
if (checkOrigin === "lax-proto") {
|
|
1439
|
+
requestHandlers.unshift(csrfLaxProtoCheckMiddleware);
|
|
1440
|
+
} else {
|
|
1441
|
+
requestHandlers.unshift(csrfCheckMiddleware);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
if (isPageRoute) {
|
|
1445
|
+
if (method === "POST" || method === "GET") {
|
|
1446
|
+
requestHandlers.push(runServerFunction);
|
|
1447
|
+
}
|
|
1448
|
+
requestHandlers.push(fixTrailingSlash);
|
|
1449
|
+
if (isInternal) {
|
|
1450
|
+
requestHandlers.push(renderQData);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
if (isPageRoute) {
|
|
1454
|
+
requestHandlers.push((ev) => {
|
|
1455
|
+
ev.sharedMap.set(RequestRouteName, routeName);
|
|
1456
|
+
});
|
|
1457
|
+
requestHandlers.push(actionsMiddleware(routeActions));
|
|
1458
|
+
requestHandlers.push(loadersMiddleware(routeLoaders));
|
|
1459
|
+
requestHandlers.push(eTagMiddleware(route));
|
|
1460
|
+
requestHandlers.push(renderHandler);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
return requestHandlers;
|
|
1464
|
+
};
|
|
1297
1465
|
|
|
1298
1466
|
let _asyncRequestStore;
|
|
1299
1467
|
if (isServer) {
|
|
1300
1468
|
import('node:async_hooks').then((module) => {
|
|
1301
1469
|
_asyncRequestStore = new module.AsyncLocalStorage();
|
|
1302
1470
|
}).catch((err) => {
|
|
1303
|
-
console.warn(
|
|
1304
|
-
"\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",
|
|
1305
|
-
err
|
|
1306
|
-
);
|
|
1471
|
+
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);
|
|
1307
1472
|
});
|
|
1308
1473
|
}
|
|
1309
1474
|
let qwikRouterConfigActual;
|
|
1475
|
+
async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrigin, renderFn, isInternal) {
|
|
1476
|
+
const { routes, serverPlugins, cacheModules } = qwikRouterConfig;
|
|
1477
|
+
const loadedRoute = await loadRoute(routes, cacheModules, pathname, isInternal);
|
|
1478
|
+
const requestHandlers = resolveRequestHandlers(serverPlugins, loadedRoute, method, checkOrigin, renderQwikMiddleware(renderFn), isInternal);
|
|
1479
|
+
return {
|
|
1480
|
+
loadedRoute,
|
|
1481
|
+
requestHandlers
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1310
1484
|
async function requestHandler(serverRequestEv, opts) {
|
|
1311
1485
|
const { render, checkOrigin } = opts;
|
|
1312
1486
|
let { qwikRouterConfig } = opts;
|
|
@@ -1323,58 +1497,15 @@ async function requestHandler(serverRequestEv, opts) {
|
|
|
1323
1497
|
if (pathname === "/.well-known" || pathname.startsWith("/.well-known/")) {
|
|
1324
1498
|
return null;
|
|
1325
1499
|
}
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
serverRequestEv.request.method,
|
|
1330
|
-
checkOrigin ?? true,
|
|
1331
|
-
render,
|
|
1332
|
-
isInternal
|
|
1333
|
-
);
|
|
1334
|
-
if (routeAndHandlers) {
|
|
1335
|
-
const [route, requestHandlers] = routeAndHandlers;
|
|
1336
|
-
const rebuildRouteInfo = async (url) => {
|
|
1337
|
-
const { pathname: pathname2 } = getRouteMatchPathname(url.pathname);
|
|
1338
|
-
const routeAndHandlers2 = await loadRequestHandlers(
|
|
1339
|
-
qwikRouterConfig,
|
|
1340
|
-
pathname2,
|
|
1341
|
-
serverRequestEv.request.method,
|
|
1342
|
-
checkOrigin ?? true,
|
|
1343
|
-
render,
|
|
1344
|
-
isInternal
|
|
1345
|
-
);
|
|
1346
|
-
if (routeAndHandlers2) {
|
|
1347
|
-
const [loadedRoute, requestHandlers2] = routeAndHandlers2;
|
|
1348
|
-
return { loadedRoute, requestHandlers: requestHandlers2 };
|
|
1349
|
-
} else {
|
|
1350
|
-
return { loadedRoute: null, requestHandlers: [] };
|
|
1351
|
-
}
|
|
1352
|
-
};
|
|
1353
|
-
return runQwikRouter(
|
|
1354
|
-
serverRequestEv,
|
|
1355
|
-
route,
|
|
1356
|
-
requestHandlers,
|
|
1357
|
-
rebuildRouteInfo,
|
|
1358
|
-
qwikRouterConfig.basePathname
|
|
1359
|
-
);
|
|
1360
|
-
}
|
|
1361
|
-
return null;
|
|
1362
|
-
}
|
|
1363
|
-
async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrigin, renderFn, isInternal) {
|
|
1364
|
-
const { routes, serverPlugins, menus, cacheModules } = qwikRouterConfig;
|
|
1365
|
-
const route = await loadRoute(routes, menus, cacheModules, pathname, isInternal);
|
|
1366
|
-
const requestHandlers = resolveRequestHandlers(
|
|
1367
|
-
serverPlugins,
|
|
1368
|
-
route,
|
|
1369
|
-
method,
|
|
1370
|
-
checkOrigin,
|
|
1371
|
-
renderQwikMiddleware(renderFn),
|
|
1372
|
-
isInternal
|
|
1373
|
-
);
|
|
1374
|
-
if (requestHandlers.length > 0) {
|
|
1375
|
-
return [route, requestHandlers];
|
|
1500
|
+
const { loadedRoute, requestHandlers } = await loadRequestHandlers(qwikRouterConfig, pathname, serverRequestEv.request.method, checkOrigin ?? true, render, isInternal);
|
|
1501
|
+
if (qwikRouterConfig.fallthrough && loadedRoute.$notFound$) {
|
|
1502
|
+
return null;
|
|
1376
1503
|
}
|
|
1377
|
-
|
|
1504
|
+
const rebuildRouteInfo = async (url) => {
|
|
1505
|
+
const { pathname: pathname2 } = getRouteMatchPathname(url.pathname);
|
|
1506
|
+
return loadRequestHandlers(qwikRouterConfig, pathname2, serverRequestEv.request.method, checkOrigin ?? true, render, isInternal);
|
|
1507
|
+
};
|
|
1508
|
+
return runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, qwikRouterConfig.basePathname);
|
|
1378
1509
|
}
|
|
1379
1510
|
|
|
1380
1511
|
const notFounds = [
|
|
@@ -1390,7 +1521,9 @@ function getNotFound(prefix) {
|
|
|
1390
1521
|
return minimalHtmlResponse(404, "Resource Not Found");
|
|
1391
1522
|
}
|
|
1392
1523
|
|
|
1393
|
-
const staticPaths = /* @__PURE__ */ new Set([
|
|
1524
|
+
const staticPaths = /* @__PURE__ */ new Set([
|
|
1525
|
+
"__QWIK_ROUTER_STATIC_PATHS_ARRAY__"
|
|
1526
|
+
]);
|
|
1394
1527
|
function isStaticPath(method, url) {
|
|
1395
1528
|
if (method.toUpperCase() !== "GET") {
|
|
1396
1529
|
return false;
|
|
@@ -1418,10 +1551,10 @@ function isStaticPath(method, url) {
|
|
|
1418
1551
|
}
|
|
1419
1552
|
|
|
1420
1553
|
class ServerError extends Error {
|
|
1554
|
+
status;
|
|
1555
|
+
data;
|
|
1421
1556
|
constructor(status, data) {
|
|
1422
|
-
super(typeof data === "string" ? data : void 0);
|
|
1423
|
-
this.status = status;
|
|
1424
|
-
this.data = data;
|
|
1557
|
+
super(typeof data === "string" ? data : void 0), this.status = status, this.data = data;
|
|
1425
1558
|
}
|
|
1426
1559
|
}
|
|
1427
1560
|
|
|
@@ -1431,9 +1564,9 @@ class RedirectMessage extends AbortMessage {
|
|
|
1431
1564
|
}
|
|
1432
1565
|
|
|
1433
1566
|
class RewriteMessage extends AbortMessage {
|
|
1567
|
+
pathname;
|
|
1434
1568
|
constructor(pathname) {
|
|
1435
|
-
super();
|
|
1436
|
-
this.pathname = pathname;
|
|
1569
|
+
super(), this.pathname = pathname;
|
|
1437
1570
|
}
|
|
1438
1571
|
}
|
|
1439
1572
|
|
|
@@ -1472,7 +1605,11 @@ class _TextEncoderStream_polyfill {
|
|
|
1472
1605
|
},
|
|
1473
1606
|
flush: (controller) => {
|
|
1474
1607
|
if (this.#pendingHighSurrogate !== null) {
|
|
1475
|
-
controller.enqueue(new Uint8Array([
|
|
1608
|
+
controller.enqueue(new Uint8Array([
|
|
1609
|
+
239,
|
|
1610
|
+
191,
|
|
1611
|
+
189
|
|
1612
|
+
]));
|
|
1476
1613
|
}
|
|
1477
1614
|
}
|
|
1478
1615
|
});
|
|
@@ -1490,4 +1627,4 @@ class _TextEncoderStream_polyfill {
|
|
|
1490
1627
|
}
|
|
1491
1628
|
}
|
|
1492
1629
|
|
|
1493
|
-
export { AbortMessage, RedirectMessage, RequestEvShareQData, RewriteMessage, ServerError, _TextEncoderStream_polyfill, _asyncRequestStore, getErrorHtml, getNotFound, isStaticPath, mergeHeadersCookies, requestHandler };
|
|
1630
|
+
export { AbortMessage, RedirectMessage, RequestEvShareQData, RewriteMessage, ServerError, _TextEncoderStream_polyfill, _asyncRequestStore, clearSsrCache, getErrorHtml, getNotFound, isStaticPath, mergeHeadersCookies, requestHandler };
|