@timber-js/app 0.2.0-alpha.18 → 0.2.0-alpha.180

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 (1026) hide show
  1. package/LICENSE +8 -0
  2. package/agent-skill.md +344 -0
  3. package/dist/_chunks/actions-O_LsyCE4.js +317 -0
  4. package/dist/_chunks/actions-O_LsyCE4.js.map +1 -0
  5. package/dist/_chunks/build-output-helper-DF5uScqS.js +158 -0
  6. package/dist/_chunks/build-output-helper-DF5uScqS.js.map +1 -0
  7. package/dist/_chunks/cache-api-B-lhk9p4.js +1202 -0
  8. package/dist/_chunks/cache-api-B-lhk9p4.js.map +1 -0
  9. package/dist/_chunks/canonicalize-DQHyFClh.js +248 -0
  10. package/dist/_chunks/canonicalize-DQHyFClh.js.map +1 -0
  11. package/dist/_chunks/cli-schema-sync-D3naS3eH.js +688 -0
  12. package/dist/_chunks/cli-schema-sync-D3naS3eH.js.map +1 -0
  13. package/dist/_chunks/cloudflare-AHoWYTYr.js +1188 -0
  14. package/dist/_chunks/cloudflare-AHoWYTYr.js.map +1 -0
  15. package/dist/_chunks/codec-registry-oOUxugz3.js +21 -0
  16. package/dist/_chunks/codec-registry-oOUxugz3.js.map +1 -0
  17. package/dist/_chunks/define-COtkxMRT.js +191 -0
  18. package/dist/_chunks/define-COtkxMRT.js.map +1 -0
  19. package/dist/_chunks/define-c4au4I9R.js +82 -0
  20. package/dist/_chunks/define-c4au4I9R.js.map +1 -0
  21. package/dist/_chunks/dist-BA3u1z3W.js +423 -0
  22. package/dist/_chunks/dist-BA3u1z3W.js.map +1 -0
  23. package/dist/_chunks/fast-hash-D6hIVt1Y.js +36 -0
  24. package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +1 -0
  25. package/dist/_chunks/format-CfwjgPz9.js +14 -0
  26. package/dist/_chunks/format-CfwjgPz9.js.map +1 -0
  27. package/dist/_chunks/href-validation-CMc5JRls.js +141 -0
  28. package/dist/_chunks/href-validation-CMc5JRls.js.map +1 -0
  29. package/dist/_chunks/json-lossy-check-ClNvBM_3.js +63 -0
  30. package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +1 -0
  31. package/dist/_chunks/logger-AWfuX-KJ.js +1468 -0
  32. package/dist/_chunks/logger-AWfuX-KJ.js.map +1 -0
  33. package/dist/_chunks/navigation-root-bUDZLw74.js +124 -0
  34. package/dist/_chunks/navigation-root-bUDZLw74.js.map +1 -0
  35. package/dist/_chunks/plugin-context---kTF5v8.js +315 -0
  36. package/dist/_chunks/plugin-context---kTF5v8.js.map +1 -0
  37. package/dist/_chunks/registry-DbJPKoBp.js +20 -0
  38. package/dist/_chunks/registry-DbJPKoBp.js.map +1 -0
  39. package/dist/_chunks/resolve-schema-Dz3fcFUo.js +50 -0
  40. package/dist/_chunks/resolve-schema-Dz3fcFUo.js.map +1 -0
  41. package/dist/_chunks/router-ref-CtmF-aPv.js +28 -0
  42. package/dist/_chunks/router-ref-CtmF-aPv.js.map +1 -0
  43. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +119 -0
  44. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +1 -0
  45. package/dist/_chunks/segment-classify-Byy425ng.js +176 -0
  46. package/dist/_chunks/segment-classify-Byy425ng.js.map +1 -0
  47. package/dist/_chunks/segment-context-ZDnXDkbz.js +34 -0
  48. package/dist/_chunks/segment-context-ZDnXDkbz.js.map +1 -0
  49. package/dist/_chunks/sizeof-lXffQ1Vr.js +35 -0
  50. package/dist/_chunks/sizeof-lXffQ1Vr.js.map +1 -0
  51. package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-BOWsq18U.js} +1 -1
  52. package/dist/_chunks/ssr-data-BOWsq18U.js.map +1 -0
  53. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-DFvWd-EA.js} +71 -26
  54. package/dist/_chunks/use-query-states-DFvWd-EA.js.map +1 -0
  55. package/dist/_chunks/use-segment-params-D1CzlgBo.js +151 -0
  56. package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +1 -0
  57. package/dist/_chunks/walkers-BtTlKviE.js +1002 -0
  58. package/dist/_chunks/walkers-BtTlKviE.js.map +1 -0
  59. package/dist/adapters/build-output-helper.d.ts +29 -0
  60. package/dist/adapters/build-output-helper.d.ts.map +1 -0
  61. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  62. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  63. package/dist/adapters/cloudflare-dev.js +73 -0
  64. package/dist/adapters/cloudflare-dev.js.map +1 -0
  65. package/dist/adapters/cloudflare-kv-cache.d.ts +65 -0
  66. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  67. package/dist/adapters/cloudflare-kv-cache.js +124 -0
  68. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  69. package/dist/adapters/cloudflare.d.ts +189 -21
  70. package/dist/adapters/cloudflare.d.ts.map +1 -1
  71. package/dist/adapters/cloudflare.js +2 -188
  72. package/dist/adapters/compress-module.d.ts +5 -4
  73. package/dist/adapters/compress-module.d.ts.map +1 -1
  74. package/dist/adapters/nitro.d.ts +41 -3
  75. package/dist/adapters/nitro.d.ts.map +1 -1
  76. package/dist/adapters/nitro.js +224 -172
  77. package/dist/adapters/nitro.js.map +1 -1
  78. package/dist/adapters/shared.d.ts +6 -0
  79. package/dist/adapters/shared.d.ts.map +1 -0
  80. package/dist/adapters/types.d.ts +2 -6
  81. package/dist/adapters/types.d.ts.map +1 -1
  82. package/dist/cache/cache-api.d.ts +48 -0
  83. package/dist/cache/cache-api.d.ts.map +1 -0
  84. package/dist/cache/handler-store.d.ts +33 -0
  85. package/dist/cache/handler-store.d.ts.map +1 -0
  86. package/dist/cache/index.d.ts +31 -8
  87. package/dist/cache/index.d.ts.map +1 -1
  88. package/dist/cache/index.js +3 -326
  89. package/dist/cache/invalidation-epoch.d.ts +43 -0
  90. package/dist/cache/invalidation-epoch.d.ts.map +1 -0
  91. package/dist/cache/json-lossy-check.d.ts +11 -0
  92. package/dist/cache/json-lossy-check.d.ts.map +1 -0
  93. package/dist/cache/redis-handler.d.ts +140 -8
  94. package/dist/cache/redis-handler.d.ts.map +1 -1
  95. package/dist/cache/singleflight.d.ts +19 -2
  96. package/dist/cache/singleflight.d.ts.map +1 -1
  97. package/dist/cache/sizeof.d.ts +22 -0
  98. package/dist/cache/sizeof.d.ts.map +1 -0
  99. package/dist/cache/stable-stringify.d.ts +9 -0
  100. package/dist/cache/stable-stringify.d.ts.map +1 -1
  101. package/dist/cache/store.d.ts +53 -0
  102. package/dist/cache/store.d.ts.map +1 -0
  103. package/dist/cache/stores/cloudflare-kv.d.ts +38 -0
  104. package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -0
  105. package/dist/cache/stores/cloudflare-kv.js +29 -0
  106. package/dist/cache/stores/cloudflare-kv.js.map +1 -0
  107. package/dist/cache/stores/memory.d.ts +42 -0
  108. package/dist/cache/stores/memory.d.ts.map +1 -0
  109. package/dist/cache/stores/memory.js +90 -0
  110. package/dist/cache/stores/memory.js.map +1 -0
  111. package/dist/cache/stores/redis.d.ts +69 -0
  112. package/dist/cache/stores/redis.d.ts.map +1 -0
  113. package/dist/cache/stores/redis.js +35 -0
  114. package/dist/cache/stores/redis.js.map +1 -0
  115. package/dist/cache/stores/vercel.d.ts +36 -0
  116. package/dist/cache/stores/vercel.d.ts.map +1 -0
  117. package/dist/cache/stores/vercel.js +33 -0
  118. package/dist/cache/stores/vercel.js.map +1 -0
  119. package/dist/cache/tag-aware-handler.d.ts +52 -0
  120. package/dist/cache/tag-aware-handler.d.ts.map +1 -0
  121. package/dist/cache/timber-cache.d.ts +20 -10
  122. package/dist/cache/timber-cache.d.ts.map +1 -1
  123. package/dist/cdn/cloudflare-purge.d.ts +23 -0
  124. package/dist/cdn/cloudflare-purge.d.ts.map +1 -0
  125. package/dist/cdn/fastly-purge.d.ts +25 -0
  126. package/dist/cdn/fastly-purge.d.ts.map +1 -0
  127. package/dist/cdn/headers.d.ts +97 -0
  128. package/dist/cdn/headers.d.ts.map +1 -0
  129. package/dist/cdn/index.d.ts +5 -0
  130. package/dist/cdn/index.d.ts.map +1 -0
  131. package/dist/cdn/purge-store.d.ts +23 -0
  132. package/dist/cdn/purge-store.d.ts.map +1 -0
  133. package/dist/cdn/workers-cache-purge.d.ts +16 -0
  134. package/dist/cdn/workers-cache-purge.d.ts.map +1 -0
  135. package/dist/cli-schema-sync.d.ts +59 -0
  136. package/dist/cli-schema-sync.d.ts.map +1 -0
  137. package/dist/cli.d.ts +35 -2
  138. package/dist/cli.d.ts.map +1 -1
  139. package/dist/cli.js +113 -34
  140. package/dist/cli.js.map +1 -1
  141. package/dist/client/browser-dev.d.ts +37 -1
  142. package/dist/client/browser-dev.d.ts.map +1 -1
  143. package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
  144. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  145. package/dist/client/browser-entry/hmr.d.ts +21 -0
  146. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  147. package/dist/client/browser-entry/hydrate.d.ts +46 -0
  148. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  149. package/dist/client/browser-entry/index.d.ts +29 -0
  150. package/dist/client/browser-entry/index.d.ts.map +1 -0
  151. package/dist/client/browser-entry/post-hydration.d.ts +26 -0
  152. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  153. package/dist/client/browser-entry/router-init.d.ts +27 -0
  154. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  155. package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
  156. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  157. package/dist/client/browser-entry/scroll.d.ts +28 -0
  158. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  159. package/dist/client/error-boundary.d.ts +12 -5
  160. package/dist/client/error-boundary.d.ts.map +1 -1
  161. package/dist/client/error-boundary.js +47 -10
  162. package/dist/client/error-boundary.js.map +1 -1
  163. package/dist/client/error-reconstituter.d.ts +61 -0
  164. package/dist/client/error-reconstituter.d.ts.map +1 -0
  165. package/dist/client/form.d.ts +16 -27
  166. package/dist/client/form.d.ts.map +1 -1
  167. package/dist/client/history.d.ts +21 -6
  168. package/dist/client/history.d.ts.map +1 -1
  169. package/dist/client/index.d.ts +10 -24
  170. package/dist/client/index.d.ts.map +1 -1
  171. package/dist/client/index.js +185 -1134
  172. package/dist/client/index.js.map +1 -1
  173. package/dist/client/internal.d.ts +19 -0
  174. package/dist/client/internal.d.ts.map +1 -0
  175. package/dist/client/internal.js +887 -0
  176. package/dist/client/internal.js.map +1 -0
  177. package/dist/client/link.d.ts +69 -60
  178. package/dist/client/link.d.ts.map +1 -1
  179. package/dist/client/navigation-api.d.ts +121 -0
  180. package/dist/client/navigation-api.d.ts.map +1 -0
  181. package/dist/client/navigation-context.d.ts +3 -2
  182. package/dist/client/navigation-context.d.ts.map +1 -1
  183. package/dist/client/navigation-root.d.ts +119 -0
  184. package/dist/client/navigation-root.d.ts.map +1 -0
  185. package/dist/client/nuqs-adapter.d.ts +1 -1
  186. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  187. package/dist/client/router-ref.d.ts +1 -1
  188. package/dist/client/router.d.ts +99 -14
  189. package/dist/client/router.d.ts.map +1 -1
  190. package/dist/client/rsc-fetch.d.ts +48 -15
  191. package/dist/client/rsc-fetch.d.ts.map +1 -1
  192. package/dist/client/segment-cache.d.ts +26 -7
  193. package/dist/client/segment-cache.d.ts.map +1 -1
  194. package/dist/client/segment-outlet.d.ts +57 -0
  195. package/dist/client/segment-outlet.d.ts.map +1 -0
  196. package/dist/client/segment-update-context.d.ts +21 -0
  197. package/dist/client/segment-update-context.d.ts.map +1 -0
  198. package/dist/client/shallow-url.d.ts +10 -0
  199. package/dist/client/shallow-url.d.ts.map +1 -0
  200. package/dist/client/slot-context.d.ts +31 -0
  201. package/dist/client/slot-context.d.ts.map +1 -0
  202. package/dist/client/slot-outlet.d.ts +16 -0
  203. package/dist/client/slot-outlet.d.ts.map +1 -0
  204. package/dist/client/slot-provider.d.ts +25 -0
  205. package/dist/client/slot-provider.d.ts.map +1 -0
  206. package/dist/client/ssr-data.d.ts +13 -4
  207. package/dist/client/ssr-data.d.ts.map +1 -1
  208. package/dist/client/state.d.ts +1 -1
  209. package/dist/client/top-loader.d.ts +5 -5
  210. package/dist/client/top-loader.d.ts.map +1 -1
  211. package/dist/client/use-cookie.d.ts +12 -0
  212. package/dist/client/use-cookie.d.ts.map +1 -1
  213. package/dist/client/use-link-status.d.ts +5 -5
  214. package/dist/client/use-link-status.d.ts.map +1 -1
  215. package/dist/client/use-pathname.d.ts.map +1 -1
  216. package/dist/client/use-pending-navigation.d.ts +23 -0
  217. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  218. package/dist/client/use-query-states.d.ts +1 -1
  219. package/dist/client/use-query-states.d.ts.map +1 -1
  220. package/dist/client/use-router.d.ts +1 -1
  221. package/dist/client/use-router.d.ts.map +1 -1
  222. package/dist/client/use-search-params.d.ts +12 -5
  223. package/dist/client/use-search-params.d.ts.map +1 -1
  224. package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +8 -6
  225. package/dist/client/use-segment-params.d.ts.map +1 -0
  226. package/dist/codec.d.ts +69 -0
  227. package/dist/codec.d.ts.map +1 -0
  228. package/dist/codec.js +76 -0
  229. package/dist/codec.js.map +1 -0
  230. package/dist/config-types.d.ts +284 -0
  231. package/dist/config-types.d.ts.map +1 -0
  232. package/dist/config-validation.d.ts +51 -0
  233. package/dist/config-validation.d.ts.map +1 -0
  234. package/dist/content/index.d.ts +1 -10
  235. package/dist/content/index.d.ts.map +1 -1
  236. package/dist/content/index.js +0 -2
  237. package/dist/cookies/define-cookie.d.ts +58 -25
  238. package/dist/cookies/define-cookie.d.ts.map +1 -1
  239. package/dist/cookies/index.d.ts +2 -1
  240. package/dist/cookies/index.d.ts.map +1 -1
  241. package/dist/cookies/index.js +257 -36
  242. package/dist/cookies/index.js.map +1 -1
  243. package/dist/cookies/json-cookie.d.ts +64 -0
  244. package/dist/cookies/json-cookie.d.ts.map +1 -0
  245. package/dist/cookies/validation.d.ts +34 -0
  246. package/dist/cookies/validation.d.ts.map +1 -0
  247. package/dist/dev-tools/404-page.d.ts +50 -0
  248. package/dist/dev-tools/404-page.d.ts.map +1 -0
  249. package/dist/dev-tools/browser-logs.d.ts +40 -0
  250. package/dist/dev-tools/browser-logs.d.ts.map +1 -0
  251. package/dist/dev-tools/dev-page-shell.d.ts +78 -0
  252. package/dist/dev-tools/dev-page-shell.d.ts.map +1 -0
  253. package/dist/dev-tools/error-page.d.ts +32 -0
  254. package/dist/dev-tools/error-page.d.ts.map +1 -0
  255. package/dist/dev-tools/holding-server.d.ts +54 -0
  256. package/dist/dev-tools/holding-server.d.ts.map +1 -0
  257. package/dist/dev-tools/hydration-overlay.d.ts +11 -0
  258. package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
  259. package/dist/dev-tools/index.d.ts +31 -0
  260. package/dist/dev-tools/index.d.ts.map +1 -0
  261. package/dist/dev-tools/instrumentation.d.ts +59 -0
  262. package/dist/dev-tools/instrumentation.d.ts.map +1 -0
  263. package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
  264. package/dist/dev-tools/logger.d.ts.map +1 -0
  265. package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +17 -3
  266. package/dist/dev-tools/logs.d.ts.map +1 -0
  267. package/dist/dev-tools/overlay.d.ts +91 -0
  268. package/dist/dev-tools/overlay.d.ts.map +1 -0
  269. package/dist/dev-tools/stack-classifier.d.ts +34 -0
  270. package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
  271. package/dist/dev-tools/terminal.d.ts +28 -0
  272. package/dist/dev-tools/terminal.d.ts.map +1 -0
  273. package/dist/fonts/ast-walk.d.ts +68 -0
  274. package/dist/fonts/ast-walk.d.ts.map +1 -0
  275. package/dist/fonts/ast.d.ts +110 -6
  276. package/dist/fonts/ast.d.ts.map +1 -1
  277. package/dist/fonts/bundle.d.ts +50 -0
  278. package/dist/fonts/bundle.d.ts.map +1 -0
  279. package/dist/fonts/dev-middleware.d.ts +22 -0
  280. package/dist/fonts/dev-middleware.d.ts.map +1 -0
  281. package/dist/fonts/fallbacks.d.ts +0 -7
  282. package/dist/fonts/fallbacks.d.ts.map +1 -1
  283. package/dist/fonts/google.d.ts +4 -2
  284. package/dist/fonts/google.d.ts.map +1 -1
  285. package/dist/fonts/local.d.ts +4 -4
  286. package/dist/fonts/local.d.ts.map +1 -1
  287. package/dist/fonts/paths.d.ts +43 -0
  288. package/dist/fonts/paths.d.ts.map +1 -0
  289. package/dist/fonts/pipeline.d.ts +177 -0
  290. package/dist/fonts/pipeline.d.ts.map +1 -0
  291. package/dist/fonts/transform.d.ts +82 -0
  292. package/dist/fonts/transform.d.ts.map +1 -0
  293. package/dist/fonts/types.d.ts +47 -1
  294. package/dist/fonts/types.d.ts.map +1 -1
  295. package/dist/fonts/virtual-modules.d.ts +77 -0
  296. package/dist/fonts/virtual-modules.d.ts.map +1 -0
  297. package/dist/index.d.ts +46 -180
  298. package/dist/index.d.ts.map +1 -1
  299. package/dist/index.js +9243 -14093
  300. package/dist/index.js.map +1 -1
  301. package/dist/params/codec-registry.d.ts +26 -0
  302. package/dist/params/codec-registry.d.ts.map +1 -0
  303. package/dist/params/define-schema.d.ts +81 -0
  304. package/dist/params/define-schema.d.ts.map +1 -0
  305. package/dist/params/index.d.ts +5 -0
  306. package/dist/params/index.d.ts.map +1 -0
  307. package/dist/params/index.js +34 -0
  308. package/dist/params/index.js.map +1 -0
  309. package/dist/params/resolve-schema.d.ts +34 -0
  310. package/dist/params/resolve-schema.d.ts.map +1 -0
  311. package/dist/plugin-context.d.ts +217 -0
  312. package/dist/plugin-context.d.ts.map +1 -0
  313. package/dist/plugins/adapter-build.d.ts +21 -1
  314. package/dist/plugins/adapter-build.d.ts.map +1 -1
  315. package/dist/plugins/build-manifest.d.ts +7 -3
  316. package/dist/plugins/build-manifest.d.ts.map +1 -1
  317. package/dist/plugins/build-report.d.ts +43 -7
  318. package/dist/plugins/build-report.d.ts.map +1 -1
  319. package/dist/plugins/cache.d.ts +64 -0
  320. package/dist/plugins/cache.d.ts.map +1 -0
  321. package/dist/plugins/callsite-ast.d.ts +117 -0
  322. package/dist/plugins/callsite-ast.d.ts.map +1 -0
  323. package/dist/plugins/callsite-jsx.d.ts +35 -0
  324. package/dist/plugins/callsite-jsx.d.ts.map +1 -0
  325. package/dist/plugins/chunks.d.ts +11 -4
  326. package/dist/plugins/chunks.d.ts.map +1 -1
  327. package/dist/plugins/client-chunks.d.ts +40 -0
  328. package/dist/plugins/client-chunks.d.ts.map +1 -0
  329. package/dist/plugins/cloudflare-wasm.d.ts +21 -0
  330. package/dist/plugins/cloudflare-wasm.d.ts.map +1 -0
  331. package/dist/plugins/content.d.ts +1 -1
  332. package/dist/plugins/content.d.ts.map +1 -1
  333. package/dist/plugins/dev-server.d.ts +17 -1
  334. package/dist/plugins/dev-server.d.ts.map +1 -1
  335. package/dist/plugins/entries.d.ts +28 -4
  336. package/dist/plugins/entries.d.ts.map +1 -1
  337. package/dist/plugins/fonts.d.ts +16 -73
  338. package/dist/plugins/fonts.d.ts.map +1 -1
  339. package/dist/plugins/mdx.d.ts +1 -1
  340. package/dist/plugins/mdx.d.ts.map +1 -1
  341. package/dist/plugins/prebuilt-capture.d.ts +60 -0
  342. package/dist/plugins/prebuilt-capture.d.ts.map +1 -0
  343. package/dist/plugins/prebuilt-options-analysis.d.ts +40 -0
  344. package/dist/plugins/prebuilt-options-analysis.d.ts.map +1 -0
  345. package/dist/plugins/prebuilt.d.ts +82 -0
  346. package/dist/plugins/prebuilt.d.ts.map +1 -0
  347. package/dist/plugins/prerender-sugar.d.ts +42 -0
  348. package/dist/plugins/prerender-sugar.d.ts.map +1 -0
  349. package/dist/plugins/request-dep.d.ts +21 -0
  350. package/dist/plugins/request-dep.d.ts.map +1 -0
  351. package/dist/plugins/routing.d.ts +1 -1
  352. package/dist/plugins/routing.d.ts.map +1 -1
  353. package/dist/plugins/server-bundle.d.ts.map +1 -1
  354. package/dist/plugins/shims.d.ts +29 -5
  355. package/dist/plugins/shims.d.ts.map +1 -1
  356. package/dist/plugins/static-build.d.ts +5 -26
  357. package/dist/plugins/static-build.d.ts.map +1 -1
  358. package/dist/routing/codegen-shared.d.ts +67 -0
  359. package/dist/routing/codegen-shared.d.ts.map +1 -0
  360. package/dist/routing/codegen-types.d.ts +64 -0
  361. package/dist/routing/codegen-types.d.ts.map +1 -0
  362. package/dist/routing/codegen.d.ts +7 -2
  363. package/dist/routing/codegen.d.ts.map +1 -1
  364. package/dist/routing/convention-lint.d.ts +41 -0
  365. package/dist/routing/convention-lint.d.ts.map +1 -0
  366. package/dist/routing/export-detect.d.ts +56 -0
  367. package/dist/routing/export-detect.d.ts.map +1 -0
  368. package/dist/routing/file-cache.d.ts +8 -0
  369. package/dist/routing/file-cache.d.ts.map +1 -0
  370. package/dist/routing/index.d.ts +7 -1
  371. package/dist/routing/index.d.ts.map +1 -1
  372. package/dist/routing/index.js +4 -2
  373. package/dist/routing/interception.d.ts +0 -5
  374. package/dist/routing/interception.d.ts.map +1 -1
  375. package/dist/routing/link-codegen.d.ts +90 -0
  376. package/dist/routing/link-codegen.d.ts.map +1 -0
  377. package/dist/routing/manifest-codegen.d.ts +32 -0
  378. package/dist/routing/manifest-codegen.d.ts.map +1 -0
  379. package/dist/routing/scanner.d.ts +1 -10
  380. package/dist/routing/scanner.d.ts.map +1 -1
  381. package/dist/routing/schema-validation.d.ts +35 -0
  382. package/dist/routing/schema-validation.d.ts.map +1 -0
  383. package/dist/routing/segment-classify.d.ts +81 -0
  384. package/dist/routing/segment-classify.d.ts.map +1 -0
  385. package/dist/routing/segment-codegen.d.ts +38 -0
  386. package/dist/routing/segment-codegen.d.ts.map +1 -0
  387. package/dist/routing/types.d.ts +81 -25
  388. package/dist/routing/types.d.ts.map +1 -1
  389. package/dist/routing/walkers.d.ts +51 -0
  390. package/dist/routing/walkers.d.ts.map +1 -0
  391. package/dist/rsc-runtime/rsc.d.ts +1 -1
  392. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  393. package/dist/rsc-runtime/ssr.d.ts +12 -0
  394. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  395. package/dist/schema-bridge.d.ts +91 -0
  396. package/dist/schema-bridge.d.ts.map +1 -0
  397. package/dist/search-params/define.d.ts +188 -0
  398. package/dist/search-params/define.d.ts.map +1 -0
  399. package/dist/search-params/index.d.ts +4 -7
  400. package/dist/search-params/index.d.ts.map +1 -1
  401. package/dist/search-params/index.js +34 -441
  402. package/dist/search-params/index.js.map +1 -1
  403. package/dist/search-params/registry.d.ts +2 -2
  404. package/dist/search-params/registry.d.ts.map +1 -1
  405. package/dist/search-params/wrappers.d.ts +53 -0
  406. package/dist/search-params/wrappers.d.ts.map +1 -0
  407. package/dist/segment-params/define.d.ts +89 -0
  408. package/dist/segment-params/define.d.ts.map +1 -0
  409. package/dist/segment-params/index.d.ts +3 -0
  410. package/dist/segment-params/index.d.ts.map +1 -0
  411. package/dist/segment-params/index.js +2 -0
  412. package/dist/server/access-gate.d.ts +8 -3
  413. package/dist/server/access-gate.d.ts.map +1 -1
  414. package/dist/server/action-client.d.ts +42 -7
  415. package/dist/server/action-client.d.ts.map +1 -1
  416. package/dist/server/action-encryption.d.ts +76 -0
  417. package/dist/server/action-encryption.d.ts.map +1 -0
  418. package/dist/server/action-handler.d.ts +35 -1
  419. package/dist/server/action-handler.d.ts.map +1 -1
  420. package/dist/server/actions.d.ts +6 -30
  421. package/dist/server/actions.d.ts.map +1 -1
  422. package/dist/server/als-registry.d.ts +93 -11
  423. package/dist/server/als-registry.d.ts.map +1 -1
  424. package/dist/server/asset-headers.d.ts +8 -18
  425. package/dist/server/asset-headers.d.ts.map +1 -1
  426. package/dist/server/body-limits.d.ts.map +1 -1
  427. package/dist/server/build-manifest.d.ts +12 -29
  428. package/dist/server/build-manifest.d.ts.map +1 -1
  429. package/dist/server/canonicalize.d.ts +10 -0
  430. package/dist/server/canonicalize.d.ts.map +1 -1
  431. package/dist/server/coalesce-tick.d.ts +40 -0
  432. package/dist/server/coalesce-tick.d.ts.map +1 -0
  433. package/dist/server/cookie-context.d.ts +170 -0
  434. package/dist/server/cookie-context.d.ts.map +1 -0
  435. package/dist/server/cookie-parsing.d.ts +65 -0
  436. package/dist/server/cookie-parsing.d.ts.map +1 -0
  437. package/dist/server/csrf.d.ts +3 -2
  438. package/dist/server/csrf.d.ts.map +1 -1
  439. package/dist/server/default-logger.d.ts +22 -0
  440. package/dist/server/default-logger.d.ts.map +1 -0
  441. package/dist/server/deny-boundary.d.ts +117 -0
  442. package/dist/server/deny-boundary.d.ts.map +1 -0
  443. package/dist/server/deny-renderer.d.ts +2 -2
  444. package/dist/server/deny-renderer.d.ts.map +1 -1
  445. package/dist/server/dev-source-map.d.ts +22 -0
  446. package/dist/server/dev-source-map.d.ts.map +1 -0
  447. package/dist/server/early-hints-sender.d.ts.map +1 -1
  448. package/dist/server/early-hints.d.ts +13 -11
  449. package/dist/server/early-hints.d.ts.map +1 -1
  450. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  451. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  452. package/dist/server/fallback-error.d.ts +12 -7
  453. package/dist/server/fallback-error.d.ts.map +1 -1
  454. package/dist/server/flight-injection-state.d.ts +66 -0
  455. package/dist/server/flight-injection-state.d.ts.map +1 -0
  456. package/dist/server/flight-scripts.d.ts +42 -0
  457. package/dist/server/flight-scripts.d.ts.map +1 -0
  458. package/dist/server/form-data.d.ts +41 -0
  459. package/dist/server/form-data.d.ts.map +1 -1
  460. package/dist/server/html-injector-core.d.ts +242 -0
  461. package/dist/server/html-injector-core.d.ts.map +1 -0
  462. package/dist/server/html-injectors.d.ts +82 -41
  463. package/dist/server/html-injectors.d.ts.map +1 -1
  464. package/dist/server/index.d.ts +11 -47
  465. package/dist/server/index.d.ts.map +1 -1
  466. package/dist/server/index.js +182 -2906
  467. package/dist/server/index.js.map +1 -1
  468. package/dist/server/internal.d.ts +49 -0
  469. package/dist/server/internal.d.ts.map +1 -0
  470. package/dist/server/internal.js +3892 -0
  471. package/dist/server/internal.js.map +1 -0
  472. package/dist/server/logger.d.ts +39 -7
  473. package/dist/server/logger.d.ts.map +1 -1
  474. package/dist/server/metadata-routes.d.ts +60 -11
  475. package/dist/server/metadata-routes.d.ts.map +1 -1
  476. package/dist/server/metadata.d.ts +8 -0
  477. package/dist/server/metadata.d.ts.map +1 -1
  478. package/dist/server/middleware-runner.d.ts +19 -4
  479. package/dist/server/middleware-runner.d.ts.map +1 -1
  480. package/dist/server/node-stream-transforms.d.ts +119 -0
  481. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  482. package/dist/server/param-coercion.d.ts +54 -0
  483. package/dist/server/param-coercion.d.ts.map +1 -0
  484. package/dist/server/pipeline-helpers.d.ts +95 -0
  485. package/dist/server/pipeline-helpers.d.ts.map +1 -0
  486. package/dist/server/pipeline-interception.d.ts +1 -1
  487. package/dist/server/pipeline-interception.d.ts.map +1 -1
  488. package/dist/server/pipeline-metadata.d.ts +6 -0
  489. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  490. package/dist/server/pipeline-outcome.d.ts +49 -0
  491. package/dist/server/pipeline-outcome.d.ts.map +1 -0
  492. package/dist/server/pipeline-phases.d.ts +59 -0
  493. package/dist/server/pipeline-phases.d.ts.map +1 -0
  494. package/dist/server/pipeline.d.ts +140 -19
  495. package/dist/server/pipeline.d.ts.map +1 -1
  496. package/dist/server/port-resolution.d.ts +117 -0
  497. package/dist/server/port-resolution.d.ts.map +1 -0
  498. package/dist/server/prebuilt/cache-key.d.ts +62 -0
  499. package/dist/server/prebuilt/cache-key.d.ts.map +1 -0
  500. package/dist/server/prebuilt/capture-state.d.ts +57 -0
  501. package/dist/server/prebuilt/capture-state.d.ts.map +1 -0
  502. package/dist/server/prebuilt/key-discipline.d.ts +23 -0
  503. package/dist/server/prebuilt/key-discipline.d.ts.map +1 -0
  504. package/dist/server/prebuilt/manifest-tag-index.d.ts +27 -0
  505. package/dist/server/prebuilt/manifest-tag-index.d.ts.map +1 -0
  506. package/dist/server/prebuilt/overlay.d.ts +100 -0
  507. package/dist/server/prebuilt/overlay.d.ts.map +1 -0
  508. package/dist/server/prebuilt/payload-source.d.ts +78 -0
  509. package/dist/server/prebuilt/payload-source.d.ts.map +1 -0
  510. package/dist/server/prebuilt/slots.d.ts +99 -0
  511. package/dist/server/prebuilt/slots.d.ts.map +1 -0
  512. package/dist/server/prebuilt/synthetic-store.d.ts +66 -0
  513. package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
  514. package/dist/server/prebuilt-builder.d.ts +120 -0
  515. package/dist/server/prebuilt-builder.d.ts.map +1 -0
  516. package/dist/server/prebuilt-runtime.d.ts +111 -0
  517. package/dist/server/prebuilt-runtime.d.ts.map +1 -0
  518. package/dist/server/primitives.d.ts +88 -43
  519. package/dist/server/primitives.d.ts.map +1 -1
  520. package/dist/server/render-timeout.d.ts +51 -0
  521. package/dist/server/render-timeout.d.ts.map +1 -0
  522. package/dist/server/render-utils.d.ts +25 -0
  523. package/dist/server/render-utils.d.ts.map +1 -0
  524. package/dist/server/request-context.d.ts +62 -107
  525. package/dist/server/request-context.d.ts.map +1 -1
  526. package/dist/server/request-dep.d.ts +15 -0
  527. package/dist/server/request-dep.d.ts.map +1 -0
  528. package/dist/server/route-element-builder.d.ts +53 -25
  529. package/dist/server/route-element-builder.d.ts.map +1 -1
  530. package/dist/server/route-handler.d.ts.map +1 -1
  531. package/dist/server/route-matcher.d.ts +25 -36
  532. package/dist/server/route-matcher.d.ts.map +1 -1
  533. package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
  534. package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
  535. package/dist/server/rsc-entry/api-handler.d.ts +12 -3
  536. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  537. package/dist/server/rsc-entry/deny-fallback.d.ts +29 -0
  538. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -0
  539. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  540. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  541. package/dist/server/rsc-entry/helpers.d.ts +69 -37
  542. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  543. package/dist/server/rsc-entry/index.d.ts +28 -6
  544. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  545. package/dist/server/rsc-entry/render-route.d.ts +51 -0
  546. package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
  547. package/dist/server/rsc-entry/revalidate-renderer.d.ts +108 -0
  548. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -0
  549. package/dist/server/rsc-entry/rsc-payload.d.ts +6 -6
  550. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  551. package/dist/server/rsc-entry/rsc-stream.d.ts +25 -1
  552. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  553. package/dist/server/rsc-entry/ssr-bridge.d.ts +5 -1
  554. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  555. package/dist/server/rsc-entry/ssr-renderer.d.ts +36 -4
  556. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  557. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +89 -0
  558. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
  559. package/dist/server/safe-load.d.ts +46 -0
  560. package/dist/server/safe-load.d.ts.map +1 -0
  561. package/dist/server/sensitive-fields.d.ts +74 -0
  562. package/dist/server/sensitive-fields.d.ts.map +1 -0
  563. package/dist/server/sitemap-generator.d.ts +129 -0
  564. package/dist/server/sitemap-generator.d.ts.map +1 -0
  565. package/dist/server/sitemap-handler.d.ts +22 -0
  566. package/dist/server/sitemap-handler.d.ts.map +1 -0
  567. package/dist/server/slot-resolver.d.ts +66 -5
  568. package/dist/server/slot-resolver.d.ts.map +1 -1
  569. package/dist/server/ssr-bridge-types.d.ts +121 -0
  570. package/dist/server/ssr-bridge-types.d.ts.map +1 -0
  571. package/dist/server/ssr-entry.d.ts +2 -43
  572. package/dist/server/ssr-entry.d.ts.map +1 -1
  573. package/dist/server/ssr-render.d.ts +64 -21
  574. package/dist/server/ssr-render.d.ts.map +1 -1
  575. package/dist/server/ssr-wrappers.d.ts +50 -0
  576. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  577. package/dist/server/state-tree-diff.d.ts +72 -9
  578. package/dist/server/state-tree-diff.d.ts.map +1 -1
  579. package/dist/server/status-code-resolver.d.ts +22 -11
  580. package/dist/server/status-code-resolver.d.ts.map +1 -1
  581. package/dist/server/stream-utils.d.ts +47 -0
  582. package/dist/server/stream-utils.d.ts.map +1 -0
  583. package/dist/server/tracing.d.ts +44 -9
  584. package/dist/server/tracing.d.ts.map +1 -1
  585. package/dist/server/tree-builder.d.ts +69 -30
  586. package/dist/server/tree-builder.d.ts.map +1 -1
  587. package/dist/server/tree-match.d.ts +49 -0
  588. package/dist/server/tree-match.d.ts.map +1 -0
  589. package/dist/server/types.d.ts +71 -6
  590. package/dist/server/types.d.ts.map +1 -1
  591. package/dist/server/utils/escape-html.d.ts +14 -0
  592. package/dist/server/utils/escape-html.d.ts.map +1 -0
  593. package/dist/server/utils/mdx-file.d.ts +15 -0
  594. package/dist/server/utils/mdx-file.d.ts.map +1 -0
  595. package/dist/server/version-skew.d.ts +61 -0
  596. package/dist/server/version-skew.d.ts.map +1 -0
  597. package/dist/server/workers-cache-bridge.d.ts +26 -0
  598. package/dist/server/workers-cache-bridge.d.ts.map +1 -0
  599. package/dist/shared/href-validation.d.ts +49 -0
  600. package/dist/shared/href-validation.d.ts.map +1 -0
  601. package/dist/shared/merge-search-params.d.ts +22 -0
  602. package/dist/shared/merge-search-params.d.ts.map +1 -0
  603. package/dist/shared/redirect-type.d.ts +17 -0
  604. package/dist/shared/redirect-type.d.ts.map +1 -0
  605. package/dist/shims/font-google.d.ts +1 -1
  606. package/dist/shims/font-google.d.ts.map +1 -1
  607. package/dist/shims/font-google.js +42 -0
  608. package/dist/shims/font-google.js.map +1 -0
  609. package/dist/shims/font-local.d.ts +26 -0
  610. package/dist/shims/font-local.d.ts.map +1 -0
  611. package/dist/shims/font-local.js +20 -0
  612. package/dist/shims/font-local.js.map +1 -0
  613. package/dist/shims/headers.d.ts +53 -1
  614. package/dist/shims/headers.d.ts.map +1 -1
  615. package/dist/shims/image.d.ts +120 -120
  616. package/dist/shims/image.d.ts.map +1 -1
  617. package/dist/shims/navigation-client.d.ts +35 -11
  618. package/dist/shims/navigation-client.d.ts.map +1 -1
  619. package/dist/shims/navigation.d.ts +11 -5
  620. package/dist/shims/navigation.d.ts.map +1 -1
  621. package/dist/utils/state-machine.d.ts +80 -0
  622. package/dist/utils/state-machine.d.ts.map +1 -0
  623. package/docs/api/30-api-server.mdx +233 -0
  624. package/docs/api/31-api-client.mdx +161 -0
  625. package/docs/api/32-api-cache.mdx +311 -0
  626. package/docs/api/33-api-search-params.mdx +154 -0
  627. package/docs/api/34-api-config.mdx +325 -0
  628. package/docs/api/35-api-typescript.mdx +170 -0
  629. package/docs/api/36-cli.mdx +143 -0
  630. package/docs/learn/00-introduction.mdx +109 -0
  631. package/docs/learn/01-quick-start.mdx +94 -0
  632. package/docs/learn/02-pages-and-layouts.mdx +147 -0
  633. package/docs/learn/03-fetching-data.mdx +211 -0
  634. package/docs/learn/03b-access-control.mdx +130 -0
  635. package/docs/learn/04-loading-states.mdx +67 -0
  636. package/docs/learn/04b-the-flush-point.mdx +115 -0
  637. package/docs/learn/05-typed-params.mdx +275 -0
  638. package/docs/learn/06-forms-and-actions.mdx +146 -0
  639. package/docs/learn/07-typed-routes.mdx +127 -0
  640. package/docs/learn/08-streaming.mdx +146 -0
  641. package/docs/learn/09-caching.mdx +252 -0
  642. package/docs/learn/10-middleware.mdx +157 -0
  643. package/docs/learn/11-error-handling.mdx +156 -0
  644. package/docs/learn/12-client-navigation.mdx +176 -0
  645. package/docs/learn/13-configuration.mdx +162 -0
  646. package/docs/learn/14-deploying.mdx +264 -0
  647. package/docs/more/01-advanced-routing.mdx +173 -0
  648. package/docs/more/02-advanced-forms.mdx +137 -0
  649. package/docs/more/03-coming-from-nextjs.mdx +186 -0
  650. package/docs/more/04-metadata-and-fonts.mdx +193 -0
  651. package/docs/more/04b-mdx.mdx +209 -0
  652. package/docs/more/05-content-collections.mdx +90 -0
  653. package/docs/more/06-instrumentation.mdx +214 -0
  654. package/docs/more/07-security.mdx +129 -0
  655. package/docs/more/08-developer-experience.mdx +134 -0
  656. package/docs/more/40-why-timber.mdx +50 -0
  657. package/docs/more/41-timber-vs-nextjs.mdx +81 -0
  658. package/docs/more/42-timber-vs-others.mdx +68 -0
  659. package/docs/more/50-ai-agent-instructions.mdx +169 -0
  660. package/llms.txt +55 -0
  661. package/package.json +105 -26
  662. package/src/adapters/build-output-helper.ts +199 -0
  663. package/src/adapters/cloudflare-dev.ts +177 -0
  664. package/src/adapters/cloudflare-kv-cache.ts +204 -0
  665. package/src/adapters/cloudflare.ts +620 -129
  666. package/src/adapters/compress-module.ts +27 -92
  667. package/src/adapters/nitro.ts +266 -122
  668. package/src/adapters/raw-imports.d.ts +5 -0
  669. package/src/adapters/shared.ts +68 -0
  670. package/src/adapters/types.ts +2 -7
  671. package/src/adapters/wrangler.d.ts +7 -0
  672. package/src/cache/cache-api.ts +107 -0
  673. package/src/cache/handler-store.ts +76 -0
  674. package/src/cache/index.ts +114 -21
  675. package/src/cache/invalidation-epoch.ts +93 -0
  676. package/src/cache/json-lossy-check.ts +75 -0
  677. package/src/cache/redis-handler.ts +197 -19
  678. package/src/cache/singleflight.ts +64 -6
  679. package/src/cache/sizeof.ts +33 -0
  680. package/src/cache/stable-stringify.ts +65 -2
  681. package/src/cache/store.ts +71 -0
  682. package/src/cache/stores/cloudflare-kv.ts +52 -0
  683. package/src/cache/stores/memory.ts +125 -0
  684. package/src/cache/stores/redis.ts +97 -0
  685. package/src/cache/stores/vercel.ts +59 -0
  686. package/src/cache/tag-aware-handler.ts +237 -0
  687. package/src/cache/timber-cache.ts +161 -36
  688. package/src/cdn/cloudflare-purge.ts +50 -0
  689. package/src/cdn/fastly-purge.ts +63 -0
  690. package/src/cdn/headers.ts +153 -0
  691. package/src/cdn/index.ts +17 -0
  692. package/src/cdn/purge-store.ts +34 -0
  693. package/src/cdn/workers-cache-purge.ts +30 -0
  694. package/src/cli-schema-sync.ts +401 -0
  695. package/src/cli.ts +167 -34
  696. package/src/client/browser-dev.ts +156 -1
  697. package/src/client/browser-entry/action-dispatch.ts +124 -0
  698. package/src/client/browser-entry/hmr.ts +70 -0
  699. package/src/client/browser-entry/hydrate.ts +187 -0
  700. package/src/client/browser-entry/index.ts +113 -0
  701. package/src/client/browser-entry/post-hydration.ts +110 -0
  702. package/src/client/browser-entry/router-init.ts +286 -0
  703. package/src/client/browser-entry/rsc-stream.ts +157 -0
  704. package/src/client/browser-entry/scroll.ts +50 -0
  705. package/src/client/error-boundary.tsx +127 -22
  706. package/src/client/error-reconstituter.tsx +79 -0
  707. package/src/client/form.tsx +31 -32
  708. package/src/client/history.ts +21 -6
  709. package/src/client/index.ts +67 -45
  710. package/src/client/internal.ts +58 -0
  711. package/src/client/link.tsx +349 -150
  712. package/src/client/navigation-api.ts +345 -0
  713. package/src/client/navigation-context.ts +15 -7
  714. package/src/client/navigation-root.tsx +355 -0
  715. package/src/client/nuqs-adapter.tsx +16 -3
  716. package/src/client/router-ref.ts +1 -1
  717. package/src/client/router.ts +565 -212
  718. package/src/client/rsc-fetch.ts +215 -34
  719. package/src/client/segment-cache.ts +91 -17
  720. package/src/client/segment-outlet.tsx +141 -0
  721. package/src/client/segment-update-context.ts +42 -0
  722. package/src/client/shallow-url.ts +22 -0
  723. package/src/client/slot-context.ts +50 -0
  724. package/src/client/slot-outlet.tsx +22 -0
  725. package/src/client/slot-provider.tsx +32 -0
  726. package/src/client/ssr-data.ts +13 -5
  727. package/src/client/state.ts +2 -2
  728. package/src/client/top-loader.tsx +11 -9
  729. package/src/client/use-cookie.ts +60 -15
  730. package/src/client/use-link-status.ts +7 -7
  731. package/src/client/use-pathname.ts +1 -0
  732. package/src/client/use-pending-navigation.ts +40 -0
  733. package/src/client/use-query-states.ts +108 -10
  734. package/src/client/use-router.ts +4 -1
  735. package/src/client/use-search-params.ts +31 -44
  736. package/src/client/{use-params.ts → use-segment-params.ts} +9 -6
  737. package/src/codec.ts +149 -0
  738. package/src/config-types.ts +282 -0
  739. package/src/config-validation.ts +330 -0
  740. package/src/content/index.ts +5 -13
  741. package/src/cookies/define-cookie.ts +217 -53
  742. package/src/cookies/index.ts +12 -1
  743. package/src/cookies/json-cookie.ts +105 -0
  744. package/src/cookies/validation.ts +192 -0
  745. package/src/dev-tools/404-page.ts +286 -0
  746. package/src/dev-tools/browser-logs.ts +55 -0
  747. package/src/dev-tools/dev-page-shell.ts +260 -0
  748. package/src/dev-tools/error-page.ts +331 -0
  749. package/src/dev-tools/holding-server.ts +187 -0
  750. package/src/dev-tools/hydration-overlay.ts +158 -0
  751. package/src/dev-tools/index.ts +83 -0
  752. package/src/dev-tools/instrumentation.ts +213 -0
  753. package/src/{server/dev-logger.ts → dev-tools/logger.ts} +33 -51
  754. package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +122 -26
  755. package/src/dev-tools/overlay.ts +469 -0
  756. package/src/dev-tools/stack-classifier.ts +75 -0
  757. package/src/dev-tools/terminal.ts +182 -0
  758. package/src/fonts/ast-walk.ts +235 -0
  759. package/src/fonts/ast.ts +477 -126
  760. package/src/fonts/bundle.ts +138 -0
  761. package/src/fonts/dev-middleware.ts +85 -0
  762. package/src/fonts/fallbacks.ts +0 -23
  763. package/src/fonts/google.ts +100 -18
  764. package/src/fonts/local.ts +9 -8
  765. package/src/fonts/paths.ts +58 -0
  766. package/src/fonts/pipeline.ts +348 -0
  767. package/src/fonts/transform.ts +311 -0
  768. package/src/fonts/types.ts +52 -1
  769. package/src/fonts/virtual-modules.ts +179 -0
  770. package/src/index.ts +446 -352
  771. package/src/params/codec-registry.ts +34 -0
  772. package/src/params/define-schema.ts +115 -0
  773. package/src/params/index.ts +17 -0
  774. package/src/params/resolve-schema.ts +84 -0
  775. package/src/plugin-context.ts +432 -0
  776. package/src/plugins/adapter-build.ts +220 -7
  777. package/src/plugins/build-manifest.ts +177 -23
  778. package/src/plugins/build-report.ts +253 -35
  779. package/src/plugins/cache.ts +243 -0
  780. package/src/plugins/callsite-ast.ts +472 -0
  781. package/src/plugins/callsite-jsx.ts +243 -0
  782. package/src/plugins/chunks.ts +74 -5
  783. package/src/plugins/client-chunks.ts +185 -0
  784. package/src/plugins/cloudflare-wasm.ts +141 -0
  785. package/src/plugins/content.ts +1 -1
  786. package/src/plugins/dev-server.ts +284 -94
  787. package/src/plugins/entries.ts +134 -16
  788. package/src/plugins/fonts.ts +225 -660
  789. package/src/plugins/mdx.ts +47 -10
  790. package/src/plugins/prebuilt-capture.ts +217 -0
  791. package/src/plugins/prebuilt-options-analysis.ts +175 -0
  792. package/src/plugins/prebuilt.ts +655 -0
  793. package/src/plugins/prerender-sugar.ts +328 -0
  794. package/src/plugins/request-dep.ts +458 -0
  795. package/src/plugins/routing.ts +237 -241
  796. package/src/plugins/server-bundle.ts +89 -12
  797. package/src/plugins/shims.ts +241 -64
  798. package/src/plugins/static-build.ts +15 -90
  799. package/src/routing/codegen-shared.ts +115 -0
  800. package/src/routing/codegen-types.ts +65 -0
  801. package/src/routing/codegen.ts +372 -178
  802. package/src/routing/convention-lint.ts +394 -0
  803. package/src/routing/export-detect.ts +304 -0
  804. package/src/routing/file-cache.ts +23 -0
  805. package/src/routing/index.ts +10 -1
  806. package/src/routing/interception.ts +3 -22
  807. package/src/routing/link-codegen.ts +313 -0
  808. package/src/routing/manifest-codegen.ts +287 -0
  809. package/src/routing/scanner.ts +338 -189
  810. package/src/routing/schema-validation.ts +155 -0
  811. package/src/routing/segment-classify.ts +223 -0
  812. package/src/routing/segment-codegen.ts +98 -0
  813. package/src/routing/types.ts +82 -25
  814. package/src/routing/walkers.ts +90 -0
  815. package/src/rsc-runtime/rsc.ts +9 -0
  816. package/src/rsc-runtime/ssr.ts +50 -0
  817. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  818. package/src/schema-bridge.ts +253 -0
  819. package/src/search-params/define.ts +576 -0
  820. package/src/search-params/index.ts +14 -20
  821. package/src/search-params/registry.ts +2 -2
  822. package/src/search-params/wrappers.ts +101 -0
  823. package/src/segment-params/define.ts +249 -0
  824. package/src/segment-params/index.ts +9 -0
  825. package/src/server/access-gate.tsx +111 -34
  826. package/src/server/action-client.ts +120 -29
  827. package/src/server/action-encryption.ts +144 -0
  828. package/src/server/action-handler.ts +123 -33
  829. package/src/server/actions.ts +48 -54
  830. package/src/server/als-registry.ts +137 -20
  831. package/src/server/asset-headers.ts +15 -37
  832. package/src/server/body-limits.ts +10 -2
  833. package/src/server/build-manifest.ts +19 -56
  834. package/src/server/canonicalize.ts +6 -3
  835. package/src/server/coalesce-tick.ts +75 -0
  836. package/src/server/compress.ts +34 -7
  837. package/src/server/cookie-context.ts +484 -0
  838. package/src/server/cookie-parsing.ts +163 -0
  839. package/src/server/csrf.ts +39 -6
  840. package/src/server/default-logger.ts +99 -0
  841. package/src/server/deny-boundary.ts +314 -0
  842. package/src/server/deny-renderer.ts +85 -77
  843. package/src/server/dev-source-map.ts +31 -0
  844. package/src/server/early-hints-sender.ts +3 -2
  845. package/src/server/early-hints.ts +37 -27
  846. package/src/server/error-boundary-wrapper.ts +61 -22
  847. package/src/server/fallback-error.ts +79 -102
  848. package/src/server/flight-injection-state.ts +113 -0
  849. package/src/server/flight-scripts.ts +62 -0
  850. package/src/server/form-data.ts +124 -12
  851. package/src/server/html-injector-core.ts +495 -0
  852. package/src/server/html-injectors.ts +271 -254
  853. package/src/server/index.ts +31 -185
  854. package/src/server/internal.ts +181 -0
  855. package/src/server/logger.ts +72 -36
  856. package/src/server/metadata-routes.ts +205 -24
  857. package/src/server/metadata.ts +21 -0
  858. package/src/server/middleware-runner.ts +31 -4
  859. package/src/server/node-stream-transforms.ts +336 -0
  860. package/src/server/param-coercion.ts +207 -0
  861. package/src/server/pipeline-helpers.ts +204 -0
  862. package/src/server/pipeline-interception.ts +45 -18
  863. package/src/server/pipeline-metadata.ts +14 -0
  864. package/src/server/pipeline-outcome.ts +197 -0
  865. package/src/server/pipeline-phases.ts +545 -0
  866. package/src/server/pipeline.ts +274 -382
  867. package/src/server/port-resolution.ts +215 -0
  868. package/src/server/prebuilt/cache-key.ts +298 -0
  869. package/src/server/prebuilt/capture-state.ts +89 -0
  870. package/src/server/prebuilt/key-discipline.ts +53 -0
  871. package/src/server/prebuilt/manifest-tag-index.ts +46 -0
  872. package/src/server/prebuilt/overlay.ts +256 -0
  873. package/src/server/prebuilt/payload-source.ts +201 -0
  874. package/src/server/prebuilt/slots.ts +190 -0
  875. package/src/server/prebuilt/synthetic-store.ts +121 -0
  876. package/src/server/prebuilt-builder.ts +809 -0
  877. package/src/server/prebuilt-runtime.ts +815 -0
  878. package/src/server/primitives.ts +160 -83
  879. package/src/server/render-timeout.ts +108 -0
  880. package/src/server/render-utils.ts +31 -0
  881. package/src/server/request-context.ts +170 -337
  882. package/src/server/request-dep.ts +37 -0
  883. package/src/server/route-element-builder.ts +699 -295
  884. package/src/server/route-handler.ts +31 -4
  885. package/src/server/route-matcher.ts +158 -277
  886. package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
  887. package/src/server/rsc-entry/api-handler.ts +69 -32
  888. package/src/server/rsc-entry/deny-fallback.ts +92 -0
  889. package/src/server/rsc-entry/error-renderer.ts +306 -89
  890. package/src/server/rsc-entry/helpers.ts +210 -85
  891. package/src/server/rsc-entry/index.ts +332 -332
  892. package/src/server/rsc-entry/render-route.ts +300 -0
  893. package/src/server/rsc-entry/revalidate-renderer.ts +349 -0
  894. package/src/server/rsc-entry/rsc-payload.ts +102 -42
  895. package/src/server/rsc-entry/rsc-stream.ts +93 -13
  896. package/src/server/rsc-entry/ssr-bridge.ts +18 -5
  897. package/src/server/rsc-entry/ssr-renderer.ts +275 -43
  898. package/src/server/rsc-entry/wrap-action-dispatch.ts +186 -0
  899. package/src/server/safe-load.ts +60 -0
  900. package/src/server/sensitive-fields.ts +230 -0
  901. package/src/server/server-only-guard-noop.js +3 -0
  902. package/src/server/sitemap-generator.ts +345 -0
  903. package/src/server/sitemap-handler.ts +157 -0
  904. package/src/server/slot-resolver.ts +574 -250
  905. package/src/server/ssr-bridge-types.ts +124 -0
  906. package/src/server/ssr-entry.ts +206 -86
  907. package/src/server/ssr-render.ts +345 -86
  908. package/src/server/ssr-wrappers.tsx +141 -0
  909. package/src/server/state-tree-diff.ts +177 -30
  910. package/src/server/status-code-resolver.ts +115 -130
  911. package/src/server/stream-utils.ts +288 -0
  912. package/src/server/tracing.ts +126 -14
  913. package/src/server/tree-builder.ts +214 -90
  914. package/src/server/tree-match.ts +262 -0
  915. package/src/server/types.ts +78 -9
  916. package/src/server/utils/escape-html.ts +20 -0
  917. package/src/server/utils/mdx-file.ts +22 -0
  918. package/src/server/version-skew.ts +104 -0
  919. package/src/server/workers-cache-bridge.ts +33 -0
  920. package/src/shared/href-validation.ts +159 -0
  921. package/src/shared/merge-search-params.ts +55 -0
  922. package/src/shared/redirect-type.ts +17 -0
  923. package/src/shims/font-google.ts +1 -1
  924. package/src/shims/font-local.ts +34 -0
  925. package/src/shims/headers.ts +122 -1
  926. package/src/shims/navigation-client.ts +51 -29
  927. package/src/shims/navigation.ts +14 -7
  928. package/src/utils/state-machine.ts +111 -0
  929. package/dist/_chunks/als-registry-B7DbZ2hS.js +0 -41
  930. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  931. package/dist/_chunks/debug-B3Gypr3D.js +0 -108
  932. package/dist/_chunks/debug-B3Gypr3D.js.map +0 -1
  933. package/dist/_chunks/format-RyoGQL74.js +0 -164
  934. package/dist/_chunks/format-RyoGQL74.js.map +0 -1
  935. package/dist/_chunks/interception-BOoWmLUA.js +0 -676
  936. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  937. package/dist/_chunks/metadata-routes-Cjmvi3rQ.js +0 -153
  938. package/dist/_chunks/metadata-routes-Cjmvi3rQ.js.map +0 -1
  939. package/dist/_chunks/request-context-BQUC8PHn.js +0 -330
  940. package/dist/_chunks/request-context-BQUC8PHn.js.map +0 -1
  941. package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
  942. package/dist/_chunks/tracing-CemImE6h.js +0 -187
  943. package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
  944. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  945. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  946. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  947. package/dist/adapters/cloudflare.js.map +0 -1
  948. package/dist/cache/index.js.map +0 -1
  949. package/dist/cache/register-cached-function.d.ts +0 -17
  950. package/dist/cache/register-cached-function.d.ts.map +0 -1
  951. package/dist/client/browser-entry.d.ts +0 -21
  952. package/dist/client/browser-entry.d.ts.map +0 -1
  953. package/dist/client/head.d.ts +0 -16
  954. package/dist/client/head.d.ts.map +0 -1
  955. package/dist/client/link-status-provider.d.ts +0 -11
  956. package/dist/client/link-status-provider.d.ts.map +0 -1
  957. package/dist/client/segment-merger.d.ts +0 -119
  958. package/dist/client/segment-merger.d.ts.map +0 -1
  959. package/dist/client/stale-reload.d.ts +0 -44
  960. package/dist/client/stale-reload.d.ts.map +0 -1
  961. package/dist/client/transition-root.d.ts +0 -74
  962. package/dist/client/transition-root.d.ts.map +0 -1
  963. package/dist/client/use-navigation-pending.d.ts +0 -26
  964. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  965. package/dist/client/use-params.d.ts.map +0 -1
  966. package/dist/plugins/cache-transform.d.ts +0 -36
  967. package/dist/plugins/cache-transform.d.ts.map +0 -1
  968. package/dist/plugins/dev-error-overlay.d.ts +0 -60
  969. package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
  970. package/dist/plugins/dev-logs.d.ts.map +0 -1
  971. package/dist/plugins/dynamic-transform.d.ts +0 -72
  972. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  973. package/dist/plugins/server-action-exports.d.ts +0 -26
  974. package/dist/plugins/server-action-exports.d.ts.map +0 -1
  975. package/dist/routing/status-file-lint.d.ts +0 -33
  976. package/dist/routing/status-file-lint.d.ts.map +0 -1
  977. package/dist/search-params/analyze.d.ts +0 -54
  978. package/dist/search-params/analyze.d.ts.map +0 -1
  979. package/dist/search-params/builtin-codecs.d.ts +0 -105
  980. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  981. package/dist/search-params/codecs.d.ts +0 -53
  982. package/dist/search-params/codecs.d.ts.map +0 -1
  983. package/dist/search-params/create.d.ts +0 -106
  984. package/dist/search-params/create.d.ts.map +0 -1
  985. package/dist/server/client-module-map.d.ts +0 -47
  986. package/dist/server/client-module-map.d.ts.map +0 -1
  987. package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
  988. package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
  989. package/dist/server/dev-logger.d.ts.map +0 -1
  990. package/dist/server/dev-span-processor.d.ts +0 -29
  991. package/dist/server/dev-span-processor.d.ts.map +0 -1
  992. package/dist/server/dev-warnings.d.ts +0 -129
  993. package/dist/server/dev-warnings.d.ts.map +0 -1
  994. package/dist/server/flush.d.ts +0 -74
  995. package/dist/server/flush.d.ts.map +0 -1
  996. package/dist/server/manifest-status-resolver.d.ts +0 -58
  997. package/dist/server/manifest-status-resolver.d.ts.map +0 -1
  998. package/dist/server/prerender.d.ts +0 -77
  999. package/dist/server/prerender.d.ts.map +0 -1
  1000. package/dist/utils/directive-parser.d.ts +0 -70
  1001. package/dist/utils/directive-parser.d.ts.map +0 -1
  1002. package/src/cache/register-cached-function.ts +0 -103
  1003. package/src/client/browser-entry.ts +0 -678
  1004. package/src/client/head.ts +0 -61
  1005. package/src/client/link-status-provider.tsx +0 -30
  1006. package/src/client/segment-merger.ts +0 -339
  1007. package/src/client/stale-reload.ts +0 -87
  1008. package/src/client/transition-root.tsx +0 -166
  1009. package/src/client/use-navigation-pending.ts +0 -38
  1010. package/src/plugins/cache-transform.ts +0 -199
  1011. package/src/plugins/dev-error-overlay.ts +0 -230
  1012. package/src/plugins/dynamic-transform.ts +0 -161
  1013. package/src/plugins/server-action-exports.ts +0 -220
  1014. package/src/routing/status-file-lint.ts +0 -112
  1015. package/src/search-params/analyze.ts +0 -192
  1016. package/src/search-params/builtin-codecs.ts +0 -228
  1017. package/src/search-params/codecs.ts +0 -153
  1018. package/src/search-params/create.ts +0 -321
  1019. package/src/server/client-module-map.ts +0 -58
  1020. package/src/server/dev-fetch-instrumentation.ts +0 -96
  1021. package/src/server/dev-span-processor.ts +0 -78
  1022. package/src/server/dev-warnings.ts +0 -283
  1023. package/src/server/flush.ts +0 -182
  1024. package/src/server/manifest-status-resolver.ts +0 -215
  1025. package/src/server/prerender.ts +0 -139
  1026. package/src/utils/directive-parser.ts +0 -529
