@rangojs/router 0.17.0 → 0.19.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 (293) hide show
  1. package/README.md +3 -2
  2. package/dist/types/browser/cookie-name.d.ts +6 -0
  3. package/dist/types/browser/event-controller.d.ts +3 -3
  4. package/dist/types/browser/history-state.d.ts +18 -0
  5. package/dist/types/browser/navigation-transaction.d.ts +20 -2
  6. package/dist/types/browser/partial-update.d.ts +16 -1
  7. package/dist/types/browser/prefetch/cache.d.ts +6 -6
  8. package/dist/types/browser/react/Link.d.ts +19 -9
  9. package/dist/types/browser/react/context.d.ts +2 -2
  10. package/dist/types/browser/react/location-state-shared.d.ts +95 -56
  11. package/dist/types/browser/react/location-state.d.ts +1 -1
  12. package/dist/types/browser/transition-when.d.ts +80 -0
  13. package/dist/types/browser/types.d.ts +104 -9
  14. package/dist/types/build/generate-manifest.d.ts +8 -0
  15. package/dist/types/cache/background-task.d.ts +24 -2
  16. package/dist/types/cache/cache-exec-scope.d.ts +31 -0
  17. package/dist/types/cache/cache-key-utils.d.ts +48 -2
  18. package/dist/types/cache/cache-policy.d.ts +18 -1
  19. package/dist/types/cache/cache-runtime.d.ts +7 -0
  20. package/dist/types/cache/cache-scope.d.ts +192 -26
  21. package/dist/types/cache/cache-tag.d.ts +116 -11
  22. package/dist/types/cache/cf/cf-base64.d.ts +6 -0
  23. package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
  24. package/dist/types/cache/cf/cf-cache-store.d.ts +224 -72
  25. package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
  26. package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
  27. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +19 -0
  28. package/dist/types/cache/document-cache.d.ts +10 -0
  29. package/dist/types/cache/handle-snapshot.d.ts +41 -8
  30. package/dist/types/cache/index.d.ts +1 -0
  31. package/dist/types/cache/invalidation-order.d.ts +23 -0
  32. package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
  33. package/dist/types/cache/request-tag-mask.d.ts +54 -0
  34. package/dist/types/cache/shell-memo.d.ts +178 -0
  35. package/dist/types/cache/shell-snapshot.d.ts +141 -105
  36. package/dist/types/cache/tag-invalidation.d.ts +54 -3
  37. package/dist/types/cache/types.d.ts +267 -96
  38. package/dist/types/cache/vercel/vercel-cache-store.d.ts +123 -18
  39. package/dist/types/client-urls/navigation.d.ts +28 -2
  40. package/dist/types/client-urls/server-projection.d.ts +5 -2
  41. package/dist/types/client-urls/types.d.ts +5 -5
  42. package/dist/types/client.d.ts +1 -1
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.rsc.d.ts +1 -1
  45. package/dist/types/prerender/build-shell-capture.d.ts +11 -4
  46. package/dist/types/route-definition/helpers-types.d.ts +11 -11
  47. package/dist/types/route-name.d.ts +7 -0
  48. package/dist/types/router/error-handling.d.ts +1 -1
  49. package/dist/types/router/instrument.d.ts +8 -0
  50. package/dist/types/router/intercept-resolution.d.ts +2 -0
  51. package/dist/types/router/match-context.d.ts +5 -0
  52. package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
  53. package/dist/types/router/middleware-types.d.ts +6 -1
  54. package/dist/types/router/router-options.d.ts +4 -1
  55. package/dist/types/router/segment-resolution/loader-cache.d.ts +58 -12
  56. package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
  57. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +33 -48
  58. package/dist/types/router/segment-resolution/mask-nested.d.ts +73 -24
  59. package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
  60. package/dist/types/router/transition-when.d.ts +24 -10
  61. package/dist/types/rsc/attach-transition-when.d.ts +18 -0
  62. package/dist/types/rsc/full-payload.d.ts +21 -0
  63. package/dist/types/rsc/handler.d.ts +1 -1
  64. package/dist/types/rsc/response-cache-serve.d.ts +15 -12
  65. package/dist/types/rsc/shell-build-manifest.d.ts +12 -3
  66. package/dist/types/rsc/shell-capture-constants.d.ts +116 -12
  67. package/dist/types/rsc/shell-capture.d.ts +202 -74
  68. package/dist/types/rsc/shell-serve.d.ts +144 -50
  69. package/dist/types/rsc/types.d.ts +9 -0
  70. package/dist/types/segment-system.d.ts +7 -0
  71. package/dist/types/server/context.d.ts +155 -33
  72. package/dist/types/server/cookie-store.d.ts +33 -0
  73. package/dist/types/server/handle-store.d.ts +52 -1
  74. package/dist/types/server/request-context.d.ts +210 -63
  75. package/dist/types/server/request-headers.d.ts +44 -0
  76. package/dist/types/server.d.ts +1 -0
  77. package/dist/types/ssr/index.d.ts +9 -0
  78. package/dist/types/ssr/ssr-root.d.ts +9 -8
  79. package/dist/types/testing/e2e/index.d.ts +1 -1
  80. package/dist/types/testing/flight.entry.d.ts +7 -0
  81. package/dist/types/testing/index.d.ts +3 -2
  82. package/dist/types/testing/internal/action-id.d.ts +7 -0
  83. package/dist/types/testing/location-state-key.d.ts +24 -0
  84. package/dist/types/testing/render-route.d.ts +17 -1
  85. package/dist/types/testing/run-loader.d.ts +18 -3
  86. package/dist/types/testing/run-transition-when.d.ts +44 -69
  87. package/dist/types/testing/serve-shell-request.d.ts +133 -0
  88. package/dist/types/testing/shell-status.d.ts +44 -19
  89. package/dist/types/transition-when-ref.d.ts +79 -0
  90. package/dist/types/types/cache-types.d.ts +15 -3
  91. package/dist/types/types/handler-context.d.ts +14 -1
  92. package/dist/types/types/index.d.ts +1 -1
  93. package/dist/types/types/segments.d.ts +86 -71
  94. package/dist/types/urls/path-helper-types.d.ts +3 -4
  95. package/dist/types/urls/pattern-types.d.ts +21 -18
  96. package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
  97. package/dist/types/vite/router-discovery.d.ts +29 -2
  98. package/dist/vite/index.js +1005 -105
  99. package/package.json +1 -1
  100. package/skills/breadcrumbs/SKILL.md +17 -7
  101. package/skills/cache-guide/SKILL.md +175 -76
  102. package/skills/caching/SKILL.md +361 -33
  103. package/skills/catalog.json +1 -1
  104. package/skills/client-urls/SKILL.md +12 -7
  105. package/skills/cloudflare/SKILL.md +15 -0
  106. package/skills/comparison/references/framework-comparison.md +52 -37
  107. package/skills/defer-hydration/SKILL.md +50 -30
  108. package/skills/deployment-caching/SKILL.md +5 -2
  109. package/skills/document-cache/SKILL.md +32 -2
  110. package/skills/handler-use/SKILL.md +2 -0
  111. package/skills/hooks/SKILL.md +3 -1
  112. package/skills/hooks/handle-and-actions.md +3 -1
  113. package/skills/hooks/navigation.md +23 -2
  114. package/skills/hooks/state.md +101 -7
  115. package/skills/intercept/SKILL.md +29 -12
  116. package/skills/loader/SKILL.md +197 -44
  117. package/skills/middleware/SKILL.md +34 -9
  118. package/skills/migrate-nextjs/SKILL.md +68 -37
  119. package/skills/migrate-react-router/SKILL.md +2 -1
  120. package/skills/migrate-react-router/component-migration.md +3 -1
  121. package/skills/migrate-react-router/data-and-actions.md +3 -1
  122. package/skills/migrate-react-router/route-mapping.md +7 -4
  123. package/skills/observability/SKILL.md +65 -0
  124. package/skills/parallel/SKILL.md +13 -8
  125. package/skills/ppr/SKILL.md +715 -371
  126. package/skills/prerender/SKILL.md +30 -17
  127. package/skills/rango/SKILL.md +72 -34
  128. package/skills/route/SKILL.md +14 -7
  129. package/skills/router-setup/SKILL.md +4 -2
  130. package/skills/scripts/SKILL.md +8 -1
  131. package/skills/server-actions/SKILL.md +11 -0
  132. package/skills/shell-manifest/SKILL.md +21 -12
  133. package/skills/testing/SKILL.md +49 -43
  134. package/skills/testing/cache-prerender.md +15 -14
  135. package/skills/testing/client-components.md +45 -3
  136. package/skills/testing/loader.md +19 -1
  137. package/skills/testing/middleware.md +1 -0
  138. package/skills/testing/predicates.md +49 -49
  139. package/skills/testing/render-handler.md +1 -0
  140. package/skills/testing/serve-shell-request.md +202 -0
  141. package/skills/testing/server-actions.md +9 -3
  142. package/skills/theme/SKILL.md +56 -4
  143. package/skills/typesafety/env-and-bindings.md +18 -2
  144. package/skills/use-cache/SKILL.md +91 -23
  145. package/skills/vercel/SKILL.md +14 -2
  146. package/skills/view-transitions/SKILL.md +150 -29
  147. package/src/__augment-tests__/augmented.check.ts +23 -0
  148. package/src/browser/cookie-name.ts +23 -0
  149. package/src/browser/event-controller.ts +4 -4
  150. package/src/browser/history-state.ts +75 -1
  151. package/src/browser/link-interceptor.ts +4 -0
  152. package/src/browser/navigation-bridge.ts +77 -18
  153. package/src/browser/navigation-client.ts +4 -3
  154. package/src/browser/navigation-store.ts +43 -1
  155. package/src/browser/navigation-transaction.ts +31 -11
  156. package/src/browser/partial-update.ts +146 -35
  157. package/src/browser/prefetch/cache.ts +6 -6
  158. package/src/browser/prefetch/fetch.ts +2 -2
  159. package/src/browser/react/Link.tsx +38 -33
  160. package/src/browser/react/NavigationProvider.tsx +2 -2
  161. package/src/browser/react/context.ts +2 -2
  162. package/src/browser/react/location-state-shared.ts +241 -49
  163. package/src/browser/react/location-state.ts +5 -2
  164. package/src/browser/rsc-router.tsx +9 -0
  165. package/src/browser/server-action-bridge.ts +84 -15
  166. package/src/browser/transition-when.ts +205 -0
  167. package/src/browser/types.ts +124 -10
  168. package/src/build/generate-manifest.ts +77 -1
  169. package/src/cache/background-task.ts +55 -2
  170. package/src/cache/cache-exec-scope.ts +48 -1
  171. package/src/cache/cache-key-utils.ts +62 -2
  172. package/src/cache/cache-policy.ts +31 -4
  173. package/src/cache/cache-runtime.ts +209 -129
  174. package/src/cache/cache-scope.ts +573 -69
  175. package/src/cache/cache-tag.ts +475 -19
  176. package/src/cache/cf/cf-base64.ts +36 -4
  177. package/src/cache/cf/cf-cache-constants.ts +12 -0
  178. package/src/cache/cf/cf-cache-store.ts +1094 -376
  179. package/src/cache/cf/cf-cache-types.ts +32 -4
  180. package/src/cache/cf/cf-shell-frame.ts +258 -0
  181. package/src/cache/cf/cf-tag-marker-memo.ts +55 -40
  182. package/src/cache/document-cache.ts +53 -7
  183. package/src/cache/handle-snapshot.ts +53 -9
  184. package/src/cache/index.ts +2 -0
  185. package/src/cache/invalidation-order.ts +84 -0
  186. package/src/cache/isolate-tag-memo.ts +308 -0
  187. package/src/cache/request-tag-mask.ts +147 -0
  188. package/src/cache/shell-memo.ts +341 -0
  189. package/src/cache/shell-snapshot.ts +249 -277
  190. package/src/cache/tag-invalidation.ts +109 -18
  191. package/src/cache/types.ts +274 -102
  192. package/src/cache/vercel/vercel-cache-store.ts +561 -74
  193. package/src/client-urls/client-root.tsx +8 -4
  194. package/src/client-urls/client-urls.ts +8 -6
  195. package/src/client-urls/navigation.ts +55 -4
  196. package/src/client-urls/server-projection.ts +31 -10
  197. package/src/client-urls/types.ts +12 -5
  198. package/src/client.tsx +2 -0
  199. package/src/host/cookie-handler.ts +2 -1
  200. package/src/index.rsc.ts +3 -0
  201. package/src/index.ts +3 -0
  202. package/src/loader-redirect.tsx +7 -3
  203. package/src/prerender/build-shell-capture.ts +173 -110
  204. package/src/route-definition/dsl-helpers.ts +6 -3
  205. package/src/route-definition/helpers-types.ts +11 -11
  206. package/src/route-name.ts +12 -0
  207. package/src/router/content-negotiation.ts +4 -1
  208. package/src/router/error-handling.ts +5 -2
  209. package/src/router/handler-context.ts +42 -5
  210. package/src/router/instrument.ts +54 -2
  211. package/src/router/intercept-resolution.ts +30 -8
  212. package/src/router/loader-resolution.ts +89 -33
  213. package/src/router/logging.ts +5 -3
  214. package/src/router/match-api.ts +89 -42
  215. package/src/router/match-context.ts +5 -0
  216. package/src/router/match-handlers.ts +14 -29
  217. package/src/router/match-middleware/background-revalidation.ts +3 -5
  218. package/src/router/match-middleware/cache-lookup.ts +52 -19
  219. package/src/router/match-middleware/cache-store.ts +36 -10
  220. package/src/router/match-result.ts +1 -0
  221. package/src/router/middleware-types.ts +6 -1
  222. package/src/router/middleware.ts +20 -4
  223. package/src/router/navigation-snapshot.ts +6 -5
  224. package/src/router/prerender-match.ts +10 -0
  225. package/src/router/request-classification.ts +7 -4
  226. package/src/router/router-options.ts +4 -1
  227. package/src/router/segment-resolution/fresh.ts +18 -13
  228. package/src/router/segment-resolution/helpers.ts +4 -2
  229. package/src/router/segment-resolution/loader-cache.ts +366 -70
  230. package/src/router/segment-resolution/loader-mask.ts +3 -4
  231. package/src/router/segment-resolution/loader-snapshot.ts +215 -126
  232. package/src/router/segment-resolution/mask-nested.ts +161 -42
  233. package/src/router/segment-resolution/revalidation.ts +27 -13
  234. package/src/router/segment-resolution/view-transition-default.ts +6 -21
  235. package/src/router/telemetry.ts +6 -3
  236. package/src/router/transition-when.ts +34 -52
  237. package/src/router.ts +2 -1
  238. package/src/rsc/attach-transition-when.ts +47 -0
  239. package/src/rsc/full-payload.ts +47 -3
  240. package/src/rsc/handler.ts +24 -10
  241. package/src/rsc/loader-fetch.ts +2 -1
  242. package/src/rsc/manifest-init.ts +4 -0
  243. package/src/rsc/origin-guard.ts +8 -5
  244. package/src/rsc/progressive-enhancement.ts +10 -32
  245. package/src/rsc/response-cache-serve.ts +69 -78
  246. package/src/rsc/response-route-handler.ts +2 -2
  247. package/src/rsc/rsc-rendering.ts +712 -338
  248. package/src/rsc/server-action.ts +8 -20
  249. package/src/rsc/shell-build-manifest.ts +49 -29
  250. package/src/rsc/shell-capture-constants.ts +182 -12
  251. package/src/rsc/shell-capture.ts +1126 -612
  252. package/src/rsc/shell-serve.ts +331 -85
  253. package/src/rsc/ssr-setup.ts +3 -2
  254. package/src/rsc/types.ts +9 -0
  255. package/src/segment-system.tsx +40 -7
  256. package/src/server/context.ts +328 -72
  257. package/src/server/cookie-store.ts +184 -133
  258. package/src/server/handle-store.ts +245 -27
  259. package/src/server/request-context.ts +364 -100
  260. package/src/server/request-headers.ts +134 -0
  261. package/src/server.ts +4 -0
  262. package/src/ssr/index.tsx +96 -37
  263. package/src/ssr/ssr-root.tsx +9 -8
  264. package/src/testing/dispatch.ts +4 -7
  265. package/src/testing/e2e/index.ts +1 -0
  266. package/src/testing/flight.entry.ts +14 -0
  267. package/src/testing/index.ts +5 -0
  268. package/src/testing/internal/action-id.ts +25 -0
  269. package/src/testing/internal/context.ts +1 -1
  270. package/src/testing/location-state-key.ts +45 -0
  271. package/src/testing/render-handler.ts +1 -1
  272. package/src/testing/render-route.tsx +109 -16
  273. package/src/testing/run-client-revalidate.ts +3 -19
  274. package/src/testing/run-loader.ts +67 -5
  275. package/src/testing/run-transition-when.ts +109 -172
  276. package/src/testing/serve-shell-request.ts +381 -0
  277. package/src/testing/shell-status.ts +73 -47
  278. package/src/theme/ThemeProvider.tsx +7 -6
  279. package/src/transition-when-ref.ts +220 -0
  280. package/src/types/cache-types.ts +15 -3
  281. package/src/types/handler-context.ts +14 -1
  282. package/src/types/index.ts +3 -0
  283. package/src/types/segments.ts +94 -91
  284. package/src/urls/path-helper-types.ts +3 -4
  285. package/src/urls/pattern-types.ts +21 -18
  286. package/src/vite/discovery/discover-routers.ts +3 -0
  287. package/src/vite/discovery/shell-prerender-phase.ts +9 -2
  288. package/src/vite/discovery/virtual-module-codegen.ts +16 -6
  289. package/src/vite/plugins/transition-when-hoist.ts +1064 -0
  290. package/src/vite/rango.ts +2 -0
  291. package/src/vite/router-discovery.ts +89 -9
  292. package/dist/types/rsc/transition-gate.d.ts +0 -23
  293. package/src/rsc/transition-gate.ts +0 -86
