@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
package/AGENTS.md ADDED
@@ -0,0 +1,17 @@
1
+ # @rangojs/router
2
+
3
+ A file-system based React Server Components router.
4
+
5
+ Run `/rango` to understand the API. Detailed guides for each feature are in the `skills/` directory (e.g. `node_modules/@rangojs/router/skills/loader`, `skills/caching`, `skills/middleware`, etc.).
6
+
7
+ ## Development rules
8
+
9
+ - Always commit generated files (e.g. `*.gen.ts`) alongside the source changes that produced them.
10
+
11
+ ## Repo-wide rules (read before pushing)
12
+
13
+ This package inherits the repo-wide conventions in the root [`AGENTS.md`](../../AGENTS.md) and [`CLAUDE.md`](../../CLAUDE.md). The ones a package-scoped reader is most likely to miss:
14
+
15
+ - **Pre-push gate** — before EVERY push, run all of the following from the **repo root** and fix any failures: `pnpm run typecheck`, `pnpm run test:unit:all`, `pnpm run lint`, `pnpm run format`.
16
+ - **`test:unit:all` is recursive** — it runs the unit AND Flight/RSC suites for every package and consumer app (cloudflare-basic, mini, vite-rsc-demo, ...), not just `@rangojs/router`. A change can pass this package's own tests while breaking a consumer app's `@rangojs/router/testing` dogfood suite, so do not run only `pnpm --filter @rangojs/router test:unit`.
17
+ - **Dev + prod e2e parity is mandatory** — every e2e test must cover BOTH dev and production modes; never add a dev-only test without its production counterpart. See the dev/prod bucketing convention in the root `AGENTS.md`.
package/README.md CHANGED
@@ -1,18 +1,443 @@
1
- # @rangojs/router
1
+ # Rango
2
2
 
3
- > **Warning:** This package is experimental and under active development. APIs may change without notice.
3
+ A code-first, type-safe React Server Components router. Django-inspired:
4
+ routes are expressed in one visible tree, URLs are built from names, and
5
+ everything past the core is opt-in.
4
6
 
5
- Type-safe RSC router with partial rendering support for Vite.
7
+ > **Experimental:** This package is under active development. APIs may change
8
+ > between releases. Install with `@experimental` tag.
6
9
 
