@rangojs/router 0.0.0-experimental.9c9afef3 → 0.0.0-experimental.a014d2b7

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 (402) 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 +3373 -1176
  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 +68 -14
  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 +224 -32
  13. package/skills/caching/SKILL.md +279 -17
  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 +235 -9
  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 +771 -0
  29. package/skills/mime-routes/SKILL.md +28 -1
  30. package/skills/observability/SKILL.md +172 -0
  31. package/skills/parallel/SKILL.md +77 -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 +70 -5
  37. package/skills/router-setup/SKILL.md +65 -8
  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 +322 -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 +186 -100
  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 +165 -112
  80. package/src/browser/prefetch/cache.ts +205 -62
  81. package/src/browser/prefetch/fetch.ts +347 -39
  82. package/src/browser/prefetch/queue.ts +42 -8
  83. package/src/browser/rango-state.ts +158 -76
  84. package/src/browser/react/Link.tsx +102 -15
  85. package/src/browser/react/NavigationProvider.tsx +295 -119
  86. package/src/browser/react/ScrollRestoration.tsx +10 -6
  87. package/src/browser/react/context.ts +7 -2
  88. package/src/browser/react/deferred-handle-resolution.ts +75 -0
  89. package/src/browser/react/filter-segment-order.ts +66 -7
  90. package/src/browser/react/index.ts +0 -48
  91. package/src/browser/react/location-state-shared.ts +178 -8
  92. package/src/browser/react/location-state.ts +39 -14
  93. package/src/browser/react/use-action.ts +6 -15
  94. package/src/browser/react/use-handle.ts +23 -69
  95. package/src/browser/react/use-href.tsx +8 -1
  96. package/src/browser/react/use-link-status.ts +33 -8
  97. package/src/browser/react/use-navigation.ts +32 -7
  98. package/src/browser/react/use-params.ts +20 -10
  99. package/src/browser/react/use-reverse.ts +106 -0
  100. package/src/browser/react/use-router.ts +46 -11
  101. package/src/browser/react/use-search-params.ts +0 -5
  102. package/src/browser/react/use-segments.ts +11 -21
  103. package/src/browser/response-adapter.ts +99 -8
  104. package/src/browser/rsc-router.tsx +114 -24
  105. package/src/browser/scroll-restoration.ts +37 -22
  106. package/src/browser/segment-reconciler.ts +36 -14
  107. package/src/browser/segment-structure-assert.ts +2 -2
  108. package/src/browser/server-action-bridge.ts +222 -72
  109. package/src/browser/types.ts +102 -12
  110. package/src/browser/validate-redirect-origin.ts +43 -16
  111. package/src/build/collect-fallback-refs.ts +107 -0
  112. package/src/build/generate-manifest.ts +65 -40
  113. package/src/build/generate-route-types.ts +5 -1
  114. package/src/build/index.ts +8 -2
  115. package/src/build/prefix-tree-utils.ts +123 -0
  116. package/src/build/route-trie.ts +165 -36
  117. package/src/build/route-types/ast-route-extraction.ts +15 -8
  118. package/src/build/route-types/codegen.ts +16 -5
  119. package/src/build/route-types/include-resolution.ts +125 -24
  120. package/src/build/route-types/param-extraction.ts +6 -3
  121. package/src/build/route-types/per-module-writer.ts +22 -6
  122. package/src/build/route-types/router-processing.ts +260 -94
  123. package/src/build/route-types/scan-filter.ts +9 -2
  124. package/src/build/route-types/source-scan.ts +216 -0
  125. package/src/build/runtime-discovery.ts +9 -20
  126. package/src/cache/cache-error.ts +104 -0
  127. package/src/cache/cache-key-utils.ts +29 -13
  128. package/src/cache/cache-policy.ts +108 -34
  129. package/src/cache/cache-runtime.ts +224 -41
  130. package/src/cache/cache-scope.ts +188 -82
  131. package/src/cache/cache-tag.ts +103 -0
  132. package/src/cache/cf/cf-base64.ts +33 -0
  133. package/src/cache/cf/cf-cache-constants.ts +127 -0
  134. package/src/cache/cf/cf-cache-store.ts +1989 -378
  135. package/src/cache/cf/cf-cache-types.ts +349 -0
  136. package/src/cache/cf/cf-kv-utils.ts +46 -0
  137. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  138. package/src/cache/cf/index.ts +6 -16
  139. package/src/cache/document-cache.ts +89 -21
  140. package/src/cache/handle-snapshot.ts +70 -0
  141. package/src/cache/index.ts +10 -20
  142. package/src/cache/memory-segment-store.ts +136 -37
  143. package/src/cache/profile-registry.ts +46 -31
  144. package/src/cache/read-through-swr.ts +56 -12
  145. package/src/cache/segment-codec.ts +9 -17
  146. package/src/cache/tag-invalidation.ts +230 -0
  147. package/src/cache/types.ts +37 -100
  148. package/src/client.rsc.tsx +44 -21
  149. package/src/client.tsx +119 -290
  150. package/src/cloudflare/index.ts +11 -0
  151. package/src/cloudflare/tracing.ts +109 -0
  152. package/src/component-utils.ts +19 -0
  153. package/src/components/DefaultDocument.tsx +8 -2
  154. package/src/context-var.ts +18 -6
  155. package/src/decode-loader-results.ts +52 -0
  156. package/src/defer.ts +196 -0
  157. package/src/deps/ssr.ts +0 -1
  158. package/src/encode-kv.ts +49 -0
  159. package/src/errors.ts +30 -4
  160. package/src/escape-script.ts +52 -0
  161. package/src/handle.ts +70 -22
  162. package/src/handles/MetaTags.tsx +62 -19
  163. package/src/handles/Scripts.tsx +183 -0
  164. package/src/handles/breadcrumbs.ts +37 -8
  165. package/src/handles/is-thenable.ts +19 -0
  166. package/src/handles/meta.ts +51 -40
  167. package/src/handles/script.ts +244 -0
  168. package/src/host/cookie-handler.ts +9 -60
  169. package/src/host/errors.ts +0 -24
  170. package/src/host/index.ts +8 -2
  171. package/src/host/pattern-matcher.ts +23 -52
  172. package/src/host/router.ts +107 -99
  173. package/src/host/testing.ts +40 -27
  174. package/src/host/types.ts +37 -4
  175. package/src/host/utils.ts +1 -1
  176. package/src/href-client.ts +137 -22
  177. package/src/index.rsc.ts +99 -13
  178. package/src/index.ts +139 -19
  179. package/src/internal-debug.ts +11 -10
  180. package/src/loader-store.ts +500 -0
  181. package/src/loader.rsc.ts +20 -13
  182. package/src/loader.ts +12 -11
  183. package/src/missing-id-error.ts +68 -0
  184. package/src/outlet-context.ts +1 -1
  185. package/src/outlet-provider.tsx +1 -5
  186. package/src/prerender/param-hash.ts +16 -16
  187. package/src/prerender/store.ts +37 -41
  188. package/src/prerender.ts +198 -82
  189. package/src/redirect-origin.ts +100 -0
  190. package/src/regex-escape.ts +8 -0
  191. package/src/render-error-thrower.tsx +20 -0
  192. package/src/response-utils.ts +62 -0
  193. package/src/reverse.ts +65 -15
  194. package/src/root-error-boundary.tsx +1 -19
  195. package/src/route-content-wrapper.tsx +19 -77
  196. package/src/route-definition/dsl-helpers.ts +461 -304
  197. package/src/route-definition/helper-factories.ts +28 -140
  198. package/src/route-definition/helpers-types.ts +143 -69
  199. package/src/route-definition/index.ts +4 -2
  200. package/src/route-definition/redirect.ts +51 -10
  201. package/src/route-definition/resolve-handler-use.ts +160 -0
  202. package/src/route-definition/use-item-types.ts +29 -0
  203. package/src/route-map-builder.ts +0 -16
  204. package/src/route-types.ts +37 -46
  205. package/src/router/basename.ts +14 -0
  206. package/src/router/content-negotiation.ts +164 -17
  207. package/src/router/error-handling.ts +45 -18
  208. package/src/router/find-match.ts +44 -23
  209. package/src/router/handler-context.ts +52 -31
  210. package/src/router/instrument.ts +350 -0
  211. package/src/router/intercept-resolution.ts +48 -24
  212. package/src/router/lazy-includes.ts +15 -52
  213. package/src/router/loader-resolution.ts +268 -56
  214. package/src/router/logging.ts +0 -6
  215. package/src/router/manifest.ts +40 -42
  216. package/src/router/match-api.ts +124 -204
  217. package/src/router/match-context.ts +0 -22
  218. package/src/router/match-handlers.ts +58 -58
  219. package/src/router/match-middleware/background-revalidation.ts +40 -24
  220. package/src/router/match-middleware/cache-lookup.ts +170 -276
  221. package/src/router/match-middleware/cache-store.ts +64 -52
  222. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  223. package/src/router/match-middleware/segment-resolution.ts +45 -14
  224. package/src/router/match-pipelines.ts +1 -42
  225. package/src/router/match-result.ts +87 -39
  226. package/src/router/metrics.ts +0 -34
  227. package/src/router/middleware-types.ts +7 -140
  228. package/src/router/middleware.ts +266 -169
  229. package/src/router/navigation-snapshot.ts +131 -0
  230. package/src/router/params-util.ts +23 -0
  231. package/src/router/pattern-matching.ts +132 -90
  232. package/src/router/prefetch-cache-ttl.ts +51 -0
  233. package/src/router/prerender-match.ts +195 -56
  234. package/src/router/preview-match.ts +32 -102
  235. package/src/router/request-classification.ts +276 -0
  236. package/src/router/revalidation.ts +123 -73
  237. package/src/router/route-snapshot.ts +244 -0
  238. package/src/router/router-context.ts +3 -28
  239. package/src/router/router-interfaces.ts +115 -35
  240. package/src/router/router-options.ts +172 -15
  241. package/src/router/router-registry.ts +2 -5
  242. package/src/router/segment-resolution/fresh.ts +162 -84
  243. package/src/router/segment-resolution/helpers.ts +86 -6
  244. package/src/router/segment-resolution/loader-cache.ts +76 -39
  245. package/src/router/segment-resolution/revalidation.ts +351 -321
  246. package/src/router/segment-resolution/static-store.ts +19 -5
  247. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  248. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  249. package/src/router/segment-resolution.ts +5 -1
  250. package/src/router/segment-wrappers.ts +6 -5
  251. package/src/router/state-cookie-name.ts +33 -0
  252. package/src/router/substitute-pattern-params.ts +56 -0
  253. package/src/router/telemetry-otel.ts +161 -199
  254. package/src/router/telemetry.ts +96 -19
  255. package/src/router/timeout.ts +0 -20
  256. package/src/router/tracing.ts +206 -0
  257. package/src/router/trie-matching.ts +163 -59
  258. package/src/router/types.ts +9 -63
  259. package/src/router/url-params.ts +44 -0
  260. package/src/router.ts +157 -54
  261. package/src/rsc/handler-context.ts +3 -2
  262. package/src/rsc/handler.ts +655 -529
  263. package/src/rsc/helpers.ts +168 -46
  264. package/src/rsc/index.ts +2 -5
  265. package/src/rsc/json-route-result.ts +38 -0
  266. package/src/rsc/loader-fetch.ts +122 -31
  267. package/src/rsc/manifest-init.ts +33 -42
  268. package/src/rsc/origin-guard.ts +39 -25
  269. package/src/rsc/progressive-enhancement.ts +131 -14
  270. package/src/rsc/redirect-guard.ts +99 -0
  271. package/src/rsc/response-cache-serve.ts +238 -0
  272. package/src/rsc/response-error.ts +79 -12
  273. package/src/rsc/response-route-handler.ts +99 -189
  274. package/src/rsc/rsc-rendering.ts +109 -74
  275. package/src/rsc/runtime-warnings.ts +23 -10
  276. package/src/rsc/server-action.ts +287 -115
  277. package/src/rsc/ssr-setup.ts +18 -2
  278. package/src/rsc/transition-gate.ts +89 -0
  279. package/src/rsc/types.ts +29 -9
  280. package/src/runtime-env.ts +18 -0
  281. package/src/search-params.ts +35 -30
  282. package/src/segment-content-promise.ts +67 -0
  283. package/src/segment-loader-promise.ts +149 -0
  284. package/src/segment-system.tsx +236 -202
  285. package/src/serialize.ts +243 -0
  286. package/src/server/context.ts +224 -52
  287. package/src/server/cookie-parse.ts +32 -0
  288. package/src/server/cookie-store.ts +80 -5
  289. package/src/server/handle-store.ts +40 -38
  290. package/src/server/loader-registry.ts +38 -46
  291. package/src/server/request-context.ts +401 -173
  292. package/src/ssr/index.tsx +24 -16
  293. package/src/static-handler.ts +27 -18
  294. package/src/testing/cache-status.ts +162 -0
  295. package/src/testing/collect-handle.ts +40 -0
  296. package/src/testing/dispatch.ts +701 -0
  297. package/src/testing/dom.entry.ts +22 -0
  298. package/src/testing/e2e/fixture.ts +188 -0
  299. package/src/testing/e2e/index.ts +128 -0
  300. package/src/testing/e2e/matchers.ts +35 -0
  301. package/src/testing/e2e/page-helpers.ts +272 -0
  302. package/src/testing/e2e/parity.ts +387 -0
  303. package/src/testing/e2e/server.ts +195 -0
  304. package/src/testing/flight-matchers.ts +97 -0
  305. package/src/testing/flight-normalize.ts +11 -0
  306. package/src/testing/flight-runtime.d.ts +57 -0
  307. package/src/testing/flight-tree.ts +682 -0
  308. package/src/testing/flight.entry.ts +52 -0
  309. package/src/testing/flight.ts +257 -0
  310. package/src/testing/generated-routes.ts +183 -0
  311. package/src/testing/index.ts +105 -0
  312. package/src/testing/internal/context.ts +371 -0
  313. package/src/testing/internal/flight-client-globals.ts +30 -0
  314. package/src/testing/internal/seed-vars.ts +54 -0
  315. package/src/testing/render-handler.ts +357 -0
  316. package/src/testing/render-route.tsx +581 -0
  317. package/src/testing/run-loader.ts +385 -0
  318. package/src/testing/run-middleware.ts +205 -0
  319. package/src/testing/run-transition-when.ts +164 -0
  320. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  321. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  322. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  323. package/src/testing/vitest-stubs/version.ts +5 -0
  324. package/src/testing/vitest.ts +305 -0
  325. package/src/theme/ThemeProvider.tsx +20 -58
  326. package/src/theme/ThemeScript.tsx +7 -9
  327. package/src/theme/constants.ts +52 -13
  328. package/src/theme/index.ts +0 -7
  329. package/src/theme/theme-context.ts +1 -5
  330. package/src/theme/theme-script.ts +22 -21
  331. package/src/theme/use-theme.ts +0 -3
  332. package/src/types/boundaries.ts +0 -35
  333. package/src/types/cache-types.ts +17 -8
  334. package/src/types/error-types.ts +30 -90
  335. package/src/types/global-namespace.ts +54 -41
  336. package/src/types/handler-context.ts +125 -71
  337. package/src/types/index.ts +3 -10
  338. package/src/types/loader-types.ts +40 -11
  339. package/src/types/request-scope.ts +112 -0
  340. package/src/types/route-config.ts +6 -50
  341. package/src/types/route-entry.ts +12 -7
  342. package/src/types/segments.ts +136 -15
  343. package/src/urls/include-helper.ts +33 -70
  344. package/src/urls/index.ts +1 -11
  345. package/src/urls/path-helper-types.ts +68 -18
  346. package/src/urls/path-helper.ts +57 -111
  347. package/src/urls/pattern-types.ts +48 -19
  348. package/src/urls/response-types.ts +25 -22
  349. package/src/urls/type-extraction.ts +58 -139
  350. package/src/urls/urls-function.ts +1 -19
  351. package/src/use-loader.tsx +346 -89
  352. package/src/vite/debug.ts +185 -0
  353. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  354. package/src/vite/discovery/discover-routers.ts +130 -85
  355. package/src/vite/discovery/discovery-errors.ts +194 -0
  356. package/src/vite/discovery/gate-state.ts +171 -0
  357. package/src/vite/discovery/prerender-collection.ts +214 -132
  358. package/src/vite/discovery/route-types-writer.ts +40 -84
  359. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  360. package/src/vite/discovery/state.ts +57 -4
  361. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  362. package/src/vite/index.ts +6 -0
  363. package/src/vite/inject-client-debug.ts +36 -0
  364. package/src/vite/plugin-types.ts +178 -5
  365. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  366. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  367. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  368. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  369. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  370. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  371. package/src/vite/plugins/expose-action-id.ts +48 -95
  372. package/src/vite/plugins/expose-id-utils.ts +96 -51
  373. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  374. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  375. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  376. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  377. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  378. package/src/vite/plugins/performance-tracks.ts +64 -170
  379. package/src/vite/plugins/refresh-cmd.ts +89 -27
  380. package/src/vite/plugins/use-cache-transform.ts +73 -83
  381. package/src/vite/plugins/version-injector.ts +40 -29
  382. package/src/vite/plugins/version-plugin.ts +37 -40
  383. package/src/vite/plugins/virtual-entries.ts +39 -25
  384. package/src/vite/rango.ts +118 -114
  385. package/src/vite/router-discovery.ts +941 -142
  386. package/src/vite/utils/ast-handler-extract.ts +26 -35
  387. package/src/vite/utils/banner.ts +1 -1
  388. package/src/vite/utils/bundle-analysis.ts +10 -15
  389. package/src/vite/utils/client-chunks.ts +184 -0
  390. package/src/vite/utils/directive-prologue.ts +40 -0
  391. package/src/vite/utils/forward-user-plugins.ts +171 -0
  392. package/src/vite/utils/manifest-utils.ts +4 -59
  393. package/src/vite/utils/package-resolution.ts +20 -52
  394. package/src/vite/utils/prerender-utils.ts +81 -34
  395. package/src/vite/utils/shared-utils.ts +92 -42
  396. package/src/browser/action-response-classifier.ts +0 -99
  397. package/src/browser/debug-channel.ts +0 -93
  398. package/src/browser/react/use-client-cache.ts +0 -58
  399. package/src/browser/shallow.ts +0 -40
  400. package/src/handles/index.ts +0 -7
  401. package/src/network-error-thrower.tsx +0 -23
  402. package/src/router/middleware-cookies.ts +0 -55
