@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
@@ -6,20 +6,25 @@
6
6
  * 2. No RSC payload: deferred root creation via installDeferredNavigation
7
7
  *
8
8
  * Pre-hydration ordering contract (MUST execute in this order):
9
- * 1. initRouter() — creates the global router so useRouter()
10
- * works during render
11
- * 2. setCurrentParams() — populates params snapshot so
12
- * + setNavigationState() useSegmentParams() and usePathname()
13
- * return correct values during hydration
14
- * 3. hydrateRoot() — synchronously executes component render
15
- * functions that depend on steps 1-2
9
+ * 1. initRouter() — creates the global router so useRouter()
10
+ * works during render
11
+ * 2. setNavigationState() — populates pathname/search so usePathname()
12
+ * returns correct values during hydration
13
+ * 3. hydrateRoot() — synchronously executes component render
14
+ * functions that depend on steps 1-2
15
+ *
16
+ * Params are not part of this sequence. They arrive on the payload root and
17
+ * are published by `PayloadRoot` at the top of the tree, so
18
+ * `useSegmentParams()` is correct during hydration without anything having to
19
+ * run before it (TIM-1294, TIM-1297).
16
20
  *
17
21
  * See design/19-client-navigation.md §"NavigationContext"
18
22
  */
19
23
 
20
24
  import { createElement } from 'react';
21
25
  import { hydrateRoot, createRoot } from 'react-dom/client';
