@timber-js/app 0.2.0-alpha.185 → 0.2.0-alpha.187

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (570) hide show
  1. package/dist/_chunks/{actions-O_LsyCE4.js → actions-35jnMdeJ.js} +4 -3
  2. package/dist/_chunks/{actions-O_LsyCE4.js.map → actions-35jnMdeJ.js.map} +1 -1
  3. package/dist/_chunks/als-registry-C6kcfprT.js +41 -0
  4. package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -0
  5. package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
  6. package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
  7. package/dist/_chunks/base-path-DaQrzbez.js +80 -0
  8. package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
  9. package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
  10. package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
  11. package/dist/_chunks/build-output-helper-C3DrfzZR.js +369 -0
  12. package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +1 -0
  13. package/dist/_chunks/{cache-api-B-lhk9p4.js → cache-api-DjNrIWRR.js} +8 -14
  14. package/dist/_chunks/cache-api-DjNrIWRR.js.map +1 -0
  15. package/dist/_chunks/cli-check-CpmN7Nh-.js +256 -0
  16. package/dist/_chunks/cli-check-CpmN7Nh-.js.map +1 -0
  17. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js +298 -0
  18. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js.map +1 -0
  19. package/dist/_chunks/{cloudflare-CnT5Lr7U.js → cloudflare-CGP6BZKO.js} +92 -14
  20. package/dist/_chunks/{cloudflare-CnT5Lr7U.js.map → cloudflare-CGP6BZKO.js.map} +1 -1
  21. package/dist/_chunks/convention-lint-kXsgc_-7.js +784 -0
  22. package/dist/_chunks/convention-lint-kXsgc_-7.js.map +1 -0
  23. package/dist/_chunks/error-boundary-D-ODYX41.js +353 -0
  24. package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -0
  25. package/dist/_chunks/{fast-hash-D6hIVt1Y.js → fast-hash-C-tVYrLb.js} +6 -1
  26. package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
  27. package/dist/_chunks/file-cache-DmX7OqZP.js +454 -0
  28. package/dist/_chunks/file-cache-DmX7OqZP.js.map +1 -0
  29. package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
  30. package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
  31. package/dist/_chunks/{logger-AWfuX-KJ.js → logger-D8xJZXIN.js} +34 -51
  32. package/dist/_chunks/logger-D8xJZXIN.js.map +1 -0
  33. package/dist/_chunks/mdx-file-C005ay-P.js +25 -0
  34. package/dist/_chunks/mdx-file-C005ay-P.js.map +1 -0
  35. package/dist/_chunks/{plugin-context---kTF5v8.js → plugin-context-rCinWLiE.js} +8 -2
  36. package/dist/_chunks/plugin-context-rCinWLiE.js.map +1 -0
  37. package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
  38. package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
  39. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js → resolve-schema-5ma5pp1b.js} +2 -2
  40. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js.map → resolve-schema-5ma5pp1b.js.map} +1 -1
  41. package/dist/_chunks/{router-ref-CtmF-aPv.js → router-ref-DuYuV_0Q.js} +2 -2
  42. package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -0
  43. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js +243 -0
  44. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js.map +1 -0
  45. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js +40 -0
  46. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js.map +1 -0
  47. package/dist/_chunks/rsc-media-type-DRqE_lD_.js +46 -0
  48. package/dist/_chunks/rsc-media-type-DRqE_lD_.js.map +1 -0
  49. package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
  50. package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
  51. package/dist/_chunks/scanner-C8b0Gcw3.js +1564 -0
  52. package/dist/_chunks/scanner-C8b0Gcw3.js.map +1 -0
  53. package/dist/_chunks/schema-bridge-Cc2Gngu1.js +199 -0
  54. package/dist/_chunks/schema-bridge-Cc2Gngu1.js.map +1 -0
  55. package/dist/_chunks/{segment-classify-Byy425ng.js → segment-classify-C539Pa2O.js} +23 -2
  56. package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
  57. package/dist/_chunks/segment-context-CjOlyB8Y.js +97 -0
  58. package/dist/_chunks/segment-context-CjOlyB8Y.js.map +1 -0
  59. package/dist/_chunks/{canonicalize-DQHyFClh.js → segment-keys-BawYuNFO.js} +61 -2
  60. package/dist/_chunks/segment-keys-BawYuNFO.js.map +1 -0
  61. package/dist/_chunks/slot-params-BCTmZkQB.js +76 -0
  62. package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -0
  63. package/dist/_chunks/{ssr-data-BOWsq18U.js → ssr-data-14MXm7Pj.js} +17 -2
  64. package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -0
  65. package/dist/_chunks/{use-query-states-DFvWd-EA.js → use-query-states-BbU5Ge1V.js} +74 -26
  66. package/dist/_chunks/use-query-states-BbU5Ge1V.js.map +1 -0
  67. package/dist/_chunks/use-segment-params-C4r4BD9T.js +398 -0
  68. package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -0
  69. package/dist/_chunks/walkers-RzN6AFjr.js +141 -0
  70. package/dist/_chunks/walkers-RzN6AFjr.js.map +1 -0
  71. package/dist/adapters/build-output-helper.d.ts +37 -0
  72. package/dist/adapters/build-output-helper.d.ts.map +1 -1
  73. package/dist/adapters/cloudflare-dev.js +1 -1
  74. package/dist/adapters/cloudflare-kv-cache.js +1 -1
  75. package/dist/adapters/cloudflare.d.ts.map +1 -1
  76. package/dist/adapters/cloudflare.js +1 -1
  77. package/dist/adapters/compress-module.d.ts +12 -0
  78. package/dist/adapters/compress-module.d.ts.map +1 -1
  79. package/dist/adapters/fs-identity.d.ts +64 -0
  80. package/dist/adapters/fs-identity.d.ts.map +1 -0
  81. package/dist/adapters/nitro.d.ts.map +1 -1
  82. package/dist/adapters/nitro.js +56 -5
  83. package/dist/adapters/nitro.js.map +1 -1
  84. package/dist/adapters/shared.d.ts +57 -1
  85. package/dist/adapters/shared.d.ts.map +1 -1
  86. package/dist/adapters/types.d.ts +13 -1
  87. package/dist/adapters/types.d.ts.map +1 -1
  88. package/dist/cache/fast-hash.d.ts +5 -0
  89. package/dist/cache/fast-hash.d.ts.map +1 -1
  90. package/dist/cache/index.js +1 -1
  91. package/dist/cdn/cloudflare-purge.js +30 -0
  92. package/dist/cdn/cloudflare-purge.js.map +1 -0
  93. package/dist/cdn/fastly-purge.js +33 -0
  94. package/dist/cdn/fastly-purge.js.map +1 -0
  95. package/dist/cdn/index.js +94 -0
  96. package/dist/cdn/index.js.map +1 -0
  97. package/dist/cdn/workers-cache-purge.js +35 -0
  98. package/dist/cdn/workers-cache-purge.js.map +1 -0
  99. package/dist/cli-check.d.ts +153 -0
  100. package/dist/cli-check.d.ts.map +1 -0
  101. package/dist/cli.d.ts +34 -8
  102. package/dist/cli.d.ts.map +1 -1
  103. package/dist/cli.js +46 -21
  104. package/dist/cli.js.map +1 -1
  105. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  106. package/dist/client/browser-entry/hydrate.d.ts +20 -9
  107. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  108. package/dist/client/browser-entry/index.d.ts +1 -1
  109. package/dist/client/browser-entry/index.d.ts.map +1 -1
  110. package/dist/client/browser-entry/post-hydration.d.ts +4 -1
  111. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
  112. package/dist/client/browser-entry/router-init.d.ts +3 -0
  113. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  114. package/dist/client/browser-entry/rsc-stream.d.ts +8 -0
  115. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -1
  116. package/dist/client/error-boundary.d.ts +7 -0
  117. package/dist/client/error-boundary.d.ts.map +1 -1
  118. package/dist/client/error-boundary.js +1 -162
  119. package/dist/client/history.d.ts +13 -6
  120. package/dist/client/history.d.ts.map +1 -1
  121. package/dist/client/index.d.ts +1 -0
  122. package/dist/client/index.d.ts.map +1 -1
  123. package/dist/client/index.js +42 -41
  124. package/dist/client/index.js.map +1 -1
  125. package/dist/client/internal.d.ts +4 -3
  126. package/dist/client/internal.d.ts.map +1 -1
  127. package/dist/client/internal.js +877 -311
  128. package/dist/client/internal.js.map +1 -1
  129. package/dist/client/link.d.ts +1 -7
  130. package/dist/client/link.d.ts.map +1 -1
  131. package/dist/client/navigation-api.d.ts +2 -2
  132. package/dist/client/navigation-commit.d.ts +87 -0
  133. package/dist/client/navigation-commit.d.ts.map +1 -0
  134. package/dist/client/navigation-context.d.ts +37 -20
  135. package/dist/client/navigation-context.d.ts.map +1 -1
  136. package/dist/client/navigation-root.d.ts +63 -23
  137. package/dist/client/navigation-root.d.ts.map +1 -1
  138. package/dist/client/params-context.d.ts +81 -0
  139. package/dist/client/params-context.d.ts.map +1 -0
  140. package/dist/client/router-effects.d.ts +129 -0
  141. package/dist/client/router-effects.d.ts.map +1 -0
  142. package/dist/client/router-lifecycle.d.ts +55 -0
  143. package/dist/client/router-lifecycle.d.ts.map +1 -0
  144. package/dist/client/router-pipeline.d.ts +84 -0
  145. package/dist/client/router-pipeline.d.ts.map +1 -0
  146. package/dist/client/router-ref.d.ts +1 -1
  147. package/dist/client/router-ref.d.ts.map +1 -1
  148. package/dist/client/router-skew.d.ts +21 -0
  149. package/dist/client/router-skew.d.ts.map +1 -0
  150. package/dist/client/router-types.d.ts +207 -0
  151. package/dist/client/router-types.d.ts.map +1 -0
  152. package/dist/client/router.d.ts +1 -182
  153. package/dist/client/router.d.ts.map +1 -1
  154. package/dist/client/rsc-fetch.d.ts +47 -26
  155. package/dist/client/rsc-fetch.d.ts.map +1 -1
  156. package/dist/client/segment-cache.d.ts +87 -34
  157. package/dist/client/segment-cache.d.ts.map +1 -1
  158. package/dist/client/ssr-data.d.ts +6 -0
  159. package/dist/client/ssr-data.d.ts.map +1 -1
  160. package/dist/client/stale-client.d.ts +69 -0
  161. package/dist/client/stale-client.d.ts.map +1 -0
  162. package/dist/client/state.d.ts +10 -1
  163. package/dist/client/state.d.ts.map +1 -1
  164. package/dist/client/top-loader.d.ts +2 -1
  165. package/dist/client/top-loader.d.ts.map +1 -1
  166. package/dist/client/unload-guard.d.ts +5 -0
  167. package/dist/client/unload-guard.d.ts.map +1 -1
  168. package/dist/client/use-cookie.d.ts.map +1 -1
  169. package/dist/client/use-query-states.d.ts +9 -3
  170. package/dist/client/use-query-states.d.ts.map +1 -1
  171. package/dist/client/use-router.d.ts +1 -1
  172. package/dist/client/use-segment-params.d.ts +18 -8
  173. package/dist/client/use-segment-params.d.ts.map +1 -1
  174. package/dist/codec.js +1 -1
  175. package/dist/cookies/define-cookie.d.ts.map +1 -1
  176. package/dist/cookies/index.js +5 -5
  177. package/dist/cookies/index.js.map +1 -1
  178. package/dist/index.d.ts +4 -1
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js +1009 -759
  181. package/dist/index.js.map +1 -1
  182. package/dist/params/index.js +1 -1
  183. package/dist/plugin-context.d.ts +46 -0
  184. package/dist/plugin-context.d.ts.map +1 -1
  185. package/dist/plugins/adapter-build.d.ts.map +1 -1
  186. package/dist/plugins/build-manifest.d.ts +1 -1
  187. package/dist/plugins/build-manifest.d.ts.map +1 -1
  188. package/dist/plugins/entries.d.ts.map +1 -1
  189. package/dist/plugins/fonts.d.ts.map +1 -1
  190. package/dist/plugins/request-dep/analysis.d.ts +106 -0
  191. package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
  192. package/dist/plugins/request-dep/index.d.ts +75 -0
  193. package/dist/plugins/request-dep/index.d.ts.map +1 -0
  194. package/dist/plugins/request-dep/origin.d.ts +61 -0
  195. package/dist/plugins/request-dep/origin.d.ts.map +1 -0
  196. package/dist/plugins/routing.d.ts.map +1 -1
  197. package/dist/plugins/shims.d.ts.map +1 -1
  198. package/dist/plugins/static-build.d.ts +160 -8
  199. package/dist/plugins/static-build.d.ts.map +1 -1
  200. package/dist/routing/codegen-shared.d.ts +3 -44
  201. package/dist/routing/codegen-shared.d.ts.map +1 -1
  202. package/dist/routing/codegen-types.d.ts +28 -31
  203. package/dist/routing/codegen-types.d.ts.map +1 -1
  204. package/dist/routing/codegen-write.d.ts +51 -0
  205. package/dist/routing/codegen-write.d.ts.map +1 -0
  206. package/dist/routing/codegen.d.ts.map +1 -1
  207. package/dist/routing/collision-probe.d.ts +104 -0
  208. package/dist/routing/collision-probe.d.ts.map +1 -0
  209. package/dist/routing/collision-spaces.d.ts +26 -0
  210. package/dist/routing/collision-spaces.d.ts.map +1 -0
  211. package/dist/routing/convention-lint.d.ts +18 -4
  212. package/dist/routing/convention-lint.d.ts.map +1 -1
  213. package/dist/routing/export-detect.d.ts +16 -0
  214. package/dist/routing/export-detect.d.ts.map +1 -1
  215. package/dist/routing/index.js +4 -3
  216. package/dist/routing/interception.d.ts +235 -6
  217. package/dist/routing/interception.d.ts.map +1 -1
  218. package/dist/routing/link-codegen.d.ts +19 -4
  219. package/dist/routing/link-codegen.d.ts.map +1 -1
  220. package/dist/routing/manifest-codegen.d.ts +1 -7
  221. package/dist/routing/manifest-codegen.d.ts.map +1 -1
  222. package/dist/routing/scanner.d.ts.map +1 -1
  223. package/dist/routing/segment-classify.d.ts +33 -0
  224. package/dist/routing/segment-classify.d.ts.map +1 -1
  225. package/dist/routing/segment-keys.d.ts +95 -0
  226. package/dist/routing/segment-keys.d.ts.map +1 -0
  227. package/dist/routing/slot-placement.d.ts +48 -0
  228. package/dist/routing/slot-placement.d.ts.map +1 -0
  229. package/dist/routing/types.d.ts +0 -6
  230. package/dist/routing/types.d.ts.map +1 -1
  231. package/dist/routing/walkers.d.ts +6 -0
  232. package/dist/routing/walkers.d.ts.map +1 -1
  233. package/dist/schema-bridge.d.ts +60 -9
  234. package/dist/schema-bridge.d.ts.map +1 -1
  235. package/dist/search-params/define.d.ts +62 -14
  236. package/dist/search-params/define.d.ts.map +1 -1
  237. package/dist/search-params/index.d.ts +0 -1
  238. package/dist/search-params/index.d.ts.map +1 -1
  239. package/dist/search-params/index.js +221 -10
  240. package/dist/search-params/index.js.map +1 -1
  241. package/dist/search-params/parse-total.d.ts +70 -0
  242. package/dist/search-params/parse-total.d.ts.map +1 -0
  243. package/dist/search-params/wrappers.d.ts +26 -3
  244. package/dist/search-params/wrappers.d.ts.map +1 -1
  245. package/dist/server/access-gate.d.ts +19 -8
  246. package/dist/server/access-gate.d.ts.map +1 -1
  247. package/dist/server/action-handler.d.ts.map +1 -1
  248. package/dist/server/actions.d.ts +6 -3
  249. package/dist/server/actions.d.ts.map +1 -1
  250. package/dist/server/als-registry.d.ts +18 -1
  251. package/dist/server/als-registry.d.ts.map +1 -1
  252. package/dist/server/build-manifest.d.ts +13 -1
  253. package/dist/server/build-manifest.d.ts.map +1 -1
  254. package/dist/server/chain-url-parts.d.ts +82 -0
  255. package/dist/server/chain-url-parts.d.ts.map +1 -0
  256. package/dist/server/children-interception.d.ts +49 -0
  257. package/dist/server/children-interception.d.ts.map +1 -0
  258. package/dist/server/compress.d.ts.map +1 -1
  259. package/dist/server/default-status-page.d.ts +45 -0
  260. package/dist/server/default-status-page.d.ts.map +1 -0
  261. package/dist/server/deny-boundary.d.ts +148 -15
  262. package/dist/server/deny-boundary.d.ts.map +1 -1
  263. package/dist/server/deny-renderer.d.ts +15 -4
  264. package/dist/server/deny-renderer.d.ts.map +1 -1
  265. package/dist/server/error-boundary-wrapper.d.ts +85 -15
  266. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  267. package/dist/server/head-response.d.ts +35 -0
  268. package/dist/server/head-response.d.ts.map +1 -0
  269. package/dist/server/index.d.ts +0 -1
  270. package/dist/server/index.d.ts.map +1 -1
  271. package/dist/server/index.js +3 -2
  272. package/dist/server/index.js.map +1 -1
  273. package/dist/server/internal.d.ts +3 -1
  274. package/dist/server/internal.d.ts.map +1 -1
  275. package/dist/server/internal.js +712 -418
  276. package/dist/server/internal.js.map +1 -1
  277. package/dist/server/metadata-collector.d.ts +52 -0
  278. package/dist/server/metadata-collector.d.ts.map +1 -0
  279. package/dist/server/param-coercion.d.ts +22 -6
  280. package/dist/server/param-coercion.d.ts.map +1 -1
  281. package/dist/server/pipeline-helpers.d.ts +0 -18
  282. package/dist/server/pipeline-helpers.d.ts.map +1 -1
  283. package/dist/server/pipeline-interception.d.ts +59 -9
  284. package/dist/server/pipeline-interception.d.ts.map +1 -1
  285. package/dist/server/pipeline-outcome.d.ts.map +1 -1
  286. package/dist/server/pipeline-phases.d.ts.map +1 -1
  287. package/dist/server/pipeline.d.ts +11 -0
  288. package/dist/server/pipeline.d.ts.map +1 -1
  289. package/dist/server/primitives.d.ts +23 -0
  290. package/dist/server/primitives.d.ts.map +1 -1
  291. package/dist/server/publish-params.d.ts +33 -0
  292. package/dist/server/publish-params.d.ts.map +1 -0
  293. package/dist/server/request-context.d.ts +48 -0
  294. package/dist/server/request-context.d.ts.map +1 -1
  295. package/dist/server/route-element-builder.d.ts +22 -3
  296. package/dist/server/route-element-builder.d.ts.map +1 -1
  297. package/dist/server/route-handler.d.ts.map +1 -1
  298. package/dist/server/route-matcher.d.ts +13 -0
  299. package/dist/server/route-matcher.d.ts.map +1 -1
  300. package/dist/server/rsc-cache-key-guard.d.ts +78 -0
  301. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
  302. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  303. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
  304. package/dist/server/rsc-entry/error-renderer.d.ts +15 -3
  305. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  306. package/dist/server/rsc-entry/helpers.d.ts +2 -17
  307. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  308. package/dist/server/rsc-entry/index.d.ts +0 -1
  309. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  310. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  311. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
  312. package/dist/server/rsc-entry/rsc-payload.d.ts +1 -2
  313. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  314. package/dist/server/rsc-entry/rsc-stream.d.ts +15 -2
  315. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  316. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  317. package/dist/server/skippable-prefix.d.ts +23 -0
  318. package/dist/server/skippable-prefix.d.ts.map +1 -0
  319. package/dist/server/slot-interception.d.ts +80 -0
  320. package/dist/server/slot-interception.d.ts.map +1 -0
  321. package/dist/server/slot-resolver.d.ts +70 -8
  322. package/dist/server/slot-resolver.d.ts.map +1 -1
  323. package/dist/server/ssr-bridge-types.d.ts +17 -0
  324. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  325. package/dist/server/ssr-entry.d.ts +0 -1
  326. package/dist/server/ssr-entry.d.ts.map +1 -1
  327. package/dist/server/ssr-wrappers.d.ts +24 -13
  328. package/dist/server/ssr-wrappers.d.ts.map +1 -1
  329. package/dist/server/state-tree-diff.d.ts +6 -27
  330. package/dist/server/state-tree-diff.d.ts.map +1 -1
  331. package/dist/server/static-generator.d.ts +6 -0
  332. package/dist/server/static-generator.d.ts.map +1 -1
  333. package/dist/server/static-not-found.d.ts +52 -0
  334. package/dist/server/static-not-found.d.ts.map +1 -0
  335. package/dist/server/status-code-resolver.d.ts +8 -1
  336. package/dist/server/status-code-resolver.d.ts.map +1 -1
  337. package/dist/server/tree-builder.d.ts +28 -36
  338. package/dist/server/tree-builder.d.ts.map +1 -1
  339. package/dist/server/types.d.ts +12 -7
  340. package/dist/server/types.d.ts.map +1 -1
  341. package/dist/server/utils/element-type.d.ts +40 -0
  342. package/dist/server/utils/element-type.d.ts.map +1 -0
  343. package/dist/shared/als-slots.d.ts +41 -0
  344. package/dist/shared/als-slots.d.ts.map +1 -0
  345. package/dist/shared/base-path.d.ts +56 -0
  346. package/dist/shared/base-path.d.ts.map +1 -0
  347. package/dist/shared/param-value.d.ts +80 -0
  348. package/dist/shared/param-value.d.ts.map +1 -0
  349. package/dist/shared/payload-root.d.ts +108 -0
  350. package/dist/shared/payload-root.d.ts.map +1 -0
  351. package/dist/shared/rsc-cache-key.d.ts +163 -0
  352. package/dist/shared/rsc-cache-key.d.ts.map +1 -0
  353. package/dist/shared/rsc-error-envelope.d.ts +25 -0
  354. package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
  355. package/dist/shared/rsc-manifest.d.ts +28 -0
  356. package/dist/shared/rsc-manifest.d.ts.map +1 -0
  357. package/dist/shared/rsc-media-type.d.ts +40 -0
  358. package/dist/shared/rsc-media-type.d.ts.map +1 -0
  359. package/dist/shared/rsc-payload-path.d.ts +42 -0
  360. package/dist/shared/rsc-payload-path.d.ts.map +1 -0
  361. package/dist/shared/segment-info.d.ts +59 -0
  362. package/dist/shared/segment-info.d.ts.map +1 -0
  363. package/dist/shared/slot-params.d.ts +51 -0
  364. package/dist/shared/slot-params.d.ts.map +1 -0
  365. package/dist/shared/static-platform-files.d.ts +71 -0
  366. package/dist/shared/static-platform-files.d.ts.map +1 -0
  367. package/docs/api/30-api-server.mdx +1 -1
  368. package/docs/api/31-api-client.mdx +4 -2
  369. package/docs/api/33-api-search-params.mdx +38 -16
  370. package/docs/api/35-api-typescript.mdx +3 -3
  371. package/docs/api/36-cli.mdx +34 -7
  372. package/docs/learn/00-introduction.mdx +1 -1
  373. package/docs/learn/02-pages-and-layouts.mdx +2 -2
  374. package/docs/learn/05-typed-params.mdx +8 -8
  375. package/docs/learn/07-typed-routes.mdx +12 -7
  376. package/docs/learn/11-error-handling.mdx +18 -0
  377. package/docs/learn/12-client-navigation.mdx +2 -2
  378. package/docs/learn/14-deploying.mdx +23 -0
  379. package/docs/more/01-advanced-routing.mdx +173 -3
  380. package/docs/more/03-coming-from-nextjs.mdx +2 -2
  381. package/docs/more/04-metadata-and-fonts.mdx +1 -1
  382. package/docs/more/50-ai-agent-instructions.mdx +6 -4
  383. package/package.json +9 -6
  384. package/src/adapters/build-output-helper.ts +116 -3
  385. package/src/adapters/cloudflare.ts +90 -12
  386. package/src/adapters/compress-module.ts +79 -1
  387. package/src/adapters/fs-identity.ts +156 -0
  388. package/src/adapters/nitro.ts +6 -6
  389. package/src/adapters/shared.ts +196 -21
  390. package/src/adapters/types.ts +13 -1
  391. package/src/cache/fast-hash.ts +5 -0
  392. package/src/cli-check.ts +458 -0
  393. package/src/cli.ts +59 -24
  394. package/src/client/browser-entry/action-dispatch.ts +11 -5
  395. package/src/client/browser-entry/hydrate.ts +40 -29
  396. package/src/client/browser-entry/index.ts +15 -6
  397. package/src/client/browser-entry/post-hydration.ts +10 -9
  398. package/src/client/browser-entry/router-init.ts +104 -48
  399. package/src/client/browser-entry/rsc-stream.ts +11 -2
  400. package/src/client/error-boundary.tsx +85 -16
  401. package/src/client/history.ts +13 -6
  402. package/src/client/index.ts +14 -3
  403. package/src/client/internal.ts +4 -3
  404. package/src/client/link.tsx +120 -72
  405. package/src/client/navigation-api.ts +3 -3
  406. package/src/client/navigation-commit.ts +197 -0
  407. package/src/client/navigation-context.ts +40 -67
  408. package/src/client/navigation-root.tsx +326 -101
  409. package/src/client/params-context.ts +192 -0
  410. package/src/client/router-effects.ts +231 -0
  411. package/src/client/router-lifecycle.ts +288 -0
  412. package/src/client/router-pipeline.ts +393 -0
  413. package/src/client/router-ref.ts +1 -1
  414. package/src/client/router-skew.ts +30 -0
  415. package/src/client/router-types.ts +230 -0
  416. package/src/client/router.ts +243 -707
  417. package/src/client/rsc-fetch.ts +183 -106
  418. package/src/client/segment-cache.ts +129 -44
  419. package/src/client/ssr-data.ts +6 -0
  420. package/src/client/stale-client.ts +191 -0
  421. package/src/client/state.ts +14 -1
  422. package/src/client/top-loader.tsx +2 -1
  423. package/src/client/unload-guard.ts +34 -2
  424. package/src/client/use-cookie.ts +9 -2
  425. package/src/client/use-query-states.ts +102 -39
  426. package/src/client/use-router.ts +1 -1
  427. package/src/client/use-segment-params.ts +41 -18
  428. package/src/cookies/define-cookie.ts +6 -1
  429. package/src/index.ts +25 -4
  430. package/src/plugin-context.ts +58 -0
  431. package/src/plugins/adapter-build.ts +4 -0
  432. package/src/plugins/build-manifest.ts +34 -13
  433. package/src/plugins/entries.ts +4 -0
  434. package/src/plugins/fonts.ts +11 -8
  435. package/src/plugins/request-dep/analysis.ts +447 -0
  436. package/src/plugins/request-dep/index.ts +376 -0
  437. package/src/plugins/request-dep/origin.ts +310 -0
  438. package/src/plugins/routing.ts +97 -102
  439. package/src/plugins/shims.ts +0 -1
  440. package/src/plugins/static-build.ts +391 -95
  441. package/src/routing/codegen-shared.ts +3 -79
  442. package/src/routing/codegen-types.ts +28 -31
  443. package/src/routing/codegen-write.ts +139 -0
  444. package/src/routing/codegen.ts +86 -172
  445. package/src/routing/collision-probe.ts +438 -0
  446. package/src/routing/collision-spaces.ts +281 -0
  447. package/src/routing/convention-lint.ts +139 -40
  448. package/src/routing/export-detect.ts +151 -7
  449. package/src/routing/interception.ts +896 -50
  450. package/src/routing/link-codegen.ts +32 -65
  451. package/src/routing/manifest-codegen.ts +6 -62
  452. package/src/routing/scanner.ts +117 -92
  453. package/src/routing/segment-classify.ts +57 -0
  454. package/src/routing/segment-keys.ts +146 -0
  455. package/src/routing/slot-placement.ts +97 -0
  456. package/src/routing/types.ts +0 -6
  457. package/src/routing/walkers.ts +8 -0
  458. package/src/schema-bridge.ts +180 -58
  459. package/src/search-params/define.ts +108 -66
  460. package/src/search-params/index.ts +0 -1
  461. package/src/search-params/parse-total.ts +78 -0
  462. package/src/search-params/wrappers.ts +60 -11
  463. package/src/server/access-gate.tsx +60 -40
  464. package/src/server/action-handler.ts +4 -5
  465. package/src/server/actions.ts +6 -3
  466. package/src/server/als-registry.ts +18 -1
  467. package/src/server/build-manifest.ts +14 -1
  468. package/src/server/chain-url-parts.ts +163 -0
  469. package/src/server/children-interception.ts +115 -0
  470. package/src/server/compress.ts +9 -1
  471. package/src/server/default-status-page.ts +127 -0
  472. package/src/server/deny-boundary.ts +269 -41
  473. package/src/server/deny-renderer.ts +111 -39
  474. package/src/server/error-boundary-wrapper.ts +166 -79
  475. package/src/server/head-response.ts +54 -0
  476. package/src/server/index.ts +1 -3
  477. package/src/server/internal.ts +2 -2
  478. package/src/server/metadata-collector.ts +115 -0
  479. package/src/server/param-coercion.ts +51 -69
  480. package/src/server/pipeline-helpers.ts +2 -47
  481. package/src/server/pipeline-interception.ts +81 -32
  482. package/src/server/pipeline-outcome.ts +4 -5
  483. package/src/server/pipeline-phases.ts +77 -25
  484. package/src/server/pipeline.ts +57 -10
  485. package/src/server/prebuilt-runtime.ts +4 -4
  486. package/src/server/primitives.ts +25 -0
  487. package/src/server/publish-params.ts +42 -0
  488. package/src/server/request-context.ts +97 -18
  489. package/src/server/route-element-builder.ts +241 -253
  490. package/src/server/route-handler.ts +8 -8
  491. package/src/server/route-matcher.ts +21 -9
  492. package/src/server/rsc-cache-key-guard.ts +164 -0
  493. package/src/server/rsc-entry/api-handler.ts +6 -8
  494. package/src/server/rsc-entry/deny-fallback.ts +3 -2
  495. package/src/server/rsc-entry/error-renderer.ts +94 -35
  496. package/src/server/rsc-entry/helpers.ts +33 -28
  497. package/src/server/rsc-entry/index.ts +36 -33
  498. package/src/server/rsc-entry/render-route.ts +18 -10
  499. package/src/server/rsc-entry/revalidate-renderer.ts +3 -2
  500. package/src/server/rsc-entry/rsc-payload.ts +113 -40
  501. package/src/server/rsc-entry/rsc-stream.ts +29 -5
  502. package/src/server/rsc-entry/ssr-renderer.ts +38 -22
  503. package/src/server/skippable-prefix.ts +92 -0
  504. package/src/server/slot-interception.ts +168 -0
  505. package/src/server/slot-resolver.ts +263 -158
  506. package/src/server/ssr-bridge-types.ts +18 -0
  507. package/src/server/ssr-entry.ts +20 -10
  508. package/src/server/ssr-wrappers.tsx +33 -32
  509. package/src/server/state-tree-diff.ts +14 -55
  510. package/src/server/static-generator.ts +68 -29
  511. package/src/server/static-not-found.ts +134 -0
  512. package/src/server/status-code-resolver.ts +28 -11
  513. package/src/server/tree-builder.ts +35 -218
  514. package/src/server/types.ts +12 -7
  515. package/src/server/utils/element-type.ts +72 -0
  516. package/src/shared/als-slots.ts +72 -0
  517. package/src/shared/base-path.ts +80 -0
  518. package/src/shared/param-value.ts +244 -0
  519. package/src/shared/payload-root.ts +151 -0
  520. package/src/shared/rsc-cache-key.ts +269 -0
  521. package/src/shared/rsc-error-envelope.ts +31 -0
  522. package/src/shared/rsc-manifest.ts +29 -0
  523. package/src/shared/rsc-media-type.ts +43 -0
  524. package/src/shared/rsc-payload-path.ts +45 -0
  525. package/src/shared/segment-info.ts +60 -0
  526. package/src/shared/slot-params.ts +111 -0
  527. package/src/shared/static-platform-files.ts +75 -0
  528. package/dist/_chunks/build-output-helper-DOGYFb_X.js +0 -196
  529. package/dist/_chunks/build-output-helper-DOGYFb_X.js.map +0 -1
  530. package/dist/_chunks/cache-api-B-lhk9p4.js.map +0 -1
  531. package/dist/_chunks/canonicalize-DQHyFClh.js.map +0 -1
  532. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js +0 -668
  533. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js.map +0 -1
  534. package/dist/_chunks/define-COtkxMRT.js +0 -191
  535. package/dist/_chunks/define-COtkxMRT.js.map +0 -1
  536. package/dist/_chunks/define-c4au4I9R.js +0 -82
  537. package/dist/_chunks/define-c4au4I9R.js.map +0 -1
  538. package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +0 -1
  539. package/dist/_chunks/logger-AWfuX-KJ.js.map +0 -1
  540. package/dist/_chunks/navigation-root-bUDZLw74.js +0 -124
  541. package/dist/_chunks/navigation-root-bUDZLw74.js.map +0 -1
  542. package/dist/_chunks/plugin-context---kTF5v8.js.map +0 -1
  543. package/dist/_chunks/registry-DbJPKoBp.js +0 -20
  544. package/dist/_chunks/registry-DbJPKoBp.js.map +0 -1
  545. package/dist/_chunks/router-ref-CtmF-aPv.js.map +0 -1
  546. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +0 -119
  547. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +0 -1
  548. package/dist/_chunks/segment-classify-Byy425ng.js.map +0 -1
  549. package/dist/_chunks/segment-context-ZDnXDkbz.js +0 -34
  550. package/dist/_chunks/segment-context-ZDnXDkbz.js.map +0 -1
  551. package/dist/_chunks/ssr-data-BOWsq18U.js.map +0 -1
  552. package/dist/_chunks/use-query-states-DFvWd-EA.js.map +0 -1
  553. package/dist/_chunks/use-segment-params-D1CzlgBo.js +0 -151
  554. package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +0 -1
  555. package/dist/_chunks/walkers-_6zKFlch.js +0 -1002
  556. package/dist/_chunks/walkers-_6zKFlch.js.map +0 -1
  557. package/dist/client/error-boundary.js.map +0 -1
  558. package/dist/plugins/request-dep.d.ts +0 -32
  559. package/dist/plugins/request-dep.d.ts.map +0 -1
  560. package/dist/search-params/registry.d.ts +0 -20
  561. package/dist/search-params/registry.d.ts.map +0 -1
  562. package/dist/segment-params/define.d.ts +0 -89
  563. package/dist/segment-params/define.d.ts.map +0 -1
  564. package/dist/segment-params/index.d.ts +0 -3
  565. package/dist/segment-params/index.d.ts.map +0 -1
  566. package/dist/segment-params/index.js +0 -2
  567. package/src/plugins/request-dep.ts +0 -499
  568. package/src/search-params/registry.ts +0 -31
  569. package/src/segment-params/define.ts +0 -249
  570. package/src/segment-params/index.ts +0 -9
