@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa

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 (411) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +296 -887
  3. package/dist/bin/rango.js +459 -91
  4. package/dist/testing/vitest.js +36 -2
  5. package/dist/vite/index.js +1708 -414
  6. package/package.json +35 -10
  7. package/skills/api-client/SKILL.md +211 -0
  8. package/skills/breadcrumbs/SKILL.md +82 -5
  9. package/skills/bundle-analysis/SKILL.md +2 -2
  10. package/skills/cache-guide/SKILL.md +14 -9
  11. package/skills/caching/SKILL.md +221 -12
  12. package/skills/catalog.json +271 -0
  13. package/skills/comparison/SKILL.md +50 -0
  14. package/skills/comparison/agents/openai.yaml +4 -0
  15. package/skills/comparison/references/framework-comparison.md +837 -0
  16. package/skills/composability/SKILL.md +83 -2
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +5 -3
  19. package/skills/defer-hydration/SKILL.md +235 -0
  20. package/skills/document-cache/SKILL.md +11 -3
  21. package/skills/fonts/SKILL.md +1 -1
  22. package/skills/handler-use/SKILL.md +9 -9
  23. package/skills/hooks/SKILL.md +73 -900
  24. package/skills/hooks/data.md +273 -0
  25. package/skills/hooks/handle-and-actions.md +103 -0
  26. package/skills/hooks/navigation.md +110 -0
  27. package/skills/hooks/outlets.md +41 -0
  28. package/skills/hooks/state.md +228 -0
  29. package/skills/hooks/urls.md +135 -0
  30. package/skills/host-router/SKILL.md +84 -7
  31. package/skills/i18n/SKILL.md +1 -1
  32. package/skills/intercept/SKILL.md +51 -17
  33. package/skills/layout/SKILL.md +38 -16
  34. package/skills/links/SKILL.md +1 -1
  35. package/skills/loader/SKILL.md +48 -20
  36. package/skills/middleware/SKILL.md +11 -5
  37. package/skills/migrate-nextjs/SKILL.md +203 -20
  38. package/skills/migrate-react-router/SKILL.md +59 -675
  39. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  40. package/skills/migrate-react-router/component-migration.md +196 -0
  41. package/skills/migrate-react-router/data-and-actions.md +225 -0
  42. package/skills/migrate-react-router/route-mapping.md +271 -0
  43. package/skills/mime-routes/SKILL.md +3 -3
  44. package/skills/observability/SKILL.md +70 -5
  45. package/skills/parallel/SKILL.md +32 -8
  46. package/skills/ppr/SKILL.md +622 -0
  47. package/skills/prerender/SKILL.md +59 -28
  48. package/skills/rango/SKILL.md +124 -50
  49. package/skills/response-routes/SKILL.md +78 -46
  50. package/skills/route/SKILL.md +85 -6
  51. package/skills/router-setup/SKILL.md +41 -6
  52. package/skills/scripts/SKILL.md +179 -0
  53. package/skills/server-actions/SKILL.md +28 -3
  54. package/skills/shell-manifest/SKILL.md +185 -0
  55. package/skills/streams-and-websockets/SKILL.md +1 -1
  56. package/skills/tailwind/SKILL.md +28 -4
  57. package/skills/testing/SKILL.md +68 -654
  58. package/skills/testing/bindings.md +103 -0
  59. package/skills/testing/cache-prerender.md +127 -0
  60. package/skills/testing/client-components.md +124 -0
  61. package/skills/testing/e2e-parity.md +125 -0
  62. package/skills/testing/flight.md +91 -0
  63. package/skills/testing/handles.md +131 -0
  64. package/skills/testing/loader.md +128 -0
  65. package/skills/testing/middleware.md +99 -0
  66. package/skills/testing/render-handler.md +122 -0
  67. package/skills/testing/response-routes.md +95 -0
  68. package/skills/testing/reverse-and-types.md +85 -0
  69. package/skills/testing/server-actions.md +107 -0
  70. package/skills/testing/server-tree.md +128 -0
  71. package/skills/testing/setup.md +123 -0
  72. package/skills/theme/SKILL.md +1 -1
  73. package/skills/typesafety/SKILL.md +45 -918
  74. package/skills/typesafety/env-and-bindings.md +254 -0
  75. package/skills/typesafety/generated-files-and-cli.md +335 -0
  76. package/skills/typesafety/params-and-search.md +153 -0
  77. package/skills/typesafety/route-types.md +209 -0
  78. package/skills/use-cache/SKILL.md +47 -17
  79. package/skills/vercel/SKILL.md +128 -0
  80. package/skills/view-transitions/SKILL.md +44 -1
  81. package/src/__augment-tests__/augmented.check.ts +2 -3
  82. package/src/__internal.ts +0 -65
  83. package/src/browser/action-coordinator.ts +1 -1
  84. package/src/browser/action-fence.ts +47 -0
  85. package/src/browser/app-shell.ts +14 -27
  86. package/src/browser/connection-warmup.ts +134 -0
  87. package/src/browser/cookie-name.ts +140 -0
  88. package/src/browser/event-controller.ts +178 -100
  89. package/src/browser/invalidate-client-cache.ts +52 -0
  90. package/src/browser/logging.ts +28 -0
  91. package/src/browser/merge-segment-loaders.ts +6 -4
  92. package/src/browser/navigation-bridge.ts +81 -68
  93. package/src/browser/navigation-client.ts +115 -70
  94. package/src/browser/navigation-store-handle.ts +38 -0
  95. package/src/browser/navigation-store.ts +153 -88
  96. package/src/browser/navigation-transaction.ts +0 -32
  97. package/src/browser/network-error-handler.ts +34 -7
  98. package/src/browser/partial-update.ts +157 -144
  99. package/src/browser/prefetch/cache.ts +148 -81
  100. package/src/browser/prefetch/fetch.ts +231 -51
  101. package/src/browser/prefetch/queue.ts +25 -7
  102. package/src/browser/rango-state.ts +157 -115
  103. package/src/browser/react/Link.tsx +40 -7
  104. package/src/browser/react/NavigationProvider.tsx +140 -99
  105. package/src/browser/react/ScrollRestoration.tsx +10 -6
  106. package/src/browser/react/filter-segment-order.ts +17 -2
  107. package/src/browser/react/index.ts +0 -51
  108. package/src/browser/react/location-state-shared.ts +14 -15
  109. package/src/browser/react/location-state.ts +0 -1
  110. package/src/browser/react/use-action.ts +6 -15
  111. package/src/browser/react/use-handle.ts +0 -5
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +33 -8
  114. package/src/browser/react/use-navigation.ts +10 -5
  115. package/src/browser/react/use-params.ts +0 -2
  116. package/src/browser/react/use-router.ts +6 -4
  117. package/src/browser/react/use-search-params.ts +0 -5
  118. package/src/browser/react/use-segments.ts +0 -13
  119. package/src/browser/response-adapter.ts +74 -8
  120. package/src/browser/rsc-router.tsx +97 -22
  121. package/src/browser/scroll-restoration.ts +15 -8
  122. package/src/browser/segment-reconciler.ts +31 -21
  123. package/src/browser/server-action-bridge.ts +216 -38
  124. package/src/browser/types.ts +94 -22
  125. package/src/browser/validate-redirect-origin.ts +43 -16
  126. package/src/build/generate-manifest.ts +155 -131
  127. package/src/build/generate-route-types.ts +1 -1
  128. package/src/build/index.ts +11 -5
  129. package/src/build/prefix-tree-utils.ts +123 -0
  130. package/src/build/route-trie.ts +152 -22
  131. package/src/build/route-types/ast-route-extraction.ts +15 -8
  132. package/src/build/route-types/codegen.ts +12 -1
  133. package/src/build/route-types/include-resolution.ts +455 -61
  134. package/src/build/route-types/param-extraction.ts +6 -3
  135. package/src/build/route-types/per-module-writer.ts +15 -2
  136. package/src/build/route-types/router-processing.ts +77 -41
  137. package/src/build/route-types/source-scan.ts +105 -7
  138. package/src/build/runtime-discovery.ts +4 -1
  139. package/src/cache/cache-error.ts +104 -0
  140. package/src/cache/cache-key-utils.ts +58 -13
  141. package/src/cache/cache-policy.ts +108 -34
  142. package/src/cache/cache-runtime.ts +454 -101
  143. package/src/cache/cache-scope.ts +159 -54
  144. package/src/cache/cache-tag.ts +149 -0
  145. package/src/cache/cf/cf-base64.ts +33 -0
  146. package/src/cache/cf/cf-cache-constants.ts +127 -0
  147. package/src/cache/cf/cf-cache-store.ts +2170 -377
  148. package/src/cache/cf/cf-cache-types.ts +349 -0
  149. package/src/cache/cf/cf-kv-utils.ts +46 -0
  150. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  151. package/src/cache/cf/index.ts +6 -16
  152. package/src/cache/document-cache.ts +126 -41
  153. package/src/cache/handle-snapshot.ts +70 -0
  154. package/src/cache/index.ts +23 -20
  155. package/src/cache/memory-segment-store.ts +243 -37
  156. package/src/cache/profile-registry.ts +46 -31
  157. package/src/cache/read-through-swr.ts +56 -12
  158. package/src/cache/segment-codec.ts +13 -21
  159. package/src/cache/shell-snapshot.ts +417 -0
  160. package/src/cache/tag-invalidation.ts +230 -0
  161. package/src/cache/types.ts +194 -99
  162. package/src/cache/vercel/index.ts +11 -0
  163. package/src/cache/vercel/vercel-cache-store.ts +1132 -0
  164. package/src/client.rsc.tsx +39 -22
  165. package/src/client.tsx +28 -58
  166. package/src/cloudflare/index.ts +11 -0
  167. package/src/cloudflare/tracing.ts +108 -0
  168. package/src/component-utils.ts +19 -0
  169. package/src/components/DefaultDocument.tsx +8 -2
  170. package/src/context-var.ts +13 -1
  171. package/src/decode-loader-results.ts +18 -2
  172. package/src/defer.ts +185 -0
  173. package/src/deps/ssr.ts +0 -1
  174. package/src/encode-kv.ts +49 -0
  175. package/src/errors.ts +0 -3
  176. package/src/escape-script.ts +52 -0
  177. package/src/handle.ts +57 -40
  178. package/src/handles/MetaTags.tsx +24 -53
  179. package/src/handles/Scripts.tsx +183 -0
  180. package/src/handles/breadcrumbs.ts +35 -8
  181. package/src/handles/deferred-resolution.ts +127 -0
  182. package/src/handles/is-thenable.ts +18 -0
  183. package/src/handles/meta.ts +14 -40
  184. package/src/handles/script.ts +244 -0
  185. package/src/host/cookie-handler.ts +9 -60
  186. package/src/host/errors.ts +13 -22
  187. package/src/host/index.ts +7 -0
  188. package/src/host/pattern-matcher.ts +23 -52
  189. package/src/host/router.ts +1 -65
  190. package/src/host/testing.ts +40 -27
  191. package/src/host/types.ts +6 -2
  192. package/src/href-client.ts +7 -12
  193. package/src/index.rsc.ts +88 -8
  194. package/src/index.ts +90 -16
  195. package/src/internal-debug.ts +11 -10
  196. package/src/loader.rsc.ts +19 -9
  197. package/src/loader.ts +12 -4
  198. package/src/outlet-provider.tsx +1 -5
  199. package/src/prerender/param-hash.ts +16 -16
  200. package/src/prerender/store.ts +32 -37
  201. package/src/prerender.ts +75 -7
  202. package/src/redirect-origin.ts +114 -0
  203. package/src/regex-escape.ts +8 -0
  204. package/src/render-error-thrower.tsx +20 -0
  205. package/src/response-utils.ts +25 -0
  206. package/src/root-error-boundary.tsx +1 -19
  207. package/src/route-content-wrapper.tsx +13 -49
  208. package/src/route-definition/dsl-helpers.ts +60 -53
  209. package/src/route-definition/helper-factories.ts +0 -2
  210. package/src/route-definition/helpers-types.ts +46 -46
  211. package/src/route-definition/index.ts +1 -2
  212. package/src/route-definition/redirect.ts +44 -11
  213. package/src/route-definition/resolve-handler-use.ts +6 -1
  214. package/src/route-definition/use-item-types.ts +3 -6
  215. package/src/route-map-builder.ts +41 -20
  216. package/src/route-types.ts +0 -5
  217. package/src/router/content-negotiation.ts +58 -23
  218. package/src/router/error-handling.ts +44 -17
  219. package/src/router/find-match.ts +129 -30
  220. package/src/router/handler-context.ts +6 -1
  221. package/src/router/instrument.ts +355 -0
  222. package/src/router/intercept-resolution.ts +35 -2
  223. package/src/router/lazy-includes.ts +79 -56
  224. package/src/router/loader-resolution.ts +151 -73
  225. package/src/router/logging.ts +0 -6
  226. package/src/router/manifest.ts +74 -40
  227. package/src/router/match-api.ts +76 -52
  228. package/src/router/match-context.ts +0 -22
  229. package/src/router/match-handlers.ts +181 -178
  230. package/src/router/match-middleware/background-revalidation.ts +40 -24
  231. package/src/router/match-middleware/cache-lookup.ts +115 -194
  232. package/src/router/match-middleware/cache-store.ts +61 -50
  233. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  234. package/src/router/match-middleware/segment-resolution.ts +0 -22
  235. package/src/router/match-pipelines.ts +1 -42
  236. package/src/router/match-result.ts +36 -67
  237. package/src/router/metrics.ts +0 -34
  238. package/src/router/middleware-types.ts +0 -116
  239. package/src/router/middleware.ts +231 -120
  240. package/src/router/navigation-snapshot.ts +7 -56
  241. package/src/router/params-util.ts +23 -0
  242. package/src/router/parse-pattern.ts +115 -0
  243. package/src/router/pattern-matching.ts +99 -152
  244. package/src/router/prefetch-cache-ttl.ts +51 -0
  245. package/src/router/prefetch-limits.ts +37 -0
  246. package/src/router/prerender-match.ts +111 -66
  247. package/src/router/preview-match.ts +3 -1
  248. package/src/router/request-classification.ts +47 -42
  249. package/src/router/revalidation.ts +75 -81
  250. package/src/router/route-snapshot.ts +14 -3
  251. package/src/router/router-context.ts +6 -29
  252. package/src/router/router-interfaces.ts +70 -8
  253. package/src/router/router-options.ts +126 -4
  254. package/src/router/segment-resolution/fresh.ts +104 -80
  255. package/src/router/segment-resolution/helpers.ts +86 -6
  256. package/src/router/segment-resolution/loader-cache.ts +155 -39
  257. package/src/router/segment-resolution/loader-mask.ts +60 -0
  258. package/src/router/segment-resolution/loader-snapshot.ts +259 -0
  259. package/src/router/segment-resolution/mask-nested.ts +83 -0
  260. package/src/router/segment-resolution/revalidation.ts +215 -304
  261. package/src/router/segment-resolution/static-store.ts +19 -5
  262. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  263. package/src/router/segment-resolution/view-transition-default.ts +35 -15
  264. package/src/router/segment-resolution.ts +5 -1
  265. package/src/router/segment-wrappers.ts +6 -5
  266. package/src/router/state-cookie-name.ts +33 -0
  267. package/src/router/substitute-pattern-params.ts +54 -35
  268. package/src/router/telemetry-otel.ts +160 -200
  269. package/src/router/telemetry.ts +9 -23
  270. package/src/router/timeout.ts +0 -20
  271. package/src/router/tracing.ts +215 -0
  272. package/src/router/trie-matching.ts +171 -64
  273. package/src/router/types.ts +1 -63
  274. package/src/router/url-params.ts +13 -5
  275. package/src/router.ts +119 -48
  276. package/src/rsc/full-payload.ts +70 -0
  277. package/src/rsc/handler-context.ts +1 -0
  278. package/src/rsc/handler.ts +267 -152
  279. package/src/rsc/helpers.ts +78 -4
  280. package/src/rsc/index.ts +1 -4
  281. package/src/rsc/json-route-result.ts +38 -0
  282. package/src/rsc/loader-fetch.ts +114 -38
  283. package/src/rsc/manifest-init.ts +29 -42
  284. package/src/rsc/nonce.ts +10 -1
  285. package/src/rsc/origin-guard.ts +11 -15
  286. package/src/rsc/progressive-enhancement.ts +120 -13
  287. package/src/rsc/redirect-guard.ts +100 -0
  288. package/src/rsc/response-cache-serve.ts +238 -0
  289. package/src/rsc/response-error.ts +79 -12
  290. package/src/rsc/response-route-handler.ts +58 -141
  291. package/src/rsc/rsc-rendering.ts +492 -49
  292. package/src/rsc/runtime-warnings.ts +14 -0
  293. package/src/rsc/server-action.ts +268 -82
  294. package/src/rsc/shell-capture.ts +1190 -0
  295. package/src/rsc/shell-serve.ts +181 -0
  296. package/src/rsc/transition-gate.ts +89 -0
  297. package/src/rsc/types.ts +45 -3
  298. package/src/runtime-env.ts +18 -0
  299. package/src/search-params.ts +31 -26
  300. package/src/segment-loader-promise.ts +49 -4
  301. package/src/segment-system.tsx +260 -95
  302. package/src/server/context.ts +99 -9
  303. package/src/server/cookie-parse.ts +32 -0
  304. package/src/server/cookie-store.ts +125 -2
  305. package/src/server/handle-store.ts +21 -38
  306. package/src/server/loader-registry.ts +33 -42
  307. package/src/server/request-context.ts +379 -138
  308. package/src/ssr/index.tsx +491 -182
  309. package/src/ssr/inject-rsc-eager.ts +167 -0
  310. package/src/ssr/ssr-root.tsx +228 -0
  311. package/src/static-handler.ts +10 -13
  312. package/src/testing/cache-status.ts +44 -48
  313. package/src/testing/collect-handle.ts +14 -31
  314. package/src/testing/dispatch.ts +533 -160
  315. package/src/testing/e2e/fixture.ts +45 -11
  316. package/src/testing/e2e/index.ts +1 -22
  317. package/src/testing/e2e/matchers.ts +0 -16
  318. package/src/testing/e2e/parity.ts +85 -4
  319. package/src/testing/e2e/server.ts +12 -0
  320. package/src/testing/flight-matchers.ts +7 -14
  321. package/src/testing/flight-normalize.ts +11 -0
  322. package/src/testing/flight-runtime.d.ts +36 -0
  323. package/src/testing/flight-tree.ts +682 -0
  324. package/src/testing/flight.entry.ts +30 -0
  325. package/src/testing/flight.ts +145 -70
  326. package/src/testing/generated-routes.ts +26 -50
  327. package/src/testing/index.ts +18 -19
  328. package/src/testing/internal/context.ts +184 -68
  329. package/src/testing/internal/flight-client-globals.ts +30 -0
  330. package/src/testing/internal/seed-vars.ts +54 -0
  331. package/src/testing/render-handler.ts +357 -0
  332. package/src/testing/render-route.tsx +134 -115
  333. package/src/testing/run-loader.ts +140 -51
  334. package/src/testing/run-middleware.ts +59 -33
  335. package/src/testing/run-transition-when.ts +164 -0
  336. package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
  337. package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
  338. package/src/testing/vitest.ts +138 -16
  339. package/src/theme/ThemeProvider.tsx +56 -84
  340. package/src/theme/ThemeScript.tsx +7 -9
  341. package/src/theme/constants.ts +52 -13
  342. package/src/theme/index.ts +0 -7
  343. package/src/theme/theme-context.ts +1 -5
  344. package/src/theme/theme-script.ts +22 -21
  345. package/src/theme/use-theme.ts +0 -3
  346. package/src/types/boundaries.ts +0 -35
  347. package/src/types/cache-types.ts +13 -4
  348. package/src/types/error-types.ts +30 -90
  349. package/src/types/global-namespace.ts +15 -15
  350. package/src/types/handler-context.ts +45 -15
  351. package/src/types/index.ts +2 -10
  352. package/src/types/loader-types.ts +6 -3
  353. package/src/types/request-scope.ts +8 -22
  354. package/src/types/route-config.ts +20 -52
  355. package/src/types/route-entry.ts +0 -6
  356. package/src/types/segments.ts +100 -13
  357. package/src/urls/include-helper.ts +10 -12
  358. package/src/urls/include-provider.ts +71 -0
  359. package/src/urls/index.ts +2 -8
  360. package/src/urls/path-helper-types.ts +52 -14
  361. package/src/urls/path-helper.ts +5 -54
  362. package/src/urls/pattern-types.ts +36 -0
  363. package/src/urls/type-extraction.ts +76 -42
  364. package/src/urls/urls-function.ts +0 -14
  365. package/src/use-loader.tsx +0 -186
  366. package/src/vercel/index.ts +11 -0
  367. package/src/vercel/tracing.ts +88 -0
  368. package/src/vite/discovery/bundle-postprocess.ts +2 -1
  369. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  370. package/src/vite/discovery/discover-routers.ts +34 -43
  371. package/src/vite/discovery/discovery-errors.ts +61 -0
  372. package/src/vite/discovery/prerender-collection.ts +33 -46
  373. package/src/vite/discovery/state.ts +12 -1
  374. package/src/vite/discovery/virtual-module-codegen.ts +1 -11
  375. package/src/vite/index.ts +9 -0
  376. package/src/vite/inject-client-debug.ts +88 -0
  377. package/src/vite/plugin-types.ts +143 -10
  378. package/src/vite/plugins/cjs-to-esm.ts +8 -12
  379. package/src/vite/plugins/client-ref-dedup.ts +0 -11
  380. package/src/vite/plugins/client-ref-hashing.ts +0 -10
  381. package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
  382. package/src/vite/plugins/expose-action-id.ts +2 -73
  383. package/src/vite/plugins/expose-id-utils.ts +85 -56
  384. package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
  385. package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
  386. package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
  387. package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
  388. package/src/vite/plugins/expose-internal-ids.ts +10 -1
  389. package/src/vite/plugins/performance-tracks.ts +0 -3
  390. package/src/vite/plugins/refresh-cmd.ts +1 -1
  391. package/src/vite/plugins/use-cache-transform.ts +21 -46
  392. package/src/vite/plugins/vercel-output.ts +384 -0
  393. package/src/vite/plugins/version-injector.ts +22 -27
  394. package/src/vite/plugins/version-plugin.ts +6 -66
  395. package/src/vite/plugins/virtual-entries.ts +137 -26
  396. package/src/vite/rango.ts +146 -135
  397. package/src/vite/router-discovery.ts +189 -48
  398. package/src/vite/utils/ast-handler-extract.ts +11 -20
  399. package/src/vite/utils/bundle-analysis.ts +6 -13
  400. package/src/vite/utils/client-chunks.ts +0 -6
  401. package/src/vite/utils/directive-prologue.ts +40 -0
  402. package/src/vite/utils/forward-user-plugins.ts +0 -22
  403. package/src/vite/utils/manifest-utils.ts +4 -75
  404. package/src/vite/utils/package-resolution.ts +1 -73
  405. package/src/vite/utils/prerender-utils.ts +71 -44
  406. package/src/vite/utils/shared-utils.ts +55 -37
  407. package/src/browser/react/use-client-cache.ts +0 -58
  408. package/src/browser/shallow.ts +0 -40
  409. package/src/handles/index.ts +0 -7
  410. package/src/network-error-thrower.tsx +0 -23
  411. 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
 
