@rangojs/router 0.0.0-experimental.79 → 0.0.0-experimental.7c7e4327

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 (440) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +301 -797
  3. package/dist/bin/rango.js +603 -145
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3750 -1160
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +96 -24
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +85 -6
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +228 -33
  12. package/skills/caching/SKILL.md +336 -19
  13. package/skills/catalog.json +271 -0
  14. package/skills/comparison/SKILL.md +50 -0
  15. package/skills/comparison/agents/openai.yaml +4 -0
  16. package/skills/comparison/references/framework-comparison.md +837 -0
  17. package/skills/composability/SKILL.md +110 -4
  18. package/skills/css/SKILL.md +76 -0
  19. package/skills/debug-manifest/SKILL.md +5 -3
  20. package/skills/defer-hydration/SKILL.md +235 -0
  21. package/skills/document-cache/SKILL.md +87 -56
  22. package/skills/fonts/SKILL.md +1 -1
  23. package/skills/handler-use/SKILL.md +12 -10
  24. package/skills/hooks/SKILL.md +73 -691
  25. package/skills/hooks/data.md +273 -0
  26. package/skills/hooks/handle-and-actions.md +103 -0
  27. package/skills/hooks/navigation.md +110 -0
  28. package/skills/hooks/outlets.md +41 -0
  29. package/skills/hooks/state.md +228 -0
  30. package/skills/hooks/urls.md +135 -0
  31. package/skills/host-router/SKILL.md +129 -27
  32. package/skills/i18n/SKILL.md +276 -0
  33. package/skills/intercept/SKILL.md +75 -19
  34. package/skills/layout/SKILL.md +40 -19
  35. package/skills/links/SKILL.md +247 -17
  36. package/skills/loader/SKILL.md +248 -10
  37. package/skills/middleware/SKILL.md +25 -13
  38. package/skills/migrate-nextjs/SKILL.md +205 -20
  39. package/skills/migrate-react-router/SKILL.md +59 -670
  40. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  41. package/skills/migrate-react-router/component-migration.md +196 -0
  42. package/skills/migrate-react-router/data-and-actions.md +225 -0
  43. package/skills/migrate-react-router/route-mapping.md +271 -0
  44. package/skills/mime-routes/SKILL.md +29 -2
  45. package/skills/observability/SKILL.md +202 -0
  46. package/skills/parallel/SKILL.md +40 -10
  47. package/skills/ppr/SKILL.md +616 -0
  48. package/skills/prerender/SKILL.md +72 -60
  49. package/skills/rango/SKILL.md +318 -26
  50. package/skills/react-compiler/SKILL.md +168 -0
  51. package/skills/response-routes/SKILL.md +138 -49
  52. package/skills/route/SKILL.md +117 -9
  53. package/skills/router-setup/SKILL.md +44 -9
  54. package/skills/scripts/SKILL.md +179 -0
  55. package/skills/server-actions/SKILL.md +776 -0
  56. package/skills/shell-manifest/SKILL.md +185 -0
  57. package/skills/streams-and-websockets/SKILL.md +283 -0
  58. package/skills/tailwind/SKILL.md +28 -4
  59. package/skills/testing/SKILL.md +130 -0
  60. package/skills/testing/bindings.md +103 -0
  61. package/skills/testing/cache-prerender.md +127 -0
  62. package/skills/testing/client-components.md +124 -0
  63. package/skills/testing/e2e-parity.md +125 -0
  64. package/skills/testing/flight.md +91 -0
  65. package/skills/testing/handles.md +131 -0
  66. package/skills/testing/loader.md +128 -0
  67. package/skills/testing/middleware.md +99 -0
  68. package/skills/testing/render-handler.md +122 -0
  69. package/skills/testing/response-routes.md +95 -0
  70. package/skills/testing/reverse-and-types.md +85 -0
  71. package/skills/testing/server-actions.md +107 -0
  72. package/skills/testing/server-tree.md +128 -0
  73. package/skills/testing/setup.md +123 -0
  74. package/skills/theme/SKILL.md +1 -1
  75. package/skills/typesafety/SKILL.md +45 -626
  76. package/skills/typesafety/env-and-bindings.md +254 -0
  77. package/skills/typesafety/generated-files-and-cli.md +335 -0
  78. package/skills/typesafety/params-and-search.md +153 -0
  79. package/skills/typesafety/route-types.md +209 -0
  80. package/skills/use-cache/SKILL.md +74 -15
  81. package/skills/vercel/SKILL.md +128 -0
  82. package/skills/view-transitions/SKILL.md +337 -0
  83. package/src/__augment-tests__/augment.ts +81 -0
  84. package/src/__augment-tests__/augmented.check.ts +116 -0
  85. package/src/__internal.ts +0 -65
  86. package/src/browser/action-coordinator.ts +53 -36
  87. package/src/browser/action-fence.ts +47 -0
  88. package/src/browser/app-shell.ts +39 -0
  89. package/src/browser/connection-warmup.ts +134 -0
  90. package/src/browser/cookie-name.ts +140 -0
  91. package/src/browser/event-controller.ts +252 -158
  92. package/src/browser/history-state.ts +21 -0
  93. package/src/browser/index.ts +3 -3
  94. package/src/browser/invalidate-client-cache.ts +52 -0
  95. package/src/browser/logging.ts +28 -0
  96. package/src/browser/merge-segment-loaders.ts +6 -4
  97. package/src/browser/navigation-bridge.ts +94 -25
  98. package/src/browser/navigation-client.ts +144 -79
  99. package/src/browser/navigation-store-handle.ts +38 -0
  100. package/src/browser/navigation-store.ts +161 -73
  101. package/src/browser/navigation-transaction.ts +9 -59
  102. package/src/browser/network-error-handler.ts +34 -7
  103. package/src/browser/partial-update.ts +183 -144
  104. package/src/browser/prefetch/cache.ts +242 -77
  105. package/src/browser/prefetch/fetch.ts +325 -69
  106. package/src/browser/prefetch/queue.ts +61 -12
  107. package/src/browser/rango-state.ts +158 -76
  108. package/src/browser/react/Link.tsx +58 -20
  109. package/src/browser/react/NavigationProvider.tsx +202 -120
  110. package/src/browser/react/ScrollRestoration.tsx +10 -6
  111. package/src/browser/react/filter-segment-order.ts +66 -7
  112. package/src/browser/react/index.ts +0 -48
  113. package/src/browser/react/location-state-shared.ts +178 -8
  114. package/src/browser/react/location-state.ts +39 -14
  115. package/src/browser/react/use-action.ts +6 -15
  116. package/src/browser/react/use-handle.ts +17 -14
  117. package/src/browser/react/use-href.tsx +8 -1
  118. package/src/browser/react/use-link-status.ts +33 -8
  119. package/src/browser/react/use-navigation.ts +32 -7
  120. package/src/browser/react/use-params.ts +20 -10
  121. package/src/browser/react/use-reverse.ts +106 -0
  122. package/src/browser/react/use-router.ts +25 -3
  123. package/src/browser/react/use-search-params.ts +0 -5
  124. package/src/browser/react/use-segments.ts +11 -21
  125. package/src/browser/response-adapter.ts +99 -8
  126. package/src/browser/rsc-router.tsx +145 -28
  127. package/src/browser/scroll-restoration.ts +37 -22
  128. package/src/browser/segment-reconciler.ts +31 -21
  129. package/src/browser/segment-structure-assert.ts +2 -2
  130. package/src/browser/server-action-bridge.ts +236 -65
  131. package/src/browser/types.ts +102 -9
  132. package/src/browser/validate-redirect-origin.ts +43 -16
  133. package/src/build/collect-fallback-refs.ts +107 -0
  134. package/src/build/generate-manifest.ts +203 -154
  135. package/src/build/generate-route-types.ts +3 -1
  136. package/src/build/index.ts +11 -3
  137. package/src/build/prefix-tree-utils.ts +123 -0
  138. package/src/build/route-trie.ts +152 -21
  139. package/src/build/route-types/ast-route-extraction.ts +15 -8
  140. package/src/build/route-types/codegen.ts +16 -5
  141. package/src/build/route-types/include-resolution.ts +456 -62
  142. package/src/build/route-types/param-extraction.ts +6 -3
  143. package/src/build/route-types/per-module-writer.ts +22 -6
  144. package/src/build/route-types/router-processing.ts +128 -51
  145. package/src/build/route-types/scan-filter.ts +1 -1
  146. package/src/build/route-types/source-scan.ts +216 -0
  147. package/src/build/runtime-discovery.ts +13 -21
  148. package/src/cache/cache-error.ts +104 -0
  149. package/src/cache/cache-key-utils.ts +58 -13
  150. package/src/cache/cache-policy.ts +108 -34
  151. package/src/cache/cache-runtime.ts +421 -58
  152. package/src/cache/cache-scope.ts +187 -96
  153. package/src/cache/cache-tag.ts +149 -0
  154. package/src/cache/cf/cf-base64.ts +33 -0
  155. package/src/cache/cf/cf-cache-constants.ts +127 -0
  156. package/src/cache/cf/cf-cache-store.ts +2202 -372
  157. package/src/cache/cf/cf-cache-types.ts +349 -0
  158. package/src/cache/cf/cf-kv-utils.ts +46 -0
  159. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  160. package/src/cache/cf/index.ts +6 -16
  161. package/src/cache/document-cache.ts +126 -41
  162. package/src/cache/handle-snapshot.ts +70 -0
  163. package/src/cache/index.ts +23 -20
  164. package/src/cache/memory-segment-store.ts +243 -37
  165. package/src/cache/profile-registry.ts +46 -31
  166. package/src/cache/read-through-swr.ts +56 -12
  167. package/src/cache/segment-codec.ts +13 -21
  168. package/src/cache/shell-snapshot.ts +417 -0
  169. package/src/cache/tag-invalidation.ts +230 -0
  170. package/src/cache/types.ts +180 -99
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1127 -0
  173. package/src/client.rsc.tsx +41 -21
  174. package/src/client.tsx +33 -61
  175. package/src/cloudflare/index.ts +11 -0
  176. package/src/cloudflare/tracing.ts +108 -0
  177. package/src/component-utils.ts +19 -0
  178. package/src/components/DefaultDocument.tsx +8 -2
  179. package/src/context-var.ts +18 -6
  180. package/src/decode-loader-results.ts +52 -0
  181. package/src/defer.ts +185 -0
  182. package/src/deps/ssr.ts +0 -1
  183. package/src/encode-kv.ts +49 -0
  184. package/src/errors.ts +30 -4
  185. package/src/escape-script.ts +52 -0
  186. package/src/handle.ts +67 -37
  187. package/src/handles/MetaTags.tsx +24 -53
  188. package/src/handles/Scripts.tsx +183 -0
  189. package/src/handles/breadcrumbs.ts +35 -8
  190. package/src/handles/deferred-resolution.ts +127 -0
  191. package/src/handles/is-thenable.ts +18 -0
  192. package/src/handles/meta.ts +14 -40
  193. package/src/handles/script.ts +244 -0
  194. package/src/host/cookie-handler.ts +9 -60
  195. package/src/host/errors.ts +13 -22
  196. package/src/host/index.ts +9 -2
  197. package/src/host/pattern-matcher.ts +23 -52
  198. package/src/host/router.ts +107 -99
  199. package/src/host/testing.ts +40 -27
  200. package/src/host/types.ts +37 -4
  201. package/src/host/utils.ts +1 -1
  202. package/src/href-client.ts +137 -22
  203. package/src/index.rsc.ts +97 -12
  204. package/src/index.ts +98 -14
  205. package/src/internal-debug.ts +11 -10
  206. package/src/loader-store.ts +500 -0
  207. package/src/loader.rsc.ts +20 -13
  208. package/src/loader.ts +12 -11
  209. package/src/missing-id-error.ts +68 -0
  210. package/src/outlet-context.ts +1 -1
  211. package/src/outlet-provider.tsx +1 -5
  212. package/src/prerender/param-hash.ts +16 -16
  213. package/src/prerender/store.ts +32 -37
  214. package/src/prerender.ts +78 -10
  215. package/src/redirect-origin.ts +114 -0
  216. package/src/regex-escape.ts +8 -0
  217. package/src/render-error-thrower.tsx +20 -0
  218. package/src/response-utils.ts +62 -0
  219. package/src/reverse.ts +65 -39
  220. package/src/root-error-boundary.tsx +1 -19
  221. package/src/route-content-wrapper.tsx +19 -77
  222. package/src/route-definition/dsl-helpers.ts +304 -309
  223. package/src/route-definition/helper-factories.ts +28 -140
  224. package/src/route-definition/helpers-types.ts +87 -59
  225. package/src/route-definition/index.ts +1 -2
  226. package/src/route-definition/redirect.ts +44 -11
  227. package/src/route-definition/resolve-handler-use.ts +12 -1
  228. package/src/route-definition/use-item-types.ts +29 -0
  229. package/src/route-map-builder.ts +41 -20
  230. package/src/route-types.ts +19 -46
  231. package/src/router/basename.ts +14 -0
  232. package/src/router/content-negotiation.ts +73 -25
  233. package/src/router/error-handling.ts +45 -18
  234. package/src/router/find-match.ts +129 -30
  235. package/src/router/handler-context.ts +27 -42
  236. package/src/router/instrument.ts +355 -0
  237. package/src/router/intercept-resolution.ts +39 -20
  238. package/src/router/lazy-includes.ts +82 -59
  239. package/src/router/loader-resolution.ts +167 -72
  240. package/src/router/logging.ts +0 -6
  241. package/src/router/manifest.ts +74 -40
  242. package/src/router/match-api.ts +80 -55
  243. package/src/router/match-context.ts +0 -22
  244. package/src/router/match-handlers.ts +211 -165
  245. package/src/router/match-middleware/background-revalidation.ts +40 -24
  246. package/src/router/match-middleware/cache-lookup.ts +159 -285
  247. package/src/router/match-middleware/cache-store.ts +64 -52
  248. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  249. package/src/router/match-middleware/segment-resolution.ts +0 -22
  250. package/src/router/match-pipelines.ts +1 -42
  251. package/src/router/match-result.ts +69 -79
  252. package/src/router/metrics.ts +0 -34
  253. package/src/router/middleware-types.ts +7 -134
  254. package/src/router/middleware.ts +298 -172
  255. package/src/router/navigation-snapshot.ts +7 -56
  256. package/src/router/params-util.ts +23 -0
  257. package/src/router/parse-pattern.ts +115 -0
  258. package/src/router/pattern-matching.ts +181 -150
  259. package/src/router/prefetch-cache-ttl.ts +51 -0
  260. package/src/router/prefetch-limits.ts +37 -0
  261. package/src/router/prerender-match.ts +112 -67
  262. package/src/router/preview-match.ts +6 -2
  263. package/src/router/request-classification.ts +50 -69
  264. package/src/router/revalidation.ts +123 -73
  265. package/src/router/route-snapshot.ts +14 -3
  266. package/src/router/router-context.ts +6 -29
  267. package/src/router/router-interfaces.ts +115 -36
  268. package/src/router/router-options.ts +166 -5
  269. package/src/router/router-registry.ts +2 -5
  270. package/src/router/segment-resolution/fresh.ts +131 -86
  271. package/src/router/segment-resolution/helpers.ts +86 -6
  272. package/src/router/segment-resolution/loader-cache.ts +139 -39
  273. package/src/router/segment-resolution/loader-mask.ts +67 -0
  274. package/src/router/segment-resolution/loader-snapshot.ts +251 -0
  275. package/src/router/segment-resolution/revalidation.ts +272 -320
  276. package/src/router/segment-resolution/static-store.ts +19 -5
  277. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  278. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  279. package/src/router/segment-resolution.ts +5 -1
  280. package/src/router/segment-wrappers.ts +6 -5
  281. package/src/router/state-cookie-name.ts +33 -0
  282. package/src/router/substitute-pattern-params.ts +75 -0
  283. package/src/router/telemetry-otel.ts +160 -200
  284. package/src/router/telemetry.ts +105 -20
  285. package/src/router/timeout.ts +0 -20
  286. package/src/router/tracing.ts +215 -0
  287. package/src/router/trie-matching.ts +171 -59
  288. package/src/router/types.ts +9 -63
  289. package/src/router/url-params.ts +57 -0
  290. package/src/router.ts +157 -71
  291. package/src/rsc/full-payload.ts +70 -0
  292. package/src/rsc/handler-context.ts +3 -2
  293. package/src/rsc/handler.ts +291 -217
  294. package/src/rsc/helpers.ts +168 -46
  295. package/src/rsc/index.ts +2 -5
  296. package/src/rsc/json-route-result.ts +38 -0
  297. package/src/rsc/loader-fetch.ts +114 -38
  298. package/src/rsc/manifest-init.ts +29 -42
  299. package/src/rsc/nonce.ts +10 -1
  300. package/src/rsc/origin-guard.ts +39 -25
  301. package/src/rsc/progressive-enhancement.ts +124 -13
  302. package/src/rsc/redirect-guard.ts +100 -0
  303. package/src/rsc/response-cache-serve.ts +238 -0
  304. package/src/rsc/response-error.ts +79 -12
  305. package/src/rsc/response-route-handler.ts +99 -189
  306. package/src/rsc/rsc-rendering.ts +421 -76
  307. package/src/rsc/runtime-warnings.ts +23 -10
  308. package/src/rsc/server-action.ts +282 -116
  309. package/src/rsc/shell-capture.ts +1158 -0
  310. package/src/rsc/shell-serve.ts +150 -0
  311. package/src/rsc/ssr-setup.ts +16 -0
  312. package/src/rsc/transition-gate.ts +89 -0
  313. package/src/rsc/types.ts +53 -5
  314. package/src/runtime-env.ts +18 -0
  315. package/src/search-params.ts +35 -30
  316. package/src/segment-loader-promise.ts +49 -4
  317. package/src/segment-system.tsx +350 -149
  318. package/src/serialize.ts +243 -0
  319. package/src/server/context.ts +208 -51
  320. package/src/server/cookie-parse.ts +32 -0
  321. package/src/server/cookie-store.ts +152 -5
  322. package/src/server/handle-store.ts +21 -38
  323. package/src/server/loader-registry.ts +33 -42
  324. package/src/server/request-context.ts +395 -176
  325. package/src/ssr/index.tsx +458 -178
  326. package/src/ssr/ssr-root.tsx +228 -0
  327. package/src/static-handler.ts +10 -13
  328. package/src/testing/cache-status.ts +162 -0
  329. package/src/testing/collect-handle.ts +46 -0
  330. package/src/testing/dispatch.ts +813 -0
  331. package/src/testing/dom.entry.ts +22 -0
  332. package/src/testing/e2e/fixture.ts +188 -0
  333. package/src/testing/e2e/index.ts +128 -0
  334. package/src/testing/e2e/matchers.ts +35 -0
  335. package/src/testing/e2e/page-helpers.ts +272 -0
  336. package/src/testing/e2e/parity.ts +387 -0
  337. package/src/testing/e2e/server.ts +195 -0
  338. package/src/testing/flight-matchers.ts +97 -0
  339. package/src/testing/flight-normalize.ts +11 -0
  340. package/src/testing/flight-runtime.d.ts +57 -0
  341. package/src/testing/flight-tree.ts +682 -0
  342. package/src/testing/flight.entry.ts +52 -0
  343. package/src/testing/flight.ts +257 -0
  344. package/src/testing/generated-routes.ts +199 -0
  345. package/src/testing/index.ts +105 -0
  346. package/src/testing/internal/context.ts +371 -0
  347. package/src/testing/internal/flight-client-globals.ts +30 -0
  348. package/src/testing/internal/seed-vars.ts +54 -0
  349. package/src/testing/render-handler.ts +357 -0
  350. package/src/testing/render-route.tsx +584 -0
  351. package/src/testing/run-loader.ts +385 -0
  352. package/src/testing/run-middleware.ts +205 -0
  353. package/src/testing/run-transition-when.ts +164 -0
  354. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  355. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  356. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  357. package/src/testing/vitest-stubs/version.ts +5 -0
  358. package/src/testing/vitest.ts +305 -0
  359. package/src/theme/ThemeProvider.tsx +56 -84
  360. package/src/theme/ThemeScript.tsx +7 -9
  361. package/src/theme/constants.ts +52 -13
  362. package/src/theme/index.ts +0 -7
  363. package/src/theme/theme-context.ts +1 -5
  364. package/src/theme/theme-script.ts +22 -21
  365. package/src/theme/use-theme.ts +0 -3
  366. package/src/types/boundaries.ts +0 -35
  367. package/src/types/cache-types.ts +13 -4
  368. package/src/types/error-types.ts +30 -90
  369. package/src/types/global-namespace.ts +54 -41
  370. package/src/types/handler-context.ts +110 -62
  371. package/src/types/index.ts +3 -10
  372. package/src/types/loader-types.ts +11 -9
  373. package/src/types/request-scope.ts +112 -0
  374. package/src/types/route-config.ts +20 -52
  375. package/src/types/route-entry.ts +0 -6
  376. package/src/types/segments.ts +135 -14
  377. package/src/urls/include-helper.ts +19 -64
  378. package/src/urls/include-provider.ts +71 -0
  379. package/src/urls/index.ts +2 -11
  380. package/src/urls/path-helper-types.ts +63 -17
  381. package/src/urls/path-helper.ts +22 -106
  382. package/src/urls/pattern-types.ts +72 -19
  383. package/src/urls/response-types.ts +22 -29
  384. package/src/urls/type-extraction.ts +98 -154
  385. package/src/urls/urls-function.ts +1 -19
  386. package/src/use-loader.tsx +292 -107
  387. package/src/vercel/index.ts +11 -0
  388. package/src/vercel/tracing.ts +88 -0
  389. package/src/vite/debug.ts +185 -0
  390. package/src/vite/discovery/bundle-postprocess.ts +8 -7
  391. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  392. package/src/vite/discovery/discover-routers.ts +127 -86
  393. package/src/vite/discovery/discovery-errors.ts +255 -0
  394. package/src/vite/discovery/gate-state.ts +171 -0
  395. package/src/vite/discovery/prerender-collection.ts +96 -68
  396. package/src/vite/discovery/route-types-writer.ts +40 -84
  397. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  398. package/src/vite/discovery/state.ts +45 -1
  399. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  400. package/src/vite/index.ts +4 -0
  401. package/src/vite/inject-client-debug.ts +88 -0
  402. package/src/vite/plugin-types.ts +210 -10
  403. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  404. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  405. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  406. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  407. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  408. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  409. package/src/vite/plugins/expose-action-id.ts +48 -95
  410. package/src/vite/plugins/expose-id-utils.ts +88 -55
  411. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  412. package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
  413. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  414. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  415. package/src/vite/plugins/expose-internal-ids.ts +505 -486
  416. package/src/vite/plugins/performance-tracks.ts +26 -25
  417. package/src/vite/plugins/refresh-cmd.ts +1 -1
  418. package/src/vite/plugins/use-cache-transform.ts +73 -83
  419. package/src/vite/plugins/vercel-output.ts +384 -0
  420. package/src/vite/plugins/version-injector.ts +40 -29
  421. package/src/vite/plugins/version-plugin.ts +37 -40
  422. package/src/vite/plugins/virtual-entries.ts +138 -27
  423. package/src/vite/rango.ts +236 -138
  424. package/src/vite/router-discovery.ts +927 -136
  425. package/src/vite/utils/ast-handler-extract.ts +26 -35
  426. package/src/vite/utils/banner.ts +1 -1
  427. package/src/vite/utils/bundle-analysis.ts +10 -15
  428. package/src/vite/utils/client-chunks.ts +184 -0
  429. package/src/vite/utils/directive-prologue.ts +40 -0
  430. package/src/vite/utils/forward-user-plugins.ts +171 -0
  431. package/src/vite/utils/manifest-utils.ts +4 -59
  432. package/src/vite/utils/package-resolution.ts +20 -52
  433. package/src/vite/utils/prerender-utils.ts +71 -43
  434. package/src/vite/utils/shared-utils.ts +142 -43
  435. package/src/browser/action-response-classifier.ts +0 -99
  436. package/src/browser/react/use-client-cache.ts +0 -58
  437. package/src/browser/shallow.ts +0 -40
  438. package/src/handles/index.ts +0 -7
  439. package/src/network-error-thrower.tsx +0 -23
  440. package/src/router/middleware-cookies.ts +0 -55