@@ -5,8 +5,17 @@
5
5
  * This module is the single source of truth for:
6
6
  * - StandardSchemaV1 interface (subset of the Standard Schema spec)
7
7
  * - validateSync() helper
8
- * - fromSchema() — bridge from Standard Schema to Codec<T>
9
- * - fromArraySchema() — bridge for array-valued codecs
8
+ * - fromSchema() — search-param bridge; scalar shape first, array second
9
+ * - fromArraySchema() — same loop, array shape first
10
+ * - fromCookieSchema() — scalar shape only; a cookie has no array shape
11
+ * - fromParamSchema() — route params; throws on failure (invalid param → 404)
12
+ *
13
+ * One parse loop, four candidate orders. Which shapes a bridge offers, and
14
+ * in what order, is the ONLY thing that differs — see §"Shape tolerance"
15
+ * below and in design/23-search-params.md. `serialize` is deliberately NOT
16
+ * shared: `null` means "omit the key" for a search param and "delete the
17
+ * cookie" for a cookie, so unifying it silently changed what
18
+ * `cookie.set([])` did (TIM-1352).
10
19
  *
11
20
  * These are re-exported from @timber-js/app/search-params, @timber-js/app/segment-params,
12
21
  * and @timber-js/app/cookies for convenience. The canonical import is
