@timber-js/app 0.2.0-alpha.1 → 0.2.0-alpha.100

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 (742) hide show
  1. package/LICENSE +8 -0
  2. package/dist/_chunks/actions-CQ8Z8VGL.js +1061 -0
  3. package/dist/_chunks/actions-CQ8Z8VGL.js.map +1 -0
  4. package/dist/_chunks/build-output-helper-DXnW0qjz.js +61 -0
  5. package/dist/_chunks/build-output-helper-DXnW0qjz.js.map +1 -0
  6. package/dist/_chunks/chunk-BYIpzuS7.js +39 -0
  7. package/dist/_chunks/define-B-Q_UMOD.js +195 -0
  8. package/dist/_chunks/define-B-Q_UMOD.js.map +1 -0
  9. package/dist/_chunks/define-CfBPoJb0.js +123 -0
  10. package/dist/_chunks/define-CfBPoJb0.js.map +1 -0
  11. package/dist/_chunks/define-cookie-BjpIt4UC.js +194 -0
  12. package/dist/_chunks/define-cookie-BjpIt4UC.js.map +1 -0
  13. package/dist/_chunks/format-Bcn-Iv1x.js +14 -0
  14. package/dist/_chunks/format-Bcn-Iv1x.js.map +1 -0
  15. package/dist/_chunks/handler-store-B-lqaGyh.js +54 -0
  16. package/dist/_chunks/handler-store-B-lqaGyh.js.map +1 -0
  17. package/dist/_chunks/logger-0m8MsKdc.js +291 -0
  18. package/dist/_chunks/logger-0m8MsKdc.js.map +1 -0
  19. package/dist/_chunks/merge-search-params-BphMdht_.js +122 -0
  20. package/dist/_chunks/merge-search-params-BphMdht_.js.map +1 -0
  21. package/dist/_chunks/{metadata-routes-CQCnF4VK.js → metadata-routes-BU684ls2.js} +1 -1
  22. package/dist/_chunks/{metadata-routes-CQCnF4VK.js.map → metadata-routes-BU684ls2.js.map} +1 -1
  23. package/dist/_chunks/navigation-root-BCYczjml.js +96 -0
  24. package/dist/_chunks/navigation-root-BCYczjml.js.map +1 -0
  25. package/dist/_chunks/registry-I2ss-lvy.js +20 -0
  26. package/dist/_chunks/registry-I2ss-lvy.js.map +1 -0
  27. package/dist/_chunks/router-ref-h3-UaCQv.js +28 -0
  28. package/dist/_chunks/router-ref-h3-UaCQv.js.map +1 -0
  29. package/dist/_chunks/schema-bridge-Cxu4l-7p.js +86 -0
  30. package/dist/_chunks/schema-bridge-Cxu4l-7p.js.map +1 -0
  31. package/dist/_chunks/segment-classify-BjfuctV2.js +137 -0
  32. package/dist/_chunks/segment-classify-BjfuctV2.js.map +1 -0
  33. package/dist/_chunks/segment-context-Dx_OizxD.js +34 -0
  34. package/dist/_chunks/segment-context-Dx_OizxD.js.map +1 -0
  35. package/dist/_chunks/{ssr-data-DLnbYpj1.js → ssr-data-B4CdH7rE.js} +1 -1
  36. package/dist/_chunks/ssr-data-B4CdH7rE.js.map +1 -0
  37. package/dist/_chunks/stale-reload-Bab885FO.js +64 -0
  38. package/dist/_chunks/stale-reload-Bab885FO.js.map +1 -0
  39. package/dist/_chunks/tracing-C8V-YGsP.js +329 -0
  40. package/dist/_chunks/tracing-C8V-YGsP.js.map +1 -0
  41. package/dist/_chunks/{use-query-states-DAhgj8Gx.js → use-query-states-B2XTqxDR.js} +7 -20
  42. package/dist/_chunks/use-query-states-B2XTqxDR.js.map +1 -0
  43. package/dist/_chunks/use-segment-params-BkpKAQ7D.js +185 -0
  44. package/dist/_chunks/use-segment-params-BkpKAQ7D.js.map +1 -0
  45. package/dist/_chunks/walkers-Tg0Alwcg.js +850 -0
  46. package/dist/_chunks/walkers-Tg0Alwcg.js.map +1 -0
  47. package/dist/_chunks/{format-DNt20Kt8.js → warnings-Cg47l5sk.js} +7 -45
  48. package/dist/_chunks/warnings-Cg47l5sk.js.map +1 -0
  49. package/dist/adapters/build-output-helper.d.ts +28 -0
  50. package/dist/adapters/build-output-helper.d.ts.map +1 -0
  51. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  52. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  53. package/dist/adapters/cloudflare-dev.js +73 -0
  54. package/dist/adapters/cloudflare-dev.js.map +1 -0
  55. package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
  56. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  57. package/dist/adapters/cloudflare-kv-cache.js +95 -0
  58. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  59. package/dist/adapters/cloudflare.d.ts +148 -12
  60. package/dist/adapters/cloudflare.d.ts.map +1 -1
  61. package/dist/adapters/cloudflare.js +142 -38
  62. package/dist/adapters/cloudflare.js.map +1 -1
  63. package/dist/adapters/compress-module.d.ts.map +1 -1
  64. package/dist/adapters/nitro.d.ts +17 -1
  65. package/dist/adapters/nitro.d.ts.map +1 -1
  66. package/dist/adapters/nitro.js +143 -45
  67. package/dist/adapters/nitro.js.map +1 -1
  68. package/dist/adapters/shared.d.ts +16 -0
  69. package/dist/adapters/shared.d.ts.map +1 -0
  70. package/dist/cache/cache-api.d.ts +24 -0
  71. package/dist/cache/cache-api.d.ts.map +1 -0
  72. package/dist/cache/fast-hash.d.ts +22 -0
  73. package/dist/cache/fast-hash.d.ts.map +1 -0
  74. package/dist/cache/handler-store.d.ts +31 -0
  75. package/dist/cache/handler-store.d.ts.map +1 -0
  76. package/dist/cache/index.d.ts +23 -7
  77. package/dist/cache/index.d.ts.map +1 -1
  78. package/dist/cache/index.js +195 -84
  79. package/dist/cache/index.js.map +1 -1
  80. package/dist/cache/singleflight.d.ts +18 -1
  81. package/dist/cache/singleflight.d.ts.map +1 -1
  82. package/dist/cache/sizeof.d.ts +22 -0
  83. package/dist/cache/sizeof.d.ts.map +1 -0
  84. package/dist/cache/timber-cache.d.ts +1 -1
  85. package/dist/cache/timber-cache.d.ts.map +1 -1
  86. package/dist/cli.d.ts +6 -1
  87. package/dist/cli.d.ts.map +1 -1
  88. package/dist/cli.js +8 -3
  89. package/dist/cli.js.map +1 -1
  90. package/dist/client/browser-dev.d.ts +34 -1
  91. package/dist/client/browser-dev.d.ts.map +1 -1
  92. package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
  93. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  94. package/dist/client/browser-entry/hmr.d.ts +21 -0
  95. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  96. package/dist/client/browser-entry/hydrate.d.ts +46 -0
  97. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  98. package/dist/client/browser-entry/index.d.ts +30 -0
  99. package/dist/client/browser-entry/index.d.ts.map +1 -0
  100. package/dist/client/browser-entry/post-hydration.d.ts +26 -0
  101. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  102. package/dist/client/browser-entry/router-init.d.ts +23 -0
  103. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  104. package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
  105. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  106. package/dist/client/browser-entry/scroll.d.ts +19 -0
  107. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  108. package/dist/client/error-boundary.d.ts +12 -5
  109. package/dist/client/error-boundary.d.ts.map +1 -1
  110. package/dist/client/error-boundary.js +26 -5
  111. package/dist/client/error-boundary.js.map +1 -1
  112. package/dist/client/error-reconstituter.d.ts +54 -0
  113. package/dist/client/error-reconstituter.d.ts.map +1 -0
  114. package/dist/client/form.d.ts +16 -27
  115. package/dist/client/form.d.ts.map +1 -1
  116. package/dist/client/history.d.ts +19 -4
  117. package/dist/client/history.d.ts.map +1 -1
  118. package/dist/client/index.d.ts +9 -24
  119. package/dist/client/index.d.ts.map +1 -1
  120. package/dist/client/index.js +312 -1109
  121. package/dist/client/index.js.map +1 -1
  122. package/dist/client/internal.d.ts +19 -0
  123. package/dist/client/internal.d.ts.map +1 -0
  124. package/dist/client/internal.js +964 -0
  125. package/dist/client/internal.js.map +1 -0
  126. package/dist/client/link-pending-store.d.ts +63 -0
  127. package/dist/client/link-pending-store.d.ts.map +1 -0
  128. package/dist/client/link.d.ts +73 -63
  129. package/dist/client/link.d.ts.map +1 -1
  130. package/dist/client/nav-link-store.d.ts +36 -0
  131. package/dist/client/nav-link-store.d.ts.map +1 -0
  132. package/dist/client/navigation-api-types.d.ts +90 -0
  133. package/dist/client/navigation-api-types.d.ts.map +1 -0
  134. package/dist/client/navigation-api.d.ts +115 -0
  135. package/dist/client/navigation-api.d.ts.map +1 -0
  136. package/dist/client/navigation-context.d.ts +22 -5
  137. package/dist/client/navigation-context.d.ts.map +1 -1
  138. package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
  139. package/dist/client/navigation-root.d.ts.map +1 -0
  140. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  141. package/dist/client/router-ref.d.ts +1 -1
  142. package/dist/client/router.d.ts +70 -4
  143. package/dist/client/router.d.ts.map +1 -1
  144. package/dist/client/rsc-fetch.d.ts +38 -3
  145. package/dist/client/rsc-fetch.d.ts.map +1 -1
  146. package/dist/client/segment-cache.d.ts +1 -1
  147. package/dist/client/segment-cache.d.ts.map +1 -1
  148. package/dist/client/segment-context.d.ts +1 -1
  149. package/dist/client/segment-context.d.ts.map +1 -1
  150. package/dist/client/segment-merger.d.ts.map +1 -1
  151. package/dist/client/segment-outlet.d.ts +63 -0
  152. package/dist/client/segment-outlet.d.ts.map +1 -0
  153. package/dist/client/ssr-data.d.ts +13 -4
  154. package/dist/client/ssr-data.d.ts.map +1 -1
  155. package/dist/client/stale-reload.d.ts +15 -0
  156. package/dist/client/stale-reload.d.ts.map +1 -1
  157. package/dist/client/state.d.ts +1 -1
  158. package/dist/client/top-loader.d.ts +5 -5
  159. package/dist/client/top-loader.d.ts.map +1 -1
  160. package/dist/client/use-cookie.d.ts +8 -0
  161. package/dist/client/use-cookie.d.ts.map +1 -1
  162. package/dist/client/use-link-status.d.ts +5 -5
  163. package/dist/client/use-link-status.d.ts.map +1 -1
  164. package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
  165. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  166. package/dist/client/use-query-states.d.ts +1 -1
  167. package/dist/client/use-query-states.d.ts.map +1 -1
  168. package/dist/client/use-router.d.ts +1 -1
  169. package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +7 -5
  170. package/dist/client/use-segment-params.d.ts.map +1 -0
  171. package/dist/codec.d.ts +33 -0
  172. package/dist/codec.d.ts.map +1 -0
  173. package/dist/codec.js +2 -0
  174. package/dist/config-types.d.ts +294 -0
  175. package/dist/config-types.d.ts.map +1 -0
  176. package/dist/config-validation.d.ts +51 -0
  177. package/dist/config-validation.d.ts.map +1 -0
  178. package/dist/content/index.d.ts +1 -10
  179. package/dist/content/index.d.ts.map +1 -1
  180. package/dist/content/index.js +0 -2
  181. package/dist/cookies/define-cookie.d.ts +98 -25
  182. package/dist/cookies/define-cookie.d.ts.map +1 -1
  183. package/dist/cookies/index.d.ts +2 -1
  184. package/dist/cookies/index.d.ts.map +1 -1
  185. package/dist/cookies/index.js +36 -72
  186. package/dist/cookies/index.js.map +1 -1
  187. package/dist/cookies/json-cookie.d.ts +64 -0
  188. package/dist/cookies/json-cookie.d.ts.map +1 -0
  189. package/dist/cookies/validation.d.ts +46 -0
  190. package/dist/cookies/validation.d.ts.map +1 -0
  191. package/dist/dev-tools/404-page.d.ts +46 -0
  192. package/dist/dev-tools/404-page.d.ts.map +1 -0
  193. package/dist/dev-tools/browser-logs.d.ts +84 -0
  194. package/dist/dev-tools/browser-logs.d.ts.map +1 -0
  195. package/dist/dev-tools/error-page.d.ts +58 -0
  196. package/dist/dev-tools/error-page.d.ts.map +1 -0
  197. package/dist/dev-tools/holding-server.d.ts +54 -0
  198. package/dist/dev-tools/holding-server.d.ts.map +1 -0
  199. package/dist/dev-tools/index.d.ts +31 -0
  200. package/dist/dev-tools/index.d.ts.map +1 -0
  201. package/dist/{server/dev-span-processor.d.ts → dev-tools/instrumentation.d.ts} +26 -6
  202. package/dist/dev-tools/instrumentation.d.ts.map +1 -0
  203. package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
  204. package/dist/dev-tools/logger.d.ts.map +1 -0
  205. package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +2 -2
  206. package/dist/dev-tools/logs.d.ts.map +1 -0
  207. package/dist/dev-tools/overlay.d.ts +91 -0
  208. package/dist/dev-tools/overlay.d.ts.map +1 -0
  209. package/dist/dev-tools/stack-classifier.d.ts +34 -0
  210. package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
  211. package/dist/dev-tools/terminal.d.ts +28 -0
  212. package/dist/dev-tools/terminal.d.ts.map +1 -0
  213. package/dist/{server/dev-warnings.d.ts → dev-tools/warnings.d.ts} +2 -22
  214. package/dist/dev-tools/warnings.d.ts.map +1 -0
  215. package/dist/fonts/bundle.d.ts +48 -0
  216. package/dist/fonts/bundle.d.ts.map +1 -0
  217. package/dist/fonts/css.d.ts +1 -0
  218. package/dist/fonts/css.d.ts.map +1 -1
  219. package/dist/fonts/dev-middleware.d.ts +22 -0
  220. package/dist/fonts/dev-middleware.d.ts.map +1 -0
  221. package/dist/fonts/local.d.ts +4 -2
  222. package/dist/fonts/local.d.ts.map +1 -1
  223. package/dist/fonts/pipeline.d.ts +167 -0
  224. package/dist/fonts/pipeline.d.ts.map +1 -0
  225. package/dist/fonts/transform.d.ts +64 -0
  226. package/dist/fonts/transform.d.ts.map +1 -0
  227. package/dist/fonts/types.d.ts +45 -1
  228. package/dist/fonts/types.d.ts.map +1 -1
  229. package/dist/fonts/virtual-modules.d.ts +103 -0
  230. package/dist/fonts/virtual-modules.d.ts.map +1 -0
  231. package/dist/index.d.ts +46 -152
  232. package/dist/index.d.ts.map +1 -1
  233. package/dist/index.js +14702 -12350
  234. package/dist/index.js.map +1 -1
  235. package/dist/plugin-context.d.ts +107 -0
  236. package/dist/plugin-context.d.ts.map +1 -0
  237. package/dist/plugins/adapter-build.d.ts +1 -1
  238. package/dist/plugins/adapter-build.d.ts.map +1 -1
  239. package/dist/plugins/build-manifest.d.ts +2 -2
  240. package/dist/plugins/build-manifest.d.ts.map +1 -1
  241. package/dist/plugins/build-report.d.ts +16 -4
  242. package/dist/plugins/build-report.d.ts.map +1 -1
  243. package/dist/plugins/chunks.d.ts +9 -1
  244. package/dist/plugins/chunks.d.ts.map +1 -1
  245. package/dist/plugins/client-chunks.d.ts +32 -0
  246. package/dist/plugins/client-chunks.d.ts.map +1 -0
  247. package/dist/plugins/content.d.ts +1 -1
  248. package/dist/plugins/content.d.ts.map +1 -1
  249. package/dist/plugins/dev-server.d.ts +1 -1
  250. package/dist/plugins/dev-server.d.ts.map +1 -1
  251. package/dist/plugins/entries.d.ts +8 -1
  252. package/dist/plugins/entries.d.ts.map +1 -1
  253. package/dist/plugins/fonts.d.ts +17 -65
  254. package/dist/plugins/fonts.d.ts.map +1 -1
  255. package/dist/plugins/mdx.d.ts +7 -1
  256. package/dist/plugins/mdx.d.ts.map +1 -1
  257. package/dist/plugins/routing.d.ts +1 -1
  258. package/dist/plugins/routing.d.ts.map +1 -1
  259. package/dist/plugins/server-bundle.d.ts.map +1 -1
  260. package/dist/plugins/shims.d.ts +6 -5
  261. package/dist/plugins/shims.d.ts.map +1 -1
  262. package/dist/plugins/static-build.d.ts +4 -4
  263. package/dist/plugins/static-build.d.ts.map +1 -1
  264. package/dist/routing/codegen-shared.d.ts +55 -0
  265. package/dist/routing/codegen-shared.d.ts.map +1 -0
  266. package/dist/routing/codegen-types.d.ts +52 -0
  267. package/dist/routing/codegen-types.d.ts.map +1 -0
  268. package/dist/routing/codegen.d.ts +2 -2
  269. package/dist/routing/codegen.d.ts.map +1 -1
  270. package/dist/routing/convention-lint.d.ts +41 -0
  271. package/dist/routing/convention-lint.d.ts.map +1 -0
  272. package/dist/routing/index.d.ts +5 -1
  273. package/dist/routing/index.d.ts.map +1 -1
  274. package/dist/routing/index.js +3 -2
  275. package/dist/routing/link-codegen.d.ts +90 -0
  276. package/dist/routing/link-codegen.d.ts.map +1 -0
  277. package/dist/routing/scanner.d.ts +1 -10
  278. package/dist/routing/scanner.d.ts.map +1 -1
  279. package/dist/routing/segment-classify.d.ts +75 -0
  280. package/dist/routing/segment-classify.d.ts.map +1 -0
  281. package/dist/routing/status-file-lint.d.ts +2 -1
  282. package/dist/routing/status-file-lint.d.ts.map +1 -1
  283. package/dist/routing/types.d.ts +77 -25
  284. package/dist/routing/types.d.ts.map +1 -1
  285. package/dist/routing/walkers.d.ts +51 -0
  286. package/dist/routing/walkers.d.ts.map +1 -0
  287. package/dist/rsc-runtime/rsc.d.ts +1 -1
  288. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  289. package/dist/rsc-runtime/ssr.d.ts +12 -0
  290. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  291. package/dist/schema-bridge.d.ts +76 -0
  292. package/dist/schema-bridge.d.ts.map +1 -0
  293. package/dist/search-params/define.d.ts +157 -0
  294. package/dist/search-params/define.d.ts.map +1 -0
  295. package/dist/search-params/index.d.ts +4 -7
  296. package/dist/search-params/index.d.ts.map +1 -1
  297. package/dist/search-params/index.js +34 -441
  298. package/dist/search-params/index.js.map +1 -1
  299. package/dist/search-params/registry.d.ts +2 -2
  300. package/dist/search-params/registry.d.ts.map +1 -1
  301. package/dist/search-params/wrappers.d.ts +53 -0
  302. package/dist/search-params/wrappers.d.ts.map +1 -0
  303. package/dist/segment-params/define.d.ts +95 -0
  304. package/dist/segment-params/define.d.ts.map +1 -0
  305. package/dist/segment-params/index.d.ts +3 -0
  306. package/dist/segment-params/index.d.ts.map +1 -0
  307. package/dist/segment-params/index.js +2 -0
  308. package/dist/server/access-gate.d.ts +8 -3
  309. package/dist/server/access-gate.d.ts.map +1 -1
  310. package/dist/server/action-client.d.ts +41 -6
  311. package/dist/server/action-client.d.ts.map +1 -1
  312. package/dist/server/action-encryption.d.ts +76 -0
  313. package/dist/server/action-encryption.d.ts.map +1 -0
  314. package/dist/server/action-handler.d.ts +35 -1
  315. package/dist/server/action-handler.d.ts.map +1 -1
  316. package/dist/server/actions.d.ts +3 -6
  317. package/dist/server/actions.d.ts.map +1 -1
  318. package/dist/server/als-registry.d.ts +33 -5
  319. package/dist/server/als-registry.d.ts.map +1 -1
  320. package/dist/server/asset-headers.d.ts +1 -15
  321. package/dist/server/asset-headers.d.ts.map +1 -1
  322. package/dist/server/build-manifest.d.ts +2 -2
  323. package/dist/server/build-manifest.d.ts.map +1 -1
  324. package/dist/server/cookie-context.d.ts +170 -0
  325. package/dist/server/cookie-context.d.ts.map +1 -0
  326. package/dist/server/cookie-parsing.d.ts +51 -0
  327. package/dist/server/cookie-parsing.d.ts.map +1 -0
  328. package/dist/server/debug.d.ts +82 -0
  329. package/dist/server/debug.d.ts.map +1 -0
  330. package/dist/server/default-logger.d.ts +22 -0
  331. package/dist/server/default-logger.d.ts.map +1 -0
  332. package/dist/server/deny-boundary.d.ts +90 -0
  333. package/dist/server/deny-boundary.d.ts.map +1 -0
  334. package/dist/server/deny-renderer.d.ts.map +1 -1
  335. package/dist/server/dev-source-map.d.ts +22 -0
  336. package/dist/server/dev-source-map.d.ts.map +1 -0
  337. package/dist/server/early-hints-sender.d.ts.map +1 -1
  338. package/dist/server/early-hints.d.ts +13 -5
  339. package/dist/server/early-hints.d.ts.map +1 -1
  340. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  341. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  342. package/dist/server/fallback-error.d.ts +12 -7
  343. package/dist/server/fallback-error.d.ts.map +1 -1
  344. package/dist/server/flight-injection-state.d.ts +66 -0
  345. package/dist/server/flight-injection-state.d.ts.map +1 -0
  346. package/dist/server/flight-scripts.d.ts +42 -0
  347. package/dist/server/flight-scripts.d.ts.map +1 -0
  348. package/dist/server/flush.d.ts.map +1 -1
  349. package/dist/server/form-data.d.ts +29 -0
  350. package/dist/server/form-data.d.ts.map +1 -1
  351. package/dist/server/html-injector-core.d.ts +212 -0
  352. package/dist/server/html-injector-core.d.ts.map +1 -0
  353. package/dist/server/html-injectors.d.ts +81 -41
  354. package/dist/server/html-injectors.d.ts.map +1 -1
  355. package/dist/server/index.d.ts +9 -46
  356. package/dist/server/index.d.ts.map +1 -1
  357. package/dist/server/index.js +158 -2899
  358. package/dist/server/index.js.map +1 -1
  359. package/dist/server/internal.d.ts +48 -0
  360. package/dist/server/internal.d.ts.map +1 -0
  361. package/dist/server/internal.js +2900 -0
  362. package/dist/server/internal.js.map +1 -0
  363. package/dist/server/logger.d.ts +39 -7
  364. package/dist/server/logger.d.ts.map +1 -1
  365. package/dist/server/middleware-runner.d.ts +36 -4
  366. package/dist/server/middleware-runner.d.ts.map +1 -1
  367. package/dist/server/node-stream-transforms.d.ts +110 -0
  368. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  369. package/dist/server/param-coercion.d.ts +26 -0
  370. package/dist/server/param-coercion.d.ts.map +1 -0
  371. package/dist/server/pipeline-helpers.d.ts +95 -0
  372. package/dist/server/pipeline-helpers.d.ts.map +1 -0
  373. package/dist/server/pipeline-interception.d.ts +1 -1
  374. package/dist/server/pipeline-interception.d.ts.map +1 -1
  375. package/dist/server/pipeline-metadata.d.ts +6 -0
  376. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  377. package/dist/server/pipeline-outcome.d.ts +49 -0
  378. package/dist/server/pipeline-outcome.d.ts.map +1 -0
  379. package/dist/server/pipeline-phases.d.ts +52 -0
  380. package/dist/server/pipeline-phases.d.ts.map +1 -0
  381. package/dist/server/pipeline.d.ts +93 -23
  382. package/dist/server/pipeline.d.ts.map +1 -1
  383. package/dist/server/port-resolution.d.ts +117 -0
  384. package/dist/server/port-resolution.d.ts.map +1 -0
  385. package/dist/server/primitives.d.ts +69 -18
  386. package/dist/server/primitives.d.ts.map +1 -1
  387. package/dist/server/render-timeout.d.ts +51 -0
  388. package/dist/server/render-timeout.d.ts.map +1 -0
  389. package/dist/server/request-context.d.ts +41 -109
  390. package/dist/server/request-context.d.ts.map +1 -1
  391. package/dist/server/route-element-builder.d.ts +27 -1
  392. package/dist/server/route-element-builder.d.ts.map +1 -1
  393. package/dist/server/route-handler.d.ts.map +1 -1
  394. package/dist/server/route-matcher.d.ts +21 -34
  395. package/dist/server/route-matcher.d.ts.map +1 -1
  396. package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
  397. package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
  398. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  399. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  400. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  401. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  402. package/dist/server/rsc-entry/helpers.d.ts +49 -6
  403. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  404. package/dist/server/rsc-entry/index.d.ts +20 -3
  405. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  406. package/dist/server/rsc-entry/render-route.d.ts +50 -0
  407. package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
  408. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  409. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  410. package/dist/server/rsc-entry/rsc-stream.d.ts +20 -1
  411. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  412. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  413. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  414. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  415. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  416. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +119 -0
  417. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
  418. package/dist/server/rsc-prop-warnings.d.ts.map +1 -1
  419. package/dist/server/safe-load.d.ts +46 -0
  420. package/dist/server/safe-load.d.ts.map +1 -0
  421. package/dist/server/sensitive-fields.d.ts +74 -0
  422. package/dist/server/sensitive-fields.d.ts.map +1 -0
  423. package/dist/server/sitemap-generator.d.ts +129 -0
  424. package/dist/server/sitemap-generator.d.ts.map +1 -0
  425. package/dist/server/sitemap-handler.d.ts +22 -0
  426. package/dist/server/sitemap-handler.d.ts.map +1 -0
  427. package/dist/server/slot-resolver.d.ts +1 -1
  428. package/dist/server/slot-resolver.d.ts.map +1 -1
  429. package/dist/server/ssr-entry.d.ts +23 -0
  430. package/dist/server/ssr-entry.d.ts.map +1 -1
  431. package/dist/server/ssr-render.d.ts +39 -21
  432. package/dist/server/ssr-render.d.ts.map +1 -1
  433. package/dist/server/ssr-wrappers.d.ts +50 -0
  434. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  435. package/dist/server/state-tree-diff.d.ts.map +1 -1
  436. package/dist/server/status-code-resolver.d.ts +16 -11
  437. package/dist/server/status-code-resolver.d.ts.map +1 -1
  438. package/dist/server/stream-utils.d.ts +36 -0
  439. package/dist/server/stream-utils.d.ts.map +1 -0
  440. package/dist/server/tracing.d.ts +15 -5
  441. package/dist/server/tracing.d.ts.map +1 -1
  442. package/dist/server/tree-builder.d.ts +62 -30
  443. package/dist/server/tree-builder.d.ts.map +1 -1
  444. package/dist/server/types.d.ts +49 -4
  445. package/dist/server/types.d.ts.map +1 -1
  446. package/dist/server/utils/escape-html.d.ts +14 -0
  447. package/dist/server/utils/escape-html.d.ts.map +1 -0
  448. package/dist/server/version-skew.d.ts +61 -0
  449. package/dist/server/version-skew.d.ts.map +1 -0
  450. package/dist/server/waituntil-bridge.d.ts.map +1 -1
  451. package/dist/shared/merge-search-params.d.ts +22 -0
  452. package/dist/shared/merge-search-params.d.ts.map +1 -0
  453. package/dist/shims/font-google.d.ts +1 -1
  454. package/dist/shims/font-google.d.ts.map +1 -1
  455. package/dist/shims/font-google.js +42 -0
  456. package/dist/shims/font-google.js.map +1 -0
  457. package/dist/shims/font-local.d.ts +26 -0
  458. package/dist/shims/font-local.d.ts.map +1 -0
  459. package/dist/shims/font-local.js +20 -0
  460. package/dist/shims/font-local.js.map +1 -0
  461. package/dist/shims/headers.d.ts +2 -1
  462. package/dist/shims/headers.d.ts.map +1 -1
  463. package/dist/shims/navigation-client.d.ts +3 -1
  464. package/dist/shims/navigation-client.d.ts.map +1 -1
  465. package/dist/shims/navigation.d.ts +11 -5
  466. package/dist/shims/navigation.d.ts.map +1 -1
  467. package/dist/utils/directive-parser.d.ts +1 -43
  468. package/dist/utils/directive-parser.d.ts.map +1 -1
  469. package/dist/utils/state-machine.d.ts +80 -0
  470. package/dist/utils/state-machine.d.ts.map +1 -0
  471. package/package.json +56 -22
  472. package/src/adapters/build-output-helper.ts +77 -0
  473. package/src/adapters/cloudflare-dev.ts +177 -0
  474. package/src/adapters/cloudflare-kv-cache.ts +142 -0
  475. package/src/adapters/cloudflare.ts +350 -76
  476. package/src/adapters/compress-module.ts +24 -4
  477. package/src/adapters/nitro.ts +148 -60
  478. package/src/adapters/shared.ts +40 -0
  479. package/src/adapters/wrangler.d.ts +7 -0
  480. package/src/cache/cache-api.ts +38 -0
  481. package/src/cache/fast-hash.ts +34 -0
  482. package/src/cache/handler-store.ts +68 -0
  483. package/src/cache/index.ts +81 -18
  484. package/src/cache/singleflight.ts +62 -4
  485. package/src/cache/sizeof.ts +31 -0
  486. package/src/cache/timber-cache.ts +41 -29
  487. package/src/cli.ts +16 -6
  488. package/src/client/browser-dev.ts +153 -1
  489. package/src/client/browser-entry/action-dispatch.ts +116 -0
  490. package/src/client/browser-entry/hmr.ts +81 -0
  491. package/src/client/browser-entry/hydrate.ts +145 -0
  492. package/src/client/browser-entry/index.ts +143 -0
  493. package/src/client/browser-entry/post-hydration.ts +119 -0
  494. package/src/client/browser-entry/router-init.ts +193 -0
  495. package/src/client/browser-entry/rsc-stream.ts +157 -0
  496. package/src/client/browser-entry/scroll.ts +27 -0
  497. package/src/client/error-boundary.tsx +97 -20
  498. package/src/client/error-reconstituter.tsx +65 -0
  499. package/src/client/form.tsx +31 -32
  500. package/src/client/history.ts +26 -4
  501. package/src/client/index.ts +77 -43
  502. package/src/client/internal.ts +58 -0
  503. package/src/client/link-pending-store.ts +111 -0
  504. package/src/client/link.tsx +432 -140
  505. package/src/client/nav-link-store.ts +47 -0
  506. package/src/client/navigation-api-types.ts +112 -0
  507. package/src/client/navigation-api.ts +332 -0
  508. package/src/client/navigation-context.ts +83 -18
  509. package/src/client/navigation-root.tsx +342 -0
  510. package/src/client/nuqs-adapter.tsx +16 -3
  511. package/src/client/router-ref.ts +1 -1
  512. package/src/client/router.ts +303 -78
  513. package/src/client/rsc-fetch.ts +112 -8
  514. package/src/client/segment-cache.ts +1 -1
  515. package/src/client/segment-context.ts +6 -1
  516. package/src/client/segment-merger.ts +2 -8
  517. package/src/client/segment-outlet.tsx +86 -0
  518. package/src/client/ssr-data.ts +13 -5
  519. package/src/client/stale-reload.ts +74 -7
  520. package/src/client/state.ts +2 -2
  521. package/src/client/top-loader.tsx +41 -25
  522. package/src/client/use-cookie.ts +29 -0
  523. package/src/client/use-link-status.ts +7 -7
  524. package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
  525. package/src/client/use-query-states.ts +9 -3
  526. package/src/client/use-router.ts +1 -1
  527. package/src/client/{use-params.ts → use-segment-params.ts} +7 -5
  528. package/src/codec.ts +45 -0
  529. package/src/config-types.ts +292 -0
  530. package/src/config-validation.ts +303 -0
  531. package/src/content/index.ts +5 -13
  532. package/src/cookies/define-cookie.ts +301 -55
  533. package/src/cookies/index.ts +12 -1
  534. package/src/cookies/json-cookie.ts +105 -0
  535. package/src/cookies/validation.ts +134 -0
  536. package/src/dev-tools/404-page.ts +387 -0
  537. package/src/dev-tools/browser-logs.ts +288 -0
  538. package/src/dev-tools/error-page.ts +509 -0
  539. package/src/dev-tools/holding-server.ts +187 -0
  540. package/src/dev-tools/index.ts +90 -0
  541. package/src/dev-tools/instrumentation.ts +176 -0
  542. package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +3 -3
  543. package/src/dev-tools/overlay.ts +456 -0
  544. package/src/dev-tools/stack-classifier.ts +75 -0
  545. package/src/dev-tools/terminal.ts +183 -0
  546. package/src/{server/dev-warnings.ts → dev-tools/warnings.ts} +6 -50
  547. package/src/fonts/bundle.ts +142 -0
  548. package/src/fonts/css.ts +2 -1
  549. package/src/fonts/dev-middleware.ts +74 -0
  550. package/src/fonts/local.ts +7 -3
  551. package/src/fonts/pipeline.ts +314 -0
  552. package/src/fonts/transform.ts +406 -0
  553. package/src/fonts/types.ts +50 -1
  554. package/src/fonts/virtual-modules.ts +227 -0
  555. package/src/index.ts +376 -315
  556. package/src/plugin-context.ts +240 -0
  557. package/src/plugins/adapter-build.ts +12 -4
  558. package/src/plugins/build-manifest.ts +13 -2
  559. package/src/plugins/build-report.ts +32 -21
  560. package/src/plugins/chunks.ts +9 -1
  561. package/src/plugins/client-chunks.ts +65 -0
  562. package/src/plugins/content.ts +1 -1
  563. package/src/plugins/dev-server.ts +154 -21
  564. package/src/plugins/entries.ts +119 -12
  565. package/src/plugins/fonts.ts +177 -524
  566. package/src/plugins/mdx.ts +52 -15
  567. package/src/plugins/routing.ts +225 -41
  568. package/src/plugins/server-action-exports.ts +1 -1
  569. package/src/plugins/server-bundle.ts +36 -1
  570. package/src/plugins/shims.ts +136 -35
  571. package/src/plugins/static-build.ts +17 -11
  572. package/src/routing/codegen-shared.ts +98 -0
  573. package/src/routing/codegen-types.ts +53 -0
  574. package/src/routing/codegen.ts +143 -176
  575. package/src/routing/convention-lint.ts +357 -0
  576. package/src/routing/index.ts +5 -1
  577. package/src/routing/interception.ts +1 -1
  578. package/src/routing/link-codegen.ts +294 -0
  579. package/src/routing/scanner.ts +107 -110
  580. package/src/routing/segment-classify.ts +188 -0
  581. package/src/routing/status-file-lint.ts +10 -7
  582. package/src/routing/types.ts +78 -25
  583. package/src/routing/walkers.ts +90 -0
  584. package/src/rsc-runtime/rsc.ts +2 -0
  585. package/src/rsc-runtime/ssr.ts +50 -0
  586. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  587. package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
  588. package/src/search-params/define.ts +538 -0
  589. package/src/search-params/index.ts +14 -20
  590. package/src/search-params/registry.ts +2 -2
  591. package/src/search-params/wrappers.ts +92 -0
  592. package/src/segment-params/define.ts +332 -0
  593. package/src/segment-params/index.ts +9 -0
  594. package/src/server/access-gate.tsx +79 -36
  595. package/src/server/action-client.ts +103 -20
  596. package/src/server/action-encryption.ts +144 -0
  597. package/src/server/action-handler.ts +112 -14
  598. package/src/server/actions.ts +10 -9
  599. package/src/server/als-registry.ts +35 -7
  600. package/src/server/asset-headers.ts +8 -34
  601. package/src/server/build-manifest.ts +10 -4
  602. package/src/server/compress.ts +25 -7
  603. package/src/server/cookie-context.ts +468 -0
  604. package/src/server/cookie-parsing.ts +135 -0
  605. package/src/server/debug.ts +137 -0
  606. package/src/server/default-logger.ts +99 -0
  607. package/src/server/deny-boundary.ts +218 -0
  608. package/src/server/deny-renderer.ts +33 -51
  609. package/src/server/dev-source-map.ts +31 -0
  610. package/src/server/early-hints-sender.ts +3 -2
  611. package/src/server/early-hints.ts +36 -15
  612. package/src/server/error-boundary-wrapper.ts +74 -22
  613. package/src/server/fallback-error.ts +74 -102
  614. package/src/server/flight-injection-state.ts +113 -0
  615. package/src/server/flight-scripts.ts +62 -0
  616. package/src/server/flush.ts +2 -1
  617. package/src/server/form-data.ts +76 -0
  618. package/src/server/html-injector-core.ts +403 -0
  619. package/src/server/html-injectors.ts +244 -223
  620. package/src/server/index.ts +31 -184
  621. package/src/server/internal.ts +176 -0
  622. package/src/server/logger.ts +67 -35
  623. package/src/server/middleware-runner.ts +75 -4
  624. package/src/server/node-stream-transforms.ts +369 -0
  625. package/src/server/param-coercion.ts +76 -0
  626. package/src/server/pipeline-helpers.ts +204 -0
  627. package/src/server/pipeline-interception.ts +17 -16
  628. package/src/server/pipeline-metadata.ts +13 -0
  629. package/src/server/pipeline-outcome.ts +167 -0
  630. package/src/server/pipeline-phases.ts +409 -0
  631. package/src/server/pipeline.ts +128 -387
  632. package/src/server/port-resolution.ts +215 -0
  633. package/src/server/primitives.ts +113 -29
  634. package/src/server/render-timeout.ts +108 -0
  635. package/src/server/request-context.ts +94 -337
  636. package/src/server/route-element-builder.ts +289 -198
  637. package/src/server/route-handler.ts +24 -4
  638. package/src/server/route-matcher.ts +44 -65
  639. package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
  640. package/src/server/rsc-entry/api-handler.ts +16 -17
  641. package/src/server/rsc-entry/error-renderer.ts +305 -89
  642. package/src/server/rsc-entry/helpers.ts +136 -12
  643. package/src/server/rsc-entry/index.ts +330 -312
  644. package/src/server/rsc-entry/render-route.ts +304 -0
  645. package/src/server/rsc-entry/rsc-payload.ts +100 -18
  646. package/src/server/rsc-entry/rsc-stream.ts +90 -17
  647. package/src/server/rsc-entry/ssr-bridge.ts +14 -5
  648. package/src/server/rsc-entry/ssr-renderer.ts +177 -37
  649. package/src/server/rsc-entry/wrap-action-dispatch.ts +449 -0
  650. package/src/server/rsc-prop-warnings.ts +3 -1
  651. package/src/server/safe-load.ts +60 -0
  652. package/src/server/sensitive-fields.ts +230 -0
  653. package/src/server/sitemap-generator.ts +338 -0
  654. package/src/server/sitemap-handler.ts +126 -0
  655. package/src/server/slot-resolver.ts +245 -230
  656. package/src/server/ssr-entry.ts +215 -32
  657. package/src/server/ssr-render.ts +289 -67
  658. package/src/server/ssr-wrappers.tsx +139 -0
  659. package/src/server/state-tree-diff.ts +4 -1
  660. package/src/server/status-code-resolver.ts +112 -128
  661. package/src/server/stream-utils.ts +213 -0
  662. package/src/server/tracing.ts +44 -10
  663. package/src/server/tree-builder.ts +202 -90
  664. package/src/server/types.ts +55 -6
  665. package/src/server/utils/escape-html.ts +20 -0
  666. package/src/server/version-skew.ts +104 -0
  667. package/src/server/waituntil-bridge.ts +4 -1
  668. package/src/shared/merge-search-params.ts +55 -0
  669. package/src/shims/font-google.ts +1 -1
  670. package/src/shims/font-local.ts +34 -0
  671. package/src/shims/headers.ts +5 -1
  672. package/src/shims/navigation-client.ts +4 -3
  673. package/src/shims/navigation.ts +14 -7
  674. package/src/utils/directive-parser.ts +1 -390
  675. package/src/utils/state-machine.ts +111 -0
  676. package/dist/_chunks/als-registry-k-AtAQ9R.js +0 -41
  677. package/dist/_chunks/als-registry-k-AtAQ9R.js.map +0 -1
  678. package/dist/_chunks/format-DNt20Kt8.js.map +0 -1
  679. package/dist/_chunks/interception-DGDIjDbR.js +0 -676
  680. package/dist/_chunks/interception-DGDIjDbR.js.map +0 -1
  681. package/dist/_chunks/request-context-CRj2Zh1E.js +0 -329
  682. package/dist/_chunks/request-context-CRj2Zh1E.js.map +0 -1
  683. package/dist/_chunks/ssr-data-DLnbYpj1.js.map +0 -1
  684. package/dist/_chunks/tracing-DF0G3FB7.js +0 -173
  685. package/dist/_chunks/tracing-DF0G3FB7.js.map +0 -1
  686. package/dist/_chunks/use-cookie-dDbpCTx-.js +0 -91
  687. package/dist/_chunks/use-cookie-dDbpCTx-.js.map +0 -1
  688. package/dist/_chunks/use-query-states-DAhgj8Gx.js.map +0 -1
  689. package/dist/cache/register-cached-function.d.ts +0 -17
  690. package/dist/cache/register-cached-function.d.ts.map +0 -1
  691. package/dist/client/browser-entry.d.ts +0 -22
  692. package/dist/client/browser-entry.d.ts.map +0 -1
  693. package/dist/client/browser-links.d.ts +0 -32
  694. package/dist/client/browser-links.d.ts.map +0 -1
  695. package/dist/client/link-navigate-interceptor.d.ts +0 -28
  696. package/dist/client/link-navigate-interceptor.d.ts.map +0 -1
  697. package/dist/client/link-status-provider.d.ts +0 -11
  698. package/dist/client/link-status-provider.d.ts.map +0 -1
  699. package/dist/client/transition-root.d.ts.map +0 -1
  700. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  701. package/dist/client/use-params.d.ts.map +0 -1
  702. package/dist/plugins/cache-transform.d.ts +0 -36
  703. package/dist/plugins/cache-transform.d.ts.map +0 -1
  704. package/dist/plugins/dev-error-overlay.d.ts +0 -60
  705. package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
  706. package/dist/plugins/dev-logs.d.ts.map +0 -1
  707. package/dist/plugins/dynamic-transform.d.ts +0 -72
  708. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  709. package/dist/search-params/analyze.d.ts +0 -54
  710. package/dist/search-params/analyze.d.ts.map +0 -1
  711. package/dist/search-params/builtin-codecs.d.ts +0 -105
  712. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  713. package/dist/search-params/codecs.d.ts +0 -53
  714. package/dist/search-params/codecs.d.ts.map +0 -1
  715. package/dist/search-params/create.d.ts +0 -106
  716. package/dist/search-params/create.d.ts.map +0 -1
  717. package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
  718. package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
  719. package/dist/server/dev-logger.d.ts.map +0 -1
  720. package/dist/server/dev-span-processor.d.ts.map +0 -1
  721. package/dist/server/dev-warnings.d.ts.map +0 -1
  722. package/dist/server/manifest-status-resolver.d.ts +0 -58
  723. package/dist/server/manifest-status-resolver.d.ts.map +0 -1
  724. package/dist/server/prerender.d.ts +0 -77
  725. package/dist/server/prerender.d.ts.map +0 -1
  726. package/src/cache/register-cached-function.ts +0 -99
  727. package/src/client/browser-entry.ts +0 -686
  728. package/src/client/browser-links.ts +0 -90
  729. package/src/client/link-navigate-interceptor.tsx +0 -62
  730. package/src/client/link-status-provider.tsx +0 -30
  731. package/src/client/transition-root.tsx +0 -160
  732. package/src/plugins/cache-transform.ts +0 -199
  733. package/src/plugins/dev-error-overlay.ts +0 -230
  734. package/src/plugins/dynamic-transform.ts +0 -161
  735. package/src/search-params/analyze.ts +0 -192
  736. package/src/search-params/builtin-codecs.ts +0 -228
  737. package/src/search-params/create.ts +0 -321
  738. package/src/server/dev-fetch-instrumentation.ts +0 -96
  739. package/src/server/dev-span-processor.ts +0 -78
  740. package/src/server/manifest-status-resolver.ts +0 -215
  741. package/src/server/prerender.ts +0 -139
  742. /package/src/{server/dev-logger.ts → dev-tools/logger.ts} +0 -0
