@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
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: caching
3
- description: Configure segment caching with memory or Cloudflare KV stores in @rangojs/router
4
- argument-hint: [setup]
3
+ description: Configure route/segment-subtree caching with memory, Cloudflare KV, or Vercel cache stores in @rangojs/router. Use when responses should be cached or revalidated, data is stale or not updating after code changes, or you are wiring up a cache store.
4
+ argument-hint: "[setup]"
5
5
  ---
6
6
 
7
7
  # Caching
@@ -14,6 +14,16 @@ argument-hint: [setup]
14
14
  > route-segment entries expire at TTL with no background revalidation — use
15
15
  > `CFCacheStore` for real segment SWR. See `/cache-guide`.
16
16
 
17
+ ## Not this skill if…
18
+
19
+ - You want to cache ONE function or component's return value — that is
20
+ `"use cache"`: see `/use-cache`.
21
+ - You want the whole HTTP response frozen at the edge, loader output included —
22
+ see `/document-cache`.
23
+ - You want the HTML shell cached while loaders stay live per request — see
24
+ `/ppr`.
25
+ - You are unsure which cache layer you need — start at `/cache-guide`.
26
+
17
27
  ## cache() is Partial Prerendering (PPR)
18
28
 
19
29
  `cache()` caches **everything except loaders**. On a cache hit, the cached
@@ -81,10 +91,116 @@ cache(
81
91
  );
82
92
  ```
83
93
 
84
- ## Named Profile Shorthand
94
+ ## When cache() does not pay
95
+
96
+ A cache hit is not free: it still runs middleware, the store read, and the
97
+ document render AROUND the cached segment. The win is proportional to what
98
+ the cached render itself costs — measured on a deployed Cloudflare worker
99
+ (2026-07), a trivial page inside `cache()` served hits at p50 36 ms while
100
+ misses (render + store) served at 35 ms: indistinguishable. The same
101
+ boundary around an expensive render (slow data, big trees) is where the TTL
102
+ pays for itself.
103
+
104
+ Rule of thumb: reach for `cache()` when the segment's own render cost is
105
+ meaningfully above your latency floor — expensive render-embedded data work,
106
+ large component trees, third-party calls captured in the render. Do not wrap cheap
107
+ pages "just in case": you add store traffic and invalidation surface for no
108
+ latency win. If the data is what's expensive and it changes per-request,
109
+ prefer a loader with `cache()` on the loader DATA (see "Loader-Level
110
+ Caching") over caching the rendered segment.
85
111
 
86
- Use a named cache profile string instead of an options object. The profile must be
87
- defined in `createRouter({ cacheProfiles })`. Unknown names throw at boot time.
112
+ ## Tag-Based Invalidation
113
+
114
+ Tag cached entries, then invalidate them on demand. Tags can be attached four ways:
115
+
116
+ ```typescript
117
+ // 1. Static tags in the cache() DSL
118
+ cache({ ttl: 300, tags: ["products"] }, () => [path("/products", List)]);
119
+
120
+ // 2. Dynamic tags (function of ctx)
121
+ cache(
122
+ { ttl: 300, tags: (ctx) => [`product:${ctx.params.id}`, "products"] },
123
+ () => [path("/products/:id", Detail)],
124
+ );
125
+
126
+ // 3. Runtime tags inside a "use cache" function
127
+ async function getProduct(id: string) {
128
+ "use cache";
129
+ cacheTag(`product:${id}`, "products"); // variadic, additive
130
+ return db.getProduct(id);
131
+ }
132
+
133
+ // 4. Render-callable — a plain server component (no "use cache" in its tree)
134
+ // records onto the request's document/shell artifact.
135
+ function CampaignBanner() {
136
+ cacheTag("campaign:spring"); // rides ctx._requestTags → shell/document entry
137
+ return <aside>Spring sale</aside>;
138
+ }
139
+ ```
140
+
141
+ Form 4 is how you make a PPR shell or a `/document-cache` page tag-invalidatable
142
+ without wrapping anything in `"use cache"`: the tag rides the request's
143
+ `_requestTags` onto the shell/document entry, and `revalidateTag` then evicts it.
144
+ On a route that is neither PPR nor document-cached the tag records where nothing
145
+ reads it — a silent no-op, so don't expect a bare `cacheTag()` to tag an ordinary
146
+ uncached page.
147
+
148
+ Invalidate with one of two server-only verbs (both variadic, imported from
149
+ `@rangojs/router`):
150
+
151
+ ```typescript
152
+ // Server Action — read-your-own-writes. Await it so the action's own re-render
153
+ // (and the next navigation) sees fresh data.
154
+ async function updateProduct(formData: FormData) {
155
+ "use server";
156
+ await db.updateProduct(formData);
157
+ await updateTag("products");
158
+ }
159
+
160
+ // Route handler / webhook — background, non-blocking (waitUntil). Hard-purge:
161
+ // the next read re-renders fresh (NOT stale-while-revalidate).
162
+ export async function POST() {
163
+ "use server";
164
+ revalidateTag("products");
165
+ return new Response("ok");
166
+ }
167
+ ```
168
+
169
+ | API | Timing | Use in | Semantics |
170
+ | ------------------------ | --------------------------- | ------------------------- | ----------------------------------------------------- |
171
+ | `updateTag(...tags)` | awaitable (`Promise<void>`) | server actions | immediate; next read is fresh |
172
+ | `revalidateTag(...tags)` | background (`void`) | route handlers / webhooks | background (non-blocking); next read re-renders fresh |
173
+
174
+ Both built-in stores support tags. For `CFCacheStore`, distributed (cross-colo)
175
+ invalidation requires a `kv` namespace — the tag-invalidation markers live in
176
+ that same namespace; there is **no** separate tag-invalidation store to wire.
177
+ If no tag-capable store is configured, `updateTag`/`revalidateTag` warn and no-op.
178
+
179
+ By default `CFCacheStore` reads the KV marker on every tagged cache read
180
+ (strongest invalidation latency). To cut KV reads on hot tagged routes, set
181
+ `tagCacheTtl` (seconds) to cache each marker in the per-colo edge cache for that
182
+ window — the colo running `updateTag`/`revalidateTag` writes the fresh marker
183
+ into its own edge cache immediately (read-your-own-writes), while other colos
184
+ converge within `tagCacheTtl` (the **maximum extra cross-colo invalidation
185
+ latency** when no purge is wired). Keep it small (e.g. 30–60), or wire a purge
186
+ (below) and set it large. (Contrast `tagInvalidationTtl`, which must be _large_
187
+ — it bounds how long the KV marker itself lives and must exceed your max entry
188
+ TTL+SWR. Left unset there is no expiry: KV markers accumulate unbounded under
189
+ high-cardinality tags, so set it above your largest entry TTL+SWR to bound them.)
190
+
191
+ To make other colos prompt without a short `tagCacheTtl`, pass `onRevalidateTag`:
192
+ each cached marker carries a namespaced Cloudflare `Cache-Tag`, and the hook is
193
+ handed exactly those tags (batched, once per `updateTag`/`revalidateTag` call) to
194
+ feed Cloudflare's purge-by-tag API — evicting the cached lookups everywhere.
195
+ Purge-by-tag is available on all plans (since April 2025), subject to per-plan
196
+ rate limits, so the batched single call matters. With a purge wired, `tagCacheTtl`
197
+ becomes a pure read-cost reducer + fallback window.
198
+
199
+ ## Named Cache Profiles
200
+
201
+ Define named profiles in `createRouter({ cacheProfiles })` so the same TTL/SWR
202
+ values can be shared across the DSL and `"use cache"` functions without repetition.
203
+ Unknown names throw at boot time.
88
204
 
89
205
  ```typescript
