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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,593 @@
1
+ import { _getAsyncLocalStorage, _resolveContextWithoutSequentialScope, _getContextEvent, _injectAsyncSignalValue, _UNINITIALIZED, _deserialize, createAsyncQrl, SerializerSymbol, _getContextContainer, _verifySerializable } from '@qwik.dev/core/internal';
2
+ import { createContextId, implicit$FirstArg, isServer as isServer$1, inlinedQrl, _captures, isDev } from '@qwik.dev/core';
3
+ import * as qwikRouterConfig from '@qwik-router-config';
4
+ import { isServer } from '@qwik.dev/core/build';
5
+ import { g as getLoaderName } from './request-path.mjs';
6
+ import { e as ensureSlash } from './pathname.mjs';
7
+
8
+ let _asyncRequestStore;
9
+ if (isServer) {
10
+ const AsyncLocalStorage = _getAsyncLocalStorage();
11
+ if (AsyncLocalStorage) {
12
+ _asyncRequestStore = new AsyncLocalStorage();
13
+ } else {
14
+ 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");
15
+ }
16
+ }
17
+
18
+ class AbortMessage {
19
+ }
20
+ class RedirectMessage extends AbortMessage {
21
+ }
22
+
23
+ class ServerError extends Error {
24
+ status;
25
+ data;
26
+ constructor(status, data) {
27
+ super(typeof data === "string" ? data : void 0), this.status = status, this.data = data;
28
+ }
29
+ }
30
+
31
+ const QACTION_KEY = "qaction";
32
+ const QFN_KEY = "qfunc";
33
+ const QDATA_KEY = "qdata";
34
+ const Q_ROUTE = "q:route";
35
+ const DEFAULT_LOADERS_SERIALIZATION_STRATEGY = globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__ || "never";
36
+
37
+ const RouteStateContext = /* @__PURE__ */ createContextId("qr-s");
38
+ const RouteLoaderCtxContext = /* @__PURE__ */ createContextId("qr-lc");
39
+ const ContentContext = /* @__PURE__ */ createContextId("qr-c");
40
+ const ContentInternalContext = /* @__PURE__ */ createContextId("qr-ic");
41
+ const DocumentHeadContext = /* @__PURE__ */ createContextId("qr-h");
42
+ const RouteLocationContext = /* @__PURE__ */ createContextId("qr-l");
43
+ const RouteNavigateContext = /* @__PURE__ */ createContextId("qr-n");
44
+ const RouteActionContext = /* @__PURE__ */ createContextId("qr-a");
45
+ const RoutePreventNavigateContext = /* @__PURE__ */ createContextId("qr-p");
46
+ const HttpStatusContext = /* @__PURE__ */ createContextId("qr-hs");
47
+
48
+ const REQUEST_LOADER_PATHS_STORE = "@loaderPathsStore";
49
+ const REQUEST_ROUTE_LOADERS = "@routeLoaders";
50
+ const REQUEST_ROUTE_LOADER_PROMISES = "@routeLoaderPromises";
51
+ const REQUEST_ROUTE_LOADER_EVENTS = "@routeLoaderEvents";
52
+ const REQUEST_ROUTE_LOADER_ROOT_EVENT = "@routeLoaderRootEvent";
53
+ const ROUTE_LOADER_VALUE_PREFIX = "__qwik_route_loader_value__";
54
+ const FULLPATH_HEADER = "X-Qwik-fullpath";
55
+ const LOADER_FETCH_CACHE_TTL = 5e3;
56
+ const LOADER_FETCH_CACHE_MAX = 128;
57
+ const fetchCache = /* @__PURE__ */ new Map();
58
+ const perfNow = () => globalThis.performance?.now() ?? Date.now();
59
+ const isRedirectStatus = (status) => status >= 300 && status < 400;
60
+ const setCache = (key, entry) => {
61
+ fetchCache.set(key, entry);
62
+ if (fetchCache.size > LOADER_FETCH_CACHE_MAX) {
63
+ const oldestKey = fetchCache.keys().next().value;
64
+ if (oldestKey !== void 0) {
65
+ fetchCache.delete(oldestKey);
66
+ }
67
+ }
68
+ };
69
+ const wrapWithAbort = (promise, signal) => {
70
+ if (signal.aborted) {
71
+ return Promise.reject(signal.reason);
72
+ }
73
+ return new Promise((resolve, reject) => {
74
+ const abort = () => reject(signal.reason);
75
+ signal.addEventListener("abort", abort, {
76
+ once: true
77
+ });
78
+ promise.finally(() => signal.removeEventListener("abort", abort)).then(resolve, reject);
79
+ });
80
+ };
81
+ const getRouteLoaderValueStateKey = (loaderId) => `${ROUTE_LOADER_VALUE_PREFIX}${loaderId}`;
82
+ const isRequestEvent = (value) => !!value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, "sharedMap") && Object.prototype.hasOwnProperty.call(value, "cookie");
83
+ const isLoaderInternal = (value) => typeof value === "function" && value.__brand === "server_loader";
84
+ const getClientManifestHash = (ctx) => {
85
+ const container = ctx.$signal$?.$container$;
86
+ return container?.qManifestHash || _getContextContainer()?.qManifestHash || "dev";
87
+ };
88
+ const fetchRouteLoaderData = async (loaderId, routePath, manifestHash, opts) => {
89
+ if (!routePath) {
90
+ return void 0;
91
+ }
92
+ let resolvedPath = routePath;
93
+ const basePath = opts?.basePath ?? "/";
94
+ if (basePath !== "/" && !resolvedPath.startsWith(basePath)) {
95
+ resolvedPath = basePath + resolvedPath.slice(1);
96
+ }
97
+ const pathBase = ensureSlash(resolvedPath);
98
+ const pageUrl = opts?.pageUrl;
99
+ const search = pageUrl?.search ?? "";
100
+ const url = `${pathBase}${getLoaderName(loaderId, manifestHash)}${search}`;
101
+ const headers = {};
102
+ if (pageUrl && pageUrl.pathname !== pathBase && !globalThis.__STRICT_LOADERS__) {
103
+ headers[FULLPATH_HEADER] = pageUrl.pathname;
104
+ }
105
+ const cacheKey = `${url}
106
+ ${headers[FULLPATH_HEADER] ?? ""}`;
107
+ if (!opts?.ignoreCache) {
108
+ const entry = fetchCache.get(cacheKey);
109
+ if (entry) {
110
+ if (entry.promise) {
111
+ return opts?.signal ? wrapWithAbort(entry.promise, opts.signal) : entry.promise;
112
+ }
113
+ if (entry.expires > perfNow()) {
114
+ return entry.value;
115
+ }
116
+ fetchCache.delete(cacheKey);
117
+ }
118
+ }
119
+ const request = async () => {
120
+ const response = await fetch(url, {
121
+ signal: opts?.signal,
122
+ cache: opts?.ignoreCache ? "reload" : "default",
123
+ headers
124
+ });
125
+ if (response.redirected) {
126
+ return {
127
+ r: response.url
128
+ };
129
+ }
130
+ if (isRedirectStatus(response.status)) {
131
+ const location1 = response.headers.get("Location");
132
+ if (location1) {
133
+ return {
134
+ r: location1
135
+ };
136
+ }
137
+ }
138
+ if (!response.ok) {
139
+ return void 0;
140
+ }
141
+ const text = await response.text();
142
+ return _deserialize(text) ?? void 0;
143
+ };
144
+ if (opts?.ignoreCache || opts?.signal) {
145
+ return request();
146
+ }
147
+ const promise = request().then((value) => {
148
+ if (value === void 0) {
149
+ fetchCache.delete(cacheKey);
150
+ } else {
151
+ setCache(cacheKey, {
152
+ value,
153
+ expires: perfNow() + LOADER_FETCH_CACHE_TTL
154
+ });
155
+ }
156
+ return value;
157
+ }, (err) => {
158
+ fetchCache.delete(cacheKey);
159
+ throw err;
160
+ });
161
+ setCache(cacheKey, {
162
+ promise,
163
+ expires: perfNow() + LOADER_FETCH_CACHE_TTL
164
+ });
165
+ return promise;
166
+ };
167
+ const filterSearchParams = (params, allowed) => {
168
+ const filtered = new URLSearchParams();
169
+ for (let i = 0; i < allowed.length; i++) {
170
+ const name = allowed[i];
171
+ const values = params.getAll(name);
172
+ for (let j = 0; j < values.length; j++) {
173
+ filtered.append(name, values[j]);
174
+ }
175
+ }
176
+ filtered.sort();
177
+ return filtered.toString() ? `?${filtered.toString()}` : "";
178
+ };
179
+ const getLoaderOptions = (rest) => {
180
+ let serializationStrategy = DEFAULT_LOADERS_SERIALIZATION_STRATEGY;
181
+ let expires;
182
+ let poll;
183
+ let eTag;
184
+ let cacheKey;
185
+ let search;
186
+ let allowStale = true;
187
+ const validators = [];
188
+ if (rest.length === 1) {
189
+ const options = rest[0];
190
+ if (options && typeof options === "object") {
191
+ if ("validate" in options) {
192
+ validators.push(options);
193
+ } else {
194
+ if (options.serializationStrategy) {
195
+ serializationStrategy = options.serializationStrategy;
196
+ }
197
+ if (options.validation) {
198
+ validators.push(...options.validation);
199
+ }
200
+ if ("expires" in options) {
201
+ expires = options.expires;
202
+ }
203
+ if ("poll" in options) {
204
+ poll = options.poll;
205
+ }
206
+ if ("eTag" in options) {
207
+ eTag = options.eTag;
208
+ }
209
+ if ("cacheKey" in options) {
210
+ cacheKey = options.cacheKey;
211
+ }
212
+ if (options.search) {
213
+ search = options.search;
214
+ } else if (globalThis.__STRICT_LOADERS__) {
215
+ search = [];
216
+ }
217
+ if (options.allowStale === false) {
218
+ allowStale = false;
219
+ }
220
+ }
221
+ }
222
+ } else if (rest.length > 1) {
223
+ validators.push(...rest.filter(Boolean));
224
+ }
225
+ return {
226
+ validators: validators.reverse(),
227
+ serializationStrategy,
228
+ expires,
229
+ poll,
230
+ eTag,
231
+ cacheKey,
232
+ search,
233
+ allowStale
234
+ };
235
+ };
236
+ const getRequestEvent = (thisArg) => {
237
+ if (!isServer$1) {
238
+ throw new Error("getRequestEvent() can only be used on the server.");
239
+ }
240
+ const requestEvent = _asyncRequestStore?.getStore() || [
241
+ thisArg,
242
+ _getContextEvent()
243
+ ].find(isRequestEvent);
244
+ if (!requestEvent) {
245
+ throw new Error("Unable to determine the current RequestEvent.");
246
+ }
247
+ return requestEvent;
248
+ };
249
+ const REQUEST_ROUTE_LOADER_VALUES = "@routeLoaderValues";
250
+ function getRouteLoaderValues(requestEv) {
251
+ let values = requestEv.sharedMap.get(REQUEST_ROUTE_LOADER_VALUES);
252
+ if (!values) {
253
+ values = {};
254
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADER_VALUES, values);
255
+ }
256
+ return values;
257
+ }
258
+ function getRouteLoaderPromises(requestEv) {
259
+ let promises = requestEv.sharedMap.get(REQUEST_ROUTE_LOADER_PROMISES);
260
+ if (!promises) {
261
+ promises = {};
262
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADER_PROMISES, promises);
263
+ }
264
+ return promises;
265
+ }
266
+ function setRouteLoaders(requestEv, loaders) {
267
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADERS, loaders);
268
+ }
269
+ function getRouteLoaders(requestEv) {
270
+ return requestEv.sharedMap.get(REQUEST_ROUTE_LOADERS) ?? [];
271
+ }
272
+ function getRouteLoaderCtx(requestEv) {
273
+ let ctx = requestEv.sharedMap.get(REQUEST_LOADER_PATHS_STORE);
274
+ if (!ctx) {
275
+ ctx = {
276
+ loaderPaths: {}
277
+ };
278
+ requestEv.sharedMap.set(REQUEST_LOADER_PATHS_STORE, ctx);
279
+ }
280
+ return ctx;
281
+ }
282
+ const updateRouteLoaderPaths = (ctx, loaderPaths, pageUrl) => {
283
+ if (!isServer$1) {
284
+ ctx.pagePathname = pageUrl.pathname;
285
+ ctx.pageSearch = pageUrl.search;
286
+ }
287
+ if (loaderPaths) {
288
+ for (const key in loaderPaths) {
289
+ ctx.loaderPaths[key] = loaderPaths[key];
290
+ }
291
+ }
292
+ };
293
+ const getModuleRouteLoaders = (mods) => {
294
+ const routeLoaders = [];
295
+ const seen = /* @__PURE__ */ new Set();
296
+ for (let i = 0; i < mods.length; i++) {
297
+ const mod = mods[i];
298
+ if (!mod) {
299
+ continue;
300
+ }
301
+ for (const key in mod) {
302
+ const value = mod[key];
303
+ if (isLoaderInternal(value) && !seen.has(value.__id)) {
304
+ seen.add(value.__id);
305
+ routeLoaders.push(value);
306
+ }
307
+ }
308
+ }
309
+ return routeLoaders;
310
+ };
311
+ const setLoaderSignalValue = (signal, value) => {
312
+ _injectAsyncSignalValue(signal, value);
313
+ };
314
+ const resolveRouteLoaderByHash = (routeLoaders, loaderId) => {
315
+ return routeLoaders.find((loader) => loader.__id === loaderId);
316
+ };
317
+ const getLoaderRequestEvent = (loader, requestEv) => {
318
+ let rootRequestEv = requestEv.sharedMap.get(REQUEST_ROUTE_LOADER_ROOT_EVENT);
319
+ if (!rootRequestEv) {
320
+ rootRequestEv = requestEv;
321
+ requestEv.sharedMap.set(REQUEST_ROUTE_LOADER_ROOT_EVENT, rootRequestEv);
322
+ }
323
+ const url = new URL(rootRequestEv.url);
324
+ const pathname = globalThis.__STRICT_LOADERS__ ? getRouteLoaderCtx(rootRequestEv).loaderPaths[loader.__id] || rootRequestEv.url.pathname : rootRequestEv.url.pathname;
325
+ const filteredSearch = loader.__search ? filterSearchParams(url.searchParams, loader.__search) : rootRequestEv.url.search;
326
+ if (pathname === rootRequestEv.url.pathname && filteredSearch === rootRequestEv.url.search) {
327
+ return rootRequestEv;
328
+ }
329
+ let events = rootRequestEv.sharedMap.get(REQUEST_ROUTE_LOADER_EVENTS);
330
+ if (!events) {
331
+ events = /* @__PURE__ */ new Map();
332
+ rootRequestEv.sharedMap.set(REQUEST_ROUTE_LOADER_EVENTS, events);
333
+ }
334
+ const eventKey = `${pathname}
335
+ ${filteredSearch}`;
336
+ let loaderRequestEv = events.get(eventKey);
337
+ if (!loaderRequestEv) {
338
+ url.pathname = pathname;
339
+ url.search = filteredSearch;
340
+ loaderRequestEv = Object.create(rootRequestEv, {
341
+ pathname: {
342
+ get: () => url.pathname,
343
+ enumerable: true
344
+ },
345
+ query: {
346
+ get: () => url.searchParams,
347
+ enumerable: true
348
+ },
349
+ url: {
350
+ value: url,
351
+ enumerable: true
352
+ }
353
+ });
354
+ events.set(eventKey, loaderRequestEv);
355
+ }
356
+ return loaderRequestEv;
357
+ };
358
+ async function runValidators(requestEv, validators, data) {
359
+ let lastResult = {
360
+ success: true,
361
+ data
362
+ };
363
+ if (validators) {
364
+ for (let i = 0; i < validators.length; i++) {
365
+ const validator = validators[i];
366
+ lastResult = await validator.validate(requestEv, data);
367
+ if (!lastResult.success) {
368
+ return lastResult;
369
+ }
370
+ data = lastResult.data;
371
+ }
372
+ }
373
+ return lastResult;
374
+ }
375
+ function verifySerializable(data, qrl) {
376
+ try {
377
+ _verifySerializable(data, void 0);
378
+ } catch (error) {
379
+ if (error instanceof Error && qrl.dev) {
380
+ error.loc = qrl.dev;
381
+ }
382
+ throw error;
383
+ }
384
+ }
385
+ const getRouteLoaderData = async (loaderQrl, validators, requestEv) => {
386
+ const loaderRequestEv = requestEv;
387
+ const result = await runValidators(requestEv, validators, void 0);
388
+ if (!result.success) {
389
+ return loaderRequestEv.fail(result.status ?? 500, result.error);
390
+ }
391
+ const resolved = await loaderQrl.call(loaderRequestEv, loaderRequestEv);
392
+ const value = typeof resolved === "function" ? resolved() : resolved;
393
+ if (isDev) {
394
+ verifySerializable(value, loaderQrl);
395
+ }
396
+ return value;
397
+ };
398
+ const loadRouteLoaderByQrl = (loaderId, loaderQrl, validators, requestEv) => {
399
+ const values = getRouteLoaderValues(requestEv);
400
+ if (loaderId in values) {
401
+ return Promise.resolve(values[loaderId]);
402
+ }
403
+ const promises = getRouteLoaderPromises(requestEv);
404
+ let promise = promises[loaderId];
405
+ if (!promise) {
406
+ promise = getRouteLoaderData(loaderQrl, validators, requestEv).then((value) => {
407
+ values[loaderId] = value;
408
+ return value;
409
+ }, (err) => {
410
+ delete promises[loaderId];
411
+ throw err;
412
+ });
413
+ promises[loaderId] = promise;
414
+ }
415
+ return promise;
416
+ };
417
+ class ServerRouteLoaderCapture {
418
+ hash;
419
+ qrl;
420
+ validators;
421
+ constructor(hash, qrl, validators) {
422
+ this.hash = hash;
423
+ this.qrl = qrl;
424
+ this.validators = validators;
425
+ }
426
+ load() {
427
+ const requestEv = getRequestEvent();
428
+ const values = getRouteLoaderValues(requestEv);
429
+ if (this.hash in values) {
430
+ return values[this.hash];
431
+ }
432
+ return loadRouteLoaderByQrl(this.hash, this.qrl, this.validators, requestEv);
433
+ }
434
+ [SerializerSymbol]() {
435
+ return this.hash;
436
+ }
437
+ }
438
+ const createRouteLoaderSignal = (loader, routeLoaderCtx, state) => {
439
+ const id = loader.__id;
440
+ const stateValues = state;
441
+ const resumeValueKey = getRouteLoaderValueStateKey(id);
442
+ const capture = isServer$1 ? new ServerRouteLoaderCapture(id, loader.__qrl, loader.__validators) : id;
443
+ const searchFilter = loader.__search;
444
+ const lastFetch = {};
445
+ return createAsyncQrl(/* @__PURE__ */ inlinedQrl(async (ctx) => {
446
+ const capture2 = _captures[0], id2 = _captures[1], lastFetch2 = _captures[2], resumeValueKey2 = _captures[3], routeLoaderCtx2 = _captures[4], searchFilter2 = _captures[5], stateValues2 = _captures[6];
447
+ if (ctx.info && typeof ctx.info === "object" && "__v" in ctx.info) {
448
+ const value = ctx.info.__v;
449
+ if (!isServer$1 && resumeValueKey2 in stateValues2) {
450
+ stateValues2[resumeValueKey2] = value;
451
+ }
452
+ return value;
453
+ }
454
+ if (isServer$1) {
455
+ return capture2.load();
456
+ }
457
+ const routePath = ctx.track(routeLoaderCtx2.loaderPaths, id2);
458
+ const pagePathname = ctx.track(routeLoaderCtx2, "pagePathname") || location.pathname;
459
+ const pageSearch = ctx.track(routeLoaderCtx2, "pageSearch") || location.search;
460
+ const pageUrl = new URL(pagePathname + pageSearch, location.href);
461
+ const mHash = getClientManifestHash(ctx);
462
+ const basePath = qwikRouterConfig.basePathname ?? "/";
463
+ const needsResumeFetch = stateValues2[resumeValueKey2] === _UNINITIALIZED;
464
+ const fetchRoutePath = routePath || (needsResumeFetch ? pageUrl.pathname : void 0);
465
+ if (!fetchRoutePath) {
466
+ return ctx.previous;
467
+ }
468
+ let fetchUrl = pageUrl;
469
+ if (searchFilter2) {
470
+ const filteredSearch = filterSearchParams(pageUrl.searchParams, searchFilter2);
471
+ if (ctx.previous !== void 0 && filteredSearch === lastFetch2.filteredSearch && fetchRoutePath === lastFetch2.routePath) {
472
+ return ctx.previous;
473
+ }
474
+ lastFetch2.filteredSearch = filteredSearch;
475
+ lastFetch2.routePath = fetchRoutePath;
476
+ fetchUrl = new URL(pageUrl.href);
477
+ fetchUrl.search = filteredSearch;
478
+ }
479
+ const response = await fetchRouteLoaderData(id2, fetchRoutePath, mHash, {
480
+ pageUrl: fetchUrl,
481
+ basePath,
482
+ ignoreCache: ctx.info === true,
483
+ signal: ctx.abortSignal
484
+ });
485
+ if (!response) {
486
+ throw new Error(`Loader ${id2} returned empty response`);
487
+ }
488
+ if (response.r) {
489
+ const goto = routeLoaderCtx2.goto;
490
+ if (goto) {
491
+ goto(response.r, {
492
+ replaceState: true
493
+ });
494
+ } else {
495
+ location.href = response.r;
496
+ }
497
+ return ctx.previous;
498
+ }
499
+ if (response.e) {
500
+ throw response.e;
501
+ }
502
+ if (needsResumeFetch) {
503
+ stateValues2[resumeValueKey2] = response.d;
504
+ }
505
+ return response.d;
506
+ }, "createRouteLoaderSignal_createAsync_0vpftJHSMyo", [
507
+ capture,
508
+ id,
509
+ lastFetch,
510
+ resumeValueKey,
511
+ routeLoaderCtx,
512
+ searchFilter,
513
+ stateValues
514
+ ]), {
515
+ serializationStrategy: loader.__serializationStrategy,
516
+ expires: loader.__expires,
517
+ poll: loader.__poll,
518
+ allowStale: loader.__allowStale
519
+ });
520
+ };
521
+ const ensureRouteLoaderSignal = (loader, state, routeLoaderCtx) => {
522
+ if (isServer$1 && loader.__serializationStrategy === "never") {
523
+ state[getRouteLoaderValueStateKey(loader.__id)] = _UNINITIALIZED;
524
+ }
525
+ return state[loader.__id] ||= createRouteLoaderSignal(loader, routeLoaderCtx, state);
526
+ };
527
+ const ensureRouteLoaderSignals = (mods, state, routeLoaderCtx) => {
528
+ const loaders = getModuleRouteLoaders(mods);
529
+ for (let i = 0; i < loaders.length; i++) {
530
+ const loader = loaders[i];
531
+ ensureRouteLoaderSignal(loader, state, routeLoaderCtx);
532
+ }
533
+ return loaders;
534
+ };
535
+ const loadRouteLoader = (loader, requestEv) => loadRouteLoaderByQrl(loader.__id, loader.__qrl, loader.__validators, getLoaderRequestEvent(loader, requestEv));
536
+ const getRouteLoaderResponse = async (loaderQrl, validators, requestEv) => {
537
+ try {
538
+ const value = await getRouteLoaderData(loaderQrl, validators, requestEv);
539
+ if (value && typeof value === "object" && value.failed) {
540
+ return {
541
+ e: new ServerError(requestEv.status(), value)
542
+ };
543
+ }
544
+ return {
545
+ d: value
546
+ };
547
+ } catch (err) {
548
+ if (err instanceof RedirectMessage) {
549
+ const location1 = requestEv.headers.get("Location") || "/";
550
+ requestEv.headers.delete("Location");
551
+ return {
552
+ r: location1
553
+ };
554
+ }
555
+ if (err instanceof ServerError) {
556
+ return {
557
+ e: err
558
+ };
559
+ }
560
+ throw err;
561
+ }
562
+ };
563
+ const routeLoaderQrl = (loaderQrl, ...rest) => {
564
+ const { validators, serializationStrategy, expires, poll, eTag, cacheKey, search, allowStale } = getLoaderOptions(rest);
565
+ function loader() {
566
+ const state = _resolveContextWithoutSequentialScope(RouteStateContext);
567
+ let signal = state[loader.__id];
568
+ if (!signal) {
569
+ const routeLoaderCtx = _resolveContextWithoutSequentialScope(RouteLoaderCtxContext);
570
+ signal = ensureRouteLoaderSignal(loader, state, routeLoaderCtx);
571
+ }
572
+ void signal.promise();
573
+ return signal;
574
+ }
575
+ loader.__brand = "server_loader";
576
+ loader.__qrl = loaderQrl;
577
+ loader.__validators = validators;
578
+ loader.__id = loaderQrl.getHash();
579
+ loader.__serializationStrategy = serializationStrategy;
580
+ loader.__expires = expires ?? 12e4;
581
+ loader.__poll = poll ?? false;
582
+ loader.__eTag = eTag;
583
+ loader.__cacheKey = cacheKey;
584
+ loader.__search = search;
585
+ loader.__allowStale = allowStale;
586
+ Object.freeze(loader);
587
+ return loader;
588
+ };
589
+ const routeLoader$ = /* @__PURE__ */ implicit$FirstArg(routeLoaderQrl);
590
+
1
591
  const deepFreeze = (obj) => {
2
592
  if (obj == null) {
3
593
  return obj;
@@ -15,4 +605,4 @@ const deepFreeze = (obj) => {
15
605
  return Object.freeze(obj);
16
606
  };
17
607
 
18
- export { deepFreeze as d };
608
+ export { AbortMessage as A, ContentContext as C, DocumentHeadContext as D, FULLPATH_HEADER as F, HttpStatusContext as H, QACTION_KEY as Q, RouteLocationContext as R, ServerError as S, _asyncRequestStore as _, ContentInternalContext as a, RouteNavigateContext as b, RouteStateContext as c, RouteLoaderCtxContext as d, ensureRouteLoaderSignals as e, fetchRouteLoaderData as f, RouteActionContext as g, RoutePreventNavigateContext as h, Q_ROUTE as i, getRequestEvent as j, QFN_KEY as k, QDATA_KEY as l, routeLoaderQrl as m, getRouteLoaderCtx as n, getRouteLoaderValues as o, loadRouteLoader as p, setRouteLoaders as q, routeLoader$ as r, setLoaderSignalValue as s, RedirectMessage as t, updateRouteLoaderPaths as u, deepFreeze as v, getRouteLoaders as w, getLoaderRequestEvent as x, resolveRouteLoaderByHash as y, getRouteLoaderResponse as z };
@@ -0,0 +1,31 @@
1
+ function toTitleCase(str) {
2
+ return str.replace(/\w\S*/g, (txt) => {
3
+ return txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase();
4
+ });
5
+ }
6
+ function addError(ctx, e) {
7
+ ctx.diagnostics.push({
8
+ type: "error",
9
+ message: e ? String(e.stack || e) : "Error"
10
+ });
11
+ }
12
+ function addWarning(ctx, message) {
13
+ ctx.diagnostics.push({
14
+ type: "warn",
15
+ message: String(message)
16
+ });
17
+ }
18
+ function msToString(ms) {
19
+ if (ms < 1) {
20
+ return ms.toFixed(2) + " ms";
21
+ }
22
+ if (ms < 1e3) {
23
+ return ms.toFixed(1) + " ms";
24
+ }
25
+ if (ms < 6e4) {
26
+ return (ms / 1e3).toFixed(1) + " s";
27
+ }
28
+ return (ms / 6e4).toFixed(1) + " m";
29
+ }
30
+
31
+ export { addError as a, addWarning as b, msToString as m, toTitleCase as t };
package/lib/chunks/fs.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { normalize, basename, dirname, relative } from 'node:path';
2
- import { t as toTitleCase, n as normalizePathname } from './pathname.mjs';
2
+ import { t as toTitleCase } from './format.mjs';
3
+ import { n as normalizePathname, e as ensureSlash } from './pathname.mjs';
3
4
 
4
5
  function parseRouteIndexName(extlessName) {
5
6
  let layoutName = "";
@@ -56,11 +57,8 @@ function normalizePath(path) {
56
57
  function getMenuPathname(opts, filePath) {
57
58
  let pathname = normalizePath(relative(opts.routesDir, filePath));
58
59
  pathname = `/` + normalizePath(dirname(pathname));
59
- let result = normalizePathname(pathname, opts.basePathname);
60
- if (!result.endsWith("/")) {
61
- result += "/";
62
- }
63
- return result;
60
+ const result = normalizePathname(pathname, opts.basePathname);
61
+ return ensureSlash(result);
64
62
  }
65
63
  function createFileId(routesDir, fsPath, explicitFileType) {
66
64
  const ids = [];