@rangojs/router 0.20.0 → 0.22.0

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 (331) hide show
  1. package/dist/bin/rango.js +39 -15
  2. package/dist/types/browser/event-controller.d.ts +49 -0
  3. package/dist/types/browser/history-state.d.ts +16 -4
  4. package/dist/types/browser/navigation-store.d.ts +9 -0
  5. package/dist/types/browser/navigation-transaction.d.ts +7 -0
  6. package/dist/types/browser/partial-update.d.ts +2 -1
  7. package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
  8. package/dist/types/browser/rango-state.d.ts +3 -1
  9. package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
  10. package/dist/types/browser/react/context.d.ts +25 -0
  11. package/dist/types/browser/react/location-state-shared.d.ts +84 -10
  12. package/dist/types/browser/react/location-state.d.ts +7 -2
  13. package/dist/types/browser/rsc-router.d.ts +13 -2
  14. package/dist/types/browser/types.d.ts +10 -0
  15. package/dist/types/build/generate-manifest.d.ts +2 -0
  16. package/dist/types/cache/background-task.d.ts +22 -0
  17. package/dist/types/cache/cache-key-utils.d.ts +50 -5
  18. package/dist/types/cache/cache-policy.d.ts +17 -0
  19. package/dist/types/cache/cache-scope.d.ts +5 -6
  20. package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
  21. package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
  22. package/dist/types/cache/document-cache.d.ts +8 -5
  23. package/dist/types/cache/handle-snapshot.d.ts +59 -50
  24. package/dist/types/cache/index.d.ts +3 -1
  25. package/dist/types/cache/invalidation-order.d.ts +14 -0
  26. package/dist/types/cache/memory-segment-store.d.ts +33 -1
  27. package/dist/types/cache/shell-snapshot.d.ts +29 -4
  28. package/dist/types/cache/store-scope.d.ts +22 -0
  29. package/dist/types/cache/tag-invalidation.d.ts +7 -6
  30. package/dist/types/cache/types.d.ts +84 -24
  31. package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
  32. package/dist/types/client-urls/navigation.d.ts +7 -1
  33. package/dist/types/client-urls/optimistic-location.d.ts +10 -4
  34. package/dist/types/errors.d.ts +6 -0
  35. package/dist/types/handles/deferred-resolution.d.ts +18 -1
  36. package/dist/types/internal-suspense-audit.d.ts +1 -0
  37. package/dist/types/loader-store.d.ts +4 -8
  38. package/dist/types/outlet-provider.d.ts +2 -1
  39. package/dist/types/prerender/build-shell-capture.d.ts +8 -6
  40. package/dist/types/prerender/cloudflare.d.ts +49 -0
  41. package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
  42. package/dist/types/prerender/index.d.ts +12 -0
  43. package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
  44. package/dist/types/prerender/on-demand.d.ts +272 -0
  45. package/dist/types/prerender/producer-guard.d.ts +33 -0
  46. package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
  47. package/dist/types/prerender/warm-request.d.ts +65 -0
  48. package/dist/types/prerender/warm.d.ts +65 -0
  49. package/dist/types/prerender/writable-store.d.ts +170 -0
  50. package/dist/types/prerender.d.ts +27 -0
  51. package/dist/types/reverse.d.ts +1 -1
  52. package/dist/types/route-content-wrapper.d.ts +3 -1
  53. package/dist/types/router/error-handling.d.ts +2 -0
  54. package/dist/types/router/handler-context.d.ts +1 -1
  55. package/dist/types/router/match-middleware/cache-lookup.d.ts +15 -1
  56. package/dist/types/router/navigation-snapshot.d.ts +8 -1
  57. package/dist/types/router/pattern-matching.d.ts +2 -0
  58. package/dist/types/router/prefetch-default.d.ts +4 -4
  59. package/dist/types/router/prerender-match.d.ts +23 -1
  60. package/dist/types/router/route-trie-builder.d.ts +8 -1
  61. package/dist/types/router/router-context.d.ts +1 -0
  62. package/dist/types/router/router-interfaces.d.ts +32 -1
  63. package/dist/types/router/router-options.d.ts +39 -5
  64. package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
  65. package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
  66. package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
  67. package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
  68. package/dist/types/router/trie-matching.d.ts +2 -0
  69. package/dist/types/router-versions.d.ts +39 -0
  70. package/dist/types/rsc/handler-context.d.ts +5 -0
  71. package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
  72. package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
  73. package/dist/types/rsc/shell-capture.d.ts +14 -1
  74. package/dist/types/rsc/shell-serve.d.ts +2 -2
  75. package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
  76. package/dist/types/rsc/types.d.ts +12 -6
  77. package/dist/types/segment-boundary-content.d.ts +17 -0
  78. package/dist/types/segment-loader-promise.d.ts +2 -6
  79. package/dist/types/server/build-version-table.d.ts +53 -0
  80. package/dist/types/server/context.d.ts +12 -4
  81. package/dist/types/server/handle-store.d.ts +89 -46
  82. package/dist/types/server/request-context.d.ts +84 -9
  83. package/dist/types/suspense-audit-react.d.ts +26 -0
  84. package/dist/types/suspense-audit.d.ts +157 -0
  85. package/dist/types/testing/action-form.d.ts +34 -0
  86. package/dist/types/testing/build-versions.d.ts +32 -0
  87. package/dist/types/testing/dom.entry.d.ts +1 -1
  88. package/dist/types/testing/flight.entry.d.ts +3 -1
  89. package/dist/types/testing/index.d.ts +6 -0
  90. package/dist/types/testing/internal/seed-vars.d.ts +7 -2
  91. package/dist/types/testing/internal/server-modules.d.ts +8 -0
  92. package/dist/types/testing/location-state-key.d.ts +5 -1
  93. package/dist/types/testing/render-route.d.ts +77 -6
  94. package/dist/types/testing/serve-shell-request.d.ts +55 -4
  95. package/dist/types/testing/shell-status.d.ts +14 -6
  96. package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
  97. package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
  98. package/dist/types/thenable-status.d.ts +6 -0
  99. package/dist/types/types/handler-context.d.ts +15 -5
  100. package/dist/types/types/route-entry.d.ts +5 -0
  101. package/dist/types/urls/path-helper.d.ts +18 -0
  102. package/dist/types/vite/discovery/build-versions.d.ts +393 -0
  103. package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
  104. package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
  105. package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
  106. package/dist/types/vite/discovery/state.d.ts +25 -0
  107. package/dist/types/vite/encryption-key.d.ts +18 -0
  108. package/dist/types/vite/inject-client-debug.d.ts +6 -25
  109. package/dist/types/vite/plugin-types.d.ts +27 -0
  110. package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
  111. package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
  112. package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
  113. package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
  114. package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
  115. package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
  116. package/dist/types/vite/router-discovery.d.ts +6 -0
  117. package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
  118. package/dist/types/vite/utils/client-chunks.d.ts +2 -0
  119. package/dist/types/vite/utils/compare-strings.d.ts +7 -0
  120. package/dist/types/vite/utils/package-resolution.d.ts +8 -0
  121. package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
  122. package/dist/vite/index.js +1707 -931
  123. package/package.json +12 -3
  124. package/skills/cache-guide/SKILL.md +102 -37
  125. package/skills/caching/SKILL.md +56 -9
  126. package/skills/catalog.json +1 -1
  127. package/skills/client-urls/SKILL.md +16 -0
  128. package/skills/cloudflare/SKILL.md +133 -1
  129. package/skills/comparison/references/framework-comparison.md +17 -13
  130. package/skills/deployment-caching/SKILL.md +33 -12
  131. package/skills/document-cache/SKILL.md +16 -14
  132. package/skills/hooks/SKILL.md +25 -0
  133. package/skills/hooks/handle-and-actions.md +5 -0
  134. package/skills/hooks/navigation.md +38 -0
  135. package/skills/hooks/state.md +213 -11
  136. package/skills/hooks/urls.md +40 -1
  137. package/skills/host-router/SKILL.md +31 -0
  138. package/skills/intercept/SKILL.md +6 -0
  139. package/skills/loader/SKILL.md +25 -5
  140. package/skills/middleware/SKILL.md +2 -0
  141. package/skills/migrate-nextjs/SKILL.md +82 -9
  142. package/skills/ppr/SKILL.md +150 -48
  143. package/skills/prerender/SKILL.md +651 -10
  144. package/skills/rango/SKILL.md +9 -7
  145. package/skills/response-routes/SKILL.md +5 -5
  146. package/skills/route/SKILL.md +29 -0
  147. package/skills/router-setup/SKILL.md +15 -1
  148. package/skills/testing/SKILL.md +32 -27
  149. package/skills/testing/cache-prerender.md +18 -17
  150. package/skills/testing/client-components.md +193 -8
  151. package/skills/testing/handles.md +2 -0
  152. package/skills/testing/loader.md +1 -1
  153. package/skills/testing/middleware.md +1 -1
  154. package/skills/testing/render-handler.md +18 -18
  155. package/skills/testing/serve-shell-request.md +167 -22
  156. package/skills/testing/server-actions.md +17 -17
  157. package/skills/testing/server-tree.md +1 -1
  158. package/skills/typesafety/generated-files-and-cli.md +1 -1
  159. package/skills/use-cache/SKILL.md +25 -10
  160. package/skills/vercel/SKILL.md +5 -3
  161. package/skills/view-transitions/SKILL.md +9 -4
  162. package/src/bin/rango.ts +1 -1
  163. package/src/browser/event-controller.ts +119 -2
  164. package/src/browser/history-state.ts +39 -17
  165. package/src/browser/link-interceptor.ts +2 -2
  166. package/src/browser/navigation-bridge.ts +104 -41
  167. package/src/browser/navigation-store.ts +26 -0
  168. package/src/browser/navigation-transaction.ts +24 -12
  169. package/src/browser/network-error-handler.ts +2 -0
  170. package/src/browser/partial-update.ts +58 -14
  171. package/src/browser/prefetch/default-strategy.ts +22 -42
  172. package/src/browser/rango-state.ts +3 -1
  173. package/src/browser/react/Link.tsx +37 -43
  174. package/src/browser/react/NavigationProvider.tsx +85 -1
  175. package/src/browser/react/context.ts +30 -0
  176. package/src/browser/react/location-state-shared.ts +200 -34
  177. package/src/browser/react/location-state.ts +28 -77
  178. package/src/browser/react/use-action.ts +4 -1
  179. package/src/browser/react/use-handle.ts +3 -0
  180. package/src/browser/react/use-link-status.ts +4 -3
  181. package/src/browser/react/use-navigation.ts +4 -1
  182. package/src/browser/react/use-params.ts +4 -1
  183. package/src/browser/react/use-pathname.ts +4 -1
  184. package/src/browser/react/use-search-params.ts +5 -3
  185. package/src/browser/react/use-segments.ts +36 -54
  186. package/src/browser/rsc-router.tsx +93 -31
  187. package/src/browser/segment-reconciler.ts +3 -3
  188. package/src/browser/server-action-bridge.ts +43 -7
  189. package/src/browser/types.ts +11 -0
  190. package/src/build/generate-manifest.ts +17 -0
  191. package/src/build/merge-full-manifests.ts +5 -0
  192. package/src/build/route-trie.ts +1 -0
  193. package/src/cache/background-task.ts +61 -0
  194. package/src/cache/cache-key-utils.ts +91 -12
  195. package/src/cache/cache-policy.ts +11 -2
  196. package/src/cache/cache-runtime.ts +23 -23
  197. package/src/cache/cache-scope.ts +48 -36
  198. package/src/cache/cf/cf-cache-store.ts +91 -66
  199. package/src/cache/cf/cf-cache-types.ts +12 -4
  200. package/src/cache/document-cache.ts +35 -14
  201. package/src/cache/handle-snapshot.ts +118 -86
  202. package/src/cache/index.ts +5 -0
  203. package/src/cache/invalidation-order.ts +53 -0
  204. package/src/cache/memory-segment-store.ts +52 -1
  205. package/src/cache/shell-snapshot.ts +52 -5
  206. package/src/cache/store-scope.ts +36 -0
  207. package/src/cache/tag-invalidation.ts +7 -5
  208. package/src/cache/types.ts +90 -24
  209. package/src/cache/vercel/vercel-cache-store.ts +68 -26
  210. package/src/client-urls/client-root.tsx +1 -0
  211. package/src/client-urls/navigation.ts +10 -0
  212. package/src/client-urls/optimistic-location.ts +10 -4
  213. package/src/client.tsx +40 -3
  214. package/src/errors.ts +13 -6
  215. package/src/handles/deferred-resolution.ts +36 -0
  216. package/src/internal-suspense-audit.ts +12 -0
  217. package/src/loader-store.ts +4 -9
  218. package/src/outlet-provider.tsx +25 -1
  219. package/src/prerender/build-shell-capture.ts +11 -9
  220. package/src/prerender/cloudflare.ts +130 -0
  221. package/src/prerender/create-prerender-trigger.ts +780 -0
  222. package/src/prerender/index.ts +39 -0
  223. package/src/prerender/memory-prerender-store.ts +115 -0
  224. package/src/prerender/on-demand.ts +339 -0
  225. package/src/prerender/producer-guard.ts +66 -0
  226. package/src/prerender/shell-manifest-key.ts +12 -17
  227. package/src/prerender/warm-request.ts +154 -0
  228. package/src/prerender/warm.ts +193 -0
  229. package/src/prerender/writable-store.ts +278 -0
  230. package/src/prerender.ts +29 -0
  231. package/src/reverse.ts +1 -1
  232. package/src/route-content-wrapper.tsx +107 -13
  233. package/src/router/error-handling.ts +12 -12
  234. package/src/router/find-match.ts +1 -0
  235. package/src/router/handler-context.ts +2 -0
  236. package/src/router/intercept-resolution.ts +15 -8
  237. package/src/router/loader-resolution.ts +2 -10
  238. package/src/router/manifest.ts +2 -0
  239. package/src/router/match-middleware/background-revalidation.ts +2 -0
  240. package/src/router/match-middleware/cache-lookup.ts +239 -54
  241. package/src/router/navigation-snapshot.ts +25 -6
  242. package/src/router/pattern-matching.ts +14 -0
  243. package/src/router/prefetch-default.ts +4 -4
  244. package/src/router/prerender-match.ts +460 -352
  245. package/src/router/request-classification.ts +15 -12
  246. package/src/router/route-trie-builder.ts +9 -0
  247. package/src/router/router-context.ts +1 -0
  248. package/src/router/router-interfaces.ts +35 -1
  249. package/src/router/router-options.ts +45 -5
  250. package/src/router/segment-resolution/fresh.ts +20 -19
  251. package/src/router/segment-resolution/loader-cache.ts +110 -77
  252. package/src/router/segment-resolution/revalidation.ts +34 -24
  253. package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
  254. package/src/router/trie-matching.ts +3 -0
  255. package/src/router-versions.ts +60 -0
  256. package/src/router.ts +107 -1
  257. package/src/rsc/full-payload.ts +6 -2
  258. package/src/rsc/handler-context.ts +5 -0
  259. package/src/rsc/handler.ts +64 -7
  260. package/src/rsc/progressive-enhancement.ts +5 -1
  261. package/src/rsc/response-cache-serve.ts +10 -4
  262. package/src/rsc/rsc-rendering.ts +65 -12
  263. package/src/rsc/shell-build-manifest.ts +17 -12
  264. package/src/rsc/shell-capture-constants.ts +39 -7
  265. package/src/rsc/shell-capture.ts +144 -45
  266. package/src/rsc/shell-serve.ts +12 -6
  267. package/src/rsc/ssr-module-loader.ts +26 -0
  268. package/src/rsc/types.ts +12 -6
  269. package/src/segment-boundary-content.ts +25 -0
  270. package/src/segment-loader-promise.ts +28 -38
  271. package/src/segment-system.tsx +117 -57
  272. package/src/server/build-version-table.ts +130 -0
  273. package/src/server/context.ts +40 -17
  274. package/src/server/cookie-store.ts +5 -0
  275. package/src/server/handle-store.ts +357 -127
  276. package/src/server/request-context.ts +149 -12
  277. package/src/ssr/ssr-root.tsx +32 -13
  278. package/src/suspense-audit-react.tsx +98 -0
  279. package/src/suspense-audit.ts +1030 -0
  280. package/src/testing/action-form.ts +66 -0
  281. package/src/testing/build-versions.ts +64 -0
  282. package/src/testing/dispatch.ts +6 -0
  283. package/src/testing/dom.entry.ts +1 -0
  284. package/src/testing/flight-runtime.d.ts +27 -0
  285. package/src/testing/flight.entry.ts +4 -0
  286. package/src/testing/index.ts +22 -0
  287. package/src/testing/internal/context.ts +2 -1
  288. package/src/testing/internal/seed-vars.ts +14 -2
  289. package/src/testing/internal/server-modules.ts +32 -0
  290. package/src/testing/location-state-key.ts +18 -8
  291. package/src/testing/render-handler.ts +2 -1
  292. package/src/testing/render-route.tsx +293 -46
  293. package/src/testing/serve-shell-request.ts +262 -37
  294. package/src/testing/shell-status.ts +17 -6
  295. package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
  296. package/src/testing/vitest-stubs/version.ts +4 -1
  297. package/src/thenable-status.ts +10 -0
  298. package/src/types/handler-context.ts +15 -5
  299. package/src/types/route-entry.ts +6 -0
  300. package/src/urls/path-helper.ts +69 -9
  301. package/src/use-loader.tsx +57 -30
  302. package/src/vite/discovery/build-versions.ts +1281 -0
  303. package/src/vite/discovery/bundle-postprocess.ts +4 -0
  304. package/src/vite/discovery/discover-routers.ts +15 -0
  305. package/src/vite/discovery/installed-packages.ts +159 -0
  306. package/src/vite/discovery/prerender-collection.ts +38 -1
  307. package/src/vite/discovery/router-versions-phase.ts +336 -0
  308. package/src/vite/discovery/shell-prerender-phase.ts +33 -43
  309. package/src/vite/discovery/state.ts +36 -1
  310. package/src/vite/discovery/virtual-module-codegen.ts +7 -2
  311. package/src/vite/encryption-key.ts +101 -9
  312. package/src/vite/inject-client-debug.ts +42 -20
  313. package/src/vite/plugin-types.ts +28 -0
  314. package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
  315. package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
  316. package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
  317. package/src/vite/plugins/expose-internal-ids.ts +12 -3
  318. package/src/vite/plugins/stable-rsc-output.ts +147 -0
  319. package/src/vite/plugins/version-plugin.ts +19 -24
  320. package/src/vite/plugins/version.d.ts +17 -2
  321. package/src/vite/plugins/virtual-entries.ts +39 -6
  322. package/src/vite/rango.ts +28 -3
  323. package/src/vite/router-discovery.ts +96 -13
  324. package/src/vite/utils/bundle-analysis.ts +39 -7
  325. package/src/vite/utils/client-chunks.ts +5 -1
  326. package/src/vite/utils/compare-strings.ts +9 -0
  327. package/src/vite/utils/package-resolution.ts +9 -0
  328. package/src/vite/utils/prerender-utils.ts +4 -1
  329. package/src/vite/utils/shared-utils.ts +1 -1
  330. package/dist/types/segment-content-promise.d.ts +0 -13
  331. package/src/segment-content-promise.ts +0 -67
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Writable prerender store contract for on-demand (ISR-style) prerender refresh.
3
+ *
4
+ * The bundled build manifest (store.ts) is immutable and read-only. On-demand
5
+ * prerender adds a writable durable overlay in front of it: `router.prerender()`
6
+ * renders a route and writes a versioned envelope here; the serve path reads the
7
+ * overlay before the bundled manifest.
8
+ *
9
+ * This module is types + pure helpers only — no React/RSC/plugin-rsc imports —
10
+ * so it can be imported by the testing barrel and platform adapters alike.
11
+ */
12
+ import type { PrerenderEntry } from "./store.js";
13
+ /**
14
+ * Structured durable-overlay key. Includes the router's cache version so a
15
+ * deploy that changed the router's server code never reads Flight payloads
16
+ * that reference its previous build, and so Cloudflare gradual deployments
17
+ * stay correct (old and new worker versions each read their own namespace).
18
+ */
19
+ export interface PrerenderKey {
20
+ routerId: string;
21
+ /**
22
+ * The owning router's cache version (its data version, or
23
+ * `createRouter({ version })`). Opaque: never set or read by app code; a
24
+ * store keys off it as given.
25
+ */
26
+ version: string;
27
+ routeName: string;
28
+ /** DJB2 8-hex hash of the canonical params (see param-hash.ts). */
29
+ paramHash: string;
30
+ }
31
+ /**
32
+ * @internal What the trigger stamps on a write. TTL is soft staleness metadata
33
+ * (`staleAt`), never a hard store expiry: hard expiry would delete the entry
34
+ * a stale-while-revalidate serve needs, and an expired overlay would fall back
35
+ * to older bundled-manifest content.
36
+ */
37
+ export interface StoredEntryOptions {
38
+ /** Seconds until the entry is considered stale. Absent = never stale. */
39
+ ttl?: number;
40
+ tags: string[];
41
+ /** Canonical params, stored for verify-on-read. */
42
+ params: Record<string, string>;
43
+ }
44
+ /** What a page and a "removed" marker both carry: a store reads either alike. */
45
+ interface StoredEnvelope {
46
+ v: 1;
47
+ meta: {
48
+ /**
49
+ * When the render started, not when the entry was written: a `markStale()`
50
+ * at or after it (strictly after in an in-process store) covers the entry.
51
+ * A `remove()` marker renders nothing and carries its write time.
52
+ */
53
+ storedAt: number;
54
+ /**
55
+ * Absent = never stale. Soft metadata only; controls `onRevalidate`
56
+ * scheduling, not serving. Counts the ttl from the write. A store may
57
+ * lower it (tag markers do).
58
+ */
59
+ staleAt?: number;
60
+ /** The configured ttl in seconds, as a result reports it. Absent = none. */
61
+ ttl?: number;
62
+ tags: string[];
63
+ /** The key's `version` at write time; verified on read. */
64
+ version: string;
65
+ /** Verified against the request's params on read (DJB2 collision guard). */
66
+ params: Record<string, string>;
67
+ };
68
+ }
69
+ type StoredPage = StoredEnvelope & {
70
+ entry: PrerenderEntry;
71
+ removed?: never;
72
+ };
73
+ /**
74
+ * The "removed" marker (tombstone) stored in place of a page, by
75
+ * `prerender.remove()` or by a refresh whose render hit `notFound()` (or
76
+ * declined with `ctx.passthrough()`). A request that finds it is not served
77
+ * the build-time entry below the overlay. No `entry`: a router from before the
78
+ * marker rejects it as malformed (a miss) instead of serving an empty page.
79
+ * `meta` is stamped like a page's for a render outcome, so that marker goes
80
+ * stale and is rechecked; a `remove()` marker has no `staleAt` and no tags.
81
+ */
82
+ type StoredTombstone = StoredEnvelope & {
83
+ removed: true;
84
+ entry?: never;
85
+ };
86
+ /**
87
+ * Versioned envelope the router composes on a refresh or a removal and
88
+ * verifies on every read: a page, or the marker that the page was removed. A
89
+ * store persists either as given and returns it as stored.
90
+ */
91
+ export type PrerenderStoredEntry = StoredPage | StoredTombstone;
92
+ /**
93
+ * The writable durable overlay: plain get/set. Backed in production by a
94
+ * platform adapter (Cloudflare KV, …) and in dev/tests by an in-memory store.
95
+ * The router composes the envelope before `set()` and verifies whatever `get()`
96
+ * returns (shape, `version`, params collision guard), so a store holds no
97
+ * policy of its own.
98
+ *
99
+ * Key everything off the `key` argument (`serializePrerenderKey(key)` carries
100
+ * `key.version`). Never call `getCacheVersions()` here: the trigger's `set()`
101
+ * runs outside the producer's request context, where it returns the
102
+ * whole-build fallback instead of the owning router's version.
103
+ */
104
+ export interface WritablePrerenderStore {
105
+ /**
106
+ * The envelope stored under `key`, or null. Never memoize a miss: a refresh
107
+ * can write the key after a request missed it. May lower `meta.staleAt` (a
108
+ * tag marked stale after the entry was written).
109
+ */
110
+ get(key: PrerenderKey): Promise<PrerenderStoredEntry | null>;
111
+ /**
112
+ * Persist `stored` (a page, or the marker that the page was removed) under
113
+ * `key`, replacing any previous entry. No expiry.
114
+ */
115
+ set(key: PrerenderKey, stored: PrerenderStoredEntry): Promise<void>;
116
+ delete?(key: PrerenderKey): Promise<void>;
117
+ /**
118
+ * Mark the entries of router `routerId` (`PrerenderKey.routerId`) carrying
119
+ * any of `tags` stale (they keep serving). A mark covers an entry whose
120
+ * `meta.storedAt` it is at or after (strictly after for an in-process
121
+ * store), including one `set()` after the mark: a store that marks held
122
+ * entries in place has to remember its marks. Scope it to that router: routers
123
+ * behind a host router share one store, and a tag is only meaningful inside
124
+ * the router whose routes declared it. Optional: without it,
125
+ * `router.prerender().markStale()` is a no-op for this store.
126
+ */
127
+ markStale?(routerId: string, tags: string[]): Promise<void>;
128
+ }
129
+ /**
130
+ * Serialize a {@link PrerenderKey} to the design's string form:
131
+ * `prerender:{routerId}:{version}:{routeName}:{paramHash}`
132
+ */
133
+ export declare function serializePrerenderKey(key: PrerenderKey): string;
134
+ /**
135
+ * @internal Compose the versioned envelope the trigger hands to `store.set()`.
136
+ * `now` is `meta.storedAt`; `staleFrom` (default `now`) is where the ttl
137
+ * starts counting. Both are passed explicitly so tests stay deterministic.
138
+ */
139
+ export declare function composeStoredEntry(key: PrerenderKey, entry: PrerenderEntry, options: StoredEntryOptions, now: number, staleFrom?: number): StoredPage;
140
+ /**
141
+ * @internal Compose the "removed" marker stored in place of a page. Its meta
142
+ * is a page's (composeStoredEntry), so `ttl` and `tags` mean the same: the
143
+ * marker of a render outcome is given the route's and is rechecked like a
144
+ * page; `prerender.remove()` gives neither, and its marker never goes stale.
145
+ */
146
+ export declare function composeStoredTombstone(key: PrerenderKey, options: StoredEntryOptions, now: number, staleFrom?: number): StoredTombstone;
147
+ /**
148
+ * @internal Verify a store's answer is safe to serve for this key: the
149
+ * envelope shape and version tag, the key version, and the stored params
150
+ * against the request's (the 8-hex DJB2 collision guard, param-hash.ts: a
151
+ * runtime write keyed off webhook-supplied params must not serve one page's
152
+ * content under another's URL, nor remove another's page). False means treat
153
+ * it as a miss. Run by the router on every read, so a third-party store
154
+ * cannot skip it.
155
+ */
156
+ export declare function isStoredEntryValidFor(stored: unknown, key: PrerenderKey, params: Record<string, string>): stored is PrerenderStoredEntry;
157
+ /** True once `now` has passed the entry's soft `staleAt`. Never-stale entries never go stale. */
158
+ export declare function isStoredEntryStale(stored: PrerenderStoredEntry, now: number): boolean;
159
+ /**
160
+ * @internal Lower `meta.staleAt` to `at` when it is unset or later. Shared by
161
+ * the stores' tag marking so the rule cannot drift between them.
162
+ */
163
+ export declare function lowerStoredEntryStaleAt(stored: PrerenderStoredEntry, at: number): void;
164
+ /**
165
+ * @internal `store.get(key)` verified for serving (isStoredEntryValidFor). A
166
+ * store error (e.g. a KV outage) reads as a miss: the serve path falls back to
167
+ * the bundled manifest or live handler, and the trigger's stale check renders.
168
+ */
169
+ export declare function readVerifiedStoredEntry(store: WritablePrerenderStore, key: PrerenderKey, params: Record<string, string>): Promise<PrerenderStoredEntry | null>;
170
+ export {};
@@ -81,6 +81,26 @@ export interface PrerenderOptions {
81
81
  * ```
82
82
  */
83
83
  concurrency?: number;
84
+ /**
85
+ * Opt this route into on-demand (ISR-style) prerender refresh via
86
+ * `router.prerender()`. `true` uses the router-level `prerender` defaults; an
87
+ * object overrides them per route.
88
+ *
89
+ * Any truthy value opts in — a literal, a spread, or an imported const:
90
+ * producer retention in the production bundle is driven by the evaluated
91
+ * route manifest (the same source that sets the runtime od flag), not a
92
+ * textual scan of the call.
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * export const ProductPage = Prerender(
97
+ * async () => [{ id: "featured" }],
98
+ * async (ctx) => <Product data={await ctx.env.PRODUCTS.get(ctx.params.id)} />,
99
+ * { onDemand: { ttl: 3600, tags: ({ params }) => [`product:${params.id}`] } },
100
+ * );
101
+ * ```
102
+ */
103
+ onDemand?: import("./prerender/on-demand.js").OnDemandOption;
84
104
  }
