@timber-js/app 0.2.0-alpha.8 → 0.2.0-alpha.80

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 (573) hide show
  1. package/LICENSE +8 -0
  2. package/dist/_chunks/actions-Dg-ANYHb.js +421 -0
  3. package/dist/_chunks/actions-Dg-ANYHb.js.map +1 -0
  4. package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
  5. package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
  6. package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
  7. package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
  8. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  9. package/dist/_chunks/define-C77ScO0m.js +106 -0
  10. package/dist/_chunks/define-C77ScO0m.js.map +1 -0
  11. package/dist/_chunks/define-CZqDwhSu.js +199 -0
  12. package/dist/_chunks/define-CZqDwhSu.js.map +1 -0
  13. package/dist/_chunks/define-cookie-C2IkoFGN.js +94 -0
  14. package/dist/_chunks/define-cookie-C2IkoFGN.js.map +1 -0
  15. package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
  16. package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
  17. package/dist/_chunks/format-CYBGxKtc.js +14 -0
  18. package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
  19. package/dist/_chunks/{interception-BOoWmLUA.js → interception-Dpn_UfAD.js} +171 -97
  20. package/dist/_chunks/interception-Dpn_UfAD.js.map +1 -0
  21. package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
  22. package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
  23. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
  24. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
  25. package/dist/_chunks/request-context-qMsWgy9C.js +478 -0
  26. package/dist/_chunks/request-context-qMsWgy9C.js.map +1 -0
  27. package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
  28. package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
  29. package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
  30. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
  31. package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
  32. package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
  33. package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
  34. package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
  35. package/dist/_chunks/stale-reload-C2plcNtG.js +64 -0
  36. package/dist/_chunks/stale-reload-C2plcNtG.js.map +1 -0
  37. package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
  38. package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
  39. package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
  40. package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
  41. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-Lo_s_pw2.js} +4 -4
  42. package/dist/_chunks/use-query-states-Lo_s_pw2.js.map +1 -0
  43. package/dist/_chunks/wrappers-_DTmImGt.js +63 -0
  44. package/dist/_chunks/wrappers-_DTmImGt.js.map +1 -0
  45. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  46. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  47. package/dist/adapters/cloudflare-dev.js +73 -0
  48. package/dist/adapters/cloudflare-dev.js.map +1 -0
  49. package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
  50. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  51. package/dist/adapters/cloudflare-kv-cache.js +95 -0
  52. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  53. package/dist/adapters/cloudflare.d.ts +148 -12
  54. package/dist/adapters/cloudflare.d.ts.map +1 -1
  55. package/dist/adapters/cloudflare.js +135 -11
  56. package/dist/adapters/cloudflare.js.map +1 -1
  57. package/dist/adapters/compress-module.d.ts.map +1 -1
  58. package/dist/adapters/nitro.d.ts +17 -1
  59. package/dist/adapters/nitro.d.ts.map +1 -1
  60. package/dist/adapters/nitro.js +56 -13
  61. package/dist/adapters/nitro.js.map +1 -1
  62. package/dist/cache/cache-api.d.ts +24 -0
  63. package/dist/cache/cache-api.d.ts.map +1 -0
  64. package/dist/cache/handler-store.d.ts +31 -0
  65. package/dist/cache/handler-store.d.ts.map +1 -0
  66. package/dist/cache/index.d.ts +23 -7
  67. package/dist/cache/index.d.ts.map +1 -1
  68. package/dist/cache/index.js +142 -80
  69. package/dist/cache/index.js.map +1 -1
  70. package/dist/cache/singleflight.d.ts +18 -1
  71. package/dist/cache/singleflight.d.ts.map +1 -1
  72. package/dist/cache/sizeof.d.ts +22 -0
  73. package/dist/cache/sizeof.d.ts.map +1 -0
  74. package/dist/cache/timber-cache.d.ts +1 -1
  75. package/dist/cache/timber-cache.d.ts.map +1 -1
  76. package/dist/cli.d.ts +6 -1
  77. package/dist/cli.d.ts.map +1 -1
  78. package/dist/cli.js +6 -1
  79. package/dist/cli.js.map +1 -1
  80. package/dist/client/browser-dev.d.ts +27 -1
  81. package/dist/client/browser-dev.d.ts.map +1 -1
  82. package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
  83. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  84. package/dist/client/browser-entry/hmr.d.ts +21 -0
  85. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  86. package/dist/client/browser-entry/hydrate.d.ts +46 -0
  87. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  88. package/dist/client/browser-entry/index.d.ts +30 -0
  89. package/dist/client/browser-entry/index.d.ts.map +1 -0
  90. package/dist/client/browser-entry/post-hydration.d.ts +26 -0
  91. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  92. package/dist/client/browser-entry/router-init.d.ts +23 -0
  93. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  94. package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
  95. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  96. package/dist/client/browser-entry/scroll.d.ts +19 -0
  97. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  98. package/dist/client/error-boundary.d.ts +12 -5
  99. package/dist/client/error-boundary.d.ts.map +1 -1
  100. package/dist/client/error-boundary.js +10 -4
  101. package/dist/client/error-boundary.js.map +1 -1
  102. package/dist/client/error-reconstituter.d.ts +54 -0
  103. package/dist/client/error-reconstituter.d.ts.map +1 -0
  104. package/dist/client/form.d.ts +2 -2
  105. package/dist/client/form.d.ts.map +1 -1
  106. package/dist/client/history.d.ts +19 -4
  107. package/dist/client/history.d.ts.map +1 -1
  108. package/dist/client/index.d.ts +7 -21
  109. package/dist/client/index.d.ts.map +1 -1
  110. package/dist/client/index.js +210 -1017
  111. package/dist/client/index.js.map +1 -1
  112. package/dist/client/internal.d.ts +18 -0
  113. package/dist/client/internal.d.ts.map +1 -0
  114. package/dist/client/internal.js +890 -0
  115. package/dist/client/internal.js.map +1 -0
  116. package/dist/client/link-pending-store.d.ts +63 -0
  117. package/dist/client/link-pending-store.d.ts.map +1 -0
  118. package/dist/client/link.d.ts +90 -32
  119. package/dist/client/link.d.ts.map +1 -1
  120. package/dist/client/nav-link-store.d.ts +36 -0
  121. package/dist/client/nav-link-store.d.ts.map +1 -0
  122. package/dist/client/navigation-api-types.d.ts +90 -0
  123. package/dist/client/navigation-api-types.d.ts.map +1 -0
  124. package/dist/client/navigation-api.d.ts +115 -0
  125. package/dist/client/navigation-api.d.ts.map +1 -0
  126. package/dist/client/navigation-context.d.ts +13 -2
  127. package/dist/client/navigation-context.d.ts.map +1 -1
  128. package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
  129. package/dist/client/navigation-root.d.ts.map +1 -0
  130. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  131. package/dist/client/router-ref.d.ts +1 -1
  132. package/dist/client/router.d.ts +70 -4
  133. package/dist/client/router.d.ts.map +1 -1
  134. package/dist/client/rsc-fetch.d.ts +38 -3
  135. package/dist/client/rsc-fetch.d.ts.map +1 -1
  136. package/dist/client/segment-cache.d.ts +1 -1
  137. package/dist/client/segment-cache.d.ts.map +1 -1
  138. package/dist/client/segment-outlet.d.ts +63 -0
  139. package/dist/client/segment-outlet.d.ts.map +1 -0
  140. package/dist/client/ssr-data.d.ts +13 -4
  141. package/dist/client/ssr-data.d.ts.map +1 -1
  142. package/dist/client/stale-reload.d.ts +15 -0
  143. package/dist/client/stale-reload.d.ts.map +1 -1
  144. package/dist/client/top-loader.d.ts +5 -5
  145. package/dist/client/top-loader.d.ts.map +1 -1
  146. package/dist/client/use-link-status.d.ts +5 -5
  147. package/dist/client/use-link-status.d.ts.map +1 -1
  148. package/dist/client/use-params.d.ts +6 -4
  149. package/dist/client/use-params.d.ts.map +1 -1
  150. package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
  151. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  152. package/dist/client/use-query-states.d.ts +1 -1
  153. package/dist/client/use-query-states.d.ts.map +1 -1
  154. package/dist/client/use-router.d.ts +1 -1
  155. package/dist/codec.d.ts +33 -0
  156. package/dist/codec.d.ts.map +1 -0
  157. package/dist/codec.js +2 -0
  158. package/dist/config-types.d.ts +210 -0
  159. package/dist/config-types.d.ts.map +1 -0
  160. package/dist/content/index.d.ts +1 -10
  161. package/dist/content/index.d.ts.map +1 -1
  162. package/dist/content/index.js +0 -2
  163. package/dist/cookies/define-cookie.d.ts +35 -14
  164. package/dist/cookies/define-cookie.d.ts.map +1 -1
  165. package/dist/cookies/index.js +1 -83
  166. package/dist/fonts/css.d.ts +1 -0
  167. package/dist/fonts/css.d.ts.map +1 -1
  168. package/dist/index.d.ts +45 -192
  169. package/dist/index.d.ts.map +1 -1
  170. package/dist/index.js +12296 -11901
  171. package/dist/index.js.map +1 -1
  172. package/dist/plugin-context.d.ts +84 -0
  173. package/dist/plugin-context.d.ts.map +1 -0
  174. package/dist/plugins/adapter-build.d.ts +1 -1
  175. package/dist/plugins/adapter-build.d.ts.map +1 -1
  176. package/dist/plugins/build-manifest.d.ts +2 -2
  177. package/dist/plugins/build-manifest.d.ts.map +1 -1
  178. package/dist/plugins/build-report.d.ts +3 -3
  179. package/dist/plugins/build-report.d.ts.map +1 -1
  180. package/dist/plugins/client-chunks.d.ts +32 -0
  181. package/dist/plugins/client-chunks.d.ts.map +1 -0
  182. package/dist/plugins/content.d.ts +1 -1
  183. package/dist/plugins/content.d.ts.map +1 -1
  184. package/dist/plugins/dev-browser-logs.d.ts +84 -0
  185. package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
  186. package/dist/plugins/dev-error-overlay.d.ts +26 -1
  187. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  188. package/dist/plugins/dev-logs.d.ts +1 -1
  189. package/dist/plugins/dev-logs.d.ts.map +1 -1
  190. package/dist/plugins/dev-server.d.ts +1 -1
  191. package/dist/plugins/dev-server.d.ts.map +1 -1
  192. package/dist/plugins/entries.d.ts +1 -1
  193. package/dist/plugins/entries.d.ts.map +1 -1
  194. package/dist/plugins/fonts.d.ts +19 -5
  195. package/dist/plugins/fonts.d.ts.map +1 -1
  196. package/dist/plugins/mdx.d.ts +1 -1
  197. package/dist/plugins/mdx.d.ts.map +1 -1
  198. package/dist/plugins/routing.d.ts +1 -1
  199. package/dist/plugins/routing.d.ts.map +1 -1
  200. package/dist/plugins/server-bundle.d.ts.map +1 -1
  201. package/dist/plugins/shims.d.ts +6 -5
  202. package/dist/plugins/shims.d.ts.map +1 -1
  203. package/dist/plugins/static-build.d.ts +4 -4
  204. package/dist/plugins/static-build.d.ts.map +1 -1
  205. package/dist/routing/codegen.d.ts +2 -2
  206. package/dist/routing/codegen.d.ts.map +1 -1
  207. package/dist/routing/index.d.ts +2 -0
  208. package/dist/routing/index.d.ts.map +1 -1
  209. package/dist/routing/index.js +3 -2
  210. package/dist/routing/scanner.d.ts.map +1 -1
  211. package/dist/routing/segment-classify.d.ts +46 -0
  212. package/dist/routing/segment-classify.d.ts.map +1 -0
  213. package/dist/routing/status-file-lint.d.ts +2 -1
  214. package/dist/routing/status-file-lint.d.ts.map +1 -1
  215. package/dist/routing/types.d.ts +16 -4
  216. package/dist/routing/types.d.ts.map +1 -1
  217. package/dist/rsc-runtime/rsc.d.ts +1 -1
  218. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  219. package/dist/rsc-runtime/ssr.d.ts +12 -0
  220. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  221. package/dist/schema-bridge.d.ts +76 -0
  222. package/dist/schema-bridge.d.ts.map +1 -0
  223. package/dist/search-params/define.d.ts +139 -0
  224. package/dist/search-params/define.d.ts.map +1 -0
  225. package/dist/search-params/index.d.ts +4 -7
  226. package/dist/search-params/index.d.ts.map +1 -1
  227. package/dist/search-params/index.js +4 -474
  228. package/dist/search-params/registry.d.ts +2 -2
  229. package/dist/search-params/registry.d.ts.map +1 -1
  230. package/dist/search-params/wrappers.d.ts +53 -0
  231. package/dist/search-params/wrappers.d.ts.map +1 -0
  232. package/dist/segment-params/define.d.ts +78 -0
  233. package/dist/segment-params/define.d.ts.map +1 -0
  234. package/dist/segment-params/index.d.ts +6 -0
  235. package/dist/segment-params/index.d.ts.map +1 -0
  236. package/dist/segment-params/index.js +4 -0
  237. package/dist/server/access-gate.d.ts +4 -0
  238. package/dist/server/access-gate.d.ts.map +1 -1
  239. package/dist/server/action-client.d.ts +12 -1
  240. package/dist/server/action-client.d.ts.map +1 -1
  241. package/dist/server/action-encryption.d.ts +76 -0
  242. package/dist/server/action-encryption.d.ts.map +1 -0
  243. package/dist/server/action-handler.d.ts.map +1 -1
  244. package/dist/server/actions.d.ts +3 -6
  245. package/dist/server/actions.d.ts.map +1 -1
  246. package/dist/server/als-registry.d.ts +32 -4
  247. package/dist/server/als-registry.d.ts.map +1 -1
  248. package/dist/server/build-manifest.d.ts +2 -2
  249. package/dist/server/build-manifest.d.ts.map +1 -1
  250. package/dist/server/debug.d.ts +1 -1
  251. package/dist/server/default-logger.d.ts +22 -0
  252. package/dist/server/default-logger.d.ts.map +1 -0
  253. package/dist/server/deny-page-resolver.d.ts +52 -0
  254. package/dist/server/deny-page-resolver.d.ts.map +1 -0
  255. package/dist/server/deny-renderer.d.ts.map +1 -1
  256. package/dist/server/dev-holding-server.d.ts +52 -0
  257. package/dist/server/dev-holding-server.d.ts.map +1 -0
  258. package/dist/server/dev-warnings.d.ts +1 -21
  259. package/dist/server/dev-warnings.d.ts.map +1 -1
  260. package/dist/server/early-hints.d.ts +13 -5
  261. package/dist/server/early-hints.d.ts.map +1 -1
  262. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  263. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  264. package/dist/server/fallback-error.d.ts +4 -3
  265. package/dist/server/fallback-error.d.ts.map +1 -1
  266. package/dist/server/flight-injection-state.d.ts +66 -0
  267. package/dist/server/flight-injection-state.d.ts.map +1 -0
  268. package/dist/server/flight-scripts.d.ts +42 -0
  269. package/dist/server/flight-scripts.d.ts.map +1 -0
  270. package/dist/server/flush.d.ts.map +1 -1
  271. package/dist/server/form-data.d.ts +29 -0
  272. package/dist/server/form-data.d.ts.map +1 -1
  273. package/dist/server/html-injectors.d.ts +51 -11
  274. package/dist/server/html-injectors.d.ts.map +1 -1
  275. package/dist/server/index.d.ts +6 -43
  276. package/dist/server/index.d.ts.map +1 -1
  277. package/dist/server/index.js +38 -2798
  278. package/dist/server/index.js.map +1 -1
  279. package/dist/server/internal.d.ts +46 -0
  280. package/dist/server/internal.d.ts.map +1 -0
  281. package/dist/server/internal.js +2883 -0
  282. package/dist/server/internal.js.map +1 -0
  283. package/dist/server/logger.d.ts +25 -7
  284. package/dist/server/logger.d.ts.map +1 -1
  285. package/dist/server/middleware-runner.d.ts +19 -4
  286. package/dist/server/middleware-runner.d.ts.map +1 -1
  287. package/dist/server/node-stream-transforms.d.ts +113 -0
  288. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  289. package/dist/server/page-deny-boundary.d.ts +31 -0
  290. package/dist/server/page-deny-boundary.d.ts.map +1 -0
  291. package/dist/server/pipeline-interception.d.ts +1 -1
  292. package/dist/server/pipeline-interception.d.ts.map +1 -1
  293. package/dist/server/pipeline-metadata.d.ts +6 -0
  294. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  295. package/dist/server/pipeline.d.ts +42 -10
  296. package/dist/server/pipeline.d.ts.map +1 -1
  297. package/dist/server/primitives.d.ts +69 -18
  298. package/dist/server/primitives.d.ts.map +1 -1
  299. package/dist/server/render-timeout.d.ts +51 -0
  300. package/dist/server/render-timeout.d.ts.map +1 -0
  301. package/dist/server/request-context.d.ts +112 -43
  302. package/dist/server/request-context.d.ts.map +1 -1
  303. package/dist/server/route-element-builder.d.ts +27 -1
  304. package/dist/server/route-element-builder.d.ts.map +1 -1
  305. package/dist/server/route-handler.d.ts.map +1 -1
  306. package/dist/server/route-matcher.d.ts +9 -2
  307. package/dist/server/route-matcher.d.ts.map +1 -1
  308. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  309. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  310. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  311. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  312. package/dist/server/rsc-entry/helpers.d.ts +48 -5
  313. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  314. package/dist/server/rsc-entry/index.d.ts +8 -3
  315. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  316. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  317. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  318. package/dist/server/rsc-entry/rsc-stream.d.ts +4 -1
  319. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  320. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  321. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  322. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  323. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  324. package/dist/server/safe-load.d.ts +46 -0
  325. package/dist/server/safe-load.d.ts.map +1 -0
  326. package/dist/server/sitemap-generator.d.ts +129 -0
  327. package/dist/server/sitemap-generator.d.ts.map +1 -0
  328. package/dist/server/sitemap-handler.d.ts +22 -0
  329. package/dist/server/sitemap-handler.d.ts.map +1 -0
  330. package/dist/server/slot-resolver.d.ts +1 -1
  331. package/dist/server/slot-resolver.d.ts.map +1 -1
  332. package/dist/server/ssr-entry.d.ts +22 -0
  333. package/dist/server/ssr-entry.d.ts.map +1 -1
  334. package/dist/server/ssr-render.d.ts +39 -21
  335. package/dist/server/ssr-render.d.ts.map +1 -1
  336. package/dist/server/ssr-wrappers.d.ts +50 -0
  337. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  338. package/dist/server/status-code-resolver.d.ts +1 -1
  339. package/dist/server/status-code-resolver.d.ts.map +1 -1
  340. package/dist/server/stream-utils.d.ts +36 -0
  341. package/dist/server/stream-utils.d.ts.map +1 -0
  342. package/dist/server/tracing.d.ts +4 -4
  343. package/dist/server/tracing.d.ts.map +1 -1
  344. package/dist/server/tree-builder.d.ts +22 -19
  345. package/dist/server/tree-builder.d.ts.map +1 -1
  346. package/dist/server/types.d.ts +1 -4
  347. package/dist/server/types.d.ts.map +1 -1
  348. package/dist/server/version-skew.d.ts +61 -0
  349. package/dist/server/version-skew.d.ts.map +1 -0
  350. package/dist/shared/merge-search-params.d.ts +22 -0
  351. package/dist/shared/merge-search-params.d.ts.map +1 -0
  352. package/dist/shims/font-google.d.ts +1 -1
  353. package/dist/shims/font-google.d.ts.map +1 -1
  354. package/dist/shims/font-google.js +42 -0
  355. package/dist/shims/font-google.js.map +1 -0
  356. package/dist/shims/font-local.d.ts +26 -0
  357. package/dist/shims/font-local.d.ts.map +1 -0
  358. package/dist/shims/font-local.js +20 -0
  359. package/dist/shims/font-local.js.map +1 -0
  360. package/dist/shims/headers.d.ts +2 -1
  361. package/dist/shims/headers.d.ts.map +1 -1
  362. package/dist/shims/navigation-client.d.ts +1 -1
  363. package/dist/shims/navigation-client.d.ts.map +1 -1
  364. package/dist/shims/navigation.d.ts +3 -2
  365. package/dist/shims/navigation.d.ts.map +1 -1
  366. package/dist/utils/directive-parser.d.ts +5 -2
  367. package/dist/utils/directive-parser.d.ts.map +1 -1
  368. package/dist/utils/state-machine.d.ts +80 -0
  369. package/dist/utils/state-machine.d.ts.map +1 -0
  370. package/package.json +53 -23
  371. package/src/adapters/cloudflare-dev.ts +177 -0
  372. package/src/adapters/cloudflare-kv-cache.ts +142 -0
  373. package/src/adapters/cloudflare.ts +342 -28
  374. package/src/adapters/compress-module.ts +24 -4
  375. package/src/adapters/nitro.ts +52 -8
  376. package/src/adapters/wrangler.d.ts +7 -0
  377. package/src/cache/cache-api.ts +38 -0
  378. package/src/cache/handler-store.ts +68 -0
  379. package/src/cache/index.ts +81 -18
  380. package/src/cache/singleflight.ts +62 -4
  381. package/src/cache/sizeof.ts +31 -0
  382. package/src/cache/timber-cache.ts +24 -20
  383. package/src/cli.ts +6 -1
  384. package/src/client/browser-dev.ts +128 -1
  385. package/src/client/browser-entry/action-dispatch.ts +116 -0
  386. package/src/client/browser-entry/hmr.ts +81 -0
  387. package/src/client/browser-entry/hydrate.ts +145 -0
  388. package/src/client/browser-entry/index.ts +138 -0
  389. package/src/client/browser-entry/post-hydration.ts +119 -0
  390. package/src/client/browser-entry/router-init.ts +193 -0
  391. package/src/client/browser-entry/rsc-stream.ts +157 -0
  392. package/src/client/browser-entry/scroll.ts +27 -0
  393. package/src/client/error-boundary.tsx +48 -16
  394. package/src/client/error-reconstituter.tsx +65 -0
  395. package/src/client/form.tsx +2 -2
  396. package/src/client/history.ts +26 -4
  397. package/src/client/index.ts +19 -38
  398. package/src/client/internal.ts +57 -0
  399. package/src/client/link-pending-store.ts +111 -0
  400. package/src/client/link.tsx +329 -97
  401. package/src/client/nav-link-store.ts +47 -0
  402. package/src/client/navigation-api-types.ts +112 -0
  403. package/src/client/navigation-api.ts +332 -0
  404. package/src/client/navigation-context.ts +31 -6
  405. package/src/client/navigation-root.tsx +342 -0
  406. package/src/client/nuqs-adapter.tsx +16 -3
  407. package/src/client/router-ref.ts +1 -1
  408. package/src/client/router.ts +299 -72
  409. package/src/client/rsc-fetch.ts +97 -8
  410. package/src/client/segment-cache.ts +1 -1
  411. package/src/client/segment-outlet.tsx +86 -0
  412. package/src/client/ssr-data.ts +13 -5
  413. package/src/client/stale-reload.ts +72 -3
  414. package/src/client/top-loader.tsx +16 -8
  415. package/src/client/use-link-status.ts +7 -7
  416. package/src/client/use-params.ts +7 -5
  417. package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
  418. package/src/client/use-query-states.ts +3 -3
  419. package/src/client/use-router.ts +1 -1
  420. package/src/codec.ts +49 -0
  421. package/src/config-types.ts +208 -0
  422. package/src/content/index.ts +5 -13
  423. package/src/cookies/define-cookie.ts +78 -25
  424. package/src/cookies/index.ts +8 -0
  425. package/src/fonts/css.ts +2 -1
  426. package/src/index.ts +258 -354
  427. package/src/plugin-context.ts +200 -0
  428. package/src/plugins/adapter-build.ts +8 -2
  429. package/src/plugins/build-manifest.ts +13 -2
  430. package/src/plugins/build-report.ts +3 -3
  431. package/src/plugins/client-chunks.ts +65 -0
  432. package/src/plugins/content.ts +1 -1
  433. package/src/plugins/dev-browser-logs.ts +288 -0
  434. package/src/plugins/dev-error-overlay.ts +70 -1
  435. package/src/plugins/dev-logs.ts +1 -1
  436. package/src/plugins/dev-server.ts +70 -9
  437. package/src/plugins/entries.ts +71 -10
  438. package/src/plugins/fonts.ts +168 -61
  439. package/src/plugins/mdx.ts +1 -1
  440. package/src/plugins/routing.ts +57 -17
  441. package/src/plugins/server-action-exports.ts +1 -1
  442. package/src/plugins/server-bundle.ts +32 -1
  443. package/src/plugins/shims.ts +135 -35
  444. package/src/plugins/static-build.ts +17 -11
  445. package/src/routing/codegen.ts +165 -105
  446. package/src/routing/index.ts +2 -0
  447. package/src/routing/scanner.ts +93 -23
  448. package/src/routing/segment-classify.ts +89 -0
  449. package/src/routing/status-file-lint.ts +3 -2
  450. package/src/routing/types.ts +17 -4
  451. package/src/rsc-runtime/rsc.ts +2 -0
  452. package/src/rsc-runtime/ssr.ts +50 -0
  453. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  454. package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
  455. package/src/search-params/define.ts +482 -0
  456. package/src/search-params/index.ts +14 -20
  457. package/src/search-params/registry.ts +2 -2
  458. package/src/search-params/wrappers.ts +85 -0
  459. package/src/segment-params/define.ts +279 -0
  460. package/src/segment-params/index.ts +29 -0
  461. package/src/server/access-gate.tsx +70 -29
  462. package/src/server/action-client.ts +21 -2
  463. package/src/server/action-encryption.ts +144 -0
  464. package/src/server/action-handler.ts +21 -4
  465. package/src/server/actions.ts +10 -9
  466. package/src/server/als-registry.ts +34 -6
  467. package/src/server/build-manifest.ts +10 -4
  468. package/src/server/compress.ts +25 -7
  469. package/src/server/debug.ts +1 -1
  470. package/src/server/default-logger.ts +99 -0
  471. package/src/server/deny-page-resolver.ts +154 -0
  472. package/src/server/deny-renderer.ts +24 -38
  473. package/src/server/dev-holding-server.ts +185 -0
  474. package/src/server/dev-warnings.ts +4 -49
  475. package/src/server/early-hints.ts +36 -15
  476. package/src/server/error-boundary-wrapper.ts +74 -22
  477. package/src/server/fallback-error.ts +31 -15
  478. package/src/server/flight-injection-state.ts +113 -0
  479. package/src/server/flight-scripts.ts +62 -0
  480. package/src/server/flush.ts +2 -1
  481. package/src/server/form-data.ts +76 -0
  482. package/src/server/html-injectors.ts +280 -120
  483. package/src/server/index.ts +26 -177
  484. package/src/server/internal.ts +169 -0
  485. package/src/server/logger.ts +44 -36
  486. package/src/server/middleware-runner.ts +31 -4
  487. package/src/server/node-stream-transforms.ts +509 -0
  488. package/src/server/page-deny-boundary.tsx +56 -0
  489. package/src/server/pipeline-interception.ts +17 -16
  490. package/src/server/pipeline-metadata.ts +13 -0
  491. package/src/server/pipeline.ts +227 -62
  492. package/src/server/primitives.ts +111 -28
  493. package/src/server/render-timeout.ts +108 -0
  494. package/src/server/request-context.ts +293 -132
  495. package/src/server/route-element-builder.ts +283 -191
  496. package/src/server/route-handler.ts +24 -4
  497. package/src/server/route-matcher.ts +24 -20
  498. package/src/server/rsc-entry/api-handler.ts +15 -16
  499. package/src/server/rsc-entry/error-renderer.ts +300 -89
  500. package/src/server/rsc-entry/helpers.ts +134 -5
  501. package/src/server/rsc-entry/index.ts +200 -112
  502. package/src/server/rsc-entry/rsc-payload.ts +65 -18
  503. package/src/server/rsc-entry/rsc-stream.ts +65 -13
  504. package/src/server/rsc-entry/ssr-bridge.ts +14 -5
  505. package/src/server/rsc-entry/ssr-renderer.ts +168 -38
  506. package/src/server/safe-load.ts +60 -0
  507. package/src/server/sitemap-generator.ts +338 -0
  508. package/src/server/sitemap-handler.ts +126 -0
  509. package/src/server/slot-resolver.ts +244 -229
  510. package/src/server/ssr-entry.ts +211 -32
  511. package/src/server/ssr-render.ts +289 -67
  512. package/src/server/ssr-wrappers.tsx +139 -0
  513. package/src/server/status-code-resolver.ts +1 -1
  514. package/src/server/stream-utils.ts +213 -0
  515. package/src/server/tracing.ts +20 -9
  516. package/src/server/tree-builder.ts +92 -58
  517. package/src/server/types.ts +3 -6
  518. package/src/server/version-skew.ts +104 -0
  519. package/src/shared/merge-search-params.ts +55 -0
  520. package/src/shims/font-google.ts +1 -1
  521. package/src/shims/font-local.ts +34 -0
  522. package/src/shims/headers.ts +5 -1
  523. package/src/shims/navigation-client.ts +1 -1
  524. package/src/shims/navigation.ts +7 -2
  525. package/src/utils/directive-parser.ts +5 -2
  526. package/src/utils/state-machine.ts +111 -0
  527. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  528. package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
  529. package/dist/_chunks/format-DviM89f0.js.map +0 -1
  530. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  531. package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
  532. package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
  533. package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
  534. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  535. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  536. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  537. package/dist/cache/register-cached-function.d.ts +0 -17
  538. package/dist/cache/register-cached-function.d.ts.map +0 -1
  539. package/dist/client/browser-entry.d.ts +0 -21
  540. package/dist/client/browser-entry.d.ts.map +0 -1
  541. package/dist/client/link-status-provider.d.ts +0 -11
  542. package/dist/client/link-status-provider.d.ts.map +0 -1
  543. package/dist/client/transition-root.d.ts.map +0 -1
  544. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  545. package/dist/cookies/index.js.map +0 -1
  546. package/dist/plugins/cache-transform.d.ts +0 -36
  547. package/dist/plugins/cache-transform.d.ts.map +0 -1
  548. package/dist/plugins/dynamic-transform.d.ts +0 -72
  549. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  550. package/dist/search-params/analyze.d.ts +0 -54
  551. package/dist/search-params/analyze.d.ts.map +0 -1
  552. package/dist/search-params/builtin-codecs.d.ts +0 -105
  553. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  554. package/dist/search-params/codecs.d.ts +0 -53
  555. package/dist/search-params/codecs.d.ts.map +0 -1
  556. package/dist/search-params/create.d.ts +0 -106
  557. package/dist/search-params/create.d.ts.map +0 -1
  558. package/dist/search-params/index.js.map +0 -1
  559. package/dist/server/prerender.d.ts +0 -77
  560. package/dist/server/prerender.d.ts.map +0 -1
  561. package/dist/server/response-cache.d.ts +0 -54
  562. package/dist/server/response-cache.d.ts.map +0 -1
  563. package/src/cache/register-cached-function.ts +0 -103
  564. package/src/client/browser-entry.ts +0 -678
  565. package/src/client/link-status-provider.tsx +0 -30
  566. package/src/client/transition-root.tsx +0 -166
  567. package/src/plugins/cache-transform.ts +0 -199
  568. package/src/plugins/dynamic-transform.ts +0 -161
  569. package/src/search-params/analyze.ts +0 -192
  570. package/src/search-params/builtin-codecs.ts +0 -228
  571. package/src/search-params/create.ts +0 -321
  572. package/src/server/prerender.ts +0 -139
  573. package/src/server/response-cache.ts +0 -410