@@ -85,9 +85,60 @@ export interface HandleStore {
85
85
  * body (loader-cache.ts replayLoaderHandles). If that loader then runs live
86
86
  * in this request, its first push removes every value replayed for it and
87
87
  * takes the first one's position (later live pushes follow it), so the
88
- * handle output stays live without a duplicate.
88
+ * handle output stays live without a duplicate. A push counts as that
89
+ * loader's when it is made in its body, or in a body it entered that has
90
+ * no replayed values of its own (the capture credits a dependency's push
91
+ * under a live-lane loader to that loader); a hole's run that ends without
92
+ * one drops them (settleLoaderRun).
89
93
  */
90
94
  pushReplayed(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
95
+ /**
96
+ * push() a document HIT's copy of `loaderId`'s settled push, restored from
97
+ * the shell's doc record (handle-snapshot.ts restoreHandles). The record is
98
+ * authoritative for that loader's settled pushes: the prelude was rendered
99
+ * from it, and a run of the loader on the HIT reads the store, not the
100
+ * capture's values. So from then on this request drops every settled,
101
+ * thenable-free push the loader makes (live, or replayed from a cache
102
+ * entry, anywhere inside its body), and keeps the ones holding a thenable
103
+ * (holdsThenable: what the record could not keep, `runs`), placed among the
104
+ * restored copies in the loader's push order. Only bake-lane owners are
105
+ * restored this way (withCacheLookup): a live-lane loader is a hole.
106
+ */
107
+ pushRestored(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
108
+ /**
109
+ * The loaders the route runs on the live lane (liveLaneLoaderIds), from a
110
+ * PPR shell record's restore (handle-snapshot.ts restoreHandles): the
111
+ * holes. A push counts for a restored loader when that loader is the
112
+ * replayed one or the innermost enclosing loader body that restored
113
+ * copies; the walk out through enclosing bodies stops at a hole's body,
114
+ * and a replay of a hole's push counts for none. So a restored loader
115
+ * never takes a push made inside a hole it awaited, while a body inside the
116
+ * hole that restored copies of its own (a dependency the capture ran under
117
+ * a bake-lane loader) still takes its pushes.
118
+ */
119
+ markLiveLane(loaderIds: ReadonlySet<string>): void;
120
+ /**
121
+ * `loaderId`'s run in this request settled (resolved or rejected), its
122
+ * pushes made (loader-resolution.ts createLoaderExecutor). When the loader
123
+ * is a hole (markLiveLane), values replayed for it that no push of the run
124
+ * replaced are dropped: the run's output decides, so a hole that throws or
125
+ * skips its push shows none rather than the capture's. Any other loader's
126
+ * replayed values stay: a bake-lane loader's record is authoritative for
127
+ * its settled pushes, as its pin is for its data. Restored copies are not
128
+ * replays and stand.
129
+ */
130
+ settleLoaderRun(loaderId: string): void;
131
+ /**
132
+ * A hole's own cache() HIT (loader-cache.ts replayLoaderHandles, once it
133
+ * claims the hole): the values replayed for hole `loaderId` before (its
134
+ * shell copies, which restoreHandles leaves unclaimed, those of the
135
+ * dependencies credited to it included) give way to the pushes the entry
136
+ * recorded, none when it recorded none, so they match the entry's data.
137
+ * `deliver` makes the pushReplayed calls, which take the removed values'
138
+ * place in each array. Any other loader, or a hole with nothing replayed,
139
+ * delivers as a plain replay.
140
+ */
141
+ redeliverReplays(loaderId: string, deliver: () => void): void;
91
142
  /**
92
143
  * Get all collected handle data after all handlers have settled.
93
144
  * Waits for `settled` (handler lane), then returns the data at that point.
@@ -22,11 +22,12 @@ import { type MetricsStore } from "./context.js";
22
22
  import type { SegmentCacheStore } from "../cache/types.js";
23
23
  import type { Theme, ResolvedThemeConfig } from "../theme/types.js";
24
24
  import type { ExecutionContext, RequestScope } from "../types/request-scope.js";
25
- import type { TransitionWhenFn } from "../types/segments.js";
25
+ import type { TransitionWhenRecord } from "../router/transition-when.js";
26
26
  import type { ResolvedTracing } from "../router/tracing.js";
27
27
  import type { RenderMode, RenderPhase } from "../router/timeout.js";
28
28
  import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
29
29
  import type { RoutineTrace } from "../rsc/routine-plan.js";
30
+ import { type ExecutionStart } from "../cache/invalidation-order.js";
30
31
  export interface RenderForegroundCursor {
31
32
  mode: RenderMode;
32
33
  phase: RenderPhase;
@@ -86,10 +87,24 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
86
87
  dynamic(): void;
87
88
  /** @internal Request-local PPR opt-out marker set by ctx.dynamic(). */
88
89
  _dynamic?: boolean;
89
- /** @internal Get a cookie value (effective: request + response mutations). Use cookies().get() instead. */
90
+ /**
91
+ * @internal Get a cookie value (effective: request + response mutations).
92
+ * Use cookies().get() instead. Guarded like cookies() (#976).
93
+ */
90
94
  cookie(name: string): string | undefined;
91
- /** @internal Get all cookies (effective merged view). Use cookies().getAll() instead. */
95
+ /**
96
+ * @internal Get all cookies (effective merged view). Use
97
+ * cookies().getAll() instead. Guarded like cookies() (#976).
98
+ */
92
99
  cookies(): Record<string, string>;
100
+ /**
101
+ * @internal `cookie()` without the identity guard: the read behind the
102
+ * cookies() store, which guards at its own call and records per read
103
+ * method. Non-enumerable, like `_readTheme`.
104
+ */
105
+ _readCookie(name: string): string | undefined;
106
+ /** @internal `cookies()` without the identity guard (see `_readCookie`). */
107
+ _readCookies(): Record<string, string>;
93
108
  /** @internal Set a cookie on the response. Use cookies().set() instead. */
94
109
  setCookie(name: string, value: string, options?: CookieOptions): void;
95
110
  /** @internal Delete a cookie. Use cookies().delete() instead. */
@@ -104,6 +119,39 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
104
119
  _rotateStateCookie(): void;
105
120
  /** @internal Set the keepClientCache() directive header on the response. */
106
121
  _setKeepCacheDirective(): void;
122
+ /**
123
+ * @internal This request carries the fresh-reads cookie: it follows an
124
+ * updateTag()/revalidateTag() by the same user, so the stores read tag
125
+ * markers and shells from the store, not from an isolate memo.
126
+ */
127
+ _freshReads?: boolean;
128
+ /**
129
+ * @internal Set the fresh-reads cookie on this response for `maxAgeMs`
130
+ * (rounded up to whole seconds; the longest stays). Called by
131
+ * updateTag()/revalidateTag().
132
+ */
133
+ _setFreshReadsCookie(maxAgeMs: number): void;
134
+ /**
135
+ * @internal The context createRequestContext() returned. A context derived
136
+ * from it with Object.create (a PPR HIT tail, a shell capture, a background
137
+ * revalidation render) inherits it, so per-request invalidation state (the
138
+ * stores' masks) is keyed by the request, not by whichever derived object
139
+ * called or read (#973).
140
+ */
141
+ _requestRoot?: RequestContext<any, any>;
142
+ /**
143
+ * @internal Where the request started in the isolate's invalidation order
144
+ * (cache/invalidation-order.ts), taken when createRequestContext() ran. The
145
+ * document cache gates its write on it (#977): a middleware ahead of the
146
+ * document cache can read tagged data the document bakes.
147
+ */
148
+ _requestStart?: ExecutionStart;
149
+ /**
150
+ * @internal The handler has handed the response to the host (rsc/handler.ts
151
+ * `rango.response`): header and cookie writes after this are lost, as from
152
+ * a streaming loader or render.
153
+ */
154
+ _responseSent?: boolean;
107
155
  /**
108
156
  * Access loader data or push handle data.
109
157
  *
@@ -137,18 +185,13 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
137
185
  */
138
186
  readonly _handleStore: HandleStore;
139
187
  /**
140
- * @internal transition({ when }) predicates for segments matched this request,
141
- * keyed by segment id. Collected during resolution (the function is stripped
142
- * from the serialized segment config), then evaluated post-handler in
143
- * rsc-rendering — outside any cache scope — to drop the transition of any
144
- * segment whose predicate returns false.
188
+ * @internal transition({ when }) client references of the matched entry
189
+ * chain, keyed by segment id. Recorded at match time from the static route
190
+ * definition (router/transition-when.ts) and attached to the payload's
191
+ * segments right before Flight (rsc/attach-transition-when.ts). The server
192
+ * never calls them, and no cache or snapshot stores them.
145
193
  */
146
- _transitionWhen?: Array<{
147
- id: string;
148
- when: TransitionWhenFn;
149
- }>;
150
- /** @internal PPR transition decisions evaluated before cache lookup/handlers. */
151
- _pprTransitionDecisions?: Map<string, boolean>;
194
+ _transitionWhenRefs?: ReadonlyMap<string, TransitionWhenRecord>;
152
195
  /**
153
196
  * @internal Post-match serve-source truth for the PPR replay reporter.
154
197
  * Stamped from the match context as `intercept`, then overwritten as
@@ -172,8 +215,8 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
172
215
  * capture task's derived request context (built by shell-capture.ts). This is
173
216
  * the switch every capture-specific behavior reads: loader masking
174
217
  * (loader-mask.ts isShellCaptureActive / fresh.ts emitStreaming) and the
175
- * cookies()/headers() capture guard (cookie-store.ts
176
- * assertNotInsideShellCapture). The foreground render never sets it, so the
218
+ * identity-read capture guard (server/context.ts guardIdentityRead). The
219
+ * foreground render never sets it, so the
177
220
  * served response is byte-identical to axis 1. The capture descriptor itself
178
221
  * (key/ttl/swr/tags/store) is NOT threaded through the request context — the
179
222
  * integrated PPR serve path (rsc/shell-serve.ts + rsc-rendering.ts) builds it
@@ -191,6 +234,53 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
191
234
  * property of the capture's derived context only.
192
235
  */
193
236
  _shellCaptureLoaderRecords?: Map<string, Promise<unknown>>;
237
+ /**
238
+ * @internal Set on a capture's derived context when a loader pushed a
239
+ * value the record cannot keep (a deferred push, masked nested promises,
240
+ * or a push outside a loader body): the loader records then carry
241
+ * `runs: 1`, so a HIT still runs their bodies for those pushes.
242
+ */
243
+ _shellCaptureUnrecordedLoaderPush?: true;
244
+ /**
245
+ * @internal The lane of each loader the capture's matched route registers
246
+ * (loader-cache.ts routeLoaderLanes), set by createMatchContextForFull
247
+ * before any loader runs. The capture's push funnel credits a push made
248
+ * under a live-lane loader's body, at any depth, to that loader
249
+ * (shell-capture.ts deriveShellCaptureContext). Own property of the
250
+ * capture's derived context only.
251
+ */
252
+ _shellCaptureLoaderLanes?: ReadonlyMap<string, "live" | "bake">;
253
+ /**
254
+ * @internal Record keys resolved for this request (CacheScope
255
+ * resolveKeyFrom): by the scope's `key()` (one result) or its store's
256
+ * keyGenerator (one per default key). A shell capture's derived context
257
+ * reads it through the prototype chain, so the capture reuses the
258
+ * partition its request resolved instead of running `key()` again.
259
+ */
260
+ _resolvedCacheKeys?: Map<unknown, Map<string, Promise<string>>>;
261
+ /**
262
+ * @internal The shell store key the PPR serve path resolved for this
263
+ * document request (rsc-rendering.ts shellServePlan), request partition
264
+ * included. Read by the testing helper serveShellRequest.
265
+ */
266
+ _shellKey?: string;
267
+ /**
268
+ * @internal The request carried the forced-MISS reload marker
269
+ * (shell-serve.ts SHELL_MISS_PARAM). The handler strips the marker from the
270
+ * request on entry and sets this; the shell gate renders the request like a
271
+ * cache miss.
272
+ */
273
+ _shellForcedMiss?: true;
274
+ /**
275
+ * @internal The freshness window of the route cache() records this
276
+ * request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
277
+ * timestamps: `freshUntil` is the record's `expiresAt`, `staleUntil` adds
278
+ * its scope's swr. The narrowest record wins. A shell capture caps its
279
+ * entry's ttl and ttl+swr to it (shell-capture.ts capShellWindow), so a
280
+ * shell is never fresher, or served longer, than the route cache() entry
281
+ * it replayed or wrote.
282
+ */
283
+ _routeRecordWindow?: RouteRecordWindow;
194
284
  /**
195
285
  * @internal Loader-family snapshot seed for a shell HIT's tail render:
196
286
  * segment-key -> the capture's elided container (already Flight-deserialized
@@ -198,21 +288,24 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
198
288
  * overlays it onto the fresh run's container (recorded paths pinned,
199
289
  * hole-marker paths keep the fresh nested promises) so the payload's baked
200
290
  * bytes match the frozen prelude; a hole-free entry resolves pin-first
201
- * without gating on the fresh run. Own property of the HIT tail's derived
202
- * context only.
291
+ * and does not run the loader. Two owners: serveShellHit sets it on the
292
+ * HIT tail's derived context, and matchPartialWithPprReplay sets it on the
293
+ * request context of a PPR partial replay once its doc record hits, and
294
+ * restores the previous value after the match.
203
295
  */
204
296
  _shellLoaderSeed?: Map<string, import("../cache/shell-snapshot.js").ShellLoaderSeedEntry>;
205
297
  /**
206
- * @internal Shell fast-path marker: makes the next eligible match treat the
207
- * whole matched route as an implicit doc-level cache() boundary (see
298
+ * @internal The doc record marker: makes the next match treat the whole
299
+ * matched route as an implicit doc-level cache() boundary (see
208
300
  * resolveShellImplicitCacheScope in cache/cache-scope.ts). Set ONLY on
209
301
  * (a) the capture's derived context — with a record-only store so the
210
302
  * capture's cacheRoute write lands in the snapshot, never the real store —
211
- * (b) a HIT tail's seeded context, and (c) an eligible normal-route partial
212
- * replay, where `store` is a request-local segment overlay. Handler-live holes
213
- * and conditional transitions decline replay.
214
- * Routes with their own cache() config are never overridden — their scope's
215
- * store/key/ttl/swr/condition semantics stay authoritative. On the
303
+ * (b) a document HIT tail's seeded context (`docTail`), and (c) an eligible
304
+ * normal-route partial replay, where `store` is a request-local segment
305
+ * overlay.
306
+ * A document HIT tail replays the record even for a route with its own
307
+ * cache() config (the gate before the commit already evaluated that
308
+ * scope's opt-outs). Elsewhere the route's scope stays authoritative. On the
216
309
  * navigation-replay serve path (`onExplicitHit` set) the marker COMPOSES with
217
310
  * such a scope instead of being ignored: the seeded doc record supplies the match
218
311
  * only when the explicit tier misses (withCacheLookup). cache(false) and a
@@ -229,12 +322,17 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
229
322
  * segment record even when the triggering request is partial.
230
323
  */
231
324
  keyPrefix?: "doc";
232
- /** @internal Called only after the implicit cache hit decodes successfully. */
233
- onHit?: () => void;
325
+ /**
326
+ * @internal Called only after the implicit cache hit decodes
327
+ * successfully; the lookup awaits it before returning the hit, so work
328
+ * it starts lands before the route's loaders resolve.
329
+ */
330
+ onHit?: () => void | Promise<void>;
234
331
  /**
235
332
  * @internal Called when the seeded document record fails server-side
236
333
  * deserialization. Partial replay uses it to replace the enclosing shell
237
- * snapshot after serving the fresh fallback.
334
+ * snapshot after serving the fresh fallback. A document HIT tail does not
335
+ * set it: withCacheLookup throws ShellRecordUnavailableError instead.
238
336
  */
239
337
  onCorrupt?: () => void;
240
338
  /**
@@ -245,6 +343,23 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
245
343
  * require the exact consumable record instead of "any segment record".
246
344
  */
247
345
  docKey?: string;
346
+ /**
347
+ * @internal Set on a document HIT tail (serveShellHit). The implicit doc
348
+ * scope replaces any route-derived cache() scope for the tail's match
349
+ * (resolveShellImplicitCacheScope), and a lookup that does not hit throws
350
+ * ShellRecordUnavailableError instead of resolving segments
351
+ * (withCacheLookup): a HIT never runs a handler. The record's
352
+ * loader-owned handle pushes restore as authoritative
353
+ * (HandleStore.pushRestored): the prelude rendered them.
354
+ */
355
+ docTail?: true;
356
+ /**
357
+ * @internal The key a document HIT tail looks the doc record up by: the
358
+ * entry's own `docKey`. Recomputing it could name another key (a store
359
+ * keyGenerator folding request data, a build-time capture's synthetic
360
+ * host) and miss the record.
361
+ */
362
+ fixedDocKey?: string;
248
363
  /**
249
364
  * @internal Set ONLY by matchPartialWithPprReplay on the navigation-replay
250
365
  * serve path. Its presence arms the explicit-scope composition in
@@ -286,30 +401,20 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
286
401
  */
287
402
  _shellFragmentPayload?: boolean;
288
403
  /**
289
- * @internal Handler-layer liveness observed DURING a shell capture, from
290
- * three sources: (a) the capture handle-store push wrapper (shell-capture.ts)
291
- * when a push made OUTSIDE a DSL loader scope carries a nested thenable
292
- * (masked to a never-filling hole); (b) still-pending top-level handler
293
- * pushes (liveness unknowable at the barrier); (c) a handler-invoked loader
294
- * executing during the capture (loader-resolution.ts — its consumption-lane
295
- * value would freeze on a handler-free HIT). captureAndStoreShell folds it
296
- * into ShellCacheEntry.handlerLiveHoles at the putShell barrier. Own
297
- * property of the capture's derived context only.
298
- */
299
- _shellCaptureHandleLiveness?: {
300
- holes: boolean;
301
- pendingPushes: number;
302
- handlerInvokedLoader: boolean;
303
- };
304
- /**
305
- * @internal Set (to the offending fn name) by the cookies()/headers()
306
- * capture guard when it throws DURING a capture render. Load-bearing for the
404
+ * @internal Set by the capture guard (server/context.ts
405
+ * guardIdentityRead) when it throws DURING a capture render: the read
406
+ * ("cookies()", "headers()", `ctx.get() for a non-cacheable variable`,
407
+ * "ctx.theme") and the fix the
408
+ * refusal warning gives for it. Load-bearing for the
307
409
  * bake lane: a guard throw inside an executing loader is swallowed by
308
410
  * wrapLoaderPromise into per-loader error UI, which would otherwise bake
309
411
  * silently into the shared shell — the capture checks this flag after the
310
412
  * render and refuses instead. Deterministic, so the capture does not retry.
311
413
  */
312
- _shellCaptureGuardTripped?: string;
414
+ _shellCaptureGuardTripped?: {
415
+ surface: string;
416
+ fix: string;
417
+ };
313
418
  /**
314
419
  * @internal The loader $$id whose BODY was executing when the capture guard
315
420
  * tripped (read off the loader-body ALS scope at trip time), or undefined
@@ -336,6 +441,21 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
336
441
  * content used and can therefore be invalidated by updateTag()/revalidateTag().
337
442
  */
338
443
  _requestTags: Set<string>;
444
+ /**
445
+ * @internal This request can write a route cache() record: its match
446
+ * resolved a cache scope (match-api.ts). Arms the record tag owners
447
+ * (cache-tag.ts armRecordTagOwners); off, the segment scopes, loader links
448
+ * and owned tag sets are skipped entirely. A capture's or background
449
+ * re-render's derived context (Object.create) inherits it.
450
+ */
451
+ _recordTagOwners?: true;
452
+ /**
453
+ * @internal This request resolves a loader bound with its own cache()
454
+ * (match-api.ts, or the binding's funnel). Arms the per-execution loader
455
+ * tag sets (cache-tag.ts armLoaderTagSets); off, a loader execution
456
+ * allocates no set and a read links nothing. Derived contexts inherit it.
457
+ */
458
+ _recordLoaderTags?: true;
339
459
  /** @internal Cache profiles for "use cache" profile resolution (per-router) */
340
460
  _cacheProfiles?: Record<string, import("../cache/profile-registry.js").CacheProfile>;
341
461
  /**
@@ -376,6 +496,11 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
376
496
  * Returns the theme value from the cookie, or the default theme if not set.
377
497
  * This is the user's preference ("light", "dark", or "system"), not the resolved value.
378
498
  *
499
+ * The visitor's cookie, so it is guarded like `cookies()`: reading it
500
+ * refuses a ppr shell capture and throws inside a `cache()` boundary or a
501
+ * `"use cache"` function (#971). A non-enumerable getter: a spread or
502
+ * `Object.assign` copy of the context does not carry it.
503
+ *
379
504
  * @example
380
505
  * ```typescript
381
506
  * route("settings", (ctx) => {
@@ -384,7 +509,7 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
384
509
  * });
385
510
  * ```
386
511
  */
387
- theme?: Theme;
512
+ readonly theme?: Theme;
388
513
  /**
389
514
  * Set the theme (only available when theme is enabled in router config)
390
515
  *
@@ -405,6 +530,27 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
405
530
  setTheme?: (theme: Theme) => void;
406
531
  /** @internal Theme configuration (null if theme not enabled) */
407
532
  _themeConfig?: ResolvedThemeConfig | null;
533
+ /**
534
+ * @internal The theme cookie (or the default) read with no identity guard.
535
+ * The guarded reads (`theme` here, the handler and middleware `ctx.theme`)
536
+ * call it after guardIdentityRead (readGuardedTheme); the router's own payload read goes
537
+ * through payloadInitialTheme (rsc/full-payload.ts), except the unmatched
538
+ * route's 404 (rsc/handler.ts), which is never stored. Undefined without
539
+ * theme config.
540
+ */
541
+ _readTheme(): Theme | undefined;
542
+ /**
543
+ * @internal Set by the document-cache middleware (cache/document-cache.ts)
544
+ * before it runs a render whose response it may store: the MISS and the
545
+ * stale refresh. payloadInitialTheme reads it (#978).
546
+ */
547
+ _documentCacheRender?: boolean;
548
+ /**
549
+ * @internal Set by payloadInitialTheme when the document payload carries
550
+ * the visitor's theme and it differs from the no-cookie default. The
551
+ * document cache does not store that response (#978).
552
+ */
553
+ _payloadVisitorTheme?: boolean;
408
554
  /**
409
555
  * Attach location state entries to the current response.
410
556
  *
@@ -439,19 +585,6 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
439
585
  _routeName?: string;
440
586
  /** @internal Previous route key (from the navigation source), used for revalidation */
441
587
  _prevRouteKey?: string;
442
- /**
443
- * @internal Navigation/action source data the transition({ when }) gate reads
444
- * to build its ShouldRevalidateFn-shaped predicate context. currentUrl/Params
445
- * come from the navigation snapshot (set at match time); action* are stashed
446
- * at the action-bearing gate call sites. All undefined when there is no source
447
- * (initial full load) or no action (plain navigation).
448
- */
449
- _gateCurrentUrl?: URL;
450
- _gateCurrentParams?: Record<string, string>;
451
- _gateActionId?: string;
452
- _gateActionUrl?: URL;
453
- _gateActionResult?: unknown;
454
- _gateFormData?: FormData;
455
588
  /**
456
589
  * @internal True while the post-action revalidation render is running (set by
457
590
  * revalidateAfterAction). The "use cache" runtime reads this to prefer
@@ -595,13 +728,27 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
595
728
  */
596
729
  _cacheSignal?: import("../router/telemetry.js").CacheSegmentSignal[];
597
730
  }
731
+ /**
732
+ * @internal The freshness window of a route cache() record, as ms
733
+ * timestamps: fresh until `freshUntil` (its `expiresAt`), stale until
734
+ * `staleUntil` (plus its scope's swr). `ttl`, `swr` and `written` describe
735
+ * the record that sets `staleUntil`: its cache() config, and whether this
736
+ * request wrote it (cacheRoute) rather than read it.
737
+ */
738
+ export interface RouteRecordWindow {
739
+ freshUntil: number;
740
+ staleUntil: number;
741
+ ttl: number;
742
+ swr: number;
743
+ written: boolean;
744
+ }
598
745
  /**
599
746
  * Public view of RequestContext, without internal methods and fields.
600
747
  *
601
748
  * This is the type exported to library consumers. Internal code should
602
749
  * use the full RequestContext interface directly.
603
750
  */
604
- export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhen" | "_pprTransitionDecisions" | "_pprReplayPostMatchReason" | "_cacheStore" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureHandleLiveness" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_locationState" | "_routeName" | "_prevRouteKey" | "_gateCurrentUrl" | "_gateCurrentParams" | "_gateActionId" | "_gateActionUrl" | "_gateActionResult" | "_gateFormData" | "_inActionRevalidation" | "_reportedErrors" | "_renderErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
751
+ export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_locationState" | "_routeName" | "_prevRouteKey" | "_inActionRevalidation" | "_reportedErrors" | "_renderErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
605
752
  /**
606
753
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
607
754
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -636,7 +783,7 @@ export declare function setRequestContextParams(params: Record<string, string>,
636
783
  * route key available for revalidation and intercept evaluation.
637
784
  * @internal
638
785
  */
639
- export declare function setRequestContextPrevRouteKey(prevRouteKey: string | undefined, currentUrl?: URL, currentParams?: Record<string, string>): void;
786
+ export declare function setRequestContextPrevRouteKey(prevRouteKey: string | undefined): void;
640
787
  /**
641
788
  * Get accumulated location state entries from the current request context.
642
789
  * Returns undefined if no state has been set.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The guarded `ctx.request.headers` (#976) and the router's raw reads.
3
+ *
4
+ * The Request the router hands to user code (handler, middleware and loader
5
+ * `ctx.request`, `getRequestContext().request`) carries an own `headers`
6
+ * getter that shadows the prototype's and runs the identity guard
7
+ * (cookie-store.ts guardRequestHeaders). A Proxy around the Request is not an
8
+ * option: `fetch(request)`, `new Request(request)` and `request.clone()` read
9
+ * the platform's internal slots, which a Proxy does not have. The own getter
10
+ * keeps the object a real Request, and those operations never call it.
11
+ */
12
+ /**
13
+ * A request's headers, past the guard. The rule: router code never reads a
14
+ * request's headers through the getter, only through this, so the guard sees
15
+ * user reads alone. Several router reads run inside the scopes the guard
16
+ * refuses (the state cookie rotation at a ppr capture, match's HMR marker,
17
+ * a store's cf-ray inside a "use cache" body, telemetry inside a loader
18
+ * fill); the rest follow the rule so a new call site cannot drift into one.
19
+ */
20
+ export declare function requestHeaders(request: Request): Headers;
21
+ /**
22
+ * Shadow `request.headers` with an own, non-enumerable getter that calls
23
+ * `beforeRead` and returns the request's own Headers (stable per request, so
24
+ * a header set through it stays visible to every reader). Idempotent. Leaves
25
+ * the request as is when `headers` is a non-configurable own property (a
26
+ * runtime that defines it per instance). Three inherited members are
27
+ * shadowed with it:
28
+ *
29
+ * - `clone()` returns a clone shadowed the same way. A plain clone was a
30
+ * Request without the getter, so `ctx.request.clone().headers` read the
31
+ * visitor's headers past the guard. (`new Request(ctx.request)` still
32
+ * returns a plain Request: the constructor cannot be intercepted.)
33
+ * - `_request`, on a lazy srvx NodeRequest (what @vitejs/plugin-rsc's Node
34
+ * dev and preview servers and the vercel-output launcher hand the
35
+ * router), runs unguarded: it builds the platform Request on first use
36
+ * from `this.headers`, for clone() and the body readers. Through the
37
+ * getter, a clone() inside a cache() boundary threw as a user read. It
38
+ * stays lazy, so a request whose body srvx reads from its buffered
39
+ * `rawBody` never builds one.
40
+ * - Node's util.inspect hook runs unguarded: undici's inspect reads
41
+ * `this.headers`, so `console.log(ctx.request)` inside a "use cache" body
42
+ * threw. A log is not a read into a shared entry.
43
+ */
44
+ export declare function shadowRequestHeaders(request: Request, beforeRead: () => void): Request;
@@ -13,4 +13,5 @@ export { registerRouteMap, setCachedManifest, clearCachedManifest, clearAllRoute
13
13
  export { registerLoaderById, setLoaderImports, } from "./server/loader-registry.js";
14
14
  export { createRequestContext, type CreateRequestContextOptions, } from "./server/request-context.js";
15
15
  export { isClientComponent, assertClientComponent } from "./component-utils.js";
16
+ export { enableTransitionWhenValidation } from "./transition-when-ref.js";
16
17
  export { clearClientUrlProjections, setClientUrlProjection, type ClientUrlProjection, } from "./client-urls/server-projection.js";
@@ -238,6 +238,15 @@ interface ShellCaptureOptions {
238
238
  * refuses to store the shell (issue #915).
239
239
  */
240
240
  onError?: (error: unknown) => void;
241
+ /**
242
+ * Called with React's errorInfo for each task still pending when the
243
+ * capture's own abort froze the prelude; its componentStack is computed
244
+ * when read. The dev no-shell warning prints the stacks: one of them is what
245
+ * suspended above <body> (issue #941).
246
+ */
247
+ onAbortedTask?: (errorInfo: {
248
+ componentStack?: string;
249
+ } | undefined) => void;
241
250
  }
242
251
  /**
243
252
  * Result of a successful shell capture. `prelude` is the raw prelude bytes;
@@ -54,14 +54,15 @@ export interface SsrRootOptions {
54
54
  nonce?: string;
55
55
  /**
56
56
  * Fires once when the Flight payload root settles (resolve OR reject) — the
57
- * signal that every client-module load the payload references completed and
58
- * fizz can start emitting the tree. The capture pass gates its abort on
59
- * this: a fully REPLAYED (prerendered) route's Flight stream goes
60
- * byte-quiet in ~1-3ms, but fizz cannot render even <html> until the
61
- * module loads finish (real module-runner I/O in dev; 100ms+ on a cold
62
- * graph), so an abort gated on Flight quiet alone fires first and freezes
63
- * a zero-byte prelude. Masked-loader holes do NOT block this signal —
64
- * they postpone below the root.
57
+ * signal that fizz can start emitting the tree. A client component used as
58
+ * an element type resolves lazily, so its module load can still be in
59
+ * flight (captureShellHTML waits for those separately, issue #949). The
60
+ * capture pass gates its abort on this: a fully REPLAYED (prerendered)
61
+ * route's Flight stream goes byte-quiet in ~1-3ms, but fizz cannot render
62
+ * even <html> until the module loads finish (real module-runner I/O in dev;
63
+ * 100ms+ on a cold graph), so an abort gated on Flight quiet alone fires
64
+ * first and freezes a zero-byte prelude. Masked-loader holes do NOT block
65
+ * this signal — they postpone below the root.
65
66
  */
66
67
  onPayloadSettled?: () => void;
67
68
  /**
@@ -4,7 +4,7 @@ import { blockPrefetch, unblockPrefetch, createPageHelpers, createStopwatch, get
4
4
  import { createParity, type ExpectParityOptions, type Parity, type ParityDescribeOptions, type ParityIntent } from "./parity.js";
5
5
  import { createRangoMatchers, type RangoMatchers } from "./matchers.js";
6
6
  export { assertCacheStatus, assertCacheDecision, parseCacheHeader, createCacheSink, filterCacheDecisions, type CacheSink, type ExpectedCacheStatus, type CacheStatusTarget, } from "../cache-status.js";
7
- export { assertPprReplayStatus, assertShellStatus, parsePprReplayStatus, parseShellStatus, PPR_REPLAY_STATUS_HEADER, shellCacheKey, SHELL_STATUS_HEADER, type PprReplayBypassReason, type PprReplayStatus, type ShellStatus, type ShellStatusTarget, } from "../shell-status.js";
7
+ export { assertPprReplayStatus, assertShellStatus, parsePprReplayStatus, parseShellStatus, PPR_REPLAY_STATUS_HEADER, shellCacheKey, SHELL_STATUS_HEADER, type PprReplayBypassReason, type PprReplayStatus, type ShellCachePartition, type ShellStatus, type ShellStatusTarget, } from "../shell-status.js";
8
8
  export { testId, waitForHydration, waitForNavigation, goBack, goForward, getHistoryState, waitForElement, isVisibleInViewport, isPrefetchRequest, blockPrefetch, unblockPrefetch, parseNumber, getNumericContent, createStopwatch, measureTime, createPageHelpers, createUseFixture, createParity, createRangoMatchers, };
9
9
  export type { Fixture, FixtureOptions, PageHelpers, Stopwatch, Parity, ParityIntent, ParityDescribeOptions, ExpectParityOptions, RangoMatchers, };
10
10
  export interface RangoE2E extends PageHelpers, Parity {
@@ -18,6 +18,11 @@
18
18
  * element tree, so you can assert typed prop fidelity across the client boundary
19
19
  * (a `Date` comes back a `Date`) and detect inlined-vs-island. Serialize +
20
20
  * deserialize only — no hydration/interaction (that is the e2e tier).
21
+ *
22
+ * `serveShellRequest` serves one request through the router's production
23
+ * handler, so a `ppr` route's MISS runs the real shell capture and a later
24
+ * request is a real HIT; only the HTML step is stubbed. `resetShellTestState`
25
+ * clears the per-isolate PPR state between tests.
21
26
  */
22
27
  export { renderToFlightString, normalizeFlight, assertFlightRuntimeAvailable, } from "./flight.js";
23
28
  export type { RenderToFlightStringOptions } from "./flight.js";
@@ -25,3 +30,5 @@ export { renderServerTree, findClientBoundaries, findElements, textContent, asse
25
30
  export type { RenderServerTreeOptions, RenderServerTreeResult, ClientBoundary, BoundarySelector, FoundElement, ElementSelector, } from "./flight-tree.js";
26
31
  export { renderHandler } from "./render-handler.js";
27
32
  export type { TestableHandler, RenderHandlerOptions, RenderHandlerResult, StateCookieSeed, } from "./render-handler.js";
33
+ export { serveShellRequest, resetShellTestState, } from "./serve-shell-request.js";
34
+ export type { ServeShellRequestOptions, ServeShellRequestResult, } from "./serve-shell-request.js";
@@ -38,7 +38,7 @@ export type { RunMiddlewareOptions, RunMiddlewareResult, } from "./run-middlewar
38
38
  export { runLoader, runLoaderResult } from "./run-loader.js";
39
39
  export type { RunLoaderOptions, RunLoaderResult, UseResolver, TestLoaderContext, } from "./run-loader.js";
40
40
  export { runTransitionWhen } from "./run-transition-when.js";
41
- export type { RunTransitionWhenOptions, RunTransitionWhenResult, } from "./run-transition-when.js";
41
+ export type { RunTransitionWhenAction, RunTransitionWhenLocation, RunTransitionWhenOptions, RunTransitionWhenResult, } from "./run-transition-when.js";
42
42
  export { runClientRevalidate } from "./run-client-revalidate.js";
43
43
  export type { RunClientRevalidateOptions } from "./run-client-revalidate.js";
44
44
  export { dispatch } from "./dispatch.js";
@@ -47,8 +47,9 @@ export { assertCacheStatus, assertCacheDecision, parseCacheHeader, createCacheSi
47
47
  export type { ExpectedCacheStatus, CacheStatusTarget, CacheSink, } from "./cache-status.js";
48
48
  export type { TelemetryEvent, TelemetrySink, CacheDecisionEvent, CacheSegmentSignal, CacheSegmentStatus, } from "../router/telemetry.js";
49
49
  export { assertPprReplayStatus, assertShellStatus, parsePprReplayStatus, parseShellStatus, PPR_REPLAY_STATUS_HEADER, shellCacheKey, SHELL_STATUS_HEADER, } from "./shell-status.js";
50
- export type { PprReplayBypassReason, PprReplayStatus, ShellStatus, ShellStatusTarget, } from "./shell-status.js";
50
+ export type { PprReplayBypassReason, PprReplayStatus, ShellCachePartition, ShellStatus, ShellStatusTarget, } from "./shell-status.js";
51
51
  export { collectHandle } from "./collect-handle.js";
52
+ export { withLocationStateKey } from "./location-state-key.js";
52
53
  export { diffGeneratedRoutes, assertGeneratedRoutesMatch, } from "./generated-routes.js";
53
54
  export type { GeneratedRoutesDiff, GeneratedRouteMismatch, } from "./generated-routes.js";
54
55
  export { createTestRequestContext, runInRequestContext, toRequest, seedVariables, } from "./internal/context.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The id a testing primitive's `action` option names: a single imported
3
+ * server action (its `$id ?? $$id`, as the action boundary derives it) or a
4
+ * raw actionId string. A function without either id throws, naming the
5
+ * primitive.
6
+ */
7
+ export declare function resolveTestActionId(action: ((...args: never[]) => unknown) | string | undefined, primitive: string): string | undefined;