@timber-js/app 0.2.0-alpha.186 → 0.2.0-alpha.188

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 (331) hide show
  1. package/dist/_chunks/{actions-C-Rw9vPc.js → actions-35jnMdeJ.js} +4 -3
  2. package/dist/_chunks/{actions-C-Rw9vPc.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-mFweg276.js → als-slots-BEEIPKYm.js} +3 -4
  6. package/dist/_chunks/{als-slots-mFweg276.js.map → als-slots-BEEIPKYm.js.map} +1 -1
  7. package/dist/_chunks/{cache-api-Cd0VZ_Pd.js → cache-api-DjNrIWRR.js} +7 -13
  8. package/dist/_chunks/cache-api-DjNrIWRR.js.map +1 -0
  9. package/dist/_chunks/cli-check-CpmN7Nh-.js +256 -0
  10. package/dist/_chunks/cli-check-CpmN7Nh-.js.map +1 -0
  11. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js +298 -0
  12. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js.map +1 -0
  13. package/dist/_chunks/{cloudflare-Cs0uZXea.js → cloudflare-CGP6BZKO.js} +4 -3
  14. package/dist/_chunks/{cloudflare-Cs0uZXea.js.map → cloudflare-CGP6BZKO.js.map} +1 -1
  15. package/dist/_chunks/convention-lint-kXsgc_-7.js +784 -0
  16. package/dist/_chunks/convention-lint-kXsgc_-7.js.map +1 -0
  17. package/dist/_chunks/{error-boundary-DpYRI_I1.js → error-boundary-D-ODYX41.js} +25 -2
  18. package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -0
  19. package/dist/_chunks/file-cache-DmX7OqZP.js +454 -0
  20. package/dist/_chunks/file-cache-DmX7OqZP.js.map +1 -0
  21. package/dist/_chunks/{logger-N7e5auP0.js → logger-D8xJZXIN.js} +27 -40
  22. package/dist/_chunks/logger-D8xJZXIN.js.map +1 -0
  23. package/dist/_chunks/mdx-file-C005ay-P.js +25 -0
  24. package/dist/_chunks/mdx-file-C005ay-P.js.map +1 -0
  25. package/dist/_chunks/{plugin-context-DEGLSJs3.js → plugin-context-rCinWLiE.js} +7 -2
  26. package/dist/_chunks/{plugin-context-DEGLSJs3.js.map → plugin-context-rCinWLiE.js.map} +1 -1
  27. package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
  28. package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
  29. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js → resolve-schema-5ma5pp1b.js} +2 -2
  30. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js.map → resolve-schema-5ma5pp1b.js.map} +1 -1
  31. package/dist/_chunks/rsc-media-type-DRqE_lD_.js +46 -0
  32. package/dist/_chunks/rsc-media-type-DRqE_lD_.js.map +1 -0
  33. package/dist/_chunks/{cli-schema-sync-CKgHC2MB.js → scanner-C8b0Gcw3.js} +5 -298
  34. package/dist/_chunks/scanner-C8b0Gcw3.js.map +1 -0
  35. package/dist/_chunks/schema-bridge-Cc2Gngu1.js +199 -0
  36. package/dist/_chunks/schema-bridge-Cc2Gngu1.js.map +1 -0
  37. package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -1
  38. package/dist/_chunks/{param-value-C8TNYchQ.js → segment-context-CjOlyB8Y.js} +33 -2
  39. package/dist/_chunks/segment-context-CjOlyB8Y.js.map +1 -0
  40. package/dist/_chunks/segment-keys-BawYuNFO.js.map +1 -1
  41. package/dist/_chunks/{use-query-states-DFvWd-EA.js → use-query-states-BbU5Ge1V.js} +74 -26
  42. package/dist/_chunks/use-query-states-BbU5Ge1V.js.map +1 -0
  43. package/dist/_chunks/{navigation-root-B29qg0_T.js → use-segment-params-C4r4BD9T.js} +129 -5
  44. package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -0
  45. package/dist/_chunks/walkers-RzN6AFjr.js +141 -0
  46. package/dist/_chunks/walkers-RzN6AFjr.js.map +1 -0
  47. package/dist/adapters/cloudflare-dev.js +1 -1
  48. package/dist/adapters/cloudflare-kv-cache.js +1 -1
  49. package/dist/adapters/cloudflare.d.ts.map +1 -1
  50. package/dist/adapters/cloudflare.js +1 -1
  51. package/dist/adapters/compress-module.d.ts +12 -0
  52. package/dist/adapters/compress-module.d.ts.map +1 -1
  53. package/dist/adapters/nitro.js +54 -2
  54. package/dist/adapters/nitro.js.map +1 -1
  55. package/dist/cache/index.js +1 -1
  56. package/dist/cdn/cloudflare-purge.js +30 -0
  57. package/dist/cdn/cloudflare-purge.js.map +1 -0
  58. package/dist/cdn/fastly-purge.js +33 -0
  59. package/dist/cdn/fastly-purge.js.map +1 -0
  60. package/dist/cdn/index.js +94 -0
  61. package/dist/cdn/index.js.map +1 -0
  62. package/dist/cdn/workers-cache-purge.js +35 -0
  63. package/dist/cdn/workers-cache-purge.js.map +1 -0
  64. package/dist/cli-check.d.ts +153 -0
  65. package/dist/cli-check.d.ts.map +1 -0
  66. package/dist/cli.d.ts +34 -8
  67. package/dist/cli.d.ts.map +1 -1
  68. package/dist/cli.js +46 -21
  69. package/dist/cli.js.map +1 -1
  70. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  71. package/dist/client/browser-entry/index.d.ts +1 -1
  72. package/dist/client/browser-entry/index.d.ts.map +1 -1
  73. package/dist/client/error-boundary.d.ts +6 -0
  74. package/dist/client/error-boundary.d.ts.map +1 -1
  75. package/dist/client/error-boundary.js +1 -1
  76. package/dist/client/index.d.ts +1 -0
  77. package/dist/client/index.d.ts.map +1 -1
  78. package/dist/client/index.js +27 -33
  79. package/dist/client/index.js.map +1 -1
  80. package/dist/client/internal.js +33 -17
  81. package/dist/client/internal.js.map +1 -1
  82. package/dist/client/link.d.ts +1 -7
  83. package/dist/client/link.d.ts.map +1 -1
  84. package/dist/client/navigation-commit.d.ts +16 -0
  85. package/dist/client/navigation-commit.d.ts.map +1 -1
  86. package/dist/client/router-pipeline.d.ts.map +1 -1
  87. package/dist/client/router.d.ts.map +1 -1
  88. package/dist/client/rsc-fetch.d.ts +9 -1
  89. package/dist/client/rsc-fetch.d.ts.map +1 -1
  90. package/dist/client/segment-cache.d.ts +14 -0
  91. package/dist/client/segment-cache.d.ts.map +1 -1
  92. package/dist/client/use-query-states.d.ts +9 -3
  93. package/dist/client/use-query-states.d.ts.map +1 -1
  94. package/dist/codec.js +1 -1
  95. package/dist/cookies/define-cookie.d.ts.map +1 -1
  96. package/dist/cookies/index.js +2 -2
  97. package/dist/cookies/index.js.map +1 -1
  98. package/dist/index.d.ts +4 -1
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +142 -477
  101. package/dist/index.js.map +1 -1
  102. package/dist/params/index.js +1 -1
  103. package/dist/plugin-context.d.ts +15 -0
  104. package/dist/plugin-context.d.ts.map +1 -1
  105. package/dist/plugins/routing.d.ts +0 -9
  106. package/dist/plugins/routing.d.ts.map +1 -1
  107. package/dist/plugins/shims.d.ts.map +1 -1
  108. package/dist/plugins/static-build.d.ts +24 -0
  109. package/dist/plugins/static-build.d.ts.map +1 -1
  110. package/dist/routing/codegen-shared.d.ts +3 -44
  111. package/dist/routing/codegen-shared.d.ts.map +1 -1
  112. package/dist/routing/codegen-types.d.ts +10 -31
  113. package/dist/routing/codegen-types.d.ts.map +1 -1
  114. package/dist/routing/codegen-write.d.ts +51 -0
  115. package/dist/routing/codegen-write.d.ts.map +1 -0
  116. package/dist/routing/codegen.d.ts.map +1 -1
  117. package/dist/routing/convention-lint.d.ts +18 -4
  118. package/dist/routing/convention-lint.d.ts.map +1 -1
  119. package/dist/routing/export-detect.d.ts +16 -0
  120. package/dist/routing/export-detect.d.ts.map +1 -1
  121. package/dist/routing/index.js +3 -2
  122. package/dist/routing/link-codegen.d.ts +19 -4
  123. package/dist/routing/link-codegen.d.ts.map +1 -1
  124. package/dist/routing/manifest-codegen.d.ts +1 -7
  125. package/dist/routing/manifest-codegen.d.ts.map +1 -1
  126. package/dist/routing/segment-keys.d.ts +22 -0
  127. package/dist/routing/segment-keys.d.ts.map +1 -1
  128. package/dist/routing/types.d.ts +0 -6
  129. package/dist/routing/types.d.ts.map +1 -1
  130. package/dist/schema-bridge.d.ts +60 -9
  131. package/dist/schema-bridge.d.ts.map +1 -1
  132. package/dist/search-params/define.d.ts +62 -8
  133. package/dist/search-params/define.d.ts.map +1 -1
  134. package/dist/search-params/index.d.ts +0 -1
  135. package/dist/search-params/index.d.ts.map +1 -1
  136. package/dist/search-params/index.js +66 -29
  137. package/dist/search-params/index.js.map +1 -1
  138. package/dist/search-params/parse-total.d.ts +70 -0
  139. package/dist/search-params/parse-total.d.ts.map +1 -0
  140. package/dist/search-params/wrappers.d.ts +26 -3
  141. package/dist/search-params/wrappers.d.ts.map +1 -1
  142. package/dist/server/access-gate.d.ts +19 -8
  143. package/dist/server/access-gate.d.ts.map +1 -1
  144. package/dist/server/action-handler.d.ts.map +1 -1
  145. package/dist/server/als-registry.d.ts +16 -0
  146. package/dist/server/als-registry.d.ts.map +1 -1
  147. package/dist/server/chain-url-parts.d.ts +2 -3
  148. package/dist/server/chain-url-parts.d.ts.map +1 -1
  149. package/dist/server/compress.d.ts.map +1 -1
  150. package/dist/server/deny-boundary.d.ts +148 -15
  151. package/dist/server/deny-boundary.d.ts.map +1 -1
  152. package/dist/server/deny-renderer.d.ts +2 -2
  153. package/dist/server/deny-renderer.d.ts.map +1 -1
  154. package/dist/server/error-boundary-wrapper.d.ts +85 -15
  155. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  156. package/dist/server/index.d.ts +0 -1
  157. package/dist/server/index.d.ts.map +1 -1
  158. package/dist/server/index.js +3 -2
  159. package/dist/server/index.js.map +1 -1
  160. package/dist/server/internal.d.ts +3 -1
  161. package/dist/server/internal.d.ts.map +1 -1
  162. package/dist/server/internal.js +344 -237
  163. package/dist/server/internal.js.map +1 -1
  164. package/dist/server/metadata-collector.d.ts +52 -0
  165. package/dist/server/metadata-collector.d.ts.map +1 -0
  166. package/dist/server/param-coercion.d.ts +12 -5
  167. package/dist/server/param-coercion.d.ts.map +1 -1
  168. package/dist/server/pipeline-helpers.d.ts.map +1 -1
  169. package/dist/server/pipeline-outcome.d.ts.map +1 -1
  170. package/dist/server/pipeline-phases.d.ts.map +1 -1
  171. package/dist/server/primitives.d.ts +23 -0
  172. package/dist/server/primitives.d.ts.map +1 -1
  173. package/dist/server/route-element-builder.d.ts +1 -12
  174. package/dist/server/route-element-builder.d.ts.map +1 -1
  175. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -1
  176. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
  177. package/dist/server/rsc-entry/error-renderer.d.ts +1 -1
  178. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  179. package/dist/server/rsc-entry/helpers.d.ts +0 -7
  180. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  181. package/dist/server/rsc-entry/index.d.ts +0 -1
  182. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  183. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  184. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
  185. package/dist/server/rsc-entry/rsc-payload.d.ts +1 -3
  186. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  187. package/dist/server/rsc-entry/rsc-stream.d.ts +12 -0
  188. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  189. package/dist/server/rsc-entry/ssr-renderer.d.ts +0 -2
  190. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  191. package/dist/server/skippable-prefix.d.ts +3 -0
  192. package/dist/server/skippable-prefix.d.ts.map +1 -1
  193. package/dist/server/slot-resolver.d.ts +18 -19
  194. package/dist/server/slot-resolver.d.ts.map +1 -1
  195. package/dist/server/ssr-bridge-types.d.ts +11 -0
  196. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  197. package/dist/server/ssr-entry.d.ts +0 -1
  198. package/dist/server/ssr-entry.d.ts.map +1 -1
  199. package/dist/server/state-tree-diff.d.ts +9 -16
  200. package/dist/server/state-tree-diff.d.ts.map +1 -1
  201. package/dist/server/static-generator.d.ts.map +1 -1
  202. package/dist/server/status-code-resolver.d.ts +8 -1
  203. package/dist/server/status-code-resolver.d.ts.map +1 -1
  204. package/dist/server/tree-builder.d.ts +28 -43
  205. package/dist/server/tree-builder.d.ts.map +1 -1
  206. package/dist/server/types.d.ts +12 -7
  207. package/dist/server/types.d.ts.map +1 -1
  208. package/dist/server/utils/element-type.d.ts +40 -0
  209. package/dist/server/utils/element-type.d.ts.map +1 -0
  210. package/dist/shared/rsc-media-type.d.ts +40 -0
  211. package/dist/shared/rsc-media-type.d.ts.map +1 -0
  212. package/dist/shared/segment-info.d.ts +7 -0
  213. package/dist/shared/segment-info.d.ts.map +1 -1
  214. package/docs/api/30-api-server.mdx +1 -1
  215. package/docs/api/33-api-search-params.mdx +38 -16
  216. package/docs/api/35-api-typescript.mdx +3 -3
  217. package/docs/api/36-cli.mdx +34 -7
  218. package/docs/learn/00-introduction.mdx +1 -1
  219. package/docs/learn/02-pages-and-layouts.mdx +1 -1
  220. package/docs/learn/05-typed-params.mdx +8 -8
  221. package/docs/learn/07-typed-routes.mdx +12 -7
  222. package/docs/learn/11-error-handling.mdx +16 -0
  223. package/docs/more/01-advanced-routing.mdx +1 -1
  224. package/docs/more/03-coming-from-nextjs.mdx +2 -2
  225. package/docs/more/50-ai-agent-instructions.mdx +6 -4
  226. package/package.json +8 -5
  227. package/src/adapters/cloudflare.ts +4 -1
  228. package/src/adapters/compress-module.ts +79 -1
  229. package/src/cli-check.ts +458 -0
  230. package/src/cli.ts +59 -24
  231. package/src/client/browser-entry/action-dispatch.ts +2 -1
  232. package/src/client/browser-entry/index.ts +0 -5
  233. package/src/client/error-boundary.tsx +65 -1
  234. package/src/client/index.ts +14 -3
  235. package/src/client/link.tsx +65 -64
  236. package/src/client/navigation-commit.ts +27 -4
  237. package/src/client/params-context.ts +4 -4
  238. package/src/client/router-pipeline.ts +4 -0
  239. package/src/client/router.ts +1 -0
  240. package/src/client/rsc-fetch.ts +14 -4
  241. package/src/client/segment-cache.ts +26 -5
  242. package/src/client/use-query-states.ts +102 -39
  243. package/src/cookies/define-cookie.ts +6 -1
  244. package/src/index.ts +20 -3
  245. package/src/plugin-context.ts +26 -0
  246. package/src/plugins/routing.ts +84 -146
  247. package/src/plugins/shims.ts +0 -1
  248. package/src/plugins/static-build.ts +78 -24
  249. package/src/routing/codegen-shared.ts +3 -79
  250. package/src/routing/codegen-types.ts +10 -31
  251. package/src/routing/codegen-write.ts +139 -0
  252. package/src/routing/codegen.ts +56 -182
  253. package/src/routing/convention-lint.ts +139 -40
  254. package/src/routing/export-detect.ts +151 -7
  255. package/src/routing/link-codegen.ts +32 -65
  256. package/src/routing/manifest-codegen.ts +1 -59
  257. package/src/routing/scanner.ts +3 -3
  258. package/src/routing/segment-keys.ts +37 -0
  259. package/src/routing/types.ts +0 -6
  260. package/src/schema-bridge.ts +180 -58
  261. package/src/search-params/define.ts +102 -37
  262. package/src/search-params/index.ts +0 -1
  263. package/src/search-params/parse-total.ts +78 -0
  264. package/src/search-params/wrappers.ts +60 -11
  265. package/src/server/access-gate.tsx +61 -68
  266. package/src/server/action-handler.ts +1 -4
  267. package/src/server/als-registry.ts +16 -0
  268. package/src/server/chain-url-parts.ts +2 -3
  269. package/src/server/compress.ts +9 -1
  270. package/src/server/deny-boundary.ts +269 -41
  271. package/src/server/deny-renderer.ts +32 -21
  272. package/src/server/error-boundary-wrapper.ts +166 -79
  273. package/src/server/index.ts +1 -3
  274. package/src/server/internal.ts +2 -2
  275. package/src/server/metadata-collector.ts +115 -0
  276. package/src/server/param-coercion.ts +13 -61
  277. package/src/server/pipeline-helpers.ts +2 -2
  278. package/src/server/pipeline-outcome.ts +2 -1
  279. package/src/server/pipeline-phases.ts +9 -9
  280. package/src/server/primitives.ts +25 -0
  281. package/src/server/route-element-builder.ts +169 -194
  282. package/src/server/rsc-cache-key-guard.ts +2 -8
  283. package/src/server/rsc-entry/deny-fallback.ts +3 -2
  284. package/src/server/rsc-entry/error-renderer.ts +31 -11
  285. package/src/server/rsc-entry/helpers.ts +3 -12
  286. package/src/server/rsc-entry/index.ts +0 -5
  287. package/src/server/rsc-entry/render-route.ts +14 -11
  288. package/src/server/rsc-entry/revalidate-renderer.ts +2 -1
  289. package/src/server/rsc-entry/rsc-payload.ts +104 -20
  290. package/src/server/rsc-entry/rsc-stream.ts +25 -2
  291. package/src/server/rsc-entry/ssr-renderer.ts +28 -16
  292. package/src/server/skippable-prefix.ts +21 -39
  293. package/src/server/slot-resolver.ts +69 -189
  294. package/src/server/ssr-bridge-types.ts +12 -0
  295. package/src/server/ssr-entry.ts +8 -6
  296. package/src/server/state-tree-diff.ts +11 -62
  297. package/src/server/static-generator.ts +3 -2
  298. package/src/server/status-code-resolver.ts +28 -11
  299. package/src/server/tree-builder.ts +35 -228
  300. package/src/server/types.ts +12 -7
  301. package/src/server/utils/element-type.ts +72 -0
  302. package/src/shared/rsc-media-type.ts +43 -0
  303. package/src/shared/segment-info.ts +7 -0
  304. package/dist/_chunks/cache-api-Cd0VZ_Pd.js.map +0 -1
  305. package/dist/_chunks/cli-schema-sync-CKgHC2MB.js.map +0 -1
  306. package/dist/_chunks/error-boundary-DpYRI_I1.js.map +0 -1
  307. package/dist/_chunks/logger-N7e5auP0.js.map +0 -1
  308. package/dist/_chunks/navigation-root-B29qg0_T.js.map +0 -1
  309. package/dist/_chunks/param-value-C8TNYchQ.js.map +0 -1
  310. package/dist/_chunks/registry-DbJPKoBp.js +0 -20
  311. package/dist/_chunks/registry-DbJPKoBp.js.map +0 -1
  312. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +0 -119
  313. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +0 -1
  314. package/dist/_chunks/segment-context-ZDnXDkbz.js +0 -34
  315. package/dist/_chunks/segment-context-ZDnXDkbz.js.map +0 -1
  316. package/dist/_chunks/use-query-states-DFvWd-EA.js.map +0 -1
  317. package/dist/_chunks/use-segment-params-ClyUNq4d.js +0 -128
  318. package/dist/_chunks/use-segment-params-ClyUNq4d.js.map +0 -1
  319. package/dist/_chunks/walkers-BhhwI9TD.js +0 -936
  320. package/dist/_chunks/walkers-BhhwI9TD.js.map +0 -1
  321. package/dist/search-params/registry.d.ts +0 -20
  322. package/dist/search-params/registry.d.ts.map +0 -1
  323. package/dist/segment-params/define.d.ts +0 -83
  324. package/dist/segment-params/define.d.ts.map +0 -1
  325. package/dist/segment-params/index.d.ts +0 -3
  326. package/dist/segment-params/index.d.ts.map +0 -1
  327. package/dist/segment-params/index.js +0 -70
  328. package/dist/segment-params/index.js.map +0 -1
  329. package/src/search-params/registry.ts +0 -31
  330. package/src/segment-params/define.ts +0 -226
  331. package/src/segment-params/index.ts +0 -9