@@ -4,8 +4,12 @@
4
4
  // See design/19-client-navigation.md § Progressive Enhancement
5
5
  //
6
6
  // Without JavaScript, <Link> renders as a plain <a> tag — standard browser
7
- // navigation. With JavaScript, the client runtime intercepts clicks on links
8
- // marked with data-timber-link, fetches RSC payloads, and reconciles the DOM.
7
+ // navigation. With JavaScript, the Link component's onClick handler triggers
8
+ // RSC-based client navigation via the router.
9
+ //
10
+ // Each Link owns its own click handler — no global event delegation.
11
+ // This keeps navigation within React's component tree, ensuring pending
12
+ // state (useLinkStatus) updates atomically with the navigation.
9
13
  //
10
14
  // Typed Link: design/09-typescript.md §"Typed Link"
11
15
  // - href validated against known routes (via codegen overloads, not runtime)
@@ -14,18 +18,63 @@
14
18
  // - params and fully-resolved string href are mutually exclusive
15
19
  // - searchParams and inline query string are mutually exclusive
16
20
 
17
- import type { AnchorHTMLAttributes, ReactNode } from 'react';
18
- import type { SearchParamsDefinition } from '#/search-params/create.js';
19
- import type { OnNavigateHandler } from './link-navigate-interceptor.js';
20
- import { LinkNavigateInterceptor } from './link-navigate-interceptor.js';
21
- import { LinkStatusProvider } from './link-status-provider.js';
21
+ import {
22
+ useOptimistic,
23
+ useEffect,
24
+ useRef,
25
+ type AnchorHTMLAttributes,
26
+ type ReactNode,
27
+ type MouseEvent as ReactMouseEvent,
28
+ } from 'react';
29
+ import type { SearchParamsDefinition } from '../search-params/define.js';
30
+ import { getSearchParamsDefinition } from '../search-params/registry.js';
31
+ import type { LinkFunction } from './index.js';
32
+ import { classifyUrlSegment, type UrlSegment } from '../routing/segment-classify.js';
33
+ import { LinkStatusContext } from './use-link-status.js';
34
+ import { getRouterOrNull } from './router-ref.js';
35
+ import { getSsrData } from './ssr-data.js';
36
+ import { mergePreservedSearchParams } from '../shared/merge-search-params.js';
37
+ import {
38
+ setLinkForCurrentNavigation,
39
+ unmountLinkForCurrentNavigation,
40
+ LINK_IDLE,
41
+ type LinkPendingInstance,
42
+ } from './link-pending-store.js';
43
+ import { setNavLinkMetadata } from './nav-link-store.js';
44
+ import { hasNavigationApi } from './navigation-api.js';
45
+
46
+ // ─── Current Search Params ────────────────────────────────────────
47
+
48
+ /**
49
+ * Read the current URL's search string without requiring a React hook.
50
+ * On the client, reads window.location.search. During SSR, reads from
51
+ * the request context (getSsrData). Returns empty string if unavailable.
52
+ */
53
+ function getCurrentSearch(): string {
54
+ if (typeof window !== 'undefined') return window.location.search;
55
+ const data = getSsrData();
56
+ if (!data) return '';
57
+ const sp = new URLSearchParams(data.searchParams);
58
+ const str = sp.toString();
59
+ return str ? `?${str}` : '';
60
+ }
22
61
 
