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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/adapters/static/vite.d.ts +1 -1
  2. package/lib/adapters/azure-swa/vite/index.d.ts +2 -2
  3. package/lib/adapters/azure-swa/vite/index.mjs +44 -58
  4. package/lib/adapters/bun-server/vite/index.d.ts +2 -2
  5. package/lib/adapters/bun-server/vite/index.mjs +16 -23
  6. package/lib/adapters/cloud-run/vite/index.d.ts +2 -2
  7. package/lib/adapters/cloud-run/vite/index.mjs +15 -20
  8. package/lib/adapters/cloudflare-pages/vite/index.d.ts +2 -2
  9. package/lib/adapters/cloudflare-pages/vite/index.mjs +45 -77
  10. package/lib/adapters/deno-server/vite/index.d.ts +2 -2
  11. package/lib/adapters/deno-server/vite/index.mjs +25 -35
  12. package/lib/adapters/netlify-edge/vite/index.d.ts +2 -2
  13. package/lib/adapters/netlify-edge/vite/index.mjs +49 -89
  14. package/lib/adapters/node-server/vite/index.d.ts +2 -2
  15. package/lib/adapters/node-server/vite/index.mjs +16 -23
  16. package/lib/adapters/shared/vite/index.d.ts +9 -22
  17. package/lib/adapters/shared/vite/index.mjs +280 -333
  18. package/lib/adapters/ssg/vite/index.d.ts +13 -0
  19. package/lib/adapters/ssg/vite/index.mjs +13 -0
  20. package/lib/adapters/vercel-edge/vite/index.d.ts +3 -3
  21. package/lib/adapters/vercel-edge/vite/index.mjs +73 -80
  22. package/lib/chunks/dev-preloaded-route-loader.mjs +2 -0
  23. package/lib/chunks/format.mjs +24 -0
  24. package/lib/chunks/fs.mjs +140 -0
  25. package/lib/chunks/head.qwik.mjs +1202 -0
  26. package/lib/chunks/http-error.qwik.mjs +27 -0
  27. package/lib/chunks/pathname.mjs +57 -0
  28. package/lib/chunks/request-body-limit.mjs +27 -0
  29. package/lib/chunks/request-path.mjs +49 -0
  30. package/lib/chunks/routes.mjs +26 -0
  31. package/lib/chunks/server-error.mjs +16 -0
  32. package/lib/chunks/system.mjs +265 -0
  33. package/lib/chunks/url.mjs +59 -0
  34. package/lib/chunks/user-response.mjs +1730 -0
  35. package/lib/chunks/worker-thread.mjs +264 -0
  36. package/lib/index.d.ts +631 -174
  37. package/lib/index.qwik.mjs +1656 -1964
  38. package/lib/middleware/aws-lambda/index.d.ts +15 -16
  39. package/lib/middleware/aws-lambda/index.mjs +45 -54
  40. package/lib/middleware/azure-swa/index.mjs +85 -295
  41. package/lib/middleware/bun/index.d.ts +20 -5
  42. package/lib/middleware/bun/index.mjs +119 -205
  43. package/lib/middleware/cloudflare-pages/index.mjs +88 -105
  44. package/lib/middleware/deno/index.d.ts +22 -5
  45. package/lib/middleware/deno/index.mjs +105 -192
  46. package/lib/middleware/firebase/index.mjs +22 -35
  47. package/lib/middleware/netlify-edge/index.mjs +63 -81
  48. package/lib/middleware/node/index.d.ts +17 -5
  49. package/lib/middleware/node/index.mjs +299 -273
  50. package/lib/middleware/request-handler/index.d.ts +206 -99
  51. package/lib/middleware/request-handler/index.mjs +105 -1648
  52. package/lib/middleware/vercel-edge/index.mjs +76 -101
  53. package/lib/modules.d.ts +11 -16
  54. package/lib/service-worker/index.mjs +13 -0
  55. package/lib/{static → ssg}/index.d.ts +46 -22
  56. package/lib/ssg/index.mjs +257 -0
  57. package/lib/vite/index.d.ts +58 -10
  58. package/lib/vite/index.mjs +2471 -27446
  59. package/modules.d.ts +11 -16
  60. package/package.json +62 -70
  61. package/ssg.d.ts +2 -0
  62. package/static.d.ts +1 -1
  63. package/lib/adapters/azure-swa/vite/index.cjs +0 -96
  64. package/lib/adapters/bun-server/vite/index.cjs +0 -50
  65. package/lib/adapters/cloud-run/vite/index.cjs +0 -47
  66. package/lib/adapters/cloudflare-pages/vite/index.cjs +0 -115
  67. package/lib/adapters/deno-server/vite/index.cjs +0 -62
  68. package/lib/adapters/netlify-edge/vite/index.cjs +0 -129
  69. package/lib/adapters/node-server/vite/index.cjs +0 -50
  70. package/lib/adapters/shared/vite/index.cjs +0 -378
  71. package/lib/adapters/static/vite/index.cjs +0 -368
  72. package/lib/adapters/static/vite/index.d.ts +0 -10
  73. package/lib/adapters/static/vite/index.mjs +0 -331
  74. package/lib/adapters/vercel-edge/vite/index.cjs +0 -118
  75. package/lib/index.qwik.cjs +0 -2022
  76. package/lib/middleware/node/index.cjs +0 -314
  77. package/lib/middleware/request-handler/index.cjs +0 -1691
  78. package/lib/service-worker.cjs +0 -17
  79. package/lib/service-worker.mjs +0 -15
  80. package/lib/static/deno.mjs +0 -8
  81. package/lib/static/index.cjs +0 -67
  82. package/lib/static/index.mjs +0 -48
  83. package/lib/static/node.cjs +0 -1126
  84. package/lib/static/node.mjs +0 -1088
  85. package/lib/vite/index.cjs +0 -27525
  86. package/middleware/request-handler/generated/not-found-paths.ts +0 -7
  87. package/middleware/request-handler/generated/static-paths.ts +0 -35
