@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
@@ -75,11 +75,22 @@ export { useSelectedLayoutSegment, useSelectedLayoutSegments } from './use-selec
75
75
  export { useActionState, useFormAction } from './form';
76
76
  export type { UseActionStateFn, UseActionStateReturn, FormErrorsResult } from './form';
77
77
 
78
- // Params — raw hook for untyped access. For typed params, use defineSegmentParams().useSegmentParams().
78
+ // Params. Called with no argument this returns the untyped accumulated params;
79
+ // pass the route's SEGMENT_PATH (from its generated `./$segment` module) to get
80
+ // the exact types `app/schema.ts` declares — `useSegmentParams(SEGMENT_PATH)`.
79
81
  export { useSegmentParams } from './use-segment-params';
80
82
 
81
- // Query states — useQueryStates lives on defineSearchParams().useQueryStates()
82
- // and is available via direct import for advanced cases.
83
+ // Query states. `definition.useQueryStates()` is the usual form; this standalone
84
+ // export is the inline codec-map form, for shared param bundles reused across
85
+ // routes (design/23-search-params.md §"Client Access").
86
+ //
87
+ // Until TIM-1341 this export did not exist, yet four doc sites told users to
88
+ // import it from here. It type-checked only because the generated `.d.ts`
89
+ // augmented this module with a `useQueryStates` overload — so TypeScript
90
+ // believed in a binding that was never emitted, and the documented import
91
+ // failed at build time. Deleting that overload removed the lie; exporting the
92
+ // hook makes the docs true.
93
+ export { useQueryStates } from './use-query-states';
83
94
 
84
95
  // Cookies — useCookie lives on defineCookie().useCookie().
85
96
  // Types still exported for advanced use.
@@ -19,7 +19,7 @@ export type {
19
19
  RouterPhase,
20
20
  RscDecoder,
21
21
  RootRenderer,
22
- } from './router.js';
22
+ } from './router-types.js';
23
23
  export { getRouter, getRouterOrNull, setGlobalRouter } from './router-ref.js';
24
24
 
25
25
  // ── SSR bridge ───────────────────────────────────────────────────────────
@@ -32,14 +32,15 @@ export type { SegmentContextValue } from './segment-context.js';
32
32
 
33
33
  // ── Segment cache ────────────────────────────────────────────────────────
34
34
  export { SegmentCache, PrefetchCache } from './segment-cache.js';
35
- export type { SegmentNode, StateTree } from './segment-cache.js';
35
+ export type { SegmentNode, PrefetchKey } from './segment-cache.js';
36
+ export type { SegmentInfo, StateTree } from '../shared/segment-info.js';
36
37
 
37
38
  // ── History ──────────────────────────────────────────────────────────────
38
39
  export { HistoryStack } from './history.js';
39
40
  export type { HistoryEntry } from './history.js';
40
41
 
41
42
  // ── Params (internal setter + raw hooks) ─────────────────────────────────
42
- export { setCurrentParams } from './use-segment-params.js';
43
+ export { setCurrentParams, setCurrentSlotParams } from './use-segment-params.js';
43
44
  export { useSearchParams } from './use-search-params.js';
44
45
 
45
46
  // ── Navigation context ───────────────────────────────────────────────────
@@ -14,18 +14,18 @@
14
14
  // Typed Link: design/09-typescript.md §"Typed Link"
15
15
  // - href validated against known routes (via codegen overloads, not runtime)
16
16
  // - params prop typed per-route, URL interpolated at runtime
17
- // - searchParams prop serialized via SearchParamsDefinition
17
+ // - searchParams prop is a query string (from `definition.buildSearchParams()`)
18
+ // or a plain object whose values are String()-coerced
18
19
  // - params and fully-resolved string href are mutually exclusive
19
20
  // - searchParams and inline query string are mutually exclusive
20
21
 
21
22
  import {
22
- useTransition,
23
+ useRef,
24
+ useState,
23
25
  type AnchorHTMLAttributes,
24
26
  type ReactNode,
25
27
  type MouseEvent as ReactMouseEvent,
26
28
  } from 'react';
27
- import type { SearchParamsDefinition } from '../search-params/define.js';
28
- import { getSearchParamsDefinition } from '../search-params/registry.js';
29
29
  import type { LinkFunction } from './index.js';
30
30
  import { classifyUrlSegment, type UrlSegment } from '../routing/segment-classify.js';
