@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
@@ -24,13 +24,24 @@
24
24
  */
25
25
 
26
26
  import type { ParamEntry, RouteEntry } from './codegen-types.js';
27
- import {
28
- buildCodecChainType,
29
- buildSchemaParamType,
30
- formatSearchParamsType,
31
- } from './codegen-shared.js';
27
+ import { buildSchemaParamType } from './codegen-shared.js';
32
28
  import { classifyUrlSegment } from './segment-classify.js';
33
29
 
30
+ /**
31
+ * The `searchParams` prop type, emitted identically on every Link variant
32
+ * — per-route pattern, resolved template, and catch-all.
33
+ *
34
+ * TIM-1343: there is no per-route narrowing any more. `params.ts` is gone,
35
+ * so codegen has no definition to read a `SearchParamsDefinition<T>` from.
36
+ * Type safety moved to the value's construction site instead: callers write
37
+ * `definition.buildSearchParams({ ... })`, which checks `Partial<T>` there
38
+ * and returns a query STRING — the only shape that survives the RSC Flight
39
+ * boundary. A plain record is the uncodec'd escape hatch. See `client/link.tsx` §"searchParams prop shapes".
40
+ *
41
+ * Declared once so the three emission sites cannot drift apart.
42
+ */
43
+ export const SEARCH_PARAMS_PROP_TYPE = 'string | Record<string, unknown>';
44
+
34
45
  /** Shared Link base-props type literal used in every emitted call signature. */
35
46
  export const LINK_BASE_PROPS_TYPE =
36
47
  "Omit<import('react').AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & { prefetch?: boolean; scroll?: boolean; preserveSearchParams?: true | string[]; onNavigate?: import('./client/link.js').OnNavigateHandler; children?: import('react').ReactNode }";