85
105
  /**
86
106
  * Context passed to Prerender() handlers at build time.
@@ -98,6 +118,13 @@ export interface BuildContext<TParams> {
98
118
  * changing build semantics.
99
119
  */
100
120
  dev: boolean;
121
+ /**
122
+ * True when this render is a requestless on-demand refresh driven by
123
+ * `router.prerender()` (rather than a build-time or dev prerender). The
124
+ * producer is still requestless — cookies/headers are unavailable — but
125
+ * `ctx.env` is the live trigger binding, not the shared build env.
126
+ */
127
+ onDemand: boolean;
101
128
  /**
102
129
  * Build-time environment bindings (KV, D1, etc.) supplied by the Vite plugin.
103
130
  * Only available when `buildEnv` is configured in rango() options.
@@ -31,7 +31,7 @@ export type ParamsFor<TRoutes, TName extends keyof TRoutes> = ExtractParams<Rout
31
31
  /**
32
32
  * Check if an object type has any keys
33
33
  */
34
- type IsEmptyObject<T> = keyof T extends never ? true : false;
34
+ export type IsEmptyObject<T> = keyof T extends never ? true : false;
35
35
  /**
36
36
  * Extract search schema from a route entry.
37
37
  * Returns {} if no search schema is defined.
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from "react";
1
+ import type { ComponentProps, ReactNode } from "react";
2
2
  import { Component } from "react";
3
3
  import type { ResolvedSegment } from "./types.js";
4
4
  /**
@@ -70,6 +70,7 @@ export declare function RouteContentWrapper({ content, fallback, segmentId, }: {
70
70
  fallback?: ReactNode;
71
71
  segmentId?: string;
72
72
  }): ReactNode;
73
+ export declare function AuditedRouteContent({ content, fallback, segmentId, }: ComponentProps<typeof RouteContentWrapper>): ReactNode;
73
74
  /**
74
75
  * LoaderBoundary - Client component that resolves loader promises and renders OutletProvider
75
76
  *
@@ -102,3 +103,4 @@ export interface LoaderBoundaryProps {
102
103
  children: ReactNode;
103
104
  }
104
105
  export declare function LoaderBoundary({ loaderDataPromise, loaderIds, loaderStreams, awaitedLoaderIds, fallback, outletKey, outletContent, segment, parallel, children, }: LoaderBoundaryProps): ReactNode;
106
+ export declare function AuditedLoaderBoundary({ fallback, children, ...resolver }: LoaderBoundaryProps): ReactNode;
@@ -78,6 +78,8 @@ export declare function findNearestNotFoundBoundary(entry: EntryData | null, def
78
78
  * Sanitizes error details in production
79
79
  */