31
31
  import {
@@ -130,26 +130,37 @@ export type LinkSegmentParams<T> = {
130
130
 
131
131
  // ─── searchParams prop shapes ────────────────────────────────────
132
132
  //
133
- // Per-route Link overloads (emitted by codegen) pass the flat values shape:
134
- // searchParams={{ page: 2, q: 'boots' }}
135
- // The framework looks up the route's SearchParamsDefinition from the
136
- // search-params registry at runtime (see TIM-830).
133
+ // Two shapes, discriminated at runtime by `typeof === 'string'`:
137
134
  //
138
- // The catch-all overload in client/index.ts (external/computed hrefs)
139
- // additionally accepts the legacy wrapped shape:
140
- // searchParams={{ definition: def, values: { page: 2 } }}
141
- // because there is no way to look up a definition from a computed string.
135
+ // 1. Codec-aware (preferred) — a query string built from a definition:
136
+ // searchParams={productParams.buildSearchParams({ page: 2, search: 'boots' })}
137
+ // `buildSearchParams` applies each codec, honours `withUrlKey` aliases,
138
+ // and omits values equal to their default. It is typed `Partial<T>` at
139
+ // the call site, so the definition supplies the type checking.
142
140
  //
143
- // `resolveHref` discriminates at runtime by presence of a `definition` key.
141
+ // 2. Plain object (escape hatch) — every value is String()-coerced:
142
+ // searchParams={{ ref: 'email' }}
143
+ // No codecs, no aliases. This is for one-off params that have no
144
+ // definition. Passing a *definition's* keys this way is a mistake the
145
+ // types cannot catch: `{ search: 'x' }` emits `?search=x`, where the
146
+ // definition would emit `?q=x`. Prefer (1) whenever a definition exists.
147
+ //
148
+ // Why a STRING and not a URLSearchParams: a Link is routinely rendered by a
149
+ // Server Component, so this prop crosses the RSC Flight boundary before the
150
+ // client Link runs. `URLSearchParams` is iterable, and React serializes any
151
+ // iterable as an array — so the prop arrived as `[['pg','2'], …]`, fell into
152
+ // the plain-object branch, and rendered `?0=pg&0=2`. Strings survive Flight
153
+ // unchanged. (Codex P1 on PR #1021; reproduced against a live dev server.)
154
+ //
155
+ // TIM-1343 removed the third shape — a flat values object resolved against a
156
+ // runtime registry keyed by href. It required scanning a `params.ts`
157
+ // convention file, a generated registry module, and eager imports of every
158
+ // route's definition into all three entries, to save one `.buildSearchParams`
159
+ // call. See design/23-search-params.md §"Link Integration".
144
160
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
145
161
  export type ParamValue = string | number | string[] | { toString(): string; [key: string]: any };
146
162
 
147
- type WrappedSearchParamsProp = {
148
- definition: SearchParamsDefinition<Record<string, unknown>>;
149
- values: Record<string, unknown>;
150
- };
151
- type FlatSearchParamsProp = Record<string, unknown>;
152
- type LinkSearchParamsProp = WrappedSearchParamsProp | FlatSearchParamsProp;
163
+ type LinkSearchParamsProp = string | Record<string, unknown>;
153
164
 
154
165
  /**
155
166
  * Runtime-only loose props used internally by the Link implementation.
@@ -302,16 +313,35 @@ export function interpolateParams(pattern: string, params: Record<string, ParamV
302
313
  *
303
314
  * Handles:
304
315
  * - params interpolation into route patterns
305
- * - searchParams serialization via SearchParamsDefinition
316
+ * - searchParams serialization (see the two shapes documented above)
306
317
  * - Validation that searchParams and inline query strings are exclusive
307
318
  */
308
319
  /**
309
- * Runtime discriminator: treat `searchParams` as the legacy wrapped shape
310
- * only when it literally has a `definition` key. Everything else is the
311
- * flat `Partial<T>` values shape (TIM-830).
320
+ * Tolerate a leading '?'. `buildSearchParams()` never emits one, but callers
321
+ * hand-rolling a query string reasonably might, and silently producing
322
+ * `?%3Fa=b` for it would be a worse failure than accepting both.
323
+ */
324
+ function stripLeadingQuestionMark(qs: string): string {
325
+ return qs.startsWith('?') ? qs.slice(1) : qs;
326
+ }
327
+
328
+ /**
329
+ * Escape-hatch serialization for a plain object: String()-coerce every
330
+ * value, append arrays as repeated keys, skip null/undefined.
331
+ *
332
+ * Deliberately codec-free and alias-free — see the shape docs above.
312
333
  */
313
- function isWrappedSearchParamsProp(sp: LinkSearchParamsProp): sp is WrappedSearchParamsProp {
314
- return 'definition' in sp;
334
+ function coerceToQueryString(values: Record<string, unknown>): string {
335
+ const usp = new URLSearchParams();
336
+ for (const [key, val] of Object.entries(values)) {
337
+ if (val === undefined || val === null) continue;
338
+ if (Array.isArray(val)) {
339
+ for (const item of val) usp.append(key, String(item));
340
+ } else {
341
+ usp.set(key, String(val));
342
+ }
343
+ }
344
+ return usp.toString();
315
345
  }
316
346
 
317
347
  export function resolveHref(
@@ -336,46 +366,18 @@ export function resolveHref(
336
366
  );
337
367
  }
338
368
 
339
- let definition: SearchParamsDefinition<Record<string, unknown>> | undefined;
340
- let values: Record<string, unknown>;
341
-
342
- if (isWrappedSearchParamsProp(searchParams)) {
343
- // Legacy wrapped shape — used by the catch-all overload for
344
- // computed/external hrefs where no route lookup is possible.
345
- definition = searchParams.definition;
346
- values = searchParams.values;
347
- } else {
348
- // Flat shape (TIM-830): look up the definition from the runtime
349
- // registry using the un-interpolated href pattern (e.g. '/products/[id]').
350
- // The search-params registry is populated eagerly at startup by the
351
- // virtual:timber-search-params-registry module generated by the
352
- // timber-routing Vite plugin.
353
- definition = getSearchParamsDefinition(href) as
354
- | SearchParamsDefinition<Record<string, unknown>>
355
- | undefined;
356
- values = searchParams;
357
- }
358
-
359
- if (definition) {
360
- const qs = definition.serialize(values);
361
- if (qs) {
362
- resolvedPath = `${resolvedPath}?${qs}`;
363
- }
364
- } else {
365
- // No registered definition — serialize flat object as plain query params.
366
- const usp = new URLSearchParams();
367
- for (const [key, val] of Object.entries(values)) {
368
- if (val === undefined || val === null) continue;
369
- if (Array.isArray(val)) {
370
- for (const item of val) usp.append(key, String(item));
371
- } else {
372
- usp.set(key, String(val));
373
- }
374
- }
375
- const qs = usp.toString();
376
- if (qs) {
377
- resolvedPath = `${resolvedPath}?${qs}`;
378
- }
369
+ // A string is already a serialized query (from
370
+ // `definition.buildSearchParams()`), so it passes through untouched.
371
+ // `typeof` is the only discriminator that survives the RSC Flight
372
+ // boundary — see the shape docs above for what happened when this was
373
+ // an object test.
374
+ const qs =
375
+ typeof searchParams === 'string'
376
+ ? stripLeadingQuestionMark(searchParams)
377
+ : coerceToQueryString(searchParams);
378
+
379
+ if (qs) {
380
+ resolvedPath = `${resolvedPath}?${qs}`;
379
381
  }
380
382
  }
381
383
 
@@ -472,11 +474,38 @@ export const Link: LinkFunction = function LinkImpl(props: any) {
472
474
  const { href: baseHref } = buildLinkProps({ href, params: segmentParams, searchParams });
473
475
 
474
476
  // ─── Per-link pending state ─────────────────────────────────────────
475
- // Each Link owns a useTransition. On click, it wraps
476
- // router.navigate() in startTransition — only this Link re-renders
477
- // for isPending, zero siblings touched. The transition tracks the
478
- // full navigation lifecycle (fetch + render + commit).
479
- const [isPending, startTransition] = useTransition();
477
+ // Local `useState`, deliberately NOT `useTransition` (TIM-1307).
478
+ //
479
+ // Either shape keeps the re-render local — the state lives on this Link's
480
+ // own fiber, so no sibling link is touched. The difference is what wrapping
481
+ // `router.navigate()` in a transition does to the REST of the app: returning
482
+ // a thenable from `startTransition` hands it to `ReactSharedInternals.S`,
483
+ // which calls react-dom's `entangleAsyncAction`. That opens an action scope
484
+ // whose `currentEntangledLane` collects every transition update scheduled
485
+ // while it is open — including `NavigationRoot`'s `setRendered`, which is a
486
+ // fully synchronous `startTransition` in a different component — and
487
+ // rendering that lane suspends on `currentEntangledActionThenable` until the
488
+ // action settles. `navigateTransition` awaits `decodePromise`, so a Link
489
+ // navigation used to commit only after the whole Flight stream had decoded,
490
+ // while `useRouter().push()` committed as soon as React could render it.
491
+ //
492
+ // Two commit-timing regimes, and the slower one was the dominant path: no
493
+ // streaming reveal, and the TIM-1301 publish (address bar, segment cache,
494
+ // `timber:navigation-end`) waited for full decode. Not opening an action
495
+ // scope is what collapses them into one.
496
+ //
497
+ // `isPending` runs from the click until `router.navigate()` settles, which
498
+ // is after `decodePromise` — the same lifecycle the router's pending store
499
+ // and the TopLoader use.
500
+ //
501
+ // `clickSeq` exists because a superseded navigation RESOLVES rather than
502
+ // rejecting: `runNavigation` swallows AbortErrors. So clicking the same link
503
+ // twice in quick succession settles the first promise while the second is
504
+ // still in flight, and an unguarded clear would report idle mid-navigation.
505
+ // Only the newest click for this link may clear its flag. Written on click
506
+ // and nowhere else, so there is no reset for a settle handler to race.
507
+ const [isPending, setIsPending] = useState(false);
508
+ const clickSeq = useRef(0);
480
509
  const linkStatus = isPending ? LINK_PENDING : LINK_IDLE;
481
510
 
482
511
  // Preserve search params from the current URL when requested.
@@ -544,8 +573,27 @@ export const Link: LinkFunction = function LinkImpl(props: any) {
544
573
  // from the RSC fetch URL inside the router (TIM-1035).
545
574
  const absoluteHref = resolved.pathname + resolved.search + resolved.hash;
546
575
 
547
- startTransition(async () => {
548
- await router.navigate(absoluteHref, { scroll: shouldScroll });
576
+ const seq = ++clickSeq.current;
577
+ const settle = () => {
578
+ if (clickSeq.current === seq) setIsPending(false);
579
+ };
580
+ setIsPending(true);
581
+ router.navigate(absoluteHref, { scroll: shouldScroll }).then(settle, (error: unknown) => {
582
+ settle();
583
+ // Rethrow, so a navigation error that the router did not already
584
+ // recover from surfaces as an unhandled rejection — the same
585
+ // regime as `useRouter().push()`'s `void router.navigate(...)`.
586
+ //
587
+ // It used to reach the nearest error boundary instead: React
588
+ // re-throws a rejected async action during render (measured on
589
+ // 19.2.7). That replaced the departing page with the app's error
590
+ // UI, which contradicts what every other failure path here
591
+ // promises — a navigation that fails leaves the user on the page
592
+ // they were already looking at (TIM-1306). Recoverable failures
593
+ // never get here anyway; `runNavigation` swallows AbortErrors and
594
+ // `recoverFromNavigationError` turns a failed fetch into a full
595
+ // document load.
596
+ throw error;
549
597
  });
550
598
  }
551
599
  : userOnClick; // External links — just pass through user's onClick
@@ -97,8 +97,8 @@ export interface NavigationApiController {
97
97
  /**
98
98
  * Resolve the deferred promise created by setRouterNavigating(true),
99
99
  * clearing the browser's native loading state. Call this when the
100
- * navigation fully completes — aligned with when the TopLoader's
101
- * pendingUrl clears (same finally block in router.navigate).
100
+ * navigation fully completes — the same finally block in router.navigate
101
+ * that clears the router's pending store.
102
102
  */
103
103
  completeRouterNavigation: () => void;
104
104
 
@@ -147,7 +147,7 @@ export function setupNavigationApi(callbacks: NavigationApiCallbacks): Navigatio
147
147
  // setRouterNavigating(true) is called, resolved by completeRouterNavigation().
148
148
  // The navigate event handler intercepts with this promise so the browser's
149
149
  // native loading state (tab spinner) stays active until the navigation
150
- // completes — aligned with TopLoader's pendingUrl lifecycle.
150
+ // completes — the same lifecycle the TopLoader is driven by.
151
151
  let routerNavDeferred: { promise: Promise<void>; resolve: () => void } | null = null;
152
152
 
153
153
  function handleNavigate(event: NavigateEvent): void {
@@ -0,0 +1,197 @@
1
+ /**
2
+ * What it means for a page to be "current" on the client.
3
+ *
4
+ * One module owns every write that makes a navigation's destination the
5
+ * current page, and the read that describes the current page back to the
6
+ * server. Keeping them together is the point: `X-Timber-State-Tree` is
7
+ * derived from the segment cache, so the thing that publishes and the thing
8
+ * that reports have to agree about when a page becomes current.
9
+ *
10
+ * See design/19-client-navigation.md §"State Update Invariants".
11
+ */
12
+
13
+ import { buildSegmentTree, type SegmentCache } from './segment-cache.js';
14
+ import type { HistoryStack } from './history.js';
15
+ import type { SegmentInfo, StateTree } from '../shared/segment-info.js';
16
+ import type { ParamsSource } from '../shared/payload-root.js';
17
+ import { setNavigationState, type NavigationState } from './navigation-context.js';
18
+
19
+ /** Everything a commit needs to describe the page it makes current. */
20
+ export interface NavigationCommitInput {
21
+ payload: unknown;
22
+ /** The params that payload published — replayed with it on popstate. */
23
+ params: ParamsSource;
24
+ /**
25
+ * The rendered chain's metadata, or null/undefined when this commit
26
+ * carries none at all — a revalidation payload, or a history entry
27
+ * stored before the channel existed.
28
+ *
29
+ * An empty *array* is a different statement from an absent one: the
30
+ * server rendered a route with no layout-bearing segments (a layoutless
31
+ * app — the missing-root-layout check is a warning, not an error), so
32
+ * the correct tree is the empty one. Collapsing the two left the
33
+ * departing route's tree in place, which `treePaths` then reported as
34
+ * mounted — enough to select an intercepting rewrite whose slot is not
35
+ * on screen (TIM-1282).
36
+ */
37
+ segmentInfo?: SegmentInfo[] | null;
38
+ /** When true, clear the segment cache if segmentInfo is absent
39
+ * (popstate replay for entries without layout metadata). */
40
+ clearSegmentCacheOnEmpty?: boolean;
41
+ /**
42
+ * HTTP status of the response this navigation rendered, when it came from a
43
+ * fetch. Omitted by replays, which re-publish a tree already judged.
44
+ *
45
+ * An error response rendered a status page, and a status page replaces a
46
+ * subtree: the deny page lands at the segment owning the matched file and
47
+ * nothing below it mounts. `segmentInfo` nonetheless describes the whole
48
+ * chain the payload was built against — it must, because the merge point is
49
+ * chosen out of it — so the cache has to be told not to learn from this one.
50
+ *
51
+ * Enforced here rather than at the call sites because there are three of
52
+ * them (`performNavigationFetch`, `refresh()`, and uncached traversal, the
53
+ * last two through `fetchCommitAndRender`) and only one had the check.
54
+ * See TIM-1356.
55
+ */
56
+ status?: number;
57
+ }
58
+
59
+ /**
60
+ * A navigation's destination, split into what a render needs and what a
61
+ * commit publishes.
62
+ */
63
+ export interface PreparedNavigation {
64
+ /** The state the incoming tree renders with. Pure — safe before winning. */
65
+ navState: NavigationState;
66
+ /** Publishes the destination. Call only once the render has won. */
67
+ commit: () => void;
68
+ }
69
+
70
+ export interface NavigationCommitter {
71
+ prepareNavigation(url: string, opts: NavigationCommitInput): PreparedNavigation;
72
+ currentStateTree(): StateTree | undefined;
73
+ updateSegmentCache(segmentInfo: SegmentInfo[] | null | undefined): void;
74
+ }
75
+
76
+ /**
77
+ * Derive the navigation state (pathname + search) a URL renders with.
78
+ *
79
+ * Pure: publishing it — the module-level fallback for tests and SSR, and the
80
+ * globalThis bridge — is `prepareNavigation`'s commit, which runs only once
81
+ * the render is known to have won (TIM-1301). Callers pass the returned value
82
+ * explicitly to renderRoot/wrapPayload, so a render never depends on the
83
+ * publish having happened first.
84
+ */
85
+ export function deriveNavigationState(url: string): NavigationState {
86
+ // Params are not part of it. They travel with the payload and are published
87
+ // by the one client-owned `ParamsProvider` as the new tree renders, which is
88
+ // also what clears the previous route's — a route with no params of its own
89
+ // still publishes an empty record (TIM-1294/TIM-1297, and the clearing
90
+ // requirement from TIM-1285).
91
+ const parsed = new URL(url, 'http://localhost');
92
+ return { pathname: parsed.pathname || '/', search: parsed.search };
93
+ }
94
+
95
+ export function createNavigationCommitter(deps: {
96
+ segmentCache: SegmentCache;
97
+ historyStack: HistoryStack;
98
+ /** Read at call time — the router's `clientSegmentCache` opt-in. */
99
+ clientSegmentCache: () => boolean | undefined;
100
+ }): NavigationCommitter {
101
+ const { segmentCache, historyStack } = deps;
102
+
103
+ /**
104
+ * Update the segment cache from server-provided segment metadata.
105
+ *
106
+ * Runs whether or not `clientSegmentCache` is enabled: the tree is also
107
+ * where the mounted tree paths come from, and those cross on every
108
+ * navigation. What the flag gates is which parts get serialized — see
109
+ * `currentStateTree`.
110
+ */
111
+ function updateSegmentCache(segmentInfo: SegmentInfo[] | null | undefined): void {
112
+ if (!segmentInfo || segmentInfo.length === 0) return;
113
+ const tree = buildSegmentTree(segmentInfo);
114
+ if (tree) {
115
+ segmentCache.set('/', tree);
116
+ }
117
+ }
118
+
119
+ return {
120
+ updateSegmentCache,
121
+
122
+ /**
123
+ * The X-Timber-State-Tree to send with the next RSC request.
124
+ *
125
+ * Two different things travel on one header. `segments`/`slots` are the
126
+ * caching opt-in and are omitted unless `clientSegmentCache` is on.
127
+ * `treePaths` is how the server learns which route is actually mounted,
128
+ * which stops being derivable from the address bar as soon as a modal is
129
+ * open — so it crosses regardless (TIM-1282). Undefined when there is
130
+ * nothing to say, so a no-op header never enters the `_rsc` cache key.
131
+ *
132
+ * Reads what the last *committed* navigation published, so a superseded
133
+ * navigation's destination can never end up describing the mounted tree
134
+ * (TIM-1301).
135
+ */
136
+ currentStateTree(): StateTree | undefined {
137
+ const tree = segmentCache.serializeStateTree();
138
+ if (deps.clientSegmentCache()) return tree;
139
+ return tree.treePaths ? { segments: [], treePaths: tree.treePaths } : undefined;
140
+ },
141
+
142
+ /**
143
+ * Prepare all navigation-owned state for a new page — without publishing
144
+ * any of it. Every code path that changes the "current page" must go
145
+ * through this function, which is what makes "forgot a field" impossible
146
+ * by construction.
147
+ *
148
+ * Returns the destination's `NavigationState`, which is a pure function of
149
+ * the URL and is what the incoming tree is *rendered* with, plus a
150
+ * `commit` thunk that performs the writes that make a page current:
151
+ * 1. Segment cache — update from server-provided segment metadata
152
+ * 2. Navigation state — pathname/search for usePathname/useSearchParams
153
+ * 3. History stack — store the payload for instant back/forward replay
154
+ *
155
+ * Nothing is written until `commit()` runs, and on a transitioned
156
+ * navigation it runs only once the transition is known to have won — see
157
+ * `renderViaTransition` and `NavigationRoot`. A navigation superseded
158
+ * while its payload was in flight never calls it, so the cache, the
159
+ * pathname the client reports and the history stack all keep describing
160
+ * the route still on screen (TIM-1301).
161
+ *
162
+ * Callers with state of their own to publish — the address bar, the
163
+ * client's record of the mounted tree — wrap this thunk rather than
164
+ * commit beside it, so there stays exactly one moment at which a page
165
+ * becomes current.
166
+ */
167
+ prepareNavigation(url: string, opts: NavigationCommitInput): PreparedNavigation {
168
+ const navState = deriveNavigationState(url);
169
+
170
+ // A tree rendered by an error response is not one to cache — see
171
+ // `status` on NavigationCommitInput. Normalized here, once, so no fetch
172
+ // caller can forget it; the history entry records the same thing, or a
173
+ // traversal back to this URL would replay the metadata this drops.
174
+ const cacheable = opts.status === undefined || opts.status < 400;
175
+ const segmentInfo = cacheable ? opts.segmentInfo : [];
176
+
177
+ return {
178
+ navState,
179
+ commit() {
180
+ if (segmentInfo && segmentInfo.length > 0) {
181
+ updateSegmentCache(segmentInfo);
182
+ } else if (segmentInfo?.length === 0 || opts.clearSegmentCacheOnEmpty) {
183
+ segmentCache.clear();
184
+ }
185
+
186
+ setNavigationState(navState);
187
+
188
+ historyStack.push(url, {
189
+ payload: opts.payload,
190
+ params: opts.params,
191
+ segmentInfo,
192
+ });
193
+ },
194
+ };
195
+ },
196
+ };
197
+ }