23
62
  // ─── Types ───────────────────────────────────────────────────────
24
63
 
64
+ export type OnNavigateEvent = {
65
+ preventDefault: () => void;
66
+ };
67
+
68
+ export type OnNavigateHandler = (e: OnNavigateEvent) => void;
69
+
25
70
  /**
26
71
  * Base props shared by all Link variants.
72
+ *
73
+ * Exported so the public `LinkFunction` interface (declared in
74
+ * `./index.ts`, where module augmentation can merge into it) can
75
+ * compose this without duplication.
27
76
  */
28
- interface LinkBaseProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
77
+ export interface LinkBaseProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
29
78
  /** Prefetch the RSC payload on hover */
30
79
  prefetch?: boolean;
31
80
  /**
@@ -33,6 +82,20 @@ interface LinkBaseProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'h
33
82
  * Set to false for tabbed interfaces where content changes within a fixed layout.
34
83
  */
35
84
  scroll?: boolean;
85
+ /**
86
+ * Preserve search params from the current URL across navigation.
87
+ *
88
+ * - `true` — preserve ALL current search params (target params take precedence)
89
+ * - `string[]` — preserve only the named params (e.g. `['private', 'token']`)
90
+ *
91
+ * Useful for route-group gating where a search param (e.g. `?private=access`)
92
+ * must persist across internal navigations. The target href's own search params
93
+ * always take precedence over preserved ones.
94
+ *
95
+ * During SSR, reads search params from the request context. On the client,
96
+ * reads from the current URL and updates reactively when the URL changes.
97
+ */
98
+ preserveSearchParams?: true | string[];
36
99
  /**
37
100
  * Called before client-side navigation commits. Call `e.preventDefault()`
38
101
  * to cancel the default navigation — the caller is then responsible for
@@ -45,48 +108,67 @@ interface LinkBaseProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'h
45
108
  children?: ReactNode;
46
109
  }
47
110
 
111
+ // ─── Typed Link Props ────────────────────────────────────────────
112
+
48
113
  /**
49
- * Link with a fully-resolved string href.
50
- * When using a string href with params already interpolated,
51
- * the params prop is not available.
114
+ * Widen server-side string params to string | number for Link convenience.
115
+ * Exported for use by codegen-generated overloads.
52
116
  */