80
80
  export declare function createErrorInfo(error: unknown, segmentId: string, segmentType: ErrorInfo["segmentType"]): ErrorInfo;
81
+ /** Invoke an errorBoundary() fallback that may be a handler or a plain node. */
82
+ export declare function renderErrorFallback(fallback: ReactNode | ErrorBoundaryHandler, errorInfo: ErrorInfo): ReactNode;
81
83
  /**
82
84
  * Create an error segment with the fallback component
83
85
  * Renders the fallback with error info and reset function
@@ -37,7 +37,7 @@ export declare function createHandlerContext<TEnv>(params: Record<string, string
37
37
  * search, reverse, and use(handle) work. Request-time properties
38
38
  * (request, env, headers, cookies, get, set, res) throw with a clear error.
39
39
  */
40
- export declare function createPrerenderContext<TEnv>(params: Record<string, string>, pathname: string, routeMap: Record<string, string>, routeName?: string, buildVars?: Record<string, any>, isPassthroughRoute?: boolean, buildEnv?: TEnv, devMode?: boolean): InternalHandlerContext<any, TEnv>;
40
+ export declare function createPrerenderContext<TEnv>(params: Record<string, string>, pathname: string, routeMap: Record<string, string>, routeName?: string, buildVars?: Record<string, any>, isPassthroughRoute?: boolean, buildEnv?: TEnv, devMode?: boolean, onDemand?: boolean): InternalHandlerContext<any, TEnv>;
41
41
  /**
42
42
  * Create a StaticContext for Static() handlers at build time.
43
43
  *
@@ -92,8 +92,18 @@
92
92
  * - Action context (if POST)
93
93
  */
