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

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 (570) hide show
  1. package/dist/_chunks/{actions-O_LsyCE4.js → actions-35jnMdeJ.js} +4 -3
  2. package/dist/_chunks/{actions-O_LsyCE4.js.map → actions-35jnMdeJ.js.map} +1 -1
  3. package/dist/_chunks/als-registry-C6kcfprT.js +41 -0
  4. package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -0
  5. package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
  6. package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
  7. package/dist/_chunks/base-path-DaQrzbez.js +80 -0
  8. package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
  9. package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
  10. package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
  11. package/dist/_chunks/build-output-helper-C3DrfzZR.js +369 -0
  12. package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +1 -0
  13. package/dist/_chunks/{cache-api-B-lhk9p4.js → cache-api-DjNrIWRR.js} +8 -14
  14. package/dist/_chunks/cache-api-DjNrIWRR.js.map +1 -0
  15. package/dist/_chunks/cli-check-CpmN7Nh-.js +256 -0
  16. package/dist/_chunks/cli-check-CpmN7Nh-.js.map +1 -0
  17. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js +298 -0
  18. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js.map +1 -0
  19. package/dist/_chunks/{cloudflare-CnT5Lr7U.js → cloudflare-CGP6BZKO.js} +92 -14
  20. package/dist/_chunks/{cloudflare-CnT5Lr7U.js.map → cloudflare-CGP6BZKO.js.map} +1 -1
  21. package/dist/_chunks/convention-lint-kXsgc_-7.js +784 -0
  22. package/dist/_chunks/convention-lint-kXsgc_-7.js.map +1 -0
  23. package/dist/_chunks/error-boundary-D-ODYX41.js +353 -0
  24. package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -0
  25. package/dist/_chunks/{fast-hash-D6hIVt1Y.js → fast-hash-C-tVYrLb.js} +6 -1
  26. package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
  27. package/dist/_chunks/file-cache-DmX7OqZP.js +454 -0
  28. package/dist/_chunks/file-cache-DmX7OqZP.js.map +1 -0
  29. package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
  30. package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
  31. package/dist/_chunks/{logger-AWfuX-KJ.js → logger-D8xJZXIN.js} +34 -51
  32. package/dist/_chunks/logger-D8xJZXIN.js.map +1 -0
  33. package/dist/_chunks/mdx-file-C005ay-P.js +25 -0
  34. package/dist/_chunks/mdx-file-C005ay-P.js.map +1 -0
  35. package/dist/_chunks/{plugin-context---kTF5v8.js → plugin-context-rCinWLiE.js} +8 -2
  36. package/dist/_chunks/plugin-context-rCinWLiE.js.map +1 -0
  37. package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
  38. package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
  39. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js → resolve-schema-5ma5pp1b.js} +2 -2
  40. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js.map → resolve-schema-5ma5pp1b.js.map} +1 -1
  41. package/dist/_chunks/{router-ref-CtmF-aPv.js → router-ref-DuYuV_0Q.js} +2 -2
  42. package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -0
  43. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js +243 -0
  44. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js.map +1 -0
  45. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js +40 -0
  46. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js.map +1 -0
  47. package/dist/_chunks/rsc-media-type-DRqE_lD_.js +46 -0
  48. package/dist/_chunks/rsc-media-type-DRqE_lD_.js.map +1 -0
  49. package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
  50. package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
  51. package/dist/_chunks/scanner-C8b0Gcw3.js +1564 -0
  52. package/dist/_chunks/scanner-C8b0Gcw3.js.map +1 -0
  53. package/dist/_chunks/schema-bridge-Cc2Gngu1.js +199 -0
  54. package/dist/_chunks/schema-bridge-Cc2Gngu1.js.map +1 -0
  55. package/dist/_chunks/{segment-classify-Byy425ng.js → segment-classify-C539Pa2O.js} +23 -2
  56. package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
  57. package/dist/_chunks/segment-context-CjOlyB8Y.js +97 -0
  58. package/dist/_chunks/segment-context-CjOlyB8Y.js.map +1 -0
  59. package/dist/_chunks/{canonicalize-DQHyFClh.js → segment-keys-BawYuNFO.js} +61 -2
  60. package/dist/_chunks/segment-keys-BawYuNFO.js.map +1 -0
  61. package/dist/_chunks/slot-params-BCTmZkQB.js +76 -0
  62. package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -0
  63. package/dist/_chunks/{ssr-data-BOWsq18U.js → ssr-data-14MXm7Pj.js} +17 -2
  64. package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -0
  65. package/dist/_chunks/{use-query-states-DFvWd-EA.js → use-query-states-BbU5Ge1V.js} +74 -26
  66. package/dist/_chunks/use-query-states-BbU5Ge1V.js.map +1 -0
  67. package/dist/_chunks/use-segment-params-C4r4BD9T.js +398 -0
  68. package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -0
  69. package/dist/_chunks/walkers-RzN6AFjr.js +141 -0
  70. package/dist/_chunks/walkers-RzN6AFjr.js.map +1 -0
  71. package/dist/adapters/build-output-helper.d.ts +37 -0
  72. package/dist/adapters/build-output-helper.d.ts.map +1 -1
  73. package/dist/adapters/cloudflare-dev.js +1 -1
  74. package/dist/adapters/cloudflare-kv-cache.js +1 -1
  75. package/dist/adapters/cloudflare.d.ts.map +1 -1
  76. package/dist/adapters/cloudflare.js +1 -1
  77. package/dist/adapters/compress-module.d.ts +12 -0
  78. package/dist/adapters/compress-module.d.ts.map +1 -1
  79. package/dist/adapters/fs-identity.d.ts +64 -0
  80. package/dist/adapters/fs-identity.d.ts.map +1 -0
  81. package/dist/adapters/nitro.d.ts.map +1 -1
  82. package/dist/adapters/nitro.js +56 -5
  83. package/dist/adapters/nitro.js.map +1 -1
  84. package/dist/adapters/shared.d.ts +57 -1
  85. package/dist/adapters/shared.d.ts.map +1 -1
  86. package/dist/adapters/types.d.ts +13 -1
  87. package/dist/adapters/types.d.ts.map +1 -1
  88. package/dist/cache/fast-hash.d.ts +5 -0
  89. package/dist/cache/fast-hash.d.ts.map +1 -1
  90. package/dist/cache/index.js +1 -1
  91. package/dist/cdn/cloudflare-purge.js +30 -0
  92. package/dist/cdn/cloudflare-purge.js.map +1 -0
  93. package/dist/cdn/fastly-purge.js +33 -0
  94. package/dist/cdn/fastly-purge.js.map +1 -0
  95. package/dist/cdn/index.js +94 -0
  96. package/dist/cdn/index.js.map +1 -0
  97. package/dist/cdn/workers-cache-purge.js +35 -0
  98. package/dist/cdn/workers-cache-purge.js.map +1 -0
  99. package/dist/cli-check.d.ts +153 -0
  100. package/dist/cli-check.d.ts.map +1 -0
  101. package/dist/cli.d.ts +34 -8
  102. package/dist/cli.d.ts.map +1 -1
  103. package/dist/cli.js +46 -21
  104. package/dist/cli.js.map +1 -1
  105. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  106. package/dist/client/browser-entry/hydrate.d.ts +20 -9
  107. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  108. package/dist/client/browser-entry/index.d.ts +1 -1
  109. package/dist/client/browser-entry/index.d.ts.map +1 -1
  110. package/dist/client/browser-entry/post-hydration.d.ts +4 -1
  111. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
  112. package/dist/client/browser-entry/router-init.d.ts +3 -0
  113. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  114. package/dist/client/browser-entry/rsc-stream.d.ts +8 -0
  115. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -1
  116. package/dist/client/error-boundary.d.ts +7 -0
  117. package/dist/client/error-boundary.d.ts.map +1 -1
  118. package/dist/client/error-boundary.js +1 -162
  119. package/dist/client/history.d.ts +13 -6
  120. package/dist/client/history.d.ts.map +1 -1
  121. package/dist/client/index.d.ts +1 -0
  122. package/dist/client/index.d.ts.map +1 -1
  123. package/dist/client/index.js +42 -41
  124. package/dist/client/index.js.map +1 -1
  125. package/dist/client/internal.d.ts +4 -3
  126. package/dist/client/internal.d.ts.map +1 -1
  127. package/dist/client/internal.js +877 -311
  128. package/dist/client/internal.js.map +1 -1
  129. package/dist/client/link.d.ts +1 -7
  130. package/dist/client/link.d.ts.map +1 -1
  131. package/dist/client/navigation-api.d.ts +2 -2
  132. package/dist/client/navigation-commit.d.ts +87 -0
  133. package/dist/client/navigation-commit.d.ts.map +1 -0
  134. package/dist/client/navigation-context.d.ts +37 -20
  135. package/dist/client/navigation-context.d.ts.map +1 -1
  136. package/dist/client/navigation-root.d.ts +63 -23
  137. package/dist/client/navigation-root.d.ts.map +1 -1
  138. package/dist/client/params-context.d.ts +81 -0
  139. package/dist/client/params-context.d.ts.map +1 -0
  140. package/dist/client/router-effects.d.ts +129 -0
  141. package/dist/client/router-effects.d.ts.map +1 -0
  142. package/dist/client/router-lifecycle.d.ts +55 -0
  143. package/dist/client/router-lifecycle.d.ts.map +1 -0
  144. package/dist/client/router-pipeline.d.ts +84 -0
  145. package/dist/client/router-pipeline.d.ts.map +1 -0
  146. package/dist/client/router-ref.d.ts +1 -1
  147. package/dist/client/router-ref.d.ts.map +1 -1
  148. package/dist/client/router-skew.d.ts +21 -0
  149. package/dist/client/router-skew.d.ts.map +1 -0
  150. package/dist/client/router-types.d.ts +207 -0
  151. package/dist/client/router-types.d.ts.map +1 -0
  152. package/dist/client/router.d.ts +1 -182
  153. package/dist/client/router.d.ts.map +1 -1
  154. package/dist/client/rsc-fetch.d.ts +47 -26
  155. package/dist/client/rsc-fetch.d.ts.map +1 -1
  156. package/dist/client/segment-cache.d.ts +87 -34
  157. package/dist/client/segment-cache.d.ts.map +1 -1
  158. package/dist/client/ssr-data.d.ts +6 -0
  159. package/dist/client/ssr-data.d.ts.map +1 -1
  160. package/dist/client/stale-client.d.ts +69 -0
  161. package/dist/client/stale-client.d.ts.map +1 -0
  162. package/dist/client/state.d.ts +10 -1
  163. package/dist/client/state.d.ts.map +1 -1
  164. package/dist/client/top-loader.d.ts +2 -1
  165. package/dist/client/top-loader.d.ts.map +1 -1
  166. package/dist/client/unload-guard.d.ts +5 -0
  167. package/dist/client/unload-guard.d.ts.map +1 -1
  168. package/dist/client/use-cookie.d.ts.map +1 -1
  169. package/dist/client/use-query-states.d.ts +9 -3
  170. package/dist/client/use-query-states.d.ts.map +1 -1
  171. package/dist/client/use-router.d.ts +1 -1
  172. package/dist/client/use-segment-params.d.ts +18 -8
  173. package/dist/client/use-segment-params.d.ts.map +1 -1
  174. package/dist/codec.js +1 -1
  175. package/dist/cookies/define-cookie.d.ts.map +1 -1
  176. package/dist/cookies/index.js +5 -5
  177. package/dist/cookies/index.js.map +1 -1
  178. package/dist/index.d.ts +4 -1
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js +1009 -759
  181. package/dist/index.js.map +1 -1
  182. package/dist/params/index.js +1 -1
  183. package/dist/plugin-context.d.ts +46 -0
  184. package/dist/plugin-context.d.ts.map +1 -1
  185. package/dist/plugins/adapter-build.d.ts.map +1 -1
  186. package/dist/plugins/build-manifest.d.ts +1 -1
  187. package/dist/plugins/build-manifest.d.ts.map +1 -1
  188. package/dist/plugins/entries.d.ts.map +1 -1
  189. package/dist/plugins/fonts.d.ts.map +1 -1
  190. package/dist/plugins/request-dep/analysis.d.ts +106 -0
  191. package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
  192. package/dist/plugins/request-dep/index.d.ts +75 -0
  193. package/dist/plugins/request-dep/index.d.ts.map +1 -0
  194. package/dist/plugins/request-dep/origin.d.ts +61 -0
  195. package/dist/plugins/request-dep/origin.d.ts.map +1 -0
  196. package/dist/plugins/routing.d.ts.map +1 -1
  197. package/dist/plugins/shims.d.ts.map +1 -1
  198. package/dist/plugins/static-build.d.ts +160 -8
  199. package/dist/plugins/static-build.d.ts.map +1 -1
  200. package/dist/routing/codegen-shared.d.ts +3 -44
  201. package/dist/routing/codegen-shared.d.ts.map +1 -1
  202. package/dist/routing/codegen-types.d.ts +28 -31
  203. package/dist/routing/codegen-types.d.ts.map +1 -1
  204. package/dist/routing/codegen-write.d.ts +51 -0
  205. package/dist/routing/codegen-write.d.ts.map +1 -0
  206. package/dist/routing/codegen.d.ts.map +1 -1
  207. package/dist/routing/collision-probe.d.ts +104 -0
  208. package/dist/routing/collision-probe.d.ts.map +1 -0
  209. package/dist/routing/collision-spaces.d.ts +26 -0
  210. package/dist/routing/collision-spaces.d.ts.map +1 -0
  211. package/dist/routing/convention-lint.d.ts +18 -4
  212. package/dist/routing/convention-lint.d.ts.map +1 -1
  213. package/dist/routing/export-detect.d.ts +16 -0
  214. package/dist/routing/export-detect.d.ts.map +1 -1
  215. package/dist/routing/index.js +4 -3
  216. package/dist/routing/interception.d.ts +235 -6
  217. package/dist/routing/interception.d.ts.map +1 -1
  218. package/dist/routing/link-codegen.d.ts +19 -4
  219. package/dist/routing/link-codegen.d.ts.map +1 -1
  220. package/dist/routing/manifest-codegen.d.ts +1 -7
  221. package/dist/routing/manifest-codegen.d.ts.map +1 -1
  222. package/dist/routing/scanner.d.ts.map +1 -1
  223. package/dist/routing/segment-classify.d.ts +33 -0
  224. package/dist/routing/segment-classify.d.ts.map +1 -1
  225. package/dist/routing/segment-keys.d.ts +95 -0
  226. package/dist/routing/segment-keys.d.ts.map +1 -0
  227. package/dist/routing/slot-placement.d.ts +48 -0
  228. package/dist/routing/slot-placement.d.ts.map +1 -0
  229. package/dist/routing/types.d.ts +0 -6
  230. package/dist/routing/types.d.ts.map +1 -1
  231. package/dist/routing/walkers.d.ts +6 -0
  232. package/dist/routing/walkers.d.ts.map +1 -1
  233. package/dist/schema-bridge.d.ts +60 -9
  234. package/dist/schema-bridge.d.ts.map +1 -1
  235. package/dist/search-params/define.d.ts +62 -14
  236. package/dist/search-params/define.d.ts.map +1 -1
  237. package/dist/search-params/index.d.ts +0 -1
  238. package/dist/search-params/index.d.ts.map +1 -1
  239. package/dist/search-params/index.js +221 -10
  240. package/dist/search-params/index.js.map +1 -1
  241. package/dist/search-params/parse-total.d.ts +70 -0
  242. package/dist/search-params/parse-total.d.ts.map +1 -0
  243. package/dist/search-params/wrappers.d.ts +26 -3
  244. package/dist/search-params/wrappers.d.ts.map +1 -1
  245. package/dist/server/access-gate.d.ts +19 -8
  246. package/dist/server/access-gate.d.ts.map +1 -1
  247. package/dist/server/action-handler.d.ts.map +1 -1
  248. package/dist/server/actions.d.ts +6 -3
  249. package/dist/server/actions.d.ts.map +1 -1
  250. package/dist/server/als-registry.d.ts +18 -1
  251. package/dist/server/als-registry.d.ts.map +1 -1
  252. package/dist/server/build-manifest.d.ts +13 -1
  253. package/dist/server/build-manifest.d.ts.map +1 -1
  254. package/dist/server/chain-url-parts.d.ts +82 -0
  255. package/dist/server/chain-url-parts.d.ts.map +1 -0
  256. package/dist/server/children-interception.d.ts +49 -0
  257. package/dist/server/children-interception.d.ts.map +1 -0
  258. package/dist/server/compress.d.ts.map +1 -1
  259. package/dist/server/default-status-page.d.ts +45 -0
  260. package/dist/server/default-status-page.d.ts.map +1 -0
  261. package/dist/server/deny-boundary.d.ts +148 -15
  262. package/dist/server/deny-boundary.d.ts.map +1 -1
  263. package/dist/server/deny-renderer.d.ts +15 -4
  264. package/dist/server/deny-renderer.d.ts.map +1 -1
  265. package/dist/server/error-boundary-wrapper.d.ts +85 -15
  266. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  267. package/dist/server/head-response.d.ts +35 -0
  268. package/dist/server/head-response.d.ts.map +1 -0
  269. package/dist/server/index.d.ts +0 -1
  270. package/dist/server/index.d.ts.map +1 -1
  271. package/dist/server/index.js +3 -2
  272. package/dist/server/index.js.map +1 -1
  273. package/dist/server/internal.d.ts +3 -1
  274. package/dist/server/internal.d.ts.map +1 -1
  275. package/dist/server/internal.js +712 -418
  276. package/dist/server/internal.js.map +1 -1
  277. package/dist/server/metadata-collector.d.ts +52 -0
  278. package/dist/server/metadata-collector.d.ts.map +1 -0
  279. package/dist/server/param-coercion.d.ts +22 -6
  280. package/dist/server/param-coercion.d.ts.map +1 -1
  281. package/dist/server/pipeline-helpers.d.ts +0 -18
  282. package/dist/server/pipeline-helpers.d.ts.map +1 -1
  283. package/dist/server/pipeline-interception.d.ts +59 -9
  284. package/dist/server/pipeline-interception.d.ts.map +1 -1
  285. package/dist/server/pipeline-outcome.d.ts.map +1 -1
  286. package/dist/server/pipeline-phases.d.ts.map +1 -1
  287. package/dist/server/pipeline.d.ts +11 -0
  288. package/dist/server/pipeline.d.ts.map +1 -1
  289. package/dist/server/primitives.d.ts +23 -0
  290. package/dist/server/primitives.d.ts.map +1 -1
  291. package/dist/server/publish-params.d.ts +33 -0
  292. package/dist/server/publish-params.d.ts.map +1 -0
  293. package/dist/server/request-context.d.ts +48 -0
  294. package/dist/server/request-context.d.ts.map +1 -1
  295. package/dist/server/route-element-builder.d.ts +22 -3
  296. package/dist/server/route-element-builder.d.ts.map +1 -1
  297. package/dist/server/route-handler.d.ts.map +1 -1
  298. package/dist/server/route-matcher.d.ts +13 -0
  299. package/dist/server/route-matcher.d.ts.map +1 -1
  300. package/dist/server/rsc-cache-key-guard.d.ts +78 -0
  301. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
  302. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  303. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
  304. package/dist/server/rsc-entry/error-renderer.d.ts +15 -3
  305. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  306. package/dist/server/rsc-entry/helpers.d.ts +2 -17
  307. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  308. package/dist/server/rsc-entry/index.d.ts +0 -1
  309. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  310. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  311. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
  312. package/dist/server/rsc-entry/rsc-payload.d.ts +1 -2
  313. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  314. package/dist/server/rsc-entry/rsc-stream.d.ts +15 -2
  315. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  316. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  317. package/dist/server/skippable-prefix.d.ts +23 -0
  318. package/dist/server/skippable-prefix.d.ts.map +1 -0
  319. package/dist/server/slot-interception.d.ts +80 -0
  320. package/dist/server/slot-interception.d.ts.map +1 -0
  321. package/dist/server/slot-resolver.d.ts +70 -8
  322. package/dist/server/slot-resolver.d.ts.map +1 -1
  323. package/dist/server/ssr-bridge-types.d.ts +17 -0
  324. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  325. package/dist/server/ssr-entry.d.ts +0 -1
  326. package/dist/server/ssr-entry.d.ts.map +1 -1
  327. package/dist/server/ssr-wrappers.d.ts +24 -13
  328. package/dist/server/ssr-wrappers.d.ts.map +1 -1
  329. package/dist/server/state-tree-diff.d.ts +6 -27
  330. package/dist/server/state-tree-diff.d.ts.map +1 -1
  331. package/dist/server/static-generator.d.ts +6 -0
  332. package/dist/server/static-generator.d.ts.map +1 -1
  333. package/dist/server/static-not-found.d.ts +52 -0
  334. package/dist/server/static-not-found.d.ts.map +1 -0
  335. package/dist/server/status-code-resolver.d.ts +8 -1
  336. package/dist/server/status-code-resolver.d.ts.map +1 -1
  337. package/dist/server/tree-builder.d.ts +28 -36
  338. package/dist/server/tree-builder.d.ts.map +1 -1
  339. package/dist/server/types.d.ts +12 -7
  340. package/dist/server/types.d.ts.map +1 -1
  341. package/dist/server/utils/element-type.d.ts +40 -0
  342. package/dist/server/utils/element-type.d.ts.map +1 -0
  343. package/dist/shared/als-slots.d.ts +41 -0
  344. package/dist/shared/als-slots.d.ts.map +1 -0
  345. package/dist/shared/base-path.d.ts +56 -0
  346. package/dist/shared/base-path.d.ts.map +1 -0
  347. package/dist/shared/param-value.d.ts +80 -0
  348. package/dist/shared/param-value.d.ts.map +1 -0
  349. package/dist/shared/payload-root.d.ts +108 -0
  350. package/dist/shared/payload-root.d.ts.map +1 -0
  351. package/dist/shared/rsc-cache-key.d.ts +163 -0
  352. package/dist/shared/rsc-cache-key.d.ts.map +1 -0
  353. package/dist/shared/rsc-error-envelope.d.ts +25 -0
  354. package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
  355. package/dist/shared/rsc-manifest.d.ts +28 -0
  356. package/dist/shared/rsc-manifest.d.ts.map +1 -0
  357. package/dist/shared/rsc-media-type.d.ts +40 -0
  358. package/dist/shared/rsc-media-type.d.ts.map +1 -0
  359. package/dist/shared/rsc-payload-path.d.ts +42 -0
  360. package/dist/shared/rsc-payload-path.d.ts.map +1 -0
  361. package/dist/shared/segment-info.d.ts +59 -0
  362. package/dist/shared/segment-info.d.ts.map +1 -0
  363. package/dist/shared/slot-params.d.ts +51 -0
  364. package/dist/shared/slot-params.d.ts.map +1 -0
  365. package/dist/shared/static-platform-files.d.ts +71 -0
  366. package/dist/shared/static-platform-files.d.ts.map +1 -0
  367. package/docs/api/30-api-server.mdx +1 -1
  368. package/docs/api/31-api-client.mdx +4 -2
  369. package/docs/api/33-api-search-params.mdx +38 -16
  370. package/docs/api/35-api-typescript.mdx +3 -3
  371. package/docs/api/36-cli.mdx +34 -7
  372. package/docs/learn/00-introduction.mdx +1 -1
  373. package/docs/learn/02-pages-and-layouts.mdx +2 -2
  374. package/docs/learn/05-typed-params.mdx +8 -8
  375. package/docs/learn/07-typed-routes.mdx +12 -7
  376. package/docs/learn/11-error-handling.mdx +18 -0
  377. package/docs/learn/12-client-navigation.mdx +2 -2
  378. package/docs/learn/14-deploying.mdx +23 -0
  379. package/docs/more/01-advanced-routing.mdx +173 -3
  380. package/docs/more/03-coming-from-nextjs.mdx +2 -2
  381. package/docs/more/04-metadata-and-fonts.mdx +1 -1
  382. package/docs/more/50-ai-agent-instructions.mdx +6 -4
  383. package/package.json +9 -6
  384. package/src/adapters/build-output-helper.ts +116 -3
  385. package/src/adapters/cloudflare.ts +90 -12
  386. package/src/adapters/compress-module.ts +79 -1
  387. package/src/adapters/fs-identity.ts +156 -0
  388. package/src/adapters/nitro.ts +6 -6
  389. package/src/adapters/shared.ts +196 -21
  390. package/src/adapters/types.ts +13 -1
  391. package/src/cache/fast-hash.ts +5 -0
  392. package/src/cli-check.ts +458 -0
  393. package/src/cli.ts +59 -24
  394. package/src/client/browser-entry/action-dispatch.ts +11 -5
  395. package/src/client/browser-entry/hydrate.ts +40 -29
  396. package/src/client/browser-entry/index.ts +15 -6
  397. package/src/client/browser-entry/post-hydration.ts +10 -9
  398. package/src/client/browser-entry/router-init.ts +104 -48
  399. package/src/client/browser-entry/rsc-stream.ts +11 -2
  400. package/src/client/error-boundary.tsx +85 -16
  401. package/src/client/history.ts +13 -6
  402. package/src/client/index.ts +14 -3
  403. package/src/client/internal.ts +4 -3
  404. package/src/client/link.tsx +120 -72
  405. package/src/client/navigation-api.ts +3 -3
  406. package/src/client/navigation-commit.ts +197 -0
  407. package/src/client/navigation-context.ts +40 -67
  408. package/src/client/navigation-root.tsx +326 -101
  409. package/src/client/params-context.ts +192 -0
  410. package/src/client/router-effects.ts +231 -0
  411. package/src/client/router-lifecycle.ts +288 -0
  412. package/src/client/router-pipeline.ts +393 -0
  413. package/src/client/router-ref.ts +1 -1
  414. package/src/client/router-skew.ts +30 -0
  415. package/src/client/router-types.ts +230 -0
  416. package/src/client/router.ts +243 -707
  417. package/src/client/rsc-fetch.ts +183 -106
  418. package/src/client/segment-cache.ts +129 -44
  419. package/src/client/ssr-data.ts +6 -0
  420. package/src/client/stale-client.ts +191 -0
  421. package/src/client/state.ts +14 -1
  422. package/src/client/top-loader.tsx +2 -1
  423. package/src/client/unload-guard.ts +34 -2
  424. package/src/client/use-cookie.ts +9 -2
  425. package/src/client/use-query-states.ts +102 -39
  426. package/src/client/use-router.ts +1 -1
  427. package/src/client/use-segment-params.ts +41 -18
  428. package/src/cookies/define-cookie.ts +6 -1
  429. package/src/index.ts +25 -4
  430. package/src/plugin-context.ts +58 -0
  431. package/src/plugins/adapter-build.ts +4 -0
  432. package/src/plugins/build-manifest.ts +34 -13
  433. package/src/plugins/entries.ts +4 -0
  434. package/src/plugins/fonts.ts +11 -8
  435. package/src/plugins/request-dep/analysis.ts +447 -0
  436. package/src/plugins/request-dep/index.ts +376 -0
  437. package/src/plugins/request-dep/origin.ts +310 -0
  438. package/src/plugins/routing.ts +97 -102
  439. package/src/plugins/shims.ts +0 -1
  440. package/src/plugins/static-build.ts +391 -95
  441. package/src/routing/codegen-shared.ts +3 -79
  442. package/src/routing/codegen-types.ts +28 -31
  443. package/src/routing/codegen-write.ts +139 -0
  444. package/src/routing/codegen.ts +86 -172
  445. package/src/routing/collision-probe.ts +438 -0
  446. package/src/routing/collision-spaces.ts +281 -0
  447. package/src/routing/convention-lint.ts +139 -40
  448. package/src/routing/export-detect.ts +151 -7
  449. package/src/routing/interception.ts +896 -50
  450. package/src/routing/link-codegen.ts +32 -65
  451. package/src/routing/manifest-codegen.ts +6 -62
  452. package/src/routing/scanner.ts +117 -92
  453. package/src/routing/segment-classify.ts +57 -0
  454. package/src/routing/segment-keys.ts +146 -0
  455. package/src/routing/slot-placement.ts +97 -0
  456. package/src/routing/types.ts +0 -6
  457. package/src/routing/walkers.ts +8 -0
  458. package/src/schema-bridge.ts +180 -58
  459. package/src/search-params/define.ts +108 -66
  460. package/src/search-params/index.ts +0 -1
  461. package/src/search-params/parse-total.ts +78 -0
  462. package/src/search-params/wrappers.ts +60 -11
  463. package/src/server/access-gate.tsx +60 -40
  464. package/src/server/action-handler.ts +4 -5
  465. package/src/server/actions.ts +6 -3
  466. package/src/server/als-registry.ts +18 -1
  467. package/src/server/build-manifest.ts +14 -1
  468. package/src/server/chain-url-parts.ts +163 -0
  469. package/src/server/children-interception.ts +115 -0
  470. package/src/server/compress.ts +9 -1
  471. package/src/server/default-status-page.ts +127 -0
  472. package/src/server/deny-boundary.ts +269 -41
  473. package/src/server/deny-renderer.ts +111 -39
  474. package/src/server/error-boundary-wrapper.ts +166 -79
  475. package/src/server/head-response.ts +54 -0
  476. package/src/server/index.ts +1 -3
  477. package/src/server/internal.ts +2 -2
  478. package/src/server/metadata-collector.ts +115 -0
  479. package/src/server/param-coercion.ts +51 -69
  480. package/src/server/pipeline-helpers.ts +2 -47
  481. package/src/server/pipeline-interception.ts +81 -32
  482. package/src/server/pipeline-outcome.ts +4 -5
  483. package/src/server/pipeline-phases.ts +77 -25
  484. package/src/server/pipeline.ts +57 -10
  485. package/src/server/prebuilt-runtime.ts +4 -4
  486. package/src/server/primitives.ts +25 -0
  487. package/src/server/publish-params.ts +42 -0
  488. package/src/server/request-context.ts +97 -18
  489. package/src/server/route-element-builder.ts +241 -253
  490. package/src/server/route-handler.ts +8 -8
  491. package/src/server/route-matcher.ts +21 -9
  492. package/src/server/rsc-cache-key-guard.ts +164 -0
  493. package/src/server/rsc-entry/api-handler.ts +6 -8
  494. package/src/server/rsc-entry/deny-fallback.ts +3 -2
  495. package/src/server/rsc-entry/error-renderer.ts +94 -35
  496. package/src/server/rsc-entry/helpers.ts +33 -28
  497. package/src/server/rsc-entry/index.ts +36 -33
  498. package/src/server/rsc-entry/render-route.ts +18 -10
  499. package/src/server/rsc-entry/revalidate-renderer.ts +3 -2
  500. package/src/server/rsc-entry/rsc-payload.ts +113 -40
  501. package/src/server/rsc-entry/rsc-stream.ts +29 -5
  502. package/src/server/rsc-entry/ssr-renderer.ts +38 -22
  503. package/src/server/skippable-prefix.ts +92 -0
  504. package/src/server/slot-interception.ts +168 -0
  505. package/src/server/slot-resolver.ts +263 -158
  506. package/src/server/ssr-bridge-types.ts +18 -0
  507. package/src/server/ssr-entry.ts +20 -10
  508. package/src/server/ssr-wrappers.tsx +33 -32
  509. package/src/server/state-tree-diff.ts +14 -55
  510. package/src/server/static-generator.ts +68 -29
  511. package/src/server/static-not-found.ts +134 -0
  512. package/src/server/status-code-resolver.ts +28 -11
  513. package/src/server/tree-builder.ts +35 -218
  514. package/src/server/types.ts +12 -7
  515. package/src/server/utils/element-type.ts +72 -0
  516. package/src/shared/als-slots.ts +72 -0
  517. package/src/shared/base-path.ts +80 -0
  518. package/src/shared/param-value.ts +244 -0
  519. package/src/shared/payload-root.ts +151 -0
  520. package/src/shared/rsc-cache-key.ts +269 -0
  521. package/src/shared/rsc-error-envelope.ts +31 -0
  522. package/src/shared/rsc-manifest.ts +29 -0
  523. package/src/shared/rsc-media-type.ts +43 -0
  524. package/src/shared/rsc-payload-path.ts +45 -0
  525. package/src/shared/segment-info.ts +60 -0
  526. package/src/shared/slot-params.ts +111 -0
  527. package/src/shared/static-platform-files.ts +75 -0
  528. package/dist/_chunks/build-output-helper-DOGYFb_X.js +0 -196
  529. package/dist/_chunks/build-output-helper-DOGYFb_X.js.map +0 -1
  530. package/dist/_chunks/cache-api-B-lhk9p4.js.map +0 -1
  531. package/dist/_chunks/canonicalize-DQHyFClh.js.map +0 -1
  532. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js +0 -668
  533. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js.map +0 -1
  534. package/dist/_chunks/define-COtkxMRT.js +0 -191
  535. package/dist/_chunks/define-COtkxMRT.js.map +0 -1
  536. package/dist/_chunks/define-c4au4I9R.js +0 -82
  537. package/dist/_chunks/define-c4au4I9R.js.map +0 -1
  538. package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +0 -1
  539. package/dist/_chunks/logger-AWfuX-KJ.js.map +0 -1
  540. package/dist/_chunks/navigation-root-bUDZLw74.js +0 -124
  541. package/dist/_chunks/navigation-root-bUDZLw74.js.map +0 -1
  542. package/dist/_chunks/plugin-context---kTF5v8.js.map +0 -1
  543. package/dist/_chunks/registry-DbJPKoBp.js +0 -20
  544. package/dist/_chunks/registry-DbJPKoBp.js.map +0 -1
  545. package/dist/_chunks/router-ref-CtmF-aPv.js.map +0 -1
  546. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +0 -119
  547. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +0 -1
  548. package/dist/_chunks/segment-classify-Byy425ng.js.map +0 -1
  549. package/dist/_chunks/segment-context-ZDnXDkbz.js +0 -34
  550. package/dist/_chunks/segment-context-ZDnXDkbz.js.map +0 -1
  551. package/dist/_chunks/ssr-data-BOWsq18U.js.map +0 -1
  552. package/dist/_chunks/use-query-states-DFvWd-EA.js.map +0 -1
  553. package/dist/_chunks/use-segment-params-D1CzlgBo.js +0 -151
  554. package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +0 -1
  555. package/dist/_chunks/walkers-_6zKFlch.js +0 -1002
  556. package/dist/_chunks/walkers-_6zKFlch.js.map +0 -1
  557. package/dist/client/error-boundary.js.map +0 -1
  558. package/dist/plugins/request-dep.d.ts +0 -32
  559. package/dist/plugins/request-dep.d.ts.map +0 -1
  560. package/dist/search-params/registry.d.ts +0 -20
  561. package/dist/search-params/registry.d.ts.map +0 -1
  562. package/dist/segment-params/define.d.ts +0 -89
  563. package/dist/segment-params/define.d.ts.map +0 -1
  564. package/dist/segment-params/index.d.ts +0 -3
  565. package/dist/segment-params/index.d.ts.map +0 -1
  566. package/dist/segment-params/index.js +0 -2
  567. package/src/plugins/request-dep.ts +0 -499
  568. package/src/search-params/registry.ts +0 -31
  569. package/src/segment-params/define.ts +0 -249
  570. package/src/segment-params/index.ts +0 -9