@@ -55,27 +64,56 @@ export declare function fromParamSchema<T>(fieldName: string, schema: StandardSc
55
64
  * @param fieldName - used in error messages
56
65
  * @param value - the codec or schema to resolve
57
66
  * @param mode - 'param' uses fromParamSchema (throws on parse failure),
58
- * 'search' uses fromSchema (falls back to default on failure)
67
+ * 'search' uses fromSchema (falls back to default on failure,
68
+ * tolerant of the repeated-key array shape),
69
+ * 'cookie' uses fromCookieSchema (same, minus the array shape,
70
+ * which a cookie value cannot have)
59
71
  */
60
- export declare function resolveCodecOrSchema(fieldName: string, value: unknown, mode?: 'param' | 'search'): Codec<unknown>;
72
+ export declare function resolveCodecOrSchema(fieldName: string, value: unknown, mode?: 'param' | 'search' | 'cookie'): Codec<unknown>;
61
73
  /**
62
74
  * Bridge a Standard Schema-compatible schema (Zod, Valibot, ArkType) to a
63
75
  * Codec<T>.
64
76
  *
65
- * Parse: coerces the raw string through the schema. On validation failure,
66
- * parses `undefined` to get the schema's default value (the schema should have
67
- * a `.default()` call). If that also fails, returns `undefined`.
77
+ * Parse: coerces the raw URL value through the schema, trying the scalar
78
+ * shape and then the array shape (see `scalarFirst`), so an array schema
79
+ * works bare: `z.array(z.string()).default([])` yields `[]` when absent,
80
+ * `['a']` for `?tags=a`, and `['a','b']` for `?tags=a&tags=b`. When no
81
+ * shape validates, parses `undefined` to get the schema's default (the
82
+ * schema should have a `.default()` call). If that also fails, returns
83
+ * `undefined`.
84
+ *
85
+ * Serialize: `String()` for primitives, `null` for null/undefined. Note
86
+ * that `String(['a','b'])` is `'a,b'` — the same string `fromArraySchema`
87
+ * writes — so a bare array schema round-trips exactly as design/09
88
+ * §"Array params" describes.
68
89
  *
69
- * Serialize: uses `String()` for primitives, `null` for null/undefined.
90
+ * This is the SEARCH-PARAM bridge. Cookies use `fromCookieSchema`; a
91
+ * cookie has no array shape (see below).
70
92
  *
71
93
  * ```ts
72
- * import { fromSchema } from '@timber-js/app/codec'
73
94
  * import { z } from 'zod/v4'
74
95
  *
75
96
  * const pageCodec = fromSchema(z.coerce.number().int().min(1).default(1))
97
+ * const tagsCodec = fromSchema(z.array(z.string()).default([]))
76
98
  * ```
77
99
  */
78
100
  export declare function fromSchema<T>(schema: StandardSchemaV1<T>): Codec<T>;
101
+ /**
102
+ * Bridge a Standard Schema for a COOKIE value.
103
+ *
104
+ * Identical to `fromSchema` minus the array shape, because a cookie cannot
105
+ * carry one: `Cookie:` headers and `document.cookie` yield a single string
106
+ * per name, and there is no repeated-key concept to be tolerant of. Sharing
107
+ * the search-param bridge here meant a cookie written by this very codec —
108
+ * `serialize(['a','b'])` → `a,b` — read back as the one-element array
109
+ * `['a,b']` instead of failing to its default: no repeated key in sight,
110
+ * just a delimiter reinterpreted as data.
111
+ *
112
+ * The `serialize` contract also differs by domain and must not be unified:
113
+ * for a search param `null` means "omit the key", for a cookie it means
114
+ * **delete the cookie** (design/29-cookies.md).
115
+ */
116
+ export declare function fromCookieSchema<T>(schema: StandardSchemaV1<T>): Codec<T>;
79
117
  /**
80
118
  * Bridge a Standard Schema for array values. Handles both single strings
81
119
  * and repeated query keys (`?tag=a&tag=b`).
@@ -86,6 +124,19 @@ export declare function fromSchema<T>(schema: StandardSchemaV1<T>): Codec<T>;
86
124
  *
87
125
  * const tagsCodec = fromArraySchema(z.array(z.string()).default([]))
88
126
  * ```
127
+ *
128
+ * Since TIM-1352 a bare array schema works through `fromSchema` too, so
129
+ * this is no longer required to make an array field parse. Two cases still
130
+ * want it, both listed in design/23 §"Shape tolerance":
131
+ *
132
+ * 1. A **permissive** schema meant as an array — one that accepts a string
133
+ * as readily as an array (`z.any()`, a hand-written coercing validator)
134
+ * — where scalar-first ordering would settle on the scalar shape.
135
+ * 2. An array schema wrapped in `.catch([])`, which swallows the failure
136
+ * that would otherwise trigger the array attempt.
137
+ *
138
+ * It also serializes an empty array to `null` (omitting the key) where
139
+ * `fromSchema` writes `''`.
89
140
  */
90
141
  export declare function fromArraySchema<T>(schema: StandardSchemaV1<T>): Codec<T>;
91
142
  //# sourceMappingURL=schema-bridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-bridge.d.ts","sourceRoot":"","sources":["../src/schema-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAUxC,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB,CAAC,MAAM,GAAG,OAAO;IAChD,WAAW,EAAE;QACX,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;KAChG,CAAC;CACH;AAED,MAAM,MAAM,oBAAoB,CAAC,MAAM,IACnC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,GACrC;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AAMtE;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EACjC,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAChC,KAAK,EAAE,OAAO,GACb,oBAAoB,CAAC,MAAM,CAAC,CAQ9B;AAMD,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAO1E;AAED,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAO/D;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAgB3F;AAMD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,OAAO,GAAG,QAAmB,GAClC,KAAK,CAAC,OAAO,CAAC,CAYhB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAmCnE;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAmCxE"}
1
+ {"version":3,"file":"schema-bridge.d.ts","sourceRoot":"","sources":["../src/schema-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAUxC,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB,CAAC,MAAM,GAAG,OAAO;IAChD,WAAW,EAAE;QACX,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;KAChG,CAAC;CACH;AAED,MAAM,MAAM,oBAAoB,CAAC,MAAM,IACnC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,GACrC;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AAMtE;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EACjC,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAChC,KAAK,EAAE,OAAO,GACb,oBAAoB,CAAC,MAAM,CAAC,CAQ9B;AAMD,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAO1E;AAED,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAO/D;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAgB3F;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,OAAO,GAAG,QAAQ,GAAG,QAAmB,GAC7C,KAAK,CAAC,OAAO,CAAC,CAYhB;AA0GD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAWnE;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAWzE;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAcxE"}
@@ -11,22 +11,46 @@
11
11
  */
12
12
  import type { StandardSchemaV1 } from '../schema-bridge.js';
13
13
  import type { Codec } from '../codec.js';
14
- /**
15
- * Register the getSearchParams function. Called once at module load time
16
- * from request-context.ts to avoid dynamic import at call time.
17
- * @internal
18
- */
19
- export declare function _setGetSearchParamsFn(fn: () => URLSearchParams): void;
20
14
  /**
21
15
  * A codec that converts between URL string values and typed values.
22
16
  *
23
- * nuqs parsers implement this interface natively — no adapter needed.
17
+ * `parse` receives the RAW url value: `string | string[] | undefined`.
18
+ * A codec must be TOTAL over that domain — return a default rather than
19
+ * throwing on an absent or repeated param.
20
+ *
21
+ * A codec whose own `parse` covers only a PRESENT, SINGLE-VALUED param
22
+ * may publish `parseServerSide` instead, and timber calls that. nuqs
23
+ * parsers do exactly this, which is how they become total here: absent →
24
+ * `null` (or their `withDefault` value), repeated → the first value, and
25
+ * a throw from the inner parse → `null`. See
26
+ * design/23-search-params.md §'nuqs parsers, made total',
27
+ * `parse-total.ts`, and tests/nuqs-codec-boundary.test.ts (TIM-1350).
28
+ *
24
29
  * Standard Schema objects (Zod, Valibot, ArkType) are auto-detected
25
- * by defineSearchParams and wrapped via fromSchema.
30
+ * by defineSearchParams and wrapped via fromSchema; those ARE total
31
+ * through `parse` and are called that way.
26
32
  */
27
33
  export interface SearchParamCodec<T> extends Codec<T> {
28
34
  /** Optional URL key alias, set by withUrlKey(). */
29
35
  urlKey?: string;
36
+ /**
37
+ * Optional TOTAL entry point over `string | string[] | undefined`,
38
+ * preferred over `parse` wherever timber invokes a codec. Declared here
39
+ * so the protocol is typed rather than duck-checked at each wrapper:
40
+ * anything that reconstructs a codec has to carry it, and a wrapper
41
+ * cannot carry a property the interface does not admit.
42
+ *
43
+ * It returns `T`, not `T | null`. This is the entry point timber calls,
44
+ * so whatever it returns IS the field's type — admitting a `null` the
45
+ * field type did not carry would let `SearchParamCodec<string>` produce
46
+ * `null` for an absent param under a non-nullable annotation. A codec
47
+ * whose absent-case answer is `null` declares that in `T`, exactly as a
48
+ * bare nuqs parser does: `parseAsString` is a `SearchParamCodec<string |
49
+ * null>` here, never a `SearchParamCodec<string>`.
50
+ *
51
+ * nuqs parser builders satisfy this. See parse-total.ts.
52
+ */
53
+ parseServerSide?(value: string | string[] | undefined): T;
30
54
  }
31
55
  /** A codec with a URL key alias attached via withUrlKey(). */
32
56
  export interface SearchParamCodecWithUrlKey<T> extends SearchParamCodec<T> {
@@ -77,7 +101,7 @@ export interface SearchParamsDefinition<T extends Record<string, unknown>> {
77
101
  *
78
102
  * ```tsx
79
103
  * // app/products/page.tsx
80
- * import { searchParams } from './params'
104
+ * import { searchParams } from './search-params'
81
105
  * export default function Page() {
82
106
  * const { page, category } = searchParams.get()
83
107
  * }
@@ -92,12 +116,19 @@ export interface SearchParamsDefinition<T extends Record<string, unknown>> {
92
116
  }>;
93
117
  /** Pick a subset of keys. Preserves codecs and aliases. */
94
118
  pick<K extends keyof T & string>(...keys: K[]): SearchParamsDefinition<Pick<T, K>>;
95
- /** Serialize values to a query string (no leading '?'), omitting defaults. */
96
- serialize(values: Partial<T>): string;
119
+ /**
120
+ * Serialize values to a query string (no leading '?'), omitting defaults
121
+ * and applying `withUrlKey` aliases. This is the value to pass to
122
+ * `<Link searchParams={...}>`.
123
+ *
124
+ * Returns a **string**, not a `URLSearchParams`. A `<Link>` prop crosses
125
+ * the RSC Flight boundary, and `URLSearchParams` is iterable — React
126
+ * serializes it as an entries array, which arrives as `[['pg','2'], …]`
127
+ * and renders as `?0=pg&0=2`. A string survives intact.
128
+ */
129
+ buildSearchParams(values: Partial<T>): string;
97
130
  /** Build a full path with query string, omitting defaults. */
98
131
  href(pathname: string, values: Partial<T>): string;
99
- /** Build a URLSearchParams instance, omitting defaults. */
100
- toSearchParams(values: Partial<T>): URLSearchParams;
101
132
  /** Read-only codec map for spreading into .extend(). */
102
133
  codecs: {
103
134
  [K in keyof T]: SearchParamCodec<T[K]>;
@@ -129,6 +160,21 @@ type InferSchemaInput<V> = V extends {
129
160
  /**
130
161
  * Infer the output type from either a SearchParamCodec or a StandardSchemaV1.
131
162
  *
163
+ * A codec publishing `parseServerSide` is read through THAT signature, not
164
+ * through `parse` — it is the entry point timber actually calls, and it is
165
+ * the one that tells the truth about absent input. A bare `parseAsString`
166
+ * declares `parse(value: string): string` but answers `null` for a missing
167
+ * param, so the field is `string | null`; `parseAsInteger.withDefault(1)`
168
+ * narrows its own `parseServerSide` to `NonNullable<number>` and the field
169
+ * stays `number`. Reading `parse` instead produced a non-nullable type for
170
+ * a nullable field (TIM-1350).
171
+ *
172
+ * The match is structural, not nuqs-specific: any codec declaring that
173
+ * signature opts into being read through it, which is exactly the contract
174
+ * `parseTotal` applies at runtime. The two must stay in step — a type
175
+ * inferred from `parse` while the runtime calls `parseServerSide` is the
176
+ * lie this branch exists to remove.
177
+ *
132
178
  * Schemas whose input type rejects `undefined` (e.g. bare `z.string()`, whose
133
179
  * input is `string`) are implicitly optional: the URL might not contain the
134
180
  * param, and fromSchema returns `undefined` when the schema rejects absent
@@ -141,7 +187,9 @@ type InferSchemaInput<V> = V extends {
141
187
  * keeps its narrow output type even though absent input yields `undefined`
142
188
  * at runtime. Add `.default()` to coerce schemas for accurate types.
143
189
  */
144
- export type InferField<V> = V extends SearchParamCodec<infer T> ? T : V extends StandardSchemaV1<infer T> ? undefined extends InferSchemaInput<V> ? T : T | undefined : never;
190
+ export type InferField<V> = V extends {
191
+ parseServerSide(value: string | string[] | undefined): infer R;
192
+ } ? R : V extends SearchParamCodec<infer T> ? T : V extends StandardSchemaV1<infer T> ? undefined extends InferSchemaInput<V> ? T : T | undefined : never;
145
193
  /** Acceptable field value for defineSearchParams: a codec or a Standard Schema. */
146
194
  export type SearchParamField<T = unknown> = SearchParamCodec<T> | StandardSchemaV1<T>;
147
195
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/search-params/define.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/search-params/define.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  export type { SearchParamCodec, SearchParamCodecWithUrlKey, InferCodec, InferField, CodecMap, SearchParamsDefinition, SetParams, SetParamsOptions, QueryStatesOptions, StandardSchemaV1, } from './define.js';
2
2
  export { defineSearchParams } from './define.js';
3
3
  export { withDefault, withUrlKey } from './wrappers.js';
4
- export { registerSearchParams, getSearchParamsDefinition } from './registry.js';
5
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search-params/index.ts"],"names":[],"mappings":"AAMA,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,UAAU,EACV,UAAU,EACV,QAAQ,EACR,sBAAsB,EACtB,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAMjD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search-params/index.ts"],"names":[],"mappings":"AAMA,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,UAAU,EACV,UAAU,EACV,QAAQ,EACR,sBAAsB,EACtB,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAMjD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
@@ -1,10 +1,211 @@
1
- import { n as registerSearchParams, t as getSearchParamsDefinition } from "../_chunks/registry-DbJPKoBp.js";
2
- import { i as isStandardSchema, n as fromSchema, r as isCodec } from "../_chunks/schema-bridge-DT_Tn0Xf.js";
3
- import { n as defineSearchParams } from "../_chunks/define-COtkxMRT.js";
1
+ import { r as getSearchParamsFromAls } from "../_chunks/als-slots-BEEIPKYm.js";
2
+ import { i as isStandardSchema, n as fromSchema, r as isCodec } from "../_chunks/schema-bridge-Cc2Gngu1.js";
3
+ import { n as useQueryStates, r as parseTotal } from "../_chunks/use-query-states-BbU5Ge1V.js";
4
+ //#region src/search-params/define.ts
5
+ /**
6
+ * defineSearchParams — factory for SearchParamsDefinition<T>.
7
+ *
8
+ * Creates a typed, composable definition for a route's search parameters.
9
+ * Accepts both SearchParamCodec values and Standard Schema objects (Zod,
10
+ * Valibot, ArkType) with auto-detection. Supports URL key aliasing via
11
+ * withUrlKey(), default-omission serialization, and composition via
12
+ * .extend() / .pick().
13
+ *
14
+ * Design doc: design/23-search-params.md §"defineSearchParams — The Factory"
15
+ */
16
+ /**
17
+ * Convert URLSearchParams or a plain record to a normalized record
18
+ * where repeated keys produce arrays.
19
+ */
20
+ function normalizeRaw(raw) {
21
+ if (raw instanceof URLSearchParams) {
22
+ const result = Object.create(null);
23
+ for (const key of new Set(raw.keys())) {
24
+ const values = raw.getAll(key);
25
+ result[key] = values.length === 1 ? values[0] : values;
26
+ }
27
+ return result;
28
+ }
29
+ return raw;
30
+ }
31
+ /**
32
+ * Compute the serialized default value for a codec. Used for
33
+ * default-omission: when serialize(value) === serialize(parse(undefined)),
34
+ * the field is omitted from the URL.
35
+ *
36
+ * Goes through `parseTotal` for the same reason request-time parsing does:
37
+ * a nuqs parser's own `parse` throws on absent input, and this is the
38
+ * absent case by construction.
39
+ *
40
+ * **A codec with no value for an absent param has no default to omit**,
41
+ * and `null` is returned rather than `serialize(null)`. Serializing it
42
+ * makes the "no value" case collide with a real one: `parseAsInteger`
43
+ * serializes `null` as the string `'null'`, so `buildSearchParams({ q:
44
+ * 'null' })` would silently drop a legitimate value (before TIM-1350 the
45
+ * absent parse was `undefined` and the swallowed input was the string
46
+ * `'undefined'` — same defect, a less likely input). Nothing is lost:
47
+ * `buildSearchParams` already skips a field whose `serialize` returns
48
+ * `null`, so a codec that encodes "no value" as an omission behaves
49
+ * identically, and one that encodes it as a real query value now writes
50
+ * it instead of dropping it.
51
+ *
52
+ * Codecs are documented to return a default rather than throw, but a
53
+ * hand-written codec that throws on absent input must not turn definition
54
+ * into a crash — treat its default as null (nothing to omit). `serialize`
55
+ * is inside the try for the same reason.
56
+ *
57
+ * Typed `SearchParamCodec<unknown>` rather than generic on purpose: the
58
+ * absent-input value is whatever the codec's total entry point returns,
59
+ * which for a nuqs parser is `T | null` while its `serialize` declares
60
+ * `T`. Widening to `unknown` states that honestly instead of casting.
61
+ */
62
+ function getDefaultSerialized(codec) {
63
+ try {
64
+ const absent = parseTotal(codec, void 0);
65
+ return absent === null || absent === void 0 ? null : codec.serialize(absent);
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ /**
71
+ * Resolve a field value to a SearchParamCodec. Auto-detects Standard Schema
72
+ * objects and wraps them with fromSchema. Reads .urlKey from codecs.
73
+ */
74
+ function resolveField(fieldName, value) {
75
+ if (isCodec(value)) return {
76
+ codec: value,
77
+ urlKey: value.urlKey
78
+ };
79
+ if (isStandardSchema(value)) return { codec: fromSchema(value) };
80
+ throw new Error(`[timber] defineSearchParams: field '${fieldName}' is not a valid codec or Standard Schema. Expected an object with { parse, serialize } methods, or a Standard Schema object (Zod, Valibot, ArkType).`);
81
+ }
82
+ function defineSearchParams(codecsOrSchema) {
83
+ if (isStandardSchema(codecsOrSchema) && hasShape(codecsOrSchema)) {
84
+ const fieldCodecs = {};
85
+ for (const [key, fieldSchema] of Object.entries(codecsOrSchema.shape)) if (isStandardSchema(fieldSchema)) fieldCodecs[key] = fieldSchema;
86
+ else throw new Error(`[timber] defineSearchParams: field '${key}' in schema.shape is not a Standard Schema. All shape properties must be Standard Schema objects (Zod, Valibot, ArkType).`);
87
+ return defineSearchParamsFromMap(fieldCodecs);
88
+ }
89
+ return defineSearchParamsFromMap(codecsOrSchema);
90
+ }
91
+ /** Check if a schema has a .shape property with object-type values. */
92
+ function hasShape(schema) {
93
+ return typeof schema === "object" && schema !== null && "shape" in schema && typeof schema.shape === "object" && schema.shape !== null;
94
+ }
95
+ function defineSearchParamsFromMap(codecs) {
96
+ const resolvedCodecs = {};
97
+ const urlKeys = {};
98
+ for (const [key, value] of Object.entries(codecs)) {
99
+ const resolved = resolveField(key, value);
100
+ resolvedCodecs[key] = resolved.codec;
101
+ if (resolved.urlKey) urlKeys[key] = resolved.urlKey;
102
+ }
103
+ return buildDefinition(resolvedCodecs, urlKeys);
104
+ }
105
+ /**
106
+ * Internal: build a SearchParamsDefinition from a typed codec map and url keys.
107
+ */
108
+ function buildDefinition(codecMap, urlKeys) {
109
+ const defaultSerialized = {};
110
+ for (const key of Object.keys(codecMap)) defaultSerialized[key] = getDefaultSerialized(codecMap[key]);
111
+ function getUrlKey(prop) {
112
+ return urlKeys[prop] ?? prop;
113
+ }
114
+ function parseSync(raw) {
115
+ const normalized = normalizeRaw(raw);
116
+ const result = {};
117
+ for (const prop of Object.keys(codecMap)) {
118
+ const rawValue = normalized[getUrlKey(prop)];
119
+ result[prop] = parseTotal(codecMap[prop], rawValue);
120
+ }
121
+ return result;
122
+ }
123
+ function parse(raw) {
124
+ if (raw instanceof Promise) return raw.then(parseSync);
125
+ return parseSync(raw);
126
+ }
127
+ function buildSearchParams(values) {
128
+ const parts = [];
129
+ for (const prop of Object.keys(codecMap)) {
130
+ if (!(prop in values)) continue;
131
+ const serialized = codecMap[prop].serialize(values[prop]);
132
+ if (serialized === defaultSerialized[prop]) continue;
133
+ if (serialized === null) continue;
134
+ parts.push(`${encodeURIComponent(getUrlKey(prop))}=${encodeURIComponent(serialized)}`);
135
+ }
136
+ return parts.join("&");
137
+ }
138
+ function href(pathname, values) {
139
+ const qs = buildSearchParams(values);
140
+ return qs ? `${pathname}?${qs}` : pathname;
141
+ }
142
+ function extend(newCodecs) {
143
+ const resolvedNewCodecs = {};
144
+ const newUrlKeys = {};
145
+ for (const [key, value] of Object.entries(newCodecs)) {
146
+ const resolved = resolveField(key, value);
147
+ resolvedNewCodecs[key] = resolved.codec;
148
+ if (resolved.urlKey) newUrlKeys[key] = resolved.urlKey;
149
+ }
150
+ return buildDefinition({
151
+ ...codecMap,
152
+ ...resolvedNewCodecs
153
+ }, {
154
+ ...urlKeys,
155
+ ...newUrlKeys
156
+ });
157
+ }
158
+ function pick(...keys) {
159
+ const pickedCodecs = {};
160
+ const pickedUrlKeys = {};
161
+ for (const key of keys) {
162
+ if (!(key in codecMap)) throw new Error(`[timber] pick('${key}'): unknown key. Available keys: ${Object.keys(codecMap).map((k) => `'${k}'`).join(", ")}.`);
163
+ pickedCodecs[key] = codecMap[key];
164
+ if (key in urlKeys) pickedUrlKeys[key] = urlKeys[key];
165
+ }
166
+ return buildDefinition(pickedCodecs, pickedUrlKeys);
167
+ }
168
+ function useQueryStates$1(options) {
169
+ return useQueryStates(codecMap, options, Object.freeze({ ...urlKeys }));
170
+ }
171
+ function get() {
172
+ if (typeof window !== "undefined") throw new Error("[timber] searchParams.get() is server-only. Use searchParams.useQueryStates() on the client.");
173
+ return parseSync(getSearchParamsFromAls());
174
+ }
175
+ return {
176
+ parse,
177
+ get,
178
+ useQueryStates: useQueryStates$1,
179
+ extend,
180
+ pick,
181
+ href,
182
+ buildSearchParams,
183
+ codecs: codecMap,
184
+ urlKeys: Object.freeze({ ...urlKeys })
185
+ };
186
+ }
187
+ //#endregion
4
188
  //#region src/search-params/wrappers.ts
5
189
  /**
6
- * Wrap a nullable codec with a default value. When the inner codec returns
7
- * null, the default is used instead. The output type becomes non-nullable.
190
+ * Wrap a nullable codec with a default value. The output type becomes
191
+ * non-nullable, and the wrapper is TOTAL over `string | string[] |
192
+ * undefined` even when the inner codec is not.
193
+ *
194
+ * The default is substituted for `null` — the documented "no value"
195
+ * answer — and for `undefined`, which is what an implicitly-optional
196
+ * Standard Schema field and a bare `parseAsString` produce for an absent
197
+ * param. Substituting only for `null` left a field typed non-nullable
198
+ * `string` holding `undefined` (TIM-1350).
199
+ *
200
+ * The inner codec is invoked through `parseTotal`, so a nuqs parser gets
201
+ * its own normalization (absent → null, repeated → first value, inner
202
+ * throw → null) before either check applies. That is what makes
203
+ * `withDefault(parseAsBoolean, false)` total; the wrapper itself does NOT
204
+ * catch. A throw from a codec is a deliberate signal — `fromSchema` throws
205
+ * on an async schema, and an app codec may `redirect()` or `notFound()` on
206
+ * a value it refuses — and swallowing it would convert a loud failure into
207
+ * a permanently-default field. design/09 §"The SearchParamCodec Protocol":
208
+ * a codec that throws bubbles as a render-phase error, by design.
8
209
  *
9
210
  * Works with any codec — nuqs parsers, custom codecs, fromSchema results.
10
211
  *
@@ -16,17 +217,25 @@ import { n as defineSearchParams } from "../_chunks/define-COtkxMRT.js";
16
217
  * // page.parse(undefined) → 1 (not null)
17
218
  * // page.parse('5') → 5
18
219
  * ```
220
+ *
221
+ * The signature strips BOTH nullish constituents from the result, not just
222
+ * `null`, because the runtime substitutes for both. An implicitly-optional
223
+ * schema field is a `SearchParamCodec<string | undefined>`, and wrapping it
224
+ * used to yield `SearchParamCodec<string | undefined>` — a field the
225
+ * wrapper guarantees is always present, still typed as maybe-absent.
19
226
  */
20
227
  function withDefault(codec, defaultValue) {
21
- return {
228
+ const wrapped = {
22
229
  parse(value) {
23
- const result = codec.parse(value);
24
- return result === null ? defaultValue : result;
230
+ const result = parseTotal(codec, value);
231
+ return result === null || result === void 0 ? defaultValue : result;
25
232
  },
26
233
  serialize(value) {
27
234
  return codec.serialize(value);
28
235
  }
29
236
  };
237
+ if (codec.urlKey !== void 0) wrapped.urlKey = codec.urlKey;
238
+ return wrapped;
30
239
  }
31
240
  /**
32
241
  * Attach a URL key alias to a codec. The alias determines what query
@@ -55,13 +264,15 @@ function withDefault(codec, defaultValue) {
55
264
  */
56
265
  function withUrlKey(codecOrSchema, urlKey) {
57
266
  const codec = isCodec(codecOrSchema) ? codecOrSchema : isStandardSchema(codecOrSchema) ? fromSchema(codecOrSchema) : codecOrSchema;
58
- return {
267
+ const wrapped = {
59
268
  parse: codec.parse.bind(codec),
60
269
  serialize: codec.serialize.bind(codec),
61
270
  urlKey
62
271
  };
272
+ if (typeof codec.parseServerSide === "function") wrapped.parseServerSide = codec.parseServerSide.bind(codec);
273
+ return wrapped;
63
274
  }
64
275
  //#endregion
65
- export { defineSearchParams, getSearchParamsDefinition, registerSearchParams, withDefault, withUrlKey };
276
+ export { defineSearchParams, withDefault, withUrlKey };
66
277
 
67
278
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/search-params/wrappers.ts"],"sourcesContent":["/**\n * Codec wrappers — withDefault and withUrlKey.\n *\n * These are timber-specific utilities that work with any SearchParamCodec.\n * For actual codecs (string, integer, boolean, etc.), use nuqs parsers\n * or Standard Schema objects (Zod, Valibot, ArkType) with auto-detection.\n *\n * Design doc: design/23-search-params.md\n */\n\nimport type {\n InferField,\n SearchParamCodec,\n SearchParamCodecWithUrlKey,\n SearchParamField,\n} from './define.js';\nimport { isCodec, isStandardSchema, fromSchema } from '../schema-bridge.js';\n\n// ---------------------------------------------------------------------------\n// withDefault\n// ---------------------------------------------------------------------------\n\n/**\n * Wrap a nullable codec with a default value. When the inner codec returns\n * null, the default is used instead. The output type becomes non-nullable.\n *\n * Works with any codec — nuqs parsers, custom codecs, fromSchema results.\n *\n * ```ts\n * import { parseAsInteger } from 'nuqs'\n * import { withDefault } from '@timber-js/app/search-params'\n *\n * const page = withDefault(parseAsInteger, 1)\n * // page.parse(undefined) → 1 (not null)\n * // page.parse('5') → 5\n * ```\n */\nexport function withDefault<T>(\n codec: SearchParamCodec<T | null>,\n defaultValue: T\n): SearchParamCodec<T> {\n return {\n parse(value: string | string[] | undefined): T {\n const result = codec.parse(value);\n return result === null ? defaultValue : result;\n },\n serialize(value: T): string | null {\n return codec.serialize(value);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// withUrlKey\n// ---------------------------------------------------------------------------\n\n/**\n * Attach a URL key alias to a codec. The alias determines what query\n * parameter key is used in the URL, while the TypeScript property name\n * stays descriptive.\n *\n * Aliases travel with codecs through object spread composition — when\n * you spread a bundle containing aliased codecs into defineSearchParams,\n * the aliases come along automatically.\n *\n * ```ts\n * import { parseAsString } from 'nuqs'\n * import { withUrlKey } from '@timber-js/app/search-params'\n *\n * export const searchable = {\n * q: withUrlKey(parseAsString, 'search'),\n * // ?search=shoes → { q: 'shoes' }\n * }\n * ```\n *\n * Composes with withDefault:\n * ```ts\n * import { parseAsInteger } from 'nuqs'\n * withUrlKey(withDefault(parseAsInteger, 1), 'p')\n * ```\n */\nexport function withUrlKey<F extends SearchParamField>(\n codecOrSchema: F,\n urlKey: string\n): SearchParamCodecWithUrlKey<InferField<F>> {\n type T = InferField<F>;\n // Auto-detect Standard Schema (Zod, Valibot, ArkType) and wrap. Schemas\n // that reject undefined input are implicitly optional — fromSchema returns\n // undefined for absent params, and InferField widens the type to include\n // undefined. design/23-search-params.md §\"Implicit Optionality\"\n const codec: SearchParamCodec<T> = isCodec(codecOrSchema)\n ? (codecOrSchema as SearchParamCodec<T>)\n : isStandardSchema(codecOrSchema)\n ? (fromSchema(codecOrSchema) as SearchParamCodec<T>)\n : (codecOrSchema as SearchParamCodec<T>);\n return {\n parse: codec.parse.bind(codec),\n serialize: codec.serialize.bind(codec),\n urlKey,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,YACd,OACA,cACqB;CACrB,OAAO;EACL,MAAM,OAAyC;GAC7C,MAAM,SAAS,MAAM,MAAM,KAAK;GAChC,OAAO,WAAW,OAAO,eAAe;EAC1C;EACA,UAAU,OAAyB;GACjC,OAAO,MAAM,UAAU,KAAK;EAC9B;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,WACd,eACA,QAC2C;CAM3C,MAAM,QAA6B,QAAQ,aAAa,IACnD,gBACD,iBAAiB,aAAa,IAC3B,WAAW,aAAa,IACxB;CACP,OAAO;EACL,OAAO,MAAM,MAAM,KAAK,KAAK;EAC7B,WAAW,MAAM,UAAU,KAAK,KAAK;EACrC;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/search-params/define.ts","../../src/search-params/wrappers.ts"],"sourcesContent":["/**\n * defineSearchParams — factory for SearchParamsDefinition<T>.\n *\n * Creates a typed, composable definition for a route's search parameters.\n * Accepts both SearchParamCodec values and Standard Schema objects (Zod,\n * Valibot, ArkType) with auto-detection. Supports URL key aliasing via\n * withUrlKey(), default-omission serialization, and composition via\n * .extend() / .pick().\n *\n * Design doc: design/23-search-params.md §\"defineSearchParams — The Factory\"\n */\n\nimport { useQueryStates as clientUseQueryStates } from '../client/use-query-states.js';\nimport { fromSchema, isStandardSchema, isCodec } from '../schema-bridge.js';\nimport type { StandardSchemaV1 } from '../schema-bridge.js';\nimport type { Codec } from '../codec.js';\n// Server-only reference for .get() — avoids pulling server ALS into client\n// bundles. In client environments, .get() throws before reaching this code\n// path. The slot lives in its own leaf module so that `request-context.ts`\n// can register the getter without importing this file, which would drag\n// `nuqs` into every server entry (TIM-1298). See shared/als-slots.ts.\nimport { getSearchParamsFromAls } from '../shared/als-slots.js';\nimport { parseTotal } from './parse-total.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A codec that converts between URL string values and typed values.\n *\n * `parse` receives the RAW url value: `string | string[] | undefined`.\n * A codec must be TOTAL over that domain — return a default rather than\n * throwing on an absent or repeated param.\n *\n * A codec whose own `parse` covers only a PRESENT, SINGLE-VALUED param\n * may publish `parseServerSide` instead, and timber calls that. nuqs\n * parsers do exactly this, which is how they become total here: absent →\n * `null` (or their `withDefault` value), repeated → the first value, and\n * a throw from the inner parse → `null`. See\n * design/23-search-params.md §'nuqs parsers, made total',\n * `parse-total.ts`, and tests/nuqs-codec-boundary.test.ts (TIM-1350).\n *\n * Standard Schema objects (Zod, Valibot, ArkType) are auto-detected\n * by defineSearchParams and wrapped via fromSchema; those ARE total\n * through `parse` and are called that way.\n */\nexport interface SearchParamCodec<T> extends Codec<T> {\n /** Optional URL key alias, set by withUrlKey(). */\n urlKey?: string;\n /**\n * Optional TOTAL entry point over `string | string[] | undefined`,\n * preferred over `parse` wherever timber invokes a codec. Declared here\n * so the protocol is typed rather than duck-checked at each wrapper:\n * anything that reconstructs a codec has to carry it, and a wrapper\n * cannot carry a property the interface does not admit.\n *\n * It returns `T`, not `T | null`. This is the entry point timber calls,\n * so whatever it returns IS the field's type — admitting a `null` the\n * field type did not carry would let `SearchParamCodec<string>` produce\n * `null` for an absent param under a non-nullable annotation. A codec\n * whose absent-case answer is `null` declares that in `T`, exactly as a\n * bare nuqs parser does: `parseAsString` is a `SearchParamCodec<string |\n * null>` here, never a `SearchParamCodec<string>`.\n *\n * nuqs parser builders satisfy this. See parse-total.ts.\n */\n parseServerSide?(value: string | string[] | undefined): T;\n}\n\n/** A codec with a URL key alias attached via withUrlKey(). */\nexport interface SearchParamCodecWithUrlKey<T> extends SearchParamCodec<T> {\n urlKey: string;\n}\n\n/** Infer the output type of a codec. */\nexport type InferCodec<C> = C extends SearchParamCodec<infer T> ? T : never;\n\n/** Map of property names to codecs. */\nexport type CodecMap<T extends Record<string, unknown>> = {\n [K in keyof T]: SearchParamCodec<T[K]>;\n};\n\n/** Options for useQueryStates setter. */\nexport interface SetParamsOptions {\n /** Update URL without server roundtrip (default: false). */\n shallow?: boolean;\n /** Scroll to top after update (default: true). */\n scroll?: boolean;\n /** 'push' (default) or 'replace' for history state. */\n history?: 'push' | 'replace';\n}\n\n/** Setter function returned by useQueryStates. */\nexport type SetParams<T> = (values: Partial<T>, options?: SetParamsOptions) => void;\n\n/** Options for useQueryStates hook. */\nexport interface QueryStatesOptions {\n /** Update URL without server roundtrip (default: false). */\n shallow?: boolean;\n /** Scroll to top after update (default: true). */\n scroll?: boolean;\n /** 'push' (default) or 'replace' for history state. */\n history?: 'push' | 'replace';\n}\n\n/**\n * A fully typed, composable search params definition.\n *\n * Returned by defineSearchParams(). Carries a phantom _type property\n * for build-time type extraction.\n */\nexport interface SearchParamsDefinition<T extends Record<string, unknown>> {\n /** Parse raw URL search params into typed values. */\n parse(raw: URLSearchParams | Record<string, string | string[] | undefined>): T;\n /** Parse a Promise of URLSearchParams (e.g., from the ALS `searchParams()` API). */\n parse(raw: Promise<URLSearchParams | Record<string, string | string[] | undefined>>): Promise<T>;\n\n /**\n * Get typed search params from the current request context (ALS-backed).\n *\n * Server-only, sync. Reads getSearchParams() from ALS and parses through codecs.\n * Throws on client.\n *\n * ```tsx\n * // app/products/page.tsx\n * import { searchParams } from './search-params'\n * export default function Page() {\n * const { page, category } = searchParams.get()\n * }\n * ```\n */\n get(): T;\n\n /** Client hook — reads current URL params and returns typed values + setter. */\n useQueryStates(options?: QueryStatesOptions): [T, SetParams<T>];\n\n /** Extend with additional codecs or Standard Schema objects. */\n extend<U extends Record<string, SearchParamCodec<unknown> | StandardSchemaV1<unknown>>>(\n codecs: U\n ): SearchParamsDefinition<T & { [K in keyof U]: InferField<U[K]> }>;\n\n /** Pick a subset of keys. Preserves codecs and aliases. */\n pick<K extends keyof T & string>(...keys: K[]): SearchParamsDefinition<Pick<T, K>>;\n\n /**\n * Serialize values to a query string (no leading '?'), omitting defaults\n * and applying `withUrlKey` aliases. This is the value to pass to\n * `<Link searchParams={...}>`.\n *\n * Returns a **string**, not a `URLSearchParams`. A `<Link>` prop crosses\n * the RSC Flight boundary, and `URLSearchParams` is iterable — React\n * serializes it as an entries array, which arrives as `[['pg','2'], …]`\n * and renders as `?0=pg&0=2`. A string survives intact.\n */\n buildSearchParams(values: Partial<T>): string;\n\n /** Build a full path with query string, omitting defaults. */\n href(pathname: string, values: Partial<T>): string;\n\n /** Read-only codec map for spreading into .extend(). */\n codecs: { [K in keyof T]: SearchParamCodec<T[K]> };\n\n /** Read-only URL key alias map. Maps property names to URL query parameter keys. */\n readonly urlKeys: Readonly<Record<string, string>>;\n\n /**\n * Phantom property for build-time type extraction.\n * Never set at runtime — exists only in the type system.\n */\n readonly _type?: T;\n}\n\n// StandardSchemaV1 is imported from schema-bridge.ts — single source of truth.\n// Re-export for consumers that import it from this module.\nexport type { StandardSchemaV1 } from '../schema-bridge.js';\n\n// ---------------------------------------------------------------------------\n// Type-level helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract a Standard Schema's declared *input* type from its optional\n * `~standard.types` property (part of the Standard Schema spec; Zod, Valibot,\n * and ArkType all declare it at the type level). Falls back to `never` when\n * the schema doesn't declare types (e.g. hand-written schemas): with no\n * metadata we can't know whether the schema handles `undefined`, so InferField\n * widens conservatively rather than risk a type lie.\n */\ntype InferSchemaInput<V> = V extends { '~standard': { types?: infer TS } }\n ? [NonNullable<TS>] extends [{ input: infer I }]\n ? I\n : never\n : never;\n\n/**\n * Infer the output type from either a SearchParamCodec or a StandardSchemaV1.\n *\n * A codec publishing `parseServerSide` is read through THAT signature, not\n * through `parse` — it is the entry point timber actually calls, and it is\n * the one that tells the truth about absent input. A bare `parseAsString`\n * declares `parse(value: string): string` but answers `null` for a missing\n * param, so the field is `string | null`; `parseAsInteger.withDefault(1)`\n * narrows its own `parseServerSide` to `NonNullable<number>` and the field\n * stays `number`. Reading `parse` instead produced a non-nullable type for\n * a nullable field (TIM-1350).\n *\n * The match is structural, not nuqs-specific: any codec declaring that\n * signature opts into being read through it, which is exactly the contract\n * `parseTotal` applies at runtime. The two must stay in step — a type\n * inferred from `parse` while the runtime calls `parseServerSide` is the\n * lie this branch exists to remove.\n *\n * Schemas whose input type rejects `undefined` (e.g. bare `z.string()`, whose\n * input is `string`) are implicitly optional: the URL might not contain the\n * param, and fromSchema returns `undefined` when the schema rejects absent\n * input and has no default. The output type widens to `T | undefined` so the\n * type doesn't lie. Schemas that accept `undefined` input (`.optional()`,\n * `.default()`) keep their declared output type.\n *\n * Limitation: `z.coerce.*` schemas declare input `unknown`, which accepts\n * `undefined` at the type level — so a coerce schema without `.default()`\n * keeps its narrow output type even though absent input yields `undefined`\n * at runtime. Add `.default()` to coerce schemas for accurate types.\n */\nexport type InferField<V> = V extends {\n parseServerSide(value: string | string[] | undefined): infer R;\n}\n ? R\n : V extends SearchParamCodec<infer T>\n ? T\n : V extends StandardSchemaV1<infer T>\n ? undefined extends InferSchemaInput<V>\n ? T\n : T | undefined\n : never;\n\n/** Acceptable field value for defineSearchParams: a codec or a Standard Schema. */\nexport type SearchParamField<T = unknown> = SearchParamCodec<T> | StandardSchemaV1<T>;\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Convert URLSearchParams or a plain record to a normalized record\n * where repeated keys produce arrays.\n */\nfunction normalizeRaw(\n raw: URLSearchParams | Record<string, string | string[] | undefined>\n): Record<string, string | string[] | undefined> {\n if (raw instanceof URLSearchParams) {\n const result: Record<string, string | string[] | undefined> = Object.create(null);\n for (const key of new Set(raw.keys())) {\n const values = raw.getAll(key);\n result[key] = values.length === 1 ? values[0] : values;\n }\n return result;\n }\n return raw;\n}\n\n/**\n * Compute the serialized default value for a codec. Used for\n * default-omission: when serialize(value) === serialize(parse(undefined)),\n * the field is omitted from the URL.\n *\n * Goes through `parseTotal` for the same reason request-time parsing does:\n * a nuqs parser's own `parse` throws on absent input, and this is the\n * absent case by construction.\n *\n * **A codec with no value for an absent param has no default to omit**,\n * and `null` is returned rather than `serialize(null)`. Serializing it\n * makes the \"no value\" case collide with a real one: `parseAsInteger`\n * serializes `null` as the string `'null'`, so `buildSearchParams({ q:\n * 'null' })` would silently drop a legitimate value (before TIM-1350 the\n * absent parse was `undefined` and the swallowed input was the string\n * `'undefined'` — same defect, a less likely input). Nothing is lost:\n * `buildSearchParams` already skips a field whose `serialize` returns\n * `null`, so a codec that encodes \"no value\" as an omission behaves\n * identically, and one that encodes it as a real query value now writes\n * it instead of dropping it.\n *\n * Codecs are documented to return a default rather than throw, but a\n * hand-written codec that throws on absent input must not turn definition\n * into a crash — treat its default as null (nothing to omit). `serialize`\n * is inside the try for the same reason.\n *\n * Typed `SearchParamCodec<unknown>` rather than generic on purpose: the\n * absent-input value is whatever the codec's total entry point returns,\n * which for a nuqs parser is `T | null` while its `serialize` declares\n * `T`. Widening to `unknown` states that honestly instead of casting.\n */\nfunction getDefaultSerialized(codec: SearchParamCodec<unknown>): string | null {\n try {\n const absent = parseTotal(codec, undefined);\n return absent === null || absent === undefined ? null : codec.serialize(absent);\n } catch {\n return null;\n }\n}\n\n// isStandardSchema and isCodec are imported from schema-bridge.ts.\n\n/**\n * Resolve a field value to a SearchParamCodec. Auto-detects Standard Schema\n * objects and wraps them with fromSchema. Reads .urlKey from codecs.\n */\nfunction resolveField(\n fieldName: string,\n value: SearchParamField\n): { codec: SearchParamCodec<unknown>; urlKey?: string } {\n // Check for codec first (codecs may also have '~standard' if they're nuqs parsers)\n if (isCodec(value)) {\n return { codec: value, urlKey: value.urlKey };\n }\n\n // Auto-detect Standard Schema. Schemas that reject undefined input and\n // have no default are implicitly optional: fromSchema returns undefined\n // for absent params, and InferField widens the output type to\n // T | undefined. design/23-search-params.md §\"Implicit Optionality\"\n if (isStandardSchema(value)) {\n return { codec: fromSchema(value) };\n }\n\n throw new Error(\n `[timber] defineSearchParams: field '${fieldName}' is not a valid codec or Standard Schema. ` +\n `Expected an object with { parse, serialize } methods, or a Standard Schema object ` +\n `(Zod, Valibot, ArkType).`\n );\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a SearchParamsDefinition from a map of codecs and/or Standard Schema\n * objects. Accepts both SearchParamCodec values and raw Zod/Valibot/ArkType\n * schemas with auto-detection.\n *\n * ```ts\n * import { defineSearchParams, withDefault, withUrlKey } from '@timber-js/app/search-params'\n * import { parseAsString, parseAsStringEnum } from 'nuqs'\n * import { z } from 'zod/v4'\n *\n * export const searchParams = defineSearchParams({\n * page: z.coerce.number().int().min(1).default(1), // Standard Schema — auto-wrapped\n * q: withUrlKey(parseAsString, 'search'), // nuqs codec with URL alias\n * sort: withDefault(parseAsStringEnum(['price', 'name']), 'price'),\n * })\n * ```\n */\n/**\n * Overload: accept a Standard Schema object schema (e.g., z.object({...})).\n *\n * The schema must have a `.shape` property whose values are themselves\n * Standard Schema objects. Each shape property becomes a field codec\n * via fromSchema().\n *\n * ```ts\n * const searchParams = defineSearchParams(\n * z.object({ page: z.coerce.number().default(1), q: z.string().optional() })\n * )\n * ```\n */\nexport function defineSearchParams<\n S extends StandardSchemaV1<Record<string, unknown>> & {\n shape: Record<string, StandardSchemaV1<unknown>>;\n },\n>(\n schema: S\n): SearchParamsDefinition<{ [K in keyof S['shape'] & string]: InferField<S['shape'][K]> }>;\n\n/**\n * Overload: accept a map of codecs and/or Standard Schema objects.\n */\nexport function defineSearchParams<C extends Record<string, SearchParamField>>(\n codecs: C\n): SearchParamsDefinition<{ [K in keyof C]: InferField<C[K]> }>;\n\nexport function defineSearchParams(\n codecsOrSchema:\n | Record<string, SearchParamField>\n | (StandardSchemaV1<unknown> & { shape: Record<string, StandardSchemaV1<unknown>> })\n): SearchParamsDefinition<Record<string, unknown>> {\n // Detect Standard Schema object with .shape (e.g., z.object(...))\n if (isStandardSchema(codecsOrSchema) && hasShape(codecsOrSchema)) {\n const fieldCodecs: Record<string, SearchParamField> = {};\n for (const [key, fieldSchema] of Object.entries(codecsOrSchema.shape)) {\n if (isStandardSchema(fieldSchema)) {\n fieldCodecs[key] = fieldSchema;\n } else {\n throw new Error(\n `[timber] defineSearchParams: field '${key}' in schema.shape is not a Standard Schema. ` +\n `All shape properties must be Standard Schema objects (Zod, Valibot, ArkType).`\n );\n }\n }\n return defineSearchParamsFromMap(fieldCodecs);\n }\n\n return defineSearchParamsFromMap(codecsOrSchema as Record<string, SearchParamField>);\n}\n\n/** Check if a schema has a .shape property with object-type values. */\nfunction hasShape(schema: unknown): schema is { shape: Record<string, unknown> } {\n return (\n typeof schema === 'object' &&\n schema !== null &&\n 'shape' in schema &&\n typeof (schema as { shape: unknown }).shape === 'object' &&\n (schema as { shape: unknown }).shape !== null\n );\n}\n\nfunction defineSearchParamsFromMap(\n codecs: Record<string, SearchParamField>\n): SearchParamsDefinition<Record<string, unknown>> {\n const resolvedCodecs: Record<string, SearchParamCodec<unknown>> = {};\n const urlKeys: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(codecs)) {\n const resolved = resolveField(key, value as SearchParamField);\n resolvedCodecs[key] = resolved.codec;\n if (resolved.urlKey) {\n urlKeys[key] = resolved.urlKey;\n }\n }\n\n return buildDefinition(resolvedCodecs as unknown as CodecMap<Record<string, unknown>>, urlKeys);\n}\n\n// ---------------------------------------------------------------------------\n// Internal: build the definition object\n// ---------------------------------------------------------------------------\n\n/**\n * Internal: build a SearchParamsDefinition from a typed codec map and url keys.\n */\nfunction buildDefinition<T extends Record<string, unknown>>(\n codecMap: CodecMap<T>,\n urlKeys: Record<string, string>\n): SearchParamsDefinition<T> {\n // Pre-compute default serialized values for omission check\n const defaultSerialized: Record<string, string | null> = {};\n for (const key of Object.keys(codecMap)) {\n defaultSerialized[key] = getDefaultSerialized(codecMap[key as keyof T]);\n }\n\n function getUrlKey(prop: string): string {\n return urlKeys[prop] ?? prop;\n }\n\n // ---- parse ----\n function parseSync(raw: URLSearchParams | Record<string, string | string[] | undefined>): T {\n const normalized = normalizeRaw(raw);\n const result: Record<string, unknown> = {};\n\n for (const prop of Object.keys(codecMap)) {\n const urlKey = getUrlKey(prop);\n const rawValue = normalized[urlKey];\n result[prop] = parseTotal(codecMap[prop as keyof T] as SearchParamCodec<unknown>, rawValue);\n }\n\n return result as T;\n }\n\n // Overloaded parse: sync when given raw params, async when given a Promise.\n // This enables the ergonomic pattern: await def.parse(searchParams())\n function parse(raw: URLSearchParams | Record<string, string | string[] | undefined>): T;\n function parse(\n raw: Promise<URLSearchParams | Record<string, string | string[] | undefined>>\n ): Promise<T>;\n function parse(\n raw:\n | URLSearchParams\n | Record<string, string | string[] | undefined>\n | Promise<URLSearchParams | Record<string, string | string[] | undefined>>\n ): T | Promise<T> {\n if (raw instanceof Promise) {\n return raw.then(parseSync);\n }\n return parseSync(raw);\n }\n\n // ---- buildSearchParams ----\n //\n // Returns a query string. It used to have a URLSearchParams-returning\n // sibling (`toSearchParams`) that `<Link>` consumed; that shape cannot\n // cross the RSC Flight boundary (see the interface docstring), and having\n // two methods produce the same query two ways was a drift waiting to\n // happen. One method now.\n function buildSearchParams(values: Partial<T>): string {\n const parts: string[] = [];\n\n for (const prop of Object.keys(codecMap)) {\n if (!(prop in values)) continue;\n const codec = codecMap[prop as keyof T] as SearchParamCodec<unknown>;\n const serialized = codec.serialize(values[prop as keyof T] as unknown);\n\n // Omit if serialized value matches the default\n if (serialized === defaultSerialized[prop]) continue;\n if (serialized === null) continue;\n\n parts.push(`${encodeURIComponent(getUrlKey(prop))}=${encodeURIComponent(serialized)}`);\n }\n\n return parts.join('&');\n }\n\n // ---- href ----\n function href(pathname: string, values: Partial<T>): string {\n const qs = buildSearchParams(values);\n return qs ? `${pathname}?${qs}` : pathname;\n }\n\n // ---- extend ----\n function extend<U extends Record<string, SearchParamCodec<unknown> | StandardSchemaV1<unknown>>>(\n newCodecs: U\n ): SearchParamsDefinition<T & { [K in keyof U]: InferField<U[K]> }> {\n type Combined = T & { [K in keyof U]: InferField<U[K]> };\n\n // Resolve any Standard Schema objects in the extension\n const resolvedNewCodecs: Record<string, SearchParamCodec<unknown>> = {};\n const newUrlKeys: Record<string, string> = {};\n for (const [key, value] of Object.entries(newCodecs)) {\n const resolved = resolveField(key, value as SearchParamField);\n resolvedNewCodecs[key] = resolved.codec;\n if (resolved.urlKey) {\n newUrlKeys[key] = resolved.urlKey;\n }\n }\n\n const combinedCodecs = {\n ...codecMap,\n ...resolvedNewCodecs,\n } as unknown as CodecMap<Combined>;\n\n // Merge URL keys: base keys + new codec urlKeys from withUrlKey\n const combinedUrlKeys: Record<string, string> = { ...urlKeys, ...newUrlKeys };\n\n return buildDefinition<Combined>(combinedCodecs, combinedUrlKeys);\n }\n\n // ---- pick ----\n function pick<K extends keyof T & string>(...keys: K[]): SearchParamsDefinition<Pick<T, K>> {\n const pickedCodecs: Record<string, SearchParamCodec<unknown>> = {};\n const pickedUrlKeys: Record<string, string> = {};\n\n for (const key of keys) {\n // Explicit guard — TypeScript prevents this, but JS callers and\n // casts reach here, and \"Cannot read properties of undefined\n // (reading 'serialize')\" is no help (TIM-1066).\n if (!(key in codecMap)) {\n throw new Error(\n `[timber] pick('${key}'): unknown key. ` +\n `Available keys: ${Object.keys(codecMap)\n .map((k) => `'${k}'`)\n .join(', ')}.`\n );\n }\n pickedCodecs[key] = codecMap[key] as SearchParamCodec<unknown>;\n if (key in urlKeys) {\n pickedUrlKeys[key] = urlKeys[key];\n }\n }\n\n return buildDefinition<Pick<T, K>>(\n pickedCodecs as unknown as CodecMap<Pick<T, K>>,\n pickedUrlKeys\n );\n }\n\n // ---- useQueryStates ----\n // Delegates to the 'use client' implementation from use-query-states.ts.\n //\n // In the RSC environment: use-query-states.ts is transformed by the RSC\n // plugin into a client reference proxy. Calling it throws — correct,\n // because hooks can't run during server component rendering.\n // In SSR: use-query-states.ts is the real nuqs-backed function. Hooks\n // work during SSR's renderToReadableStream, so this works correctly.\n // On the client: same as SSR — the real function is available.\n function useQueryStates(options?: QueryStatesOptions): [T, SetParams<T>] {\n return clientUseQueryStates(codecMap, options, Object.freeze({ ...urlKeys })) as [\n T,\n SetParams<T>,\n ];\n }\n\n // ---- get ----\n // ALS-backed: reads getSearchParams() from the current request context\n // and parses through codecs. Server-only, sync.\n function get(): T {\n if (typeof window !== 'undefined') {\n throw new Error(\n '[timber] searchParams.get() is server-only. ' +\n 'Use searchParams.useQueryStates() on the client.'\n );\n }\n const raw = getSearchParamsFromAls();\n return parseSync(raw);\n }\n\n const definition: SearchParamsDefinition<T> = {\n parse,\n get,\n useQueryStates,\n extend,\n pick,\n href,\n buildSearchParams,\n codecs: codecMap,\n urlKeys: Object.freeze({ ...urlKeys }),\n };\n\n return definition;\n}\n","/**\n * Codec wrappers — withDefault and withUrlKey.\n *\n * These are timber-specific utilities that work with any SearchParamCodec.\n * For actual codecs (string, integer, boolean, etc.), use nuqs parsers\n * or Standard Schema objects (Zod, Valibot, ArkType) with auto-detection.\n *\n * Design doc: design/23-search-params.md\n */\n\nimport type {\n InferField,\n SearchParamCodec,\n SearchParamCodecWithUrlKey,\n SearchParamField,\n} from './define.js';\nimport { isCodec, isStandardSchema, fromSchema } from '../schema-bridge.js';\nimport { parseTotal } from './parse-total.js';\n\n// ---------------------------------------------------------------------------\n// withDefault\n// ---------------------------------------------------------------------------\n\n/**\n * Wrap a nullable codec with a default value. The output type becomes\n * non-nullable, and the wrapper is TOTAL over `string | string[] |\n * undefined` even when the inner codec is not.\n *\n * The default is substituted for `null` — the documented \"no value\"\n * answer — and for `undefined`, which is what an implicitly-optional\n * Standard Schema field and a bare `parseAsString` produce for an absent\n * param. Substituting only for `null` left a field typed non-nullable\n * `string` holding `undefined` (TIM-1350).\n *\n * The inner codec is invoked through `parseTotal`, so a nuqs parser gets\n * its own normalization (absent → null, repeated → first value, inner\n * throw → null) before either check applies. That is what makes\n * `withDefault(parseAsBoolean, false)` total; the wrapper itself does NOT\n * catch. A throw from a codec is a deliberate signal — `fromSchema` throws\n * on an async schema, and an app codec may `redirect()` or `notFound()` on\n * a value it refuses — and swallowing it would convert a loud failure into\n * a permanently-default field. design/09 §\"The SearchParamCodec Protocol\":\n * a codec that throws bubbles as a render-phase error, by design.\n *\n * Works with any codec — nuqs parsers, custom codecs, fromSchema results.\n *\n * ```ts\n * import { parseAsInteger } from 'nuqs'\n * import { withDefault } from '@timber-js/app/search-params'\n *\n * const page = withDefault(parseAsInteger, 1)\n * // page.parse(undefined) → 1 (not null)\n * // page.parse('5') → 5\n * ```\n *\n * The signature strips BOTH nullish constituents from the result, not just\n * `null`, because the runtime substitutes for both. An implicitly-optional\n * schema field is a `SearchParamCodec<string | undefined>`, and wrapping it\n * used to yield `SearchParamCodec<string | undefined>` — a field the\n * wrapper guarantees is always present, still typed as maybe-absent.\n */\nexport function withDefault<T>(\n codec: SearchParamCodec<T | null | undefined>,\n defaultValue: NonNullable<T>\n): SearchParamCodec<NonNullable<T>> {\n // A wrapper that rebuilds a codec from two methods drops everything else\n // the codec carries. `withUrlKey` lost `parseServerSide` that way; this\n // one lost `urlKey`, so `withDefault(withUrlKey(parseAsInteger, 'p'), 1)`\n // silently read `?page=` instead of `?p=`. Carry it explicitly rather\n // than spreading: this wrapper's own `parse` IS the total entry point,\n // and re-publishing the inner `parseServerSide` would let `parseTotal`\n // reach past it and skip the default entirely.\n const wrapped: SearchParamCodec<NonNullable<T>> = {\n parse(value: string | string[] | undefined): NonNullable<T> {\n const result = parseTotal(codec, value);\n return result === null || result === undefined ? defaultValue : result;\n },\n serialize(value: NonNullable<T>): string | null {\n return codec.serialize(value);\n },\n };\n if (codec.urlKey !== undefined) wrapped.urlKey = codec.urlKey;\n return wrapped;\n}\n\n// ---------------------------------------------------------------------------\n// withUrlKey\n// ---------------------------------------------------------------------------\n\n/**\n * Attach a URL key alias to a codec. The alias determines what query\n * parameter key is used in the URL, while the TypeScript property name\n * stays descriptive.\n *\n * Aliases travel with codecs through object spread composition — when\n * you spread a bundle containing aliased codecs into defineSearchParams,\n * the aliases come along automatically.\n *\n * ```ts\n * import { parseAsString } from 'nuqs'\n * import { withUrlKey } from '@timber-js/app/search-params'\n *\n * export const searchable = {\n * q: withUrlKey(parseAsString, 'search'),\n * // ?search=shoes → { q: 'shoes' }\n * }\n * ```\n *\n * Composes with withDefault:\n * ```ts\n * import { parseAsInteger } from 'nuqs'\n * withUrlKey(withDefault(parseAsInteger, 1), 'p')\n * ```\n */\nexport function withUrlKey<F extends SearchParamField>(\n codecOrSchema: F,\n urlKey: string\n): SearchParamCodecWithUrlKey<InferField<F>> {\n type T = InferField<F>;\n // Auto-detect Standard Schema (Zod, Valibot, ArkType) and wrap. Schemas\n // that reject undefined input are implicitly optional — fromSchema returns\n // undefined for absent params, and InferField widens the type to include\n // undefined. design/23-search-params.md §\"Implicit Optionality\"\n const codec: SearchParamCodec<T> = isCodec(codecOrSchema)\n ? (codecOrSchema as SearchParamCodec<T>)\n : isStandardSchema(codecOrSchema)\n ? (fromSchema(codecOrSchema) as SearchParamCodec<T>)\n : (codecOrSchema as SearchParamCodec<T>);\n // Carry the total entry point, bound like the other two methods. A\n // codec's totality lives in a THIRD property, `parseServerSide` (see\n // parse-total.ts); picking only `parse`/`serialize` silently produced a\n // non-total alias, so `withUrlKey(parseAsBoolean, 'b')` threw on an\n // absent param while the bare parser did not (TIM-1350).\n //\n // Bound explicitly rather than spread: a spread copies own enumerable\n // properties only, so a class-based codec — whose `parse` and\n // `serialize` this wrapper already reaches through the prototype —\n // would have kept its methods and lost exactly the one that makes it\n // total. Three properties, one rule, no dependence on how the inner\n // codec was constructed.\n const wrapped: SearchParamCodecWithUrlKey<T> = {\n parse: codec.parse.bind(codec),\n serialize: codec.serialize.bind(codec),\n urlKey,\n };\n if (typeof codec.parseServerSide === 'function') {\n wrapped.parseServerSide = codec.parseServerSide.bind(codec);\n }\n return wrapped;\n}\n"],"mappings":"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"}