@@ -133,7 +133,7 @@ declare global {
133
133
 
134
134
  `RegisteredRoutes` is what exposes the richer routeMap entries containing
135
135
  response payload metadata. Without it, URL-pattern response lookup has paths but
136
- no payloads, so response types resolve to `ResponseEnvelope<never>`.
136
+ no payloads, so response types resolve to `never`.
137
137
 
138
138
  ## How It Works
139
139
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: observability
3
- description: Debug Rango request performance with debugPerformance, Server-Timing, structured telemetry, and tracing
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
4
  argument-hint:
5
5
  ---
6
6
 
@@ -58,6 +58,14 @@ Read the timeline as intervals:
58
58
  - Cache, route matching, middleware pre/post, RSC serialization, and SSR phases
59
59
  appear as separate spans, so the slow phase is visible without guessing.
60
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
+
61
69
  ## Structured telemetry
62
70
 
63
71
  Use telemetry when you want durable production events rather than a one-request
@@ -73,19 +81,75 @@ const router = createRouter({
73
81
  });
74
82
  ```
75
83
 
76
- For OpenTelemetry:
84
+ For OpenTelemetry — phase spans come from the `tracing` slot
85
+ (`createOTelTracing`), discrete-fact spans from the `telemetry` sink
86
+ (`createOTelSink`):
77
87
 
78
88
  ```typescript
79
- import { createRouter, createOTelSink } from "@rangojs/router";
89
+ import {
90
+ createRouter,
91
+ createOTelTracing,
92
+ createOTelSink,
93
+ } from "@rangojs/router";
80
94
  import { trace } from "@opentelemetry/api";
81
95
 
96
+ const tracer = trace.getTracer("my-app");
97
+
82
98
  const router = createRouter({
83
99
  document: Document,
84
100
  urls: urlpatterns,
85
- telemetry: createOTelSink(trace.getTracer("my-app")),
101
+ tracing: createOTelTracing(tracer), // request/loader/render/… phase spans
102
+ telemetry: createOTelSink(tracer), // handler errors, cache decisions, …
86
103
  });
87
104
  ```
88
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
+
89
153
  Custom sinks implement `emit(event)`:
90
154
 
91
155
  ```typescript
@@ -103,7 +167,8 @@ const router = createRouter({
103
167
  ```
104
168
 
105
169
  Events include `request.start/end/error`, `loader.start/end/error`,
106
- `handler.error`, `cache.decision`, and `revalidation.decision`.
170
+ `handler.error`, `cache.decision`, `revalidation.decision`, `request.timeout`,
171
+ and `request.origin-rejected`.
107
172
 
108
173
  ## Debugging revalidation and stale data
109
174
 
@@ -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,6 +8,13 @@ argument-hint: [@slot-name]
8
8
 
9
9
  Parallel routes render multiple components simultaneously in named slots.
10
10
 
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`.
17
+
11
18
  ## Basic Parallel Routes
12
19
 
13
20
  ```typescript
@@ -232,6 +239,8 @@ layout(<AccountLayout />, () => [
232
239
 
233
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.
234
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
+
235
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.
236
245
 
237
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.
@@ -264,6 +273,8 @@ parallel(
264
273
 
265
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.
266
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
+
267
278
  ## Slot Override Semantics
268
279
 
269
280
  When multiple `parallel()` calls define the same slot name, **the last
@@ -330,6 +341,8 @@ parallel({
330
341
  Control when parallel routes revalidate:
331
342
 
332
343
  ```typescript
344
+ import * as CartActions from "./actions/cart";
345
+
333
346
  parallel(
334
347
  {
335
348
  "@cart": () => <CartSummary />,
@@ -337,14 +350,22 @@ parallel(
337
350
  () => [
338
351
  loader(CartLoader),
339
352
  // Revalidate when cart actions occur
340
- revalidate(({ actionId }) => actionId?.includes("Cart") || undefined),
353
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
341
354
  ]
342
355
  )
343
356
  ```
344
357
 
345
- Revalidating only the parallel does not re-run outer handlers/layouts.
346
- If the slot reads `ctx.get()` data established above it, opt the outer
347
- 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").
348
369
 
349
370
  A `revalidate()` callback may return a hard `boolean`, a soft
350
371
  `{ defaultShouldRevalidate }` object, or nothing (`void` / `null` /
@@ -360,8 +381,10 @@ the parallel consumer:
360
381
 
361
382
  ```typescript
362
383
  // revalidation-contracts.ts
363
- export const revalidateCartData = ({ actionId }) =>
364
- actionId?.includes("src/actions/cart.ts#") || undefined;
384
+ import * as CartActions from "./actions/cart";
385
+
386
+ export const revalidateCartData = (ctx) =>
387
+ ctx.isAction(CartActions) || undefined;
365
388
 
366
389
  layout(CartLayout, () => [
367
390
  revalidate(revalidateCartData), // producer reruns
@@ -429,6 +452,7 @@ function MyLayout() {
429
452
  ```typescript
430
453
  import { urls } from "@rangojs/router";
431
454
  import { Outlet, ParallelOutlet } from "@rangojs/router/client";
455
+ import * as CartActions from "./actions/cart";
432
456
 
433
457
  function ShopLayout() {
434
458
  return (
@@ -479,7 +503,7 @@ export const shopPatterns = urls(({
479
503
  () => [
480
504
  loader(CartLoader),
481
505
  loading(<CartSkeleton />),
482
- revalidate(({ actionId }) => actionId?.includes("Cart") || undefined),
506
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
483
507
  ]
484
508
  ),
485
509