@timber-js/app 0.2.0-alpha.185 → 0.2.0-alpha.186

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 (418) hide show
  1. package/dist/_chunks/{actions-O_LsyCE4.js → actions-C-Rw9vPc.js} +3 -3
  2. package/dist/_chunks/{actions-O_LsyCE4.js.map → actions-C-Rw9vPc.js.map} +1 -1
  3. package/dist/_chunks/als-slots-mFweg276.js +27 -0
  4. package/dist/_chunks/als-slots-mFweg276.js.map +1 -0
  5. package/dist/_chunks/base-path-DaQrzbez.js +80 -0
  6. package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
  7. package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
  8. package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
  9. package/dist/_chunks/build-output-helper-C3DrfzZR.js +369 -0
  10. package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +1 -0
  11. package/dist/_chunks/{cache-api-B-lhk9p4.js → cache-api-Cd0VZ_Pd.js} +3 -3
  12. package/dist/_chunks/{cache-api-B-lhk9p4.js.map → cache-api-Cd0VZ_Pd.js.map} +1 -1
  13. package/dist/_chunks/cli-schema-sync-CKgHC2MB.js +1857 -0
  14. package/dist/_chunks/cli-schema-sync-CKgHC2MB.js.map +1 -0
  15. package/dist/_chunks/{cloudflare-CnT5Lr7U.js → cloudflare-Cs0uZXea.js} +89 -12
  16. package/dist/_chunks/{cloudflare-CnT5Lr7U.js.map → cloudflare-Cs0uZXea.js.map} +1 -1
  17. package/dist/_chunks/error-boundary-DpYRI_I1.js +330 -0
  18. package/dist/_chunks/error-boundary-DpYRI_I1.js.map +1 -0
  19. package/dist/_chunks/{fast-hash-D6hIVt1Y.js → fast-hash-C-tVYrLb.js} +6 -1
  20. package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
  21. package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
  22. package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
  23. package/dist/_chunks/{logger-AWfuX-KJ.js → logger-N7e5auP0.js} +9 -13
  24. package/dist/_chunks/logger-N7e5auP0.js.map +1 -0
  25. package/dist/_chunks/navigation-root-B29qg0_T.js +274 -0
  26. package/dist/_chunks/navigation-root-B29qg0_T.js.map +1 -0
  27. package/dist/_chunks/param-value-C8TNYchQ.js +66 -0
  28. package/dist/_chunks/param-value-C8TNYchQ.js.map +1 -0
  29. package/dist/_chunks/{plugin-context---kTF5v8.js → plugin-context-DEGLSJs3.js} +2 -1
  30. package/dist/_chunks/plugin-context-DEGLSJs3.js.map +1 -0
  31. package/dist/_chunks/{router-ref-CtmF-aPv.js → router-ref-DuYuV_0Q.js} +2 -2
  32. package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -0
  33. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js +243 -0
  34. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js.map +1 -0
  35. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js +40 -0
  36. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js.map +1 -0
  37. package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
  38. package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
  39. package/dist/_chunks/{segment-classify-Byy425ng.js → segment-classify-C539Pa2O.js} +23 -2
  40. package/dist/_chunks/{segment-classify-Byy425ng.js.map → segment-classify-C539Pa2O.js.map} +1 -1
  41. package/dist/_chunks/{canonicalize-DQHyFClh.js → segment-keys-BawYuNFO.js} +61 -2
  42. package/dist/_chunks/segment-keys-BawYuNFO.js.map +1 -0
  43. package/dist/_chunks/slot-params-BCTmZkQB.js +76 -0
  44. package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -0
  45. package/dist/_chunks/{ssr-data-BOWsq18U.js → ssr-data-14MXm7Pj.js} +17 -2
  46. package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -0
  47. package/dist/_chunks/use-segment-params-ClyUNq4d.js +128 -0
  48. package/dist/_chunks/use-segment-params-ClyUNq4d.js.map +1 -0
  49. package/dist/_chunks/{walkers-_6zKFlch.js → walkers-BhhwI9TD.js} +21 -87
  50. package/dist/_chunks/walkers-BhhwI9TD.js.map +1 -0
  51. package/dist/adapters/build-output-helper.d.ts +37 -0
  52. package/dist/adapters/build-output-helper.d.ts.map +1 -1
  53. package/dist/adapters/cloudflare-dev.js +1 -1
  54. package/dist/adapters/cloudflare-kv-cache.js +1 -1
  55. package/dist/adapters/cloudflare.d.ts.map +1 -1
  56. package/dist/adapters/cloudflare.js +1 -1
  57. package/dist/adapters/fs-identity.d.ts +64 -0
  58. package/dist/adapters/fs-identity.d.ts.map +1 -0
  59. package/dist/adapters/nitro.d.ts.map +1 -1
  60. package/dist/adapters/nitro.js +2 -3
  61. package/dist/adapters/nitro.js.map +1 -1
  62. package/dist/adapters/shared.d.ts +57 -1
  63. package/dist/adapters/shared.d.ts.map +1 -1
  64. package/dist/adapters/types.d.ts +13 -1
  65. package/dist/adapters/types.d.ts.map +1 -1
  66. package/dist/cache/fast-hash.d.ts +5 -0
  67. package/dist/cache/fast-hash.d.ts.map +1 -1
  68. package/dist/cache/index.js +1 -1
  69. package/dist/cli.js +2 -2
  70. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  71. package/dist/client/browser-entry/hydrate.d.ts +20 -9
  72. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  73. package/dist/client/browser-entry/post-hydration.d.ts +4 -1
  74. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
  75. package/dist/client/browser-entry/router-init.d.ts +3 -0
  76. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  77. package/dist/client/browser-entry/rsc-stream.d.ts +8 -0
  78. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -1
  79. package/dist/client/error-boundary.d.ts +1 -0
  80. package/dist/client/error-boundary.d.ts.map +1 -1
  81. package/dist/client/error-boundary.js +1 -162
  82. package/dist/client/history.d.ts +13 -6
  83. package/dist/client/history.d.ts.map +1 -1
  84. package/dist/client/index.js +18 -11
  85. package/dist/client/index.js.map +1 -1
  86. package/dist/client/internal.d.ts +4 -3
  87. package/dist/client/internal.d.ts.map +1 -1
  88. package/dist/client/internal.js +865 -306
  89. package/dist/client/internal.js.map +1 -1
  90. package/dist/client/link.d.ts.map +1 -1
  91. package/dist/client/navigation-api.d.ts +2 -2
  92. package/dist/client/navigation-commit.d.ts +71 -0
  93. package/dist/client/navigation-commit.d.ts.map +1 -0
  94. package/dist/client/navigation-context.d.ts +37 -20
  95. package/dist/client/navigation-context.d.ts.map +1 -1
  96. package/dist/client/navigation-root.d.ts +63 -23
  97. package/dist/client/navigation-root.d.ts.map +1 -1
  98. package/dist/client/params-context.d.ts +81 -0
  99. package/dist/client/params-context.d.ts.map +1 -0
  100. package/dist/client/router-effects.d.ts +129 -0
  101. package/dist/client/router-effects.d.ts.map +1 -0
  102. package/dist/client/router-lifecycle.d.ts +55 -0
  103. package/dist/client/router-lifecycle.d.ts.map +1 -0
  104. package/dist/client/router-pipeline.d.ts +84 -0
  105. package/dist/client/router-pipeline.d.ts.map +1 -0
  106. package/dist/client/router-ref.d.ts +1 -1
  107. package/dist/client/router-ref.d.ts.map +1 -1
  108. package/dist/client/router-skew.d.ts +21 -0
  109. package/dist/client/router-skew.d.ts.map +1 -0
  110. package/dist/client/router-types.d.ts +207 -0
  111. package/dist/client/router-types.d.ts.map +1 -0
  112. package/dist/client/router.d.ts +1 -182
  113. package/dist/client/router.d.ts.map +1 -1
  114. package/dist/client/rsc-fetch.d.ts +38 -25
  115. package/dist/client/rsc-fetch.d.ts.map +1 -1
  116. package/dist/client/segment-cache.d.ts +79 -34
  117. package/dist/client/segment-cache.d.ts.map +1 -1
  118. package/dist/client/ssr-data.d.ts +6 -0
  119. package/dist/client/ssr-data.d.ts.map +1 -1
  120. package/dist/client/stale-client.d.ts +69 -0
  121. package/dist/client/stale-client.d.ts.map +1 -0
  122. package/dist/client/state.d.ts +10 -1
  123. package/dist/client/state.d.ts.map +1 -1
  124. package/dist/client/top-loader.d.ts +2 -1
  125. package/dist/client/top-loader.d.ts.map +1 -1
  126. package/dist/client/unload-guard.d.ts +5 -0
  127. package/dist/client/unload-guard.d.ts.map +1 -1
  128. package/dist/client/use-cookie.d.ts.map +1 -1
  129. package/dist/client/use-router.d.ts +1 -1
  130. package/dist/client/use-segment-params.d.ts +18 -8
  131. package/dist/client/use-segment-params.d.ts.map +1 -1
  132. package/dist/cookies/index.js +3 -3
  133. package/dist/cookies/index.js.map +1 -1
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +906 -321
  136. package/dist/index.js.map +1 -1
  137. package/dist/plugin-context.d.ts +31 -0
  138. package/dist/plugin-context.d.ts.map +1 -1
  139. package/dist/plugins/adapter-build.d.ts.map +1 -1
  140. package/dist/plugins/build-manifest.d.ts +1 -1
  141. package/dist/plugins/build-manifest.d.ts.map +1 -1
  142. package/dist/plugins/entries.d.ts.map +1 -1
  143. package/dist/plugins/fonts.d.ts.map +1 -1
  144. package/dist/plugins/request-dep/analysis.d.ts +106 -0
  145. package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
  146. package/dist/plugins/request-dep/index.d.ts +75 -0
  147. package/dist/plugins/request-dep/index.d.ts.map +1 -0
  148. package/dist/plugins/request-dep/origin.d.ts +61 -0
  149. package/dist/plugins/request-dep/origin.d.ts.map +1 -0
  150. package/dist/plugins/routing.d.ts +9 -0
  151. package/dist/plugins/routing.d.ts.map +1 -1
  152. package/dist/plugins/static-build.d.ts +136 -8
  153. package/dist/plugins/static-build.d.ts.map +1 -1
  154. package/dist/routing/codegen-types.d.ts +18 -0
  155. package/dist/routing/codegen-types.d.ts.map +1 -1
  156. package/dist/routing/codegen.d.ts.map +1 -1
  157. package/dist/routing/collision-probe.d.ts +104 -0
  158. package/dist/routing/collision-probe.d.ts.map +1 -0
  159. package/dist/routing/collision-spaces.d.ts +26 -0
  160. package/dist/routing/collision-spaces.d.ts.map +1 -0
  161. package/dist/routing/index.js +3 -3
  162. package/dist/routing/interception.d.ts +235 -6
  163. package/dist/routing/interception.d.ts.map +1 -1
  164. package/dist/routing/manifest-codegen.d.ts.map +1 -1
  165. package/dist/routing/scanner.d.ts.map +1 -1
  166. package/dist/routing/segment-classify.d.ts +33 -0
  167. package/dist/routing/segment-classify.d.ts.map +1 -1
  168. package/dist/routing/segment-keys.d.ts +95 -0
  169. package/dist/routing/segment-keys.d.ts.map +1 -0
  170. package/dist/routing/slot-placement.d.ts +48 -0
  171. package/dist/routing/slot-placement.d.ts.map +1 -0
  172. package/dist/routing/walkers.d.ts +6 -0
  173. package/dist/routing/walkers.d.ts.map +1 -1
  174. package/dist/search-params/define.d.ts +0 -6
  175. package/dist/search-params/define.d.ts.map +1 -1
  176. package/dist/search-params/index.js +176 -2
  177. package/dist/search-params/index.js.map +1 -1
  178. package/dist/segment-params/define.d.ts +0 -6
  179. package/dist/segment-params/define.d.ts.map +1 -1
  180. package/dist/segment-params/index.js +69 -1
  181. package/dist/segment-params/index.js.map +1 -0
  182. package/dist/server/actions.d.ts +6 -3
  183. package/dist/server/actions.d.ts.map +1 -1
  184. package/dist/server/als-registry.d.ts +2 -1
  185. package/dist/server/als-registry.d.ts.map +1 -1
  186. package/dist/server/build-manifest.d.ts +13 -1
  187. package/dist/server/build-manifest.d.ts.map +1 -1
  188. package/dist/server/chain-url-parts.d.ts +82 -0
  189. package/dist/server/chain-url-parts.d.ts.map +1 -0
  190. package/dist/server/children-interception.d.ts +49 -0
  191. package/dist/server/children-interception.d.ts.map +1 -0
  192. package/dist/server/default-status-page.d.ts +45 -0
  193. package/dist/server/default-status-page.d.ts.map +1 -0
  194. package/dist/server/deny-renderer.d.ts +14 -3
  195. package/dist/server/deny-renderer.d.ts.map +1 -1
  196. package/dist/server/head-response.d.ts +35 -0
  197. package/dist/server/head-response.d.ts.map +1 -0
  198. package/dist/server/index.js +2 -2
  199. package/dist/server/internal.js +393 -212
  200. package/dist/server/internal.js.map +1 -1
  201. package/dist/server/param-coercion.d.ts +10 -1
  202. package/dist/server/param-coercion.d.ts.map +1 -1
  203. package/dist/server/pipeline-helpers.d.ts +0 -18
  204. package/dist/server/pipeline-helpers.d.ts.map +1 -1
  205. package/dist/server/pipeline-interception.d.ts +59 -9
  206. package/dist/server/pipeline-interception.d.ts.map +1 -1
  207. package/dist/server/pipeline-outcome.d.ts.map +1 -1
  208. package/dist/server/pipeline-phases.d.ts.map +1 -1
  209. package/dist/server/pipeline.d.ts +11 -0
  210. package/dist/server/pipeline.d.ts.map +1 -1
  211. package/dist/server/publish-params.d.ts +33 -0
  212. package/dist/server/publish-params.d.ts.map +1 -0
  213. package/dist/server/request-context.d.ts +48 -0
  214. package/dist/server/request-context.d.ts.map +1 -1
  215. package/dist/server/route-element-builder.d.ts +32 -2
  216. package/dist/server/route-element-builder.d.ts.map +1 -1
  217. package/dist/server/route-handler.d.ts.map +1 -1
  218. package/dist/server/route-matcher.d.ts +13 -0
  219. package/dist/server/route-matcher.d.ts.map +1 -1
  220. package/dist/server/rsc-cache-key-guard.d.ts +78 -0
  221. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
  222. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  223. package/dist/server/rsc-entry/error-renderer.d.ts +14 -2
  224. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  225. package/dist/server/rsc-entry/helpers.d.ts +2 -10
  226. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  227. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  228. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  229. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -2
  230. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  231. package/dist/server/rsc-entry/rsc-stream.d.ts +3 -2
  232. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  233. package/dist/server/rsc-entry/ssr-renderer.d.ts +2 -0
  234. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  235. package/dist/server/skippable-prefix.d.ts +23 -0
  236. package/dist/server/skippable-prefix.d.ts.map +1 -0
  237. package/dist/server/slot-interception.d.ts +80 -0
  238. package/dist/server/slot-interception.d.ts.map +1 -0
  239. package/dist/server/slot-resolver.d.ts +70 -8
  240. package/dist/server/slot-resolver.d.ts.map +1 -1
  241. package/dist/server/ssr-bridge-types.d.ts +6 -0
  242. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  243. package/dist/server/ssr-entry.d.ts.map +1 -1
  244. package/dist/server/ssr-wrappers.d.ts +24 -13
  245. package/dist/server/ssr-wrappers.d.ts.map +1 -1
  246. package/dist/server/state-tree-diff.d.ts +6 -27
  247. package/dist/server/state-tree-diff.d.ts.map +1 -1
  248. package/dist/server/static-generator.d.ts +6 -0
  249. package/dist/server/static-generator.d.ts.map +1 -1
  250. package/dist/server/static-not-found.d.ts +52 -0
  251. package/dist/server/static-not-found.d.ts.map +1 -0
  252. package/dist/shared/als-slots.d.ts +41 -0
  253. package/dist/shared/als-slots.d.ts.map +1 -0
  254. package/dist/shared/base-path.d.ts +56 -0
  255. package/dist/shared/base-path.d.ts.map +1 -0
  256. package/dist/shared/param-value.d.ts +80 -0
  257. package/dist/shared/param-value.d.ts.map +1 -0
  258. package/dist/shared/payload-root.d.ts +108 -0
  259. package/dist/shared/payload-root.d.ts.map +1 -0
  260. package/dist/shared/rsc-cache-key.d.ts +163 -0
  261. package/dist/shared/rsc-cache-key.d.ts.map +1 -0
  262. package/dist/shared/rsc-error-envelope.d.ts +25 -0
  263. package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
  264. package/dist/shared/rsc-manifest.d.ts +28 -0
  265. package/dist/shared/rsc-manifest.d.ts.map +1 -0
  266. package/dist/shared/rsc-payload-path.d.ts +42 -0
  267. package/dist/shared/rsc-payload-path.d.ts.map +1 -0
  268. package/dist/shared/segment-info.d.ts +59 -0
  269. package/dist/shared/segment-info.d.ts.map +1 -0
  270. package/dist/shared/slot-params.d.ts +51 -0
  271. package/dist/shared/slot-params.d.ts.map +1 -0
  272. package/dist/shared/static-platform-files.d.ts +71 -0
  273. package/dist/shared/static-platform-files.d.ts.map +1 -0
  274. package/docs/api/31-api-client.mdx +4 -2
  275. package/docs/learn/02-pages-and-layouts.mdx +1 -1
  276. package/docs/learn/11-error-handling.mdx +2 -0
  277. package/docs/learn/12-client-navigation.mdx +2 -2
  278. package/docs/learn/14-deploying.mdx +23 -0
  279. package/docs/more/01-advanced-routing.mdx +172 -2
  280. package/docs/more/04-metadata-and-fonts.mdx +1 -1
  281. package/package.json +2 -2
  282. package/src/adapters/build-output-helper.ts +116 -3
  283. package/src/adapters/cloudflare.ts +86 -11
  284. package/src/adapters/fs-identity.ts +156 -0
  285. package/src/adapters/nitro.ts +6 -6
  286. package/src/adapters/shared.ts +196 -21
  287. package/src/adapters/types.ts +13 -1
  288. package/src/cache/fast-hash.ts +5 -0
  289. package/src/client/browser-entry/action-dispatch.ts +9 -4
  290. package/src/client/browser-entry/hydrate.ts +40 -29
  291. package/src/client/browser-entry/index.ts +15 -1
  292. package/src/client/browser-entry/post-hydration.ts +10 -9
  293. package/src/client/browser-entry/router-init.ts +104 -48
  294. package/src/client/browser-entry/rsc-stream.ts +11 -2
  295. package/src/client/error-boundary.tsx +20 -15
  296. package/src/client/history.ts +13 -6
  297. package/src/client/internal.ts +4 -3
  298. package/src/client/link.tsx +55 -8
  299. package/src/client/navigation-api.ts +3 -3
  300. package/src/client/navigation-commit.ts +174 -0
  301. package/src/client/navigation-context.ts +40 -67
  302. package/src/client/navigation-root.tsx +326 -101
  303. package/src/client/params-context.ts +192 -0
  304. package/src/client/router-effects.ts +231 -0
  305. package/src/client/router-lifecycle.ts +288 -0
  306. package/src/client/router-pipeline.ts +389 -0
  307. package/src/client/router-ref.ts +1 -1
  308. package/src/client/router-skew.ts +30 -0
  309. package/src/client/router-types.ts +230 -0
  310. package/src/client/router.ts +242 -707
  311. package/src/client/rsc-fetch.ts +169 -102
  312. package/src/client/segment-cache.ts +121 -44
  313. package/src/client/ssr-data.ts +6 -0
  314. package/src/client/stale-client.ts +191 -0
  315. package/src/client/state.ts +14 -1
  316. package/src/client/top-loader.tsx +2 -1
  317. package/src/client/unload-guard.ts +34 -2
  318. package/src/client/use-cookie.ts +9 -2
  319. package/src/client/use-router.ts +1 -1
  320. package/src/client/use-segment-params.ts +41 -18
  321. package/src/index.ts +5 -1
  322. package/src/plugin-context.ts +32 -0
  323. package/src/plugins/adapter-build.ts +4 -0
  324. package/src/plugins/build-manifest.ts +34 -13
  325. package/src/plugins/entries.ts +4 -0
  326. package/src/plugins/fonts.ts +11 -8
  327. package/src/plugins/request-dep/analysis.ts +447 -0
  328. package/src/plugins/request-dep/index.ts +376 -0
  329. package/src/plugins/request-dep/origin.ts +310 -0
  330. package/src/plugins/routing.ts +59 -2
  331. package/src/plugins/static-build.ts +315 -73
  332. package/src/routing/codegen-types.ts +18 -0
  333. package/src/routing/codegen.ts +50 -10
  334. package/src/routing/collision-probe.ts +438 -0
  335. package/src/routing/collision-spaces.ts +281 -0
  336. package/src/routing/interception.ts +896 -50
  337. package/src/routing/manifest-codegen.ts +5 -3
  338. package/src/routing/scanner.ts +114 -89
  339. package/src/routing/segment-classify.ts +57 -0
  340. package/src/routing/segment-keys.ts +146 -0
  341. package/src/routing/slot-placement.ts +97 -0
  342. package/src/routing/walkers.ts +8 -0
  343. package/src/search-params/define.ts +6 -29
  344. package/src/segment-params/define.ts +4 -27
  345. package/src/server/action-handler.ts +3 -1
  346. package/src/server/actions.ts +6 -3
  347. package/src/server/als-registry.ts +2 -1
  348. package/src/server/build-manifest.ts +14 -1
  349. package/src/server/chain-url-parts.ts +163 -0
  350. package/src/server/children-interception.ts +115 -0
  351. package/src/server/default-status-page.ts +127 -0
  352. package/src/server/deny-renderer.ts +81 -20
  353. package/src/server/head-response.ts +54 -0
  354. package/src/server/param-coercion.ts +48 -18
  355. package/src/server/pipeline-helpers.ts +0 -45
  356. package/src/server/pipeline-interception.ts +81 -32
  357. package/src/server/pipeline-outcome.ts +2 -4
  358. package/src/server/pipeline-phases.ts +68 -16
  359. package/src/server/pipeline.ts +57 -10
  360. package/src/server/prebuilt-runtime.ts +4 -4
  361. package/src/server/publish-params.ts +42 -0
  362. package/src/server/request-context.ts +97 -18
  363. package/src/server/route-element-builder.ts +89 -98
  364. package/src/server/route-handler.ts +8 -8
  365. package/src/server/route-matcher.ts +21 -9
  366. package/src/server/rsc-cache-key-guard.ts +170 -0
  367. package/src/server/rsc-entry/api-handler.ts +6 -8
  368. package/src/server/rsc-entry/error-renderer.ts +64 -25
  369. package/src/server/rsc-entry/helpers.ts +31 -16
  370. package/src/server/rsc-entry/index.ts +36 -28
  371. package/src/server/rsc-entry/render-route.ts +9 -4
  372. package/src/server/rsc-entry/revalidate-renderer.ts +1 -1
  373. package/src/server/rsc-entry/rsc-payload.ts +14 -25
  374. package/src/server/rsc-entry/rsc-stream.ts +4 -3
  375. package/src/server/rsc-entry/ssr-renderer.ts +13 -9
  376. package/src/server/skippable-prefix.ts +92 -0
  377. package/src/server/slot-interception.ts +168 -0
  378. package/src/server/slot-resolver.ts +253 -156
  379. package/src/server/ssr-bridge-types.ts +6 -0
  380. package/src/server/ssr-entry.ts +12 -4
  381. package/src/server/ssr-wrappers.tsx +33 -32
  382. package/src/server/state-tree-diff.ts +14 -55
  383. package/src/server/static-generator.ts +65 -27
  384. package/src/server/static-not-found.ts +134 -0
  385. package/src/shared/als-slots.ts +72 -0
  386. package/src/shared/base-path.ts +80 -0
  387. package/src/shared/param-value.ts +244 -0
  388. package/src/shared/payload-root.ts +151 -0
  389. package/src/shared/rsc-cache-key.ts +269 -0
  390. package/src/shared/rsc-error-envelope.ts +31 -0
  391. package/src/shared/rsc-manifest.ts +29 -0
  392. package/src/shared/rsc-payload-path.ts +45 -0
  393. package/src/shared/segment-info.ts +60 -0
  394. package/src/shared/slot-params.ts +111 -0
  395. package/src/shared/static-platform-files.ts +75 -0
  396. package/dist/_chunks/build-output-helper-DOGYFb_X.js +0 -196
  397. package/dist/_chunks/build-output-helper-DOGYFb_X.js.map +0 -1
  398. package/dist/_chunks/canonicalize-DQHyFClh.js.map +0 -1
  399. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js +0 -668
  400. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js.map +0 -1
  401. package/dist/_chunks/define-COtkxMRT.js +0 -191
  402. package/dist/_chunks/define-COtkxMRT.js.map +0 -1
  403. package/dist/_chunks/define-c4au4I9R.js +0 -82
  404. package/dist/_chunks/define-c4au4I9R.js.map +0 -1
  405. package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +0 -1
  406. package/dist/_chunks/logger-AWfuX-KJ.js.map +0 -1
  407. package/dist/_chunks/navigation-root-bUDZLw74.js +0 -124
  408. package/dist/_chunks/navigation-root-bUDZLw74.js.map +0 -1
  409. package/dist/_chunks/plugin-context---kTF5v8.js.map +0 -1
  410. package/dist/_chunks/router-ref-CtmF-aPv.js.map +0 -1
  411. package/dist/_chunks/ssr-data-BOWsq18U.js.map +0 -1
  412. package/dist/_chunks/use-segment-params-D1CzlgBo.js +0 -151
  413. package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +0 -1
  414. package/dist/_chunks/walkers-_6zKFlch.js.map +0 -1
  415. package/dist/client/error-boundary.js.map +0 -1
  416. package/dist/plugins/request-dep.d.ts +0 -32
  417. package/dist/plugins/request-dep.d.ts.map +0 -1
  418. package/src/plugins/request-dep.ts +0 -499