@@ -20,7 +20,13 @@ interface AstNode {
20
20
  exportKind?: string;
21
21
  }>;
22
22
  id?: { name: string };
23
- declarations?: Array<{ id?: { name: string } }>;
23
+ declarations?: Array<{ id?: { name: string }; init?: AstNode }>;
24
+ /** Set on re-exports: `export { X } from './y'`. Absent on local exports. */
25
+ source?: { value?: string } | null;
26
+ /** Set on runtime-transparent wrappers: `X as T`, `X satisfies T`, `(X)`, `X!`. */
27
+ expression?: AstNode;
28
+ /** Set on `Identifier` nodes. */
29
+ name?: string;
24
30
  }
25
31
 
26
32
  interface ProgramNode {
@@ -71,19 +77,41 @@ function collectNamedExports(program: ProgramNode): Set<string> {
71
77
  return names;
72
78
  }
73
79
 
80
+ /**
81
+ * The specifier exporting a *runtime* default from this statement, if any.
82
+ *
83
+ * Type-only exports erase, so they are not default exports at runtime — and
84
+ * TypeScript spells that two ways, on two different nodes: `export type { X as
85
+ * default }` marks the **statement**, `export { type X as default }` marks the
86
+ * **specifier**. Both have to be checked, or a type alias reads as a component:
87
+ * a status file whose only default is a type has nothing for the error boundary
88
+ * to receive (the renderer's `mod?.default` skips it), so treating it as one
89
+ * would fail a build over a file that cannot break anything.
90
+ *
91
+ * One implementation because two callers must agree on what "has a default
92
+ * export" means: `hasDefaultExport` decides whether to warn that a page has
93
+ * none, and `fileDefaultExportIsLocalValue` decides whether to fail the build.
94
+ */
95
+ function defaultSpecifier(stmt: AstNode): NonNullable<AstNode['specifiers']>[number] | null {
96
+ if (stmt.type !== 'ExportNamedDeclaration' || !stmt.specifiers) return null;
97
+ if (stmt.exportKind === 'type') return null;
98
+ for (const spec of stmt.specifiers) {
99
+ if (spec.exportKind === 'type') continue;
100
+ if (spec.exported?.name === 'default') return spec;
101
+ }
102
+ return null;
103
+ }
104
+
74
105
  /**
75
106
  * Check whether a program has a default export.
76
107
  * Handles: `export default ...`, `export { X as default }`,
77
- * `export { default } from '...'`.
108
+ * `export { default } from '...'`. Type-only defaults do not count —
109
+ * see `defaultSpecifier`.
78
110
  */
79
111
  function hasDefaultExport(program: ProgramNode): boolean {
80
112
  for (const stmt of program.body) {
81
113
  if (stmt.type === 'ExportDefaultDeclaration') return true;
82
- if (stmt.type === 'ExportNamedDeclaration' && stmt.specifiers) {
83
- for (const spec of stmt.specifiers) {
84
- if (spec.exported?.name === 'default') return true;
85
- }
86
- }
114
+ if (defaultSpecifier(stmt)) return true;
87
115
  }
88
116
  return false;
89
117
  }
@@ -152,6 +180,122 @@ export function fileHasDefaultExport(filePath: string): boolean {
152
180
  }
153
181
  }
