@rangojs/router 0.0.0-experimental.19 → 0.0.0-experimental.1c0bdfad

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 (406) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +291 -61
  3. package/dist/bin/rango.js +544 -143
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3744 -1329
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +67 -13
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +312 -0
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +247 -23
  12. package/skills/caching/SKILL.md +322 -19
  13. package/skills/composability/SKILL.md +27 -2
  14. package/skills/css/SKILL.md +76 -0
  15. package/skills/debug-manifest/SKILL.md +4 -2
  16. package/skills/document-cache/SKILL.md +78 -55
  17. package/skills/handler-use/SKILL.md +364 -0
  18. package/skills/hooks/SKILL.md +282 -60
  19. package/skills/host-router/SKILL.md +278 -0
  20. package/skills/i18n/SKILL.md +276 -0
  21. package/skills/intercept/SKILL.md +50 -6
  22. package/skills/layout/SKILL.md +35 -9
  23. package/skills/links/SKILL.md +249 -17
  24. package/skills/loader/SKILL.md +297 -31
  25. package/skills/middleware/SKILL.md +52 -13
  26. package/skills/migrate-nextjs/SKILL.md +584 -0
  27. package/skills/migrate-react-router/SKILL.md +771 -0
  28. package/skills/mime-routes/SKILL.md +28 -1
  29. package/skills/observability/SKILL.md +172 -0
  30. package/skills/parallel/SKILL.md +203 -7
  31. package/skills/prerender/SKILL.md +155 -111
  32. package/skills/rango/SKILL.md +251 -23
  33. package/skills/react-compiler/SKILL.md +168 -0
  34. package/skills/response-routes/SKILL.md +123 -48
  35. package/skills/route/SKILL.md +104 -9
  36. package/skills/router-setup/SKILL.md +124 -11
  37. package/skills/scripts/SKILL.md +179 -0
  38. package/skills/server-actions/SKILL.md +775 -0
  39. package/skills/streams-and-websockets/SKILL.md +283 -0
  40. package/skills/tailwind/SKILL.md +27 -3
  41. package/skills/testing/SKILL.md +125 -222
  42. package/skills/testing/bindings.md +103 -0
  43. package/skills/testing/cache-prerender.md +127 -0
  44. package/skills/testing/client-components.md +124 -0
  45. package/skills/testing/e2e-parity.md +125 -0
  46. package/skills/testing/flight.md +91 -0
  47. package/skills/testing/handles.md +129 -0
  48. package/skills/testing/loader.md +128 -0
  49. package/skills/testing/middleware.md +99 -0
  50. package/skills/testing/render-handler.md +121 -0
  51. package/skills/testing/response-routes.md +95 -0
  52. package/skills/testing/reverse-and-types.md +84 -0
  53. package/skills/testing/server-actions.md +107 -0
  54. package/skills/testing/server-tree.md +128 -0
  55. package/skills/testing/setup.md +123 -0
  56. package/skills/typesafety/SKILL.md +357 -52
  57. package/skills/use-cache/SKILL.md +46 -14
  58. package/skills/view-transitions/SKILL.md +294 -0
  59. package/src/__augment-tests__/augment.ts +81 -0
  60. package/src/__augment-tests__/augmented.check.ts +116 -0
  61. package/src/__internal.ts +67 -40
  62. package/src/bin/rango.ts +18 -0
  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 +197 -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/link-interceptor.ts +4 -0
  74. package/src/browser/navigation-bridge.ts +200 -30
  75. package/src/browser/navigation-client.ts +217 -58
  76. package/src/browser/navigation-store-handle.ts +38 -0
  77. package/src/browser/navigation-store.ts +76 -67
  78. package/src/browser/navigation-transaction.ts +18 -66
  79. package/src/browser/network-error-handler.ts +34 -7
  80. package/src/browser/partial-update.ts +187 -112
  81. package/src/browser/prefetch/cache.ts +312 -30
  82. package/src/browser/prefetch/fetch.ts +344 -47
  83. package/src/browser/prefetch/policy.ts +6 -0
  84. package/src/browser/prefetch/queue.ts +126 -20
  85. package/src/browser/prefetch/resource-ready.ts +77 -0
  86. package/src/browser/rango-state.ts +158 -76
  87. package/src/browser/react/Link.tsx +125 -18
  88. package/src/browser/react/NavigationProvider.tsx +135 -120
  89. package/src/browser/react/ScrollRestoration.tsx +10 -6
  90. package/src/browser/react/context.ts +7 -2
  91. package/src/browser/react/filter-segment-order.ts +66 -7
  92. package/src/browser/react/index.ts +0 -48
  93. package/src/browser/react/location-state-shared.ts +178 -8
  94. package/src/browser/react/location-state.ts +39 -14
  95. package/src/browser/react/use-action.ts +6 -15
  96. package/src/browser/react/use-handle.ts +23 -69
  97. package/src/browser/react/use-href.tsx +8 -1
  98. package/src/browser/react/use-link-status.ts +33 -8
  99. package/src/browser/react/use-navigation.ts +32 -7
  100. package/src/browser/react/use-params.ts +20 -10
  101. package/src/browser/react/use-reverse.ts +106 -0
  102. package/src/browser/react/use-router.ts +46 -11
  103. package/src/browser/react/use-search-params.ts +0 -5
  104. package/src/browser/react/use-segments.ts +11 -21
  105. package/src/browser/response-adapter.ts +80 -5
  106. package/src/browser/rsc-router.tsx +226 -75
  107. package/src/browser/scroll-restoration.ts +54 -42
  108. package/src/browser/segment-reconciler.ts +36 -9
  109. package/src/browser/segment-structure-assert.ts +2 -2
  110. package/src/browser/server-action-bridge.ts +619 -442
  111. package/src/browser/types.ts +115 -11
  112. package/src/browser/validate-redirect-origin.ts +43 -16
  113. package/src/build/collect-fallback-refs.ts +107 -0
  114. package/src/build/generate-manifest.ts +65 -40
  115. package/src/build/generate-route-types.ts +7 -1
  116. package/src/build/index.ts +8 -2
  117. package/src/build/prefix-tree-utils.ts +123 -0
  118. package/src/build/route-trie.ts +182 -37
  119. package/src/build/route-types/ast-route-extraction.ts +15 -8
  120. package/src/build/route-types/codegen.ts +16 -5
  121. package/src/build/route-types/include-resolution.ts +125 -24
  122. package/src/build/route-types/param-extraction.ts +6 -3
  123. package/src/build/route-types/per-module-writer.ts +22 -6
  124. package/src/build/route-types/router-processing.ts +392 -106
  125. package/src/build/route-types/scan-filter.ts +9 -2
  126. package/src/build/route-types/source-scan.ts +216 -0
  127. package/src/build/runtime-discovery.ts +9 -20
  128. package/src/cache/cache-error.ts +104 -0
  129. package/src/cache/cache-key-utils.ts +29 -13
  130. package/src/cache/cache-policy.ts +108 -34
  131. package/src/cache/cache-runtime.ts +214 -48
  132. package/src/cache/cache-scope.ts +236 -89
  133. package/src/cache/cache-tag.ts +103 -0
  134. package/src/cache/cf/cf-base64.ts +33 -0
  135. package/src/cache/cf/cf-cache-constants.ts +127 -0
  136. package/src/cache/cf/cf-cache-store.ts +2224 -171
  137. package/src/cache/cf/cf-cache-types.ts +349 -0
  138. package/src/cache/cf/cf-kv-utils.ts +46 -0
  139. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  140. package/src/cache/cf/index.ts +11 -17
  141. package/src/cache/document-cache.ts +89 -27
  142. package/src/cache/handle-snapshot.ts +70 -0
  143. package/src/cache/index.ts +11 -20
  144. package/src/cache/memory-segment-store.ts +136 -37
  145. package/src/cache/profile-registry.ts +31 -31
  146. package/src/cache/read-through-swr.ts +41 -11
  147. package/src/cache/segment-codec.ts +9 -17
  148. package/src/cache/tag-invalidation.ts +230 -0
  149. package/src/cache/taint.ts +55 -0
  150. package/src/cache/types.ts +37 -100
  151. package/src/client.rsc.tsx +45 -21
  152. package/src/client.tsx +120 -336
  153. package/src/cloudflare/index.ts +11 -0
  154. package/src/cloudflare/tracing.ts +109 -0
  155. package/src/component-utils.ts +19 -0
  156. package/src/components/DefaultDocument.tsx +8 -2
  157. package/src/context-var.ts +84 -2
  158. package/src/debug.ts +2 -2
  159. package/src/decode-loader-results.ts +52 -0
  160. package/src/defer.ts +196 -0
  161. package/src/deps/ssr.ts +0 -1
  162. package/src/encode-kv.ts +49 -0
  163. package/src/errors.ts +30 -4
  164. package/src/escape-script.ts +52 -0
  165. package/src/handle.ts +70 -22
  166. package/src/handles/MetaTags.tsx +56 -19
  167. package/src/handles/Scripts.tsx +183 -0
  168. package/src/handles/breadcrumbs.ts +95 -0
  169. package/src/handles/is-thenable.ts +19 -0
  170. package/src/handles/meta.ts +51 -40
  171. package/src/handles/script.ts +244 -0
  172. package/src/host/cookie-handler.ts +9 -60
  173. package/src/host/errors.ts +0 -24
  174. package/src/host/index.ts +8 -5
  175. package/src/host/pattern-matcher.ts +23 -52
  176. package/src/host/router.ts +107 -99
  177. package/src/host/testing.ts +40 -27
  178. package/src/host/types.ts +37 -4
  179. package/src/host/utils.ts +1 -1
  180. package/src/href-client.ts +137 -22
  181. package/src/index.rsc.ts +79 -29
  182. package/src/index.ts +149 -65
  183. package/src/internal-debug.ts +11 -10
  184. package/src/loader-store.ts +500 -0
  185. package/src/loader.rsc.ts +20 -13
  186. package/src/loader.ts +12 -11
  187. package/src/missing-id-error.ts +68 -0
  188. package/src/outlet-context.ts +1 -1
  189. package/src/outlet-provider.tsx +1 -5
  190. package/src/prerender/param-hash.ts +16 -16
  191. package/src/prerender/store.ts +63 -26
  192. package/src/prerender.ts +198 -82
  193. package/src/redirect-origin.ts +100 -0
  194. package/src/regex-escape.ts +8 -0
  195. package/src/render-error-thrower.tsx +20 -0
  196. package/src/response-utils.ts +62 -0
  197. package/src/reverse.ts +65 -15
  198. package/src/root-error-boundary.tsx +1 -19
  199. package/src/route-content-wrapper.tsx +7 -72
  200. package/src/route-definition/dsl-helpers.ts +469 -276
  201. package/src/route-definition/helper-factories.ts +29 -139
  202. package/src/route-definition/helpers-types.ts +113 -37
  203. package/src/route-definition/index.ts +3 -3
  204. package/src/route-definition/redirect.ts +53 -12
  205. package/src/route-definition/resolve-handler-use.ts +161 -0
  206. package/src/route-definition/use-item-types.ts +32 -0
  207. package/src/route-map-builder.ts +7 -17
  208. package/src/route-types.ts +37 -41
  209. package/src/router/basename.ts +14 -0
  210. package/src/router/content-negotiation.ts +164 -17
  211. package/src/router/error-handling.ts +45 -18
  212. package/src/router/find-match.ts +45 -22
  213. package/src/router/handler-context.ts +110 -39
  214. package/src/router/instrument.ts +350 -0
  215. package/src/router/intercept-resolution.ts +50 -24
  216. package/src/router/lazy-includes.ts +19 -53
  217. package/src/router/loader-resolution.ts +274 -56
  218. package/src/router/logging.ts +5 -8
  219. package/src/router/manifest.ts +49 -45
  220. package/src/router/match-api.ts +121 -205
  221. package/src/router/match-context.ts +0 -22
  222. package/src/router/match-handlers.ts +58 -58
  223. package/src/router/match-middleware/background-revalidation.ts +33 -6
  224. package/src/router/match-middleware/cache-lookup.ts +214 -263
  225. package/src/router/match-middleware/cache-store.ts +73 -33
  226. package/src/router/match-middleware/intercept-resolution.ts +8 -28
  227. package/src/router/match-middleware/segment-resolution.ts +52 -18
  228. package/src/router/match-pipelines.ts +1 -42
  229. package/src/router/match-result.ts +104 -49
  230. package/src/router/metrics.ts +217 -26
  231. package/src/router/middleware-types.ts +24 -110
  232. package/src/router/middleware.ts +384 -197
  233. package/src/router/navigation-snapshot.ts +131 -0
  234. package/src/router/params-util.ts +23 -0
  235. package/src/router/pattern-matching.ts +148 -91
  236. package/src/router/prefetch-cache-ttl.ts +51 -0
  237. package/src/router/prerender-match.ts +199 -56
  238. package/src/router/preview-match.ts +32 -102
  239. package/src/router/request-classification.ts +276 -0
  240. package/src/router/revalidation.ts +144 -74
  241. package/src/router/route-snapshot.ts +244 -0
  242. package/src/router/router-context.ts +8 -28
  243. package/src/router/router-interfaces.ts +129 -36
  244. package/src/router/router-options.ts +185 -23
  245. package/src/router/router-registry.ts +2 -5
  246. package/src/router/segment-resolution/fresh.ts +281 -76
  247. package/src/router/segment-resolution/helpers.ts +116 -31
  248. package/src/router/segment-resolution/loader-cache.ts +63 -37
  249. package/src/router/segment-resolution/revalidation.ts +493 -391
  250. package/src/router/segment-resolution/static-store.ts +19 -5
  251. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  252. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  253. package/src/router/segment-resolution.ts +5 -1
  254. package/src/router/segment-wrappers.ts +8 -5
  255. package/src/router/state-cookie-name.ts +33 -0
  256. package/src/router/substitute-pattern-params.ts +56 -0
  257. package/src/router/telemetry-otel.ts +161 -199
  258. package/src/router/telemetry.ts +96 -19
  259. package/src/router/timeout.ts +0 -20
  260. package/src/router/tracing.ts +206 -0
  261. package/src/router/trie-matching.ts +180 -58
  262. package/src/router/types.ts +10 -63
  263. package/src/router/url-params.ts +44 -0
  264. package/src/router.ts +182 -54
  265. package/src/rsc/handler-context.ts +3 -2
  266. package/src/rsc/handler.ts +702 -460
  267. package/src/rsc/helpers.ts +168 -46
  268. package/src/rsc/index.ts +2 -25
  269. package/src/rsc/json-route-result.ts +38 -0
  270. package/src/rsc/loader-fetch.ts +127 -31
  271. package/src/rsc/manifest-init.ts +33 -42
  272. package/src/rsc/origin-guard.ts +39 -25
  273. package/src/rsc/progressive-enhancement.ts +98 -19
  274. package/src/rsc/redirect-guard.ts +99 -0
  275. package/src/rsc/response-cache-serve.ts +238 -0
  276. package/src/rsc/response-error.ts +79 -12
  277. package/src/rsc/response-route-handler.ts +99 -189
  278. package/src/rsc/rsc-rendering.ts +126 -106
  279. package/src/rsc/runtime-warnings.ts +23 -10
  280. package/src/rsc/server-action.ts +269 -114
  281. package/src/rsc/ssr-setup.ts +144 -0
  282. package/src/rsc/types.ts +34 -6
  283. package/src/runtime-env.ts +18 -0
  284. package/src/search-params.ts +49 -41
  285. package/src/segment-content-promise.ts +67 -0
  286. package/src/segment-loader-promise.ts +149 -0
  287. package/src/segment-system.tsx +281 -129
  288. package/src/serialize.ts +243 -0
  289. package/src/server/context.ts +317 -63
  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 +26 -46
  294. package/src/server/request-context.ts +425 -177
  295. package/src/server.ts +6 -0
  296. package/src/ssr/index.tsx +25 -16
  297. package/src/static-handler.ts +27 -18
  298. package/src/testing/cache-status.ts +162 -0
  299. package/src/testing/collect-handle.ts +40 -0
  300. package/src/testing/dispatch.ts +701 -0
  301. package/src/testing/dom.entry.ts +22 -0
  302. package/src/testing/e2e/fixture.ts +188 -0
  303. package/src/testing/e2e/index.ts +128 -0
  304. package/src/testing/e2e/matchers.ts +35 -0
  305. package/src/testing/e2e/page-helpers.ts +272 -0
  306. package/src/testing/e2e/parity.ts +387 -0
  307. package/src/testing/e2e/server.ts +195 -0
  308. package/src/testing/flight-matchers.ts +97 -0
  309. package/src/testing/flight-normalize.ts +11 -0
  310. package/src/testing/flight-runtime.d.ts +57 -0
  311. package/src/testing/flight-tree.ts +682 -0
  312. package/src/testing/flight.entry.ts +52 -0
  313. package/src/testing/flight.ts +257 -0
  314. package/src/testing/generated-routes.ts +183 -0
  315. package/src/testing/index.ts +99 -0
  316. package/src/testing/internal/context.ts +371 -0
  317. package/src/testing/internal/flight-client-globals.ts +30 -0
  318. package/src/testing/internal/seed-vars.ts +54 -0
  319. package/src/testing/render-handler.ts +343 -0
  320. package/src/testing/render-route.tsx +581 -0
  321. package/src/testing/run-loader.ts +385 -0
  322. package/src/testing/run-middleware.ts +205 -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 +3 -19
  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 +236 -88
  340. package/src/types/index.ts +1 -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 +10 -45
  344. package/src/types/route-entry.ts +19 -7
  345. package/src/types/segments.ts +37 -19
  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 +58 -11
  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 -18
  354. package/src/use-loader.tsx +346 -89
  355. package/src/vite/debug.ts +185 -0
  356. package/src/vite/discovery/bundle-postprocess.ts +64 -91
  357. package/src/vite/discovery/discover-routers.ts +147 -88
  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 +247 -145
  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 +61 -13
  364. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  365. package/src/vite/index.ts +10 -3
  366. package/src/vite/inject-client-debug.ts +36 -0
  367. package/src/vite/plugin-types.ts +155 -65
  368. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  369. package/src/vite/plugins/client-ref-dedup.ts +120 -0
  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 +49 -98
  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 +127 -0
  383. package/src/vite/plugins/use-cache-transform.ts +73 -83
  384. package/src/vite/plugins/version-injector.ts +21 -25
  385. package/src/vite/plugins/version-plugin.ts +46 -37
  386. package/src/vite/plugins/virtual-entries.ts +13 -18
  387. package/src/vite/rango.ts +241 -287
  388. package/src/vite/router-discovery.ts +956 -149
  389. package/src/vite/utils/ast-handler-extract.ts +26 -35
  390. package/src/vite/utils/banner.ts +4 -4
  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 +141 -34
  398. package/src/vite/utils/shared-utils.ts +92 -42
  399. package/CLAUDE.md +0 -5
  400. package/src/browser/action-response-classifier.ts +0 -99
  401. package/src/browser/react/use-client-cache.ts +0 -58
  402. package/src/browser/shallow.ts +0 -40
  403. package/src/handles/index.ts +0 -6
  404. package/src/network-error-thrower.tsx +0 -23
  405. package/src/route-definition/route-function.ts +0 -119
  406. 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)
