@rangojs/router 0.0.0-experimental.11 → 0.0.0-experimental.111

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 (1141) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +1037 -4
  3. package/dist/__internal.d.ts +83 -0
  4. package/dist/__internal.d.ts.map +1 -0
  5. package/dist/__internal.js +19 -0
  6. package/dist/__internal.js.map +1 -0
  7. package/dist/__mocks__/version.d.ts +7 -0
  8. package/dist/__mocks__/version.d.ts.map +1 -0
  9. package/dist/__mocks__/version.js +7 -0
  10. package/dist/__mocks__/version.js.map +1 -0
  11. package/dist/__tests__/client-href.test.d.ts +2 -0
  12. package/dist/__tests__/client-href.test.d.ts.map +1 -0
  13. package/dist/__tests__/client-href.test.js +74 -0
  14. package/dist/__tests__/client-href.test.js.map +1 -0
  15. package/dist/__tests__/component-utils.test.d.ts +2 -0
  16. package/dist/__tests__/component-utils.test.d.ts.map +1 -0
  17. package/dist/__tests__/component-utils.test.js +51 -0
  18. package/dist/__tests__/component-utils.test.js.map +1 -0
  19. package/dist/__tests__/event-controller.test.d.ts +2 -0
  20. package/dist/__tests__/event-controller.test.d.ts.map +1 -0
  21. package/dist/__tests__/event-controller.test.js +538 -0
  22. package/dist/__tests__/event-controller.test.js.map +1 -0
  23. package/dist/__tests__/helpers/route-tree.d.ts +118 -0
  24. package/dist/__tests__/helpers/route-tree.d.ts.map +1 -0
  25. package/dist/__tests__/helpers/route-tree.js +374 -0
  26. package/dist/__tests__/helpers/route-tree.js.map +1 -0
  27. package/dist/__tests__/match-result.test.d.ts +2 -0
  28. package/dist/__tests__/match-result.test.d.ts.map +1 -0
  29. package/dist/__tests__/match-result.test.js +154 -0
  30. package/dist/__tests__/match-result.test.js.map +1 -0
  31. package/dist/__tests__/navigation-store.test.d.ts +2 -0
  32. package/dist/__tests__/navigation-store.test.d.ts.map +1 -0
  33. package/dist/__tests__/navigation-store.test.js +440 -0
  34. package/dist/__tests__/navigation-store.test.js.map +1 -0
  35. package/dist/__tests__/partial-update.test.d.ts +2 -0
  36. package/dist/__tests__/partial-update.test.d.ts.map +1 -0
  37. package/dist/__tests__/partial-update.test.js +1009 -0
  38. package/dist/__tests__/partial-update.test.js.map +1 -0
  39. package/dist/__tests__/reverse-types.test.d.ts +8 -0
  40. package/dist/__tests__/reverse-types.test.d.ts.map +1 -0
  41. package/dist/__tests__/reverse-types.test.js +656 -0
  42. package/dist/__tests__/reverse-types.test.js.map +1 -0
  43. package/dist/__tests__/route-definition.test.d.ts +2 -0
  44. package/dist/__tests__/route-definition.test.d.ts.map +1 -0
  45. package/dist/__tests__/route-definition.test.js +55 -0
  46. package/dist/__tests__/route-definition.test.js.map +1 -0
  47. package/dist/__tests__/router-helpers.test.d.ts +2 -0
  48. package/dist/__tests__/router-helpers.test.d.ts.map +1 -0
  49. package/dist/__tests__/router-helpers.test.js +377 -0
  50. package/dist/__tests__/router-helpers.test.js.map +1 -0
  51. package/dist/__tests__/router-integration-2.test.d.ts +2 -0
  52. package/dist/__tests__/router-integration-2.test.d.ts.map +1 -0
  53. package/dist/__tests__/router-integration-2.test.js +426 -0
  54. package/dist/__tests__/router-integration-2.test.js.map +1 -0
  55. package/dist/__tests__/router-integration.test.d.ts +2 -0
  56. package/dist/__tests__/router-integration.test.d.ts.map +1 -0
  57. package/dist/__tests__/router-integration.test.js +1051 -0
  58. package/dist/__tests__/router-integration.test.js.map +1 -0
  59. package/dist/__tests__/search-params.test.d.ts +5 -0
  60. package/dist/__tests__/search-params.test.d.ts.map +1 -0
  61. package/dist/__tests__/search-params.test.js +306 -0
  62. package/dist/__tests__/search-params.test.js.map +1 -0
  63. package/dist/__tests__/segment-system.test.d.ts +2 -0
  64. package/dist/__tests__/segment-system.test.d.ts.map +1 -0
  65. package/dist/__tests__/segment-system.test.js +627 -0
  66. package/dist/__tests__/segment-system.test.js.map +1 -0
  67. package/dist/__tests__/static-handler-types.test.d.ts +8 -0
  68. package/dist/__tests__/static-handler-types.test.d.ts.map +1 -0
  69. package/dist/__tests__/static-handler-types.test.js +63 -0
  70. package/dist/__tests__/static-handler-types.test.js.map +1 -0
  71. package/dist/__tests__/urls.test.d.ts +2 -0
  72. package/dist/__tests__/urls.test.d.ts.map +1 -0
  73. package/dist/__tests__/urls.test.js +421 -0
  74. package/dist/__tests__/urls.test.js.map +1 -0
  75. package/dist/__tests__/use-mount.test.d.ts +2 -0
  76. package/dist/__tests__/use-mount.test.d.ts.map +1 -0
  77. package/dist/__tests__/use-mount.test.js +35 -0
  78. package/dist/__tests__/use-mount.test.js.map +1 -0
  79. package/dist/bin/rango.d.ts +2 -0
  80. package/dist/bin/rango.d.ts.map +1 -0
  81. package/dist/bin/rango.js +1635 -158
  82. package/dist/bin/rango.js.map +1 -0
  83. package/dist/browser/event-controller.d.ts +191 -0
  84. package/dist/browser/event-controller.d.ts.map +1 -0
  85. package/dist/browser/event-controller.js +559 -0
  86. package/dist/browser/event-controller.js.map +1 -0
  87. package/dist/browser/index.d.ts +2 -0
  88. package/dist/browser/index.d.ts.map +1 -0
  89. package/dist/browser/index.js +14 -0
  90. package/dist/browser/index.js.map +1 -0
  91. package/dist/browser/link-interceptor.d.ts +38 -0
  92. package/dist/browser/link-interceptor.d.ts.map +1 -0
  93. package/dist/browser/link-interceptor.js +99 -0
  94. package/dist/browser/link-interceptor.js.map +1 -0
  95. package/dist/browser/logging.d.ts +10 -0
  96. package/dist/browser/logging.d.ts.map +1 -0
  97. package/dist/browser/logging.js +29 -0
  98. package/dist/browser/logging.js.map +1 -0
  99. package/dist/browser/lru-cache.d.ts +17 -0
  100. package/dist/browser/lru-cache.d.ts.map +1 -0
  101. package/dist/browser/lru-cache.js +50 -0
  102. package/dist/browser/lru-cache.js.map +1 -0
  103. package/dist/browser/merge-segment-loaders.d.ts +39 -0
  104. package/dist/browser/merge-segment-loaders.d.ts.map +1 -0
  105. package/dist/browser/merge-segment-loaders.js +102 -0
  106. package/dist/browser/merge-segment-loaders.js.map +1 -0
  107. package/dist/browser/navigation-bridge.d.ts +102 -0
  108. package/dist/browser/navigation-bridge.d.ts.map +1 -0
  109. package/dist/browser/navigation-bridge.js +708 -0
  110. package/dist/browser/navigation-bridge.js.map +1 -0
  111. package/dist/browser/navigation-client.d.ts +25 -0
  112. package/dist/browser/navigation-client.d.ts.map +1 -0
  113. package/dist/browser/navigation-client.js +157 -0
  114. package/dist/browser/navigation-client.js.map +1 -0
  115. package/dist/browser/navigation-store.d.ts +101 -0
  116. package/dist/browser/navigation-store.d.ts.map +1 -0
  117. package/dist/browser/navigation-store.js +625 -0
  118. package/dist/browser/navigation-store.js.map +1 -0
  119. package/dist/browser/partial-update.d.ts +75 -0
  120. package/dist/browser/partial-update.d.ts.map +1 -0
  121. package/dist/browser/partial-update.js +426 -0
  122. package/dist/browser/partial-update.js.map +1 -0
  123. package/dist/browser/react/Link.d.ts +86 -0
  124. package/dist/browser/react/Link.d.ts.map +1 -0
  125. package/dist/browser/react/Link.js +128 -0
  126. package/dist/browser/react/Link.js.map +1 -0
  127. package/dist/browser/react/NavigationProvider.d.ts +63 -0
  128. package/dist/browser/react/NavigationProvider.d.ts.map +1 -0
  129. package/dist/browser/react/NavigationProvider.js +216 -0
  130. package/dist/browser/react/NavigationProvider.js.map +1 -0
  131. package/dist/browser/react/ScrollRestoration.d.ts +75 -0
  132. package/dist/browser/react/ScrollRestoration.d.ts.map +1 -0
  133. package/dist/browser/react/ScrollRestoration.js +57 -0
  134. package/dist/browser/react/ScrollRestoration.js.map +1 -0
  135. package/dist/browser/react/context.d.ts +46 -0
  136. package/dist/browser/react/context.d.ts.map +1 -0
  137. package/dist/browser/react/context.js +10 -0
  138. package/dist/browser/react/context.js.map +1 -0
  139. package/dist/browser/react/index.d.ts +11 -0
  140. package/dist/browser/react/index.d.ts.map +1 -0
  141. package/dist/browser/react/index.js +22 -0
  142. package/dist/browser/react/index.js.map +1 -0
  143. package/dist/browser/react/location-state-shared.d.ts +63 -0
  144. package/dist/browser/react/location-state-shared.d.ts.map +1 -0
  145. package/dist/browser/react/location-state-shared.js +81 -0
  146. package/dist/browser/react/location-state-shared.js.map +1 -0
  147. package/dist/browser/react/location-state.d.ts +23 -0
  148. package/dist/browser/react/location-state.d.ts.map +1 -0
  149. package/dist/browser/react/location-state.js +29 -0
  150. package/dist/browser/react/location-state.js.map +1 -0
  151. package/dist/browser/react/mount-context.d.ts +24 -0
  152. package/dist/browser/react/mount-context.d.ts.map +1 -0
  153. package/dist/browser/react/mount-context.js +24 -0
  154. package/dist/browser/react/mount-context.js.map +1 -0
  155. package/dist/browser/react/use-action.d.ts +64 -0
  156. package/dist/browser/react/use-action.d.ts.map +1 -0
  157. package/dist/browser/react/use-action.js +134 -0
  158. package/dist/browser/react/use-action.js.map +1 -0
  159. package/dist/browser/react/use-client-cache.d.ts +41 -0
  160. package/dist/browser/react/use-client-cache.d.ts.map +1 -0
  161. package/dist/browser/react/use-client-cache.js +39 -0
  162. package/dist/browser/react/use-client-cache.js.map +1 -0
  163. package/dist/browser/react/use-handle.d.ts +31 -0
  164. package/dist/browser/react/use-handle.d.ts.map +1 -0
  165. package/dist/browser/react/use-handle.js +144 -0
  166. package/dist/browser/react/use-handle.js.map +1 -0
  167. package/dist/browser/react/use-href.d.ts +33 -0
  168. package/dist/browser/react/use-href.d.ts.map +1 -0
  169. package/dist/browser/react/use-href.js +39 -0
  170. package/dist/browser/react/use-href.js.map +1 -0
  171. package/dist/browser/react/use-link-status.d.ts +37 -0
  172. package/dist/browser/react/use-link-status.d.ts.map +1 -0
  173. package/dist/browser/react/use-link-status.js +99 -0
  174. package/dist/browser/react/use-link-status.js.map +1 -0
  175. package/dist/browser/react/use-mount.d.ts +25 -0
  176. package/dist/browser/react/use-mount.d.ts.map +1 -0
  177. package/dist/browser/react/use-mount.js +30 -0
  178. package/dist/browser/react/use-mount.js.map +1 -0
  179. package/dist/browser/react/use-navigation.d.ts +27 -0
  180. package/dist/browser/react/use-navigation.d.ts.map +1 -0
  181. package/dist/browser/react/use-navigation.js +87 -0
  182. package/dist/browser/react/use-navigation.js.map +1 -0
  183. package/dist/browser/react/use-segments.d.ts +38 -0
  184. package/dist/browser/react/use-segments.d.ts.map +1 -0
  185. package/dist/browser/react/use-segments.js +130 -0
  186. package/dist/browser/react/use-segments.js.map +1 -0
  187. package/dist/browser/request-controller.d.ts +26 -0
  188. package/dist/browser/request-controller.d.ts.map +1 -0
  189. package/dist/browser/request-controller.js +147 -0
  190. package/dist/browser/request-controller.js.map +1 -0
  191. package/dist/browser/rsc-router.d.ts +129 -0
  192. package/dist/browser/rsc-router.d.ts.map +1 -0
  193. package/dist/browser/rsc-router.js +195 -0
  194. package/dist/browser/rsc-router.js.map +1 -0
  195. package/dist/browser/scroll-restoration.d.ts +93 -0
  196. package/dist/browser/scroll-restoration.d.ts.map +1 -0
  197. package/dist/browser/scroll-restoration.js +321 -0
  198. package/dist/browser/scroll-restoration.js.map +1 -0
  199. package/dist/browser/segment-structure-assert.d.ts +17 -0
  200. package/dist/browser/segment-structure-assert.d.ts.map +1 -0
  201. package/dist/browser/segment-structure-assert.js +59 -0
  202. package/dist/browser/segment-structure-assert.js.map +1 -0
  203. package/dist/browser/server-action-bridge.d.ts +26 -0
  204. package/dist/browser/server-action-bridge.d.ts.map +1 -0
  205. package/dist/browser/server-action-bridge.js +668 -0
  206. package/dist/browser/server-action-bridge.js.map +1 -0
  207. package/dist/browser/shallow.d.ts +12 -0
  208. package/dist/browser/shallow.d.ts.map +1 -0
  209. package/dist/browser/shallow.js +34 -0
  210. package/dist/browser/shallow.js.map +1 -0
  211. package/dist/browser/types.d.ts +369 -0
  212. package/dist/browser/types.d.ts.map +1 -0
  213. package/dist/browser/types.js +2 -0
  214. package/dist/browser/types.js.map +1 -0
  215. package/dist/build/__tests__/generate-cli.test.d.ts +2 -0
  216. package/dist/build/__tests__/generate-cli.test.d.ts.map +1 -0
  217. package/dist/build/__tests__/generate-cli.test.js +237 -0
  218. package/dist/build/__tests__/generate-cli.test.js.map +1 -0
  219. package/dist/build/__tests__/generate-manifest.test.d.ts +2 -0
  220. package/dist/build/__tests__/generate-manifest.test.d.ts.map +1 -0
  221. package/dist/build/__tests__/generate-manifest.test.js +119 -0
  222. package/dist/build/__tests__/generate-manifest.test.js.map +1 -0
  223. package/dist/build/__tests__/generate-route-types.test.d.ts +2 -0
  224. package/dist/build/__tests__/generate-route-types.test.d.ts.map +1 -0
  225. package/dist/build/__tests__/generate-route-types.test.js +620 -0
  226. package/dist/build/__tests__/generate-route-types.test.js.map +1 -0
  227. package/dist/build/__tests__/per-router-manifest.test.d.ts +2 -0
  228. package/dist/build/__tests__/per-router-manifest.test.d.ts.map +1 -0
  229. package/dist/build/__tests__/per-router-manifest.test.js +308 -0
  230. package/dist/build/__tests__/per-router-manifest.test.js.map +1 -0
  231. package/dist/build/generate-manifest.d.ts +81 -0
  232. package/dist/build/generate-manifest.d.ts.map +1 -0
  233. package/dist/build/generate-manifest.js +276 -0
  234. package/dist/build/generate-manifest.js.map +1 -0
  235. package/dist/build/generate-route-types.d.ts +115 -0
  236. package/dist/build/generate-route-types.d.ts.map +1 -0
  237. package/dist/build/generate-route-types.js +740 -0
  238. package/dist/build/generate-route-types.js.map +1 -0
  239. package/dist/build/index.d.ts +21 -0
  240. package/dist/build/index.d.ts.map +1 -0
  241. package/dist/build/index.js +21 -0
  242. package/dist/build/index.js.map +1 -0
  243. package/dist/build/route-trie.d.ts +71 -0
  244. package/dist/build/route-trie.d.ts.map +1 -0
  245. package/dist/build/route-trie.js +175 -0
  246. package/dist/build/route-trie.js.map +1 -0
  247. package/dist/cache/__tests__/cache-scope.test.d.ts +2 -0
  248. package/dist/cache/__tests__/cache-scope.test.d.ts.map +1 -0
  249. package/dist/cache/__tests__/cache-scope.test.js +208 -0
  250. package/dist/cache/__tests__/cache-scope.test.js.map +1 -0
  251. package/dist/cache/__tests__/document-cache.test.d.ts +2 -0
  252. package/dist/cache/__tests__/document-cache.test.d.ts.map +1 -0
  253. package/dist/cache/__tests__/document-cache.test.js +345 -0
  254. package/dist/cache/__tests__/document-cache.test.js.map +1 -0
  255. package/dist/cache/__tests__/memory-segment-store.test.d.ts +2 -0
  256. package/dist/cache/__tests__/memory-segment-store.test.d.ts.map +1 -0
  257. package/dist/cache/__tests__/memory-segment-store.test.js +425 -0
  258. package/dist/cache/__tests__/memory-segment-store.test.js.map +1 -0
  259. package/dist/cache/__tests__/memory-store.test.d.ts +2 -0
  260. package/dist/cache/__tests__/memory-store.test.d.ts.map +1 -0
  261. package/dist/cache/__tests__/memory-store.test.js +367 -0
  262. package/dist/cache/__tests__/memory-store.test.js.map +1 -0
  263. package/dist/cache/cache-scope.d.ts +102 -0
  264. package/dist/cache/cache-scope.d.ts.map +1 -0
  265. package/dist/cache/cache-scope.js +440 -0
  266. package/dist/cache/cache-scope.js.map +1 -0
  267. package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts +2 -0
  268. package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts.map +1 -0
  269. package/dist/cache/cf/__tests__/cf-cache-store.test.js +330 -0
  270. package/dist/cache/cf/__tests__/cf-cache-store.test.js.map +1 -0
  271. package/dist/cache/cf/cf-cache-store.d.ts +165 -0
  272. package/dist/cache/cf/cf-cache-store.d.ts.map +1 -0
  273. package/dist/cache/cf/cf-cache-store.js +242 -0
  274. package/dist/cache/cf/cf-cache-store.js.map +1 -0
  275. package/dist/cache/cf/index.d.ts +14 -0
  276. package/dist/cache/cf/index.d.ts.map +1 -0
  277. package/dist/cache/cf/index.js +17 -0
  278. package/dist/cache/cf/index.js.map +1 -0
  279. package/dist/cache/document-cache.d.ts +64 -0
  280. package/dist/cache/document-cache.d.ts.map +1 -0
  281. package/dist/cache/document-cache.js +228 -0
  282. package/dist/cache/document-cache.js.map +1 -0
  283. package/dist/cache/index.d.ts +19 -0
  284. package/dist/cache/index.d.ts.map +1 -0
  285. package/dist/cache/index.js +21 -0
  286. package/dist/cache/index.js.map +1 -0
  287. package/dist/cache/memory-segment-store.d.ts +110 -0
  288. package/dist/cache/memory-segment-store.d.ts.map +1 -0
  289. package/dist/cache/memory-segment-store.js +117 -0
  290. package/dist/cache/memory-segment-store.js.map +1 -0
  291. package/dist/cache/memory-store.d.ts +41 -0
  292. package/dist/cache/memory-store.d.ts.map +1 -0
  293. package/dist/cache/memory-store.js +191 -0
  294. package/dist/cache/memory-store.js.map +1 -0
  295. package/dist/cache/types.d.ts +317 -0
  296. package/dist/cache/types.d.ts.map +1 -0
  297. package/dist/cache/types.js +12 -0
  298. package/dist/cache/types.js.map +1 -0
  299. package/dist/client.d.ts +248 -0
  300. package/dist/client.d.ts.map +1 -0
  301. package/dist/client.js +367 -0
  302. package/dist/client.js.map +1 -0
  303. package/dist/client.rsc.d.ts +26 -0
  304. package/dist/client.rsc.d.ts.map +1 -0
  305. package/dist/client.rsc.js +46 -0
  306. package/dist/client.rsc.js.map +1 -0
  307. package/dist/component-utils.d.ts +36 -0
  308. package/dist/component-utils.d.ts.map +1 -0
  309. package/dist/component-utils.js +61 -0
  310. package/dist/component-utils.js.map +1 -0
  311. package/dist/components/DefaultDocument.d.ts +13 -0
  312. package/dist/components/DefaultDocument.d.ts.map +1 -0
  313. package/dist/components/DefaultDocument.js +15 -0
  314. package/dist/components/DefaultDocument.js.map +1 -0
  315. package/dist/debug.d.ts +58 -0
  316. package/dist/debug.d.ts.map +1 -0
  317. package/dist/debug.js +157 -0
  318. package/dist/debug.js.map +1 -0
  319. package/dist/default-error-boundary.d.ts +11 -0
  320. package/dist/default-error-boundary.d.ts.map +1 -0
  321. package/dist/default-error-boundary.js +45 -0
  322. package/dist/default-error-boundary.js.map +1 -0
  323. package/dist/deps/browser.d.ts +2 -0
  324. package/dist/deps/browser.d.ts.map +1 -0
  325. package/dist/deps/browser.js +3 -0
  326. package/dist/deps/browser.js.map +1 -0
  327. package/dist/deps/html-stream-client.d.ts +2 -0
  328. package/dist/deps/html-stream-client.d.ts.map +1 -0
  329. package/dist/deps/html-stream-client.js +3 -0
  330. package/dist/deps/html-stream-client.js.map +1 -0
  331. package/dist/deps/html-stream-server.d.ts +2 -0
  332. package/dist/deps/html-stream-server.d.ts.map +1 -0
  333. package/dist/deps/html-stream-server.js +3 -0
  334. package/dist/deps/html-stream-server.js.map +1 -0
  335. package/dist/deps/rsc.d.ts +2 -0
  336. package/dist/deps/rsc.d.ts.map +1 -0
  337. package/dist/deps/rsc.js +4 -0
  338. package/dist/deps/rsc.js.map +1 -0
  339. package/dist/deps/ssr.d.ts +2 -0
  340. package/dist/deps/ssr.d.ts.map +1 -0
  341. package/dist/deps/ssr.js +3 -0
  342. package/dist/deps/ssr.js.map +1 -0
  343. package/dist/errors.d.ts +174 -0
  344. package/dist/errors.d.ts.map +1 -0
  345. package/dist/errors.js +241 -0
  346. package/dist/errors.js.map +1 -0
  347. package/dist/handle.d.ts +78 -0
  348. package/dist/handle.d.ts.map +1 -0
  349. package/dist/handle.js +82 -0
  350. package/dist/handle.js.map +1 -0
  351. package/dist/handles/MetaTags.d.ts +14 -0
  352. package/dist/handles/MetaTags.d.ts.map +1 -0
  353. package/dist/handles/MetaTags.js +136 -0
  354. package/dist/handles/MetaTags.js.map +1 -0
  355. package/dist/handles/index.d.ts +6 -0
  356. package/dist/handles/index.d.ts.map +1 -0
  357. package/dist/handles/index.js +6 -0
  358. package/dist/handles/index.js.map +1 -0
  359. package/dist/handles/meta.d.ts +39 -0
  360. package/dist/handles/meta.d.ts.map +1 -0
  361. package/dist/handles/meta.js +202 -0
  362. package/dist/handles/meta.js.map +1 -0
  363. package/dist/host/__tests__/errors.test.d.ts +2 -0
  364. package/dist/host/__tests__/errors.test.d.ts.map +1 -0
  365. package/dist/host/__tests__/errors.test.js +76 -0
  366. package/dist/host/__tests__/errors.test.js.map +1 -0
  367. package/dist/host/__tests__/pattern-comprehensive.test.d.ts +2 -0
  368. package/dist/host/__tests__/pattern-comprehensive.test.d.ts.map +1 -0
  369. package/dist/host/__tests__/pattern-comprehensive.test.js +732 -0
  370. package/dist/host/__tests__/pattern-comprehensive.test.js.map +1 -0
  371. package/dist/host/__tests__/pattern-matcher.test.d.ts +2 -0
  372. package/dist/host/__tests__/pattern-matcher.test.d.ts.map +1 -0
  373. package/dist/host/__tests__/pattern-matcher.test.js +251 -0
  374. package/dist/host/__tests__/pattern-matcher.test.js.map +1 -0
  375. package/dist/host/__tests__/router.test.d.ts +2 -0
  376. package/dist/host/__tests__/router.test.d.ts.map +1 -0
  377. package/dist/host/__tests__/router.test.js +241 -0
  378. package/dist/host/__tests__/router.test.js.map +1 -0
  379. package/dist/host/__tests__/testing.test.d.ts +2 -0
  380. package/dist/host/__tests__/testing.test.d.ts.map +1 -0
  381. package/dist/host/__tests__/testing.test.js +64 -0
  382. package/dist/host/__tests__/testing.test.js.map +1 -0
  383. package/dist/host/__tests__/utils.test.d.ts +2 -0
  384. package/dist/host/__tests__/utils.test.d.ts.map +1 -0
  385. package/dist/host/__tests__/utils.test.js +29 -0
  386. package/dist/host/__tests__/utils.test.js.map +1 -0
  387. package/dist/host/cookie-handler.d.ts +34 -0
  388. package/dist/host/cookie-handler.d.ts.map +1 -0
  389. package/dist/host/cookie-handler.js +124 -0
  390. package/dist/host/cookie-handler.js.map +1 -0
  391. package/dist/host/errors.d.ts +56 -0
  392. package/dist/host/errors.d.ts.map +1 -0
  393. package/dist/host/errors.js +79 -0
  394. package/dist/host/errors.js.map +1 -0
  395. package/dist/host/index.d.ts +29 -0
  396. package/dist/host/index.d.ts.map +1 -0
  397. package/dist/host/index.js +32 -0
  398. package/dist/host/index.js.map +1 -0
  399. package/dist/host/pattern-matcher.d.ts +36 -0
  400. package/dist/host/pattern-matcher.d.ts.map +1 -0
  401. package/dist/host/pattern-matcher.js +172 -0
  402. package/dist/host/pattern-matcher.js.map +1 -0
  403. package/dist/host/router.d.ts +26 -0
  404. package/dist/host/router.d.ts.map +1 -0
  405. package/dist/host/router.js +218 -0
  406. package/dist/host/router.js.map +1 -0
  407. package/dist/host/testing.d.ts +36 -0
  408. package/dist/host/testing.d.ts.map +1 -0
  409. package/dist/host/testing.js +55 -0
  410. package/dist/host/testing.js.map +1 -0
  411. package/dist/host/types.d.ts +115 -0
  412. package/dist/host/types.d.ts.map +1 -0
  413. package/dist/host/types.js +7 -0
  414. package/dist/host/types.js.map +1 -0
  415. package/dist/host/utils.d.ts +21 -0
  416. package/dist/host/utils.d.ts.map +1 -0
  417. package/dist/host/utils.js +23 -0
  418. package/dist/host/utils.js.map +1 -0
  419. package/dist/href-client.d.ts +131 -0
  420. package/dist/href-client.d.ts.map +1 -0
  421. package/dist/href-client.js +64 -0
  422. package/dist/href-client.js.map +1 -0
  423. package/{src/href-context.ts → dist/href-context.d.ts} +7 -11
  424. package/dist/href-context.d.ts.map +1 -0
  425. package/dist/href-context.js +21 -0
  426. package/dist/href-context.js.map +1 -0
  427. package/dist/index.d.ts +73 -0
  428. package/dist/index.d.ts.map +1 -0
  429. package/dist/index.js +91 -0
  430. package/dist/index.js.map +1 -0
  431. package/dist/index.rsc.d.ts +32 -0
  432. package/dist/index.rsc.d.ts.map +1 -0
  433. package/dist/index.rsc.js +40 -0
  434. package/dist/index.rsc.js.map +1 -0
  435. package/dist/internal-debug.d.ts +2 -0
  436. package/dist/internal-debug.d.ts.map +1 -0
  437. package/dist/internal-debug.js +5 -0
  438. package/dist/internal-debug.js.map +1 -0
  439. package/dist/loader.d.ts +14 -0
  440. package/dist/loader.d.ts.map +1 -0
  441. package/dist/loader.js +20 -0
  442. package/dist/loader.js.map +1 -0
  443. package/dist/loader.rsc.d.ts +19 -0
  444. package/dist/loader.rsc.d.ts.map +1 -0
  445. package/dist/loader.rsc.js +99 -0
  446. package/dist/loader.rsc.js.map +1 -0
  447. package/dist/network-error-thrower.d.ts +17 -0
  448. package/dist/network-error-thrower.d.ts.map +1 -0
  449. package/dist/network-error-thrower.js +14 -0
  450. package/dist/network-error-thrower.js.map +1 -0
  451. package/dist/outlet-context.d.ts +13 -0
  452. package/dist/outlet-context.d.ts.map +1 -0
  453. package/dist/outlet-context.js +3 -0
  454. package/dist/outlet-context.js.map +1 -0
  455. package/dist/prerender/__tests__/param-hash.test.d.ts +2 -0
  456. package/dist/prerender/__tests__/param-hash.test.d.ts.map +1 -0
  457. package/dist/prerender/__tests__/param-hash.test.js +148 -0
  458. package/dist/prerender/__tests__/param-hash.test.js.map +1 -0
  459. package/dist/prerender/param-hash.d.ts +16 -0
  460. package/dist/prerender/param-hash.d.ts.map +1 -0
  461. package/dist/prerender/param-hash.js +36 -0
  462. package/dist/prerender/param-hash.js.map +1 -0
  463. package/dist/prerender/store.d.ts +38 -0
  464. package/dist/prerender/store.d.ts.map +1 -0
  465. package/dist/prerender/store.js +61 -0
  466. package/dist/prerender/store.js.map +1 -0
  467. package/dist/prerender.d.ts +66 -0
  468. package/dist/prerender.d.ts.map +1 -0
  469. package/dist/prerender.js +57 -0
  470. package/dist/prerender.js.map +1 -0
  471. package/dist/reverse.d.ts +196 -0
  472. package/dist/reverse.d.ts.map +1 -0
  473. package/dist/reverse.js +78 -0
  474. package/dist/reverse.js.map +1 -0
  475. package/dist/root-error-boundary.d.ts +33 -0
  476. package/dist/root-error-boundary.d.ts.map +1 -0
  477. package/dist/root-error-boundary.js +165 -0
  478. package/dist/root-error-boundary.js.map +1 -0
  479. package/dist/route-content-wrapper.d.ts +46 -0
  480. package/dist/route-content-wrapper.d.ts.map +1 -0
  481. package/dist/route-content-wrapper.js +77 -0
  482. package/dist/route-content-wrapper.js.map +1 -0
  483. package/dist/route-definition.d.ts +421 -0
  484. package/dist/route-definition.d.ts.map +1 -0
  485. package/dist/route-definition.js +868 -0
  486. package/dist/route-definition.js.map +1 -0
  487. package/dist/route-map-builder.d.ts +155 -0
  488. package/dist/route-map-builder.d.ts.map +1 -0
  489. package/dist/route-map-builder.js +237 -0
  490. package/dist/route-map-builder.js.map +1 -0
  491. package/dist/route-types.d.ts +165 -0
  492. package/dist/route-types.d.ts.map +1 -0
  493. package/dist/route-types.js +7 -0
  494. package/dist/route-types.js.map +1 -0
  495. package/dist/router/__tests__/handler-context.test.d.ts +2 -0
  496. package/dist/router/__tests__/handler-context.test.d.ts.map +1 -0
  497. package/dist/router/__tests__/handler-context.test.js +65 -0
  498. package/dist/router/__tests__/handler-context.test.js.map +1 -0
  499. package/dist/router/__tests__/loader-cycle-detection.test.d.ts +2 -0
  500. package/dist/router/__tests__/loader-cycle-detection.test.d.ts.map +1 -0
  501. package/dist/router/__tests__/loader-cycle-detection.test.js +221 -0
  502. package/dist/router/__tests__/loader-cycle-detection.test.js.map +1 -0
  503. package/dist/router/__tests__/match-context.test.d.ts +2 -0
  504. package/dist/router/__tests__/match-context.test.d.ts.map +1 -0
  505. package/dist/router/__tests__/match-context.test.js +92 -0
  506. package/dist/router/__tests__/match-context.test.js.map +1 -0
  507. package/dist/router/__tests__/match-pipelines.test.d.ts +2 -0
  508. package/dist/router/__tests__/match-pipelines.test.d.ts.map +1 -0
  509. package/dist/router/__tests__/match-pipelines.test.js +417 -0
  510. package/dist/router/__tests__/match-pipelines.test.js.map +1 -0
  511. package/dist/router/__tests__/match-result.test.d.ts +2 -0
  512. package/dist/router/__tests__/match-result.test.d.ts.map +1 -0
  513. package/dist/router/__tests__/match-result.test.js +457 -0
  514. package/dist/router/__tests__/match-result.test.js.map +1 -0
  515. package/dist/router/__tests__/on-error.test.d.ts +2 -0
  516. package/dist/router/__tests__/on-error.test.d.ts.map +1 -0
  517. package/dist/router/__tests__/on-error.test.js +678 -0
  518. package/dist/router/__tests__/on-error.test.js.map +1 -0
  519. package/dist/router/__tests__/pattern-matching.test.d.ts +2 -0
  520. package/dist/router/__tests__/pattern-matching.test.d.ts.map +1 -0
  521. package/dist/router/__tests__/pattern-matching.test.js +629 -0
  522. package/dist/router/__tests__/pattern-matching.test.js.map +1 -0
  523. package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts +2 -0
  524. package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts.map +1 -0
  525. package/dist/router/__tests__/segment-resolution-parallel-loading.test.js +155 -0
  526. package/dist/router/__tests__/segment-resolution-parallel-loading.test.js.map +1 -0
  527. package/dist/router/error-handling.d.ts +77 -0
  528. package/dist/router/error-handling.d.ts.map +1 -0
  529. package/dist/router/error-handling.js +202 -0
  530. package/dist/router/error-handling.js.map +1 -0
  531. package/dist/router/handler-context.d.ts +20 -0
  532. package/dist/router/handler-context.d.ts.map +1 -0
  533. package/dist/router/handler-context.js +198 -0
  534. package/dist/router/handler-context.js.map +1 -0
  535. package/dist/router/intercept-resolution.d.ts +66 -0
  536. package/dist/router/intercept-resolution.d.ts.map +1 -0
  537. package/dist/router/intercept-resolution.js +246 -0
  538. package/dist/router/intercept-resolution.js.map +1 -0
  539. package/dist/router/loader-resolution.d.ts +64 -0
  540. package/dist/router/loader-resolution.d.ts.map +1 -0
  541. package/dist/router/loader-resolution.js +284 -0
  542. package/dist/router/loader-resolution.js.map +1 -0
  543. package/dist/router/logging.d.ts +15 -0
  544. package/dist/router/logging.d.ts.map +1 -0
  545. package/dist/router/logging.js +99 -0
  546. package/dist/router/logging.js.map +1 -0
  547. package/dist/router/manifest.d.ts +22 -0
  548. package/dist/router/manifest.d.ts.map +1 -0
  549. package/dist/router/manifest.js +181 -0
  550. package/dist/router/manifest.js.map +1 -0
  551. package/dist/router/match-api.d.ts +35 -0
  552. package/dist/router/match-api.d.ts.map +1 -0
  553. package/dist/router/match-api.js +406 -0
  554. package/dist/router/match-api.js.map +1 -0
  555. package/dist/router/match-context.d.ts +206 -0
  556. package/dist/router/match-context.d.ts.map +1 -0
  557. package/dist/router/match-context.js +17 -0
  558. package/dist/router/match-context.js.map +1 -0
  559. package/dist/router/match-middleware/background-revalidation.d.ts +127 -0
  560. package/dist/router/match-middleware/background-revalidation.d.ts.map +1 -0
  561. package/dist/router/match-middleware/background-revalidation.js +75 -0
  562. package/dist/router/match-middleware/background-revalidation.js.map +1 -0
  563. package/dist/router/match-middleware/cache-lookup.d.ts +112 -0
  564. package/dist/router/match-middleware/cache-lookup.d.ts.map +1 -0
  565. package/dist/router/match-middleware/cache-lookup.js +257 -0
  566. package/dist/router/match-middleware/cache-lookup.js.map +1 -0
  567. package/dist/router/match-middleware/cache-store.d.ts +113 -0
  568. package/dist/router/match-middleware/cache-store.d.ts.map +1 -0
  569. package/dist/router/match-middleware/cache-store.js +108 -0
  570. package/dist/router/match-middleware/cache-store.js.map +1 -0
  571. package/dist/router/match-middleware/index.d.ts +81 -0
  572. package/dist/router/match-middleware/index.d.ts.map +1 -0
  573. package/dist/router/match-middleware/index.js +80 -0
  574. package/dist/router/match-middleware/index.js.map +1 -0
  575. package/dist/router/match-middleware/intercept-resolution.d.ts +117 -0
  576. package/dist/router/match-middleware/intercept-resolution.d.ts.map +1 -0
  577. package/dist/router/match-middleware/intercept-resolution.js +134 -0
  578. package/dist/router/match-middleware/intercept-resolution.js.map +1 -0
  579. package/dist/router/match-middleware/segment-resolution.d.ts +99 -0
  580. package/dist/router/match-middleware/segment-resolution.d.ts.map +1 -0
  581. package/dist/router/match-middleware/segment-resolution.js +53 -0
  582. package/dist/router/match-middleware/segment-resolution.js.map +1 -0
  583. package/dist/router/match-pipelines.d.ts +147 -0
  584. package/dist/router/match-pipelines.d.ts.map +1 -0
  585. package/dist/router/match-pipelines.js +82 -0
  586. package/dist/router/match-pipelines.js.map +1 -0
  587. package/dist/router/match-result.d.ts +126 -0
  588. package/dist/router/match-result.d.ts.map +1 -0
  589. package/dist/router/match-result.js +93 -0
  590. package/dist/router/match-result.js.map +1 -0
  591. package/dist/router/metrics.d.ts +20 -0
  592. package/dist/router/metrics.d.ts.map +1 -0
  593. package/dist/router/metrics.js +47 -0
  594. package/dist/router/metrics.js.map +1 -0
  595. package/dist/router/middleware.d.ts +249 -0
  596. package/dist/router/middleware.d.ts.map +1 -0
  597. package/dist/router/middleware.js +434 -0
  598. package/dist/router/middleware.js.map +1 -0
  599. package/dist/router/middleware.test.d.ts +2 -0
  600. package/dist/router/middleware.test.d.ts.map +1 -0
  601. package/dist/router/middleware.test.js +816 -0
  602. package/dist/router/middleware.test.js.map +1 -0
  603. package/dist/router/pattern-matching.d.ts +149 -0
  604. package/dist/router/pattern-matching.d.ts.map +1 -0
  605. package/dist/router/pattern-matching.js +349 -0
  606. package/dist/router/pattern-matching.js.map +1 -0
  607. package/dist/router/revalidation.d.ts +44 -0
  608. package/dist/router/revalidation.d.ts.map +1 -0
  609. package/dist/router/revalidation.js +147 -0
  610. package/dist/router/revalidation.js.map +1 -0
  611. package/dist/router/router-context.d.ts +135 -0
  612. package/dist/router/router-context.d.ts.map +1 -0
  613. package/dist/router/router-context.js +36 -0
  614. package/dist/router/router-context.js.map +1 -0
  615. package/dist/router/segment-resolution.d.ts +127 -0
  616. package/dist/router/segment-resolution.d.ts.map +1 -0
  617. package/dist/router/segment-resolution.js +919 -0
  618. package/dist/router/segment-resolution.js.map +1 -0
  619. package/dist/router/trie-matching.d.ts +40 -0
  620. package/dist/router/trie-matching.d.ts.map +1 -0
  621. package/dist/router/trie-matching.js +127 -0
  622. package/dist/router/trie-matching.js.map +1 -0
  623. package/dist/router/types.d.ts +136 -0
  624. package/dist/router/types.d.ts.map +1 -0
  625. package/dist/router/types.js +7 -0
  626. package/dist/router/types.js.map +1 -0
  627. package/dist/router.d.ts +753 -0
  628. package/dist/router.d.ts.map +1 -0
  629. package/dist/router.gen.d.ts +6 -0
  630. package/dist/router.gen.d.ts.map +1 -0
  631. package/dist/router.gen.js +6 -0
  632. package/dist/router.gen.js.map +1 -0
  633. package/dist/router.js +1304 -0
  634. package/dist/router.js.map +1 -0
  635. package/dist/rsc/__tests__/helpers.test.d.ts +2 -0
  636. package/dist/rsc/__tests__/helpers.test.d.ts.map +1 -0
  637. package/dist/rsc/__tests__/helpers.test.js +140 -0
  638. package/dist/rsc/__tests__/helpers.test.js.map +1 -0
  639. package/dist/rsc/handler.d.ts +45 -0
  640. package/dist/rsc/handler.d.ts.map +1 -0
  641. package/dist/rsc/handler.js +1172 -0
  642. package/dist/rsc/handler.js.map +1 -0
  643. package/dist/rsc/helpers.d.ts +16 -0
  644. package/dist/rsc/helpers.d.ts.map +1 -0
  645. package/dist/rsc/helpers.js +55 -0
  646. package/dist/rsc/helpers.js.map +1 -0
  647. package/dist/rsc/index.d.ts +22 -0
  648. package/dist/rsc/index.d.ts.map +1 -0
  649. package/dist/rsc/index.js +23 -0
  650. package/dist/rsc/index.js.map +1 -0
  651. package/dist/rsc/nonce.d.ts +9 -0
  652. package/dist/rsc/nonce.d.ts.map +1 -0
  653. package/dist/rsc/nonce.js +18 -0
  654. package/dist/rsc/nonce.js.map +1 -0
  655. package/dist/rsc/types.d.ts +206 -0
  656. package/dist/rsc/types.d.ts.map +1 -0
  657. package/dist/rsc/types.js +8 -0
  658. package/dist/rsc/types.js.map +1 -0
  659. package/dist/search-params.d.ts +103 -0
  660. package/dist/search-params.d.ts.map +1 -0
  661. package/dist/search-params.js +74 -0
  662. package/dist/search-params.js.map +1 -0
  663. package/dist/segment-system.d.ts +75 -0
  664. package/dist/segment-system.d.ts.map +1 -0
  665. package/dist/segment-system.js +336 -0
  666. package/dist/segment-system.js.map +1 -0
  667. package/dist/server/context.d.ts +245 -0
  668. package/dist/server/context.d.ts.map +1 -0
  669. package/dist/server/context.js +197 -0
  670. package/dist/server/context.js.map +1 -0
  671. package/dist/server/fetchable-loader-store.d.ts +18 -0
  672. package/dist/server/fetchable-loader-store.d.ts.map +1 -0
  673. package/dist/server/fetchable-loader-store.js +18 -0
  674. package/dist/server/fetchable-loader-store.js.map +1 -0
  675. package/dist/server/handle-store.d.ts +85 -0
  676. package/dist/server/handle-store.d.ts.map +1 -0
  677. package/dist/server/handle-store.js +142 -0
  678. package/dist/server/handle-store.js.map +1 -0
  679. package/dist/server/loader-registry.d.ts +55 -0
  680. package/dist/server/loader-registry.d.ts.map +1 -0
  681. package/dist/server/loader-registry.js +132 -0
  682. package/dist/server/loader-registry.js.map +1 -0
  683. package/dist/server/request-context.d.ts +226 -0
  684. package/dist/server/request-context.d.ts.map +1 -0
  685. package/dist/server/request-context.js +290 -0
  686. package/dist/server/request-context.js.map +1 -0
  687. package/dist/server/root-layout.d.ts +4 -0
  688. package/dist/server/root-layout.d.ts.map +1 -0
  689. package/dist/server/root-layout.js +5 -0
  690. package/dist/server/root-layout.js.map +1 -0
  691. package/dist/server.d.ts +15 -0
  692. package/dist/server.d.ts.map +1 -0
  693. package/dist/server.js +20 -0
  694. package/dist/server.js.map +1 -0
  695. package/dist/ssr/__tests__/ssr-handler.test.d.ts +2 -0
  696. package/dist/ssr/__tests__/ssr-handler.test.d.ts.map +1 -0
  697. package/dist/ssr/__tests__/ssr-handler.test.js +132 -0
  698. package/dist/ssr/__tests__/ssr-handler.test.js.map +1 -0
  699. package/dist/ssr/index.d.ts +98 -0
  700. package/dist/ssr/index.d.ts.map +1 -0
  701. package/dist/ssr/index.js +158 -0
  702. package/dist/ssr/index.js.map +1 -0
  703. package/dist/static-handler.d.ts +50 -0
  704. package/dist/static-handler.d.ts.map +1 -0
  705. package/dist/static-handler.gen.d.ts +5 -0
  706. package/dist/static-handler.gen.d.ts.map +1 -0
  707. package/dist/static-handler.gen.js +5 -0
  708. package/dist/static-handler.gen.js.map +1 -0
  709. package/dist/static-handler.js +29 -0
  710. package/dist/static-handler.js.map +1 -0
  711. package/dist/theme/ThemeProvider.d.ts +20 -0
  712. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  713. package/dist/theme/ThemeProvider.js +240 -0
  714. package/dist/theme/ThemeProvider.js.map +1 -0
  715. package/dist/theme/ThemeScript.d.ts +48 -0
  716. package/dist/theme/ThemeScript.d.ts.map +1 -0
  717. package/dist/theme/ThemeScript.js +13 -0
  718. package/dist/theme/ThemeScript.js.map +1 -0
  719. package/dist/theme/__tests__/theme.test.d.ts +2 -0
  720. package/dist/theme/__tests__/theme.test.d.ts.map +1 -0
  721. package/dist/theme/__tests__/theme.test.js +103 -0
  722. package/dist/theme/__tests__/theme.test.js.map +1 -0
  723. package/dist/theme/constants.d.ts +29 -0
  724. package/dist/theme/constants.d.ts.map +1 -0
  725. package/dist/theme/constants.js +48 -0
  726. package/dist/theme/constants.js.map +1 -0
  727. package/dist/theme/index.d.ts +31 -0
  728. package/dist/theme/index.d.ts.map +1 -0
  729. package/dist/theme/index.js +36 -0
  730. package/dist/theme/index.js.map +1 -0
  731. package/dist/theme/theme-context.d.ts +40 -0
  732. package/dist/theme/theme-context.d.ts.map +1 -0
  733. package/dist/theme/theme-context.js +60 -0
  734. package/dist/theme/theme-context.js.map +1 -0
  735. package/dist/theme/theme-script.d.ts +27 -0
  736. package/dist/theme/theme-script.d.ts.map +1 -0
  737. package/dist/theme/theme-script.js +147 -0
  738. package/dist/theme/theme-script.js.map +1 -0
  739. package/dist/theme/types.d.ts +163 -0
  740. package/dist/theme/types.d.ts.map +1 -0
  741. package/dist/theme/types.js +11 -0
  742. package/dist/theme/types.js.map +1 -0
  743. package/dist/theme/use-theme.d.ts +12 -0
  744. package/dist/theme/use-theme.d.ts.map +1 -0
  745. package/dist/theme/use-theme.js +40 -0
  746. package/dist/theme/use-theme.js.map +1 -0
  747. package/dist/types.d.ts +1479 -0
  748. package/dist/types.d.ts.map +1 -0
  749. package/dist/types.js +10 -0
  750. package/dist/types.js.map +1 -0
  751. package/dist/urls.d.ts +441 -0
  752. package/dist/urls.d.ts.map +1 -0
  753. package/dist/urls.gen.d.ts +8 -0
  754. package/dist/urls.gen.d.ts.map +1 -0
  755. package/dist/urls.gen.js +8 -0
  756. package/dist/urls.gen.js.map +1 -0
  757. package/dist/urls.js +443 -0
  758. package/dist/urls.js.map +1 -0
  759. package/dist/use-loader.d.ts +127 -0
  760. package/dist/use-loader.d.ts.map +1 -0
  761. package/dist/use-loader.js +237 -0
  762. package/dist/use-loader.js.map +1 -0
  763. package/dist/vite/__tests__/ast-handler-extract.test.d.ts +2 -0
  764. package/dist/vite/__tests__/ast-handler-extract.test.d.ts.map +1 -0
  765. package/dist/vite/__tests__/ast-handler-extract.test.js +294 -0
  766. package/dist/vite/__tests__/ast-handler-extract.test.js.map +1 -0
  767. package/dist/vite/__tests__/expose-id-utils.test.d.ts +2 -0
  768. package/dist/vite/__tests__/expose-id-utils.test.d.ts.map +1 -0
  769. package/dist/vite/__tests__/expose-id-utils.test.js +224 -0
  770. package/dist/vite/__tests__/expose-id-utils.test.js.map +1 -0
  771. package/dist/vite/__tests__/expose-internal-ids.test.d.ts +2 -0
  772. package/dist/vite/__tests__/expose-internal-ids.test.d.ts.map +1 -0
  773. package/dist/vite/__tests__/expose-internal-ids.test.js +647 -0
  774. package/dist/vite/__tests__/expose-internal-ids.test.js.map +1 -0
  775. package/dist/vite/__tests__/expose-router-id.test.d.ts +2 -0
  776. package/dist/vite/__tests__/expose-router-id.test.d.ts.map +1 -0
  777. package/dist/vite/__tests__/expose-router-id.test.js +39 -0
  778. package/dist/vite/__tests__/expose-router-id.test.js.map +1 -0
  779. package/dist/vite/ast-handler-extract.d.ts +49 -0
  780. package/dist/vite/ast-handler-extract.d.ts.map +1 -0
  781. package/dist/vite/ast-handler-extract.js +249 -0
  782. package/dist/vite/ast-handler-extract.js.map +1 -0
  783. package/dist/vite/expose-action-id.d.ts +19 -0
  784. package/dist/vite/expose-action-id.d.ts.map +1 -0
  785. package/dist/vite/expose-action-id.js +250 -0
  786. package/dist/vite/expose-action-id.js.map +1 -0
  787. package/dist/vite/expose-id-utils.d.ts +69 -0
  788. package/dist/vite/expose-id-utils.d.ts.map +1 -0
  789. package/dist/vite/expose-id-utils.js +289 -0
  790. package/dist/vite/expose-id-utils.js.map +1 -0
  791. package/dist/vite/expose-internal-ids.d.ts +22 -0
  792. package/dist/vite/expose-internal-ids.d.ts.map +1 -0
  793. package/dist/vite/expose-internal-ids.js +886 -0
  794. package/dist/vite/expose-internal-ids.js.map +1 -0
  795. package/dist/vite/index.d.ts +149 -0
  796. package/dist/vite/index.d.ts.map +1 -0
  797. package/dist/vite/index.js +6148 -2425
  798. package/dist/vite/index.js.bak +5448 -0
  799. package/dist/vite/index.js.map +1 -0
  800. package/dist/vite/index.named-routes.gen.ts +103 -0
  801. package/dist/vite/package-resolution.d.ts +43 -0
  802. package/dist/vite/package-resolution.d.ts.map +1 -0
  803. package/{src/vite/package-resolution.ts → dist/vite/package-resolution.js} +53 -66
  804. package/dist/vite/package-resolution.js.map +1 -0
  805. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  806. package/dist/vite/virtual-entries.d.ts +25 -0
  807. package/dist/vite/virtual-entries.d.ts.map +1 -0
  808. package/{src/vite/virtual-entries.ts → dist/vite/virtual-entries.js} +12 -16
  809. package/dist/vite/virtual-entries.js.map +1 -0
  810. package/package.json +62 -54
  811. package/skills/breadcrumbs/SKILL.md +252 -0
  812. package/skills/bundle-analysis/SKILL.md +159 -0
  813. package/skills/cache-guide/SKILL.md +473 -0
  814. package/skills/caching/SKILL.md +94 -24
  815. package/skills/composability/SKILL.md +197 -0
  816. package/skills/debug-manifest/SKILL.md +12 -8
  817. package/skills/document-cache/SKILL.md +18 -16
  818. package/skills/fonts/SKILL.md +6 -4
  819. package/skills/handler-use/SKILL.md +364 -0
  820. package/skills/hooks/SKILL.md +524 -71
  821. package/skills/host-router/SKILL.md +243 -0
  822. package/skills/i18n/SKILL.md +276 -0
  823. package/skills/intercept/SKILL.md +173 -8
  824. package/skills/layout/SKILL.md +123 -5
  825. package/skills/links/SKILL.md +316 -25
  826. package/skills/loader/SKILL.md +620 -50
  827. package/skills/middleware/SKILL.md +211 -37
  828. package/skills/migrate-nextjs/SKILL.md +562 -0
  829. package/skills/migrate-react-router/SKILL.md +769 -0
  830. package/skills/mime-routes/SKILL.md +42 -11
  831. package/skills/observability/SKILL.md +137 -0
  832. package/skills/parallel/SKILL.md +271 -3
  833. package/skills/prerender/SKILL.md +448 -63
  834. package/skills/rango/SKILL.md +293 -21
  835. package/skills/response-routes/SKILL.md +210 -100
  836. package/skills/route/SKILL.md +310 -14
  837. package/skills/router-setup/SKILL.md +211 -33
  838. package/skills/server-actions/SKILL.md +751 -0
  839. package/skills/streams-and-websockets/SKILL.md +283 -0
  840. package/skills/theme/SKILL.md +9 -8
  841. package/skills/typesafety/SKILL.md +622 -91
  842. package/skills/use-cache/SKILL.md +324 -0
  843. package/skills/view-transitions/SKILL.md +212 -0
  844. package/src/__augment-tests__/augment.ts +81 -0
  845. package/src/__augment-tests__/augmented.check.ts +117 -0
  846. package/src/__internal.ts +102 -4
  847. package/src/bin/rango.ts +312 -15
  848. package/src/browser/action-coordinator.ts +97 -0
  849. package/src/browser/action-response-classifier.ts +99 -0
  850. package/src/browser/app-shell.ts +52 -0
  851. package/src/browser/app-version.ts +14 -0
  852. package/src/browser/event-controller.ts +136 -68
  853. package/src/browser/history-state.ts +101 -0
  854. package/src/browser/index.ts +3 -3
  855. package/src/browser/intercept-utils.ts +52 -0
  856. package/src/browser/link-interceptor.ts +24 -4
  857. package/src/browser/logging.ts +55 -0
  858. package/src/browser/merge-segment-loaders.ts +20 -12
  859. package/src/browser/navigation-bridge.ts +370 -561
  860. package/src/browser/navigation-client.ts +228 -70
  861. package/src/browser/navigation-store.ts +97 -55
  862. package/src/browser/navigation-transaction.ts +293 -0
  863. package/src/browser/network-error-handler.ts +61 -0
  864. package/src/browser/partial-update.ts +376 -315
  865. package/src/browser/prefetch/cache.ts +314 -0
  866. package/src/browser/prefetch/fetch.ts +282 -0
  867. package/src/browser/prefetch/observer.ts +65 -0
  868. package/src/browser/prefetch/policy.ts +48 -0
  869. package/src/browser/prefetch/queue.ts +191 -0
  870. package/src/browser/prefetch/resource-ready.ts +77 -0
  871. package/src/browser/rango-state.ts +152 -0
  872. package/src/browser/react/Link.tsx +255 -71
  873. package/src/browser/react/NavigationProvider.tsx +152 -24
  874. package/src/browser/react/context.ts +11 -0
  875. package/src/browser/react/filter-segment-order.ts +55 -0
  876. package/src/browser/react/index.ts +15 -12
  877. package/src/browser/react/location-state-shared.ts +176 -53
  878. package/src/browser/react/location-state.ts +90 -19
  879. package/src/browser/react/mount-context.ts +6 -1
  880. package/src/browser/react/nonce-context.ts +23 -0
  881. package/src/browser/react/shallow-equal.ts +27 -0
  882. package/src/browser/react/use-action.ts +29 -51
  883. package/src/browser/react/use-client-cache.ts +5 -3
  884. package/src/browser/react/use-handle.ts +41 -123
  885. package/src/browser/react/use-link-status.ts +6 -5
  886. package/src/browser/react/use-navigation.ts +44 -65
  887. package/src/browser/react/use-params.ts +78 -0
  888. package/src/browser/react/use-pathname.ts +47 -0
  889. package/src/browser/react/use-reverse.ts +99 -0
  890. package/src/browser/react/use-router.ts +96 -0
  891. package/src/browser/react/use-search-params.ts +56 -0
  892. package/src/browser/react/use-segments.ts +85 -99
  893. package/src/browser/response-adapter.ts +73 -0
  894. package/src/browser/rsc-router.tsx +254 -72
  895. package/src/browser/scroll-restoration.ts +132 -49
  896. package/src/browser/segment-reconciler.ts +243 -0
  897. package/src/browser/segment-structure-assert.ts +17 -1
  898. package/src/browser/server-action-bridge.ts +510 -603
  899. package/src/browser/shallow.ts +6 -1
  900. package/src/browser/types.ts +158 -48
  901. package/src/browser/validate-redirect-origin.ts +29 -0
  902. package/src/build/generate-manifest.ts +87 -26
  903. package/src/build/generate-route-types.ts +39 -828
  904. package/src/build/index.ts +2 -5
  905. package/src/build/route-trie.ts +84 -31
  906. package/src/build/route-types/ast-helpers.ts +25 -0
  907. package/src/build/route-types/ast-route-extraction.ts +98 -0
  908. package/src/build/route-types/codegen.ts +102 -0
  909. package/src/build/route-types/include-resolution.ts +418 -0
  910. package/src/build/route-types/param-extraction.ts +48 -0
  911. package/src/build/route-types/per-module-writer.ts +128 -0
  912. package/src/build/route-types/router-processing.ts +618 -0
  913. package/src/build/route-types/scan-filter.ts +85 -0
  914. package/src/build/runtime-discovery.ts +231 -0
  915. package/src/cache/background-task.ts +34 -0
  916. package/src/cache/cache-key-utils.ts +44 -0
  917. package/src/cache/cache-policy.ts +125 -0
  918. package/src/cache/cache-runtime.ts +342 -0
  919. package/src/cache/cache-scope.ts +167 -307
  920. package/src/cache/cf/cf-cache-store.ts +573 -21
  921. package/src/cache/cf/index.ts +13 -3
  922. package/src/cache/document-cache.ts +116 -77
  923. package/src/cache/handle-capture.ts +81 -0
  924. package/src/cache/handle-snapshot.ts +41 -0
  925. package/src/cache/index.ts +1 -15
  926. package/src/cache/memory-segment-store.ts +191 -13
  927. package/src/cache/profile-registry.ts +73 -0
  928. package/src/cache/read-through-swr.ts +134 -0
  929. package/src/cache/segment-codec.ts +256 -0
  930. package/src/cache/taint.ts +153 -0
  931. package/src/cache/types.ts +72 -122
  932. package/src/client.rsc.tsx +6 -1
  933. package/src/client.tsx +117 -303
  934. package/src/component-utils.ts +4 -4
  935. package/src/components/DefaultDocument.tsx +5 -1
  936. package/src/context-var.ts +156 -0
  937. package/src/debug.ts +19 -9
  938. package/src/errors.ts +96 -8
  939. package/src/handle.ts +56 -11
  940. package/src/handles/MetaTags.tsx +73 -20
  941. package/src/handles/breadcrumbs.ts +66 -0
  942. package/src/handles/index.ts +1 -0
  943. package/src/handles/meta.ts +30 -13
  944. package/src/host/cookie-handler.ts +21 -15
  945. package/src/host/errors.ts +8 -8
  946. package/src/host/index.ts +6 -9
  947. package/src/host/pattern-matcher.ts +27 -27
  948. package/src/host/router.ts +176 -82
  949. package/src/host/testing.ts +8 -8
  950. package/src/host/types.ts +46 -9
  951. package/src/host/utils.ts +2 -2
  952. package/src/href-client.ts +196 -56
  953. package/src/index.rsc.ts +141 -22
  954. package/src/index.ts +215 -53
  955. package/src/internal-debug.ts +11 -0
  956. package/src/loader-store.ts +463 -0
  957. package/src/loader.rsc.ts +25 -143
  958. package/src/loader.ts +27 -10
  959. package/src/network-error-thrower.tsx +3 -1
  960. package/src/outlet-context.ts +1 -1
  961. package/src/outlet-provider.tsx +45 -0
  962. package/src/prerender/param-hash.ts +4 -2
  963. package/src/prerender/store.ts +122 -17
  964. package/src/prerender.ts +397 -29
  965. package/src/response-utils.ts +28 -0
  966. package/src/reverse.ts +231 -121
  967. package/src/root-error-boundary.tsx +41 -29
  968. package/src/route-content-wrapper.tsx +7 -4
  969. package/src/route-definition/dsl-helpers.ts +1106 -0
  970. package/src/route-definition/helper-factories.ts +90 -0
  971. package/src/route-definition/helpers-types.ts +485 -0
  972. package/src/route-definition/index.ts +55 -0
  973. package/src/route-definition/redirect.ts +101 -0
  974. package/src/route-definition/resolve-handler-use.ts +155 -0
  975. package/src/route-definition/use-item-types.ts +32 -0
  976. package/src/route-definition.ts +1 -1431
  977. package/src/route-map-builder.ts +162 -123
  978. package/src/route-name.ts +53 -0
  979. package/src/route-types.ts +77 -44
  980. package/src/router/content-negotiation.ts +215 -0
  981. package/src/router/debug-manifest.ts +72 -0
  982. package/src/router/error-handling.ts +10 -10
  983. package/src/router/find-match.ts +160 -0
  984. package/src/router/handler-context.ts +376 -109
  985. package/src/router/intercept-resolution.ts +35 -20
  986. package/src/router/lazy-includes.ts +237 -0
  987. package/src/router/loader-resolution.ts +330 -145
  988. package/src/router/logging.ts +251 -0
  989. package/src/router/manifest.ts +70 -22
  990. package/src/router/match-api.ts +196 -261
  991. package/src/router/match-context.ts +4 -2
  992. package/src/router/match-handlers.ts +441 -0
  993. package/src/router/match-middleware/background-revalidation.ts +108 -93
  994. package/src/router/match-middleware/cache-lookup.ts +414 -91
  995. package/src/router/match-middleware/cache-store.ts +91 -29
  996. package/src/router/match-middleware/intercept-resolution.ts +48 -21
  997. package/src/router/match-middleware/segment-resolution.ts +73 -9
  998. package/src/router/match-pipelines.ts +10 -45
  999. package/src/router/match-result.ts +154 -35
  1000. package/src/router/metrics.ts +241 -16
  1001. package/src/router/middleware-cookies.ts +55 -0
  1002. package/src/router/middleware-types.ts +209 -0
  1003. package/src/router/middleware.ts +373 -371
  1004. package/src/router/navigation-snapshot.ts +182 -0
  1005. package/src/router/pattern-matching.ts +291 -54
  1006. package/src/router/prerender-match.ts +502 -0
  1007. package/src/router/preview-match.ts +98 -0
  1008. package/src/router/request-classification.ts +310 -0
  1009. package/src/router/revalidation.ts +195 -40
  1010. package/src/router/route-snapshot.ts +245 -0
  1011. package/src/router/router-context.ts +41 -21
  1012. package/src/router/router-interfaces.ts +490 -0
  1013. package/src/router/router-options.ts +618 -0
  1014. package/src/router/router-registry.ts +21 -0
  1015. package/src/router/segment-resolution/fresh.ts +756 -0
  1016. package/src/router/segment-resolution/helpers.ts +268 -0
  1017. package/src/router/segment-resolution/loader-cache.ts +199 -0
  1018. package/src/router/segment-resolution/revalidation.ts +1407 -0
  1019. package/src/router/segment-resolution/static-store.ts +67 -0
  1020. package/src/router/segment-resolution.ts +21 -1336
  1021. package/src/router/segment-wrappers.ts +291 -0
  1022. package/src/router/substitute-pattern-params.ts +56 -0
  1023. package/src/router/telemetry-otel.ts +299 -0
  1024. package/src/router/telemetry.ts +300 -0
  1025. package/src/router/timeout.ts +148 -0
  1026. package/src/router/trie-matching.ts +111 -39
  1027. package/src/router/types.ts +17 -9
  1028. package/src/router/url-params.ts +49 -0
  1029. package/src/router.ts +707 -2291
  1030. package/src/rsc/handler-context.ts +45 -0
  1031. package/src/rsc/handler.ts +864 -1117
  1032. package/src/rsc/helpers.ts +181 -19
  1033. package/src/rsc/index.ts +1 -21
  1034. package/src/rsc/loader-fetch.ts +229 -0
  1035. package/src/rsc/manifest-init.ts +90 -0
  1036. package/src/rsc/nonce.ts +14 -0
  1037. package/src/rsc/origin-guard.ts +141 -0
  1038. package/src/rsc/progressive-enhancement.ts +395 -0
  1039. package/src/rsc/response-error.ts +37 -0
  1040. package/src/rsc/response-route-handler.ts +360 -0
  1041. package/src/rsc/rsc-rendering.ts +256 -0
  1042. package/src/rsc/runtime-warnings.ts +42 -0
  1043. package/src/rsc/server-action.ts +360 -0
  1044. package/src/rsc/ssr-setup.ts +128 -0
  1045. package/src/rsc/types.ts +52 -11
  1046. package/src/search-params.ts +230 -0
  1047. package/src/segment-content-promise.ts +67 -0
  1048. package/src/segment-loader-promise.ts +122 -0
  1049. package/src/segment-system.tsx +187 -38
  1050. package/src/serialize.ts +243 -0
  1051. package/src/server/context.ts +403 -88
  1052. package/src/server/cookie-store.ts +190 -0
  1053. package/src/server/fetchable-loader-store.ts +37 -0
  1054. package/src/server/handle-store.ts +113 -15
  1055. package/src/server/loader-registry.ts +24 -64
  1056. package/src/server/request-context.ts +603 -109
  1057. package/src/server.ts +35 -155
  1058. package/src/ssr/index.tsx +107 -30
  1059. package/src/static-handler.ts +126 -0
  1060. package/src/theme/ThemeProvider.tsx +21 -15
  1061. package/src/theme/ThemeScript.tsx +5 -5
  1062. package/src/theme/constants.ts +5 -2
  1063. package/src/theme/index.ts +4 -14
  1064. package/src/theme/theme-context.ts +4 -30
  1065. package/src/theme/theme-script.ts +21 -18
  1066. package/src/types/boundaries.ts +158 -0
  1067. package/src/types/cache-types.ts +198 -0
  1068. package/src/types/error-types.ts +192 -0
  1069. package/src/types/global-namespace.ts +113 -0
  1070. package/src/types/handler-context.ts +806 -0
  1071. package/src/types/index.ts +89 -0
  1072. package/src/types/loader-types.ts +209 -0
  1073. package/src/types/request-scope.ts +126 -0
  1074. package/src/types/route-config.ts +170 -0
  1075. package/src/types/route-entry.ts +120 -0
  1076. package/src/types/segments.ts +167 -0
  1077. package/src/types.ts +1 -1763
  1078. package/src/urls/include-helper.ts +164 -0
  1079. package/src/urls/index.ts +50 -0
  1080. package/src/urls/path-helper-types.ts +372 -0
  1081. package/src/urls/path-helper.ts +329 -0
  1082. package/src/urls/pattern-types.ts +124 -0
  1083. package/src/urls/response-types.ts +109 -0
  1084. package/src/urls/type-extraction.ts +282 -0
  1085. package/src/urls/urls-function.ts +94 -0
  1086. package/src/urls.ts +1 -1288
  1087. package/src/use-loader.tsx +511 -107
  1088. package/src/vite/debug.ts +184 -0
  1089. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  1090. package/src/vite/discovery/discover-routers.ts +374 -0
  1091. package/src/vite/discovery/discovery-errors.ts +194 -0
  1092. package/src/vite/discovery/gate-state.ts +171 -0
  1093. package/src/vite/discovery/prerender-collection.ts +480 -0
  1094. package/src/vite/discovery/route-types-writer.ts +258 -0
  1095. package/src/vite/discovery/self-gen-tracking.ts +73 -0
  1096. package/src/vite/discovery/state.ts +143 -0
  1097. package/src/vite/discovery/virtual-module-codegen.ts +193 -0
  1098. package/src/vite/index.ts +15 -2012
  1099. package/src/vite/plugin-types.ts +103 -0
  1100. package/src/vite/plugins/cjs-to-esm.ts +98 -0
  1101. package/src/vite/plugins/client-ref-dedup.ts +131 -0
  1102. package/src/vite/plugins/client-ref-hashing.ts +117 -0
  1103. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  1104. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  1105. package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
  1106. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +109 -66
  1107. package/src/vite/plugins/expose-id-utils.ts +303 -0
  1108. package/src/vite/plugins/expose-ids/export-analysis.ts +320 -0
  1109. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  1110. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  1111. package/src/vite/plugins/expose-ids/router-transform.ts +127 -0
  1112. package/src/vite/plugins/expose-ids/types.ts +45 -0
  1113. package/src/vite/plugins/expose-internal-ids.ts +816 -0
  1114. package/src/vite/plugins/performance-tracks.ts +92 -0
  1115. package/src/vite/plugins/refresh-cmd.ts +127 -0
  1116. package/src/vite/plugins/use-cache-transform.ts +336 -0
  1117. package/src/vite/plugins/version-injector.ts +109 -0
  1118. package/src/vite/plugins/version-plugin.ts +323 -0
  1119. package/src/vite/plugins/virtual-entries.ts +123 -0
  1120. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  1121. package/src/vite/rango.ts +509 -0
  1122. package/src/vite/router-discovery.ts +1511 -0
  1123. package/src/vite/utils/ast-handler-extract.ts +517 -0
  1124. package/src/vite/utils/banner.ts +36 -0
  1125. package/src/vite/utils/bundle-analysis.ts +139 -0
  1126. package/src/vite/utils/forward-user-plugins.ts +193 -0
  1127. package/src/vite/utils/manifest-utils.ts +86 -0
  1128. package/src/vite/utils/package-resolution.ts +161 -0
  1129. package/src/vite/utils/prerender-utils.ts +222 -0
  1130. package/src/vite/utils/shared-utils.ts +174 -0
  1131. package/CLAUDE.md +0 -43
  1132. package/src/browser/lru-cache.ts +0 -69
  1133. package/src/browser/request-controller.ts +0 -164
  1134. package/src/cache/memory-store.ts +0 -253
  1135. package/src/router.gen.ts +0 -6
  1136. package/src/urls.gen.ts +0 -8
  1137. package/src/vite/expose-handle-id.ts +0 -209
  1138. package/src/vite/expose-loader-id.ts +0 -426
  1139. package/src/vite/expose-location-state-id.ts +0 -177
  1140. package/src/vite/expose-prerender-handler-id.ts +0 -429
  1141. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
