@qwik.dev/router 2.0.0-beta.36 → 2.0.0-beta.37

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.
@@ -1,73 +1,13 @@
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, b as loadRoute } from '../../chunks/routing.qwik.mjs';
2
- import { isDev, _UNINITIALIZED, _deserialize, _verifySerializable, _serialize, _getAsyncLocalStorage } 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';
1
+ import { n as getRouteLoaderCtx, o as getRouteLoaderValues, i as Q_ROUTE, p as loadRouteLoader, q as setRouteLoaders, S as ServerError, t as RedirectMessage, k as QFN_KEY, Q as QACTION_KEY, A as AbortMessage, l as QDATA_KEY, _ as _asyncRequestStore, F as FULLPATH_HEADER } from '../../chunks/deepFreeze.qwik.mjs';
2
+ import { d as resolveRouteConfig, e as isPromise, l as loadRoute } from '../../chunks/head.qwik.mjs';
3
+ import { I as IsQLoader, Q as QLoaderId, a as QActionId, b as IsQAction, t as trimRecognizedInternalPathname, r as recognizeRequest, c as resolveValidInternalFullPathname, d as trimInternalPathname, L as LOADER_REGEX } from '../../chunks/request-path.mjs';
4
+ import { g as getRequestRoute, a as getRequestMode, R as RequestRouteName, b as RequestEvSharedNonce, c as RequestEvSharedActionId, d as RequestEvSharedActionFormData, e as RequestEvHttpStatusMessage, j as jsonRequestWrapper, l as loaderHandler, f as actionHandler, h as hash, n as normalizeETag, p as performETagMatch, s as setETagHeader, i as setCachedLoader, k as setCachedSsr, r as resolveETag, m as resolveCacheKey, M as MAX_CACHE_SIZE, o as getCachedLoader, q as getCachedSsr, t as defaultLoaderCacheKey, u as defaultSsrCacheKey, v as RequestEvShareServerTiming, w as RequestEvETagCacheKey, x as createRequestEventWithDeps } from '../../chunks/action-handler.mjs';
5
+ export { y as clearLoaderCache, z as clearSsrCache } from '../../chunks/action-handler.mjs';
6
+ import { isDev, inlinedQrl } from '@qwik.dev/core';
7
+ import { _verifySerializable, _serialize, isDev as isDev$1 } from '@qwik.dev/core/internal';
8
+ import { e as ensureSlash } from '../../chunks/pathname.mjs';
6
9
  import { g as getErrorHtml, m as minimalHtmlResponse } from '../../chunks/error-handler.mjs';