@@ -1,411 +1,125 @@
1
1
  /**
2
- * timber-fonts — Vite sub-plugin for build-time font processing.
2
+ * timber-fonts — Vite sub-plugin shell for build-time font processing.
3
3
  *
4
- * Handles:
5
- * - Virtual module resolution for `@timber/fonts/google` and `@timber/fonts/local`
6
- * - Static analysis of font function calls during `transform`
7
- * - @font-face CSS generation and scoped class output
8
- * - Size-adjusted fallback font generation
4
+ * This file is intentionally thin: it wires the Vite plugin hooks to the
5
+ * pipeline + per-concern modules under `../fonts/`. All real logic lives
6
+ * in:
9
7
  *
10
- * Does NOT handle (separate tasks):
11
- * - Google Fonts downloading/caching (timber-nk5)
12
- * - Build manifest / Early Hints integration (timber-qnx)
8
+ * - `../fonts/pipeline.ts` — `FontPipeline` (state, mutators)
9
+ * - `../fonts/transform.ts` — transform-hook logic, parsing helpers
10
+ * - `../fonts/dev-middleware.ts` — dev font binary server
11
+ * - `../fonts/virtual-modules.ts` — virtual module ID constants + source
12
+ *
13
+ * The public exports below are the stable API that the test suite and
14
+ * other parts of the framework import. Anything new should be added to
15
+ * one of the per-concern modules and re-exported here only if external
16
+ * consumers need it.
13
17
  *
14
18
  * Design doc: 24-fonts.md
15
19
  */