package/src/router.ts CHANGED
@@ -1,65 +1,45 @@
1
- import type { ComponentType } from "react";
2
1
  import { type ReactNode } from "react";
3
2
  import { createCacheScope } from "./cache/cache-scope.js";
4
- import type { SegmentCacheStore } from "./cache/types.js";
3
+ import {
4
+ setCacheProfiles,
5
+ resolveCacheProfiles,
6
+ } from "./cache/profile-registry.js";
7
+ import { isCachedFunction } from "./cache/taint.js";
5
8
  import { assertClientComponent } from "./component-utils.js";
6
9
  import { DefaultDocument } from "./components/DefaultDocument.js";
7
- import {
8
- sanitizeError,
9
- } from "./errors";
10
- import { serializeManifest, type SerializedManifest } from "./debug.js";
11
- import {
12
- createReverse,
13
- type ReverseFunction,
14
- type PrefixRoutePatterns,
15
- } from "./reverse.js";
10
+ import type { SerializedManifest } from "./debug.js";
11
+ import { createReverse, type ReverseFunction } from "./reverse.js";
16
12
  import {
17
13
  registerRouteMap,
18
14
  getPrecomputedEntries,
19
- getRouteTrie,
15
+ getRouterManifest,
16
+ getRouterPrecomputedEntries,
17
+ ensureRouterManifest,
20
18
  } from "./route-map-builder.js";