@@ -8,8 +8,8 @@
8
8
  * No runtime overhead — purely static type generation.
9
9
  */
10
10
 
11
- import { existsSync } from 'node:fs';
12
- import { join, relative, posix } from 'node:path';
11
+ import { existsSync, readFileSync } from 'node:fs';
12
+ import { relative, posix } from 'node:path';
13
13
  import type { RouteTree, SegmentNode } from './types.js';
14
14
 
15
15
  /** A single route entry extracted from the segment tree. */
@@ -18,10 +18,10 @@ interface RouteEntry {
18
18
  urlPath: string;
19
19
  /** Accumulated params from all ancestor dynamic segments */
20
20
  params: ParamEntry[];
21
- /** Whether this route has a co-located search-params.ts */
21
+ /** Whether the page.tsx exports searchParams */
22
22
  hasSearchParams: boolean;
23
- /** Absolute path to search-params.ts (for computing relative import paths) */
24
- searchParamsAbsPath?: string;
23
+ /** Absolute path to the page file that exports searchParams (for import paths) */
24
+ searchParamsPagePath?: string;
25
25
  /** Whether this is an API route (route.ts) vs page route */
26
26
  isApiRoute: boolean;
27
27
  }
@@ -29,15 +29,17 @@ interface RouteEntry {
29
29
  interface ParamEntry {
30
30
  name: string;
31
31
  type: 'string' | 'string[]' | 'string[] | undefined';
32
+ /** When a layout/page exports defineParams, the absolute path to that file. */
33
+ codecFilePath?: string;
32
34
  }
33
35
 
34
36
  /** Options for route map generation. */
35
37
  export interface CodegenOptions {
36
- /** Absolute path to the app/ directory. Required for search-params.ts detection. */
38
+ /** Absolute path to the app/ directory. Required for page searchParams detection. */
37
39
  appDir?: string;
38
40
  /**
39
41
  * Absolute path to the directory where the .d.ts file will be written.
40
- * Used to compute correct relative import paths for search-params.ts files.
42
+ * Used to compute correct relative import paths for page files.
41
43
  * Defaults to appDir when not provided (preserves backward compat for tests).
42
44
  */
43
45
  outputDir?: string;
@@ -51,7 +53,7 @@ export interface CodegenOptions {
51
53
  */
52
54
  export function generateRouteMap(tree: RouteTree, options: CodegenOptions = {}): string {
53
55
  const routes: RouteEntry[] = [];
54
- collectRoutes(tree.root, [], options.appDir, routes);
56
+ collectRoutes(tree.root, [], routes);
55
57
 
56
58
  // Sort routes alphabetically for deterministic output
57
59
  routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));
@@ -71,15 +73,17 @@ export function generateRouteMap(tree: RouteTree, options: CodegenOptions = {}):
71
73
  function collectRoutes(
72
74
  node: SegmentNode,
73
75
  ancestorParams: ParamEntry[],
74
- appDir: string | undefined,
75
76
  routes: RouteEntry[]
76
77
  ): void {
77
78
  // Accumulate params from this segment
78
79
  const params = [...ancestorParams];
79
80
  if (node.paramName) {
81
+ // Check if layout or page exports a params codec for this segment
82
+ const codecFile = findParamsExport(node);
80
83
  params.push({
81
84
  name: node.paramName,
82
85
  type: paramTypeForSegment(node.segmentType),
86
+ codecFilePath: codecFile,
83
87
  });
84
88
  }
85
89
 
@@ -95,13 +99,14 @@ function collectRoutes(
95
99
  isApiRoute,
96
100
  };
97
101
 
98
- // Detect co-located search-params.ts
99
- if (appDir && isPage) {
100
- const segmentDir = resolveSegmentDir(appDir, node);
101
- const searchParamsFile = findSearchParamsFile(segmentDir);
102
- if (searchParamsFile) {
102
+ // Detect searchParams export from params.ts (primary) or page.tsx (fallback)
103
+ if (isPage) {
104
+ if (node.params && fileHasExport(node.params.filePath, 'searchParams')) {
103
105
  entry.hasSearchParams = true;
104
- entry.searchParamsAbsPath = searchParamsFile;
106
+ entry.searchParamsPagePath = node.params.filePath;
107
+ } else if (node.page && fileHasExport(node.page.filePath, 'searchParams')) {
108
+ entry.hasSearchParams = true;
109
+ entry.searchParamsPagePath = node.page.filePath;
105
110
  }
106
111
  }
107
112
 
@@ -110,12 +115,12 @@ function collectRoutes(
110
115
 
111
116
  // Recurse into children
112
117
  for (const child of node.children) {
113
- collectRoutes(child, params, appDir, routes);
118
+ collectRoutes(child, params, routes);
114
119
  }
115
120
 
116
121
  // Recurse into slots (they share the parent's URL path, but may have their own pages)
117
122
  for (const [, slot] of node.slots) {
118
- collectRoutes(slot, params, appDir, routes);
123
+ collectRoutes(slot, params, routes);
119
124
  }
120
125
  }
121
126
 
@@ -134,33 +139,43 @@ function paramTypeForSegment(segmentType: string): ParamEntry['type'] {
134
139
  }
135
140
 
136
141
  /**
137
- * Resolve the absolute directory path for a segment node.
142
+ * Check if a file exports a specific named export.
138
143
  *
139
- * Reconstructs the filesystem path by walking from appDir through
140
- * the segment names encoded in the urlPath, accounting for groups and slots.
144
+ * Uses a lightweight regex check not full AST parsing. The actual type
145
+ * extraction happens via the TypeScript compiler in the generated .d.ts.
141
146
  */
142
- function resolveSegmentDir(appDir: string, node: SegmentNode): string {
143
- // The node's page/route file path gives us the actual directory
144
- const file = node.page ?? node.route;
145
- if (file) {
146
- // The file is in the segment directory — go up one level
147
- const parts = file.filePath.split('/');
148
- parts.pop(); // remove filename
149
- return parts.join('/');
147
+ function fileHasExport(filePath: string, exportName: string): boolean {
148
+ if (!existsSync(filePath)) return false;
149
+ try {
150
+ const content = readFileSync(filePath, 'utf-8');
151
+ const e = exportName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
152
+ return (
153
+ new RegExp(`export\\s+(const|let|var)\\s+${e}\\b`).test(content) ||
154
+ new RegExp(`export\\s*\\{[^}]*\\b${e}\\b[^}]*\\}`).test(content)
155
+ );
156
+ } catch {
157
+ return false;
150
158
  }
151
- // Fallback: construct from urlPath (imprecise for groups, but acceptable)
152
- return appDir;
153
159
  }
154
160
 
155
161
  /**
156
- * Find a search-params.ts file in a directory.
162
+ * Find which file exports `segmentParams` for a dynamic segment.
163
+ *
164
+ * Priority: params.ts (convention file) > layout > page.
165
+ * params.ts is the canonical location (TIM-508). Layout/page fallback
166
+ * exists for backward compat during migration.
157
167
  */
158
- function findSearchParamsFile(dirPath: string): string | undefined {
159
- for (const ext of ['ts', 'tsx']) {
160
- const candidate = join(dirPath, `search-params.${ext}`);
161
- if (existsSync(candidate)) {
162
- return candidate;
163
- }
168
+ function findParamsExport(node: SegmentNode): string | undefined {
169
+ // params.ts convention file primary location
170
+ if (node.params && fileHasExport(node.params.filePath, 'segmentParams')) {
171
+ return node.params.filePath;
172
+ }
173
+ // Fallback: layout or page export (legacy, will be removed)
174
+ if (node.layout && fileHasExport(node.layout.filePath, 'segmentParams')) {
175
+ return node.layout.filePath;
176
+ }
177
+ if (node.page && fileHasExport(node.page.filePath, 'segmentParams')) {
178
+ return node.page.filePath;
164
179
  }
165
180
  return undefined;
166
181
  }
@@ -184,11 +199,11 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
184
199
  lines.push(' interface Routes {');
185
200
 
186
201
  for (const route of routes) {
187
- const paramsType = formatParamsType(route.params);
202
+ const paramsType = formatParamsType(route.params, importBase);
188
203
  const searchParamsType = formatSearchParamsType(route, importBase);
189
204
 
190
205
  lines.push(` '${route.urlPath}': {`);
191
- lines.push(` params: ${paramsType}`);
206
+ lines.push(` segmentParams: ${paramsType}`);
192
207
  lines.push(` searchParams: ${searchParamsType}`);
193
208
  lines.push(` }`);
194
209
  }
@@ -200,15 +215,9 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
200
215
  // Generate @timber-js/app/server augmentation — typed searchParams() generic
201
216
  const pageRoutes = routes.filter((r) => !r.isApiRoute);
202
217
 
203
- if (pageRoutes.length > 0) {
204
- lines.push("declare module '@timber-js/app/server' {");
205
- lines.push(" import type { Routes } from '@timber-js/app'");
206
- lines.push(
207
- " export function searchParams<R extends keyof Routes>(): Promise<Routes[R]['searchParams']>"
208
- );
209
- lines.push('}');
210
- lines.push('');
211
- }
218
+ // Note: searchParams() always returns Promise<URLSearchParams>.
219
+ // Typed parsing is done via definition.parse(searchParams()).
220
+ // No module augmentation needed for @timber-js/app/server.
212
221
 
213
222
  // Generate overloads for @timber-js/app/client
214
223
  const dynamicRoutes = routes.filter((r) => r.params.length > 0);
@@ -223,10 +232,10 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
223
232
  // useParams overloads
224
233
  if (dynamicRoutes.length > 0) {
225
234
  for (const route of dynamicRoutes) {
226
- const paramsType = formatParamsType(route.params);
227
- lines.push(` export function useParams(route: '${route.urlPath}'): ${paramsType}`);
235
+ const paramsType = formatParamsType(route.params, importBase);
236
+ lines.push(` export function useSegmentParams(route: '${route.urlPath}'): ${paramsType}`);
228
237
  }
229
- lines.push(' export function useParams(): Record<string, string | string[]>');
238
+ lines.push(' export function useSegmentParams(): Record<string, string | string[]>');
230
239
  lines.push('');
231
240
  }
232
241
 
@@ -236,10 +245,14 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
236
245
  lines.push('');
237
246
  }
238
247
 
239
- // Typed Link overloads
248
+ // Typed Link overloads — per-route with DIRECT types (no conditionals).
249
+ // Direct types preserve TypeScript's excess property checking.
250
+ // The catch-all overload (segmentParams?: never) lives in link.tsx.
251
+ // See TIM-624.
240
252
  if (pageRoutes.length > 0) {
241
- lines.push(' // Typed Link props per route');
253
+ lines.push(' // Typed Link overloads per route');
242
254
  lines.push(...formatTypedLinkOverloads(pageRoutes, importBase));
255
+ lines.push('');
243
256
  }
244
257
 
245
258
  lines.push('}');
@@ -252,31 +265,56 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
252
265
  /**
253
266
  * Format the params type for a route entry.
254
267
  */
255
- function formatParamsType(params: ParamEntry[]): string {
268
+ function formatParamsType(params: ParamEntry[], importBase?: string): string {
256
269
  if (params.length === 0) {
257
270
  return '{}';
258
271
  }
259
272
 
260
- const fields = params.map((p) => `${p.name}: ${p.type}`);
273
+ const fields = params.map((p) => {
274
+ if (p.codecFilePath) {
275
+ // Use the codec's inferred type from the layout/page file
276
+ const absPath = p.codecFilePath.replace(/\.(ts|tsx)$/, '');
277
+ let importPath: string;
278
+ if (importBase) {
279
+ importPath = './' + relative(importBase, absPath).replace(/\\/g, '/');
280
+ } else {
281
+ importPath = './' + posix.basename(absPath);
282
+ }
283
+ // Extract T from the 'segmentParams' named export's ParamsDefinition<T>
284
+ const codecType = `(typeof import('${importPath}'))['segmentParams'] extends import('@timber-js/app/segment-params').ParamsDefinition<infer T> ? T[${JSON.stringify(p.name)}] : ${p.type}`;
285
+ return `${p.name}: ${codecType}`;
286
+ }
287
+ return `${p.name}: ${p.type}`;
288
+ });
261
289
  return `{ ${fields.join('; ')} }`;
262
290
  }
263
291
 
264
292
  /**
265
- * Format the params type for Link props.
293
+ * Format the params type for Link overloads.
266
294
  *
267
295
  * Link params accept `string | number` for single dynamic segments
268
296
  * (convenience — values are stringified at runtime). Catch-all and
269
297
  * optional catch-all remain `string[]` / `string[] | undefined`.
270
298
  *
271
- * See design/07-routing.md §"Typed params and searchParams on <Link>"
299
+ * Uses DIRECT types (not conditional) to preserve excess property checking.
272
300
  */
273
- function formatLinkParamsType(params: ParamEntry[]): string {
301
+ function formatLinkParamsType(params: ParamEntry[], importBase?: string): string {
274
302
  if (params.length === 0) {
275
303
  return '{}';
276
304
  }
277
305
 
278
306
  const fields = params.map((p) => {
279
- // Single dynamic segments accept string | number for convenience
307
+ if (p.codecFilePath) {
308
+ const absPath = p.codecFilePath.replace(/\.(ts|tsx)$/, '');
309
+ let importPath: string;
310
+ if (importBase) {
311
+ importPath = './' + relative(importBase, absPath).replace(/\\/g, '/');
312
+ } else {
313
+ importPath = './' + posix.basename(absPath);
314
+ }
315
+ const codecType = `(typeof import('${importPath}'))['segmentParams'] extends import('@timber-js/app/segment-params').ParamsDefinition<infer T> ? T[${JSON.stringify(p.name)}] : ${p.type}`;
316
+ return `${p.name}: ${codecType}`;
317
+ }
280
318
  const type = p.type === 'string' ? 'string | number' : p.type;
281
319
  return `${p.name}: ${type}`;
282
320
  });
@@ -286,13 +324,13 @@ function formatLinkParamsType(params: ParamEntry[]): string {
286
324
  /**
287
325
  * Format the searchParams type for a route entry.
288
326
  *
289
- * When a search-params.ts exists, we reference its inferred type via an import type.
327
+ * When a page.tsx exports searchParams, we reference its inferred type via an import type.
290
328
  * The import path is relative to `importBase` (the directory where the .d.ts will be
291
329
  * written). When importBase is undefined, falls back to a bare relative path.
292
330
  */
293
331
  function formatSearchParamsType(route: RouteEntry, importBase?: string): string {
294
- if (route.hasSearchParams && route.searchParamsAbsPath) {
295
- const absPath = route.searchParamsAbsPath.replace(/\.(ts|tsx)$/, '');
332
+ if (route.hasSearchParams && route.searchParamsPagePath) {
333
+ const absPath = route.searchParamsPagePath.replace(/\.(ts|tsx)$/, '');
296
334
  let importPath: string;
297
335
  if (importBase) {
298
336
  // Make the path relative to the output directory, converted to posix separators
@@ -300,10 +338,8 @@ function formatSearchParamsType(route: RouteEntry, importBase?: string): string
300
338
  } else {
301
339
  importPath = './' + posix.basename(absPath);
302
340
  }
303
- // Use (typeof import('...'))[' default'] instead of import('...').default
304
- // because with moduleResolution:"bundler", import('...').default is treated as
305
- // a namespace member access which doesn't work for default exports.
306
- return `(typeof import('${importPath}'))['default'] extends import('@timber-js/app/search-params').SearchParamsDefinition<infer T> ? T : never`;
341
+ // Extract the type from the named 'searchParams' export of the page module.
342
+ return `(typeof import('${importPath}'))['searchParams'] extends import('@timber-js/app/search-params').SearchParamsDefinition<infer T> ? T : never`;
307
343
  }
308
344
  return '{}';
309
345
  }
@@ -338,59 +374,83 @@ function formatUseQueryStatesOverloads(routes: RouteEntry[], importBase?: string
338
374
  }
339
375
 
340
376
  /**
341
- * Generate typed Link overloads.
377
+ * Build a TypeScript template literal pattern for a dynamic route.
378
+ * e.g. '/products/[id]' → '/products/${string}'
379
+ * '/blog/[...slug]' → '/blog/${string}'
380
+ * '/docs/[[...path]]' → '/docs/${string}' (also matches /docs)
381
+ * '/[org]/[repo]' → '/${string}/${string}'
382
+ */
383
+ function buildResolvedPattern(route: RouteEntry): string | null {
384
+ const parts = route.urlPath.split('/');
385
+ const templateParts = parts.map((part) => {
386
+ if (part.startsWith('[[...') && part.endsWith(']]')) {
387
+ // Optional catch-all — matches any trailing path
388
+ return '${string}';
389
+ }
390
+ if (part.startsWith('[...') && part.endsWith(']')) {
391
+ // Catch-all — matches one or more segments
392
+ return '${string}';
393
+ }
394
+ if (part.startsWith('[') && part.endsWith(']')) {
395
+ // Dynamic segment
396
+ return '${string}';
397
+ }
398
+ return part;
399
+ });
400
+ return templateParts.join('/');
401
+ }
402
+
403
+ /**
404
+ * Generate typed Link call signatures via LinkFunction interface merging.
342
405
  *
343
- * For each page route, we generate a Link function overload that:
344
- * - Constrains href to the route pattern
345
- * - Types the params prop based on dynamic segments
346
- * - Types the searchParams prop based on search-params.ts (if present)
406
+ * Each call signature uses DIRECT types (not conditional types) for
407
+ * segmentParams, preserving TypeScript's excess property checking.
408
+ * Interface merging is the only reliable way to add "overloads" via
409
+ * module augmentation function overloads can't be augmented.
347
410
  *
348
- * Routes without dynamic segments accept href as a literal string with no params.
349
- * Routes with dynamic segments require a params prop.
411
+ * The catch-all call signature (external protocols + computed strings)
412
+ * lives in link.tsx. See TIM-624.
350
413
  */
351
414
  function formatTypedLinkOverloads(routes: RouteEntry[], importBase?: string): string[] {
352
415
  const lines: string[] = [];
416
+ const baseProps =
417
+ "Omit<import('react').AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & { prefetch?: boolean; scroll?: boolean; preserveSearchParams?: true | string[]; onNavigate?: import('./client/link.js').OnNavigateHandler; children?: import('react').ReactNode }";
353
418
 
419
+ lines.push(' interface LinkFunction {');
354
420
  for (const route of routes) {
355
421
  const hasDynamicParams = route.params.length > 0;
356
- const paramsType = formatLinkParamsType(route.params);
422
+ const paramsProp = hasDynamicParams
423
+ ? `segmentParams: ${formatLinkParamsType(route.params, importBase)}`
424
+ : 'segmentParams?: never';
425
+
357
426
  const searchParamsType = route.hasSearchParams
358
427
  ? formatSearchParamsType(route, importBase)
359
428
  : null;
360
-
429
+ const searchParamsProp = searchParamsType
430
+ ? `searchParams?: { definition: SearchParamsDefinition<${searchParamsType}>; values: Partial<${searchParamsType}> }`
431
+ : 'searchParams?: never';
432
+
433
+ lines.push(` (props: ${baseProps} & {`);
434
+ lines.push(` href: '${route.urlPath}'`);
435
+ lines.push(` ${paramsProp}`);
436
+ lines.push(` ${searchParamsProp}`);
437
+ lines.push(` }): import('react').JSX.Element`);
438
+
439
+ // For dynamic routes, also emit a resolved-pattern signature.
440
+ // This accepts template literal hrefs like `/products/${id}` without
441
+ // segmentParams — the params are already interpolated into the URL.
361
442
  if (hasDynamicParams) {
362
- // Route with dynamic segments — params prop required
363
- const spProp = searchParamsType
364
- ? `searchParams?: { definition: SearchParamsDefinition<${searchParamsType}>; values: Partial<${searchParamsType}> }`
365
- : `searchParams?: never`;
366
- lines.push(
367
- ` export function Link(props: Omit<import('react').AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {`
368
- );
369
- lines.push(` href: '${route.urlPath}'`);
370
- lines.push(` params: ${paramsType}`);
371
- lines.push(` ${spProp}`);
372
- lines.push(` prefetch?: boolean; scroll?: boolean; children?: import('react').ReactNode`);
373
- lines.push(` }): import('react').JSX.Element`);
374
- } else {
375
- // Static route — no params needed
376
- const spProp = searchParamsType
377
- ? `searchParams?: { definition: SearchParamsDefinition<${searchParamsType}>; values: Partial<${searchParamsType}> }`
378
- : `searchParams?: never`;
379
- lines.push(
380
- ` export function Link(props: Omit<import('react').AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {`
381
- );
382
- lines.push(` href: '${route.urlPath}'`);
383
- lines.push(` params?: never`);
384
- lines.push(` ${spProp}`);
385
- lines.push(` prefetch?: boolean; scroll?: boolean; children?: import('react').ReactNode`);
386
- lines.push(` }): import('react').JSX.Element`);
443
+ const templatePattern = buildResolvedPattern(route);
444
+ if (templatePattern) {
445
+ lines.push(` (props: ${baseProps} & {`);
446
+ lines.push(` href: \`${templatePattern}\``);
447
+ lines.push(` segmentParams?: never`);
448
+ lines.push(` ${searchParamsProp}`);
449
+ lines.push(` }): import('react').JSX.Element`);
450
+ }
387
451
  }
388
452
  }
389
-
390
- // Fallback overload for arbitrary string hrefs (escape hatch)
391
- lines.push(
392
- ` export function Link(props: import('./client/link.js').LinkProps): import('react').JSX.Element`
393
- );
453
+ lines.push(' }');
394
454
 
395
455
  return lines;
396
456
  }
@@ -12,3 +12,5 @@ export type {
12
12
  export { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS } from './types.js';
13
13
  export { collectInterceptionRewrites } from './interception.js';
14
14
  export type { InterceptionRewrite } from './interception.js';
15
+ export { classifyUrlSegment } from './segment-classify.js';
16
+ export type { UrlSegment } from './segment-classify.js';
@@ -18,8 +18,9 @@ import type {
18
18
  ScannerConfig,
19
19
  InterceptionMarker,
20
20
  } from './types.js';
21
+ import { classifyUrlSegment } from './segment-classify.js';
21
22
  import { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS } from './types.js';
22
- import { classifyMetadataRoute, isDynamicMetadataExtension } from '#/server/metadata-routes.js';
23
+ import { classifyMetadataRoute, isDynamicMetadataExtension } from '../server/metadata-routes.js';
23
24
 
24
25
  /**
25
26
  * Pattern matching encoded path delimiters that must be rejected during route discovery.
@@ -53,7 +54,7 @@ const LEGACY_STATUS_FILES: Record<string, number> = {
53
54
  /**
54
55
  * File convention names that are always .ts/.tsx (never .mdx etc.)
55
56
  */
56
- const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', 'prerender', 'search-params']);
57
+ const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', 'params']);
57
58
 
58
59
  /**
59
60
  * Status-code file patterns:
@@ -83,6 +84,14 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
83
84
  tree.proxy = proxyFile;
84
85
  }
85
86
 
87
+ // Check for global-error.{tsx,ts,jsx,js} at app root.
88
+ // Tier 2 error page — renders standalone (no layouts) when no segment-level
89
+ // error file is found. See design/10-error-handling.md §"Tier 2".
90
+ const globalErrorFile = findPageExtFile(appDir, 'global-error', extSet);
91
+ if (globalErrorFile) {
92
+ tree.globalError = globalErrorFile;
93
+ }
94
+
86
95
  // Scan the root directory's files
87
96
  scanSegmentFiles(appDir, tree.root, extSet);
88
97
 
@@ -92,6 +101,10 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
92
101
  // Validate: detect route group collisions (different groups producing pages at the same URL)
93
102
  validateRouteGroupCollisions(tree.root);
94
103
 
104
+ // Validate: detect duplicate param names in nested dynamic segments
105
+ // e.g., /[id]/items/[id] — same param name in ancestor and descendant
106
+ validateDuplicateParamNames(tree.root);
107
+
95
108
  return tree;
96
109
  }
97
110
 
@@ -153,22 +166,12 @@ export function classifySegment(dirName: string): {
153
166
  return { type: 'group' };
154
167
  }
155
168
 
156
- // Optional catch-all: [[...name]]
157
- if (dirName.startsWith('[[...') && dirName.endsWith(']]')) {
158
- const paramName = dirName.slice(5, -2);
159
- return { type: 'optional-catch-all', paramName };
160
- }
161
-
162
- // Catch-all: [...name]
163
- if (dirName.startsWith('[...') && dirName.endsWith(']')) {
164
- const paramName = dirName.slice(4, -1);
165
- return { type: 'catch-all', paramName };
166
- }
167
-
168
- // Dynamic: [name]
169
- if (dirName.startsWith('[') && dirName.endsWith(']')) {
170
- const paramName = dirName.slice(1, -1);
171
- return { type: 'dynamic', paramName };
169
+ // Bracket-syntax segments: [param], [...param], [[...param]]
170
+ // Delegated to the shared character-based classifier. If you change
171
+ // bracket syntax, update segment-classify.ts — not here.
172
+ const urlSeg = classifyUrlSegment(dirName);
173
+ if (urlSeg.kind !== 'static') {
174
+ return { type: urlSeg.kind, paramName: urlSeg.name };
172
175
  }
173
176
 
174
177
  return { type: 'static' };
@@ -278,11 +281,8 @@ function scanSegmentFiles(dirPath: string, node: SegmentNode, extSet: Set<string
278
281
  case 'route':
279
282
  node.route = file;
280
283
  break;
281
- case 'prerender':
282
- node.prerender = file;
283
- break;
284
- case 'search-params':
285
- node.searchParams = file;
284
+ case 'params':
285
+ node.params = file;
286
286
  break;
287
287
  }
288
288
  continue;
@@ -482,6 +482,54 @@ function collectRoutableLeaves(
482
482
  }
483
483
  }
484
484
 
485
+ /**
486
+ * Validate that no route chain contains duplicate dynamic param names.
487
+ *
488
+ * Example violation:
489
+ * app/[id]/items/[id]/page.tsx — 'id' appears twice in the ancestor chain.
490
+ *
491
+ * Route groups are transparent — params accumulate through them.
492
+ * Slots are independent — duplicate detection does NOT cross slot boundaries.
493
+ *
494
+ * See design/07-routing.md §"Duplicate Param Name Detection"
495
+ */
496
+ function validateDuplicateParamNames(root: SegmentNode): void {
497
+ walkForDuplicateParams(root, new Map());
498
+ }
499
+
500
+ /**
501
+ * Recursively walk the segment tree, tracking seen param names → segment paths.
502
+ * Throws on the first duplicate found.
503
+ */
504
+ function walkForDuplicateParams(node: SegmentNode, seen: Map<string, string>): void {
505
+ // If this node introduces a param name, check for duplicates
506
+ if (node.paramName) {
507
+ const existing = seen.get(node.paramName);
508
+ if (existing) {
509
+ throw new Error(
510
+ `[timber] Duplicate param name '${node.paramName}' in route chain.\n` +
511
+ ` First defined at: ${existing}\n` +
512
+ ` Duplicate at: ${node.urlPath || '/'}\n` +
513
+ ` Rename one of the segments to avoid ambiguity.`
514
+ );
515
+ }
516
+ // Add to seen for descendants (use a new Map to avoid polluting siblings)
517
+ seen = new Map(seen);
518
+ seen.set(node.paramName, node.urlPath || '/');
519
+ }
520
+
521
+ // Recurse into children (they inherit the accumulated params)
522
+ for (const child of node.children) {
523
+ walkForDuplicateParams(child, seen);
524
+ }
525
+
526
+ // Slots are independent parallel routes — start fresh param tracking
527
+ // (a slot's params don't conflict with the main route's params)
528
+ for (const [, slotNode] of node.slots) {
529
+ walkForDuplicateParams(slotNode, new Map(seen));
530
+ }
531
+ }
532
+
485
533
  /**
486
534
  * Find a fixed-extension file (proxy.ts) in a directory.
487
535
  */
@@ -498,3 +546,25 @@ function findFixedFile(dirPath: string, name: string): RouteFile | undefined {
498
546
  }
499
547
  return undefined;
500
548
  }
549
+
550
+ /**
551
+ * Find a file using the configured page extensions (tsx, ts, jsx, js, mdx, etc.).
552
+ * Used for app-root conventions like global-error that aren't per-segment.
553
+ */
554
+ function findPageExtFile(
555
+ dirPath: string,
556
+ name: string,
557
+ extSet: Set<string>
558
+ ): RouteFile | undefined {
559
+ for (const ext of extSet) {
560
+ const fullPath = join(dirPath, `${name}.${ext}`);
561
+ try {
562
+ if (statSync(fullPath).isFile()) {
563
+ return { filePath: fullPath, extension: ext };
564
+ }
565
+ } catch {
566
+ // File doesn't exist
567
+ }
568
+ }
569
+ return undefined;
570
+ }