@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
@@ -42,10 +42,30 @@ export interface InvokeOnErrorContext<TEnv = any> {
42
42
  * @param logPrefix - Prefix for console.error messages (e.g., "Router" or "RSC")
43
43
  */
44
44
  export declare function invokeOnError<TEnv = any>(onError: OnErrorCallback<TEnv> | undefined, error: unknown, phase: ErrorPhase, context: InvokeOnErrorContext<TEnv>, logPrefix?: string): void;
45
+ /**
46
+ * First non-undefined `pick(orphan)` over the routeless entries in
47
+ * `entry.layout` and, recursively, in theirs: depth-first in render order
48
+ * (resolveOrphanLayout in segment-resolution/fresh.ts). Since #922 a routeless
49
+ * entry nested in another renders (a layout() after a bare cache() marker, a
50
+ * layout() in a routeless wrapper); a one-level scan missed the boundaries and
51
+ * intercepts it declares (#926).
52
+ *
53
+ * `skip` is the entry an upward walk came from. Only a bare cache() marker is
54
+ * both in its layout's layout[] and in the chain, and its subtree was already
55
+ * scanned at its chain position.
56
+ */
57
+ export declare function findInOrphans<T>(entry: EntryData, pick: (orphan: EntryData) => T | undefined, skip?: EntryData | null): T | undefined;
58
+ /** `findInOrphans` pick: the orphan when it declares an errorBoundary(). */
59
+ export declare const withErrorBoundary: (entry: EntryData) => EntryData | undefined;
45
60
  /**
46
61
  * Find the nearest error boundary by walking up the entry chain
47
62
  * Also checks sibling layouts (orphan layouts) for error boundaries
48
63
  * Returns the first fallback found, or the default error boundary if configured
64
+ *
65
+ * An orphan's parent is null, so from an orphan the walk continues at its
66
+ * orphanOwner (EntryData). Without that step, errors from an intercept declared
67
+ * in a routeless layout, or from that layout's loaders, stopped at the orphan
68
+ * and skipped every ancestor boundary (#898).
49
69
  */
50
70
  export declare function findNearestErrorBoundary(entry: EntryData | null, defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler): ReactNode | ErrorBoundaryHandler | null;
51
71
  /**
@@ -4,6 +4,12 @@
4
4
  * Creates the handler context object passed to route handlers, middleware, and loaders.
5
5
  */
6
6
  import type { InternalHandlerContext } from "../types";
7
+ /**
8
+ * `headers` whose mutating methods run `assertWrite(method)` first. Shared by
9
+ * the handler ctx (createHandlerContext) and the middleware ctx
10
+ * (createMiddlewareContext).
11
+ */
12
+ export declare function guardHeaderWrites(headers: Headers, assertWrite: (method: string | symbol) => void): Headers;
7
13
  /**
8
14
  * Strip internal _rsc* query params from a URL.
9
15
  * Returns a new URL with only user-facing params.
@@ -163,6 +163,14 @@ export declare function observePhase<T>(spec: PhaseSpec, fn: (span: TraceSpan) =
163
163
  * nothing to record here and short-circuits.
164
164
  */
165
165
  export declare function observeHandler<C, R>(id: string, handler: (ctx: C) => R, ctx: C): R;
166
+ /**
167
+ * observeHandler, inside segment `segmentId`'s tag scope, so the tags the
168
+ * handler records reach the route's cache() record (#957, cache-tag.ts
169
+ * runInSegmentTagScope). `spanId` is observeHandler's `id`. A request that
170
+ * cannot write a record takes observeHandler's path as is, with the same one
171
+ * request-context read: no scope, no closure.
172
+ */
173
+ export declare function observeSegmentHandler<C, R>(segmentId: string, spanId: string, handler: (ctx: C) => R, ctx: C): R;
166
174
  /**
167
175
  * Emit one discrete telemetry event (the event-shaped counterpart to
168
176
  * observePhase). Resolves the sink from the active router context and stamps the
@@ -82,13 +82,13 @@
82
82
  * ISOLATION FROM RESPONSE
83
83
  * =======================
84
84
  *
85
- * Background revalidation creates fully isolated context:
86
- * - Fresh handleStore (prevents polluting the response stream)
85
+ * Background revalidation re-renders through rerenderAndCacheRoute (shared
86
+ * with proactive caching in cache-store.ts):
87
+ * - Derived request context with its own handleStore, transition({ when })
88
+ * predicates and no perf metrics (the shared fields are never touched;
89
+ * the foreground is still producing the page)
87
90
  * - Fresh handlerContext + loaderPromises (prevents reusing memoized
88
91
  * loader results from the foreground pass)
89
- * - handleStore is saved/restored in try/finally
90
- *
91
- * This matches the proactive caching pattern in cache-store.ts.
92
92
  *
93
93
  *
94
94
  * FRESH RESOLUTION (NO REVALIDATION)
@@ -101,7 +101,48 @@
101
101
  */
102
102
  import type { ResolvedSegment } from "../../types.js";
103
103
  import type { MatchContext, MatchPipelineState } from "../match-context.js";
104
+ import { type RouterContext } from "../router-context.js";
105
+ import type { CacheScope } from "../../cache/cache-scope.js";
104
106
  import type { GeneratorMiddleware } from "./cache-lookup.js";
107
+ import { type RequestContext } from "../../server/request-context.js";
108
+ /**
109
+ * Re-render a cached route in the background and write it with
110
+ * cacheScope.cacheRoute: the stale-hit refresh below and proactive caching
111
+ * (cache-store.ts). Returns the number of segments written.
112
+ *
113
+ * A render whose status is not 200 (an error or notFound boundary resolved)
114
+ * is not written and returns 0, as a non-200 MISS is not cached
115
+ * (cache-store.ts): the entry it would replace keeps serving until a later
116
+ * refresh succeeds or it expires. Nothing is held in process; a store's own
117
+ * revalidation marker (CFCacheStore's REVALIDATING) re-arms after
118
+ * MAX_REVALIDATION_INTERVAL, as after a refresh that throws.
119
+ *
120
+ * Runs on a DERIVED request context that owns the per-render state the
121
+ * foreground reads while it is still producing the page (a stale HIT re-runs
122
+ * its loaders; a proactive render starts once the Response exists, while its
123
+ * body streams):
124
+ * - _handleStore: read late (loader pushes and aux-lane tracking in
125
+ * loader-resolution.ts, nested cache restores and captures in
126
+ * cache-scope.ts), so a swap sent live pushes into this render.
127
+ * setupLoaderAccess binds the store at setup, so it runs inside the
128
+ * derived context too.
129
+ * - _transitionWhen: fresh resolution appends transition({ when })
130
+ * predicates; the foreground's gateTransitions reads the array after the
131
+ * match, and a stale HIT (which replays the stored transition) must not
132
+ * evaluate this render's predicates.
133
+ * - _metricsStore: undefined, and the DSL store below has `metrics` unset
134
+ * (track() reads that one), so nothing lands on the foreground's perf
135
+ * timeline. ctx.Store.run closes over ctx.Store, so the derived store
136
+ * needs its own run.
137
+ * - response writes (headers, cookies, status, onResponse callbacks) go to
138
+ * a throwaway context (whose status gates the write, above) and are
139
+ * dropped: a layout above the cache() boundary is outside the header
140
+ * guard and an error boundary sets a status, so they would otherwise
141
+ * reach the live response.
142
+ * runWithRequestContext also re-establishes the request ALS, which a waitUntil
143
+ * task on workerd loses; the DSL store is a different ALS (build context).
144
+ */
145
+ export declare function rerenderAndCacheRoute<TEnv>(ctx: MatchContext<TEnv>, requestCtx: RequestContext<TEnv>, cacheScope: CacheScope, routerCtx: RouterContext<TEnv>): Promise<number>;
105
146
  /**
106
147
  * Creates background revalidation middleware
107
148
  *
@@ -1,6 +1,6 @@
1
1
  import type { ContextVar } from "../context-var.js";
2
2
  import type { DefaultReverseRouteMap, DefaultRouteName, DefaultVars } from "../types/global-namespace.js";
3
- import type { ScopedReverseFunction } from "../reverse.js";
3
+ import type { GlobalReverseFunction } from "../reverse.js";
4
4
  import type { Theme } from "../theme/types.js";
5
5
  import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
6
6
  import type { RequestScope } from "../types/request-scope.js";
@@ -48,10 +48,16 @@ export interface MiddlewareContext<TEnv = any, TParams = Record<string, string |
48
48
  header(name: string, value: string): void;
49
49
  routeName?: DefaultRouteName;
50
50
  debugPerformance(): void;
51
- theme?: Theme;
51
+ /**
52
+ * The visitor's theme (cookie or default); undefined without theme config.
53
+ * Guarded like `cookies()`: a read inside a `"use cache"` function throws
54
+ * (#971).
55
+ */
56
+ readonly theme?: Theme;
52
57
  setTheme?: (theme: Theme) => void;
53
58
  setLocationState(entries: LocationStateEntry | LocationStateEntry[]): void;
54
- reverse: ScopedReverseFunction<Record<string, string>, DefaultReverseRouteMap>;
59
+ /** Global route names only; see {@link GlobalReverseFunction}. */
60
+ reverse: GlobalReverseFunction<DefaultReverseRouteMap>;
55
61
  }