@@ -258,10 +290,24 @@ export interface RSCRouterInternal<
258
290
 
259
291
  /**
260
292
  * Cache-Control header value for prefetch responses.
261
- * False means no browser caching of prefetch responses.
293
+ * False means no caching of prefetch responses.
294
+ * Derived from prefetchCacheTTL.
262
295
  */
263
296
  readonly prefetchCacheControl: string | false;
264
297
 
298
+ /**
299
+ * TTL in milliseconds for the client-side in-memory prefetch cache.
300
+ * 0 means caching is disabled.
301
+ */
302
+ readonly prefetchCacheTTL: number;
303
+
304
+ /**
305
+ * Resolved rango state cookie name (`{prefix}_{routerId}`), composed once at
306
+ * router init and shipped to the client in payload metadata. The server-side
307
+ * cookie writer reads it from here; the client reads it from metadata.
308
+ */
309
+ readonly resolvedStateCookieName: string;
310
+
265
311
  /**
266
312
  * Whether connection warmup is enabled.
267
313
  * When true, the client sends HEAD /?_rsc_warmup after idle periods
@@ -269,6 +315,26 @@ export interface RSCRouterInternal<
269
315
  */
270
316
  readonly warmupEnabled: boolean;
271
317
 
318
+ /**
319
+ * Whether the client hydrates inside React.StrictMode. Resolved from
320
+ * createRouter({ strictMode }) (default true) and shipped to the client in
321
+ * the initial payload metadata.
322
+ */
323
+ readonly strictMode: boolean;
324
+
325
+ /**
326
+ * Whether router-wide performance debugging is enabled.
327
+ * Used by the request handler to create metrics before middleware runs.
328
+ */
329
+ readonly debugPerformance?: boolean;
330
+
331
+ /**
332
+ * Resolved platform phase-span tracing (Cloudflare custom spans or OTel), or
333
+ * undefined when off. Threaded onto the request context and read at each
334
+ * traced phase.
335
+ */
336
+ readonly tracing?: ResolvedTracing;
337
+
272
338
  /**
273
339
  * Whether ?__debug_manifest is allowed in production.
274
340
  * Always enabled in development.
@@ -325,6 +391,20 @@ export interface RSCRouterInternal<
325
391
  */
