@rangojs/router 0.16.0 → 0.18.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 (309) hide show
  1. package/README.md +255 -89
  2. package/dist/testing/vitest.js +252 -0
  3. package/dist/types/browser/cookie-name.d.ts +6 -0
  4. package/dist/types/browser/history-state.d.ts +16 -0
  5. package/dist/types/browser/navigation-transaction.d.ts +6 -0
  6. package/dist/types/browser/partial-update.d.ts +11 -0
  7. package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
  8. package/dist/types/browser/rsc-router.d.ts +1 -1
  9. package/dist/types/browser/scroll-restoration.d.ts +7 -0
  10. package/dist/types/cache/cache-exec-scope.d.ts +18 -1
  11. package/dist/types/cache/cache-key-utils.d.ts +17 -2
  12. package/dist/types/cache/cache-policy.d.ts +17 -0
  13. package/dist/types/cache/cache-scope.d.ts +132 -19
  14. package/dist/types/cache/cache-tag.d.ts +92 -7
  15. package/dist/types/cache/cf/cf-base64.d.ts +6 -0
  16. package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
  17. package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
  18. package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
  19. package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
  20. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
  21. package/dist/types/cache/handle-capture.d.ts +41 -3
  22. package/dist/types/cache/handle-snapshot.d.ts +54 -13
  23. package/dist/types/cache/index.d.ts +1 -0
  24. package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
  25. package/dist/types/cache/segment-codec.d.ts +10 -3
  26. package/dist/types/cache/shell-memo.d.ts +178 -0
  27. package/dist/types/cache/shell-snapshot.d.ts +110 -21
  28. package/dist/types/cache/tag-invalidation.d.ts +30 -3
  29. package/dist/types/cache/taint.d.ts +1 -1
  30. package/dist/types/cache/types.d.ts +220 -44
  31. package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
  32. package/dist/types/client.d.ts +4 -4
  33. package/dist/types/client.rsc.d.ts +4 -5
  34. package/dist/types/components/DefaultDocument.d.ts +5 -2
  35. package/dist/types/context-var.d.ts +6 -5
  36. package/dist/types/escape-script.d.ts +1 -1
  37. package/dist/types/handles/MetaTags.d.ts +5 -4
  38. package/dist/types/handles/Scripts.d.ts +8 -7
  39. package/dist/types/handles/meta.d.ts +2 -2
  40. package/dist/types/handles/script.d.ts +17 -16
  41. package/dist/types/href-client.d.ts +1 -1
  42. package/dist/types/html.d.ts +12 -0
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.rsc.d.ts +3 -2
  45. package/dist/types/loader-store.d.ts +7 -4
  46. package/dist/types/prerender/build-shell-capture.d.ts +11 -4
  47. package/dist/types/reverse.d.ts +36 -4
  48. package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
  49. package/dist/types/route-definition/helpers-types.d.ts +33 -9
  50. package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
  51. package/dist/types/route-types.d.ts +1 -1
  52. package/dist/types/router/debug-manifest.d.ts +3 -2
  53. package/dist/types/router/error-handling.d.ts +20 -0
  54. package/dist/types/router/handler-context.d.ts +6 -0
  55. package/dist/types/router/instrument.d.ts +8 -0
  56. package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
  57. package/dist/types/router/middleware-types.d.ts +9 -3
  58. package/dist/types/router/router-context.d.ts +3 -1
  59. package/dist/types/router/router-interfaces.d.ts +24 -2
  60. package/dist/types/router/router-options.d.ts +8 -5
  61. package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
  62. package/dist/types/router/segment-resolution/loader-cache.d.ts +66 -1
  63. package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
  64. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +23 -12
  65. package/dist/types/router/segment-resolution/mask-nested.d.ts +67 -26
  66. package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
  67. package/dist/types/router/segment-wrappers.d.ts +1 -1
  68. package/dist/types/rsc/full-payload.d.ts +14 -0
  69. package/dist/types/rsc/handler.d.ts +1 -1
  70. package/dist/types/rsc/response-route-handler.d.ts +1 -1
  71. package/dist/types/rsc/rsc-rendering.d.ts +1 -2
  72. package/dist/types/rsc/shell-build-manifest.d.ts +8 -0
  73. package/dist/types/rsc/shell-capture-constants.d.ts +61 -6
  74. package/dist/types/rsc/shell-capture.d.ts +151 -19
  75. package/dist/types/rsc/shell-serve.d.ts +140 -17
  76. package/dist/types/rsc/ssr-setup.d.ts +6 -6
  77. package/dist/types/rsc/types.d.ts +17 -0
  78. package/dist/types/server/context.d.ts +139 -15
  79. package/dist/types/server/cookie-store.d.ts +21 -0
  80. package/dist/types/server/handle-store.d.ts +26 -2
  81. package/dist/types/server/request-context.d.ts +182 -53
  82. package/dist/types/ssr/index.d.ts +24 -0
  83. package/dist/types/ssr/ssr-root.d.ts +9 -8
  84. package/dist/types/static-handler.d.ts +4 -1
  85. package/dist/types/testing/flight.entry.d.ts +7 -0
  86. package/dist/types/testing/generated-routes.d.ts +2 -2
  87. package/dist/types/testing/internal/context.d.ts +1 -1
  88. package/dist/types/testing/render-route.d.ts +32 -6
  89. package/dist/types/testing/run-loader.d.ts +18 -3
  90. package/dist/types/testing/serve-shell-request.d.ts +132 -0
  91. package/dist/types/testing/shell-status.d.ts +23 -10
  92. package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
  93. package/dist/types/testing/vitest.d.ts +35 -1
  94. package/dist/types/theme/ThemeScript.d.ts +3 -3
  95. package/dist/types/types/cache-types.d.ts +14 -10
  96. package/dist/types/types/handler-context.d.ts +28 -1
  97. package/dist/types/types/loader-types.d.ts +8 -6
  98. package/dist/types/urls/pattern-types.d.ts +22 -18
  99. package/dist/types/urls/response-types.d.ts +3 -12
  100. package/dist/types/use-loader.d.ts +12 -3
  101. package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
  102. package/dist/types/vite/rango.d.ts +1 -1
  103. package/dist/types/vite/router-discovery.d.ts +29 -2
  104. package/dist/vite/index.js +1420 -1348
  105. package/package.json +2 -2
  106. package/skills/api-client/SKILL.md +22 -10
  107. package/skills/breadcrumbs/SKILL.md +75 -22
  108. package/skills/bundle-analysis/SKILL.md +22 -22
  109. package/skills/cache-guide/SKILL.md +306 -124
  110. package/skills/caching/SKILL.md +530 -98
  111. package/skills/catalog.json +16 -16
  112. package/skills/client-urls/SKILL.md +65 -38
  113. package/skills/cloudflare/SKILL.md +87 -20
  114. package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
  115. package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
  116. package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
  117. package/skills/comparison/SKILL.md +5 -0
  118. package/skills/comparison/references/framework-comparison.md +75 -57
  119. package/skills/composability/SKILL.md +38 -29
  120. package/skills/css/SKILL.md +10 -13
  121. package/skills/debug-manifest/SKILL.md +74 -31
  122. package/skills/defer-hydration/SKILL.md +52 -31
  123. package/skills/deployment-caching/SKILL.md +11 -3
  124. package/skills/document-cache/SKILL.md +98 -28
  125. package/skills/fonts/SKILL.md +16 -8
  126. package/skills/handler-use/SKILL.md +55 -17
  127. package/skills/hooks/SKILL.md +28 -20
  128. package/skills/hooks/data.md +23 -3
  129. package/skills/hooks/handle-and-actions.md +34 -17
  130. package/skills/hooks/navigation.md +39 -10
  131. package/skills/hooks/outlets.md +13 -6
  132. package/skills/hooks/state.md +39 -15
  133. package/skills/hooks/urls.md +7 -5
  134. package/skills/host-router/SKILL.md +64 -12
  135. package/skills/i18n/SKILL.md +60 -34
  136. package/skills/intercept/SKILL.md +161 -26
  137. package/skills/layout/SKILL.md +106 -50
  138. package/skills/links/SKILL.md +51 -19
  139. package/skills/loader/SKILL.md +386 -128
  140. package/skills/middleware/SKILL.md +129 -26
  141. package/skills/migrate-nextjs/SKILL.md +156 -70
  142. package/skills/migrate-nextjs/backend-host-swap.md +5 -2
  143. package/skills/migrate-react-router/SKILL.md +51 -39
  144. package/skills/migrate-react-router/component-migration.md +28 -7
  145. package/skills/migrate-react-router/data-and-actions.md +21 -6
  146. package/skills/migrate-react-router/route-mapping.md +19 -10
  147. package/skills/mime-routes/SKILL.md +12 -7
  148. package/skills/observability/SKILL.md +92 -14
  149. package/skills/parallel/SKILL.md +88 -47
  150. package/skills/ppr/SKILL.md +866 -379
  151. package/skills/prerender/SKILL.md +210 -108
  152. package/skills/rango/SKILL.md +115 -65
  153. package/skills/react-compiler/SKILL.md +6 -5
  154. package/skills/response-routes/SKILL.md +133 -25
  155. package/skills/route/SKILL.md +170 -60
  156. package/skills/router-setup/SKILL.md +420 -240
  157. package/skills/scripts/SKILL.md +39 -21
  158. package/skills/server-actions/SKILL.md +231 -59
  159. package/skills/shell-manifest/SKILL.md +28 -14
  160. package/skills/streams-and-websockets/SKILL.md +32 -14
  161. package/skills/tailwind/SKILL.md +37 -33
  162. package/skills/testing/SKILL.md +73 -33
  163. package/skills/testing/cache-prerender.md +60 -33
  164. package/skills/testing/client-components.md +59 -6
  165. package/skills/testing/e2e-parity.md +12 -2
  166. package/skills/testing/flight.md +19 -11
  167. package/skills/testing/handles.md +8 -5
  168. package/skills/testing/loader.md +26 -6
  169. package/skills/testing/middleware.md +8 -3
  170. package/skills/testing/predicates.md +120 -0
  171. package/skills/testing/render-handler.md +70 -22
  172. package/skills/testing/response-routes.md +11 -4
  173. package/skills/testing/reverse-and-types.md +20 -14
  174. package/skills/testing/serve-shell-request.md +188 -0
  175. package/skills/testing/server-actions.md +12 -3
  176. package/skills/testing/server-tree.md +9 -0
  177. package/skills/testing/setup.md +9 -5
  178. package/skills/theme/SKILL.md +155 -30
  179. package/skills/typesafety/SKILL.md +20 -9
  180. package/skills/typesafety/env-and-bindings.md +137 -50
  181. package/skills/typesafety/generated-files-and-cli.md +26 -14
  182. package/skills/typesafety/params-and-search.md +44 -19
  183. package/skills/typesafety/route-types.md +50 -14
  184. package/skills/use-cache/SKILL.md +224 -83
  185. package/skills/vercel/SKILL.md +35 -13
  186. package/skills/view-transitions/SKILL.md +42 -21
  187. package/src/__augment-tests__/augmented.check.ts +26 -1
  188. package/src/browser/cookie-name.ts +23 -0
  189. package/src/browser/history-state.ts +23 -0
  190. package/src/browser/index.ts +2 -2
  191. package/src/browser/navigation-bridge.ts +3 -4
  192. package/src/browser/navigation-transaction.ts +22 -2
  193. package/src/browser/partial-update.ts +35 -25
  194. package/src/browser/react/ScrollRestoration.tsx +6 -6
  195. package/src/browser/rsc-router.tsx +6 -1
  196. package/src/browser/scroll-restoration.ts +53 -6
  197. package/src/cache/cache-exec-scope.ts +37 -4
  198. package/src/cache/cache-key-utils.ts +23 -8
  199. package/src/cache/cache-policy.ts +22 -0
  200. package/src/cache/cache-runtime.ts +264 -68
  201. package/src/cache/cache-scope.ts +419 -43
  202. package/src/cache/cache-tag.ts +375 -11
  203. package/src/cache/cf/cf-base64.ts +36 -4
  204. package/src/cache/cf/cf-cache-constants.ts +12 -0
  205. package/src/cache/cf/cf-cache-store.ts +990 -348
  206. package/src/cache/cf/cf-cache-types.ts +32 -4
  207. package/src/cache/cf/cf-shell-frame.ts +258 -0
  208. package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
  209. package/src/cache/document-cache.ts +15 -0
  210. package/src/cache/handle-capture.ts +90 -10
  211. package/src/cache/handle-snapshot.ts +133 -28
  212. package/src/cache/index.ts +2 -0
  213. package/src/cache/isolate-tag-memo.ts +308 -0
  214. package/src/cache/segment-codec.ts +26 -7
  215. package/src/cache/shell-memo.ts +341 -0
  216. package/src/cache/shell-snapshot.ts +217 -27
  217. package/src/cache/tag-invalidation.ts +108 -22
  218. package/src/cache/taint.ts +1 -1
  219. package/src/cache/types.ts +225 -44
  220. package/src/cache/vercel/vercel-cache-store.ts +545 -61
  221. package/src/client.rsc.tsx +10 -9
  222. package/src/client.tsx +5 -4
  223. package/src/components/DefaultDocument.tsx +7 -2
  224. package/src/context-var.ts +6 -5
  225. package/src/escape-script.ts +1 -1
  226. package/src/handles/MetaTags.tsx +13 -11
  227. package/src/handles/Scripts.tsx +11 -10
  228. package/src/handles/meta.ts +2 -2
  229. package/src/handles/script.ts +17 -16
  230. package/src/href-client.ts +1 -1
  231. package/src/html.ts +12 -0
  232. package/src/index.rsc.ts +5 -0
  233. package/src/index.ts +1 -0
  234. package/src/loader-store.ts +7 -4
  235. package/src/prerender/build-shell-capture.ts +73 -22
  236. package/src/reverse.ts +44 -4
  237. package/src/route-definition/dsl-helpers.ts +121 -33
  238. package/src/route-definition/helpers-types.ts +33 -9
  239. package/src/route-definition/resolve-handler-use.ts +121 -6
  240. package/src/route-types.ts +0 -3
  241. package/src/router/debug-manifest.ts +10 -2
  242. package/src/router/error-handling.ts +51 -15
  243. package/src/router/handler-context.ts +71 -28
  244. package/src/router/instrument.ts +54 -2
  245. package/src/router/intercept-resolution.ts +141 -43
  246. package/src/router/loader-resolution.ts +115 -39
  247. package/src/router/match-api.ts +40 -26
  248. package/src/router/match-handlers.ts +5 -0
  249. package/src/router/match-middleware/background-revalidation.ts +161 -96
  250. package/src/router/match-middleware/cache-lookup.ts +110 -10
  251. package/src/router/match-middleware/cache-store.ts +48 -101
  252. package/src/router/middleware-types.ts +9 -6
  253. package/src/router/middleware.ts +75 -13
  254. package/src/router/prerender-match.ts +59 -19
  255. package/src/router/route-snapshot.ts +11 -1
  256. package/src/router/router-context.ts +2 -0
  257. package/src/router/router-interfaces.ts +25 -2
  258. package/src/router/router-options.ts +8 -5
  259. package/src/router/segment-resolution/fresh.ts +62 -21
  260. package/src/router/segment-resolution/helpers.ts +4 -2
  261. package/src/router/segment-resolution/loader-cache.ts +407 -76
  262. package/src/router/segment-resolution/loader-mask.ts +12 -22
  263. package/src/router/segment-resolution/loader-snapshot.ts +208 -56
  264. package/src/router/segment-resolution/mask-nested.ts +138 -44
  265. package/src/router/segment-resolution/revalidation.ts +61 -16
  266. package/src/router/segment-wrappers.ts +4 -0
  267. package/src/rsc/full-payload.ts +25 -1
  268. package/src/rsc/handler.ts +14 -2
  269. package/src/rsc/progressive-enhancement.ts +3 -2
  270. package/src/rsc/render-pipeline.ts +3 -0
  271. package/src/rsc/response-cache-serve.ts +9 -6
  272. package/src/rsc/response-route-handler.ts +11 -3
  273. package/src/rsc/rsc-rendering.ts +608 -225
  274. package/src/rsc/shell-build-manifest.ts +27 -9
  275. package/src/rsc/shell-capture-constants.ts +73 -6
  276. package/src/rsc/shell-capture.ts +1068 -296
  277. package/src/rsc/shell-serve.ts +316 -34
  278. package/src/rsc/ssr-setup.ts +14 -8
  279. package/src/rsc/types.ts +18 -0
  280. package/src/server/context.ts +300 -32
  281. package/src/server/cookie-store.ts +87 -61
  282. package/src/server/handle-store.ts +232 -7
  283. package/src/server/request-context.ts +297 -67
  284. package/src/ssr/index.tsx +136 -44
  285. package/src/ssr/ssr-root.tsx +9 -8
  286. package/src/static-handler.ts +4 -1
  287. package/src/testing/flight-runtime.d.ts +21 -0
  288. package/src/testing/flight.entry.ts +14 -0
  289. package/src/testing/generated-routes.ts +2 -2
  290. package/src/testing/internal/context.ts +1 -1
  291. package/src/testing/internal/flight-client-globals.ts +7 -5
  292. package/src/testing/render-route.tsx +85 -24
  293. package/src/testing/run-loader.ts +68 -6
  294. package/src/testing/serve-shell-request.ts +378 -0
  295. package/src/testing/shell-status.ts +34 -12
  296. package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
  297. package/src/testing/vitest.ts +62 -1
  298. package/src/theme/ThemeProvider.tsx +7 -6
  299. package/src/theme/ThemeScript.tsx +3 -3
  300. package/src/types/cache-types.ts +14 -10
  301. package/src/types/handler-context.ts +28 -1
  302. package/src/types/loader-types.ts +8 -6
  303. package/src/urls/pattern-types.ts +22 -18
  304. package/src/urls/response-types.ts +3 -23
  305. package/src/use-loader.tsx +12 -3
  306. package/src/vite/discovery/shell-prerender-phase.ts +9 -0
  307. package/src/vite/plugins/use-cache-transform.ts +118 -74
  308. package/src/vite/rango.ts +7 -3
  309. package/src/vite/router-discovery.ts +14 -4