@@ -81,7 +81,7 @@ export const urlpatterns = urls(({ path }) => [
81
81
  - `Accept: application/json` — JSON handler
82
82
  - `Accept: text/plain` — text handler
83
83
  - `Accept: application/xml` — XML handler
84
- - `Accept: */*` — first variant (JSON, since it was registered first)
84
+ - `Accept: */*` — RSC page (the primary, since it was registered first)
85
85
 
86
86
  ## Wildcard Routes
87
87
 
@@ -108,6 +108,33 @@ path.text("/api/data", () => "plain text version", { name: "dataText" }),
108
108
  Without an RSC primary, there is no `text/html` candidate — the Accept header
109
109
  picks among the response-type candidates directly.
110
110
 
111
+ ## Type Safety For Negotiated Paths
112
+
113
+ `router.named-routes.gen.ts` validates route names, params, search, `href()`, and
114
+ the `Rango.Path` type, but it does not carry response payload metadata. For MIME or
115
+ response payload types, use one of these surfaces:
116
+
117
+ - `RouteResponse<typeof patterns, "routeName">` for a specific response variant
118
+ by route name. This is the clearest option when several MIME variants share
119
+ one URL pattern.
120
+ - `Rango.PathResponse<"/products/:id">` (ambient, no import) for global lookup by URL pattern or concrete path after the app
121
+ registers `typeof router.routeMap`:
122
+
123
+ ```typescript
124
+ // router.tsx
125
+ export const router = createRouter({ document: Document }).routes(urlpatterns);
126
+
127
+ declare global {
128
+ namespace Rango {
129
+ interface RegisteredRoutes extends typeof router.routeMap {}
130
+ }
131
+ }
132
+ ```
133
+
134
+ `RegisteredRoutes` is what exposes the richer routeMap entries containing
135
+ response payload metadata. Without it, URL-pattern response lookup has paths but
136
+ no payloads, so response types resolve to `never`.
137
+
111
138
  ## How It Works
112
139
 
113
140
  1. **Build time**: `buildRouteTrie()` calls `mergeLeaves()` when multiple routes share a pattern.
@@ -0,0 +1,172 @@
1
+ ---
2
+ name: observability
3
+ description: Debug Rango request performance with debugPerformance, Server-Timing, structured telemetry, and tracing
4
+ argument-hint:
5
+ ---
6
+
7
+ # Observability
8
+
9
+ Use this when you need to understand request latency, cache decisions,
10
+ revalidation behavior, loader overlap, or production traces.
11
+
12
+ Rango exposes two complementary observability surfaces:
13
+
14
+ 1. **Performance timeline** (`debugPerformance`) — per-request waterfall for
15
+ local or targeted debugging. It prints to the console and emits
16
+ `Server-Timing`.
17
+ 2. **Structured telemetry** (`telemetry`) — lifecycle events sent to a pluggable
18
+ sink for production monitoring, OpenTelemetry, or custom metrics.
19
+
20
+ The essentials are below. The exported `TelemetryEvent` union type
21
+ (`import type { TelemetryEvent } from "@rangojs/router"`) is the full event
22
+ contract — every event kind and its fields are typed there.
23
+
24
+ ## Performance timeline
25
+
26
+ Enable globally while debugging:
27
+
28
+ ```typescript
29
+ import { createRouter } from "@rangojs/router";
30
+
31
+ const router = createRouter({
32
+ document: Document,
33
+ urls: urlpatterns,
34
+ debugPerformance: true,
35
+ });
36
+ ```
37
+
38
+ Or enable for selected requests from middleware:
39
+
40
+ ```typescript
41
+ middleware(async (ctx, next) => {
42
+ if (ctx.url.searchParams.has("debug")) {
43
+ ctx.debugPerformance();
44
+ }
45
+ await next();
46
+ });
47
+ ```
48
+
49
+ Call `ctx.debugPerformance()` before `await next()`. The request then prints a
50
+ shared-axis waterfall and adds a `Server-Timing` header.
51
+
52
+ Read the timeline as intervals:
53
+
54
+ - `handler:total` is the whole router request.
55
+ - `render:total` / `ssr-render-html` show the render pass.
56
+ - `loader:*` rows should overlap render work. If a loader starts only after the
57
+ render bar, it is serialized latency.
58
+ - Cache, route matching, middleware pre/post, RSC serialization, and SSR phases
59
+ appear as separate spans, so the slow phase is visible without guessing.
60
+
61
+ ## Structured telemetry
62
+
63
+ Use telemetry when you want durable production events rather than a one-request
64
+ debug waterfall.
65
+
66
+ ```typescript
67
+ import { createRouter, createConsoleSink } from "@rangojs/router";
68
+
69
+ const router = createRouter({
70
+ document: Document,
71
+ urls: urlpatterns,
72
+ telemetry: createConsoleSink(),
73
+ });
74
+ ```
75
+
76
+ For OpenTelemetry — phase spans come from the `tracing` slot
77
+ (`createOTelTracing`), discrete-fact spans from the `telemetry` sink
78
+ (`createOTelSink`):
79
+
80
+ ```typescript
81
+ import {
82
+ createRouter,
83
+ createOTelTracing,
84
+ createOTelSink,
85
+ } from "@rangojs/router";
86
+ import { trace } from "@opentelemetry/api";
87
+
88
+ const tracer = trace.getTracer("my-app");
89
+
90
+ const router = createRouter({
91
+ document: Document,
92
+ urls: urlpatterns,
93
+ tracing: createOTelTracing(tracer), // request/loader/render/… phase spans
94
+ telemetry: createOTelSink(tracer), // handler errors, cache decisions, …
95
+ });
96
+ ```
97
+
98
+ On **Cloudflare Workers**, use `createCloudflareTracing` for the `tracing` slot
99
+ instead — it emits the same phases as native Cloudflare custom spans (in the
100
+ Workers trace waterfall, next to the automatic KV/D1/fetch spans), with no
101
+ `@opentelemetry/api` dependency:
102
+
103
+ ```typescript
104
+ import { createRouter } from "@rangojs/router";
105
+ import { createCloudflareTracing } from "@rangojs/router/cloudflare";
106
+
107
+ const router = createRouter({
108
+ document: Document,
109
+ urls: urlpatterns,
110
+ tracing: createCloudflareTracing(), // all phases on by default
111
+ // tracing: createCloudflareTracing({ spans: { ssr: false } }), // toggle phases
112
+ });
113
+ ```
114
+
115
+ Both factories return a `RouterTracingConfig` for the same `tracing` slot;
116
+ `telemetry` stays independent (events only, no phase spans). Phase spans:
117
+ `rango.request`, `rango.middleware`, `rango.action`, `rango.loader`,
118
+ `rango.render`, `rango.ssr` — the same phases the `debugPerformance` timeline
119
+ shows, co-emitted from one site. Off-platform (no Cloudflare tracing destination
120
+ / no OTel SDK) every span call is a transparent pass-through, so the request
121
+ behaves as if tracing were off.
122
+
123
+ Custom sinks implement `emit(event)`:
124
+
125
+ ```typescript
126
+ import { createRouter } from "@rangojs/router";
127
+
128
+ const router = createRouter({
129
+ document: Document,
130
+ urls: urlpatterns,
131
+ telemetry: {
132
+ emit(event) {
133
+ myMetrics.record(event);
134
+ },
135
+ },
136
+ });
137
+ ```
138
+
139
+ Events include `request.start/end/error`, `loader.start/end/error`,
140
+ `handler.error`, `cache.decision`, `revalidation.decision`, `request.timeout`,
141
+ and `request.origin-rejected`.
142
+
143
+ ## Debugging revalidation and stale data
144
+
145
+ When stale UI or unexpected partial renders are the question, use all three
146
+ layers together:
147
+
148
+ ```typescript
149
+ import { createConsoleSink, createRouter } from "@rangojs/router";
150
+
151
+ const router = createRouter({
152
+ document: Document,
153
+ urls: urlpatterns,
154
+ debugPerformance: true,
155
+ telemetry: createConsoleSink(),
156
+ });
157
+ ```
158
+
159
+ Then inspect:
160
+
161
+ - `revalidation.decision` telemetry to see which segment re-ran or skipped.
162
+ - cache spans / `cache.decision` events to see hit, miss, stale, and background
163
+ revalidation behavior.
164
+ - loader spans to confirm live loaders overlap the render rather than blocking
165
+ first paint.
166
+ - the `Server-Timing` header to compare local logs with browser-network timing.
167
+
168
+ ## Zero-overhead defaults
169
+
170
+ `debugPerformance` is off by default, and `telemetry` emits nothing unless a sink
171
+ is configured. Per-request `ctx.debugPerformance()` lets you turn on the
172
+ waterfall only for the route, user, or query param you are investigating.
@@ -8,9 +8,6 @@ argument-hint: [@slot-name]
8
8
 
9
9
  Parallel routes render multiple components simultaneously in named slots.
10
10
 
11
- Canonical semantics reference:
12
- [docs/execution-model.md](../../docs/internal/execution-model.md)
13
-
14
11
  ## Basic Parallel Routes
15
12
 
16
13
  ```typescript
@@ -206,6 +203,67 @@ parallel(
206
203
  )
207
204
  ```
208
205
 
206
+ ## Composable Slots via `handler.use`
207
+
208
+ Slot handlers can carry their own loader, loading, error/notFound boundaries, revalidation, and transition defaults via `.use`. The mount site then declares **just the slot names** — no per-call data wiring.
209
+
210
+ ```typescript
211
+ const CartSummary: Handler = async (ctx) => {
212
+ const cart = await ctx.use(CartLoader);
213
+ return <CartSummaryView cart={cart} />;
214
+ };
215
+ CartSummary.use = () => [
216
+ loader(CartLoader),
217
+ loading(<CartSkeleton />),
218
+ revalidate(revalidateCartData),
219
+ ];
220
+
221
+ // Same slot, no copy-pasted plumbing across layouts.
222
+ layout(<DashboardLayout />, () => [
223
+ parallel({ "@cart": CartSummary }),
224
+ path("/dashboard", DashboardIndex, { name: "dashboard.index" }),
225
+ ]);
226
+
227
+ layout(<AccountLayout />, () => [
228
+ parallel({ "@cart": CartSummary }),
229
+ path("/account", AccountIndex, { name: "account.index" }),
230
+ ]);
231
+ ```
232
+
233
+ A slot's `loading()` (whether from `handler.use` or explicit) makes that slot an independent streaming unit, exactly as in the **Streaming Behavior** section above.
234
+
235
+ The `parallel` mount site has the narrowest allow-list for `handler.use` items — slots cannot bring their own middleware or layout, only `revalidate`, `loader`, `loading`, `errorBoundary`, `notFoundBoundary`, and `transition`. See [skills/handler-use](../handler-use/SKILL.md) for the full table and merge rules.
236
+
237
+ `transition` is allowed in the slot allow-list, but slot-level rendering does **not** currently apply a `<ViewTransition>` wrapper — only the layout/route wraps take effect at render time. For a modal-only morph today, use an element-level React `<ViewTransition>` inside the slot's component. The reverse direction is the useful guarantee: a layout-level `transition()` fires when the layout's default outlet content changes but **not** when a `<ParallelOutlet />` mounts new content (modal opens are not subtree updates of the layout VT). See [skills/view-transitions](../view-transitions/SKILL.md) for the wrap rules and the intercept caveat.
238
+
239
+ ### Two scopes for explicit `use`: shared (broadcast) and slot-local
240
+
241
+ `parallel({...slots}, () => [...use])` runs the shared `use()` callback **once per slot** ([dsl-helpers.ts](../../src/route-definition/dsl-helpers.ts)) — items in that callback land on every slot's entry. That's the right behavior for the items the parallel allow-list permits and that accumulate (`loader`, `revalidate`, `errorBoundary`, `notFoundBoundary`, `transition`). (Slots cannot bring `middleware` or `layout` — see the allowed-types note above.)
242
+
243
+ For single-assignment items like `loading()`, broadcasting overwrites every slot's `handler.use` default. Pass a **slot descriptor** `{ handler, use }` instead — items in the descriptor's `use` apply only to that slot:
244
+
245
+ ```typescript
246
+ // @cart gets a custom skeleton; @notifs keeps its handler.use default.
247
+ parallel({
248
+ "@cart": {
249
+ handler: Cart,
250
+ use: () => [loading(<CustomCartSkeleton />)],
251
+ },
252
+ "@notifs": Notifs,
253
+ });
254
+
255
+ // Opt one slot out of streaming while siblings still stream the broadcast.
256
+ parallel(
257
+ {
258
+ "@cart": { handler: Cart, use: () => [loading(false)] },
259
+ "@notifs": Notifs,
260
+ },
261
+ () => [loading(<BroadcastSkeleton />)],
262
+ );
263
+ ```
264
+
265
+ Per-slot merge order is **handler.use → shared use → slot-local use**. Slot-local is the narrowest scope, so it wins for last-write-wins items. See [skills/handler-use § `loading()` is a single-assignment item — scope it correctly](../handler-use/SKILL.md#loading-is-a-single-assignment-item--scope-it-correctly) for the full reasoning.
266
+
209
267
  ## Slot Override Semantics
210
268
 
211
269
  When multiple `parallel()` calls define the same slot name, **the last
@@ -272,6 +330,8 @@ parallel({
272
330
  Control when parallel routes revalidate:
273
331
 
274
332
  ```typescript
333
+ import * as CartActions from "./actions/cart";
334
+
275
335
  parallel(
276
336
  {
277
337
  "@cart": () => <CartSummary />,
@@ -279,7 +339,7 @@ parallel(
279
339
  () => [
280
340
  loader(CartLoader),
281
341
  // Revalidate when cart actions occur
282
- revalidate(({ actionId }) => actionId?.includes("Cart") ?? false),
342
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
283
343
  ]
284
344
  )
285
345
  ```
@@ -288,6 +348,13 @@ Revalidating only the parallel does not re-run outer handlers/layouts.
288
348
  If the slot reads `ctx.get()` data established above it, opt the outer
289
349
  segment into revalidation as well.
290
350
 
351
+ A `revalidate()` callback may return a hard `boolean`, a soft
352
+ `{ defaultShouldRevalidate }` object, or nothing (`void` / `null` /
353
+ `undefined`) to defer to the next revalidator. See
354
+ [loader/SKILL.md#revalidate-return-shapes](../loader/SKILL.md#revalidate-return-shapes)
355
+ for the full contract — it's the same across `loader()`, `path()`,
356
+ `layout()`, `parallel()`, and `intercept()`.
357
+
291
358
  ### Revalidation Contracts for Parallel Dependencies
292
359
 
293
360
  Prefer named revalidation contracts shared by both the upstream producer and
@@ -295,8 +362,10 @@ the parallel consumer:
295
362
 
296
363
  ```typescript
297
364
  // revalidation-contracts.ts
298
- export const revalidateCartData = ({ actionId }) =>
299
- actionId?.includes("src/actions/cart.ts#") ?? false;
365
+ import * as CartActions from "./actions/cart";
366
+
367
+ export const revalidateCartData = (ctx) =>
368
+ ctx.isAction(CartActions) || undefined;
300
369
 
301
370
  layout(CartLayout, () => [
302
371
  revalidate(revalidateCartData), // producer reruns
@@ -364,6 +433,7 @@ function MyLayout() {
364
433
  ```typescript
365
434
  import { urls } from "@rangojs/router";
366
435
  import { Outlet, ParallelOutlet } from "@rangojs/router/client";
436
+ import * as CartActions from "./actions/cart";
367
437
 
368
438
  function ShopLayout() {
369
439
  return (
@@ -414,7 +484,7 @@ export const shopPatterns = urls(({
414
484
  () => [
415
485
  loader(CartLoader),
416
486
  loading(<CartSkeleton />),
417
- revalidate(({ actionId }) => actionId?.includes("Cart") ?? false),
487
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
418
488
  ]
419
489
  ),
420
490