@@ -26,11 +26,14 @@ import type { InterceptionContext, RouteMatch } from './pipeline.js';
26
26
  import { DenySignal, RedirectSignal } from './primitives.js';
27
27
  import { logRenderError } from './logger.js';
28
28
  import type { ManifestSegmentNode } from './route-matcher.js';
29
- import { setSlotParams } from './request-context.js';
29
+ import { setSlotParams, runWithSlotSegmentParams } from './request-context.js';
30
30
  import { coerceSlotParams } from './param-coercion.js';
31
31
  import { matchUrlParts } from './tree-match.js';
32
+ import { extractUrlParts, consumedPartsThroughSegment } from './chain-url-parts.js';
33
+ import { findInterceptingMatch } from './slot-interception.js';
32
34
  import { SegmentOutlet } from '../client/segment-outlet.js';
33
- import { computeSlotKey, shouldSkipSlot, type ClientStateTree } from './state-tree-diff.js';
35
+ import { shouldSkipSlot, type ClientStateTree } from './state-tree-diff.js';
36
+ import { computeSlotKey } from '../routing/segment-keys.js';
34
37
  import { isStaticRequestDependent } from './request-dep.js';
35
38
 
36
39
  type CreateElementFn = (...args: unknown[]) => React.ReactElement;
@@ -96,21 +99,27 @@ export async function resolveSlotElement(
96
99
  : findSlotMatch(slotNode, match);
97
100
 
98
101
  if (slotMatch) {
99
- // Store per-slot params in ALS so getSegmentParams(segmentPath) returns
100
- // the slot's own param types (e.g. catch-all → string[] vs dynamic → string).
101
- if (parentTreePath && Object.keys(slotMatch.slotParams).length > 0) {
102
- // Build the full tree path: parent prefix + slot chain segment names.
103
- const slotSuffix = slotMatch.chain
104
- .map((s) => s.segmentName)
105
- .filter(Boolean)
106
- .join('/');
107
- const prefix = parentTreePath === '/' ? '' : parentTreePath;
108
- const fullSlotPath = `${prefix}/${slotSuffix}`;
109
-
110
- // Coerce slot params through global schema codecs (same as main route).
111
- const coerced = coerceSlotParams(slotMatch.chain, slotMatch.slotParams);
102
+ // Coerce the slot's own chain params through the global schema codecs
103
+ // (same as the main route) and expose them two ways:
104
+ //
105
+ // - keyed, in the ALS slot map, so `getSegmentParams(slotPath)` resolves
106
+ // from anywhere in the request;
107
+ // - scoped, around every component this resolver invokes from the slot's
108
+ // matched chain, so a no-arg `getSegmentParams()` inside the slot
109
+ // returns the slot's params instead of the main route's. An
110
+ // intercepting page has no other way to see its own params: the
111
+ // pipeline re-matched the SOURCE pathname, so the main params describe
112
+ // the page rendering *behind* the modal (TIM-1283).
113
+ //
114
+ // Both derive from the same coerced record, so the keyed overload and the
115
+ // no-arg call inside the slot can never disagree.
116
+ const coerced = coerceSlotParams(slotMatch.chain, slotMatch.slotParams);
117
+ const fullSlotPath = computeSlotSegmentPath(slotMatch.chain, parentTreePath);
118
+
119
+ if (fullSlotPath && Object.keys(coerced).length > 0) {
112
120
  setSlotParams(fullSlotPath, coerced);
113
121
  }
122
+ const scope = <T>(fn: () => T): T => runWithSlotSegmentParams(fullSlotPath, coerced, fn);
114
123
 
115
124
  const SlotPage = await loadComponent(slotMatch.page);
116
125
  if (SlotPage) {
@@ -137,7 +146,9 @@ export async function resolveSlotElement(
137
146
  } else {
138
147
  const SafeSlotPage = async (props: Record<string, unknown>) => {
139
148
  try {
140
- return await (SlotPage as (props: Record<string, unknown>) => unknown)(props);
149
+ return await scope(() =>
150
+ (SlotPage as (props: Record<string, unknown>) => unknown)(props)
151
+ );
141
152
  } catch (error) {
142
153
  // RedirectSignal must propagate — the pipeline handles redirects
143
154
  // at the top level. Swallowing it here would silently return
@@ -165,11 +176,17 @@ export async function resolveSlotElement(
165
176
  // intermediate slot segments (everything between slot root and leaf).
166
177
  // Process innermost-first, same order as route-element-builder.ts
167
178
  // handles main segments. The slot root (index 0) is handled below.
168
- element = await wrapWithIntermediateSegments(slotMatch.chain, element, h, accessVerdicts);
179
+ element = await wrapWithIntermediateSegments(
180
+ slotMatch.chain,
181
+ element,
182
+ h,
183
+ accessVerdicts,
184
+ scope
185
+ );
169
186
 
170
187
  // Wrap with slot root's layout — INSIDE the access gate, so the layout
171
188
  // server component never executes when access.ts denies. See TIM-1074.
172
- element = await wrapWithLayout(slotNode, element, h);
189
+ element = await wrapWithLayout(slotNode, element, h, scope);
173
190
 
174
191
  // Wrap in SlotAccessGate if slot root has access.ts. The gate is
175
192
  // OUTSIDE the layout, matching the segment model in
@@ -178,10 +195,14 @@ export async function resolveSlotElement(
178
195
  // On denial: denied.tsx → default.tsx → null (graceful degradation),
179
196
  // rendered WITHOUT the denied slot's own layout.
180
197
  // See design/04-authorization.md §"Slot-Level Auth".
181
- element = await wrapWithAccessGate(slotNode, element, h, accessVerdicts);
198
+ element = await wrapWithAccessGate(slotNode, element, h, accessVerdicts, scope);
182
199
 
183
200
  // Wrap with slot root's error boundaries (outermost)
184
- element = await wrapSegmentWithErrorBoundaries(slotNode, element, h);
201
+ element = await wrapSegmentWithErrorBoundaries(slotNode, element, {
202
+ loadModule,
203
+ createElement: h,
204
+ errorBoundaryComponent: TimberErrorBoundary,
205
+ });
185
206
 
186
207
  // Catch-all error boundary: ensures slot errors NEVER propagate to the
187
208
  // parent layout. Without this, a slot without error.tsx that throws
@@ -207,6 +228,33 @@ export async function resolveSlotElement(
207
228
  return renderDefaultFallback(slotNode, h);
208
229
  }
209
230
 
231
+ /**
232
+ * The full tree path of a slot's matched chain — the key both the ALS slot
233
+ * params map and the generated `getSegmentParams` overloads use.
234
+ *
235
+ * Built from the parent's tree path plus each chain node's directory name,
236
+ * so an intercepting node contributes its marker
237
+ * (`/gallery/@modal/(.)photo/[id]`) and a route group contributes its
238
+ * parentheses. Returns undefined when the caller has no parent tree path,
239
+ * which is how the resolver's test callers and any path-less entry point opt
240
+ * out of keyed lookups.
241
+ *
242
+ * One definition for both the render path and the eager access path: they
243
+ * key the same map, and a divergence would silently strand one of them.
244
+ */
245
+ function computeSlotSegmentPath(
246
+ chain: ManifestSegmentNode[],
247
+ parentTreePath: string | undefined
248
+ ): string | undefined {
249
+ if (!parentTreePath) return undefined;
250
+ const slotSuffix = chain
251
+ .map((s) => s.segmentName)
252
+ .filter(Boolean)
253
+ .join('/');
254
+ const prefix = parentTreePath === '/' ? '' : parentTreePath;
255
+ return `${prefix}/${slotSuffix}`;
256
+ }
257
+
210
258
  // ─── Element Wrapping Helpers ───────────────────────────────────────────────
211
259
 
212
260
  /**
@@ -229,29 +277,80 @@ async function wrapWithIntermediateSegments(
229
277
  chain: ManifestSegmentNode[],
230
278
  element: React.ReactElement,
231
279
  h: CreateElementFn,
232
- accessVerdicts?: SlotAccessVerdict[]
280
+ accessVerdicts?: SlotAccessVerdict[],
281
+ scope?: SlotParamScope
233
282
  ): Promise<React.ReactElement> {
234
283
  for (let i = chain.length - 1; i > 0; i--) {
235
284
  const seg = chain[i];
236
- element = await wrapSegmentWithErrorBoundaries(seg, element, h);
237
- element = await wrapWithLayout(seg, element, h);
238
- element = await wrapWithAccessGate(seg, element, h, accessVerdicts);
285
+ element = await wrapSegmentWithErrorBoundaries(seg, element, {
286
+ loadModule,
287
+ createElement: h,
288
+ errorBoundaryComponent: TimberErrorBoundary,
289
+ });
290
+ element = await wrapWithLayout(seg, element, h, scope);
291
+ element = await wrapWithAccessGate(seg, element, h, accessVerdicts, scope);
239
292
  }
240
293
  return element;
241
294
  }
242
295
 
296
+ /**
297
+ * Runs a function with the slot's own segment params in scope.
298
+ *
299
+ * Applied to every component this module invokes from a slot's matched chain
300
+ * — page, layouts, access functions — so all of them agree on what a no-arg
301
+ * `getSegmentParams()` means inside a slot. A partial application would be
302
+ * worse than none: a layout and the page under it would disagree about the
303
+ * params of the same render.
304
+ */
305
+ type SlotParamScope = <T>(fn: () => T) => T;
306
+
307
+ /**
308
+ * Invokes a slot layout inside that slot's param scope.
309
+ *
310
+ * Declared at module scope, and given the layout and the scope as props,
311
+ * so its component identity is the same on every render. A closure created
312
+ * per render would be a new component type each time, and React would
313
+ * unmount and remount the whole layout subtree — including client
314
+ * components' state — on every navigation that re-renders the slot.
315
+ *
316
+ * Server component: the function-valued props are called here on the server
317
+ * and never reach the Flight stream, the same way `SlotAccessGate` takes
318
+ * `accessFn`.
319
+ */
320
+ function ScopedSlotLayout(props: {
321
+ layout: (props: Record<string, unknown>) => unknown;
322
+ scope: SlotParamScope;
323
+ children: React.ReactElement;
324
+ }): unknown {
325
+ return props.scope(() => props.layout({ children: props.children }));
326
+ }
327
+
243
328
  /**
244
329
  * Wrap an element with a segment's layout component, if present.
330
+ *
331
+ * A server-component layout is invoked through the slot param scope, so it
332
+ * sees the slot's params rather than the main route's — a layout and the
333
+ * page beneath it must not disagree about the params of one render. A
334
+ * client-reference layout is passed through untouched: it never executes on
335
+ * the server, and its params arrive over the client channel
336
+ * (`useSegmentParams`).
245
337
  */
246
338
  async function wrapWithLayout(
247
339
  node: ManifestSegmentNode,
248
340
  element: React.ReactElement,
249
- h: CreateElementFn
341
+ h: CreateElementFn,
342
+ scope?: SlotParamScope
250
343
  ): Promise<React.ReactElement> {
251
344
  if (!node.layout) return element;
252
345
  const Layout = await loadComponent(node.layout);
253
346
  if (!Layout) return element;
254
- return h(Layout, { children: element });
347
+ if (!scope || isClientReference(Layout)) return h(Layout, { children: element });
348
+
349
+ return h(ScopedSlotLayout, {
350
+ layout: Layout as (props: Record<string, unknown>) => unknown,
351
+ scope,
352
+ children: element,
353
+ });
255
354
  }
256
355
 
257
356
  /**
@@ -262,12 +361,17 @@ async function wrapWithAccessGate(
262
361
  slotNode: ManifestSegmentNode,
263
362
  element: React.ReactElement,
264
363
  h: CreateElementFn,
265
- accessVerdicts?: SlotAccessVerdict[]
364
+ accessVerdicts?: SlotAccessVerdict[],
365
+ scope?: SlotParamScope
266
366
  ): Promise<React.ReactElement> {
267
367
  if (!slotNode.access) return element;
268
368
 
269
- const accessFn = await loadComponent(slotNode.access);
270
- if (!accessFn) return element;
369
+ const loaded = await loadComponent(slotNode.access);
370
+ if (!loaded) return element;
371
+
372
+ // The gate calls this during render, so the scope has to travel with the
373
+ // function rather than wrap the call site.
374
+ const accessFn = scope ? () => scope(() => loaded()) : loaded;
271
375
 
272
376
  let DeniedComponent: ((...args: unknown[]) => unknown) | null = null;
273
377
  if (slotNode.denied) {
@@ -302,7 +406,7 @@ async function wrapWithAccessGate(
302
406
  // ─── Slot Matching ──────────────────────────────────────────────────────────
303
407
 
304
408
  /** Result of matching a slot's sub-tree against the current route. */
305
- interface SlotMatchResult {
409
+ export interface SlotMatchResult {
306
410
  /** The page file at the matched leaf. */
307
411
  page: NonNullable<ManifestSegmentNode['page']>;
308
412
  /** The full chain of slot nodes traversed (slot root → … → leaf with page). */
@@ -326,25 +430,50 @@ interface SlotMatchResult {
326
430
  * We compare the matched route's segment chain against the slot's children
327
431
  * to find the deepest matching page.
328
432
  */
329
- function findSlotMatch(slotNode: ManifestSegmentNode, match: RouteMatch): SlotMatchResult | null {
330
- const segments = match.segments;
331
-
332
- // Find the parent segment that owns this slot by comparing urlPaths.
333
- // The slot's urlPath matches its parent's urlPath (slots don't add URL depth).
334
- // Search BACKWARDS to find the deepest (last) matching segment. Multiple
335
- // segments can share the same urlPath when route groups are involved (e.g.,
336
- // Root urlPath='/' and (browse) urlPath='/'). The slot's parent is always
337
- // the deepest one — searching forward would incorrectly pick the root,
338
- // making remainingSegments too long and breaking slot matching.
339
- const slotUrlPath = slotNode.urlPath;
340
- let parentIndex = -1;
433
+ /**
434
+ * The index in the matched chain of the segment that owns this slot.
435
+ *
436
+ * **By identity**, because `urlPath` cannot answer it. Slots add no URL depth,
437
+ * so the owner shares the slot's `urlPath` — but so does every route group
438
+ * above it (`/` for both the root and `(browse)`), and since TIM-1280 so does
439
+ * an intercepting node on the children path, which sits *below* the owner.
440
+ * Picking the deepest urlPath match — the rule before this — therefore chose
441
+ * the intercepting node for a tree like `(browse)/@sidebar/` +
442
+ * `(browse)/(.)item/[id]/`, slicing one segment too many off the chain and
443
+ * handing `@sidebar` a shorter URL than it matches against. It would render
444
+ * its `default.tsx` where a page exists.
445
+ *
446
+ * The index must also agree with `slotUrlParts`, which slices the destination
447
+ * pathname at the same point and already used `indexOf(owner)`. Two derivations
448
+ * of one index is how they came apart; this is the shared one.
449
+ *
450
+ * The `urlPath` search survives only as a fallback for a `slotNode` that is not
451
+ * attached to any segment in the chain. Production never does that —
452
+ * `resolveSlotProps` iterates `segment.slots` — but unit tests construct a slot
453
+ * node standalone, and for those the old behaviour is still the right answer.
454
+ */
455
+ export function findSlotOwnerIndex(
456
+ slotNode: ManifestSegmentNode,
457
+ segments: ManifestSegmentNode[]
458
+ ): number {
341
459
  for (let i = segments.length - 1; i >= 0; i--) {
342
- if (segments[i].urlPath === slotUrlPath) {
343
- parentIndex = i;
344
- break;
460
+ for (const candidate of Object.values(segments[i].slots ?? {})) {
461
+ if (candidate === slotNode) return i;
345
462
  }
346
463
  }
347
464
 
465
+ for (let i = segments.length - 1; i >= 0; i--) {
466
+ if (segments[i].urlPath === slotNode.urlPath) return i;
467
+ }
468
+
469
+ return -1;
470
+ }
471
+
472
+ function findSlotMatch(slotNode: ManifestSegmentNode, match: RouteMatch): SlotMatchResult | null {
473
+ const segments = match.segments;
474
+
475
+ const parentIndex = findSlotOwnerIndex(slotNode, segments);
476
+
348
477
  // The remaining segments after the parent are what we need to match
349
478
  // against the slot's children.
350
479
  const remainingSegments = parentIndex >= 0 ? segments.slice(parentIndex + 1) : [];
@@ -367,96 +496,6 @@ function findSlotMatch(slotNode: ManifestSegmentNode, match: RouteMatch): SlotMa
367
496
  return { page: leaf.page, chain: result.chain, slotParams: result.params };
368
497
  }
369
498
 
370
- /**
371
- * Extract raw URL path parts from a main-route segment chain.
372
- *
373
- * Each dynamic segment consumed one URL part (its param value).
374
- * Static segments consumed their own name. Groups are transparent.
375
- * Catch-all segments consumed multiple parts (their param value is string[]).
376
- *
377
- * Uses rawSegmentParams (pre-coercion) to get actual URL strings.
378
- * Values are coerced to String() defensively in case a codec leaked
379
- * a non-string value into the params map.
380
- */
381
- export function extractUrlParts(
382
- segments: ManifestSegmentNode[],
383
- mainParams: Record<string, string | string[]>
384
- ): string[] {
385
- const parts: string[] = [];
386
- for (const seg of segments) {
387
- if (seg.segmentType === 'group') continue;
388
- if (seg.segmentType === 'static') {
389
- parts.push(seg.segmentName);
390
- } else if (seg.paramName) {
391
- const value = mainParams[seg.paramName];
392
- if (Array.isArray(value)) {
393
- parts.push(...value.map(String));
394
- } else if (value !== undefined) {
395
- // Reconstruct the original URL part for affixed segments.
396
- // The param value is the stripped middle (e.g. "123" for [id].png
397
- // matching "123.png"), so we re-attach prefix/suffix so that slot
398
- // matching through matchUrlParts sees the original part.
399
- const prefix = seg.paramPrefix ?? '';
400
- const suffix = seg.paramSuffix ?? '';
401
- parts.push(prefix + String(value) + suffix);
402
- }
403
- }
404
- }
405
- return parts;
406
- }
407
-
408
- /**
409
- * Find a matching intercepting route in a slot's children for the target pathname.
410
- *
411
- * When interception is active, the pipeline has already re-matched the source URL.
412
- * Here we check the slot's intercepting children (e.g. `(.)photo/[id]`) against
413
- * the target pathname to find which intercepting page to render.
414
- *
415
- * The interceptedSegmentName tells us the first URL segment to look for in the
416
- * target pathname. We then walk the intercepting child's sub-tree to match
417
- * remaining segments.
418
- */
419
- function findInterceptingMatch(
420
- slotNode: ManifestSegmentNode,
421
- targetPathname: string
422
- ): SlotMatchResult | null {
423
- const targetParts = targetPathname === '/' ? [] : targetPathname.slice(1).split('/');
424
-
425
- for (const child of slotNode.children) {
426
- if (child.segmentType !== 'intercepting' || !child.interceptedSegmentName) continue;
427
-
428
- const segName = child.interceptedSegmentName;
429
-
430
- // Find where the intercepted segment name appears in the target parts.
431
- // Search from the end since intercepted routes match the URL tail.
432
- let matchIdx = -1;
433
- for (let i = targetParts.length - 1; i >= 0; i--) {
434
- if (targetParts[i] === segName) {
435
- matchIdx = i;
436
- break;
437
- }
438
- }
439
- if (matchIdx < 0) continue;
440
-
441
- // Match remaining target parts against the intercepting child's sub-tree.
442
- const remaining = targetParts.slice(matchIdx + 1);
443
- const result = matchUrlParts(child, remaining);
444
- if (result) {
445
- const leaf = result.chain[result.chain.length - 1];
446
- if (leaf.page) {
447
- return {
448
- page: leaf.page,
449
- // Prepend slotNode — matchUrlParts starts from child, not slot root
450
- chain: [slotNode, ...result.chain],
451
- slotParams: result.params,
452
- };
453
- }
454
- }
455
- }
456
-
457
- return null;
458
- }
459
-
460
499
  // ─── Slot Access Evaluation ─────────────────────────────────────────────────
461
500
 
462
501
  /** Result of eagerly evaluating one segment's access.ts. */
@@ -483,7 +522,8 @@ export interface SlotAccessVerdict {
483
522
  */
484
523
  async function evaluateSlotAccessChain(
485
524
  slotRoot: ManifestSegmentNode,
486
- chain: ManifestSegmentNode[]
525
+ chain: ManifestSegmentNode[],
526
+ scope?: SlotParamScope
487
527
  ): Promise<SlotAccessVerdict[]> {
488
528
  // Collect all nodes with access.ts: slot root + intermediate chain segments
489
529
  const nodesWithAccess: ManifestSegmentNode[] = [];
@@ -502,7 +542,7 @@ async function evaluateSlotAccessChain(
502
542
  continue;
503
543
  }
504
544
  try {
505
- await accessFn();
545
+ await (scope ? scope(() => accessFn()) : accessFn());
506
546
  results.push({ node, verdict: 'pass' });
507
547
  } catch (e) {
508
548
  if (e instanceof DenySignal) {
@@ -541,6 +581,68 @@ export interface SlotSkipEntry {
541
581
  skipped?: boolean;
542
582
  }
543
583
 
584
+ /**
585
+ * The destination URL parts a segment's slots match against.
586
+ *
587
+ * A slot walks its own sub-tree starting where its owning segment stopped
588
+ * consuming the URL, so the parts are sliced at the length its ancestors
589
+ * consumed. Shared by `resolveSlotProps` and `publishSlotSegmentParams` — both
590
+ * have to slice identically or the two would disagree about which page a slot
591
+ * matched, and only one of them would be right.
592
+ *
593
+ * @internal
594
+ */
595
+ export function slotUrlParts(
596
+ segment: ManifestSegmentNode,
597
+ match: RouteMatch,
598
+ url: string
599
+ ): string[] {
600
+ const pathname = new URL(url, 'http://localhost').pathname;
601
+ // Slice through the owning segment inclusive, to match findSlotMatch, which
602
+ // walks the chain from parentIndex + 1. `consumedUrlParts` drops the root
603
+ // (it consumes no URL part) and honors the interception anchor, so a slot on
604
+ // a retained owner above a climbing marker is not handed parts the target
605
+ // does not contain.
606
+ const sliceAt = consumedPartsThroughSegment(segment, match).length;
607
+ const all = pathname === '/' ? [] : pathname.slice(1).split('/');
608
+ return all.slice(sliceAt);
609
+ }
610
+
611
+ /**
612
+ * Seed per-slot segment params for a segment whose layout is being SKIPPED.
613
+ *
614
+ * `resolveSlotProps` seeds these as part of resolving slot props, but a skipped
615
+ * layout never gets there — `route-element-builder` continues past it. Its
616
+ * slots are still mounted on the client, though, so leaving them out of the
617
+ * published map made `useSegmentParams(slotPath)` fall back to the main route's
618
+ * record after any navigation that skipped their parent (TIM-1285).
619
+ *
620
+ * Only the params are seeded. Nothing renders, no access chain runs — a skipped
621
+ * layout's slots are unchanged by definition, which is what made it skippable.
622
+ *
623
+ * @internal
624
+ */
625
+ export function publishSlotSegmentParams(
626
+ segment: ManifestSegmentNode,
627
+ match: RouteMatch,
628
+ destinationUrl: string,
629
+ parentTreePath: string | undefined
630
+ ): void {
631
+ const slotEntries = Object.entries(segment.slots ?? {});
632
+ if (slotEntries.length === 0) return;
633
+ const destinationParts = slotUrlParts(segment, match, destinationUrl);
634
+
635
+ for (const [, slotNode] of slotEntries) {
636
+ const destMatch = matchUrlParts(slotNode as ManifestSegmentNode, destinationParts);
637
+ if (!destMatch) continue;
638
+ const coerced = coerceSlotParams(destMatch.chain, destMatch.params);
639
+ const fullSlotPath = computeSlotSegmentPath(destMatch.chain, parentTreePath);
640
+ if (fullSlotPath && Object.keys(coerced).length > 0) {
641
+ setSlotParams(fullSlotPath, coerced);
642
+ }
643
+ }
644
+ }
645
+
544
646
  interface ResolveSlotPropsArgs {
545
647
  segment: ManifestSegmentNode;
546
648
  segmentId: string;
@@ -591,16 +693,7 @@ export async function resolveSlotProps({
591
693
  const destinationPathname = destParsed.pathname;
592
694
  const departingPathname = depParsed?.pathname ?? null;
593
695
 
594
- // Compute URL parts for slot skip comparison.
595
- // Include the owning segment (segIdx + 1) to match findSlotMatch,
596
- // which slices at parentIndex + 1. Filter out the root segment
597
- // (segmentName === '') — it maps to '/' and doesn't consume a URL part.
598
- const segIdx = match.segments.indexOf(segment);
599
- const parentSegments =
600
- segIdx >= 0 ? match.segments.slice(0, segIdx + 1).filter((s) => s.segmentName !== '') : [];
601
- const rawParams = match.rawSegmentParams ?? match.segmentParams ?? {};
602
- const parentConsumedParts = extractUrlParts(parentSegments, rawParams);
603
- const sliceAt = parentConsumedParts.length;
696
+ const sliceAt = consumedPartsThroughSegment(segment, match).length;
604
697
 
605
698
  function splitPathname(pathname: string): string[] {
606
699
  return pathname === '/' ? [] : pathname.slice(1).split('/');
@@ -608,7 +701,7 @@ export async function resolveSlotProps({
608
701
 
609
702
  const destinationAll = splitPathname(destinationPathname);
610
703
  const departingAll = departingPathname ? splitPathname(departingPathname) : null;
611
- const destinationParts = destinationAll.slice(sliceAt);
704
+ const destinationParts = slotUrlParts(segment, match, destinationUrl);
612
705
  const departingParts = departingAll ? departingAll.slice(sliceAt) : null;
613
706
  const clientSlots = clientStateTree?.slots ?? null;
614
707
 
@@ -633,15 +726,18 @@ export async function resolveSlotProps({
633
726
  // files calling getSegmentParams() see the slot's own coerced params,
634
727
  // not the main route's. This is the same seeding that resolveSlotElement
635
728
  // does, but we need it here for the eager path.
636
- if (destMatch && parentTreePath && Object.keys(destMatch.params).length > 0) {
637
- const slotSuffix = destMatch.chain
638
- .map((s) => s.segmentName)
639
- .filter(Boolean)
640
- .join('/');
641
- const prefix = parentTreePath === '/' ? '' : parentTreePath;
642
- const fullSlotPath = `${prefix}/${slotSuffix}`;
729
+ let eagerScope: SlotParamScope | undefined;
730
+ if (destMatch) {
643
731
  const coerced = coerceSlotParams(destMatch.chain, destMatch.params);
644
- setSlotParams(fullSlotPath, coerced);
732
+ const fullSlotPath = computeSlotSegmentPath(destMatch.chain, parentTreePath);
733
+ if (fullSlotPath && Object.keys(coerced).length > 0) {
734
+ setSlotParams(fullSlotPath, coerced);
735
+ }
736
+ // The eager path calls access.ts outside the React tree, so the render
737
+ // scope in resolveSlotElement cannot cover it. Without this, the same
738
+ // access.ts would read the main route's params when the slot is a skip
739
+ // candidate and the slot's own params when it is not.
740
+ eagerScope = (fn) => runWithSlotSegmentParams(fullSlotPath, coerced, fn);
645
741
  }
646
742
 
647
743
  // Check non-access skip conditions first. If any of these fail,
@@ -674,7 +770,7 @@ export async function resolveSlotProps({
674
770
  // "No access check for default.tsx" (destMatch null = unmatched slot).
675
771
  const chainVerdicts =
676
772
  isSkipCandidate && destMatch
677
- ? await evaluateSlotAccessChain(slotManifest, destMatch.chain)
773
+ ? await evaluateSlotAccessChain(slotManifest, destMatch.chain, eagerScope)
678
774
  : [];
679
775
  const accessBlocked = chainVerdicts.some((v) => v.verdict !== 'pass');
680
776
  const canSkip = isSkipCandidate && !accessBlocked;
@@ -713,7 +809,16 @@ export async function resolveSlotProps({
713
809
  let slotRequestDep = false;
714
810
  const destLeaf = destMatch?.chain[destMatch.chain.length - 1];
715
811
  const hasRenderedPage = destMatch && destLeaf?.page;
716
- if (hasRenderedPage) {
812
+ if (interception) {
813
+ // `destMatch` walks the slot's ordinary children against the
814
+ // destination URL; the interception resolver renders an intercepting
815
+ // child instead, which that walk never sees. So the files analyzed
816
+ // below are not the files that rendered — and `false` here tells the
817
+ // client the slot is reusable. Stay conservative: a needlessly
818
+ // request-dependent slot is a wasted refetch, a wrongly static one is
819
+ // a stale modal.
820
+ slotRequestDep = true;
821
+ } else if (hasRenderedPage) {
717
822
  // Check slot root layout (rendered by wrapWithLayout)
718
823
  if (
719
824
  slotManifest.layout?.filePath &&
@@ -42,6 +42,12 @@ export interface NavContext {
42
42
  segmentParams: Record<string, string | string[]>;
43
43
  /** Search params from the URL */
44
44
  searchParams: Record<string, string>;
45
+ /**
46
+ * Per-slot segment params, keyed by slot tree path. Absent when the request
47
+ * rendered no slot with params of its own. Feeds `useSegmentParams(path)`
48
+ * during SSR and, via `__timber_slot_params`, after hydration (TIM-1285).
49
+ */
50
+ slotParams?: Record<string, Record<string, string | string[]>>;
45
51
  /** The committed HTTP status code */
46
52
  statusCode: number;
47
53
  /** Response headers from middleware/proxy */
@@ -64,6 +70,18 @@ export interface NavContext {
64
70
  /** Request cookies as name→value pairs. Used by useCookie() during SSR
65
71
  * to return correct cookie values before hydration. */
66
72
  cookies?: Map<string, string>;
73
+ /**
74
+ * Lazy thunk that produces the `<script>self.__timber_segments=…</script>`
75
+ * tag. Invoked by the SSR entry AFTER `renderSsrNodeStream` /
76
+ * `renderSsrStream` returns (shell ready ⇒ AccessGates settled), so the
77
+ * `getFirstDeniedSegmentIndex()` ALS value is authoritative. The result
78
+ * is appended to headHtml before the head injector runs.
79
+ *
80
+ * Undefined when client JS is disabled (no client to consume it).
81
+ * See TIM-1365, TIM-1359.
82
+ */
83
+ getHeadSegmentScript?: () => string;
84
+
67
85
  /**
68
86
  * Mutable flag: set by TimberErrorBoundary during SSR when it catches
69
87
  * a DenySignal (via digest). This tells the RSC entry that the denial