@rangojs/router 0.0.0-experimental.135c6902 → 0.0.0-experimental.136

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 (404) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +245 -49
  3. package/dist/bin/rango.js +440 -133
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3386 -1111
  6. package/dist/vite/index.js.bak +5448 -0
  7. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  8. package/package.json +78 -25
  9. package/skills/api-client/SKILL.md +211 -0
  10. package/skills/breadcrumbs/SKILL.md +64 -2
  11. package/skills/bundle-analysis/SKILL.md +159 -0
  12. package/skills/cache-guide/SKILL.md +247 -23
  13. package/skills/caching/SKILL.md +281 -11
  14. package/skills/composability/SKILL.md +27 -3
  15. package/skills/css/SKILL.md +76 -0
  16. package/skills/debug-manifest/SKILL.md +4 -2
  17. package/skills/document-cache/SKILL.md +78 -55
  18. package/skills/handler-use/SKILL.md +364 -0
  19. package/skills/hooks/SKILL.md +250 -30
  20. package/skills/host-router/SKILL.md +83 -23
  21. package/skills/i18n/SKILL.md +276 -0
  22. package/skills/intercept/SKILL.md +87 -18
  23. package/skills/layout/SKILL.md +35 -9
  24. package/skills/links/SKILL.md +249 -17
  25. package/skills/loader/SKILL.md +289 -53
  26. package/skills/middleware/SKILL.md +52 -13
  27. package/skills/migrate-nextjs/SKILL.md +584 -0
  28. package/skills/migrate-react-router/SKILL.md +914 -0
  29. package/skills/mime-routes/SKILL.md +28 -1
  30. package/skills/observability/SKILL.md +172 -0
  31. package/skills/parallel/SKILL.md +144 -7
  32. package/skills/prerender/SKILL.md +172 -125
  33. package/skills/rango/SKILL.md +251 -22
  34. package/skills/react-compiler/SKILL.md +168 -0
  35. package/skills/response-routes/SKILL.md +123 -48
  36. package/skills/route/SKILL.md +101 -5
  37. package/skills/router-setup/SKILL.md +117 -10
  38. package/skills/scripts/SKILL.md +179 -0
  39. package/skills/server-actions/SKILL.md +775 -0
  40. package/skills/streams-and-websockets/SKILL.md +283 -0
  41. package/skills/tailwind/SKILL.md +27 -3
  42. package/skills/testing/SKILL.md +130 -0
  43. package/skills/testing/bindings.md +103 -0
  44. package/skills/testing/cache-prerender.md +127 -0
  45. package/skills/testing/client-components.md +124 -0
  46. package/skills/testing/e2e-parity.md +125 -0
  47. package/skills/testing/flight.md +91 -0
  48. package/skills/testing/handles.md +129 -0
  49. package/skills/testing/loader.md +128 -0
  50. package/skills/testing/middleware.md +99 -0
  51. package/skills/testing/render-handler.md +122 -0
  52. package/skills/testing/response-routes.md +95 -0
  53. package/skills/testing/reverse-and-types.md +84 -0
  54. package/skills/testing/server-actions.md +107 -0
  55. package/skills/testing/server-tree.md +128 -0
  56. package/skills/testing/setup.md +123 -0
  57. package/skills/typesafety/SKILL.md +332 -29
  58. package/skills/use-cache/SKILL.md +57 -14
  59. package/skills/view-transitions/SKILL.md +337 -0
  60. package/src/__augment-tests__/augment.ts +81 -0
  61. package/src/__augment-tests__/augmented.check.ts +116 -0
  62. package/src/__internal.ts +1 -66
  63. package/src/browser/action-coordinator.ts +53 -36
  64. package/src/browser/action-fence.ts +47 -0
  65. package/src/browser/app-shell.ts +39 -0
  66. package/src/browser/app-version.ts +14 -0
  67. package/src/browser/connection-warmup.ts +134 -0
  68. package/src/browser/cookie-name.ts +140 -0
  69. package/src/browser/event-controller.ts +192 -150
  70. package/src/browser/history-state.ts +21 -0
  71. package/src/browser/index.ts +3 -3
  72. package/src/browser/invalidate-client-cache.ts +52 -0
  73. package/src/browser/navigation-bridge.ts +131 -30
  74. package/src/browser/navigation-client.ts +199 -86
  75. package/src/browser/navigation-store-handle.ts +38 -0
  76. package/src/browser/navigation-store.ts +157 -74
  77. package/src/browser/navigation-transaction.ts +9 -59
  78. package/src/browser/network-error-handler.ts +34 -7
  79. package/src/browser/partial-update.ts +174 -109
  80. package/src/browser/prefetch/cache.ts +222 -69
  81. package/src/browser/prefetch/fetch.ts +347 -39
  82. package/src/browser/prefetch/queue.ts +113 -32
  83. package/src/browser/prefetch/resource-ready.ts +77 -0
  84. package/src/browser/rango-state.ts +158 -76
  85. package/src/browser/react/Link.tsx +102 -15
  86. package/src/browser/react/NavigationProvider.tsx +300 -122
  87. package/src/browser/react/ScrollRestoration.tsx +10 -6
  88. package/src/browser/react/context.ts +7 -2
  89. package/src/browser/react/deferred-handle-resolution.ts +75 -0
  90. package/src/browser/react/filter-segment-order.ts +66 -7
  91. package/src/browser/react/index.ts +0 -48
  92. package/src/browser/react/location-state-shared.ts +178 -8
  93. package/src/browser/react/location-state.ts +39 -14
  94. package/src/browser/react/use-action.ts +6 -15
  95. package/src/browser/react/use-handle.ts +23 -69
  96. package/src/browser/react/use-href.tsx +8 -1
  97. package/src/browser/react/use-link-status.ts +33 -8
  98. package/src/browser/react/use-navigation.ts +32 -7
  99. package/src/browser/react/use-params.ts +20 -10
  100. package/src/browser/react/use-reverse.ts +106 -0
  101. package/src/browser/react/use-router.ts +46 -11
  102. package/src/browser/react/use-search-params.ts +0 -5
  103. package/src/browser/react/use-segments.ts +11 -21
  104. package/src/browser/response-adapter.ts +99 -8
  105. package/src/browser/rsc-router.tsx +125 -28
  106. package/src/browser/scroll-restoration.ts +37 -22
  107. package/src/browser/segment-reconciler.ts +36 -14
  108. package/src/browser/segment-structure-assert.ts +2 -2
  109. package/src/browser/server-action-bridge.ts +222 -61
  110. package/src/browser/types.ts +115 -12
  111. package/src/browser/validate-redirect-origin.ts +43 -16
  112. package/src/build/collect-fallback-refs.ts +107 -0
  113. package/src/build/generate-manifest.ts +65 -40
  114. package/src/build/generate-route-types.ts +5 -1
  115. package/src/build/index.ts +8 -2
  116. package/src/build/prefix-tree-utils.ts +123 -0
  117. package/src/build/route-trie.ts +165 -36
  118. package/src/build/route-types/ast-route-extraction.ts +15 -8
  119. package/src/build/route-types/codegen.ts +16 -5
  120. package/src/build/route-types/include-resolution.ts +125 -24
  121. package/src/build/route-types/param-extraction.ts +6 -3
  122. package/src/build/route-types/per-module-writer.ts +22 -6
  123. package/src/build/route-types/router-processing.ts +260 -94
  124. package/src/build/route-types/scan-filter.ts +9 -2
  125. package/src/build/route-types/source-scan.ts +216 -0
  126. package/src/build/runtime-discovery.ts +9 -20
  127. package/src/cache/cache-error.ts +104 -0
  128. package/src/cache/cache-key-utils.ts +29 -13
  129. package/src/cache/cache-policy.ts +108 -34
  130. package/src/cache/cache-runtime.ts +239 -52
  131. package/src/cache/cache-scope.ts +234 -87
  132. package/src/cache/cache-tag.ts +103 -0
  133. package/src/cache/cf/cf-base64.ts +33 -0
  134. package/src/cache/cf/cf-cache-constants.ts +127 -0
  135. package/src/cache/cf/cf-cache-store.ts +1989 -378
  136. package/src/cache/cf/cf-cache-types.ts +349 -0
  137. package/src/cache/cf/cf-kv-utils.ts +46 -0
  138. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  139. package/src/cache/cf/index.ts +6 -16
  140. package/src/cache/document-cache.ts +89 -21
  141. package/src/cache/handle-snapshot.ts +70 -0
  142. package/src/cache/index.ts +10 -20
  143. package/src/cache/memory-segment-store.ts +136 -37
  144. package/src/cache/profile-registry.ts +46 -31
  145. package/src/cache/read-through-swr.ts +56 -12
  146. package/src/cache/segment-codec.ts +9 -17
  147. package/src/cache/tag-invalidation.ts +230 -0
  148. package/src/cache/taint.ts +55 -0
  149. package/src/cache/types.ts +37 -100
  150. package/src/client.rsc.tsx +44 -21
  151. package/src/client.tsx +119 -290
  152. package/src/cloudflare/index.ts +11 -0
  153. package/src/cloudflare/tracing.ts +109 -0
  154. package/src/component-utils.ts +19 -0
  155. package/src/components/DefaultDocument.tsx +8 -2
  156. package/src/context-var.ts +84 -2
  157. package/src/decode-loader-results.ts +52 -0
  158. package/src/defer.ts +196 -0
  159. package/src/deps/ssr.ts +0 -1
  160. package/src/encode-kv.ts +49 -0
  161. package/src/errors.ts +30 -4
  162. package/src/escape-script.ts +52 -0
  163. package/src/handle.ts +70 -22
  164. package/src/handles/MetaTags.tsx +62 -19
  165. package/src/handles/Scripts.tsx +183 -0
  166. package/src/handles/breadcrumbs.ts +37 -8
  167. package/src/handles/is-thenable.ts +19 -0
  168. package/src/handles/meta.ts +51 -40
  169. package/src/handles/script.ts +244 -0
  170. package/src/host/cookie-handler.ts +9 -60
  171. package/src/host/errors.ts +0 -24
  172. package/src/host/index.ts +8 -2
  173. package/src/host/pattern-matcher.ts +23 -52
  174. package/src/host/router.ts +107 -99
  175. package/src/host/testing.ts +40 -27
  176. package/src/host/types.ts +37 -4
  177. package/src/host/utils.ts +1 -1
  178. package/src/href-client.ts +137 -22
  179. package/src/index.rsc.ts +99 -13
  180. package/src/index.ts +139 -19
  181. package/src/internal-debug.ts +11 -10
  182. package/src/loader-store.ts +500 -0
  183. package/src/loader.rsc.ts +20 -13
  184. package/src/loader.ts +12 -11
  185. package/src/missing-id-error.ts +68 -0
  186. package/src/outlet-context.ts +1 -1
  187. package/src/outlet-provider.tsx +1 -5
  188. package/src/prerender/param-hash.ts +16 -16
  189. package/src/prerender/store.ts +37 -41
  190. package/src/prerender.ts +198 -82
  191. package/src/redirect-origin.ts +100 -0
  192. package/src/regex-escape.ts +8 -0
  193. package/src/render-error-thrower.tsx +20 -0
  194. package/src/response-utils.ts +62 -0
  195. package/src/reverse.ts +65 -15
  196. package/src/root-error-boundary.tsx +1 -19
  197. package/src/route-content-wrapper.tsx +19 -77
  198. package/src/route-definition/dsl-helpers.ts +461 -304
  199. package/src/route-definition/helper-factories.ts +28 -140
  200. package/src/route-definition/helpers-types.ts +149 -74
  201. package/src/route-definition/index.ts +4 -2
  202. package/src/route-definition/redirect.ts +51 -10
  203. package/src/route-definition/resolve-handler-use.ts +160 -0
  204. package/src/route-definition/use-item-types.ts +29 -0
  205. package/src/route-map-builder.ts +0 -16
  206. package/src/route-types.ts +37 -46
  207. package/src/router/basename.ts +14 -0
  208. package/src/router/content-negotiation.ts +164 -17
  209. package/src/router/error-handling.ts +45 -18
  210. package/src/router/find-match.ts +44 -23
  211. package/src/router/handler-context.ts +83 -39
  212. package/src/router/instrument.ts +350 -0
  213. package/src/router/intercept-resolution.ts +48 -24
  214. package/src/router/lazy-includes.ts +15 -52
  215. package/src/router/loader-resolution.ts +274 -56
  216. package/src/router/logging.ts +0 -6
  217. package/src/router/manifest.ts +40 -42
  218. package/src/router/match-api.ts +124 -204
  219. package/src/router/match-context.ts +0 -22
  220. package/src/router/match-handlers.ts +58 -58
  221. package/src/router/match-middleware/background-revalidation.ts +54 -25
  222. package/src/router/match-middleware/cache-lookup.ts +205 -271
  223. package/src/router/match-middleware/cache-store.ts +81 -50
  224. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  225. package/src/router/match-middleware/segment-resolution.ts +45 -14
  226. package/src/router/match-pipelines.ts +1 -42
  227. package/src/router/match-result.ts +93 -39
  228. package/src/router/metrics.ts +5 -34
  229. package/src/router/middleware-types.ts +13 -142
  230. package/src/router/middleware.ts +268 -171
  231. package/src/router/navigation-snapshot.ts +131 -0
  232. package/src/router/params-util.ts +23 -0
  233. package/src/router/pattern-matching.ts +132 -90
  234. package/src/router/prefetch-cache-ttl.ts +51 -0
  235. package/src/router/prefetch-limits.ts +37 -0
  236. package/src/router/prerender-match.ts +195 -56
  237. package/src/router/preview-match.ts +32 -102
  238. package/src/router/request-classification.ts +276 -0
  239. package/src/router/revalidation.ts +123 -73
  240. package/src/router/route-snapshot.ts +244 -0
  241. package/src/router/router-context.ts +3 -27
  242. package/src/router/router-interfaces.ts +129 -35
  243. package/src/router/router-options.ts +202 -15
  244. package/src/router/router-registry.ts +2 -5
  245. package/src/router/segment-resolution/fresh.ts +197 -92
  246. package/src/router/segment-resolution/helpers.ts +115 -30
  247. package/src/router/segment-resolution/loader-cache.ts +76 -39
  248. package/src/router/segment-resolution/revalidation.ts +392 -338
  249. package/src/router/segment-resolution/static-store.ts +19 -5
  250. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  251. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  252. package/src/router/segment-resolution.ts +5 -1
  253. package/src/router/segment-wrappers.ts +6 -5
  254. package/src/router/state-cookie-name.ts +33 -0
  255. package/src/router/substitute-pattern-params.ts +56 -0
  256. package/src/router/telemetry-otel.ts +161 -199
  257. package/src/router/telemetry.ts +96 -19
  258. package/src/router/timeout.ts +0 -20
  259. package/src/router/tracing.ts +206 -0
  260. package/src/router/trie-matching.ts +163 -59
  261. package/src/router/types.ts +10 -63
  262. package/src/router/url-params.ts +44 -0
  263. package/src/router.ts +174 -54
  264. package/src/rsc/handler-context.ts +3 -2
  265. package/src/rsc/handler.ts +660 -518
  266. package/src/rsc/helpers.ts +168 -46
  267. package/src/rsc/index.ts +2 -5
  268. package/src/rsc/json-route-result.ts +38 -0
  269. package/src/rsc/loader-fetch.ts +127 -31
  270. package/src/rsc/manifest-init.ts +33 -42
  271. package/src/rsc/origin-guard.ts +39 -25
  272. package/src/rsc/progressive-enhancement.ts +133 -13
  273. package/src/rsc/redirect-guard.ts +99 -0
  274. package/src/rsc/response-cache-serve.ts +238 -0
  275. package/src/rsc/response-error.ts +79 -12
  276. package/src/rsc/response-route-handler.ts +99 -189
  277. package/src/rsc/rsc-rendering.ts +115 -73
  278. package/src/rsc/runtime-warnings.ts +23 -10
  279. package/src/rsc/server-action.ts +287 -113
  280. package/src/rsc/ssr-setup.ts +18 -2
  281. package/src/rsc/transition-gate.ts +89 -0
  282. package/src/rsc/types.ts +36 -6
  283. package/src/runtime-env.ts +18 -0
  284. package/src/search-params.ts +35 -30
  285. package/src/segment-content-promise.ts +67 -0
  286. package/src/segment-loader-promise.ts +149 -0
  287. package/src/segment-system.tsx +269 -202
  288. package/src/serialize.ts +243 -0
  289. package/src/server/context.ts +235 -51
  290. package/src/server/cookie-parse.ts +32 -0
  291. package/src/server/cookie-store.ts +80 -5
  292. package/src/server/handle-store.ts +40 -38
  293. package/src/server/loader-registry.ts +38 -46
  294. package/src/server/request-context.ts +442 -173
  295. package/src/ssr/index.tsx +24 -16
  296. package/src/static-handler.ts +27 -18
  297. package/src/testing/cache-status.ts +162 -0
  298. package/src/testing/collect-handle.ts +40 -0
  299. package/src/testing/dispatch.ts +701 -0
  300. package/src/testing/dom.entry.ts +22 -0
  301. package/src/testing/e2e/fixture.ts +188 -0
  302. package/src/testing/e2e/index.ts +128 -0
  303. package/src/testing/e2e/matchers.ts +35 -0
  304. package/src/testing/e2e/page-helpers.ts +272 -0
  305. package/src/testing/e2e/parity.ts +387 -0
  306. package/src/testing/e2e/server.ts +195 -0
  307. package/src/testing/flight-matchers.ts +97 -0
  308. package/src/testing/flight-normalize.ts +11 -0
  309. package/src/testing/flight-runtime.d.ts +57 -0
  310. package/src/testing/flight-tree.ts +682 -0
  311. package/src/testing/flight.entry.ts +52 -0
  312. package/src/testing/flight.ts +257 -0
  313. package/src/testing/generated-routes.ts +183 -0
  314. package/src/testing/index.ts +105 -0
  315. package/src/testing/internal/context.ts +371 -0
  316. package/src/testing/internal/flight-client-globals.ts +30 -0
  317. package/src/testing/internal/seed-vars.ts +54 -0
  318. package/src/testing/render-handler.ts +357 -0
  319. package/src/testing/render-route.tsx +581 -0
  320. package/src/testing/run-loader.ts +385 -0
  321. package/src/testing/run-middleware.ts +205 -0
  322. package/src/testing/run-transition-when.ts +164 -0
  323. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  324. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  325. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  326. package/src/testing/vitest-stubs/version.ts +5 -0
  327. package/src/testing/vitest.ts +305 -0
  328. package/src/theme/ThemeProvider.tsx +20 -58
  329. package/src/theme/ThemeScript.tsx +7 -9
  330. package/src/theme/constants.ts +52 -13
  331. package/src/theme/index.ts +0 -7
  332. package/src/theme/theme-context.ts +1 -5
  333. package/src/theme/theme-script.ts +22 -21
  334. package/src/theme/use-theme.ts +0 -3
  335. package/src/types/boundaries.ts +0 -35
  336. package/src/types/cache-types.ts +17 -8
  337. package/src/types/error-types.ts +30 -90
  338. package/src/types/global-namespace.ts +54 -41
  339. package/src/types/handler-context.ts +234 -82
  340. package/src/types/index.ts +3 -10
  341. package/src/types/loader-types.ts +44 -15
  342. package/src/types/request-scope.ts +112 -0
  343. package/src/types/route-config.ts +6 -50
  344. package/src/types/route-entry.ts +12 -7
  345. package/src/types/segments.ts +136 -15
  346. package/src/urls/include-helper.ts +33 -70
  347. package/src/urls/index.ts +1 -11
  348. package/src/urls/path-helper-types.ts +68 -18
  349. package/src/urls/path-helper.ts +57 -111
  350. package/src/urls/pattern-types.ts +48 -19
  351. package/src/urls/response-types.ts +25 -22
  352. package/src/urls/type-extraction.ts +58 -139
  353. package/src/urls/urls-function.ts +1 -19
  354. package/src/use-loader.tsx +346 -89
  355. package/src/vite/debug.ts +185 -0
  356. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  357. package/src/vite/discovery/discover-routers.ts +130 -85
  358. package/src/vite/discovery/discovery-errors.ts +194 -0
  359. package/src/vite/discovery/gate-state.ts +171 -0
  360. package/src/vite/discovery/prerender-collection.ts +214 -132
  361. package/src/vite/discovery/route-types-writer.ts +40 -84
  362. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  363. package/src/vite/discovery/state.ts +57 -4
  364. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  365. package/src/vite/index.ts +6 -0
  366. package/src/vite/inject-client-debug.ts +36 -0
  367. package/src/vite/plugin-types.ts +178 -5
  368. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  369. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  370. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  371. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  372. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  373. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  374. package/src/vite/plugins/expose-action-id.ts +48 -95
  375. package/src/vite/plugins/expose-id-utils.ts +96 -51
  376. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  377. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  378. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  379. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  380. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  381. package/src/vite/plugins/performance-tracks.ts +89 -0
  382. package/src/vite/plugins/refresh-cmd.ts +89 -27
  383. package/src/vite/plugins/use-cache-transform.ts +73 -83
  384. package/src/vite/plugins/version-injector.ts +40 -29
  385. package/src/vite/plugins/version-plugin.ts +37 -40
  386. package/src/vite/plugins/virtual-entries.ts +39 -25
  387. package/src/vite/rango.ts +119 -111
  388. package/src/vite/router-discovery.ts +941 -142
  389. package/src/vite/utils/ast-handler-extract.ts +26 -35
  390. package/src/vite/utils/banner.ts +1 -1
  391. package/src/vite/utils/bundle-analysis.ts +10 -15
  392. package/src/vite/utils/client-chunks.ts +184 -0
  393. package/src/vite/utils/directive-prologue.ts +40 -0
  394. package/src/vite/utils/forward-user-plugins.ts +171 -0
  395. package/src/vite/utils/manifest-utils.ts +4 -59
  396. package/src/vite/utils/package-resolution.ts +20 -52
  397. package/src/vite/utils/prerender-utils.ts +81 -34
  398. package/src/vite/utils/shared-utils.ts +92 -42
  399. package/src/browser/action-response-classifier.ts +0 -99
  400. package/src/browser/react/use-client-cache.ts +0 -58
  401. package/src/browser/shallow.ts +0 -40
  402. package/src/handles/index.ts +0 -7
  403. package/src/network-error-thrower.tsx +0 -23
  404. package/src/router/middleware-cookies.ts +0 -55
