@rangojs/router 0.27.0 → 0.28.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 (212) hide show
  1. package/dist/bin/rango.js +1 -1
  2. package/dist/types/__internal.d.ts +7 -1
  3. package/dist/types/browser/event-controller.d.ts +2 -1
  4. package/dist/types/browser/history-state.d.ts +3 -9
  5. package/dist/types/browser/navigation-store.d.ts +8 -6
  6. package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
  7. package/dist/types/browser/segment-reconciler.d.ts +6 -4
  8. package/dist/types/browser/types.d.ts +2 -1
  9. package/dist/types/browser/wire-protocol.d.ts +25 -0
  10. package/dist/types/cache/cache-key-utils.d.ts +11 -5
  11. package/dist/types/cache/cache-scope.d.ts +34 -22
  12. package/dist/types/cache/cf/cf-cache-constants.d.ts +2 -2
  13. package/dist/types/cache/cf/cf-cache-store.d.ts +47 -65
  14. package/dist/types/cache/cf/cf-kv-utils.d.ts +1 -1
  15. package/dist/types/cache/handle-snapshot.d.ts +9 -4
  16. package/dist/types/cache/segment-codec.d.ts +14 -0
  17. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  18. package/dist/types/cache/tag-invalidation.d.ts +10 -0
  19. package/dist/types/cache/taint.d.ts +5 -3
  20. package/dist/types/cache/types.d.ts +7 -3
  21. package/dist/types/cache/vercel/vercel-cache-store.d.ts +8 -6
  22. package/dist/types/prefetch-markers.d.ts +5 -14
  23. package/dist/types/prerender/store.d.ts +31 -0
  24. package/dist/types/prerender/warm-request.d.ts +3 -3
  25. package/dist/types/prerender.d.ts +2 -2
  26. package/dist/types/route-name.d.ts +5 -0
  27. package/dist/types/router/error-handling.d.ts +4 -4
  28. package/dist/types/router/instrument.d.ts +4 -3
  29. package/dist/types/router/intercept-resolution.d.ts +25 -9
  30. package/dist/types/router/match-context.d.ts +4 -11
  31. package/dist/types/router/match-handlers.d.ts +2 -6
  32. package/dist/types/router/match-middleware/background-revalidation.d.ts +10 -20
  33. package/dist/types/router/match-middleware/cache-lookup.d.ts +34 -86
  34. package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
  35. package/dist/types/router/prerender-match.d.ts +21 -6
  36. package/dist/types/router/preview-match.d.ts +2 -7
  37. package/dist/types/router/request-classification.d.ts +5 -0
  38. package/dist/types/router/router-context.d.ts +7 -46
  39. package/dist/types/router/router-interfaces.d.ts +8 -14
  40. package/dist/types/router/segment-resolution/loader-cache.d.ts +3 -3
  41. package/dist/types/router/segment-resolution/loader-mask.d.ts +4 -4
  42. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +20 -18
  43. package/dist/types/router/segment-resolution/resolution-pass.d.ts +93 -0
  44. package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
  45. package/dist/types/router/segment-resolution.d.ts +1 -2
  46. package/dist/types/router/segment-wrappers.d.ts +11 -48
  47. package/dist/types/router/telemetry.d.ts +2 -0
  48. package/dist/types/router/types.d.ts +10 -0
  49. package/dist/types/rsc/full-payload.d.ts +2 -2
  50. package/dist/types/rsc/handler-context.d.ts +6 -6
  51. package/dist/types/rsc/json-route-result.d.ts +5 -9
  52. package/dist/types/rsc/request-stages.d.ts +203 -0
  53. package/dist/types/rsc/response-cache-serve.d.ts +7 -12
  54. package/dist/types/rsc/response-route-handler.d.ts +2 -2
  55. package/dist/types/rsc/routine-plan.d.ts +1 -1
  56. package/dist/types/rsc/server-action.d.ts +2 -2
  57. package/dist/types/rsc/shell-capture-constants.d.ts +1 -1
  58. package/dist/types/rsc/shell-capture.d.ts +132 -15
  59. package/dist/types/rsc/shell-serve.d.ts +37 -12
  60. package/dist/types/server/context.d.ts +9 -8
  61. package/dist/types/server/handle-store.d.ts +16 -0
  62. package/dist/types/server/render-pass.d.ts +72 -0
  63. package/dist/types/server/request-context.d.ts +24 -104
  64. package/dist/types/server/rewrite-trail.d.ts +2 -2
  65. package/dist/types/testing/dispatch.d.ts +35 -18
  66. package/dist/types/types/cache-types.d.ts +6 -3
  67. package/dist/types/types/error-types.d.ts +9 -1
  68. package/dist/types/types/handler-context.d.ts +9 -1
  69. package/dist/types/types/segments.d.ts +1 -1
  70. package/dist/types/vite/discovery/build-discovery-phase.d.ts +40 -0
  71. package/dist/types/vite/discovery/build-env.d.ts +22 -0
  72. package/dist/types/vite/discovery/bundle-scan-phase.d.ts +12 -0
  73. package/dist/types/vite/discovery/dev-prerender-cache.d.ts +3 -2
  74. package/dist/types/vite/discovery/dev-server-phase.d.ts +26 -0
  75. package/dist/types/vite/discovery/discovery-errors.d.ts +1 -1
  76. package/dist/types/vite/discovery/state.d.ts +12 -0
  77. package/dist/types/vite/plugins/version-plugin.d.ts +1 -1
  78. package/dist/types/vite/plugins/virtual-entries.d.ts +1 -1
  79. package/dist/types/vite/router-discovery.d.ts +8 -47
  80. package/dist/types/vite/temp-rsc-server.d.ts +39 -0
  81. package/dist/types/vite/utils/prerender-utils.d.ts +9 -0
  82. package/dist/types/wire-params.d.ts +34 -0
  83. package/dist/vite/index.js +3809 -3710
  84. package/package.json +1 -1
  85. package/skills/cache-guide/SKILL.md +8 -5
  86. package/skills/caching/SKILL.md +37 -18
  87. package/skills/document-cache/SKILL.md +13 -1
  88. package/skills/handler-use/SKILL.md +1 -1
  89. package/skills/intercept/SKILL.md +17 -7
  90. package/skills/middleware/SKILL.md +18 -0
  91. package/skills/ppr/SKILL.md +18 -3
  92. package/skills/prerender/SKILL.md +39 -15
  93. package/skills/rango/SKILL.md +5 -1
  94. package/skills/server-actions/SKILL.md +8 -1
  95. package/skills/testing/response-routes.md +6 -4
  96. package/skills/use-cache/SKILL.md +46 -8
  97. package/src/__internal.ts +7 -1
  98. package/src/browser/connection-warmup.ts +3 -1
  99. package/src/browser/event-controller.ts +5 -3
  100. package/src/browser/history-state.ts +6 -12
  101. package/src/browser/navigation-bridge.ts +14 -13
  102. package/src/browser/navigation-client.ts +18 -25
  103. package/src/browser/navigation-store.ts +25 -27
  104. package/src/browser/navigation-transaction.ts +4 -1
  105. package/src/browser/prefetch/cache.ts +2 -1
  106. package/src/browser/prefetch/fetch.ts +8 -16
  107. package/src/browser/prefetch/queue.ts +4 -4
  108. package/src/browser/react/NavigationProvider.tsx +2 -1
  109. package/src/browser/react/filter-segment-order.ts +2 -2
  110. package/src/browser/rsc-router.tsx +1 -0
  111. package/src/browser/segment-reconciler.ts +66 -53
  112. package/src/browser/server-action-bridge.ts +50 -57
  113. package/src/browser/types.ts +2 -1
  114. package/src/browser/wire-protocol.ts +41 -0
  115. package/src/cache/cache-key-utils.ts +11 -5
  116. package/src/cache/cache-runtime.ts +110 -50
  117. package/src/cache/cache-scope.ts +110 -64
  118. package/src/cache/cf/cf-cache-constants.ts +2 -2
  119. package/src/cache/cf/cf-cache-store.ts +486 -874
  120. package/src/cache/cf/cf-kv-utils.ts +1 -1
  121. package/src/cache/document-cache.ts +34 -13
  122. package/src/cache/handle-snapshot.ts +19 -7
  123. package/src/cache/segment-codec.ts +55 -0
  124. package/src/cache/shell-snapshot.ts +2 -2
  125. package/src/cache/tag-invalidation.ts +21 -2
  126. package/src/cache/taint.ts +5 -3
  127. package/src/cache/types.ts +7 -3
  128. package/src/cache/vercel/vercel-cache-store.ts +243 -310
  129. package/src/handles/pushed-by.ts +1 -1
  130. package/src/prefetch-markers.ts +5 -16
  131. package/src/prerender/store.ts +76 -0
  132. package/src/prerender/warm-request.ts +8 -4
  133. package/src/prerender.ts +2 -2
  134. package/src/route-name.ts +8 -0
  135. package/src/router/error-handling.ts +4 -4
  136. package/src/router/instrument.ts +4 -3
  137. package/src/router/intercept-resolution.ts +77 -75
  138. package/src/router/loader-resolution.ts +5 -4
  139. package/src/router/match-api.ts +4 -5
  140. package/src/router/match-context.ts +20 -12
  141. package/src/router/match-handlers.ts +8 -20
  142. package/src/router/match-middleware/background-revalidation.ts +41 -53
  143. package/src/router/match-middleware/cache-lookup.ts +675 -726
  144. package/src/router/match-middleware/cache-store.ts +4 -8
  145. package/src/router/match-middleware/intercept-resolution.ts +3 -23
  146. package/src/router/match-middleware/segment-resolution.ts +34 -61
  147. package/src/router/middleware.ts +69 -11
  148. package/src/router/navigation-snapshot.ts +4 -4
  149. package/src/router/prerender-match.ts +100 -44
  150. package/src/router/preview-match.ts +6 -41
  151. package/src/router/request-classification.ts +13 -7
  152. package/src/router/route-snapshot.ts +2 -5
  153. package/src/router/router-context.ts +10 -95
  154. package/src/router/router-interfaces.ts +8 -14
  155. package/src/router/segment-resolution/loader-cache.ts +14 -9
  156. package/src/router/segment-resolution/loader-mask.ts +5 -5
  157. package/src/router/segment-resolution/prefetch-deferral.ts +30 -27
  158. package/src/router/segment-resolution/resolution-pass.ts +137 -0
  159. package/src/router/segment-resolution/revalidation.ts +897 -776
  160. package/src/router/segment-resolution.ts +4 -13
  161. package/src/router/segment-wrappers.ts +51 -269
  162. package/src/router/telemetry.ts +5 -0
  163. package/src/router/types.ts +10 -0
  164. package/src/router.ts +12 -13
  165. package/src/rsc/full-payload.ts +6 -5
  166. package/src/rsc/handler-context.ts +8 -14
  167. package/src/rsc/handler.ts +126 -507
  168. package/src/rsc/json-route-result.ts +5 -9
  169. package/src/rsc/loader-fetch.ts +6 -5
  170. package/src/rsc/progressive-enhancement.ts +5 -0
  171. package/src/rsc/request-stages.ts +757 -0
  172. package/src/rsc/response-cache-serve.ts +10 -14
  173. package/src/rsc/response-route-handler.ts +13 -5
  174. package/src/rsc/rewrite-passes.ts +2 -1
  175. package/src/rsc/routine-plan.ts +1 -1
  176. package/src/rsc/rsc-rendering.ts +164 -349
  177. package/src/rsc/server-action.ts +87 -113
  178. package/src/rsc/shell-capture-constants.ts +1 -1
  179. package/src/rsc/shell-capture.ts +212 -169
  180. package/src/rsc/shell-serve.ts +121 -18
  181. package/src/rsc/ssr-setup.ts +5 -4
  182. package/src/segment-system.tsx +3 -3
  183. package/src/server/context.ts +22 -25
  184. package/src/server/handle-store.ts +55 -0
  185. package/src/server/render-pass.ts +291 -0
  186. package/src/server/request-context.ts +26 -115
  187. package/src/server/rewrite-trail.ts +6 -4
  188. package/src/ssr/index.tsx +1 -1
  189. package/src/testing/dispatch.ts +223 -710
  190. package/src/testing/e2e/page-helpers.ts +2 -2
  191. package/src/testing/serve-shell-request.ts +23 -36
  192. package/src/types/cache-types.ts +6 -3
  193. package/src/types/error-types.ts +9 -1
  194. package/src/types/handler-context.ts +12 -1
  195. package/src/types/segments.ts +1 -1
  196. package/src/vite/discovery/build-discovery-phase.ts +204 -0
  197. package/src/vite/discovery/build-env.ts +148 -0
  198. package/src/vite/discovery/bundle-scan-phase.ts +128 -0
  199. package/src/vite/discovery/dev-prerender-cache.ts +8 -3
  200. package/src/vite/discovery/dev-server-phase.ts +1776 -0
  201. package/src/vite/discovery/discover-routers.ts +1 -1
  202. package/src/vite/discovery/discovery-errors.ts +1 -1
  203. package/src/vite/discovery/prerender-collection.ts +24 -39
  204. package/src/vite/discovery/state.ts +15 -0
  205. package/src/vite/plugins/version-plugin.ts +1 -1
  206. package/src/vite/plugins/virtual-entries.ts +1 -1
  207. package/src/vite/router-discovery.ts +29 -2428
  208. package/src/vite/temp-rsc-server.ts +223 -0
  209. package/src/vite/utils/prerender-utils.ts +47 -0
  210. package/src/wire-params.ts +35 -0
  211. package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
  212. package/src/router/segment-resolution/fresh.ts +0 -945