22
- import { getRouterOrNull, setCurrentParams } from '#client-internal';
26
+ import { getRouterOrNull } from '#client-internal';
27
+ import { PayloadRoot } from '../params-context.js';
23
28
  import {
24
29
  NavigationProvider,
25
30
  getNavigationState,
@@ -79,26 +84,21 @@ interface HydrateOptions {
79
84
  }
80
85
 
81
86
  /**
82
- * Run the pre-hydration sequence: read server-embedded params and
83
- * set navigation state. Must be called AFTER initRouter().
87
+ * Run the pre-hydration sequence: set navigation state from the address bar.
88
+ * Must be called AFTER initRouter().
89
+ *
90
+ * Params are no longer seeded here. They used to arrive on two inline scripts
91
+ * that had to execute before `hydrateRoot()`, because hydration synchronously
92
+ * renders components that read them. They now ride the payload root, and the
93
+ * provider that publishes them renders before its own descendants — so the
94
+ * ordering the step existed to guarantee is now a property of the tree rather
95
+ * than of the bootstrap sequence (TIM-1294, TIM-1297).
84
96
  */
85
97
  export function runPreHydration(): void {
86
- const earlyParams = (self as unknown as Record<string, unknown>).__timber_params;
87
- if (earlyParams && typeof earlyParams === 'object') {
88
- setCurrentParams(earlyParams as Record<string, string | string[]>);
89
- setNavigationState({
90
- params: earlyParams as Record<string, string | string[]>,
91
- pathname: window.location.pathname,
92
- search: window.location.search,
93
- });
94
- delete (self as unknown as Record<string, unknown>).__timber_params;
95
- } else {
96
- setNavigationState({
97
- params: {},
98
- pathname: window.location.pathname,
99
- search: window.location.search,
100
- });
101
- }
98
+ setNavigationState({
99
+ pathname: window.location.pathname,
100
+ search: window.location.search,
101
+ });
102
102
  }
103
103
 
104
104
  /**
@@ -123,11 +123,22 @@ export function hydrateApp({ rscResult, config }: HydrateOptions): void {
123
123
  // startTransition, so React keeps old UI visible while new Suspense
124
124
  // boundaries resolve during navigation. See design/05-streaming.md.
125
125
  const navState = getNavigationState();
126
- const withNav = createElement(
127
- NavigationProvider,
128
- { value: navState },
126
+ // The same chain `renderTree()` in router-init.ts builds on every
127
+ // navigation, in the same order. It has to be: an element type that is
128
+ // present here and absent on the first navigation (or the reverse)
129
+ // changes the type at that position, and React remounts everything below
130
+ // it — losing the layout state partial navigation exists to preserve.
131
+ //
132
+ // `source` is the payload's params promise, not a resolved record: the
133
+ // inlined Flight stream is still arriving and hydration cannot wait for
134
+ // it. PayloadRoot suspends on it exactly where React was going to suspend
135
+ // on `element` (TIM-1297).
136
+ const withParams = createElement(
137
+ PayloadRoot,
138
+ { source: rscResult.params },
129
139
  element as React.ReactNode
130
140
  );
141
+ const withNav = createElement(NavigationProvider, { value: navState }, withParams);
131
142
  const withUpdates = createElement(
132
143
  SegmentUpdateContext.Provider,
133
144
  { value: EMPTY_SEGMENT_UPDATES },
@@ -28,11 +28,6 @@
28
28
 
29
29
  // @ts-expect-error — virtual module provided by timber-entries plugin
30
30
  import config from 'virtual:timber-config';
31
- // TIM-830: Populate the search-params registry eagerly so <Link> on the
32
- // client can serialize flat `Partial<T>` values synchronously during
33
- // render and click handlers. Side-effect-only import.
34
- // @ts-expect-error — virtual module provided by timber-routing plugin
35
- import 'virtual:timber-search-params-registry';
36
31
  // TIM-932: Populate the codec registry so Link's interpolateParams can
37
32
  // use codec.serialize() for URL construction. Side-effect-only import.
38
33
  // @ts-expect-error — virtual module provided by timber-routing plugin
@@ -40,11 +35,13 @@ import schemaCodecs from 'virtual:timber-schema';
40
35
  import { setLinkCodecs } from '../../params/codec-registry.js';
41
36
  setLinkCodecs(schemaCodecs);
42
37
 
43
- import { setClientDeploymentId, setStaticMode } from '../rsc-fetch.js';
38
+ import { setClientDeploymentId, setStaticMode, setBasePath } from '../rsc-fetch.js';
39
+ import { initStaleClient } from '../stale-client.js';
44
40
 
45
41
  import { setupServerActions } from './action-dispatch.js';
46
42
  import { createRscPayloadStream } from './rsc-stream.js';
47
43
  import { createTimberRouter } from './router-init.js';
44
+ import { readPublishedParams } from '../../shared/payload-root.js';
48
45
  import { runPreHydration, hydrateApp } from './hydrate.js';
49
46
  import { setupPostHydration } from './post-hydration.js';
50
47
  import { setupHmr } from './hmr.js';
@@ -63,6 +60,16 @@ function bootstrap(runtimeConfig: typeof config): void {
63
60
  setClientDeploymentId(deploymentId);
64
61
  }
65
62
 
63
+ // Reactive skew recovery for failures that never reach the router —
64
+ // lazily imported client components, preloaded stylesheets. No-ops when
65
+ // there is no deployment ID, i.e. in dev (TIM-1260).
66
+ initStaleClient(deploymentId);
67
+
68
+ // Deployment base path (Vite's resolved `base`). Must be set before any
69
+ // RSC fetch — under a non-root base the payloads live below the prefix
70
+ // like every other emitted file (TIM-1261).
71
+ setBasePath((runtimeConfig as Record<string, unknown>).base as string | undefined);
72
+
66
73
  // Static mode: fetch _rsc/*.rsc files instead of route URLs with
67
74
  // Accept headers. Static hosts ignore Accept headers (TIM-1243).
68
75
  if ((runtimeConfig as Record<string, unknown>).output === 'static') {
@@ -75,6 +82,7 @@ function bootstrap(runtimeConfig: typeof config): void {
75
82
  // Step 3: Create router + Navigation API integration
76
83
  const { router, navApiController } = createTimberRouter({
77
84
  initialElement: rscResult?.element ?? undefined,
85
+ initialParams: rscResult?.params,
78
86
  clientSegmentCache:
79
87
  ((runtimeConfig as Record<string, unknown>).clientSegmentCache as boolean) ?? false,
80
88
  });
@@ -90,6 +98,7 @@ function bootstrap(runtimeConfig: typeof config): void {
90
98
  router,
91
99
  navApiController,
92
100
  initialElement: rscResult?.element ?? null,
101
+ initialParams: rscResult?.params ?? readPublishedParams(undefined),
93
102
  });
94
103
 
95
104
  // Step 7: HMR (dev-only, no-op in production)
@@ -15,12 +15,15 @@ import type { RouterInstance } from '#client-internal';
15
15
  import { getNavigationState } from '../navigation-context.js';
16
16
  import type { NavigationApiController } from '../navigation-api.js';
17
17
  import { getScrollY } from './scroll.js';
18
+ import type { ParamsSource } from '../../shared/payload-root.js';
18
19
 
19
20
  interface PostHydrationOptions {
20
21
  router: RouterInstance;
21
22
  navApiController: NavigationApiController | null;
22
23
  /** Decoded RSC element from initial SSR (null if no RSC payload) */
23
24
  initialElement: unknown;
25
+ /** The params that payload published, from the same decode. */
26
+ initialParams: ParamsSource;
24
27
  }
