@rangojs/router 0.18.0 → 0.19.1

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 (244) hide show
  1. package/dist/types/browser/event-controller.d.ts +3 -3
  2. package/dist/types/browser/history-state.d.ts +2 -0
  3. package/dist/types/browser/navigation-transaction.d.ts +20 -2
  4. package/dist/types/browser/partial-update.d.ts +16 -1
  5. package/dist/types/browser/prefetch/cache.d.ts +6 -6
  6. package/dist/types/browser/react/Link.d.ts +19 -9
  7. package/dist/types/browser/react/context.d.ts +2 -2
  8. package/dist/types/browser/react/location-state-shared.d.ts +95 -56
  9. package/dist/types/browser/react/location-state.d.ts +1 -1
  10. package/dist/types/browser/transition-when.d.ts +80 -0
  11. package/dist/types/browser/types.d.ts +104 -9
  12. package/dist/types/build/generate-manifest.d.ts +8 -0
  13. package/dist/types/cache/background-task.d.ts +24 -2
  14. package/dist/types/cache/cache-exec-scope.d.ts +37 -0
  15. package/dist/types/cache/cache-key-utils.d.ts +44 -13
  16. package/dist/types/cache/cache-policy.d.ts +1 -1
  17. package/dist/types/cache/cache-runtime.d.ts +7 -0
  18. package/dist/types/cache/cache-scope.d.ts +117 -35
  19. package/dist/types/cache/cache-tag.d.ts +48 -5
  20. package/dist/types/cache/cf/cf-cache-store.d.ts +55 -44
  21. package/dist/types/cache/cf/cf-shell-frame.d.ts +1 -1
  22. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +0 -15
  23. package/dist/types/cache/document-cache.d.ts +10 -0
  24. package/dist/types/cache/handle-snapshot.d.ts +40 -8
  25. package/dist/types/cache/invalidation-order.d.ts +23 -0
  26. package/dist/types/cache/request-tag-mask.d.ts +54 -0
  27. package/dist/types/cache/shell-snapshot.d.ts +88 -141
  28. package/dist/types/cache/tag-invalidation.d.ts +38 -14
  29. package/dist/types/cache/types.d.ts +68 -61
  30. package/dist/types/cache/vercel/vercel-cache-store.d.ts +23 -16
  31. package/dist/types/client-urls/navigation.d.ts +28 -2
  32. package/dist/types/client-urls/server-projection.d.ts +5 -2
  33. package/dist/types/client-urls/types.d.ts +5 -5
  34. package/dist/types/client.d.ts +1 -1
  35. package/dist/types/index.d.ts +1 -1
  36. package/dist/types/index.rsc.d.ts +1 -1
  37. package/dist/types/route-definition/helpers-types.d.ts +11 -11
  38. package/dist/types/route-name.d.ts +7 -0
  39. package/dist/types/router/error-handling.d.ts +1 -1
  40. package/dist/types/router/intercept-resolution.d.ts +2 -0
  41. package/dist/types/router/match-context.d.ts +5 -0
  42. package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
  43. package/dist/types/router/router-options.d.ts +4 -1
  44. package/dist/types/router/segment-resolution/loader-cache.d.ts +18 -1
  45. package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
  46. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +14 -40
  47. package/dist/types/router/segment-resolution/mask-nested.d.ts +11 -3
  48. package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
  49. package/dist/types/router/transition-when.d.ts +24 -10
  50. package/dist/types/rsc/attach-transition-when.d.ts +18 -0
  51. package/dist/types/rsc/full-payload.d.ts +14 -7
  52. package/dist/types/rsc/response-cache-serve.d.ts +15 -12
  53. package/dist/types/rsc/shell-build-manifest.d.ts +4 -3
  54. package/dist/types/rsc/shell-capture-constants.d.ts +77 -20
  55. package/dist/types/rsc/shell-capture.d.ts +78 -81
  56. package/dist/types/rsc/shell-serve.d.ts +19 -48
  57. package/dist/types/rsc/types.d.ts +2 -0
  58. package/dist/types/segment-system.d.ts +7 -0
  59. package/dist/types/server/context.d.ts +126 -61
  60. package/dist/types/server/cookie-store.d.ts +30 -18
  61. package/dist/types/server/handle-store.d.ts +52 -1
  62. package/dist/types/server/request-context.d.ts +66 -45
  63. package/dist/types/server/request-headers.d.ts +44 -0
  64. package/dist/types/server.d.ts +1 -0
  65. package/dist/types/testing/e2e/index.d.ts +1 -1
  66. package/dist/types/testing/index.d.ts +3 -2
  67. package/dist/types/testing/internal/action-id.d.ts +7 -0
  68. package/dist/types/testing/location-state-key.d.ts +24 -0
  69. package/dist/types/testing/render-route.d.ts +17 -1
  70. package/dist/types/testing/run-transition-when.d.ts +44 -69
  71. package/dist/types/testing/serve-shell-request.d.ts +7 -6
  72. package/dist/types/testing/shell-status.d.ts +34 -22
  73. package/dist/types/transition-when-ref.d.ts +79 -0
  74. package/dist/types/types/cache-types.d.ts +15 -3
  75. package/dist/types/types/index.d.ts +1 -1
  76. package/dist/types/types/segments.d.ts +86 -71
  77. package/dist/types/urls/path-helper-types.d.ts +3 -4
  78. package/dist/types/urls/pattern-types.d.ts +3 -4
  79. package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
  80. package/dist/vite/index.js +962 -97
  81. package/package.json +1 -1
  82. package/skills/cache-guide/SKILL.md +76 -49
  83. package/skills/caching/SKILL.md +167 -69
  84. package/skills/client-urls/SKILL.md +1 -1
  85. package/skills/comparison/references/framework-comparison.md +8 -5
  86. package/skills/document-cache/SKILL.md +24 -0
  87. package/skills/hooks/SKILL.md +3 -1
  88. package/skills/hooks/navigation.md +23 -2
  89. package/skills/hooks/state.md +98 -6
  90. package/skills/intercept/SKILL.md +29 -12
  91. package/skills/loader/SKILL.md +52 -21
  92. package/skills/middleware/SKILL.md +18 -0
  93. package/skills/migrate-nextjs/SKILL.md +3 -3
  94. package/skills/observability/SKILL.md +6 -5
  95. package/skills/parallel/SKILL.md +1 -1
  96. package/skills/ppr/SKILL.md +129 -77
  97. package/skills/prerender/SKILL.md +3 -3
  98. package/skills/rango/SKILL.md +25 -6
  99. package/skills/route/SKILL.md +2 -0
  100. package/skills/testing/SKILL.md +27 -25
  101. package/skills/testing/cache-prerender.md +9 -9
  102. package/skills/testing/client-components.md +45 -3
  103. package/skills/testing/loader.md +3 -2
  104. package/skills/testing/middleware.md +1 -0
  105. package/skills/testing/predicates.md +49 -49
  106. package/skills/testing/render-handler.md +1 -0
  107. package/skills/testing/serve-shell-request.md +14 -0
  108. package/skills/testing/server-actions.md +9 -3
  109. package/skills/theme/SKILL.md +8 -4
  110. package/skills/typesafety/env-and-bindings.md +8 -0
  111. package/skills/use-cache/SKILL.md +67 -19
  112. package/skills/view-transitions/SKILL.md +150 -29
  113. package/src/__augment-tests__/augmented.check.ts +23 -0
  114. package/src/browser/event-controller.ts +4 -4
  115. package/src/browser/history-state.ts +52 -1
  116. package/src/browser/link-interceptor.ts +4 -0
  117. package/src/browser/navigation-bridge.ts +77 -18
  118. package/src/browser/navigation-client.ts +4 -3
  119. package/src/browser/navigation-store.ts +43 -1
  120. package/src/browser/navigation-transaction.ts +31 -11
  121. package/src/browser/partial-update.ts +146 -35
  122. package/src/browser/prefetch/cache.ts +6 -6
  123. package/src/browser/prefetch/fetch.ts +2 -2
  124. package/src/browser/react/Link.tsx +38 -33
  125. package/src/browser/react/NavigationProvider.tsx +2 -2
  126. package/src/browser/react/context.ts +2 -2
  127. package/src/browser/react/location-state-shared.ts +241 -49
  128. package/src/browser/react/location-state.ts +5 -2
  129. package/src/browser/rsc-router.tsx +4 -0
  130. package/src/browser/server-action-bridge.ts +84 -15
  131. package/src/browser/transition-when.ts +205 -0
  132. package/src/browser/types.ts +124 -10
  133. package/src/build/generate-manifest.ts +77 -1
  134. package/src/cache/background-task.ts +55 -2
  135. package/src/cache/cache-exec-scope.ts +54 -1
  136. package/src/cache/cache-key-utils.ts +56 -16
  137. package/src/cache/cache-policy.ts +9 -4
  138. package/src/cache/cache-runtime.ts +202 -144
  139. package/src/cache/cache-scope.ts +304 -112
  140. package/src/cache/cache-tag.ts +209 -13
  141. package/src/cache/cf/cf-cache-store.ts +152 -76
  142. package/src/cache/cf/cf-shell-frame.ts +2 -2
  143. package/src/cache/cf/cf-tag-marker-memo.ts +11 -100
  144. package/src/cache/document-cache.ts +53 -7
  145. package/src/cache/handle-snapshot.ts +52 -9
  146. package/src/cache/invalidation-order.ts +84 -0
  147. package/src/cache/request-tag-mask.ts +147 -0
  148. package/src/cache/shell-snapshot.ts +130 -348
  149. package/src/cache/tag-invalidation.ts +57 -51
  150. package/src/cache/types.ts +71 -67
  151. package/src/cache/vercel/vercel-cache-store.ts +61 -58
  152. package/src/client-urls/client-root.tsx +8 -4
  153. package/src/client-urls/client-urls.ts +8 -6
  154. package/src/client-urls/navigation.ts +55 -4
  155. package/src/client-urls/server-projection.ts +31 -10
  156. package/src/client-urls/types.ts +12 -5
  157. package/src/client.tsx +2 -0
  158. package/src/host/cookie-handler.ts +2 -1
  159. package/src/index.rsc.ts +3 -0
  160. package/src/index.ts +3 -0
  161. package/src/loader-redirect.tsx +7 -3
  162. package/src/prerender/build-shell-capture.ts +155 -146
  163. package/src/route-definition/dsl-helpers.ts +2 -0
  164. package/src/route-definition/helpers-types.ts +11 -11
  165. package/src/route-name.ts +12 -0
  166. package/src/router/content-negotiation.ts +4 -1
  167. package/src/router/error-handling.ts +5 -2
  168. package/src/router/handler-context.ts +10 -7
  169. package/src/router/intercept-resolution.ts +11 -1
  170. package/src/router/loader-resolution.ts +42 -5
  171. package/src/router/logging.ts +5 -3
  172. package/src/router/match-api.ts +62 -34
  173. package/src/router/match-context.ts +5 -0
  174. package/src/router/match-handlers.ts +9 -29
  175. package/src/router/match-middleware/background-revalidation.ts +3 -5
  176. package/src/router/match-middleware/cache-lookup.ts +35 -19
  177. package/src/router/match-middleware/cache-store.ts +15 -9
  178. package/src/router/match-result.ts +1 -0
  179. package/src/router/middleware.ts +2 -5
  180. package/src/router/navigation-snapshot.ts +6 -5
  181. package/src/router/prerender-match.ts +4 -0
  182. package/src/router/request-classification.ts +7 -4
  183. package/src/router/router-options.ts +4 -1
  184. package/src/router/segment-resolution/fresh.ts +0 -4
  185. package/src/router/segment-resolution/loader-cache.ts +152 -26
  186. package/src/router/segment-resolution/loader-mask.ts +3 -4
  187. package/src/router/segment-resolution/loader-snapshot.ts +15 -78
  188. package/src/router/segment-resolution/mask-nested.ts +47 -22
  189. package/src/router/segment-resolution/revalidation.ts +0 -3
  190. package/src/router/segment-resolution/view-transition-default.ts +6 -21
  191. package/src/router/telemetry.ts +6 -3
  192. package/src/router/transition-when.ts +34 -52
  193. package/src/router.ts +2 -1
  194. package/src/rsc/attach-transition-when.ts +47 -0
  195. package/src/rsc/full-payload.ts +30 -10
  196. package/src/rsc/handler.ts +12 -10
  197. package/src/rsc/loader-fetch.ts +2 -1
  198. package/src/rsc/manifest-init.ts +4 -0
  199. package/src/rsc/origin-guard.ts +8 -5
  200. package/src/rsc/progressive-enhancement.ts +7 -30
  201. package/src/rsc/response-cache-serve.ts +68 -80
  202. package/src/rsc/response-route-handler.ts +2 -2
  203. package/src/rsc/rsc-rendering.ts +206 -252
  204. package/src/rsc/server-action.ts +8 -20
  205. package/src/rsc/shell-build-manifest.ts +22 -20
  206. package/src/rsc/shell-capture-constants.ts +136 -20
  207. package/src/rsc/shell-capture.ts +352 -589
  208. package/src/rsc/shell-serve.ts +73 -109
  209. package/src/rsc/ssr-setup.ts +3 -2
  210. package/src/rsc/types.ts +2 -0
  211. package/src/segment-system.tsx +40 -7
  212. package/src/server/context.ts +263 -124
  213. package/src/server/cookie-store.ts +153 -127
  214. package/src/server/handle-store.ts +245 -27
  215. package/src/server/request-context.ts +134 -87
  216. package/src/server/request-headers.ts +134 -0
  217. package/src/server.ts +4 -0
  218. package/src/testing/dispatch.ts +4 -7
  219. package/src/testing/e2e/index.ts +1 -0
  220. package/src/testing/index.ts +5 -0
  221. package/src/testing/internal/action-id.ts +25 -0
  222. package/src/testing/internal/context.ts +1 -1
  223. package/src/testing/location-state-key.ts +45 -0
  224. package/src/testing/render-handler.ts +1 -1
  225. package/src/testing/render-route.tsx +109 -16
  226. package/src/testing/run-client-revalidate.ts +3 -19
  227. package/src/testing/run-loader.ts +5 -1
  228. package/src/testing/run-transition-when.ts +109 -172
  229. package/src/testing/serve-shell-request.ts +10 -7
  230. package/src/testing/shell-status.ts +60 -56
  231. package/src/transition-when-ref.ts +220 -0
  232. package/src/types/cache-types.ts +15 -3
  233. package/src/types/index.ts +3 -0
  234. package/src/types/segments.ts +94 -91
  235. package/src/urls/path-helper-types.ts +3 -4
  236. package/src/urls/pattern-types.ts +3 -4
  237. package/src/vite/discovery/discover-routers.ts +3 -0
  238. package/src/vite/discovery/shell-prerender-phase.ts +0 -2
  239. package/src/vite/discovery/virtual-module-codegen.ts +16 -6
  240. package/src/vite/plugins/transition-when-hoist.ts +1064 -0
  241. package/src/vite/rango.ts +2 -0
  242. package/src/vite/router-discovery.ts +75 -5
  243. package/dist/types/rsc/transition-gate.d.ts +0 -23
  244. package/src/rsc/transition-gate.ts +0 -86