21
- import { tryTrieMatch } from "./router/trie-matching.js";
22
- import {
23
- createRouteHelpers,
24
- type RouteHandlers,
25
- } from "./route-definition.js";
26
19
  import MapRootLayout from "./server/root-layout.js";
27
- import type { AllUseItems, IncludeItem } from "./route-types.js";
20
+ import type { AllUseItems } from "./route-types.js";
28
21
  import type { UrlPatterns } from "./urls.js";
22
+ import type { UrlBuilder } from "./urls/pattern-types.js";
23
+ import { urls } from "./urls.js";
29
24
  import {
30
- EntryData,
31
- InterceptEntry,
32
- InterceptSelectorContext,
25
+ type EntryData,
33
26
  getContext,
34
- RSCRouterContext,
35
- runWithPrefixes,
27
+ RangoContext,
36
28
  type MetricsStore,
37
29
  } from "./server/context";
38
30
  import { createHandleStore, type HandleStore } from "./server/handle-store.js";
39
- import { getRequestContext } from "./server/request-context.js";
31
+ import {
32
+ getRequestContext,
33
+ _getRequestContext,
34
+ } from "./server/request-context.js";
40
35
  import type {
41
- ErrorBoundaryHandler,
42
- ErrorInfo,
43
36
  ErrorPhase,
44
37
  HandlerContext,
45
38
  LoaderDataResult,
46
- MatchResult,
47
- NotFoundBoundaryHandler,
48
- OnErrorCallback,
49
39
  ResolvedRouteMap,
50
- RouteDefinition,
51
40
  RouteEntry,
52
41
  TrailingSlashMode,
53
42
  } from "./types";
54
- import type {
55
- NonceProvider,
56
- } from "./rsc/types.js";
57
- import {
58
- runWithRequestContext,
59
- type RequestContext,
60
- type ExecutionContext,
61
- } from "./server/request-context.js";
62
- import type { SerializedSegmentData, SegmentHandleData } from "./cache/types.js";
63
43
 
64
44
  // Extracted router utilities
