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