@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.140

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 (460) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +432 -7
  3. package/dist/bin/rango.js +2073 -213
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +7258 -2714
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +140 -67
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +329 -0
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +487 -0
  12. package/skills/caching/SKILL.md +357 -25
  13. package/skills/comparison/SKILL.md +50 -0
  14. package/skills/comparison/agents/openai.yaml +4 -0
  15. package/skills/comparison/references/framework-comparison.md +837 -0
  16. package/skills/composability/SKILL.md +246 -0
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +16 -10
  19. package/skills/document-cache/SKILL.md +87 -62
  20. package/skills/fonts/SKILL.md +6 -4
  21. package/skills/handler-use/SKILL.md +364 -0
  22. package/skills/hooks/SKILL.md +557 -79
  23. package/skills/host-router/SKILL.md +320 -0
  24. package/skills/i18n/SKILL.md +276 -0
  25. package/skills/intercept/SKILL.md +207 -15
  26. package/skills/layout/SKILL.md +146 -6
  27. package/skills/links/SKILL.md +304 -25
  28. package/skills/loader/SKILL.md +616 -54
  29. package/skills/middleware/SKILL.md +217 -37
  30. package/skills/migrate-nextjs/SKILL.md +611 -0
  31. package/skills/migrate-react-router/SKILL.md +927 -0
  32. package/skills/mime-routes/SKILL.md +42 -11
  33. package/skills/observability/SKILL.md +194 -0
  34. package/skills/parallel/SKILL.md +284 -3
  35. package/skills/ppr/SKILL.md +426 -0
  36. package/skills/prerender/SKILL.md +437 -52
  37. package/skills/rango/SKILL.md +369 -22
  38. package/skills/react-compiler/SKILL.md +168 -0
  39. package/skills/response-routes/SKILL.md +263 -121
  40. package/skills/route/SKILL.md +350 -21
  41. package/skills/router-setup/SKILL.md +246 -33
  42. package/skills/scripts/SKILL.md +179 -0
  43. package/skills/server-actions/SKILL.md +775 -0
  44. package/skills/shell-manifest/SKILL.md +185 -0
  45. package/skills/streams-and-websockets/SKILL.md +283 -0
  46. package/skills/tailwind/SKILL.md +27 -3
  47. package/skills/testing/SKILL.md +126 -222
  48. package/skills/testing/bindings.md +103 -0
  49. package/skills/testing/cache-prerender.md +127 -0
  50. package/skills/testing/client-components.md +124 -0
  51. package/skills/testing/e2e-parity.md +125 -0
  52. package/skills/testing/flight.md +91 -0
  53. package/skills/testing/handles.md +131 -0
  54. package/skills/testing/loader.md +128 -0
  55. package/skills/testing/middleware.md +99 -0
  56. package/skills/testing/render-handler.md +122 -0
  57. package/skills/testing/response-routes.md +95 -0
  58. package/skills/testing/reverse-and-types.md +85 -0
  59. package/skills/testing/server-actions.md +107 -0
  60. package/skills/testing/server-tree.md +128 -0
  61. package/skills/testing/setup.md +123 -0
  62. package/skills/theme/SKILL.md +9 -8
  63. package/skills/typesafety/SKILL.md +532 -103
  64. package/skills/use-cache/SKILL.md +367 -0
  65. package/skills/vercel/SKILL.md +128 -0
  66. package/skills/view-transitions/SKILL.md +337 -0
  67. package/src/__augment-tests__/augment.ts +81 -0
  68. package/src/__augment-tests__/augmented.check.ts +116 -0
  69. package/src/__internal.ts +77 -44
  70. package/src/bin/rango.ts +312 -15
  71. package/src/browser/action-coordinator.ts +114 -0
  72. package/src/browser/action-fence.ts +47 -0
  73. package/src/browser/app-shell.ts +39 -0
  74. package/src/browser/app-version.ts +14 -0
  75. package/src/browser/connection-warmup.ts +134 -0
  76. package/src/browser/cookie-name.ts +140 -0
  77. package/src/browser/event-controller.ts +293 -202
  78. package/src/browser/history-state.ts +101 -0
  79. package/src/browser/index.ts +3 -3
  80. package/src/browser/intercept-utils.ts +52 -0
  81. package/src/browser/invalidate-client-cache.ts +52 -0
  82. package/src/browser/link-interceptor.ts +24 -4
  83. package/src/browser/logging.ts +11 -0
  84. package/src/browser/merge-segment-loaders.ts +20 -12
  85. package/src/browser/navigation-bridge.ts +385 -576
  86. package/src/browser/navigation-client.ts +245 -75
  87. package/src/browser/navigation-store-handle.ts +38 -0
  88. package/src/browser/navigation-store.ts +184 -118
  89. package/src/browser/navigation-transaction.ts +247 -0
  90. package/src/browser/network-error-handler.ts +88 -0
  91. package/src/browser/partial-update.ts +412 -364
  92. package/src/browser/prefetch/cache.ts +359 -0
  93. package/src/browser/prefetch/fetch.ts +452 -0
  94. package/src/browser/prefetch/observer.ts +65 -0
  95. package/src/browser/prefetch/policy.ts +48 -0
  96. package/src/browser/prefetch/queue.ts +209 -0
  97. package/src/browser/prefetch/resource-ready.ts +77 -0
  98. package/src/browser/rango-state.ts +194 -0
  99. package/src/browser/react/Link.tsx +275 -68
  100. package/src/browser/react/NavigationProvider.tsx +265 -109
  101. package/src/browser/react/ScrollRestoration.tsx +10 -6
  102. package/src/browser/react/context.ts +11 -0
  103. package/src/browser/react/filter-segment-order.ts +70 -0
  104. package/src/browser/react/index.ts +0 -48
  105. package/src/browser/react/location-state-shared.ts +272 -60
  106. package/src/browser/react/location-state.ts +90 -20
  107. package/src/browser/react/mount-context.ts +6 -1
  108. package/src/browser/react/nonce-context.ts +23 -0
  109. package/src/browser/react/shallow-equal.ts +27 -0
  110. package/src/browser/react/use-action.ts +35 -66
  111. package/src/browser/react/use-handle.ts +39 -126
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +39 -13
  114. package/src/browser/react/use-navigation.ts +53 -69
  115. package/src/browser/react/use-params.ts +75 -0
  116. package/src/browser/react/use-pathname.ts +47 -0
  117. package/src/browser/react/use-reverse.ts +106 -0
  118. package/src/browser/react/use-router.ts +98 -0
  119. package/src/browser/react/use-search-params.ts +51 -0
  120. package/src/browser/react/use-segments.ts +72 -99
  121. package/src/browser/response-adapter.ts +164 -0
  122. package/src/browser/rsc-router.tsx +300 -72
  123. package/src/browser/scroll-restoration.ts +138 -50
  124. package/src/browser/segment-reconciler.ts +243 -0
  125. package/src/browser/segment-structure-assert.ts +17 -1
  126. package/src/browser/server-action-bridge.ts +668 -613
  127. package/src/browser/types.ts +223 -51
  128. package/src/browser/validate-redirect-origin.ts +56 -0
  129. package/src/build/collect-fallback-refs.ts +107 -0
  130. package/src/build/generate-manifest.ts +252 -161
  131. package/src/build/generate-route-types.ts +41 -1038
  132. package/src/build/index.ts +12 -7
  133. package/src/build/prefix-tree-utils.ts +123 -0
  134. package/src/build/route-trie.ts +225 -42
  135. package/src/build/route-types/ast-helpers.ts +25 -0
  136. package/src/build/route-types/ast-route-extraction.ts +105 -0
  137. package/src/build/route-types/codegen.ts +113 -0
  138. package/src/build/route-types/include-resolution.ts +812 -0
  139. package/src/build/route-types/param-extraction.ts +51 -0
  140. package/src/build/route-types/per-module-writer.ts +144 -0
  141. package/src/build/route-types/router-processing.ts +695 -0
  142. package/src/build/route-types/scan-filter.ts +85 -0
  143. package/src/build/route-types/source-scan.ts +216 -0
  144. package/src/build/runtime-discovery.ts +223 -0
  145. package/src/cache/background-task.ts +34 -0
  146. package/src/cache/cache-error.ts +104 -0
  147. package/src/cache/cache-key-utils.ts +60 -0
  148. package/src/cache/cache-policy.ts +199 -0
  149. package/src/cache/cache-runtime.ts +525 -0
  150. package/src/cache/cache-scope.ts +298 -332
  151. package/src/cache/cache-tag.ts +103 -0
  152. package/src/cache/cf/cf-base64.ts +33 -0
  153. package/src/cache/cf/cf-cache-constants.ts +127 -0
  154. package/src/cache/cf/cf-cache-store.ts +2500 -158
  155. package/src/cache/cf/cf-cache-types.ts +349 -0
  156. package/src/cache/cf/cf-kv-utils.ts +46 -0
  157. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  158. package/src/cache/cf/index.ts +17 -17
  159. package/src/cache/document-cache.ts +199 -92
  160. package/src/cache/handle-capture.ts +81 -0
  161. package/src/cache/handle-snapshot.ts +111 -0
  162. package/src/cache/index.ts +29 -35
  163. package/src/cache/memory-segment-store.ts +363 -30
  164. package/src/cache/profile-registry.ts +88 -0
  165. package/src/cache/read-through-swr.ts +178 -0
  166. package/src/cache/segment-codec.ts +248 -0
  167. package/src/cache/shell-cache.ts +386 -0
  168. package/src/cache/tag-invalidation.ts +230 -0
  169. package/src/cache/taint.ts +153 -0
  170. package/src/cache/types.ts +156 -211
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1102 -0
  173. package/src/client.rsc.tsx +43 -21
  174. package/src/client.tsx +131 -347
  175. package/src/cloudflare/index.ts +11 -0
  176. package/src/cloudflare/tracing.ts +109 -0
  177. package/src/component-utils.ts +23 -4
  178. package/src/components/DefaultDocument.tsx +13 -3
  179. package/src/context-var.ts +168 -0
  180. package/src/debug.ts +19 -9
  181. package/src/decode-loader-results.ts +52 -0
  182. package/src/defer.ts +185 -0
  183. package/src/deps/ssr.ts +0 -1
  184. package/src/encode-kv.ts +49 -0
  185. package/src/errors.ts +106 -10
  186. package/src/escape-script.ts +52 -0
  187. package/src/handle.ts +110 -35
  188. package/src/handles/MetaTags.tsx +83 -59
  189. package/src/handles/Scripts.tsx +183 -0
  190. package/src/handles/breadcrumbs.ts +93 -0
  191. package/src/handles/deferred-resolution.ts +127 -0
  192. package/src/handles/is-thenable.ts +18 -0
  193. package/src/handles/meta.ts +44 -53
  194. package/src/handles/script.ts +244 -0
  195. package/src/host/cookie-handler.ts +20 -65
  196. package/src/host/errors.ts +21 -30
  197. package/src/host/index.ts +13 -9
  198. package/src/host/pattern-matcher.ts +50 -79
  199. package/src/host/router.ts +151 -121
  200. package/src/host/testing.ts +45 -32
  201. package/src/host/types.ts +52 -11
  202. package/src/host/utils.ts +2 -2
  203. package/src/href-client.ts +192 -57
  204. package/src/index.rsc.ts +177 -35
  205. package/src/index.ts +255 -71
  206. package/src/internal-debug.ts +9 -2
  207. package/src/loader-store.ts +500 -0
  208. package/src/loader.rsc.ts +31 -99
  209. package/src/loader.ts +30 -12
  210. package/src/missing-id-error.ts +68 -0
  211. package/src/outlet-context.ts +1 -1
  212. package/src/outlet-provider.tsx +41 -0
  213. package/src/prerender/param-hash.ts +16 -14
  214. package/src/prerender/store.ts +121 -21
  215. package/src/prerender.ts +460 -26
  216. package/src/redirect-origin.ts +100 -0
  217. package/src/regex-escape.ts +8 -0
  218. package/src/render-error-thrower.tsx +20 -0
  219. package/src/response-utils.ts +62 -0
  220. package/src/reverse.ts +198 -128
  221. package/src/root-error-boundary.tsx +42 -48
  222. package/src/route-content-wrapper.tsx +22 -77
  223. package/src/route-definition/dsl-helpers.ts +1116 -0
  224. package/src/route-definition/helper-factories.ts +88 -0
  225. package/src/route-definition/helpers-types.ts +505 -0
  226. package/src/route-definition/index.ts +54 -0
  227. package/src/route-definition/redirect.ts +134 -0
  228. package/src/route-definition/resolve-handler-use.ts +160 -0
  229. package/src/route-definition/use-item-types.ts +29 -0
  230. package/src/route-definition.ts +1 -1481
  231. package/src/route-map-builder.ts +82 -144
  232. package/src/route-name.ts +53 -0
  233. package/src/route-types.ts +71 -45
  234. package/src/router/basename.ts +14 -0
  235. package/src/router/content-negotiation.ts +263 -0
  236. package/src/router/debug-manifest.ts +72 -0
  237. package/src/router/error-handling.ts +54 -27
  238. package/src/router/find-match.ts +245 -0
  239. package/src/router/handler-context.ts +377 -125
  240. package/src/router/instrument.ts +350 -0
  241. package/src/router/intercept-resolution.ts +59 -28
  242. package/src/router/lazy-includes.ts +254 -0
  243. package/src/router/loader-resolution.ts +421 -157
  244. package/src/router/logging.ts +106 -6
  245. package/src/router/manifest.ts +131 -57
  246. package/src/router/match-api.ts +167 -246
  247. package/src/router/match-context.ts +4 -24
  248. package/src/router/match-handlers.ts +440 -0
  249. package/src/router/match-middleware/background-revalidation.ts +117 -93
  250. package/src/router/match-middleware/cache-lookup.ts +297 -150
  251. package/src/router/match-middleware/cache-store.ts +123 -51
  252. package/src/router/match-middleware/intercept-resolution.ts +44 -43
  253. package/src/router/match-middleware/segment-resolution.ts +64 -22
  254. package/src/router/match-pipelines.ts +11 -87
  255. package/src/router/match-result.ts +121 -50
  256. package/src/router/metrics.ts +219 -28
  257. package/src/router/middleware-types.ts +93 -0
  258. package/src/router/middleware.ts +505 -441
  259. package/src/router/navigation-snapshot.ts +133 -0
  260. package/src/router/params-util.ts +23 -0
  261. package/src/router/parse-pattern.ts +115 -0
  262. package/src/router/pattern-matching.ts +311 -142
  263. package/src/router/prefetch-cache-ttl.ts +51 -0
  264. package/src/router/prefetch-limits.ts +37 -0
  265. package/src/router/prerender-match.ts +547 -0
  266. package/src/router/preview-match.ts +102 -0
  267. package/src/router/request-classification.ts +278 -0
  268. package/src/router/revalidation.ts +203 -62
  269. package/src/router/route-snapshot.ts +246 -0
  270. package/src/router/router-context.ts +45 -48
  271. package/src/router/router-interfaces.ts +554 -0
  272. package/src/router/router-options.ts +779 -0
  273. package/src/router/router-registry.ts +21 -0
  274. package/src/router/segment-resolution/fresh.ts +772 -0
  275. package/src/router/segment-resolution/helpers.ts +348 -0
  276. package/src/router/segment-resolution/loader-cache.ts +250 -0
  277. package/src/router/segment-resolution/loader-mask.ts +44 -0
  278. package/src/router/segment-resolution/revalidation.ts +1331 -0
  279. package/src/router/segment-resolution/static-store.ts +81 -0
  280. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  281. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  282. package/src/router/segment-resolution.ts +25 -1354
  283. package/src/router/segment-wrappers.ts +292 -0
  284. package/src/router/state-cookie-name.ts +33 -0
  285. package/src/router/substitute-pattern-params.ts +75 -0
  286. package/src/router/telemetry-otel.ts +261 -0
  287. package/src/router/telemetry.ts +377 -0
  288. package/src/router/timeout.ts +128 -0
  289. package/src/router/tracing.ts +206 -0
  290. package/src/router/trie-matching.ts +240 -61
  291. package/src/router/types.ts +23 -70
  292. package/src/router/url-params.ts +57 -0
  293. package/src/router.ts +781 -2378
  294. package/src/rsc/full-payload.ts +70 -0
  295. package/src/rsc/handler-context.ts +46 -0
  296. package/src/rsc/handler.ts +905 -1142
  297. package/src/rsc/helpers.ts +275 -19
  298. package/src/rsc/index.ts +2 -25
  299. package/src/rsc/json-route-result.ts +38 -0
  300. package/src/rsc/loader-fetch.ts +305 -0
  301. package/src/rsc/manifest-init.ts +77 -0
  302. package/src/rsc/nonce.ts +14 -0
  303. package/src/rsc/origin-guard.ts +155 -0
  304. package/src/rsc/progressive-enhancement.ts +502 -0
  305. package/src/rsc/redirect-guard.ts +99 -0
  306. package/src/rsc/response-cache-serve.ts +238 -0
  307. package/src/rsc/response-error.ts +104 -0
  308. package/src/rsc/response-route-handler.ts +257 -0
  309. package/src/rsc/rsc-rendering.ts +337 -0
  310. package/src/rsc/runtime-warnings.ts +55 -0
  311. package/src/rsc/server-action.ts +522 -0
  312. package/src/rsc/shell-capture.ts +439 -0
  313. package/src/rsc/ssr-setup.ts +144 -0
  314. package/src/rsc/transition-gate.ts +89 -0
  315. package/src/rsc/types.ts +95 -12
  316. package/src/runtime-env.ts +18 -0
  317. package/src/search-params.ts +99 -82
  318. package/src/segment-content-promise.ts +67 -0
  319. package/src/segment-loader-promise.ts +149 -0
  320. package/src/segment-system.tsx +349 -134
  321. package/src/serialize.ts +243 -0
  322. package/src/server/context.ts +452 -85
  323. package/src/server/cookie-parse.ts +32 -0
  324. package/src/server/cookie-store.ts +310 -0
  325. package/src/server/fetchable-loader-store.ts +11 -6
  326. package/src/server/handle-store.ts +123 -42
  327. package/src/server/live.ts +130 -0
  328. package/src/server/loader-registry.ts +51 -100
  329. package/src/server/request-context.ts +842 -157
  330. package/src/server.ts +15 -8
  331. package/src/ssr/index.tsx +412 -136
  332. package/src/ssr/ssr-root.tsx +228 -0
  333. package/src/static-handler.ts +45 -18
  334. package/src/testing/cache-status.ts +162 -0
  335. package/src/testing/collect-handle.ts +46 -0
  336. package/src/testing/dispatch.ts +701 -0
  337. package/src/testing/dom.entry.ts +22 -0
  338. package/src/testing/e2e/fixture.ts +188 -0
  339. package/src/testing/e2e/index.ts +128 -0
  340. package/src/testing/e2e/matchers.ts +35 -0
  341. package/src/testing/e2e/page-helpers.ts +272 -0
  342. package/src/testing/e2e/parity.ts +387 -0
  343. package/src/testing/e2e/server.ts +195 -0
  344. package/src/testing/flight-matchers.ts +97 -0
  345. package/src/testing/flight-normalize.ts +11 -0
  346. package/src/testing/flight-runtime.d.ts +57 -0
  347. package/src/testing/flight-tree.ts +682 -0
  348. package/src/testing/flight.entry.ts +52 -0
  349. package/src/testing/flight.ts +257 -0
  350. package/src/testing/generated-routes.ts +199 -0
  351. package/src/testing/index.ts +105 -0
  352. package/src/testing/internal/context.ts +371 -0
  353. package/src/testing/internal/flight-client-globals.ts +30 -0
  354. package/src/testing/internal/seed-vars.ts +54 -0
  355. package/src/testing/render-handler.ts +357 -0
  356. package/src/testing/render-route.tsx +584 -0
  357. package/src/testing/run-loader.ts +385 -0
  358. package/src/testing/run-middleware.ts +205 -0
  359. package/src/testing/run-transition-when.ts +164 -0
  360. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  361. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  362. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  363. package/src/testing/vitest-stubs/version.ts +5 -0
  364. package/src/testing/vitest.ts +305 -0
  365. package/src/theme/ThemeProvider.tsx +40 -72
  366. package/src/theme/ThemeScript.tsx +12 -14
  367. package/src/theme/constants.ts +57 -15
  368. package/src/theme/index.ts +3 -20
  369. package/src/theme/theme-context.ts +5 -35
  370. package/src/theme/theme-script.ts +43 -39
  371. package/src/theme/use-theme.ts +0 -3
  372. package/src/types/boundaries.ts +123 -0
  373. package/src/types/cache-types.ts +207 -0
  374. package/src/types/error-types.ts +132 -0
  375. package/src/types/global-namespace.ts +113 -0
  376. package/src/types/handler-context.ts +839 -0
  377. package/src/types/index.ts +81 -0
  378. package/src/types/loader-types.ts +212 -0
  379. package/src/types/request-scope.ts +112 -0
  380. package/src/types/route-config.ts +138 -0
  381. package/src/types/route-entry.ts +114 -0
  382. package/src/types/segments.ts +271 -0
  383. package/src/types.ts +1 -1795
  384. package/src/urls/include-helper.ts +162 -0
  385. package/src/urls/include-provider.ts +71 -0
  386. package/src/urls/index.ts +43 -0
  387. package/src/urls/path-helper-types.ts +413 -0
  388. package/src/urls/path-helper.ts +275 -0
  389. package/src/urls/pattern-types.ts +124 -0
  390. package/src/urls/response-types.ts +109 -0
  391. package/src/urls/type-extraction.ts +316 -0
  392. package/src/urls/urls-function.ts +80 -0
  393. package/src/urls.ts +1 -1341
  394. package/src/use-loader.tsx +406 -141
  395. package/src/vercel/index.ts +11 -0
  396. package/src/vercel/tracing.ts +88 -0
  397. package/src/vite/debug.ts +185 -0
  398. package/src/vite/discovery/bundle-postprocess.ts +182 -0
  399. package/src/vite/discovery/discover-routers.ts +389 -0
  400. package/src/vite/discovery/discovery-errors.ts +255 -0
  401. package/src/vite/discovery/gate-state.ts +171 -0
  402. package/src/vite/discovery/prerender-collection.ts +467 -0
  403. package/src/vite/discovery/route-types-writer.ts +214 -0
  404. package/src/vite/discovery/self-gen-tracking.ts +73 -0
  405. package/src/vite/discovery/state.ts +161 -0
  406. package/src/vite/discovery/virtual-module-codegen.ts +183 -0
  407. package/src/vite/index.ts +23 -2255
  408. package/src/vite/inject-client-debug.ts +36 -0
  409. package/src/vite/plugin-types.ts +303 -0
  410. package/src/vite/plugins/cjs-to-esm.ts +90 -0
  411. package/src/vite/plugins/client-ref-dedup.ts +120 -0
  412. package/src/vite/plugins/client-ref-hashing.ts +118 -0
  413. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  414. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  415. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  416. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
  417. package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
  418. package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
  419. package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
  420. package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
  421. package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
  422. package/src/vite/plugins/expose-ids/types.ts +45 -0
  423. package/src/vite/plugins/expose-internal-ids.ts +805 -0
  424. package/src/vite/plugins/performance-tracks.ts +89 -0
  425. package/src/vite/plugins/refresh-cmd.ts +127 -0
  426. package/src/vite/plugins/use-cache-transform.ts +313 -0
  427. package/src/vite/plugins/vercel-output.ts +384 -0
  428. package/src/vite/plugins/version-injector.ts +94 -0
  429. package/src/vite/plugins/version-plugin.ts +263 -0
  430. package/src/vite/plugins/virtual-entries.ts +234 -0
  431. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  432. package/src/vite/rango.ts +560 -0
  433. package/src/vite/router-discovery.ts +1638 -0
  434. package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
  435. package/src/vite/utils/banner.ts +36 -0
  436. package/src/vite/utils/bundle-analysis.ts +132 -0
  437. package/src/vite/utils/client-chunks.ts +184 -0
  438. package/src/vite/utils/directive-prologue.ts +40 -0
  439. package/src/vite/utils/forward-user-plugins.ts +171 -0
  440. package/src/vite/utils/manifest-utils.ts +15 -0
  441. package/src/vite/utils/package-resolution.ts +89 -0
  442. package/src/vite/utils/prerender-utils.ts +249 -0
  443. package/src/vite/utils/shared-utils.ts +269 -0
  444. package/CLAUDE.md +0 -43
  445. package/dist/vite/index.named-routes.gen.ts +0 -103
  446. package/src/browser/lru-cache.ts +0 -69
  447. package/src/browser/react/use-client-cache.ts +0 -56
  448. package/src/browser/request-controller.ts +0 -164
  449. package/src/browser/shallow.ts +0 -35
  450. package/src/cache/memory-store.ts +0 -253
  451. package/src/handles/index.ts +0 -6
  452. package/src/href-context.ts +0 -33
  453. package/src/network-error-thrower.tsx +0 -21
  454. package/src/router.gen.ts +0 -6
  455. package/src/static-handler.gen.ts +0 -5
  456. package/src/urls.gen.ts +0 -8
  457. package/src/vite/expose-internal-ids.ts +0 -1167
  458. package/src/vite/package-resolution.ts +0 -125
  459. package/src/vite/virtual-entries.ts +0 -114
  460. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -1,10 +1,44 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { INTERNAL_RANGO_DEBUG } from "../internal-debug.js";