7
10
 
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 = "/";
17
- }
18
- }
19
- return {
20
- pathname,
21
- isInternal
22
- };
23
- }
24
-
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;
30
- }
31
- if (typeof eTagExport === "function") {
32
- return eTagExport(headProps);
33
- }
34
- return eTagExport;
35
- }
36
- function resolveCacheKey(cacheKeyExport, status, eTag, pathname) {
37
- if (cacheKeyExport === true) {
38
- return `${status}|${eTag}|${pathname}`;
39
- }
40
- if (typeof cacheKeyExport !== "function") {
41
- return null;
42
- }
43
- return cacheKeyExport(status, eTag, pathname);
44
- }
45
- function getCachedHtml(key) {
46
- const html = ssrCache.get(key);
47
- if (html !== void 0) {
48
- ssrCache.delete(key);
49
- ssrCache.set(key, html);
50
- }
51
- return html;
52
- }
53
- function setCachedHtml(key, html) {
54
- if (MAX_CACHE_SIZE <= 0) {
55
- return;
56
- }
57
- if (ssrCache.size >= MAX_CACHE_SIZE) {
58
- const firstKey = ssrCache.keys().next().value;
59
- ssrCache.delete(firstKey);
60
- }
61
- ssrCache.set(key, html);
62
- }
63
- function clearSsrCache(cacheKey) {
64
- if (cacheKey != null) {
65
- ssrCache.delete(cacheKey);
66
- } else {
67
- ssrCache.clear();
68
- }
69
- }
70
-
71
11
  var HttpStatus = /* @__PURE__ */ (function(HttpStatus2) {
72
12
  HttpStatus2[HttpStatus2["Continue"] = 100] = "Continue";
73
13
  HttpStatus2[HttpStatus2["SwitchingProtocols"] = 101] = "SwitchingProtocols";
@@ -133,457 +73,12 @@ var HttpStatus = /* @__PURE__ */ (function(HttpStatus2) {
133
73
  return HttpStatus2;
134
74
  })({});
135
75
 
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];
151
- }
152
- function getRequestLoaderSerializationStrategyMap(requestEv) {
153
- return requestEv[RequestEvLoaderSerializationStrategyMap];
154
- }
155
- function getRequestRoute(requestEv) {
156
- return requestEv[RequestEvRoute];
157
- }
158
- function getRequestMode(requestEv) {
159
- return requestEv[RequestEvMode];
160
- }
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
- }
174
- }
175
- if (hasDangerousKey) {
176
- continue;
177
- }
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
- }
191
- }
192
- }
193
- return new Set(Array.from(arrayCandidates.entries()).filter(([, isArrayPath]) => isArrayPath).map(([path]) => path));
194
- };
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
- }
206
- }
207
- if (hasDangerousKey) {
208
- continue;
209
- }
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;
240
- }
241
- }
242
- }
243
- return values;
244
- };
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
- }
263
- }
264
- return _deserialize(await request.text());
265
- }
266
- return void 0;
267
- };
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);
278
- }
279
- let routeModuleIndex = -1;
280
- let writableStream = null;
281
- let requestData = void 0;
282
- let locale = serverRequestEv.locale;
283
- let status = loadedRoute?.$notFound$ ? 404 : 200;
284
- const next = async () => {
285
- routeModuleIndex++;
286
- while (routeModuleIndex < requestHandlers.length) {
287
- const moduleRequestHandler = requestHandlers[routeModuleIndex];
288
- const result = moduleRequestHandler(requestEv);
289
- if (deps.isPromise(result)) {
290
- await result;
291
- }
292
- routeModuleIndex++;
293
- }
294
- };
295
- const resetRoute = (_loadedRoute, _requestHandlers, _url = url) => {
296
- loadedRoute = _loadedRoute;
297
- status = loadedRoute?.$notFound$ ? 404 : 200;
298
- requestHandlers = _requestHandlers;
299
- url.pathname = _url.pathname;
300
- url.search = _url.search;
301
- routeModuleIndex = -1;
302
- };
303
- const check = () => {
304
- if (writableStream !== null) {
305
- throw new Error("Response already sent");
306
- }
307
- };
308
- const send = (statusOrResponse, body) => {
309
- check();
310
- if (typeof statusOrResponse === "number") {
311
- status = statusOrResponse;
312
- const writableStream2 = requestEv.getWritableStream();
313
- const writer = writableStream2.getWriter();
314
- writer.write(typeof body === "string" ? deps.encoder.encode(body) : body);
315
- writer.close();
316
- } else {
317
- status = statusOrResponse.status;
318
- statusOrResponse.headers.forEach((value, key) => {
319
- if (key.toLowerCase() === "set-cookie") {
320
- return;
321
- }
322
- headers.append(key, value);
323
- });
324
- statusOrResponse.headers.getSetCookie().forEach((ck) => {
325
- const index = ck.indexOf("=");
326
- if (index === -1) {
327
- return;
328
- }
329
- const key = ck.slice(0, index).trim();
330
- const value = ck.slice(index + 1).trim();
331
- cookie.set(key, value);
332
- });
333
- if (statusOrResponse.body) {
334
- const writableStream2 = requestEv.getWritableStream();
335
- statusOrResponse.body.pipeTo(writableStream2);
336
- } else {
337
- requestEv.getWritableStream().getWriter().close();
338
- }
339
- }
340
- return exit();
341
- };
342
- const exit = (message = new deps.AbortMessage()) => {
343
- routeModuleIndex = ABORT_INDEX;
344
- return message;
345
- };
346
- const loaders = {};
347
- const requestEv = {
348
- [RequestEvLoaders]: loaders,
349
- [RequestEvLoaderSerializationStrategyMap]: /* @__PURE__ */ new Map(),
350
- [RequestEvMode]: serverRequestEv.mode,
351
- get [RequestEvRoute]() {
352
- return loadedRoute;
353
- },
354
- cookie,
355
- headers,
356
- env,
357
- method: request.method,
358
- signal: request.signal,
359
- originalUrl: new URL(url),
360
- get params() {
361
- return loadedRoute?.$params$ ?? {};
362
- },
363
- get pathname() {
364
- return url.pathname;
365
- },
366
- platform,
367
- get query() {
368
- return url.searchParams;
369
- },
370
- request,
371
- url,
372
- basePathname,
373
- sharedMap,
374
- get headersSent() {
375
- return writableStream !== null;
376
- },
377
- get exited() {
378
- return routeModuleIndex >= ABORT_INDEX;
379
- },
380
- get clientConn() {
381
- return serverRequestEv.getClientConn();
382
- },
383
- next,
384
- resetRoute,
385
- exit,
386
- cacheControl: (cacheControl, target = "Cache-Control") => {
387
- check();
388
- headers.set(target, deps.createCacheControl(cacheControl));
389
- },
390
- resolveValue: async (loaderOrAction) => {
391
- const id = loaderOrAction.__id;
392
- if (loaderOrAction.__brand === "server_loader") {
393
- if (!(id in loaders)) {
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);
398
- }
399
- }
400
- return loaders[id];
401
- },
402
- status: (statusCode) => {
403
- if (typeof statusCode === "number") {
404
- check();
405
- status = statusCode;
406
- return statusCode;
407
- }
408
- return status;
409
- },
410
- locale: (_locale) => {
411
- if (typeof _locale === "string") {
412
- locale = _locale;
413
- }
414
- return locale || "";
415
- },
416
- error: (statusCode, message) => {
417
- status = statusCode;
418
- headers.delete("Cache-Control");
419
- return new deps.ServerError(statusCode, message);
420
- },
421
- redirect: (statusCode, url2) => {
422
- check();
423
- status = statusCode;
424
- if (url2) {
425
- if (
426
- // //test.com
427
- /^\/\//.test(url2) || // /test//path
428
- /([^:])\/\/+/.test(url2)
429
- ) {
430
- const fixedURL = url2.replace(/^\/\/+/, "/").replace(/([^:])\/\/+/g, "$1/");
431
- console.warn(`Redirect URL ${url2} is invalid, fixing to ${fixedURL}`);
432
- url2 = fixedURL;
433
- }
434
- headers.set("Location", url2);
435
- }
436
- headers.delete("Cache-Control");
437
- if (statusCode > 301) {
438
- headers.set("Cache-Control", "no-store");
439
- }
440
- return exit(new deps.RedirectMessage());
441
- },
442
- rewrite: (pathname2) => {
443
- check();
444
- if (pathname2.startsWith("http")) {
445
- throw new deps.ServerError(400, isDev ? "Rewrite does not support absolute urls" : "Bad Request");
446
- }
447
- sharedMap.set(RequestEvIsRewrite, true);
448
- return exit(new deps.RewriteMessage(pathname2.replace(/\/+/g, "/")));
449
- },
450
- defer: (returnData) => {
451
- return typeof returnData === "function" ? returnData : () => returnData;
452
- },
453
- fail: (statusCode, data) => {
454
- check();
455
- status = statusCode;
456
- headers.delete("Cache-Control");
457
- return {
458
- failed: true,
459
- ...data
460
- };
461
- },
462
- text: (statusCode, text) => {
463
- headers.set("Content-Type", "text/plain; charset=utf-8");
464
- return send(statusCode, text);
465
- },
466
- html: (statusCode, html) => {
467
- headers.set("Content-Type", "text/html; charset=utf-8");
468
- return send(statusCode, html);
469
- },
470
- parseBody: async () => {
471
- if (requestData !== void 0) {
472
- return requestData;
473
- }
474
- return requestData = parseRequest(deps, requestEv, sharedMap);
475
- },
476
- json: (statusCode, data) => {
477
- headers.set("Content-Type", "application/json; charset=utf-8");
478
- return send(statusCode, JSON.stringify(data));
479
- },
480
- send,
481
- isDirty: () => {
482
- return writableStream !== null;
483
- },
484
- getWritableStream: () => {
485
- if (writableStream === null) {
486
- if (isDev) {
487
- const serverTiming = sharedMap.get(RequestEvShareServerTiming);
488
- if (serverTiming) {
489
- headers.set("Server-Timing", serverTiming.map(([name, duration]) => `${name};dur=${duration}`).join(","));
490
- }
491
- }
492
- writableStream = serverRequestEv.getWritableStream(status, headers, cookie, resolved, requestEv);
493
- }
494
- return writableStream;
495
- }
496
- };
497
- return requestEv;
498
- }
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
- }
509
- }
510
- function now() {
511
- return typeof performance !== "undefined" ? performance.now() : 0;
512
- }
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
- }
528
- }
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;
549
- }
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
76
  function getQwikRouterServerDataWithDeps(deps, requestEv) {
583
77
  const { params, request, status, locale, originalUrl } = requestEv;
584
78
  const requestHeaders = {};
585
79
  request.headers.forEach((value, key) => requestHeaders[key] = value);
586
80
  const action = requestEv.sharedMap.get(deps.RequestEvSharedActionId);
81
+ const actionResult = requestEv.sharedMap.get("@actionResult");
587
82
  const formData = requestEv.sharedMap.get(deps.RequestEvSharedActionFormData);
588
83
  const routeName = requestEv.sharedMap.get(deps.RequestRouteName);
589
84
  const nonce = requestEv.sharedMap.get(deps.RequestEvSharedNonce);
@@ -598,8 +93,8 @@ function getQwikRouterServerDataWithDeps(deps, requestEv) {
598
93
  if (protocol) {
599
94
  reconstructedUrl.protocol = protocol;
600
95
  }
601
- const loaders = deps.getRequestLoaders(requestEv);
602
- const loadersSerializationStrategy = deps.getRequestLoaderSerializationStrategyMap(requestEv);
96
+ const routeLoaderCtx = getRouteLoaderCtx(requestEv);
97
+ const loaderValues = getRouteLoaderValues(requestEv);
603
98
  return {
604
99
  url: reconstructedUrl.href,
605
100
  requestHeaders,
@@ -616,12 +111,13 @@ function getQwikRouterServerDataWithDeps(deps, requestEv) {
616
111
  ...params
617
112
  },
618
113
  loadedRoute: deps.getRequestRoute(requestEv),
114
+ routeLoaderCtx,
115
+ loaderValues,
619
116
  response: {
620
117
  status: status(),
621
118
  statusMessage: requestEv.sharedMap.get(deps.RequestEvHttpStatusMessage),
622
- loaders,
623
- loadersSerializationStrategy,
624
119
  action,
120
+ actionResult,
625
121
  formData
626
122
  }
627
123
  }
@@ -635,8 +131,6 @@ const responsePageDeps = {
635
131
  RequestEvSharedActionId,
636
132
  RequestEvSharedNonce,
637
133
  RequestRouteName,
638
- getRequestLoaders,
639
- getRequestLoaderSerializationStrategyMap,
640
134
  getRequestMode,
641
135
  getRequestRoute
642
136
  };
@@ -645,22 +139,20 @@ function getQwikRouterServerData(...args) {
645
139
  }
646
140
 
647
141
  function createResolveRequestHandlers(deps) {
648
- const resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler, isInternal) => {
142
+ const resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderHandler) => {
649
143
  const routeLoaders = [];
650
144
  const routeActions = [];
651
145
  const requestHandlers = [];
652
146
  const isPageRoute = !!isLastModulePageRoute(route.$mods$);
653
- if (isInternal) {
654
- requestHandlers.push(handleQDataRedirect);
655
- }
656
147
  if (isPageRoute) {
148
+ requestHandlers.push(jsonRequestWrapper());
657
149
  requestHandlers.push(serverErrorMiddleware(route, renderHandler));
658
150
  }
659
151
  if (serverPlugins) {
660
152
  _resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, serverPlugins, isPageRoute, method);
661
153
  }
662
154
  const routeModules = route.$mods$;
663
- _resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, routeModules, isPageRoute, method);
155
+ _resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, routeModules, isPageRoute, method, isPageRoute);
664
156
  const routeName = route.$routeName$;