56
62
  export type MiddlewareFn<TEnv = any, TParams = Record<string, string | undefined>> = (ctx: MiddlewareContext<TEnv, TParams>, next: () => Promise<Response>) => Response | void | Promise<Response | void>;
57
63
  export interface MiddlewareEntry<TEnv = any> {
@@ -49,7 +49,9 @@ export interface RouterContext<TEnv = any> {
49
49
  getMetricsStore: () => MetricsStore | undefined;
50
50
  createCacheScope: (cacheConfig: any, parent: CacheScope | null) => CacheScope | null;
51
51
  findInterceptForRoute: (routeKey: string, parentEntry: EntryData | null, selectorContext: InterceptSelectorContext, isAction: boolean) => InterceptResult | null;
52
- resolveAllSegmentsWithRevalidation: (entries: EntryData[], routeKey: string, params: Record<string, string>, handlerContext: HandlerContext<any, TEnv>, clientSegmentSet: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, actionContext: any | undefined, interceptResult: InterceptResult | null, localRouteName: string, pathname: string, stale?: boolean) => Promise<{
52
+ resolveAllSegmentsWithRevalidation: (entries: EntryData[], routeKey: string, params: Record<string, string>, handlerContext: HandlerContext<any, TEnv>, clientSegmentSet: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, actionContext: any | undefined, interceptResult: InterceptResult | null, localRouteName: string, pathname: string, stale?: boolean,
53
+ /** The matched route's full chain when `entries` is part of it (ResolveSegmentOptions.chain). */
54
+ chain?: readonly EntryData[]) => Promise<{
53
55
  segments: ResolvedSegment[];
54
56
  matchedIds: string[];
55
57
  }>;
@@ -137,6 +137,22 @@ export interface Rango<TEnv = any, TRoutes extends Record<string, unknown> = Rec
137
137
  * ```
138
138
  */
139
139
  readonly routeMap: TRoutes;
140
+ /**
141
+ * Serialize the route manifest for inspection: every route and layout the
142
+ * router's `.routes()` / `urls` mounts register, with shortCodes, parent
143
+ * links, and loader/middleware/error-boundary/parallel/intercept flags.
144
+ *
145
+ * Server-only development aid. It re-evaluates each mount's `urls()` tree.
146
+ * Groups mounted with `include()` are lazy and are not expanded: their
147
+ * routes are absent from the result.
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const manifest = await router.debugManifest();
152
+ * console.log(manifest.totalRoutes, Object.keys(manifest.routes));
153
+ * ```
154
+ */
155
+ debugManifest(): Promise<SerializedManifest>;
140
156
  /**
141
157
  * Handle an RSC request.
142
158
  *
@@ -147,7 +163,13 @@ export interface Rango<TEnv = any, TRoutes extends Record<string, unknown> = Rec
147
163
  * ```tsx
148
164
  * import { router } from "./router";
149
165
  *
150
- * export default { fetch: router.fetch };
166
+ * // Workers call fetch(request, env, ctx); `{ fetch: router.fetch }` would
167
+ * // drop env and ctx.
168
+ * export default {
169
+ * fetch(request, env, ctx) {
170
+ * return router.fetch(request, { env, ctx });
171
+ * },
172
+ * } satisfies ExportedHandler;
151
173
  * ```
152
174
  *
153
175
  * @example Direct export
@@ -238,7 +260,7 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
238
260
  readonly notFound?: RangoOptions<TEnv>["notFound"];
239
261
  /**
240
262
  * Resolved theme configuration (null if theme not enabled)
241
- * Used by NavigationProvider to include ThemeProvider and by MetaTags to render theme script
263
+ * Used by NavigationProvider to include ThemeProvider and by `Html.Meta` to render theme script
242
264
  */
243
265
  readonly themeConfig: import("../theme/types.js").ResolvedThemeConfig | null;
244
266
  /**
@@ -146,8 +146,10 @@ export interface RangoOptions<TEnv = any> {
146
146
  *
147
147
  * Must be a client component ("use client") that accepts { children }.
148
148
  *
149
- * If not provided, a default document with basic HTML structure is used:
150
- * `<html><head><meta charset/viewport></head><body>{children}</body></html>`
149
+ * If not provided, a default document is used: `Html.Meta` and `Html.Scripts`
150
+ * in `<head>`, `Html.Scripts position="body"` before `{children}` and
151
+ * `Html.ScrollRestoration` after it. Pass your own to set `getKey` or to
152
+ * leave back/forward scrolling to the browser.
151
153
  *
152
154
  * @example
153
155
  * ```typescript
@@ -181,7 +183,8 @@ export interface RangoOptions<TEnv = any> {
181
183
  defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler;
182
184
  /**
183
185
  * Default not-found boundary fallback used when no notFoundBoundary is defined in the route tree
184
- * If not provided, DataNotFoundError will be treated as a regular error
186
+ * If not provided, notFound() renders the `notFound` option, else a plain
187
+ * `<h1>Not Found</h1>` (status 404)
185
188
  */
186
189
  defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler;
187
190
  /**
@@ -190,7 +193,7 @@ export interface RangoOptions<TEnv = any> {
190
193
  * This is rendered within your document/app shell with a 404 status code.
191
194
  * Use this for a custom 404 page that maintains your app's look and feel.
192
195
  *
193
- * If not provided, a default "Page not found" component is rendered.
196
+ * If not provided, a plain `<h1>Not Found</h1>` is rendered.
194
197
  *
195
198
  * Can be a static ReactNode or a function receiving the pathname.
196
199
  *
@@ -337,7 +340,7 @@ export interface RangoOptions<TEnv = any> {
337
340
  * When provided, enables:
338
341
  * - ctx.theme and ctx.setTheme() in route handlers
339
342
  * - useTheme() hook for client components
340
- * - FOUC prevention via inline script in MetaTags
343
+ * - FOUC prevention via inline script in `<Html.Meta />`
341
344
  * - Automatic ThemeProvider wrapping in NavigationProvider
342
345
  *
343
346
  * @example
@@ -27,6 +27,16 @@ export interface ResolveSegmentOptions {
27
27
  * so error boundaries keep catching at request time.
28
28
  */
29
29
  throwOnError?: boolean;
30
+ /**
31
+ * The matched route's full entry chain. resolveAllSegments defaults it to
32
+ * its `entries`; withCacheLookup passes it when it resolves only the entries
33
+ * above a cache() boundary. An orphan list can hold an entry of the chain: a
34
+ * bare cache() marker sits in its layout's layout[] (it wraps that layout's
35
+ * routes) and is the parent of the routes after it. For those routes it
36
+ * resolves once, as a chain entry, below the cache() header latch (issue
37
+ * #918: resolved twice on a MISS, once and discarded on a HIT).
38
+ */
39
+ chain?: readonly EntryData[];
30
40
  }
31
41
  /**
32
42
  * Resolve segments from EntryData.
@@ -16,9 +16,40 @@
16
16
  * On hit: returns cached data directly, skips loader execution.
17
17
  * On stale hit (SWR): returns stale data, schedules background revalidation.
18
18
  * On miss: executes loader, schedules non-blocking cache write.
19
+ *
20
+ * Identity (#972): without a key() or a store keyGenerator the entry is
21
+ * shared across users, so a fill whose execution recorded a request-identity
22
+ * read fails and is not stored, whoever started that execution
23
+ * (server/context.ts recordLoaderIdentityRead).
24
+ *
25
+ * Handle pushes (`ctx.use(Handle)(...)` in the loader body) are a side effect
26
+ * the HIT must reproduce: the MISS records the pushes of the body and of the
27
+ * loaders it awaits via ctx.use into the entry's `handles` blob (the
28
+ * "use cache" capture/encode), and every HIT — stale included — replays
29
+ * them, each loader's pushes at most once per request (a dependency another
30
+ * reader already ran keeps its live pushes). See replayLoaderHandles.
31
+ *
32
+ * Tags too (#964): the entry stores its cache() tags plus every tag its
33
+ * execution recorded, those of the loader values it read included
34
+ * (cache-tag.ts "Recorded-tag sets"), so updateTag() of any of them drops it.
35
+ * Every HIT records the stored tags through the loader's tag owner
36
+ * (recordLoaderTags), so a route cache() record, PPR shell or document built
37
+ * over the HIT carries them, and a loader that reads this one takes them on.
38
+ * Once the binding started, a loader body's ctx.use of it gets the same
39
+ * dataPromise as a handler read (createLoaderExecutor's useLoader); a stale
40
+ * refresh does not (setupLoaderAccess _runLoaderIsolated).
19
41
  */
20
- import type { LoaderEntry } from "../../server/context.js";
42
+ import { type EntryData, type LoaderEntry } from "../../server/context.js";
21
43
  import type { HandlerContext } from "../../types.js";
44
+ /**
45
+ * Whether a request over the matched chain `entries` resolves a loader bound
46
+ * with its own cache(): on a chain entry, or on its parallel slots, orphan
47
+ * layouts or intercepts. The match arms the per-execution loader tag sets on
48
+ * it (cache-tag.ts armLoaderTagSets), before any loader starts, so a
49
+ * dependency the handler or another binding starts first still records.
50
+ * Memoized per entry.
51
+ */
52
+ export declare function bindsLoaderCache(entries: readonly EntryData[]): boolean;
22
53
  /**
23
54
  * Resolve loader data with optional caching.
24
55
  *
@@ -29,5 +60,39 @@ import type { HandlerContext } from "../../types.js";
29
60
  * (observePhase; see instrument.ts). A cache HIT returns without calling ctx.use,
30
61
  * so it emits no loader phase (the loader did not execute; the hit is only a
31
62
  * LoaderCache debug log).
63
+ *
64
+ * PPR loader lane rule — the canonical source statement; other sites point
65
+ * here (consumer docs: skills/ppr/SKILL.md "The loader lane rule";
66
+ * docs/design/loader-container-bake.md). This is the single funnel every
67
+ * loader segment path routes through (fresh resolveLoaders, cache-hit
68
+ * resolveLoadersOnly, revalidation resolveLoadersOnlyWithRevalidation, and
69
+ * intercept loaders in intercept-resolution.ts, which pass no bake key and
70
+ * never run under a shell capture), so the lane is decided here, per LOADER,
71
+ * never by the entry's loading():
72
+ *
73
+ * - BAKE lane: `loader(Def, { ssr: false })` (LoaderEntry `bake`: the
74
+ * caller passes a `bakeSegmentKey` for it on document and navigation
75
+ * evaluations alike; a capture, a document evaluation, also has
76
+ * awaitBeforeFlush). The loader EXECUTES at capture (the
77
+ * flag's "data in the HTML before first flush" maps to the frozen prelude)
78
+ * and its settled non-promise data bakes into the shell. Promises nested in
79
+ * plain objects, arrays and JSX props are masked (mask-nested.ts) and stay
80
+ * live holes at the consumer's own Suspense — per-request material must be
81
+ * promise-shaped (the #692 cross-session scar). The masked container
82
+ * registers on `_shellCaptureLoaderRecords`: it holds the capture gate
83
+ * (bounded by `ppr.captureTimeout`) and pins into the snapshot's loader
84
+ * family, and on a HIT the recorded container is overlaid onto the fresh
85
+ * run (below) so the payload matches the frozen prelude outside the holes.
86
+ * A server-component element holding a promise is a hole as a whole, so its
87
+ * other props come from the fresh run (loader-snapshot.ts
88
+ * elideLoaderContainer). cookies()/headers() in its body (nested promise
89
+ * bodies included) trip the capture guard.
90
+ * - LIVE lane: every other loader, whatever its entry's loading(). Never
91
+ * executes at capture: the slot gets a never-resolving promise
92
+ * (loader-mask.ts) and postpones at the reader's boundary — loading() or an
93
+ * inline Suspense — then streams fresh per request. A masked read with NO
94
+ * boundary above it root-postpones and the <body> sanity gate refuses the
95
+ * shell (eternal-MISS warning). A route whose loaders are ALL `ssr: false`
96
+ * needs no loading(): nothing masks.
32
97
  */
33
98
  export declare function resolveLoaderData<TEnv>(loaderEntry: LoaderEntry, ctx: HandlerContext<any, TEnv>, pathname: string, bakeSegmentKey?: string | null): Promise<any>;
@@ -2,13 +2,10 @@
2
2
  * PPR shell-capture loader masking.
3
3
  *
4
4
  * During a shell CAPTURE re-render (Axis 2, see docs/design/ppr-shell-resume.md)
5
- * route loaders are the "live lane": they must NOT execute — no side effects, no
6
- * cost, no cache round-trips. Instead every loader segment's value slot receives
7
- * a never-resolving promise, so the loader-consuming Suspense subtree stays
8
- * pending and React's static `prerender` marks it as a postponed hole. The frozen
9
- * shell (prelude) captures only the fallback; the resumed serve pass runs the
10
- * loaders fresh through the unchanged execution path and streams their output
11
- * into the holes.
5
+ * live-lane loaders (lane rule: see resolveLoaderData, loader-cache.ts) must
6
+ * NOT execute; their value slot gets a never-resolving promise so the
7
+ * consuming Suspense subtree postpones as a hole, and the serve pass runs them
8
+ * fresh into it.
12
9
  *
13
10
  * Capture mode is signalled by `requestCtx._shellCaptureRun`, set to true ONLY on
14
11
  * the derived request context of the background capture task (shell-capture.ts) —
@@ -28,17 +25,10 @@ import { type RequestContext } from "../../server/request-context.js";
28
25
  export declare function isShellCaptureActive(reqCtx?: RequestContext<any> | undefined): boolean;
29
26
  export { createMaskedLoaderPromise } from "./mask-nested.js";
30
27
  /**
31
- * Entry-level lane input for an entry's loaders under PPR (the loading()
32
- * value; docs/design/loader-container-bake.md). The CAPTURE decision itself
33
- * is per LOADER in loader-cache.ts: an `ssr: false`
34
- * (awaitBeforeFlush) loader BAKES at capture regardless of this value — the
35
- * flag's document promise ("data in the HTML before first flush") maps to
36
- * the frozen prelude — while every other loader is LIVE (masked at capture,
37
- * fresh on every serve), postponing at loading() or an inline Suspense.
38
- * This helper still gates which entries pass a bake segment key for the
39
- * legacy loading()-less shape and the HIT-tail seed overlay.
40
- *
41
- * Mirrors segment-system's isRenderableLoading so the mask decision and the
42
- * tree's boundary placement can never disagree.
28
+ * True when the entry's loading() is renderable (mirrors segment-system's
29
+ * isRenderableLoading). Not the lane decision (lane rule: see
30
+ * resolveLoaderData, loader-cache.ts): callers only use it to decide whether
31
+ * an unflagged loader's segment key rides as the bake/seed key, which is inert
32
+ * at capture.
43
33
  */
44
34
  export declare function entryLoadingMasksLoaders(loading: unknown): boolean;
@@ -2,11 +2,13 @@
2
2
  * Loader-family capture snapshot: elide + overlay for bake-lane loader
3
3
  * containers (docs/design/loader-container-bake.md).
4
4
  *
5
- * A loader on an entry with NO renderable loading() executes during shell
6
- * capture; its settled container bakes into the prelude while every promise
7
- * still pending at the quiet window postpones as a hole. To keep a HIT's fresh
8
- * payload byte-identical to that frozen prelude, the capture pins the container
9
- * in the shell snapshot:
5
+ * A bake-lane loader (lane rule: see resolveLoaderData, loader-cache.ts)
6
+ * executes during shell capture; its settled container bakes into the prelude
7
+ * while nested promises postpone as holes. To keep a HIT's fresh payload in
8
+ * agreement with that frozen prelude, the capture pins the container in the
9
+ * shell snapshot. Everything outside a hole is pinned; the one exception is a
10
+ * server-component element holding a promise, which is a hole as a whole (see
11
+ * elideLoaderContainer):
10
12
  *
11
13
  * - elide: deep-walk the settled container; a PENDING nested promise is a
12
14
  * hole, replaced by {@link LOADER_HOLE_KEY} — and since
@@ -27,7 +29,8 @@
27
29
  * storefront PDP regression) — and fresh-only paths pass through
28
30
  * (they cannot contradict prelude bytes that never rendered them).
29
31
  */
30
- export { maskNestedContainerThenables } from "./mask-nested.js";
32
+ import { maskNestedContainerThenables } from "./mask-nested.js";
33
+ export { maskNestedContainerThenables };
31
34
  /**
32
35
  * Marker object standing in for a pending nested promise in a recorded loader
33
36
  * container. Shape-checked (not identity-checked) because the record round-trips
@@ -70,21 +73,29 @@ export type ElideResult = {
70
73
  * promises pin their value behind a settled marker (they baked, but consumers
71
74
  * hold a promise-shaped key); pending ones become hole markers; a REJECTED
72
75
  * nested promise poisons the record (error UI must never bake into a shared
73
- * shell) — the caller refuses the capture. Only plain objects/arrays are
74
- * traversed; anything else (Date, Map, class instance) is a pinned leaf.
75
- * Cycles are cut as pinned references (best effort — Flight rejects true
76
- * cycles later regardless).
76
+ * shell) — the caller refuses the capture. Plain data objects, arrays and the
77
+ * props of host, Suspense/Fragment and client-reference elements are
78
+ * traversed copy-on-write (an element through cloneElementWithProps); a shared
79
+ * subtree or a cycle resolves to the same elided result. An element Flight
80
+ * renders by calling user code (see rendersOnServer) is a leaf, or ONE hole
81
+ * marker when a thenable sits anywhere in its props: the pin encode calls that
82
+ * component, so a marker inside its props would reach it. Anything else
83
+ * (Date, Map, class instance, lazy node) is a pinned leaf.
77
84
  *
78
85
  * The ROOT container promise-chain unwraps with NO marker: loader-cache
79
86
  * overlays against the AWAITED fresh container, so the recorded root must be
80
87
  * the unwrapped structure. Everything below it goes through elideNested.
81
88
  */
82
- export declare function elideLoaderContainer(value: unknown, seen?: Set<object>): Promise<ElideResult>;
89
+ export declare function elideLoaderContainer(value: unknown, seen?: Map<object, ElideResult>): Promise<ElideResult>;
83
90
  /**
84
91
  * Overlay a recorded (elided) container onto the fresh run's container for a
85
92
  * shell HIT. Recorded wins per path; hole markers take the fresh value (the
86
93
  * live nested promise); fresh-only object keys pass through. Where the shapes
87
94
  * disagree structurally, recorded wins wholesale — it is what the prelude
88
- * froze, and parity beats freshness inside the shell.
95
+ * froze, and parity beats freshness inside the shell. Copy-on-write: a
96
+ * recorded subtree without markers comes back by identity. A recorded element
97
+ * is rebuilt through cloneElementWithProps only at its marker paths, so its
98
+ * other props stay pinned; props the fresh element adds do not pass through
99
+ * (the prelude rendered the element without them).
89
100
  */
90
101
  export declare function overlayLoaderContainer(fresh: unknown, recorded: unknown): unknown;
@@ -1,13 +1,16 @@
1
1
  /**
2
- * Capture-side nested-thenable masking — the mechanism behind "nested-promise
3
- * shape is the liveness declaration" for BOTH bake-lane loader containers
4
- * (loader-cache.ts) and pushed handle containers (request-context.ts
5
- * createUseFunction).
2
+ * Capture-side nested thenables. Masking is the mechanism behind "nested-
3
+ * promise shape is the liveness declaration" for the loader lane: bake-lane
4
+ * loader containers (loader-cache.ts) and DSL loader handle pushes (the
5
+ * capture handle store's push wrap in rsc/shell-capture.ts). Handler handle
6
+ * pushes are handler output and bake: the capture waits for their nested
7
+ * promises instead (settleNestedThenables).
6
8
  *
7
- * Deliberately a LEAF module: request-context needs the mask for handle
8
- * pushes, and loader-mask (the other natural home) imports request-context —
9
- * importing from there would cycle. This module imports only is-thenable.
9
+ * Deliberately a LEAF module: loader-mask (the other natural home) imports
10
+ * request-context, so any funnel importing the mask from there inherits that
11
+ * graph. This module imports only is-thenable and react.
10
12
  */
13
+ import { type ReactElement } from "react";
11
14
  /**
12
15
  * A promise that never settles — the masked stand-in for a per-request value
13
16
  * during shell capture. The consuming Suspense subtree suspends forever, so
@@ -18,11 +21,55 @@
18
21
  */
19
22
  export declare function createMaskedLoaderPromise<T = unknown>(): Promise<T>;
20
23
  /**
21
- * Deep-copy a container with every NESTED thenable replaced by a masked
24
+ * A data object the container walks descend into: prototype Object.prototype
25
+ * or null, and no symbol `$$typeof`. React elements, lazy nodes and references
26
+ * are plain objects too, told apart by that symbol (Flight switches on it).
27
+ * They are React's, not data: an element's dev-only fields (`_debugStack`,
28
+ * `_debugTask`, `_debugInfo`, `ref`) are non-enumerable, so a key-by-key copy
29
+ * drops them and dev Flight refuses it ("Attempted to render <x> without
30
+ * development properties", issue #942).
31
+ */
32
+ export declare function isPlainDataObject(value: unknown): value is Record<string, unknown>;
33
+ /**
34
+ * cloneElement with only the given props replaced, keeping React's dev key
35
+ * validation. React 19 dev cloneElement resets `_store.validated`, so a
36
+ * keyless child of a static children list (validated at creation) would warn
37
+ * "Each child in a list should have a unique key" once cloned. Pass only the
38
+ * props that change: cloneElement re-parents the element (owner) when its
39
+ * config carries `ref`.
40
+ */
41
+ export declare function cloneElementWithProps(element: ReactElement, props: Record<string, unknown>): ReactElement;
42
+ /**
43
+ * Resolves once `value` and every thenable reachable from it through plain
44
+ * data objects, arrays and React element props has settled, following what
45
+ * each thenable resolves to. A rejection counts as settled: the consumer that
46
+ * encodes the value reports it. Other objects are leaves (the same walk as
47
+ * maskNestedContainerThenables), so a promise inside a Map is not waited for.
48
+ * An element is walked through its props only (`<X data={promise} />` in a
49
+ * handle value is handler output too), never its owner or type, and is never
50
+ * rebuilt: nothing is copied, only awaited.
51
+ *
52
+ * The capture waits on this for HANDLER handle pushes (shell-capture.ts):
53
+ * handler output is baked, so its promises must settle before the doc record
54
+ * encodes the handles every HIT replays.
55
+ */
56
+ export declare function settleNestedThenables(value: unknown): Promise<void>;
57
+ /**
58
+ * Optional single-walk report for maskNestedContainerThenables: `thenable`
59
+ * flips true when the walk masked at least one thenable. The capture push
60
+ * funnel reads it for a loader push: a container with a masked nested
61
+ * promise keeps its loader tag, so the handle encode never waits on a mask.
62
+ * Same single-pass shape as elideLoaderContainer's `hasHole`.
63
+ */
64
+ export interface MaskReport {
65
+ thenable: boolean;
66
+ }
67
+ /**
68
+ * Copy a container with every NESTED thenable replaced by a masked
22
69
  * (never-resolving) promise. Applied during shell capture to (a) bake-lane
23
- * loader containers (loader-cache.ts) and (b) pushed handle containers
24
- * (createUseFunction) — the two rango-owned funnels where consumers declare
25
- * per-request data by promise SHAPE.
70
+ * loader containers (loader-cache.ts) and (b) DSL loader handle pushes
71
+ * (shell-capture.ts capture store push wrap) — the rango-owned funnels where
72
+ * a loader declares per-request data by promise SHAPE.
26
73
  *
27
74
  * Why: a nested promise that happened to SETTLE before the capture's quiet
28
75
  * window closed used to bake its value into the SHARED shell (and, for
@@ -34,20 +81,14 @@ export declare function createMaskedLoaderPromise<T = unknown>(): Promise<T>;
34
81
  * Masking makes the consuming subtree postpone as a hole no matter when the
35
82
  * promise settles: liveness by declaration, not by racing the window.
36
83
  *
37
- * Only plain objects/arrays are traversed; other values are leaves. The INPUT
38
- * IS NEVER MUTATED — handler-side loader consumption (the consumption-lane
39
- * rule, semantic-matrix PPR3) shares the raw container and must keep real
40
- * values. Cycles are preserved as cycles in the copy.
41
- */
42
- /**
43
- * Optional single-walk report for maskNestedContainerThenables: `thenable`
44
- * flips true when the walk masked at least one thenable. The shell fast path
45
- * reads it at handle-push time — a pushed container with a nested thenable
46
- * declares per-request data, and a shell entry whose HANDLER layer made such
47
- * a declaration cannot be served handler-free (the hole would never fill).
48
- * Same single-pass shape as elideLoaderContainer's `hasHole`.
84
+ * Plain data objects, arrays and React element props are traversed: JSX
85
+ * carrying a promise (`<Reviews data={fetchReviews()} />`) declares
86
+ * per-request data the same way a plain container does. Other values, lazy
87
+ * nodes included, are leaves. Copy-on-write: a subtree without a thenable
88
+ * comes back by identity, so an element is rebuilt only when its props hold
89
+ * one, and then through cloneElementWithProps, which keeps its type, key,
90
+ * owner, dev fields and key validation. The INPUT IS NEVER MUTATED — handler-side loader consumption (the
91
+ * consumption-lane rule, semantic-matrix PPR3) shares the raw container and
92
+ * must keep real values. Cycles are preserved as cycles in the copy.
49
93
  */
50
- export interface MaskReport {
51
- thenable: boolean;
52
- }
53
94
  export declare function maskNestedContainerThenables(value: unknown, seen?: Map<object, unknown>, report?: MaskReport): unknown;
@@ -66,7 +66,9 @@ export declare function resolveEntryHandlerWithRevalidation<TEnv>(entry: Exclude
66
66
  */
67
67
  export declare function resolveSegmentWithRevalidation<TEnv>(entry: Exclude<EntryData, {
68
68
  type: "parallel";
69
- }>, routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentIds: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, deps: SegmentResolutionDeps<TEnv>, actionContext?: ActionContext, stale?: boolean): Promise<SegmentRevalidationResult>;
69
+ }>, routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentIds: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, deps: SegmentResolutionDeps<TEnv>, actionContext?: ActionContext, stale?: boolean,
70
+ /** The matched route's full chain; see ResolveSegmentOptions.chain (fresh.ts). */
71
+ chain?: readonly EntryData[]): Promise<SegmentRevalidationResult>;
70
72
  /**
71
73
  * Resolve orphan layout with revalidation.
72
74
  */