3
3
 
4
+ export interface RevalidationTraceEntry {
5
+ segmentId: string;
6
+ segmentType: string;
7
+ belongsToRoute: boolean;
8
+ source:
9
+ | "segment-resolution"
10
+ | "cache-hit"
11
+ | "loader"
12
+ | "parallel"
13
+ | "orphan-layout"
14
+ | "route-handler"
15
+ | "layout-handler"
16
+ | "intercept-loader";
17
+ defaultShouldRevalidate: boolean;
18
+ finalShouldRevalidate: boolean;
19
+ reason: string;
20
+ customRevalidators?: number;
21
+ }
22
+
23
+ export interface RevalidationTraceMeta {
24
+ method: string;
25
+ prevUrl: string;
26
+ nextUrl: string;
27
+ routeKey: string;
28
+ isAction: boolean;
29
+ stale?: boolean;
30
+ }
31
+
32
+ export interface RevalidationTrace {
33
+ meta: RevalidationTraceMeta;
34
+ entries: RevalidationTraceEntry[];
35
+ }
36
+
4
37
  interface RouterLogContext {
5
38
  requestId: string;
6
39
  transactionId: string;
7
40
  depth: number;
41
+ revalidationTrace?: RevalidationTrace;
8
42
  }
9
43
 
10
44
  interface RouterLogOptions {
@@ -36,7 +70,7 @@ function getHeaderRequestId(request: Request): string | null {
36
70
  return trimmed.length > 0 ? trimmed : null;
37
71
  }
38
72
 
39
- function getOrCreateRequestId(request: Request): string {
73
+ export function getOrCreateRequestId(request: Request): string {
40
74
  const existing = requestIds.get(request);
41
75
  if (existing) return existing;
42
76
 
@@ -74,9 +108,15 @@ export function runWithRouterLogContext<T>(
74
108
  );
75
109
  }
76
110
 
77
- export function withRouterLogScope<T>(label: string, fn: () => Promise<T>): Promise<T>;
111
+ export function withRouterLogScope<T>(
112
+ label: string,
113
+ fn: () => Promise<T>,
114
+ ): Promise<T>;
78
115
  export function withRouterLogScope<T>(label: string, fn: () => T): T;
79
- export function withRouterLogScope<T>(label: string, fn: () => Promise<T> | T): Promise<T> | T {
116
+ export function withRouterLogScope<T>(
117
+ label: string,
118
+ fn: () => Promise<T> | T,
119
+ ): Promise<T> | T {
80
120
  const ctx = routerLogContext.getStore();
81
121
  if (!INTERNAL_RANGO_DEBUG || !ctx) {
82
122
  return fn();
@@ -88,9 +128,16 @@ export function withRouterLogScope<T>(label: string, fn: () => Promise<T> | T):
88
128
  try {
89
129
  const result = fn();
90
130
  if (result && typeof (result as Promise<T>).then === "function") {
91
- return (result as Promise<T>).finally(() => {
92
- debugLog(label, "end");
93
- });
131
+ return (result as Promise<T>).then(
132
+ (value) => {
133
+ debugLog(label, "end");
134
+ return value;
135
+ },
136
+ (error) => {
137
+ debugLog(label, "error", { error: String(error) });
138
+ throw error;
139
+ },
140
+ );
94
141
  }
95
142
  debugLog(label, "end");
96
143
  return result;
@@ -143,3 +190,56 @@ export function debugWarn(
143
190
 
144
191
  console.warn(`${prefix} ${message}`);
145
192
  }
193
+
194
+ export function isTraceActive(): boolean {
195
+ if (!INTERNAL_RANGO_DEBUG) return false;
196
+ const ctx = routerLogContext.getStore();
197
+ return !!ctx?.revalidationTrace;
198
+ }
199
+
200
+ export function startRevalidationTrace(meta: RevalidationTraceMeta): void {
201
+ const ctx = routerLogContext.getStore();
202
+ if (!ctx || !INTERNAL_RANGO_DEBUG) return;
203
+ ctx.revalidationTrace = { meta, entries: [] };
204
+ }
205
+
206
+ export function pushRevalidationTraceEntry(
207
+ entry: RevalidationTraceEntry,
208
+ ): void {
209
+ const ctx = routerLogContext.getStore();
210
+ if (!ctx?.revalidationTrace) return;
211
+ ctx.revalidationTrace.entries.push(entry);
212
+ }
213
+
214
+ export function flushRevalidationTrace(): RevalidationTrace | null {
215
+ const ctx = routerLogContext.getStore();
216
+ if (!ctx?.revalidationTrace) return null;
217
+ const trace = ctx.revalidationTrace;
218
+ ctx.revalidationTrace = undefined;
219
+
220
+ if (trace.entries.length === 0) return trace;
221
+
222
+ const revalidated = trace.entries.filter((e) => e.finalShouldRevalidate);
223
+ const skipped = trace.entries.filter((e) => !e.finalShouldRevalidate);
224
+
225
+ debugLog("revalidation-trace", "flush", {
226
+ method: trace.meta.method,
227
+ routeKey: trace.meta.routeKey,
228
+ isAction: trace.meta.isAction,
229
+ stale: trace.meta.stale,
230
+ prevUrl: trace.meta.prevUrl,
231
+ nextUrl: trace.meta.nextUrl,
232
+ total: trace.entries.length,
233
+ revalidated: revalidated.length,
234
+ skipped: skipped.length,
235
+ entries: trace.entries.map((e) => ({
236
+ segmentId: e.segmentId,
237
+ type: e.segmentType,
238
+ source: e.source,
239
+ revalidate: e.finalShouldRevalidate,
240
+ reason: e.reason,
241
+ })),
242
+ });
243
+
244
+ return trace;
245
+ }
@@ -1,36 +1,45 @@
1
- /**
2
- * Router Manifest Loading
3
- *
4
- * Handles lazy loading and validation of route manifests.
5
- */
6
-
7
1
  import { invariant, RouteNotFoundError } from "../errors";
8
2
  import { createRouteHelpers } from "../route-definition";
9
- import { getContext, runWithPrefixes, type EntryData, type MetricsStore } from "../server/context";
3
+ import {
4
+ getContext,
5
+ runWithPrefixes,
6
+ getIsolatedLazyParent,
7
+ type EntryData,
8
+ type MetricsStore,
9
+ } from "../server/context";
10
10
  import MapRootLayout from "../server/root-layout";
11
+ import { joinPrefix } from "./pattern-matching.js";
11
12
  import type { RouteEntry } from "../types";
12
13
  import type { UrlPatterns } from "../urls";
14
+ import {
15
+ isIncludeProvider,
16
+ resolveIncludeModule,
17
+ } from "../urls/include-provider.js";
13
18
  import { VERSION } from "@rangojs/router:version";
14
19
 
20
+ // Tags an error thrown while dynamically importing an async include's module
21
+ // (`() => import("./routes")`) so loadManifest's outer catch re-raises it as a
22
+ // server error rather than masking it as a RouteNotFoundError (404).
23
+ const MODULE_LOAD_FAILURE = Symbol.for("rango.moduleLoadFailure");
24
+
15
25
  // Module-level manifest cache: avoids re-executing DSL handler on every request.
16
26
  // Handler execution is deterministic (components, loaders, middleware are module-level
17
27
  // stable references), so the resulting EntryData tree can be safely cached and reused
18
28
  // across requests within the same isolate.
19
29
  //
20
- // Cache is keyed by (VERSION, mountIndex, routeKey, isSSR). VERSION comes from the
30
+ // Cache is keyed by (VERSION, routerId, mountIndex, routeKey, isSSR). routeKey is
31
+ // REQUIRED in the key: loadManifest() runs the handler with forRoute=routeKey, and
32
+ // path-helper.ts prunes (skips registering) every route except forRoute, so the
33
+ // resulting Store.manifest is pruned to the requested route — NOT the full include.
34
+ // Dropping routeKey would make a sibling route miss and overwrite this entry with its
35
+ // own pruned manifest, so alternating sibling requests would thrash (re-run the
36
+ // handler every time). Running the include handler once per isolate instead of once
37
+ // per route is possible but needs an unpruned manifest cache with prune-on-read — see
38
+ // LP1 in docs/internal/matching-and-lazy-discovery.md. VERSION comes from the
21
39
  // @rangojs/router:version virtual module which Vite invalidates on RSC module HMR.
22
40
  // When VERSION changes, this module re-evaluates and the cache is recreated empty.
23
- // Including VERSION in the key is additional defense against stale entries.
24
41
  const manifestModuleCache = new Map<string, Map<string, EntryData>>();
25
42
 
26
- /**
27
- * Load manifest from route entry with AsyncLocalStorage context
28
- * Handles lazy imports, unwrapping, and validation
29
- *
30
- * Results are cached at module level after first execution. Subsequent calls
31
- * for the same (routeKey, isSSR) within the same isolate return cached data
32
- * without re-executing the DSL handler.
33
- */
34
43
  /**
35
44
  * Clear the module-level manifest cache.
36
45
  * Called on HMR to ensure stale handler references are discarded.
@@ -59,8 +68,12 @@ export async function loadManifest(
59
68
 
60
69
  const mountIndex = entry.mountIndex;
61
70
 
62
- // Check module-level cache (persists across requests within same isolate)
63
- const cacheKey = `${VERSION}:${mountIndex ?? ''}:${routeKey}:${isSSR ? 1 : 0}`;
71
+ // Check module-level cache (persists across requests within same isolate).
72
+ // Include routerId so multi-router setups (host routing) don't share cached
73
+ // EntryData across routers with overlapping mountIndex + routeKey combinations.
74
+ // routeKey is in the key because loadManifest() builds a manifest pruned to
75
+ // forRoute=routeKey (see path-helper.ts) — see the cache comment above.
76
+ const cacheKey = `${VERSION}:${entry.routerId ?? ""}:${mountIndex ?? ""}:${routeKey}:${isSSR ? 1 : 0}`;
64
77
  const cached = manifestModuleCache.get(cacheKey);
65
78
  if (cached) {
66
79
  const cacheStart = performance.now();
@@ -80,47 +93,71 @@ export async function loadManifest(
80
93
  const storeSetupStart = performance.now();
81
94
  const Store = getContext().getOrCreateStore(routeKey);
82
95
 
83
- // Set mount index in store for unique shortCode prefixes
84
96
  Store.mountIndex = mountIndex;
85
-
86
- // Set isSSR flag so loading() can check if we're in SSR
87
97
  Store.isSSR = isSSR;
88
98
 
89
- // Attach metrics store to context if provided
90
99
  if (metricsStore) {
91
100
  Store.metrics = metricsStore;
92
101
  }
93
102
 
94
103
  pushMetric?.("manifest:store-setup", storeSetupStart);
95
104
 
96
- // Clear manifest before rebuilding to prevent stale entry mutations
97
105
  const clearStart = performance.now();
98
106
  Store.manifest.clear();
99
107
  pushMetric?.("manifest:clear", clearStart);
100
108
 
101
109
  try {
102
110
  // Include mountIndex in namespace to ensure unique cache keys per mount
103
- const namespaceWithMount = mountIndex !== undefined
104
- ? `#router.M${mountIndex}`
105
- : "#router";
111
+ const namespaceWithMount =
112
+ mountIndex !== undefined ? `#router.M${mountIndex}` : "#router";
106
113
 
107
114
  // For lazy entries, use the captured parent from include() context
108
115
  // This ensures routes are registered under the correct layout hierarchy
109
- const lazyContext = entry.lazy && entry.lazyPatterns ? entry.lazyContext : null;
110
- const parentForContext = lazyContext?.parent as EntryData | null ?? Store.parent;
116
+ const lazyContext =
117
+ entry.lazy && entry.lazyPatterns ? entry.lazyContext : null;
118
+ const parentForContext = lazyContext
119
+ ? getIsolatedLazyParent(
120
+ (lazyContext.parent as EntryData | null) ?? Store.parent,
121
+ )
122
+ : Store.parent;
111
123
 
112
124
  // For lazy entries, merge captured counters from include() so the
113
125
  // handler's entries get shortCode indices after sibling entries that
114
126
  // were created during pattern extraction. This prevents shortCode
115
127
  // collisions between lazy and non-lazy entries under the same parent
116
128
  // (e.g., ArticlesLayout and BlogLayout both under NavLayout).
117
- if (lazyContext && (lazyContext as any).counters) {
118
- const captured = (lazyContext as any).counters as Record<string, number>;
119
- for (const [key, value] of Object.entries(captured)) {
129
+ if (lazyContext?.counters) {
130
+ for (const [key, value] of Object.entries(lazyContext.counters)) {
120
131
  Store.counters[key] = Math.max(Store.counters[key] ?? 0, value);
121
132
  }
122
133
  }
123
134
 
135
+ // Propagate cache profiles for DSL-time cache("profileName") resolution.
136
+ // Non-lazy entries carry profiles directly; lazy entries carry them
137
+ // in the captured lazyContext from include() time. Always write
138
+ // (including clearing to undefined) so a prior lazy build's profile
139
+ // map cannot leak into a later non-lazy build on the same ALS-backed
140
+ // Store — which would otherwise let cache("name") resolve a profile
141
+ // from an unrelated entry.
142
+ Store.cacheProfiles = entry.cacheProfiles ?? lazyContext?.cacheProfiles;
143
+
144
+ // Propagate rootScoped from lazyContext so that routes inside
145
+ // nested { name: "sub" } under { name: "" } keep inherited root scope
146
+ // when the manifest is rebuilt on each request. Always write
147
+ // (including clearing to undefined, which makes getRootScoped()
148
+ // return its true default) so a prior lazy build's scope cannot leak
149
+ // into a later non-lazy build on the same ALS-backed Store — which
150
+ // would otherwise mis-register plain routes as non-root-scoped and
151
+ // break dot-local reverse resolution.
152
+ Store.rootScoped = lazyContext?.rootScoped;
153
+
154
+ // Propagate includeScope from lazyContext so that direct-descendant
155
+ // shortCodes of this include use the correct scoped counter namespace
156
+ // on every manifest rebuild. Always write (including clearing to
157
+ // undefined) so a prior lazy build's scope cannot leak into a later
158
+ // non-lazy build on the same ALS-backed Store.
159
+ Store.includeScope = lazyContext?.includeScope;
160
+
124
161
  const handlerExecStart = performance.now();
125
162
  const useItems = await getContext().runWithStore(
126
163
  Store,
@@ -137,64 +174,91 @@ export async function loadManifest(
137
174
  // not exist in the non-lazy (root handler) path and would produce
138
175
  // mismatched shortCodes.
139
176
  if (entry.lazy && entry.lazyPatterns) {
177
+ // Resolve an async include provider (`() => import("./routes")`) before
178
+ // running its handler. The match-time precomputed shortcut can skip
179
+ // evaluateLazyEntry's resolution, so render-time must resolve it here;
180
+ // cache the resolved patterns on the entry so later renders reuse them.
181
+ if (isIncludeProvider(entry.lazyPatterns)) {
182
+ try {
183
+ entry.lazyPatterns = resolveIncludeModule(
184
+ await entry.lazyPatterns(),
185
+ entry.staticPrefix,
186
+ ) as unknown as UrlPatterns<any>;
187
+ } catch (err) {
188
+ // A failed dynamic import of a REAL, matched route's module is a
189
+ // server error, not a missing route. Tag it so the outer catch
190
+ // surfaces it as a 5xx instead of masking it as a
191
+ // RouteNotFoundError — which renders the 404 page (monitoring
192
+ // misses the failure and a CDN could cache the 404).
193
+ if (err && typeof err === "object") {
194
+ (err as Record<PropertyKey, unknown>)[MODULE_LOAD_FAILURE] =
195
+ true;
196
+ }
197
+ throw err;
198
+ }
199
+ }
140
200
  const lazyPatterns = entry.lazyPatterns as UrlPatterns<any>;
141
201
  const includePrefix = (entry as any)._lazyPrefix || "";
142
- const fullPrefix = (lazyContext?.urlPrefix || "") + includePrefix;
202
+ // Slash-collapsing join so a trailing-slash parent prefix does not
203
+ // bake a double slash into the registered route patterns (must match
204
+ // the same join in evaluateLazyEntry / the build-time runWithPrefixes).
205
+ const fullPrefix = joinPrefix(lazyContext?.urlPrefix, includePrefix);
143
206
 
144
207
  if (fullPrefix || lazyContext?.namePrefix) {
145
- return runWithPrefixes(
146
- fullPrefix,
147
- lazyContext?.namePrefix,
148
- () => lazyPatterns.handler()
208
+ return runWithPrefixes(fullPrefix, lazyContext?.namePrefix, () =>
209
+ lazyPatterns.handler(),
149
210
  );
150
211
  }
151
212
  return lazyPatterns.handler();
152
213
  }
153
214
 
154
- // Wrap handler execution in root layout so routes get correct parent
155
- // This ensures all routes are registered with the layout as their parent
156
215
  let promiseResult: Promise<any> | null = null;
157
216
  const wrappedItems = helpers.layout(MapRootLayout, () => {
158
217
  const result = entry.handler();
159
218
  if (result instanceof Promise) {
160
- // Lazy handler detected - capture promise for async handling
161
219
  promiseResult = result;
162
- return []; // Return empty, we'll discard this wrapped result
220
+ return [];
163
221
  }
164
222
  return result;
165
223
  });
166
224
 
167
- // Handle lazy (Promise-based) handlers
168
225
  if (promiseResult !== null) {
169
226
  const load = await (promiseResult as Promise<any>);
170
- if (
171
- load &&
172
- load !== null &&
173
- typeof load === "object" &&
174
- "default" in load
175
- ) {
227
+ if (load && typeof load === "object" && "default" in load) {
176
228
  // Promise<{ default: () => Array }> - e.g., dynamic import
177
- // Lazy-loaded handlers may need helpers (passed as optional arg)
229
+ if (typeof load.default !== "function") {
230
+ throw new Error(
231
+ `[@rangojs/router] Unsupported async handler: { default } must be a function, ` +
232
+ `got ${typeof load.default}. Use () => import('./urls') for lazy loading.`,
233
+ );
234
+ }
178
235
  return (load.default as (h?: any) => any)(helpers);
179
236
  }
180
237
  if (typeof load === "function") {
181
238
  // Promise<() => Array>
182
239
  return (load as (h?: any) => any)(helpers);
183
240
  }
184
- // Promise<Array> - direct array from async handler
185
- return load;
241
+ // Reject unsupported async handler results. Supported shapes are:
242
+ // Promise<{ default: fn }> — dynamic import
243
+ // Promise<fn> — lazy function
244
+ // Direct Promise<Array> is not supported; use a function wrapper.
245
+ throw new Error(
246
+ `[@rangojs/router] Unsupported async handler result (${typeof load}). ` +
247
+ `Lazy route handlers must resolve to a function or { default: fn }, ` +
248
+ `not a direct array. Wrap your handler: () => import('./urls') or ` +
249
+ `() => Promise.resolve((h) => [...])`,
250
+ );
186
251
  }
187
252
 
188
- // Inline handler - routes were registered with correct parent inside layout
189
253
  return [wrappedItems].flat(3);
190
- }
254
+ },
191
255
  );
192
256
  pushMetric?.("manifest:handler-exec", handlerExecStart);
193
257
 
194
258
  const validationStart = performance.now();
195
259
  invariant(
196
260
  useItems && useItems.length > 0,
197
- "Did not receive any handler from router.map()"
261
+ "Did not receive any handler from router.map()",
198
262
  );
199
263
  // For non-lazy entries the root handler is wrapped in MapRootLayout,
200
264
  // so the result always contains a layout item. Lazy entries run the
@@ -203,13 +267,13 @@ export async function loadManifest(
203
267
  if (!lazyContext) {
204
268
  invariant(
205
269
  useItems.some((item: { type: string }) => item.type === "layout"),
206
- "Top-level handler must be a layout"
270
+ "Top-level handler must be a layout",
207
271
  );
208
272
  }
209
273
 
210
274
  invariant(
211
275
  Store.manifest.has(routeKey),
212
- `Route must be registered for ${routeKey}`
276
+ `Route must be registered for ${routeKey}`,
213
277
  );
214
278
  pushMetric?.("manifest:validation", validationStart);
215
279
 
@@ -218,6 +282,16 @@ export async function loadManifest(
218
282
 
219
283
  return Store.manifest.get(routeKey)!;
220
284
  } catch (e) {
285
+ // A tagged async-include module-load failure is a server error for a REAL
286
+ // matched route — re-raise it unchanged (becomes a 5xx) instead of masking
287
+ // it as a RouteNotFoundError (which renders/caches a 404).
288
+ if (
289
+ e &&
290
+ typeof e === "object" &&
291
+ (e as Record<PropertyKey, unknown>)[MODULE_LOAD_FAILURE]
292
+ ) {
293
+ throw e;
294
+ }
221
295
  throw new RouteNotFoundError(
222
296
  `Failed to load route handlers for ${path}: ${(e as Error).message}`,
223
297
  {
@@ -228,7 +302,7 @@ export async function loadManifest(
228
302
  routeKey,
229
303
  },
230
304
  },
231
- }
305
+ },
232
306
  );
233
307
  }
234
308
  }