90
206
  // Define profiles in router
@@ -95,19 +211,25 @@ createRouter({
95
211
  long: { ttl: 3600, swr: 7200 },
96
212
  },
97
213
  });
214
+ ```
98
215
 
99
- // Use by name in urls
216
+ In the DSL, pass the profile's options directly to `cache()`:
217
+
218
+ ```typescript
100
219
  export const urlpatterns = urls(({ path, cache }) => [
101
- cache("long", () => [path("/blog", BlogIndex, { name: "blog" })]),
220
+ cache({ ttl: 3600, swr: 7200 }, () => [
221
+ path("/blog", BlogIndex, { name: "blog" }),
222
+ ]),
102
223
 
103
- // Also works without children (orphan cache boundary)
104
- cache("short"),
224
+ // Orphan cache boundary (covers subsequent siblings)
225
+ cache({ ttl: 60, swr: 120 }),
105
226
  path("/feed", FeedPage, { name: "feed" }),
106
227
  ]);
107
228
  ```
108
229
 
109
- These profile names are shared with the `"use cache: <name>"` directive. See
110
- `/use-cache` for function-level caching.
230
+ The DSL `cache()` helper does NOT accept a string profile name strings are only
231
+ valid in the `"use cache: <name>"` directive inside server functions. See
232
+ `/use-cache` for function-level caching with named profiles.
111
233
 
112
234
  ## Loader-Level Caching
113
235
 
@@ -156,9 +278,15 @@ import { MemorySegmentCacheStore } from "@rangojs/router/cache";
156
278
 
157
279
  const store = new MemorySegmentCacheStore({
158
280
  defaults: { ttl: 60, swr: 300 },
281
+ maxEntries: 1000, // per-family FIFO cap (default 1000)
159
282
  });
160
283
  ```
