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

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 +293 -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 +2508 -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 +24 -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-snapshot.ts +368 -0
  168. package/src/cache/tag-invalidation.ts +230 -0
  169. package/src/cache/taint.ts +153 -0
  170. package/src/cache/types.ts +222 -211
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1113 -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 +173 -35
  205. package/src/index.ts +241 -73
  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 +527 -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 +897 -0
  313. package/src/rsc/shell-serve.ts +124 -0
  314. package/src/rsc/ssr-setup.ts +144 -0
  315. package/src/rsc/transition-gate.ts +89 -0
  316. package/src/rsc/types.ts +95 -12
  317. package/src/runtime-env.ts +18 -0
  318. package/src/search-params.ts +99 -82
  319. package/src/segment-content-promise.ts +67 -0
  320. package/src/segment-loader-promise.ts +149 -0
  321. package/src/segment-system.tsx +349 -134
  322. package/src/serialize.ts +243 -0
  323. package/src/server/context.ts +459 -85
  324. package/src/server/cookie-parse.ts +32 -0
  325. package/src/server/cookie-store.ts +310 -0
  326. package/src/server/fetchable-loader-store.ts +11 -6
  327. package/src/server/handle-store.ts +123 -42
  328. package/src/server/loader-registry.ts +51 -100
  329. package/src/server/request-context.ts +848 -157
  330. package/src/server.ts +15 -8
  331. package/src/ssr/index.tsx +443 -135
  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 +76 -98
  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 +44 -0
  387. package/src/urls/path-helper-types.ts +413 -0
  388. package/src/urls/path-helper.ts +280 -0
  389. package/src/urls/pattern-types.ts +160 -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
@@ -33,6 +33,69 @@ urls(({ path }) => [
33
33
  ]);
34
34
  ```
35
35
 
36
+ ### Optional URL params at runtime
37
+
38
+ Absent optional params are **omitted from `ctx.params`** — `ctx.params.<name>`
39
+ reads as `undefined`, matching the `RouteParams<"name">` type
40
+ (`{ query?: string }`). Use `??` to default and `=== undefined` to check
41
+ absence:
42
+
43
+ ```typescript
44
+ path("/search/:query?", (ctx) => {
45
+ const query = ctx.params.query ?? ""; // works — undefined coalesces
46
+ if (ctx.params.query === undefined) return <EmptySearch />;
47
+ return <Results query={ctx.params.query} />;
48
+ }, { name: "search" });
49
+ ```
50
+
51
+ For the common pattern of an optional locale prefix
52
+ (`include("/:locale?", routes)`) and the wider react-intl integration —
53
+ locale detection, fallback chains, URL generation with absent locale —
54
+ see `/i18n`.
55
+
56
+ ### Named catch-all params (`:name+` / `:name*`)
57
+
58
+ A catch-all consumes the **rest of the path** and exposes it as a single
59
+ decoded string at `ctx.params.<name>`, with the internal `/` separators kept.
60
+ It must be the **last** segment of the pattern.
61
+
62
+ - `:name+` — **one-or-more** segments (Next `[...name]`, React-Router splat).
63
+ `/docs/:slug+` matches `/docs/a` and `/docs/a/b/c`, but **not** the bare
64
+ `/docs`.
65
+ - `:name*` — **zero-or-more** segments (Next `[[...name]]`). `/docs/:slug*`
66
+ additionally matches the bare `/docs`, binding `ctx.params.slug` to `""`.
67
+
68
+ ```typescript
69
+ urls(({ path }) => [
70
+ // /shop/electronics/phones -> ctx.params.path === "electronics/phones"
71
+ path("/shop/:path+", ShopCatchAll, { name: "shopCatchAll" }),
72
+
73
+ // /docs -> ctx.params.slug === ""
74
+ // /docs/intro -> ctx.params.slug === "intro"
75
+ // /docs/a/b -> ctx.params.slug === "a/b"
76
+ path("/docs/:slug*", (ctx) => {
77
+ const parts = ctx.params.slug === "" ? [] : ctx.params.slug.split("/");
78
+ return <Docs segments={parts} />;
79
+ }, { name: "docs" }),
80
+ ]);
81
+ ```
82
+
83
+ `ctx.params.<name>` is always a `string` for a catch-all (never `undefined`) —
84
+ `:name*` binds `""` for the empty case, so read it directly. `reverse()` /
85
+ `ctx.reverse()` rebuild the URL with separators preserved:
86
+ `reverse("docs", { slug: "a/b" })` -> `/docs/a/b`.
87
+
88
+ The value is the URL-decoded remainder. `split("/")` recovers the segments in the
89
+ common case, but note that a segment containing an encoded slash (`%2F`) decodes
90
+ to a literal `/` and is therefore indistinguishable from a separator — the same
91
+ trade-off the bare `*` splat has. If you need to distinguish those, match on the
92
+ raw pathname instead.
93
+
94
+ The bare unnamed wildcard `path("/files/*", …)` still works and is read at
95
+ `ctx.params["*"]`; prefer a named catch-all when you want a typed param key.
96
+ Combining a modifier with `?`, a literal suffix, or a constraint
97
+ (`:slug*?`, `:slug*.html`, `:slug(a|b)+`) is rejected at build time.
98
+
36
99
  ## Route Handler Patterns
37
100
 
38
101
  ### Component Function
@@ -74,19 +137,19 @@ path("/product/:slug", async (ctx) => {
74
137
 
75
138
  ```typescript
