@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.81

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 (316) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +942 -4
  3. package/dist/bin/rango.js +1689 -0
  4. package/dist/vite/index.js +5091 -941
  5. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  6. package/package.json +61 -52
  7. package/skills/breadcrumbs/SKILL.md +250 -0
  8. package/skills/cache-guide/SKILL.md +294 -0
  9. package/skills/caching/SKILL.md +93 -23
  10. package/skills/composability/SKILL.md +172 -0
  11. package/skills/debug-manifest/SKILL.md +12 -8
  12. package/skills/document-cache/SKILL.md +18 -16
  13. package/skills/fonts/SKILL.md +167 -0
  14. package/skills/handler-use/SKILL.md +362 -0
  15. package/skills/hooks/SKILL.md +340 -72
  16. package/skills/host-router/SKILL.md +218 -0
  17. package/skills/intercept/SKILL.md +151 -8
  18. package/skills/layout/SKILL.md +122 -3
  19. package/skills/links/SKILL.md +92 -31
  20. package/skills/loader/SKILL.md +404 -44
  21. package/skills/middleware/SKILL.md +205 -37
  22. package/skills/migrate-nextjs/SKILL.md +560 -0
  23. package/skills/migrate-react-router/SKILL.md +765 -0
  24. package/skills/mime-routes/SKILL.md +128 -0
  25. package/skills/parallel/SKILL.md +263 -1
  26. package/skills/prerender/SKILL.md +685 -0
  27. package/skills/rango/SKILL.md +87 -16
  28. package/skills/response-routes/SKILL.md +411 -0
  29. package/skills/route/SKILL.md +281 -14
  30. package/skills/router-setup/SKILL.md +210 -32
  31. package/skills/tailwind/SKILL.md +129 -0
  32. package/skills/theme/SKILL.md +9 -8
  33. package/skills/typesafety/SKILL.md +328 -89
  34. package/skills/use-cache/SKILL.md +324 -0
  35. package/src/__internal.ts +102 -4
  36. package/src/bin/rango.ts +321 -0
  37. package/src/browser/action-coordinator.ts +97 -0
  38. package/src/browser/action-response-classifier.ts +99 -0
  39. package/src/browser/app-version.ts +14 -0
  40. package/src/browser/event-controller.ts +92 -64
  41. package/src/browser/history-state.ts +80 -0
  42. package/src/browser/intercept-utils.ts +52 -0
  43. package/src/browser/link-interceptor.ts +24 -4
  44. package/src/browser/logging.ts +55 -0
  45. package/src/browser/merge-segment-loaders.ts +20 -12
  46. package/src/browser/navigation-bridge.ts +317 -560
  47. package/src/browser/navigation-client.ts +206 -68
  48. package/src/browser/navigation-store.ts +73 -55
  49. package/src/browser/navigation-transaction.ts +297 -0
  50. package/src/browser/network-error-handler.ts +61 -0
  51. package/src/browser/partial-update.ts +343 -316
  52. package/src/browser/prefetch/cache.ts +216 -0
  53. package/src/browser/prefetch/fetch.ts +206 -0
  54. package/src/browser/prefetch/observer.ts +65 -0
  55. package/src/browser/prefetch/policy.ts +48 -0
  56. package/src/browser/prefetch/queue.ts +160 -0
  57. package/src/browser/prefetch/resource-ready.ts +77 -0
  58. package/src/browser/rango-state.ts +112 -0
  59. package/src/browser/react/Link.tsx +253 -74
  60. package/src/browser/react/NavigationProvider.tsx +91 -11
  61. package/src/browser/react/context.ts +11 -0
  62. package/src/browser/react/filter-segment-order.ts +11 -0
  63. package/src/browser/react/index.ts +12 -12
  64. package/src/browser/react/location-state-shared.ts +95 -53
  65. package/src/browser/react/location-state.ts +60 -15
  66. package/src/browser/react/mount-context.ts +6 -1
  67. package/src/browser/react/nonce-context.ts +23 -0
  68. package/src/browser/react/shallow-equal.ts +27 -0
  69. package/src/browser/react/use-action.ts +29 -51
  70. package/src/browser/react/use-client-cache.ts +5 -3
  71. package/src/browser/react/use-handle.ts +30 -126
  72. package/src/browser/react/use-href.tsx +2 -2
  73. package/src/browser/react/use-link-status.ts +6 -5
  74. package/src/browser/react/use-navigation.ts +44 -65
  75. package/src/browser/react/use-params.ts +75 -0
  76. package/src/browser/react/use-pathname.ts +47 -0
  77. package/src/browser/react/use-router.ts +76 -0
  78. package/src/browser/react/use-search-params.ts +56 -0
  79. package/src/browser/react/use-segments.ts +80 -97
  80. package/src/browser/response-adapter.ts +73 -0
  81. package/src/browser/rsc-router.tsx +214 -58
  82. package/src/browser/scroll-restoration.ts +127 -52
  83. package/src/browser/segment-reconciler.ts +243 -0
  84. package/src/browser/segment-structure-assert.ts +16 -0
  85. package/src/browser/server-action-bridge.ts +510 -603
  86. package/src/browser/shallow.ts +6 -1
  87. package/src/browser/types.ts +141 -48
  88. package/src/browser/validate-redirect-origin.ts +29 -0
  89. package/src/build/generate-manifest.ts +235 -24
  90. package/src/build/generate-route-types.ts +39 -0
  91. package/src/build/index.ts +13 -0
  92. package/src/build/route-trie.ts +291 -0
  93. package/src/build/route-types/ast-helpers.ts +25 -0
  94. package/src/build/route-types/ast-route-extraction.ts +98 -0
  95. package/src/build/route-types/codegen.ts +102 -0
  96. package/src/build/route-types/include-resolution.ts +418 -0
  97. package/src/build/route-types/param-extraction.ts +48 -0
  98. package/src/build/route-types/per-module-writer.ts +128 -0
  99. package/src/build/route-types/router-processing.ts +618 -0
  100. package/src/build/route-types/scan-filter.ts +85 -0
  101. package/src/build/runtime-discovery.ts +231 -0
  102. package/src/cache/background-task.ts +34 -0
  103. package/src/cache/cache-key-utils.ts +44 -0
  104. package/src/cache/cache-policy.ts +125 -0
  105. package/src/cache/cache-runtime.ts +342 -0
  106. package/src/cache/cache-scope.ts +167 -309
  107. package/src/cache/cf/cf-cache-store.ts +571 -17
  108. package/src/cache/cf/index.ts +13 -3
  109. package/src/cache/document-cache.ts +116 -77
  110. package/src/cache/handle-capture.ts +81 -0
  111. package/src/cache/handle-snapshot.ts +41 -0
  112. package/src/cache/index.ts +1 -15
  113. package/src/cache/memory-segment-store.ts +191 -13
  114. package/src/cache/profile-registry.ts +73 -0
  115. package/src/cache/read-through-swr.ts +134 -0
  116. package/src/cache/segment-codec.ts +256 -0
  117. package/src/cache/taint.ts +153 -0
  118. package/src/cache/types.ts +72 -122
  119. package/src/client.rsc.tsx +3 -1
  120. package/src/client.tsx +135 -301
  121. package/src/component-utils.ts +4 -4
  122. package/src/components/DefaultDocument.tsx +5 -1
  123. package/src/context-var.ts +156 -0
  124. package/src/debug.ts +19 -9
  125. package/src/errors.ts +108 -2
  126. package/src/handle.ts +55 -29
  127. package/src/handles/MetaTags.tsx +73 -20
  128. package/src/handles/breadcrumbs.ts +66 -0
  129. package/src/handles/index.ts +1 -0
  130. package/src/handles/meta.ts +30 -13
  131. package/src/host/cookie-handler.ts +21 -15
  132. package/src/host/errors.ts +8 -8
  133. package/src/host/index.ts +4 -7
  134. package/src/host/pattern-matcher.ts +27 -27
  135. package/src/host/router.ts +61 -39
  136. package/src/host/testing.ts +8 -8
  137. package/src/host/types.ts +15 -7
  138. package/src/host/utils.ts +1 -1
  139. package/src/href-client.ts +119 -29
  140. package/src/index.rsc.ts +155 -19
  141. package/src/index.ts +251 -30
  142. package/src/internal-debug.ts +11 -0
  143. package/src/loader.rsc.ts +26 -157
  144. package/src/loader.ts +27 -10
  145. package/src/network-error-thrower.tsx +3 -1
  146. package/src/outlet-provider.tsx +45 -0
  147. package/src/prerender/param-hash.ts +37 -0
  148. package/src/prerender/store.ts +186 -0
  149. package/src/prerender.ts +524 -0
  150. package/src/reverse.ts +354 -0
  151. package/src/root-error-boundary.tsx +41 -29
  152. package/src/route-content-wrapper.tsx +7 -4
  153. package/src/route-definition/dsl-helpers.ts +1121 -0
  154. package/src/route-definition/helper-factories.ts +200 -0
  155. package/src/route-definition/helpers-types.ts +478 -0
  156. package/src/route-definition/index.ts +55 -0
  157. package/src/route-definition/redirect.ts +101 -0
  158. package/src/route-definition/resolve-handler-use.ts +149 -0
  159. package/src/route-definition.ts +1 -1428
  160. package/src/route-map-builder.ts +217 -123
  161. package/src/route-name.ts +53 -0
  162. package/src/route-types.ts +77 -8
  163. package/src/router/content-negotiation.ts +215 -0
  164. package/src/router/debug-manifest.ts +72 -0
  165. package/src/router/error-handling.ts +9 -9
  166. package/src/router/find-match.ts +160 -0
  167. package/src/router/handler-context.ts +438 -86
  168. package/src/router/intercept-resolution.ts +402 -0
  169. package/src/router/lazy-includes.ts +237 -0
  170. package/src/router/loader-resolution.ts +356 -128
  171. package/src/router/logging.ts +251 -0
  172. package/src/router/manifest.ts +163 -35
  173. package/src/router/match-api.ts +555 -0
  174. package/src/router/match-context.ts +5 -3
  175. package/src/router/match-handlers.ts +440 -0
  176. package/src/router/match-middleware/background-revalidation.ts +108 -93
  177. package/src/router/match-middleware/cache-lookup.ts +460 -10
  178. package/src/router/match-middleware/cache-store.ts +98 -26
  179. package/src/router/match-middleware/intercept-resolution.ts +57 -17
  180. package/src/router/match-middleware/segment-resolution.ts +80 -6
  181. package/src/router/match-pipelines.ts +10 -45
  182. package/src/router/match-result.ts +135 -35
  183. package/src/router/metrics.ts +240 -15
  184. package/src/router/middleware-cookies.ts +55 -0
  185. package/src/router/middleware-types.ts +220 -0
  186. package/src/router/middleware.ts +324 -369
  187. package/src/router/navigation-snapshot.ts +182 -0
  188. package/src/router/pattern-matching.ts +211 -43
  189. package/src/router/prerender-match.ts +502 -0
  190. package/src/router/preview-match.ts +98 -0
  191. package/src/router/request-classification.ts +310 -0
  192. package/src/router/revalidation.ts +137 -38
  193. package/src/router/route-snapshot.ts +245 -0
  194. package/src/router/router-context.ts +41 -21
  195. package/src/router/router-interfaces.ts +484 -0
  196. package/src/router/router-options.ts +618 -0
  197. package/src/router/router-registry.ts +24 -0
  198. package/src/router/segment-resolution/fresh.ts +748 -0
  199. package/src/router/segment-resolution/helpers.ts +268 -0
  200. package/src/router/segment-resolution/loader-cache.ts +199 -0
  201. package/src/router/segment-resolution/revalidation.ts +1379 -0
  202. package/src/router/segment-resolution/static-store.ts +67 -0
  203. package/src/router/segment-resolution.ts +21 -0
  204. package/src/router/segment-wrappers.ts +291 -0
  205. package/src/router/telemetry-otel.ts +299 -0
  206. package/src/router/telemetry.ts +300 -0
  207. package/src/router/timeout.ts +148 -0
  208. package/src/router/trie-matching.ts +239 -0
  209. package/src/router/types.ts +78 -3
  210. package/src/router.ts +740 -4252
  211. package/src/rsc/handler-context.ts +45 -0
  212. package/src/rsc/handler.ts +907 -797
  213. package/src/rsc/helpers.ts +140 -6
  214. package/src/rsc/index.ts +0 -20
  215. package/src/rsc/loader-fetch.ts +229 -0
  216. package/src/rsc/manifest-init.ts +90 -0
  217. package/src/rsc/nonce.ts +14 -0
  218. package/src/rsc/origin-guard.ts +141 -0
  219. package/src/rsc/progressive-enhancement.ts +393 -0
  220. package/src/rsc/response-error.ts +37 -0
  221. package/src/rsc/response-route-handler.ts +347 -0
  222. package/src/rsc/rsc-rendering.ts +246 -0
  223. package/src/rsc/runtime-warnings.ts +42 -0
  224. package/src/rsc/server-action.ts +358 -0
  225. package/src/rsc/ssr-setup.ts +128 -0
  226. package/src/rsc/types.ts +46 -11
  227. package/src/search-params.ts +230 -0
  228. package/src/segment-content-promise.ts +67 -0
  229. package/src/segment-loader-promise.ts +122 -0
  230. package/src/segment-system.tsx +134 -36
  231. package/src/server/context.ts +341 -61
  232. package/src/server/cookie-store.ts +190 -0
  233. package/src/server/fetchable-loader-store.ts +37 -0
  234. package/src/server/handle-store.ts +113 -15
  235. package/src/server/loader-registry.ts +24 -64
  236. package/src/server/request-context.ts +607 -81
  237. package/src/server.ts +35 -130
  238. package/src/ssr/index.tsx +103 -30
  239. package/src/static-handler.ts +126 -0
  240. package/src/theme/ThemeProvider.tsx +21 -15
  241. package/src/theme/ThemeScript.tsx +5 -5
  242. package/src/theme/constants.ts +5 -2
  243. package/src/theme/index.ts +4 -14
  244. package/src/theme/theme-context.ts +4 -30
  245. package/src/theme/theme-script.ts +21 -18
  246. package/src/types/boundaries.ts +158 -0
  247. package/src/types/cache-types.ts +198 -0
  248. package/src/types/error-types.ts +192 -0
  249. package/src/types/global-namespace.ts +100 -0
  250. package/src/types/handler-context.ts +791 -0
  251. package/src/types/index.ts +88 -0
  252. package/src/types/loader-types.ts +210 -0
  253. package/src/types/route-config.ts +170 -0
  254. package/src/types/route-entry.ts +120 -0
  255. package/src/types/segments.ts +150 -0
  256. package/src/types.ts +1 -1623
  257. package/src/urls/include-helper.ts +207 -0
  258. package/src/urls/index.ts +53 -0
  259. package/src/urls/path-helper-types.ts +372 -0
  260. package/src/urls/path-helper.ts +364 -0
  261. package/src/urls/pattern-types.ts +107 -0
  262. package/src/urls/response-types.ts +116 -0
  263. package/src/urls/type-extraction.ts +372 -0
  264. package/src/urls/urls-function.ts +98 -0
  265. package/src/urls.ts +1 -802
  266. package/src/use-loader.tsx +161 -81
  267. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  268. package/src/vite/discovery/discover-routers.ts +348 -0
  269. package/src/vite/discovery/prerender-collection.ts +439 -0
  270. package/src/vite/discovery/route-types-writer.ts +258 -0
  271. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  272. package/src/vite/discovery/state.ts +117 -0
  273. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  274. package/src/vite/index.ts +15 -1133
  275. package/src/vite/plugin-types.ts +103 -0
  276. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  277. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  278. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  279. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  280. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  281. package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
  282. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
  283. package/src/vite/plugins/expose-id-utils.ts +299 -0
  284. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  285. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  286. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  287. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  288. package/src/vite/plugins/expose-ids/types.ts +45 -0
  289. package/src/vite/plugins/expose-internal-ids.ts +786 -0
  290. package/src/vite/plugins/performance-tracks.ts +88 -0
  291. package/src/vite/plugins/refresh-cmd.ts +127 -0
  292. package/src/vite/plugins/use-cache-transform.ts +323 -0
  293. package/src/vite/plugins/version-injector.ts +83 -0
  294. package/src/vite/plugins/version-plugin.ts +266 -0
  295. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  296. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  297. package/src/vite/rango.ts +462 -0
  298. package/src/vite/router-discovery.ts +977 -0
  299. package/src/vite/utils/ast-handler-extract.ts +517 -0
  300. package/src/vite/utils/banner.ts +36 -0
  301. package/src/vite/utils/bundle-analysis.ts +137 -0
  302. package/src/vite/utils/manifest-utils.ts +70 -0
  303. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  304. package/src/vite/utils/prerender-utils.ts +221 -0
  305. package/src/vite/utils/shared-utils.ts +170 -0
  306. package/CLAUDE.md +0 -43
  307. package/src/browser/lru-cache.ts +0 -69
  308. package/src/browser/request-controller.ts +0 -164
  309. package/src/cache/memory-store.ts +0 -253
  310. package/src/href-context.ts +0 -33
  311. package/src/href.ts +0 -255
  312. package/src/server/route-manifest-cache.ts +0 -173
  313. package/src/vite/expose-handle-id.ts +0 -209
  314. package/src/vite/expose-loader-id.ts +0 -426
  315. package/src/vite/expose-location-state-id.ts +0 -177
  316. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -0,0 +1,324 @@