665
157
  if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
666
158
  if (checkOrigin === "lax-proto") {
@@ -670,70 +162,32 @@ function createResolveRequestHandlers(deps) {
670
162
  }
671
163
  }
672
164
  if (isPageRoute) {
165
+ requestHandlers.push(loaderHandler(routeLoaders, route.$loaderPaths$));
166
+ requestHandlers.push(actionHandler(routeActions));
673
167
  if (method === "POST" || method === "GET") {
674
168
  requestHandlers.push(runServerFunction);
675
169
  }
676
170
  if (!route.$notFound$) {
677
171
  requestHandlers.push(fixTrailingSlash);
678
172
  }
679
- if (isInternal) {
680
- requestHandlers.push(renderQData);
681
- }
682
173
  }
683
174
  if (isPageRoute) {
684
175
  requestHandlers.push((ev) => {
685
176
  ev.sharedMap.set(deps.RequestRouteName, routeName);
686
177
  });
687
178
  requestHandlers.push(actionsMiddleware(routeActions));
688
- requestHandlers.push(loadersMiddleware(routeLoaders));
179
+ requestHandlers.push(loadersMiddleware(routeLoaders, route));
689
180
  requestHandlers.push(eTagMiddleware(route));
690
181
  requestHandlers.push(renderHandler);
691
182
  }
692
183
  return requestHandlers;
693
184
  };