@@ -0,0 +1,1202 @@
1
+ import { t as ensureSlash } from "./pathname.mjs";
2
+ import { o as getLoaderName } from "./request-path.mjs";
3
+ import { i as RedirectMessage, n as throwIfControlFlowSignal, t as ServerError } from "./server-error.mjs";
4
+ import { _captures, createComputedQrl, createContextId, implicit$FirstArg, inlinedQrl, isDev, isServer, withLocale } from "@qwik.dev/core";
5
+ import * as qwikRouterConfig from "@qwik-router-config";
6
+ import { SerializerSymbol, _UNINITIALIZED, _deserialize, _getAsyncLocalStorage, _getContextEvent, _injectAsyncSignalValue, _markSignalAsExternallyOwned, _resolveContextWithoutSequentialScope, _verifySerializable } from "@qwik.dev/core/internal";
7
+ import { isServer as isServer$1 } from "@qwik.dev/core/build";
8
+ /** @internal */ var _asyncRequestStore;
9
+ if (isServer$1) {
10
+ const AsyncLocalStorage = _getAsyncLocalStorage();
11
+ if (AsyncLocalStorage) _asyncRequestStore = new AsyncLocalStorage();
12
+ else 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");
13
+ }
14
+ var QACTION_KEY = "qaction";
15
+ var QFN_KEY = "qfunc";
16
+ var QDATA_KEY = "qdata";
17
+ /** @public */ var Q_ROUTE = "q:route";
18
+ var DEFAULT_LOADERS_SERIALIZATION_STRATEGY = globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__ || "never";
19
+ var RouteStateContext = /*#__PURE__*/ createContextId("qr-s");
20
+ var RouteLoaderCtxContext = /*#__PURE__*/ createContextId("qr-lc");
21
+ var ContentContext = /*#__PURE__*/ createContextId("qr-c");
22
+ var ContentInternalContext = /*#__PURE__*/ createContextId("qr-ic");
23
+ var DocumentHeadContext = /*#__PURE__*/ createContextId("qr-h");
24
+ var RouteLocationContext = /*#__PURE__*/ createContextId("qr-l");
25
+ var RouteNavigateContext = /*#__PURE__*/ createContextId("qr-n");
26
+ var RouteActionContext = /*#__PURE__*/ createContextId("qr-a");
27
+ var RoutePreventNavigateContext = /*#__PURE__*/ createContextId("qr-p");
28
+ var HttpStatusContext = /*#__PURE__*/ createContextId("qr-hs");
29
+ /**
30
+ * Route loaders read data before the route rendering starts, based on the route being navigated to.
31
+ * They automatically update when the route changes on the client.
32
+ *
33
+ * They are represented by a ComputedSignal.
34
+ */ var REQUEST_ROUTE_LOADER_STATE = "@routeLoaderState";
35
+ var REQUEST_LOADER_PATHS_STORE = "@loaderPathsStore";
36
+ var REQUEST_ROUTE_LOADERS = "@routeLoaders";
37
+ var REQUEST_ROUTE_LOADER_PROMISES = "@routeLoaderPromises";
38
+ var REQUEST_ROUTE_LOADER_EVENTS = "@routeLoaderEvents";
39
+ var REQUEST_ROUTE_LOADER_ROOT_EVENT = "@routeLoaderRootEvent";
40
+ var ROUTE_LOADER_VALUE_PREFIX = "__qwik_route_loader_value__";
41
+ /** Header name sent by client to tell the server the actual page URL for loader requests. */ var FULLPATH_HEADER = "X-Qwik-fullpath";
42
+ /** Dev route hint that preserves the loader URL. */ var ROUTE_PATH_HEADER = "X-Qwik-route-path";
43
+ /**
44
+ * Per-navigation fetch dedupe: shares in-flight and completed fetches (hover prefetch → click nav)
45
+ * and prevents repeat hover fetches. Cleared after each navigation kicks off its loader fetches;
46
+ * across navigations the browser HTTP cache is the freshness authority.
47
+ */ var navFetchCache = /* @__PURE__ */ new Map();
48
+ var clearNavFetchCache = () => navFetchCache.clear();
49
+ var isRedirectStatus = (status) => status >= 300 && status < 400;
50
+ /** We don't have aborts when preloading so we just pretend we do */ var wrapWithAbort = (promise, signal) => {
51
+ if (signal.aborted) return Promise.reject(signal.reason);
52
+ return new Promise((resolve, reject) => {
53
+ const abort = () => reject(signal.reason);
54
+ signal.addEventListener("abort", abort, { once: true });
55
+ promise.finally(() => signal.removeEventListener("abort", abort)).then(resolve, reject);
56
+ });
57
+ };
58
+ var getRouteLoaderValueStateKey = (loaderId) => `${ROUTE_LOADER_VALUE_PREFIX}${loaderId}`;
59
+ var isRequestEvent = (value) => !!value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, "sharedMap") && Object.prototype.hasOwnProperty.call(value, "cookie");
60
+ var isLoaderInternal = (value) => typeof value === "function" && value.__brand === "server_loader";
61
+ /**
62
+ * Fetch a single loader's raw JSON response from the server.
63
+ *
64
+ * URL pattern: `{basePath}{routePath}/q-loader-{loaderId}.{manifestHash}.json`
65
+ */ var fetchRouteLoaderData = async (loaderId, routePath, manifestHash, opts) => {
66
+ if (!routePath) return;
67
+ let resolvedPath = routePath;
68
+ const basePath = opts?.basePath ?? "/";
69
+ if (basePath !== "/" && !resolvedPath.startsWith(basePath)) resolvedPath = basePath + resolvedPath.slice(1);
70
+ const pathBase = ensureSlash(resolvedPath);
71
+ const pageUrl = opts?.pageUrl;
72
+ const search = pageUrl?.search ?? "";
73
+ const url = `${pathBase}${getLoaderName(loaderId, manifestHash)}${search}`;
74
+ const headers = {};
75
+ if (pageUrl && pageUrl.pathname !== pathBase) {
76
+ if (!globalThis.__STRICT_LOADERS__) headers[FULLPATH_HEADER] = pageUrl.pathname;
77
+ else if (isDev) headers[ROUTE_PATH_HEADER] = pageUrl.pathname;
78
+ }
79
+ const cacheKey = `${url}\n${headers["X-Qwik-fullpath"] ?? ""}`;
80
+ if (!opts?.ignoreCache) {
81
+ const entry = navFetchCache.get(cacheKey);
82
+ if (entry) return opts?.signal ? wrapWithAbort(entry, opts.signal) : entry;
83
+ }
84
+ const request = async () => {
85
+ const response = await fetch(url, {
86
+ signal: opts?.signal,
87
+ cache: opts?.ignoreCache ? "reload" : "default",
88
+ headers
89
+ });
90
+ if (response.redirected) return { r: response.url };
91
+ if (isRedirectStatus(response.status)) {
92
+ const location1 = response.headers.get("Location");
93
+ if (location1) return { r: location1 };
94
+ }
95
+ if (!response.ok) return;
96
+ return { raw: await response.text() };
97
+ };
98
+ if (opts?.ignoreCache) return request();
99
+ if (opts?.signal) return request().then((value) => {
100
+ if (value !== void 0 && !navFetchCache.has(cacheKey)) navFetchCache.set(cacheKey, Promise.resolve(value));
101
+ return value;
102
+ });
103
+ const promise = request().then((value) => {
104
+ if (value === void 0) navFetchCache.delete(cacheKey);
105
+ return value;
106
+ }, (err) => {
107
+ navFetchCache.delete(cacheKey);
108
+ throw err;
109
+ });
110
+ navFetchCache.set(cacheKey, promise);
111
+ return promise;
112
+ };
113
+ /** Build a sorted, stable search string from only the allowed param names. */ var filterSearchParams = (params, allowed) => {
114
+ const filtered = new URLSearchParams();
115
+ for (let i = 0; i < allowed.length; i++) {
116
+ const name = allowed[i];
117
+ const values = params.getAll(name);
118
+ for (let j = 0; j < values.length; j++) filtered.append(name, values[j]);
119
+ }
120
+ filtered.sort();
121
+ return filtered.toString() ? `?${filtered.toString()}` : "";
122
+ };
123
+ var getLoaderOptions = (rest) => {
124
+ let id;
125
+ let serializationStrategy = DEFAULT_LOADERS_SERIALIZATION_STRATEGY;
126
+ let cacheControl;
127
+ let eTag;
128
+ let cacheKey;
129
+ let search;
130
+ let blockSSR = true;
131
+ const validators = [];
132
+ if (rest.length === 1) {
133
+ const options = rest[0];
134
+ if (options && typeof options === "object") {
135
+ if ("validate" in options) validators.push(options);
136
+ else {
137
+ if (options.id) id = options.id;
138
+ if (options.serializationStrategy) serializationStrategy = options.serializationStrategy;
139
+ if (options.validation) validators.push(...options.validation);
140
+ if ("cacheControl" in options) cacheControl = options.cacheControl;
141
+ if ("eTag" in options) eTag = options.eTag;
142
+ if ("cacheKey" in options) cacheKey = options.cacheKey;
143
+ if (options.search) search = options.search;
144
+ else if (globalThis.__STRICT_LOADERS__) search = [];
145
+ if (options.blockSSR === false) {
146
+ if (!__EXPERIMENTAL__.blockSSR) throw new Error("`blockSSR: false` is an experimental feature and is not enabled. Please enable the feature flag by adding `experimental: [\"blockSSR\"]` to your qwikVite plugin options.");
147
+ blockSSR = false;
148
+ }
149
+ }
150
+ }
151
+ } else if (rest.length > 1) validators.push(...rest.filter(Boolean));
152
+ return {
153
+ id,
154
+ validators: validators.reverse(),
155
+ serializationStrategy,
156
+ cacheControl,
157
+ eTag,
158
+ cacheKey,
159
+ search,
160
+ blockSSR
161
+ };
162
+ };
163
+ /**
164
+ * Returns the current RequestEvent if possible. Only usable on the server, and only during request
165
+ * processing.
166
+ *
167
+ * @public
168
+ */ var getRequestEvent = (thisArg) => {
169
+ if (!isServer) throw new Error("getRequestEvent() can only be used on the server.");
170
+ return _asyncRequestStore?.getStore() || [thisArg, _getContextEvent()].find(isRequestEvent);
171
+ };
172
+ var REQUEST_ROUTE_LOADER_VALUES = "@routeLoaderValues";
173
+ /** Get/create the record of pre-loaded loader values (used by middleware before component). */ function getRouteLoaderValues(requestEv) {
174
+ let values = requestEv.sharedMap.get(REQUEST_ROUTE_LOADER_VALUES);
175
+ if (!values) {
176
+ values = {};
177
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADER_VALUES, values);
178
+ }
179
+ return values;
180
+ }
181
+ function getRouteLoaderPromises(requestEv) {
182
+ let promises = requestEv.sharedMap.get(REQUEST_ROUTE_LOADER_PROMISES);
183
+ if (!promises) {
184
+ promises = {};
185
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADER_PROMISES, promises);
186
+ }
187
+ return promises;
188
+ }
189
+ /** Clear loader state before rendering a route-independent error boundary. */ function clearRouteLoaderData(requestEv) {
190
+ requestEv.sharedMap.delete(REQUEST_ROUTE_LOADER_STATE);
191
+ requestEv.sharedMap.delete(REQUEST_ROUTE_LOADER_VALUES);
192
+ requestEv.sharedMap.delete(REQUEST_ROUTE_LOADER_PROMISES);
193
+ requestEv.sharedMap.delete(REQUEST_ROUTE_LOADER_EVENTS);
194
+ requestEv.sharedMap.delete(REQUEST_ROUTE_LOADER_ROOT_EVENT);
195
+ requestEv.sharedMap.delete(REQUEST_ROUTE_LOADERS);
196
+ }
197
+ /** Store the route loader internals on the request for SSG to read. */ function setRouteLoaders(requestEv, loaders) {
198
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADERS, loaders);
199
+ }
200
+ /** Get the route loader internals stored on the request. */ function getRouteLoaders(requestEv) {
201
+ return requestEv.sharedMap.get(REQUEST_ROUTE_LOADERS) ?? [];
202
+ }
203
+ function getRouteLoaderCtx(requestEv) {
204
+ let ctx = requestEv.sharedMap.get(REQUEST_LOADER_PATHS_STORE);
205
+ if (!ctx) {
206
+ ctx = { loaderPaths: {} };
207
+ requestEv.sharedMap.set(REQUEST_LOADER_PATHS_STORE, ctx);
208
+ }
209
+ return ctx;
210
+ }
211
+ /** Update route loader matching state on navigation. */ var updateRouteLoaderPaths = (ctx, loaderPaths, pageUrl) => {
212
+ if (!isServer) {
213
+ ctx.pagePathname = pageUrl.pathname;
214
+ ctx.pageSearch = pageUrl.search;
215
+ ctx.routeLoaderCandidates = loaderPaths;
216
+ } else if (loaderPaths) for (const key in loaderPaths) ctx.loaderPaths[key] = loaderPaths[key];
217
+ };
218
+ var getModuleRouteLoaders = (mods) => {
219
+ const routeLoaders = [];
220
+ const seen = /* @__PURE__ */ new Map();
221
+ for (let i = 0; i < mods.length; i++) {
222
+ const mod = mods[i];
223
+ if (!mod) continue;
224
+ for (const key in mod) {
225
+ const value = mod[key];
226
+ if (isLoaderInternal(value)) {
227
+ const existing = seen.get(value.__id);
228
+ if (existing) {
229
+ if (isDev && existing !== value) console.warn(`Two route loaders share the same id "${value.__id}". Only the first will run; the others are ignored. If they are created by a shared wrapper around routeLoader$, give each loader a distinct \`id\` option.`);
230
+ continue;
231
+ }
232
+ seen.set(value.__id, value);
233
+ routeLoaders.push(value);
234
+ }
235
+ }
236
+ }
237
+ return routeLoaders;
238
+ };
239
+ /**
240
+ * Loader ids declared `cacheControl: 'immutable'`. Their data cannot change until a rebuild, so
241
+ * nav-wide invalidation skips them; they still re-fetch when their tracked URL inputs change.
242
+ * Registered on every nav via ensureRouteLoaderSignal, so resumed signals are covered too.
243
+ */ var immutableLoaderIds = /* @__PURE__ */ new Set();
244
+ var isImmutableLoader = (loaderId) => immutableLoaderIds.has(loaderId);
245
+ /**
246
+ * Invalidate every loader signal on navigation: the browser HTTP cache (driven by each loader's
247
+ * cacheControl) decides freshness. Unsubscribed signals only mark stale and refetch lazily when
248
+ * read again. Immutable loaders are skipped — their data cannot change until a rebuild; tracked URL
249
+ * inputs still invalidate them.
250
+ */ var invalidateNavRouteLoaders = (state) => {
251
+ for (const id in state) if (!id.startsWith(ROUTE_LOADER_VALUE_PREFIX) && !immutableLoaderIds.has(id)) state[id].invalidate();
252
+ };
253
+ var applyClientRouteLoaderPath = (loaderId, ctx) => {
254
+ const currentPath = ctx.routeLoaderCandidates?.[loaderId];
255
+ if (currentPath) ctx.loaderPaths[loaderId] = currentPath;
256
+ else if (isDev && ctx.pagePathname) ctx.loaderPaths[loaderId] = ctx.pagePathname;
257
+ };
258
+ /**
259
+ * Inject a pre-loaded value into a ComputedSignal while preserving subscriptions. Delegates to the
260
+ * core helper which calls `invalidate({__v})` + `$computeIfNeeded$()` so the compute function runs
261
+ * synchronously and returns the pre-loaded value without fetching. Must go through the core helper
262
+ * because `$computeIfNeeded$` is mangled in core builds and not directly callable from this
263
+ * package.
264
+ */ var setLoaderSignalValue = (signal, value) => {
265
+ _injectAsyncSignalValue(signal, value);
266
+ };
267
+ var matchesRouteLoaderId = (loader, loaderId) => {
268
+ return typeof loaderId === "string" && (loader.__id === loaderId || isDev && loader.__qrl.getHash() === loaderId);
269
+ };
270
+ var resolveRouteLoaderByHash = (routeLoaders, loaderId) => {
271
+ return routeLoaders.find((loader) => matchesRouteLoaderId(loader, loaderId));
272
+ };
273
+ /** @internal */ var getLoaderRequestEvent = (loader, requestEv) => {
274
+ let rootRequestEv = requestEv.sharedMap.get(REQUEST_ROUTE_LOADER_ROOT_EVENT);
275
+ if (!rootRequestEv) {
276
+ rootRequestEv = requestEv;
277
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADER_ROOT_EVENT, rootRequestEv);
278
+ }
279
+ const url = new URL(rootRequestEv.url);
280
+ const pathname = globalThis.__STRICT_LOADERS__ ? getRouteLoaderCtx(rootRequestEv).loaderPaths[loader.__id] || rootRequestEv.url.pathname : rootRequestEv.url.pathname;
281
+ const filteredSearch = loader.__search ? filterSearchParams(url.searchParams, loader.__search) : rootRequestEv.url.search;
282
+ if (pathname === rootRequestEv.url.pathname && filteredSearch === rootRequestEv.url.search) return rootRequestEv;
283
+ let events = rootRequestEv.sharedMap.get(REQUEST_ROUTE_LOADER_EVENTS);
284
+ if (!events) {
285
+ events = /* @__PURE__ */ new Map();
286
+ rootRequestEv.sharedMap.set(REQUEST_ROUTE_LOADER_EVENTS, events);
287
+ }
288
+ const eventKey = `${pathname}\n${filteredSearch}`;
289
+ let loaderRequestEv = events.get(eventKey);
290
+ if (!loaderRequestEv) {
291
+ url.pathname = pathname;
292
+ url.search = filteredSearch;
293
+ const request = new Request(url, rootRequestEv.request);
294
+ loaderRequestEv = Object.create(rootRequestEv, {
295
+ originalUrl: {
296
+ value: new URL(url),
297
+ enumerable: true
298
+ },
299
+ params: {
300
+ value: rootRequestEv.params,
301
+ enumerable: true
302
+ },
303
+ pathname: {
304
+ get: () => url.pathname,
305
+ enumerable: true
306
+ },
307
+ query: {
308
+ get: () => url.searchParams,
309
+ enumerable: true
310
+ },
311
+ request: {
312
+ value: request,
313
+ enumerable: true
314
+ },
315
+ url: {
316
+ value: url,
317
+ enumerable: true
318
+ }
319
+ });
320
+ events.set(eventKey, loaderRequestEv);
321
+ }
322
+ return loaderRequestEv;
323
+ };
324
+ /**
325
+ * View of a request event whose response controls (status/headers/redirect/error/fail/cacheControl)
326
+ * are captured locally, so a background (`blockSSR: false`) loader's status/redirect/error surfaces
327
+ * on its own signal instead of mutating the page response. The originals also call `check()`, which
328
+ * throws once SSR streaming has started — a background loader must fail on its signal, not crash.
329
+ */ var detachResponseFromEvent = (requestEv) => {
330
+ let status = 200;
331
+ const headers = new Headers();
332
+ return Object.create(requestEv, {
333
+ headers: {
334
+ value: headers,
335
+ enumerable: true
336
+ },
337
+ status: {
338
+ value: (statusCode) => {
339
+ if (typeof statusCode === "number") status = statusCode;
340
+ return status;
341
+ },
342
+ enumerable: true
343
+ },
344
+ error: {
345
+ value: (statusCode, message) => {
346
+ status = statusCode;
347
+ return new ServerError(statusCode, message);
348
+ },
349
+ enumerable: true
350
+ },
351
+ redirect: {
352
+ value: (statusCode, url) => {
353
+ status = statusCode;
354
+ if (url) headers.set("Location", url);
355
+ return new RedirectMessage();
356
+ },
357
+ enumerable: true
358
+ },
359
+ fail: {
360
+ value: (statusCode, data) => {
361
+ status = statusCode;
362
+ return {
363
+ failed: true,
364
+ ...data
365
+ };
366
+ },
367
+ enumerable: true
368
+ },
369
+ cacheControl: {
370
+ value: () => {},
371
+ enumerable: true
372
+ }
373
+ });
374
+ };
375
+ async function runValidators(requestEv, validators, data) {
376
+ let lastResult = {
377
+ success: true,
378
+ data
379
+ };
380
+ if (validators) for (let i = 0; i < validators.length; i++) {
381
+ lastResult = await validators[i].validate(requestEv, data);
382
+ if (!lastResult.success) return lastResult;
383
+ data = lastResult.data;
384
+ }
385
+ return lastResult;
386
+ }
387
+ function verifySerializable(data, qrl) {
388
+ try {
389
+ _verifySerializable(data, void 0);
390
+ } catch (error) {
391
+ if (error instanceof Error && qrl.dev) error.loc = qrl.dev;
392
+ throw error;
393
+ }
394
+ }
395
+ /** Run a loader and return its raw value. Errors/redirects propagate as exceptions. */ var getRouteLoaderData = async (loaderQrl, validators, requestEv) => {
396
+ const loaderRequestEv = requestEv;
397
+ const result = await runValidators(requestEv, validators, void 0);
398
+ if (!result.success) return loaderRequestEv.fail(result.status ?? 500, result.error);
399
+ const resolved = await loaderQrl.call(loaderRequestEv, loaderRequestEv);
400
+ const value = typeof resolved === "function" ? resolved() : resolved;
401
+ throwIfControlFlowSignal(value);
402
+ if (isDev) verifySerializable(value, loaderQrl);
403
+ return value;
404
+ };
405
+ var loadRouteLoaderByQrl = (loaderId, loaderQrl, validators, requestEv) => {
406
+ const values = getRouteLoaderValues(requestEv);
407
+ if (loaderId in values) return Promise.resolve(values[loaderId]);
408
+ const promises = getRouteLoaderPromises(requestEv);
409
+ let promise = promises[loaderId];
410
+ if (!promise) {
411
+ promise = getRouteLoaderData(loaderQrl, validators, requestEv).then((value) => {
412
+ values[loaderId] = value;
413
+ return value;
414
+ }, (err) => {
415
+ delete promises[loaderId];
416
+ throw err;
417
+ });
418
+ promises[loaderId] = promise;
419
+ }
420
+ return promise;
421
+ };
422
+ var ServerRouteLoaderCapture = class {
423
+ hash;
424
+ qrl;
425
+ validators;
426
+ blockSSR;
427
+ constructor(hash, qrl, validators, blockSSR) {
428
+ this.hash = hash;
429
+ this.qrl = qrl;
430
+ this.validators = validators;
431
+ this.blockSSR = blockSSR;
432
+ }
433
+ load() {
434
+ const requestEv = getRequestEvent();
435
+ if (!requestEv) throw new Error("Unable to determine the current RequestEvent.");
436
+ const values = getRouteLoaderValues(requestEv);
437
+ if (this.hash in values) return values[this.hash];
438
+ const ev = this.blockSSR ? requestEv : detachResponseFromEvent(requestEv);
439
+ return loadRouteLoaderByQrl(this.hash, this.qrl, this.validators, ev);
440
+ }
441
+ [SerializerSymbol]() {
442
+ return this.hash;
443
+ }
444
+ };
445
+ var createRouteLoaderSignal = (loader, routeLoaderCtx, state) => {
446
+ const id = loader.__id;
447
+ const stateValues = state;
448
+ const resumeValueKey = getRouteLoaderValueStateKey(id);
449
+ const capture = isServer ? new ServerRouteLoaderCapture(id, loader.__qrl, loader.__validators, loader.__blockSSR) : id;
450
+ const searchFilter = loader.__search;
451
+ const signal = createComputedQrl(/*#__PURE__*/ inlinedQrl(async (ctx) => {
452
+ const capture = _captures[0], id = _captures[1], lastFetch = _captures[2], resumeValueKey = _captures[3], routeLoaderCtx = _captures[4], searchFilter = _captures[5], stateValues = _captures[6];
453
+ const hasInjectedValue = !!ctx.info && typeof ctx.info === "object" && "__v" in ctx.info;
454
+ const trackedRoutePath = ctx.track(routeLoaderCtx.loaderPaths, id);
455
+ const trackedPagePathname = ctx.track(routeLoaderCtx, "pagePathname");
456
+ const trackedPageSearch = ctx.track(routeLoaderCtx, "pageSearch");
457
+ if (hasInjectedValue) {
458
+ const value = ctx.info.__v;
459
+ if (!isServer && resumeValueKey in stateValues) stateValues[resumeValueKey] = value;
460
+ lastFetch.raw = void 0;
461
+ return value;
462
+ }
463
+ if (isServer) return capture.load();
464
+ const pagePathname = trackedPagePathname || location.pathname;
465
+ const pageSearch = trackedPageSearch || location.search;
466
+ const pageUrl = new URL(pagePathname + pageSearch, location.href);
467
+ const mHash = routeLoaderCtx.manifestHash || "dev";
468
+ const basePath = qwikRouterConfig.basePathname ?? "/";
469
+ const needsResumeFetch = stateValues[resumeValueKey] === _UNINITIALIZED;
470
+ const fetchRoutePath = trackedRoutePath || (needsResumeFetch ? pageUrl.pathname : void 0);
471
+ if (!fetchRoutePath) return ctx.previous;
472
+ let fetchUrl = pageUrl;
473
+ if (searchFilter) {
474
+ fetchUrl = new URL(pageUrl.href);
475
+ fetchUrl.search = filterSearchParams(pageUrl.searchParams, searchFilter);
476
+ }
477
+ const result = await fetchRouteLoaderData(id, fetchRoutePath, mHash, {
478
+ pageUrl: fetchUrl,
479
+ basePath,
480
+ ignoreCache: ctx.info === true,
481
+ signal: ctx.abortSignal
482
+ });
483
+ if (!result) throw new Error(`Loader ${id} returned empty response`);
484
+ let response;
485
+ if (result.raw === void 0) response = result;
486
+ else {
487
+ if (result.raw === lastFetch.raw && ctx.previous !== void 0) return ctx.previous;
488
+ response = await _deserialize(result.raw);
489
+ if (!response) throw new Error(`Loader ${id} returned empty response`);
490
+ }
491
+ if (response.r) {
492
+ const goto = routeLoaderCtx.goto;
493
+ if (goto) goto(response.r, { replaceState: true });
494
+ else location.href = response.r;
495
+ return ctx.previous;
496
+ }
497
+ if (response.e) throw response.e;
498
+ lastFetch.raw = result.raw;
499
+ if (needsResumeFetch) stateValues[resumeValueKey] = response.d;
500
+ return response.d;
501
+ }, "createRouteLoaderSignal_signal_createComputed_4s4ZDCYhDOA", [
502
+ capture,
503
+ id,
504
+ {},
505
+ resumeValueKey,
506
+ routeLoaderCtx,
507
+ searchFilter,
508
+ stateValues
509
+ ]), { serializationStrategy: loader.__serializationStrategy });
510
+ _markSignalAsExternallyOwned(signal);
511
+ return signal;
512
+ };
513
+ var ensureRouteLoaderSignal = (loader, state, routeLoaderCtx) => {
514
+ if (!isServer && routeLoaderCtx.pagePathname) applyClientRouteLoaderPath(loader.__id, routeLoaderCtx);
515
+ if (loader.__cacheControl === "immutable") immutableLoaderIds.add(loader.__id);
516
+ if (isServer && loader.__serializationStrategy === "never") state[getRouteLoaderValueStateKey(loader.__id)] = _UNINITIALIZED;
517
+ return state[loader.__id] ||= createRouteLoaderSignal(loader, routeLoaderCtx, state);
518
+ };
519
+ var ensureRouteLoaderSignals = (mods, state, routeLoaderCtx) => {
520
+ const loaders = getModuleRouteLoaders(mods);
521
+ for (let i = 0; i < loaders.length; i++) ensureRouteLoaderSignal(loaders[i], state, routeLoaderCtx);
522
+ return loaders;
523
+ };
524
+ var loadRouteLoader = (loader, requestEv) => {
525
+ const loaderEv = getLoaderRequestEvent(loader, requestEv);
526
+ return loadRouteLoaderByQrl(loader.__id, loader.__qrl, loader.__validators, loader.__blockSSR ? loaderEv : detachResponseFromEvent(loaderEv));
527
+ };
528
+ /** Run a loader and wrap the result in a LoaderResponse envelope. Catches redirects/errors. */ var getRouteLoaderResponse = async (loaderQrl, validators, requestEv) => {
529
+ try {
530
+ return { d: await getRouteLoaderData(loaderQrl, validators, requestEv) };
531
+ } catch (err) {
532
+ if (err instanceof RedirectMessage) {
533
+ const location1 = requestEv.headers.get("Location") || "/";
534
+ requestEv.headers.delete("Location");
535
+ return { r: location1 };
536
+ }
537
+ if (err instanceof ServerError) return { e: err };
538
+ throw err;
539
+ }
540
+ };
541
+ /** @internal */ var routeLoaderQrl = (loaderQrl, ...rest) => {
542
+ const { id, validators, serializationStrategy, cacheControl, eTag, cacheKey, search, blockSSR } = getLoaderOptions(rest);
543
+ function loader() {
544
+ const signal = ensureRouteLoaderSignal(loader, _resolveContextWithoutSequentialScope(RouteStateContext), _resolveContextWithoutSequentialScope(RouteLoaderCtxContext));
545
+ signal.promise();
546
+ return signal;
547
+ }
548
+ loader.__brand = "server_loader";
549
+ loader.__qrl = loaderQrl;
550
+ loader.__validators = validators;
551
+ loader.__id = id ?? loaderQrl.getHash();
552
+ loader.__serializationStrategy = serializationStrategy;
553
+ loader.__cacheControl = cacheControl;
554
+ loader.__eTag = eTag;
555
+ loader.__cacheKey = cacheKey;
556
+ loader.__search = search;
557
+ loader.__blockSSR = blockSSR;
558
+ Object.freeze(loader);
559
+ return loader;
560
+ };
561
+ /**
562
+ * Define a route loader that fetches data before the route renders.
563
+ *
564
+ * Route loaders run on the server during SSR and return data as a `ComputedSignal`. On the client,
565
+ * loaders automatically re-fetch when the route changes (SPA navigation). Each loader gets its own
566
+ * JSON endpoint (`q-loader-{id}.{hash}.json`), so only the loaders present on the target route are
567
+ * fetched.
568
+ *
569
+ * **Important:** Route loader data uses Qwik's custom serialization format, not standard JSON. This
570
+ * means the data supports features like circular references, Dates, and other non-JSON types, but
571
+ * it cannot be consumed by external clients expecting plain JSON.
572
+ *
573
+ * ## Options
574
+ *
575
+ * - `search: string[]`: Allowlist of URL search params the loader depends on. Only listed params are
576
+ * sent in the request and changes to other params are ignored. During SSR and loader JSON
577
+ * requests, the loader's request event is filtered to those params too. `search: []` means no
578
+ * search params are sent and only route path changes trigger a re-fetch.
579
+ * - `eTag`: Enable ETag-based caching. Can be `true` (auto-hash), a string, or a function.
580
+ * - `cacheControl`: Cache-Control for loader JSON responses; the browser HTTP cache controls
581
+ * client-side freshness. `'immutable'` additionally lets SSG write the loader file.
582
+ *
583
+ * The `strictLoaders` Vite plugin option applies `search: []` globally for all loaders that don't
584
+ * specify an explicit `search` option.
585
+ *
586
+ * @public
587
+ */ var routeLoader$ = /*#__PURE__*/ implicit$FirstArg(routeLoaderQrl);
588
+ var deepFreeze = (obj) => {
589
+ if (obj == null) return obj;
590
+ Object.getOwnPropertyNames(obj).forEach((prop) => {
591
+ const value = obj[prop];
592
+ if (value && typeof value === "object" && !Object.isFrozen(value)) try {
593
+ deepFreeze(value);
594
+ } catch {
595
+ return obj;
596
+ }
597
+ });
598
+ return Object.freeze(obj);
599
+ };
600
+ /** LoadRoute() runs in both client and server. */ var MODULE_CACHE = /*#__PURE__*/ new WeakMap();
601
+ /** Built-in fallback error component loader */ var httpErrorLoader = () => import("./http-error.qwik.mjs");
602
+ /**
603
+ * Walk trie keys from root, gathering `_L` layouts along the way. Returns the final node and
604
+ * collected layouts, or undefined if any key is missing.
605
+ */ function walkTrieKeys(root, keys) {
606
+ let node = root;
607
+ const layouts = [];
608
+ if (node._L) layouts.push(node._L);
609
+ for (let i = 0; i < keys.length; i++) {
610
+ const key = keys[i];
611
+ let next = node[key];
612
+ if (!next && node._M) for (let j = 0; j < node._M.length; j++) {
613
+ const group = node._M[j];
614
+ next = group[key];
615
+ if (next) {
616
+ if (group._L) layouts.push(group._L);
617
+ break;
618
+ }
619
+ }
620
+ if (!next) return;
621
+ node = next;
622
+ if (node._L) layouts.push(node._L);
623
+ }
624
+ return {
625
+ node,
626
+ layouts
627
+ };
628
+ }
629
+ /**
630
+ * The full chain to render for a boundary: a bare loader in its snapshot layouts, an override
631
+ * as-is.
632
+ */ var boundaryChain = (ref) => ref.v ? Array.isArray(ref.v) ? ref.v : [...ref.layouts, ref.v] : void 0;
633
+ /**
634
+ * Collect layouts, the nearest error (`_E`) and not-found (`_4`) boundaries, and the menu from a
635
+ * node and the group ancestors entered to reach it.
636
+ */ function collectNodeMeta(node, groups, layouts, errorLoaderRef, notFoundLoaderRef, menuLoaderRef, loaderHashes, loaderPathsByHash, matchedPathname = "/") {
637
+ for (let j = 0; j < groups.length; j++) {
638
+ const g = groups[j];
639
+ if (g._L) layouts.push(g._L);
640
+ if (g._R && loaderHashes) {
641
+ loaderHashes.push(...g._R);
642
+ if (loaderPathsByHash) for (let i = 0; i < g._R.length; i++) {
643
+ const hash = g._R[i];
644
+ loaderPathsByHash[hash] = matchedPathname;
645
+ }
646
+ }
647
+ if (g._E) {
648
+ errorLoaderRef.v = g._E;
649
+ errorLoaderRef.layouts = [...layouts];
650
+ }
651
+ if (g._4) {
652
+ notFoundLoaderRef.v = g._4;
653
+ notFoundLoaderRef.layouts = [...layouts];
654
+ }
655
+ if (g._N) menuLoaderRef.v = g._N;
656
+ }
657
+ if (node._L) layouts.push(node._L);
658
+ if (node._R && loaderHashes) {
659
+ loaderHashes.push(...node._R);
660
+ if (loaderPathsByHash) for (let i = 0; i < node._R.length; i++) {
661
+ const hash = node._R[i];
662
+ loaderPathsByHash[hash] = matchedPathname;
663
+ }
664
+ }
665
+ if (node._E) {
666
+ errorLoaderRef.v = node._E;
667
+ errorLoaderRef.layouts = [...layouts];
668
+ }
669
+ if (node._4) {
670
+ notFoundLoaderRef.v = node._4;
671
+ notFoundLoaderRef.layouts = [...layouts];
672
+ }
673
+ if (node._N) menuLoaderRef.v = node._N;
674
+ }
675
+ /** Try to match a segment against a node's wildcard children (_W, _A). */ function tryWildcardMatch(node, part, partLower, parts, partIndex) {
676
+ let next = node._W;
677
+ if (next) {
678
+ const prefix = next._0;
679
+ const suffix = next._9;
680
+ if (prefix || suffix) {
681
+ const pre = prefix || "";
682
+ const suf = suffix || "";
683
+ if (partLower.length > pre.length + suf.length && (!pre || partLower.startsWith(pre.toLowerCase())) && (!suf || partLower.endsWith(suf.toLowerCase()))) {
684
+ const paramName = next._P;
685
+ const value = part.slice(pre.length, suf ? part.length - suf.length : void 0);
686
+ return {
687
+ next,
688
+ routePart: `${pre}[${paramName}]${suf}`,
689
+ done: false,
690
+ kind: 1,
691
+ paramName,
692
+ paramValue: value
693
+ };
694
+ }
695
+ } else {
696
+ const paramName = next._P;
697
+ return {
698
+ next,
699
+ routePart: `[${paramName}]`,
700
+ done: false,
701
+ kind: 1,
702
+ paramName,
703
+ paramValue: part
704
+ };
705
+ }
706
+ }
707
+ next = node._A;
708
+ if (next) {
709
+ const paramName = next._P;
710
+ const restValue = parts.slice(partIndex).join("/");
711
+ return {
712
+ next,
713
+ routePart: `[...${paramName}]`,
714
+ done: true,
715
+ kind: 2,
716
+ paramName,
717
+ paramValue: restValue
718
+ };
719
+ }
720
+ }
721
+ /**
722
+ * Try to find a child matching `partLower` in `node`, including inside group children (_M). Returns
723
+ * the matched child node, the groups entered to reach it, what to push to routeParts, and which
724
+ * kind of edge matched. Returns undefined if no match.
725
+ *
726
+ * Priority: exact match → _M groups (recursively) → _W wildcard → _A rest wildcard. This ensures
727
+ * exact matches inside nested groups take precedence over wildcards at parent level.
728
+ */ function findChild(node, part, partLower, parts, partIndex) {
729
+ const exact = node[partLower];
730
+ if (exact) return {
731
+ next: exact,
732
+ groups: [],
733
+ routePart: part,
734
+ done: false,
735
+ kind: 0
736
+ };
737
+ if (node._M) for (let j = 0; j < node._M.length; j++) {
738
+ const group = node._M[j];
739
+ const groupResult = findChild(group, part, partLower, parts, partIndex);
740
+ if (groupResult) {
741
+ groupResult.groups.unshift(group);
742
+ return groupResult;
743
+ }
744
+ }
745
+ const wildcard = tryWildcardMatch(node, part, partLower, parts, partIndex);
746
+ if (wildcard) return {
747
+ ...wildcard,
748
+ groups: []
749
+ };
750
+ }
751
+ /**
752
+ * Descend through a node and its pathless `_M` groups (depth-first, in `_M` order), returning the
753
+ * first node for which `hit` yields a value, plus the chain of groups entered to reach it. The
754
+ * shared traversal behind the index / rest / boundary lookups inside groups.
755
+ */ function descendGroups(node, hit) {
756
+ const value = hit(node);
757
+ if (value !== void 0) return {
758
+ value,
759
+ node,
760
+ groups: []
761
+ };
762
+ if (node._M) for (let j = 0; j < node._M.length; j++) {
763
+ const group = node._M[j];
764
+ const result = descendGroups(group, hit);
765
+ if (result) {
766
+ result.groups.unshift(group);
767
+ return result;
768
+ }
769
+ }
770
+ }
771
+ /**
772
+ * Find a node with `_I`/`_G` at the current level, including inside `_M` groups. Returns it and the
773
+ * groups entered to reach it — excluding the target itself, whose `_L` the caller applies (so it
774
+ * isn't double-counted).
775
+ */ function findIndexNode(node) {
776
+ const r = descendGroups(node, (n) => n._I || n._G != null ? n : void 0);
777
+ return r ? {
778
+ target: r.node,
779
+ groups: r.groups.filter((g) => g !== r.node)
780
+ } : void 0;
781
+ }
782
+ /**
783
+ * Given a matched node that has `_I` or `_G`, resolve the final loaders array.
784
+ *
785
+ * - `_G`: re-walk from root to gather target's layouts and `_I`
786
+ * - `_I` array: use as-is (override, e.g. layout stop)
787
+ * - `_I` function: prepend gathered layouts
788
+ */ function resolveLoaders(root, node, gatheredLayouts) {
789
+ if (node._G != null) {
790
+ const target = walkTrieKeys(root, node._G.split("/").filter((p) => p.length > 0));
791
+ if (!target) return;
792
+ let targetNode = target.node;
793
+ const targetLayouts = target.layouts;
794
+ if (!targetNode._I && targetNode._G == null) {
795
+ const indexResult = findIndexNode(targetNode);
796
+ if (indexResult) {
797
+ for (let j = 0; j < indexResult.groups.length; j++) {
798
+ const g = indexResult.groups[j];
799
+ if (g._L) targetLayouts.push(g._L);
800
+ }
801
+ targetNode = indexResult.target;
802
+ if (targetNode._L) targetLayouts.push(targetNode._L);
803
+ }
804
+ }
805
+ return resolveLoaders(root, targetNode, targetLayouts);
806
+ }
807
+ const index = node._I;
808
+ if (!index) return;
809
+ if (Array.isArray(index)) return index;
810
+ return [...gatheredLayouts, index];
811
+ }
812
+ /**
813
+ * Find a rest wildcard (`_A`) at the current node or inside its `_M` groups, with the groups
814
+ * entered to reach it. Used to save fallback checkpoints during matching.
815
+ */ function findRestNode(node) {
816
+ const r = descendGroups(node, (n) => n._A);
817
+ return r ? {
818
+ next: r.value,
819
+ groups: r.groups
820
+ } : void 0;
821
+ }
822
+ /**
823
+ * Find a `_4`/`_E` boundary inside a node's pathless `_M` groups (first in `_M` order), wrapped in
824
+ * those groups' layouts.
825
+ */ function findGroupBoundary(node, layouts, kind) {
826
+ const r = descendGroups(node, (n) => n[kind]);
827
+ if (!r) return;
828
+ const groupLayouts = [...layouts];
829
+ for (const g of r.groups) if (g._L) groupLayouts.push(g._L);
830
+ return {
831
+ v: r.value,
832
+ layouts: groupLayouts
833
+ };
834
+ }
835
+ /**
836
+ * Match a URL pathname against the route trie.
837
+ *
838
+ * Always returns a result. When no route matches, `notFound` is true and `loaders` contains only
839
+ * the error component (from the nearest `_E` or `_4` ancestor, or the built-in fallback).
840
+ *
841
+ * Group nodes (in `_M` arrays) are pathless — they don't consume a URL segment but contribute their
842
+ * `_L` layout to the chain. The matcher transparently enters groups when searching for a matching
843
+ * child.
844
+ */ function matchRouteTree(root = {}, pathname) {
845
+ let node = root;
846
+ const params = {};
847
+ const routeParts = [];
848
+ const layouts = [];
849
+ const loaderHashes = [];
850
+ const loaderPathsByHash = {};
851
+ const errorLoaderRef = {
852
+ v: void 0,
853
+ layouts: []
854
+ };
855
+ const notFoundLoaderRef = {
856
+ v: void 0,
857
+ layouts: []
858
+ };
859
+ const menuLoaderRef = { v: void 0 };
860
+ const groupNodes = [];
861
+ collectNodeMeta(root, [], layouts, errorLoaderRef, notFoundLoaderRef, menuLoaderRef, loaderHashes, loaderPathsByHash);
862
+ if (root._M) groupNodes.push({
863
+ node: root,
864
+ depth: layouts.length
865
+ });
866
+ let done = false;
867
+ let matched = true;
868
+ const parts = pathname.split("/").filter((p) => p.length > 0).map(decodeURIComponent);
869
+ let restFallback;
870
+ let i = 0;
871
+ const len = parts.length;
872
+ for (; !done && i < len; i++) {
873
+ const part = parts[i];
874
+ const partLower = part.toLowerCase();
875
+ const found = findChild(node, part, partLower, parts, i);
876
+ if (!found) {
877
+ matched = false;
878
+ break;
879
+ }
880
+ const restInfo = found.kind === 1 ? findRestNode(node) : void 0;
881
+ if (restInfo) restFallback = {
882
+ aNode: restInfo.next,
883
+ groups: restInfo.groups,
884
+ paramName: restInfo.next._P,
885
+ restValue: parts.slice(i).join("/"),
886
+ routeParts: [...routeParts],
887
+ params: { ...params },
888
+ layouts: [...layouts],
889
+ loaderPathsByHash: { ...loaderPathsByHash },
890
+ errorLoader: errorLoaderRef.v,
891
+ errorLayouts: errorLoaderRef.layouts,
892
+ notFoundLoader: notFoundLoaderRef.v,
893
+ notFoundLayouts: notFoundLoaderRef.layouts,
894
+ menuLoader: menuLoaderRef.v
895
+ };
896
+ if (found.paramName) params[found.paramName] = found.paramValue;
897
+ routeParts.push(found.routePart);
898
+ done = found.done;
899
+ node = found.next;
900
+ const matchedPathname = `/${parts.slice(0, found.done ? len : i + 1).join("/")}/`;
901
+ collectNodeMeta(node, found.groups, layouts, errorLoaderRef, notFoundLoaderRef, menuLoaderRef, loaderHashes, loaderPathsByHash, matchedPathname);
902
+ if (node._M) groupNodes.push({
903
+ node,
904
+ depth: layouts.length
905
+ });
906
+ }
907
+ if (matched && !done && i === len) {
908
+ if (!node._I && node._G == null) {
909
+ const indexResult = findIndexNode(node);
910
+ if (indexResult) {
911
+ collectNodeMeta(indexResult.target, indexResult.groups, layouts, errorLoaderRef, notFoundLoaderRef, menuLoaderRef, loaderHashes, loaderPathsByHash, pathname);
912
+ node = indexResult.target;
913
+ }
914
+ }
915
+ if (!node._I && node._G == null) {
916
+ const restInfo = findRestNode(node);
917
+ if (restInfo) {
918
+ const next = restInfo.next;
919
+ const paramName = next._P;
920
+ params[paramName] = "";
921
+ routeParts.push(`[...${paramName}]`);
922
+ collectNodeMeta(next, restInfo.groups, layouts, errorLoaderRef, notFoundLoaderRef, menuLoaderRef, loaderHashes, loaderPathsByHash, pathname);
923
+ node = next;
924
+ }
925
+ }
926
+ }
927
+ const loaders = matched && (done || i >= len) ? resolveLoaders(root, node, layouts) : void 0;
928
+ if (!loaders && restFallback) {
929
+ const fb = restFallback;
930
+ const fbParams = {
931
+ ...fb.params,
932
+ [fb.paramName]: fb.restValue
933
+ };
934
+ const fbRouteParts = [...fb.routeParts, `[...${fb.paramName}]`];
935
+ const fbLayouts = [...fb.layouts];
936
+ const fbLoaderPathsByHash = { ...fb.loaderPathsByHash };
937
+ const fbErrorRef = {
938
+ v: fb.errorLoader,
939
+ layouts: fb.errorLayouts
940
+ };
941
+ const fbNotFoundRef = {
942
+ v: fb.notFoundLoader,
943
+ layouts: fb.notFoundLayouts
944
+ };
945
+ const fbMenuRef = { v: fb.menuLoader };
946
+ const fbLoaderHashes = [];
947
+ collectNodeMeta(fb.aNode, fb.groups, fbLayouts, fbErrorRef, fbNotFoundRef, fbMenuRef, fbLoaderHashes, fbLoaderPathsByHash, pathname);
948
+ const fbLoaders = resolveLoaders(root, fb.aNode, fbLayouts);
949
+ if (fbLoaders) return {
950
+ loaders: fbLoaders,
951
+ params: fbParams,
952
+ routeParts: fbRouteParts,
953
+ notFound: false,
954
+ routeBundleNames: fb.aNode._B,
955
+ loaderHashes: fbLoaderHashes.length > 0 ? fbLoaderHashes : void 0,
956
+ loaderPathsByHash: Object.keys(fbLoaderPathsByHash).length > 0 ? fbLoaderPathsByHash : void 0,
957
+ menuLoader: fbMenuRef.v,
958
+ errorLoader: boundaryChain(fbErrorRef)
959
+ };
960
+ errorLoaderRef.v = fbErrorRef.v;
961
+ errorLoaderRef.layouts = fbErrorRef.layouts;
962
+ notFoundLoaderRef.v = fbNotFoundRef.v;
963
+ notFoundLoaderRef.layouts = fbNotFoundRef.layouts;
964
+ menuLoaderRef.v = fbMenuRef.v;
965
+ }
966
+ if (!loaders) {
967
+ const recover = (kind) => {
968
+ for (let k = groupNodes.length - 1; k >= 0; k--) {
969
+ const found = findGroupBoundary(groupNodes[k].node, layouts.slice(0, groupNodes[k].depth), kind);
970
+ if (found) return found;
971
+ }
972
+ };
973
+ if (!notFoundLoaderRef.v) {
974
+ const g = recover("_4");
975
+ if (g) {
976
+ notFoundLoaderRef.v = g.v;
977
+ notFoundLoaderRef.layouts = g.layouts;
978
+ }
979
+ }
980
+ if (!errorLoaderRef.v) {
981
+ const g = recover("_E");
982
+ if (g) {
983
+ errorLoaderRef.v = g.v;
984
+ errorLoaderRef.layouts = g.layouts;
985
+ }
986
+ }
987
+ const ref = notFoundLoaderRef.v ? notFoundLoaderRef : errorLoaderRef.v ? errorLoaderRef : null;
988
+ const boundary = ref?.v ?? httpErrorLoader;
989
+ const boundaryLayouts = ref ? ref.layouts : layouts;
990
+ return {
991
+ loaders: Array.isArray(boundary) ? boundary : [...boundaryLayouts, boundary],
992
+ params,
993
+ routeParts,
994
+ notFound: true,
995
+ routeBundleNames: void 0,
996
+ loaderHashes: void 0,
997
+ loaderPathsByHash: void 0,
998
+ menuLoader: menuLoaderRef.v,
999
+ errorLoader: boundaryChain(errorLoaderRef)
1000
+ };
1001
+ }
1002
+ if (node._R) {
1003
+ loaderHashes.push(...node._R);
1004
+ const matchedPathname = ensureSlash(pathname);
1005
+ for (let i = 0; i < node._R.length; i++) {
1006
+ const hash = node._R[i];
1007
+ loaderPathsByHash[hash] = matchedPathname;
1008
+ }
1009
+ }
1010
+ return {
1011
+ loaders,
1012
+ params,
1013
+ routeParts,
1014
+ notFound: false,
1015
+ routeBundleNames: node._B,
1016
+ loaderHashes: loaderHashes.length > 0 ? loaderHashes : void 0,
1017
+ loaderPathsByHash: Object.keys(loaderPathsByHash).length > 0 ? loaderPathsByHash : void 0,
1018
+ menuLoader: menuLoaderRef.v,
1019
+ errorLoader: boundaryChain(errorLoaderRef)
1020
+ };
1021
+ }
1022
+ var loadModule = (moduleLoader, pendingLoads, moduleSetter, cacheModules) => {
1023
+ if (typeof moduleLoader === "function") {
1024
+ const loadedModule = MODULE_CACHE.get(moduleLoader);
1025
+ if (loadedModule) moduleSetter(loadedModule);
1026
+ else {
1027
+ const moduleOrPromise = moduleLoader();
1028
+ if (typeof moduleOrPromise.then === "function") pendingLoads.push(moduleOrPromise.then((loadedModule) => {
1029
+ if (cacheModules !== false) MODULE_CACHE.set(moduleLoader, loadedModule);
1030
+ moduleSetter(loadedModule);
1031
+ }));
1032
+ else if (moduleOrPromise) moduleSetter(moduleOrPromise);
1033
+ }
1034
+ }
1035
+ };
1036
+ var loadRoute = async (routes, cacheModules, pathname) => {
1037
+ const { loaders, params, routeParts, notFound, routeBundleNames, loaderHashes, loaderPathsByHash, menuLoader, errorLoader } = matchRouteTree(routes, pathname);
1038
+ const routeName = "/" + routeParts.join("/");
1039
+ const modules = new Array(loaders.length);
1040
+ const pendingLoads = [];
1041
+ for (let i = 0; i < loaders.length; i++) {
1042
+ const moduleLoader = loaders[i];
1043
+ loadModule(moduleLoader, pendingLoads, (routeModule) => modules[i] = routeModule, cacheModules);
1044
+ }
1045
+ let menu = void 0;
1046
+ loadModule(menuLoader, pendingLoads, (menuModule) => menu = menuModule?.default, cacheModules);
1047
+ if (pendingLoads.length > 0) await Promise.all(pendingLoads);
1048
+ return {
1049
+ $routeName$: routeName,
1050
+ $params$: params,
1051
+ $mods$: modules,
1052
+ $menu$: deepFreeze(menu),
1053
+ $routeBundleNames$: routeBundleNames,
1054
+ $notFound$: notFound,
1055
+ $errorLoader$: errorLoader,
1056
+ $loaders$: loaderHashes,
1057
+ $loaderPaths$: loaderPathsByHash
1058
+ };
1059
+ };
1060
+ /** Gets an absolute url path string (url.pathname + url.search + url.hash) */ var toPath = (url) => url.pathname + url.search + url.hash;
1061
+ /** Create a URL from a string and baseUrl */ var toUrl = (url, baseUrl) => new URL(url, baseUrl.href);
1062
+ /** Checks only if the origins are the same. */ var isSameOrigin = (a, b) => a.origin === b.origin;
1063
+ /** Checks only if the pathnames are the same for the URLs (doesn't include search and hash) */ var isSamePathname = ({ pathname: a }, { pathname: b }) => {
1064
+ const lDiff = Math.abs(a.length - b.length);
1065
+ return lDiff === 0 ? a === b : lDiff === 1 && ensureSlash(a) === ensureSlash(b);
1066
+ };
1067
+ /** Checks only if the search query strings are the same for the URLs */ var isSameSearchQuery = (a, b) => a.search === b.search;
1068
+ /** Checks only if the pathname + search are the same for the URLs. */ var isSamePath = (a, b) => isSameSearchQuery(a, b) && isSamePathname(a, b);
1069
+ var getClientNavPath = (props, baseUrl) => {
1070
+ const href = props.href;
1071
+ if (typeof href === "string" && typeof props.target !== "string" && !props.reload) try {
1072
+ const linkUrl = toUrl(href.trim(), baseUrl.url);
1073
+ if (isSameOrigin(linkUrl, toUrl("", baseUrl.url))) return toPath(linkUrl);
1074
+ } catch (e) {
1075
+ console.error(e);
1076
+ }
1077
+ else if (props.reload) return toPath(toUrl("", baseUrl.url));
1078
+ return null;
1079
+ };
1080
+ var shouldPreload = (clientNavPath, currentLoc) => {
1081
+ if (clientNavPath) return !isSamePathname(toUrl(clientNavPath, currentLoc.url), toUrl("", currentLoc.url));
1082
+ return false;
1083
+ };
1084
+ var isPromise = (value) => {
1085
+ return value && typeof value.then === "function";
1086
+ };
1087
+ var mergeArray = (existingArr, newArr) => {
1088
+ if (Array.isArray(newArr)) for (const newItem of newArr) {
1089
+ if (typeof newItem.key === "string") {
1090
+ const existingIndex = existingArr.findIndex((i) => i.key === newItem.key);
1091
+ if (existingIndex > -1) {
1092
+ existingArr[existingIndex] = newItem;
1093
+ continue;
1094
+ }
1095
+ }
1096
+ existingArr.push(newItem);
1097
+ }
1098
+ };
1099
+ var resolveDocumentHead = (resolvedHead, updatedHead) => {
1100
+ if (typeof updatedHead.title === "string") resolvedHead.title = updatedHead.title;
1101
+ mergeArray(resolvedHead.meta, updatedHead.meta);
1102
+ mergeArray(resolvedHead.links, updatedHead.links);
1103
+ mergeArray(resolvedHead.styles, updatedHead.styles);
1104
+ mergeArray(resolvedHead.scripts, updatedHead.scripts);
1105
+ Object.assign(resolvedHead.frontmatter, updatedHead.frontmatter);
1106
+ };
1107
+ var createDocumentHead = (defaults, manifestHash) => ({
1108
+ title: defaults?.title || "",
1109
+ meta: [...defaults?.meta || []],
1110
+ links: [...defaults?.links || []],
1111
+ styles: [...defaults?.styles || []],
1112
+ scripts: [...defaults?.scripts || []],
1113
+ frontmatter: { ...defaults?.frontmatter },
1114
+ manifestHash: manifestHash || "dev"
1115
+ });
1116
+ /**
1117
+ * Resolve the full route config (head + eTag + cacheKey) from all content modules. Uses the same
1118
+ * resolution rules as DocumentHead: objects are merged immediately, functions are queued and
1119
+ * executed inner-before-outer.
1120
+ */ var resolveRouteConfig = (resolveValue, routeLocation, contentModules, locale, status, defaults) => withLocale(locale, () => {
1121
+ const head = createDocumentHead(defaults);
1122
+ let eTag;
1123
+ let cacheKey;
1124
+ const fns = [];
1125
+ for (let i = 0; i < contentModules.length; i++) {
1126
+ const contentModule = contentModules[i];
1127
+ if (!contentModule) continue;
1128
+ const isLast = i === contentModules.length - 1;
1129
+ let config;
1130
+ if (contentModule.routeConfig) config = contentModule.routeConfig;
1131
+ else if (contentModule.head) {
1132
+ const synthetic = { head: void 0 };
1133
+ const headExport = contentModule.head;
1134
+ if (typeof headExport === "function") {
1135
+ const mod = contentModule;
1136
+ config = (props) => ({
1137
+ head: headExport(props),
1138
+ eTag: mod.eTag,
1139
+ cacheKey: mod.cacheKey
1140
+ });
1141
+ } else {
1142
+ synthetic.head = headExport;
1143
+ const mod = contentModule;
1144
+ if (mod.eTag !== void 0) synthetic.eTag = mod.eTag;
1145
+ if (mod.cacheKey !== void 0) synthetic.cacheKey = mod.cacheKey;
1146
+ config = synthetic;
1147
+ }
1148
+ } else {
1149
+ const mod = contentModule;
1150
+ if (mod.eTag !== void 0 || mod.cacheKey !== void 0) config = {
1151
+ eTag: mod.eTag,
1152
+ cacheKey: mod.cacheKey
1153
+ };
1154
+ }
1155
+ if (!config) continue;
1156
+ if (typeof config === "function") fns.unshift({
1157
+ fn: config,
1158
+ isLast
1159
+ });
1160
+ else {
1161
+ if (config.head) resolveDocumentHead(head, config.head);
1162
+ if (config.eTag !== void 0) eTag = config.eTag;
1163
+ if (config.cacheKey !== void 0) cacheKey = config.cacheKey;
1164
+ }
1165
+ }
1166
+ if (fns.length) {
1167
+ const headProps = {
1168
+ head,
1169
+ status,
1170
+ withLocale: (fn) => fn(),
1171
+ resolveValue,
1172
+ ...routeLocation
1173
+ };
1174
+ for (const { fn } of fns) {
1175
+ const result = fn(headProps);
1176
+ if (result.head) resolveDocumentHead(head, result.head);
1177
+ if (result.eTag !== void 0) eTag = result.eTag;
1178
+ if (result.cacheKey !== void 0) cacheKey = result.cacheKey;
1179
+ }
1180
+ }
1181
+ return {
1182
+ head,
1183
+ eTag,
1184
+ cacheKey
1185
+ };
1186
+ });
1187
+ /**
1188
+ * Resolve only the document head from all content modules. This is the browser-side entry point
1189
+ * that ignores eTag/cacheKey (server-only concerns).
1190
+ *
1191
+ * Signal values may throw a promise on the client when still loading — callers should wrap this in
1192
+ * `retryOnPromise` to handle that.
1193
+ */ var resolveHead = (actionData, loaderState, routeLocation, contentModules, locale, defaults) => {
1194
+ const getData = (loaderOrAction) => {
1195
+ const id = loaderOrAction.__id;
1196
+ const signal = loaderState?.[id];
1197
+ if (signal) return signal.value;
1198
+ if (actionData?.action === id) return actionData.actionResult;
1199
+ };
1200
+ return resolveRouteConfig(getData, routeLocation, contentModules, locale, actionData?.status ?? 200, defaults).head;
1201
+ };
1202
+ export { routeLoader$ as A, RouteLoaderCtxContext as B, getRouteLoaderValues as C, loadRouteLoader as D, isImmutableLoader as E, ContentContext as F, QACTION_KEY as G, RouteNavigateContext as H, ContentInternalContext as I, Q_ROUTE as J, QDATA_KEY as K, DocumentHeadContext as L, setLoaderSignalValue as M, setRouteLoaders as N, matchesRouteLoaderId as O, updateRouteLoaderPaths as P, HttpStatusContext as R, getRouteLoaderResponse as S, invalidateNavRouteLoaders as T, RoutePreventNavigateContext as U, RouteLocationContext as V, RouteStateContext as W, _asyncRequestStore as Y, fetchRouteLoaderData as _, isPromise as a, getRequestEvent as b, shouldPreload as c, loadRoute as d, FULLPATH_HEADER as f, ensureRouteLoaderSignals as g, clearRouteLoaderData as h, getClientNavPath as i, routeLoaderQrl as j, resolveRouteLoaderByHash as k, toPath as l, clearNavFetchCache as m, resolveHead as n, isSameOrigin as o, ROUTE_PATH_HEADER as p, QFN_KEY as q, resolveRouteConfig as r, isSamePath as s, createDocumentHead as t, toUrl as u, getLoaderRequestEvent as v, getRouteLoaders as w, getRouteLoaderCtx as x, getModuleRouteLoaders as y, RouteActionContext as z };