7
- ## Installation
10
+ This page is a tour: it builds one small shop and meets the entire core API
11
+ along the way — about six primitives. Everything else is opt-in and linked at
12
+ the end. For the design rationale behind these APIs, read
13
+ [Why Rango](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/why-rango.md); this page shows how it feels, that page
14
+ argues why it's right.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install @rangojs/router@experimental react @vitejs/plugin-rsc
20
+ ```
21
+
22
+ ```ts
23
+ // vite.config.ts
24
+ import react from "@vitejs/plugin-react";
25
+ import { defineConfig } from "vite";
26
+ import { rango } from "@rangojs/router/vite";
27
+
28
+ export default defineConfig({
29
+ plugins: [react(), rango({ preset: "cloudflare" })],
30
+ });
31
+ ```
32
+
33
+ The `cloudflare` preset targets Cloudflare Workers (add
34
+ `@cloudflare/vite-plugin`); the `vercel` preset emits a ready-to-deploy
35
+ `.vercel/output` (Build Output API) from a plain `vite build` — see the
36
+ [`/vercel` skill](./skills/vercel/SKILL.md); omit `preset` for the default
37
+ Node setup.
38
+
39
+ ## 1. Pages
40
+
41
+ A router is a tree. `path()` places a page, `layout()` wraps children,
42
+ `{ name }` gives a route an identity:
43
+
44
+ ```tsx
45
+ // src/router.tsx
46
+ import { createRouter, urls } from "@rangojs/router";
47
+ import { Document } from "./document";
48
+ import { ShopLayout } from "./layouts/shop";
49
+ import { HomePage } from "./routes/home";
50
+ import { ProductPage } from "./routes/product";
51
+
52
+ const urlpatterns = urls(({ path, layout }) => [
53
+ layout(<ShopLayout />, () => [
54
+ path("/", HomePage, { name: "home" }),
55
+ path("/products/:slug", ProductPage, { name: "product" }),
56
+ ]),
57
+ ]);
58
+
59
+ export const router = createRouter({ document: Document }).routes(urlpatterns);
60
+ ```
61
+
62
+ ```tsx
63
+ // src/layouts/shop.tsx
64
+ import { Outlet } from "@rangojs/router/client";
65
+
66
+ export function ShopLayout() {
67
+ return (
68
+ <div>
69
+ <nav>Shop</nav>
70
+ <main>
71
+ <Outlet /> {/* child routes render here */}
72
+ </main>
73
+ </div>
74
+ );
75
+ }
76
+ ```
77
+
78
+ ```tsx
79
+ // src/document.tsx
80
+ "use client";
81
+
82
+ import type { ReactNode } from "react";
83
+ import { MetaTags, Scripts } from "@rangojs/router/client";
84
+
85
+ export function Document({ children }: { children: ReactNode }) {
86
+ return (
87
+ <html lang="en">
88
+ <head>
89
+ <MetaTags />
90
+ <Scripts />
91
+ </head>
92
+ <body>
93
+ <Scripts position="body" />
94
+ {children}
95
+ </body>
96
+ </html>
97
+ );
98
+ }
99
+ ```
100
+
101
+ (The built-in `DefaultDocument` already wires all of this — a custom document
102
+ is optional.)
103
+
104
+ A handler is a function of `ctx`. Typing it by route name gives typed params
105
+ — the Vite plugin generates the route map automatically, nothing to register:
106
+
107
+ ```tsx
108
+ // src/routes/product.tsx
109
+ import type { Handler } from "@rangojs/router";
110
+
111
+ export const ProductPage: Handler<"product"> = (ctx) => {
112
+ return <h1>{ctx.params.slug}</h1>; // slug: string, from the pattern
113
+ };
114
+ ```
115
+
116
+ And because routes have names, URLs are built, never hand-written:
117
+
118
+ ```tsx
119
+ const url = ctx.reverse("product", { slug: "espresso-cup" });
120
+ // "/products/espresso-cup" — name and params compile-time checked
121
+ ```
122
+
123
+ Rename `/products/:slug` to `/shop/:slug` in the one place it's defined and
124
+ every link, redirect, and prefetch follows. In client components, `href()`
125
+ validates static paths against the registered patterns:
126
+ `<Link to={href("/")}>Home</Link>`.
127
+
128
+ The tree is also lazy-first, which is the shape serverless cold starts want.
129
+ `include()` mounts a whole route module under a prefix — and with the async
130
+ form, `include("/shop", () => import("./shop"))`, the group is code-split:
131
+ its module doesn't load or run until a request matches it, a group nobody
132
+ visits never evaluates at all, and warm requests run zero route handlers.
133
+ Boot cost stays flat as the app grows — one module body at startup, not one
134
+ per group — while matching stays an `O(path length)` prefix trie, identical
135
+ in dev and production. None of this is assumed: the trie is benchmarked
136
+ in-repo against multi-thousand-route manifests, and the lazy guarantees are
137
+ pinned by run-count tests (see
138
+ [matching & lazy discovery](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/internal/matching-and-lazy-discovery.md)).
139
+ Grow the tree without watching the boot time.
140
+
141
+ That's a working site. Everything below adds to this app.
142
+
143
+ ## 2. Data
144
+
145
+ The product page needs data. A handler is an async server component — fetch
146
+ where you render:
147
+
148
+ ```tsx
149
+ // src/routes/product.tsx
150
+ export const ProductPage: Handler<"product"> = async (ctx) => {
151
+ const product = await db.products.find(ctx.params.slug);
152
+ ctx.use(Meta)({ title: product.name }); // metadata where the data is
153
+ return <ProductView product={product} />;
154
+ };
155
+ ```
156
+
157
+ That's the default data path. React Router and Remix split data into a
158
+ loader beside the component because components couldn't fetch; RSC collapses
159
+ the split, and Rango doesn't reintroduce it. (That `ctx.use(Meta)` line is
160
+ also the whole metadata story: push tags where the data already is, layouts
161
+ set title templates, deeper segments override — no separate metadata export,
162
+ no second fetch.)
163
+
164
+ Loaders enter when data needs a life of its own. First case: a **client
165
+ component** needs server data — the stock badge is interactive, but the
166
+ stock lives in the database:
167
+
168
+ ```tsx
169
+ // src/loaders/stock.ts
170
+ import { createLoader } from "@rangojs/router";
171
+
172
+ export const StockLoader = createLoader(async (ctx) => {
173
+ "use server";
174
+ return db.stockFor(ctx.params.slug);
175
+ });
176
+ ```
177
+
178
+ ```tsx
179
+ path("/products/:slug", ProductPage, { name: "product" }, () => [
180
+ loader(StockLoader),
181
+ loading(<ProductSkeleton />),
182
+ ]),
183
+ ```
184
+
185
+ ```tsx
186
+ // src/components/stock-badge.tsx
187
+ "use client";
188
+ import { useLoader } from "@rangojs/router/client";
189
+ import { StockLoader } from "../loaders/stock";
190
+
191
+ export function StockBadge() {
192
+ const { data } = useLoader(StockLoader);
193
+ return <span>{data.inStock ? "In stock" : "Sold out"}</span>;
194
+ }
195
+ ```
196
+
197
+ Loaders run in parallel with the handler and stream; `loading()` opts the
198
+ segment into skeleton-then-stream. Without it, document requests arrive
199
+ **ready** — the HTML ships with data in place; the skeleton is a per-segment
200
+ choice, not the first impression.
201
+
202
+ The rule of thumb: fetch in the **handler** when the data belongs to the
203
+ rendered page — it will be frozen with the shell if you cache it (step 4).
204
+ Put data in a **loader** when it must outlive the shell: shared with client
205
+ components, fresh on every hit even when the segment is cached, refetchable
206
+ from the client, or revalidated on its own after actions.
207
+
208
+ ## 3. Mutations
209
+
210
+ Users add to cart. A server action is a plain `"use server"` function; the
211
+ form posts to it with standard React 19 hooks — and it works without
212
+ JavaScript:
213
+
214
+ ```tsx
215
+ // src/actions/cart.ts
216
+ "use server";
217
+
218
+ export async function addToCart(productId: string) {
219
+ await db.cart.insert({ productId });
220
+ }
221
+ ```
222
+
223
+ ```tsx
224
+ // src/components/add-to-cart.tsx
225
+ "use client";
226
+ import { useActionState } from "react";
227
+ import { addToCart } from "../actions/cart";
228
+
229
+ export function AddToCart({ productId }: { productId: string }) {
230
+ const [, action, pending] = useActionState(() => addToCart(productId), null);
231
+ return (
232
+ <form action={action}>
233
+ <button disabled={pending}>{pending ? "Adding…" : "Add to cart"}</button>
234
+ </form>
235
+ );
236
+ }
237
+ ```
238
+
239
+ After an action, route segments and loaders re-render by default so the UI
240
+ reflects the new state. `revalidate()` narrows that to the segments that
241
+ actually own the data — matched by action **reference**, so renames are
242
+ compile errors, not stale predicates:
243
+
244
+ ```tsx
245
+ import * as CartActions from "./actions/cart";
246
+
247
+ path("/cart", CartPage, { name: "cart" }, () => [
248
+ loader(CartLoader, () => [
249
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
250
+ ]),
251
+ ]),
252
+ ```
253
+
254
+ Notice what you didn't write: no API endpoint, no fetch wrapper, and no
255
+ client-cache invalidation call. Actions invalidate the client-side caches
256
+ (history entries, prefetches, HTTP cache key) automatically — a no-op action
257
+ can opt out per invocation with `keepClientCache()`.
258
+
259
+ ## 4. Speed
260
+
261
+ Production traffic. Wrap a segment in `cache()` and the rendered shell —
262
+ including everything the handler fetched — is stored, while every loader on
263
+ it keeps running fresh on each hit. This is where the handler-vs-loader
264
+ choice from step 2 pays off: handler data freezes with the shell, the
265
+ `StockLoader` stays live. Cached shell, live data, one line:
266
+
267
+ ```tsx
268
+ const urlpatterns = urls(({ path, layout, loader, loading, cache }) => [
269
+ layout(<ShopLayout />, () => [
270
+ path("/", HomePage, { name: "home" }),
271
+ cache({ ttl: 600, swr: 3600, tags: ["products"] }, () => [
272
+ path("/products/:slug", ProductPage, { name: "product" }, () => [
273
+ loader(StockLoader), // never cached: re-runs on every hit
274
+ loading(<ProductSkeleton />),
275
+ ]),
276
+ ]),
277
+ ]),
278
+ ]);
279
+ ```
280
+
281
+ Wire a store once on the router (`MemorySegmentCacheStore` for dev,
282
+ `CFCacheStore` for Cloudflare — see the [`/caching` skill](./skills/caching/SKILL.md)),
283
+ and bust by tag from the mutation that changes the data:
284
+
285
+ ```tsx
286
+ // src/actions/products.ts
287
+ "use server";
288
+ import { updateTag } from "@rangojs/router";
289
+
290
+ export async function renameProduct(id: string, name: string) {
291
+ await db.products.rename(id, name);
292
+ await updateTag("products"); // awaitable, read-your-own-writes
293
+ }
294
+ ```
295
+
296
+ Navigation speed is a `Link` prop away:
297
+
298
+ ```tsx
299
+ <Link to={url} prefetch="viewport">
300
+ {product.name}
301
+ </Link>
302
+ ```
303
+
304
+ A fully-prefetched navigation commits a **finished page** — no skeleton, no
305
+ loading flash — and staying correct is the router's job: every action
306
+ invalidates the prefetch caches by default, so a prefetched page can't show
307
+ pre-mutation data.
308
+
309
+ To move the shell's cost to build time entirely, `Prerender()` bakes it while
310
+ loaders stay live at runtime — same mental model, earlier cache write. See
311
+ the [`/prerender` skill](./skills/prerender/SKILL.md).
312
+
313
+ ## 5. An API, when you need one
314
+
315
+ Response routes live in the same tree — `path.json()`, `path.text()`,
316
+ `path.xml()`, `path.image()`, `path.stream()`:
317
+
318
+ ```tsx
319
+ path("/products/:slug", ProductPage, { name: "product" }),
320
+ path.json("/products/:slug", (ctx) => db.products.find(ctx.params.slug), {
321
+ name: "productJson",
322
+ }),
323
+ ```
324
+
325
+ Same URL: browsers get the page, API clients get JSON, negotiated by
326
+ `Accept` header in the route trie. Handlers return bare values; errors
327
+ serialize as RFC 9457 `application/problem+json`. The payload type is
328
+ inferred from the handler — no codegen:
329
+
330
+ ```ts
331
+ type Product = RouteResponse<typeof urlpatterns, "productJson">;
332
+ ```
333
+
334
+ See the [`/api-client` skill](./skills/api-client/SKILL.md) for a small typed
335
+ client over these endpoints.
336
+
337
+ ## Everything else, when you need it
338
+
339
+ That was the core: `path`/`layout`/`include`, names, loaders, actions +
340
+ `revalidate`, `cache`, response routes. The rest is opt-in — reach for it
341
+ when the requirement appears:
342
+
343
+ | I need to… | Skill |
344
+ | ----------------------------------------------- | -------------------------------------------------------------------------------------------- |
345
+ | guard or shape requests (auth, headers) | [`/middleware`](./skills/middleware/SKILL.md) |
346
+ | multi-column layouts, independent slots | [`/parallel`](./skills/parallel/SKILL.md) |
347
+ | open a route as a modal on soft navigation | [`/intercept`](./skills/intercept/SKILL.md) |
348
+ | compose route modules / sub-apps | [`/route`](./skills/route/SKILL.md), [`/composability`](./skills/composability/SKILL.md) |
349
+ | cache a single function or component | [`/use-cache`](./skills/use-cache/SKILL.md), [`/cache-guide`](./skills/cache-guide/SKILL.md) |
350
+ | feed live loaders from a cached shell | [`/shell-manifest`](./skills/shell-manifest/SKILL.md) |
351
+ | edge caching with Cache-Control | [`/document-cache`](./skills/document-cache/SKILL.md) |
352
+ | light/dark mode without FOUC | [`/theme`](./skills/theme/SKILL.md) |
353
+ | analytics / third-party scripts with CSP nonce | [`/scripts`](./skills/scripts/SKILL.md) |
354
+ | locale routing | [`/i18n`](./skills/i18n/SKILL.md) |
355
+ | SSE and WebSockets | [`/streams-and-websockets`](./skills/streams-and-websockets/SKILL.md) |
356
+ | multi-app routing by domain | [`/host-router`](./skills/host-router/SKILL.md) |
357
+ | animate navigations | [`/view-transitions`](./skills/view-transitions/SKILL.md) |
358
+ | test loaders, middleware, handlers, Flight | [`/testing`](./skills/testing/SKILL.md) |
359
+ | see where request time goes | [`/observability`](./skills/observability/SKILL.md) |
360
+ | deploy to Vercel (cache store, tracing, output) | [`/vercel`](./skills/vercel/SKILL.md) |
361
+ | compare Rango with Next.js / TanStack / Waku | [`/comparison`](./skills/comparison/SKILL.md) |
362
+
363
+ The [`/rango` skill](./skills/rango/SKILL.md) is the full catalog and the
364
+ mental model that ties it together.
365
+
366
+ ## Reference
367
+
368
+ ### Imports and subpaths
369
+
370
+ | Export | Description |
371
+ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
372
+ | `@rangojs/router` | Server/RSC core and shared types: `createRouter`, `urls`, `createLoader`, `Handler`, `Prerender`, `Meta` |
373
+ | `@rangojs/router/client` | Client: `Link`, `Outlet`, `href`, `useNavigation`, `useLoader`, `MetaTags` |
374
+ | `@rangojs/router/cache` | Cache: `CFCacheStore`, `VercelCacheStore`, `MemorySegmentCacheStore`, `createDocumentCacheMiddleware` |
375
+ | `@rangojs/router/theme` | Theme: `useTheme`, `ThemeProvider`, `ThemeScript` |
376
+ | `@rangojs/router/host` | Host routing: `createHostRouter`, `defineHosts`, `isNoRouteMatchError` |
377
+ | `@rangojs/router/vercel` | Vercel: `createVercelTracing` (phase spans via `@vercel/otel`'s global tracer) |
378
+ | `@rangojs/router/vite` | Vite plugin: `rango()` |
379
+ | `@rangojs/router/testing` | Consumer testing primitives: `runLoader`, `runMiddleware`, `dispatch` (plus `/testing/dom`, `/testing/flight`, `/testing/e2e`) |
380
+ | `@rangojs/router/rsc` | Advanced server pipeline APIs: `createRSCHandler`, request-context access |
381
+ | `@rangojs/router/ssr` | Advanced SSR bridge APIs: `createSSRHandler` |
382
+
383
+ Use only subpaths that are explicitly exported; avoid deep imports.
384
+
385
+ The root entry is conditionally resolved: server-only APIs (`createRouter`,
386
+ `urls`, `redirect`, `Prerender`, `cookies`) run under the `react-server`
387
+ condition and throw guidance errors elsewhere. If you hit a root-entrypoint
388
+ stub error: hooks and components (`Link`, `Outlet`, `useLoader`, `MetaTags`)
389
+ live in `@rangojs/router/client`; cache APIs in `@rangojs/router/cache`;
390
+ host APIs in `@rangojs/router/host`.
391
+
392
+ ### Type safety
393
+
394
+ The Vite plugin generates `router.named-routes.gen.ts` automatically (on dev
395
+ startup, HMR, and builds), registering route names, params, and search
396
+ schemas globally via `Rango.GeneratedRouteMap`. That powers `Handler<"name">`,
397
+ `ctx.reverse()`, and `RouteParams<"name">` with no manual registration.
398
+
399
+ For response-aware and path-based utilities (`href()`, `Rango.Path`,
400
+ `RouteResponse`), augment `Rango.RegisteredRoutes` once:
401
+
402
+ ```ts
403
+ // router.tsx
404
+ const router = createRouter<AppBindings>({}).routes(urlpatterns);
405
+
406
+ declare global {
407
+ namespace Rango {
408
+ interface Env extends AppEnv {}
409
+ interface RegisteredRoutes extends typeof router.routeMap {}
410
+ }
411
+ }
412
+ ```
413
+
414
+ See the [`/typesafety` skill](./skills/typesafety/SKILL.md) for the full
415
+ surface breakdown.
416
+
417
+ ### CLI
418
+
419
+ Route types are generated by the Vite plugin; the CLI is the manual fallback
420
+ for CI or pre-first-run IDE support:
8
421
 
9
422
  ```bash