694
- const _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, routeModules, collectActions, method) => {
695
- for (const routeModule of routeModules) {
696
- if (typeof routeModule.onRequest === "function") {
697
- requestHandlers.push(routeModule.onRequest);
698
- } else if (Array.isArray(routeModule.onRequest)) {
699
- requestHandlers.push(...routeModule.onRequest);
700
- }
701
- let methodReqHandler;
702
- switch (method) {
703
- case "GET": {
704
- methodReqHandler = routeModule.onGet;
705
- break;
706
- }
707
- case "POST": {
708
- methodReqHandler = routeModule.onPost;
709
- break;
710
- }
711
- case "PUT": {
712
- methodReqHandler = routeModule.onPut;
713
- break;
714
- }
715
- case "PATCH": {
716
- methodReqHandler = routeModule.onPatch;
717
- break;
718
- }
719
- case "DELETE": {
720
- methodReqHandler = routeModule.onDelete;
721
- break;
722
- }
723
- case "OPTIONS": {
724
- methodReqHandler = routeModule.onOptions;
725
- break;
726
- }
727
- case "HEAD": {
728
- methodReqHandler = routeModule.onHead;
729
- break;
730
- }
731
- }
732
- if (typeof methodReqHandler === "function") {
733
- requestHandlers.push(methodReqHandler);
734
- } else if (Array.isArray(methodReqHandler)) {
735
- requestHandlers.push(...methodReqHandler);
736
- }
185
+ function _resolveRequestHandlers(routeLoaders, routeActions, requestHandlers, routeModules, collectActions, method, guardPageHandlersForLoader = false) {
186
+ for (let i = 0; i < routeModules.length; i++) {
187
+ const routeModule = routeModules[i];
188
+ const moduleHandlers = getModuleRequestHandlers(routeModule, method);
189
+ const shouldGuardPageHandlers = guardPageHandlersForLoader && i === routeModules.length - 1;
190
+ requestHandlers.push(...shouldGuardPageHandlers ? moduleHandlers.map((handler) => guardPageHandlerForLoader(routeModule, handler)) : moduleHandlers);
737
191
  if (collectActions) {
738
192
  for (const module of Object.values(routeModule)) {
739
193
  if (typeof module === "function") {
@@ -746,7 +200,73 @@ function createResolveRequestHandlers(deps) {
746
200
  }
747
201
  }
748
202
  }
749
- };
203
+ }
204
+ function getModuleRequestHandlers(routeModule, method) {
205
+ const handlers = [];
206
+ addRequestHandlers(handlers, routeModule.onRequest);
207
+ let methodReqHandler;
208
+ switch (method) {
209
+ case "GET": {
210
+ methodReqHandler = routeModule.onGet;
211
+ break;
212
+ }
213
+ case "POST": {
214
+ methodReqHandler = routeModule.onPost;
215
+ break;
216
+ }
217
+ case "PUT": {
218
+ methodReqHandler = routeModule.onPut;
219
+ break;
220
+ }
221
+ case "PATCH": {
222
+ methodReqHandler = routeModule.onPatch;
223
+ break;
224
+ }
225
+ case "DELETE": {
226
+ methodReqHandler = routeModule.onDelete;
227
+ break;
228
+ }
229
+ case "OPTIONS": {
230
+ methodReqHandler = routeModule.onOptions;
231
+ break;
232
+ }
233
+ case "HEAD": {
234
+ methodReqHandler = routeModule.onHead;
235
+ break;
236
+ }
237
+ }
238
+ addRequestHandlers(handlers, methodReqHandler);
239
+ return handlers;
240
+ }
241
+ function addRequestHandlers(handlers, handler) {
242
+ if (typeof handler === "function") {
243
+ handlers.push(handler);
244
+ } else if (Array.isArray(handler)) {
245
+ handlers.push(...handler);
246
+ }
247
+ }
248
+ function guardPageHandlerForLoader(routeModule, handler) {
249
+ return (requestEv) => {
250
+ if (requestEv.sharedMap.has(IsQLoader)) {
251
+ const loaderId = requestEv.sharedMap.get(QLoaderId);
252
+ if (!moduleHasLoader(routeModule, loaderId)) {
253
+ return;
254
+ }
255
+ }
256
+ return handler(requestEv);
257
+ };
258
+ }
259
+ function moduleHasLoader(routeModule, loaderId) {
260
+ if (typeof loaderId !== "string") {
261
+ return false;
262
+ }
263
+ for (const value of Object.values(routeModule)) {
264
+ if (checkBrand(value, "server_loader") && value.__id === loaderId) {
265
+ return true;
266
+ }
267
+ }
268
+ return false;
269
+ }
750
270
  const checkBrand = (obj, brand) => {
751
271
  return obj && typeof obj === "function" && obj.__brand === brand;
752
272
  };
@@ -758,7 +278,6 @@ function createResolveRequestHandlers(deps) {
758
278
  return;
759
279
  }
760
280
  const { method } = requestEv;
761
- const loaders = deps.getRequestLoaders(requestEv);
762
281
  if (isDev && method === "GET") {
763
282
  if (requestEv.query.has(deps.QACTION_KEY)) {
764
283
  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">');
@@ -776,66 +295,79 @@ function createResolveRequestHandlers(deps) {
776
295
  throw new Error(`Expected request data for the action id ${selectedActionId} to be an object`);
777
296
  }
778
297
  const result = await runValidators(requestEv, action.__validators, data);
298
+ let actionResult;
779
299
  if (!result.success) {
780
- loaders[selectedActionId] = requestEv.fail(result.status ?? 500, result.error);
300
+ actionResult = requestEv.fail(result.status ?? 500, result.error);
781
301
  } else {
782
302
  const actionResolved = isDev ? await measure(requestEv, action.__qrl.getHash(), () => action.__qrl.call(requestEv, result.data, requestEv)) : await action.__qrl.call(requestEv, result.data, requestEv);
783
303
  if (isDev) {
784
304
  verifySerializable(actionResolved, action.__qrl);
785
305
  }
786
- loaders[selectedActionId] = actionResolved;
306
+ actionResult = actionResolved;
787
307
  }
308
+ requestEv.sharedMap.set("@actionResult", actionResult);
788
309
  }
789
310
  }
790
311
  }
791
312
  };
792
313
  }