@@ -2,19 +2,19 @@ import type { ComponentType, ReactNode } from "react";
2
2
  import type { SerializedManifest } from "../debug.js";
3
3
  import type { ReverseFunction } from "../reverse.js";
4
4
  import type { UrlPatterns } from "../urls.js";
5
+ import type { UrlBuilder, EnvCompatible } from "../urls/pattern-types.js";
5
6
  import type { EntryData } from "../server/context";
6
7
  import type { ErrorInfo, MatchResult } from "../types";
7
8
  import type { NonceProvider } from "../rsc/types.js";
8
9
  import type { ExecutionContext } from "../server/request-context.js";
9
- import type {
10
- SerializedSegmentData,
11
- SegmentHandleData,
12
- } from "../cache/types.js";
10
+ import type { SerializedSegmentData } from "../cache/types.js";
13
11
  import type { MiddlewareEntry, MiddlewareFn } from "./middleware.js";
12
+ import type { ExtractParams } from "../types/route-config.js";
14
13
  import { RSC_ROUTER_BRAND } from "./router-registry.js";
15
- import type { RSCRouterOptions, RootLayoutProps } from "./router-options.js";
14
+ import type { RangoOptions, RootLayoutProps } from "./router-options.js";
16
15
  import type { DefaultVars } from "../types/global-namespace.js";