94
94
  import type { ResolvedSegment } from "../../types.js";
95
- import type { EntryData } from "../../server/context.js";
95
+ import { type EntryData } from "../../server/context.js";
96
96
  import type { MatchContext, MatchPipelineState } from "../match-context.js";
97
+ import type { PrerenderStore } from "../../prerender/store.js";
98
+ import type { PrerenderTargetObject, ResolvedPrerender } from "../../prerender/on-demand.js";
99
+ import { type RequestContext } from "../../server/request-context.js";
100
+ /**
101
+ * @internal Replace the prerender store this module serves from, and return
102
+ * the one it replaced. For serveShellRequest (testing/serve-shell-request.ts),
103
+ * which installs the production store over the artifacts it bakes for a call
104
+ * and puts the previous one back after it.
105
+ */
106
+ export declare function setPrerenderStoreForTests(store: PrerenderStore | null | undefined): PrerenderStore | null | undefined;
97
107
  /**
98
108
  * Whether the prerender store holds a baked entry for this route + params.
99
109
  * Consulted by the PPR replay gate (matchPartialWithPprReplay), which must
@@ -106,6 +116,10 @@ import type { MatchContext, MatchPipelineState } from "../match-context.js";
106
116
  * subsequent get() share one underlying load.
107
117
  */