326
392
  readonly __sourceFile?: string;
327
393
 
394
+ /** @internal basename for runtime manifest generation */
395
+ readonly __basename?: string;
396
+
397
+ /**
398
+ * @internal Router-level error/notFound fallbacks (`createRouter` options),
399
+ * exposed for the build-time clientChunks discovery so a `"use client"`
400
+ * default boundary is routed into the dedicated `app-fallback` chunk. Unlike
401
+ * the route-tree `errorBoundary()`/`notFoundBoundary()` helpers these never
402
+ * land in `EntryData`, so they are read directly off the router instance.
403
+ */
404
+ readonly __defaultErrorBoundary?: RangoOptions<TEnv>["defaultErrorBoundary"];
405
+ readonly __defaultNotFoundBoundary?: RangoOptions<TEnv>["defaultNotFoundBoundary"];
406
+ readonly __notFound?: RangoOptions<TEnv>["notFound"];
407
+
328
408
  match(
329
409
  request: Request,
330
410
  input?: RouterRequestInput<TEnv>,
@@ -340,13 +420,17 @@ export interface RSCRouterInternal<
340
420
  params: Record<string, string>,
341
421
  buildVars?: Record<string, any>,
342
422
  isPassthroughRoute?: boolean,
423
+ buildEnv?: any,
424
+ devMode?: boolean,
343
425
  ): Promise<{
344
426
  segments: SerializedSegmentData[];
345
- handles: Record<string, SegmentHandleData>;
427
+ /** RSC-encoded handle map ("" when none) — see handle-snapshot.ts. */
428
+ handles: string;
346
429
  routeName: string;
347
430
  params: Record<string, string>;
348
431
  interceptSegments?: SerializedSegmentData[];
349
- interceptHandles?: Record<string, SegmentHandleData>;
432
+ /** RSC-encoded MERGED (main + intercept) handle map for the intercept artifact. */
433
+ interceptHandles?: string;
350
434
  passthrough?: true;
351
435
  } | null>;
