@askrjs/askr 0.0.33 → 0.0.35

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,5 @@
1
+ import { defineContext, readContext } from "../runtime/context.js";
2
+ import { markReactivePropsDirtySource, markReadableDerivedSubscribersDirty, notifyReadableReaders, recordReadableRead } from "../runtime/readable.js";
1
3
  import { getCurrentComponentInstance } from "../runtime/component.js";
2
4
  import { computeRank, matchSegments, parseSegments } from "./match.js";
3
5
  import { requireAuth, requireGuest, requirePermission, requireRole } from "./policy.js";
@@ -11,12 +13,14 @@ import { getRenderContext } from "../ssr/context.js";
11
13
  * Primary public authoring:
12
14
  * - `registerRoutes(() => { ... }, options?)`
13
15
  * - `group(options, () => { ... })`
16
+ * - `page(path, Component, () => { ... })`
17
+ * - `index(Component, options?)`
14
18
  * - `route(path, Component, options?)`
15
19
  * - `fallback(Component)`
20
+ * - `Outlet()` for page child rendering
16
21
  * - `currentRoute()` for render-time access
17
22
  *
18
23
  */
19
- /** Legacy flat route array — kept for resolver and route() accessor backward compat. */
20
24
  const routes = [];
21
25
  /** Normalized route records built by the declarative registration API. */
22
26
  const records = [];
@@ -24,6 +28,7 @@ const records = [];
24
28
  const registrationScopeStack = [];
25
29
  const registrationSessionStack = [];
26
30
  const namespaces = /* @__PURE__ */ new Set();
31
+ let registrationLocked = false;
27
32
  let defaultRouteAuthOptions;
28
33
  let activeClientRouteAuthOptions;
29
34
  const HAS_ROUTES_KEY = Symbol.for("__ASKR_HAS_ROUTES__");
@@ -72,6 +77,9 @@ function cachedSortedList(routeList) {
72
77
  }
73
78
  return sorted;
74
79
  }
80
+ let currentRouteSnapshot = buildRouteSnapshot("/", "", "");
81
+ const currentRouteSource = (() => currentRouteSnapshot);
82
+ currentRouteSource._readers = /* @__PURE__ */ new Map();
75
83
  let serverLocation = null;