@@ -79,7 +81,9 @@ parentRouteEntry?: EntryData): Promise<SegmentRevalidationResult>;
79
81
  export declare function resolveAllSegmentsWithRevalidation<TEnv>(entries: EntryData[], routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentSet: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, actionContext: ActionContext | undefined, interceptResult: {
80
82
  intercept: any;
81
83
  entry: EntryData;
82
- } | null, localRouteName: string, pathname: string, deps: SegmentResolutionDeps<TEnv>, stale?: boolean): Promise<{
84
+ } | null, localRouteName: string, pathname: string, deps: SegmentResolutionDeps<TEnv>, stale?: boolean,
85
+ /** The matched route's full chain; see ResolveSegmentOptions.chain (fresh.ts). */
86
+ chain?: readonly EntryData[]): Promise<{
83
87
  segments: ResolvedSegment[];
84
88
  matchedIds: string[];
85
89
  }>;
@@ -27,7 +27,7 @@ export interface SegmentWrappers<TEnv = any> {
27
27
  } | undefined, interceptResult: {
28
28
  intercept: InterceptEntry;
29
29
  entry: EntryData;
30
- } | null, localRouteName: string, pathname: string) => Promise<{
30
+ } | null, localRouteName: string, pathname: string, stale?: boolean, chain?: readonly EntryData[]) => Promise<{
31
31
  segments: ResolvedSegment[];
32
32
  matchedIds: string[];
33
33
  }>;