17
16
  import type { ResolvedTimeouts, OnTimeoutCallback } from "./timeout.js";
17
+ import type { ResolvedTracing } from "./tracing.js";
18
18
 
19
19
  /**
20
20
  * Options passed to router.fetch(), router.match(), and other request entrypoints.
@@ -48,16 +48,16 @@ type MergeRoutesWithResponses<
48
48
  };
49
49
 
50
50
  /**
51
- * Public RSC Router interface — the user-facing API surface.
51
+ * Public Rango router interface — the user-facing API surface.
52
52
  *
53
53
  * Users interact with this type when building and using routers.
54
- * Internal framework code uses RSCRouterInternal (via toInternal()) to access
54
+ * Internal framework code uses RangoInternal (via toInternal()) to access
55
55
  * matching, build-time, and configuration members that are not part of the
56
56
  * public contract.
57
57
  *
58
58
  * TRoutes accumulates all registered route types through the builder chain.
59
59
  */
60
- export interface RSCRouter<
60
+ export interface Rango<
61
61
  TEnv = any,
62
62
  TRoutes extends Record<string, unknown> = Record<string, string>,
63
63
  > {
@@ -68,23 +68,36 @@ export interface RSCRouter<
68
68
  readonly id: string;
69
69
 
70
70
  /**
71
- * Register routes using URL patterns from urls()
71
+ * URL prefix applied to all routes. Undefined when no basename is configured.
72
+ */
73
+ readonly basename: string | undefined;
74
+
75
+ /**
76
+ * Register routes using URL patterns from urls() or a builder function
72
77
  *
73
78
  * @example
74
79
  * ```typescript
75
- * createRouter({})
76
- * .routes(urlpatterns)
80
+ * // With urls()
81
+ * createRouter({}).routes(urlpatterns)
82
+ *
83
+ * // With builder function (urls() is implicit)
84
+ * createRouter({}).routes(({ path, layout }) => [
85
+ * layout(RootLayout, () => [
86
+ * path("/", HomePage),
87
+ * ]),
88
+ * ])
77
89
  * ```
78
90
  */
79
- routes<T extends UrlPatterns<TEnv, any>>(
80
- patterns: T,
81
- ): RSCRouter<
91
+ routes<T extends UrlPatterns<any, any, any>>(
92
+ patterns: T & EnvCompatible<T, TEnv>,
93
+ ): Rango<
82
94
  TEnv,
83
95
  TRoutes &
84
96
  (NonNullable<T["_routes"]> extends Record<string, unknown>
85
97
  ? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
86
98
  : Record<string, string>)
87
99
  >;
100
+ routes(builder: UrlBuilder<TEnv>): Rango<TEnv, TRoutes>;
88
101
 
89
102
  /**
90
103
  * Add global middleware that runs on all routes
@@ -94,13 +107,18 @@ export interface RSCRouter<
94
107
  * createRouter({ document: RootLayout })
95
108
  * .use(loggerMiddleware) // All routes
96
109
  * .use("/api/*", rateLimiter) // Pattern match
110
+ * .use("/users/:id", (ctx) => {}) // ctx.params.id is typed
97
111
  * .routes(urlpatterns)
98
112
  * ```
99
113
  */
114
+ use<Pattern extends string>(
115
+ pattern: Pattern,
116
+ middleware: MiddlewareFn<TEnv, ExtractParams<Pattern>>,
117
+ ): Rango<TEnv, TRoutes>;
100
118
  use(
101
119
  patternOrMiddleware: string | MiddlewareFn<TEnv>,
102
120
  middleware?: MiddlewareFn<TEnv>,
103
- ): RSCRouter<TEnv, TRoutes>;
121
+ ): Rango<TEnv, TRoutes>;
104
122
 