@@ -30,6 +30,8 @@ import { checkVersionSkew, applyReloadHeaders } from './version-skew.js';
30
30
  import { serveStaticMetadataFile, serializeSitemap } from './pipeline-metadata.js';
31
31
  import { loadModule } from './safe-load.js';
32
32
  import { findInterceptionMatch } from './pipeline-interception.js';
33
+ import { computeSegmentTreePaths } from '../routing/segment-keys.js';
34
+ import { parseClientStateTree } from './state-tree-diff.js';
33
35
  import { applyCookieJar, cloneWithMutableHeaders, type ProxyResolver } from './pipeline-helpers.js';
34
36
  import { coerceSegmentParams } from './param-coercion.js';
35
37
  import { outcomeToResponse, type PhaseOutcome } from './pipeline-outcome.js';
@@ -293,17 +295,6 @@ export async function handleRequest(
293
295
  // outer Server-Timing writer can append without hitting an
294
296
  // immutable header bag (e.g. user returns Response.redirect()).
295
297
  if (handlerResult instanceof Response) {
296
- if (method === 'HEAD') {
297
- const headHeaders = new Headers(handlerResult.headers);
298
- if (handlerResult.ok && !headHeaders.has('Cache-Control')) {
299
- headHeaders.set('Cache-Control', 'public, max-age=14400, must-revalidate');
300
- }
301
- return new Response(null, {
302
- status: handlerResult.status,
303
- statusText: handlerResult.statusText,
304
- headers: headHeaders,
305
- });
306
- }
307
298
  const res = cloneWithMutableHeaders(handlerResult);
308
299
  if (res.ok && !res.headers.has('Cache-Control')) {
309
300
  res.headers.set('Cache-Control', 'public, max-age=14400, must-revalidate');
@@ -401,14 +392,75 @@ export async function handleRequest(
401
392
  ? validateInterceptionHeader(rawSourceUrl, stripTrailingSlash)
402
393
  : null;
403
394
  if (validatedSourceUrl) {
404
- const intercepted = findInterceptionMatch(
395
+ // The scope of an interception is the segment that owns the intercepting
396
+ // slot, so the guard asks whether the route the user is LEAVING renders
397
+ // that segment. Two independent answers to "what is on screen?", tried in
398
+ // order — deferred behind a thunk so neither runs unless a rewrite's
399
+ // target pattern matches.
400
+ //
401
+ // 1. What the client says it has mounted (X-Timber-State-Tree
402
+ // `treePaths`). Authoritative about tree shape and nothing else.
403
+ // 2. What re-matching X-Timber-URL implies. Correct while the address bar
404
+ // still holds the source page, which stops being true the moment a
405
+ // modal is open — the address is then the *intercepted* URL and
406
+ // re-matching it resolves through whichever group owns the canonical
407
+ // page (TIM-1282).
408
+ //
409
+ // Neither is trusted: both are client-supplied, and satisfying the scope
410
+ // only selects which build-time rewrite applies. The rendered pathname is
411
+ // always the rewrite's own `interceptingPrefix`, the server re-derives the
412
+ // rendered chain from it below, and every access.ts runs regardless.
413
+ //
414
+ // They are handed over as two sets in that order rather than one union:
415
+ // each describes a single rendered chain, and only within one chain does
416
+ // "the deepest scope" name the innermost owner (TIM-1318). Unioned, a
417
+ // deeper scope from the address-implied canonical branch — which after
418
+ // (2) may be a route group the client never mounted — would outrank the
419
+ // owner actually on screen.
420
+ const resolveSourceScopes = () => {
421
+ const mounted = new Set(parseClientStateTree(req)?.treePaths ?? []);
422
+ const sourceRoute = config.matchRoute(validatedSourceUrl);
423
+ const addressed = new Set(sourceRoute ? computeSegmentTreePaths(sourceRoute.segments) : []);
424
+ const scopes = [mounted, addressed].filter((scope) => scope.size > 0);
425
+ // Neither channel produced a tree — no scope can contain anything, and
426
+ // an origin that matches no route is not a legitimate soft navigation.
427
+ return scopes.length > 0 ? scopes : null;
428
+ };
429
+ const rewrite = findInterceptionMatch(
405
430
  canonicalPathname,
406
- validatedSourceUrl,
431
+ resolveSourceScopes,
407
432
  config.interceptionRewrites
408
433
  );
409
- if (intercepted) {
410
- const sourceMatch = config.matchRoute(intercepted.sourcePathname);
411
- if (sourceMatch) {
434
+ if (rewrite?.mode === 'children') {
435
+ // Sibling layout swap (TIM-1280). Nothing is re-matched: the resolver
436
+ // addresses the owner directory by tree path and returns the chain
437
+ // `[…owner ancestors, interceptingNode, …descendants]`, which renders
438
+ // as an ordinary route. `interception` stays unset — there is no slot
439
+ // to intercept into, and setting it would additionally arm the modal
440
+ // path for every slot in the tree we are about to render.
441
+ //
442
+ // A null here means the scope named nothing in this manifest, or no
443
+ // intercepting child matched the target. Both fall through to the
444
+ // canonical route, which is what a hard navigation renders.
445
+ const interceptedMatch = config.matchInterceptedRoute?.(
446
+ canonicalPathname,
447
+ rewrite.interceptingScope
448
+ );
449
+ if (interceptedMatch) match = interceptedMatch;
450
+ } else if (rewrite) {
451
+ const sourceMatch = config.matchRoute(rewrite.interceptingPrefix);
452
+ // The scope test above was about the route the user is LEAVING. The
453
+ // route we are about to render is a different one —
454
+ // `interceptingPrefix` is URL-derived, and route groups are
455
+ // URL-invisible, so `/` can resolve into a sibling group that does not
456
+ // own the slot. Rendering that would reproduce the TIM-1278 failure on
457
+ // a valid tree: the rewrite hijacks the navigation and no slot exists
458
+ // to render the intercepting page. Fall through to the canonical
459
+ // target route instead.
460
+ const rendersTheSlot =
461
+ sourceMatch !== null &&
462
+ computeSegmentTreePaths(sourceMatch.segments).includes(rewrite.interceptingScope);
463
+ if (rendersTheSlot) {
412
464
  match = sourceMatch;
413
465
  interception = { targetPathname: canonicalPathname };
414
466
  }
@@ -35,6 +35,9 @@ import { makeProxyResolver } from './pipeline-helpers.js';
35
35
  import { handleRequest, runProxyPhase } from './pipeline-phases.js';
36
36
  import { outcomeToResponse } from './pipeline-outcome.js';
37
37
  import { canonicalize } from './canonicalize.js';
38
+ import { enforceRscCacheKey, hardenRscPayloadResponse } from './rsc-cache-key-guard.js';
39
+ import { stripHeadBody } from './head-response.js';
40
+ import { RSC_KEY_HEADERS } from '../shared/rsc-cache-key.js';
38
41
  import { isDebug } from './debug.js';
39
42
 
40
43
  // ─── Route Match Result ────────────────────────────────────────────────────
@@ -142,6 +145,17 @@ export interface PipelineConfig {
142
145
  * See design/07-routing.md §"Intercepting Routes"
143
146
  */
144
147
  interceptionRewrites?: import('../routing/interception.js').InterceptionRewrite[];
148
+ /**
149
+ * Resolver for children-path interceptions — the sibling layout swap.
150
+ *
151
+ * Separate from `matchRoute` because it addresses the owner directory by
152
+ * tree path rather than by pathname, which needs the manifest tree itself.
153
+ * Omitting it disables the `'children'` interception shape and leaves the
154
+ * canonical route rendering, which is the fail-safe outcome.
155
+ *
156
+ * See design/07-routing.md §"Intercepting Routes"
157
+ */
158
+ matchInterceptedRoute?: import('./children-interception.js').InterceptedRouteMatcher;
145
159
  /**
146
160
  * Control Server-Timing header output.
147
161
  *
@@ -393,17 +407,30 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
393
407
  // DevSpanProcessor reads this for tree/summary output.
394
408
  await setSpanAttribute('http.response.status_code', result.status);
395
409
 
396
- // Vary: Accept — CDNs must cache HTML and RSC payload responses
397
- // separately for the same URL. Without this, a shared cache may
398
- // serve an RSC Flight payload to a browser expecting HTML (or
399
- // vice versa). See GHSA-wfc6-r584-vfw7, design/13-security.md.
410
+ // Vary on exactly the headers the `_rsc` cache key hashes.
400
411
  //
401
- // Vary: X-Timber-URL — intercepting route responses depend on
402
- // the source URL, so caches must store them separately.
403
- const varyTokens = ['Accept'];
404
- if (config.interceptionRewrites?.length) {
405
- varyTokens.push('X-Timber-URL');
406
- }
412
+ // Those two mechanisms answer the same question — which request
413
+ // headers change this response — so they are the same list, not
414
+ // two lists that happen to agree. A separate hand-written list
415
+ // here drifted from `RSC_KEY_HEADERS` the moment the key set
416
+ // grew, and the drift is invisible: `Vary` is the *fallback*
417
+ // layer, used only when a cache omits the query from its key,
418
+ // which is precisely when nobody is watching (TIM-1268).
419
+ //
420
+ // Why any of it: without `Vary: Accept` a shared cache may serve
421
+ // an RSC Flight payload to a browser expecting HTML, or the
422
+ // reverse (GHSA-wfc6-r584-vfw7, design/13-security.md). The
423
+ // `_rsc` param puts that distinction in the URL, so correctness
424
+ // no longer *depends* on `Vary` — which is opt-in configuration
425
+ // on Cloudflare and CloudFront. `Vary` covers the requests that
426
+ // arrive without the param: a stripped query, a hand-rolled
427
+ // client.
428
+ //
429
+ // It costs no hit rate. Document requests send no `X-Timber-*`
430
+ // header at all, so they collapse to a single cache key; payload
431
+ // requests are already fragmented by these same values via the
432
+ // URL.
433
+ const varyTokens = [...RSC_KEY_HEADERS];
407
434
  const existingVary = result.headers.get('Vary');
408
435
  const existingTokens = existingVary
409
436
  ? existingVary
@@ -419,6 +446,26 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
419
446
  );
420
447
  }
421
448
 
449
+ // A request may only claim an `_rsc` cache key that matches its
450
+ // own headers. The key is predictable by design, so without this
451
+ // a caller could render its own variant under another client's
452
+ // key and have a shared cache store it there (TIM-1268).
453
+ await enforceRscCacheKey(canonicalReq, result);
454
+
455
+ // Flight payloads must never be sniffable into a renderable
456
+ // type — applied at this single exit so every producer is
457
+ // covered, not just the success path (TIM-1268).
458
+ hardenRscPayloadResponse(result);
459
+
460
+ // A HEAD response carries the headers its GET would produce and
461
+ // no content (RFC 9110 §9.3.2). Applied at this single exit so
462
+ // every response shape is covered — page render, API route,
463
+ // metadata route, deny page, error page, proxy short-circuit —
464
+ // rather than per-renderer, where it was missing for page
465
+ // renders entirely (TIM-1324). The render still runs: the
466
+ // headers have to be the ones a GET would have sent.
467
+ result = stripHeadBody(result, method);
468
+
422
469
  // Append Server-Timing header based on configured mode.
423
470
  // Header mutability is guaranteed by the producer-side clone
424
471
  // in `outcomeToResponse` and the metadata-route / auto-sitemap
@@ -173,17 +173,17 @@ const registry = new Map<string, PrebuiltRegistration>();
173
173
  */
174
174
  function resolveKeyParams(store: {
175
175
  segmentParams?: Record<string, string | string[]>;
176
- slotParamsMap?: Map<string, Record<string, string | string[]>>;
176
+ slotParams?: Record<string, Record<string, string | string[]>>;
177
177
  }): Record<string, string | string[]> | null {
178
178
  const main = store.segmentParams ?? {};
179
- const map = store.slotParamsMap;
180
- if (!map || map.size === 0) return main;
179
+ const slots = store.slotParams;
180
+ if (!slots || Object.keys(slots).length === 0) return main;
181
181
  // Spread before canonicalizing: param records are framework-produced
182
182
  // Object.create(null) objects (prototype-pollution defense) — normalize
183
183
  // the records themselves, let nested values face the full allowlist.
184
184
  const mainCanonical = tryCanonicalize({ ...main });
185
185
  if (mainCanonical === null) return null;
186
- for (const slotParams of map.values()) {
186
+ for (const slotParams of Object.values(slots)) {
187
187
  const merged = tryCanonicalize({ ...main, ...slotParams });
188
188
  if (merged === null || merged !== mainCanonical) return null;
189
189
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Publishing the request's params onto the RSC payload.
3
+ *
4
+ * Every tree the server sends the browser goes through here: the ordinary
5
+ * route payload (`route-element-builder.ts`), both deny renderers
6
+ * (`deny-renderer.ts`) and the error renderer. One helper rather than a wrap
7
+ * at each site, because these previously *were* separate sites — a response
8
+ * header, an inline script, and a second copy of each on the deny path — and
9
+ * the deny path shipping empty params was the bug that came of it (TIM-1285).
10
+ *
11
+ * Reads the request store rather than taking params as an argument, so a
12
+ * caller cannot pass a different record than the one the request rendered
13
+ * with. See design/41-global-params.md §"Transport".
14
+ */
15
+
16
+ import { toPlainRecord } from '../shared/param-value.js';
17
+ import type { RscPayloadRoot } from '../shared/payload-root.js';
18
+ import { getSegmentParamsForClient, getSlotParamsForClient } from './request-context.js';
19
+
20
+ /**
21
+ * Build the payload root: the tree, and the params it rendered with beside it.
22
+ *
23
+ * The params are a *sibling* of the tree, not a provider around it. A provider
24
+ * inside the payload is shadowed by the retained tree's own provider on a
25
+ * partial navigation, and its props are not readable at the instant the root
26
+ * row resolves — see `shared/payload-root.ts` for both, and TIM-1297. The
27
+ * client renders the one provider readers see, above the merge point.
28
+ *
29
+ * The records are flattened to plain objects on the way out. Every param
30
+ * record the framework builds is `Object.create(null)` (design/13-security.md
31
+ * #36b/#36c), and React Flight rejects a null prototype — "Classes or null
32
+ * prototypes are not supported". `ParamsProvider` restores the prototype on
33
+ * the other side, so what the app reads is unchanged; only the wire
34
+ * representation differs.
35
+ */
36
+ export function withPublishedParams(element: React.ReactElement): RscPayloadRoot {
37
+ return {
38
+ tree: element,
39
+ params: toPlainRecord(getSegmentParamsForClient()),
40
+ slotParams: toPlainRecord(getSlotParamsForClient() ?? null),
41
+ };
42
+ }
@@ -15,9 +15,14 @@
15
15
  */
16
16
 
17
17
  import { requestContextAls, type RequestContextStore } from './als-registry.js';
18
- import { _setGetSearchParamsFn } from '../search-params/define.js';
19
- import { _setGetSegmentParamsFn } from '../segment-params/define.js';
18
+ import { _setGetSearchParamsFn, _setGetSegmentParamsFn } from '../shared/als-slots.js';
20
19
  import { consumeSeededCookies } from './cookie-context.js';
20
+ import { appVisibleSearch } from '../shared/rsc-cache-key.js';
21
+ import {
22
+ mergeSlotParams,
23
+ resolveSegmentParams,
24
+ type SlotParamsRecord,
25
+ } from '../shared/slot-params.js';
21
26
  import { isDebug } from './debug.js';
22
27
 
23
28
  // Re-export the ALS for framework-internal consumers that need direct access.
@@ -111,17 +116,13 @@ export function getSegmentParams(segmentPath?: string): Record<string, string |
111
116
  );
112
117
  }
113
118
 
114
- // Check slot params map first — parallel slots may have different param
115
- // types than the main route (e.g. catch-all [..year] → string[] vs
116
- // dynamic [year] → string). If the requested segment path matches a
117
- // stored slot, return its params merged with the main route's.
118
- if (segmentPath && store.slotParamsMap?.has(segmentPath)) {
119
- const slotParams = store.slotParamsMap.get(segmentPath)!;
120
- // Merge: main params as base, slot-specific params override.
121
- // This ensures params from segments above the slot (that the slot
122
- // doesn't re-derive) are still available.
123
- return { ...store.segmentParams, ...slotParams };
124
- }
119
+ // Parallel slots may derive a param the main route never had, or the same
120
+ // name with a different type (catch-all [...year] → string[] vs dynamic
121
+ // [year] → string). `resolveSegmentParams` is the shared definition the
122
+ // client's useSegmentParams() also reads, so the two halves of one
123
+ // documented API cannot drift (TIM-1285).
124
+ const slotResolved = resolveSegmentParams(store.segmentParams, store.slotParams, segmentPath);
125
+ if (slotResolved !== store.segmentParams) return slotResolved;
125
126
 
126
127
  // Dev-mode validation: warn when the segment path expects dynamic
127
128
  // segments that don't exist on the actual matched segment. This catches
@@ -173,8 +174,82 @@ export function setSlotParams(
173
174
  ): void {
174
175
  const store = requestContextAls.getStore();
175
176
  if (!store) return; // non-throwing — optional diagnostic
176
- if (!store.slotParamsMap) store.slotParamsMap = new Map();
177
- store.slotParamsMap.set(segmentPath, params);
177
+ if (!store.slotParams) store.slotParams = Object.create(null) as SlotParamsRecord;
178
+ store.slotParams[segmentPath] = params;
179
+ }
180
+
181
+ /**
182
+ * Run `fn` with the segment params a parallel slot's own chain produced, so
183
+ * a no-arg `getSegmentParams()` inside that slot returns the slot's params
184
+ * rather than the main route's.
185
+ *
186
+ * ALS is the only channel available: the slot's page and layouts are plain
187
+ * components that receive no params prop and cannot know their own tree
188
+ * path, so they have no way to ask for the keyed overload. The slot resolver
189
+ * invokes each of them itself (page through `SafeSlotPage`, layouts and
190
+ * access functions through their wrappers), and this scopes those calls.
191
+ *
192
+ * The store is wrapped in a Proxy rather than cloned. Everything a slot
193
+ * renders can write to the *live* request store — `setDenyStatus` from an
194
+ * access gate, cookie writes, the flush flag — and a clone would silently
195
+ * strand those writes in a copy the pipeline never reads. Only the two
196
+ * params fields are shadowed; every other read and every write passes
197
+ * straight through to the real store.
198
+ *
199
+ * Returns `fn()`'s result unchanged, and no-ops outside a request context or
200
+ * before route matching has set the main params. See TIM-1283.
201
+ *
202
+ * @internal — framework use only
203
+ */
204
+ export function runWithSlotSegmentParams<T>(
205
+ slotSegmentPath: string | undefined,
206
+ slotParams: Record<string, string | string[]>,
207
+ fn: () => T
208
+ ): T {
209
+ const store = requestContextAls.getStore();
210
+ if (!store?.segmentParams) return fn();
211
+
212
+ const merged = mergeSlotParams(store.segmentParams, slotParams);
213
+ const matchedSegmentPath = slotSegmentPath ?? store.matchedSegmentPath;
214
+ const scoped = new Proxy(store, {
215
+ get(target, prop, receiver) {
216
+ if (prop === 'segmentParams') return merged;
217
+ if (prop === 'matchedSegmentPath') return matchedSegmentPath;
218
+ return Reflect.get(target, prop, receiver);
219
+ },
220
+ });
221
+ return requestContextAls.run(scoped, fn);
222
+ }
223
+
224
+ /**
225
+ * The main route's coerced params, or an empty record before route matching.
226
+ *
227
+ * Non-throwing, unlike `getSegmentParams()`: the deny payload path publishes
228
+ * params from wherever the pipeline happened to fail, which may be before
229
+ * matching completed.
230
+ *
231
+ * @internal — framework use only. See TIM-1285.
232
+ */
233
+ export function getSegmentParamsForClient(): Record<string, string | string[]> {
234
+ return requestContextAls.getStore()?.segmentParams ?? {};
235
+ }
236
+
237
+ /**
238
+ * The per-slot params to publish to the client, or `undefined` when the
239
+ * request rendered no slot with params of its own.
240
+ *
241
+ * The client cannot derive these: a slot matches the URL through its own
242
+ * sub-tree, and the browser only ever sees the main route's record. Reading
243
+ * the map here — rather than threading it back out of the element builder —
244
+ * keeps one producer, since `setSlotParams` already writes it during slot
245
+ * resolution and every serialization site runs after that completes.
246
+ *
247
+ * @internal — framework use only. See TIM-1285.
248
+ */
249
+ export function getSlotParamsForClient(): SlotParamsRecord | undefined {
250
+ const store = requestContextAls.getStore();
251
+ if (!store?.slotParams) return undefined;
252
+ return Object.keys(store.slotParams).length > 0 ? store.slotParams : undefined;
178
253
  }
179
254
 
180
255
  /**
@@ -247,7 +322,7 @@ export type ReadonlyHeaders = Pick<
247
322
  */
248
323
  export function runWithRequestContext<T>(req: Request, fn: () => T): T {
249
324
  const originalCopy = new Headers(req.headers);
250
- const parsedUrl = new URL(req.url);
325
+ const appVisible = appVisibleSearch(new URL(req.url));
251
326
  const seed = consumeSeededCookies(req);
252
327
  const store: RequestContextStore = {
253
328
  headers: freezeHeaders(req.headers),
@@ -257,8 +332,12 @@ export function runWithRequestContext<T>(req: Request, fn: () => T): T {
257
332
  // gated on `parsedCookies` being undefined.
258
333
  cookieHeader: seed ? '' : (req.headers.get('cookie') ?? ''),
259
334
  parsedCookies: seed,
260
- searchParams: parsedUrl.searchParams,
261
- searchString: parsedUrl.search,
335
+ // Not `parsedUrl.searchParams` / `parsedUrl.search`: this store is what
336
+ // `getSearchParams()` and `redirect({ preserveSearchParams })` read, and
337
+ // the RSC payload URL carries the framework's `_rsc` cache key that no
338
+ // other request has (TIM-1272).
339
+ searchParams: appVisible.params,
340
+ searchString: appVisible.search,
262
341
  cookieJar: new Map(),
263
342
  flushed: false,
264
343
  mutableContext: false,