@@ -0,0 +1,271 @@
1
+ # Project Setup and Route Mapping
2
+
3
+ ## 1. Project Setup
4
+
5
+ Replace React Router tooling with Vite + Rango:
6
+
7
+ ```bash
8
+ # Framework mode:
9
+ npm remove react-router @react-router/dev @react-router/node @react-router/serve
10
+ # Library mode:
11
+ npm remove react-router react-router-dom
12
+
13
+ npm install @rangojs/router
14
+ ```
15
+
16
+ Replace the `@react-router/dev` Vite plugin with `rango()`:
17
+
18
+ ```typescript
19
+ // vite.config.ts
20
+ // Before: import { reactRouter } from "@react-router/dev/vite";
21
+ import { defineConfig } from "vite";
22
+ import { rango } from "@rangojs/router/vite";
23
+
24
+ export default defineConfig({
25
+ plugins: [rango()],
26
+ });
27
+ ```
28
+
29
+ Delete `react-router.config.ts` — route configuration moves to the `urls()` DSL.
30
+
31
+ ```typescript
32
+ // src/router.tsx
33
+ import { createRouter } from "@rangojs/router";
34
+ import { Document } from "./document";
35
+ import { urlpatterns } from "./urls";
36
+
37
+ export default createRouter({
38
+ document: Document,
39
+ }).routes(urlpatterns);
40
+ ```
41
+
42
+ ## 2. Route Mapping
43
+
44
+ ### RR7 framework mode: route modules → urls() DSL
45
+
46
+ In framework mode, each route is a file with conventional exports (`loader`,
47
+ `action`, `default`, `meta`, `headers`, `shouldRevalidate`, `handle`,
48
+ `ErrorBoundary`, `HydrateFallback`). In Rango, all of these become part of the
49
+ `urls()` DSL or move into the server component handler:
50
+
51
+ ```text
52
+ RR7 route module export → Rango equivalent
53
+ ─────────────────────────────────────────────────────
54
+ default (Component) → handler in path()
55
+ loader → fetch in handler, or createLoader()
56
+ action → "use server" function
57
+ meta → ctx.use(Meta) in handler
58
+ headers → ctx.header() in handler or middleware
59
+ shouldRevalidate → revalidate() DSL
60
+ ErrorBoundary → errorBoundary() DSL
61
+ HydrateFallback → loading() DSL
62
+ handle → createHandle() for cross-segment data (breadcrumbs, etc.)
63
+ clientLoader / clientAction → "use client" component with React hooks
64
+ ```
65
+
66
+ #### Example: full route module migration
67
+
68
+ ```typescript
69
+ // RR7 framework mode: app/routes/product.$slug.tsx
70
+ import type { Route } from "./+types/product.$slug";
71
+
72
+ export async function loader({ params }: Route.LoaderArgs) {
73
+ const product = await getProduct(params.slug);
74
+ if (!product) throw new Response("Not Found", { status: 404 });
75
+ return { product };
76
+ }
77
+
78
+ export async function action({ request }: Route.ActionArgs) {
79
+ const formData = await request.formData();
80
+ await addToCart(formData.get("productId") as string);
81
+ return { ok: true };
82
+ }
83
+
84
+ export function meta({ data }: Route.MetaArgs) {
85
+ return [{ title: data.product.name }];
86
+ }
87
+
88
+ export function headers() {
89
+ return { "Cache-Control": "max-age=300" };
90
+ }
91
+
92
+ export function shouldRevalidate({ actionResult }) {
93
+ return !!actionResult;
94
+ }
95
+
96
+ export default function ProductPage({ loaderData }: Route.ComponentProps) {
97
+ return <div>{loaderData.product.name}</div>;
98
+ }
99
+
100
+ export function ErrorBoundary() {
101
+ return <div>Product error</div>;
102
+ }
103
+ ```
104
+
105
+ ```typescript
106
+ // Rango: urls.tsx + handler
107
+ import { notFound } from "@rangojs/router";
108
+
109
+ const ProductPage: Handler<"product"> = async (ctx) => {
110
+ const product = await getProduct(ctx.params.slug);
111
+ if (!product) notFound("Product not found");
112
+
113
+ const meta = ctx.use(Meta);
114
+ meta({ title: product.name });
115
+ ctx.header("Cache-Control", "max-age=300");
116
+
117
+ return <div>{product.name}</div>;
118
+ };
119
+
120
+ // In urls.tsx:
121
+ path("/product/:slug", ProductPage, { name: "product" }, () => [
122
+ revalidate(({ actionId }) => !!actionId),
123
+ errorBoundary(() => <div>Product error</div>),
124
+ loading(<ProductSkeleton />),
125
+ ])
126
+ ```
127
+
128
+ Key shift: the route module's scattered exports consolidate into the handler
129
+ (data fetching, meta, headers) and the DSL (revalidation, error boundary, loading).
130
+
131
+ ### RR7 file routing → urls() DSL
132
+
133
+ | RR7 file path | Rango |
134
+ | ---------------------------------------- | ------------------------------------------------------------- |
135
+ | `app/routes/_index.tsx` | `path("/", HomePage, { name: "home" })` |
136
+ | `app/routes/about.tsx` | `path("/about", AboutPage, { name: "about" })` |
137
+ | `app/routes/blog.$slug.tsx` | `path("/blog/:slug", BlogPost, { name: "blogPost" })` |
138
+ | `app/routes/files.$.tsx` (splat) | `path("/files/:path*", FileBrowser, { name: "files" })` |
139
+ | `app/routes/dashboard.tsx` (layout) | `layout(<DashboardLayout />, () => [...])` |
140
+ | `app/routes/dashboard._index.tsx` | `path("/dashboard", DashboardIndex, { name: "dashboard" })` |
141
+ | `app/routes/dashboard.settings.tsx` | `path("/dashboard/settings", Settings, { name: "settings" })` |
142
+ | `app/routes/_auth.tsx` (pathless layout) | `layout(<AuthLayout />, () => [...])` |
143
+ | `app/routes/_auth.login.tsx` | `path("/login", LoginPage, { name: "login" })` |
144
+
145
+ ### Library mode: config routes → urls() DSL
146
+
147
+ | React Router | Rango |
148
+ | -------------------------------------- | ------------------------------------------------------- |
149
+ | `path: "/"` | `path("/", HomePage, { name: "home" })` |
150
+ | `path: "about"` | `path("/about", AboutPage, { name: "about" })` |
151
+ | `path: "blog/:slug"` | `path("/blog/:slug", BlogPost, { name: "blogPost" })` |
152
+ | `path: "files/*"` (splat) | `path("/files/:path*", FileBrowser, { name: "files" })` |
153
+ | `path: "docs/:lang?"` (optional param) | `path("/docs/:lang?", Docs, { name: "docs" })` |
154
+
155
+ The RR splat (`$` / `*`) matches the bare parent too (`/files` binds `""`), so
156
+ it maps to `:path*` (zero-or-more). Use `:path+` only when you require at least
157
+ one trailing segment. RR reads the splat at `params["*"]`; Rango exposes it as a
158
+ named string at `ctx.params.path` with the `/` separators preserved (split to
159
+ recover RR's array):
160
+
161
+ ```typescript
162
+ path("/files/:path*", (ctx) => {
163
+ const parts = ctx.params.path === "" ? [] : ctx.params.path.split("/");
164
+ return <FileBrowser path={parts} />;
165
+ }, { name: "files" });
166
+ ```
167
+
168
+ ### Layouts
169
+
170
+ React Router layouts use `<Outlet />` — same concept in Rango:
171
+
172
+ ```typescript
173
+ // React Router:
174
+ function DashboardLayout() {
175
+ return (
176
+ <div className="dashboard">
177
+ <Outlet />
178
+ </div>
179
+ );
180
+ }
181
+
182
+ // route config:
183
+ { path: "dashboard", element: <DashboardLayout />, children: [...] }
184
+
185
+ // Rango: same <Outlet />, from @rangojs/router/client
186
+ import { Outlet } from "@rangojs/router/client";
187
+
188
+ layout(<DashboardLayout />, () => [
189
+ path("/dashboard", DashboardIndex, { name: "dashboard" }),
190
+ path("/dashboard/settings", Settings, { name: "settings" }),
191
+ ])
192
+ ```
193
+
194
+ ### Dynamic layouts (with data)
195
+
196
+ ```typescript
197
+ // React Router: useLoaderData() in layout component
198
+ function DashboardLayout() {
199
+ const { user } = useLoaderData();
200
+ return <Shell user={user}><Outlet /></Shell>;
201
+ }
202
+
203
+ // Rango: handler function layout (server component)
204
+ layout(async (ctx) => {
205
+ const user = ctx.get("user");
206
+ return (
207
+ <Shell user={user}>
208
+ <Outlet />
209
+ </Shell>
210
+ );
211
+ }, () => [
212
+ path("/dashboard", DashboardIndex, { name: "dashboard" }),
213
+ ])
214
+ ```
215
+
216
+ ### Nested routes
217
+
218
+ React Router's nested route tree maps directly to Rango's `layout()` nesting:
219
+
220
+ ```typescript
221
+ // React Router:
222
+ createBrowserRouter([{
223
+ path: "/",
224
+ element: <RootLayout />,
225
+ children: [
226
+ { path: "dashboard",
227
+ element: <DashboardLayout />,
228
+ children: [
229
+ { index: true, element: <DashboardIndex /> },
230
+ { path: "settings", element: <Settings /> },
231
+ ]
232
+ },
233
+ ]
234
+ }])
235
+
236
+ // Rango:
237
+ urls(({ path, layout }) => [
238
+ layout(<RootLayout />, () => [
239
+ layout(<DashboardLayout />, () => [
240
+ path("/dashboard", DashboardIndex, { name: "dashboard" }),
241
+ path("/dashboard/settings", Settings, { name: "settings" }),
242
+ ]),
243
+ ]),
244
+ ])
245
+ ```
246
+
247
+ ### Route groups / pathless layouts
248
+
249
+ React Router's pathless routes (layout routes without a path) are Rango's
250
+ layouts without a URL prefix:
251
+
252
+ ```typescript
253
+ // React Router: { element: <AuthLayout />, children: [...] }
254
+
255
+ // Rango: layout with no URL segment
256
+ layout(<AuthLayout />, () => [
257
+ path("/login", LoginPage, { name: "login" }),
258
+ path("/register", RegisterPage, { name: "register" }),
259
+ ])
260
+ ```
261
+
262
+ ### Index routes
263
+
264
+ ```typescript
265
+ // React Router: { index: true, element: <Home /> }
266
+
267
+ // Rango: path with "/" inside a layout
268
+ layout(<RootLayout />, () => [
269
+ path("/", HomePage, { name: "home" }),
270
+ ])
271
+ ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mime-routes
3
- description: Content negotiation — serve different response types (RSC, JSON, text, XML) from the same URL based on Accept header
3
+ description: Content negotiation — serve different response types (RSC, JSON, text, XML) from the same URL based on Accept header. Use when the same URL needs to return JSON for API clients and HTML/RSC for browsers, or branching a handler on the Accept header.
4
4
  argument-hint: [negotiate|vary|accept]
5
5
  ---
6
6
 
@@ -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,202 @@
1
+ ---
2
+ name: observability
3
+ description: Debug Rango request performance with debugPerformance, Server-Timing, structured telemetry, and tracing. Use when a request feels slow and you need to see where time is spent, or wiring up tracing/telemetry for production requests.
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
+ **Deployed Cloudflare caveat**: on production Workers, timers are frozen
62
+ during request execution (Spectre mitigation), so `Server-Timing` durations
63
+ read as ~0 on the deployed edge — they only advance across genuine awaited
64
+ I/O. The waterfall is a LOCAL diagnostic (dev, `vite preview`,
65
+ `wrangler dev`); for deployed workers, measure from the client
66
+ (`PerformanceResourceTiming`, TTFB) and use structured telemetry below for
67
+ server-side events.
68
+
69
+ ## Structured telemetry
70
+
71
+ Use telemetry when you want durable production events rather than a one-request
72
+ debug waterfall.
73
+
74
+ ```typescript
75
+ import { createRouter, createConsoleSink } from "@rangojs/router";
76
+
77
+ const router = createRouter({
78
+ document: Document,
79
+ urls: urlpatterns,
80
+ telemetry: createConsoleSink(),
81
+ });
82
+ ```
83
+
84
+ For OpenTelemetry — phase spans come from the `tracing` slot
85
+ (`createOTelTracing`), discrete-fact spans from the `telemetry` sink
86
+ (`createOTelSink`):
87
+
88
+ ```typescript
89
+ import {
90
+ createRouter,
91
+ createOTelTracing,
92
+ createOTelSink,
93
+ } from "@rangojs/router";
94
+ import { trace } from "@opentelemetry/api";
95
+
96
+ const tracer = trace.getTracer("my-app");
97
+
98
+ const router = createRouter({
99
+ document: Document,
100
+ urls: urlpatterns,
101
+ tracing: createOTelTracing(tracer), // request/loader/render/… phase spans
102
+ telemetry: createOTelSink(tracer), // handler errors, cache decisions, …
103
+ });
104
+ ```
105
+
106
+ On **Cloudflare Workers**, use `createCloudflareTracing` for the `tracing` slot
107
+ instead — it emits the same phases as native Cloudflare custom spans (in the
108
+ Workers trace waterfall, next to the automatic KV/D1/fetch spans), with no
109
+ `@opentelemetry/api` dependency:
110
+
111
+ ```typescript
112
+ import { createRouter } from "@rangojs/router";
113
+ import { createCloudflareTracing } from "@rangojs/router/cloudflare";
114
+
115
+ const router = createRouter({
116
+ document: Document,
117
+ urls: urlpatterns,
118
+ tracing: createCloudflareTracing(), // all phases on by default
119
+ // tracing: createCloudflareTracing({ spans: { ssr: false } }), // toggle phases
120
+ });
121
+ ```
122
+
123
+ On **Vercel Functions** (Node runtime), use `createVercelTracing` — a thin
124
+ wrapper over `createOTelTracing` that reads the global OTel tracer
125
+ `@vercel/otel`'s `registerOTel()` installs, so you do not call `trace.getTracer`
126
+ yourself. Custom spans are Node-only (unsupported on the Edge runtime):
127
+
128
+ ```typescript
129
+ // instrumentation.ts — install the provider, then export the tracing config.
130
+ // Importing this module is what runs registerOTel() — a Rango/Vite app does not
131
+ // auto-load instrumentation.ts like Next.js, so a standalone registerOTel() that
132
+ // nothing imports is a silent no-op.
133
+ import { registerOTel } from "@vercel/otel";
134
+ import { createVercelTracing } from "@rangojs/router/vercel";
135
+ registerOTel({ serviceName: "my-app" });
136
+ export const tracing = createVercelTracing(); // { enabled, spans, tracerName, tracer }
137
+
138
+ // router.tsx — importing `tracing` runs instrumentation.ts
139
+ import { createRouter } from "@rangojs/router";
140
+ import { tracing } from "./instrumentation.js";
141
+
142
+ const router = createRouter({ document: Document, urls: urlpatterns, tracing });
143
+ ```
144
+
145
+ These factories return a `RouterTracingConfig` for the same `tracing` slot;
146
+ `telemetry` stays independent (events only, no phase spans). Phase spans:
147
+ `rango.request`, `rango.middleware`, `rango.action`, `rango.loader`,
148
+ `rango.render`, `rango.ssr` — the same phases the `debugPerformance` timeline
149
+ shows, co-emitted from one site. Off-platform (no Cloudflare tracing destination
150
+ / no OTel SDK) every span call is a transparent pass-through, so the request
151
+ behaves as if tracing were off.
152
+
153
+ Custom sinks implement `emit(event)`:
154
+
155
+ ```typescript
156
+ import { createRouter } from "@rangojs/router";
157
+
158
+ const router = createRouter({
159
+ document: Document,
160
+ urls: urlpatterns,
161
+ telemetry: {
162
+ emit(event) {
163
+ myMetrics.record(event);
164
+ },
165
+ },
166
+ });
167
+ ```
168
+
169
+ Events include `request.start/end/error`, `loader.start/end/error`,
170
+ `handler.error`, `cache.decision`, `revalidation.decision`, `request.timeout`,
171
+ and `request.origin-rejected`.
172
+
173
+ ## Debugging revalidation and stale data
174
+
175
+ When stale UI or unexpected partial renders are the question, use all three
176
+ layers together:
177
+
178
+ ```typescript
179
+ import { createConsoleSink, createRouter } from "@rangojs/router";
180
+
181
+ const router = createRouter({
182
+ document: Document,
183
+ urls: urlpatterns,
184
+ debugPerformance: true,
185
+ telemetry: createConsoleSink(),
186
+ });
187
+ ```
188
+
189
+ Then inspect:
190
+
191
+ - `revalidation.decision` telemetry to see which segment re-ran or skipped.
192
+ - cache spans / `cache.decision` events to see hit, miss, stale, and background
193
+ revalidation behavior.
194
+ - loader spans to confirm live loaders overlap the render rather than blocking
195
+ first paint.
196
+ - the `Server-Timing` header to compare local logs with browser-network timing.
197
+
198
+ ## Zero-overhead defaults
199
+
200
+ `debugPerformance` is off by default, and `telemetry` emits nothing unless a sink
201
+ is configured. Per-request `ctx.debugPerformance()` lets you turn on the
202
+ waterfall only for the route, user, or query param you are investigating.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: parallel
3
- description: Define parallel routes for multi-column layouts, sidebars, and modal slots in @rangojs/router
3
+ description: Define parallel routes for multi-column layouts, sidebars, and modal slots in @rangojs/router. Use when a layout needs multiple independently-loading regions (e.g. a sidebar and main panel), or rendering more than one route segment at the same URL.
4
4
  argument-hint: [@slot-name]
5
5
  ---
6
6
 
@@ -8,8 +8,12 @@ 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)
11
+ ## Not this skill if…
12
+
13
+ - You want a modal or slide-over that appears only on soft navigation and shows
14
+ the full page on hard navigation — that is `intercept()`: see `/intercept`.
15
+ - You want a slot rendered conditionally on HOW the user navigated — parallel
16
+ slots ALWAYS render alongside the page; see `/intercept`.
13
17
 
14
18
  ## Basic Parallel Routes
15
19
 
@@ -235,8 +239,12 @@ layout(<AccountLayout />, () => [
235
239
 
236
240
  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.
237
241
 
242
+ Under a shared artifact (`cache()`, `"use cache"`, a PPR shell), the server-side `await ctx.use(CartLoader)` above is the BAKED lane — the capture-time value (identity reads included) freezes into the artifact; consume the loader client-side (`useLoader` in a `"use client"` component) to keep the slot live per request. One rule, stated once: `/rango` → Invariants ("the consumption-lane rule").
243
+
238
244
  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.
239
245
 
246
+ `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.
247
+
240
248
  ### Two scopes for explicit `use`: shared (broadcast) and slot-local
241
249
 
242
250
  `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.)
@@ -265,6 +273,8 @@ parallel(
265
273
 
266
274
  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.
267
275
 
276
+ Typing note: a BARE arrow slot handler infers its ctx (`"@cart": (ctx) => ...`), but an arrow inside a DESCRIPTOR needs an explicit annotation — `handler: (ctx: HandlerContext) => ...` — because `StaticHandlerDefinition` in the slot union contributes a second callable to the contextual type and TS declines to pick a signature.
277
+
268
278
  ## Slot Override Semantics
269
279
 
270
280
  When multiple `parallel()` calls define the same slot name, **the last
@@ -331,6 +341,8 @@ parallel({
331
341
  Control when parallel routes revalidate:
332
342
 
333
343
  ```typescript
344
+ import * as CartActions from "./actions/cart";
345
+
334
346
  parallel(
335
347
  {
336
348
  "@cart": () => <CartSummary />,
@@ -338,14 +350,29 @@ parallel(
338
350
  () => [
339
351
  loader(CartLoader),
340
352
  // Revalidate when cart actions occur
341
- revalidate(({ actionId }) => actionId?.includes("Cart") ?? false),
353
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
342
354
  ]
343
355
  )
344
356
  ```
345
357
 
346
- Revalidating only the parallel does not re-run outer handlers/layouts.
347
- If the slot reads `ctx.get()` data established above it, opt the outer
348
- segment into revalidation as well.
358
+ Where the slot sits decides its action default. A parallel under a
359
+ `path()` (or one of its orphan layouts) belongs to the route entry and
360
+ revalidates together with it on every action — handler-set data stays
361
+ consistent with no configuration. A parallel under a standalone
362
+ `layout()` entry follows the parent-chain default instead: skipped on
363
+ actions unless a `revalidate()` opts it in.
364
+
365
+ In either position, revalidating only the parallel does not re-run outer
366
+ handlers/layouts. If the slot reads `ctx.get()` data established above
367
+ it, opt the outer segment into revalidation as well (see `/rango` →
368
+ "Passing data down the tree").
369
+
370
+ A `revalidate()` callback may return a hard `boolean`, a soft
371
+ `{ defaultShouldRevalidate }` object, or nothing (`void` / `null` /
372
+ `undefined`) to defer to the next revalidator. See
373
+ [loader/SKILL.md#revalidate-return-shapes](../loader/SKILL.md#revalidate-return-shapes)
374
+ for the full contract — it's the same across `loader()`, `path()`,
375
+ `layout()`, `parallel()`, and `intercept()`.
349
376
 
350
377
  ### Revalidation Contracts for Parallel Dependencies
351
378
 
@@ -354,8 +381,10 @@ the parallel consumer:
354
381
 
355
382
  ```typescript
356
383
  // revalidation-contracts.ts
357
- export const revalidateCartData = ({ actionId }) =>
358
- actionId?.includes("src/actions/cart.ts#") ?? false;
384
+ import * as CartActions from "./actions/cart";
385
+
386
+ export const revalidateCartData = (ctx) =>
387
+ ctx.isAction(CartActions) || undefined;
359
388
 
360
389
  layout(CartLayout, () => [
361
390
  revalidate(revalidateCartData), // producer reruns
@@ -423,6 +452,7 @@ function MyLayout() {
423
452
  ```typescript
424
453
  import { urls } from "@rangojs/router";
425
454
  import { Outlet, ParallelOutlet } from "@rangojs/router/client";
455
+ import * as CartActions from "./actions/cart";
426
456
 
427
457
  function ShopLayout() {
428
458
  return (
@@ -473,7 +503,7 @@ export const shopPatterns = urls(({
473
503
  () => [
474
504
  loader(CartLoader),
475
505
  loading(<CartSkeleton />),
476
- revalidate(({ actionId }) => actionId?.includes("Cart") ?? false),
506
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
477
507
  ]
478
508
  ),
479
509