53
- export interface LinkPropsWithHref extends LinkBaseProps {
54
- href: string;
55
- params?: never;
56
- /**
57
- * Typed search params — serialized via the route's SearchParamsDefinition.
58
- * Mutually exclusive with an inline query string in href.
59
- */
60
- searchParams?: {
61
- definition: SearchParamsDefinition<Record<string, unknown>>;
62
- values: Record<string, unknown>;
63
- };
64
- }
117
+ export type LinkSegmentParams<T> = {
118
+ [K in keyof T]: [string] extends [T[K]] ? string | number : T[K];
119
+ };
120
+
121
+ // ─── External Href Types ─────────────────────────────────────────
122
+ //
123
+ // `ExternalHref` and the public `LinkFunction` interface live in
124
+ // `./index.ts` rather than this file. They MUST be originally declared
125
+ // in the same module that the codegen augments (`@timber-js/app/client`)
126
+ // so that codegen-generated per-route call signatures merge with the
127
+ // same interface that types the `Link` constant. Re-exporting an
128
+ // interface via `export type {}` does NOT participate in module
129
+ // augmentation merging — only originally-declared interfaces do.
130
+ // See TIM-624.
131
+
132
+ // ─── searchParams prop shapes ────────────────────────────────────
133
+ //
134
+ // Per-route Link overloads (emitted by codegen) pass the flat values shape:
135
+ // searchParams={{ page: 2, q: 'boots' }}
136
+ // The framework looks up the route's SearchParamsDefinition from the
137
+ // search-params registry at runtime (see TIM-830).
138
+ //
139
+ // The catch-all overload in client/index.ts (external/computed hrefs)
140
+ // additionally accepts the legacy wrapped shape:
141
+ // searchParams={{ definition: def, values: { page: 2 } }}
142
+ // because there is no way to look up a definition from a computed string.
143
+ //
144
+ // `resolveHref` discriminates at runtime by presence of a `definition` key.
145
+ type WrappedSearchParamsProp = {
146
+ definition: SearchParamsDefinition<Record<string, unknown>>;
147
+ values: Record<string, unknown>;
148
+ };
149
+ type FlatSearchParamsProp = Record<string, unknown>;
150
+ type LinkSearchParamsProp = WrappedSearchParamsProp | FlatSearchParamsProp;
65
151
 