105
123
  /**
106
124
  * Type-safe URL builder for registered routes
@@ -127,7 +145,7 @@ export interface RSCRouter<
127
145
  * type AppRoutes = typeof _router.routeMap;
128
146
  *
129
147
  * declare global {
130
- * namespace RSCRouter {
148
+ * namespace Rango {
131
149
  * interface RegisteredRoutes extends AppRoutes {}
132
150
  * }
133
151
  * }
@@ -163,16 +181,16 @@ export interface RSCRouter<
163
181
  }
164
182
 
165
183
  /**
166
- * Internal RSC Router interface — the full framework-facing API.
184
+ * Internal Rango router interface — the full framework-facing API.
167
185
  *
168
186
  * This type includes all members used by the Vite plugin, RSC handler,
169
187
  * pre-rendering pipeline, and other framework internals. It is NOT exported
170
188
  * from the public package API.
171
189
  *
172
- * Use toInternal(router) to assert a public RSCRouter into this type
190
+ * Use toInternal(router) to assert a public Rango into this type
173
191
  * at the boundary where framework code receives a user-provided router.
174
192
  */
175
- export interface RSCRouterInternal<
193
+ export interface RangoInternal<
176
194
  TEnv = any,
177
195
  TRoutes extends Record<string, unknown> = Record<string, string>,