108
118
  export declare function prerenderEntryExists(routeKey: string | undefined, params: Record<string, string>, pathname: string, entries: EntryData[]): Promise<boolean>;
119
+ /** @internal Tests only (testing/serve-shell-request.ts resetShellTestState). */
120
+ export declare function resetOverlayRevalidationsForTests(): void;
121
+ /** @internal Exported for the eviction unit test. */
122
+ export declare function scheduleOverlayRevalidation<TEnv>(serializedKey: string, onRevalidate: NonNullable<ResolvedPrerender["config"]["onRevalidate"]>, target: PrerenderTargetObject, reqCtx: RequestContext<TEnv>, now?: number): void;
109
123
  /**
110
124
  * Async generator middleware type
111
125
  */
@@ -25,8 +25,15 @@ export interface ResolveNavigationDeps {
25
25
  * never produce a partial match, so the replay path must decide
26
26
  * `no-navigation-context` BEFORE spending shell-store reads — the two
27
27
  * predicates drifting apart would misattribute the bypass again.
28
+ *
29
+ * `requestOrigin` is the origin pathname matching uses (`url.origin`), which
30
+ * may not be `request.url`'s. `X-RSC-Router-Client-Path` is returned as sent.
31
+ * A Referer counts only when it resolves against that origin and stays there.
32
+ * A cross-origin Referer is dropped: resolveNavigation matches only the
33
+ * pathname, so a foreign URL would be treated as a route on this app. A value
34
+ * that does not parse is no context either.
28
35
  */
29
- export declare function getNavigationContextHeader(request: Request): string | null;
36
+ export declare function getNavigationContextHeader(request: Request, requestOrigin: string): string | null;
30
37
  /**
31
38
  * Whether withCacheLookup's prerender short-circuit will serve this partial
32
39
  * from the build-time prerender store: a Prerender() match (`matched.pr`)
@@ -134,6 +134,8 @@ export interface RouteMatchResult<TEnv = any> {
134
134
  pr?: true;
135
135
  /** Passthrough: handler kept for live fallback on unknown params (from trie) */
136
136
  pt?: true;
137
+ /** On-demand prerender eligible (router.prerender() refreshable) */
138
+ od?: true;
137
139
  /** Response type for non-RSC routes (json, text, image, any) */
138
140
  responseType?: string;
139
141
  /** Negotiate variants: response-type routes sharing this path */
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Resolve the router-wide default Link prefetch strategy once, at router init.
3
- * The resolved value ships to the client in payload metadata; the browser
4
- * entry applies it via `setDefaultPrefetchStrategy` (browser/prefetch/
5
- * default-strategy.ts) and every `<Link>` without an explicit `prefetch` prop
6
- * falls back to it.
3
+ * The resolved value ships to the client in payload metadata; the router
4
+ * store carries it (`NavigationStoreContext.defaultPrefetch`, see
5
+ * browser/prefetch/default-strategy.ts) and every `<Link>` without an explicit
6
+ * `prefetch` prop falls back to it.
7
7
  *
8
8
  * The type lives HERE (not in browser/react/Link.tsx) because both seats need
9
9
  * it: this server-side resolver and the client Link/default-strategy modules.
@@ -5,10 +5,19 @@ import type { PartialPrerenderProps } from "../urls/pattern-types.js";
5
5
  import type { HandlerContext, ResolvedSegment } from "../types";
6
6
  import type { SerializedSegmentData } from "../cache/types.js";
7
7
  import type { RouteMatchResult } from "./pattern-matching.js";
8
+ import type { RouterVersions } from "../router-versions.js";
9
+ import type { OnDemandRouteConfig } from "../prerender/on-demand.js";
8
10
  export interface PrerenderMatchDeps<TEnv = any> {
9
11
  /** Owning router id; scopes bake-time root-scope/search-schema lookups the
10
12
  * same way reqCtx._routerId does at runtime (issue #762). */
11
13
  routerId?: string;
14
+ /**
15
+ * The owning router's cache versions. Set on the requestless on-demand
16
+ * producer's context as `_versions`, so cache stores built inside the render
17
+ * key under the router's pair like a live request does instead of the
18
+ * whole-build fallback (server/build-version-table.ts getCacheVersions).
19
+ */
20
+ versions?: RouterVersions;
12
21
  findMatch: (pathname: string) => RouteMatchResult<TEnv> | null | Promise<RouteMatchResult<TEnv> | null>;
13
22
  buildRouterContext: () => RouterContext<TEnv>;
14
23
  mergedRouteMap: Record<string, string>;
@@ -20,7 +29,15 @@ export interface PrerenderMatchDeps<TEnv = any> {
20
29
  */
21
30
  export declare function matchForPrerender<TEnv = any>(pathname: string, params: Record<string, string>, deps: PrerenderMatchDeps<TEnv>, buildVars?: Record<string, any>, isPassthroughRoute?: boolean, buildEnv?: TEnv,
22
31
  /** Dev-only: check getParams() for passthrough routes to skip unknown params. */
23
- devMode?: boolean): Promise<{
32
+ devMode?: boolean,
33
+ /**
34
+ * Requestless on-demand refresh (router.prerender()). Arms the personalization
35
+ * guard: cookies()/headers()/response mutations throw a
36
+ * PrerenderPersonalizationError so the caller maps a personalized render to
37
+ * skipped-personalized instead of baking a shared payload. `buildEnv` here is
38
+ * the live trigger env, not the shared build env.
39
+ */
40
+ onDemand?: boolean): Promise<{
24
41
  segments: SerializedSegmentData[];
25
42
  /** RSC-encoded handle map ("" when none) — see handle-snapshot.ts. Encoded in
26
43
  * the producer (where the Flight codec resolves) so the node-side build/dev
@@ -33,6 +50,11 @@ devMode?: boolean): Promise<{
33
50
  * the sinks store it as-is (no longer merge raw records). */
34
51
  interceptHandles?: string;
35
52
  passthrough?: true;
53
+ /** On-demand only: the render hit `notFound()` and nothing else failed. */
54
+ notFound?: true;
55
+ /** Route-level onDemand config (ttl/tags) read off the route entry; only set
56
+ * when `onDemand` and the route declared an onDemand object literal. */
57
+ onDemandConfig?: OnDemandRouteConfig;
36
58
  /**
37
59
  * The matched route entry's `ppr` path option, surfaced so the build
38
60
  * collection can flag Prerender+ppr routes as build-time shell candidates
@@ -31,6 +31,12 @@ export interface TrieLeaf {
31
31
  pr?: true;
32
32
  /** Passthrough: handler kept in bundle for live fallback on unknown params */
33
33
  pt?: true;
34
+ /**
35
+ * On-demand prerender eligible: the route opted into router.prerender()
36
+ * refresh. Distinct from `pr` — an od route may have no build-baked entry yet
37
+ * still needs a writable-overlay lookup at serve time.
38
+ */
39
+ od?: true;
34
40
  /** Response type for non-RSC routes (json, text, image, any) */
35
41
  rt?: string;
36
42
  /** Negotiate variants: response-type routes sharing this path */
@@ -73,5 +79,6 @@ export interface TrieNode {
73
79
  * @param prerenderRouteNames - Optional set of prerendered route names (sets leaf.pr)
74
80
  * @param passthroughRouteNames - Optional set of passthrough route names (sets leaf.pt)
75
81
  * @param responseTypeRoutes - Optional map of route name to response type (sets leaf.rt)
82
+ * @param onDemandRouteNames - Optional set of on-demand-eligible route names (sets leaf.od)
76
83
  */
77
- export declare function buildRouteTrie(routeManifest: Record<string, string>, routeToStaticPrefix: Record<string, string>, routeTrailingSlash?: Record<string, string>, prerenderRouteNames?: Set<string>, passthroughRouteNames?: Set<string>, responseTypeRoutes?: Record<string, string>): TrieNode;
84
+ export declare function buildRouteTrie(routeManifest: Record<string, string>, routeToStaticPrefix: Record<string, string>, routeTrailingSlash?: Record<string, string>, prerenderRouteNames?: Set<string>, passthroughRouteNames?: Set<string>, responseTypeRoutes?: Record<string, string>, onDemandRouteNames?: Set<string>): TrieNode;
@@ -45,6 +45,7 @@ export interface RouterContext<TEnv = any> {
45
45
  getContext: () => {
46
46
  getOrCreateStore: (key: string) => any;
47
47
  runWithStore: <T>(store: any, namespace: string, parent: any, fn: () => T) => T;
48
+ runIsolated: <T>(forRoute: string, fn: () => T) => T;
48
49
  };
49
50
  getMetricsStore: () => MetricsStore | undefined;
50
51
  createCacheScope: (cacheConfig: any, parent: CacheScope | null) => CacheScope | null;
@@ -184,6 +184,28 @@ export interface Rango<TEnv = any, TRoutes extends Record<string, unknown> = Rec
184
184
  * ```
185
185
  */
186
186
  fetch(request: Request, input?: RouterRequestInput<TEnv>): Promise<Response>;
187
+ /**
188
+ * Bind `{ env, ctx }` and get the on-demand (ISR-style) prerender runner, to refresh from a running app —
189
+ * fetch handler, cron, queue, workflow, webhook, or server action.
190
+ *
191
+ * Requestless: the producer renders with route params and env only, never the
192
+ * caller's cookies/headers/session. Only routes that opted in via
193
+ * `Prerender(..., { onDemand })` are persistable; others return a skipped
194
+ * result. Configure the store via the `prerender` router option.
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * const prerender = router.prerender({ env, ctx });
199
+ * await prerender("/products/42");
200
+ * await prerender(
201
+ * { route: "products.detail", params: { id: "42" } },
202
+ * { throwOnError: true },
203
+ * );
204
+ * await prerender.many(targets, { concurrency: 4 });
205
+ * await prerender.markStale(["product:42"]);
206
+ * ```
207
+ */
208
+ prerender: import("../prerender/on-demand.js").PrerenderFn<TEnv, TRoutes>;
187
209
  }
188
210
  /**
189
211
  * Internal Rango router interface — the full framework-facing API.
@@ -254,6 +276,12 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
254
276
  * Cache configuration
255
277
  */
256
278
  readonly cache?: RangoOptions<TEnv>["cache"];
279
+ /**
280
+ * Prerender store configuration (the writable durable overlay for on-demand
281
+ * prerender). Stored separately from the `prerender` trigger method so the RSC
282
+ * handler can resolve it per request. @internal
283
+ */
284
+ readonly _prerenderConfig?: RangoOptions<TEnv>["prerender"];
257
285
  /**
258
286
  * Not found component to render when no route matches
259
287
  */
@@ -357,7 +385,8 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
357
385
  */
358
386
  readonly nonce?: NonceProvider<TEnv>;
359
387
  /**
360
- * RSC version string
388
+ * The consumer-set version (createRouter({ version })), used for both of the
389
+ * router's versions. Undefined when the router uses its build versions.
361
390
  */
362
391
  readonly version?: string;
363
392
  /**
@@ -470,6 +499,8 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
470
499
  * Handle an RSC request.
471
500
  */
472
501
  fetch(request: Request, input?: RouterRequestInput<TEnv>): Promise<Response>;
502
+ /** On-demand prerender binder: router.prerender({ env, ctx }) returns the runner. */
503
+ prerender: import("../prerender/on-demand.js").PrerenderFn<TEnv, TRoutes>;
473
504
  }
474
505
  /**
475
506
  * Assert a public Rango into the internal type.
@@ -314,6 +314,30 @@ export interface RangoOptions<TEnv = any> {
314
314
  enabled?: boolean;
315
315
  searchParams?: CacheSearchParams;
316
316
  });
317
+ /**
318
+ * Writable prerender store for on-demand (ISR-style) prerender refresh.
319
+ *
320
+ * A durable overlay in front of the bundled build manifest. When provided,
321
+ * `router.prerender(target, { env, ctx })` renders a route requestlessly and
322
+ * writes a versioned payload here; the serve path reads the overlay before the
323
+ * bundled manifest. Same union shape as `cache`: a plain config object or a
324
+ * factory resolved per request/per call (never at `createRouter()` time), so
325
+ * multi-tenant apps never memoize one request's binding for another.
326
+ *
327
+ * @example Cloudflare KV overlay with SWR revalidation
328
+ * ```typescript
329
+ * import { createKVPrerenderStore } from "@rangojs/router/prerender/cloudflare";
330
+ *
331
+ * const router = createRouter<AppEnv>({
332
+ * prerender: (env) => ({
333
+ * store: createKVPrerenderStore(env.PRERENDER_KV),
334
+ * ttl: 3600,
335
+ * onRevalidate: (target, e) => e.PRERENDER_QUEUE.send({ target }),
336
+ * }),
337
+ * });
338
+ * ```
339
+ */
340
+ prerender?: import("../prerender/on-demand.js").PrerenderConfig<TEnv> | ((env: TEnv, ctx?: ExecutionContext) => import("../prerender/on-demand.js").PrerenderConfig<TEnv>);
317
341
  /**
318
342
  * Named cache profiles for "use cache" directive.
319
343
  * Profile names map to TTL/SWR configuration.
@@ -466,13 +490,23 @@ export interface RangoOptions<TEnv = any> {
466
490
  */
467
491
  nonce?: NonceProvider<TEnv>;
468
492
  /**
469
- * RSC version string included in metadata.
470
- * The browser sends this back on partial requests to detect version mismatches.
493
+ * Version override. When set, this exact value is used for both of the
494
+ * router's versions: it keys the router's cached data (segments, `"use
495
+ * cache"` values, loader data) and its stored HTML (PPR shells,
496
+ * document-cache responses), is sent in payload metadata, and is what the
497
+ * browser's `_rsc_v` is compared with (a mismatch reloads the tab).
498
+ *
499
+ * Leave it unset for the default: rango computes two versions per router at
500
+ * build time, a data version from the router's server code and a document
501
+ * version that also covers the client assets. The same code builds to the
502
+ * same versions, so a deploy that does not change this router keeps its
503
+ * cache. In dev both are a stamp bumped on every RSC module edit.
471
504
  *
472
- * Defaults to the auto-generated VERSION from `@rangojs/router:version` virtual module.
473
- * Only set this if you need a custom versioning strategy.
505
+ * Set it to clear this router's cache on demand (change the value), or to
506
+ * tie the cache to your own release id (a per-deploy value clears the cache
507
+ * on every deploy).
474
508
  *
475
- * @default VERSION from @rangojs/router:version
509
+ * @default the router's build versions
476
510
  */
477
511
  version?: string;
478
512
  /**
@@ -37,6 +37,13 @@ export interface ResolveSegmentOptions {
37
37
  * #918: resolved twice on a MISS, once and discarded on a HIT).
38
38
  */
39
39
  chain?: readonly EntryData[];
40
+ /**
41
+ * The matched chain entry being resolved: where the sync path catches a
42
+ * handler error, so a streamed handler (or slot owned by a routeless layout)
43
+ * recovers into the same boundary. resolveSegment sets it for the entry it
44
+ * resolves; nested resolutions keep the outer value.
45
+ */
46
+ boundaryEntry?: EntryData;
40
47
  }
41
48
  /**
42
49
  * Resolve segments from EntryData.
@@ -9,7 +9,8 @@
9
9
  * 1. options.key(requestCtx) — full override, stored namespaced as
10
10
  * loader:{loaderId}:key:{encodeURIComponent(result)} (#1009)
11
11
  * 2. store.keyGenerator(requestCtx, defaultKey) — store-level modification
12
- * 3. loader:{loaderId}:{host}{pathname}:{sortedParams} — default
12
+ * 3. loader:{loaderId}:{routerId}@{host}{pathname}:{sortedParams} — default
13
+ * (a loader's ctx is one router's: cache-key-utils.ts, the router rule)
13
14
  *
14
15
  * Values are serialized via RSC Flight (serializeResult/deserializeResult),
15
16
  * supporting ReactNode, Promises, null, and all RSC-serializable types.
@@ -42,6 +43,8 @@
42
43
  */
43
44
  import { type EntryData, type LoaderEntry } from "../../server/context.js";
44
45
  import type { HandlerContext } from "../../types.js";
46
+ import { type OwnedPushDelivery } from "../../cache/handle-snapshot.js";
47
+ import { type RequestContext } from "../../server/request-context.js";
45
48
  /**
46
49
  * Whether a request over the matched chain `entries` resolves a loader bound
47
50
  * with its own cache(): on a chain entry, or on its parallel slots, orphan
@@ -51,15 +54,6 @@ import type { HandlerContext } from "../../types.js";
51
54
  * Memoized per entry.
52
55
  */
53
56
  export declare function bindsLoaderCache(entries: readonly EntryData[]): boolean;
54
- /**
55
- * The ids of the loaders a request over the matched chain `entries` runs on
56
- * the live lane (no `ssr: false`), on a chain entry, its orphan layouts or
57
- * its parallel slots. A document HIT tail restores the record's pushes of
58
- * every other owner as authoritative (withCacheLookup, HandleStore
59
- * pushRestored); a live-lane loader is a hole, so its live run replaces its
60
- * recorded pushes instead. Memoized per entry.
61
- */
62
- export declare function liveLaneLoaderIds(entries: readonly EntryData[]): ReadonlySet<string>;
63
57
  /**
64
58
  * The lane of each loader the matched chain `entries` registers: "live" (no
65
59
  * `ssr: false`) or "bake". A loader registered on both is "live". A PPR
@@ -67,6 +61,25 @@ export declare function liveLaneLoaderIds(entries: readonly EntryData[]): Readon
67
61
  * one is live (shell-capture.ts deriveShellCaptureContext).
68
62
  */
69
63
  export declare function routeLoaderLanes(entries: readonly EntryData[]): ReadonlyMap<string, "live" | "bake">;
64
+ /**
65
+ * What a record restored on a request over the matched chain `entries` is to
66
+ * each loader's handle pushes (HandleStore RecordAuthority), from the pins
67
+ * the request serves (servedPins). Call it when the record hits: the pins are
68
+ * read here, once, because a navigation replay arms its seed for the match
69
+ * only and the store asks while loader bodies run.
70
+ *
71
+ * Each side applies its own lane to the pin. The value is per registration
72
+ * (resolveLoaderData: an `ssr: false` registration is served its pin). The
73
+ * pushes are per loader: one the route also registers without `ssr: false`
74
+ * is a hole whatever its other registration's pin says, because the capture
75
+ * credited its pushes to the live registration's run (routeLoaderLanes).
76
+ *
77
+ * A dependency the route does not register has no pin of its own, and the
78
+ * record does not name the loader that ran it at capture: its copies stand
79
+ * only while every `ssr: false` loader is pinned (exact when the pins are
80
+ * all there or all gone).
81
+ */
82
+ export declare function loaderPins(entries: readonly EntryData[], reqCtx: RequestContext<any> | undefined): OwnedPushDelivery;
70
83
  /**
71
84
  * Resolve loader data with optional caching.
72
85
  *
@@ -51,6 +51,8 @@ export declare function resolveParallelSegmentsWithRevalidation<TEnv>(entry: Ent
51
51
  * to it: loader sub-ids are filtered out and slots are re-grouped by parent).
52
52
  */
53
53
  loaderOrder?: "after" | "before";
54
+ /** Matched chain entry being resolved; see ResolveSegmentOptions.boundaryEntry. */
55
+ boundaryEntry?: EntryData;
54
56
  }): Promise<SegmentRevalidationResult>;
55
57
  /**
56
58
  * Resolve entry handler (layout, cache, or route) with revalidation.
@@ -74,7 +76,9 @@ chain?: readonly EntryData[]): Promise<SegmentRevalidationResult>;
74
76
  */
75
77
  export declare function resolveOrphanLayoutWithRevalidation<TEnv>(orphan: EntryData, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentIds: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, routeKey: string, belongsToRoute: boolean, deps: SegmentResolutionDeps<TEnv>, actionContext?: ActionContext, stale?: boolean,
76
78
  /** Parent route entry — its loaders are inherited so parallel slots can access them. */
77
- parentRouteEntry?: EntryData): Promise<SegmentRevalidationResult>;
79
+ parentRouteEntry?: EntryData,
80
+ /** Matched chain entry being resolved (see ResolveSegmentOptions.boundaryEntry); defaults to parentRouteEntry. */
81
+ boundaryEntry?: EntryData | undefined): Promise<SegmentRevalidationResult>;
78
82
  /**
79
83
  * Resolve all segments for a route with revalidation logic (for matchPartial).
80
84
  */