66
152
  /**
67
- * Link with a route pattern + params for interpolation.
68
- * e.g. <Link href="/products/[id]" params={{ id: "123" }}>
69
- * <Link href="/products/[id]" params={{ id: 123 }}>
153
+ * Runtime-only loose props used internally by the Link implementation.
154
+ * Not exposed to callers — the public API uses LinkFunction.
70
155
  */
71
- export interface LinkPropsWithParams extends LinkBaseProps {
72
- /** Route pattern with dynamic segments (e.g. "/products/[id]") */
156
+ interface LinkRuntimeProps extends LinkBaseProps {
73
157
  href: string;
74
- /**
75
- * Dynamic segment values to interpolate into the href.
76
- * Single dynamic segments accept string | number (numbers are stringified).
77
- * Catch-all segments accept string[].
78
- */
79
- params: Record<string, string | number | string[]>;
80
- /**
81
- * Typed search params — serialized via the route's SearchParamsDefinition.
82
- */
83
- searchParams?: {
84
- definition: SearchParamsDefinition<Record<string, unknown>>;
85
- values: Record<string, unknown>;
86
- };
158
+ segmentParams?: Record<string, string | number | string[]>;
159
+ searchParams?: LinkSearchParamsProp;
87
160
  }
88
161
 
89
- export type LinkProps = LinkPropsWithHref | LinkPropsWithParams;
162
+ // Legacy exports for backward compat (used by buildLinkProps, tests, etc.)
163
+ export type LinkPropsWithHref = LinkBaseProps & {
164
+ href: string;
165
+ segmentParams?: never;
166
+ searchParams?: LinkSearchParamsProp;
167
+ };
168
+ export type LinkPropsWithParams = LinkRuntimeProps & {
169
+ segmentParams: Record<string, string | number | string[]>;
170
+ };
171
+ export type LinkProps = LinkRuntimeProps;
90
172
 
91
173
  // ─── Dangerous URL Scheme Detection ──────────────────────────────
92
174
 
@@ -108,7 +190,7 @@ export function validateLinkHref(href: string): void {
108
190
  // ─── Internal Link Detection ─────────────────────────────────────
109
191
 
110
192
  /** Returns true if the href is an internal path (not an external URL) */
111
- function isInternalHref(href: string): boolean {
193
+ export function isInternalHref(href: string): boolean {
112
194
  // Relative paths, root-relative paths, and hash links are internal
113
195
  if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {
114
196
  return true;
@@ -132,57 +214,91 @@ function isInternalHref(href: string): boolean {
132
214
  * - [...param] → catch-all (joined with /)
133
215
  * - [[...param]] → optional catch-all (omitted if undefined/empty)
134
216
  */
217
+ /**
218
+ * Parse a route pattern's path portion into classified segments.
219
+ * Exported for testing. Uses the shared character-based classifier.
220
+ */
221
+ export function parseSegments(pattern: string): UrlSegment[] {
222
+ return pattern.split('/').filter(Boolean).map(classifyUrlSegment);
223
+ }
224
+
225
+ /**
226
+ * Resolve a single classified segment into its string representation.
227
+ * Returns null for optional catch-all with no value (filtered out before join).
228
+ */
229
+ function resolveSegment(
230
+ seg: UrlSegment,
231
+ params: Record<string, string | number | string[]>,
232
+ pattern: string
233
+ ): string | null {
234
+ switch (seg.kind) {
235
+ case 'static':
236
+ return seg.value;
237
+
238
+ case 'optional-catch-all': {
239
+ const value = params[seg.name];
240
+ if (value === undefined || (Array.isArray(value) && value.length === 0)) {
241
+ return null;
242
+ }
243
+ const segments = Array.isArray(value) ? value : [value];
244
+ return segments.map(encodeURIComponent).join('/');
245
+ }
246
+
247
+ case 'catch-all': {
248
+ const value = params[seg.name];
249
+ if (value === undefined) {
250
+ throw new Error(
251
+ `<Link> missing required catch-all param "${seg.name}" for pattern "${pattern}".`
252
+ );
253
+ }
254
+ const segments = Array.isArray(value) ? value : [value];
255
+ if (segments.length === 0) {
256
+ throw new Error(
257
+ `<Link> catch-all param "${seg.name}" must have at least one segment for pattern "${pattern}".`
258
+ );
259
+ }
260
+ return segments.map(encodeURIComponent).join('/');
261
+ }
262
+
263
+ case 'dynamic': {
264
+ const value = params[seg.name];
265
+ if (value === undefined) {
266
+ throw new Error(`<Link> missing required param "${seg.name}" for pattern "${pattern}".`);
267
+ }
268
+ if (Array.isArray(value)) {
269
+ throw new Error(
270
+ `<Link> param "${seg.name}" expected a string but received an array for pattern "${pattern}".`
271
+ );
272
+ }
273
+ return encodeURIComponent(String(value));
274
+ }
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Split a URL pattern into the path portion and any trailing ?query/#hash suffix.
280
+ * Uses URL parsing for correctness rather than manual index arithmetic.
281
+ */
282
+ function splitPatternSuffix(pattern: string): [path: string, suffix: string] {
283
+ if (!pattern.includes('?') && !pattern.includes('#')) {
284
+ return [pattern, ''];
285
+ }
286
+ const url = new URL(pattern, 'http://x');
287
+ const suffix = url.search + url.hash;
288
+ const path = pattern.slice(0, pattern.length - suffix.length);
289
+ return [path, suffix];
290
+ }
291
+
135
292
  export function interpolateParams(
136
293
  pattern: string,
137
294
  params: Record<string, string | number | string[]>
138
295
  ): string {
139
- return (
140
- pattern
141
- .replace(
142
- /\[\[\.\.\.(\w+)\]\]|\[\.\.\.(\w+)\]|\[(\w+)\]/g,
143
- (_match, optionalCatchAll, catchAll, single) => {
144
- if (optionalCatchAll) {
145
- const value = params[optionalCatchAll];
146
- if (value === undefined || (Array.isArray(value) && value.length === 0)) {
147
- return '';
148
- }
149
- const segments = Array.isArray(value) ? value : [value];
150
- return segments.map(encodeURIComponent).join('/');
151
- }
152
-
153
- if (catchAll) {
154
- const value = params[catchAll];
155
- if (value === undefined) {
156
- throw new Error(
157
- `<Link> missing required catch-all param "${catchAll}" for pattern "${pattern}".`
158
- );
159
- }
160
- const segments = Array.isArray(value) ? value : [value];
161
- if (segments.length === 0) {
162
- throw new Error(
163
- `<Link> catch-all param "${catchAll}" must have at least one segment for pattern "${pattern}".`
164
- );
165
- }
166
- return segments.map(encodeURIComponent).join('/');
167
- }
296
+ const [pathPart, suffix] = splitPatternSuffix(pattern);
168
297
 
169
- // single dynamic segment
170
- const value = params[single];
171
- if (value === undefined) {
172
- throw new Error(`<Link> missing required param "${single}" for pattern "${pattern}".`);
173
- }
174
- if (Array.isArray(value)) {
175
- throw new Error(
176
- `<Link> param "${single}" expected a string but received an array for pattern "${pattern}".`
177
- );
178
- }
179
- // Accept numbers — coerce to string for URL interpolation
180
- return encodeURIComponent(String(value));
181
- }
182
- )
183
- // Clean up trailing slash from empty optional catch-all
184
- .replace(/\/+$/, '') || '/'
185
- );
298
+ const resolved = parseSegments(pathPart)
299
+ .map((seg) => resolveSegment(seg, params, pattern))
300
+ .filter((s): s is string => s !== null);
301
+ return ('/' + resolved.join('/') || '/') + suffix;
186
302
  }
187
303
 
188
304
  // ─── Resolve Href ───────────────────────────────────────────────
@@ -195,13 +311,19 @@ export function interpolateParams(
195
311
  * - searchParams serialization via SearchParamsDefinition
196
312
  * - Validation that searchParams and inline query strings are exclusive
197
313
  */
314
+ /**
315
+ * Runtime discriminator: treat `searchParams` as the legacy wrapped shape
316
+ * only when it literally has a `definition` key. Everything else is the
317
+ * flat `Partial<T>` values shape (TIM-830).
318
+ */
319
+ function isWrappedSearchParamsProp(sp: LinkSearchParamsProp): sp is WrappedSearchParamsProp {
320
+ return 'definition' in sp;
321
+ }
322
+
198
323
  export function resolveHref(
199
324
  href: string,
200
325
  params?: Record<string, string | number | string[]>,
201
- searchParams?: {
202
- definition: SearchParamsDefinition<Record<string, unknown>>;
203
- values: Record<string, unknown>;
204
- }
326
+ searchParams?: LinkSearchParamsProp
205
327
  ): string {
206
328
  let resolvedPath = href;
207
329
 
@@ -220,7 +342,36 @@ export function resolveHref(
220
342
  );
221
343
  }
222
344
 
223
- const qs = searchParams.definition.serialize(searchParams.values);
345
+ let definition: SearchParamsDefinition<Record<string, unknown>> | undefined;
346
+ let values: Record<string, unknown>;
347
+
348
+ if (isWrappedSearchParamsProp(searchParams)) {
349
+ // Legacy wrapped shape — used by the catch-all overload for
350
+ // computed/external hrefs where no route lookup is possible.
351
+ definition = searchParams.definition;
352
+ values = searchParams.values;
353
+ } else {
354
+ // Flat shape (TIM-830): look up the definition from the runtime
355
+ // registry using the un-interpolated href pattern (e.g. '/products/[id]').
356
+ // The search-params registry is populated eagerly at startup by the
357
+ // virtual:timber-search-params-registry module generated by the
358
+ // timber-routing Vite plugin.
359
+ definition = getSearchParamsDefinition(href) as
360
+ | SearchParamsDefinition<Record<string, unknown>>
361
+ | undefined;
362
+ values = searchParams;
363
+ if (!definition) {
364
+ throw new Error(
365
+ `<Link> received a flat searchParams object for href "${href}", but no ` +
366
+ `SearchParamsDefinition is registered for that route. ` +
367
+ `Either the route does not export \`searchParams\` from its \`params.ts\`/\`page.tsx\`, ` +
368
+ `or the search-params registry module was not loaded. ` +
369
+ `For external or computed hrefs, pass the legacy \`{ definition, values }\` shape instead.`
370
+ );
371
+ }
372
+ }
373
+
374
+ const qs = definition.serialize(values);
224
375
  if (qs) {
225
376
  resolvedPath = `${resolvedPath}?${qs}`;
226
377
  }
@@ -232,10 +383,7 @@ export function resolveHref(
232
383
  // ─── Build Props ─────────────────────────────────────────────────
233
384
 
234
385
  interface LinkOutputProps {
235
- 'href': string;
236
- 'data-timber-link'?: boolean;
237
- 'data-timber-prefetch'?: boolean;
238
- 'data-timber-scroll'?: string;
386
+ href: string;
239
387
  }
240
388
 
241
389
  /**
@@ -243,34 +391,44 @@ interface LinkOutputProps {
243
391
  * for testability — the component just spreads these onto an <a>.
244
392
  */
245
393
  export function buildLinkProps(
246
- props: Pick<LinkPropsWithHref, 'href' | 'prefetch' | 'scroll'> & {
394
+ props: Pick<LinkPropsWithHref, 'href'> & {
247
395
  params?: Record<string, string | number | string[]>;
248
- searchParams?: {
249
- definition: SearchParamsDefinition<Record<string, unknown>>;
250
- values: Record<string, unknown>;
251
- };
396
+ searchParams?: LinkSearchParamsProp;
252
397
  }
253
398
  ): LinkOutputProps {
254
399
  const resolvedHref = resolveHref(props.href, props.params, props.searchParams);
255
-
256
400
  validateLinkHref(resolvedHref);
401
+ return { href: resolvedHref };
402
+ }
257
403
 
258
- const output: LinkOutputProps = { href: resolvedHref };
259
- const internal = isInternalHref(resolvedHref);
404
+ // ─── Click Handler ───────────────────────────────────────────────
260
405
 
261
- if (internal) {
262
- output['data-timber-link'] = true;
406
+ /**
407
+ * Should this click be intercepted for SPA navigation?
408
+ *
409
+ * Returns false (pass through to browser) when:
410
+ * - Modified keys are held (Ctrl, Meta, Shift, Alt) — open in new tab
411
+ * - The click is not the primary button
412
+ * - The event was already prevented by a parent handler
413
+ * - The link has target="_blank" or similar
414
+ * - The link has a download attribute
415
+ * - The href is external
416
+ */
417
+ function shouldInterceptClick(
418
+ event: ReactMouseEvent<HTMLAnchorElement>,
419
+ resolvedHref: string
420
+ ): boolean {
421
+ if (event.button !== 0) return false;
422
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return false;
423
+ if (event.defaultPrevented) return false;
263
424
 
264
- if (props.prefetch) {
265
- output['data-timber-prefetch'] = true;
266
- }
425
+ const anchor = event.currentTarget;
426
+ if (anchor.target && anchor.target !== '_self') return false;
427
+ if (anchor.hasAttribute('download')) return false;
267
428
 
268
- if (props.scroll === false) {
269
- output['data-timber-scroll'] = 'false';
270
- }
271
- }
429
+ if (!isInternalHref(resolvedHref)) return false;
272
430
 
273
- return output;
431
+ return true;
274
432
  }
275
433
 
276
434
  // ─── Link Component ──────────────────────────────────────────────
@@ -279,34 +437,168 @@ export function buildLinkProps(
279
437
  * Navigation link with progressive enhancement.
280
438
  *
281
439
  * Renders as a plain `<a>` tag — works without JavaScript. When the client
282
- * runtime is active, it intercepts clicks on links marked with
283
- * `data-timber-link` to perform RSC-based client navigation.
440
+ * runtime is active, the Link's onClick handler triggers RSC-based client
441
+ * navigation via the router. No global event delegation — each Link owns
442
+ * its own click handling.
284
443
  *
285
- * Supports typed routes via codegen overloads. At runtime:
286
- * - `params` prop interpolates dynamic segments in the href pattern
444
+ * Supports typed routes via the Routes interface (populated by codegen).
445
+ * At runtime:
446
+ * - `segmentParams` prop interpolates dynamic segments in the href pattern
287
447
  * - `searchParams` prop serializes query parameters via a SearchParamsDefinition
448
+ *
449
+ * Typed via the LinkFunction callable interface. The base call signature
450
+ * forbids segmentParams; per-route signatures are added by codegen via
451
+ * interface merging. See TIM-624.
288
452
  */
289
- export function Link({
290
- href,
291
- prefetch,
292
- scroll,
293
- params,
294
- searchParams,
295
- onNavigate,
296
- children,
297
- ...rest
298
- }: LinkProps) {
299
- const linkProps = buildLinkProps({ href, prefetch, scroll, params, searchParams });
300
-
301
- const inner = <LinkStatusProvider href={linkProps.href}>{children}</LinkStatusProvider>;
453
+ // Cast to LinkFunction — the callable interface provides the public type,
454
+ // but the implementation destructures LinkRuntimeProps internally.
455
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
456
+ export const Link: LinkFunction = function LinkImpl(props: any) {
457
+ const {
458
+ href,
459
+ prefetch,
460
+ scroll,
461
+ segmentParams,
462
+ searchParams,
463
+ preserveSearchParams,
464
+ onNavigate,
465
+ onClick: userOnClick,
466
+ onMouseEnter: userOnMouseEnter,
467
+ children,
468
+ ...rest
469
+ } = props as LinkRuntimeProps;
470
+ const { href: baseHref } = buildLinkProps({ href, params: segmentParams, searchParams });
471
+
472
+ // ─── Per-link pending state (useOptimistic) ────────────────────────
473
+ // Each Link has its own pending state. Only the clicked link's
474
+ // setter is invoked during navigation — zero other links re-render.
475
+ //
476
+ // Link click stores the instance; NavigationRoot activates inside startTransition.
477
+ // useOptimistic auto-reverts to LINK_IDLE when the navigation
478
+ // startTransition — batched with the new tree commit.
479
+ //
480
+ // See design/19-client-navigation.md §"Per-Link Pending State"
481
+ const [linkStatus, setIsPending] = useOptimistic(LINK_IDLE);
482
+
483
+ // Build the link instance ref for the pending store.
484
+ // The ref is stable across renders — we update the setter on each
485
+ // render to keep it current.
486
+ const linkInstanceRef = useRef<LinkPendingInstance | null>(null);
487
+ if (!linkInstanceRef.current) {
488
+ linkInstanceRef.current = { setIsPending };
489
+ } else {
490
+ linkInstanceRef.current.setIsPending = setIsPending;
491
+ }
492
+
493
+ // Clean up if this link unmounts while it's the current navigation link.
494
+ // Prevents calling setOptimistic on an unmounted component.
495
+ useEffect(() => {
496
+ const instance = linkInstanceRef.current;
497
+ return () => {
498
+ if (instance) {
499
+ unmountLinkForCurrentNavigation(instance);
500
+ }
501
+ };
502
+ }, []);
503
+
504
+ // Preserve search params from the current URL when requested.
505
+ // useSearchParams() works during both SSR (reads from request context)
506
+ // and on the client (reads from window.location, reactive to URL changes).
507
+ // We read current search params directly to avoid unconditional hook calls.
508
+ // On the client, window.location.search is always current; during SSR,
509
+ // getSsrData() provides the request's search params.
510
+ const resolvedHref = preserveSearchParams
511
+ ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams)
512
+ : baseHref;
513
+
514
+ const internal = isInternalHref(resolvedHref);
515
+
516
+ // ─── Click handler ───────────────────────────────────────────
517
+ // Each Link component owns its click handling. The router is
518
+ // accessed via the singleton ref — during SSR, getRouterOrNull()
519
+ // returns null and onClick is a no-op (the <a> works as a plain link).
520
+ const handleClick = internal
521
+ ? (event: ReactMouseEvent<HTMLAnchorElement>) => {
522
+ // Call user's onClick first (e.g., analytics)
523
+ userOnClick?.(event);
524
+
525
+ if (!shouldInterceptClick(event, resolvedHref)) return;
526
+
527
+ // Call onNavigate if provided — allows caller to cancel
528
+ if (onNavigate) {
529
+ let prevented = false;
530
+ onNavigate({
531
+ preventDefault: () => {
532
+ prevented = true;
533
+ },
534
+ });
535
+ if (prevented) {
536
+ event.preventDefault();
537
+ return;
538
+ }
539
+ }
540
+
541
+ const router = getRouterOrNull();
542
+ if (!router) return; // SSR or pre-hydration — fall through to browser nav
543
+
544
+ const shouldScroll = scroll !== false;
545
+
546
+ // Register this link in the pending store. The actual
547
+ // setIsPending(LINK_PENDING) call happens inside NavigationRoot's
548
+ // async startTransition via activateLinkPending().
549
+
550
+ setLinkForCurrentNavigation(linkInstanceRef.current);
551
+
552
+ // When Navigation API is active, let the <a> click propagate
553
+ // naturally — do NOT call preventDefault(). The navigate event
554
+ // handler intercepts it and runs the RSC pipeline. This is a
555
+ // user-initiated navigation, so Chrome shows the native loading
556
+ // indicator (tab spinner). Metadata (scroll, link instance) is
557
+ // passed via nav-link-store so the handler can configure the nav.
558
+ //
559
+ // Without Navigation API (fallback), preventDefault and drive
560
+ // navigation through the router as before.
561
+ if (hasNavigationApi()) {
562
+ setNavLinkMetadata({
563
+ scroll: shouldScroll,
564
+ linkInstance: linkInstanceRef.current,
565
+ });
566
+ // Don't preventDefault — let the <a> click fire the navigate event
567
+ return;
568
+ }
569
+
570
+ // History API fallback — prevent default and navigate via router
571
+ event.preventDefault();
572
+
573
+ // Re-merge preserved search params at click time to pick up any
574
+ // URL changes since render (e.g. from other navigations or pushState).
575
+ const navHref = preserveSearchParams
576
+ ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams)
577
+ : resolvedHref;
578
+
579
+ void router.navigate(navHref, { scroll: shouldScroll });
580
+ }
581
+ : userOnClick; // External links — just pass through user's onClick
582
+
583
+ // ─── Hover prefetch ──────────────────────────────────────────
584
+ const handleMouseEnter =
585
+ internal && prefetch
586
+ ? (event: ReactMouseEvent<HTMLAnchorElement>) => {
587
+ userOnMouseEnter?.(event);
588
+ const router = getRouterOrNull();
589
+ if (router) {
590
+ // Re-merge preserved search params at hover time for fresh prefetch URL
591
+ const prefetchHref = preserveSearchParams
592
+ ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams)
593
+ : resolvedHref;
594
+ router.prefetch(prefetchHref);
595
+ }
596
+ }
597
+ : userOnMouseEnter;
302
598
 
303
599
  return (
304
- <a {...rest} {...linkProps}>
305
- {onNavigate ? (
306
- <LinkNavigateInterceptor onNavigate={onNavigate}>{inner}</LinkNavigateInterceptor>
307
- ) : (
308
- inner
309
- )}
600
+ <a {...rest} href={resolvedHref} onClick={handleClick} onMouseEnter={handleMouseEnter}>
601
+ <LinkStatusContext.Provider value={linkStatus}>{children}</LinkStatusContext.Provider>
310
602
  </a>
311
603
  );
312
- }
604
+ };