76
84
  function setServerLocation(url) {
77
85
  serverLocation = url;
@@ -79,27 +87,87 @@ function setServerLocation(url) {
79
87
  function isPromise(value) {
80
88
  return value instanceof Promise;
81
89
  }
90
+ function buildRouteSnapshot(pathname, search, hash) {
91
+ const query = makeQuery(search);
92
+ const matches = computeMatchesFromRoutes(pathname, getActiveRoutes());
93
+ return Object.freeze({
94
+ path: pathname,
95
+ params: deepFreeze({ ...matches[0]?.params }),
96
+ query,
97
+ hash: hash || null,
98
+ matches: Object.freeze(matches)
99
+ });
100
+ }
101
+ function setCurrentRouteSnapshot(pathname, search, hash) {
102
+ currentRouteSnapshot = buildRouteSnapshot(pathname, search, hash);
103
+ const instance = getCurrentComponentInstance();
104
+ markReadableDerivedSubscribersDirty(currentRouteSource);
105
+ markReactivePropsDirtySource(currentRouteSource);
106
+ notifyReadableReaders(currentRouteSource, instance);
107
+ }
108
+ function matchFallbackPrefix(pathname, fallbackPrefix) {
109
+ const normalizedPath = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
110
+ const normalizedPrefix = fallbackPrefix.endsWith("/") && fallbackPrefix !== "/" ? fallbackPrefix.slice(0, -1) : fallbackPrefix;
111
+ if (normalizedPrefix === "/") {
112
+ const urlParts = normalizedPath === "/" ? [] : normalizedPath.split("/").filter(Boolean);
113
+ return { "*": urlParts.length === 0 ? "/" : urlParts.length === 1 ? urlParts[0] : "/" + urlParts.join("/") };
114
+ }
115
+ if (normalizedPath !== normalizedPrefix && !normalizedPath.startsWith(`${normalizedPrefix}/`)) return null;
116
+ const remainder = normalizedPath === normalizedPrefix ? "/" : normalizedPath.slice(normalizedPrefix.length + 1);
117
+ const remainderParts = remainder === "/" ? [] : remainder.split("/").filter(Boolean);
118
+ return { "*": remainderParts.length === 0 ? "/" : remainderParts.length === 1 ? remainderParts[0] : "/" + remainderParts.join("/") };
119
+ }
82
120
  function computeMatchesFromRoutes(pathname, routesList) {
83
- const matches = [];
121
+ const bestMatch = routesList === routes ? getMatchingRecord(pathname, records) : findBestResolvedRouteFromRoutes(pathname, routesList);
122
+ if (!bestMatch) return [];
123
+ return [{
124
+ path: "route" in bestMatch ? bestMatch.route.path : bestMatch.record.path,
125
+ params: deepFreeze({ ...bestMatch.params }),
126
+ name: "route" in bestMatch ? bestMatch.route.name : void 0,
127
+ namespace: "route" in bestMatch ? bestMatch.route.namespace : bestMatch.record.options.namespace
128
+ }];
129
+ }
130
+ function findBestResolvedRouteFromRoutes(pathname, routeList) {
84
131
  const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
85
132
  const urlParts = normalized === "/" ? [] : normalized.split("/").filter(Boolean);
86
- for (const r of routesList) {
87
- const params = matchSegments(urlParts, cachedSegs(r));
88
- if (params !== null) matches.push({
89
- pattern: r.path,
90
- params,
91
- name: r.name,
92
- namespace: r.namespace,
93
- rank: cachedRank(r)
94
- });
133
+ const sorted = cachedSortedList(routeList);
134
+ let bestRoute = null;
135
+ let bestParams = {};
136
+ let bestRank = -Infinity;
137
+ for (const route of sorted) {
138
+ if (route.fallbackPrefix) continue;
139
+ const rank = cachedRank(route);
140
+ if (rank < bestRank) break;
141
+ if (bestRoute !== null && rank === bestRank) continue;
142
+ const params = matchSegments(urlParts, cachedSegs(route));
143
+ if (params !== null) {
144
+ bestRoute = route;
145
+ bestParams = params;
146
+ bestRank = rank;
147
+ }
95
148
  }
96
- matches.sort((a, b) => b.rank - a.rank);
97
- return matches.map((m) => ({
98
- path: m.pattern,
99
- params: deepFreeze({ ...m.params }),
100
- name: m.name,
101
- namespace: m.namespace
102
- }));
149
+ if (bestRoute !== null) return {
150
+ route: bestRoute,
151
+ params: bestParams
152
+ };
153
+ let bestFallback = null;
154
+ let bestFallbackParams = null;
155
+ let bestPrefixLength = -1;
156
+ for (const route of routeList) {
157
+ const internalRoute = route;
158
+ if (!internalRoute.fallbackPrefix) continue;
159
+ const params = matchFallbackPrefix(normalized, internalRoute.fallbackPrefix);
160
+ if (params === null) continue;
161
+ if (internalRoute.fallbackPrefix.length > bestPrefixLength) {
162
+ bestFallback = internalRoute;
163
+ bestFallbackParams = params;
164
+ bestPrefixLength = internalRoute.fallbackPrefix.length;
165
+ }
166
+ }
167
+ return bestFallback && bestFallbackParams ? {
168
+ route: bestFallback,
169
+ params: bestFallbackParams
170
+ } : null;
103
171
  }
104
172
  function getActiveRoutes() {
105
173
  return getRenderContext()?.routes ?? routes;
@@ -125,6 +193,20 @@ function getCurrentLayoutChain() {
125
193
  for (const scope of registrationScopeStack) if (scope.layout) layoutChain.push({ component: scope.layout });
126
194
  return layoutChain;
127
195
  }
196
+ function getCurrentPageChain() {
197
+ const pageChain = [];
198
+ for (const scope of registrationScopeStack) if (scope.page) pageChain.push({ component: scope.page });
199
+ return pageChain;
200
+ }
201
+ function hasActivePageScope() {
202
+ return registrationScopeStack.some((scope) => !!scope.page);
203
+ }
204
+ function getCurrentScopeKind() {
205
+ return registrationScopeStack[registrationScopeStack.length - 1]?.kind ?? null;
206
+ }
207
+ function getCurrentPathPrefix() {
208
+ return registrationScopeStack[registrationScopeStack.length - 1]?.pathPrefix ?? "";
209
+ }
128
210
  function getCurrentInheritedPolicies() {
129
211
  const policies = [];
130
212
  for (const scope of registrationScopeStack) if (scope.policies.length > 0) policies.push(...scope.policies);
@@ -134,7 +216,6 @@ function getCurrentInheritedPolicies() {
134
216
  * Prevent route registrations after the app has started.
135
217
  * Enforced in production; tests may unlock explicitly.
136
218
  */
137
- let registrationLocked = false;
138
219
  function lockRouteRegistration() {
139
220
  registrationLocked = true;
140
221
  }
@@ -145,6 +226,37 @@ function validateRoutePath(path) {
145
226
  throw new Error(`Route parameter syntax uses {name} interpolation, not :name. Use "${suggested}" instead of "${path}".`);
146
227
  }
147
228
  }
229
+ function normalizeAbsoluteRoutePath(path) {
230
+ if (!path || path === "/") return "/";
231
+ return (path.endsWith("/") ? path.slice(0, -1) : path) || "/";
232
+ }
233
+ function joinRoutePaths(prefix, path) {
234
+ const normalizedPrefix = normalizeAbsoluteRoutePath(prefix || "/");
235
+ const normalizedPath = path.replace(/^\/+|\/+$/g, "");
236
+ if (!normalizedPath) return normalizedPrefix;
237
+ return normalizedPrefix === "/" ? `/${normalizedPath}` : `${normalizedPrefix}/${normalizedPath}`;
238
+ }
239
+ function resolvePageScopePath(path) {
240
+ if (!path) throw new Error("page(path, Component, fn) requires a non-empty path.");
241
+ if (path.startsWith("/")) {
242
+ validateRoutePath(path);
243
+ return normalizeAbsoluteRoutePath(path);
244
+ }
245
+ return joinRoutePaths(getCurrentPathPrefix(), path);
246
+ }
247
+ function resolveIndexPath() {
248
+ return normalizeAbsoluteRoutePath(getCurrentPathPrefix() || "/");
249
+ }
250
+ function resolveRouteRegistrationPath(path) {
251
+ if (path.startsWith("/")) {
252
+ if (hasActivePageScope()) throw new Error(`Child route paths inside page() must be relative. Use "${path.slice(1)}" instead of "${path}".`);
253
+ validateRoutePath(path);
254
+ return normalizeAbsoluteRoutePath(path);
255
+ }
256
+ const prefix = getCurrentPathPrefix();
257
+ if (!prefix) throw new Error(`Route path must begin with "/". Got: "${path}"`);
258
+ return joinRoutePaths(prefix, path);
259
+ }
148
260
  function insertRecordSorted(record) {
149
261
  let lo = 0;
150
262
  let hi = records.length;
@@ -169,6 +281,10 @@ function addRouteToStores(routeObj) {
169
281
  }
170
282
  /** Promises from in-flight lazy() imports, drained by createSPA / hydrateSPA. */
171
283
  const pendingLazy = /* @__PURE__ */ new Set();
284
+ const outletContext = defineContext(null);
285
+ function Outlet() {
286
+ return readContext(outletContext);
287
+ }
172
288
  /**
173
289
  * Snapshot the current in-flight lazy() imports.
174
290
  * Boot uses this before clearing route state so manifest-based startup can
@@ -227,9 +343,30 @@ function _drainLazy(additionalPending = []) {
227
343
  function group(options, fn) {
228
344
  pushGroupScope(options, fn);
229
345
  }
346
+ function page(path, Component, optionsOrFn, maybeFn) {
347
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
348
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
349
+ if (typeof Component !== "function") throw new Error("page(path, Component, fn) requires a component function as the second argument.");
350
+ if (typeof fn !== "function") throw new Error("page(path, Component, fn) requires a route definition callback as the final argument.");
351
+ pushPageScope(path, Component, options, fn);
352
+ }
353
+ function index(Component, options) {
354
+ registerRouteAtResolvedPath(resolveIndexPath(), Component, options);
355
+ }
230
356
  function fallback(Component) {
357
+ if (hasActivePageScope()) {
358
+ if (getCurrentScopeKind() !== "page") throw new Error("fallback() inside page() must be declared directly in the page scope, not inside nested group().");
359
+ registerRouteAtResolvedPath(`${getCurrentPathPrefix()}/*`, Component, void 0, {
360
+ isFallback: true,
361
+ fallbackPrefix: getCurrentPathPrefix()
362
+ });
363
+ return;
364
+ }
231
365
  if (!registrationScopeStack.every((scope) => scope.policies.length === 0 && !scope.state.guestOnly && !scope.state.authenticated)) throw new Error("fallback() can only be registered at the root scope. Use route(\"/*\", Component) if you need compatibility behavior.");
232
- route("/*", Component);
366
+ registerRouteAtResolvedPath("/*", Component, void 0, {
367
+ isFallback: true,
368
+ fallbackPrefix: "/"
369
+ });
233
370
  }
234
371
  function pushRegistrationScope(scope, fn) {
235
372
  registrationScopeStack.push(scope);
@@ -246,11 +383,28 @@ function pushGroupScope(options, fn) {
246
383
  });
247
384
  const policies = compileNodePolicies(options);
248
385
  pushRegistrationScope({
386
+ kind: "group",
387
+ pathPrefix: getCurrentPathPrefix(),
249
388
  layout: options.layout,
250
389
  policies,
251
390
  state: nextAccessScopeState(options, getCurrentAccessScopeState())
252
391
  }, fn);
253
392
  }
393
+ function pushPageScope(path, Component, options, fn) {
394
+ if (hasActivePageScope()) throw new Error("page() cannot be nested inside another page(). Use route() for child leaves or group() for inherited behavior inside the existing page scope.");
395
+ validateAccessMetadata(options, {
396
+ authConfigured: getCurrentRegistrationSession().authConfigured,
397
+ state: getCurrentAccessScopeState()
398
+ });
399
+ const policies = compileNodePolicies(options);
400
+ pushRegistrationScope({
401
+ kind: "page",
402
+ pathPrefix: resolvePageScopePath(path),
403
+ page: Component,
404
+ policies,
405
+ state: nextAccessScopeState(options, getCurrentAccessScopeState())
406
+ }, fn);
407
+ }
254
408
  function hasBuiltInAuthMetadata(node) {
255
409
  return node.auth !== void 0 || !!node.role || !!node.permission;
256
410
  }
@@ -297,6 +451,55 @@ function normalizeRouteOptions(options) {
297
451
  ...options.namespace ? { namespace: options.namespace } : {}
298
452
  };
299
453
  }
454
+ function applyPageChain(pageChain, params, content) {
455
+ let nextContent = content;
456
+ for (let i = pageChain.length - 1; i >= 0; i--) nextContent = outletContext.Scope({
457
+ value: nextContent,
458
+ children: pageChain[i].component(params)
459
+ });
460
+ return nextContent;
461
+ }
462
+ function registerRouteAtResolvedPath(path, Component, options, metadata) {
463
+ validateAccessMetadata(options ?? {}, {
464
+ authConfigured: getCurrentRegistrationSession().authConfigured,
465
+ state: getCurrentAccessScopeState()
466
+ });
467
+ const chain = getCurrentLayoutChain();
468
+ const pageChain = getCurrentPageChain();
469
+ const segments = parseSegments(path);
470
+ const rank = computeRank(segments);
471
+ const isFallback = metadata?.isFallback ?? path === "/*";
472
+ const comp = Component;
473
+ const normalizedOptions = normalizeRouteOptions(options);
474
+ const policies = [...getCurrentInheritedPolicies(), ...normalizedOptions?.policies ?? []];
475
+ const handler = (params) => {
476
+ let content = comp(params);
477
+ content = applyPageChain(pageChain, params, content);
478
+ for (let i = chain.length - 1; i >= 0; i--) content = chain[i].component({ children: content });
479
+ return content;
480
+ };
481
+ insertRecordSorted({
482
+ path,
483
+ component: comp,
484
+ segments,
485
+ rank,
486
+ layoutChain: chain,
487
+ pageChain,
488
+ options: normalizedOptions ? {
489
+ ...normalizedOptions,
490
+ ...policies.length > 0 ? { policies } : {}
491
+ } : policies.length > 0 ? { policies } : {},
492
+ isFallback,
493
+ handler,
494
+ ...metadata?.fallbackPrefix ? { fallbackPrefix: metadata.fallbackPrefix } : {}
495
+ });
496
+ addRouteToStores({
497
+ path,
498
+ handler,
499
+ namespace: normalizedOptions?.namespace ?? options?.namespace,
500
+ ...metadata?.fallbackPrefix ? { fallbackPrefix: metadata.fallbackPrefix } : {}
501
+ });
502
+ }
300
503
  function registerRoutes(definition, options = {}) {
301
504
  defaultRouteAuthOptions = options.auth;
302
505
  registrationSessionStack.push({ authConfigured: !!options.auth?.resolve });
@@ -341,8 +544,19 @@ function readCurrentRouteSnapshot() {
341
544
  });
342
545
  }
343
546
  function currentRoute() {
547
+ const instance = getCurrentComponentInstance();
548
+ if (!instance) throw new Error("currentRoute() can only be called during component render execution. Call currentRoute() from inside your component function.");
549
+ if (typeof window === "undefined" || instance.ssr) return readCurrentRouteSnapshot();
550
+ if (currentRouteSnapshot.path !== (window.location.pathname || "/")) {
551
+ recordReadableRead(currentRouteSource);
552
+ return readCurrentRouteSnapshot();
553
+ }
554
+ recordReadableRead(currentRouteSource);
344
555
  return readCurrentRouteSnapshot();
345
556
  }
557
+ function syncCurrentRouteSnapshot(pathname, search, hash) {
558
+ setCurrentRouteSnapshot(pathname, search, hash);
559
+ }
346
560
  function route(path, Component, options) {
347
561
  if (getExecutionModel() === "islands") throw new Error("Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead.");
348
562
  if (typeof path === "undefined") throw new Error("route() is only for route registration. Use currentRoute() inside components.");
@@ -350,41 +564,7 @@ function route(path, Component, options) {
350
564
  if (currentInst && currentInst.ssr) throw new Error("route() cannot be called during SSR rendering. Register routes at module load time instead.");
351
565
  if (registrationLocked) throw new Error("Route registration is locked after app startup. Register routes at module load time before calling createSPA or createSSR.");
352
566
  if (typeof Component !== "function") throw new Error("route(path, Component) requires a component function as the second argument. Passing JSX elements or VNodes directly is not supported.");
353
- validateRoutePath(path);
354
- validateAccessMetadata(options ?? {}, {
355
- authConfigured: getCurrentRegistrationSession().authConfigured,
356
- state: getCurrentAccessScopeState()
357
- });
358
- const chain = getCurrentLayoutChain();
359
- const segments = parseSegments(path);
360
- const rank = computeRank(segments);
361
- const isFallback = path === "/*";
362
- const comp = Component;
363
- const normalizedOptions = normalizeRouteOptions(options);
364
- const policies = [...getCurrentInheritedPolicies(), ...normalizedOptions?.policies ?? []];
365
- const handler = (params) => {
366
- let content = comp(params);
367
- for (let i = chain.length - 1; i >= 0; i--) content = chain[i].component({ children: content });
368
- return content;
369
- };
370
- insertRecordSorted({
371
- path,
372
- component: comp,
373
- segments,
374
- rank,
375
- layoutChain: chain,
376
- options: normalizedOptions ? {
377
- ...normalizedOptions,
378
- ...policies.length > 0 ? { policies } : {}
379
- } : policies.length > 0 ? { policies } : {},
380
- isFallback,
381
- handler
382
- });
383
- addRouteToStores({
384
- path,
385
- handler,
386
- namespace: normalizedOptions?.namespace ?? options?.namespace
387
- });
567
+ registerRouteAtResolvedPath(resolveRouteRegistrationPath(path), Component, options);
388
568
  }
389
569
  /**
390
570
  * Return the normalized route manifest built from registered route definitions.
@@ -410,14 +590,14 @@ function getManifest() {
410
590
  function _applyManifest(manifest) {
411
591
  defaultRouteAuthOptions = manifest.auth;
412
592
  for (const record of manifest.records) {
413
- records.push(record);
593
+ insertRecordSorted(record);
414
594
  addRouteToStores({
415
595
  path: record.path,
416
596
  handler: record.handler,
417
- namespace: record.options.namespace
597
+ namespace: record.options.namespace,
598
+ ..."fallbackPrefix" in record && typeof record.fallbackPrefix === "string" ? { fallbackPrefix: record.fallbackPrefix } : {}
418
599
  });
419
600
  }
420
- records.sort((a, b) => b.rank - a.rank);
421
601
  }
422
602
  /**
423
603
  * Get all registered routes (flat list, insertion order).
@@ -467,6 +647,26 @@ function clearRoutes() {
467
647
  function getLoadedNamespaces() {
468
648
  return Array.from(namespaces);
469
649
  }
650
+ function findBestScopedFallbackRecord(pathname, routeRecords) {
651
+ let bestRecord = null;
652
+ let bestParams = null;
653
+ let bestPrefixLength = -1;
654
+ for (const routeRecord of routeRecords) {
655
+ const record = routeRecord;
656
+ if (!record.fallbackPrefix) continue;
657
+ const params = matchFallbackPrefix(pathname, record.fallbackPrefix);
658
+ if (params === null) continue;
659
+ if (record.fallbackPrefix.length > bestPrefixLength) {
660
+ bestRecord = record;
661
+ bestParams = params;
662
+ bestPrefixLength = record.fallbackPrefix.length;
663
+ }
664
+ }
665
+ return bestRecord && bestParams ? {
666
+ record: bestRecord,
667
+ params: bestParams
668
+ } : null;
669
+ }
470
670
  /**
471
671
  * Resolve a path to a route handler.
472
672
  *
@@ -479,26 +679,32 @@ function resolveRoute(pathname) {
479
679
  const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
480
680
  const urlParts = normalized === "/" ? [] : normalized.split("/").filter(Boolean);
481
681
  for (const record of records) {
682
+ if (record.fallbackPrefix) continue;
482
683
  const params = matchSegments(urlParts, record.segments);
483
684
  if (params !== null) return {
484
685
  handler: record.handler,
485
686
  params
486
687
  };
487
688
  }
488
- return null;
689
+ const fallbackMatch = findBestScopedFallbackRecord(normalized, records);
690
+ return fallbackMatch ? {
691
+ handler: fallbackMatch.record.handler,
692
+ params: fallbackMatch.params
693
+ } : null;
489
694
  }
490
695
  function getMatchingRecord(target, routeRecords) {
491
696
  const location = parseLocation(target);
492
697
  const normalized = location.pathname.endsWith("/") && location.pathname !== "/" ? location.pathname.slice(0, -1) : location.pathname;
493
698
  const urlParts = normalized === "/" ? [] : normalized.split("/").filter(Boolean);
494
699
  for (const record of routeRecords) {
700
+ if (record.fallbackPrefix) continue;
495
701
  const params = matchSegments(urlParts, record.segments);
496
702
  if (params !== null) return {
497
703
  record,
498
704
  params
499
705
  };
500
706
  }
501
- return null;
707
+ return findBestScopedFallbackRecord(normalized, routeRecords);
502
708
  }
503
709
  function getRoutePolicies(options) {
504
710
  if (!options) return [];
@@ -571,29 +777,13 @@ function resolveRouteRequest(target, options = {}) {
571
777
  */
572
778
  function resolveRouteFromRoutes(pathname, routeList) {
573
779
  if (routeList === routes) return resolveRoute(pathname);
574
- const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
575
- const urlParts = normalized === "/" ? [] : normalized.split("/").filter(Boolean);
576
- const sorted = cachedSortedList(routeList);
577
- let bestHandler = null;
578
- let bestParams = {};
579
- let bestRank = -Infinity;
580
- for (const r of sorted) {
581
- const rank = cachedRank(r);
582
- if (rank < bestRank) break;
583
- if (bestHandler !== null && rank === bestRank) continue;
584
- const params = matchSegments(urlParts, cachedSegs(r));
585
- if (params !== null) {
586
- bestHandler = r.handler;
587
- bestParams = params;
588
- bestRank = rank;
589
- }
590
- }
591
- return bestHandler !== null ? {
592
- handler: bestHandler,
593
- params: bestParams
780
+ const match = findBestResolvedRouteFromRoutes(pathname, routeList);
781
+ return match ? {
782
+ handler: match.route.handler,
783
+ params: match.params
594
784
  } : null;
595
785
  }
596
786
  //#endregion
597
- export { _applyManifest, _drainLazy, _setActiveRouteAuthOptions, _snapshotLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, lazy, lockRouteRegistration, registerRoutes, resolveRoute, resolveRouteFromRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace };
787
+ export { Outlet, _applyManifest, _drainLazy, _setActiveRouteAuthOptions, _snapshotLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, index, lazy, lockRouteRegistration, page, registerRoutes, resolveRoute, resolveRouteFromRoutes, resolveRouteRequest, route, setServerLocation, syncCurrentRouteSnapshot, unloadNamespace };
598
788
 
599
789
  //# sourceMappingURL=route.js.map