76
139
  path("/product/:slug", ProductPage, {
77
- name: "product", // Route name for href() and navigation
78
- })
140
+ name: "product", // Route name for href() and navigation
141
+ });
79
142
  ```
80
143
 
81
144
  ### Typed Search Params
82
145
 
83
- Add a `search` schema to get typed `ctx.searchParams` instead of `URLSearchParams`:
146
+ Add a `search` schema to get typed `ctx.search`:
84
147
 
85
148
  ```typescript
86
149
  path("/search", SearchPage, {
87
150
  name: "search",
88
151
  search: { q: "string", page: "number?", sort: "string?" },
89
- })
152
+ });
90
153
  ```
91
154
 
92
155
  Use `Handler<"name">` for typed search params (resolves from the generated route map automatically):
@@ -95,23 +158,24 @@ Use `Handler<"name">` for typed search params (resolves from the generated route
95
158
  import type { Handler } from "@rangojs/router";
96
159
 
97
160
  export const SearchPage: Handler<"search"> = (ctx) => {
98
- // ctx.searchParams is typed: { q: string; page?: number; sort?: string }
99
- const { q, page, sort } = ctx.searchParams;
161
+ // ctx.search is typed: { q: string; page?: number; sort?: string }
162
+ const { q, page, sort } = ctx.search;
163
+ // ctx.searchParams is always URLSearchParams
100
164
  return <SearchResults q={q} page={page} sort={sort} />;
101
165
  };
102
166
  ```
103
167
 
104
168
  Supported types: `"string"`, `"number"`, `"boolean"`, with `?` suffix for optional.
105
- Required params default to zero values when missing (`""`, `0`, `false`).
106
- Optional params are omitted from the result when not in the query string.
169
+ Missing params are `undefined` regardless of required/optional. The required/optional
170
+ distinction is a consumer-facing contract (for `href()` and `reverse()` autocomplete).
107
171
 
108
172
  Use `RouteSearchParams<"name">` and `RouteParams<"name">` to extract types for props:
109
173
 
110
174
  ```typescript
111
175
  import type { RouteSearchParams, RouteParams } from "@rangojs/router";
112
176
 
113
- type SP = RouteSearchParams<"search">; // { q: string; page?: number; sort?: string }
114
- type P = RouteParams<"blogPost">; // { slug: string }
177
+ type SP = RouteSearchParams<"search">; // { q: string; page?: number; sort?: string }
178
+ type P = RouteParams<"blogPost">; // { slug: string }
115
179
  ```
116
180
 
117
181
  ## Route Children
@@ -126,19 +190,257 @@ path("/product/:slug", ProductPage, { name: "product" }, () => [
126
190
  ])