@@ -4,9 +4,9 @@
4
4
  * Capture does NOT flow through the HTTP middleware pipeline. The integrated PPR
5
5
  * serve path (rsc-rendering.ts + shell-serve.ts) builds a ShellCaptureDescriptor
6
6
  * from the route's `ppr` path option after the served response is built and calls
7
- * scheduleShellCapture. The capture then runs as a background task that re-derives
7
+ * planShellCapture with it (ShellCaptureInput). The capture then runs as a background task that re-derives
8
8
  * the page via `ctx.router.match()` under its OWN derived request context — fresh
9
- * handle store, `_shellCaptureRun: true` so live-lane loaders mask (loader-mask.ts)
9
+ * handle store, `_shellCaptureState.run` so live-lane loaders mask (loader-mask.ts)
10
10
  * and postpone at their loading() or inline <Suspense> boundary. The match is
11
11
  * MIXED-CHAIN: cache()'d segments replay from ring 3, uncached segments execute
12
12
  * their handlers. The record-first step (settleCaptureRecord) waits for the
@@ -20,7 +20,7 @@
20
20
  */
21
21
  import { type MatchResult } from "../types.js";
22
22
  import { type ShellCaptureRefusal } from "./shell-capture-constants.js";
23
- import { type RequestContext, type RouteRecordWindow } from "../server/request-context.js";
23
+ import { type RequestContext } from "../server/request-context.js";
24
24
  import { type HandleStore } from "../server/handle-store.js";