352
436
 
@@ -358,7 +442,9 @@ export interface RSCRouterInternal<
358
442
  handler: Function,
359
443
  handlerId: string,
360
444
  routeName?: string,
361
- ): Promise<{ encoded: string; handles: Record<string, unknown[]> } | null>;
445
+ buildEnv?: any,
446
+ devMode?: boolean,
447
+ ): Promise<{ encoded: string; handles: string } | null>;
362
448
 
363
449
  /**
364
450
  * Preview match - returns route middleware without segment resolution.
@@ -411,6 +497,13 @@ export interface RSCRouterInternal<
411
497
  segmentType?: ErrorInfo["segmentType"],
412
498
  ): Promise<MatchResult | null>;
413
499
 
500
+ /**
501
+ * Low-level route matching function.
502
+ * Used by classifyRequest() for request classification without
503
+ * entering the full match pipeline.
504
+ */
505
+ findMatch(pathname: string, metricsStore?: any): any;
506
+
414
507
  /**
415
508
  * Debug utility to serialize the manifest for inspection
416
509
  * Returns a JSON-friendly representation of all routes and layouts
@@ -424,16 +517,16 @@ export interface RSCRouterInternal<
424
517
  }
425
518
 
426
519
  /**
427
- * Assert a public RSCRouter into the internal type.
520
+ * Assert a public Rango into the internal type.
428
521
  *
429
522
  * Use this at the boundary where framework code receives a user-provided
430
523
  * router and needs access to internal members (match, config, build-time).
431
524
  * The cast is safe because createRouter() always produces an object that
432
- * satisfies RSCRouterInternal; the public type is just a narrower view.
525
+ * satisfies RangoInternal; the public type is just a narrower view.
433
526
  */