25
28
 
26
29
  /**
@@ -30,20 +33,14 @@ export function setupPostHydration({
30
33
  router,
31
34
  navApiController,
32
35
  initialElement,
36
+ initialParams,
33
37
  }: PostHydrationOptions): void {
34
- // Store the initial page in the history stack so back-button works
35
- // after the first navigation. We store the decoded RSC element so
36
- // back navigation can replay it instantly without a server fetch.
37
- // Params were captured from the server-embedded __timber_params by
38
- // runPreHydration() — without them on the entry, the cached replay on
39
- // back-navigation would normalize params to {} and wipe every
40
- // useSegmentParams() consumer on the initial page (TIM-1037).
41
38
  // Populate the segment cache from server-embedded segment metadata.
42
39
  // This enables state tree diffing from the very first client navigation.
43
40
  // See design/19-client-navigation.md §"X-Timber-State-Tree Header"
44
41
  const timberSegments = (self as unknown as Record<string, unknown>).__timber_segments;
45
42
  const initialSegmentInfo = Array.isArray(timberSegments)
46
- ? (timberSegments as import('../segment-cache').SegmentInfo[])
43
+ ? (timberSegments as import('../../shared/segment-info.js').SegmentInfo[])
47
44
  : null;
48
45
  if (initialSegmentInfo) {
49
46
  router.initSegmentCache(initialSegmentInfo);
@@ -53,9 +50,13 @@ export function setupPostHydration({
53
50
  // Store the initial page in the history stack so back-button works
54
51
  // after the first navigation. Include segmentInfo so the segment
55
52
  // cache is restored correctly on popstate cached replay.
53
+ // Replaying this entry on a Back re-renders `initialElement` and republishes
54
+ // `initialParams`. Both came out of one split of one decoded payload root
55
+ // (rsc-stream.ts), so the entry cannot replay with another route's params —
56
+ // which is what a separately-seeded copy used to do (TIM-1037, TIM-1285).
56
57
  router.historyStack.push(window.location.pathname + window.location.search, {
57
58
  payload: initialElement,
58
- params: getNavigationState().params,
59
+ params: initialParams,
59
60
  segmentInfo: initialSegmentInfo,
60
61
  });
61
62
 
@@ -9,6 +9,8 @@
9
9
 
10
10
  import { createElement } from 'react';
11
11
  import { createFromFetch } from '../../rsc-runtime/browser.js';
12
+ import { PayloadRoot } from '../params-context.js';
13
+ import { readPublishedParams, type ParamsSource } from '../../shared/payload-root.js';
12
14
  import { createRouter, setGlobalRouter } from '#client-internal';
13
15
  import type { RouterDeps, RouterInstance } from '#client-internal';
14
16
  import type { NavigationState } from '#client-internal';
@@ -29,6 +31,8 @@ import { getScrollY, scrollToHashTarget } from './scroll.js';
29
31
 
30
32
  export interface RouterInitOptions {
31
33
  initialElement?: unknown;
34
+ /** The params the hydration payload published, beside `initialElement`. */
35
+ initialParams?: ParamsSource;
32
36
  clientSegmentCache?: boolean;