10
- npm install @rangojs/router@experimental
423
+ npx rango generate src/router.tsx # global named-route map
424
+ npx rango generate src/ # recursive scan
11
425
  ```
12
426
 
13
- ## Status
427
+ ### Examples
428
+
429
+ - [`e2e/mini`](https://github.com/ivogt/vite-rsc/tree/main/packages/rangojs-router/e2e/mini) — single-file demo app
430
+ - [`cloudflare-basic`](https://github.com/ivogt/vite-rsc/tree/main/tests/cloudflare-basic) — Cloudflare Workers with caching, loaders, theme, and pre-rendering
431
+ - [`cloudflare-multi-router`](https://github.com/ivogt/vite-rsc/tree/main/examples/cloudflare-multi-router) — multi-app host routing
432
+ - [`vercel-basic`](https://github.com/ivogt/vite-rsc/tree/main/examples/vercel-basic) — Vercel deployment with `preset: "vercel"`, `VercelCacheStore`, and OTel tracing
433
+ - [`vercel-multi-router`](https://github.com/ivogt/vite-rsc/tree/main/examples/vercel-multi-router) — multi-app host routing on Vercel (single function, routed by Host header)
434
+
435
+ ### Going deeper
14
436
 
15
- This package is in early experimental stages. It is not recommended for production use.
437
+ - [Why Rango](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/why-rango.md) the design rationale, claim by claim
438
+ - [Framework comparison](./skills/comparison/references/framework-comparison.md) — Rango vs Next.js App Router, TanStack Start, and Waku, capability by capability
439
+ - [Docs index](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/README.md) — architecture, caching, prerender, testing
440
+ - [Execution model](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/internal/execution-model.md) — the runtime contract
16
441
 
17
442
  ## License
18
443