127
191
  ```
128
192
 
193
+ ## Handler Data Ownership
194
+
195
+ When a route has children (orphan layouts, parallels), the handler executes
196
+ first. Use `ctx.set(key, value)` to share data with children, who read it
197
+ via `ctx.get(key)`. Caching wraps all segments together, so either all run
198
+ or none do.
199
+
200
+ This pattern is also safe under partial action revalidation: on an action,
201
+ the route entry re-runs as a unit by default — route segment, loaders, and
202
+ `belongsToRoute` children (orphan layouts, entry parallels) all seed
203
+ revalidate-true, with handler-first ordering preserved. Handler-set data
204
+ stays consistent with no configuration. See `/rango` → "Passing data down
205
+ the tree" for the safest-first ladder.
206
+
207
+ ### Typed context variables with createVar
208
+
209
+ Use `createVar<T>()` to create a typed token for `ctx.set()`/`ctx.get()`.
210
+ The token is imported by both the handler (producer) and layout (consumer),
211
+ making the data contract explicit and compile-time verified:
212
+
213
+ ```typescript
214
+ import { createVar } from "@rangojs/router";
215
+ import { Outlet, ParallelOutlet } from "@rangojs/router/client";
216
+
217
+ // Typed token -- shared between handler and layout
218
+ interface DashboardData {
219
+ title: string;
220
+ stats: { views: number };
221
+ }
222
+ const Dashboard = createVar<DashboardData>();
223
+
224
+ path("/dashboard/:id", async (ctx) => {
225
+ const data = await fetchDashboard(ctx.params.id);
226
+ ctx.set(Dashboard, data); // type-checked
227
+ return <DashboardPage data={data} />;
228
+ }, { name: "dashboard" }, () => [
229
+ layout((ctx) => {
230
+ const data = ctx.get(Dashboard); // typed as DashboardData | undefined
231
+ return (
232
+ <div>
233
+ <h1>{data?.title}</h1>
234
+ <Outlet />
235
+ <ParallelOutlet name="@sidebar" />
236
+ </div>
237
+ );
238
+ }),
239
+ parallel({
240
+ "@sidebar": (ctx) => {
241
+ const data = ctx.get(Dashboard);
242
+ return <Sidebar stats={data?.stats} />;
243
+ },
244
+ }),
245
+ ])
246
+ ```
247
+
248
+ String keys still work (`ctx.set("key", value)` / `ctx.get("key")`), but
249
+ `createVar<T>()` is preferred for type safety.
250
+
251
+ Only route handlers and middleware can call `ctx.set()`. Layouts, parallels,
252
+ and intercepts can only read via `ctx.get()`.
253
+
254
+ #### Non-cacheable context variables
255
+
256
+ Mark a var as non-cacheable when it holds inherently request-specific data
257
+ (sessions, auth tokens, per-request IDs). There are two ways:
258
+
259
+ ```typescript
260
+ // Var-level: every value written to this var is non-cacheable
261
+ const Session = createVar<SessionData>({ cache: false });
262
+
263
+ // Write-level: escalate a normally-cacheable var for this specific write
264
+ const Theme = createVar<string>();
265
+ ctx.set(Theme, userTheme, { cache: false });
266
+ ```
267
+
268
+ "Least cacheable wins" — if either the var definition or the write site says
269
+ `cache: false`, the value is non-cacheable.
270
+
271
+ Reading a non-cacheable var inside `cache()` or `"use cache"` throws at
272
+ runtime. This prevents request-specific data from leaking into cached output:
273
+
274
+ ```typescript
275
+ // This throws — Session is non-cacheable
276
+ async function CachedWidget(ctx) {
277
+ "use cache";
278
+ const session = ctx.get(Session); // Error: non-cacheable var read inside cache scope
279
+ return <Widget />;
280
+ }
281
+ ```
282
+
283
+ Cacheable vars (the default) can be read freely inside cache scopes.
284
+
285
+ ### Revalidation Contracts for Handler Data
286
+
287
+ > **Scope: `revalidate()` is a partial-render concern, not a cache concern.**
288
+ > It decides whether this segment re-runs and streams to the client on a
289
+ > navigation or action — never whether a cached value is stale. The cache
290
+ > decides hit/miss/ttl/swr independently and never reads `revalidate()`. See
291
+ > `/cache-guide` → "Two axes" and `/rango` → "The shape of rango".
292
+
293
+ With no `revalidate()` configured, an entry needs no contract: on an action
294
+ the route handler and its children re-run together by default, so handler
295
+ data stays consistent on its own. Contracts matter in two cases:
296
+
297
+ 1. **You narrow the entry's revalidation** with a predicate that can return a
298
+ hard `false` (e.g. bare `ctx.isAction(X)`). A hard `false` on one side of a
299
+ producer/consumer pair desyncs it — the child re-runs by default and reads
300
+ `undefined`, or vice versa. Put the same named contract on the route and
301
+ its dependent children so they narrow together.
302
+ 2. **The producer is an outer entry** (a standalone `layout()` above this
303
+ route). Outer entries skip action revalidation by default, so the shared
304
+ contract is mandatory — see `/layout` → "Revalidation Contracts".
305
+
306
+ ```typescript
307
+ // revalidation-contracts.ts
308
+ import * as CheckoutActions from "./actions/checkout";
309
+
310
+ // Defer (|| undefined), not ?? false: a hard `false` short-circuits the chain,
311
+ // so when the same segment composes multiple contracts the later ones never run.
312
+ export const revalidateCheckoutData = (ctx) =>
313
+ ctx.isAction(CheckoutActions) || undefined;
314
+
315
+ path("/checkout", CheckoutPage, { name: "checkout" }, () => [
316
+ revalidate(revalidateCheckoutData), // producer (route handler) reruns
317
+ layout(CheckoutLayout, () => [
318
+ revalidate(revalidateCheckoutData), // consumer reruns
319
+ parallel({ "@summary": CheckoutSummary }, () => [
320
+ revalidate(revalidateCheckoutData),
321
+ ]),
322
+ ]),
323
+ ]);
324
+ ```
325
+
326
+ If children depend on multiple upstream domains, compose multiple contracts on
327
+ the same segment (`revalidateAuthData`, `revalidateCheckoutData`, and so on).
328
+
329
+ For cleaner route trees, expose contract helpers and spread them:
330
+
331
+ ```typescript
332
+ import { revalidate } from "@rangojs/router";
333
+
334
+ export const revalidateCheckout = () => [revalidate(revalidateCheckoutData)];
335
+
336
+ path("/checkout", CheckoutPage, { name: "checkout" }, () => [
337
+ revalidateCheckout(),
338
+ layout(CheckoutLayout, () => [revalidateCheckout()]),
339
+ ]);
340
+ ```
341
+
342
+ ## Redirects
343
+
344
+ ### Basic redirect
345
+
346
+ ```typescript
347
+ import { redirect } from "@rangojs/router";
348
+
349
+ path("/old-page", () => redirect("/new-page"), { name: "oldPage" });
350
+ ```
351
+
352
+ ### Redirect with custom status
353
+
354
+ ```typescript
355
+ path("/moved", () => redirect("/new-location", 301), { name: "moved" });
356
+ ```
357
+
358
+ > **Redirecting from a route with `loading()`:** an `async` handler that returns
359
+ > a `Response`/`redirect()` on a route that also declares `loading()` is streamed,
360
+ > so the redirect is rendered into the RSC stream instead of becoming an HTTP
361
+ > redirect. Issue the redirect from `middleware`, a loader, or a **synchronous**
362
+ > handler return instead. (Dev logs a warning if this is hit.)
363
+
364
+ ### Redirect with location state
365
+
366
+ Carry typed state through redirects (e.g. flash messages):
367
+
368
+ ```typescript
369
+ import { redirect, createLocationState } from "@rangojs/router";
370
+
371
+ export const FlashMessage = createLocationState<{ text: string }>({
372
+ flash: true,
373
+ });
374
+
375
+ path(
376
+ "/save",
377
+ (ctx) => {
378
+ // ... save logic
379
+ return redirect("/dashboard", {
380
+ state: [FlashMessage({ text: "Item saved!" })],
381
+ });
382
+ },
383
+ { name: "save" },
384
+ );
385
+
386
+ // With custom status + state
387
+ path(
388
+ "/action",
389
+ (ctx) => {
390
+ return redirect("/target", {
391
+ status: 303,
392
+ state: [FlashMessage({ text: "Action complete" })],
393
+ });
394
+ },
395
+ { name: "action" },
396
+ );
397
+ ```
398
+
399
+ Read the state on the target page with `useLocationState(FlashMessage)`. The
400
+ `{ flash: true }` option makes it auto-clear. Without `{ flash: true }`,
401
+ state persists on back/forward. See `/hooks` for details.
402
+
403
+ ### ctx.setLocationState()
404
+
405
+ Attach location state to any server response (not just redirects):
406
+
407
+ ```typescript
408
+ import { createLocationState } from "@rangojs/router";
409
+
410
+ const ServerInfo = createLocationState<{ data: string }>();
411
+
412
+ path("/dashboard", (ctx) => {
413
+ ctx.setLocationState(ServerInfo({ data: "welcome" }));
414
+ return <Dashboard />;
415
+ }, { name: "dashboard" })
416
+ ```
417
+
418
+ State flows to the browser via the RSC payload and is merged into
419
+ `history.pushState()`. Only works for SPA (partial) navigations.
420
+
129
421
  ## Handler Context
130
422
 
131
423
  Every handler receives a context object:
132
424
 
133
425
  ```typescript