65
45
  import {
@@ -69,1049 +49,89 @@ import {
69
49
  invokeOnError,
70
50
  } from "./router/error-handling.js";
71
51
 
72
- // Extracted segment resolution functions
73
- import {
74
- resolveAllSegments as _resolveAllSegments,
75
- resolveLoadersOnly as _resolveLoadersOnly,
76
- resolveLoadersOnlyWithRevalidation as _resolveLoadersOnlyWithRevalidation,
77
- buildEntryRevalidateMap as _buildEntryRevalidateMap,
78
- resolveAllSegmentsWithRevalidation as _resolveAllSegmentsWithRevalidation,
79
- } from "./router/segment-resolution.js";
80
-
81
- // Extracted intercept resolution functions
82
- import {
83
- findInterceptForRoute as _findInterceptForRoute,
84
- resolveInterceptEntry as _resolveInterceptEntry,
85
- resolveInterceptLoadersOnly as _resolveInterceptLoadersOnly,
86
- } from "./router/intercept-resolution.js";
87
-
88
- // Extracted match API functions
89
- import {
90
- createMatchContextForFull as _createMatchContextForFull,
91
- createMatchContextForPartial as _createMatchContextForPartial,
92
- matchError as _matchError,
93
- } from "./router/match-api.js";
52
+ // Extracted module factories
53
+ import { createSegmentWrappers } from "./router/segment-wrappers.js";
54
+ import { createMatchHandlers } from "./router/match-handlers.js";
55
+ import { buildDebugManifest } from "./router/debug-manifest.js";
94
56
 
95
57
  import type { SegmentResolutionDeps, MatchApiDeps } from "./router/types.js";
96
- import { createHandlerContext, createBuildContext } from "./router/handler-context.js";
58
+ import { createHandlerContext } from "./router/handler-context.js";
97
59
  import {
98
60
  setupLoaderAccess,
99
61
  setupLoaderAccessSilent,
100
- setupBuildUse,
101
62
  wrapLoaderWithErrorHandling,
102
63
  } from "./router/loader-resolution.js";
103
64
  import { loadManifest } from "./router/manifest.js";
65
+ import { createMetricsStore } from "./router/metrics.js";
104
66
  import {
105
- createMetricsStore,
106
- } from "./router/metrics.js";
107
- import {
108
- collectRouteMiddleware,
109
67
  parsePattern,
110
68
  type MiddlewareEntry,
111
69
  type MiddlewareFn,
112
70
  } from "./router/middleware.js";
113
71
  import {
114
72
  extractStaticPrefix,
115
- findMatch as findRouteMatch,
116
- isLazyEvaluationNeeded,
117
73
  traverseBack,
118
- type RouteMatchResult,
119
74
  } from "./router/pattern-matching.js";
75
+ import { resolveSink, safeEmit, getRequestId } from "./router/telemetry.js";
120
76
  import { evaluateRevalidation } from "./router/revalidation.js";
121
77
  import {
122
78
  type RouterContext,
123
79
  runWithRouterContext,
124
80
  } from "./router/router-context.js";
125
- import {
126
- type ActionContext,
127
- type MatchContext,
128
- createPipelineState,
129
- } from "./router/match-context.js";
130
- import { createMatchPartialPipeline } from "./router/match-pipelines.js";
131
- import { collectMatchResult } from "./router/match-result.js";
132
81
  import { resolveThemeConfig } from "./theme/constants.js";
82
+ import { resolveTimeouts } from "./router/timeout.js";
133
83
 
134
- // Response type -> MIME type used for Accept header matching
135
- const RESPONSE_TYPE_MIME: Record<string, string> = {
136
- json: "application/json",
137
- text: "text/plain",
138
- xml: "application/xml",
139
- html: "text/html",
140
- md: "text/markdown",
141
- };
142
-
143
- // Reverse lookup: MIME type -> response type tag (e.g. "text/html" -> "html")
144
- const MIME_RESPONSE_TYPE: Record<string, string> = Object.fromEntries(
145
- Object.entries(RESPONSE_TYPE_MIME).map(([tag, mime]) => [mime, tag]),
146
- );
147
-
148
- interface AcceptEntry {
149
- mime: string;
150
- q: number;
151
- order: number;
152
- }
153
-
154
- /**
155
- * Parse an Accept header into a sorted array of MIME entries.
156
- * Respects q-values (default 1.0) and uses client order as tiebreaker
157
- * when q-values are equal (matching Express/Hono behavior).
158
- */
159
- function parseAcceptTypes(accept: string): AcceptEntry[] {
160
- const entries: AcceptEntry[] = [];
161
- const parts = accept.split(",");
162
- for (let i = 0; i < parts.length; i++) {
163
- const part = parts[i]!;
164
- const segments = part.split(";");
165
- const mime = segments[0]!.trim();
166
- if (!mime) continue;
167
- let q = 1.0;
168
- for (let j = 1; j < segments.length; j++) {
169
- const param = segments[j]!.trim();
170
- if (param.startsWith("q=")) {
171
- q = Math.max(0, Math.min(1, Number(param.slice(2)) || 0));
172
- }
173
- }
174
- entries.push({ mime, q, order: i });
175
- }
176
- // Sort: highest q first, then lowest client order first (stable)
177
- entries.sort((a, b) => b.q - a.q || a.order - b.order);
178
- return entries;
179
- }
180
-
181
- // Sentinel response type for RSC routes in negotiation candidates
182
- const RSC_RESPONSE_TYPE = "__rsc__";
183
-
184
- /**
185
- * Pick the best negotiate variant by walking the client's sorted Accept list.
186
- * For each accepted MIME type (in q-value/order priority), check if any
187
- * candidate serves that type. Wildcards (*\/*) match the first candidate.
188
- * Falls back to the first candidate if nothing matches.
189
- */
190
- function pickNegotiateVariant(
191
- acceptEntries: AcceptEntry[],
192
- candidates: Array<{ routeKey: string; responseType: string }>,
193
- ): { routeKey: string; responseType: string } {
194
- // Build a MIME -> candidate lookup for O(1) matching
195
- const byCandidateMime = new Map<string, { routeKey: string; responseType: string }>();
196
- for (const c of candidates) {
197
- const mime = c.responseType === RSC_RESPONSE_TYPE ? "text/html" : RESPONSE_TYPE_MIME[c.responseType];
198
- if (mime && !byCandidateMime.has(mime)) {
199
- byCandidateMime.set(mime, c);
200
- }
201
- }
202
-
203
- for (const entry of acceptEntries) {
204
- if (entry.q === 0) continue;
205
- // Wildcard matches first candidate
206
- if (entry.mime === "*/*") return candidates[0]!;
207
- // Type wildcard (e.g. "text/*") — match first candidate with that type
208
- if (entry.mime.endsWith("/*")) {
209
- const typePrefix = entry.mime.slice(0, entry.mime.indexOf("/"));
210
- for (const [mime, candidate] of byCandidateMime) {
211
- if (mime.startsWith(typePrefix + "/")) return candidate;
212
- }
213
- continue;
214
- }
215
- const match = byCandidateMime.get(entry.mime);
216
- if (match) return match;
217
- }
218
- // No match — use first candidate as default
219
- return candidates[0]!;
220
- }
221
-
222
- /**
223
- * Props passed to the root layout component
224
- */
225
- export interface RootLayoutProps {
226
- children: ReactNode;
227
- }
228
-
229
- /**
230
- * Router configuration options
231
- */
232
- /**
233
- * Brand marker for identifying router instances at build time.
234
- * Used by the Vite plugin to auto-discover routers from module exports.
235
- */
236
- export const RSC_ROUTER_BRAND: "__rsc_router__" = "__rsc_router__";
237
-
238
- /**
239
- * Global registry of all router instances created via createRouter().
240
- * Each router is keyed by its id (auto-generated or user-provided).
241
- * Used by the Vite plugin at build time to discover routers and extract
242
- * manifests, prefix trees, and pre-render candidates.
243
- */
244
- export const RouterRegistry: Map<string, RSCRouter<any, any>> = new Map();
245
-
246
- let routerAutoId = 0;
247
-
248
- export interface RSCRouterOptions<TEnv = any> {
249
- /**
250
- * Unique identifier for this router instance.
251
- * Used to namespace static output files and route maps.
252
- * Auto-generated if not provided.
253
- */
254
- id?: string;
255
-
256
- /**
257
- * Enable performance metrics collection
258
- * When enabled, metrics are output to console and available via Server-Timing header
259
- */
260
- debugPerformance?: boolean;
261
-
262
- /**
263
- * Allow the `?__debug_manifest` query parameter to return route manifest data as JSON.
264
- * In development mode this is always enabled regardless of this setting.
265
- * Defaults to true. Set to false to disable in production.
266
- * @internal
267
- */
268
- allowDebugManifest?: boolean;
269
-
270
- /**
271
- * Document component that wraps the entire application.
272
- *
273
- * This component provides the HTML structure for your app and wraps
274
- * both normal route content AND error states, preventing the app shell
275
- * from unmounting during errors (avoids FOUC).
276
- *
277
- * Must be a client component ("use client") that accepts { children }.
278
- *
279
- * If not provided, a default document with basic HTML structure is used:
280
- * `<html><head><meta charset/viewport></head><body>{children}</body></html>`
281
- *
282
- * @example
283
- * ```typescript
284
- * // components/Document.tsx
285
- * "use client";
286
- * export function Document({ children }: { children: ReactNode }) {
287
- * return (
288
- * <html lang="en">
289
- * <head>
290
- * <link rel="stylesheet" href="/styles.css" />
291
- * </head>
292
- * <body>
293
- * <nav>...</nav>
294
- * {children}
295
- * </body>
296
- * </html>
297
- * );
298
- * }
299
- *
300
- * // router.tsx
301
- * const router = createRouter<AppEnv>({
302
- * document: Document,
303
- * });
304
- * ```
305
- */
306
- document?: ComponentType<RootLayoutProps>;
307
-
308
- /**
309
- * Default error boundary fallback used when no error boundary is defined in the route tree
310
- * If not provided, errors will propagate and crash the request
311
- */
312
- defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler;
313
-
314
- /**
315
- * Default not-found boundary fallback used when no notFoundBoundary is defined in the route tree
316
- * If not provided, DataNotFoundError will be treated as a regular error
317
- */
318
- defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler;
319
-
320
- /**
321
- * Component to render when no route matches the requested URL.
322
- *
323
- * This is rendered within your document/app shell with a 404 status code.
324
- * Use this for a custom 404 page that maintains your app's look and feel.
325
- *
326
- * If not provided, a default "Page not found" component is rendered.
327
- *
328
- * Can be a static ReactNode or a function receiving the pathname.
329
- *
330
- * @example
331
- * ```typescript
332
- * // Simple static component
333
- * const router = createRouter<AppEnv>({
334
- * document: Document,
335
- * notFound: <NotFound404 />,
336
- * });
337
- *
338
- * // Dynamic component with pathname
339
- * const router = createRouter<AppEnv>({
340
- * document: Document,
341
- * notFound: ({ pathname }) => (
342
- * <div>
343
- * <h1>404 - Not Found</h1>
344
- * <p>No page exists at {pathname}</p>
345
- * <a href="/">Go home</a>
346
- * </div>
347
- * ),
348
- * });
349
- * ```
350
- */
351
- notFound?: ReactNode | ((props: { pathname: string }) => ReactNode);
352
-
353
- /**
354
- * Callback invoked when an error occurs during request handling.
355
- *
356
- * This callback is for notification/logging purposes - it cannot modify
357
- * the error handling flow. Use errorBoundary() in route definitions to
358
- * customize error UI.
359
- *
360
- * The callback receives comprehensive context about the error including:
361
- * - The error itself
362
- * - Phase where it occurred (routing, middleware, loader, handler, etc.)
363
- * - Request info (URL, method, params)
364
- * - Route info (routeKey, segmentId)
365
- * - Environment/bindings
366
- * - Duration from request start
367
- *
368
- * @example
369
- * ```typescript
370
- * const router = createRouter<AppEnv>({
371
- * onError: (context) => {
372
- * // Send to error tracking service
373
- * Sentry.captureException(context.error, {
374
- * tags: {
375
- * phase: context.phase,
376
- * route: context.routeKey,
377
- * },
378
- * extra: {
379
- * url: context.url.toString(),
380
- * params: context.params,
381
- * duration: context.duration,
382
- * },
383
- * });
384
- * },
385
- * });
386
- * ```
387
- */
388
- onError?: OnErrorCallback<TEnv>;
389
-
390
- /**
391
- * Cache store for segment caching.
392
- *
393
- * When provided, enables route-level caching via cache() boundaries.
394
- * The store handles persistence (memory, KV, Redis, etc.).
395
- *
396
- * Can be a static config or a function receiving env for runtime bindings.
397
- *
398
- * @example Static config
399
- * ```typescript
400
- * import { MemorySegmentCacheStore } from "rsc-router/rsc";
401
- *
402
- * const router = createRouter({
403
- * cache: {
404
- * store: new MemorySegmentCacheStore({ defaults: { ttl: 60 } }),
405
- * },
406
- * });
407
- * ```
408
- *
409
- * @example Dynamic config with env (e.g., Cloudflare Workers with ExecutionContext)
410
- * ```typescript
411
- * const router = createRouter<AppEnv>({
412
- * cache: (env) => ({
413
- * store: new CFCacheStore({
414
- * defaults: { ttl: 60 },
415
- * ctx: env.ctx, // ExecutionContext for non-blocking writes
416
- * }),
417
- * }),
418
- * });
419
- * ```
420
- */
421
- cache?:
422
- | { store: SegmentCacheStore; enabled?: boolean }
423
- | ((env: TEnv & { ctx?: ExecutionContext }) => {
424
- store: SegmentCacheStore;
425
- enabled?: boolean;
426
- });
427
-
428
- /**
429
- * Theme configuration for automatic theme management.
430
- *
431
- * When provided, enables:
432
- * - ctx.theme and ctx.setTheme() in route handlers
433
- * - useTheme() hook for client components
434
- * - FOUC prevention via inline script in MetaTags
435
- * - Automatic ThemeProvider wrapping in NavigationProvider
436
- *
437
- * @example
438
- * ```typescript
439
- * const router = createRouter<AppEnv>({
440
- * theme: {
441
- * defaultTheme: "system",
442
- * themes: ["light", "dark"],
443
- * }
444
- * });
445
- *
446
- * // In route handler:
447
- * route("settings", (ctx) => {
448
- * const theme = ctx.theme; // "light" | "dark" | "system"
449
- * ctx.setTheme("dark"); // Sets cookie
450
- * return <SettingsPage />;
451
- * });
452
- *
453
- * // In client component:
454
- * import { useTheme } from "@rangojs/router/theme";
455
- *
456
- * function ThemeToggle() {
457
- * const { theme, setTheme, themes } = useTheme();
458
- * return <select value={theme} onChange={e => setTheme(e.target.value)}>
459
- * {themes.map(t => <option key={t}>{t}</option>)}
460
- * </select>;
461
- * }
462
- * ```
463
- *
464
- * Use `theme: true` to enable with all defaults.
465
- */
466
- theme?: import("./theme/types.js").ThemeConfig | true;
467
-
468
- /**
469
- * URL patterns to register with the router.
470
- *
471
- * Alternative to calling `.routes()` method - allows passing patterns
472
- * directly in the config for a more concise setup.
473
- *
474
- * @example
475
- * ```typescript
476
- * import { urls } from "@rangojs/router/server";
477
- *
478
- * const urlpatterns = urls(({ path, layout }) => [
479
- * path("/", HomePage, { name: "home" }),
480
- * path("/about", AboutPage, { name: "about" }),
481
- * ]);
482
- *
483
- * const router = createRouter<AppEnv>({
484
- * document: Document,
485
- * urls: urlpatterns,
486
- * });
487
- * ```
488
- */
489
- urls?: UrlPatterns<TEnv, any>;
490
-
491
- /**
492
- * Nonce provider for Content Security Policy (CSP).
493
- *
494
- * Can be:
495
- * - A function that returns a nonce string
496
- * - A function that returns `true` to auto-generate a nonce
497
- * - Undefined to disable nonce (default)
498
- *
499
- * The nonce will be applied to inline scripts injected by the RSC payload.
500
- * It's also available to middleware via `ctx.get('nonce')`.
501
- *
502
- * @example Auto-generate nonce
503
- * ```tsx
504
- * createRouter({
505
- * nonce: () => true,
506
- * });
507
- * ```
508
- *
509
- * @example Custom nonce from request context
510
- * ```tsx
511
- * createRouter({
512
- * nonce: (request, env) => env.nonce,
513
- * });
514
- * ```
515
- */
516
- nonce?: NonceProvider<TEnv>;
517
-
518
- /**
519
- * RSC version string included in metadata.
520
- * The browser sends this back on partial requests to detect version mismatches.
521
- *
522
- * Defaults to the auto-generated VERSION from `@rangojs/router:version` virtual module.
523
- * Only set this if you need a custom versioning strategy.
524
- *
525
- * @default VERSION from @rangojs/router:version
526
- */
527
- version?: string;
528
-
529
- /**
530
- * Enable connection warmup to keep TCP+TLS alive after idle periods.
531
- *
532
- * When enabled, the client sends a HEAD request after the user returns
533
- * from an idle period (60s+), prewarming the TLS connection before
534
- * the next navigation.
535
- *
536
- * @default true
537
- */
538
- warmup?: boolean;
539
- }
540
-
541
- /**
542
- * Merge route patterns with response types into a single route map.
543
- * Routes with response types get { path, response } objects; others stay as strings.
544
- */
545
- type MergeRoutesWithResponses<
546
- TRoutes extends Record<string, string>,
547
- TResponses,
548
- > = {
549
- [K in keyof TRoutes]: K extends keyof NonNullable<TResponses>
550
- ? unknown extends NonNullable<TResponses>[K]
551
- ? TRoutes[K] // RSC route — TData defaults to unknown, keep as plain string
552
- : { readonly path: TRoutes[K]; readonly response: NonNullable<TResponses>[K] }
553
- : TRoutes[K]
554
- };
555
-
556
- /**
557
- * Extract the URL pattern from a route entry (string or { path, response } object)
558
- */
559
- type PatternOfEntry<V> =
560
- V extends string ? V
561
- : V extends { readonly path: infer P extends string } ? P
562
- : never;
563
-
564
- /**
565
- * Type-level detection of conflicting route keys.
566
- * Extracts keys that exist in both TExisting and TNew but with different URL patterns.
567
- * Returns `never` if no conflicts exist.
568
- * Compares patterns (not full entries) to handle both string and { path, response } values.
569
- *
570
- * @example
571
- * ```typescript
572
- * ConflictingKeys<{ a: "/a" }, { a: "/b" }> // "a" (conflict - same key, different URLs)
573
- * ConflictingKeys<{ a: "/a" }, { a: "/a" }> // never (no conflict - same key and URL)
574
- * ConflictingKeys<{ a: "/a" }, { b: "/b" }> // never (no conflict - different keys)
575
- * ```
576
- */
577
- type ConflictingKeys<
578
- TExisting extends Record<string, unknown>,
579
- TNew extends Record<string, unknown>,
580
- > = {
581
- [K in keyof TExisting & keyof TNew]: PatternOfEntry<TExisting[K]> extends PatternOfEntry<TNew[K]>
582
- ? PatternOfEntry<TNew[K]> extends PatternOfEntry<TExisting[K]>
583
- ? never // Same pattern, no conflict
584
- : K // Different patterns, conflict
585
- : K; // Different patterns, conflict
586
- }[keyof TExisting & keyof TNew];
587
-
588
- /**
589
- * Error type returned when route keys conflict.
590
- * Methods require an impossible `never` parameter so TypeScript errors at the call site.
591
- */
592
- type RouteConflictError<TConflicts extends string> = {
593
- __error: `Route key conflict! Key "${TConflicts}" already exists with a different URL pattern.`;
594
- hint: "Route keys must be globally unique. Use prefixed names like 'blog.index' instead of 'index'.";
595
- conflictingKeys: TConflicts;
596
- // These methods require `never` so calling them produces an error at the call site
597
- routes: (
598
- __conflict: `Fix route key conflict: "${TConflicts}" is already defined with a different URL pattern`,
599
- ) => never;
600
- map: (
601
- __conflict: `Fix route key conflict: "${TConflicts}" is already defined with a different URL pattern`,
602
- ) => never;
603
- };
604
-
605
- /**
606
- * Simplified route helpers for inline route definitions.
607
- * Uses TRoutes (Record<string, string>) instead of RouteDefinition.
608
- *
609
- * Note: Some helpers use `any` for context types as a trade-off for simpler usage.
610
- * The main type safety is in the `route` helper which enforces valid route names.
611
- * For full type safety, use the standard map() API with separate handler files.
612
- */
613
- type InlineRouteHelpers<TRoutes extends Record<string, string>, TEnv> = {
614
- /**
615
- * Define a route handler for a specific route pattern
616
- */
617
- route: <K extends keyof TRoutes & string>(
618
- name: K,
619
- handler:
620
- | ((ctx: HandlerContext<{}, TEnv>) => ReactNode | Promise<ReactNode>)
621
- | ReactNode,
622
- ) => AllUseItems;
623
-
624
- /**
625
- * Define a layout that wraps child routes
626
- */
627
- layout: (
628
- component:
629
- | ReactNode
630
- | ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>),
631
- use?: () => AllUseItems[],
632
- ) => AllUseItems;
633
-
634
- /**
635
- * Define parallel routes
636
- */
637
- parallel: (
638
- slots: Record<
639
- `@${string}`,
640
- | ReactNode
641
- | ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>)
642
- >,
643
- use?: () => AllUseItems[],
644
- ) => AllUseItems;
645
-
646
- /**
647
- * Define route middleware
648
- */
649
- middleware: (
650
- fn: (ctx: any, next: () => Promise<void>) => Promise<void>,
651
- ) => AllUseItems;
652
-
653
- /**
654
- * Define revalidation handlers
655
- */
656
- revalidate: (fn: (ctx: any) => boolean | Promise<boolean>) => AllUseItems;
657
-
658
- /**
659
- * Define data loaders
660
- */
661
- loader: (loader: any, use?: () => AllUseItems[]) => AllUseItems;
662
-
663
- /**
664
- * Define loading states
665
- */
666
- loading: (component: ReactNode) => AllUseItems;
667
-
668
- /**
669
- * Define error boundaries
670
- */
671
- errorBoundary: (
672
- handler: ReactNode | ((props: { error: Error }) => ReactNode),
673
- ) => AllUseItems;
674
-
675
- /**
676
- * Define not found boundaries
677
- */
678
- notFoundBoundary: (
679
- handler: ReactNode | ((props: { pathname: string }) => ReactNode),
680
- ) => AllUseItems;
681
-
682
- /**
683
- * Define intercept routes
684
- */
685
- intercept: (
686
- name: string,
687
- handler:
688
- | ReactNode
689
- | ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>),
690
- use?: () => AllUseItems[],
691
- ) => AllUseItems;
692
-
693
- /**
694
- * Define when conditions for intercepts
695
- */
696
- when: (condition: (ctx: any) => boolean | Promise<boolean>) => AllUseItems;
697
-
698
- /**
699
- * Define cache configuration
700
- */
701
- cache: (
702
- config: { ttl?: number; swr?: number } | false,
703
- use?: () => AllUseItems[],
704
- ) => AllUseItems;
705
- };
706
-
707
- /**
708
- * Router builder for chaining .use() and .map()
709
- * TRoutes accumulates all registered route types through the chain
710
- * TLocalRoutes contains the routes for the current .routes() call (for inline handler typing)
711
- */
712
- interface RouteBuilder<
713
- T extends RouteDefinition,
714
- TEnv,
715
- TRoutes extends Record<string, unknown>,
716
- TLocalRoutes extends Record<string, string> = Record<string, string>,
717
- > {
718
- /**
719
- * Add middleware scoped to this mount
720
- * Called between .routes() and .map()
721
- *
722
- * @example
723
- * ```typescript
724
- * .routes("/admin", adminRoutes)
725
- * .use(authMiddleware) // All of /admin/*
726
- * .use("/danger/*", superAuth) // Only /admin/danger/*
727
- * .map(() => import("./admin"))
728
- * ```
729
- */
730
- use(
731
- patternOrMiddleware: string | MiddlewareFn<TEnv>,
732
- middleware?: MiddlewareFn<TEnv>,
733
- ): RouteBuilder<T, TEnv, TRoutes, TLocalRoutes>;
734
-
735
- /**
736
- * Map routes to handlers
737
- *
738
- * Supports two patterns:
739
- *
740
- * 1. Lazy loading (code-split):
741
- * ```typescript
742
- * .routes(homeRoutes)
743
- * .map(() => import("./handlers/home"))
744
- * ```
745
- *
746
- * 2. Inline definition:
747
- * ```typescript
748
- * .routes({ index: "/", about: "/about" })
749
- * .map(({ route }) => [
750
- * route("index", () => <HomePage />),
751
- * route("about", () => <AboutPage />),
752
- * ])
753
- * ```
754
- */
755
- // Inline definition overload - handler receives helpers (must be first for correct inference)
756
- // Uses TLocalRoutes so route names don't need the prefix
757
- map<
758
- H extends (
759
- helpers: InlineRouteHelpers<TLocalRoutes, TEnv>,
760
- ) => Array<AllUseItems>,
761
- >(
762
- handler: H,
763
- ): RSCRouter<TEnv, TRoutes>;
764
- // Lazy loading overload - verifies imported handlers match route definition
765
- map(
766
- handler: () =>
767
- | Array<AllUseItems>
768
- | Promise<{ default: RouteHandlers<TLocalRoutes> }>
769
- | Promise<RouteHandlers<TLocalRoutes>>,
770
- ): RSCRouter<TEnv, TRoutes>;
771
-
772
- /**
773
- * Accumulated route map for typeof extraction
774
- * Used for module augmentation: `type AppRoutes = typeof _router.routeMap`
775
- */
776
- readonly routeMap: TRoutes;
777
- }
778
-
779
- /**
780
- * RSC Router interface
781
- * TRoutes accumulates all registered route types through the builder chain
782
- */
783
- export interface RSCRouter<
784
- TEnv = any,
785
- TRoutes extends Record<string, unknown> = Record<string, string>,
786
- > {
787
- /**
788
- * Brand marker for build-time discovery.
789
- * The Vite plugin uses this to identify router instances in module exports.
790
- */
791
- readonly __brand: typeof RSC_ROUTER_BRAND;
792
-
793
- /**
794
- * Unique identifier for this router instance.
795
- * Used to namespace static output and isolate route maps between routers.
796
- */
797
- readonly id: string;
798
-
799
- /**
800
- * Register routes with a prefix
801
- * Route keys stay unchanged, only URL patterns get the prefix applied.
802
- * This enables composable route modules that work regardless of mount point.
803
- *
804
- * @throws Compile-time error if route keys conflict with previously registered routes
805
- */
806
- routes<const TPrefix extends string, const T extends Record<string, string>>(
807
- prefix: TPrefix,
808
- routes: T,
809
- ): ConflictingKeys<TRoutes, PrefixRoutePatterns<T, TPrefix>> extends never
810
- ? RouteBuilder<
811
- RouteDefinition,
812
- TEnv,
813
- TRoutes & PrefixRoutePatterns<T, TPrefix>,
814
- T
815
- >
816
- : RouteConflictError<
817
- ConflictingKeys<TRoutes, PrefixRoutePatterns<T, TPrefix>> & string
818
- >;
819
-
820
- /**
821
- * Register routes without a prefix
822
- * Route types are accumulated through the chain
823
- *
824
- * @throws Compile-time error if route keys conflict with previously registered routes
825
- */
826
- routes<const T extends Record<string, string>>(
827
- routes: T,
828
- ): ConflictingKeys<TRoutes, T> extends never
829
- ? RouteBuilder<RouteDefinition, TEnv, TRoutes & T, T>
830
- : RouteConflictError<ConflictingKeys<TRoutes, T> & string>;
831
-
832
- /**
833
- * Register routes using Django-style URL patterns
834
- * This is the new API for @rangojs/router - call once with urls() result
835
- *
836
- * @example
837
- * ```typescript
838
- * createRouter({})
839
- * .routes(urlpatterns) // Single call with urls() result
840
- * ```
841
- */
842
- routes<T extends UrlPatterns<TEnv, any>>(
843
- patterns: T,
844
- ): RSCRouter<
845
- TEnv,
846
- TRoutes &
847
- (NonNullable<T["_routes"]> extends Record<string, string>
848
- ? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
849
- : Record<string, string>)
850
- >;
851
-
852
- /**
853
- * Add global middleware that runs on all routes
854
- * Position matters: middleware before any .routes() is global
855
- *
856
- * @example
857
- * ```typescript
858
- * createRouter({ document: RootLayout })
859
- * .use(loggerMiddleware) // All routes
860
- * .use("/api/*", rateLimiter) // Pattern match
861
- * .routes(homeRoutes)
862
- * .map(() => import("./home"))
863
- * ```
864
- */
865
- use(
866
- patternOrMiddleware: string | MiddlewareFn<TEnv>,
867
- middleware?: MiddlewareFn<TEnv>,
868
- ): RSCRouter<TEnv, TRoutes>;
869
-
870
- /**
871
- * Type-safe URL builder for registered routes
872
- * Types are inferred from the accumulated route registrations
873
- * Route keys stay unchanged regardless of mount prefix.
874
- *
875
- * @example
876
- * ```typescript
877
- * // Given: .routes("/shop", { cart: "/cart", detail: "/product/:slug" })
878
- * router.reverse("cart"); // "/shop/cart"
879
- * router.reverse("detail", { slug: "widget" }); // "/shop/product/widget"
880
- * ```
881
- */
882
- reverse: ReverseFunction<TRoutes>;
883
-
884
- /**
885
- * Accumulated route map for typeof extraction
886
- * Used for module augmentation: `type AppRoutes = typeof _router.routeMap`
887
- *
888
- * @example
889
- * ```typescript
890
- * const _router = createRouter<AppEnv>()
891
- * .routes(homeRoutes).map(() => import('./home'))
892
- * .routes('/shop', shopRoutes).map(() => import('./shop'));
893
- *
894
- * type AppRoutes = typeof _router.routeMap;
895
- *
896
- * declare global {
897
- * namespace RSCRouter {
898
- * interface RegisteredRoutes extends AppRoutes {}
899
- * }
900
- * }
901
- * ```
902
- */
903
- readonly routeMap: TRoutes;
904
-
905
- /**
906
- * Root layout component that wraps the entire application
907
- * Access this to pass to renderSegments
908
- */
909
- readonly rootLayout?: ComponentType<RootLayoutProps>;
910
-
911
- /**
912
- * Error callback for monitoring/alerting
913
- * Called when errors occur in loaders, actions, or routes
914
- */
915
- readonly onError?: RSCRouterOptions<TEnv>["onError"];
916
-
917
- /**
918
- * Cache configuration (for internal use by RSC handler)
919
- */
920
- readonly cache?: RSCRouterOptions<TEnv>["cache"];
921
-
922
- /**
923
- * Not found component to render when no route matches (for internal use by RSC handler)
924
- */
925
- readonly notFound?: RSCRouterOptions<TEnv>["notFound"];
926
-
927
- /**
928
- * Resolved theme configuration (null if theme not enabled)
929
- * Used by NavigationProvider to include ThemeProvider and by MetaTags to render theme script
930
- */
931
- readonly themeConfig: import("./theme/types.js").ResolvedThemeConfig | null;
932
-
933
- /**
934
- * Whether connection warmup is enabled.
935
- * When true, the client sends HEAD /?_rsc_warmup after idle periods
936
- * and the server responds with 204 No Content.
937
- */
938
- readonly warmupEnabled: boolean;
939
-
940
- /**
941
- * Whether ?__debug_manifest is allowed in production.
942
- * Always enabled in development.
943
- * @internal
944
- */
945
- readonly allowDebugManifest: boolean;
946
-
947
- /**
948
- * App-level middleware entries (for internal use by RSC handler)
949
- * These wrap the entire request/response cycle
950
- */
951
- readonly middleware: MiddlewareEntry<TEnv>[];
952
-
953
- /**
954
- * Nonce provider for CSP (for internal use by createHandler)
955
- */
956
- readonly nonce?: NonceProvider<TEnv>;
957
-
958
- /**
959
- * RSC version string (for internal use by createHandler)
960
- */
961
- readonly version?: string;
962
-
963
- /**
964
- * URL patterns reference for build-time manifest generation
965
- * @internal
966
- */
967
- readonly urlpatterns?: UrlPatterns<TEnv, any>;
968
-
969
- /**
970
- * Source file path where createRouter() was called.
971
- * Set via Error.stack parsing at construction time.
972
- * Used by the Vite plugin to write per-router named-routes.gen.ts files.
973
- * @internal
974
- */
975
- readonly __sourceFile?: string;
976
-
977
- match(request: Request, context: TEnv): Promise<MatchResult>;
978
-
979
- /**
980
- * Build-time pre-render match. Resolves segments with a BuildContext
981
- * (no request/env/headers/cookies), skipping middleware and loaders.
982
- * Used by the Vite plugin to collect pre-render data at build time.
983
- * @internal
984
- */
985
- matchForPrerender(
986
- pathname: string,
987
- params: Record<string, string>,
988
- ): Promise<{
989
- segments: SerializedSegmentData[];
990
- handles: Record<string, SegmentHandleData>;
991
- routeName: string;
992
- params: Record<string, string>;
993
- } | null>;
994
-
995
- /**
996
- * Preview match - returns route middleware without segment resolution.
997
- * Also returns responseType and handler for response routes (non-RSC short-circuit).
998
- */
999
- previewMatch(
1000
- request: Request,
1001
- context: TEnv,
1002
- ): Promise<{
1003
- routeMiddleware?: Array<{
1004
- handler: import("./router/middleware.js").MiddlewareFn;
1005
- params: Record<string, string>;
1006
- }>;
1007
- responseType?: string;
1008
- handler?: Function;
1009
- params?: Record<string, string>;
1010
- negotiated?: boolean;
1011
- } | null>;
1012
-
1013
- matchPartial(
1014
- request: Request,
1015
- context: TEnv,
1016
- actionContext?: {
1017
- actionId?: string;
1018
- actionUrl?: URL;
1019
- actionResult?: any;
1020
- formData?: FormData;
1021
- },
1022
- ): Promise<MatchResult | null>;
1023
-
1024
- /**
1025
- * Match an error to the nearest error boundary and return error segments
1026
- *
1027
- * Used when an action or other operation fails and we need to render
1028
- * the error boundary UI. Finds the nearest errorBoundary in the route tree
1029
- * for the current URL and renders it with the error info.
1030
- *
1031
- * @param request - The current request (used to match the route)
1032
- * @param context - Environment context
1033
- * @param error - The error that occurred
1034
- * @param segmentType - Type of segment where error occurred (default: "route")
1035
- * @returns MatchResult with error segment, or null if no error boundary found
1036
- */
1037
- matchError(
1038
- request: Request,
1039
- context: TEnv,
1040
- error: unknown,
1041
- segmentType?: ErrorInfo["segmentType"],
1042
- ): Promise<MatchResult | null>;
1043
-
1044
- /**
1045
- * @internal
1046
- * Debug utility to serialize the manifest for inspection
1047
- * Returns a JSON-friendly representation of all routes and layouts
1048
- */
1049
- debugManifest(): Promise<SerializedManifest>;
84
+ // Extracted content negotiation utilities
85
+ import { flattenNamedRoutes } from "./router/content-negotiation.js";
1050
86
 
1051
- /**
1052
- * Handle an RSC request.
1053
- *
1054
- * Uses the router's configuration (nonce, version, cache) automatically.
1055
- * The handler is lazily created on first call.
1056
- *
1057
- * @example Cloudflare Workers
1058
- * ```tsx
1059
- * import { router } from "./router";
1060
- *
1061
- * export default { fetch: router.fetch };
1062
- * ```
1063
- *
1064
- * @example Direct export
1065
- * ```tsx
1066
- * const router = createRouter({
1067
- * document: Document,
1068
- * urls: urlpatterns,
1069
- * nonce: () => true,
1070
- * });
1071
- *
1072
- * export const fetch = router.fetch;
1073
- * ```
1074
- */
1075
- fetch(
1076
- request: Request,
1077
- env: TEnv & { ctx?: ExecutionContext },
1078
- ): Promise<Response>;
1079
- }
87
+ // Extracted router types and registry
88
+ import {
89
+ RSC_ROUTER_BRAND,
90
+ RouterRegistry,
91
+ nextRouterAutoId,
92
+ } from "./router/router-registry.js";
93
+ import type { RangoOptions, RootLayoutProps } from "./router/router-options.js";
94
+ import type {
95
+ Rango,
96
+ RangoInternal,
97
+ RouterRequestInput,
98
+ } from "./router/router-interfaces.js";
1080
99
 
