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