16
20
 
17
- import type { Plugin, ViteDevServer } from 'vite';
18
- import { readFileSync, existsSync } from 'node:fs';
19
- import { resolve, normalize } from 'node:path';
20
- import type { PluginContext } from '#/index.js';
21
- import type { ExtractedFont, GoogleFontConfig } from '#/fonts/types.js';
22
- import type { ManifestFontEntry } from '#/server/build-manifest.js';
23
- import { generateVariableClass, generateFontFamilyClass, generateFontFaces } from '#/fonts/css.js';
24
- import { generateFallbackCss, buildFontStack } from '#/fonts/fallbacks.js';
25
- import { processLocalFont, generateLocalFontFaces } from '#/fonts/local.js';
26
- import { inferFontFormat } from '#/fonts/local.js';
27
- import { downloadAndCacheFonts, type CachedFont } from '#/fonts/google.js';
21
+ import { parseAst } from 'vite';
22
+ import type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';
23
+ import type { PluginContext } from '../plugin-context.js';
28
24
  import {
29
- extractFontConfigAst,
30
- extractLocalFontConfigAst,
31
- detectDynamicFontCallAst,
32
- } from '#/fonts/ast.js';
33
-
34
- const VIRTUAL_GOOGLE = '@timber/fonts/google';
35
- const VIRTUAL_LOCAL = '@timber/fonts/local';
36
- const RESOLVED_GOOGLE = '\0@timber/fonts/google';
37
- const RESOLVED_LOCAL = '\0@timber/fonts/local';
38
-
39
- /**
40
- * Virtual side-effect module that registers font CSS on globalThis.
41
- *
42
- * When a file calls localFont() or a Google font function, the transform
43
- * hook injects `import 'virtual:timber-font-css-register'` into that file.
44
- * This virtual module sets `globalThis.__timber_font_css` with the combined
45
- * @font-face CSS. The RSC entry reads it at render time to inline a <style> tag.
46
- *
47
- * This approach avoids timing issues because:
48
- * 1. The font file is in the RSC module graph (imported by layout.tsx)
49
- * 2. The side-effect import is added to the font file during transform
50
- * 3. When layout.tsx is loaded, fonts.ts runs → side-effect module runs → globalThis is set
51
- * 4. RSC entry renders → reads globalThis → inlines <style>
52
- */
53
- const VIRTUAL_FONT_CSS_REGISTER = 'virtual:timber-font-css-register';
54
- const RESOLVED_FONT_CSS_REGISTER = '\0virtual:timber-font-css-register';
55
-
56
- /**
57
- * Registry of fonts extracted during transform.
58
- * Keyed by a unique font ID derived from family + config.
59
- */
60
- export type FontRegistry = Map<string, ExtractedFont>;
61
-
62
- /**
63
- * Convert a font family name to a PascalCase export name.
64
- * e.g. "JetBrains Mono" → "JetBrains_Mono"
65
- */
66
- function familyToExportName(family: string): string {
67
- return family.replace(/\s+/g, '_');
68
- }
69
-
70
- /**
71
- * Convert a font family name to a scoped class name.
72
- * e.g. "JetBrains Mono" → "timber-font-jetbrains-mono"
73
- */
74
- function familyToClassName(family: string): string {
75
- return `timber-font-${family.toLowerCase().replace(/\s+/g, '-')}`;
76
- }
77
-
78
- /**
79
- * Generate a unique font ID from family + config hash.
80
- */
81
- function generateFontId(family: string, config: GoogleFontConfig): string {
82
- const weights = normalizeToArray(config.weight);
83
- const styles = normalizeToArray(config.style);
84
- const subsets = config.subsets ?? ['latin'];
85
- return `${family.toLowerCase()}-${weights.join(',')}-${styles.join(',')}-${subsets.join(',')}`;
86
- }
87
-
88
- /**
89
- * Normalize a string or string array to an array.
90
- */
91
- function normalizeToArray(value: string | string[] | undefined): string[] {
92
- if (!value) return ['400'];
93
- return Array.isArray(value) ? value : [value];
94
- }
95
-
96
- /**
97
- * Normalize style to an array.
98
- */
99
- function normalizeStyleArray(value: string | string[] | undefined): string[] {
100
- if (!value) return ['normal'];
101
- return Array.isArray(value) ? value : [value];
102
- }
103
-
104
- /**
105
- * Extract static font config from a font function call in source code.
106
- *
107
- * Parses patterns like:
108
- * const inter = Inter({ subsets: ['latin'], weight: '400', display: 'swap', variable: '--font-sans' })
109
- *
110
- * Returns null if the call cannot be statically analyzed.
111
- *
112
- * Uses acorn AST parsing for robust handling of comments, trailing commas,
113
- * and multi-line configs.
114
- */
115
- export function extractFontConfig(callSource: string): GoogleFontConfig | null {
116
- return extractFontConfigAst(callSource);
117
- }
118
-
119
- /**
120
- * Detect if a source file contains dynamic/computed font function calls
121
- * that cannot be statically analyzed.
122
- *
123
- * Returns the offending expression if found, null if all calls are static.
124
- *
125
- * Uses acorn AST parsing for accurate detection.
126
- */
127
- export function detectDynamicFontCall(source: string, importedNames: string[]): string | null {
128
- return detectDynamicFontCallAst(source, importedNames);
129
- }
130
-
131
- /**
132
- * Regex that matches imports from either `@timber/fonts/google` or `next/font/google`.
133
- * The shims plugin resolves `next/font/google` to the same virtual module,
134
- * but the source code still contains the original import specifier.
135
- */
136
- const GOOGLE_FONT_IMPORT_RE =
137
- /import\s*\{([^}]+)\}\s*from\s*['"](?:@timber\/fonts\/google|next\/font\/google)['"]/g;
138
-
139
- /**
140
- * Parse import specifiers from a source file that imports from
141
- * `@timber/fonts/google` or `next/font/google`.
142
- *
143
- * Returns the list of imported font names (e.g. ['Inter', 'JetBrains_Mono']).
144
- */
145
- export function parseGoogleFontImports(source: string): string[] {
146
- const importPattern = new RegExp(GOOGLE_FONT_IMPORT_RE.source, 'g');
147
- const names: string[] = [];
148
-
149
- let match;
150
- while ((match = importPattern.exec(source)) !== null) {
151
- const specifiers = match[1]
152
- .split(',')
153
- .map((s) => s.trim())
154
- .filter(Boolean);
155
- for (const spec of specifiers) {
156
- // Handle `Inter as MyInter` — we want the local name
157
- const parts = spec.split(/\s+as\s+/);
158
- names.push(parts[parts.length - 1].trim());
159
- }
160
- }
161
-
162
- return names;
163
- }
164
-
165
- /**
166
- * Parse the original (remote) font family names from imports.
167
- *
168
- * Returns a map of local name → family name.
169
- * e.g. { Inter: 'Inter', JetBrains_Mono: 'JetBrains Mono' }
170
- */
171
- export function parseGoogleFontFamilies(source: string): Map<string, string> {
172
- const importPattern = new RegExp(GOOGLE_FONT_IMPORT_RE.source, 'g');
173
- const families = new Map<string, string>();
174
-
175
- let match;
176
- while ((match = importPattern.exec(source)) !== null) {
177
- const specifiers = match[1]
178
- .split(',')
179
- .map((s) => s.trim())
180
- .filter(Boolean);
181
- for (const spec of specifiers) {
182
- const parts = spec.split(/\s+as\s+/);
183
- const originalName = parts[0].trim();
184
- const localName = parts[parts.length - 1].trim();
185
- // Convert export name back to family name: JetBrains_Mono → JetBrains Mono
186
- const family = originalName.replace(/_/g, ' ');
187
- families.set(localName, family);
188
- }
189
- }
190
-
191
- return families;
192
- }
193
-
194
- /**
195
- * Generate the virtual module source for `@timber/fonts/google`.
196
- *
197
- * Each Google Font family gets a named export that returns a FontResult.
198
- * In this base implementation, the functions return static data.
199
- * The Google Fonts download task (timber-nk5) will add real font file URLs.
200
- */
201
- function generateGoogleVirtualModule(registry: FontRegistry): string {
202
- // Collect unique families from the registry
203
- const families = new Set<string>();
204
- for (const font of registry.values()) {
205
- if (font.provider === 'google') families.add(font.family);
206
- }
207
-
208
- const lines = [
209
- '// Auto-generated virtual module: @timber/fonts/google',
210
- '// Each export is a font loader function that returns a FontResult.',
211
- '',
212
- ];
213
-
214
- // If no fonts registered yet, export a generic loader for any font
215
- // This is the initial load — the transform hook will process actual calls
216
- lines.push('function createFontResult(family, config) {');
217
- lines.push(' return {');
218
- lines.push(' className: `timber-font-${family.toLowerCase().replace(/\\s+/g, "-")}`,');
219
- lines.push(' style: { fontFamily: family },');
220
- lines.push(' variable: config?.variable,');
221
- lines.push(' };');
222
- lines.push('}');
223
- lines.push('');
224
-
225
- // Export a Proxy-based default that handles any font name import
226
- lines.push('export default new Proxy({}, {');
227
- lines.push(' get(_, prop) {');
228
- lines.push(' if (typeof prop === "string") {');
229
- lines.push(' return (config) => createFontResult(prop.replace(/_/g, " "), config);');
230
- lines.push(' }');
231
- lines.push(' }');
232
- lines.push('});');
233
-
234
- // Also export known families as named exports for tree-shaking
235
- for (const family of families) {
236
- const exportName = familyToExportName(family);
237
- lines.push('');
238
- lines.push(`export function ${exportName}(config) {`);
239
- lines.push(` return createFontResult('${family}', config);`);
240
- lines.push('}');
241
- }
242
-
243
- return lines.join('\n');
244
- }
245
-
246
- /**
247
- * Generate the virtual module source for `@timber/fonts/local`.
248
- */
249
- function generateLocalVirtualModule(): string {
250
- return [
251
- '// Auto-generated virtual module: @timber/fonts/local',
252
- '',
253
- 'export default function localFont(config) {',
254
- ' const family = config?.family || "Local Font";',
255
- ' return {',
256
- ' className: `timber-font-${family.toLowerCase().replace(/\\s+/g, "-")}`,',
257
- ' style: { fontFamily: family },',
258
- ' variable: config?.variable,',
259
- ' };',
260
- '}',
261
- ].join('\n');
262
- }
263
-
264
- /**
265
- * Generate CSS for a single extracted font.
266
- *
267
- * Includes @font-face rules (for local fonts), fallback @font-face,
268
- * and the scoped class rule.
269
- */
270
- export function generateFontCss(font: ExtractedFont): string {
271
- const cssParts: string[] = [];
272
-
273
- if (font.provider === 'local' && font.localSources) {
274
- const faces = generateLocalFontFaces(font.family, font.localSources, font.display);
275
- const faceCss = generateFontFaces(faces);
276
- if (faceCss) cssParts.push(faceCss);
277
- }
278
-
279
- const fallbackCss = generateFallbackCss(font.family);
280
- if (fallbackCss) cssParts.push(fallbackCss);
281
-
282
- if (font.variable) {
283
- cssParts.push(generateVariableClass(font.className, font.variable, font.fontFamily));
284
- } else {
285
- cssParts.push(generateFontFamilyClass(font.className, font.fontFamily));
286
- }
287
-
288
- return cssParts.join('\n\n');
289
- }
290
-
291
- /**
292
- * Generate the CSS output for all extracted fonts.
293
- *
294
- * Includes @font-face rules for local fonts, fallback @font-face rules,
295
- * and scoped classes.
296
- */
297
- export function generateAllFontCss(registry: FontRegistry): string {
298
- const cssParts: string[] = [];
299
- for (const font of registry.values()) {
300
- cssParts.push(generateFontCss(font));
301
- }
302
- return cssParts.join('\n\n');
303
- }
304
-
305
- /**
306
- * Parse the local name used for the default import of `@timber/fonts/local`.
307
- *
308
- * Handles:
309
- * import localFont from '@timber/fonts/local'
310
- * import myLoader from '@timber/fonts/local'
311
- */
312
- export function parseLocalFontImportName(source: string): string | null {
313
- const match = source.match(
314
- /import\s+(\w+)\s+from\s*['"](?:@timber\/fonts\/local|next\/font\/local)['"]/
315
- );
316
- return match ? match[1] : null;
317
- }
318
-
319
- /**
320
- * Transform local font calls in source code.
321
- *
322
- * Finds `localFont({ ... })` calls, extracts the config,
323
- * registers the font, and replaces the call with a static FontResult.
324
- */
325
- function transformLocalFonts(
326
- transformedCode: string,
327
- originalCode: string,
328
- importerId: string,
329
- registry: FontRegistry,
330
- emitError: (msg: string) => void
331
- ): string {
332
- const localName = parseLocalFontImportName(originalCode);
333
- if (!localName) return transformedCode;
334
-
335
- // Check for dynamic calls
336
- const dynamicCall = detectDynamicFontCall(originalCode, [localName]);
337
- if (dynamicCall) {
338
- emitError(
339
- `Font function calls must be statically analyzable. ` +
340
- `Found dynamic call: ${dynamicCall}. ` +
341
- `Pass a literal object with string/array values instead.`
342
- );
343
- }
344
-
345
- // Find all calls: const varName = localFont({ ... })
346
- const callPattern = new RegExp(
347
- `(?:const|let|var)\\s+(\\w+)\\s*=\\s*${localName}\\s*\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`,
348
- 'g'
349
- );
350
-
351
- let callMatch;
352
- while ((callMatch = callPattern.exec(originalCode)) !== null) {
353
- const varName = callMatch[1];
354
- const configSource = callMatch[2];
355
- const fullMatch = callMatch[0];
356
-
357
- const config = extractLocalFontConfigAst(`(${configSource})`);
358
- if (!config) {
359
- emitError(
360
- `Could not statically analyze local font config. ` +
361
- `Ensure src is a string or array of { path, weight?, style? } objects.`
362
- );
363
- return transformedCode;
364
- }
365
-
366
- const extracted = processLocalFont(config, importerId);
367
- registry.set(extracted.id, extracted);
368
-
369
- const resultObj = extracted.variable
370
- ? `{ className: "${extracted.className}", style: { fontFamily: "${extracted.fontFamily}" }, variable: "${extracted.variable}" }`
371
- : `{ className: "${extracted.className}", style: { fontFamily: "${extracted.fontFamily}" } }`;
372
-
373
- const replacement = `const ${varName} = ${resultObj}`;
374
- transformedCode = transformedCode.replace(fullMatch, replacement);
375
- }
376
-
377
- // Remove the import statement
378
- transformedCode = transformedCode.replace(
379
- /import\s+\w+\s+from\s*['"](?:@timber\/fonts\/local|next\/font\/local)['"];?\s*\n?/g,
380
- ''
381
- );
382
-
383
- return transformedCode;
384
- }
25
+ downloadAndCacheFonts,
26
+ generateProductionFontFaces,
27
+ resolveDevFontFaces,
28
+ } from '../fonts/google.js';
29
+ import { fontUrlPrefix } from '../fonts/paths.js';
30
+ import { FontPipeline } from '../fonts/pipeline.js';
31
+ import { runFontsTransform } from '../fonts/transform.js';
32
+ import { installFontDevMiddleware } from '../fonts/dev-middleware.js';
33
+ import { emitFontAssets, writeFontManifest, groupCachedFontsByFamily } from '../fonts/bundle.js';
34
+ import {
35
+ RESOLVED_GOOGLE,
36
+ RESOLVED_LOCAL,
37
+ VIRTUAL_GOOGLE,
38
+ VIRTUAL_LOCAL,
39
+ generateGoogleVirtualModule,
40
+ generateLocalVirtualModule,
41
+ } from '../fonts/virtual-modules.js';
42
+
43
+ // ── Public re-exports ────────────────────────────────────────────────────
44
+ //
45
+ // These exports are part of the stable surface area imported by tests and
46
+ // downstream consumers. Do NOT change their names or signatures without
47
+ // updating every caller. New helpers should be added to the per-concern
48
+ // module first and re-exported here only if external code needs them.
49
+
50
+ export { FontPipeline } from '../fonts/pipeline.js';
51
+ export {
52
+ generateFontId,
53
+ extractFontConfig,
54
+ detectDynamicFontCall,
55
+ parseGoogleFontImports,
56
+ parseGoogleFontFamilies,
57
+ parseLocalFontImportName,
58
+ } from '../fonts/transform.js';
385
59
 
386
60
  /**
387
61
  * Create the timber-fonts Vite plugin.
388
62
  */
389
63
  export function timberFonts(ctx: PluginContext): Plugin {
390
- const registry: FontRegistry = new Map();
391
- /** Fonts downloaded during buildStart (production only). */
392
- let cachedFonts: CachedFont[] = [];
64
+ const pipeline = new FontPipeline({ hashOnRegister: !ctx.dev });
65
+ let resolvedBase = '/';
393
66
 
394
67
  return {
395
68
  name: 'timber-fonts',
396
69
 
397
70
  /**
398
- * Resolve `@timber/fonts/google`, `@timber/fonts/local`,
399
- * and `virtual:timber-font-css` virtual modules.
71
+ * Capture Vite's resolved `base` so every font URL the pipeline emits
72
+ * (@font-face src, manifest hrefs, dev middleware matching) carries
73
+ * the prefix. Emitted file locations are unaffected — only URLs.
74
+ */
75
+ configResolved(config: ResolvedConfig) {
76
+ resolvedBase = config.base;
77
+ pipeline.setBase(config.base);
78
+
79
+ // Font binaries are emitted in generateBundle, after Vite's CSS
80
+ // url() resolution runs. The warnings are benign — suppress them.
81
+ const originalWarnOnce = config.logger.warnOnce.bind(config.logger);
82
+ config.logger.warnOnce = (msg, options) => {
83
+ if (msg.includes('_timber/fonts/') && msg.includes("didn't resolve at build time")) return;
84
+ originalWarnOnce(msg, options);
85
+ };
86
+ },
87
+
88
+ /**
89
+ * `enforce: 'pre'` is load-bearing for the font CSS pipeline (TIM-828).
90
+ *
91
+ * The transform hook injects a side-effect
92
+ * `import 'virtual:timber-font-css/<hash>.css'` into every file that
93
+ * registers a font. @vitejs/plugin-rsc's `rsc:rsc-css-export-transform`
94
+ * later inspects each server component's source for CSS imports and
95
+ * wraps the default export in `import.meta.viteRsc.loadCss(...)` so
96
+ * the matched virtual CSS module ends up `preinit`'d as
97
+ * `<link rel="stylesheet" data-rsc-css-href=...>`.
98
+ *
99
+ * If timber-fonts ran in normal order it would inject the CSS import
100
+ * *after* plugin-rsc had already scanned the source, and the font CSS
101
+ * would be silently dropped from the rendered HTML. Running in the
102
+ * `pre` slot guarantees our injected import is visible to plugin-rsc's
103
+ * later CSS-export scan.
104
+ */
105
+ enforce: 'pre',
106
+
107
+ /**
108
+ * Resolve `@timber/fonts/google`, `@timber/fonts/local`, and the
109
+ * per-importer `virtual:timber-font-css/<hash>.css` modules injected
110
+ * by the transform hook.
400
111
  *
401
- * Handles \0 prefix and root prefix stripping for RSC/SSR
402
- * environments where the RSC plugin re-imports virtual modules
403
- * with additional prefixes.
112
+ * Strips the `\0` prefix added by the RSC plugin's re-imports and the
113
+ * absolute root prefix added by SSR build entries before comparing
114
+ * against the public IDs. The `.css` suffix on font-css ids is
115
+ * preserved so Vite's CSS pipeline (`isCSSRequest`) recognises the
116
+ * resolved id as CSS.
404
117
  */
405
118
  resolveId(id: string) {
406
- // Strip \0 prefix (RSC plugin re-imports)
407
119
  let cleanId = id.startsWith('\0') ? id.slice(1) : id;
408
- // Strip root prefix (SSR build entries)
120
+ const qIdx = cleanId.indexOf('?');
121
+ const query = qIdx !== -1 ? cleanId.slice(qIdx) : '';
122
+ if (qIdx !== -1) cleanId = cleanId.slice(0, qIdx);
409
123
  if (cleanId.startsWith(ctx.root)) {
410
124
  const stripped = cleanId.slice(ctx.root.length);
411
125
  if (stripped.startsWith('/') || stripped.startsWith('\\')) {
@@ -417,317 +131,168 @@ export function timberFonts(ctx: PluginContext): Plugin {
417
131
 
418
132
  if (cleanId === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
419
133
  if (cleanId === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
420
- if (cleanId === VIRTUAL_FONT_CSS_REGISTER) return RESOLVED_FONT_CSS_REGISTER;
134
+ // Preserve query suffix (notably `?direct`) on the resolved CSS id.
135
+ // Vite's transform middleware appends `?direct` when the browser
136
+ // fetches the URL as a `<link rel="stylesheet">`, and the CSS plugin
137
+ // only skips its JS-wrapping step when `isDirectCSSRequest(id)` sees
138
+ // that query on the resolved id. Dropping it here caused virtual
139
+ // font CSS to be served as Vite's HMR JS shim, leaving the
140
+ // `<link>`-loaded stylesheet empty (TIM-937 follow-up).
141
+ if (pipeline.cssIdMap.matches(cleanId)) return '\0' + cleanId + query;
421
142
  return null;
422
143
  },
423
144
 
424
145
  /**
425
146
  * Return generated source for font virtual modules.
426
147
  *
427
- * `virtual:timber-font-css` exports the combined @font-face CSS
428
- * as a string. The RSC entry imports it and inlines a <style> tag.
429
- * Because this is loaded lazily (on first request), the font
430
- * registry is always populated by the time it's needed.
431
- */
432
- load(id: string) {
433
- if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
434
- if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
435
-
436
- if (id === RESOLVED_FONT_CSS_REGISTER) {
437
- const css = generateAllFontCss(registry);
438
- // Side-effect module: sets font CSS on globalThis for the RSC entry to read.
439
- return `globalThis.__timber_font_css = ${JSON.stringify(css)};`;
440
- }
441
- return null;
442
- },
443
-
444
- /**
445
- * Serve local font files and font CSS in dev mode under `/_timber/fonts/`.
446
- *
447
- * Serves:
448
- * - `/_timber/fonts/fonts.css` — combined @font-face + scoped class CSS
449
- * - `/_timber/fonts/<filename>` — individual font files from the registry
148
+ * The per-importer `virtual:timber-font-css/<hash>.css` modules
149
+ * return the combined font CSS for the specific importer that
150
+ * registered them. Vite's CSS pipeline handles injection from here:
151
+ * in dev the module rides the CSS HMR channel; in production it is
152
+ * emitted as a real CSS asset and @vitejs/plugin-rsc's `collectCss`
153
+ * walks the RSC module graph to find it.
450
154
  *
451
- * Only files registered in the font registry are served.
452
- * Paths are validated to prevent directory traversal.
155
+ * Google `@font-face` descriptors are resolved lazily here (both
156
+ * dev and production) because `load` runs after `transform` has
157
+ * registered the font. `buildStart` runs before any transforms,
158
+ * so fonts aren't in the pipeline yet when it fires for the first
159
+ * environment.
453
160
  */
454
- configureServer(server: ViteDevServer) {
455
- server.middlewares.use((req, res, next) => {
456
- const url = req.url;
457
- if (!url || !url.startsWith('/_timber/fonts/')) return next();
161
+ async load(id: string) {
162
+ if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(pipeline.fonts());
163
+ if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
458
164
 
459
- const requestedFilename = url.slice('/_timber/fonts/'.length);
460
- // Reject path traversal attempts
461
- if (requestedFilename.includes('..') || requestedFilename.includes('/')) {
462
- res.statusCode = 400;
463
- res.end('Bad request');
464
- return;
165
+ if (pipeline.cssIdMap.matches(id)) {
166
+ const importer = pipeline.cssIdMap.importerFor(id);
167
+ if (!importer) {
168
+ return '';
465
169
  }
466
170
 
467
- // Font CSS is now injected via Vite's CSS pipeline (virtual:timber-font-css modules).
468
- // This middleware only serves font binary files (woff2, etc.).
171
+ const skipFonts = process.env.TIMBER_SKIP_FONTS === '1';
469
172
 
470
- // Find the matching font file in the registry
471
- for (const font of registry.values()) {
472
- if (font.provider !== 'local' || !font.localSources) continue;
473
- for (const src of font.localSources) {
474
- const basename = src.path.split('/').pop() ?? '';
475
- if (basename === requestedFilename) {
476
- const absolutePath = normalize(resolve(src.path));
477
- if (!existsSync(absolutePath)) {
478
- res.statusCode = 404;
479
- res.end('Not found');
480
- return;
481
- }
482
- const data = readFileSync(absolutePath);
483
- const ext = absolutePath.split('.').pop()?.toLowerCase();
484
- const mimeMap: Record<string, string> = {
485
- woff2: 'font/woff2',
486
- woff: 'font/woff',
487
- ttf: 'font/ttf',
488
- otf: 'font/otf',
489
- eot: 'application/vnd.ms-fontopen',
490
- };
491
- res.setHeader('Content-Type', mimeMap[ext ?? ''] ?? 'application/octet-stream');
492
- res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
493
- res.setHeader('Access-Control-Allow-Origin', '*');
494
- res.end(data);
495
- return;
173
+ for (const font of pipeline.googleFonts()) {
174
+ if (font.importer !== importer) continue;
175
+ if (pipeline.hasFaces(font.id)) continue;
176
+ if (skipFonts && !ctx.dev) {
177
+ console.warn(`[timber-fonts] Skipping font "${font.family}" (TIMBER_SKIP_FONTS=1)`);
178
+ continue;
179
+ }
180
+ try {
181
+ if (ctx.dev) {
182
+ const faces = await resolveDevFontFaces(font);
183
+ pipeline.attachFaces(font.id, faces);
184
+ } else {
185
+ const cached = await downloadAndCacheFonts([font], ctx.root);
186
+ const byFamily = groupCachedFontsByFamily(cached);
187
+ const familyCached = byFamily.get(font.family.toLowerCase()) ?? [];
188
+ pipeline.attachCachedFiles(font.id, familyCached);
189
+ pipeline.attachFaces(
190
+ font.id,
191
+ generateProductionFontFaces(familyCached, font.display, fontUrlPrefix(resolvedBase))
192
+ );
496
193
  }
194
+ } catch (e) {
195
+ if (!ctx.dev) throw e;
196
+ const msg = e instanceof Error ? e.message : String(e);
197
+ console.warn(
198
+ `[timber-fonts] Failed to resolve Google font "${font.family}": ${msg}. Will retry on next request.`
199
+ );
497
200
  }
498
201
  }
499
202
 
500
- next();
501
- });
203
+ return pipeline.getCssForSegment(importer);
204
+ }
205
+ return null;
502
206
  },
503
207
 
504
208
  /**
505
- * Download and cache Google Fonts during production builds.
506
- *
507
- * In dev mode this is a no-op — fonts point to the Google CDN.
508
- * The registry is populated by the transform hook which runs before
509
- * buildStart in the build pipeline, so all fonts are known here.
209
+ * Serve local font files in dev mode under `/_timber/fonts/<basename>`.
210
+ * Font CSS goes through Vite's CSS pipeline (virtual modules), not
211
+ * this middleware.
510
212
  */
511
- async buildStart() {
512
- if (ctx.dev) return;
513
-
514
- const googleFonts = [...registry.values()].filter((f) => f.provider === 'google');
515
- if (googleFonts.length === 0) return;
516
-
517
- cachedFonts = await downloadAndCacheFonts(googleFonts, ctx.root);
213
+ configureServer(server: ViteDevServer) {
214
+ installFontDevMiddleware(server, pipeline, resolvedBase);
518
215
  },
519
216
 
520
217
  /**
521
- * Scan source files for font function calls and extract static config.
218
+ * No-op. Font downloading and face attachment happen lazily in `load()`
219
+ * because `buildStart` runs before `transform` — fonts aren't registered
220
+ * in the pipeline yet when this fires for the first environment.
522
221
  *
523
- * When a file imports from `@timber/fonts/google`, we:
524
- * 1. Parse the import specifiers to get font family names
525
- * 2. Find each font function call and extract its config
526
- * 3. Validate that all calls are statically analyzable
527
- * 4. Register extracted fonts in the registry
528
- * 5. Replace the function call with a static FontResult object
222
+ * Local font hashing is handled at registration time by the pipeline
223
+ * (when `hashOnRegister` is set) so hashed filenames are available
224
+ * before the virtual CSS `load()` hook runs.
529
225
  */
530
- transform(code: string, id: string) {
531
- // Skip virtual modules and node_modules
532
- if (id.startsWith('\0') || id.includes('node_modules')) return null;
533
-
534
- const hasGoogleImport =
535
- code.includes('@timber/fonts/google') || code.includes('next/font/google');
536
- const hasLocalImport =
537
- code.includes('@timber/fonts/local') || code.includes('next/font/local');
538
- if (!hasGoogleImport && !hasLocalImport) return null;
539
-
540
- let transformedCode = code;
541
-
542
- // ── Google font transform ──────────────────────────────────────────
543
- if (hasGoogleImport) {
544
- const families = parseGoogleFontFamilies(code);
545
- if (families.size > 0) {
546
- const importedNames = [...families.keys()];
547
-
548
- const dynamicCall = detectDynamicFontCall(code, importedNames);
549
- if (dynamicCall) {
550
- this.error(
551
- `Font function calls must be statically analyzable. ` +
552
- `Found dynamic call: ${dynamicCall}. ` +
553
- `Pass a literal object with string/array values instead.`
554
- );
555
- }
556
-
557
- for (const [localName, family] of families) {
558
- const callPattern = new RegExp(
559
- `(?:const|let|var)\\s+(\\w+)\\s*=\\s*${localName}\\s*\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`,
560
- 'g'
561
- );
562
-
563
- let callMatch;
564
- while ((callMatch = callPattern.exec(code)) !== null) {
565
- const varName = callMatch[1];
566
- const configSource = callMatch[2];
567
- const fullMatch = callMatch[0];
568
-
569
- const config = extractFontConfig(`(${configSource})`);
570
- if (!config) {
571
- this.error(
572
- `Could not statically analyze font config for ${family}. ` +
573
- `Ensure all config values are string literals or arrays of string literals.`
574
- );
575
- return null;
576
- }
577
-
578
- const fontId = generateFontId(family, config);
579
- const className = familyToClassName(family);
580
- const fontStack = buildFontStack(family);
581
- const display = config.display ?? 'swap';
582
-
583
- const extracted: ExtractedFont = {
584
- id: fontId,
585
- family,
586
- provider: 'google',
587
- weights: normalizeToArray(config.weight),
588
- styles: normalizeStyleArray(config.style),
589
- subsets: config.subsets ?? ['latin'],
590
- display,
591
- variable: config.variable,
592
- className,
593
- fontFamily: fontStack,
594
- importer: id,
595
- };
596
-
597
- registry.set(fontId, extracted);
598
-
599
- const resultObj = config.variable
600
- ? `{ className: "${className}", style: { fontFamily: "${fontStack}" }, variable: "${config.variable}" }`
601
- : `{ className: "${className}", style: { fontFamily: "${fontStack}" } }`;
602
-
603
- const replacement = `const ${varName} = ${resultObj}`;
604
- transformedCode = transformedCode.replace(fullMatch, replacement);
605
- }
606
- }
226
+ buildStart() {},
607
227
 
608
- transformedCode = transformedCode.replace(
609
- /import\s*\{[^}]+\}\s*from\s*['"](?:@timber\/fonts\/google|next\/font\/google)['"];?\s*\n?/g,
610
- ''
611
- );
612
- }
613
- }
614
-
615
- // ── Local font transform ───────────────────────────────────────────
616
- if (hasLocalImport) {
617
- transformedCode = transformLocalFonts(
618
- transformedCode,
619
- code,
620
- id,
621
- registry,
622
- this.error.bind(this)
623
- );
228
+ /**
229
+ * Prune stale font entries when a module that previously imported fonts
230
+ * no longer contains any font import. The transform hook's `filter.code`
231
+ * skips such modules, so without this hook the old entries would persist
232
+ * until dev restart. See TIM-1087.
233
+ */
234
+ async hotUpdate({ type, file, read }) {
235
+ if (!pipeline.hasImporter(file)) return;
236
+ if (type === 'delete') {
237
+ pipeline.pruneImporter(file);
238
+ return;
624
239
  }
625
-
626
- if (transformedCode !== code) {
627
- // Inject side-effect import that registers font CSS on globalThis.
628
- // The RSC entry reads globalThis.__timber_font_css to inline a <style> tag.
629
- if (registry.size > 0) {
630
- transformedCode = `import '${VIRTUAL_FONT_CSS_REGISTER}';\n` + transformedCode;
631
- }
632
- return { code: transformedCode, map: null };
240
+ const code = await read();
241
+ const hasFontImport =
242
+ code.includes('@timber/fonts/') ||
243
+ code.includes('@timber-js/app/fonts/') ||
244
+ code.includes('next/font/');
245
+ if (hasFontImport) return;
246
+ // Only prune if the new source parses successfully. A syntax error
247
+ // means the HMR update will fail and the old module stays active —
248
+ // pruning would leave it without font CSS until the next valid save.
249
+ try {
250
+ parseAst(code, { lang: 'tsx' });
251
+ } catch {
252
+ return;
633
253
  }
634
-
635
- return null;
254
+ pipeline.pruneImporter(file);
636
255
  },
637
256
 
638
257
  /**
639
- * Emit font files and metadata into the build output.
258
+ * Scan source files for font function calls and extract static config.
640
259
  *
641
- * For Google fonts: emits the downloaded, content-hashed woff2 files
642
- * and writes ManifestFontEntry arrays using real hashed URLs.
260
+ * Delegates to `runFontsTransform`. Errors raised through the
261
+ * `this.error` callback are surfaced as Vite plugin errors.
643
262
  *
644
- * For local fonts: emits entries using the source file paths.
263
+ * The `filter` option uses Vite 8's rolldown-native hook filters to
264
+ * skip non-JS/TS files and files that don't mention any font module
265
+ * before crossing into JS — replacing the hand-rolled pre-filter that
266
+ * was previously inside `runFontsTransform` (TIM-840, TIM-1147).
267
+ */
268
+ transform: {
269
+ filter: {
270
+ id: {
271
+ include: /^[^?]*\.(?:js|jsx|ts|tsx|mjs|cjs|mts|cts)(?:\?|$)/,
272
+ exclude: /(?:^\0|(?:^|\/)node_modules\/)/,
273
+ },
274
+ code: ['@timber/fonts/', '@timber-js/app/fonts/', 'next/font/'],
275
+ },
276
+ handler(code: string, id: string) {
277
+ return runFontsTransform(code, id, pipeline, (msg) => this.error(msg));
278
+ },
279
+ },
280
+
281
+ /**
282
+ * Emit font binaries and build-manifest entries.
645
283
  *
646
- * In dev mode the build manifest is null, so this is a no-op.
284
+ * All font binaries (Google and local) use content-hashed filenames
285
+ * for immutable caching. Font CSS is handled by Vite's CSS pipeline
286
+ * via virtual modules — we only emit binaries here.
647
287
  */
648
288
  generateBundle() {
649
- // Emit cached Google Font files into the build output
650
- for (const cf of cachedFonts) {
651
- this.emitFile({
652
- type: 'asset',
653
- fileName: `_timber/fonts/${cf.hashedFilename}`,
654
- source: cf.data,
655
- });
656
- }
657
-
658
- // Emit local font files as assets
659
- for (const font of registry.values()) {
660
- if (font.provider !== 'local' || !font.localSources) continue;
661
- for (const src of font.localSources) {
662
- const absolutePath = normalize(resolve(src.path));
663
- if (!existsSync(absolutePath)) {
664
- this.warn(`Local font file not found: ${absolutePath}`);
665
- continue;
666
- }
667
- const basename = src.path.split('/').pop() ?? src.path;
668
- const data = readFileSync(absolutePath);
669
- this.emitFile({
670
- type: 'asset',
671
- fileName: `_timber/fonts/${basename}`,
672
- source: data,
673
- });
674
- }
675
- }
676
-
677
- // Font CSS is emitted by Vite's CSS pipeline via virtual:timber-font-css modules.
678
- // We only need to emit font binary files and update the build manifest here.
679
-
289
+ emitFontAssets(
290
+ pipeline,
291
+ (asset) => this.emitFile(asset),
292
+ (msg) => this.warn(msg)
293
+ );
680
294
  if (!ctx.buildManifest) return;
681
-
682
- // Build a lookup from font family → cached files for manifest entries
683
- const cachedByFamily = new Map<string, CachedFont[]>();
684
- for (const cf of cachedFonts) {
685
- const key = cf.face.family.toLowerCase();
686
- const arr = cachedByFamily.get(key) ?? [];
687
- arr.push(cf);
688
- cachedByFamily.set(key, arr);
689
- }
690
-
691
- const fontsByImporter = new Map<string, ManifestFontEntry[]>();
692
-
693
- for (const font of registry.values()) {
694
- const entries = fontsByImporter.get(font.importer) ?? [];
695
-
696
- if (font.provider === 'local' && font.localSources) {
697
- // Local fonts: one entry per source file
698
- for (const src of font.localSources) {
699
- const filename = src.path.split('/').pop() ?? src.path;
700
- const format = inferFontFormat(src.path);
701
- entries.push({
702
- href: `/_timber/fonts/${filename}`,
703
- format,
704
- crossOrigin: 'anonymous',
705
- });
706
- }
707
- } else {
708
- // Google fonts: use real content-hashed URLs from cached downloads
709
- const familyKey = font.family.toLowerCase();
710
- const familyCached = cachedByFamily.get(familyKey) ?? [];
711
- for (const cf of familyCached) {
712
- entries.push({
713
- href: `/_timber/fonts/${cf.hashedFilename}`,
714
- format: 'woff2',
715
- crossOrigin: 'anonymous',
716
- });
717
- }
718
- }
719
-
720
- fontsByImporter.set(font.importer, entries);
721
- }
722
-
723
- // Normalize importer paths to be relative to project root (matching
724
- // how Vite's manifest.json keys work for css/js).
725
- for (const [importer, entries] of fontsByImporter) {
726
- const relativePath = importer.startsWith(ctx.root)
727
- ? importer.slice(ctx.root.length + 1)
728
- : importer;
729
- ctx.buildManifest.fonts[relativePath] = entries;
730
- }
295
+ writeFontManifest(pipeline, ctx.buildManifest, resolvedBase);
731
296
  },
732
297
  };
733
298
  }