793
- function loadersMiddleware(routeLoaders) {
314
+ function loadersMiddleware(routeLoaders, route) {
794
315
  return async (requestEvent) => {
795
316
  const requestEv = requestEvent;
796
317
  if (requestEv.headersSent) {
797
318
  requestEv.exit();
798
319
  return;
799
320
  }
800
- const loaders = deps.getRequestLoaders(requestEv);
801
- const loadersSerializationStrategy = deps.getRequestLoaderSerializationStrategyMap(requestEv);
802
321
  if (routeLoaders.length > 0) {
803
- const resolvedLoadersPromises = routeLoaders.map((loader) => deps.getRouteLoaderPromise(loader, loaders, loadersSerializationStrategy, requestEv));
804
- await Promise.all(resolvedLoadersPromises);
322
+ setLoaderData(requestEv, routeLoaders, route);
323
+ const loaderValues = getRouteLoaderValues(requestEv);
324
+ await Promise.all(routeLoaders.map(async (loader) => {
325
+ loaderValues[loader.__id] = await loadRouteLoader(loader, requestEv);
326
+ }));
805
327
  }
806
328
  };
807
329
  }
330
+ function setLoaderData(requestEv, routeLoaders, route) {
331
+ if (routeLoaders.length === 0) {
332
+ return;
333
+ }
334
+ const routeLoaderCtx = getRouteLoaderCtx(requestEv);
335
+ if (route.$loaderPaths$) {
336
+ Object.assign(routeLoaderCtx.loaderPaths, route.$loaderPaths$);
337
+ }
338
+ setRouteLoaders(requestEv, routeLoaders);
339
+ }
808
340
  function eTagMiddleware(route) {
809
341
  return (requestEv) => {
810
342
  if (requestEv.headersSent) {
811
343
  return;
812
344
  }
813
- if (requestEv.method !== "GET" || requestEv.sharedMap.has(deps.IsQData)) {
345
+ if (requestEv.method !== "GET") {
814
346
  return;
815
347
  }
816
348
  const mods = route.$mods$;
817
- const hasETag = mods.some((m) => {
349
+ const hasCachingConfig = mods.some((m) => {
818
350
  if (!m) {
819
351
  return false;
820
352
  }
821
353
  if (m.routeConfig) {
822
- return typeof m.routeConfig === "function" || m.routeConfig.eTag !== void 0;
354
+ return typeof m.routeConfig === "function" || m.routeConfig.eTag !== void 0 || m.routeConfig.cacheKey !== void 0;
823
355
  }
824
- return m.eTag !== void 0;
356
+ return m.eTag !== void 0 || m.cacheKey !== void 0;
825
357
  });
826
- if (!hasETag) {
358
+ if (!hasCachingConfig) {
827
359
  return;
828
360
  }
829
- const loaders = deps.getRequestLoaders(requestEv);
361
+ const loaderValues = getRouteLoaderValues(requestEv);
830
362
  const getData = (loaderOrAction) => {
831
363
  const id = loaderOrAction.__id;
832
- if (loaderOrAction.__brand === "server_loader" && !(id in loaders)) {
833
- throw new Error("Loader not executed for this request.");
834
- }
835
- if (loaders[id] instanceof Promise) {
836
- throw new Error("Loaders returning a promise cannot be resolved for the eTag function.");
364
+ if (loaderOrAction.__brand === "server_loader") {
365
+ if (!(id in loaderValues)) {
366
+ throw new Error("Loader not executed for this request.");
367
+ }
368
+ return loaderValues[id];
837
369
  }
838
- return loaders[id];
370
+ return requestEv.sharedMap.get(deps.RequestEvSharedActionId) === id ? requestEv.sharedMap.get("@actionResult") : void 0;
839
371
  };
840
372
  const routeLocation = {
841
373
  params: requestEv.params,
@@ -852,32 +384,36 @@ function createResolveRequestHandlers(deps) {
852
384
  resolveValue: getData,
853
385
  ...routeLocation
854
386
  };
855
- const eTag = deps.resolveETag(config.eTag, headProps);
856
- if (!eTag) {
857
- return;
858
- }
859
- requestEv.headers.set("ETag", eTag);
860
- const ifNoneMatch = requestEv.request.headers.get("If-None-Match");
861
- if (ifNoneMatch && (ifNoneMatch === eTag || ifNoneMatch === `W/${eTag}` || `W/${ifNoneMatch}` === eTag)) {
862
- requestEv.status(304);
863
- requestEv.send(304, "");
387
+ const resolvedETag = deps.resolveETag(config.eTag, headProps);
388
+ const normalizedETag = resolvedETag !== null ? normalizeETag(resolvedETag) : "";
389
+ if (normalizedETag && performETagMatch(requestEv, normalizedETag)) {
864
390
  return;
865
391
  }
866
392
  if (deps.MAX_CACHE_SIZE <= 0) {
867
393
  return;
868
394
  }
869
- const cacheKey = deps.resolveCacheKey(config.cacheKey, status, eTag, requestEv.url.pathname);
395
+ const cacheKey = deps.resolveCacheKey(config.cacheKey, deps.defaultSsrCacheKey, requestEv, normalizedETag);
870
396
  if (!cacheKey) {
871
397
  return;
872
398
  }
873
- const cachedHtml = deps.getCachedHtml(cacheKey);
874
- if (cachedHtml) {
399
+ const cached = deps.getCachedSsr(cacheKey);
400
+ if (cached) {
875
401
  requestEv.headers.set("Content-Type", "text/html; charset=utf-8");
876
402
  requestEv.headers.set("X-SSR-Cache", "HIT");
877
- requestEv.send(status, cachedHtml);
403
+ if (!normalizedETag) {
404
+ if (performETagMatch(requestEv, cached.eTag)) {
405
+ return;
406
+ }
407
+ } else {
408
+ setETagHeader(requestEv, cached.eTag);
409
+ }
410
+ requestEv.send(status, cached.body);
878
411
  return;
879
412
  }
880
- requestEv.sharedMap.set(deps.RequestEvETagCacheKey, cacheKey);
413
+ requestEv.sharedMap.set(deps.RequestEvETagCacheKey, {
414
+ key: cacheKey,
415
+ eTag: normalizedETag
416
+ });
881
417
  };
882
418
  }
883
419
  function serverErrorMiddleware(route, renderHandler) {
@@ -888,9 +424,6 @@ function createResolveRequestHandlers(deps) {
888
424
  if (!(e instanceof deps.ServerError) || requestEv.headersSent) {
889
425
  throw e;
890
426
  }
891
- if (requestEv.sharedMap.has(deps.IsQData)) {
892
- throw e;
893
- }
894
427
  const accept = requestEv.request.headers.get("Accept");
895
428
  if (accept && !accept.includes("text/html")) {
896
429
  throw e;
@@ -980,16 +513,15 @@ function createResolveRequestHandlers(deps) {
980
513
  }
981
514
  }
982
515
  function fixTrailingSlash(ev) {
983
- const { basePathname, originalUrl, sharedMap } = ev;
516
+ const { basePathname, originalUrl } = ev;
984
517
  const { pathname, search } = originalUrl;
985
- const isQData = sharedMap.has(deps.IsQData);
986
518
  if (!pathname.startsWith("/") || pathname.startsWith("//")) {
987
519
  return;
988
520
  }
989
- if (!isQData && pathname !== basePathname && !pathname.endsWith(".html")) {
521
+ if (pathname !== basePathname && !pathname.endsWith(".html")) {
990
522
  if (!globalThis.__NO_TRAILING_SLASH__) {
991
523
  if (!pathname.endsWith("/")) {
992
- throw ev.redirect(deps.HttpStatus.MovedPermanently, pathname + "/" + search);
524
+ throw ev.redirect(deps.HttpStatus.MovedPermanently, ensureSlash(pathname) + search);
993
525
  }
994
526
  } else {
995
527
  if (pathname.endsWith("/")) {
@@ -1017,12 +549,9 @@ function createResolveRequestHandlers(deps) {
1017
549
  }
1018
550
  function getPathname(url) {
1019
551
  url = new URL(url);
1020
- if (url.pathname.endsWith(deps.QDATA_JSON)) {
1021
- url.pathname = url.pathname.slice(0, -deps.QDATA_JSON.length);
1022
- }
1023
552
  if (!globalThis.__NO_TRAILING_SLASH__) {
1024
553
  if (!url.pathname.endsWith("/")) {
1025
- url.pathname += "/";
554
+ url.pathname = ensureSlash(url.pathname);
1026
555
  }
1027
556
  } else {
1028
557
  if (url.pathname.endsWith("/")) {
@@ -1059,19 +588,16 @@ The request origin "${inputOrigin}" does not match the server origin "${origin}"
1059
588
  if (requestEv.headersSent) {
1060
589
  return;
1061
590
  }
1062
- if (requestEv.sharedMap.has(deps.IsQData)) {
1063
- return;
1064
- }
1065
591
  const responseHeaders = requestEv.headers;
1066
592
  if (!responseHeaders.has("Content-Type")) {
1067
593
  responseHeaders.set("Content-Type", "text/html; charset=utf-8");
1068
594
  }
1069
- const eTagCacheKey = requestEv.sharedMap.get(deps.RequestEvETagCacheKey);
595
+ const cachePlan = requestEv.sharedMap.get(deps.RequestEvETagCacheKey);
1070
596
  const { readable, writable } = new TextEncoderStream();
1071
597
  const writableStream = requestEv.getWritableStream();
1072
598
  let cacheChunks;
1073
599
  let pipeSource = readable;
1074
- if (eTagCacheKey) {
600
+ if (cachePlan) {
1075
601
  cacheChunks = [];
1076
602
  const capture = new TransformStream({
1077
603
  transform(chunk, controller) {
@@ -1088,7 +614,6 @@ The request origin "${inputOrigin}" does not match the server origin "${origin}"
1088
614
  pipeError = error;
1089
615
  });
1090
616
  const stream = writable.getWriter();
1091
- const status = requestEv.status();
1092
617
  try {
1093
618
  const isStatic = deps.getRequestMode(requestEv) === "static";
1094
619
  const serverData = deps.getQwikRouterServerData(requestEv);
@@ -1104,16 +629,9 @@ The request origin "${inputOrigin}" does not match the server origin "${origin}"
1104
629
  ...serverData.containerAttributes
1105
630
  }
1106
631
  });
1107
- const qData = {
1108
- loaders: deps.getRequestLoaders(requestEv),
1109
- action: requestEv.sharedMap.get(deps.RequestEvSharedActionId),
1110
- status: status !== 200 ? status : 200,
1111
- href: getPathname(requestEv.url)
1112
- };
1113
632
  if (typeof result.html === "string") {
1114
633
  await stream.write(result.html);
1115
634
  }
1116
- requestEv.sharedMap.set(deps.RequestEvShareQData, qData);
1117
635
  } finally {
1118
636
  await stream.ready;
1119
637
  await stream.close();
@@ -1122,7 +640,7 @@ The request origin "${inputOrigin}" does not match the server origin "${origin}"
1122
640
  if (pipeError) {
1123
641
  throw pipeError;
1124
642
  }
1125
- if (eTagCacheKey && cacheChunks && cacheChunks.length > 0) {
643
+ if (cachePlan && cacheChunks && cacheChunks.length > 0) {
1126
644
  const totalLength = cacheChunks.reduce((sum, chunk) => sum + chunk.length, 0);
1127
645
  const combined = new Uint8Array(totalLength);
1128
646
  let offset = 0;
@@ -1130,86 +648,16 @@ The request origin "${inputOrigin}" does not match the server origin "${origin}"
1130
648
  combined.set(chunk, offset);
1131
649
  offset += chunk.length;
1132
650
  }
1133
- deps.setCachedHtml(eTagCacheKey, new TextDecoder().decode(combined));
651
+ const html = new TextDecoder().decode(combined);
652
+ const cachedETag = cachePlan.eTag || hash(html);
653
+ deps.setCachedSsr(cachePlan.key, {
654
+ eTag: cachedETag,
655
+ body: html
656
+ });
1134
657
  }
1135
658
  await writableStream.close();
1136
659
  };
1137
660
  }
1138
- async function handleQDataRedirect(requestEv) {
1139
- try {
1140
- await requestEv.next();
1141
- } catch (err) {
1142
- if (!(err instanceof deps.RedirectMessage)) {
1143
- throw err;
1144
- }
1145
- }
1146
- if (requestEv.headersSent) {
1147
- return;
1148
- }
1149
- const status = requestEv.status();
1150
- const location = requestEv.headers.get("Location");
1151
- const isRedirect = status >= 301 && status <= 308 && location;
1152
- if (isRedirect) {
1153
- const adaptedLocation = makeQDataPath(location);
1154
- if (adaptedLocation) {
1155
- requestEv.headers.set("Location", adaptedLocation);
1156
- requestEv.getWritableStream().close();
1157
- return;
1158
- } else {
1159
- requestEv.status(200);
1160
- requestEv.headers.delete("Location");
1161
- }
1162
- }
1163
- }
1164
- async function renderQData(requestEv) {
1165
- await requestEv.next();
1166
- if (requestEv.headersSent || requestEv.exited) {
1167
- return;
1168
- }
1169
- const status = requestEv.status();
1170
- const redirectLocation = requestEv.headers.get("Location");
1171
- requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
1172
- let loaders = deps.getRequestLoaders(requestEv);
1173
- const selectedLoaderIds = requestEv.query.getAll(deps.QLOADER_KEY);
1174
- const hasCustomLoaders = selectedLoaderIds.length > 0;
1175
- if (hasCustomLoaders) {
1176
- const selectedLoaders = {};
1177
- for (const loaderId of selectedLoaderIds) {
1178
- const loader = loaders[loaderId];
1179
- selectedLoaders[loaderId] = loader;
1180
- }
1181
- loaders = selectedLoaders;
1182
- }
1183
- const qData = hasCustomLoaders ? {
1184
- loaders,
1185
- status: status !== 200 ? status : 200,
1186
- href: getPathname(requestEv.url)
1187
- } : {
1188
- loaders,
1189
- action: requestEv.sharedMap.get(deps.RequestEvSharedActionId),
1190
- status: status !== 200 ? status : 200,
1191
- href: getPathname(requestEv.url),
1192
- redirect: redirectLocation ?? void 0,
1193
- isRewrite: requestEv.sharedMap.get(deps.RequestEvIsRewrite)
1194
- };
1195
- const writer = requestEv.getWritableStream().getWriter();
1196
- const data = await _serialize(qData);
1197
- writer.write(deps.encoder.encode(data));
1198
- requestEv.sharedMap.set(deps.RequestEvShareQData, qData);
1199
- writer.close();
1200
- }
1201
- function makeQDataPath(href) {
1202
- if (href.startsWith("/")) {
1203
- if (!href.includes(deps.QDATA_JSON)) {
1204
- const url = new URL(href, "http://localhost");
1205
- const pathname = url.pathname.endsWith("/") ? url.pathname.slice(0, -1) : url.pathname;
1206
- return pathname + deps.QDATA_JSON + url.search;
1207
- }
1208
- return href;
1209
- } else {
1210
- return void 0;
1211
- }
1212
- }
1213
661
  function now() {
1214
662
  return typeof performance !== "undefined" ? performance.now() : 0;
1215
663
  }
@@ -1259,24 +707,11 @@ function isContentType(headers, ...types) {
1259
707
  return false;
1260
708
  }
1261
709
 
1262
- class ServerError extends Error {
1263
- status;
1264
- data;
1265
- constructor(status, data) {
1266
- super(typeof data === "string" ? data : void 0), this.status = status, this.data = data;
1267
- }
1268
- }
1269
-
1270
710
  const requestHandlers = createResolveRequestHandlers({
1271
711
  QACTION_KEY,
1272
712
  QFN_KEY,
1273
- QLOADER_KEY,
1274
- QDATA_JSON,
1275
- IsQData,
1276
713
  RequestEvETagCacheKey,
1277
714
  RequestEvHttpStatusMessage,
1278
- RequestEvIsRewrite,
1279
- RequestEvShareQData,
1280
715
  RequestEvShareServerTiming,
1281
716
  RequestEvSharedActionId,
1282
717
  RequestRouteName,
@@ -1285,31 +720,22 @@ const requestHandlers = createResolveRequestHandlers({
1285
720
  HttpStatus,
1286
721
  encoder,
1287
722
  isContentType,
1288
- getCachedHtml,
723
+ defaultSsrCacheKey,
724
+ defaultLoaderCacheKey,
725
+ getCachedSsr,
726
+ getCachedLoader,
1289
727
  getQwikRouterServerData,
1290
- getRequestLoaderSerializationStrategyMap,
1291
- getRequestLoaders,
1292
728
  getRequestMode,
1293
- getRouteLoaderPromise,
1294
729
  loadHttpError: () => import('../../chunks/http-error.qwik.mjs'),
1295
730
  MAX_CACHE_SIZE,
1296
731
  resolveCacheKey,
1297
732
  resolveETag,
1298
733
  resolveRouteConfig,
1299
- setCachedHtml
734
+ setCachedSsr,
735
+ setCachedLoader
1300
736
  });
1301
737
  const { renderQwikMiddleware, resolveRequestHandlers} = requestHandlers;
1302
738
 
1303
- let _asyncRequestStore;
1304
- if (isServer) {
1305
- const AsyncLocalStorage = _getAsyncLocalStorage();
1306
- if (AsyncLocalStorage) {
1307
- _asyncRequestStore = new AsyncLocalStorage();
1308
- } else {
1309
- 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");
1310
- }
1311
- }
1312
-
1313
739
  function createCacheControl(cacheControl) {
1314
740
  const controls = [];
1315
741
  if (cacheControl === "day") {
@@ -1530,6 +956,7 @@ class RewriteMessage extends AbortMessage {
1530
956
 
1531
957
  const requestEventDeps = {
1532
958
  QDATA_KEY,
959
+ QACTION_KEY,
1533
960
  isPromise,
1534
961
  createCacheControl,
1535
962
  Cookie,
@@ -1537,9 +964,12 @@ const requestEventDeps = {
1537
964
  RedirectMessage,
1538
965
  RewriteMessage,
1539
966
  ServerError,
1540
- getRouteLoaderPromise,
1541
- getRouteMatchPathname,
1542
- IsQData,
967
+ recognizeRequest,
968
+ trimRecognizedInternalPathname,
969
+ IsQLoader,
970
+ IsQAction,
971
+ QLoaderId,
972
+ QActionId,
1543
973
  encoder,
1544
974
  getContentType
1545
975
  };
@@ -1590,7 +1020,7 @@ async function runNextWithDeps(requestEv, rebuildRouteInfo, resolve, deps) {
1590
1020
  }
1591
1021
  return e;
1592
1022
  }
1593
- if (!isDev) {
1023
+ if (!isDev$1) {
1594
1024
  try {
1595
1025
  if (!requestEv.headersSent) {
1596
1026
  requestEv.headers.set("content-type", "text/html; charset=utf-8");
@@ -1651,10 +1081,21 @@ async function getConfig() {
1651
1081
  }
1652
1082
  return qwikRouterConfig;
1653
1083
  }
1654
- async function loadRequestHandlers(qwikRouterConfig2, pathname, method, checkOrigin, renderFn, isInternal) {
1084
+ function getRequestHandlerPathname(serverRequestEv) {
1085
+ const recognized = recognizeRequest(serverRequestEv.url.pathname);
1086
+ if (!recognized) {
1087
+ return serverRequestEv.url.pathname;
1088
+ }
1089
+ const loaderPathname = trimRecognizedInternalPathname(serverRequestEv.url.pathname, recognized);
1090
+ if (recognized.type !== IsQLoader) {
1091
+ return loaderPathname;
1092
+ }
1093
+ return resolveValidInternalFullPathname(loaderPathname, serverRequestEv.request.headers.get(FULLPATH_HEADER)) ?? loaderPathname;
1094
+ }
1095
+ async function loadRequestHandlers(qwikRouterConfig2, pathname, method, checkOrigin, renderFn) {
1655
1096
  const { routes, serverPlugins, cacheModules } = qwikRouterConfig2;
1656
- const loadedRoute = await loadRoute(routes, cacheModules, pathname, isInternal);
1657
- const requestHandlers = resolveRequestHandlers(serverPlugins, loadedRoute, method, checkOrigin, renderQwikMiddleware(renderFn), isInternal);
1097
+ const loadedRoute = await loadRoute(routes, cacheModules, pathname);
1098
+ const requestHandlers = resolveRequestHandlers(serverPlugins, loadedRoute, method, checkOrigin, renderQwikMiddleware(renderFn));
1658
1099
  return {
1659
1100
  loadedRoute,
1660
1101
  requestHandlers
@@ -1663,17 +1104,17 @@ async function loadRequestHandlers(qwikRouterConfig2, pathname, method, checkOri
1663
1104
  async function requestHandler(serverRequestEv, opts) {
1664
1105
  const { render, checkOrigin } = opts;
1665
1106
  const config = await getConfig();
1666
- const { pathname, isInternal } = getRouteMatchPathname(serverRequestEv.url.pathname);
1107
+ const pathname = getRequestHandlerPathname(serverRequestEv);
1667
1108
  if (pathname === "/.well-known" || pathname.startsWith("/.well-known/")) {
1668
1109
  return null;
1669
1110
  }
1670
- const { loadedRoute, requestHandlers } = await loadRequestHandlers(config, pathname, serverRequestEv.request.method, checkOrigin ?? true, render, isInternal);
1111
+ const { loadedRoute, requestHandlers } = await loadRequestHandlers(config, pathname, serverRequestEv.request.method, checkOrigin ?? true, render);
1671
1112
  if (config.fallthrough && loadedRoute.$notFound$) {
1672
1113
  return null;
1673
1114
  }
1674
1115
  const rebuildRouteInfo = async (url) => {
1675
- const { pathname: pathname2 } = getRouteMatchPathname(url.pathname);
1676
- return loadRequestHandlers(config, pathname2, serverRequestEv.request.method, checkOrigin ?? true, render, isInternal);
1116
+ const cleanPathname = trimInternalPathname(url.pathname);
1117
+ return loadRequestHandlers(config, cleanPathname, serverRequestEv.request.method, checkOrigin ?? true, render);
1677
1118
  };
1678
1119
  return runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, config.basePathname);
1679
1120
  }
@@ -1708,12 +1149,10 @@ function isStaticPath(method, url) {
1708
1149
  if (staticPaths.has(p)) {
1709
1150
  return true;
1710
1151
  }
1711
- if (p.endsWith("/q-data.json")) {
1712
- const pWithoutQdata = p.replace(/\/q-data.json$/, "");
1713
- if (staticPaths.has(pWithoutQdata + "/")) {
1714
- return true;
1715
- }
1716
- if (staticPaths.has(pWithoutQdata)) {
1152
+ const loaderMatch = p.match(LOADER_REGEX);
1153
+ if (loaderMatch) {
1154
+ const pWithoutLoader = p.slice(0, p.length - loaderMatch[0].length);
1155
+ if (staticPaths.has(pWithoutLoader + "/") || staticPaths.has(pWithoutLoader)) {
1717
1156
  return true;
1718
1157
  }
1719
1158
  }
@@ -1777,4 +1216,4 @@ class _TextEncoderStream_polyfill {
1777
1216
  }
1778
1217
  }
1779
1218
 
1780
- export { AbortMessage, RedirectMessage, RequestEvShareQData, RewriteMessage, ServerError, _TextEncoderStream_polyfill, _asyncRequestStore, clearSsrCache, getErrorHtml, getNotFound, isStaticPath, mergeHeadersCookies, requestHandler };
1219
+ export { AbortMessage, RedirectMessage, RewriteMessage, ServerError, _TextEncoderStream_polyfill, _asyncRequestStore, getErrorHtml, getNotFound, isStaticPath, mergeHeadersCookies, requestHandler };