@@ -12,6 +12,7 @@ import type { ResolvedSegment } from "../types.js";
12
12
  import type { SegmentCacheStore } from "./types.js";
13
13
  import type { RequestContext } from "../server/request-context.js";
14
14
  export declare function resolveCacheTags(config: PartialCacheOptions | false, ctx: RequestContext | undefined): string[] | undefined;
15
+ type CacheKeyFn = NonNullable<PartialCacheOptions["key"]>;
15
16
  /**
16
17
  * Discriminated outcome of a route cache lookup — see
17
18
  * {@link CacheScope.lookupRouteDetailed} for what each status licenses.
@@ -44,11 +45,48 @@ export type CacheRouteLookupOutcome = {
44
45
  */
45
46
  export declare class CacheScope {
46
47
  private readonly defaultKeyPrefix?;
48
+ /**
49
+ * @internal shortCode of the outermost cache() entry of this scope's
50
+ * enabled chain (createCacheScope). Entries above it are live: their
51
+ * segments are not stored and resolve fresh on a hit (withCacheLookup).
52
+ * Undefined covers the whole matched chain (the implicit shell doc scope,
53
+ * a ppr route).
54
+ */
55
+ readonly boundary?: string | undefined;
47
56
  readonly config: PartialCacheOptions | false;
48
57
  readonly parent: CacheScope | null;
49
58
  /** Explicit store from cache() options, if specified */
50
59
  private readonly explicitStore;
51
- constructor(config: PartialCacheOptions | false, parent?: CacheScope | null, defaultKeyPrefix?: "doc" | undefined);
60
+ /**
61
+ * @internal The `key()` functions that partition this scope's records,
62
+ * outermost first: every cache() on the parent chain that sets one, this
63
+ * scope's last (#970). `cache(false)` adds none and does not cut the chain,
64
+ * so a cache() re-enabled under it stays in the partition. Before, the
65
+ * innermost config alone decided the key: an inner cache() without `key()`
66
+ * wrote under the default key and an inner `key()` dropped the outer one,
67
+ * so a request in one partition HIT another partition's inner records.
68
+ */
69
+ readonly keyFns: readonly CacheKeyFn[];
70
+ /** Whether this scope's own config sets `key()` (the last of keyFns). */
71
+ private readonly hasOwnKey;
72
+ constructor(config: PartialCacheOptions | false, parent?: CacheScope | null, defaultKeyPrefix?: "doc" | undefined,
73
+ /**
74
+ * @internal shortCode of the outermost cache() entry of this scope's
75
+ * enabled chain (createCacheScope). Entries above it are live: their
76
+ * segments are not stored and resolve fresh on a hit (withCacheLookup).
77
+ * Undefined covers the whole matched chain (the implicit shell doc scope,
78
+ * a ppr route).
79
+ */
80
+ boundary?: string | undefined);
81
+ /**
82
+ * @internal Whether a segment belongs to this scope's cache entry. ShortCodes are
83
+ * hierarchical (server/context.ts getShortCode: parent shortCode + include
84
+ * scope + type letter + counter), so the boundary's subtree is every id that
85
+ * extends the boundary shortCode at a non-digit (`C1` must not claim `C10`).
86
+ * Intercept slot segments ride the target route's entry wherever the
87
+ * intercept is declared.
88
+ */
89
+ covers(id: string, namespace?: string): boolean;
52
90
  /**
53
91
  * Whether caching is enabled for this scope
54
92
  */
@@ -81,6 +119,57 @@ export declare class CacheScope {
81
119
  * @internal
82
120
  */
83
121
  private resolveKey;
122
+ /**
123
+ * A shell captured from a route record this request read or wrote must not
124
+ * outlive it (noteRouteRecordWindow). The implicit doc scope's own record
125
+ * is the shell's, so it notes nothing.
126
+ */
127
+ private noteRecordWindow;
128
+ /**
129
+ * @internal This scope's record key for `defaultKey`, resolved once per
130
+ * request: a ppr route's shell partition (resolvePartition) and the record
131
+ * lookup share the `key()` runs, and a rejection is shared too.
132
+ *
133
+ * With `key()` functions on the chain (keyFns) the parts are their results,
134
+ * outermost first, composed by composeCacheKeys (a single part raw), so a
135
+ * nested cache() keys its records within the enclosing partition (#970).
136
+ * A scope whose own config sets no `key()` appends its own default key
137
+ * (resolveDefaultKey). Reusing the outer `key()` result alone would give
138
+ * every route under the inner cache() one record: a `key()` replaces the
139
+ * whole default key, so an outer key that names no route (`tier:gold`)
140
+ * would make `/a` HIT `/b`'s record. A scope with its own `key()` adds no
141
+ * default key: a `key()` is a full override, and no keyGenerator runs.
142
+ * Without `key()` on the chain it is resolveDefaultKey alone. With one but
143
+ * no request context it rejects (keyWithoutContextError).
144
+ *
145
+ * Each `key()` result lives on the request context (`_resolvedCacheKeys`),
146
+ * by function: it runs once per request whatever the default key
147
+ * (document, partial or `doc` shell prefix) and however many scopes share
148
+ * it (sibling routes under one keyed cache()). A shell capture, whose
149
+ * context is `Object.create` of the request's (shell-capture.ts), reads the
150
+ * foreground's results through the prototype chain and never runs `key()`
151
+ * itself: a `key()` calling `cookies()` would trip the capture guard there,
152
+ * and a capture must store the partition its request resolved.
153
+ */
154
+ resolveKeyFrom(defaultKey: string): Promise<string>;
155
+ /**
156
+ * @internal The request partition of a ppr route's shell under this scope
157
+ * (resolveShellPartition): the chain's `key()` results, composed like the
158
+ * record key but without the default key, which the URL-based shell key
159
+ * already carries. A scope without its own `key()` whose store has a
160
+ * keyGenerator adds that result when it differs from the `doc` default
161
+ * key, as an unkeyed scope's partition always did: the record is split by
162
+ * it, so the shell must be too. Undefined (synchronously, with no work)
163
+ * when nothing can partition; null when nothing does.
164
+ */
165
+ resolvePartition(pathname: string, params: Record<string, string> | undefined): Promise<string | null> | undefined;
166
+ /** The chain's `key()` results, each once per request (memoizedKey). */
167
+ private resolveKeyResults;
168
+ /**
169
+ * This scope's store keyGenerator result for `defaultKey` (once per request
170
+ * and default key), else `defaultKey` (resolveCacheKey).
171
+ */
172
+ private resolveDefaultKey;
84
173
  /**
85
174
  * @internal Whether a cache read/write is allowed for the current request:
86
175
  * the scope is enabled AND its `condition` (if any) returns true. "read"
@@ -127,8 +216,10 @@ export declare class CacheScope {
127
216
  * @param pathname - URL pathname for cache key generation
128
217
  * @param params - Route params for cache key generation
129
218
  * @param isIntercept - Whether this is an intercept navigation (uses different cache key)
219
+ * @param claimLoaderPushes - The handler context's _claimLoaderPushes, for
220
+ * restoreHandles' loader-owned values
130
221
  */
131
- lookupRoute(pathname: string, params: Record<string, string>, isIntercept?: boolean): Promise<{
222
+ lookupRoute(pathname: string, params: Record<string, string>, isIntercept?: boolean, claimLoaderPushes?: (loaderId: string) => boolean): Promise<{
132
223
  segments: ResolvedSegment[];
133
224
  shouldRevalidate: boolean;
134
225
  } | null>;
@@ -150,7 +241,7 @@ export declare class CacheScope {
150
241
  * A corrupt entry that was evicted reads as `miss`: the store was consulted
151
242
  * and holds nothing servable, which is the post-eviction truth.
152
243
  */
153
- lookupRouteDetailed(pathname: string, params: Record<string, string>, isIntercept?: boolean): Promise<CacheRouteLookupOutcome>;
244
+ lookupRouteDetailed(pathname: string, params: Record<string, string>, isIntercept?: boolean, claimLoaderPushes?: (loaderId: string) => boolean): Promise<CacheRouteLookupOutcome>;
154
245
  /**
155
246
  * Record this scope's segment-DSL cache({ tags }) into the request tag union
156
247
  * synchronously, under the same gate cacheRoute() uses for a write.
@@ -179,11 +270,28 @@ export declare class CacheScope {
179
270
  cacheRoute(pathname: string, params: Record<string, string>, segments: ResolvedSegment[], isIntercept?: boolean): Promise<void>;
180
271
  }
181
272
  /**
182
- * Create a cache scope from entry's cache config
273
+ * @internal The request partition of a ppr route's shell: with a route
274
+ * cache() scope, its CacheScope.resolvePartition (the chain's `key()`
275
+ * results, composed, plus a keyGenerator's contribution for a scope without
276
+ * its own `key()` (#970)); with none, the app store's keyGenerator result
277
+ * given the document default key. Undefined (synchronously, with no work)
278
+ * when neither applies: the shell key stays host + path + filtered search.
279
+ * Resolves to null when the partition is the default key itself (a
280
+ * keyGenerator that returns it unchanged): that partitions nothing, so the
281
+ * shell stays unpartitioned and keeps its build shell. The shell's key, its
282
+ * read and capture, and partial replay all use it, so a visitor is only
283
+ * served its own partition. A rejected promise is a failed key resolution:
284
+ * the caller serves no shell.
285
+ */
286
+ export declare function resolveShellPartition(routeScope: CacheScope | null | undefined, appStore: SegmentCacheStore | null | undefined, pathname: string, params: Record<string, string> | undefined): Promise<string | null> | undefined;
287
+ /**
288
+ * Create a cache scope from entry's cache config. `shortCode` is the cache()
289
+ * entry's: a scope nested in an enabled parent keeps the parent's boundary
290
+ * (one entry covers both), any other opens its own at this entry.
183
291
  */
184
292
  export declare function createCacheScope(config: {
185
293
  options: PartialCacheOptions | false;
186
- } | undefined, parent?: CacheScope | null): CacheScope | null;
294
+ } | undefined, parent?: CacheScope | null, shortCode?: string): CacheScope | null;
187
295
  type ShellImplicitCacheMarker = NonNullable<RequestContext["_shellImplicitCache"]>;
188
296
  /**
189
297
  * Mint the implicit doc-level scope for a `_shellImplicitCache` marker: key
@@ -192,24 +300,29 @@ type ShellImplicitCacheMarker = NonNullable<RequestContext["_shellImplicitCache"
192
300
  * {@link resolveShellImplicitCacheScope} (routes that derived no scope) and
193
301
  * the explicit-scope composition sites (capture doc record in the cache-store
194
302
  * middleware, seeded replay fallback in withCacheLookup) so both ends of the
195
- * shell contract resolve the SAME canonical document key.
303
+ * shell contract resolve the SAME canonical document key. A document HIT
304
+ * tail's marker carries the entry's own key (`fixedDocKey`), which wins over
305
+ * key resolution.
196
306
  */
197
307
  export declare function createShellImplicitDocScope(marker: ShellImplicitCacheMarker): CacheScope;
198
308
  /**
199
- * Shell fast path: when the route tree derived NO cache scope and the current
200
- * request context carries the `_shellImplicitCache` marker (a shell capture,
201
- * an eligible HIT tail, or a normal partial navigation replay), substitute an
202
- * implicit doc-level scope so withCacheLookup/withCacheStore treat the WHOLE
203
- * matched route as a cache() boundary — the shell entry IS a cache() of the
204
- * handler layer, with loaders as the live carve-outs
205
- * (resolveFreshLoadersAndYield).
309
+ * The doc record scope: when the current request context carries the
310
+ * `_shellImplicitCache` marker (a shell capture, a document HIT tail, or a
311
+ * normal partial navigation replay), substitute an implicit doc-level scope
312
+ * so withCacheLookup/withCacheStore treat the WHOLE matched route as a
313
+ * cache() boundary — the shell entry IS a cache() of the handler layer, with
314
+ * loaders as the live carve-outs (resolveFreshLoadersAndYield).
206
315
  *
207
- * An existing scope — including an explicit cache(false) opt-out — always
208
- * wins HERE: the consumer's cache() semantics (their ttl/swr/store/condition)
209
- * are never overridden, and cache(false) keeps the tail on the full handler
210
- * re-run path. On the navigation-replay serve path the marker still composes
211
- * with an explicit scope downstream (withCacheLookup's seeded fallback after
212
- * an explicit-tier miss) — see `onExplicitHit` on `_shellImplicitCache`.
316
+ * A document HIT tail (`docTail`) always gets the implicit scope: it replays
317
+ * the shell's own record and never consults a route-derived scope, whose
318
+ * opt-outs the serve gate evaluated before the commit (shellServePlan). Every
319
+ * other marker leaves an existing scope — including an explicit cache(false)
320
+ * — in place: the consumer's cache() semantics (their ttl/swr/store/condition)
321
+ * are never overridden. On the navigation-replay serve path the marker still
322
+ * composes with an explicit scope downstream (withCacheLookup's seeded
323
+ * fallback after an explicit-tier miss) — see `onExplicitHit` on
324
+ * `_shellImplicitCache`; during a capture, recordShellCaptureDocRecord
325
+ * (cache-store.ts) writes the record for such a scope.
213
326
  */
214
327
  export declare function resolveShellImplicitCacheScope(scope: CacheScope | null): CacheScope | null;
215
328
  export {};
@@ -10,6 +10,54 @@
10
10
  * profile/DSL tags before storing.
11
11
  */
12
12
  import { type RequestContext } from "../server/request-context.js";
13
+ import { type LoaderIdentityRead } from "../server/context.js";
14
+ /**
15
+ * Arm the record tag owners for `ctx`: its match resolved a cache scope, so
16
+ * it can write a route cache() record (match-api.ts). A capture's or
17
+ * background re-render's derived context inherits the flag.
18
+ */
19
+ export declare function armRecordTagOwners(ctx?: RequestContext | undefined): void;
20
+ /** Whether `ctx` records tag owners (see armRecordTagOwners). */
21
+ export declare function recordTagOwnersArmed(ctx?: RequestContext | undefined): boolean;
22
+ /**
23
+ * Call `fn(arg)` inside segment `segmentId`'s tag scope: tags recorded while
24
+ * it or its async continuations run (outside a loader body) are owned by that
25
+ * segment. Unarmed, it is a plain call.
26
+ */
27
+ export declare function runInSegmentTagScope<R, A = undefined>(segmentId: string, fn: (arg: A) => R, arg?: A): R;
28
+ /**
29
+ * Record that the current owner reads loader `loaderId`'s value (ctx.use),
30
+ * so the loader's tags follow the reader onto a record. The DSL funnel
31
+ * starting a loader (resolveLoaderData, inside the DSL loader scope but no
32
+ * loader body) is not a reader.
33
+ */
34
+ export declare function linkLoaderTags(loaderId: string, ctx?: RequestContext | undefined): void;
35
+ /**
36
+ * Record `tags` as loader `loaderId`'s own, read outside its body (its
37
+ * cache() config tags, or a loader-cache HIT's stored tags):
38
+ * recordRequestTags with an explicit owner.
39
+ */
40
+ export declare function recordLoaderTags(loaderId: string, tags: Iterable<string> | undefined, ctx?: RequestContext | undefined): void;
41
+ /**
42
+ * The tags segment `segmentId`'s content recorded in `ctx`: its own, plus
43
+ * those of every loader it consumed, transitively.
44
+ */
45
+ export declare function getSegmentTags(ctx: RequestContext, segmentId: string): ReadonlySet<string>;
46
+ /**
47
+ * Record `tags` onto each of `segmentIds` (a route cache() HIT replaying
48
+ * those segments): a record written from the replay, such as a shell
49
+ * capture's doc record (match-middleware/cache-store.ts), then carries them
50
+ * as a fresh render's record would. Unarmed, a no-op.
51
+ */
52
+ export declare function recordSegmentTags(segmentIds: readonly string[], tags: Iterable<string> | undefined, ctx?: RequestContext | undefined): void;
53
+ /**
54
+ * The owner of the loaders a shell capture bakes (loader-cache.ts bake
55
+ * lane): their data is shell material that no handler reads, so their tags
56
+ * reach the shell through this owner (shell-capture.ts), not a record.
57
+ */
58
+ export declare const SHELL_BAKE_TAG_OWNER: string;
59
+ /** Link loader `loaderId`'s tags to `ownerId` (see SHELL_BAKE_TAG_OWNER). */
60
+ export declare function linkLoaderTagsTo(ownerId: string, loaderId: string, ctx?: RequestContext | undefined): void;
13
61
  export declare function normalizeTag(tag: string): string | null;
14
62
  export declare function normalizeTags(tags: Iterable<string>): string[];
15
63
  /**
@@ -32,14 +80,15 @@ export declare function normalizeTags(tags: Iterable<string>): string[];
32
80
  * cache" in its tree. This is PPR's DERIVATIVE invalidation: PPR is
33
81
  * execution-PRESERVING (everything still runs underneath; only document bytes
34
82
  * are shortcut), so its tags ride this existing instrument rather than a
35
- * first-class ppr key/tag API. The shell-expiry invariant holds by
36
- * construction — baked ⇒ evicts (bake-lane loaders execute during capture and
37
- * record here), hole ⇒ fresh (masked loaders behind a renderable loading()
38
- * never execute during capture, so nothing under a hole can tag the shell).
83
+ * first-class ppr key/tag API. Whatever renders into the shell records here,
84
+ * at capture or on the route's cache() record the capture replays. A masked
85
+ * live-lane loader never executes at capture, so its own tags reach a shell
86
+ * only through a handler that reads it (ctx.use).
39
87
  *
40
- * Inside a cache() DSL segment the render-callable form records at the DOCUMENT
41
- * level, not the segment (only the "use cache" runtime enters the tag scope) — a
42
- * documented semantic, not a filtered one. An empty/whitespace-only tag is
88
+ * Inside a route cache() boundary the render-callable form also tags that
89
+ * route's cache() record, which re-records it on every HIT (#957). A loader's
90
+ * tags reach the record only when a handler consumes its value (ctx.use);
91
+ * see runInSegmentTagScope / linkLoaderTags. An empty/whitespace-only tag is
43
92
  * dropped in both forms (the render-callable form silently, via normalizeTags in
44
93
  * recordRequestTags; the scope form with a dev warning).
45
94
  *
@@ -63,6 +112,42 @@ export declare function normalizeTags(tags: Iterable<string>): string[];
63
112
  */
64
113
  export declare function cacheTag(...tags: string[]): void;
65
114
  export declare function recordRequestTags(tags: Iterable<string> | undefined, ctx?: RequestContext | undefined): void;
115
+ /**
116
+ * Arm the per-execution loader tag sets for `ctx`: its match resolved a
117
+ * loader bound with its own cache() (match-api.ts, bindsLoaderCache), or such
118
+ * a binding started (loader-cache.ts). A loader-cache MISS captures its own
119
+ * execution and encodes either way.
120
+ */
121
+ export declare function armLoaderTagSets(ctx?: RequestContext | undefined): void;
122
+ /** Whether `ctx` records per-execution loader tag sets (armLoaderTagSets). */
123
+ export declare function loaderTagSetsArmed(ctx: RequestContext | undefined): boolean;
124
+ /**
125
+ * Call `fn`, adding every tag recorded in its async chain
126
+ * (recordRequestTags, recordLoaderTags) to `into`, until a loader body
127
+ * started inside it takes over with its own set.
128
+ */
129
+ export declare function captureRecordedTags<T>(into: Set<string>, fn: () => T): T;
130
+ /** `into` also answers for every tag `from` records. */
131
+ export declare function linkRecordedTags(into: Set<string>, from: Set<string>): void;
132
+ /** Mark a loader's value promise as carrying `tags` (see readValueTags). */
133
+ export declare function tagLoaderValue(value: object, tags: Set<string>): void;
134
+ /** A loader value's tags also answer for `tags` (tagLoaderValue). */
135
+ export declare function linkValueTags(value: object, tags: Set<string>): void;
136
+ /** The current execution reads a loader's value: it takes on its tags. */
137
+ export declare function readValueTags(value: object): void;
138
+ /**
139
+ * A loader-cache HIT restores the read its entry's MISS recorded onto the
140
+ * value's set, so an unkeyed reader of the value refuses it as it would on
141
+ * the MISS (loader-cache.ts identity mark).
142
+ */
143
+ export declare function markIdentityRead(set: Set<string>, read: LoaderIdentityRead): void;
144
+ /**
145
+ * The identity read `root`'s execution recorded, or one a set it links to
146
+ * recorded, nearest first (breadth-first, so the execution's own read wins).
147
+ */
148
+ export declare function recordedIdentityRead(root: Set<string>): LoaderIdentityRead | undefined;
149
+ /** `root`'s tags plus those of every set it links to, transitively. */
150
+ export declare function flattenRecordedTags(root: Set<string>): Set<string>;
66
151
  /**
67
152
  * Run a function within a cache tag scope. Any cacheTag() calls inside `fn`
68
153
  * accumulate into the returned Set.
@@ -1,4 +1,10 @@
1
1
  /** Encode ArrayBuffer to base64 string. */
2
2
  export declare function bufferToBase64(buffer: ArrayBuffer): string;
3
+ /** Encode bytes (a view's own region only) to a base64 string. */
4
+ export declare function bytesToBase64(bytes: Uint8Array): string;
5
+ /** Decode a base64 string to bytes. Throws on a character outside the alphabet. */
6
+ export declare function base64ToBytes(base64: string): Uint8Array;
7
+ /** The byte length `base64` decodes to (padded or not), without decoding. */
8
+ export declare function base64ByteLength(base64: string): number;
3
9
  /** Decode base64 string to ArrayBuffer. */
4
10
  export declare function base64ToBuffer(base64: string): ArrayBuffer;
@@ -110,3 +110,14 @@ export declare const EDGE_READ_TIMEOUT_MS = 20;
110
110
  * Override per store via `CFCacheStoreOptions.kvReadTimeoutMs` (<= 0 disables).
111
111
  */
112
112
  export declare const KV_READ_TIMEOUT_MS = 170;
113
+ /**
114
+ * Floor (ms) on the budget for reading a PPR shell's snapshot, the rest of a
115
+ * frame whose head and prelude were already read. A document HIT has sent
116
+ * its prelude by then and cannot render the rest without the snapshot's doc
117
+ * record, so a timed-out read degrades the HIT (the entry is replaced, the
118
+ * page reloads once into a MISS; rsc-rendering.ts degradeUnreplayableShell).
119
+ * That costs far more than waiting, so a slow body read gets at least this
120
+ * long; `kvReadTimeoutMs` above it wins, and `kvReadTimeoutMs <= 0` still
121
+ * disables the bound.
122
+ */
123
+ export declare const SHELL_SNAPSHOT_READ_MIN_TIMEOUT_MS = 1000;