33
37
  }
34
38
 
@@ -58,6 +62,63 @@ export function createTimberRouter(options?: RouterInitOptions): RouterInitResul
58
62
  // very first client navigation (before any wrapPayload call).
59
63
  let currentPayload: unknown = options?.initialElement ?? null;
60
64
 
65
+ // The params `currentPayload` is displayed with. Tracked beside it because
66
+ // the two render paths that do NOT receive a payload — a shallow search
67
+ // update and any re-wrap of the current tree — must republish the same
68
+ // record rather than dropping it. They are written together, in one place
69
+ // (`renderTree`), so they cannot come apart.
70
+ let currentParams: ParamsSource = options?.initialParams ?? readPublishedParams(undefined);
71
+
72
+ /**
73
+ * Build the client's wrapper chain around a tree. **The only place it is
74
+ * built.**
75
+ *
76
+ * Every render path goes through here — hydration builds the same chain in
77
+ * `hydrate.ts` against this shape, and a navigation, a shallow search
78
+ * update, a popstate replay and a revalidation all call this. That matters
79
+ * beyond tidiness: an element type present on one render and absent on the
80
+ * next changes the type at that position, so React unmounts and remounts
81
+ * everything below it, destroying the layout state partial navigation
82
+ * exists to preserve (caught by tests/e2e/segment-merge-navigation.test.ts
83
+ * when the params wrapper was conditional).
84
+ *
85
+ * `PayloadRoot` is *above* `currentPayload`, which on a partial navigation
86
+ * is the retained tree. That position is the whole design: it is the only
87
+ * provider a reader in a skipped layout can resolve to (TIM-1297).
88
+ *
89
+ * Pure — building the element does not make it the displayed one. Every
90
+ * caller pairs this with `publishTree` at the point the tree is actually
91
+ * handed to React, because a navigation builds its element before it is
92
+ * known to have won and a superseded one must leave `currentPayload`
93
+ * describing the route still on screen (TIM-1301).
94
+ */
95
+ function renderTree(
96
+ tree: unknown,
97
+ navState: NavigationState,
98
+ params: ParamsSource,
99
+ segmentUpdates?: Map<string, React.ReactNode>
100
+ ): React.ReactElement {
101
+ const withParams = createElement(PayloadRoot, { source: params }, tree as React.ReactNode);
102
+ const withNav = createElement(NavigationProvider, { value: navState }, withParams);
103
+ const withUpdates = createElement(
104
+ SegmentUpdateContext.Provider,
105
+ { value: segmentUpdates ?? EMPTY_SEGMENT_UPDATES },
106
+ withNav
107
+ );
108
+ return createElement(TimberNuqsAdapter, null, withUpdates);
109
+ }
110
+
111
+ /**
112
+ * Record the tree the client is now displaying, and the params published
113
+ * over it. Written together — the two paths that re-wrap without a fresh
114
+ * payload (a shallow search update, a partial navigation) read them back as
115
+ * a pair and would otherwise restore one route's tree with another's params.
116
+ */
117
+ function publishTree(tree: unknown, params: ParamsSource): void {
118
+ currentPayload = tree;
119
+ currentParams = params;
120
+ }
121
+
61
122
  // ─── History API Patch ──────────────────────────────────────────
62
123
  // Patch pushState/replaceState to detect external URL changes (nuqs
63
124
  // shallow updates, replaceUrl, third-party libraries). When the router
@@ -93,25 +154,20 @@ export function createTimberRouter(options?: RouterInitOptions): RouterInitResul
93
154
  if (currentSearch === navState.search) return;
94
155
  if (!currentPayload) return;
95
156
 