134
426
  interface HandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch = {}> {
135
- params: TParams; // URL parameters
136
- request: Request; // Original request
137
- searchParams: URLSearchParams | ResolveSearchSchema<TSearch>; // Query params (typed when search schema is set)
138
- url: URL; // Parsed URL
139
- env: TEnv; // Environment (bindings + variables)
140
- use<T>(handle: Handle<T>): T; // Access handles
141
- reverse(name: string, params?: Record<string, string>, search?: Record<string, unknown>): string; // URL generation
427
+ params: TParams; // URL parameters
428
+ request: Request; // Original request
429
+ searchParams: URLSearchParams; // Query params (always URLSearchParams)
430
+ search: {} | ResolveSearchSchema<TSearch>; // Typed search params (from search schema)
431
+ url: URL; // Parsed URL
432
+ env: TEnv; // Environment (bindings + variables)
433
+ set(key: string, value: any): void; // Set context variable (untyped string key)
434
+ set<T>(contextVar: ContextVar<T>, value: T): void; // Set typed context variable
435
+ get(key: string): any; // Read context variable (untyped string key)
436
+ get<T>(contextVar: ContextVar<T>): T | undefined; // Read typed context variable
437
+ use<T>(handle: Handle<T>): T; // Access handles
438
+ reverse(
439
+ name: string,
440
+ params?: Record<string, string>,
441
+ search?: Record<string, unknown>,
442
+ ): string; // URL generation
443
+ setLocationState(entries: LocationStateEntry[]): void; // Attach state to response
142
444
  }