@@ -3,28 +3,27 @@
3
3
  *
4
4
  * Owns the single response-cache contract — cache-scope resolution from the
5
5
  * matched entry tree, condition eval, key resolution (route key() > store
6
- * keyGenerator > default), tag resolution, pre-handler-callback timing, and the
7
- * fresh-hit / SWR-revalidate / miss-write branches — for BOTH the production
6
+ * keyGenerator > default, CacheScope.resolveKeyFrom), tag resolution,
7
+ * pre-handler-callback timing, and the fresh-hit / SWR-revalidate /
8
+ * miss-write branches — for BOTH the production
8
9
  * response-route handler (rsc/response-route-handler.ts) and the dispatch testing
9
10
  * primitive (testing/dispatch.ts), so the two can never drift.
10
11
  *
11
12
  * Plugin-rsc hazard: cache-scope.ts pulls @vitejs/plugin-rsc (via segment-codec),
12
13
  * which the non-Vite unit-test runner cannot resolve, and this module is on the
13
- * testing barrel's EAGER graph (dispatch imports it). So `createCacheScope` and
14
- * `resolveCacheTags` are NOT imported here at runtime — they are INJECTED by the
15
- * caller (production imports them statically; dispatch lazy-imports them only once
16
- * a response route matches). The only runtime imports here are plugin-rsc-free
14
+ * testing barrel's EAGER graph (dispatch imports it). So `createCacheScope` is
15
+ * NOT imported here at runtime — it is INJECTED by the caller (production
16
+ * imports it statically; dispatch lazy-imports it only once a response route
17
+ * matches). The only runtime imports here are plugin-rsc-free
17
18
  * (helpers' isCacheableStatus/finalizeResponse, traverseBack); cache-scope is a
18
19
  * type-only import (erased at build).
19
20
  */
20
21
  import type { CacheScope } from "../cache/cache-scope.js";
21
- import type { PartialCacheOptions } from "../types.js";
22
- import type { RequestContext } from "../server/request-context.js";
22
+ import { type RequestContext } from "../server/request-context.js";
23
23
  import type { EntryCacheConfig, EntryData } from "../server/context.js";
24
- /** Injected cache-scope builders (kept off this module's runtime import graph). */
24
+ /** Injected cache-scope builder (kept off this module's runtime import graph). */
25
25
  export interface CacheScopeDeps {
26
26
  createCacheScope: (config: EntryCacheConfig | undefined, parent?: CacheScope | null) => CacheScope | null;
27
- resolveCacheTags: (config: PartialCacheOptions | false, ctx: RequestContext | undefined) => string[] | undefined;
28
27
  }
29
28
  export interface ServeResponseRouteWithCacheArgs {
30
29
  reqCtx: RequestContext;
@@ -40,7 +39,11 @@ export interface ServeResponseRouteWithCacheArgs {
40
39
  * applies (no scope, disabled, condition false, or store lacks get/putResponse)
41
40
  * so the caller falls through to a plain `executeHandler()` run.
42
41
  *
43
- * Must run inside runWithRequestContext (reads the ambient request context via
44
- * the helpers and reqCtx.waitUntil for background writes).
42
+ * Must run inside runWithRequestContext for `reqCtx` (reads the ambient
43
+ * request context via the helpers and reqCtx.waitUntil for background writes).
44
+ * Outside it, the route runs uncached: the scope resolves `key()`, a store
45
+ * keyGenerator and `condition()` against the ambient context, and without
46
+ * it a keyGenerator was skipped and the entry landed on the broad default
47
+ * key.
45
48
  */
46
49
  export declare function serveResponseRouteWithCache(args: ServeResponseRouteWithCacheArgs): Promise<Response | undefined>;
@@ -31,10 +31,8 @@ export interface BuildShellEntry {
31
31
  entry: ShellCacheEntry;
32
32
  /** Resolved ppr ttl (seconds) — drives staleness/recapture, never expiry. */
33
33
  ttl: number;
34
- swr?: number;
35
34
  /** The putShell-barrier tag union baked at build (static + recorded). */
36
35
  tags?: string[];
37
- routeName: string;
38
36
  }
39
37
  interface ShellManifestModule {
40
38
  /** Manifest key (pathname — see shell-manifest-key.ts) -> asset specifier. */
@@ -46,7 +44,10 @@ interface ShellManifestModule {
46
44
  declare global {
47
45
  var __loadShellManifestModule: (() => Promise<ShellManifestModule>) | undefined;
48
46
  }
49
- /** Reset the memoized manifest (unit tests swap the global loader). */
47
+ /**
48
+ * Reset the memoized manifest (unit tests swap the global loader) and the
49
+ * shell path's once-per-key warnings, the tag-check one included.
50
+ */
50
51
  export declare function resetBuildShellManifestForTests(): void;
51
52
  export interface BuildShellHit {
52
53
  entry: DocumentShellCacheEntry;
@@ -1,37 +1,81 @@
1
+ /**
2
+ * React-free leaf of the PPR shell path: its constants, the shell key
3
+ * builders, the status header names and bypass reasons, and the once-per-key
4
+ * warning registry. The ssr graph (ssr/index.tsx), the testing barrels
5
+ * (testing/shell-status.ts) and cookie-store.ts import from here without
6
+ * pulling the capture orchestration module or shell-serve.ts (React).
7
+ */
8
+ import type { SearchParamsFilter } from "../cache/search-params-filter.js";
1
9
  /**
2
10
  * Default upper bound on the capture prerender wait before forcing the abort
3
11
  * that freezes the shell — the ONLY wall-clock on the capture path, and a
4
12
  * pathological guard: it should never fire once the caller's `quiesce` is a
5
13
  * task-quantized, frozen-byte signal (the capture gate in shell-capture.ts).
6
- *
7
- * Leaf module on purpose (imports nothing): shell-capture.ts re-exports it
8
- * (single import site for the rsc graph — shell-build-manifest.ts sizes the
9
- * dev fetch envelope from that re-export) and ssr/index.tsx uses it as
10
- * captureShellHTML's own fallback; the ssr graph must not pull the capture
11
- * orchestration module for one number.
14
+ * ssr/index.tsx uses it as captureShellHTML's own fallback.
12
15
  *
13
16
  * 15s, raised from 5s: captures are background work (waitUntil), so the budget
14
17
  * costs latency-to-HIT only — never a served response — and 5s spuriously
15
18
  * refused legitimately-slow deferred shell material (a real storefront's meta
16
19
  * chains settle at ~7s). Ceiling math: workerd's waitUntil lifetime is ~30s
17
20
  * past response completion. An attempt that consumed the whole budget is not
18
- * retried in place (shell-capture.ts noShellCauses), so the envelope is one
19
- * budget plus store I/O; the retry follows only an attempt that ended early
20
- * (a cold-module abort). Past the ceiling the platform kill degrades to the
21
- * existing best-effort contract (the key stays MISS; a later request
22
- * re-captures).
21
+ * retried in place (shell-capture.ts CaptureAttemptStats.noShellCause), so
22
+ * the envelope is one budget plus store I/O; the retry follows only an
23
+ * attempt that ended early (a cold-module abort). Past the ceiling the
24
+ * platform kill degrades to the existing best-effort contract (the key stays
25
+ * MISS; a later request re-captures).
23
26
  * Node/dev and build-time captures have no waitUntil ceiling. The per-route
24
27
  * `ppr.captureTimeout` knob remains for tightening below the default. See
25
28
  * docs/design/ppr-shell-resume.md (Cost model).
26
29
  */
27
30
  export declare const SHELL_CAPTURE_MAX_WAIT_MS = 15000;
31
+ /** Debug/status header on a ppr document response: `HIT` | `MISS`. */
32
+ export declare const SHELL_STATUS_HEADER: string;
33
+ /**
34
+ * Partial-navigation replay status header, set only after the captured
35
+ * segment record was consumed (`HIT`) or with the reason it was not.
36
+ */
37
+ export declare const PPR_REPLAY_STATUS_HEADER: string;
38
+ /**
39
+ * Bounded reasons a partial request to a ppr route falls open to the ordinary
40
+ * match (`x-rango-ppr-replay: BYPASS; reason=<reason>`). One list for the
41
+ * producer (rsc-rendering.ts) and the parser (testing/shell-status.ts): a
42
+ * reason the parser does not list parses as null.
43
+ */
44
+ export declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "no-segment-snapshot", "snapshot-miss", "explicit-cache-hit"];
45
+ /** One of {@link PPR_REPLAY_BYPASS_REASONS}. */
46
+ export type PprReplayBypassReason = (typeof PPR_REPLAY_BYPASS_REASONS)[number];
47
+ /**
48
+ * The shell key's search portion (`?`-prefixed sorted search with the
49
+ * cache.searchParams filter applied, or "") — ALSO the string the capture and
50
+ * resume SSR renders seed their store location with (SSRRenderOptions.search
51
+ * / ShellCaptureOptions.search / ShellResumeOptions.search). Search is part
52
+ * of shell identity, so static-part `useSearchParams` reads render exactly
53
+ * what the key names; deriving seed and key from this one helper is what
54
+ * keeps capture, resume, and lookup byte-agreed (drift = replay mismatch or
55
+ * permanent MISS).
56
+ */
57
+ export declare function shellSearchSeed(url: URL, filter?: SearchParamsFilter): string;
58
+ /**
59
+ * Shell cache key: host + pathname + sorted search + a `:shell` namespace suffix
60
+ * (so it can never collide with a document-cache key; the store further isolates
61
+ * the shell family internally).
62
+ *
63
+ * The key includes the request HOST: in a multi-tenant host-router deployment
64
+ * (one worker, one shared KV/runtime-cache store) a host-less key would serve
65
+ * tenant A's captured shell to tenant B's users.
66
+ *
67
+ * `filter` is the request's compiled `cache.searchParams` config
68
+ * (ctx._searchParamsFilter): excluded params collapse onto one shell slot.
69
+ * Callers on the serve/capture path MUST pass it -- key drift between capture
70
+ * and lookup makes every shell request a permanent miss. The testing helper
71
+ * `shellCacheKey` (testing/shell-status.ts) builds its key with it too.
72
+ */
73
+ export declare function buildShellKey(url: URL, filter?: SearchParamsFilter): string;
28
74
  /**
29
75
  * The shell key for one request partition (cache-scope.ts
30
76
  * resolveShellPartition): the route cache() `key()` or store keyGenerator
31
77
  * result that partitions the route's record partitions its shell too, so
32
- * each partition captures and serves its own. Here, in the leaf module, so
33
- * the testing helper `shellCacheKey` (testing/shell-status.ts) calls it
34
- * without pulling shell-serve.ts.
78
+ * each partition captures and serves its own.
35
79
  *
36
80
  * The partition is URI-encoded: it is request-derived, and raw it could end
37
81
  * in a suffix another key is built with (navigationShellKey), so a partition
@@ -53,12 +97,12 @@ export declare function navigationShellKey(key: string): string;
53
97
  * (ssr/index.tsx) and by the testing SSR stub (testing/serve-shell-request.ts),
54
98
  * so the stub freezes the same Flight the real capture would.
55
99
  *
56
- * Why 16 and not the original 2: under the REPLAY-ONLY capture model
57
- * (docs/design/ppr-shell-resume.md), the capture Flight render serializes ring-3
58
- * cached segments that are ALREADY serialized, so it emits the whole shell payload
59
- * in the first tick and the gate declares quiesce almost immediately (~a few ms).
60
- * On the old fresh-execution path the Flight dribbled out as handlers ran, so
61
- * Flight-quiet effectively meant "the shell has rendered" and 2 hops sufficed.
100
+ * Why 16 and not 2: the capture's Flight input is the doc record's stored
101
+ * fragments (settleCaptureRecord, shell-capture.ts), already serialized, so the
102
+ * render emits the whole shell payload in the first tick and the gate declares
103
+ * quiesce within a few ms, before fizz has rendered the shell to <body>. When
104
+ * the capture Flight dribbled out as handlers ran, Flight-quiet meant "the shell
105
+ * has rendered" and 2 hops sufficed.
62
106
  *
63
107
  * Hops alone are NOT render-readiness: fizz cannot emit even <html> until the
64
108
  * payload root settles, nor complete a shell whose client components are
@@ -97,3 +141,16 @@ export declare const SHELL_CAPTURE_TASK_HARD_CAP_MS = 25000;
97
141
  * rule: resolveLoaderData (router/segment-resolution/loader-cache.ts).
98
142
  */
99
143
  export declare const PPR_LANE_HINT: string;
144
+ /** Whether {@link warnOnce} already warned for `scope` and `key`. */
145
+ export declare function hasWarnedOnce(scope: string, key: string): boolean;
146
+ /**
147
+ * `console.warn(message())` once per `scope` and `key`; `message` is built only
148
+ * when it prints. Returns true when it warned.
149
+ */
150
+ export declare function warnOnce(scope: string, key: string, message: () => string): boolean;
151
+ /**
152
+ * @internal Forget every once-per-key shell warning. Tests only: the capture,
153
+ * serve and build-shell resets (testing/serve-shell-request.ts
154
+ * resetShellTestState) call it.
155
+ */
156
+ export declare function resetShellWarningsForTests(): void;
@@ -6,29 +6,24 @@
6
6
  * from the route's `ppr` path option after the served response is built and calls
7
7
  * scheduleShellCapture. 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 loaders mask (loader-mask.ts) and every
10
- * loading() subtree postpones. The render is MIXED-CHAIN: cache()'d segments replay
11
- * from ring 3, uncached segments execute their handlers fresh. It drives the static
12
- * prerender to a quiescent shell, aborts to freeze the prelude + postponed state,
13
- * and stores the pair via putShell. Because it uses match() rather than the HTTP
14
- * pipeline, the middleware chain (auth, logging) never re-runs — it already ran for
15
- * the triggering request, and the derived context inherits its post-middleware
16
- * state (variables, cache store). Guarding is serve-time.
9
+ * handle store, `_shellCaptureRun: true` so live-lane loaders mask (loader-mask.ts)
10
+ * and postpone at their loading() or inline <Suspense> boundary. The match is
11
+ * MIXED-CHAIN: cache()'d segments replay from ring 3, uncached segments execute
12
+ * their handlers. The record-first step (settleCaptureRecord) waits for the
13
+ * handler layer, writes the doc record every HIT replays, and renders the
14
+ * capture's Flight payload from it; the static prerender runs to a quiescent
15
+ * shell, aborts to freeze the prelude + postponed state, and putShell stores the
16
+ * pair with the snapshot. Because it uses match() rather than the HTTP pipeline,
17
+ * the middleware chain (auth, logging) never re-runs — it already ran for the
18
+ * triggering request, and the derived context inherits its post-middleware state
19
+ * (variables, cache store). Guarding is serve-time.
17
20
  */
18
21
  import { type MatchResult } from "../types.js";
19
- import { SHELL_CAPTURE_MAX_WAIT_MS } from "./shell-capture-constants.js";
20
22
  import { type RequestContext, type RouteRecordWindow } from "../server/request-context.js";
21
23
  import { type HandleStore } from "../server/handle-store.js";
22
24
  import type { SegmentCacheStore } from "../cache/types.js";
23
25
  import type { HandlerContext } from "./handler-context.js";
24
26
  import type { SSRModule } from "./types.js";
25
- /**
26
- * Default capture budget. Canonical value, raise rationale, and ceiling math
27
- * live on the leaf module (shell-capture-constants.ts, importable from the ssr
28
- * graph too). Re-exported here so shell-build-manifest.ts's envelope math
29
- * keeps its existing import site and cannot drift from the capture.
30
- */
31
- export { SHELL_CAPTURE_MAX_WAIT_MS };
32
27
  /**
33
28
  * Delay before the in-place retry of a capture that produced no usable shell.
34
29
  *
@@ -80,6 +75,7 @@ declare const REFUSED_CAPTURE_MAX_MS = 60000;
80
75
  * docs/design/ppr-shell-resume.md ("Refused-capture backoff").
81
76
  */
82
77
  declare const REFUSED_CAPTURE_DEV_MAX_MS = 2000;
78
+ /** True iff `key` is still inside its (exponential) backoff window. */
83
79
  declare function isCaptureBackedOff(key: string): boolean;
84
80
  /**
85
81
  * Record a refused/failed capture, escalating the backoff window exponentially up
@@ -187,15 +183,6 @@ export interface ShellCaptureDebugEvent {
187
183
  * same-or-higher priority. 0 = this capture starts immediately.
188
184
  */
189
185
  queueAhead?: number;
190
- /**
191
- * Ms the capture gate was HELD waiting for the slowest bake source — a
192
- * top-level pushed handle promise or a bake-lane loader container — to
193
- * settle, measured from capture start. Bake time is by-design shell latency
194
- * (the hole doctrine: top-level promises bake), but it recurs on EVERY
195
- * capture of the route and occupies the serialized queue; this field makes
196
- * it attributable. Absent when nothing held the gate.
197
- */
198
- bakeWaitMs?: number;
199
186
  /**
200
187
  * How long the capture waited for its doc record: the handler layer's
201
188
  * promises, async server components and handle pushes settling, then the
@@ -265,19 +252,12 @@ export interface FlightCaptureGate {
265
252
  * closing (no holes) fires quiesce immediately for the DATA variant — the
266
253
  * TransformStream then closes the readable, so fizz completes with postponed null.
267
254
  *
268
- * `holdUntil` keeps the gate from FREEZING before shell material with real latency
269
- * has emitted. The hole doctrine bakes TOP-LEVEL pushed handle promises into the
270
- * shell (resolvedHandleStream awaits them before the handles row emits), but a
271
- * pushed promise that takes longer than the quiet window would otherwise be frozen
272
- * out — the handles row would never reach fizz and the prelude would come back
273
- * trivial. While `holdUntil` is pending, byte-quiet detection keeps running but the
274
- * gate neither fires nor freezes; once it resolves, the quiet counter restarts so a
275
- * burst of rows unblocked by it (the resolved handles row) is still captured. It
276
- * never delays a HOLE from postponing: holes are pending promises that emit no
277
- * bytes, so holding the gate open longer only ever admits shell rows. Bounded by
278
- * captureShellHTML's maxWaitMs like every other quiesce input.
255
+ * Nothing the shell bakes can still be pending here: settleCaptureRecord already
256
+ * waited for the top-level handle promises and the bake-lane loader containers
257
+ * before the capture's Flight render began, so the handles row and the baked
258
+ * loader rows emit at once and only the holes stay silent.
279
259
  */
280
- export declare function gateFlightForCapture(source: ReadableStream<Uint8Array>, quietHops?: number, holdUntil?: Promise<unknown>): FlightCaptureGate;
260
+ export declare function gateFlightForCapture(source: ReadableStream<Uint8Array>): FlightCaptureGate;
281
261
  /**
282
262
  * The background shell-capture descriptor: everything the capture task needs to
283
263
  * store the shell. Built by the integrated PPR serve path (rsc-rendering.ts) from
@@ -324,16 +304,13 @@ export interface ShellCaptureDescriptor {
324
304
  tags?: string[];
325
305
  /**
326
306
  * Per-route capture settle budget in ms (`ppr.captureTimeout`, resolved by
327
- * resolvePprConfig). Feeds captureShellHTML's maxWaitMs — the ONE deadline
328
- * bounding the whole capture, so it covers BOTH the fizz prerender AND the
329
- * deferred-material settle window (the handlesBaked/loader-container
330
- * holdUntil that keeps the gate from freezing while top-level pushes are
331
- * pending). Undefined = SHELL_CAPTURE_MAX_WAIT_MS (15_000).
307
+ * resolvePprConfig): the ONE deadline bounding the whole capture — the match,
308
+ * the record-first settle (settleCaptureRecord), then the fizz prerender with
309
+ * what is left (captureShellHTML's maxWaitMs). Undefined =
310
+ * SHELL_CAPTURE_MAX_WAIT_MS (15_000).
332
311
  */
333
312
  captureTimeout?: number;
334
313
  store?: SegmentCacheStore<any>;
335
- /** Gates the concise per-attempt capture breadcrumbs (INTERNAL_RANGO_DEBUG). */
336
- debug?: boolean;
337
314
  /**
338
315
  * Cap (serialized UTF-8 bytes) on the entry's capture data snapshot; over it
339
316
  * the snapshot is skipped and the shell stored without it (reported once per
@@ -402,22 +379,47 @@ export declare function capShellWindow(ttl: number, swr: number, record: Pick<Ro
402
379
  * - `no-shell`: captureShellHTML returned null because the prelude was unusable
403
380
  * or its private capture abort landed before the shell completed, or the
404
381
  * capture ran out of ppr.captureTimeout. Retried once in place, when no
405
- * deadline ran out (noShellCauses).
382
+ * deadline ran out (CaptureAttemptStats.noShellCause).
406
383
  * - `expired`: the route cache() record the capture read (not wrote) ran out
407
384
  * before the store (capShellWindow null): it was near its end (its age,
408
385
  * queue wait). Retried once in place, where a fresh match reads or renders
409
- * a newer record; a second `expired`, or no hard-cap budget left for the
386
+ * a newer record; an `expired` retry, or no hard-cap budget left for the
410
387
  * retry, is terminal `no-shell` (backoff, warned once per route).
411
388
  */
412
389
  type CaptureAttemptOutcome = "stored" | "redirect" | "no-shell" | "refused" | "expired";
413
390
  /**
414
- * Per-attempt observability fields, filled along the capture path (barrier in
415
- * attemptCapture, the rest in captureAndStoreShell) and folded into the
416
- * attempt's {@link ShellCaptureDebugEvent} by runShellCapture. A plain mutable
417
- * bag, not a return value: captureAndStoreShell's outcome type stays a string
418
- * union its existing callers (producer B, tests) consume unchanged.
391
+ * What a capture task ends with (runShellCapture): a refusal and a terminal
392
+ * `expired` are `no-shell`, which the scheduler backs off.
419
393
  */
420
- type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "writeSettleMs" | "preludeBytes" | "snapshotBytes" | "snapshotSkipped" | "untaggedBake" | "storeWrite" | "bakeWaitMs" | "recordSettleMs" | "entryBytes">;
394
+ type CaptureTaskOutcome = "stored" | "redirect" | "no-shell";
395
+ /**
396
+ * One attempt's record, filled along the capture path (barrier and deadline
397
+ * causes in attemptCapture, the rest in captureAndStoreShell). runShellCapture
398
+ * folds the observability fields into the attempt's
399
+ * {@link ShellCaptureDebugEvent} and reads the rest to decide the retry and
400
+ * the warning. A plain mutable bag, not a return value: captureAndStoreShell's
401
+ * outcome type stays a string union producer B consumes unchanged.
402
+ */
403
+ type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "writeSettleMs" | "preludeBytes" | "snapshotBytes" | "snapshotSkipped" | "untaggedBake" | "storeWrite" | "recordSettleMs" | "entryBytes"> & {
404
+ /**
405
+ * Why a no-shell attempt ran out of ppr.captureTimeout (the match, the
406
+ * handler output, or the prerender after them). A set cause skips the
407
+ * in-place retry: the attempt's match may still be running.
408
+ */
409
+ noShellCause?: string;
410
+ /**
411
+ * Dev only: component stacks of the tasks still pending at a no-shell
412
+ * attempt's abort, reported through prerender's onError (captureShellHTML's
413
+ * onAbortedTask).
414
+ */
415
+ pendingStacks?: string[];
416
+ /** The route cache() record an `expired` attempt ran out on. */
417
+ expired?: {
418
+ route: string;
419
+ record: RouteRecordWindow;
420
+ captureMs: number;
421
+ };
422
+ };
421
423
  /**
422
424
  * Run the shell capture with a single in-place retry, then store the result.
423
425
  *
@@ -430,14 +432,16 @@ type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "write
430
432
  * attempt a short beat later usually completes the shell in the SAME background
431
433
  * task. That kills the old multi-request warmup where the caller had to re-issue
432
434
  * several HTTP requests before a capture stuck. We retry ONLY on `no-shell`
433
- * that did not run out of ppr.captureTimeout (noShellCauses); a genuine render
434
- * error is NOT retried — it propagates to scheduleShellCapture's
435
- * reportCacheError. See docs/design/ppr-shell-resume.md.
435
+ * that did not run out of ppr.captureTimeout (CaptureAttemptStats.noShellCause),
436
+ * and on `expired`; a genuine render error is NOT retried — it propagates to
437
+ * scheduleShellCapture's reportCacheError. See docs/design/ppr-shell-resume.md.
436
438
  *
437
- * `retryDelayMs` is a parameter (defaulting to the module const) so unit tests can
438
- * drive the retry without a real 400ms wall-clock wait.
439
+ * `request` and `url` are the capture's own identity (scheduleShellCapture
440
+ * strips a navigation-only capture's transport parameters). `retryDelayMs` is
441
+ * a parameter (defaulting to the module const) so unit tests can drive the
442
+ * retry without a real 400ms wall-clock wait.
439
443
  */
440
- declare function runShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule, descriptor: ShellCaptureDescriptor, retryDelayMs?: number): Promise<CaptureAttemptOutcome>;
444
+ declare function runShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule, descriptor: ShellCaptureDescriptor, retryDelayMs?: number): Promise<CaptureTaskOutcome>;
441
445
  /**
442
446
  * What the record-first step produced ({@link settleCaptureRecord}):
443
447
  * - `record`: the doc record settled; `match` carries its fragments in place
@@ -486,17 +490,6 @@ export type CaptureRecordOutcome = {
486
490
  * scope's own write), and the deferred writes settle.
487
491
  */
488
492
  export declare function settleCaptureRecord(match: MatchResult, derivation: CaptureContextDerivation, capture: Pick<ShellCaptureDescriptor, "key">, deadline: number): Promise<CaptureRecordOutcome>;
489
- /**
490
- * Race `work` against an absolute deadline, keeping its value. The losing
491
- * work is not cancelled (a router match has no abort signal); callers that
492
- * lose do not start it again (runShellCapture skips its in-place retry).
493
- */
494
- export declare function withinDeadline<T>(work: Promise<T>, deadline: number): Promise<{
495
- done: true;
496
- value: T;
497
- } | {
498
- done: false;
499
- }>;
500
493
  /**
501
494
  * The derived capture context and its fresh (mask-funneled) handle store,
502
495
  * shared by BOTH shell producers: the runtime background capture
@@ -530,27 +523,31 @@ export declare function deriveShellCaptureContext(reqCtx: RequestContext<any>, d
530
523
  url: URL;
531
524
  }): CaptureContextDerivation;
532
525
  /**
533
- * Seal handles, derive the quiesce signal, prerender + abort via the SSR module's
534
- * captureShellHTML, and store the result. Returns the attempt outcome (the caller
535
- * owns retry/warn decisions — this function no longer warns). Never throws out of
536
- * the store write: a failed putShell is routed through reportCacheError so the
537
- * background task stays best-effort, and the attempt still counts as `stored` (the
538
- * capture worked; only the store I/O failed). `ssrModule.captureShellHTML` MUST be
539
- * present (eligibility is checked before scheduling).
526
+ * Derive the quiesce signal, prerender + abort via the SSR module's
527
+ * captureShellHTML, and store the result. Runs after settleCaptureRecord (both
528
+ * producers), which sealed the capture's handle store (`reqCtx._handleStore`)
529
+ * and waited for everything the shell bakes. Returns the attempt outcome (the
530
+ * caller owns retry/warn decisions). Never throws out of the store write: a
531
+ * failed putShell is routed through reportCacheError so the background task
532
+ * stays best-effort, and the attempt still counts as `stored` (the capture
533
+ * worked; only the store I/O failed). `ssrModule.captureShellHTML` MUST be
534
+ * present (eligibility is checked before scheduling). `captureStartedAt` is the
535
+ * capture generation's start, stamped before the match (ShellCacheEntry
536
+ * .createdAt).
540
537
  *
541
538
  * A `no-shell` result from captureShellHTML is the only retryable outcome. Every
542
539
  * captureShellHTML error propagates to reportCacheError and is NOT retried. The
543
540
  * capture handler converts only its own private abort sentinel to null before this
544
541
  * layer sees it.
545
542
  */
546
- declare function captureAndStoreShell(ssrModule: SSRModule, rscStream: ReadableStream<Uint8Array>, handleStore: HandleStore, reqCtx: RequestContext<any>, capture: ShellCaptureDescriptor, stats?: CaptureAttemptStats, captureStartedAt?: number): Promise<Exclude<CaptureAttemptOutcome, "redirect">>;
543
+ declare function captureAndStoreShell(ssrModule: SSRModule, rscStream: ReadableStream<Uint8Array>, reqCtx: RequestContext<any>, capture: ShellCaptureDescriptor, captureStartedAt: number, stats?: CaptureAttemptStats): Promise<Exclude<CaptureAttemptOutcome, "redirect">>;
547
544
  export { runShellCapture, captureAndStoreShell, delay, SHELL_CAPTURE_RETRY_DELAY_MS, };
548
545
  export { isCaptureBackedOff, markCaptureBackoff, clearCaptureBackoff, REFUSED_CAPTURE_BASE_MS, REFUSED_CAPTURE_MAX_MS, REFUSED_CAPTURE_DEV_MAX_MS, };
549
546
  /**
550
547
  * @internal Reset this module's per-isolate state: the capture stampede
551
- * guard, the refused-capture backoff, the recorded no-shell causes (which
552
- * also skip a timed-out capture's in-place retry), the once-per-key warnings
553
- * and the buffered debug events. Tests only (testing/serve-shell-request.ts
554
- * resetShellTestState), between requests, never while a capture runs.
548
+ * guard, the refused-capture backoff, the once-per-key warnings (the shell
549
+ * path's one registry), the stored-capture sequence and the buffered debug
550
+ * events. Tests only (testing/serve-shell-request.ts resetShellTestState),
551
+ * between requests, never while a capture runs.
555
552
  */
556
553
  export declare function resetShellCaptureStateForTests(): void;
@@ -16,12 +16,8 @@
16
16
  * intent cannot be honored — unlike an undeclared route, which is silent).
17
17
  */
18
18
  import { type EntryData } from "../server/context.js";
19
- import type { SearchParamsFilter } from "../cache/search-params-filter.js";
20
- import type { DocumentShellCacheEntry, ShellCacheEntry, ShellDocumentRead, ShellReadStats, ShellSnapshotFailure, ShellSnapshotRecord, SegmentCacheStore } from "../cache/types.js";
21
- /** Debug/status header the browser (and e2e assertions) can read: HIT | MISS. */
22
- export declare const SHELL_STATUS_HEADER = "x-rango-shell";
23
- /** Partial-navigation status header set only after captured PPR segments are consumed. */
24
- export declare const PPR_REPLAY_STATUS_HEADER = "x-rango-ppr-replay";
19
+ import type { DocumentShellCacheEntry, ShellCacheEntry, ShellDocumentRead, ShellEntryHead, ShellReadStats, ShellSnapshotFailure, ShellSnapshotRecord, SegmentCacheStore } from "../cache/types.js";
20
+ export { PPR_REPLAY_STATUS_HEADER, SHELL_STATUS_HEADER, buildShellKey, navigationShellKey, partitionShellKey, shellSearchSeed, } from "./shell-capture-constants.js";
25
21
  /**
26
22
  * Default shell ttl (seconds) for `ppr: true` and for a PartialPrerenderProps
27
23
  * that omits `ttl`.
@@ -79,22 +75,6 @@ export declare function normalizeCaptureTimeout(value: unknown): number | undefi
79
75
  * inheritance (declaring it on a layout is not supported — a follow-up).
80
76
  */
81
77
  export declare function resolvePprConfig(entry: EntryData | undefined | null): ResolvedPprConfig | null;
82
- /**
83
- * Shell cache key: host + pathname + sorted search + a `:shell` namespace suffix
84
- * (so it can never collide with a document-cache key; the store further isolates
85
- * the shell family internally).
86
- *
87
- * The key includes the request HOST: in a multi-tenant host-router deployment
88
- * (one worker, one shared KV/runtime-cache store) a host-less key would serve
89
- * tenant A's captured shell to tenant B's users.
90
- *
91
- * `filter` is the request's compiled `cache.searchParams` config
92
- * (ctx._searchParamsFilter): excluded params collapse onto one shell slot.
93
- * Callers on the serve/capture path MUST pass it -- key drift between capture
94
- * and lookup makes every shell request a permanent miss.
95
- */
96
- export declare function buildShellKey(url: URL, filter?: SearchParamsFilter): string;
97
- export { navigationShellKey, partitionShellKey, } from "./shell-capture-constants.js";
98
78
  /**
99
79
  * The forced-MISS query marker. A document HIT that cannot finish its tail
100
80
  * reloads the page with it (shellReloadScript); the serve gate renders a
@@ -122,35 +102,24 @@ export declare function withoutShellMissMarker(request: Request): Request | unde
122
102
  * did (a server that ignores the marker) it would return without touching
123
103
  * the page. window.stop() runs only when it reloads: it keeps the half-sent
124
104
  * Flight stream from being closed by DOMContentLoaded, which would throw
125
- * React's "Connection closed" (#412) before the reload lands. `nonce` is the
126
- * request's CSP nonce; a ppr route with an active nonce is axis 1
127
- * (rsc-rendering.ts shellServePlan), so on a HIT it is normally absent.
105
+ * React's "Connection closed" (#412) before the reload lands.
128
106
  */
129
- export declare function shellReloadScript(nonce?: string): string;
130
- /** An inline script a shell HIT's tail appends, carrying the CSP nonce if any. */
131
- export declare function inlineShellScript(body: string, nonce?: string): string;
107
+ export declare function shellReloadScript(): string;
132
108
  /**
133
- * The shell key's search portion (`?`-prefixed sorted search with the
134
- * cache.searchParams filter applied, or "") — ALSO the string the capture and
135
- * resume SSR renders seed their store location with (SSRRenderOptions.search
136
- * / ShellCaptureOptions.search / ShellResumeOptions.search). Search is part
137
- * of shell identity, so static-part `useSearchParams` reads render exactly
138
- * what the key names; deriving seed and key from this one helper is what
139
- * keeps capture, resume, and lookup byte-agreed (drift = replay mismatch or
140
- * permanent MISS).
109
+ * An inline script a shell HIT's tail appends. It carries no CSP nonce: a
110
+ * request with an active per-request nonce never reaches a HIT
111
+ * (rsc-rendering.ts shellServePlan serves it on axis 1).
141
112
  */
142
- export declare function shellSearchSeed(url: URL, filter?: SearchParamsFilter): string;
113
+ export declare function inlineShellScript(body: string): string;
143
114
  /**
144
115
  * Version gates for a stored shell: reactVersion AND buildVersion must both
145
116
  * match the running server. The postponed blob encodes hole positions against
146
117
  * one exact tree, so resuming it under a different React OR a different app
147
118
  * build tree-mismatches inside resume() — after the 200 + prelude committed,
148
119
  * with no recovery. Either mismatch is a miss: the recapture overwrites the
149
- * same key (self-healing) and the entry otherwise ages out via TTL. An entry
150
- * with no buildVersion (stored before the field existed) is a miss for the
151
- * same reason — its build is unknown, so it cannot be proven resumable.
120
+ * same key (self-healing) and the entry otherwise ages out via TTL.
152
121
  */
153
- export declare function isValidShellHit(entry: ShellCacheEntry, buildVersion: string): boolean;
122
+ export declare function isValidShellHit(entry: Pick<ShellCacheEntry, "reactVersion" | "buildVersion">, buildVersion: string): boolean;
154
123
  /**
155
124
  * DOCUMENT-half structural gate and type narrowing, without decoding the
156
125
  * prelude: the prelude is a string and the postponed blob parses. Partial
@@ -167,7 +136,7 @@ export declare function isValidShellHit(entry: ShellCacheEntry, buildVersion: st
167
136
  export declare function hasIntactShellPayload(entry: ShellCacheEntry): entry is DocumentShellCacheEntry;
168
137
  /** A document shell ready to serve: its prelude decoded exactly once. */
169
138
  export interface ShellDocument {
170
- entry: ShellCacheEntry;
139
+ entry: ShellEntryHead;
171
140
  prelude: Uint8Array;
172
141
  /** React's postponed state, parse-checked (null = DATA variant). */
173
142
  postponed: string | null;
@@ -176,7 +145,7 @@ export interface ShellDocument {
176
145
  * after a prelude-first read (SegmentCacheStore.readShellDocument), which
177
146
  * only the tail awaits.
178
147
  */
179
- snapshot: ShellSnapshotRecord[] | undefined | Promise<ShellSnapshotRecord[] | undefined>;
148
+ snapshot: ShellSnapshotRecord[] | Promise<ShellSnapshotRecord[] | undefined>;
180
149
  /** Why a prelude-first read's snapshot is missing (ShellDocumentRead). */
181
150
  snapshotFailure?: Promise<ShellSnapshotFailure | undefined>;
182
151
  /** The prelude-first read's stats, when perf metrics are on. */
@@ -194,7 +163,8 @@ export interface ShellDocument {
194
163
  * A prelude-first `read` (SegmentCacheStore.readShellDocument) already carries
195
164
  * the raw bytes and a pending snapshot, so only its postponed blob is checked.
196
165
  */
197
- export declare function openShellDocument(entry: ShellCacheEntry, read?: Pick<ShellDocumentRead, "prelude" | "snapshot" | "snapshotFailure" | "stats">): ShellDocument | null;
166
+ export declare function openShellDocument(entry: ShellCacheEntry): ShellDocument | null;
167
+ export declare function openShellDocument(entry: ShellEntryHead, read: Pick<ShellDocumentRead, "prelude" | "snapshot" | "snapshotFailure" | "stats">): ShellDocument | null;
198
168
  /**
199
169
  * Prelude enqueue granularity. A streaming compressor in front of the worker
200
170
  * emits its first byte only after compressing the whole write it was handed:
@@ -228,7 +198,7 @@ export interface ShellTailTiming {
228
198
  snapshotReadMs?: number;
229
199
  /** Snapshot JSON.parse CPU (reads 0 on a deployed worker: see bytes). */
230
200
  snapshotParseMs?: number;
231
- /** Snapshot records by family, e.g. `segment:1/item:5` (no commas: it rides a Server-Timing desc). */
201
+ /** Snapshot records by family, e.g. `segment:1/loader:2` (no commas: it rides a Server-Timing desc). */
232
202
  snapshotRecords?: string;
233
203
  /** Records the capture pruned from the snapshot, same format (ShellCacheEntry.prunedRecords). */
234
204
  snapshotPruned?: string;
@@ -251,7 +221,7 @@ export interface ShellTailTiming {
251
221
  }
252
222
  /**
253
223
  * Compact single-line form for the console log and the Server-Timing mirror's
254
- * `desc`: alphanumerics and `=`, `-`, `:`, `/` only (records=segment:1 pruned=item:5),
224
+ * `desc`: alphanumerics and `=`, `-`, `:`, `/` only (records=segment:1/loader:2 pruned=loader:1),
255
225
  * so no quoted-string escaping is needed. Offsets are from the commit; the
256
226
  * `-cpu` fields are CPU-only durations.
257
227
  */
@@ -317,7 +287,8 @@ export declare function partitionBuildShellCheckDone(pathname: string, routeName
317
287
  */
318
288
  export declare function notePartitionBuildShellCheck(pathname: string, routeName: string | undefined, found: boolean): void;
319
289
  /**
320
- * @internal Reset the serve path's once-per-key warnings and buffered tail
321
- * timings. Tests only (testing/serve-shell-request.ts resetShellTestState).
290
+ * @internal Reset the serve path's once-per-key warnings (the shell path's
291
+ * one registry), its build-shell probe memo and buffered tail timings. Tests
292
+ * only (testing/serve-shell-request.ts resetShellTestState).
322
293
  */
323
294
  export declare function resetShellServeStateForTests(): void;
@@ -32,6 +32,8 @@ export interface RscPayload {
32
32
  resolvedIds?: string[];
33
33
  /** Merged route params from the matched route */
34
34
  params?: Record<string, string>;
35
+ /** Matched route name, when named (transition({ when }) route names). */
36
+ routeName?: string;
35
37
  slots?: Record<string, SlotState>;
36
38
  /**
37
39
  * Intercept TARGET route names reachable from this location as a
@@ -19,6 +19,13 @@ export interface RenderSegmentsOptions {
19
19
  forceAwait?: boolean;
20
20
  /** Seeded descendant client-route pending state for testing. */
21
21
  outletPending?: boolean;
22
+ /**
23
+ * This commit's transition({ when }) decision was false
24
+ * (browser/transition-when.ts): the navigation is urgent, so no segment
25
+ * animates. Every router <ViewTransition> stays in the tree with each class
26
+ * "none", so the element type never changes; keys never read this (#995).
27
+ */
28
+ transitionGatedOff?: boolean;
22
29
  /**
23
30
  * Intercept segments to inject into the tree.
24
31
  * These are parallel segments from intercept routes that need to be