154
182
 
183
+ /** Node types whose value is unambiguously constructed by this module. */
184
+ const FUNCTION_LIKE = new Set([
185
+ 'FunctionDeclaration',
186
+ 'FunctionExpression',
187
+ 'ArrowFunctionExpression',
188
+ 'ClassDeclaration',
189
+ 'ClassExpression',
190
+ ]);
191
+
192
+ /**
193
+ * Expression wrappers that erase at runtime and so cannot change where a value
194
+ * was constructed: `X as T`, `X satisfies T`, `<T>X`, `X!`, `X<T>`, `(X)`.
195
+ */
196
+ const TRANSPARENT_WRAPPERS = new Set([
197
+ 'TSAsExpression',
198
+ 'TSSatisfiesExpression',
199
+ 'TSTypeAssertion',
200
+ 'TSNonNullExpression',
201
+ 'TSInstantiationExpression',
202
+ 'ParenthesizedExpression',
203
+ ]);
204
+
205
+ /**
206
+ * Strip runtime-transparent wrappers so the node underneath can be classified.
207
+ *
208
+ * Without this, `(() => <h1 />) satisfies React.FC` reads as a
209
+ * `TSSatisfiesExpression` rather than the arrow function it compiles to, and a
210
+ * provably-local component is misread as one whose origin cannot be
211
+ * determined — turning a build error into a warning.
212
+ */
213
+ function unwrapTransparent(node: AstNode): AstNode {
214
+ let current = node;
215
+ while (TRANSPARENT_WRAPPERS.has(current.type) && current.expression) {
216
+ current = current.expression;
217
+ }
218
+ return current;
219
+ }
220
+
221
+ /**
222
+ * Whether `name` is bound at module top level to a function or class written
223
+ * in this file. An imported binding can never match: imports are
224
+ * `ImportDeclaration` specifiers, not function/class/variable declarations,
225
+ * and a module-level name cannot be both.
226
+ */
227
+ function bindsLocalFunction(program: ProgramNode, name: string): boolean {
228
+ for (const stmt of program.body) {
229
+ // `export function X() {}` binds X locally too — unwrap the export.
230
+ const decl = stmt.type === 'ExportNamedDeclaration' ? stmt.declaration : stmt;
231
+ if (!decl) continue;
232
+ if (
233
+ (decl.type === 'FunctionDeclaration' || decl.type === 'ClassDeclaration') &&
234
+ decl.id?.name === name
235
+ ) {
236
+ return true;
237
+ }
238
+ if (decl.type === 'VariableDeclaration') {
239
+ for (const d of decl.declarations ?? []) {
240
+ if (d.id?.name === name && d.init && FUNCTION_LIKE.has(unwrapTransparent(d.init).type)) {
241
+ return true;
242
+ }
243
+ }
244
+ }
245
+ }
246
+ return false;
247
+ }
248
+
249
+ /**
250
+ * Whether the default export is *provably* a value constructed by this module:
251
+ * `export default function/class/() => {}`, or a name bound to a function or
252
+ * class declared here — whether it leaves via `export default Name` or
253
+ * `export { Name as default }`. Both spellings are the same fact about where
254
+ * the value was built, so both must answer the same way.
255
+ *
256
+ * This is the sound half of "is this a server component?". A file with no
257
+ * `'use client'` directive whose default export is built here is a server
258
+ * component, full stop. Everything else — `export { default } from
259
+ * './client-thing'`, `export default Imported`, `export default memo(X)`,
260
+ * an unparseable file — returns false, because the exported value may have
261
+ * been minted in a module that *does* carry the directive. Callers must not
262
+ * infer "server component" from a missing directive alone.
263
+ */
264
+ export function fileDefaultExportIsLocalValue(filePath: string): boolean {
265
+ if (!existsSync(filePath)) return false;
266
+ try {
267
+ const source = readFileCached(filePath);
268
+ const program = tryParse(source);
269
+ if (!program) return false;
270
+ for (const stmt of program.body) {
271
+ if (stmt.type === 'ExportDefaultDeclaration') {
272
+ const decl = stmt.declaration && unwrapTransparent(stmt.declaration);
273
+ if (!decl) return false;
274
+ if (FUNCTION_LIKE.has(decl.type)) return true;
275
+ if (decl.type === 'Identifier' && decl.name) {
276
+ return bindsLocalFunction(program, decl.name);
277
+ }
278
+ return false;
279
+ }
280
+
281
+ // `export { Name as default }` — the same default export by another
282
+ // spelling. `hasDefaultExport` already counts it, so an analysis that
283
+ // skipped it here would let the exact defect this powers slip through
284
+ // as a warning.
285
+ const spec = defaultSpecifier(stmt);
286
+ if (spec) {
287
+ // `export { X as default } from './client-thing'` re-exports another
288
+ // module's value — the directive governing it lives over there.
289
+ if (stmt.source) return false;
290
+ return spec.local?.name ? bindsLocalFunction(program, spec.local.name) : false;
291
+ }
292
+ }
293
+ return false;
294
+ } catch {
295
+ return false;
296
+ }
297
+ }
298
+
155
299
  /**
156
300
  * Check if a file has any `export * from '...'` declarations.
157
301
  * Returns false if the file doesn't exist or can't be parsed.
@@ -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];
@@ -190,58 +184,6 @@ export function generateManifestModule(tree: RouteTree, viteRoot: string): strin
190
184
  return code;
191
185
  }
192
186
 
193
- // ── Search-params registry ──────────────────────────────────────────────
194
-
195
- /**
196
- * Walk the route tree and collect every page that exports a
197
- * `searchParams` definition, then emit a module that statically imports
198
- * each export and registers it into the shared search-params registry.
199
- */
200
- export function generateSearchParamsRegistryModule(tree: RouteTree): string {
201
- const entries: Array<{ urlPath: string; filePath: string }> = [];
202
-
203
- function walk(node: SegmentNode): void {
204
- if (node.page) {
205
- if (node.params && fileHasSearchParamsExport(node.params.filePath)) {
206
- entries.push({ urlPath: node.urlPath, filePath: node.params.filePath });
207
- } else if (fileHasSearchParamsExport(node.page.filePath)) {
208
- entries.push({ urlPath: node.urlPath, filePath: node.page.filePath });
209
- }
210
- }
211
- for (const child of node.children) walk(child);
212
- for (const slot of Object.values(node.slots)) walk(slot);
213
- }
214
- walk(tree.root);
215
-
216
- entries.sort((a, b) => a.urlPath.localeCompare(b.urlPath));
217
-
218
- const lines: string[] = [];
219
- lines.push('// Auto-generated search-params registry — do not edit.');
220
- lines.push('// Generated by timber-routing plugin (TIM-830).');
221
- lines.push('');
222
- lines.push("import { registerSearchParams } from '@timber-js/app/search-params';");
223
- lines.push('');
224
-
225
- entries.forEach((entry, i) => {
226
- lines.push(`import { searchParams as r${i} } from ${JSON.stringify(entry.filePath)};`);
227
- });
228
- lines.push('');
229
-
230
- entries.forEach((entry, i) => {
231
- lines.push(`registerSearchParams(${JSON.stringify(entry.urlPath)}, r${i});`);
232
- });
233
- lines.push('');
234
-
235
- lines.push('export {};');
236
- lines.push('');
237
-
238
- return lines.join('\n');
239
- }
240
-
241
- function fileHasSearchParamsExport(filePath: string): boolean {
242
- return fileHasExport(filePath, 'searchParams');
243
- }
244
-
245
187
  // ── Schema module ───────────────────────────────────────────────────────