1081
- /**
1082
- * Create an RSC router with generic context type
1083
- * Route types are accumulated automatically through the builder chain
1084
- *
1085
- * @example
1086
- * ```typescript
1087
- * interface AppContext {
1088
- * db: Database;
1089
- * user?: User;
1090
- * }
1091
- *
1092
- * const router = createRouter<AppContext>({
1093
- * debugPerformance: true // Enable metrics
1094
- * });
1095
- *
1096
- * // Route types accumulate through the chain - no module augmentation needed!
1097
- * // Keys stay unchanged, only URL patterns get the prefix
1098
- * router
1099
- * .routes(homeRoutes) // accumulates homeRoutes
1100
- * .map(() => import('./home'))
1101
- * .routes('/shop', shopRoutes) // accumulates shopRoutes with prefixed URLs
1102
- * .map(() => import('./shop'));
1103
- *
1104
- * // router.reverse now has type-safe autocomplete for all registered routes
1105
- * // Given shopRoutes = { cart: "/cart" }, reverse uses original key:
1106
- * router.reverse("cart"); // "/shop/cart"
1107
- * ```
1108
- */
100
+ // Extracted closure functions
101
+ import {
102
+ findLazyIncludes,
103
+ evaluateLazyEntry as _evaluateLazyEntry,
104
+ type LazyEvalDeps,
105
+ } from "./router/lazy-includes.js";
106
+ import { createFindMatch } from "./router/find-match.js";
107
+ import {
108
+ matchForPrerender as _matchForPrerender,
109
+ renderStaticSegment as _renderStaticSegment,
110
+ } from "./router/prerender-match.js";
111
+
112
+ // Re-export public types and values from extracted modules
113
+ export { RSC_ROUTER_BRAND, RouterRegistry } from "./router/router-registry.js";
114
+ export type {
115
+ RangoOptions,
116
+ RootLayoutProps,
117
+ SSRStreamMode,
118
+ SSROptions,
119
+ ResolveStreamingContext,
120
+ } from "./router/router-options.js";
121
+ export type {
122
+ Rango,
123
+ RangoInternal,
124
+ RouterRequestInput,
125
+ } from "./router/router-interfaces.js";
126
+ export { toInternal } from "./router/router-interfaces.js";
1109
127
 