178
196
  > {
@@ -188,26 +206,40 @@ export interface RSCRouterInternal<
188
206
  */
189
207
  readonly id: string;
190
208
 
209
+ /** URL prefix applied to all routes. */
210
+ readonly basename: string | undefined;
211
+
191
212
  /**
192
- * Register routes using URL patterns from urls()
193
- */
194
- routes<T extends UrlPatterns<TEnv, any>>(
195
- patterns: T,
196
- ): RSCRouter<
213
+ * Register routes using URL patterns from urls() or a builder function.
214
+ *
215
+ * Env compatibility is checked by EnvCompatible: an env-agnostic urls() block
216
+ * (its env is `unknown` — e.g. a shared module, or an app that does not augment
217
+ * `Rango.Env`) attaches to any router, while a urls<TEnv>() block carrying a
218
+ * concrete env is accepted only when this router's `TEnv` satisfies it. So a
219
+ * `urls<{ DB }>()` cannot be mounted on a `createRouter<{}>()`.
220
+ */
221
+ routes<T extends UrlPatterns<any, any, any>>(
222
+ patterns: T & EnvCompatible<T, TEnv>,
223
+ ): Rango<
197
224
  TEnv,
198
225
  TRoutes &
199
226
  (NonNullable<T["_routes"]> extends Record<string, unknown>
200
227
  ? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
201
228
  : Record<string, string>)
202
229
  >;
230
+ routes(builder: UrlBuilder<TEnv>): Rango<TEnv, TRoutes>;
203
231
 
204
232
  /**
205
233
  * Add global middleware that runs on all routes
206
234
  */
235
+ use<Pattern extends string>(
236
+ pattern: Pattern,
237
+ middleware: MiddlewareFn<TEnv, ExtractParams<Pattern>>,
238
+ ): Rango<TEnv, TRoutes>;
207
239
  use(
208
240
  patternOrMiddleware: string | MiddlewareFn<TEnv>,
209
241
  middleware?: MiddlewareFn<TEnv>,
210
- ): RSCRouter<TEnv, TRoutes>;
242
+ ): Rango<TEnv, TRoutes>;
211
243
 
212
244
  /**
213
245
  * Type-safe URL builder for registered routes
@@ -229,17 +261,17 @@ export interface RSCRouterInternal<
229
261
  * Error callback for monitoring/alerting
230
262
  * Called when errors occur in loaders, actions, or routes
231
263
  */
232
- readonly onError?: RSCRouterOptions<TEnv>["onError"];
264
+ readonly onError?: RangoOptions<TEnv>["onError"];
233
265
 
234
266
  /**
235
267
  * Cache configuration
236
268
  */
237
- readonly cache?: RSCRouterOptions<TEnv>["cache"];
269
+ readonly cache?: RangoOptions<TEnv>["cache"];
238
270
 
239
271
  /**
240
272
  * Not found component to render when no route matches
241
273
  */
242
- readonly notFound?: RSCRouterOptions<TEnv>["notFound"];
274
+ readonly notFound?: RangoOptions<TEnv>["notFound"];
243
275
 
244
276
  /**
245
277
  * Resolved theme configuration (null if theme not enabled)
@@ -269,6 +301,27 @@ export interface RSCRouterInternal<
269
301
  */
270
302
  readonly prefetchCacheTTL: number;
271
303
 
304
+ /**
305
+ * Maximum number of decoded prefetch payloads the client keeps in its
306
+ * in-memory prefetch cache (FIFO eviction at capacity). Shipped to the
307
+ * client in payload metadata. Derived from prefetchCacheSize.
308
+ */
309
+ readonly prefetchCacheSize: number;
310
+
311
+ /**
312
+ * Maximum number of speculative prefetch requests the client runs
313
+ * concurrently. Shipped to the client in payload metadata. Derived from
314
+ * prefetchConcurrency.
315
+ */
316
+ readonly prefetchConcurrency: number;
317
+
318
+ /**
319
+ * Resolved rango state cookie name (`{prefix}_{routerId}`), composed once at
320
+ * router init and shipped to the client in payload metadata. The server-side
321
+ * cookie writer reads it from here; the client reads it from metadata.
322
+ */
323
+ readonly resolvedStateCookieName: string;
324
+
272
325
  /**
273
326
  * Whether connection warmup is enabled.
274
327
  * When true, the client sends HEAD /?_rsc_warmup after idle periods
@@ -276,12 +329,26 @@ export interface RSCRouterInternal<
276
329
  */