25
25
  import type { SegmentCacheStore } from "../cache/types.js";
26
26
  import type { HandlerContext } from "./handler-context.js";
@@ -128,7 +128,7 @@ export interface ShellCaptureDebugEvent {
128
128
  * - skip-stored: a capture for the key stored after the scheduling request
129
129
  * read the store and missed (ShellCaptureDescriptor.storedSeqAtRead), so
130
130
  * the shell that request missed exists now
131
- * - skip-in-flight: scheduleShellCapture found a capture already running for
131
+ * - skip-in-flight: planShellCapture found a capture already running for
132
132
  * the key (stampede guard) and scheduled nothing
133
133
  * - skip-backoff: the key is inside its refused-capture backoff window and
134
134
  * the capture was not attempted
@@ -268,7 +268,7 @@ export declare function gateFlightForCapture(source: ReadableStream<Uint8Array>)
268
268
  * The background shell-capture descriptor: everything the capture task needs to
269
269
  * store the shell. Built by the integrated PPR serve path (rsc-rendering.ts) from
270
270
  * the route's `ppr` path option (`PartialPrerenderProps`) and the app-level cache
271
- * store, and passed to scheduleShellCapture directly — it is NOT threaded through
271
+ * store, and passed to planShellCapture in its input — it is NOT threaded through
272
272
  * the request context. `tags` carries the route's OPERATIONAL `ppr.tags`; the
273
273
  * capture UNIONS them with the shell's own auto-collected (non-loader) request
274
274
  * tags from its derived render (the collected set stays authoritative). That
@@ -336,7 +336,7 @@ export interface ShellCaptureDescriptor {
336
336
  /**
337
337
  * Set for a shell keyed by the visitor's URL (`rewrite(...).shell("visitor")`,
338
338
  * visitorShellKey): the capture renders the visitor's location
339
- * (`RequestContext._shellCaptureForVisitor`) and stores it as
339
+ * (`ShellCaptureState.forVisitor`) and stores it as
340
340
  * ShellCacheEntry.pathname.
341
341
  */
342
342
  pathname?: string;
@@ -351,7 +351,7 @@ export interface ShellCaptureDescriptor {
351
351
  /**
352
352
  * A `router.prerender()` warm's capture (rsc-rendering.ts shellServePlan):
353
353
  * one explicit call that must store, so the guards that shed a herd of
354
- * visitors do not apply to it. scheduleShellCapture skips the in-flight
354
+ * visitors do not apply to it. planShellCapture skips the in-flight
355
355
  * dedup and the refused-capture backoff, and attemptCapture waits longer on
356
356
  * the write barrier. Every correctness guard, the inert-store skip and the
357
357
  * queue limits still decide.
@@ -360,6 +360,21 @@ export interface ShellCaptureDescriptor {
360
360
  }
361
361
  /** The latest stored capture's sequence number for `key` in this isolate, or 0. */
362
362
  export declare function lastStoredCaptureSeq(key: string): number;
363
+ /** One shell capture: the request it re-renders and what it stores. */
364
+ export interface ShellCaptureInput {
365
+ ctx: HandlerContext<any>;
366
+ request: Request;
367
+ env: any;
368
+ url: URL;
369
+ reqCtx: RequestContext<any>;
370
+ /**
371
+ * The SSR module for the capture's own request and URL, called once the
372
+ * capture leaves the queue. A document passes the module it already
373
+ * resolved, returned as is, so the capture awaits only a pending one.
374
+ */
375
+ ssr: (request: Request, url: URL) => SSRModule | null | Promise<SSRModule | null>;
376
+ descriptor: ShellCaptureDescriptor;
377
+ }
363
378
  /**
364
379
  * Schedule the background shell capture for a served document. Stampede-guarded:
365
380
  * one capture per key per isolate. Runs via runBackground (waitUntil on workerd,
@@ -367,15 +382,13 @@ export declare function lastStoredCaptureSeq(key: string): number;
367
382
  * error is routed through reportCacheError — capture is best-effort; a failure just
368
383
  * means the next request recaptures.
369
384
  *
370
- * Eligibility (nonce/partial/status/strategy) is decided by the caller. An SSR
371
- * module loader may be passed for cold partial requests; it runs only after the
372
- * capture enters the guarded background queue, never on response latency.
385
+ * Eligibility (nonce/partial/status/strategy) is decided by the caller.
373
386
  */
374
- export declare function scheduleShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule | ((request: Request, url: URL) => Promise<SSRModule | null>), descriptor: ShellCaptureDescriptor): void;
387
+ export declare function planShellCapture(input: ShellCaptureInput): void;
375
388
  /**
376
389
  * The ttl/swr a shell is stored with: the route's ppr policy, capped by the
377
390
  * route cache() records the capture replayed or wrote
378
- * (RequestContext._routeRecordWindow). A HIT replays the capture's handler
391
+ * (ShellCaptureState.routeRecordWindow). A HIT replays the capture's handler
379
392
  * output, while a client navigation reads the route's cache() tier first, so
380
393
  * a shell that outlived its record would show a document request other
381
394
  * handler output than a navigation of the same URL. Freshness and total
@@ -456,9 +469,9 @@ type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "write
456
469
  * several HTTP requests before a capture stuck. We retry ONLY on `no-shell`
457
470
  * that did not run out of ppr.captureTimeout (CaptureAttemptStats.noShellCause),
458
471
  * and on `expired`; a genuine render error is NOT retried — it propagates to
459
- * scheduleShellCapture's reportCacheError. See docs/design/ppr-shell-resume.md.
472
+ * planShellCapture's reportCacheError. See docs/design/ppr-shell-resume.md.
460
473
  *
461
- * `request` and `url` are the capture's own identity (scheduleShellCapture
474
+ * `request` and `url` are the capture's own identity (planShellCapture
462
475
  * strips a navigation-only capture's transport parameters). `retryDelayMs` is
463
476
  * a parameter (defaulting to the module const) so unit tests can drive the
464
477
  * retry without a real 400ms wall-clock wait.
@@ -511,9 +524,113 @@ export type CaptureRecordOutcome = {
511
524
  * a HIT restores, and its handle encode has its own 5s timeout that must
512
525
  * never be the one that fires); then the capture's onResponse callbacks fire
513
526
  * with a synthetic 200 (the implicit doc scope's cacheRoute, an explicit
514
- * scope's own write), and the deferred writes settle.
527
+ * scope's own write), and the deferred writes settle. A match holding an
528
+ * error or notFound boundary throws before the callbacks fire.
515
529
  */
516
530
  export declare function settleCaptureRecord(match: MatchResult, derivation: CaptureContextDerivation, capture: Pick<ShellCaptureDescriptor, "key">, deadline: number): Promise<CaptureRecordOutcome>;
531
+ /**
532
+ * @internal The freshness window of a route cache() record, as ms
533
+ * timestamps: fresh until `freshUntil` (its `expiresAt`), stale until
534
+ * `staleUntil` (plus its scope's swr). `ttl`, `swr` and `written` describe
535
+ * the record that sets `staleUntil`: its cache() config, and whether this
536
+ * capture wrote it (cacheRoute) rather than read it.
537
+ */
538
+ export interface RouteRecordWindow {
539
+ freshUntil: number;
540
+ staleUntil: number;
541
+ ttl: number;
542
+ swr: number;
543
+ written: boolean;
544
+ }
545
+ /**
546
+ * @internal What a shell capture's render records about itself, on its
547
+ * derived request context as `_shellCaptureState`.
548
+ * RENDER_PASS_FIELDS["shell-capture"] (server/render-pass.ts) creates it with
549
+ * every field present, so it keeps one shape while the capture writes it. A
550
+ * background re-render the capture starts has none: it writes a route
551
+ * record, under cache() rules (RENDER_PASS_FIELDS["background-revalidation"]).
552
+ */
553
+ export interface ShellCaptureState {
554
+ /**
555
+ * @internal PPR shell-capture ACTIVE marker. True ONLY inside the background
556
+ * capture task's derived request context (built by shell-capture.ts). This is
557
+ * the switch every capture-specific behavior reads: loader masking
558
+ * (loader-mask.ts isShellCaptureActive / resolveOwnerLoaders) and the
559
+ * identity-read capture guard (server/context.ts guardIdentityRead). The
560
+ * foreground render never sets it, so the
561
+ * served response is byte-identical to axis 1. The capture descriptor itself
562
+ * (key/ttl/swr/tags/store) is NOT threaded through the request context — the
563
+ * integrated PPR serve path (rsc/shell-serve.ts + rsc-rendering.ts) builds it
564
+ * locally and passes it to planShellCapture in its input.
565
+ */
566
+ readonly run: true;
567
+ /**
568
+ * @internal Set beside `run` when the shell is keyed by the
569
+ * visitor's URL (`rewrite(...).shell("visitor")`): the capture renders the
570
+ * visitor's location and `ctx.rewrittenFrom`; the theme stays the default.
571
+ */
572
+ forVisitor: boolean | undefined;
573
+ /**
574
+ * @internal Bake-lane loader containers collected DURING a shell capture:
575
+ * segment-key -> the loader's (pre-wrap) result promise. Populated by
576
+ * resolveLoaderData for bake-lane loaders (lane rule: see its JSDoc in
577
+ * loader-cache.ts). Drained by captureAndStoreShell after the shell
578
+ * quiesces: settled containers are promise-elided, Flight-serialized, and
579
+ * pinned into the snapshot's loader family; a REJECTED container refuses
580
+ * the capture (error UI must never bake into the shared shell).
581
+ */
582
+ loaderRecords: Map<string, Promise<unknown>>;
583
+ /**
584
+ * @internal Set when a loader pushed a
585
+ * value the record cannot keep (masked nested promises, a pushed promise
586
+ * that settled to one, a live-lane loader's push, or a push outside a
587
+ * loader body): the loader records then carry `runs: 1`, so a HIT still
588
+ * runs their bodies for those pushes.
589
+ */
590
+ unrecordedLoaderPush: true | undefined;
591
+ /**
592
+ * @internal The lane of each loader the capture's matched route registers
593
+ * (loader-cache.ts routeLoaderLanes), set by createMatchContextForFull
594
+ * before any loader runs. The capture's push funnel credits a push made
595
+ * under a live-lane loader's body, at any depth, to that loader
596
+ * (shell-capture.ts deriveShellCaptureContext).
597
+ */
598
+ loaderLanes: ReadonlyMap<string, "live" | "bake"> | undefined;
599
+ /**
600
+ * @internal Set by the capture guard (server/context.ts
601
+ * guardIdentityRead) when it throws DURING a capture render: the read
602
+ * ("cookies()", "headers()", `ctx.get() for a non-cacheable variable`,
603
+ * "ctx.theme") and the fix the
604
+ * refusal warning gives for it. Load-bearing for the
605
+ * bake lane: a guard throw inside an executing loader is swallowed by
606
+ * wrapLoaderPromise into per-loader error UI, which would otherwise bake
607
+ * silently into the shared shell — the capture checks this flag after the
608
+ * render and refuses instead. Deterministic, so the capture does not retry.
609
+ */
610
+ guardTripped: {
611
+ surface: string;
612
+ fix: string;
613
+ } | undefined;
614
+ /**
615
+ * @internal The loader $$id whose BODY was executing when the capture guard
616
+ * tripped (read off the loader-body ALS scope at trip time), or undefined
617
+ * when the read came from handler/render code. Only used to make the
618
+ * once-per-key refusal warning name the real source — the old text
619
+ * hardcoded "a bake-lane loader", which misattributed handler-land reads
620
+ * and sent users debugging the wrong lane (issue #672, secondary).
621
+ */
622
+ guardTrippedLoaderId: string | undefined;
623
+ /**
624
+ * @internal The freshness window of the route cache() records this
625
+ * capture read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
626
+ * timestamps: `freshUntil` is the record's `expiresAt`, `staleUntil` adds
627
+ * its scope's swr. The narrowest record wins. A shell capture caps its
628
+ * entry's ttl and ttl+swr to it (shell-capture.ts capShellWindow), so a
629
+ * shell is never fresher, or served longer, than the route cache() entry
630
+ * it replayed or wrote.
631
+ */
632
+ routeRecordWindow: RouteRecordWindow | undefined;
633
+ }
517
634
  /**
518
635
  * The derived capture context and its fresh (mask-funneled) handle store,
519
636
  * shared by BOTH shell producers: the runtime background capture
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import { type EntryData } from "../server/context.js";
19
19
  import type { DocumentShellCacheEntry, ShellCacheEntry, ShellDocumentRead, ShellEntryHead, ShellReadStats, ShellSnapshotFailure, ShellSnapshotRecord, SegmentCacheStore } from "../cache/types.js";
20
+ import type { MetricsStore } from "../server/context.js";
20
21
  export { PPR_REPLAY_STATUS_HEADER, SHELL_STATUS_HEADER, buildShellKey, navigationShellKey, partitionShellKey, shellSearchSeed, } from "./shell-capture-constants.js";
21
22
  /**
22
23
  * Default shell ttl (seconds) for `ppr: true` and for a PartialPrerenderProps
@@ -76,18 +77,13 @@ export declare function normalizeCaptureTimeout(value: unknown): number | undefi
76
77
  */
77
78
  export declare function resolvePprConfig(entry: EntryData | undefined | null): ResolvedPprConfig | null;
78
79
  /**
79
- * The forced-MISS query marker. A document HIT that cannot finish its tail
80
- * reloads the page with it (shellReloadScript); the serve gate renders a
81
- * request carrying it on axis 1, with no shell read and no capture, so the
82
- * reload can never be a HIT that degrades again. The handler drops it from
83
- * the request on entry (withoutShellMissMarker) and keeps only the flag
84
- * (RequestContext._shellForcedMiss), so nothing else sees it.
85
- */
86
- export declare const SHELL_MISS_PARAM: string;
87
- /**
88
- * The request without the forced-MISS marker, or undefined when it carries
89
- * none. The handler calls it before anything reads the request: left in, the
90
- * marker reached `ctx.request.url`, `originalUrl`, middleware, and the SSR
80
+ * The request without the forced-MISS marker (`WIRE.shellMiss`), or
81
+ * undefined when it carries none. A document HIT that cannot finish its tail
82
+ * reloads the page with the marker (shellReloadScript); the serve gate
83
+ * renders a request carrying it on axis 1, with no shell read and no
84
+ * capture, so the reload can never be a HIT that degrades again. The handler
85
+ * calls this on entry, before anything reads the request, and keeps only the
86
+ * flag (RequestContext._shellForcedMiss): left in, the marker reached `ctx.request.url`, `originalUrl`, middleware, and the SSR
91
87
  * search seed (so `useSearchParams` rendered it), and a `"use cache"` key
92
88
  * built from the request URL was never read again. GET and HEAD only: the
93
89
  * reload is a navigation, and a request with a body cannot be re-created
@@ -165,6 +161,35 @@ export interface ShellDocument {
165
161
  */
166
162
  export declare function openShellDocument(entry: ShellCacheEntry): ShellDocument | null;
167
163
  export declare function openShellDocument(entry: ShellEntryHead, read: Pick<ShellDocumentRead, "prelude" | "snapshot" | "snapshotFailure" | "stats">): ShellDocument | null;
164
+ /**
165
+ * A document serve's store read: a getShell entry, or a prelude-first read
166
+ * (readShellDocument) whose entry is the head and whose snapshot arrives on
167
+ * its own promise.
168
+ */
169
+ export type ShellRead = {
170
+ entry: ShellCacheEntry;
171
+ shouldRevalidate?: boolean;
172
+ read?: undefined;
173
+ } | {
174
+ entry: ShellEntryHead;
175
+ shouldRevalidate?: boolean;
176
+ read: ShellDocumentRead;
177
+ };
178
+ /**
179
+ * The document serve's shell read from `source`, the app cache store, that
180
+ * degrades to null on failure (axis 1 MISS, never a 500) and records the raw
181
+ * `ppr:shell-read` outcome (pre-validity-gates, so a version-mismatch
182
+ * lifecycle miss stays distinguishable from a store miss). A store with a
183
+ * prelude-first read (readShellDocument) resolves before the snapshot is
184
+ * read, so the HIT commits without waiting for it. A build shell is read by
185
+ * shell-build-manifest.ts lookupBuildShell, which imports this module.
186
+ */
187
+ export declare function readShell(source: SegmentCacheStore & {
188
+ getShell: NonNullable<SegmentCacheStore["getShell"]>;
189
+ }, key: string, opts: {
190
+ tagHints?: readonly string[];
191
+ metrics?: MetricsStore;
192
+ }): Promise<ShellRead | null>;
168
193
  /**
169
194
  * Prelude enqueue granularity. A streaming compressor in front of the worker
170
195
  * emits its first byte only after compressing the whole write it was handed:
@@ -121,7 +121,7 @@ export type LoaderEntry = {
121
121
  * thrown notFound()/redirect() deterministically precede first flush.
122
122
  * Resolved at DSL-evaluation time from ctx.isSSR — entries are cached
123
123
  * per-isSSR (router/manifest.ts cache key), so the flag is already
124
- * request-mode-correct when resolveLoaders (fresh.ts) reads it and never
124
+ * request-mode-correct when resolveOwnerLoaders reads it and never
125
125
  * appears on navigation-lane entries. Set by documentModeLoader, which
126
126
  * getDocumentModeEntry also applies to a lazy include's captured ancestors.
127
127
  */
@@ -566,7 +566,7 @@ export interface IdentityReadWording {
566
566
  * only observed; it is never rendered. A cached body, loader body or
567
567
  * funnel they start is guarded again.
568
568
  * 1. A PPR shell capture (`ctx` is the capture's derived context,
569
- * `_shellCaptureRun`) trips first: the capture context is flagged (so a
569
+ * `_shellCaptureState`) trips first: the capture context is flagged (so a
570
570
  * caught throw still refuses the capture) and the read throws. The shell is
571
571
  * shared per host+URL, and every HIT replays what the capture read. There
572
572
  * is no loader-body exemption here: a bake-lane loader and a loader a
@@ -737,12 +737,13 @@ export declare function latchPprHeaderScopeForEntries(entries: EntryData[], rout
737
737
  * ONLY the ppr (shell) axis is dropped — dynamic() does NOT opt off the CACHE
738
738
  * axis. Two cases:
739
739
  * - Pure ppr funnel (no cache() boundary): clear the latch → writes re-permit.
740
- * - ppr route nested under a cache() boundary: fresh.ts latches "ppr" at the
741
- * funnel top (first-wins), which MASKS the positional cache() latch, but the
742
- * handler still runs inside the cache scope (`insideCacheScope`). A cache()
743
- * HIT skips that handler, so the write is still non-deterministic — UNMASK to
744
- * "cache" instead of clearing, so the guard keeps throwing (accurate cache()
745
- * wording). This is why the check keys off `insideCacheScope`, not just kind.
740
+ * - ppr route nested under a cache() boundary: resolveAllSegments
741
+ * latches "ppr" at the funnel top (first-wins), which MASKS the positional
742
+ * cache() latch, but the handler still runs inside the cache scope
743
+ * (`insideCacheScope`). A cache() HIT skips that handler, so the write is
744
+ * still non-deterministic — UNMASK to "cache" instead of clearing, so the
745
+ * guard keeps throwing (accurate cache() wording). This is why the check keys
746
+ * off `insideCacheScope`, not just kind.
746
747
  *
747
748
  * A subsequent cache() entered AFTER dynamic() on a pure-ppr funnel re-latches
748
749
  * "cache" via latchCachedHeaderScope's `!store.cachedHeaderScope` guard (the
@@ -169,6 +169,22 @@ export interface HandleStore {
169
169
  * array, in order. Without placeholders it is a plain replay.
170
170
  */
171
171
  replacePlaceholders(loaderIds: readonly string[], deliver: () => void): void;
172
+ /**
173
+ * A cache() or Prerender() HIT restored its stored values into
174
+ * `segmentIds` (cache-lookup.ts serveStoredSegments). The MISS ran each
175
+ * segment's handler after it started the segment's loaders, so a push into
176
+ * a restored array goes in front of the stored values until
177
+ * releaseRecordedValues: a loader's push lands where the same loader timing
178
+ * puts it on the MISS.
179
+ */
180
+ holdRecordedValues(segmentIds: readonly string[]): void;
181
+ /**
182
+ * The HIT's loader walk reached the place where the MISS ran
183
+ * `segmentId`'s handler (revalidation.ts resolveLoadersOnly,
184
+ * intercept-resolution.ts resolveInterceptLoadersOnly): later pushes
185
+ * follow the record's values.
186
+ */
187
+ releaseRecordedValues(segmentId: string): void;
172
188
  /**
173
189
  * Get all collected handle data after all handlers have settled.
174
190
  * Waits for `settled` (handler lane), then returns the data at that point.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Derived render passes over a request past its middleware (PPR shell
3
+ * capture, PPR HIT tail, background re-render, document cache re-run), each
4
+ * `Object.create(base)`.
5
+ * A field missing from a RENDER_PASS_FIELDS row reads the foreground
6
+ * request's value (#684). derived-context-shape.rsc-test.tsx pins each row's
7
+ * own keys.
8
+ */
9
+ import type { RecordingShellStore } from "../cache/shell-snapshot.js";
10
+ import type { HandleStore } from "./handle-store.js";
11
+ import { type RequestContext } from "./request-context.js";
12
+ type ShellImplicitCache = NonNullable<RequestContext["_shellImplicitCache"]>;
13
+ /** _handleStore, readonly on RequestContext, is written by the rows. */
14
+ type PassUnderConstruction = RequestContext<any> & {
15
+ _handleStore: HandleStore;
16
+ };
17
+ /** What each purpose's caller builds for its row. */
18
+ export interface RenderPassInit {
19
+ "shell-capture": {
20
+ handleStore: HandleStore;
21
+ /** A navigation-only capture renders this URL instead of the request's. */
22
+ identity: {
23
+ request: Request;
24
+ url: URL;
25
+ } | undefined;
26
+ /** Only with a cache store on the request. */
27
+ recording: {
28
+ store: RecordingShellStore;
29
+ implicitCache: ShellImplicitCache;
30
+ } | undefined;
31
+ };
32
+ "ppr-tail": {
33
+ /** The request's store, shared: the tail's handles are this response's. */
34
+ handleStore: HandleStore;
35
+ loaderSeed: RequestContext["_shellLoaderSeed"];
36
+ implicitCache: ShellImplicitCache;
37
+ };
38
+ "background-revalidation": {
39
+ handleStore: HandleStore;
40
+ /** Throwaway: the pass's response writes land here and are dropped. */
41
+ sink: RequestContext<any>;
42
+ };
43
+ "document-revalidation": {
44
+ /** The request's: the stale HIT pushed nothing into it. */
45
+ handleStore: HandleStore;
46
+ /**
47
+ * Holds the re-run's response writes, which make the response the
48
+ * document cache stores; starts from the request's response stub.
49
+ */
50
+ sink: RequestContext<any>;
51
+ };
52
+ }
53
+ export type RenderPurpose = keyof RenderPassInit;
54
+ interface PassFieldPolicy<I> {
55
+ /** "own": wireRenderBarrier(pass, init.handleStore) before `own` runs. */
56
+ readonly renderBarrier: "own" | "inherited";
57
+ /**
58
+ * Named stores, not one Object.assign: on Node 24 an Object.assign that
59
+ * takes the object to 20 own properties leaves it in V8 dictionary mode
60
+ * (#1109).
61
+ */
62
+ readonly own: (pass: PassUnderConstruction, init: I, base: RequestContext<any>) => void;
63
+ }
64
+ export declare const RENDER_PASS_FIELDS: {
65
+ readonly [P in RenderPurpose]: PassFieldPolicy<RenderPassInit[P]>;
66
+ };
67
+ /**
68
+ * `Object.create(base)` with RENDER_PASS_FIELDS[purpose]'s own fields. The only
69
+ * place a request context is derived (tools/check-internals.mjs).
70
+ */
71
+ export declare function deriveRenderPass<P extends RenderPurpose, TEnv>(base: RequestContext<TEnv>, purpose: P, init: RenderPassInit[P]): RequestContext<TEnv>;
72
+ export {};
@@ -29,6 +29,7 @@ import type { RenderMode, RenderPhase } from "../router/timeout.js";
29
29
  import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
30
30
  import type { RoutineTrace } from "../rsc/routine-plan.js";
31
31
  import type { ActionContinuation } from "../rsc/server-action.js";
32
+ import type { ShellCaptureState } from "../rsc/shell-capture.js";
32
33
  import type { FormActionOutcome } from "../rsc/progressive-enhancement.js";
33
34
  import { type ExecutionStart } from "../cache/invalidation-order.js";
34
35
  export interface RenderForegroundCursor {
@@ -182,8 +183,8 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
182
183
  method: string;
183
184
  /**
184
185
  * @internal Handle store for tracking handle data across segments.
185
- * Readonly: a background render that needs its own store derives a context
186
- * (rerenderAndCacheRoute, shell-capture.ts) instead of swapping this field,
186
+ * Readonly: a render that needs its own store derives a render pass
187
+ * (deriveRenderPass, server/render-pass.ts) instead of swapping this field,
187
188
  * which the foreground still reads while it produces the page.
188
189
  */
189
190
  readonly _handleStore: HandleStore;
@@ -233,52 +234,13 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
233
234
  */
234
235
  _searchParamsFilter?: import("../cache/search-params-filter.js").SearchParamsFilter;
235
236
  /**
236
- * @internal PPR shell-capture ACTIVE marker. True ONLY inside the background
237
- * capture task's derived request context (built by shell-capture.ts). This is
238
- * the switch every capture-specific behavior reads: loader masking
239
- * (loader-mask.ts isShellCaptureActive / fresh.ts emitStreaming) and the
240
- * identity-read capture guard (server/context.ts guardIdentityRead). The
241
- * foreground render never sets it, so the
242
- * served response is byte-identical to axis 1. The capture descriptor itself
243
- * (key/ttl/swr/tags/store) is NOT threaded through the request context — the
244
- * integrated PPR serve path (rsc/shell-serve.ts + rsc-rendering.ts) builds it
245
- * locally and passes it to scheduleShellCapture directly.
246
- */
247
- _shellCaptureRun?: boolean;
248
- /**
249
- * @internal Set beside `_shellCaptureRun` when the shell is keyed by the
250
- * visitor's URL (`rewrite(...).shell("visitor")`): the capture renders the
251
- * visitor's location and `ctx.rewrittenFrom`; the theme stays the default.
252
- */
253
- _shellCaptureForVisitor?: boolean;
254
- /**
255
- * @internal Bake-lane loader containers collected DURING a shell capture:
256
- * segment-key -> the loader's (pre-wrap) result promise. Populated by
257
- * resolveLoaderData for bake-lane loaders (lane rule: see its JSDoc in
258
- * loader-cache.ts). Drained by captureAndStoreShell after the shell
259
- * quiesces: settled containers are promise-elided, Flight-serialized, and
260
- * pinned into the snapshot's loader family; a REJECTED container refuses
261
- * the capture (error UI must never bake into the shared shell). Own
262
- * property of the capture's derived context only.
263
- */
264
- _shellCaptureLoaderRecords?: Map<string, Promise<unknown>>;
265
- /**
266
- * @internal Set on a capture's derived context when a loader pushed a
267
- * value the record cannot keep (masked nested promises, a pushed promise
268
- * that settled to one, a live-lane loader's push, or a push outside a
269
- * loader body): the loader records then carry `runs: 1`, so a HIT still
270
- * runs their bodies for those pushes.
271
- */
272
- _shellCaptureUnrecordedLoaderPush?: true;
273
- /**
274
- * @internal The lane of each loader the capture's matched route registers
275
- * (loader-cache.ts routeLoaderLanes), set by createMatchContextForFull
276
- * before any loader runs. The capture's push funnel credits a push made
277
- * under a live-lane loader's body, at any depth, to that loader
278
- * (shell-capture.ts deriveShellCaptureContext). Own property of the
279
- * capture's derived context only.
280
- */
281
- _shellCaptureLoaderLanes?: ReadonlyMap<string, "live" | "bake">;
237
+ * @internal A PPR shell capture's own state (rsc/shell-capture.ts
238
+ * ShellCaptureState): created by RENDER_PASS_FIELDS["shell-capture"]
239
+ * (server/render-pass.ts) on the capture's derived context. The foreground
240
+ * render and every background re-render never have one, so
241
+ * `_shellCaptureState?.run` is the capture switch.
242
+ */
243
+ _shellCaptureState?: ShellCaptureState;
282
244
  /**
283
245
  * @internal Record keys resolved for this request (CacheScope
284
246
  * resolveKeyFrom): by the scope's `key()` (one result) or its store's
@@ -295,9 +257,9 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
295
257
  _shellKey?: string;
296
258
  /**
297
259
  * @internal The request carried the forced-MISS reload marker
298
- * (shell-serve.ts SHELL_MISS_PARAM). The handler strips the marker from the
299
- * request on entry and sets this; the shell gate renders the request like a
300
- * cache miss.
260
+ * (`WIRE.shellMiss`). The handler strips the marker from the request on
261
+ * entry (shell-serve.ts withoutShellMissMarker) and sets this; the shell
262
+ * gate renders the request like a cache miss.
301
263
  */
302
264
  _shellForcedMiss?: true;
303
265
  /**
@@ -314,16 +276,6 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
314
276
  * runtime has no AsyncLocalStorage.snapshot.
315
277
  */
316
278
  _runAtRequestEntry?: <T>(fn: () => T) => T;
317
- /**
318
- * @internal The freshness window of the route cache() records this
319
- * request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
320
- * timestamps: `freshUntil` is the record's `expiresAt`, `staleUntil` adds
321
- * its scope's swr. The narrowest record wins. A shell capture caps its
322
- * entry's ttl and ttl+swr to it (shell-capture.ts capShellWindow), so a
323
- * shell is never fresher, or served longer, than the route cache() entry
324
- * it replayed or wrote.
325
- */
326
- _routeRecordWindow?: RouteRecordWindow;
327
279
  /**
328
280
  * @internal Loader-family snapshot seed for a shell HIT's tail render:
329
281
  * loader id -> the capture's elided container (already Flight-deserialized
@@ -445,30 +397,6 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
445
397
  * it as an own property for exactly that reason.
446
398
  */
447
399
  _shellFragmentPayload?: boolean;
448
- /**
449
- * @internal Set by the capture guard (server/context.ts
450
- * guardIdentityRead) when it throws DURING a capture render: the read
451
- * ("cookies()", "headers()", `ctx.get() for a non-cacheable variable`,
452
- * "ctx.theme") and the fix the
453
- * refusal warning gives for it. Load-bearing for the
454
- * bake lane: a guard throw inside an executing loader is swallowed by
455
- * wrapLoaderPromise into per-loader error UI, which would otherwise bake
456
- * silently into the shared shell — the capture checks this flag after the
457
- * render and refuses instead. Deterministic, so the capture does not retry.
458
- */
459
- _shellCaptureGuardTripped?: {
460
- surface: string;
461
- fix: string;
462
- };
463
- /**
464
- * @internal The loader $$id whose BODY was executing when the capture guard
465
- * tripped (read off the loader-body ALS scope at trip time), or undefined
466
- * when the read came from handler/render code. Only used to make the
467
- * once-per-key refusal warning name the real source — the old text
468
- * hardcoded "a bake-lane loader", which misattributed handler-land reads
469
- * and sent users debugging the wrong lane (issue #672, secondary).
470
- */
471
- _shellCaptureGuardTrippedLoaderId?: string;
472
400
  /**
473
401
  * @internal Handler-owned registry of explicit per-scope stores from
474
402
  * cache({ store }). Created once per createRSCHandler() and threaded into
@@ -732,8 +660,8 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
732
660
  * (loader(Def, { ssr: false })): segment resolution awaits these
733
661
  * before returning, so the render barrier cannot resolve until they settle.
734
662
  * rendered() checks this set to fail fast — a flagged loader awaiting the
735
- * barrier is a guaranteed cycle, not a race. Registered by resolveLoaders
736
- * (fresh.ts) before loader kickoff; only ever populated on document renders
663
+ * barrier is a guaranteed cycle, not a race. Registered by resolveOwnerLoaders
664
+ * before loader kickoff; only ever populated on document renders
737
665
  * (the flag is stamped per-isSSR at DSL evaluation).
738
666
  */
739
667
  _awaitBeforeFlushLoaderIds?: Set<string>;
@@ -811,6 +739,12 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
811
739
  * keeping phases that began before the opt-in at their true (non-negative) offset.
812
740
  */
813
741
  _handlerStart?: number;
742
+ /**
743
+ * @internal Handler-level Server-Timing entries (rsc/handler.ts): the
744
+ * bootstrap timings, then the core handler's classify. A stale document
745
+ * cache entry's re-run has its own (render-pass.ts).
746
+ */
747
+ _handlerTiming?: string[];
814
748
  /** @internal Resolved platform phase-span tracing for this request (Cloudflare or OTel) */
815
749
  _tracing?: ResolvedTracing;
816
750
  /** @internal Router basename for this request (used by redirect()) */
@@ -846,27 +780,13 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
846
780
  */
847
781
  _cacheSignal?: import("../router/telemetry.js").CacheSegmentSignal[];
848
782
  }
849
- /**
850
- * @internal The freshness window of a route cache() record, as ms
851
- * timestamps: fresh until `freshUntil` (its `expiresAt`), stale until
852
- * `staleUntil` (plus its scope's swr). `ttl`, `swr` and `written` describe
853
- * the record that sets `staleUntil`: its cache() config, and whether this
854
- * request wrote it (cacheRoute) rather than read it.
855
- */
856
- export interface RouteRecordWindow {
857
- freshUntil: number;
858
- staleUntil: number;
859
- ttl: number;
860
- swr: number;
861
- written: boolean;
862
- }
863
783
  /**
864
784
  * Public view of RequestContext, without internal methods and fields.
865
785
  *
866
786
  * This is the type exported to library consumers. Internal code should
867
787
  * use the full RequestContext interface directly.
868
788
  */
869
- export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellCaptureForVisitor" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_payloadVisitorLocation" | "_locationState" | "_routeName" | "_prevRouteKey" | "_visitorMoved" | "_inActionRevalidation" | "_actionRan" | "_reportedErrors" | "_printedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
789
+ export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureState" | "_shellImplicitCache" | "_shellLoaderSeed" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_shellFragmentPayload" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_payloadVisitorLocation" | "_locationState" | "_routeName" | "_prevRouteKey" | "_visitorMoved" | "_inActionRevalidation" | "_actionRan" | "_reportedErrors" | "_printedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_handlerTiming" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
870
790
  /**
871
791
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
872
792
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -1004,8 +924,8 @@ export declare function rebaseRequestContext(ctx: RequestContext<any>, request:
1004
924
  /**
1005
925
  * Wire a fresh render barrier onto `ctx`, closure-bound to THIS ctx and THIS
1006
926
  * handle store. Called by createRequestContext for every fresh context, and by
1007
- * deriveShellCaptureContext (rsc/shell-capture.ts) for the PPR capture's
1008
- * derived context.
927
+ * deriveRenderPass (server/render-pass.ts) for a derived pass whose
928
+ * RENDER_PASS_FIELDS row owns its barrier (the PPR capture and the HIT tail).
1009
929
  *
1010
930
  * The derived-context call is load-bearing (issue #684, plan 009): the capture
1011
931
  * context is `Object.create(reqCtx)`, so without its own wiring every