1110
128
  export function createRouter<TEnv = any>(
1111
- options: RSCRouterOptions<TEnv> = {},
1112
- ): RSCRouter<TEnv, {}> {
129
+ options: RangoOptions<TEnv> = {},
130
+ ): Rango<TEnv, {}> {
1113
131
  const {
1114
132
  id: userProvidedId,
133
+ $$id: injectedId,
134
+ basename: basenameOption,
1115
135
  debugPerformance = false,
1116
136
  document: documentOption,
1117
137
  defaultErrorBoundary,
@@ -1119,32 +139,84 @@ export function createRouter<TEnv = any>(
1119
139
  notFound,
1120
140
  onError,
1121
141
  cache,
142
+ cacheProfiles: cacheProfilesOption,
1122
143
  theme: themeOption,
1123
144
  urls: urlsOption,
145
+ $$routeNames: staticRouteNames,
146
+ $$sourceFile: injectedSourceFile,
1124
147
  nonce,
1125
148
  version,
149
+ prefetchCacheTTL: prefetchCacheTTLOption,
1126
150
  warmup: warmupOption,
1127
- allowDebugManifest: allowDebugManifestOption = true,
151
+ allowDebugManifest: allowDebugManifestOption = false,
152
+ telemetry: telemetrySink,
153
+ ssr: ssrOption,
154
+ timeout: timeoutShorthand,
155
+ timeouts: timeoutsOption,
156
+ onTimeout,
157
+ originCheck: originCheckOption,
1128
158
  } = options;
1129
159
 
1130
- const routerId = userProvidedId ?? `router_${routerAutoId++}`;
1131
-
1132
- // Capture the source file that called createRouter() via stack trace parsing.
1133
- // Used by the Vite plugin to write per-router named-routes.gen.ts files.
1134
- let __sourceFile: string | undefined;
1135
- try {
1136
- const stack = new Error().stack;
1137
- if (stack) {
1138
- const lines = stack.split("\n");
1139
- for (const line of lines) {
1140
- const match = line.match(/\((.+?\.(ts|tsx|js|jsx)):\d+:\d+\)/);
1141
- if (match && !match[1].includes("/router.ts") && !match[1].includes("@rangojs/router")) {
1142
- __sourceFile = match[1];
1143
- break;
160
+ // Normalize basename: ensure leading slash, strip trailing slash.
161
+ // A bare "/" is equivalent to no basename.
162
+ const basename =
163
+ basenameOption && basenameOption.replace(/^\/+|\/+$/g, "")
164
+ ? "/" + basenameOption.replace(/^\/+|\/+$/g, "")
165
+ : undefined;
166
+
167
+ // Resolve telemetry sink (no-op when not configured)
168
+ const telemetry = resolveSink(telemetrySink);
169
+
170
+ // Resolve cache profiles: merge user config with guaranteed default profile.
171
+ // This resolved map is both stored on the router (for per-request context)
172
+ // and written to the global registry (for DSL-time cache("profileName")).
173
+ const resolvedCacheProfiles = resolveCacheProfiles(cacheProfilesOption);
174
+ setCacheProfiles(resolvedCacheProfiles);
175
+
176
+ // Source file: prefer Vite-injected path (zero cost), fall back to
177
+ // stack trace parsing for non-Vite environments (e.g. tests).
178
+ let __sourceFile: string | undefined = injectedSourceFile;
179
+ if (!__sourceFile) {
180
+ try {
181
+ const stack = new Error().stack;
182
+ if (stack) {
183
+ const lines = stack.split("\n");
184
+ for (const line of lines) {
185
+ const match = line.match(/\((.+?\.(ts|tsx|js|jsx)):\d+:\d+\)/);
186
+ if (
187
+ match &&
188
+ !match[1].endsWith("/router.ts") &&
189
+ !match[1].includes("@rangojs/router") &&
190
+ !match[1].includes("node_modules")
191
+ ) {
192
+ __sourceFile = match[1].startsWith("file:")
193
+ ? match[1].slice(5)
194
+ : match[1];
195
+ break;
196
+ }
1144
197
  }
1145
198
  }
1146
- }
1147
- } catch {}
199
+ } catch {}
200
+ }
201
+
202
+ // Router ID priority: explicit id > Vite-injected $$id > counter fallback.
203
+ // $$id is a hash of filename+line injected by the Vite transform at compile
204
+ // time, so it's stable across build/runtime regardless of module evaluation
205
+ // order (unlike the counter which depends on import order).
206
+ const routerId =
207
+ userProvidedId ?? injectedId ?? `router_${nextRouterAutoId()}`;
208
+
209
+ // Resolve prefetch cache TTL (default: 300 seconds / 5 minutes)
210
+ // Clamp to a non-negative integer for valid Cache-Control max-age.
211
+ const rawTTL =
212
+ prefetchCacheTTLOption !== undefined ? prefetchCacheTTLOption : 300;
213
+ const prefetchCacheTTLSeconds =
214
+ rawTTL === false ? 0 : Math.max(0, Math.floor(rawTTL));
215
+ const prefetchCacheTTL = prefetchCacheTTLSeconds * 1000;
216
+ const prefetchCacheControl: string | false =
217
+ prefetchCacheTTLSeconds === 0
218
+ ? false
219
+ : `private, max-age=${prefetchCacheTTLSeconds}`;
1148
220
 
1149
221
  // Resolve warmup enabled flag (default: true)
1150
222
  const warmupEnabled = warmupOption !== false;
@@ -1154,15 +226,29 @@ export function createRouter<TEnv = any>(
1154
226
  ? resolveThemeConfig(themeOption)
1155
227
  : null;
1156
228
 
229
+ // Resolve timeout config (merge shorthand + structured)
230
+ const resolvedTimeouts = resolveTimeouts(timeoutShorthand, timeoutsOption);
231
+
1157
232
  /**
1158
233
  * Wrapper for invokeOnError that binds the router's onError callback.
1159
234
  * Uses the shared utility from router/error-handling.ts for consistent behavior.
235
+ *
236
+ * Deduplicates via per-request WeakSet stored on the ALS request context.
237
+ * A closure-level WeakSet would silently swallow errors if the same object
238
+ * instance is thrown across separate requests (e.g. a singleton error).
1160
239
  */
1161
240
  function callOnError(
1162
241
  error: unknown,
1163
242
  phase: ErrorPhase,
1164
243
  context: Parameters<typeof invokeOnError<TEnv>>[3],
1165
244
  ): void {
245
+ if (error != null && typeof error === "object") {
246
+ const reportedErrors = _getRequestContext()?._reportedErrors;
247
+ if (reportedErrors) {
248
+ if (reportedErrors.has(error)) return;
249
+ reportedErrors.add(error);
250
+ }
251
+ }
1166
252
  invokeOnError(onError, error, phase, context, "Router");
1167
253
  }
1168
254
 
@@ -1205,6 +291,18 @@ export function createRouter<TEnv = any>(
1205
291
  handler = patternOrMiddleware;
1206
292
  }
1207
293
 
294
+ // Prevent "use cache" functions from being used as middleware.
295
+ // They return data/JSX and do not call next() — silently accepting
296
+ // them would be a confusing no-op.
297
+ if (isCachedFunction(handler)) {
298
+ throw new Error(
299
+ `A "use cache" function cannot be used as middleware. ` +
300
+ `Cached functions return data and do not participate in the ` +
301
+ `middleware chain. Remove the "use cache" directive or use a ` +
302
+ `regular middleware function instead.`,
303
+ );
304
+ }
305
+
1208
306
  // If mount-scoped, prepend mount prefix to pattern
1209
307
  let fullPattern = pattern;
1210
308
  if (mountPrefix && pattern) {
@@ -1234,789 +332,258 @@ export function createRouter<TEnv = any>(
1234
332
  });
1235
333
  }
1236
334
 
1237
- // Track all registered routes with their prefixes for reverse()
1238
- const mergedRouteMap: Record<string, string> = {};
1239
-
1240
- // Build a Map from precomputed entries for O(1) lookup by staticPrefix.
1241
- // The array is set at import time (from the virtual module) before createRouter runs.
1242
- const precomputedEntriesRaw = getPrecomputedEntries();
1243
- const precomputedByPrefix: Map<string, Record<string, string>> | null =
1244
- precomputedEntriesRaw
1245
- ? new Map(precomputedEntriesRaw.map((e) => [e.staticPrefix, e.routes]))
1246
- : null;
1247
-
1248
-
1249
- // Wrapper to pass debugPerformance to external createMetricsStore
1250
- const getMetricsStore = () => createMetricsStore(debugPerformance);
1251
-
1252
- // Wrapper to pass defaults to error/notFound boundary finders
1253
- const findNearestErrorBoundary = (entry: EntryData | null) =>
1254
- findErrorBoundary(entry, defaultErrorBoundary);
1255
-
1256
- const findNearestNotFoundBoundary = (entry: EntryData | null) =>
1257
- findNotFoundBoundary(entry, defaultNotFoundBoundary);
1258
-
1259
- // Helper to get handleStore from request context
1260
- const getHandleStore = (): HandleStore | undefined => {
1261
- return getRequestContext()?._handleStore;
1262
- };
1263
-
1264
- // Track a pending handler promise (non-blocking)
1265
- const trackHandler = <T>(promise: Promise<T>): Promise<T> => {
1266
- const store = getHandleStore();
1267
- return store ? store.track(promise) : promise;
1268
- };
1269
-
1270
- // Wrapper for wrapLoaderWithErrorHandling that uses router's error boundary finder
1271
- // Includes onError callback for loader error notification
1272
- function wrapLoaderPromise<T>(
1273
- promise: Promise<T>,
1274
- entry: EntryData,
1275
- segmentId: string,
1276
- pathname: string,
1277
- errorContext?: {
1278
- request: Request;
1279
- url: URL;
1280
- routeKey?: string;
1281
- params?: Record<string, string>;
1282
- env?: TEnv;
1283
- isPartial?: boolean;
1284
- requestStartTime?: number;
1285
- },
1286
- ): Promise<LoaderDataResult<T>> {
1287
- return wrapLoaderWithErrorHandling(
1288
- promise,
1289
- entry,
1290
- segmentId,
1291
- pathname,
1292
- findNearestErrorBoundary,
1293
- createErrorInfo,
1294
- // Invoke onError when loader fails
1295
- errorContext
1296
- ? (error, ctx) => {
1297
- callOnError(error, "loader", {
1298
- request: errorContext.request,
1299
- url: errorContext.url,
1300
- routeKey: errorContext.routeKey,
1301
- params: errorContext.params,
1302
- segmentId: ctx.segmentId,
1303
- segmentType: "loader",
1304
- loaderName: ctx.loaderName,
1305
- env: errorContext.env,
1306
- isPartial: errorContext.isPartial,
1307
- handledByBoundary: ctx.handledByBoundary,
1308
- requestStartTime: errorContext.requestStartTime,
1309
- });
1310
- }
1311
- : undefined,
1312
- );
1313
- }
1314
-
1315
- // Dependencies object for extracted segment resolution functions.
1316
- // Captures closure-bound helpers from createRouter.
1317
- const segmentDeps: SegmentResolutionDeps<TEnv> = {
1318
- wrapLoaderPromise,
1319
- trackHandler,
1320
- findNearestErrorBoundary,
1321
- findNearestNotFoundBoundary,
1322
- callOnError,
1323
- };
1324
-
1325
- // Match API dependencies
1326
- const matchApiDeps: MatchApiDeps<TEnv> = {
1327
- findMatch: (pathname: string, ms?: any) => findMatch(pathname, ms),
1328
- getMetricsStore,
1329
- findInterceptForRoute: (routeKey, parentEntry, selectorContext, isAction) =>
1330
- findInterceptForRoute(routeKey, parentEntry, selectorContext, isAction),
1331
- callOnError,
1332
- findNearestErrorBoundary,
1333
- };
1334
-
1335
- // Thin wrappers that bind the deps to extracted functions.
1336
- // These maintain the same signatures as the original inline functions
1337
- // so that RouterContext and call sites don't need to change.
1338
-
1339
- function resolveAllSegments(
1340
- entries: EntryData[],
1341
- routeKey: string,
1342
- params: Record<string, string>,
1343
- context: HandlerContext<any, TEnv>,
1344
- loaderPromises: Map<string, Promise<any>>,
1345
- options?: { skipLoaders?: boolean },
1346
- ) {
1347
- return _resolveAllSegments(entries, routeKey, params, context, loaderPromises, segmentDeps, options);
1348
- }
1349
-
1350
- function resolveLoadersOnly(
1351
- entries: EntryData[],
1352
- context: HandlerContext<any, TEnv>,
1353
- ) {
1354
- return _resolveLoadersOnly(entries, context, segmentDeps);
1355
- }
1356
-
1357
- function resolveLoadersOnlyWithRevalidation(
1358
- entries: EntryData[],
1359
- context: HandlerContext<any, TEnv>,
1360
- clientSegmentIds: Set<string>,
1361
- prevParams: Record<string, string>,
1362
- request: Request,
1363
- prevUrl: URL,
1364
- nextUrl: URL,
1365
- routeKey: string,
1366
- actionContext?: { actionId?: string; actionUrl?: URL; actionResult?: any; formData?: FormData },
1367
- ) {
1368
- return _resolveLoadersOnlyWithRevalidation(
1369
- entries, context, clientSegmentIds, prevParams, request,
1370
- prevUrl, nextUrl, routeKey, segmentDeps, actionContext,
1371
- );
1372
- }
1373
-
1374
- function buildEntryRevalidateMap(entries: EntryData[]) {
1375
- return _buildEntryRevalidateMap(entries);
1376
- }
1377
-
1378
- function resolveAllSegmentsWithRevalidation(
1379
- entries: EntryData[],
1380
- routeKey: string,
1381
- params: Record<string, string>,
1382
- context: HandlerContext<any, TEnv>,
1383
- clientSegmentSet: Set<string>,
1384
- prevParams: Record<string, string>,
1385
- request: Request,
1386
- prevUrl: URL,
1387
- nextUrl: URL,
1388
- loaderPromises: Map<string, Promise<any>>,
1389
- actionContext: { actionId?: string; actionUrl?: URL; actionResult?: any; formData?: FormData } | undefined,
1390
- interceptResult: { intercept: InterceptEntry; entry: EntryData } | null,
1391
- localRouteName: string,
1392
- pathname: string,
1393
- ) {
1394
- return _resolveAllSegmentsWithRevalidation(
1395
- entries, routeKey, params, context, clientSegmentSet, prevParams, request,
1396
- prevUrl, nextUrl, loaderPromises, actionContext, interceptResult,
1397
- localRouteName, pathname, segmentDeps,
1398
- );
1399
- }
1400
-
1401
- function findInterceptForRoute(
1402
- targetRouteKey: string,
1403
- fromEntry: EntryData | null,
1404
- selectorContext: InterceptSelectorContext | null = null,
1405
- isAction: boolean = false,
1406
- ) {
1407
- return _findInterceptForRoute(targetRouteKey, fromEntry, selectorContext, isAction);
1408
- }
1409
-
1410
- function resolveInterceptEntry(
1411
- interceptEntry: InterceptEntry,
1412
- parentEntry: EntryData,
1413
- params: Record<string, string>,
1414
- context: HandlerContext<any, TEnv>,
1415
- belongsToRoute: boolean = true,
1416
- revalidationContext?: any,
1417
- ) {
1418
- return _resolveInterceptEntry(
1419
- interceptEntry, parentEntry, params, context, belongsToRoute,
1420
- segmentDeps, revalidationContext,
1421
- );
1422
- }
1423
-
1424
- function resolveInterceptLoadersOnly(
1425
- interceptEntry: InterceptEntry,
1426
- parentEntry: EntryData,
1427
- params: Record<string, string>,
1428
- context: HandlerContext<any, TEnv>,
1429
- belongsToRoute: boolean = true,
1430
- revalidationContext: any,
1431
- ) {
1432
- return _resolveInterceptLoadersOnly(
1433
- interceptEntry, parentEntry, params, context, belongsToRoute,
1434
- segmentDeps, revalidationContext,
1435
- );
1436
- }
1437
-
1438
- // Detect lazy includes in handler result and create placeholder entries
1439
- // Lazy includes are IncludeItem with lazy: true and _lazyContext
1440
- // Moved to outer scope so it can be reused by evaluateLazyEntry for nested includes
1441
- function findLazyIncludes(items: AllUseItems[]): Array<{
1442
- prefix: string;
1443
- patterns: UrlPatterns<TEnv>;
1444
- context: {
1445
- urlPrefix: string;
1446
- namePrefix: string | undefined;
1447
- parent: unknown;
1448
- };
1449
- }> {
1450
- const lazyItems: Array<{
1451
- prefix: string;
1452
- patterns: UrlPatterns<TEnv>;
1453
- context: {
1454
- urlPrefix: string;
1455
- namePrefix: string | undefined;
1456
- parent: unknown;
1457
- };
1458
- }> = [];
1459
-
1460
- for (const item of items) {
1461
- if (!item) continue;
1462
- if (item.type === "include") {
1463
- const includeItem = item as IncludeItem;
1464
- if (includeItem.lazy === true && includeItem._lazyContext) {
1465
- lazyItems.push({
1466
- prefix: includeItem.prefix,
1467
- patterns: includeItem.patterns as UrlPatterns<TEnv>,
1468
- context: includeItem._lazyContext,
1469
- });
1470
- }
1471
- }
1472
- // Recursively check nested items (in layouts, etc.)
1473
- if ((item as any).uses && Array.isArray((item as any).uses)) {
1474
- lazyItems.push(...findLazyIncludes((item as any).uses));
1475
- }
1476
- }
1477
-
1478
- return lazyItems;
1479
- }
1480
-
1481
- /**
1482
- * Evaluate a lazy entry's patterns and populate its routes
1483
- * This runs the lazy patterns handler and updates the entry in-place
1484
- * Also detects nested lazy includes and registers them as new entries
1485
- */
1486
- function evaluateLazyEntry(entry: RouteEntry<TEnv>): void {
1487
- if (!entry.lazy || entry.lazyEvaluated || !entry.lazyPatterns) {
1488
- return;
1489
- }
1490
-
1491
- // Check for pre-computed routes from build-time data.
1492
- // Only leaf nodes (no nested includes) are precomputed, so entries with
1493
- // nested lazy includes fall through to the handler below.
1494
- if (precomputedByPrefix) {
1495
- const routes = precomputedByPrefix.get(entry.staticPrefix);
1496
- if (routes) {
1497
- entry.lazyEvaluated = true;
1498
- entry.routes = routes as ResolvedRouteMap<any>;
1499
- for (const [name, pattern] of Object.entries(routes)) {
1500
- mergedRouteMap[name] = pattern;
1501
- }
1502
- registerRouteMap(mergedRouteMap);
1503
- return;
1504
- }
1505
- }
1506
-
1507
- // Mark as evaluated immediately to prevent concurrent evaluation.
1508
- // JS is single-threaded but handlers.handler() could theoretically yield,
1509
- // and the while-loop in findMatch retries after evaluation.
1510
- entry.lazyEvaluated = true;
1511
-
1512
- const lazyPatterns = entry.lazyPatterns as UrlPatterns<TEnv>;
1513
- const lazyContext = entry.lazyContext;
1514
-
1515
- // Create a new context for evaluating the lazy patterns
1516
- const manifest = new Map<string, EntryData>();
1517
- const patterns = new Map<string, string>();
1518
- const patternsByPrefix = new Map<string, Map<string, string>>();
1519
- const trailingSlashMap = new Map<string, TrailingSlashMode>();
1520
-
1521
- // Capture the handler result to detect nested lazy includes
1522
- let handlerResult: AllUseItems[] = [];
1523
-
1524
- // Merge captured counters from include() to maintain consistent
1525
- // shortCode indices with sibling entries from pattern extraction
1526
- const lazyCounters: Record<string, number> = {};
1527
- if (lazyContext && (lazyContext as any).counters) {
1528
- const captured = (lazyContext as any).counters as Record<string, number>;
1529
- for (const [key, value] of Object.entries(captured)) {
1530
- lazyCounters[key] = value;
1531
- }
1532
- }
1533
-
1534
- RSCRouterContext.run(
1535
- {
1536
- manifest,
1537
- patterns,
1538
- patternsByPrefix,
1539
- trailingSlash: trailingSlashMap,
1540
- namespace: "lazy",
1541
- parent: (lazyContext?.parent as EntryData | null) ?? null,
1542
- counters: lazyCounters,
1543
- },
1544
- () => {
1545
- // Run the lazy patterns handler with the original context prefixes
1546
- // The prefix comes from the IncludeItem stored in lazyPatterns
1547
- const includePrefix = (entry as any)._lazyPrefix || "";
1548
- const fullPrefix = (lazyContext?.urlPrefix || "") + includePrefix;
1549
-
1550
- if (fullPrefix || lazyContext?.namePrefix) {
1551
- runWithPrefixes(fullPrefix, lazyContext?.namePrefix, () => {
1552
- handlerResult = lazyPatterns.handler() as AllUseItems[];
1553
- });
1554
- } else {
1555
- handlerResult = lazyPatterns.handler() as AllUseItems[];
1556
- }
1557
- },
1558
- );
1559
-
1560
- // Populate the entry's routes from the patterns
1561
- const routesObject: Record<string, string> = {};
1562
- for (const [name, pattern] of patterns.entries()) {
1563
- routesObject[name] = pattern;
1564
- // Also add to merged route map for reverse() support
1565
- const existingPattern = mergedRouteMap[name];
1566
- if (existingPattern !== undefined && existingPattern !== pattern) {
1567
- console.warn(
1568
- `[@rangojs/router] Route name conflict: "${name}" already maps to "${existingPattern}", ` +
1569
- `overwriting with "${pattern}" (from lazy include). Use unique route names to avoid this.`,
1570
- );
1571
- }
1572
- mergedRouteMap[name] = pattern;
1573
- }
1574
-
1575
- // Update the entry in-place
1576
- entry.routes = routesObject as ResolvedRouteMap<any>;
1577
-
1578
- // Note: Do NOT clear lazyPatterns/lazyContext here.
1579
- // loadManifest() needs them on every request to re-run the handler
1580
- // in the correct AsyncLocalStorage context (Store.manifest).
1581
-
1582
- // Update trailing slash config if available
1583
- if (trailingSlashMap.size > 0) {
1584
- entry.trailingSlash = Object.fromEntries(trailingSlashMap);
1585
- }
1586
-
1587
- // Detect nested lazy includes and register them as new entries
1588
- const nestedLazyIncludes = findLazyIncludes(handlerResult);
1589
- for (const lazyInclude of nestedLazyIncludes) {
1590
- // Compute the full URL prefix (combining parent prefix if any)
1591
- const fullPrefix = lazyInclude.context.urlPrefix
1592
- ? lazyInclude.context.urlPrefix + lazyInclude.prefix
1593
- : lazyInclude.prefix;
1594
-
1595
- const nestedEntry: RouteEntry<TEnv> & { _lazyPrefix?: string } = {
1596
- prefix: "",
1597
- staticPrefix: extractStaticPrefix(fullPrefix),
1598
- routes: {} as ResolvedRouteMap<any>, // Empty until first match
1599
- trailingSlash: entry.trailingSlash,
1600
- handler: (lazyInclude.patterns as UrlPatterns<TEnv>).handler,
1601
- mountIndex: entry.mountIndex,
1602
- // Lazy evaluation fields
1603
- lazy: true,
1604
- lazyPatterns: lazyInclude.patterns,
1605
- lazyContext: lazyInclude.context,
1606
- lazyEvaluated: false,
1607
- // Store the include prefix for evaluation
1608
- _lazyPrefix: lazyInclude.prefix,
1609
- };
1610
- // Insert nested lazy entry before any entry whose staticPrefix is a
1611
- // prefix of (but shorter than) this lazy entry's staticPrefix.
1612
- // This ensures more specific lazy includes are matched before
1613
- // less specific eager entries (e.g., "/href/nested" before "/href/:id").
1614
- const nestedPrefix = nestedEntry.staticPrefix;
1615
- let insertIndex = routesEntries.length;
1616
- if (nestedPrefix) {
1617
- for (let i = 0; i < routesEntries.length; i++) {
1618
- const existing = routesEntries[i]!;
1619
- if (
1620
- nestedPrefix.startsWith(existing.staticPrefix) &&
1621
- nestedPrefix.length > existing.staticPrefix.length
1622
- ) {
1623
- insertIndex = i;
1624
- break;
1625
- }
1626
- }
1627
- }
1628
- routesEntries.splice(insertIndex, 0, nestedEntry);
1629
- }
1630
-
1631
- // Re-register route map for runtime reverse() usage
1632
- registerRouteMap(mergedRouteMap);
1633
- }
1634
-
1635
- // Single-entry cache for findMatch to avoid redundant matching within the same request.
1636
- // previewMatch and match both call findMatch with the same pathname — this ensures
1637
- // the route matching work (which may check thousands of routes) only happens once.
1638
- let lastFindMatchPathname: string | null = null;
1639
- let lastFindMatchResult: RouteMatchResult<TEnv> | null = null;
1640
-
1641
- // Wrapper for findMatch that uses routesEntries
1642
- // Handles lazy evaluation by evaluating lazy entries on first match.
1643
- // Phase 1: try O(path_length) trie match.
1644
- // Phase 2: fall back to regex iteration.
1645
- function findMatch(
1646
- pathname: string,
1647
- ms?: MetricsStore,
1648
- ): RouteMatchResult<TEnv> | null {
1649
- // Return cached result if same pathname (avoids double-match per request)
1650
- if (lastFindMatchPathname === pathname) {
1651
- return lastFindMatchResult;
1652
- }
1653
-
1654
- // Helper to push sub-metrics
1655
- const pushMetric = ms
1656
- ? (label: string, start: number) => {
1657
- ms.metrics.push({
1658
- label,
1659
- duration: performance.now() - start,
1660
- startTime: start - ms.requestStart,
1661
- });
1662
- }
1663
- : undefined;
1664
-
1665
- // Phase 1: Try trie match (O(path_length))
1666
- const routeTrie = getRouteTrie();
1667
- if (routeTrie) {
1668
- const trieStart = performance.now();
1669
- const trieResult = tryTrieMatch(routeTrie, pathname);
1670
- pushMetric?.("match:trie", trieStart);
1671
-
1672
- if (trieResult) {
1673
- // Find the RouteEntry that contains this route.
1674
- // Multiple entries can share the same staticPrefix (e.g., several
1675
- // include("/", patterns) calls all produce staticPrefix=""). Evaluate
1676
- // each candidate and pick the one whose routes include the matched key.
1677
- const entryStart = performance.now();
1678
- let entry: RouteEntry<TEnv> | undefined;
1679
- let fallbackEntry: RouteEntry<TEnv> | undefined;
1680
-
1681
- for (const e of routesEntries) {
1682
- if (e.staticPrefix !== trieResult.sp) continue;
1683
- if (!fallbackEntry) fallbackEntry = e;
1684
- evaluateLazyEntry(e);
1685
- if (
1686
- e.routes &&
1687
- trieResult.routeKey in (e.routes as Record<string, unknown>)
1688
- ) {
1689
- entry = e;
1690
- break;
1691
- }
1692
- }
1693
-
1694
- // If no entry had the route in its routes map, use the first matching
1695
- // entry as fallback (handles main entry with inline routes not yet
1696
- // reflected in its routes object).
1697
- if (!entry) entry = fallbackEntry;
1698
-
1699
- // If entry not found (nested include not yet discovered), evaluate parent
1700
- if (!entry) {
1701
- const parent = routesEntries.find(
1702
- (e) =>
1703
- trieResult.sp.startsWith(e.staticPrefix) &&
1704
- e.staticPrefix !== trieResult.sp,
1705
- );
1706
- if (parent) {
1707
- const lazyStart = performance.now();
1708
- evaluateLazyEntry(parent);
1709
- pushMetric?.("match:lazy-eval", lazyStart);
1710
- }
1711
- entry = routesEntries.find((e) => e.staticPrefix === trieResult.sp);
1712
- }
1713
- pushMetric?.("match:entry-resolve", entryStart);
1714
-
1715
- if (entry) {
1716
- lastFindMatchPathname = pathname;
1717
- lastFindMatchResult = {
1718
- entry,
1719
- routeKey: trieResult.routeKey,
1720
- params: trieResult.params,
1721
- optionalParams: new Set(trieResult.optionalParams || []),
1722
- redirectTo: trieResult.redirectTo,
1723
- ancestry: trieResult.ancestry,
1724
- ...(trieResult.pr ? { pr: true } : {}),
1725
- ...(trieResult.pt ? { pt: true } : {}),
1726
- ...(trieResult.responseType ? { responseType: trieResult.responseType } : {}),
1727
- ...(trieResult.negotiateVariants ? { negotiateVariants: trieResult.negotiateVariants } : {}),
1728
- ...(trieResult.rscFirst ? { rscFirst: true } : {}),
1729
- };
1730
- return lastFindMatchResult;
1731
- }
1732
- }
1733
- }
1734
-
1735
- // Phase 2: Fall back to existing matching (regex iteration)
1736
- const regexStart = performance.now();
1737
- let result = findRouteMatch(pathname, routesEntries);
1738
-
1739
- // If we hit a lazy entry that needs evaluation, evaluate and retry.
1740
- // Cap iterations to prevent infinite loops from pathological nesting.
1741
- const MAX_LAZY_ITERATIONS = 100;
1742
- let iterations = 0;
1743
- while (isLazyEvaluationNeeded(result)) {
1744
- if (++iterations > MAX_LAZY_ITERATIONS) {
1745
- console.error(
1746
- `[@rangojs/router] Exceeded ${MAX_LAZY_ITERATIONS} lazy evaluation iterations ` +
1747
- `for pathname "${pathname}". This likely indicates circular lazy includes.`,
1748
- );
1749
- lastFindMatchPathname = pathname;
1750
- lastFindMatchResult = null;
1751
- return null;
1752
- }
1753
- evaluateLazyEntry(result.lazyEntry);
1754
- result = findRouteMatch(pathname, routesEntries);
1755
- }
1756
- pushMetric?.("match:regex-fallback", regexStart);
1757
-
1758
- lastFindMatchPathname = pathname;
1759
- lastFindMatchResult = result;
1760
- return result;
1761
- }
1762
-
1763
-
1764
- /**
1765
- * Build-time pre-render match. Resolves segments with a BuildContext
1766
- * (no request/env/headers/cookies), skipping middleware and loaders.
1767
- */
1768
- async function matchForPrerender(
1769
- pathname: string,
1770
- params: Record<string, string>,
1771
- ): Promise<{
1772
- segments: SerializedSegmentData[];
1773
- handles: Record<string, SegmentHandleData>;
1774
- routeName: string;
1775
- params: Record<string, string>;
1776
- } | null> {
1777
- // 1. Find the matching route entry
1778
- const matched = findMatch(pathname);
1779
- if (!matched) return null;
1780
-
1781
- // Use params from trie match if available, fall back to provided params
1782
- const matchedParams = matched.params ?? params;
1783
-
1784
- // Build a minimal RouterContext for loadManifest/traverseBack
1785
- const routerCtx: RouterContext<TEnv> = {
1786
- findMatch,
1787
- loadManifest,
1788
- traverseBack,
1789
- createHandlerContext,
1790
- setupLoaderAccess,
1791
- setupLoaderAccessSilent,
1792
- getContext,
1793
- getMetricsStore,
1794
- createCacheScope,
1795
- findInterceptForRoute,
1796
- resolveAllSegmentsWithRevalidation,
1797
- resolveInterceptEntry,
1798
- evaluateRevalidation,
1799
- getRequestContext,
1800
- resolveAllSegments,
1801
- createHandleStore,
1802
- buildEntryRevalidateMap,
1803
- resolveLoadersOnlyWithRevalidation,
1804
- resolveInterceptLoadersOnly,
1805
- resolveLoadersOnly,
1806
- };
1807
-
1808
- return runWithRouterContext(routerCtx, async () => {
1809
- // 2. Load the manifest entry tree
1810
- const manifestEntry = await loadManifest(
1811
- matched.entry,
1812
- matched.routeKey,
1813
- pathname,
1814
- undefined,
1815
- false,
1816
- );
1817
-
1818
- // 3. Build ancestor chain [root, ..., route]
1819
- const entries: EntryData[] = [];
1820
- for (const entry of traverseBack(manifestEntry)) {
1821
- entries.push(entry);
1822
- }
335
+ // Track all registered routes with their prefixes for reverse().
336
+ // Seed from injected NamedRoutes so reverse() works at module load time
337
+ // for routes that come from lazy includes.
338
+ const mergedRouteMap: Record<string, string> =
339
+ flattenNamedRoutes(staticRouteNames);
340
+
341
+ // Track names that came from the static seed so we can silently overwrite
342
+ // them during routes() registration. The gen file may be stale during HMR,
343
+ // so conflicts between seeded and runtime-registered values are expected.
344
+ const seededNames = new Set(Object.keys(mergedRouteMap));
345
+
346
+ // Lazy precomputed entries lookup: rebuilt when per-router data arrives.
347
+ // In production multi-router setups, per-router data is loaded lazily via
348
+ // ensureRouterManifest(). At createRouter() time the data isn't available yet,
349
+ // so we defer building the Map until first use and invalidate when the
350
+ // per-router source changes.
351
+ let precomputedByPrefix: Map<string, Record<string, string>> | null = null;
352
+ let precomputedSource:
353
+ | Array<{ staticPrefix: string; routes: Record<string, string> }>
354
+ | null
355
+ | undefined;
356
+
357
+ function getPrecomputedByPrefix(): Map<
358
+ string,
359
+ Record<string, string>
360
+ > | null {
361
+ const current =
362
+ getRouterPrecomputedEntries(routerId) ?? getPrecomputedEntries();
363
+ if (current !== precomputedSource) {
364
+ precomputedSource = current;
365
+ precomputedByPrefix = current
366
+ ? new Map(current.map((e) => [e.staticPrefix, e.routes]))
367
+ : null;
368
+ }
369
+ return precomputedByPrefix;
370
+ }
1823
371
 
1824
- // 4. Create handle store for collecting handle data
1825
- const handleStore = createHandleStore();
372
+ // Wrapper to pass debugPerformance to external createMetricsStore.
373
+ // Also checks per-request flag set by ctx.debugPerformance() in middleware.
374
+ const getMetricsStore = () => {
375
+ const reqCtx = _getRequestContext();
376
+ const enabled = debugPerformance || !!reqCtx?._debugPerformance;
377
+ if (!enabled) return undefined;
378
+ if (!reqCtx) {
379
+ return createMetricsStore(true);
380
+ }
381
+ reqCtx._metricsStore ??= createMetricsStore(true);
382
+ return reqCtx._metricsStore;
383
+ };
1826
384
 
1827
- // 5. Create a minimal request context with the handle store
1828
- const stubRes = new Response(null, { status: 200 });
1829
- const minimalRequestContext: RequestContext<TEnv> = {
1830
- env: {} as TEnv,
1831
- request: new Request("http://prerender" + pathname),
1832
- url: new URL("http://prerender" + pathname),
1833
- pathname,
1834
- searchParams: new URLSearchParams(),
1835
- var: {},
1836
- get: () => undefined as any,
1837
- set: () => {},
1838
- params: matchedParams,
1839
- res: stubRes,
1840
- cookie: () => undefined,
1841
- cookies: () => ({}),
1842
- setCookie: () => {},
1843
- deleteCookie: () => {},
1844
- header: () => {},
1845
- use: (() => {
1846
- throw new Error("use() not available during pre-rendering");
1847
- }) as any,
1848
- method: "GET",
1849
- _handleStore: handleStore,
1850
- waitUntil: () => {},
1851
- onResponse: () => {},
1852
- _onResponseCallbacks: [],
1853
- };
385
+ // Wrapper to pass defaults to error/notFound boundary finders
386
+ const findNearestErrorBoundary = (entry: EntryData | null) =>
387
+ findErrorBoundary(entry, defaultErrorBoundary);
1854
388
 
1855
- return runWithRequestContext(minimalRequestContext, async () => {
1856
- // 6. Create BuildContext (no request/env/headers/cookies)
1857
- const buildCtx = createBuildContext<TEnv>(
1858
- matchedParams,
1859
- pathname,
1860
- handleStore,
1861
- );
389
+ const findNearestNotFoundBoundary = (entry: EntryData | null) =>
390
+ findNotFoundBoundary(entry, defaultNotFoundBoundary);
1862
391
 
1863
- // 7. Wire use() for handles only (loaders throw)
1864
- setupBuildUse(buildCtx);
1865
-
1866
- // 8. Resolve all segments with skipLoaders
1867
- const loaderPromises = new Map<string, Promise<any>>();
1868
- const allSegments = await resolveAllSegments(
1869
- entries,
1870
- matched.routeKey,
1871
- matchedParams,
1872
- buildCtx,
1873
- loaderPromises,
1874
- { skipLoaders: true },
1875
- );
392
+ // Helper to get handleStore from request context
393
+ const getHandleStore = (): HandleStore | undefined => {
394
+ return _getRequestContext()?._handleStore;
395
+ };
1876
396
 
1877
- // 9. Filter out any loader segments (belt-and-suspenders)
1878
- const nonLoaderSegments = allSegments.filter((s) => s.type !== "loader");
397
+ // Track a pending handler promise (non-blocking).
398
+ // Attaches a side-effect .catch() to report streaming handler errors to onError
399
+ // without altering the rejection chain (React's streaming error boundary still handles it).
400
+ const trackHandler = <T>(
401
+ promise: Promise<T>,
402
+ errorContext?: {
403
+ segmentId?: string;
404
+ segmentType?: string;
405
+ },
406
+ ): Promise<T> => {
407
+ const store = getHandleStore();
408
+ const tracked = store ? store.track(promise) : promise;
409
+
410
+ // Report streaming handler errors to onError as a side-effect.
411
+ // The rejection still propagates to the RSC stream for client error boundaries.
412
+ // Captures request context eagerly (closure) so the catch handler has full context.
413
+ const reqCtx = _getRequestContext();
414
+ if (reqCtx && onError) {
415
+ tracked.catch((error) => {
416
+ callOnError(error, "handler", {
417
+ request: reqCtx.request,
418
+ url: reqCtx.url,
419
+ routeKey: reqCtx._routeName,
420
+ params: reqCtx.params as Record<string, string>,
421
+ env: reqCtx.env as TEnv,
422
+ segmentId: errorContext?.segmentId,
423
+ segmentType: errorContext?.segmentType as any,
424
+ handledByBoundary: true,
425
+ });
426
+ });
427
+ }
1879
428
 
1880
- // 10. Wait for handles to settle
1881
- await handleStore.settled;
429
+ return tracked;
430
+ };
1882
431
 
1883
- // 11. Serialize segments using the cache serializer
1884
- const { serializeSegments } = await import("./cache/cache-scope.js");
1885
- const serializedSegments = await serializeSegments(nonLoaderSegments);
432
+ // Wrapper for wrapLoaderWithErrorHandling that uses router's error boundary finder
433
+ // Includes onError callback for loader error notification and telemetry emission.
434
+ function wrapLoaderPromise<T>(
435
+ promise: Promise<T>,
436
+ entry: EntryData,
437
+ segmentId: string,
438
+ pathname: string,
439
+ errorContext?: {
440
+ request: Request;
441
+ url: URL;
442
+ routeKey?: string;
443
+ params?: Record<string, string>;
444
+ env?: TEnv;
445
+ isPartial?: boolean;
446
+ requestStartTime?: number;
447
+ },
448
+ ): Promise<LoaderDataResult<T>> {
449
+ const loaderStart = telemetrySink ? performance.now() : 0;
450
+ const loaderRequestId = telemetrySink
451
+ ? errorContext?.request
452
+ ? getRequestId(errorContext.request)
453
+ : undefined
454
+ : undefined;
455
+ if (telemetrySink) {
456
+ const loaderName = segmentId.split(".").pop() || "unknown";
457
+ safeEmit(telemetry, {
458
+ type: "loader.start",
459
+ timestamp: loaderStart,
460
+ requestId: loaderRequestId,
461
+ segmentId,
462
+ loaderName,
463
+ pathname,
464
+ });
465
+ }
1886
466
 
1887
- // 12. Collect handle data per segment (skip segments with no handle data)
1888
- const handles: Record<string, SegmentHandleData> = {};
1889
- for (const seg of nonLoaderSegments) {
1890
- const segHandles = handleStore.getDataForSegment(seg.id);
1891
- if (Object.keys(segHandles).length > 0) {
1892
- handles[seg.id] = segHandles;
467
+ const result = wrapLoaderWithErrorHandling(
468
+ promise,
469
+ entry,
470
+ segmentId,
471
+ pathname,
472
+ findNearestErrorBoundary,
473
+ createErrorInfo,
474
+ // Invoke onError when loader fails
475
+ errorContext
476
+ ? (error, ctx) => {
477
+ callOnError(error, "loader", {
478
+ request: errorContext.request,
479
+ url: errorContext.url,
480
+ routeKey: errorContext.routeKey,
481
+ params: errorContext.params,
482
+ segmentId: ctx.segmentId,
483
+ segmentType: "loader",
484
+ loaderName: ctx.loaderName,
485
+ env: errorContext.env,
486
+ isPartial: errorContext.isPartial,
487
+ handledByBoundary: ctx.handledByBoundary,
488
+ requestStartTime: errorContext.requestStartTime,
489
+ });
490
+ if (telemetrySink) {
491
+ const errorObj =
492
+ error instanceof Error ? error : new Error(String(error));
493
+ safeEmit(telemetry, {
494
+ type: "loader.error",
495
+ timestamp: performance.now(),
496
+ requestId: loaderRequestId,
497
+ segmentId: ctx.segmentId,
498
+ loaderName: ctx.loaderName,
499
+ pathname,
500
+ error: errorObj,
501
+ handledByBoundary: ctx.handledByBoundary,
502
+ });
503
+ }
1893
504
  }
1894
- }
1895
-
1896
- // Use the trie-level route key (e.g., "docs", "docs.article")
1897
- const routeName = matched.routeKey;
505
+ : undefined,
506
+ );
1898
507
 
1899
- return {
1900
- segments: serializedSegments,
1901
- handles,
1902
- routeName,
1903
- params: matchedParams,
1904
- };
508
+ // Emit loader.end after the promise settles (fire-and-forget)
509
+ if (telemetrySink) {
510
+ const loaderName = segmentId.split(".").pop() || "unknown";
511
+ result.then((r) => {
512
+ safeEmit(telemetry, {
513
+ type: "loader.end",
514
+ timestamp: performance.now(),
515
+ requestId: loaderRequestId,
516
+ segmentId,
517
+ loaderName,
518
+ pathname,
519
+ durationMs: performance.now() - loaderStart,
520
+ ok: r.ok,
521
+ });
1905
522
  });
1906
- });
1907
- }
1908
-
1909
- /**
1910
- * Match request and return segments (document/SSR requests)
1911
- *
1912
- * Uses generator middleware pipeline for clean separation of concerns:
1913
- * - cache-lookup: Check cache first
1914
- * - segment-resolution: Resolve segments on cache miss
1915
- * - cache-store: Store results in cache
1916
- * - background-revalidation: SWR revalidation
1917
- */
1918
- async function match(request: Request, env: TEnv): Promise<MatchResult> {
1919
- // Build RouterContext with all closure functions needed by middleware
1920
- const routerCtx: RouterContext<TEnv> = {
1921
- findMatch,
1922
- loadManifest,
1923
- traverseBack,
1924
- createHandlerContext,
1925
- setupLoaderAccess,
1926
- setupLoaderAccessSilent,
1927
- getContext,
1928
- getMetricsStore,
1929
- createCacheScope,
1930
- findInterceptForRoute,
1931
- resolveAllSegmentsWithRevalidation,
1932
- resolveInterceptEntry,
1933
- evaluateRevalidation,
1934
- getRequestContext,
1935
- resolveAllSegments,
1936
- createHandleStore,
1937
- buildEntryRevalidateMap,
1938
- resolveLoadersOnlyWithRevalidation,
1939
- resolveInterceptLoadersOnly,
1940
- resolveLoadersOnly,
1941
- };
1942
-
1943
- return runWithRouterContext(routerCtx, async () => {
1944
- const result = await createMatchContextForFull(request, env);
1945
-
1946
- // Handle redirect case
1947
- if ("type" in result && result.type === "redirect") {
1948
- return {
1949
- segments: [],
1950
- matched: [],
1951
- diff: [],
1952
- params: {},
1953
- redirect: result.redirectUrl,
1954
- };
1955
- }
523
+ }
1956
524
 
1957
- const ctx = result as MatchContext<TEnv>;
1958
-
1959
- try {
1960
- const state = createPipelineState();
1961
- const pipeline = createMatchPartialPipeline(ctx, state);
1962
- return await collectMatchResult(pipeline, ctx, state);
1963
- } catch (error) {
1964
- if (error instanceof Response) throw error;
1965
- // Report unhandled errors during full match pipeline
1966
- callOnError(error, "routing", {
1967
- request,
1968
- url: ctx.url,
1969
- env,
1970
- isPartial: false,
1971
- handledByBoundary: false,
1972
- });
1973
- throw sanitizeError(error);
1974
- }
1975
- });
525
+ return result;
1976
526
  }
1977
527
 
1978
- async function matchError(
1979
- request: Request,
1980
- _context: TEnv,
1981
- error: unknown,
1982
- segmentType: ErrorInfo["segmentType"] = "route",
1983
- ): Promise<MatchResult | null> {
1984
- return _matchError(request, _context, error, matchApiDeps, defaultErrorBoundary, segmentType);
1985
- }
528
+ // Dependencies object for extracted segment resolution functions.
529
+ // Captures closure-bound helpers from createRouter.
530
+ const segmentDeps: SegmentResolutionDeps<TEnv> = {
531
+ wrapLoaderPromise,
532
+ trackHandler,
533
+ findNearestErrorBoundary,
534
+ findNearestNotFoundBoundary,
535
+ notFoundComponent: notFound,
536
+ callOnError,
537
+ };
538
+
539
+ // Match API dependencies
540
+ const matchApiDeps: MatchApiDeps<TEnv> = {
541
+ findMatch: (pathname: string, ms?: any) => findMatch(pathname, ms),
542
+ getMetricsStore,
543
+ findInterceptForRoute: (routeKey, parentEntry, selectorContext, isAction) =>
544
+ findInterceptForRoute(routeKey, parentEntry, selectorContext, isAction),
545
+ callOnError,
546
+ findNearestErrorBoundary,
547
+ // Use per-router manifest when available, otherwise the static named map
548
+ // seeded into mergedRouteMap at router creation.
549
+ getRouteMap: () => getRouterManifest(routerId) ?? mergedRouteMap,
550
+ };
1986
551
 
552
+ // Create segment resolution wrappers bound to segmentDeps
553
+ const {
554
+ resolveAllSegments,
555
+ resolveLoadersOnly,
556
+ resolveLoadersOnlyWithRevalidation,
557
+ buildEntryRevalidateMap,
558
+ resolveAllSegmentsWithRevalidation,
559
+ findInterceptForRoute,
560
+ resolveInterceptEntry,
561
+ resolveInterceptLoadersOnly,
562
+ } = createSegmentWrappers<TEnv>(segmentDeps);
563
+
564
+ // Lazy evaluation deps — captures closure state for extracted evaluateLazyEntry
565
+ const lazyEvalDeps: LazyEvalDeps<TEnv> = {
566
+ routesEntries,
567
+ mergedRouteMap,
568
+ nextMountIndex: () => mountIndex++,
569
+ getPrecomputedByPrefix,
570
+ routerId,
571
+ };
1987
572
 
1988
- async function createMatchContextForFull(
1989
- request: Request,
1990
- env: TEnv,
1991
- ) {
1992
- return _createMatchContextForFull(request, env, matchApiDeps, findInterceptForRoute);
573
+ function evaluateLazyEntry(entry: RouteEntry<TEnv>): void {
574
+ _evaluateLazyEntry(entry, lazyEvalDeps);
1993
575
  }
1994
576
 
1995
- async function createMatchContextForPartial(
1996
- request: Request,
1997
- env: TEnv,
1998
- actionContext?: { actionId?: string; actionUrl?: URL; actionResult?: any; formData?: FormData },
1999
- ) {
2000
- return _createMatchContextForPartial(request, env, matchApiDeps, findInterceptForRoute, actionContext);
2001
- }
577
+ // Create findMatch with single-entry cache, bound to router state
578
+ const findMatch = createFindMatch<TEnv>({
579
+ routesEntries,
580
+ evaluateLazyEntry,
581
+ routerId,
582
+ });
2002
583
 
2003
- /**
2004
- * Match partial request with revalidation
2005
- *
2006
- * Uses generator middleware pipeline for clean separation of concerns:
2007
- * - cache-lookup: Check cache first
2008
- * - segment-resolution: Resolve segments on cache miss
2009
- * - intercept-resolution: Handle intercept routes
2010
- * - cache-store: Store results in cache
2011
- * - background-revalidation: SWR revalidation
2012
- */
2013
- async function matchPartial(
2014
- request: Request,
2015
- context: TEnv,
2016
- actionContext?: ActionContext,
2017
- ): Promise<MatchResult | null> {
2018
- // Build RouterContext with all closure functions needed by middleware
2019
- const routerCtx: RouterContext<TEnv> = {
584
+ // Build a RouterContext once — shared by match, matchPartial, matchForPrerender
585
+ function buildRouterContext(): RouterContext<TEnv> {
586
+ return {
2020
587
  findMatch,
2021
588
  loadManifest,
2022
589
  traverseBack,
@@ -2036,463 +603,302 @@ export function createRouter<TEnv = any>(
2036
603
  buildEntryRevalidateMap,
2037
604
  resolveLoadersOnlyWithRevalidation,
2038
605
  resolveInterceptLoadersOnly,
606
+ resolveLoadersOnly,
607
+ telemetry: telemetrySink,
2039
608
  };
2040
-
2041
- return runWithRouterContext(routerCtx, async () => {
2042
- const ctx = await createMatchContextForPartial(
2043
- request,
2044
- context,
2045
- actionContext,
2046
- );
2047
- if (!ctx) return null;
2048
-
2049
- try {
2050
- const state = createPipelineState();
2051
- const pipeline = createMatchPartialPipeline(ctx, state);
2052
- return await collectMatchResult(pipeline, ctx, state);
2053
- } catch (error) {
2054
- if (error instanceof Response) throw error;
2055
- // Report unhandled errors during partial match pipeline
2056
- callOnError(error, actionContext ? "action" : "revalidation", {
2057
- request,
2058
- url: ctx.url,
2059
- env: context,
2060
- actionId: actionContext?.actionId,
2061
- isPartial: true,
2062
- handledByBoundary: false,
2063
- });
2064
- throw sanitizeError(error);
2065
- }
2066
- });
2067
609
  }
2068
610
 
2069
- /**
2070
- * Preview match - returns route middleware without segment resolution.
2071
- * Also returns responseType and handler for response routes (non-RSC short-circuit).
2072
- */
2073
- async function previewMatch(
2074
- request: Request,
2075
- _context: TEnv,
2076
- ): Promise<{
2077
- routeMiddleware?: Array<{
2078
- handler: import("./router/middleware.js").MiddlewareFn;
2079
- params: Record<string, string>;
2080
- }>;
2081
- responseType?: string;
2082
- handler?: Function;
2083
- params?: Record<string, string>;
2084
- negotiated?: boolean;
2085
- } | null> {
2086
- const url = new URL(request.url);
2087
- const pathname = url.pathname;
2088
-
2089
- // Quick route matching
2090
- const matched = findMatch(pathname);
2091
- if (!matched) {
2092
- return null;
2093
- }
2094
-
2095
- // Skip redirect check - will be handled in full match
2096
- if (matched.redirectTo) {
2097
- return { routeMiddleware: undefined };
2098
- }
611
+ // Prerender/static match deps (bind closure state for extracted functions)
612
+ const prerenderDeps = {
613
+ findMatch,
614
+ buildRouterContext,
615
+ mergedRouteMap,
616
+ resolveAllSegments,
617
+ };
2099
618
 
2100
- // Load manifest (without segment resolution)
2101
- const manifestEntry = await loadManifest(
2102
- matched.entry,
2103
- matched.routeKey,
619
+ async function matchForPrerender(
620
+ pathname: string,
621
+ params: Record<string, string>,
622
+ buildVars?: Record<string, any>,
623
+ isPassthroughRoute?: boolean,
624
+ buildEnv?: TEnv,
625
+ devMode?: boolean,
626
+ ) {
627
+ return _matchForPrerender(
2104
628
  pathname,
2105
- undefined, // No metrics store for preview
2106
- false, // isSSR - doesn't matter for preview
629
+ params,
630
+ prerenderDeps,
631
+ buildVars,
632
+ isPassthroughRoute,
633
+ buildEnv,
634
+ devMode,
2107
635
  );
636
+ }
2108
637
 
2109
- // Collect route-level middleware from entry tree
2110
- // Includes middleware from orphan layouts (inline layouts within routes)
2111
- const routeMiddleware = collectRouteMiddleware(
2112
- traverseBack(manifestEntry),
2113
- matched.params,
638
+ async function renderStaticSegment(
639
+ handler: Function,
640
+ handlerId: string,
641
+ routeName?: string,
642
+ buildEnv?: TEnv,
643
+ devMode?: boolean,
644
+ ) {
645
+ return _renderStaticSegment<TEnv>(
646
+ handler,
647
+ handlerId,
648
+ mergedRouteMap,
649
+ routeName,
650
+ buildEnv,
651
+ devMode,
2114
652
  );
2115
-
2116
- // Check for response type (from trie match or manifest entry)
2117
- const responseType = matched.responseType ||
2118
- (manifestEntry.type === "route" ? manifestEntry.responseType : undefined);
2119
-
2120
- // Content negotiation: when negotiate variants exist, pick the best
2121
- // handler based on the Accept header. Uses q-values and client order
2122
- // as tiebreaker (matching Express/Hono behavior). RSC routes participate
2123
- // as text/html candidates so browsers naturally get HTML without
2124
- // special-casing.
2125
- if (matched.negotiateVariants && matched.negotiateVariants.length > 0) {
2126
- const acceptEntries = parseAcceptTypes(request.headers.get("accept") || "");
2127
-
2128
- // Build candidate list preserving definition order.
2129
- // For wildcard (*/*) and no-Accept fallback, the first candidate wins.
2130
- const variants = matched.negotiateVariants;
2131
- let candidates: Array<{ routeKey: string; responseType: string }>;
2132
- if (responseType) {
2133
- // Primary is response-type — include it as a candidate
2134
- candidates = [...variants, { routeKey: matched.routeKey, responseType }];
2135
- } else {
2136
- // Primary is RSC — insert as text/html candidate in definition order
2137
- const rscCandidate = { routeKey: matched.routeKey, responseType: RSC_RESPONSE_TYPE };
2138
- candidates = matched.rscFirst
2139
- ? [rscCandidate, ...variants]
2140
- : [...variants, rscCandidate];
2141
- }
2142
-
2143
- const variant = pickNegotiateVariant(acceptEntries, candidates);
2144
-
2145
- // If the winner is RSC, fall through to default RSC handling
2146
- if (variant.responseType === RSC_RESPONSE_TYPE) {
2147
- // Fall through — RSC won negotiation
2148
- } else if (responseType && variant.routeKey === matched.routeKey) {
2149
- // Fall through — response-type primary won, already set
2150
- } else {
2151
- const negotiateEntry = await loadManifest(
2152
- matched.entry,
2153
- variant.routeKey,
2154
- pathname,
2155
- undefined,
2156
- false,
2157
- );
2158
- return {
2159
- routeMiddleware: routeMiddleware.length > 0 ? routeMiddleware : undefined,
2160
- responseType: variant.responseType,
2161
- handler: negotiateEntry.type === "route" ? negotiateEntry.handler : undefined,
2162
- params: matched.params,
2163
- negotiated: true,
2164
- };
2165
- }
2166
- }
2167
-
2168
- // If we passed through the negotiation block (variants exist), mark as
2169
- // negotiated so the handler sets Vary: Accept on the response.
2170
- const hasVariants = matched.negotiateVariants && matched.negotiateVariants.length > 0;
2171
- return {
2172
- routeMiddleware: routeMiddleware.length > 0 ? routeMiddleware : undefined,
2173
- ...(responseType ? {
2174
- responseType,
2175
- handler: manifestEntry.type === "route" ? manifestEntry.handler : undefined,
2176
- params: matched.params,
2177
- } : {}),
2178
- ...(hasVariants ? { negotiated: true } : {}),
2179
- };
2180
653
  }
2181
654
 
2182
- /**
2183
- * Create route builder with accumulated route types
2184
- * The TNewRoutes type parameter captures the new routes being added
2185
- */
2186
- function createRouteBuilder<TNewRoutes extends Record<string, string>>(
2187
- prefix: string,
2188
- routes: TNewRoutes,
2189
- ): RouteBuilder<RouteDefinition, TEnv, any, TNewRoutes> {
2190
- const currentMountIndex = mountIndex++;
2191
-
2192
- // Merge routes into the reverse map
2193
- // Keys stay unchanged for composability - only URL patterns get prefixed
2194
- const routeEntries = routes as Record<string, string>;
2195
- for (const [key, pattern] of Object.entries(routeEntries)) {
2196
- // Build prefixed pattern: "/shop" + "/cart" -> "/shop/cart"
2197
- const prefixedPattern =
2198
- prefix && pattern !== "/"
2199
- ? `${prefix}${pattern}`
2200
- : prefix && pattern === "/"
2201
- ? prefix
2202
- : pattern;
2203
-
2204
- // Runtime validation: warn if key already exists with different pattern
2205
- const existingPattern = mergedRouteMap[key];
2206
- if (
2207
- existingPattern !== undefined &&
2208
- existingPattern !== prefixedPattern
2209
- ) {
2210
- console.warn(
2211
- `[rsc-router] Route key conflict: "${key}" already maps to "${existingPattern}", ` +
2212
- `overwriting with "${prefixedPattern}". Use unique key names to avoid this.`,
2213
- );
2214
- }
2215
-
2216
- // Use original key - enables reusable route modules
2217
- mergedRouteMap[key] = prefixedPattern;
2218
- }
2219
-
2220
- // Auto-register route map for runtime reverse() usage
2221
- registerRouteMap(mergedRouteMap);
2222
-
2223
- // Extract trailing slash config if present (attached by route())
2224
- const trailingSlashConfig = (routes as any).__trailingSlash as
2225
- | Record<string, TrailingSlashMode>
2226
- | undefined;
2227
-
2228
- // Create builder object so .use() can return it
2229
- const builder: RouteBuilder<RouteDefinition, TEnv, any, TNewRoutes> = {
2230
- use(
2231
- patternOrMiddleware: string | MiddlewareFn<TEnv>,
2232
- middleware?: MiddlewareFn<TEnv>,
2233
- ) {
2234
- // Mount-scoped middleware - prefix is the mount prefix
2235
- addMiddleware(patternOrMiddleware, middleware, prefix || null);
2236
- return builder;
2237
- },
2238
-
2239
- map(
2240
- handler:
2241
- | ((
2242
- helpers: InlineRouteHelpers<TNewRoutes, TEnv>,
2243
- ) => Array<AllUseItems>)
2244
- | (() =>
2245
- | Array<AllUseItems>
2246
- | Promise<{ default: () => Array<AllUseItems> }>
2247
- | Promise<() => Array<AllUseItems>>),
2248
- ) {
2249
- // Store handler as-is - detection happens at call time based on return type
2250
- // Both patterns use the same signature:
2251
- // - Inline: ({ route }) => [...] - receives helpers, returns Array
2252
- // - Lazy: () => import(...) - ignores helpers, returns Promise
2253
- routesEntries.push({
2254
- prefix,
2255
- staticPrefix: extractStaticPrefix(prefix),
2256
- routes: routes as ResolvedRouteMap<any>,
2257
- trailingSlash: trailingSlashConfig,
2258
- handler: handler as any,
2259
- mountIndex: currentMountIndex,
2260
- });
2261
- // Return router with accumulated types
2262
- // At runtime this is the same object, but TypeScript tracks the accumulated route types
2263
- return router as any;
2264
- },
2265
-
2266
- // Expose accumulated route map for typeof extraction
2267
- get routeMap() {
2268
- return mergedRouteMap as TNewRoutes;
2269
- },
2270
- };
655
+ // Create match handler functions bound to router state
656
+ const matchHandlers = createMatchHandlers<TEnv>({
657
+ buildRouterContext,
658
+ callOnError,
659
+ matchApiDeps,
660
+ defaultErrorBoundary,
661
+ findMatch,
662
+ findInterceptForRoute,
663
+ telemetry: telemetrySink,
664
+ });
2271
665
 
2272
- return builder;
2273
- }
666
+ const { match, matchPartial, matchError, previewMatch } = matchHandlers;
2274
667
 
2275
668
  /**
2276
669
  * Router instance
2277
670
  * The type system tracks accumulated routes through the builder chain
2278
671
  * Initial TRoutes is {} (empty) to avoid poisoning accumulated types with Record<string, string>
2279
672
  */
2280
- const router: RSCRouter<TEnv, {}> = {
673
+ const router: RangoInternal<TEnv, {}> = {
2281
674
  __brand: RSC_ROUTER_BRAND,
2282
675
  id: routerId,
676
+ basename,
2283
677
 
2284
- routes(
2285
- prefixOrRoutes: string | Record<string, string> | UrlPatterns<TEnv>,
2286
- maybeRoutes?: Record<string, string>,
2287
- ): any {
2288
- // Note: Multiple .routes() calls are allowed for backwards compatibility
2289
- // with the old map() pattern. For new code, prefer urls() with include().
2290
-
2291
- // Check if argument is UrlPatterns (new Django-style API)
2292
- // Detect by checking for handler and definitions properties
2293
- if (
2294
- typeof prefixOrRoutes === "object" &&
2295
- prefixOrRoutes !== null &&
2296
- "handler" in prefixOrRoutes &&
2297
- "definitions" in prefixOrRoutes &&
2298
- typeof (prefixOrRoutes as UrlPatterns<TEnv>).handler === "function"
2299
- ) {
2300
- const urlPatterns = prefixOrRoutes as UrlPatterns<TEnv>;
2301
- // Store reference for runtime manifest generation
2302
- storedUrlPatterns = urlPatterns;
2303
- const currentMountIndex = mountIndex++;
2304
-
2305
- // Create manifest and patterns maps for route registration
2306
- const manifest = new Map<string, EntryData>();
2307
- const patterns = new Map<string, string>();
2308
- const patternsByPrefix = new Map<string, Map<string, string>>();
2309
- const trailingSlashMap = new Map<string, TrailingSlashMode>();
2310
-
2311
- // Run the handler once to extract patterns for route matching.
2312
- // Note: loadManifest will re-run the handler to register entries in its context.
2313
- // Lazy includes are detected in the return value and handled separately.
2314
- //
2315
- // Pattern extraction must use the same mountIndex and MapRootLayout root
2316
- // parent as loadManifest so that shortCodes produced here match those at
2317
- // runtime. include() captures the current parent and counters; if those
2318
- // shortCodes diverge from the runtime tree the segment reconciliation on
2319
- // the client will see a full mismatch and remount the entire page.
2320
- const syntheticMapRoot: EntryData = {
2321
- type: "layout",
2322
- id: `#synthetic-maproot-M${currentMountIndex}`,
2323
- shortCode: `M${currentMountIndex}L0`,
2324
- parent: null,
2325
- handler: MapRootLayout,
2326
- middleware: [],
2327
- revalidate: [],
2328
- errorBoundary: [],
2329
- notFoundBoundary: [],
2330
- layout: [],
2331
- parallel: [],
2332
- intercept: [],
2333
- loader: [],
2334
- };
678
+ routes(patternsOrBuilder: UrlPatterns<TEnv> | UrlBuilder<TEnv>): any {
679
+ // Wrap builder functions in urls() automatically
680
+ const urlPatterns: UrlPatterns<TEnv> =
681
+ typeof patternsOrBuilder === "function"
682
+ ? (urls(patternsOrBuilder) as UrlPatterns<TEnv>)
683
+ : patternsOrBuilder;
2335
684
 
2336
- let handlerResult: AllUseItems[] = [];
2337
- RSCRouterContext.run(
2338
- {
2339
- manifest,
2340
- patterns,
2341
- patternsByPrefix,
2342
- trailingSlash: trailingSlashMap,
2343
- namespace: "root",
2344
- parent: syntheticMapRoot,
2345
- counters: {},
2346
- mountIndex: currentMountIndex,
2347
- },
2348
- () => {
2349
- handlerResult = urlPatterns.handler() as AllUseItems[];
2350
- },
2351
- );
685
+ // Store reference for runtime manifest generation
686
+ storedUrlPatterns = urlPatterns;
687
+ const currentMountIndex = mountIndex++;
2352
688
 
2353
- // Store the ORIGINAL handler - loadManifest will re-run it to register manifest entries
2354
- // Convert trailingSlash map to object for the router
2355
- const trailingSlashConfig =
2356
- trailingSlashMap.size > 0
2357
- ? Object.fromEntries(trailingSlashMap)
2358
- : undefined;
2359
-
2360
- // Collect route keys that have prerender handlers (for non-trie match path)
2361
- let prerenderRouteKeys: Set<string> | undefined;
2362
- for (const [name, entry] of manifest.entries()) {
2363
- if (entry.type === "route" && entry.isPrerender) {
2364
- if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
2365
- prerenderRouteKeys.add(name);
2366
- }
2367
- }
689
+ // Create manifest and patterns maps for route registration
690
+ const manifest = new Map<string, EntryData>();
691
+ const routePatterns = new Map<string, string>();
692
+ const patternsByPrefix = new Map<string, Map<string, string>>();
693
+ const trailingSlashMap = new Map<string, TrailingSlashMode>();
694
+
695
+ // Run the handler once to extract patterns for route matching.
696
+ // Note: loadManifest will re-run the handler to register entries in its context.
697
+ // Lazy includes are detected in the return value and handled separately.
698
+ //
699
+ // Pattern extraction must use the same mountIndex and MapRootLayout root
700
+ // parent as loadManifest so that shortCodes produced here match those at
701
+ // runtime. include() captures the current parent and counters; if those
702
+ // shortCodes diverge from the runtime tree the segment reconciliation on
703
+ // the client will see a full mismatch and remount the entire page.
704
+ const syntheticMapRoot: EntryData = {
705
+ type: "layout",
706
+ id: `#synthetic-maproot-M${currentMountIndex}`,
707
+ shortCode: `M${currentMountIndex}L0`,
708
+ parent: null,
709
+ handler: MapRootLayout,
710
+ middleware: [],
711
+ revalidate: [],
712
+ errorBoundary: [],
713
+ notFoundBoundary: [],
714
+ layout: [],
715
+ parallel: {},
716
+ intercept: [],
717
+ loader: [],
718
+ };
2368
719
 
2369
- // Create separate RouteEntry for each URL prefix group
2370
- // This enables prefix-based short-circuit optimization
2371
- if (patternsByPrefix.size > 0) {
2372
- for (const [prefix, prefixPatterns] of patternsByPrefix.entries()) {
2373
- const routesObject: Record<string, string> = {};
2374
- for (const [name, pattern] of prefixPatterns.entries()) {
2375
- routesObject[name] = pattern;
2376
- }
720
+ let handlerResult: AllUseItems[] = [];
721
+ RangoContext.run(
722
+ {
723
+ manifest,
724
+ patterns: routePatterns,
725
+ patternsByPrefix,
726
+ trailingSlash: trailingSlashMap,
727
+ namespace: "root",
728
+ parent: syntheticMapRoot,
729
+ counters: {},
730
+ mountIndex: currentMountIndex,
731
+ cacheProfiles: resolvedCacheProfiles,
732
+ // basename sets the initial URL prefix so all path() patterns
733
+ // are registered with the prefix (e.g. "/admin" + "/users" = "/admin/users").
734
+ // No namePrefix — route names stay unprefixed.
735
+ ...(basename ? { urlPrefix: basename } : {}),
736
+ },
737
+ () => {
738
+ handlerResult = urlPatterns.handler() as AllUseItems[];
739
+ },
740
+ );
2377
741
 
2378
- routesEntries.push({
2379
- // prefix is "" because patterns already include the URL prefix
2380
- // (e.g., "/site/:locale/user1/:id" not just "/user1/:id")
2381
- prefix: "",
2382
- // staticPrefix is the actual prefix for short-circuit optimization
2383
- staticPrefix: extractStaticPrefix(prefix),
2384
- routes: routesObject as ResolvedRouteMap<any>,
2385
- trailingSlash: trailingSlashConfig,
2386
- handler: urlPatterns.handler,
2387
- mountIndex: currentMountIndex,
2388
- ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
2389
- });
742
+ // Convert trailingSlash map to object for the router
743
+ const trailingSlashConfig =
744
+ trailingSlashMap.size > 0
745
+ ? Object.fromEntries(trailingSlashMap)
746
+ : undefined;
747
+
748
+ // Collect route keys that have prerender handlers (for non-trie match path)
749
+ let prerenderRouteKeys: Set<string> | undefined;
750
+ let passthroughRouteKeys: Set<string> | undefined;
751
+ for (const [name, entry] of manifest.entries()) {
752
+ if (entry.type === "route" && entry.isPrerender) {
753
+ if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
754
+ prerenderRouteKeys.add(name);
755
+ if (entry.isPassthrough === true) {
756
+ if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
757
+ passthroughRouteKeys.add(name);
2390
758
  }
2391
- } else {
2392
- // Fallback: no prefix grouping, use flat patterns map
759
+ }
760
+ }
761
+
762
+ // Create separate RouteEntry for each URL prefix group
763
+ // This enables prefix-based short-circuit optimization
764
+ if (patternsByPrefix.size > 0) {
765
+ for (const [prefix, prefixPatterns] of patternsByPrefix.entries()) {
2393
766
  const routesObject: Record<string, string> = {};
2394
- for (const [name, pattern] of patterns.entries()) {
767
+ for (const [name, pattern] of prefixPatterns.entries()) {
2395
768
  routesObject[name] = pattern;
2396
769
  }
2397
770
 
2398
771
  routesEntries.push({
772
+ // prefix is "" because patterns already include the URL prefix
773
+ // (e.g., "/site/:locale/user1/:id" not just "/user1/:id")
2399
774
  prefix: "",
2400
- staticPrefix: "",
775
+ // staticPrefix is the actual prefix for short-circuit optimization
776
+ staticPrefix: extractStaticPrefix(prefix),
2401
777
  routes: routesObject as ResolvedRouteMap<any>,
2402
778
  trailingSlash: trailingSlashConfig,
2403
779
  handler: urlPatterns.handler,
2404
780
  mountIndex: currentMountIndex,
781
+ routerId,
782
+ cacheProfiles: resolvedCacheProfiles,
2405
783
  ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
784
+ ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
2406
785
  });
2407
786
  }
787
+ } else {
788
+ // Fallback: no prefix grouping, use flat patterns map
789
+ const routesObject: Record<string, string> = {};
790
+ for (const [name, pattern] of routePatterns.entries()) {
791
+ routesObject[name] = pattern;
792
+ }
2408
793
 
2409
- // Build route map from registered patterns
2410
- for (const [name, pattern] of patterns.entries()) {
2411
- // Runtime validation: warn if key already exists with different pattern
2412
- const existingPattern = mergedRouteMap[name];
2413
- if (existingPattern !== undefined && existingPattern !== pattern) {
2414
- console.warn(
2415
- `[@rangojs/router] Route name conflict: "${name}" already maps to "${existingPattern}", ` +
2416
- `overwriting with "${pattern}". Use unique route names to avoid this.`,
2417
- );
2418
- }
2419
- mergedRouteMap[name] = pattern;
794
+ routesEntries.push({
795
+ prefix: "",
796
+ staticPrefix: "",
797
+ routes: routesObject as ResolvedRouteMap<any>,
798
+ trailingSlash: trailingSlashConfig,
799
+ handler: urlPatterns.handler,
800
+ mountIndex: currentMountIndex,
801
+ routerId,
802
+ cacheProfiles: resolvedCacheProfiles,
803
+ ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
804
+ ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
805
+ });
806
+ }
807
+
808
+ // Build route map from registered patterns
809
+ for (const [name, pattern] of routePatterns.entries()) {
810
+ // Runtime validation: warn if key already exists with different pattern.
811
+ // Skip warning for entries that came from the static seed — the gen file
812
+ // can be stale during HMR, so runtime registration is authoritative.
813
+ const existingPattern = mergedRouteMap[name];
814
+ if (
815
+ existingPattern !== undefined &&
816
+ existingPattern !== pattern &&
817
+ !seededNames.has(name)
818
+ ) {
819
+ console.warn(
820
+ `[@rangojs/router] Route name conflict: "${name}" already maps to "${existingPattern}", ` +
821
+ `overwriting with "${pattern}". Use unique route names to avoid this.`,
822
+ );
2420
823
  }
824
+ mergedRouteMap[name] = pattern;
825
+ seededNames.delete(name);
826
+ }
2421
827
 
2422
- // Detect lazy includes in handler result and create placeholder entries
2423
- // Uses findLazyIncludes from outer scope (shared with evaluateLazyEntry)
2424
- const lazyIncludes = findLazyIncludes(handlerResult);
828
+ // Detect lazy includes in handler result and create placeholder entries
829
+ const lazyIncludes = findLazyIncludes(handlerResult);
2425
830
 
2426
- // Create placeholder RouteEntry for each lazy include
2427
- for (const lazyInclude of lazyIncludes) {
2428
- // Compute the full URL prefix (combining parent prefix if any)
2429
- const fullPrefix = lazyInclude.context.urlPrefix
2430
- ? lazyInclude.context.urlPrefix + lazyInclude.prefix
2431
- : lazyInclude.prefix;
831
+ // Create placeholder RouteEntry for each lazy include
832
+ for (const lazyInclude of lazyIncludes) {
833
+ // Compute the full URL prefix (combining parent prefix if any)
834
+ const fullPrefix = lazyInclude.context.urlPrefix
835
+ ? lazyInclude.context.urlPrefix + lazyInclude.prefix
836
+ : lazyInclude.prefix;
2432
837
 
2433
- const lazyEntry: RouteEntry<TEnv> & { _lazyPrefix?: string } = {
2434
- prefix: "",
2435
- staticPrefix: extractStaticPrefix(fullPrefix),
2436
- routes: {} as ResolvedRouteMap<any>, // Empty until first match
2437
- trailingSlash: trailingSlashConfig,
2438
- handler: urlPatterns.handler,
2439
- mountIndex: currentMountIndex,
2440
- // Lazy evaluation fields
2441
- lazy: true,
2442
- lazyPatterns: lazyInclude.patterns,
2443
- lazyContext: lazyInclude.context,
2444
- lazyEvaluated: false,
2445
- // Store the include prefix for evaluation
2446
- _lazyPrefix: lazyInclude.prefix,
2447
- };
2448
- // Insert lazy entry before any entry whose staticPrefix is a
2449
- // prefix of (but shorter than) this lazy entry's staticPrefix.
2450
- // This ensures more specific lazy includes are matched before
2451
- // less specific eager entries (e.g., "/href/nested" before "/href/:id").
2452
- const lazyPrefix = lazyEntry.staticPrefix;
2453
- let insertIndex = routesEntries.length;
2454
- if (lazyPrefix) {
2455
- for (let i = 0; i < routesEntries.length; i++) {
2456
- const existing = routesEntries[i]!;
2457
- if (
2458
- lazyPrefix.startsWith(existing.staticPrefix) &&
2459
- lazyPrefix.length > existing.staticPrefix.length
2460
- ) {
2461
- insertIndex = i;
2462
- break;
2463
- }
838
+ const lazyEntry: RouteEntry<TEnv> & { _lazyPrefix?: string } = {
839
+ prefix: "",
840
+ staticPrefix: extractStaticPrefix(fullPrefix),
841
+ routes: {} as ResolvedRouteMap<any>, // Empty until first match
842
+ trailingSlash: trailingSlashConfig,
843
+ handler: urlPatterns.handler,
844
+ mountIndex: mountIndex++,
845
+ routerId,
846
+ // Lazy evaluation fields
847
+ lazy: true,
848
+ lazyPatterns: lazyInclude.patterns,
849
+ lazyContext: lazyInclude.context,
850
+ lazyEvaluated: false,
851
+ _lazyPrefix: lazyInclude.prefix,
852
+ };
853
+ // Insert lazy entry before any entry whose staticPrefix is a
854
+ // prefix of (but shorter than) this lazy entry's staticPrefix.
855
+ // This ensures more specific lazy includes are matched before
856
+ // less specific eager entries (e.g., "/href/nested" before "/href/:id").
857
+ const lazyPrefix = lazyEntry.staticPrefix;
858
+ let insertIndex = routesEntries.length;
859
+ if (lazyPrefix) {
860
+ for (let i = 0; i < routesEntries.length; i++) {
861
+ const existing = routesEntries[i]!;
862
+ if (
863
+ lazyPrefix.startsWith(existing.staticPrefix) &&
864
+ lazyPrefix.length > existing.staticPrefix.length
865
+ ) {
866
+ insertIndex = i;
867
+ break;
2464
868
  }
2465
869
  }
2466
- routesEntries.splice(insertIndex, 0, lazyEntry);
2467
870
  }
2468
-
2469
- // Auto-register route map for runtime reverse() usage
2470
- registerRouteMap(mergedRouteMap);
2471
-
2472
- // Return the router (no .map() needed for UrlPatterns)
2473
- return router;
871
+ routesEntries.splice(insertIndex, 0, lazyEntry);
2474
872
  }
2475
873
 
2476
- // Legacy API: route() + map() pattern
2477
- // If second argument exists, first is prefix
2478
- if (maybeRoutes !== undefined) {
2479
- return createRouteBuilder(prefixOrRoutes as string, maybeRoutes);
2480
- }
2481
- // Otherwise, first argument is routes with empty prefix
2482
- return createRouteBuilder("", prefixOrRoutes as Record<string, string>);
874
+ // Auto-register route map for runtime reverse() usage
875
+ registerRouteMap(mergedRouteMap);
876
+
877
+ return router;
2483
878
  },
2484
879
 
2485
880
  use(
2486
881
  patternOrMiddleware: string | MiddlewareFn<TEnv>,
2487
882
  middleware?: MiddlewareFn<TEnv>,
2488
883
  ): any {
2489
- // Global middleware - no mount prefix
2490
- addMiddleware(patternOrMiddleware, middleware, null);
884
+ // Auto-prefix pattern with basename so router-level middleware
885
+ // patterns are router-relative (e.g. "/users/*" matches "/app/users/*").
886
+ if (basename && typeof patternOrMiddleware === "string") {
887
+ const pattern = patternOrMiddleware;
888
+ const prefixed =
889
+ pattern === "/*" || pattern === "*"
890
+ ? `${basename}/*`
891
+ : `${basename}${pattern}`;
892
+ addMiddleware(prefixed, middleware, null);
893
+ } else {
894
+ addMiddleware(patternOrMiddleware, middleware, null);
895
+ }
2491
896
  return router;
2492
897
  },
2493
898
 
2494
899
  // Type-safe URL builder using merged route map
2495
900
  // Types are tracked through the builder chain via TRoutes parameter
901
+ // Seeded with static route names from the generated file (injected by Vite)
2496
902
  reverse: createReverse(mergedRouteMap),
2497
903
 
2498
904
  // Expose accumulated route map for typeof extraction
@@ -2516,20 +922,62 @@ export function createRouter<TEnv = any>(
2516
922
  // Expose resolved theme configuration for NavigationProvider and MetaTags
2517
923
  themeConfig: resolvedThemeConfig,
2518
924
 
925
+ // Expose resolved cache profiles for per-request resolution
926
+ cacheProfiles: resolvedCacheProfiles,
927
+
928
+ // Expose prefetch cache settings
929
+ prefetchCacheControl,
930
+ prefetchCacheTTL,
931
+
2519
932
  // Expose warmup enabled flag for handler and client
2520
933
  warmupEnabled,
2521
934
 
935
+ // Expose router-wide performance debugging for request-level metrics setup
936
+ debugPerformance,
937
+
2522
938
  // Expose debug manifest flag for handler
2523
939
  allowDebugManifest: allowDebugManifestOption,
2524
940
 
941
+ // Expose origin check configuration for handler (default: enabled)
942
+ originCheck: originCheckOption ?? true,
943
+
944
+ // Expose SSR configuration for handler
945
+ ssr: ssrOption,
946
+
947
+ // Expose resolved timeouts for RSC handler
948
+ timeouts: resolvedTimeouts,
949
+ onTimeout,
950
+
2525
951
  // Expose global middleware for RSC handler
2526
952
  middleware: globalMiddleware,
2527
953
 
2528
- match,
954
+ match: (request: Request, input: RouterRequestInput<TEnv> = {}) => {
955
+ const env = input.env ?? ({} as TEnv);
956
+ return match(request, env);
957
+ },
2529
958
  matchForPrerender,
2530
- matchPartial,
2531
- matchError,
2532
- previewMatch,
959
+ renderStaticSegment,
960
+ matchPartial: (
961
+ request: Request,
962
+ input: RouterRequestInput<TEnv> = {},
963
+ actionContext?: Parameters<typeof matchPartial>[2],
964
+ ) => {
965
+ const env = input.env ?? ({} as TEnv);
966
+ return matchPartial(request, env, actionContext);
967
+ },
968
+ matchError: (
969
+ request: Request,
970
+ input: RouterRequestInput<TEnv> | undefined,
971
+ error: unknown,
972
+ segmentType?: Parameters<typeof matchError>[3],
973
+ ) => {
974
+ const env = input?.env ?? ({} as TEnv);
975
+ return matchError(request, env, error, segmentType);
976
+ },
977
+ previewMatch: (request: Request, input: RouterRequestInput<TEnv> = {}) => {
978
+ const env = input.env ?? ({} as TEnv);
979
+ return previewMatch(request, env);
980
+ },
2533
981
 
2534
982
  // Expose nonce provider for fetch
2535
983
  nonce,
@@ -2545,90 +993,58 @@ export function createRouter<TEnv = any>(
2545
993
  // Expose source file for per-router type generation
2546
994
  __sourceFile,
2547
995
 
996
+ // Expose basename for runtime manifest generation
997
+ __basename: basename,
998
+
2548
999
  // RSC request handler (lazily created on first call)
2549
1000
  fetch: (() => {
2550
1001
  // Handler is created on first call and reused
2551
1002
  let handler:
2552
1003
  | ((
2553
1004
  request: Request,
2554
- env: TEnv & { ctx?: ExecutionContext },
1005
+ input: RouterRequestInput<TEnv>,
2555
1006
  ) => Promise<Response>)
2556
1007
  | null = null;
2557
1008
 
2558
- return async (
2559
- request: Request,
2560
- env: TEnv & { ctx?: ExecutionContext },
2561
- ) => {
1009
+ return async (request: Request, input: RouterRequestInput<TEnv> = {}) => {
1010
+ // Trigger lazy import of per-router manifest data before route matching.
1011
+ // No-op if data is already loaded or no loader is registered.
1012
+ await ensureRouterManifest(routerId);
2562
1013
  if (!handler) {
2563
1014
  // Lazy import deferred to first request to avoid dev mode issues
2564
1015
  const { createRSCHandler } = await import("./rsc/handler.js");
1016
+ // Cast: handler.ts still accepts (request, env) — will be updated
1017
+ // separately to accept RouterRequestInput.
2565
1018
  handler = createRSCHandler({
2566
1019
  router: router as any,
2567
1020
  cache,
2568
1021
  nonce,
2569
1022
  version,
2570
- });
1023
+ }) as (
1024
+ request: Request,
1025
+ input: RouterRequestInput<TEnv>,
1026
+ ) => Promise<Response>;
2571
1027
  }
2572
- return handler(request, env);
1028
+ return handler!(request, input);
2573
1029
  };
2574
1030
  })(),
2575
1031
 
2576
- // Debug utility for manifest inspection
2577
- async debugManifest(): Promise<SerializedManifest> {
2578
- const manifest = new Map<string, EntryData>();
2579
-
2580
- for (const entry of routesEntries) {
2581
- const Store = {
2582
- manifest,
2583
- namespace: `debug.M${entry.mountIndex}`,
2584
- parent: null as EntryData | null,
2585
- counters: {} as Record<string, number>,
2586
- mountIndex: entry.mountIndex,
2587
- patterns: new Map<string, string>(),
2588
- trailingSlash: new Map<string, TrailingSlashMode>(),
2589
- };
2590
-
2591
- await getContext().runWithStore(
2592
- Store,
2593
- `debug.M${entry.mountIndex}`,
2594
- null,
2595
- async () => {
2596
- const helpers = createRouteHelpers();
2597
-
2598
- // Wrap handler execution in root layout (same as loadManifest)
2599
- let promiseResult: Promise<any> | null = null;
2600
- helpers.layout(MapRootLayout, () => {
2601
- const result = entry.handler();
2602
- if (result instanceof Promise) {
2603
- promiseResult = result;
2604
- return [];
2605
- }
2606
- return result;
2607
- });
2608
-
2609
- if (promiseResult !== null) {
2610
- const load = await (promiseResult as Promise<any>);
2611
- if (load && typeof load === "object" && "default" in load) {
2612
- const useItems = load.default;
2613
- if (typeof useItems === "function") {
2614
- useItems(helpers);
2615
- }
2616
- }
2617
- }
2618
- },
2619
- );
2620
- }
1032
+ // Low-level route matching for request classification
1033
+ findMatch: (pathname: string, metricsStore?: any) =>
1034
+ findMatch(pathname, metricsStore),
2621
1035
 
2622
- return serializeManifest(manifest);
2623
- },
1036
+ // Debug utility for manifest inspection
1037
+ debugManifest: () => buildDebugManifest<TEnv>(routesEntries),
2624
1038
  };
2625
1039
 
2626
1040
  // Register router in the global registry for build-time discovery
2627
1041
  RouterRegistry.set(routerId, router);
2628
1042
 
2629
1043
  // If urls option was provided, auto-register them
2630
- if (urlsOption) {
2631
- return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
1044
+ if (typeof urlsOption === "function") {
1045
+ return router.routes(urlsOption) as Rango<TEnv, {}>;
1046
+ } else if (urlsOption) {
1047
+ return router.routes(urlsOption) as Rango<TEnv, {}>;
2632
1048
  }
2633
1049
 
2634
1050
  return router;