277
330
  readonly warmupEnabled: boolean;
278
331
 
332
+ /**
333
+ * Whether the client hydrates inside React.StrictMode. Resolved from
334
+ * createRouter({ strictMode }) (default true) and shipped to the client in
335
+ * the initial payload metadata.
336
+ */
337
+ readonly strictMode: boolean;
338
+
279
339
  /**
280
340
  * Whether router-wide performance debugging is enabled.
281
341
  * Used by the request handler to create metrics before middleware runs.
282
342
  */
283
343
  readonly debugPerformance?: boolean;
284
344
 
345
+ /**
346
+ * Resolved platform phase-span tracing (Cloudflare custom spans or OTel), or
347
+ * undefined when off. Threaded onto the request context and read at each
348
+ * traced phase.
349
+ */
350
+ readonly tracing?: ResolvedTracing;
351
+
285
352
  /**
286
353
  * Whether ?__debug_manifest is allowed in production.
287
354
  * Always enabled in development.
@@ -338,6 +405,20 @@ export interface RSCRouterInternal<
338
405
  */
339
406
  readonly __sourceFile?: string;
340
407
 
408
+ /** @internal basename for runtime manifest generation */
409
+ readonly __basename?: string;
410
+
411
+ /**
412
+ * @internal Router-level error/notFound fallbacks (`createRouter` options),
413
+ * exposed for the build-time clientChunks discovery so a `"use client"`
414
+ * default boundary is routed into the dedicated `app-fallback` chunk. Unlike
415
+ * the route-tree `errorBoundary()`/`notFoundBoundary()` helpers these never
416
+ * land in `EntryData`, so they are read directly off the router instance.
417
+ */
418
+ readonly __defaultErrorBoundary?: RangoOptions<TEnv>["defaultErrorBoundary"];
419
+ readonly __defaultNotFoundBoundary?: RangoOptions<TEnv>["defaultNotFoundBoundary"];
420
+ readonly __notFound?: RangoOptions<TEnv>["notFound"];
421
+
341
422
  match(
342
423
  request: Request,
343
424
  input?: RouterRequestInput<TEnv>,
@@ -353,13 +434,17 @@ export interface RSCRouterInternal<
353
434
  params: Record<string, string>,
354
435
  buildVars?: Record<string, any>,
355
436
  isPassthroughRoute?: boolean,
437
+ buildEnv?: any,
438
+ devMode?: boolean,
356
439
  ): Promise<{
357
440
  segments: SerializedSegmentData[];
358
- handles: Record<string, SegmentHandleData>;
441
+ /** RSC-encoded handle map ("" when none) — see handle-snapshot.ts. */
442
+ handles: string;
359
443
  routeName: string;
360
444
  params: Record<string, string>;
361
445
  interceptSegments?: SerializedSegmentData[];
362
- interceptHandles?: Record<string, SegmentHandleData>;
446
+ /** RSC-encoded MERGED (main + intercept) handle map for the intercept artifact. */
447
+ interceptHandles?: string;
363
448
  passthrough?: true;
364
449
  } | null>;
365
450
 
@@ -371,7 +456,9 @@ export interface RSCRouterInternal<
371
456
  handler: Function,
372
457
  handlerId: string,
373
458
  routeName?: string,
374
- ): Promise<{ encoded: string; handles: Record<string, unknown[]> } | null>;
459
+ buildEnv?: any,
460
+ devMode?: boolean,
461
+ ): Promise<{ encoded: string; handles: string } | null>;
375
462
 
376
463
  /**
377
464
  * Preview match - returns route middleware without segment resolution.
@@ -424,6 +511,13 @@ export interface RSCRouterInternal<
424
511
  segmentType?: ErrorInfo["segmentType"],
425
512
  ): Promise<MatchResult | null>;
426
513
 
514
+ /**
515
+ * Low-level route matching function.
516
+ * Used by classifyRequest() for request classification without
517
+ * entering the full match pipeline.
518
+ */
519
+ findMatch(pathname: string, metricsStore?: any): any;
520
+
427
521
  /**
428
522
  * Debug utility to serialize the manifest for inspection
429
523
  * Returns a JSON-friendly representation of all routes and layouts
@@ -437,16 +531,16 @@ export interface RSCRouterInternal<
437
531
  }
438
532
 
439
533
  /**
440
- * Assert a public RSCRouter into the internal type.
534
+ * Assert a public Rango into the internal type.
441
535
  *
442
536
  * Use this at the boundary where framework code receives a user-provided
443
537
  * router and needs access to internal members (match, config, build-time).
444
538
  * The cast is safe because createRouter() always produces an object that
445
- * satisfies RSCRouterInternal; the public type is just a narrower view.
539
+ * satisfies RangoInternal; the public type is just a narrower view.
446
540
  */
447
541
  export function toInternal<
448
542
  TEnv = any,
449
543
  TRoutes extends Record<string, unknown> = Record<string, string>,