1
+ ---
2
+ name: use-cache
3
+ description: Function-level caching with "use cache" directive for RSC data functions and components
4
+ argument-hint: [profile-name]
5
+ ---
6
+
7
+ # "use cache" Directive
8
+
9
+ Function-level caching for async server functions and RSC components. Caches
10
+ return values with TTL + stale-while-revalidate. Complementary to the route-level
11
+ `cache()` DSL and build-time `Static()`/`Prerender()`.
12
+
13
+ ## Basic Usage
14
+
15
+ ### File-level (all exports cached with default profile)
16
+
17
+ ```typescript
18
+ "use cache";
19
+
20
+ export async function getProducts() {
21
+ return await db.query("SELECT * FROM products");
22
+ }
23
+
24
+ export async function getCategories() {
25
+ return await db.query("SELECT * FROM categories");
26
+ }
27
+ ```
28
+
29
+ ### Function-level (per-function profile)
30
+
31
+ ```typescript
32
+ export async function getProducts() {
33
+ "use cache: short";
34
+ return await db.query("SELECT * FROM products");
35
+ }
36
+
37
+ export async function getCategories() {
38
+ "use cache: long";
39
+ return await db.query("SELECT * FROM categories");
40
+ }
41
+ ```
42
+
43
+ ### RSC component
44
+
45
+ ```typescript
46
+ export async function ProductCard({ id }: { id: string }) {
47
+ "use cache: products"
48
+ const product = await db.query('SELECT * FROM products WHERE id = ?', [id]);
49
+ return <div>{product.name}</div>;
50
+ }
51
+ ```
52
+
53
+ ## Named Cache Profiles
54
+
55
+ Define profiles in createRouter. Profile names map to `"use cache: <name>"` and
56
+ `cache('<name>')` in the DSL.
57
+
58
+ ```typescript
59
+ createRouter({
60
+ cacheProfiles: {
61
+ default: { ttl: 900, swr: 1800 },
62
+ short: { ttl: 60, swr: 120 },
63
+ long: { ttl: 3600, swr: 7200 },
64
+ products: { ttl: 300, swr: 600, tags: ["products"] },
65
+ },
66
+ });
67
+ ```
68
+
69
+ - `"use cache"` (no name) resolves to `default`.
70
+ - `"use cache: short"` resolves to the `short` profile.
71
+ - Unknown profile names throw at build/boot time.
72
+
73
+ ## Cache Key
74
+
75
+ ```
76
+ use-cache:{functionId}:{serializedArgs}
77
+ ```
78
+
79
+ - `functionId` -- stable ID from Vite transform (module path + export name).
80
+ - `serializedArgs` -- non-tainted arguments serialized via RSC `encodeReply()`.
81
+
82
+ Different functions always produce different cache keys, even for the same route.
83
+ This is important for intercepted routes -- the path handler and intercept handler
84
+ each have their own `functionId` and therefore their own cache entries.
85
+
86
+ ## Tainted Arguments (ctx, env, req)
87
+
88
+ Request-scoped objects are branded with `Symbol.for('rango:nocache')` at creation.
89
+ When detected:
90
+
91
+ 1. **Excluded from cache key** -- request-scoped, not meaningful for keying.
92
+ 2. **Handle data captured on miss** -- side effects via `ctx.use(Handle)` are recorded.
93
+ 3. **Handle data replayed on hit** -- restored into the current request's HandleStore.
94
+
95
+ ```typescript
96
+ export async function getProductData(ctx) {
97
+ "use cache: short";
98
+ const breadcrumb = ctx.use(Breadcrumbs);
99
+ breadcrumb({ label: "Products", href: "/products" });
100
+ return await db.query("SELECT * FROM products");
101
+ }
102
+ // On hit: return value restored, breadcrumb replayed.
103
+ ```
104
+
105
+ ## Request-Scoped Guards
106
+
107
+ ### Read Guards
108
+
109
+ `cookies()` and `headers()` **throw** inside a `"use cache"` function because
110
+ per-request values (cookies, headers) are not reflected in the cache key. Without
111
+ this guard, one user's data would be served to another.
112
+
113
+ Extract the value before the cached function and pass it as an argument:
114
+
115
+ ```typescript
116
+ const locale = cookies().get("locale")?.value ?? "en";
117
+ const data = await getCachedData(locale); // locale is now in the cache key
118
+ ```
119
+
120
+ ### Side-Effect Guards
121
+
122
+ These ctx methods **throw** inside a `"use cache"` function because their effects
123
+ are lost on cache hit (the function body is skipped):
124
+
125
+ - `ctx.set()` / `ctx.get()` for passing values to children
126
+ - `ctx.header()`
127
+ - `ctx.setTheme()`
128
+ - `ctx.setLocationState()`
129
+ - `ctx.onResponse()`
130
+
131
+ The error message recommends two alternatives:
132
+
133
+ 1. Extract the data fetch into a separate cached function and call ctx methods outside it.
134
+ 2. Use the route-level `cache()` DSL which caches all segments together.
135
+
136
+ **`ctx.use(Handle)` is NOT guarded** -- handle push is captured on miss and replayed
137
+ on hit. This is the correct way to pass data from cached functions.
138
+
139
+ ### Pattern: Separate cached function from ctx side effects
140
+
141
+ ```typescript
142
+ // Cached data fetch (pure)
143
+ async function getNavData() {
144
+ "use cache: short"
145
+ return await db.query('SELECT * FROM nav_items');
146
+ }
147
+
148
+ // Handler (uncached, calls ctx methods freely)
149
+ async function NavLayout(ctx) {
150
+ const navData = await getNavData();
151
+ ctx.set("navItems", navData); // Works -- outside "use cache"
152
+ return <Nav items={navData}><Outlet /></Nav>;
153
+ }
154
+ ```
155
+
156
+ ## Misuse Guards
157
+
158
+ ### Cannot use as middleware
159
+
160
+ Cached functions cannot be passed to `middleware()`. Middleware runs on every
161
+ request (onion model) and must not be cached.
162
+
163
+ ```typescript
164
+ // WRONG -- throws at boot time
165
+ middleware(cachedFn);
166
+
167
+ // RIGHT -- call cached function inside middleware
168
+ middleware(async (ctx, next) => {
169
+ const data = await getCachedData();
170
+ ctx.set("data", data);
171
+ await next();
172
+ });
173
+ ```
174
+
175
+ ### Cannot use as Static() handler
176
+
177
+ Static handlers render once at build time. `"use cache"` is redundant.
178
+
179
+ ```typescript
180
+ // WRONG -- throws at boot time
181
+ export const Page = Static(cachedFn);
182
+
183
+ // RIGHT -- remove "use cache", Static already caches
184
+ export const Page = Static(async (ctx) => {
185
+ return <div>Built once</div>;
186
+ });
187
+ ```
188
+
189
+ ### Cannot use as Prerender() handler or getParams
190
+
191
+ Prerender handlers render at build time. `"use cache"` is redundant.
192
+
193
+ ```typescript
194
+ // WRONG -- throws at boot time (handler)
195
+ export const Page = Prerender(getParams, cachedFn);
196
+
197
+ // WRONG -- throws at boot time (getParams)
198
+ export const Page = Prerender(cachedGetParams, handler);
199
+
200
+ // RIGHT -- remove "use cache"
201
+ export const Page = Prerender(
202
+ async () => [{ slug: "a" }],
203
+ async (ctx) => <Page slug={ctx.params.slug} />,
204
+ );
205
+ ```
206
+
207
+ ## Performance: waitUntil
208
+
209
+ On cache miss, the function executes and the result is serialized inline (blocking).
210
+ The cache **store write** (`setItem`) is deferred to `waitUntil` and does NOT block
211
+ the response.
212
+
213
+ On stale hit, stale data is returned immediately. Background revalidation (re-execute
214
+
215
+ - store) runs entirely inside `waitUntil`.
216
+
217
+ | Phase | Blocks response? |
218
+ | ------------------------------------ | ---------------- |
219
+ | Function execution (miss) | Yes |
220
+ | Result serialization (miss) | Yes |
221
+ | Cache store write (miss) | No (waitUntil) |
222
+ | Stale value return (stale hit) | No (immediate) |
223
+ | Background revalidation (stale) | No (waitUntil) |
224
+ | Cache lookup + deserialization (hit) | Yes (fast) |
225
+
226
+ ## Using with Loaders
227
+
228
+ `"use cache"` works inside loaders. The loader runs every request, but the inner
229
+ cached function returns cached data:
230
+
231
+ ```typescript
232
+ // Cached data function
233
+ export async function getProductData(slug: string) {
234
+ "use cache";
235
+ return await db.query("SELECT * FROM products WHERE slug = ?", [slug]);
236
+ }
237
+
238
+ // Loader runs every request, but inner call is cached
239
+ export const ProductLoader = createLoader(async (ctx) => {
240
+ return getProductData(ctx.params.slug);
241
+ });
242
+ ```
243
+
244
+ ## Using with Intercepted Routes
245
+
246
+ Path handlers and intercept handlers have different `functionId` values from the
247
+ Vite transform, so they naturally get distinct cache entries even for the same URL:
248
+
249
+ ```typescript
250
+ // Path handler -- cached separately
251
+ path("/product/:id", async (ctx) => {
252
+ "use cache"
253
+ return <FullProductPage id={ctx.params.id} />;
254
+ }),
255
+
256
+ // Intercept handler -- cached separately (different functionId)
257
+ intercept("@modal", ".product", async (ctx) => {
258
+ "use cache"
259
+ return <ProductModal id={ctx.params.id} />;
260
+ }),
261
+ ```
262
+
263
+ ## Vite Transform
264
+
265
+ The `rango:use-cache` Vite plugin detects the directive and wraps exports with
266
+ `registerCachedFunction()`:
267
+
268
+ ```typescript
269
+ // Input
270
+ "use cache"
271
+ export async function getProducts() { ... }
272
+
273
+ // Output
274
+ import { registerCachedFunction } from '@rangojs/router/cache-runtime';
275
+ export const getProducts = registerCachedFunction(
276
+ async function getProducts() { ... },
277
+ "src/data/products.ts#getProducts",
278
+ "default"
279
+ );
280
+ ```
281
+
282
+ Function-level directives are hoisted:
283
+
284
+ ```typescript
285
+ // Input
286
+ export async function getProducts() {
287
+ "use cache: short";
288
+ return await db.query("...");
289
+ }
290
+
291
+ // Output
292
+ const __rango_cached_getProducts = registerCachedFunction(
293
+ async function getProducts() {
294
+ return await db.query("...");
295
+ },
296
+ "src/data/products.ts#getProducts",
297
+ "short",
298
+ );
299
+ export async function getProducts() {
300
+ return __rango_cached_getProducts();
301
+ }
302
+ ```
303
+
304
+ ## Backing Store
305
+
306
+ Writes to the same `SegmentCacheStore` as `cache()` DSL, `Static()`, and `Prerender()`.
307
+ One store, one configuration, one invalidation API. Tag-based invalidation
308
+ (`revalidateTag`) works across all mechanisms.
309
+
310
+ ## Interaction with Other Caching
311
+
312
+ | Mechanism | Granularity | When | Use case |
313
+ | ------------------ | ------------------ | ---------- | ----------------------------------------------- |
314
+ | `"use cache"` | Function/component | Runtime | Cache individual data fetches or components |
315
+ | `cache()` DSL | Route segment | Runtime | Cache entire route subtrees with children |
316
+ | `cache('profile')` | Route segment | Runtime | Same as cache() with a named profile |
317
+ | `Static()` | Route segment | Build-time | Render once, never re-render |
318
+ | `Prerender()` | Route segment | Build-time | Pre-render known params, optional live fallback |
319
+
320
+ ## Dev Mode
321
+
322
+ In development, the Vite transform still wraps functions, but the cache store is
323
+ a `MemorySegmentCacheStore` that works locally. Functions cache normally in dev
324
+ for testing cache behavior.
package/src/__internal.ts CHANGED
@@ -108,7 +108,11 @@ export type {
108
108
  * @internal
109
109
  * Router context for AsyncLocalStorage.
110
110
  */
111
- export type { RouterContext, RevalidationContext, InterceptResult } from "./router/router-context.js";
111
+ export type {
112
+ RouterContext,
113
+ RevalidationContext,
114
+ InterceptResult,
115
+ } from "./router/router-context.js";
112
116
 
113
117
  // ============================================================================
114
118
  // Match Pipeline (Internal)
@@ -118,7 +122,10 @@ export type { RouterContext, RevalidationContext, InterceptResult } from "./rout
118
122
  * @internal
119
123
  * Route match context during pipeline processing.
120
124
  */
121
- export type { MatchContext, MatchPipelineState } from "./router/match-context.js";
125
+ export type {
126
+ MatchContext,
127
+ MatchPipelineState,
128
+ } from "./router/match-context.js";
122
129
 
123
130
  /**
124
131
  * @internal
@@ -153,10 +160,102 @@ export type {
153
160
  /**
154
161
  * @internal
155
162
  * Internal handler context with additional props for router internals.
156
- * Includes `_originalRequest` and `_currentSegmentId`.
163
+ * Includes `_currentSegmentId` and `_responseType`.
157
164
  */
158
165
  export type { InternalHandlerContext } from "./types.js";
159
166
 
167
+ // ============================================================================
168
+ // Rendering (Internal)
169
+ // ============================================================================
170
+
171
+ /**
172
+ * @internal
173
+ * Builds React element trees from route segments.
174
+ */
175
+ export { renderSegments } from "./segment-system.js";
176
+
177
+ // ============================================================================
178
+ // Error Utilities (Internal)
179
+ // ============================================================================
180
+
181
+ /**
182
+ * @internal
183
+ * Error sanitization and network error utilities.
184
+ */
185
+ export { sanitizeError, NetworkError, isNetworkError } from "./errors.js";
186
+
187
+ // ============================================================================
188
+ // Type Utilities (Internal)
189
+ // ============================================================================
190
+
191
+ /**
192
+ * @internal
193
+ * Scoped view of GeneratedRouteMap for Handler<"localName", ScopedRouteMap<"prefix">>.
194
+ */
195
+ export type { ScopedRouteMap } from "./types.js";
196
+
197
+ /**
198
+ * @internal
199
+ * Type-level utilities for reverse URL generation.
200
+ */
201
+ export type { MergeRoutes, SanitizePrefix } from "./reverse.js";
202
+
203
+ /**
204
+ * @internal
205
+ * Individual telemetry event types.
206
+ */
207
+ export type {
208
+ RequestStartEvent,
209
+ RequestEndEvent,
210
+ RequestErrorEvent,
211
+ RequestTimeoutEvent,
212
+ LoaderStartEvent,
213
+ LoaderEndEvent,
214
+ LoaderErrorEvent,
215
+ HandlerErrorEvent,
216
+ CacheDecisionEvent,
217
+ RevalidationDecisionEvent,
218
+ } from "./router/telemetry.js";
219
+
220
+ // ============================================================================
221
+ // Pre-render / Static Handler Guards (Internal)
222
+ // ============================================================================
223
+
224
+ /**
225
+ * @internal
226
+ * Type guard for prerender handler definitions.
227
+ */
228
+ export { isPrerenderHandler, isPassthroughHandler } from "./prerender.js";
229
+
230
+ /**
231
+ * @internal
232
+ * Type guard for static handler definitions.
233
+ */
234
+ export { isStaticHandler } from "./static-handler.js";
235
+
236
+ // ============================================================================
237
+ // URL Pattern Internals
238
+ // ============================================================================
239
+
240
+ /**
241
+ * @internal
242
+ * Sentinel used to tag response-type route entries.
243
+ */
244
+ export { RESPONSE_TYPE } from "./urls.js";
245
+
246
+ // ============================================================================
247
+ // Route Match Debug (Internal)
248
+ // ============================================================================
249
+
250
+ /**
251
+ * @internal
252
+ * Debug utilities for route matching performance analysis.
253
+ */
254
+ export {
255
+ enableMatchDebug,
256
+ getMatchDebugStats,
257
+ } from "./router/pattern-matching.js";
258
+
160
259
  // ============================================================================
161
260
  // Debug Utilities (Internal)
162
261
  // ============================================================================
@@ -172,4 +271,3 @@ export {
172
271
  type SerializedEntry,
173
272
  type SerializedManifest,
174
273
  } from "./debug.js";
175
-