143
445
  ```
144
446
 
@@ -152,8 +454,8 @@ path("/product/:slug", (ctx) => {
152
454
  // Access query params (untyped - use search schema for typed access)
153
455
  const tab = ctx.searchParams.get("tab");
154
456
 
155
- // Access environment
156
- const db = ctx.env.Bindings.DB;
457
+ // Access platform bindings
458
+ const db = ctx.env.DB;
157
459
 
158
460
  // Access handles
159
461
  const breadcrumbs = ctx.use(Breadcrumbs);
@@ -177,11 +479,38 @@ urls(({ path, layout }) => [
177
479
  ])
178
480
  ```
179
481
 
482
+ ## View Transitions
483
+
484
+ A route can configure its own `transition()` — the wrap goes around the route's component itself (routes are leaves; they have no separate default outlet channel). If the route component renders a `<ParallelOutlet />` directly, that slot remains inside the route's VT subtree, so prefer mounting parallel slots in a layout when combining intercept modals with route-level transitions. See [skills/view-transitions](../view-transitions/SKILL.md) for examples and the wrap-location rules across layouts, routes, and slots.
485
+
486
+ ## Handler-attached `.use`
487
+
488
+ Page handlers can carry their own loader, middleware, error boundaries, parallels, and other defaults via a `.use` callback — so the page is self-contained and reusable across mount sites without re-wiring the same items.
489
+
490
+ ```typescript
491
+ const ProductPage: Handler<"/product/:slug"> = async (ctx) => {
492
+ const product = await ctx.use(ProductLoader);
493
+ return <ProductView product={product} />;
494
+ };
495
+ ProductPage.use = () => [
496
+ loader(ProductLoader),
497
+ loading(<ProductSkeleton />),
498
+ middleware(async (ctx, next) => {
499
+ await next();
500
+ ctx.header("Cache-Control", "private, max-age=60");
501
+ }),
502
+ ];
503
+
504
+ // Mount site has no per-page wiring — defaults travel with the handler.
505
+ path("/product/:slug", ProductPage, { name: "product" });
506
+ ```
507
+
508
+ Explicit `use()` at the mount site merges with `handler.use` (handler defaults first, explicit second). See [skills/handler-use](../handler-use/SKILL.md) for the merge order, allowed item types per mount site, and override semantics.
509
+
180
510
  ## Complete Example
181
511
 
182
512
  ```typescript
183
- import { urls } from "@rangojs/router";
184
- import { Breadcrumbs } from "./handles/breadcrumbs";
513
+ import { urls, Breadcrumbs } from "@rangojs/router";
185
514
 
186
515
  export const urlpatterns = urls(({ path, layout, loader, loading }) => [
187
516
  // Simple route