246
188
 
247
189
  /**
@@ -35,7 +35,7 @@ const PAGE_EXT_CONVENTIONS = new Set(['page', 'layout', 'error', 'default', 'den
35
35
  /**
36
36
  * File convention names that are always .ts/.tsx (never .mdx etc.)
37
37
  */
38
- const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', 'params']);
38
+ const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route']);
39
39
 
40
40
  /**
41
41
  * Status-code file patterns:
@@ -184,12 +184,12 @@ function scanSegmentFiles(dirPath: string, node: SegmentNode, extSet: Set<string
184
184
  continue;
185
185
  }
186
186
 
187
- // Fixed conventions (middleware, access, route, params) — only
187
+ // Fixed conventions (middleware, access, route) — only
188
188
  // .ts/.tsx/.js/.jsx, never pageExtensions like .mdx. The regex is
189
189
  // anchored: mts/cts/mjs/cjs (and stray tail matches like `.foots`)
190
190
  // are NOT recognized. See design/07-routing.md §"Page Extensions".
191
191
  if (FIXED_CONVENTIONS.has(name) && /^[jt]sx?$/.test(ext)) {
192
- const key = name as 'middleware' | 'access' | 'route' | 'params';
192
+ const key = name as 'middleware' | 'access' | 'route';
193
193
  const existing = node[key];
194
194
  if (existing) {
195
195
  throwDuplicateConvention(name, existing.filePath, fullPath);
@@ -144,3 +144,40 @@ export function computeSlotKey(parentSegmentId: string, slotName: string): strin
144
144
  const prefix = parentSegmentId === '/' ? '' : parentSegmentId;
145
145
  return `${prefix}/${name}`;
146
146
  }
147
+
148
+ /**
149
+ * Compute a content key for a parallel route slot.
150
+ *
151
+ * The content key encodes everything that determines the slot's rendered
152
+ * output for a given navigation: the slot key (which includes the owning
153
+ * segment's identity and the slot name), the URL parts consumed by the
154
+ * owning segment (which determine parent params the slot page might
155
+ * read), the matched page file (or a sentinel for `default.tsx`), and
156
+ * the slot's own extracted params.
157
+ *
158
+ * The slot key prevents cross-group collisions: two route groups at the
159
+ * same URL level each owning a `@sidebar` slot produce different keys
160
+ * even when both fall back to `default.tsx`.
161
+ *
162
+ * The key is opaque to the client — it stores whatever the server sent
163
+ * and advertises it back. The server computes the destination key and
164
+ * checks membership. This eliminates the need for the server to
165
+ * reconstruct the client's state from a departing URL.
166
+ *
167
+ * See design/07-routing.md §"Segment Tree Diffing on Navigation"
168
+ */
169
+ export function computeSlotContentKey(
170
+ slotKey: string,
171
+ ownerParts: string[],
172
+ entryFile: string | null,
173
+ slotParams: Record<string, string | string[]>
174
+ ): string {
175
+ const owner = ownerParts.join('/');
176
+ const entry = entryFile ?? '\x01';
177
+ const paramKeys = Object.keys(slotParams).sort();
178
+ const paramParts = paramKeys.map((k) => {
179
+ const v = slotParams[k];
180
+ return Array.isArray(v) ? `${k}=${v.join('\x02')}` : `${k}=${v}`;
181
+ });
182
+ return [slotKey, owner, entry, ...paramParts].join('\0');
183
+ }
@@ -96,12 +96,6 @@ export interface SegmentNode<TFile = RouteFile> {
96
96
  middleware?: TFile;
97
97
  access?: TFile;
98
98
  route?: TFile;
99
- /**
100
- * params.ts — isomorphic convention file exporting segmentParams and/or searchParams.
101
- * Discovered by the scanner like middleware.ts and access.ts.
102
- * See design/07-routing.md §"params.ts Convention File"
103
- */
104
- params?: TFile;
105
99
  error?: TFile;
106
100
  default?: TFile;
107
101
  /** Status-code files: 4xx.tsx, 5xx.tsx, {status}.tsx (component format) */