@rangojs/router 0.0.0-experimental.9 → 0.0.0-experimental.a5f27bd5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. package/AGENTS.md +5 -0
  2. package/README.md +884 -4
  3. package/dist/bin/rango.js +1531 -155
  4. package/dist/vite/index.js +4440 -2170
  5. package/package.json +60 -54
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +262 -0
  8. package/skills/caching/SKILL.md +50 -21
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +12 -8
  11. package/skills/document-cache/SKILL.md +18 -16
  12. package/skills/fonts/SKILL.md +6 -4
  13. package/skills/hooks/SKILL.md +333 -71
  14. package/skills/host-router/SKILL.md +218 -0
  15. package/skills/intercept/SKILL.md +131 -8
  16. package/skills/layout/SKILL.md +100 -3
  17. package/skills/links/SKILL.md +74 -15
  18. package/skills/loader/SKILL.md +388 -38
  19. package/skills/middleware/SKILL.md +171 -34
  20. package/skills/mime-routes/SKILL.md +15 -11
  21. package/skills/parallel/SKILL.md +78 -1
  22. package/skills/prerender/SKILL.md +405 -45
  23. package/skills/rango/SKILL.md +85 -21
  24. package/skills/response-routes/SKILL.md +144 -91
  25. package/skills/route/SKILL.md +226 -14
  26. package/skills/router-setup/SKILL.md +123 -30
  27. package/skills/theme/SKILL.md +9 -8
  28. package/skills/typesafety/SKILL.md +316 -87
  29. package/skills/use-cache/SKILL.md +324 -0
  30. package/src/__internal.ts +102 -4
  31. package/src/bin/rango.ts +312 -15
  32. package/src/browser/action-coordinator.ts +97 -0
  33. package/src/browser/action-response-classifier.ts +99 -0
  34. package/src/browser/event-controller.ts +87 -64
  35. package/src/browser/history-state.ts +80 -0
  36. package/src/browser/intercept-utils.ts +52 -0
  37. package/src/browser/link-interceptor.ts +24 -4
  38. package/src/browser/logging.ts +55 -0
  39. package/src/browser/merge-segment-loaders.ts +20 -12
  40. package/src/browser/navigation-bridge.ts +285 -553
  41. package/src/browser/navigation-client.ts +123 -73
  42. package/src/browser/navigation-store.ts +33 -50
  43. package/src/browser/navigation-transaction.ts +295 -0
  44. package/src/browser/network-error-handler.ts +61 -0
  45. package/src/browser/partial-update.ts +261 -309
  46. package/src/browser/prefetch/cache.ts +154 -0
  47. package/src/browser/prefetch/fetch.ts +135 -0
  48. package/src/browser/prefetch/observer.ts +65 -0
  49. package/src/browser/prefetch/policy.ts +48 -0
  50. package/src/browser/prefetch/queue.ts +88 -0
  51. package/src/browser/rango-state.ts +112 -0
  52. package/src/browser/react/Link.tsx +182 -70
  53. package/src/browser/react/NavigationProvider.tsx +51 -11
  54. package/src/browser/react/context.ts +6 -0
  55. package/src/browser/react/filter-segment-order.ts +11 -0
  56. package/src/browser/react/index.ts +12 -12
  57. package/src/browser/react/location-state-shared.ts +95 -53
  58. package/src/browser/react/location-state.ts +60 -15
  59. package/src/browser/react/mount-context.ts +6 -1
  60. package/src/browser/react/nonce-context.ts +23 -0
  61. package/src/browser/react/shallow-equal.ts +27 -0
  62. package/src/browser/react/use-action.ts +29 -51
  63. package/src/browser/react/use-client-cache.ts +5 -3
  64. package/src/browser/react/use-handle.ts +29 -70
  65. package/src/browser/react/use-link-status.ts +6 -5
  66. package/src/browser/react/use-navigation.ts +22 -63
  67. package/src/browser/react/use-params.ts +65 -0
  68. package/src/browser/react/use-pathname.ts +47 -0
  69. package/src/browser/react/use-router.ts +63 -0
  70. package/src/browser/react/use-search-params.ts +56 -0
  71. package/src/browser/react/use-segments.ts +80 -97
  72. package/src/browser/response-adapter.ts +73 -0
  73. package/src/browser/rsc-router.tsx +106 -27
  74. package/src/browser/scroll-restoration.ts +92 -16
  75. package/src/browser/segment-reconciler.ts +216 -0
  76. package/src/browser/segment-structure-assert.ts +16 -0
  77. package/src/browser/server-action-bridge.ts +504 -599
  78. package/src/browser/shallow.ts +6 -1
  79. package/src/browser/types.ts +107 -47
  80. package/src/browser/validate-redirect-origin.ts +29 -0
  81. package/src/build/generate-manifest.ts +82 -21
  82. package/src/build/generate-route-types.ts +36 -752
  83. package/src/build/index.ts +6 -5
  84. package/src/build/route-trie.ts +39 -13
  85. package/src/build/route-types/ast-helpers.ts +25 -0
  86. package/src/build/route-types/ast-route-extraction.ts +98 -0
  87. package/src/build/route-types/codegen.ts +102 -0
  88. package/src/build/route-types/include-resolution.ts +411 -0
  89. package/src/build/route-types/param-extraction.ts +48 -0
  90. package/src/build/route-types/per-module-writer.ts +128 -0
  91. package/src/build/route-types/router-processing.ts +469 -0
  92. package/src/build/route-types/scan-filter.ts +78 -0
  93. package/src/build/runtime-discovery.ts +231 -0
  94. package/src/cache/background-task.ts +34 -0
  95. package/src/cache/cache-key-utils.ts +44 -0
  96. package/src/cache/cache-policy.ts +125 -0
  97. package/src/cache/cache-runtime.ts +338 -0
  98. package/src/cache/cache-scope.ts +120 -301
  99. package/src/cache/cf/cf-cache-store.ts +119 -7
  100. package/src/cache/cf/index.ts +8 -2
  101. package/src/cache/document-cache.ts +101 -72
  102. package/src/cache/handle-capture.ts +81 -0
  103. package/src/cache/handle-snapshot.ts +41 -0
  104. package/src/cache/index.ts +0 -15
  105. package/src/cache/memory-segment-store.ts +191 -13
  106. package/src/cache/profile-registry.ts +73 -0
  107. package/src/cache/read-through-swr.ts +134 -0
  108. package/src/cache/segment-codec.ts +256 -0
  109. package/src/cache/taint.ts +98 -0
  110. package/src/cache/types.ts +72 -122
  111. package/src/client.rsc.tsx +3 -1
  112. package/src/client.tsx +84 -126
  113. package/src/component-utils.ts +4 -4
  114. package/src/components/DefaultDocument.tsx +5 -1
  115. package/src/context-var.ts +86 -0
  116. package/src/debug.ts +17 -7
  117. package/src/errors.ts +77 -7
  118. package/src/handle.ts +15 -10
  119. package/src/handles/MetaTags.tsx +73 -20
  120. package/src/handles/breadcrumbs.ts +66 -0
  121. package/src/handles/index.ts +1 -0
  122. package/src/handles/meta.ts +30 -13
  123. package/src/host/cookie-handler.ts +21 -15
  124. package/src/host/errors.ts +8 -8
  125. package/src/host/index.ts +4 -7
  126. package/src/host/pattern-matcher.ts +27 -27
  127. package/src/host/router.ts +61 -39
  128. package/src/host/testing.ts +8 -8
  129. package/src/host/types.ts +15 -7
  130. package/src/host/utils.ts +1 -1
  131. package/src/href-client.ts +65 -45
  132. package/src/index.rsc.ts +133 -21
  133. package/src/index.ts +164 -52
  134. package/src/internal-debug.ts +11 -0
  135. package/src/loader.rsc.ts +25 -143
  136. package/src/loader.ts +27 -10
  137. package/src/network-error-thrower.tsx +3 -1
  138. package/src/outlet-provider.tsx +45 -0
  139. package/src/prerender/param-hash.ts +4 -2
  140. package/src/prerender/store.ts +158 -13
  141. package/src/prerender.ts +333 -26
  142. package/src/reverse.ts +184 -121
  143. package/src/root-error-boundary.tsx +41 -29
  144. package/src/route-content-wrapper.tsx +7 -4
  145. package/src/route-definition/dsl-helpers.ts +934 -0
  146. package/src/route-definition/helper-factories.ts +200 -0
  147. package/src/route-definition/helpers-types.ts +430 -0
  148. package/src/route-definition/index.ts +52 -0
  149. package/src/route-definition/redirect.ts +93 -0
  150. package/src/route-definition.ts +1 -1431
  151. package/src/route-map-builder.ts +156 -123
  152. package/src/route-name.ts +53 -0
  153. package/src/route-types.ts +48 -9
  154. package/src/router/content-negotiation.ts +116 -0
  155. package/src/router/debug-manifest.ts +72 -0
  156. package/src/router/error-handling.ts +9 -9
  157. package/src/router/find-match.ts +158 -0
  158. package/src/router/handler-context.ts +374 -81
  159. package/src/router/intercept-resolution.ts +24 -16
  160. package/src/router/lazy-includes.ts +234 -0
  161. package/src/router/loader-resolution.ts +215 -122
  162. package/src/router/logging.ts +248 -0
  163. package/src/router/manifest.ts +83 -32
  164. package/src/router/match-api.ts +118 -119
  165. package/src/router/match-context.ts +4 -2
  166. package/src/router/match-handlers.ts +440 -0
  167. package/src/router/match-middleware/background-revalidation.ts +80 -93
  168. package/src/router/match-middleware/cache-lookup.ts +336 -84
  169. package/src/router/match-middleware/cache-store.ts +43 -24
  170. package/src/router/match-middleware/intercept-resolution.ts +45 -20
  171. package/src/router/match-middleware/segment-resolution.ts +16 -8
  172. package/src/router/match-pipelines.ts +10 -45
  173. package/src/router/match-result.ts +34 -28
  174. package/src/router/metrics.ts +235 -15
  175. package/src/router/middleware-cookies.ts +55 -0
  176. package/src/router/middleware-types.ts +222 -0
  177. package/src/router/middleware.ts +324 -367
  178. package/src/router/pattern-matching.ts +197 -41
  179. package/src/router/prerender-match.ts +402 -0
  180. package/src/router/preview-match.ts +170 -0
  181. package/src/router/revalidation.ts +137 -38
  182. package/src/router/router-context.ts +36 -21
  183. package/src/router/router-interfaces.ts +452 -0
  184. package/src/router/router-options.ts +592 -0
  185. package/src/router/router-registry.ts +24 -0
  186. package/src/router/segment-resolution/fresh.ts +570 -0
  187. package/src/router/segment-resolution/helpers.ts +263 -0
  188. package/src/router/segment-resolution/loader-cache.ts +198 -0
  189. package/src/router/segment-resolution/revalidation.ts +1239 -0
  190. package/src/router/segment-resolution/static-store.ts +67 -0
  191. package/src/router/segment-resolution.ts +21 -1315
  192. package/src/router/segment-wrappers.ts +289 -0
  193. package/src/router/telemetry-otel.ts +299 -0
  194. package/src/router/telemetry.ts +300 -0
  195. package/src/router/timeout.ts +148 -0
  196. package/src/router/trie-matching.ts +96 -29
  197. package/src/router/types.ts +16 -9
  198. package/src/router.ts +590 -1983
  199. package/src/rsc/handler-context.ts +45 -0
  200. package/src/rsc/handler.ts +661 -1015
  201. package/src/rsc/helpers.ts +140 -6
  202. package/src/rsc/index.ts +0 -20
  203. package/src/rsc/loader-fetch.ts +209 -0
  204. package/src/rsc/manifest-init.ts +86 -0
  205. package/src/rsc/nonce.ts +14 -0
  206. package/src/rsc/origin-guard.ts +141 -0
  207. package/src/rsc/progressive-enhancement.ts +379 -0
  208. package/src/rsc/response-error.ts +37 -0
  209. package/src/rsc/response-route-handler.ts +347 -0
  210. package/src/rsc/rsc-rendering.ts +237 -0
  211. package/src/rsc/runtime-warnings.ts +42 -0
  212. package/src/rsc/server-action.ts +348 -0
  213. package/src/rsc/ssr-setup.ts +128 -0
  214. package/src/rsc/types.ts +38 -11
  215. package/src/search-params.ts +230 -0
  216. package/src/segment-system.tsx +25 -13
  217. package/src/server/context.ts +173 -48
  218. package/src/server/cookie-store.ts +190 -0
  219. package/src/server/fetchable-loader-store.ts +37 -0
  220. package/src/server/handle-store.ts +94 -15
  221. package/src/server/loader-registry.ts +15 -56
  222. package/src/server/request-context.ts +430 -70
  223. package/src/server.ts +35 -155
  224. package/src/ssr/index.tsx +100 -31
  225. package/src/static-handler.ts +114 -0
  226. package/src/theme/ThemeProvider.tsx +21 -15
  227. package/src/theme/ThemeScript.tsx +5 -5
  228. package/src/theme/constants.ts +5 -2
  229. package/src/theme/index.ts +4 -14
  230. package/src/theme/theme-context.ts +4 -30
  231. package/src/theme/theme-script.ts +21 -18
  232. package/src/types/boundaries.ts +158 -0
  233. package/src/types/cache-types.ts +198 -0
  234. package/src/types/error-types.ts +192 -0
  235. package/src/types/global-namespace.ts +100 -0
  236. package/src/types/handler-context.ts +687 -0
  237. package/src/types/index.ts +88 -0
  238. package/src/types/loader-types.ts +183 -0
  239. package/src/types/route-config.ts +170 -0
  240. package/src/types/route-entry.ts +102 -0
  241. package/src/types/segments.ts +148 -0
  242. package/src/types.ts +1 -1757
  243. package/src/urls/include-helper.ts +197 -0
  244. package/src/urls/index.ts +53 -0
  245. package/src/urls/path-helper-types.ts +339 -0
  246. package/src/urls/path-helper.ts +329 -0
  247. package/src/urls/pattern-types.ts +95 -0
  248. package/src/urls/response-types.ts +106 -0
  249. package/src/urls/type-extraction.ts +372 -0
  250. package/src/urls/urls-function.ts +98 -0
  251. package/src/urls.ts +1 -1282
  252. package/src/use-loader.tsx +85 -77
  253. package/src/vite/discovery/bundle-postprocess.ts +184 -0
  254. package/src/vite/discovery/discover-routers.ts +344 -0
  255. package/src/vite/discovery/prerender-collection.ts +385 -0
  256. package/src/vite/discovery/route-types-writer.ts +258 -0
  257. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  258. package/src/vite/discovery/state.ts +110 -0
  259. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  260. package/src/vite/index.ts +11 -1963
  261. package/src/vite/plugin-types.ts +131 -0
  262. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  263. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  264. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  265. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -51
  266. package/src/vite/plugins/expose-id-utils.ts +287 -0
  267. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  268. package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
  269. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  270. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  271. package/src/vite/plugins/expose-ids/types.ts +45 -0
  272. package/src/vite/plugins/expose-internal-ids.ts +569 -0
  273. package/src/vite/plugins/refresh-cmd.ts +65 -0
  274. package/src/vite/plugins/use-cache-transform.ts +323 -0
  275. package/src/vite/plugins/version-injector.ts +83 -0
  276. package/src/vite/plugins/version-plugin.ts +254 -0
  277. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  278. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  279. package/src/vite/rango.ts +510 -0
  280. package/src/vite/router-discovery.ts +785 -0
  281. package/src/vite/utils/ast-handler-extract.ts +517 -0
  282. package/src/vite/utils/banner.ts +36 -0
  283. package/src/vite/utils/bundle-analysis.ts +137 -0
  284. package/src/vite/utils/manifest-utils.ts +70 -0
  285. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  286. package/src/vite/utils/prerender-utils.ts +189 -0
  287. package/src/vite/utils/shared-utils.ts +169 -0
  288. package/CLAUDE.md +0 -43
  289. package/src/browser/lru-cache.ts +0 -69
  290. package/src/browser/request-controller.ts +0 -164
  291. package/src/cache/memory-store.ts +0 -253
  292. package/src/href-context.ts +0 -33
  293. package/src/router.gen.ts +0 -6
  294. package/src/urls.gen.ts +0 -8
  295. package/src/vite/expose-handle-id.ts +0 -209
  296. package/src/vite/expose-loader-id.ts +0 -426
  297. package/src/vite/expose-location-state-id.ts +0 -177
  298. package/src/vite/expose-prerender-handler-id.ts +0 -429
  299. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -60,7 +60,7 @@ export function invokeOnError<TEnv = any>(
60
60
  error: unknown,
61
61
  phase: ErrorPhase,
62
62
  context: InvokeOnErrorContext<TEnv>,
63
- logPrefix: string = "Router"
63
+ logPrefix: string = "Router",
64
64
  ): void {
65
65
  if (!onError) return;
66
66
 
@@ -74,8 +74,8 @@ export function invokeOnError<TEnv = any>(
74
74
  phase,
75
75
  request: context.request,
76
76
  url: context.url,
77
- pathname: context.url.pathname,
78
- method: context.request.method,
77
+ pathname: context.url?.pathname,
78
+ method: context.request?.method,
79
79
  routeKey: context.routeKey,
80
80
  params: context.params,
81
81
  segmentId: context.segmentId,
@@ -112,7 +112,7 @@ export function invokeOnError<TEnv = any>(
112
112
  */
113
113
  export function findNearestErrorBoundary(
114
114
  entry: EntryData | null,
115
- defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler
115
+ defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler,
116
116
  ): ReactNode | ErrorBoundaryHandler | null {
117
117
  let current: EntryData | null = entry;
118
118
 
@@ -148,7 +148,7 @@ export function findNearestErrorBoundary(
148
148
  */
149
149
  export function findNearestNotFoundBoundary(
150
150
  entry: EntryData | null,
151
- defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler
151
+ defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler,
152
152
  ): ReactNode | NotFoundBoundaryHandler | null {
153
153
  let current: EntryData | null = entry;
154
154
 
@@ -172,7 +172,7 @@ export function findNearestNotFoundBoundary(
172
172
  export function createErrorInfo(
173
173
  error: unknown,
174
174
  segmentId: string,
175
- segmentType: ErrorInfo["segmentType"]
175
+ segmentType: ErrorInfo["segmentType"],
176
176
  ): ErrorInfo {
177
177
  const isDev = process.env.NODE_ENV !== "production";
178
178
 
@@ -205,7 +205,7 @@ export function createErrorSegment(
205
205
  errorInfo: ErrorInfo,
206
206
  fallback: ReactNode | ErrorBoundaryHandler,
207
207
  entry: EntryData,
208
- params: Record<string, string>
208
+ params: Record<string, string>,
209
209
  ): ResolvedSegment {
210
210
  // Determine the component to render
211
211
  let component: ReactNode;
@@ -241,7 +241,7 @@ export function createNotFoundInfo(
241
241
  error: { message: string },
242
242
  segmentId: string,
243
243
  segmentType: NotFoundInfo["segmentType"],
244
- pathname?: string
244
+ pathname?: string,
245
245
  ): NotFoundInfo {
246
246
  return {
247
247
  message: error.message,
@@ -259,7 +259,7 @@ export function createNotFoundSegment(
259
259
  notFoundInfo: NotFoundInfo,
260
260
  fallback: ReactNode | NotFoundBoundaryHandler,
261
261
  entry: EntryData,
262
- params: Record<string, string>
262
+ params: Record<string, string>,
263
263
  ): ResolvedSegment {
264
264
  // Determine the component to render
265
265
  let component: ReactNode;
@@ -0,0 +1,158 @@
1
+ import { tryTrieMatch } from "./trie-matching.js";
2
+ import { getRouteTrie, getRouterTrie } from "../route-map-builder.js";
3
+ import {
4
+ findMatch as findRouteMatch,
5
+ isLazyEvaluationNeeded,
6
+ type RouteMatchResult,
7
+ } from "./pattern-matching.js";
8
+ import type { MetricsStore } from "../server/context";
9
+ import type { RouteEntry } from "../types";
10
+
11
+ export interface FindMatchDeps<TEnv = any> {
12
+ routesEntries: RouteEntry<TEnv>[];
13
+ evaluateLazyEntry: (entry: RouteEntry<TEnv>) => void;
14
+ routerId: string;
15
+ }
16
+
17
+ /**
18
+ * Create a findMatch function bound to router state.
19
+ * Includes single-entry cache to avoid redundant matching within the same request.
20
+ */
21
+ export function createFindMatch<TEnv = any>(
22
+ deps: FindMatchDeps<TEnv>,
23
+ ): (pathname: string, ms?: MetricsStore) => RouteMatchResult<TEnv> | null {
24
+ // Single-entry cache for findMatch to avoid redundant matching within the same request.
25
+ // previewMatch and match both call findMatch with the same pathname — this ensures
26
+ // the route matching work (which may check thousands of routes) only happens once.
27
+ let lastFindMatchPathname: string | null = null;
28
+ let lastFindMatchResult: RouteMatchResult<TEnv> | null = null;
29
+
30
+ // Wrapper for findMatch that uses routesEntries
31
+ // Handles lazy evaluation by evaluating lazy entries on first match.
32
+ // Phase 1: try O(path_length) trie match.
33
+ // Phase 2: fall back to regex iteration.
34
+ return function findMatch(
35
+ pathname: string,
36
+ ms?: MetricsStore,
37
+ ): RouteMatchResult<TEnv> | null {
38
+ // Return cached result if same pathname (avoids double-match per request)
39
+ if (lastFindMatchPathname === pathname) {
40
+ return lastFindMatchResult;
41
+ }
42
+
43
+ // Helper to push sub-metrics
44
+ const pushMetric = ms
45
+ ? (label: string, start: number) => {
46
+ ms.metrics.push({
47
+ label,
48
+ duration: performance.now() - start,
49
+ startTime: start - ms.requestStart,
50
+ });
51
+ }
52
+ : undefined;
53
+
54
+ // Phase 1: Try trie match (O(path_length))
55
+ // Prefer per-router trie (isolated) over global trie (merged).
56
+ const routeTrie = getRouterTrie(deps.routerId) ?? getRouteTrie();
57
+ if (routeTrie) {
58
+ const trieStart = performance.now();
59
+ const trieResult = tryTrieMatch(routeTrie, pathname);
60
+ pushMetric?.("match:trie", trieStart);
61
+
62
+ if (trieResult) {
63
+ // Find the RouteEntry that contains this route.
64
+ // Multiple entries can share the same staticPrefix (e.g., several
65
+ // include("/", patterns) calls all produce staticPrefix=""). Evaluate
66
+ // each candidate and pick the one whose routes include the matched key.
67
+ const entryStart = performance.now();
68
+ let entry: RouteEntry<TEnv> | undefined;
69
+ let fallbackEntry: RouteEntry<TEnv> | undefined;
70
+
71
+ for (const e of deps.routesEntries) {
72
+ if (e.staticPrefix !== trieResult.sp) continue;
73
+ if (!fallbackEntry) fallbackEntry = e;
74
+ deps.evaluateLazyEntry(e);
75
+ if (
76
+ e.routes &&
77
+ trieResult.routeKey in (e.routes as Record<string, unknown>)
78
+ ) {
79
+ entry = e;
80
+ break;
81
+ }
82
+ }
83
+
84
+ // If no entry had the route in its routes map, use the first matching
85
+ // entry as fallback (handles main entry with inline routes not yet
86
+ // reflected in its routes object).
87
+ if (!entry) entry = fallbackEntry;
88
+
89
+ // If entry not found (nested include not yet discovered), evaluate parent
90
+ if (!entry) {
91
+ const parent = deps.routesEntries.find(
92
+ (e) =>
93
+ trieResult.sp.startsWith(e.staticPrefix) &&
94
+ e.staticPrefix !== trieResult.sp,
95
+ );
96
+ if (parent) {
97
+ const lazyStart = performance.now();
98
+ deps.evaluateLazyEntry(parent);
99
+ pushMetric?.("match:lazy-eval", lazyStart);
100
+ }
101
+ entry = deps.routesEntries.find(
102
+ (e) => e.staticPrefix === trieResult.sp,
103
+ );
104
+ }
105
+ pushMetric?.("match:entry-resolve", entryStart);
106
+
107
+ if (entry) {
108
+ lastFindMatchPathname = pathname;
109
+ lastFindMatchResult = {
110
+ entry,
111
+ routeKey: trieResult.routeKey,
112
+ params: trieResult.params,
113
+ optionalParams: new Set(trieResult.optionalParams || []),
114
+ redirectTo: trieResult.redirectTo,
115
+ ancestry: trieResult.ancestry,
116
+ ...(trieResult.pr ? { pr: true } : {}),
117
+ ...(trieResult.pt ? { pt: true } : {}),
118
+ ...(trieResult.responseType
119
+ ? { responseType: trieResult.responseType }
120
+ : {}),
121
+ ...(trieResult.negotiateVariants
122
+ ? { negotiateVariants: trieResult.negotiateVariants }
123
+ : {}),
124
+ ...(trieResult.rscFirst ? { rscFirst: true } : {}),
125
+ };
126
+ return lastFindMatchResult;
127
+ }
128
+ }
129
+ }
130
+
131
+ // Phase 2: Fall back to existing matching (regex iteration)
132
+ const regexStart = performance.now();
133
+ let result = findRouteMatch(pathname, deps.routesEntries);
134
+
135
+ // If we hit a lazy entry that needs evaluation, evaluate and retry.
136
+ // Cap iterations to prevent infinite loops from pathological nesting.
137
+ const MAX_LAZY_ITERATIONS = 100;
138
+ let iterations = 0;
139
+ while (isLazyEvaluationNeeded(result)) {
140
+ if (++iterations > MAX_LAZY_ITERATIONS) {
141
+ console.error(
142
+ `[@rangojs/router] Exceeded ${MAX_LAZY_ITERATIONS} lazy evaluation iterations ` +
143
+ `for pathname "${pathname}". This likely indicates circular lazy includes.`,
144
+ );
145
+ lastFindMatchPathname = pathname;
146
+ lastFindMatchResult = null;
147
+ return null;
148
+ }
149
+ deps.evaluateLazyEntry(result.lazyEntry);
150
+ result = findRouteMatch(pathname, deps.routesEntries);
151
+ }
152
+ pushMetric?.("match:regex-fallback", regexStart);
153
+
154
+ lastFindMatchPathname = pathname;
155
+ lastFindMatchResult = result;
156
+ return result;
157
+ };
158
+ }