161
284
 
285
+ Each internal family (segments, responses, `"use cache"` items, PPR shells) is
286
+ capped at `maxEntries`; on insert past the cap the oldest entry is evicted FIFO
287
+ and its tag-index entries are cleaned up, so a long-lived process cannot grow
288
+ without bound. TTL expiry stays lazy on top of the cap.
289
+
162
290
  ### Cloudflare Edge Cache Store
163
291
 
164
292
  For distributed caching on Cloudflare Workers using the Cache API:
@@ -212,6 +340,80 @@ const router = createRouter<AppBindings>({
212
340
  KV entries require `expirationTtl >= 60s`. Short-lived entries (< 60s total TTL)
213
341
  are only cached in L1.
214
342
 
343
+ ### Resilience & latency budgets
344
+
345
+ Every cache read is **fail-safe**: a degraded tier never stalls or fails the
346
+ request — it degrades to the next tier (L1 → L2 → render). Three optional latency
347
+ budgets (milliseconds) bound each tier so a slow colo or KV namespace cannot pin
348
+ a request behind it:
349
+
350
+ | Option | Default | Bounds |
351
+ | --------------------- | ------- | ----------------------------------- |
352
+ | `edgeLookupTimeoutMs` | `10` | L1 `cache.match` (the lookup) |
353
+ | `edgeReadTimeoutMs` | `20` | L1 body read (CF streams it lazily) |
354
+ | `kvReadTimeoutMs` | `170` | L2 / KV read |
355
+
356
+ Set any to `0` (or a negative value) to disable that budget and always await the
357
+ read. A non-finite value (e.g. `Number(env.UNSET)`) falls back to the default.
358
+ The tag-invalidation marker reads inherit these same budgets and **fail open** on
359
+ a KV timeout — the entry is served rather than wrongly treated as invalidated.
360
+
361
+ ```typescript
362
+ new CFCacheStore({
363
+ ctx,
364
+ kv: env.CACHE_KV,
365
+ defaults: { ttl: 60, swr: 300 },
366
+ // Raise a budget only if your HEALTHY reads legitimately run slower (large
367
+ // Flight payloads, far-from-colo regions); measure the p99 first. These are
368
+ // degradation guard-rails, not tuning levers for "slow is normal here".
369
+ kvReadTimeoutMs: 250,
370
+ });
371
+ ```
372
+
373
+ Failure handling, by kind — none of these fail the request:
374
+
375
+ | Failure | Behavior |
376
+ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
377
+ | Transient read error (5xx/blip) | Degrade to the next tier; entry left intact |
378
+ | Read budget exceeded (timeout) | Abandon the read, degrade to the next tier |
379
+ | Corrupt / unparseable L1 entry | Reported corrupt; degrade to L2 (served if present). The L1 entry is evicted ONLY when L2 has no copy — so the evict can't race the L2→L1 promote |
380
+ | Corrupt / unparseable KV entry | Reported corrupt; evicted (self-heal) + render (no tier below it) |
381
+ | Write failure | No-op (entry simply not cached); never throws |
382
+
383
+ Each is surfaced to the router's `onError` callback (phase `"cache"`, with
384
+ `metadata.category` one of `cache-read`, `cache-corrupt`, `cache-write`,
385
+ `cache-delete`, `cache-invalidate`, `stale-revalidation`) so you can observe
386
+ cache health without affecting users.
387
+
388
+ ### Validating cache behavior with `debug`
389
+
390
+ Pass `debug` to emit one structured event per L1 read — use it to confirm on a
391
+ real deployment (via `wrangler tail`) that the store behaves as expected before
392
+ relying on it. It is intended for validation, not steady-state production.
393
+
394
+ ```typescript
395
+ new CFCacheStore({
396
+ ctx,
397
+ kv: env.CACHE_KV,
398
+ debug: true, // logs each CFCacheReadDebugEvent to the console
399
+ // ...or capture programmatically:
400
+ // debug: (event) => myTelemetry.record(event),
401
+ });
402
+ ```
403
+
404
+ Each event reports which tier answered and why (`outcome`: `l1-fresh`,
405
+ `l1-stale-revalidate`, `l1-revalidating-guarded`, `match-timeout`, `match-error`,
406
+ `body-timeout`, `body-error`, `non-200`, `tag-invalidated`, `l1-miss`, `kv-fresh`,
407
+ `kv-stale`, `kv-stale-suppressed`, `kv-miss`, `kv-timeout`, `error`), the
408
+ staleness / revalidating timestamps, and the measured per-tier durations:
409
+ `matchMs` (the L1 `match`), `markerMs` (the tag-marker resolution tail for a
410
+ tagged entry, between `matchMs` and `bodyReadMs`; absent or 0 for an untagged
411
+ entry or a per-request memo hit), and `bodyReadMs` (the L1 body read). A
412
+ persistently large `markerMs` signals a degraded KV namespace; on a healthy
413
+ deployment KV keeps markers hot in its per-colo edge cache, so it stays a few
414
+ milliseconds. `match-error` (a transient `cache.match` rejection that falls
415
+ through to L2) is kept distinct from a plain `l1-miss`.
416
+
215
417
  ## Cache purity & tainted objects
216
418
 
217
419
  A `cache()` boundary caches everything except loaders, so anything read inside a
@@ -248,6 +450,12 @@ is **not** guarded. `ctx.use()` is a server-side escape hatch for non-rendered
248
450
  uses (set a ctx var, make a routing decision); never render its result inside a
249
451
  cached handler.
250
452
 
453
+ This is the **consumption-lane rule**, and it holds identically for every
454
+ shared artifact — `cache()`, `"use cache"`, and the PPR shell (`/ppr`):
455
+ handler consumption = baked copy with identity reads permitted; client-side
456
+ `useLoader` = live. Stated once in `/rango` → Invariants; pinned by
457
+ semantic-matrix row PPR3 and the `e2e/cache.test.ts` "baked copy" case.
458
+
251
459
  ```typescript
252
460
  // WRONG — throws: cookies() read directly in a cached handler
253
461
  cache({ ttl: 60 }, () => [
@@ -325,6 +533,7 @@ cache({ store: checkoutCache }, () => [
325
533
  ```typescript
326
534
  import { urls } from "@rangojs/router";
327
535
  import { MemorySegmentCacheStore } from "@rangojs/router/cache";
536
+ import * as CartActions from "./actions/cart";
328
537
 
329
538
  // Custom store for checkout (short TTL)
330
539
  const checkoutCache = new MemorySegmentCacheStore({
@@ -353,7 +562,7 @@ export const urlpatterns = urls(({ path, layout, cache, loader, revalidate }) =>
353
562
  path("/shop/product/:slug", ProductPage, { name: "product" }, () => [
354
563
  loader(ProductLoader, () => [cache({ ttl: 120 })]),
355
564
  loader(CartLoader, () => [
356
- revalidate(({ actionId }) => actionId?.includes("Cart") || undefined),
565
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
357
566
  ]),
358
567
  ]),
359
568
  ]),
@@ -0,0 +1,271 @@
1
+ {
2
+ "$schema-note": "Generated by tools/generate-skills-catalog.mjs — do not edit by hand.",
3
+ "package": "@rangojs/router",
4
+ "entry": "rango",
5
+ "skills": [
6
+ {
7
+ "name": "api-client",
8
+ "description": "Build a typed client for consuming your own response-route JSON APIs (no codegen). Use when calling your own JSON endpoints from another service or script, or you want typed fetch calls without a codegen step.",
9
+ "argumentHint": "",
10
+ "path": "skills/api-client/SKILL.md"
11
+ },
12
+ {
13
+ "name": "breadcrumbs",
14
+ "description": "Built-in Breadcrumbs handle for accumulating breadcrumb navigation across route segments. Use when building a breadcrumb trail for nested routes, or asking how to show the current navigation path in a layout.",
15
+ "argumentHint": "[setup]",
16
+ "path": "skills/breadcrumbs/SKILL.md"
17
+ },
18
+ {
19
+ "name": "bundle-analysis",
20
+ "description": "Audit a Rango app's production bundle for server-side code leaking into the client, dev/prod React duplication, oversized chunks, and inefficient client-reference grouping. Use when investigating bundle size growth, before a production deploy, or when the client/SSR/RSC output suddenly balloons.",
21
+ "argumentHint": "<app-dir>",
22
+ "path": "skills/bundle-analysis/SKILL.md"
23
+ },
24
+ {
25
+ "name": "cache-guide",
26
+ "description": "When to use cache() DSL vs \"use cache\" directive — key differences and decision guide. Use when unsure which caching mechanism fits a given problem, comparing route/segment caching, function-level caching, and document-level caching, or asking \"which cache API should I use\".",
27
+ "argumentHint": "",
28
+ "path": "skills/cache-guide/SKILL.md"
29
+ },
30
+ {
31
+ "name": "caching",
32
+ "description": "Configure route/segment-subtree caching with memory, Cloudflare KV, or Vercel cache stores in @rangojs/router. Use when responses should be cached or revalidated, data is stale or not updating after code changes, or you are wiring up a cache store.",
33
+ "argumentHint": "[setup]",
34
+ "path": "skills/caching/SKILL.md"
35
+ },
36
+ {
37
+ "name": "comparison",
38
+ "description": "Compare Rango with Next.js App Router, TanStack Start, and Waku. Use when evaluating React frameworks, explaining why Rango, writing positioning or adoption guidance, answering migration questions, or checking claims about Rango's routing, loaders, caching, rendering, prefetching, safety, testing, observability, and production behavior.",
39
+ "argumentHint": "",
40
+ "path": "skills/comparison/SKILL.md"
41
+ },
42
+ {
43
+ "name": "composability",
44
+ "description": "Reusable composition patterns with globally importable route helpers in @rangojs/router. Use when sharing loaders, middleware, or handler logic across multiple route files, or avoiding copy-pasting the same route setup everywhere.",
45
+ "argumentHint": "pattern-name",
46
+ "path": "skills/composability/SKILL.md"
47
+ },
48
+ {
49
+ "name": "css",
50
+ "description": "Import and apply CSS in a Rango app. Render document/app stylesheets in the Document `<head>` with Vite's `?url` import plus a `precedence`-managed `<link rel=\"stylesheet\">` (React 19 resource model — deduped, ordered, loaded before paint). Use when wiring global/app CSS or a Document `<head>` stylesheet, or when deciding between `?url` + `<link>` and side-effect imports. Cross-app (host-router) navigation is a full document load, so each app's document CSS is always re-established by its own load.",
51
+ "argumentHint": "",
52
+ "path": "skills/css/SKILL.md"
53
+ },
54
+ {
55
+ "name": "debug-manifest",
56
+ "description": "Debug and inspect route manifest structure. Use when routes aren't matching as expected, you need to see the generated route tree, or a path resolves to the wrong handler.",
57
+ "argumentHint": "",
58
+ "path": "skills/debug-manifest/SKILL.md"
59
+ },
60
+ {
61
+ "name": "defer-hydration",
62
+ "description": "Keep the full body HTML in a PPR shell's first paint while moving a heavy subtree's hydration off the initial main-thread task — a gated Suspense boundary with the content as its own fallback, released on first idle. Use when a shell HIT paints fast but one long hydration task blocks the main thread, TTI/INP is poor despite instant paint, or a plain Suspense boundary left an empty hole in the frozen prelude.",
63
+ "argumentHint": "",
64
+ "path": "skills/defer-hydration/SKILL.md"
65
+ },
66
+ {
67
+ "name": "document-cache",
68
+ "description": "Cache the whole HTTP response at the edge with Cache-Control headers. Use when caching an entire page or response at a CDN edge, setting Cache-Control headers, or cutting origin hits for public pages — not for caching a single segment or function.",
69
+ "argumentHint": "[setup]",
70
+ "path": "skills/document-cache/SKILL.md"
71
+ },
72
+ {
73
+ "name": "fonts",
74
+ "description": "Load and configure web fonts with preload hints for optimal performance. Use when adding a custom font to a Rango app, fonts flash or swap on load (FOUT/FOIT), or you want font preload for performance.",
75
+ "argumentHint": "[provider]",
76
+ "path": "skills/fonts/SKILL.md"
77
+ },
78
+ {
79
+ "name": "handler-use",
80
+ "description": "Attach default loaders, middleware, parallels, and other use items directly to handlers via handler.use, and compose them with explicit use() at mount sites. Use when a handler needs its own default middleware/loader without repeating use() at every mount site, or deciding between handler-level defaults and per-route use().",
81
+ "argumentHint": "[handler]",
82
+ "path": "skills/handler-use/SKILL.md"
83
+ },
84
+ {
85
+ "name": "hooks",
86
+ "description": "Client-side React hooks for navigation, loaders, and state in @rangojs/router. Use when a client component needs the current URL, params, search params, navigation state, or loader data — e.g. \"how do I read the route param in a component\".",
87
+ "argumentHint": "[hook-name]",
88
+ "path": "skills/hooks/SKILL.md"
89
+ },
90
+ {
91
+ "name": "host-router",
92
+ "description": "Multi-app host routing with domain/subdomain patterns. Use when running multiple apps behind one domain or across subdomains, or routing requests to different apps based on hostname.",
93
+ "argumentHint": "",
94
+ "path": "skills/host-router/SKILL.md"
95
+ },
96
+ {
97
+ "name": "i18n",
98
+ "description": "Locale-aware routing with `include(\"/:locale?\", ...)`, locale resolution chains, and react-intl integration. Use when building a multi-language app, routes need a locale segment, or wiring up react-intl translations.",
99
+ "argumentHint": "[topic]",
100
+ "path": "skills/i18n/SKILL.md"
101
+ },
102
+ {
103
+ "name": "intercept",
104
+ "description": "Define intercept routes for modals, slide-overs, and soft navigation patterns in @rangojs/router. Use when opening a route as a modal/overlay on top of the current page while keeping the URL shareable, or asking \"how do I show this page in a modal\".",
105
+ "argumentHint": "[@slot-name] [route-to-intercept]",
106
+ "path": "skills/intercept/SKILL.md"
107
+ },
108
+ {
109
+ "name": "layout",
110
+ "description": "Define layout routes that wrap child routes in @rangojs/router. Use when sharing a persistent UI shell (nav, sidebar) across nested routes, or asking how to wrap child pages with a common layout.",
111
+ "argumentHint": "[component]",
112
+ "path": "skills/layout/SKILL.md"
113
+ },
114
+ {
115
+ "name": "links",
116
+ "description": "URL generation with ctx.reverse (server default), href (client), useHref (mounted), useMount, useReverse, and scopedReverse. Use when generating a link to a route by name instead of hardcoding a path, or a link breaks after routes move or get mounted elsewhere.",
117
+ "argumentHint": "[ctx.reverse|href|useHref|useMount|useReverse|scopedReverse]",
118
+ "path": "skills/links/SKILL.md"
119
+ },
120
+ {
121
+ "name": "loader",
122
+ "description": "Define data loaders for fetching data in routes with createLoader. Use when pages need per-request data that stays fresh, data should stream while the page renders, or client components need reactive server data.",
123
+ "argumentHint": "[loader]",
124
+ "path": "skills/loader/SKILL.md"
125
+ },
126
+ {
127
+ "name": "middleware",
128
+ "description": "Define middleware for authentication, logging, and request processing in @rangojs/router. Use when gating routes behind auth checks, logging requests, or running shared logic before a handler runs.",
129
+ "argumentHint": "[middleware-name]",
130
+ "path": "skills/middleware/SKILL.md"
131
+ },
132
+ {
133
+ "name": "migrate-nextjs",
134
+ "description": "Migrate a Next.js App Router project to @rangojs/router. Use when the user asks to \"migrate from Next.js\", \"convert Next.js to Rango\", \"replace Next.js\", or has a Next.js app they want to port.",
135
+ "argumentHint": "[path-to-nextjs-app]",
136
+ "path": "skills/migrate-nextjs/SKILL.md"
137
+ },
138
+ {
139
+ "name": "migrate-react-router",
140
+ "description": "Migrate a React Router v7/v6 project to @rangojs/router. Use when the user asks to \"migrate from React Router\", \"convert React Router to Rango\", \"replace React Router\", \"move from Remix to Rango\", or has a React Router / Remix app they want to port.",
141
+ "argumentHint": "path-to-react-router-app",
142
+ "path": "skills/migrate-react-router/SKILL.md"
143
+ },
144
+ {
145
+ "name": "mime-routes",
146
+ "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.",
147
+ "argumentHint": "[negotiate|vary|accept]",
148
+ "path": "skills/mime-routes/SKILL.md"
149
+ },
150
+ {
151
+ "name": "observability",
152
+ "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.",
153
+ "argumentHint": "",
154
+ "path": "skills/observability/SKILL.md"
155
+ },
156
+ {
157
+ "name": "parallel",
158
+ "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.",
159
+ "argumentHint": "[@slot-name]",
160
+ "path": "skills/parallel/SKILL.md"
161
+ },
162
+ {
163
+ "name": "ppr",
164
+ "description": "PPR shell caching — opt a page route in with the `ppr` path option; the router serves the cached HTML shell instantly and resumes the live holes. Use when a page should render instantly from a cached shell while specific parts stay live, or asking about partial prerendering in Rango.",
165
+ "argumentHint": "[setup]",
166
+ "path": "skills/ppr/SKILL.md"
167
+ },
168
+ {
169
+ "name": "prerender",
170
+ "description": "Pre-render route segments at build time with Prerender and Passthrough live fallback. Use when a page's content is mostly static and shouldn't render on every request, speeding up cold responses, or deciding which routes to prerender vs render live.",
171
+ "argumentHint": "[passthrough]",
172
+ "path": "skills/prerender/SKILL.md"
173
+ },
174
+ {
175
+ "name": "rango",
176
+ "description": "Overview of @rangojs/router and available skills. Use when unsure which skill to reach for, starting a new task in a Rango app, or asking \"what can this router do\".",
177
+ "argumentHint": "",
178
+ "path": "skills/rango/SKILL.md"
179
+ },
180
+ {
181
+ "name": "react-compiler",
182
+ "description": "Enable the React Compiler in a Rango app the @vitejs/plugin-rsc way — a separate @rolldown/plugin-babel running reactCompilerPreset(), ordered after react() and before the plugin that supplies @vitejs/plugin-rsc. Use when a consumer wants to turn React Compiler on, hits the dead plugin-react v6 `react({ babel })` path, or is unsure why server components aren't being compiled.",
183
+ "argumentHint": "",
184
+ "path": "skills/react-compiler/SKILL.md"
185
+ },
186
+ {
187
+ "name": "response-routes",
188
+ "description": "Response routes (path.json, path.text, etc.) for non-RSC endpoints with typed responses. Use when building a JSON/text API endpoint alongside your pages, or asking how to return raw JSON instead of RSC from a route.",
189
+ "argumentHint": "[json|text|html|xml|md|image|stream]",
190
+ "path": "skills/response-routes/SKILL.md"
191
+ },
192
+ {
193
+ "name": "route",
194
+ "description": "Define routes with path() in @rangojs/router. Use when creating a new page or route, or asking how to define a URL path and its handler.",
195
+ "argumentHint": "[pattern]",
196
+ "path": "skills/route/SKILL.md"
197
+ },
198
+ {
199
+ "name": "router-setup",
200
+ "description": "Create and configure the RSC router with createRouter. Use when bootstrapping a new Rango app, or configuring top-level router options like base path, cache store, or environment.",
201
+ "argumentHint": "[option]",
202
+ "path": "skills/router-setup/SKILL.md"
203
+ },
204
+ {
205
+ "name": "scripts",
206
+ "description": "Inject third-party scripts (GTM, analytics, widgets) into the document head/body via the Script handle. Use when adding Google Tag Manager, an analytics snippet, or a third-party widget script to the page.",
207
+ "argumentHint": "[vendor]",
208
+ "path": "skills/scripts/SKILL.md"
209
+ },
210
+ {
211
+ "name": "server-actions",
212
+ "description": "Define and call server actions (`\"use server\"`) — forms, useActionState, useOptimistic, validation, error handling, redirects, revalidation. Use when handling a form submission on the server, calling a server function from a client component, or needing optimistic UI after a mutation.",
213
+ "argumentHint": "[action]",
214
+ "path": "skills/server-actions/SKILL.md"
215
+ },
216
+ {
217
+ "name": "shell-manifest",
218
+ "description": "Shell manifest pattern — replayed handles as cache metadata that live loaders read, e.g. a prerendered product list with batched live prices. Use when a cached/prerendered shell needs to feed IDs or metadata to a live loader for freshly-fetched data.",
219
+ "argumentHint": "",
220
+ "path": "skills/shell-manifest/SKILL.md"
221
+ },
222
+ {
223
+ "name": "streams-and-websockets",
224
+ "description": "Long-lived Response handlers — Server-Sent Events (SSE) via path.stream and WebSocket upgrades via path.any on Cloudflare Workers, including middleware interaction and runtime caveats. Use when streaming live updates to the browser, or opening a WebSocket connection from a route on Cloudflare Workers.",
225
+ "argumentHint": "[sse | websocket | agents]",
226
+ "path": "skills/streams-and-websockets/SKILL.md"
227
+ },
228
+ {
229
+ "name": "tailwind",
230
+ "description": "Set up Tailwind CSS v4 with the Document component and CSS imports. Use when adding Tailwind CSS to a Rango app, or Tailwind classes aren't being applied or generated.",
231
+ "argumentHint": "[setup]",
232
+ "path": "skills/tailwind/SKILL.md"
233
+ },
234
+ {
235
+ "name": "testing",
236
+ "description": "Test @rangojs/router apps — unit (loaders/middleware/reverse/components), integration (dispatch/Flight), and e2e (dev+prod parity, progressive enhancement). Use when writing a unit test for a loader or middleware, or asking how to test a route end-to-end in dev and production.",
237
+ "argumentHint": "[layer]",
238
+ "path": "skills/testing/SKILL.md"
239
+ },
240
+ {
241
+ "name": "theme",
242
+ "description": "Opt-in theme system with FOUC prevention for light/dark mode. Use when adding a light/dark mode toggle, or the page flashes the wrong theme on load (FOUC).",
243
+ "argumentHint": "[setup]",
244
+ "path": "skills/theme/SKILL.md"
245
+ },
246
+ {
247
+ "name": "typesafety",
248
+ "description": "Set up type-safe routes, params, and environment types in @rangojs/router. Use when route or search params aren't typed, TypeScript can't infer a loader's return type, or wiring up typed environment bindings.",
249
+ "argumentHint": "[setup]",
250
+ "path": "skills/typesafety/SKILL.md"
251
+ },
252
+ {
253
+ "name": "use-cache",
254
+ "description": "Function-level caching with the \"use cache\" directive for RSC data functions and components in @rangojs/router. Use when a single function or component should memoize its own output, not a whole route/segment subtree or HTTP response.",
255
+ "argumentHint": "[profile-name]",
256
+ "path": "skills/use-cache/SKILL.md"
257
+ },
258
+ {
259
+ "name": "vercel",
260
+ "description": "Deploy a Rango app to Vercel Functions (Build Output API v3). Use when deploying a Rango app to Vercel, or asking how the router works with Vercel Functions and the Build Output API.",
261
+ "argumentHint": "",
262
+ "path": "skills/vercel/SKILL.md"
263
+ },
264
+ {
265
+ "name": "view-transitions",
266
+ "description": "Configure React View Transitions on layouts, routes, and parallel slots in @rangojs/router. Use when navigation should animate smoothly between pages, or wiring up React View Transitions on a route or layout.",
267
+ "argumentHint": "[layout|route|parallel|intercept]",
268
+ "path": "skills/view-transitions/SKILL.md"
269
+ }
270
+ ]
271
+ }
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: comparison
3
+ description: Compare Rango with Next.js App Router, TanStack Start, and Waku. Use when evaluating React frameworks, explaining why Rango, writing positioning or adoption guidance, answering migration questions, or checking claims about Rango's routing, loaders, caching, rendering, prefetching, safety, testing, observability, and production behavior.
4
+ ---
5
+
6
+ # Compare Rango with other React frameworks
7
+
8
+ Use the canonical [framework comparison](references/framework-comparison.md) as
9
+ the factual baseline. Read the sections relevant to the question; read the full
10
+ reference when producing an overall evaluation or editing the comparison itself.
11
+
12
+ ## Comparison rules
13
+
14
+ 1. Compare capabilities and architecture separately from ecosystem size, hiring,
15
+ integrations, and organizational familiarity.
16
+ 2. Present Rango's range clearly: start with `path()` and a component, then add
17
+ named routes, `include()`, loaders, caching, `revalidate()`, slots, intercepts,
18
+ safety, and diagnostics in the same declared route graph.
19
+ 3. Do not confuse Rango's `revalidate()` with cache invalidation. Cache APIs decide
20
+ stored-value freshness; `revalidate()` decides client render selection.
21
+ 4. Describe loaders as live-by-default RSC data slots beneath cached or prerendered
22
+ UI, not as renamed Remix or TanStack route loaders.
23
+ 5. Include production correctness where relevant: Rango State, userland client-cache
24
+ invalidation, deployment-skew recovery, tainted request context, CSP nonce
25
+ propagation, default CSRF origin checks, prefetch guards, testing, and timing.
26
+ 6. State boundaries and tradeoffs. In particular, distinguish origin checking from
27
+ token-based CSRF protection, nonce plumbing from application-owned CSP policy,
28
+ and reload-based skew recovery from Vercel deployment pinning.
29
+ 7. Credit competing frameworks where they lead. Next.js leads in ecosystem and
30
+ hiring, TanStack in search-param ergonomics and client/data devtools, and Waku
31
+ in minimal surface area.
32
+
33
+ ## Currency and evidence
34
+
35
+ - Treat Rango identifiers and behavior as source-verifiable. Check the current
36
+ package source or the relevant Rango skill when changing a precise claim.
37
+ - Competitor details age quickly. Before publishing or materially revising a claim,
38
+ verify it against current official documentation and link that primary source.
39
+ - Do not weaken a current, sourced claim merely because an older model remembers a
40
+ previous release. Check first: examples include TanStack Start's Rsbuild support,
41
+ Next.js `proxy.ts` and Cache Components, and Waku handler interceptors.
42
+ - Avoid declaring a framework universally "better." State which model fits the
43
+ application's constraints and why.
44
+
45
+ ## Output shape
46
+
47
+ Lead with the decision or differentiator. For a short answer, use the TL;DR and the
48
+ relevant framework-specific paragraph from the reference. For a decision memo,
49
+ cover the at-a-glance table, the simple-to-complex growth path, substantive runtime
50
+ differences, and the section where competitors still lead.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Rango Comparison"
3
+ short_description: "Compare Rango with other React frameworks"
4
+ default_prompt: "Use $comparison to compare Rango with Next.js, TanStack Start, and Waku."