@@ -71,23 +82,18 @@ export function buildResolvedPattern(route: RouteEntry): string | null {
71
82
  * (convenience — values are stringified at runtime). Catch-all and
72
83
  * optional catch-all remain `string[]` / `string[] | undefined`.
73
84
  *
74
- * When the segment's params chain (TIM-834) declares a typed codec, the
75
- * inferred type from the codec wins via a nested conditional.
85
+ * With a global schema, the schema codec's inferred type wins. Without
86
+ * one, a URL segment is a raw string (widened to string | number for
87
+ * Link convenience) — per-segment codec chains were deleted in TIM-1342.
76
88
  */
77
- export function formatLinkParamsType(
78
- params: ParamEntry[],
79
- importBase?: string,
80
- hasSchema?: boolean
81
- ): string {
89
+ export function formatLinkParamsType(params: ParamEntry[], hasSchema?: boolean): string {
82
90
  if (params.length === 0) {
83
91
  return '{}';
84
92
  }
85
93
 
86
94
  const fields = params.map((p) => {
87
95
  const fallback = p.type === 'string' ? 'string | number' : p.type;
88
- const codecType = hasSchema
89
- ? buildSchemaParamType(p, fallback)
90
- : buildCodecChainType(p, importBase, fallback);
96
+ const codecType = hasSchema ? buildSchemaParamType(p, fallback) : fallback;
91
97
  return `${p.name}: ${codecType}`;
92
98
  });
93
99
  return `{ ${fields.join('; ')} }`;
@@ -109,15 +115,7 @@ export function formatLinkCatchAllOverloads(): string[] {
109
115
  const lines: string[] = [];
110
116
  const baseProps = LINK_BASE_PROPS_TYPE;
111
117
 
112
- // TIM-830: the catch-all signatures accept EITHER the legacy
113
- // `{ definition, values }` wrapper OR a flat `Record<string, unknown>`
114
- // values object. External/computed hrefs can't be looked up in the
115
- // runtime registry, so the wrapped form is still the reliable path;
116
- // the flat form is kept permissive for callers migrating from typed-
117
- // route hrefs to computed strings. `resolveHref` discriminates at
118
- // runtime via the presence of a `definition` key.
119
- const catchAllSearchParams =
120
- '{ definition: SearchParamsDefinition<Record<string, unknown>>; values: Record<string, unknown> } | Record<string, unknown>';
118
+ const catchAllSearchParams = SEARCH_PARAMS_PROP_TYPE;
121
119
 
122
120
  // ExternalHref inlined here rather than referenced as an exported
123
121
  // alias so the generated .d.ts stands alone without source imports.
@@ -207,11 +205,7 @@ export function formatLinkCatchAllOverloads(): string[] {
207
205
  * so the resolved-template-vs-pattern ordering reduces to placing the
208
206
  * pattern variant before the resolved-template variant inside the union.
209
207
  */
210
- export function formatTypedLinkOverloads(
211
- routes: RouteEntry[],
212
- importBase?: string,
213
- hasSchema?: boolean
214
- ): string[] {
208
+ export function formatTypedLinkOverloads(routes: RouteEntry[], hasSchema?: boolean): string[] {
215
209
  const lines: string[] = [];
216
210
  const baseProps = LINK_BASE_PROPS_TYPE;
217
211
 
@@ -234,52 +228,25 @@ export function formatTypedLinkOverloads(
234
228
  // segmentParams. `Record<string, unknown>` keeps generic spreads
235
229
  // compiling and gives a readable error if a non-object is passed.
236
230
  const paramsProp = hasDynamicParams
237
- ? `segmentParams: ${formatLinkParamsType(route.params, importBase, hasSchema)}`
231
+ ? `segmentParams: ${formatLinkParamsType(route.params, hasSchema)}`
238
232
  : 'segmentParams?: Record<string, unknown>';
239
233
 
240
- const searchParamsType = route.hasSearchParams
241
- ? formatSearchParamsType(route, importBase)
242
- : null;
243
- // TIM-830: pattern href uses the FLAT `Partial<T>` shape — the
244
- // runtime registry is keyed by the un-interpolated pattern.
245
- //
246
- // TIM-833: when the route has NO searchParams definition, use
247
- // `Record<string, unknown>` (open shape) instead of
248
- // `Record<string, never>` so generic `LinkProps`-spreading wrappers
249
- // compile. The trade-off vs the original TIM-835 strict shape is
250
- // that excess searchParams keys on a no-def route no longer raise
251
- // a type error — but those keys are runtime no-ops anyway, and
252
- // wrapper compatibility is the more common pain point. Routes WITH
253
- // a searchParams definition still get strict `Partial<T>` typing.
254
- const patternSearchParamsProp = searchParamsType
255
- ? `searchParams?: Partial<${searchParamsType}>`
256
- : 'searchParams?: Record<string, unknown>';
234
+ // TIM-1343: searchParams is no longer typed per-route. There is no
235
+ // convention file to read a definition from, so codegen has nothing to
236
+ // narrow with — the value is either a URLSearchParams built by
237
+ // `definition.buildSearchParams()` (which type-checks its own
238
+ // `Partial<T>` at that call) or a plain String()-coerced record.
239
+ const searchParamsProp = `searchParams?: ${SEARCH_PARAMS_PROP_TYPE}`;
257
240
 
258
241
  // Pattern variant FIRST (more specific).
259
242
  variants.push(
260
- `${baseProps} & { href: '${route.urlPath}'; ${paramsProp}; ${patternSearchParamsProp} }`
243
+ `${baseProps} & { href: '${route.urlPath}'; ${paramsProp}; ${searchParamsProp} }`
261
244
  );
262
245
 
263
246
  // Resolved-template variant SECOND (looser, matches interpolated hrefs).
264
247
  if (hasDynamicParams) {
265
248
  const templatePattern = buildResolvedPattern(route);
266
249
  if (templatePattern) {
267
- // TIM-830: resolved-template href keeps the WRAPPED
268
- // `{ definition, values }` shape — the registry can't be looked
269
- // up by an already-interpolated href.
270
- //
271
- // TIM-833: searchParams falls back to `Record<string, unknown>`
272
- // (was `Record<string, never>`) when the route has no
273
- // definition, mirroring the pattern-variant change above. The
274
- // resolved-template `segmentParams` is intentionally KEPT as
275
- // `Record<string, never>` below to preserve TIM-835's
276
- // pattern-variant typo detection: loosening segmentParams here
277
- // would let the resolved-template variant shadow the pattern
278
- // variant on literal pattern hrefs and silently swallow keyed
279
- // typos like `<Link href="/[id]" segmentParams={{ idz: 1 }} />`.
280
- const resolvedSearchParamsProp = searchParamsType
281
- ? `searchParams?: { definition: SearchParamsDefinition<${searchParamsType}>; values: Partial<${searchParamsType}> }`
282
- : 'searchParams?: Record<string, unknown>';
283
250
  // TIM-835: `Record<string, never>` for segmentParams forbids ANY
284
251
  // provided keys on the resolved-template variant. Without this,
285
252
  // the resolved-template would shadow the pattern variant for
@@ -288,7 +255,7 @@ export function formatTypedLinkOverloads(
288
255
  // and the looser variant would silently swallow segmentParams
289
256
  // type errors.
290
257
  variants.push(
291
- `${baseProps} & { href: \`${templatePattern}\`; segmentParams?: Record<string, never>; ${resolvedSearchParamsProp} }`
258
+ `${baseProps} & { href: \`${templatePattern}\`; segmentParams?: Record<string, never>; ${searchParamsProp} }`
292
259
  );
293
260
  }
294
261
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Route manifest codegen — generates virtual module source for the route
3
- * manifest, search-params registry, and global schema.
3
+ * manifest and the global schema loader.
4
4
  *
5
5
  * Extracted from plugins/routing.ts to keep it under the 500-line budget.
6
6
  * See design/18-build-system.md §"Virtual Modules".
@@ -11,7 +11,6 @@
11
11
  import { existsSync } from 'node:fs';
12
12
  import { join } from 'node:path';
13
13
  import { collectInterceptionRewrites } from './interception.js';
14
- import { fileHasExport } from './export-detect.js';
15
14
  import type { RouteTree, SegmentNode, RouteFile } from './types.js';
16
15
 
17
16
  // ── Single-file conventions ─────────────────────────────────────────────
@@ -26,7 +25,6 @@ const SINGLE_FILE_KEYS = [
26
25
  'error',
27
26
  'default',
28
27
  'denied',
29
- 'params',
30
28
  ] as const;
31
29
 
32
30
  // ── Record-shaped conventions ───────────────────────────────────────────
@@ -107,10 +105,6 @@ export function generateManifestModule(tree: RouteTree, viteRoot: string): strin
107
105
  }
108
106
  }
109
107
 
110
- // searchParams is now a named export from page.tsx, not a separate file.
111
- // The page module's searchParams export is loaded via the page's lazy import.
112
- // Runtime registration happens in the route loader using the page module.
113
-
114
108
  // Record-shaped conventions — table-driven
115
109
  for (const key of RECORD_FILE_KEYS) {
116
110
  const record = node[key];
@@ -160,11 +154,13 @@ export function generateManifestModule(tree: RouteTree, viteRoot: string): strin
160
154
  globalErrorLine = ` globalError: { load: ${v}, filePath: ${JSON.stringify(tree.globalError.filePath)} },`;
161
155
  }
162
156
 
157
+ // Serialize the rewrite objects wholesale — an explicit field list here
158
+ // silently drops any field added to InterceptionRewrite, and the guard that
159
+ // reads it would then fall back to matching too broadly. InterceptionRewrite
160
+ // is plain JSON data by construction (no file references, no functions).
163
161
  const rewrites = collectInterceptionRewrites(tree.root);
164
162
  const rewritesLine =
165
- rewrites.length > 0
166
- ? ` interceptionRewrites: ${JSON.stringify(rewrites.map((r) => ({ interceptedPattern: r.interceptedPattern, interceptingPrefix: r.interceptingPrefix })))},`
167
- : '';
163
+ rewrites.length > 0 ? ` interceptionRewrites: ${JSON.stringify(rewrites)},` : '';
168
164
 
169
165
  const code = [
170
166
  '// Auto-generated route manifest — do not edit.',
@@ -188,58 +184,6 @@ export function generateManifestModule(tree: RouteTree, viteRoot: string): strin
188
184
  return code;
189
185
  }
190
186
 
191
- // ── Search-params registry ──────────────────────────────────────────────
192
-
193
- /**
194
- * Walk the route tree and collect every page that exports a
195
- * `searchParams` definition, then emit a module that statically imports
196
- * each export and registers it into the shared search-params registry.
197
- */
198
- export function generateSearchParamsRegistryModule(tree: RouteTree): string {
199
- const entries: Array<{ urlPath: string; filePath: string }> = [];
200
-
201
- function walk(node: SegmentNode): void {
202
- if (node.page) {
203
- if (node.params && fileHasSearchParamsExport(node.params.filePath)) {
204
- entries.push({ urlPath: node.urlPath, filePath: node.params.filePath });
205
- } else if (fileHasSearchParamsExport(node.page.filePath)) {
206
- entries.push({ urlPath: node.urlPath, filePath: node.page.filePath });
207
- }
208
- }
209
- for (const child of node.children) walk(child);
210
- for (const slot of Object.values(node.slots)) walk(slot);
211
- }
212
- walk(tree.root);
213
-
214
- entries.sort((a, b) => a.urlPath.localeCompare(b.urlPath));
215
-
216
- const lines: string[] = [];
217
- lines.push('// Auto-generated search-params registry — do not edit.');
218
- lines.push('// Generated by timber-routing plugin (TIM-830).');
219
- lines.push('');
220
- lines.push("import { registerSearchParams } from '@timber-js/app/search-params';");
221
- lines.push('');
222
-
223
- entries.forEach((entry, i) => {
224
- lines.push(`import { searchParams as r${i} } from ${JSON.stringify(entry.filePath)};`);
225
- });
226
- lines.push('');
227
-
228
- entries.forEach((entry, i) => {
229
- lines.push(`registerSearchParams(${JSON.stringify(entry.urlPath)}, r${i});`);
230
- });
231
- lines.push('');
232
-
233
- lines.push('export {};');
234
- lines.push('');
235
-
236
- return lines.join('\n');
237
- }
238
-
239
- function fileHasSearchParamsExport(filePath: string): boolean {
240
- return fileHasExport(filePath, 'searchParams');
241
- }
242
-
243
187
  // ── Schema module ───────────────────────────────────────────────────────
244
188
 
245
189
  /**
@@ -18,7 +18,10 @@ import type {
18
18
  ScannerConfig,
19
19
  InterceptionMarker,
20
20
  } from './types.js';
21
- import { classifySegment } from './segment-classify.js';
21
+ import { classifySegment, effectiveUrlSegment } from './segment-classify.js';
22
+ import { validateInterceptionPlacement, computeInterceptedBase } from './interception.js';
23
+ import { validateRouteGroupCollisions } from './collision-spaces.js';
24
+ import { validateSlotPlacement } from './slot-placement.js';
22
25
  import { DEFAULT_PAGE_EXTENSIONS } from './types.js';
23
26
  import { classifyMetadataRoute, isDynamicMetadataExtension } from '../server/metadata-routes.js';
24
27
  import { swallow } from '../server/logger.js';
@@ -32,7 +35,7 @@ const PAGE_EXT_CONVENTIONS = new Set(['page', 'layout', 'error', 'default', 'den
32
35
  /**
33
36
  * File convention names that are always .ts/.tsx (never .mdx etc.)
34
37
  */
35
- const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', 'params']);
38
+ const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route']);
36
39
 
37
40
  /**
38
41
  * Status-code file patterns:
@@ -76,6 +79,12 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
76
79
  // Scan children recursively
77
80
  scanChildren(appDir, tree.root, extSet);
78
81
 
82
+ // Validate: every parallel slot sits where a renderer reaches it. First,
83
+ // because a slot nested inside another slot never renders, and a collision
84
+ // reported from inside one would send the author to fix an ambiguity between
85
+ // two pages that were both already dead.
86
+ validateSlotPlacement(tree.root);
87
+
79
88
  // Validate: detect route group collisions (different groups producing pages at the same URL)
80
89
  validateRouteGroupCollisions(tree.root);
81
90
 
@@ -91,6 +100,10 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
91
100
  // e.g., a-[id] and [slug]-b both have prefix+suffix length = 2
92
101
  validateAffixedSiblingConflicts(tree.root);
93
102
 
103
+ // Validate: intercepting routes must be direct children of a parallel slot —
104
+ // the slot resolver is the only thing that can render one.
105
+ validateInterceptionPlacement(tree.root);
106
+
94
107
  return tree;
95
108
  }
96
109
 
@@ -171,12 +184,12 @@ function scanSegmentFiles(dirPath: string, node: SegmentNode, extSet: Set<string
171
184
  continue;
172
185
  }
173
186
 
174
- // Fixed conventions (middleware, access, route, params) — only
187
+ // Fixed conventions (middleware, access, route) — only
175
188
  // .ts/.tsx/.js/.jsx, never pageExtensions like .mdx. The regex is
176
189
  // anchored: mts/cts/mjs/cjs (and stray tail matches like `.foots`)
177
190
  // are NOT recognized. See design/07-routing.md §"Page Extensions".
178
191
  if (FIXED_CONVENTIONS.has(name) && /^[jt]sx?$/.test(ext)) {
179
- const key = name as 'middleware' | 'access' | 'route' | 'params';
192
+ const key = name as 'middleware' | 'access' | 'route';
180
193
  const existing = node[key];
181
194
  if (existing) {
182
195
  throwDuplicateConvention(name, existing.filePath, fullPath);
@@ -355,69 +368,6 @@ function scanChildren(dirPath: string, parentNode: SegmentNode, extSet: Set<stri
355
368
  }
356
369
  }
357
370
 
358
- /**
359
- * Validate that route groups don't produce conflicting pages/routes at the same URL path.
360
- *
361
- * Two route groups like (auth)/login/page.tsx and (marketing)/login/page.tsx both claim
362
- * /login — the scanner must detect and reject this at build time.
363
- *
364
- * Each parallel slot is validated as its OWN collision space: a slot's pages
365
- * intentionally share URL paths with the parent tree (that's the point of
366
- * parallel routes), but two route groups INSIDE one slot claiming the same
367
- * URL — e.g. @side/(a)/x/page.tsx + @side/(b)/x/page.tsx — still collide.
368
- */
369
- function validateRouteGroupCollisions(root: SegmentNode): void {
370
- // Map from urlPath → { filePath, source } for the first page/route seen at that path
371
- collectRoutableLeaves(root, new Map(), '');
372
- }
373
-
374
- /**
375
- * Walk the segment tree and collect all routable leaves (page or route files),
376
- * throwing on collision. Each slot recurses with a FRESH collision map —
377
- * slots are parallel routes that intentionally share URL paths with their
378
- * parent tree, but collisions within a single slot are real errors.
379
- */
380
- function collectRoutableLeaves(
381
- node: SegmentNode,
382
- seen: Map<string, { filePath: string; segmentPath: string }>,
383
- segmentPath: string
384
- ): void {
385
- // Intercepting routes are resolved by the slot resolver, not URL matching,
386
- // and their computed urlPaths intentionally mirror other routes (e.g. two
387
- // interceptors in one slot both produce /gallery/[id]). Skip them entirely.
388
- if (node.segmentType === 'intercepting') return;
389
-
390
- const currentPath = segmentPath
391
- ? `${segmentPath}/${node.segmentName}`
392
- : node.segmentName || '(root)';
393
-
394
- const routableFile = node.page ?? node.route;
395
- if (routableFile) {
396
- const existing = seen.get(node.urlPath);
397
- if (existing) {
398
- throw new Error(
399
- `Build error: route collision — multiple route groups produce a page/route at the same URL path.\n` +
400
- ` URL path: ${node.urlPath}\n` +
401
- ` File 1: ${existing.filePath} (via ${existing.segmentPath})\n` +
402
- ` File 2: ${routableFile.filePath} (via ${currentPath})\n` +
403
- `Each URL path must map to exactly one page or route handler. ` +
404
- `Rename or move one of the conflicting files.`
405
- );
406
- }
407
- seen.set(node.urlPath, { filePath: routableFile.filePath, segmentPath: currentPath });
408
- }
409
-
410
- // Recurse into children
411
- for (const child of node.children) {
412
- collectRoutableLeaves(child, seen, currentPath);
413
- }
414
-
415
- // Recurse into slots — each slot gets a fresh map (its own collision space)
416
- for (const slotNode of Object.values(node.slots)) {
417
- collectRoutableLeaves(slotNode, new Map(), currentPath);
418
- }
419
- }
420
-
421
371
  /**
422
372
  * Validate that no route chain contains duplicate dynamic param names.
423
373
  *
@@ -438,12 +388,20 @@ function validateDuplicateParamNames(root: SegmentNode): void {
438
388
  * Throws on the first duplicate found.
439
389
  */
440
390
  function walkForDuplicateParams(node: SegmentNode, seen: Map<string, string>): void {
391
+ // Read through the effective identity so an intercepting directory is seen
392
+ // as the segment it intercepts: the scanner leaves `paramName` unset on
393
+ // `(.)[id]`, so a validator reading the node directly is blind to a param
394
+ // the resolver goes on to bind — `@modal/(.)[id]/[id]` would pass here and
395
+ // then silently overwrite the outer `id` at match time, where the ordinary
396
+ // `/[id]/[id]` is rejected. See TIM-1288.
397
+ const { paramName } = effectiveUrlSegment(node);
398
+
441
399
  // If this node introduces a param name, check for duplicates
442
- if (node.paramName) {
443
- const existing = seen.get(node.paramName);
400
+ if (paramName) {
401
+ const existing = seen.get(paramName);
444
402
  if (existing) {
445
403
  throw new Error(
446
- `[timber] Duplicate param name '${node.paramName}' in route chain.\n` +
404
+ `[timber] Duplicate param name '${paramName}' in route chain.\n` +
447
405
  ` First defined at: ${existing}\n` +
448
406
  ` Duplicate at: ${node.urlPath || '/'}\n` +
449
407
  ` Rename one of the segments to avoid ambiguity.`
@@ -451,7 +409,7 @@ function walkForDuplicateParams(node: SegmentNode, seen: Map<string, string>): v
451
409
  }
452
410
  // Add to seen for descendants (use a new Map to avoid polluting siblings)
453
411
  seen = new Map(seen);
454
- seen.set(node.paramName, node.urlPath || '/');
412
+ seen.set(paramName, node.urlPath || '/');
455
413
  }
456
414
 
457
415
  // Recurse into children (they inherit the accumulated params)
@@ -459,8 +417,16 @@ function walkForDuplicateParams(node: SegmentNode, seen: Map<string, string>): v
459
417
  walkForDuplicateParams(child, seen);
460
418
  }
461
419
 
462
- // Slots are independent parallel routes — start fresh param tracking
463
- // (a slot's params don't conflict with the main route's params)
420
+ // A slot INHERITS the ancestor params rather than starting fresh: a slot
421
+ // child may not reuse a name its owner already bound
422
+ // (`app/gallery/[id]/@modal/[id]` is rejected). The copy is so sibling
423
+ // slots don't see each other's names, not so the chain is reset.
424
+ //
425
+ // Whether that rule is right is a separate question — slot params are
426
+ // merged over the main route's at read time, so a collision is defined
427
+ // rather than ambiguous — but changing it would change every slot.
428
+ // Tracked as TIM-1287; do not "fix" this by making the map fresh without
429
+ // deciding that.
464
430
  for (const slotNode of Object.values(node.slots)) {
465
431
  walkForDuplicateParams(slotNode, new Map(seen));
466
432
  }
@@ -488,25 +454,29 @@ function collectBracketForms(
488
454
  node: SegmentNode,
489
455
  forms: Map<string, { segmentType: SegmentType; urlPath: string }>
490
456
  ): void {
491
- if (node.paramName && node.segmentType !== 'static' && node.segmentType !== 'group') {
492
- const existing = forms.get(node.paramName);
493
- if (existing && existing.segmentType !== node.segmentType) {
457
+ // Effective identity, so `(.)[...rest]` is compared as the catch-all it
458
+ // intercepts rather than skipped as an 'intercepting' node (TIM-1288).
459
+ const { paramName, segmentType } = effectiveUrlSegment(node);
460
+
461
+ if (paramName && segmentType !== 'static' && segmentType !== 'group') {
462
+ const existing = forms.get(paramName);
463
+ if (existing && existing.segmentType !== segmentType) {
494
464
  const bracketExamples: Record<string, string> = {
495
- 'dynamic': `[${node.paramName}]`,
496
- 'catch-all': `[...${node.paramName}]`,
497
- 'optional-catch-all': `[[...${node.paramName}]]`,
465
+ 'dynamic': `[${paramName}]`,
466
+ 'catch-all': `[...${paramName}]`,
467
+ 'optional-catch-all': `[[...${paramName}]]`,
498
468
  };
499
469
  throw new Error(
500
- `[timber] Param name '${node.paramName}' uses multiple bracket forms.\n` +
470
+ `[timber] Param name '${paramName}' uses multiple bracket forms.\n` +
501
471
  ` ${bracketExamples[existing.segmentType] ?? existing.segmentType} at: ${existing.urlPath}\n` +
502
- ` ${bracketExamples[node.segmentType] ?? node.segmentType} at: ${node.urlPath || '/'}\n` +
472
+ ` ${bracketExamples[segmentType] ?? segmentType} at: ${node.urlPath || '/'}\n` +
503
473
  ` Each param name must use a single bracket form across all routes.\n` +
504
- ` Rename one of the segments to fix this (e.g., [${node.paramName}] → [${node.paramName}Id]).`
474
+ ` Rename one of the segments to fix this (e.g., [${paramName}] → [${paramName}Id]).`
505
475
  );
506
476
  }
507
477
  if (!existing) {
508
- forms.set(node.paramName, {
509
- segmentType: node.segmentType,
478
+ forms.set(paramName, {
479
+ segmentType,
510
480
  urlPath: node.urlPath || '/',
511
481
  });
512
482
  }
@@ -530,20 +500,39 @@ function collectBracketForms(
530
500
  * Route groups are URL-transparent, so affixed segments inside different groups
531
501
  * at the same level still conflict with each other.
532
502
  *
533
- * See design/07-routing.md §"Priority"
503
+ * Ambiguity requires the two segments to be candidates for the *same* URL
504
+ * part, which is narrower than "same parent" once interception is involved:
505
+ *
506
+ * - Plain children and intercepting children never compete. They are resolved
507
+ * by different walks — `findSlotMatch` matches the slot subtree (where
508
+ * `tree-match.ts` ignores intercepting nodes outright) and
509
+ * `findInterceptingMatch` builds a synthetic parent holding only
510
+ * interceptors.
511
+ * - Two interceptors compete only at the same anchor. `(.)a-[id]` and
512
+ * `(..)[slug]-b` in one slot are based at different URL depths, so no
513
+ * pathname reaches both, and `anchorIndex` rejects the one whose base does
514
+ * not match the target. Grouping them together would fail the build for a
515
+ * pair that can never be ambiguous.
516
+ *
517
+ * So candidates are keyed by the position they contend for, then by affix
518
+ * length. See design/07-routing.md §"Priority" and §"Intercepting Routes".
534
519
  */
535
520
  function validateAffixedSiblingConflicts(node: SegmentNode): void {
536
521
  const affixed = collectEffectiveAffixed(node);
537
522
 
538
523
  if (affixed.length >= 2) {
539
- const byLength = new Map<number, SegmentNode[]>();
524
+ const byLength = new Map<string, SegmentNode[]>();
540
525
  for (const child of affixed) {
541
- const len = (child.paramPrefix?.length ?? 0) + (child.paramSuffix?.length ?? 0);
542
- const group = byLength.get(len);
526
+ // `\0` as the separator, written as the escape rather than a literal
527
+ // byte: a raw NUL in the source makes git and grep treat this file as
528
+ // binary. A contention key is a URL path, which cannot contain one, so
529
+ // the two halves of the key can never run together.
530
+ const key = `${contentionKey(node, child)}\0${affixLengthOf(child)}`;
531
+ const group = byLength.get(key);
543
532
  if (group) {
544
533
  group.push(child);
545
534
  } else {
546
- byLength.set(len, [child]);
535
+ byLength.set(key, [child]);
547
536
  }
548
537
  }
549
538
 
@@ -553,7 +542,7 @@ function validateAffixedSiblingConflicts(node: SegmentNode): void {
553
542
  `Build error: ambiguous affixed dynamic siblings with equal specificity.\n` +
554
543
  ` Parent: ${node.urlPath || '/'}\n` +
555
544
  ` Segments: ${group.map((s) => s.segmentName).join(', ')}\n` +
556
- ` Combined prefix+suffix length: ${(group[0]!.paramPrefix?.length ?? 0) + (group[0]!.paramSuffix?.length ?? 0)}\n` +
545
+ ` Combined prefix+suffix length: ${affixLengthOf(group[0]!)}\n` +
557
546
  `The router cannot deterministically choose between these — filesystem scan order is platform-dependent.\n` +
558
547
  `Rename one segment to give it a longer or shorter combined affix.`
559
548
  );
@@ -569,16 +558,52 @@ function validateAffixedSiblingConflicts(node: SegmentNode): void {
569
558
  }
570
559
  }
571
560
 
561
+ /**
562
+ * The URL position a child contends for, as a comparable key.
563
+ *
564
+ * Plain children contend for the parent's next part. An intercepting child
565
+ * contends for a part determined by its marker's intercepted base, so two
566
+ * markers of different depth are simply different positions — and two markers
567
+ * that compute the *same* base do contend, which is why the key is the base
568
+ * rather than the marker (`(..)` and `(...)` under `/feed` both base at `/`).
569
+ *
570
+ * `groupByInterceptedAnchor` (`routing/interception.ts`) is the canonical
571
+ * statement of that grouping — it is what the resolver walks and what the
572
+ * collision validator checks. This computes the same key from the same
573
+ * `computeInterceptedBase` rather than calling it, because affix ambiguity is
574
+ * decided per *child* and `collectEffectiveAffixed` looks through route groups,
575
+ * so the two do not partition the same set of nodes.
576
+ */
577
+ function contentionKey(parent: SegmentNode, child: SegmentNode): string {
578
+ if (child.segmentType !== 'intercepting') return 'child';
579
+ return `intercept:${computeInterceptedBase(parent.urlPath, child.interceptionMarker ?? '(.)')}`;
580
+ }
581
+
582
+ /** Combined affix length of a node, read through its effective identity. */
583
+ function affixLengthOf(node: SegmentNode): number {
584
+ const { paramPrefix, paramSuffix } = effectiveUrlSegment(node);
585
+ return (paramPrefix?.length ?? 0) + (paramSuffix?.length ?? 0);
586
+ }
587
+
572
588
  /**
573
589
  * Collect affixed dynamic segments that are effective children of a node.
574
590
  * Route groups are URL-transparent, so we look through them recursively.
591
+ *
592
+ * Segments are read through `effectiveUrlSegment`, so an intercepting
593
+ * directory counts as the affixed segment it intercepts: `(.)a-[id]` is
594
+ * `a-[id]`. The proxy the slot resolver builds hands those affixes to
595
+ * `matchUrlParts`, whose equal-length sort is not stable across equal
596
+ * specificity — so two intercepting siblings with the same combined affix
597
+ * length would resolve by filesystem enumeration order, which is precisely
598
+ * what this validator exists to prevent for ordinary siblings (TIM-1288).
575
599
  */
576
600
  function collectEffectiveAffixed(node: SegmentNode): SegmentNode[] {
577
601
  const result: SegmentNode[] = [];
578
602
  for (const child of node.children) {
579
- if (child.segmentType === 'dynamic' && (child.paramPrefix || child.paramSuffix)) {
603
+ const { segmentType, paramPrefix, paramSuffix } = effectiveUrlSegment(child);
604
+ if (segmentType === 'dynamic' && (paramPrefix || paramSuffix)) {
580
605
  result.push(child);
581
- } else if (child.segmentType === 'group') {
606
+ } else if (segmentType === 'group') {
582
607
  result.push(...collectEffectiveAffixed(child));
583
608
  }
584
609
  }
@@ -192,6 +192,63 @@ export function classifySegment(dirName: string): SegmentClassification {
192
192
  return { type: 'static' };
193
193
  }
194
194
 
195
+ /**
196
+ * The URL-matching identity of a segment node.
197
+ *
198
+ * For every node except an intercepting one this is the node itself. An
199
+ * intercepting node is different: its directory name carries a marker
200
+ * (`(.)photo`, `(.)[id]`), so the node's own `segmentType` is
201
+ * `'intercepting'` and the bracket syntax of the segment it intercepts was
202
+ * never classified. Everything that has to reason about *the URL part this
203
+ * node stands for* — matching it, and keying its param for codec coercion —
204
+ * needs that classification.
205
+ *
206
+ * Deriving it here, from `interceptedSegmentName`, keeps interception out
207
+ * of `classifySegment`'s output and out of the serialized manifest: there
208
+ * is no second copy of the classification to drift from this one. The
209
+ * returned `segmentName` is the intercepted name (`photo`, `[id]`), NOT the
210
+ * node's directory name — callers that need the directory name for tree
211
+ * paths must keep reading the node. See TIM-1281.
212
+ */
213
+ export interface UrlSegmentIdentity {
214
+ segmentName: string;
215
+ segmentType: SegmentType;
216
+ paramName?: string;
217
+ paramPrefix?: string;
218
+ paramSuffix?: string;
219
+ }
220
+
221
+ export function effectiveUrlSegment(node: {
222
+ segmentName: string;
223
+ segmentType: SegmentType;
224
+ paramName?: string;
225
+ paramPrefix?: string;
226
+ paramSuffix?: string;
227
+ interceptedSegmentName?: string;
228
+ }): UrlSegmentIdentity {
229
+ if (node.segmentType !== 'intercepting' || !node.interceptedSegmentName) {
230
+ return {
231
+ segmentName: node.segmentName,
232
+ segmentType: node.segmentType,
233
+ paramName: node.paramName,
234
+ paramPrefix: node.paramPrefix,
235
+ paramSuffix: node.paramSuffix,
236
+ };
237
+ }
238
+
239
+ const seg = classifyUrlSegment(node.interceptedSegmentName);
240
+ if (seg.kind === 'static') {
241
+ return { segmentName: seg.value, segmentType: 'static' };
242
+ }
243
+ return {
244
+ segmentName: node.interceptedSegmentName,
245
+ segmentType: seg.kind,
246
+ paramName: seg.name,
247
+ paramPrefix: seg.kind === 'dynamic' ? seg.prefix : undefined,
248
+ paramSuffix: seg.kind === 'dynamic' ? seg.suffix : undefined,
249
+ };
250
+ }
251
+
195
252
  /**
196
253
  * Parse an interception marker from a directory name.
197
254
  *