434
527
  export function toInternal<
435
528
  TEnv = any,
436
529
  TRoutes extends Record<string, unknown> = Record<string, string>,
437
- >(router: RSCRouter<TEnv, TRoutes>): RSCRouterInternal<TEnv, TRoutes> {
438
- return router as RSCRouterInternal<TEnv, TRoutes>;
530
+ >(router: Rango<TEnv, TRoutes>): RangoInternal<TEnv, TRoutes> {
531
+ return router as RangoInternal<TEnv, TRoutes>;
439
532
  }
@@ -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
  *
@@ -239,7 +278,7 @@ export interface RSCRouterOptions<TEnv = any> {
239
278
  *
240
279
  * @example Static config
241
280
  * ```typescript
242
- * import { MemorySegmentCacheStore } from "rsc-router/rsc";
281
+ * import { MemorySegmentCacheStore } from "@rangojs/router/cache";
243
282
  *
244
283
  * const router = createRouter({
245
284
  * cache: {
@@ -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.
@@ -415,16 +481,36 @@ export interface RSCRouterOptions<TEnv = any> {
415
481
  version?: string;
416
482
 
417
483
  /**
418
- * Cache-Control header value for prefetch responses.
419
- * Only applied to non-intercept partial responses that include the
420
- * `X-Rango-Prefetch` header (sent by the Link component's prefetch fetch).
421
- * Navigation responses are never cached by the browser.
484
+ * TTL (in seconds) for the in-memory prefetch cache and the
485
+ * Cache-Control header on prefetch responses.
486
+ *
487
+ * Controls how long prefetch responses are kept in the client-side
488
+ * in-memory cache and sets `Cache-Control: private, max-age=<ttl>`
489
+ * on server responses for CDN/edge caching.
422
490
  *
423
- * Set to `false` to disable browser caching of prefetch responses entirely.
491
+ * The cache is automatically invalidated on server actions regardless
492
+ * of TTL, so this is primarily a staleness safety net.
424
493
  *
425
- * @default "private, max-age=300"
494
+ * Set to `false` to disable prefetch caching entirely.
495
+ *
496
+ * @default 300 (5 minutes)
426
497
  */
427
- prefetchCacheControl?: string | false;
498
+ prefetchCacheTTL?: number | false;
499
+
500
+ /**
501
+ * Prefix for the rango state cookie name. The resolved name is
502
+ * `{prefix}_{routerId}`; the prefix is sanitized to cookie-name-safe
503
+ * characters (`[A-Za-z0-9-]`) and an empty result falls back to the default.
504
+ *
505
+ * The rango state cookie keys the client's prefetch / HTTP caches. Overriding
506
+ * the prefix lets you align it with cookie-naming policies or consent-manager
507
+ * classification lists, or avoid colliding with an existing `rango-state`
508
+ * cookie. It is not a full-name override: the `_{routerId}` suffix is what
509
+ * keeps sibling apps on one origin from clobbering each other's state.
510
+ *
511
+ * @default "rango-state"
512
+ */
513
+ stateCookiePrefix?: string;
428
514
 
429
515
  /**
430
516
  * Enable connection warmup to keep TCP+TLS alive after idle periods.
@@ -437,6 +523,29 @@ export interface RSCRouterOptions<TEnv = any> {
437
523
  */
438
524
  warmup?: boolean;
439
525
 
526
+ /**
527
+ * Wrap the hydrated client tree in `React.StrictMode`.
528
+ *
529
+ * The Rango browser entry hydrates the app inside `<React.StrictMode>` by
530
+ * default. StrictMode double-invokes render and (in development) mounts,
531
+ * unmounts, then remounts every effect to surface impure renders and missing
532
+ * effect cleanup. Production builds treat StrictMode as a no-op, so this flag
533
+ * only changes development behavior in a normal app.
534
+ *
535
+ * Set to `false` to hydrate without the StrictMode wrapper. The main reason to
536
+ * opt out is to isolate StrictMode's intentional double-render/double-effect
537
+ * from genuine re-renders when measuring client-hook stability — with
538
+ * StrictMode off, render counts are exact in development too.
539
+ *
540
+ * The value is resolved server-side at router creation and shipped to the
541
+ * client in the initial payload metadata; the browser entry reads it once at
542
+ * hydration. Changing it does not affect the SSR HTML (StrictMode emits no
543
+ * DOM), so toggling it never causes a hydration mismatch.
544
+ *
545
+ * @default true
546
+ */
547
+ strictMode?: boolean;
548
+
440
549
  /**
441
550
  * Shorthand timeout (ms) applied to both action execution and render start.
442
551
  * Does NOT apply to streamIdleMs.
@@ -489,11 +598,14 @@ export interface RSCRouterOptions<TEnv = any> {
489
598
  onTimeout?: OnTimeoutCallback<TEnv>;
490
599
 
491
600
  /**
492
- * Telemetry sink for structured lifecycle events.
601
+ * Telemetry sink for structured, discrete lifecycle EVENTS: request
602
+ * start/end/error, loader start/end/error, handler errors, cache decisions,
603
+ * revalidation decisions, timeouts, origin rejections.
493
604
  *
494
- * When provided, the router emits events for request start/end,
495
- * loader start/end/error, handler errors, cache decisions, and
496
- * revalidation decisions.
605
+ * This is the EVENT surface. Phase-duration SPANS (request/middleware/action/
606
+ * handler/loader/render/ssr timing wired into a tracing backend) come from the
607
+ * separate `tracing` option below — a sink does not emit them, because async-context nesting
608
+ * cannot be faithfully reconstructed from after-the-fact start/end events.
497
609
  *
498
610
  * No-op when not configured (zero overhead).
499
611
  *
@@ -506,6 +618,18 @@ export interface RSCRouterOptions<TEnv = any> {
506
618
  * });
507
619
  * ```
508
620
  *
621
+ * @example OpenTelemetry — pair the event sink with the tracing slot
622
+ * ```typescript
623
+ * import { createOTelTracing, createOTelSink } from "@rangojs/router";
624
+ * import { trace } from "@opentelemetry/api";
625
+ *
626
+ * const tracer = trace.getTracer("my-app");
627
+ * const router = createRouter({
628
+ * tracing: createOTelTracing(tracer), // phase spans
629
+ * telemetry: createOTelSink(tracer), // discrete-fact events
630
+ * });
631
+ * ```
632
+ *
509
633
  * @example Custom sink
510
634
  * ```typescript
511
635
  * const router = createRouter({
@@ -519,6 +643,44 @@ export interface RSCRouterOptions<TEnv = any> {
519
643
  */
520
644
  telemetry?: TelemetrySink;
521
645
 
646
+ /**
647
+ * Span tracing for the router's performance phases (request, middleware, action,
648
+ * loaders, render, ssr). Connects the same phases shown in the
649
+ * `debugPerformance` timeline to the host platform's tracing system. This is
650
+ * the SPAN surface (the `telemetry` option above is the event surface).
651
+ *
652
+ * Two factories produce a config, both for this slot:
653
+ * - `createOTelTracing(tracer)` from `@rangojs/router` — any platform with an
654
+ * OpenTelemetry SDK (including Node). Bridges the phases onto
655
+ * `tracer.startActiveSpan`.
656
+ * - `createCloudflareTracing()` from `@rangojs/router/cloudflare` — Cloudflare
657
+ * Workers native custom spans, alongside the automatic KV/D1/fetch spans.
658
+ *
659
+ * When tracing is unset — or off-platform (no OTel SDK / no Cloudflare tracing
660
+ * destination) — every span call falls through to the work directly, so the
661
+ * request behaves exactly as if tracing were off.
662
+ *
663
+ * @example OpenTelemetry
664
+ * ```typescript
665
+ * import { createOTelTracing } from "@rangojs/router";
666
+ * import { trace } from "@opentelemetry/api";
667
+ *
668
+ * const router = createRouter({
669
+ * tracing: createOTelTracing(trace.getTracer("my-app")),
670
+ * });
671
+ * ```
672
+ *
673
+ * @example Cloudflare
674
+ * ```typescript
675
+ * import { createCloudflareTracing } from "@rangojs/router/cloudflare";
676
+ *
677
+ * const router = createRouter({
678
+ * tracing: createCloudflareTracing({ spans: { ssr: false } }),
679
+ * });
680
+ * ```
681
+ */
682
+ tracing?: RouterTracingConfig;
683
+
522
684
  /**
523
685
  * SSR configuration options.
524
686
  *
@@ -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