157
+ // A shallow search update does not re-render the tree from the server, so
158
+ // the params are unchanged — but they are the client's to publish now, and
159
+ // this path rebuilds the whole chain. Republishing `currentParams` is what
160
+ // keeps a `?q=` change from silently clearing the route's params
161
+ // (TIM-1285's failure mode, on a path that used to be exempt from it
162
+ // because the record lived inside the payload).
96
163
  const newNavState: NavigationState = {
97
- params: navState.params,
98
164
  pathname: navState.pathname,
99
165
  search: currentSearch,
100
166
  };
101
167
  setNavigationState(newNavState);
102
168
 
103
- const withNav = createElement(
104
- NavigationProvider,
105
- { value: newNavState },
106
- currentPayload as React.ReactNode
107
- );
108
- const withUpdates = createElement(
109
- SegmentUpdateContext.Provider,
110
- { value: EMPTY_SEGMENT_UPDATES },
111
- withNav
112
- );
113
- const wrapped = createElement(TimberNuqsAdapter, null, withUpdates);
114
- transitionRender(wrapped);
169
+ publishTree(currentPayload, currentParams);
170
+ transitionRender(renderTree(currentPayload, newNavState, currentParams));
115
171
  }
116
172
 
117
173
  window.history.pushState = function (
@@ -179,58 +235,58 @@ export function createTimberRouter(options?: RouterInitOptions): RouterInitResul
179
235
  // Wraps with NavigationProvider + TimberNuqsAdapter.
180
236
  //
181
237
  // For navigation renders (navigate, refresh, popstate-with-fetch),
182
- // navigateTransition is used instead — it wraps the entire navigation
183
- // in a React transition with useOptimistic for the pending URL.
238
+ // navigateTransition is used instead — it hands the destination tree to
239
+ // React in a transition so the departing page stays visible.
184
240
  //
185
241
  // navState is passed explicitly by the router — no temporal coupling
186
242
  // with getNavigationState().
187
- renderRoot: (element: unknown, navState: NavigationState) => {
188
- currentPayload = element;
189
- const withNav = createElement(
190
- NavigationProvider,
191
- { value: navState },
192
- element as React.ReactNode
193
- );
194
- const withUpdates = createElement(
195
- SegmentUpdateContext.Provider,
196
- { value: EMPTY_SEGMENT_UPDATES },
197
- withNav
198
- );
199
- const wrapped = createElement(TimberNuqsAdapter, null, withUpdates);
200
- transitionRender(wrapped);
243
+ renderRoot: (element: unknown, navState: NavigationState, params: ParamsSource) => {
244
+ // These paths render what is already decided (a replay, a
245
+ // revalidation), so publishing here is the commit.
246
+ publishTree(element, params);
247
+ transitionRender(renderTree(element, navState, params));
201
248
  },
202
249
 
203
- // Run a navigation inside a React transition with optimistic pending URL.
204
- // The entire fetch + state update runs inside startTransition. useOptimistic
205
- // shows the pending URL immediately and reverts to null when the transition
206
- // commits (atomic with the new tree + params).
250
+ // Hand a navigation's tree to React in a transition (navigation-root.tsx).
251
+ // The fetch runs outside any transition scope; only the state update that
252
+ // hands the tree over is wrapped, and in a synchronous `startTransition`.
253
+ // Do NOT make this callback's caller an async React action — see the
254
+ // entanglement note in `navigateTransition` (TIM-1306, TIM-1307).
207
255
  //
208
256
  // The perform callback receives a wrapPayload function that wraps the
209
257
  // decoded RSC payload with NavigationProvider + NuqsAdapter. navState
210
258
  // is passed explicitly by the router — no getNavigationState() needed.
211
- navigateTransition: (pendingUrl: string, perform) => {
212
- return navigateTransition(pendingUrl, async () => {
213
- const { element, decodePromise } = await perform(
259
+ navigateTransition: (url: string, perform) => {
260
+ return navigateTransition(url, async () => {
261
+ // What wrapPayload built, held until the transition wins. The client's
262
+ // record of the displayed tree is navigation state like any other, so
263
+ // it rides the same commit as the segment cache rather than being
264
+ // written as a side effect of building the element (TIM-1301).
265
+ let displayed: { tree: unknown; params: ParamsSource } | null = null;
266
+ const { element, decodePromise, commit } = await perform(
214
267
  (
215
268
  rawPayload: unknown,
216
269
  navState: NavigationState,
270
+ params: ParamsSource,
217
271
  segmentUpdates?: Map<string, unknown>
218
272
  ) => {
219
- currentPayload = rawPayload;
220
- const withNav = createElement(
221
- NavigationProvider,
222
- { value: navState },
223
- rawPayload as React.ReactNode
224
- );
225
- const withUpdates = createElement(
226
- SegmentUpdateContext.Provider,
227
- { value: (segmentUpdates ?? EMPTY_SEGMENT_UPDATES) as Map<string, React.ReactNode> },
228
- withNav
273
+ displayed = { tree: rawPayload, params };
274
+ return renderTree(
275
+ rawPayload,
276
+ navState,
277
+ params,
278
+ segmentUpdates as Map<string, React.ReactNode> | undefined
229
279
  );
230
- return createElement(TimberNuqsAdapter, null, withUpdates);
231
280
  }
232
281
  );
233
- return { element: element as React.ReactNode, decodePromise };
282
+ return {
283
+ element: element as React.ReactNode,
284
+ decodePromise,
285
+ commit: () => {
286
+ if (displayed) publishTree(displayed.tree, displayed.params);
287
+ commit();
288
+ },
289
+ };
234
290
  });
235
291
  },
236
292
 
@@ -13,12 +13,20 @@
13
13
 
14
14
  import { createFromReadableStream } from '../../rsc-runtime/browser.js';
15
15
  import { isPageUnloading } from '../unload-guard.js';
16
+ import { splitPayloadRoot, type PublishedParams } from '../../shared/payload-root.js';
16
17
 
17
18
  type FlightSegment = [isBootstrap: 0] | [isData: 1, data: string];
18
19
 
19
20
  export interface RscStreamResult {
20
21
  /** The decoded RSC element (thenable/lazy — resolved by React during render) */
21
22
  element: unknown;
23
+ /**
24
+ * The params the same payload published beside that tree. A promise: the
25
+ * inlined Flight stream is still arriving when this runs, and hydration must
26
+ * not wait for it. `PayloadRoot` suspends on it at the position React was
27
+ * going to suspend on `element` anyway (TIM-1297).
28
+ */
29
+ params: Promise<PublishedParams>;
22
30
  }
23
31
 
24
32
  /**
@@ -152,6 +160,7 @@ export function createRscPayloadStream(): RscStreamResult | null {
152
160
  queueMicrotask(onDOMContentLoaded);
153
161
  }
154
162
 
155
- const element = createFromReadableStream(rscPayload);
156
- return { element };
163
+ const { tree, params } = splitPayloadRoot(createFromReadableStream(rscPayload));
164
+ // The stream is a thenable, so the split is asynchronous on both halves.
165
+ return { element: tree, params: params as Promise<PublishedParams> };
157
166
  }
@@ -21,20 +21,12 @@
21
21
  import { Component, createElement, type ReactNode } from 'react';
22
22
  import { getSsrData } from './ssr-data.js';
23
23
  import { getRouterOrNull } from './router-ref.js';
24
-
25
- // ─── Page Unload Detection ───────────────────────────────────────────────────
26
- // Track whether the page is being unloaded (user refreshed or navigated away).
27
- // When this is true, error boundaries suppress activation — the error is from
28
- // the aborted connection, not an application error.
29
- let _isUnloading = false;
30
- if (typeof window !== 'undefined') {
31
- window.addEventListener('beforeunload', () => {
32
- _isUnloading = true;
33
- });
34
- window.addEventListener('pagehide', () => {
35
- _isUnloading = true;
36
- });
37
- }
24
+ import { markStaleFromError } from './stale-client.js';
25
+ // Page unload detection: when the page is being torn down, error boundaries
26
+ // suppress activation — the error is from the aborted connection, not the
27
+ // application. unload-guard.ts is the single owner of that state; this module
28
+ // used to keep its own copy, which drifted (TIM-1260).
29
+ import { isPageUnloading } from './unload-guard.js';
38
30
 
39
31
  // ─── Digest Types ────────────────────────────────────────────────────────────
40
32
 
@@ -43,6 +35,12 @@ interface DenyDigest {
43
35
  type: 'deny';
44
36
  status: number;
45
37
  data: unknown;
38
+ /**
39
+ * Segment key of the segment that owns the matched deny page, present when
40
+ * an in-tree catch site matched a file it may not render at its own
41
+ * position and re-threw to reach the owner. See TIM-1356.
42
+ */
43
+ ownerKey?: string;
46
44
  }
47
45
 
48
46
  /** Structured digest returned by RSC onError for RenderError. */
@@ -86,6 +84,12 @@ export interface TimberErrorBoundaryProps {
86
84
  * graceful degradation — they must NOT change the HTTP status code.
87
85
  */
88
86
  isSlotBoundary?: boolean;
87
+ /**
88
+ * Segment key of the segment that declared this boundary. Only meaningful
89
+ * against a deny digest carrying an `ownerKey`. See the decline rule in
90
+ * `render()` and TIM-1356.
91
+ */
92
+ segmentKey?: string;
89
93
  children: ReactNode;
90
94
  }
91
95
 
@@ -124,13 +128,26 @@ export class TimberErrorBoundary extends Component<
124
128
  // The aborted connection causes React's streaming hydration to error,
125
129
  // but the page is about to be replaced — showing an error boundary
126
130
  // would be a jarring flash for the user.
127
- if (_isUnloading) {
131
+ if (isPageUnloading()) {
128
132
  return { hasError: false, error: null };
129
133
  }
130
134
 
131
135
  return { hasError: true, error };
132
136
  }
133
137
 
138
+ componentDidCatch(error: Error): void {
139
+ // A stale bundle most often surfaces here rather than as a rejected
140
+ // navigation: a client reference missing from this build's manifest, or
141
+ // a lazily-imported chunk the CDN no longer has, thrown during render.
142
+ //
143
+ // Recording it is all that happens — this boundary still renders its
144
+ // fallback, and the recovery is the user's next navigation, which the
145
+ // router turns into a full document load. Reloading from here would be a
146
+ // page load the user did not ask for, on a page that may be mid-rollout
147
+ // and would come back just as stale (TIM-1275).
148
+ markStaleFromError(error);
149
+ }
150
+
134
151
  componentDidUpdate(prevProps: TimberErrorBoundaryProps): void {
135
152
  // Reset error state when children change (e.g. client-side navigation).
136
153
  // Without this, navigating from one error page to another keeps the
@@ -204,6 +221,34 @@ export class TimberErrorBoundary extends Component<
204
221
  return null;
205
222
  }
206
223
 
224
+ // Owner-addressed denies: an in-tree catch site already resolved the
225
+ // fallback chain and matched a file it may not render at its own
226
+ // position, so it re-threw to reach the segment that owns that file.
227
+ // Every boundary but that one declines — otherwise the nearest boundary
228
+ // whose status filter happens to match catches first and renders the
229
+ // deny page at its own depth, wrapped in the layouts the hoist existed
230
+ // to skip, and from a different file than the chain chose. (Boundary
231
+ // nesting is per-segment `{status} → category → error`; the 4xx chain
232
+ // runs status files across ALL segments before any error.tsx, so a
233
+ // leaf error.tsx would otherwise beat a root 404.tsx.)
234
+ //
235
+ // Declining is the default: an unkeyed boundary — a slot boundary, or
236
+ // one from a construction site that builds no deny chains — never
237
+ // claims a deny addressed to a segment. See TIM-1356.
238
+ // `typeof === 'string'`, not a null check: the digest is untrusted JSON —
239
+ // `parseDigest` validates only `type`, and any component can set
240
+ // `error.digest` itself. A non-string `ownerKey` is unequal to every
241
+ // boundary's key, so a truthiness test would let one error decline its
242
+ // way past the entire tree and blank the page, where it would otherwise
243
+ // have hit the nearest matching boundary.
244
+ if (
245
+ parsed?.type === 'deny' &&
246
+ typeof parsed.ownerKey === 'string' &&
247
+ parsed.ownerKey !== this.props.segmentKey
248
+ ) {
249
+ throw error;
250
+ }
251
+
207
252
  // If this boundary has a status filter, check whether the error matches.
208
253
  // Non-matching errors re-throw so an outer boundary can catch them.
209
254
  if (this.props.status != null) {
@@ -267,7 +312,7 @@ export class TimberErrorBoundary extends Component<
267
312
  });
268
313
  }
269
314
  return createElement(this.props.fallbackComponent as never, {
270
- error,
315
+ error: denyError(parsed.status, error),
271
316
  digest: null,
272
317
  reset: this.reset,
273
318
  status: parsed.status,
@@ -307,6 +352,30 @@ function parseDigest(error: Error): ParsedDigest | null {
307
352
  return null;
308
353
  }
309
354
 
355
+ /**
356
+ * The Error an `error.tsx` serving a deny should receive.
357
+ *
358
+ * The error that actually arrives here is React's, not the framework's: a
359
+ * server-thrown error crossing Flight has its message and name replaced with
360
+ * a generic redacted string in production, by design. An `error.tsx` written
361
+ * per the docs branches on `error.message` — so handing it the redacted error
362
+ * gives it nothing to branch on, while the in-tree path hands the same file a
363
+ * `DenySignal` named error reading `Access denied with status <N>` (see
364
+ * `renderDenyEntry`). This reconstructs that shape from the digest, which is
365
+ * where the status already is.
366
+ *
367
+ * Derived from the status alone — no stack, no server data — so it is safe on
368
+ * the client for the same reason the digest is. See design/13-security.md
369
+ * §"Errors don't leak", TIM-1081.
370
+ */
371
+ function denyError(status: number, original: Error): Error {
372
+ // A dev build may have preserved something more useful than the redaction.
373
+ if (original.name === 'DenySignal') return original;
374
+ const error = new Error(`Access denied with status ${status}`);
375
+ error.name = 'DenySignal';
376
+ return error;
377
+ }
378
+
310
379
  /**
311
380
  * Extract the HTTP status code from a parsed digest or error message.
312
381
  * Falls back to message pattern matching for errors without a digest.
@@ -1,7 +1,8 @@
1
1
  // History Stack — stores RSC payloads by URL for instant back/forward navigation
2
2
  // See design/19-client-navigation.md § History Stack
3
3
 
4
- import type { SegmentInfo } from './segment-cache';
4
+ import type { ParamsSource } from '../shared/payload-root.js';
5
+ import type { SegmentInfo } from '../shared/segment-info.js';
5
6
 
6
7
  // ─── Types ───────────────────────────────────────────────────────
7
8
 
@@ -9,12 +10,18 @@ export interface HistoryEntry {
9
10
  /** The complete segment tree payload at the time of navigation */
10
11
  payload: unknown;
11
12
  /**
12
- * Route params for this page (for useSegmentParams). Every entry that can
13
- * be replayed must carry them — the initial SSR entry gets them from the
14
- * server-embedded __timber_params, navigation entries from X-Timber-Params,
15
- * and revalidation overwrites preserve the current state (TIM-1037).
13
+ * The params that payload published. Replaying the tree republishes them,
14
+ * because the client owns the provider now and reads it from here
15
+ * (TIM-1297).
16
+ *
17
+ * Stored beside the tree but never *produced* beside it: both come out of
18
+ * one `splitPayloadRoot` on one decoded root and travel together through
19
+ * `prepareNavigation`, the only producer of an entry. That is the property
20
+ * that matters — when they were derived from separate channels, a replay
21
+ * could restore one route's tree with another route's params (TIM-1037,
22
+ * TIM-1285).
16
23
  */
17
- params?: Record<string, string | string[]> | null;
24
+ params: ParamsSource;
18
25
  /**
19
26
  * Segment metadata for this page's route. Restored into the segment cache
20
27
  * on popstate cached replay so the next forward navigation computes a