450
- >(router: RSCRouter<TEnv, TRoutes>): RSCRouterInternal<TEnv, TRoutes> {
451
- return router as RSCRouterInternal<TEnv, TRoutes>;
544
+ >(router: Rango<TEnv, TRoutes>): RangoInternal<TEnv, TRoutes> {
545
+ return router as RangoInternal<TEnv, TRoutes>;
452
546
  }
@@ -8,8 +8,10 @@ import type {
8
8
  import type { NonceProvider } from "../rsc/types.js";
9
9
  import type { ExecutionContext } from "../server/request-context.js";
10
10
  import type { UrlPatterns } from "../urls.js";
11
+ import type { UrlBuilder } from "../urls/pattern-types.js";
11
12
  import type { NamedRouteEntry } from "./content-negotiation.js";
12
13
  import type { TelemetrySink } from "./telemetry.js";
14
+ import type { RouterTracingConfig } from "./tracing.js";
13
15
  import type { RouterTimeouts, OnTimeoutCallback } from "./timeout.js";
14
16
 
15
17
  /**
@@ -72,7 +74,7 @@ export interface RootLayoutProps {
72
74
  /**
73
75
  * Router configuration options
74
76
  */
75
- export interface RSCRouterOptions<TEnv = any> {
77
+ export interface RangoOptions<TEnv = any> {
76
78
  /**
77
79
  * Unique identifier for this router instance.
78
80
  * Used to namespace static output files and route maps.
@@ -95,6 +97,28 @@ export interface RSCRouterOptions<TEnv = any> {
95
97
  */
96
98
  $$sourceFile?: string;
97
99
 
100
+ /**
101
+ * URL prefix applied to all routes registered with this router.
102
+ *
103
+ * Useful when the app is served under a sub-path (e.g. `/admin` or `/v2`).
104
+ * All `path()` patterns are automatically prefixed and `reverse()` returns
105
+ * full paths including the basename. Route names are NOT prefixed.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const router = createRouter({
110
+ * basename: "/admin",
111
+ * }).routes(({ path }) => [
112
+ * path("/", Dashboard, { name: "home" }), // matches /admin
113
+ * path("/users", Users, { name: "users" }), // matches /admin/users
114
+ * ]);
115
+ *
116
+ * router.reverse("home"); // "/admin"
117
+ * router.reverse("users"); // "/admin/users"
118
+ * ```
119
+ */
120
+ basename?: string;
121
+
98
122
  /**
99
123
  * Enable performance metrics collection
100
124
  * When enabled, metrics are output to console and available via Server-Timing header
@@ -109,6 +133,21 @@ export interface RSCRouterOptions<TEnv = any> {
109
133
  */
110
134
  allowDebugManifest?: boolean;
111
135
 
136
+ /**
137
+ * DEVELOPMENT/TEST ONLY. Emit an `X-Rango-Cache` response header describing
138
+ * the cache status of the matched route, for use by testing primitives such
139
+ * as `assertCacheStatus`.
140
+ *
141
+ * Defaults to `false`. When neither this option nor the
142
+ * `RANGO_TEST_SIGNALS=1` environment flag is set, NO header is emitted and
143
+ * router output is byte-identical to the default.
144
+ *
145
+ * The header encodes per-segment (v1: coarse route-level) status keyed by the
146
+ * route NAME, e.g. `X-Rango-Cache: product.detail=hit`. Do NOT enable in
147
+ * production — it exposes internal cache decisions.
148
+ */
149
+ debugCacheSignal?: boolean;
150
+
112
151
  /**
113
152
  * Document component that wraps the entire application.
114
153
  *
@@ -335,27 +374,54 @@ export interface RSCRouterOptions<TEnv = any> {
335
374
  theme?: import("../theme/types.js").ThemeConfig | true;
336
375
 
337
376
  /**
338
- * URL patterns to register with the router.
377
+ * Default for whether the router wraps `transition()` segments in its own
378
+ * React `<ViewTransition>` boundary (experimental React only).
339
379
  *
340
- * Alternative to calling `.routes()` method - allows passing patterns
341
- * directly in the config for a more concise setup.
380
+ * - "auto" (default): every route/layout that opts in via `transition()`
381
+ * gets a router-owned cross-fade.
382
+ * - false: the router never places its own boundary. Routes that use
383
+ * `transition()` still drive navigation through startTransition (so loaders
384
+ * hold instead of flashing a skeleton) and still let consumer-placed
385
+ * `<ViewTransition>` elements animate — the router just contributes no
386
+ * cross-fade of its own. This is the "router triggers, you place the
387
+ * transitions" model.
388
+ *
389
+ * A per-segment `transition({ viewTransition })` overrides this default.
342
390
  *
343
391
  * @example
344
392
  * ```typescript
345
- * import { urls } from "@rangojs/router/server";
393
+ * // App-wide: drive + hold, but never auto-wrap. Place <ViewTransition>
394
+ * // yourself in components where you want a morph.
395
+ * const router = createRouter<AppEnv>({ viewTransition: false });
396
+ * ```
397
+ */
398
+ viewTransition?: "auto" | false;
399
+
400
+ /**
401
+ * URL patterns to register with the router.
346
402
  *
347
- * const urlpatterns = urls(({ path, layout }) => [
348
- * path("/", HomePage, { name: "home" }),
349
- * path("/about", AboutPage, { name: "about" }),
350
- * ]);
403
+ * Accepts either a `UrlPatterns` object from `urls()` or a builder function
404
+ * directly (urls() is called implicitly).
351
405
  *
352
- * const router = createRouter<AppEnv>({
406
+ * @example
407
+ * ```typescript
408
+ * // With urls()
409
+ * createRouter<AppEnv>({
353
410
  * document: Document,
354
411
  * urls: urlpatterns,
355
412
  * });
413
+ *
414
+ * // With builder function
415
+ * createRouter<AppEnv>({
416
+ * document: Document,
417
+ * urls: ({ path }) => [
418
+ * path("/", HomePage, { name: "home" }),
419
+ * path("/about", AboutPage, { name: "about" }),
420
+ * ],
421
+ * });
356
422
  * ```
357
423
  */
358
- urls?: UrlPatterns<TEnv, any>;
424
+ urls?: UrlPatterns<TEnv, any> | UrlBuilder<TEnv>;
359
425
 
360
426
  /**
361
427
  * Injected by the Vite transform at compile time.
@@ -431,6 +497,51 @@ export interface RSCRouterOptions<TEnv = any> {
431
497
  */
432
498
  prefetchCacheTTL?: number | false;
433
499
 
500
+ /**
501
+ * Maximum number of decoded prefetch payloads the client keeps in its
502
+ * in-memory prefetch cache. When the cache is full the oldest entry is
503
+ * evicted (FIFO) to make room for a new prefetch.
504
+ *
505
+ * Each entry retains a fully decoded RSC payload (and the route's client
506
+ * chunks pulled in while decoding), so this is the lever on client-side
507
+ * prefetch memory: a higher value warms more routes at the cost of more
508
+ * retained payloads. Staleness is bounded separately by `prefetchCacheTTL`;
509
+ * this bounds the entry COUNT.
510
+ *
511
+ * Values below 1 (or non-finite) fall back to the default. To turn
512
+ * prefetching off entirely, set `prefetchCacheTTL: false` instead.
513
+ *
514
+ * @default 100
515
+ */
516
+ prefetchCacheSize?: number;
517
+
518
+ /**
519
+ * Maximum number of speculative prefetch requests (viewport/render strategy)
520
+ * the client runs concurrently. Hover prefetches bypass this queue and fire
521
+ * immediately; this caps only the background, idle-gated queue so prefetches
522
+ * never saturate the browser's connection pool.
523
+ *
524
+ * Values below 1 (or non-finite) fall back to the default.
525
+ *
526
+ * @default 2
527
+ */
528
+ prefetchConcurrency?: number;
529
+
530
+ /**
531
+ * Prefix for the rango state cookie name. The resolved name is
532
+ * `{prefix}_{routerId}`; the prefix is sanitized to cookie-name-safe
533
+ * characters (`[A-Za-z0-9-]`) and an empty result falls back to the default.
534
+ *
535
+ * The rango state cookie keys the client's prefetch / HTTP caches. Overriding
536
+ * the prefix lets you align it with cookie-naming policies or consent-manager
537
+ * classification lists, or avoid colliding with an existing `rango-state`
538
+ * cookie. It is not a full-name override: the `_{routerId}` suffix is what
539
+ * keeps sibling apps on one origin from clobbering each other's state.
540
+ *
541
+ * @default "rango-state"
542
+ */
543
+ stateCookiePrefix?: string;
544
+
434
545
  /**
435
546
  * Enable connection warmup to keep TCP+TLS alive after idle periods.
436
547
  *
@@ -442,6 +553,29 @@ export interface RSCRouterOptions<TEnv = any> {
442
553
  */
443
554
  warmup?: boolean;
444
555
 
556
+ /**
557
+ * Wrap the hydrated client tree in `React.StrictMode`.
558
+ *
559
+ * The Rango browser entry hydrates the app inside `<React.StrictMode>` by
560
+ * default. StrictMode double-invokes render and (in development) mounts,
561
+ * unmounts, then remounts every effect to surface impure renders and missing
562
+ * effect cleanup. Production builds treat StrictMode as a no-op, so this flag
563
+ * only changes development behavior in a normal app.
564
+ *
565
+ * Set to `false` to hydrate without the StrictMode wrapper. The main reason to
566
+ * opt out is to isolate StrictMode's intentional double-render/double-effect
567
+ * from genuine re-renders when measuring client-hook stability — with
568
+ * StrictMode off, render counts are exact in development too.
569
+ *
570
+ * The value is resolved server-side at router creation and shipped to the
571
+ * client in the initial payload metadata; the browser entry reads it once at
572
+ * hydration. Changing it does not affect the SSR HTML (StrictMode emits no
573
+ * DOM), so toggling it never causes a hydration mismatch.
574
+ *
575
+ * @default true
576
+ */
577
+ strictMode?: boolean;
578
+
445
579
  /**
446
580
  * Shorthand timeout (ms) applied to both action execution and render start.
447
581
  * Does NOT apply to streamIdleMs.
@@ -494,11 +628,14 @@ export interface RSCRouterOptions<TEnv = any> {
494
628
  onTimeout?: OnTimeoutCallback<TEnv>;
495
629
 
496
630
  /**
497
- * Telemetry sink for structured lifecycle events.
631
+ * Telemetry sink for structured, discrete lifecycle EVENTS: request
632
+ * start/end/error, loader start/end/error, handler errors, cache decisions,
633
+ * revalidation decisions, timeouts, origin rejections.
498
634
  *
499
- * When provided, the router emits events for request start/end,
500
- * loader start/end/error, handler errors, cache decisions, and
501
- * revalidation decisions.
635
+ * This is the EVENT surface. Phase-duration SPANS (request/middleware/action/
636
+ * handler/loader/render/ssr timing wired into a tracing backend) come from the
637
+ * separate `tracing` option below — a sink does not emit them, because async-context nesting
638
+ * cannot be faithfully reconstructed from after-the-fact start/end events.
502
639
  *
503
640
  * No-op when not configured (zero overhead).
504
641
  *
@@ -511,6 +648,18 @@ export interface RSCRouterOptions<TEnv = any> {
511
648
  * });
512
649
  * ```
513
650
  *
651
+ * @example OpenTelemetry — pair the event sink with the tracing slot
652
+ * ```typescript
653
+ * import { createOTelTracing, createOTelSink } from "@rangojs/router";
654
+ * import { trace } from "@opentelemetry/api";
655
+ *
656
+ * const tracer = trace.getTracer("my-app");
657
+ * const router = createRouter({
658
+ * tracing: createOTelTracing(tracer), // phase spans
659
+ * telemetry: createOTelSink(tracer), // discrete-fact events
660
+ * });
661
+ * ```
662
+ *
514
663
  * @example Custom sink
515
664
  * ```typescript
516
665
  * const router = createRouter({
@@ -524,6 +673,44 @@ export interface RSCRouterOptions<TEnv = any> {
524
673
  */
525
674
  telemetry?: TelemetrySink;
526
675
 
676
+ /**
677
+ * Span tracing for the router's performance phases (request, middleware, action,
678
+ * loaders, render, ssr). Connects the same phases shown in the
679
+ * `debugPerformance` timeline to the host platform's tracing system. This is
680
+ * the SPAN surface (the `telemetry` option above is the event surface).
681
+ *
682
+ * Two factories produce a config, both for this slot:
683
+ * - `createOTelTracing(tracer)` from `@rangojs/router` — any platform with an
684
+ * OpenTelemetry SDK (including Node). Bridges the phases onto
685
+ * `tracer.startActiveSpan`.
686
+ * - `createCloudflareTracing()` from `@rangojs/router/cloudflare` — Cloudflare
687
+ * Workers native custom spans, alongside the automatic KV/D1/fetch spans.
688
+ *
689
+ * When tracing is unset — or off-platform (no OTel SDK / no Cloudflare tracing
690
+ * destination) — every span call falls through to the work directly, so the
691
+ * request behaves exactly as if tracing were off.
692
+ *
693
+ * @example OpenTelemetry
694
+ * ```typescript
695
+ * import { createOTelTracing } from "@rangojs/router";
696
+ * import { trace } from "@opentelemetry/api";
697
+ *
698
+ * const router = createRouter({
699
+ * tracing: createOTelTracing(trace.getTracer("my-app")),
700
+ * });
701
+ * ```
702
+ *
703
+ * @example Cloudflare
704
+ * ```typescript
705
+ * import { createCloudflareTracing } from "@rangojs/router/cloudflare";
706
+ *
707
+ * const router = createRouter({
708
+ * tracing: createCloudflareTracing({ spans: { ssr: false } }),
709
+ * });
710
+ * ```
711
+ */
712
+ tracing?: RouterTracingConfig;
713
+
527
714
  /**
528
715
  * SSR configuration options.
529
716
  *
@@ -1,4 +1,4 @@
1
- import type { RSCRouterInternal } from "./router-interfaces.js";
1
+ import type { RangoInternal } from "./router-interfaces.js";
2
2
 
3
3
  /**
4
4
  * Brand marker for identifying router instances at build time.
@@ -12,10 +12,7 @@ export const RSC_ROUTER_BRAND = "__rsc_router__" as const;
12
12
  * Used by the Vite plugin at build time to discover routers and extract
13
13
  * manifests, prefix trees, and pre-render candidates.
14
14
  */
15
- export const RouterRegistry: Map<
16
- string,
17
- RSCRouterInternal<any, any>
18
- > = new Map();
15
+ export const RouterRegistry: Map<string, RangoInternal<any, any>> = new Map();
19
16
 
20
17
  export let routerAutoId = 0;
21
18