@timber-js/app 0.2.0-alpha.9 → 0.2.0-alpha.91

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 (619) hide show
  1. package/dist/_chunks/actions-DLnUaR65.js +421 -0
  2. package/dist/_chunks/actions-DLnUaR65.js.map +1 -0
  3. package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
  4. package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
  5. package/dist/_chunks/chunk-BYIpzuS7.js +39 -0
  6. package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
  7. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  8. package/dist/_chunks/define-C77ScO0m.js +106 -0
  9. package/dist/_chunks/define-C77ScO0m.js.map +1 -0
  10. package/dist/_chunks/define-Itxvcd7F.js +199 -0
  11. package/dist/_chunks/define-Itxvcd7F.js.map +1 -0
  12. package/dist/_chunks/define-cookie-BowvzoP0.js +94 -0
  13. package/dist/_chunks/define-cookie-BowvzoP0.js.map +1 -0
  14. package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
  15. package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
  16. package/dist/_chunks/format-CYBGxKtc.js +14 -0
  17. package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
  18. package/dist/_chunks/{interception-BOoWmLUA.js → interception-ErnB33JX.js} +301 -133
  19. package/dist/_chunks/interception-ErnB33JX.js.map +1 -0
  20. package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
  21. package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
  22. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
  23. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
  24. package/dist/_chunks/request-context-CK5tZqIP.js +478 -0
  25. package/dist/_chunks/request-context-CK5tZqIP.js.map +1 -0
  26. package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
  27. package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
  28. package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
  29. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
  30. package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
  31. package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
  32. package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
  33. package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
  34. package/dist/_chunks/stale-reload-BX5gL1r-.js +64 -0
  35. package/dist/_chunks/stale-reload-BX5gL1r-.js.map +1 -0
  36. package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
  37. package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
  38. package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
  39. package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
  40. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-BiV5GJgm.js} +7 -4
  41. package/dist/_chunks/use-query-states-BiV5GJgm.js.map +1 -0
  42. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  43. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  44. package/dist/adapters/cloudflare-dev.js +73 -0
  45. package/dist/adapters/cloudflare-dev.js.map +1 -0
  46. package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
  47. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  48. package/dist/adapters/cloudflare-kv-cache.js +95 -0
  49. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  50. package/dist/adapters/cloudflare.d.ts +148 -12
  51. package/dist/adapters/cloudflare.d.ts.map +1 -1
  52. package/dist/adapters/cloudflare.js +135 -11
  53. package/dist/adapters/cloudflare.js.map +1 -1
  54. package/dist/adapters/compress-module.d.ts.map +1 -1
  55. package/dist/adapters/nitro.d.ts +17 -1
  56. package/dist/adapters/nitro.d.ts.map +1 -1
  57. package/dist/adapters/nitro.js +56 -13
  58. package/dist/adapters/nitro.js.map +1 -1
  59. package/dist/cache/cache-api.d.ts +24 -0
  60. package/dist/cache/cache-api.d.ts.map +1 -0
  61. package/dist/cache/handler-store.d.ts +31 -0
  62. package/dist/cache/handler-store.d.ts.map +1 -0
  63. package/dist/cache/index.d.ts +23 -7
  64. package/dist/cache/index.d.ts.map +1 -1
  65. package/dist/cache/index.js +142 -80
  66. package/dist/cache/index.js.map +1 -1
  67. package/dist/cache/singleflight.d.ts +18 -1
  68. package/dist/cache/singleflight.d.ts.map +1 -1
  69. package/dist/cache/sizeof.d.ts +22 -0
  70. package/dist/cache/sizeof.d.ts.map +1 -0
  71. package/dist/cache/timber-cache.d.ts +1 -1
  72. package/dist/cache/timber-cache.d.ts.map +1 -1
  73. package/dist/cli.d.ts +6 -1
  74. package/dist/cli.d.ts.map +1 -1
  75. package/dist/cli.js +8 -3
  76. package/dist/cli.js.map +1 -1
  77. package/dist/client/browser-dev.d.ts +27 -1
  78. package/dist/client/browser-dev.d.ts.map +1 -1
  79. package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
  80. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  81. package/dist/client/browser-entry/hmr.d.ts +21 -0
  82. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  83. package/dist/client/browser-entry/hydrate.d.ts +46 -0
  84. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  85. package/dist/client/browser-entry/index.d.ts +30 -0
  86. package/dist/client/browser-entry/index.d.ts.map +1 -0
  87. package/dist/client/browser-entry/post-hydration.d.ts +26 -0
  88. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  89. package/dist/client/browser-entry/router-init.d.ts +23 -0
  90. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  91. package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
  92. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  93. package/dist/client/browser-entry/scroll.d.ts +19 -0
  94. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  95. package/dist/client/error-boundary.d.ts +12 -5
  96. package/dist/client/error-boundary.d.ts.map +1 -1
  97. package/dist/client/error-boundary.js +10 -4
  98. package/dist/client/error-boundary.js.map +1 -1
  99. package/dist/client/error-reconstituter.d.ts +54 -0
  100. package/dist/client/error-reconstituter.d.ts.map +1 -0
  101. package/dist/client/form.d.ts +6 -3
  102. package/dist/client/form.d.ts.map +1 -1
  103. package/dist/client/history.d.ts +19 -4
  104. package/dist/client/history.d.ts.map +1 -1
  105. package/dist/client/index.d.ts +9 -21
  106. package/dist/client/index.d.ts.map +1 -1
  107. package/dist/client/index.js +229 -1018
  108. package/dist/client/index.js.map +1 -1
  109. package/dist/client/internal.d.ts +18 -0
  110. package/dist/client/internal.d.ts.map +1 -0
  111. package/dist/client/internal.js +890 -0
  112. package/dist/client/internal.js.map +1 -0
  113. package/dist/client/link-pending-store.d.ts +63 -0
  114. package/dist/client/link-pending-store.d.ts.map +1 -0
  115. package/dist/client/link.d.ts +62 -55
  116. package/dist/client/link.d.ts.map +1 -1
  117. package/dist/client/nav-link-store.d.ts +36 -0
  118. package/dist/client/nav-link-store.d.ts.map +1 -0
  119. package/dist/client/navigation-api-types.d.ts +90 -0
  120. package/dist/client/navigation-api-types.d.ts.map +1 -0
  121. package/dist/client/navigation-api.d.ts +115 -0
  122. package/dist/client/navigation-api.d.ts.map +1 -0
  123. package/dist/client/navigation-context.d.ts +13 -2
  124. package/dist/client/navigation-context.d.ts.map +1 -1
  125. package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
  126. package/dist/client/navigation-root.d.ts.map +1 -0
  127. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  128. package/dist/client/router-ref.d.ts +1 -1
  129. package/dist/client/router.d.ts +70 -4
  130. package/dist/client/router.d.ts.map +1 -1
  131. package/dist/client/rsc-fetch.d.ts +38 -3
  132. package/dist/client/rsc-fetch.d.ts.map +1 -1
  133. package/dist/client/segment-cache.d.ts +1 -1
  134. package/dist/client/segment-cache.d.ts.map +1 -1
  135. package/dist/client/segment-outlet.d.ts +63 -0
  136. package/dist/client/segment-outlet.d.ts.map +1 -0
  137. package/dist/client/ssr-data.d.ts +13 -4
  138. package/dist/client/ssr-data.d.ts.map +1 -1
  139. package/dist/client/stale-reload.d.ts +15 -0
  140. package/dist/client/stale-reload.d.ts.map +1 -1
  141. package/dist/client/top-loader.d.ts +5 -5
  142. package/dist/client/top-loader.d.ts.map +1 -1
  143. package/dist/client/use-link-status.d.ts +5 -5
  144. package/dist/client/use-link-status.d.ts.map +1 -1
  145. package/dist/client/use-params.d.ts +6 -4
  146. package/dist/client/use-params.d.ts.map +1 -1
  147. package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
  148. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  149. package/dist/client/use-query-states.d.ts +1 -1
  150. package/dist/client/use-query-states.d.ts.map +1 -1
  151. package/dist/client/use-router.d.ts +1 -1
  152. package/dist/codec.d.ts +33 -0
  153. package/dist/codec.d.ts.map +1 -0
  154. package/dist/codec.js +2 -0
  155. package/dist/config-types.d.ts +266 -0
  156. package/dist/config-types.d.ts.map +1 -0
  157. package/dist/config-validation.d.ts +51 -0
  158. package/dist/config-validation.d.ts.map +1 -0
  159. package/dist/content/index.d.ts +1 -10
  160. package/dist/content/index.d.ts.map +1 -1
  161. package/dist/content/index.js +0 -2
  162. package/dist/cookies/define-cookie.d.ts +35 -14
  163. package/dist/cookies/define-cookie.d.ts.map +1 -1
  164. package/dist/cookies/index.js +1 -83
  165. package/dist/fonts/bundle.d.ts +48 -0
  166. package/dist/fonts/bundle.d.ts.map +1 -0
  167. package/dist/fonts/css.d.ts +1 -0
  168. package/dist/fonts/css.d.ts.map +1 -1
  169. package/dist/fonts/dev-middleware.d.ts +22 -0
  170. package/dist/fonts/dev-middleware.d.ts.map +1 -0
  171. package/dist/fonts/pipeline.d.ts +138 -0
  172. package/dist/fonts/pipeline.d.ts.map +1 -0
  173. package/dist/fonts/transform.d.ts +72 -0
  174. package/dist/fonts/transform.d.ts.map +1 -0
  175. package/dist/fonts/types.d.ts +45 -1
  176. package/dist/fonts/types.d.ts.map +1 -1
  177. package/dist/fonts/virtual-modules.d.ts +59 -0
  178. package/dist/fonts/virtual-modules.d.ts.map +1 -0
  179. package/dist/index.d.ts +45 -190
  180. package/dist/index.d.ts.map +1 -1
  181. package/dist/index.js +4294 -2453
  182. package/dist/index.js.map +1 -1
  183. package/dist/plugin-context.d.ts +107 -0
  184. package/dist/plugin-context.d.ts.map +1 -0
  185. package/dist/plugins/adapter-build.d.ts +1 -1
  186. package/dist/plugins/adapter-build.d.ts.map +1 -1
  187. package/dist/plugins/build-manifest.d.ts +2 -2
  188. package/dist/plugins/build-manifest.d.ts.map +1 -1
  189. package/dist/plugins/build-report.d.ts +3 -3
  190. package/dist/plugins/build-report.d.ts.map +1 -1
  191. package/dist/plugins/client-chunks.d.ts +32 -0
  192. package/dist/plugins/client-chunks.d.ts.map +1 -0
  193. package/dist/plugins/content.d.ts +1 -1
  194. package/dist/plugins/content.d.ts.map +1 -1
  195. package/dist/plugins/dev-404-page.d.ts +56 -0
  196. package/dist/plugins/dev-404-page.d.ts.map +1 -0
  197. package/dist/plugins/dev-browser-logs.d.ts +84 -0
  198. package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
  199. package/dist/plugins/dev-error-overlay.d.ts +49 -9
  200. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  201. package/dist/plugins/dev-error-page.d.ts +58 -0
  202. package/dist/plugins/dev-error-page.d.ts.map +1 -0
  203. package/dist/plugins/dev-logs.d.ts +1 -1
  204. package/dist/plugins/dev-logs.d.ts.map +1 -1
  205. package/dist/plugins/dev-server.d.ts +1 -1
  206. package/dist/plugins/dev-server.d.ts.map +1 -1
  207. package/dist/plugins/dev-terminal-error.d.ts +28 -0
  208. package/dist/plugins/dev-terminal-error.d.ts.map +1 -0
  209. package/dist/plugins/entries.d.ts +1 -1
  210. package/dist/plugins/entries.d.ts.map +1 -1
  211. package/dist/plugins/fonts.d.ts +17 -73
  212. package/dist/plugins/fonts.d.ts.map +1 -1
  213. package/dist/plugins/mdx.d.ts +1 -1
  214. package/dist/plugins/mdx.d.ts.map +1 -1
  215. package/dist/plugins/routing.d.ts +1 -1
  216. package/dist/plugins/routing.d.ts.map +1 -1
  217. package/dist/plugins/server-bundle.d.ts.map +1 -1
  218. package/dist/plugins/shims.d.ts +6 -5
  219. package/dist/plugins/shims.d.ts.map +1 -1
  220. package/dist/plugins/static-build.d.ts +4 -4
  221. package/dist/plugins/static-build.d.ts.map +1 -1
  222. package/dist/routing/codegen-shared.d.ts +38 -0
  223. package/dist/routing/codegen-shared.d.ts.map +1 -0
  224. package/dist/routing/codegen-types.d.ts +36 -0
  225. package/dist/routing/codegen-types.d.ts.map +1 -0
  226. package/dist/routing/codegen.d.ts +2 -2
  227. package/dist/routing/codegen.d.ts.map +1 -1
  228. package/dist/routing/convention-lint.d.ts +41 -0
  229. package/dist/routing/convention-lint.d.ts.map +1 -0
  230. package/dist/routing/index.d.ts +2 -0
  231. package/dist/routing/index.d.ts.map +1 -1
  232. package/dist/routing/index.js +3 -2
  233. package/dist/routing/link-codegen.d.ts +90 -0
  234. package/dist/routing/link-codegen.d.ts.map +1 -0
  235. package/dist/routing/scanner.d.ts.map +1 -1
  236. package/dist/routing/segment-classify.d.ts +46 -0
  237. package/dist/routing/segment-classify.d.ts.map +1 -0
  238. package/dist/routing/status-file-lint.d.ts +2 -1
  239. package/dist/routing/status-file-lint.d.ts.map +1 -1
  240. package/dist/routing/types.d.ts +16 -4
  241. package/dist/routing/types.d.ts.map +1 -1
  242. package/dist/rsc-runtime/rsc.d.ts +1 -1
  243. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  244. package/dist/rsc-runtime/ssr.d.ts +12 -0
  245. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  246. package/dist/schema-bridge.d.ts +76 -0
  247. package/dist/schema-bridge.d.ts.map +1 -0
  248. package/dist/search-params/define.d.ts +139 -0
  249. package/dist/search-params/define.d.ts.map +1 -0
  250. package/dist/search-params/index.d.ts +4 -7
  251. package/dist/search-params/index.d.ts.map +1 -1
  252. package/dist/search-params/index.js +32 -441
  253. package/dist/search-params/index.js.map +1 -1
  254. package/dist/search-params/registry.d.ts +2 -2
  255. package/dist/search-params/registry.d.ts.map +1 -1
  256. package/dist/search-params/wrappers.d.ts +53 -0
  257. package/dist/search-params/wrappers.d.ts.map +1 -0
  258. package/dist/segment-params/define.d.ts +78 -0
  259. package/dist/segment-params/define.d.ts.map +1 -0
  260. package/dist/segment-params/index.d.ts +3 -0
  261. package/dist/segment-params/index.d.ts.map +1 -0
  262. package/dist/segment-params/index.js +2 -0
  263. package/dist/server/access-gate.d.ts +4 -0
  264. package/dist/server/access-gate.d.ts.map +1 -1
  265. package/dist/server/action-client.d.ts +41 -6
  266. package/dist/server/action-client.d.ts.map +1 -1
  267. package/dist/server/action-encryption.d.ts +76 -0
  268. package/dist/server/action-encryption.d.ts.map +1 -0
  269. package/dist/server/action-handler.d.ts +7 -0
  270. package/dist/server/action-handler.d.ts.map +1 -1
  271. package/dist/server/actions.d.ts +3 -6
  272. package/dist/server/actions.d.ts.map +1 -1
  273. package/dist/server/als-registry.d.ts +32 -4
  274. package/dist/server/als-registry.d.ts.map +1 -1
  275. package/dist/server/build-manifest.d.ts +2 -2
  276. package/dist/server/build-manifest.d.ts.map +1 -1
  277. package/dist/server/debug.d.ts +1 -1
  278. package/dist/server/default-logger.d.ts +22 -0
  279. package/dist/server/default-logger.d.ts.map +1 -0
  280. package/dist/server/deny-page-resolver.d.ts +52 -0
  281. package/dist/server/deny-page-resolver.d.ts.map +1 -0
  282. package/dist/server/deny-renderer.d.ts.map +1 -1
  283. package/dist/server/dev-holding-server.d.ts +52 -0
  284. package/dist/server/dev-holding-server.d.ts.map +1 -0
  285. package/dist/server/dev-source-map.d.ts +22 -0
  286. package/dist/server/dev-source-map.d.ts.map +1 -0
  287. package/dist/server/dev-warnings.d.ts +1 -21
  288. package/dist/server/dev-warnings.d.ts.map +1 -1
  289. package/dist/server/early-hints.d.ts +13 -5
  290. package/dist/server/early-hints.d.ts.map +1 -1
  291. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  292. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  293. package/dist/server/fallback-error.d.ts +12 -7
  294. package/dist/server/fallback-error.d.ts.map +1 -1
  295. package/dist/server/flight-injection-state.d.ts +66 -0
  296. package/dist/server/flight-injection-state.d.ts.map +1 -0
  297. package/dist/server/flight-scripts.d.ts +42 -0
  298. package/dist/server/flight-scripts.d.ts.map +1 -0
  299. package/dist/server/flush.d.ts.map +1 -1
  300. package/dist/server/form-data.d.ts +29 -0
  301. package/dist/server/form-data.d.ts.map +1 -1
  302. package/dist/server/html-injectors.d.ts +51 -11
  303. package/dist/server/html-injectors.d.ts.map +1 -1
  304. package/dist/server/index.d.ts +5 -43
  305. package/dist/server/index.d.ts.map +1 -1
  306. package/dist/server/index.js +195 -2800
  307. package/dist/server/index.js.map +1 -1
  308. package/dist/server/internal.d.ts +46 -0
  309. package/dist/server/internal.d.ts.map +1 -0
  310. package/dist/server/internal.js +2900 -0
  311. package/dist/server/internal.js.map +1 -0
  312. package/dist/server/logger.d.ts +25 -7
  313. package/dist/server/logger.d.ts.map +1 -1
  314. package/dist/server/middleware-runner.d.ts +19 -4
  315. package/dist/server/middleware-runner.d.ts.map +1 -1
  316. package/dist/server/node-stream-transforms.d.ts +113 -0
  317. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  318. package/dist/server/page-deny-boundary.d.ts +31 -0
  319. package/dist/server/page-deny-boundary.d.ts.map +1 -0
  320. package/dist/server/pipeline-interception.d.ts +1 -1
  321. package/dist/server/pipeline-interception.d.ts.map +1 -1
  322. package/dist/server/pipeline-metadata.d.ts +6 -0
  323. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  324. package/dist/server/pipeline.d.ts +52 -10
  325. package/dist/server/pipeline.d.ts.map +1 -1
  326. package/dist/server/primitives.d.ts +69 -18
  327. package/dist/server/primitives.d.ts.map +1 -1
  328. package/dist/server/render-timeout.d.ts +51 -0
  329. package/dist/server/render-timeout.d.ts.map +1 -0
  330. package/dist/server/request-context.d.ts +112 -43
  331. package/dist/server/request-context.d.ts.map +1 -1
  332. package/dist/server/route-element-builder.d.ts +27 -1
  333. package/dist/server/route-element-builder.d.ts.map +1 -1
  334. package/dist/server/route-handler.d.ts.map +1 -1
  335. package/dist/server/route-matcher.d.ts +16 -2
  336. package/dist/server/route-matcher.d.ts.map +1 -1
  337. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  338. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  339. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  340. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  341. package/dist/server/rsc-entry/helpers.d.ts +48 -5
  342. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  343. package/dist/server/rsc-entry/index.d.ts +20 -3
  344. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  345. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  346. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  347. package/dist/server/rsc-entry/rsc-stream.d.ts +14 -1
  348. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  349. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  350. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  351. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  352. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  353. package/dist/server/safe-load.d.ts +46 -0
  354. package/dist/server/safe-load.d.ts.map +1 -0
  355. package/dist/server/sensitive-fields.d.ts +74 -0
  356. package/dist/server/sensitive-fields.d.ts.map +1 -0
  357. package/dist/server/sitemap-generator.d.ts +129 -0
  358. package/dist/server/sitemap-generator.d.ts.map +1 -0
  359. package/dist/server/sitemap-handler.d.ts +22 -0
  360. package/dist/server/sitemap-handler.d.ts.map +1 -0
  361. package/dist/server/slot-resolver.d.ts +1 -1
  362. package/dist/server/slot-resolver.d.ts.map +1 -1
  363. package/dist/server/ssr-entry.d.ts +23 -0
  364. package/dist/server/ssr-entry.d.ts.map +1 -1
  365. package/dist/server/ssr-render.d.ts +39 -21
  366. package/dist/server/ssr-render.d.ts.map +1 -1
  367. package/dist/server/ssr-wrappers.d.ts +50 -0
  368. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  369. package/dist/server/status-code-resolver.d.ts +1 -1
  370. package/dist/server/status-code-resolver.d.ts.map +1 -1
  371. package/dist/server/stream-utils.d.ts +36 -0
  372. package/dist/server/stream-utils.d.ts.map +1 -0
  373. package/dist/server/tracing.d.ts +4 -4
  374. package/dist/server/tracing.d.ts.map +1 -1
  375. package/dist/server/tree-builder.d.ts +22 -19
  376. package/dist/server/tree-builder.d.ts.map +1 -1
  377. package/dist/server/types.d.ts +1 -4
  378. package/dist/server/types.d.ts.map +1 -1
  379. package/dist/server/version-skew.d.ts +61 -0
  380. package/dist/server/version-skew.d.ts.map +1 -0
  381. package/dist/shared/merge-search-params.d.ts +22 -0
  382. package/dist/shared/merge-search-params.d.ts.map +1 -0
  383. package/dist/shims/font-google.d.ts +1 -1
  384. package/dist/shims/font-google.d.ts.map +1 -1
  385. package/dist/shims/font-google.js +42 -0
  386. package/dist/shims/font-google.js.map +1 -0
  387. package/dist/shims/font-local.d.ts +26 -0
  388. package/dist/shims/font-local.d.ts.map +1 -0
  389. package/dist/shims/font-local.js +20 -0
  390. package/dist/shims/font-local.js.map +1 -0
  391. package/dist/shims/headers.d.ts +2 -1
  392. package/dist/shims/headers.d.ts.map +1 -1
  393. package/dist/shims/navigation-client.d.ts +1 -1
  394. package/dist/shims/navigation-client.d.ts.map +1 -1
  395. package/dist/shims/navigation.d.ts +3 -2
  396. package/dist/shims/navigation.d.ts.map +1 -1
  397. package/dist/utils/directive-parser.d.ts +5 -2
  398. package/dist/utils/directive-parser.d.ts.map +1 -1
  399. package/dist/utils/state-machine.d.ts +80 -0
  400. package/dist/utils/state-machine.d.ts.map +1 -0
  401. package/package.json +51 -16
  402. package/src/adapters/cloudflare-dev.ts +177 -0
  403. package/src/adapters/cloudflare-kv-cache.ts +142 -0
  404. package/src/adapters/cloudflare.ts +342 -28
  405. package/src/adapters/compress-module.ts +24 -4
  406. package/src/adapters/nitro.ts +52 -8
  407. package/src/adapters/wrangler.d.ts +7 -0
  408. package/src/cache/cache-api.ts +38 -0
  409. package/src/cache/handler-store.ts +68 -0
  410. package/src/cache/index.ts +81 -18
  411. package/src/cache/singleflight.ts +62 -4
  412. package/src/cache/sizeof.ts +31 -0
  413. package/src/cache/timber-cache.ts +24 -20
  414. package/src/cli.ts +16 -6
  415. package/src/client/browser-dev.ts +128 -1
  416. package/src/client/browser-entry/action-dispatch.ts +116 -0
  417. package/src/client/browser-entry/hmr.ts +81 -0
  418. package/src/client/browser-entry/hydrate.ts +145 -0
  419. package/src/client/browser-entry/index.ts +143 -0
  420. package/src/client/browser-entry/post-hydration.ts +119 -0
  421. package/src/client/browser-entry/router-init.ts +193 -0
  422. package/src/client/browser-entry/rsc-stream.ts +157 -0
  423. package/src/client/browser-entry/scroll.ts +27 -0
  424. package/src/client/error-boundary.tsx +48 -16
  425. package/src/client/error-reconstituter.tsx +65 -0
  426. package/src/client/form.tsx +14 -7
  427. package/src/client/history.ts +26 -4
  428. package/src/client/index.ts +65 -38
  429. package/src/client/internal.ts +57 -0
  430. package/src/client/link-pending-store.ts +111 -0
  431. package/src/client/link.tsx +342 -113
  432. package/src/client/nav-link-store.ts +47 -0
  433. package/src/client/navigation-api-types.ts +112 -0
  434. package/src/client/navigation-api.ts +332 -0
  435. package/src/client/navigation-context.ts +31 -6
  436. package/src/client/navigation-root.tsx +342 -0
  437. package/src/client/nuqs-adapter.tsx +16 -3
  438. package/src/client/router-ref.ts +1 -1
  439. package/src/client/router.ts +299 -72
  440. package/src/client/rsc-fetch.ts +97 -8
  441. package/src/client/segment-cache.ts +1 -1
  442. package/src/client/segment-outlet.tsx +86 -0
  443. package/src/client/ssr-data.ts +13 -5
  444. package/src/client/stale-reload.ts +72 -3
  445. package/src/client/top-loader.tsx +18 -6
  446. package/src/client/use-link-status.ts +7 -7
  447. package/src/client/use-params.ts +7 -5
  448. package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
  449. package/src/client/use-query-states.ts +9 -3
  450. package/src/client/use-router.ts +1 -1
  451. package/src/codec.ts +49 -0
  452. package/src/config-types.ts +264 -0
  453. package/src/config-validation.ts +303 -0
  454. package/src/content/index.ts +5 -13
  455. package/src/cookies/define-cookie.ts +78 -25
  456. package/src/cookies/index.ts +8 -0
  457. package/src/fonts/bundle.ts +142 -0
  458. package/src/fonts/css.ts +2 -1
  459. package/src/fonts/dev-middleware.ts +74 -0
  460. package/src/fonts/pipeline.ts +275 -0
  461. package/src/fonts/transform.ts +353 -0
  462. package/src/fonts/types.ts +50 -1
  463. package/src/fonts/virtual-modules.ts +159 -0
  464. package/src/index.ts +314 -355
  465. package/src/plugin-context.ts +240 -0
  466. package/src/plugins/adapter-build.ts +9 -3
  467. package/src/plugins/build-manifest.ts +13 -2
  468. package/src/plugins/build-report.ts +3 -3
  469. package/src/plugins/client-chunks.ts +65 -0
  470. package/src/plugins/content.ts +1 -1
  471. package/src/plugins/dev-404-page.ts +418 -0
  472. package/src/plugins/dev-browser-logs.ts +288 -0
  473. package/src/plugins/dev-error-overlay.ts +286 -42
  474. package/src/plugins/dev-error-page.ts +536 -0
  475. package/src/plugins/dev-logs.ts +1 -1
  476. package/src/plugins/dev-server.ts +146 -19
  477. package/src/plugins/dev-terminal-error.ts +217 -0
  478. package/src/plugins/entries.ts +111 -10
  479. package/src/plugins/fonts.ts +133 -638
  480. package/src/plugins/mdx.ts +1 -1
  481. package/src/plugins/routing.ts +213 -31
  482. package/src/plugins/server-action-exports.ts +1 -1
  483. package/src/plugins/server-bundle.ts +32 -1
  484. package/src/plugins/shims.ts +136 -35
  485. package/src/plugins/static-build.ts +17 -11
  486. package/src/routing/codegen-shared.ts +74 -0
  487. package/src/routing/codegen-types.ts +37 -0
  488. package/src/routing/codegen.ts +112 -173
  489. package/src/routing/convention-lint.ts +356 -0
  490. package/src/routing/index.ts +2 -0
  491. package/src/routing/link-codegen.ts +262 -0
  492. package/src/routing/scanner.ts +93 -23
  493. package/src/routing/segment-classify.ts +89 -0
  494. package/src/routing/status-file-lint.ts +3 -2
  495. package/src/routing/types.ts +17 -4
  496. package/src/rsc-runtime/rsc.ts +2 -0
  497. package/src/rsc-runtime/ssr.ts +50 -0
  498. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  499. package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
  500. package/src/search-params/define.ts +482 -0
  501. package/src/search-params/index.ts +14 -20
  502. package/src/search-params/registry.ts +2 -2
  503. package/src/search-params/wrappers.ts +85 -0
  504. package/src/segment-params/define.ts +279 -0
  505. package/src/segment-params/index.ts +9 -0
  506. package/src/server/access-gate.tsx +70 -29
  507. package/src/server/action-client.ts +88 -15
  508. package/src/server/action-encryption.ts +144 -0
  509. package/src/server/action-handler.ts +53 -6
  510. package/src/server/actions.ts +10 -9
  511. package/src/server/als-registry.ts +34 -6
  512. package/src/server/build-manifest.ts +10 -4
  513. package/src/server/compress.ts +25 -7
  514. package/src/server/debug.ts +1 -1
  515. package/src/server/default-logger.ts +99 -0
  516. package/src/server/deny-page-resolver.ts +154 -0
  517. package/src/server/deny-renderer.ts +24 -38
  518. package/src/server/dev-holding-server.ts +185 -0
  519. package/src/server/dev-source-map.ts +31 -0
  520. package/src/server/dev-warnings.ts +4 -49
  521. package/src/server/early-hints.ts +36 -15
  522. package/src/server/error-boundary-wrapper.ts +74 -22
  523. package/src/server/fallback-error.ts +74 -102
  524. package/src/server/flight-injection-state.ts +113 -0
  525. package/src/server/flight-scripts.ts +62 -0
  526. package/src/server/flush.ts +2 -1
  527. package/src/server/form-data.ts +76 -0
  528. package/src/server/html-injectors.ts +280 -120
  529. package/src/server/index.ts +25 -177
  530. package/src/server/internal.ts +169 -0
  531. package/src/server/logger.ts +44 -36
  532. package/src/server/middleware-runner.ts +31 -4
  533. package/src/server/node-stream-transforms.ts +509 -0
  534. package/src/server/page-deny-boundary.tsx +56 -0
  535. package/src/server/pipeline-interception.ts +17 -16
  536. package/src/server/pipeline-metadata.ts +13 -0
  537. package/src/server/pipeline.ts +261 -66
  538. package/src/server/primitives.ts +111 -28
  539. package/src/server/render-timeout.ts +108 -0
  540. package/src/server/request-context.ts +293 -132
  541. package/src/server/route-element-builder.ts +283 -191
  542. package/src/server/route-handler.ts +24 -4
  543. package/src/server/route-matcher.ts +31 -20
  544. package/src/server/rsc-entry/api-handler.ts +15 -16
  545. package/src/server/rsc-entry/error-renderer.ts +305 -89
  546. package/src/server/rsc-entry/helpers.ts +134 -5
  547. package/src/server/rsc-entry/index.ts +304 -111
  548. package/src/server/rsc-entry/rsc-payload.ts +65 -18
  549. package/src/server/rsc-entry/rsc-stream.ts +81 -13
  550. package/src/server/rsc-entry/ssr-bridge.ts +14 -5
  551. package/src/server/rsc-entry/ssr-renderer.ts +171 -38
  552. package/src/server/safe-load.ts +60 -0
  553. package/src/server/sensitive-fields.ts +230 -0
  554. package/src/server/sitemap-generator.ts +338 -0
  555. package/src/server/sitemap-handler.ts +126 -0
  556. package/src/server/slot-resolver.ts +244 -229
  557. package/src/server/ssr-entry.ts +215 -32
  558. package/src/server/ssr-render.ts +289 -67
  559. package/src/server/ssr-wrappers.tsx +139 -0
  560. package/src/server/status-code-resolver.ts +1 -1
  561. package/src/server/stream-utils.ts +213 -0
  562. package/src/server/tracing.ts +20 -9
  563. package/src/server/tree-builder.ts +92 -58
  564. package/src/server/types.ts +3 -6
  565. package/src/server/version-skew.ts +104 -0
  566. package/src/shared/merge-search-params.ts +55 -0
  567. package/src/shims/font-google.ts +1 -1
  568. package/src/shims/font-local.ts +34 -0
  569. package/src/shims/headers.ts +5 -1
  570. package/src/shims/navigation-client.ts +1 -1
  571. package/src/shims/navigation.ts +7 -2
  572. package/src/utils/directive-parser.ts +5 -2
  573. package/src/utils/state-machine.ts +111 -0
  574. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  575. package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
  576. package/dist/_chunks/format-DviM89f0.js.map +0 -1
  577. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  578. package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
  579. package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
  580. package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
  581. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  582. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  583. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  584. package/dist/cache/register-cached-function.d.ts +0 -17
  585. package/dist/cache/register-cached-function.d.ts.map +0 -1
  586. package/dist/client/browser-entry.d.ts +0 -21
  587. package/dist/client/browser-entry.d.ts.map +0 -1
  588. package/dist/client/link-status-provider.d.ts +0 -11
  589. package/dist/client/link-status-provider.d.ts.map +0 -1
  590. package/dist/client/transition-root.d.ts.map +0 -1
  591. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  592. package/dist/cookies/index.js.map +0 -1
  593. package/dist/plugins/cache-transform.d.ts +0 -36
  594. package/dist/plugins/cache-transform.d.ts.map +0 -1
  595. package/dist/plugins/dynamic-transform.d.ts +0 -72
  596. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  597. package/dist/search-params/analyze.d.ts +0 -54
  598. package/dist/search-params/analyze.d.ts.map +0 -1
  599. package/dist/search-params/builtin-codecs.d.ts +0 -105
  600. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  601. package/dist/search-params/codecs.d.ts +0 -53
  602. package/dist/search-params/codecs.d.ts.map +0 -1
  603. package/dist/search-params/create.d.ts +0 -106
  604. package/dist/search-params/create.d.ts.map +0 -1
  605. package/dist/server/prerender.d.ts +0 -77
  606. package/dist/server/prerender.d.ts.map +0 -1
  607. package/dist/server/response-cache.d.ts +0 -54
  608. package/dist/server/response-cache.d.ts.map +0 -1
  609. package/src/cache/register-cached-function.ts +0 -103
  610. package/src/client/browser-entry.ts +0 -678
  611. package/src/client/link-status-provider.tsx +0 -30
  612. package/src/client/transition-root.tsx +0 -166
  613. package/src/plugins/cache-transform.ts +0 -199
  614. package/src/plugins/dynamic-transform.ts +0 -161
  615. package/src/search-params/analyze.ts +0 -192
  616. package/src/search-params/builtin-codecs.ts +0 -228
  617. package/src/search-params/create.ts +0 -321
  618. package/src/server/prerender.ts +0 -139
  619. package/src/server/response-cache.ts +0 -410
@@ -1,704 +1,199 @@
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
21
  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';
22
+ import type { PluginContext } from '../plugin-context.js';
28
23
  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 module that exports the combined font CSS string.
41
- *
42
- * The RSC entry imports this module and inlines it as a <style> tag.
43
- * Unlike a config-based approach, this module is loaded lazily (on first
44
- * request), so it always has up-to-date font data from the registry.
45
- */
46
- const VIRTUAL_FONT_CSS = 'virtual:timber-font-css';
47
- const RESOLVED_FONT_CSS = '\0virtual:timber-font-css';
48
-
49
- /**
50
- * Registry of fonts extracted during transform.
51
- * Keyed by a unique font ID derived from family + config.
52
- */
53
- export type FontRegistry = Map<string, ExtractedFont>;
54
-
55
- /**
56
- * Convert a font family name to a PascalCase export name.
57
- * e.g. "JetBrains Mono" → "JetBrains_Mono"
58
- */
59
- function familyToExportName(family: string): string {
60
- return family.replace(/\s+/g, '_');
61
- }
62
-
63
- /**
64
- * Convert a font family name to a scoped class name.
65
- * e.g. "JetBrains Mono" → "timber-font-jetbrains-mono"
66
- */
67
- function familyToClassName(family: string): string {
68
- return `timber-font-${family.toLowerCase().replace(/\s+/g, '-')}`;
69
- }
70
-
71
- /**
72
- * Generate a unique font ID from family + config hash.
73
- */
74
- function generateFontId(family: string, config: GoogleFontConfig): string {
75
- const weights = normalizeToArray(config.weight);
76
- const styles = normalizeToArray(config.style);
77
- const subsets = config.subsets ?? ['latin'];
78
- return `${family.toLowerCase()}-${weights.join(',')}-${styles.join(',')}-${subsets.join(',')}`;
79
- }
80
-
81
- /**
82
- * Normalize a string or string array to an array.
83
- */
84
- function normalizeToArray(value: string | string[] | undefined): string[] {
85
- if (!value) return ['400'];
86
- return Array.isArray(value) ? value : [value];
87
- }
88
-
89
- /**
90
- * Normalize style to an array.
91
- */
92
- function normalizeStyleArray(value: string | string[] | undefined): string[] {
93
- if (!value) return ['normal'];
94
- return Array.isArray(value) ? value : [value];
95
- }
96
-
97
- /**
98
- * Extract static font config from a font function call in source code.
99
- *
100
- * Parses patterns like:
101
- * const inter = Inter({ subsets: ['latin'], weight: '400', display: 'swap', variable: '--font-sans' })
102
- *
103
- * Returns null if the call cannot be statically analyzed.
104
- *
105
- * Uses acorn AST parsing for robust handling of comments, trailing commas,
106
- * and multi-line configs.
107
- */
108
- export function extractFontConfig(callSource: string): GoogleFontConfig | null {
109
- return extractFontConfigAst(callSource);
110
- }
111
-
112
- /**
113
- * Detect if a source file contains dynamic/computed font function calls
114
- * that cannot be statically analyzed.
115
- *
116
- * Returns the offending expression if found, null if all calls are static.
117
- *
118
- * Uses acorn AST parsing for accurate detection.
119
- */
120
- export function detectDynamicFontCall(source: string, importedNames: string[]): string | null {
121
- return detectDynamicFontCallAst(source, importedNames);
122
- }
123
-
124
- /**
125
- * Regex that matches imports from either `@timber/fonts/google` or `next/font/google`.
126
- * The shims plugin resolves `next/font/google` to the same virtual module,
127
- * but the source code still contains the original import specifier.
128
- */
129
- const GOOGLE_FONT_IMPORT_RE =
130
- /import\s*\{([^}]+)\}\s*from\s*['"](?:@timber\/fonts\/google|next\/font\/google)['"]/g;
131
-
132
- /**
133
- * Parse import specifiers from a source file that imports from
134
- * `@timber/fonts/google` or `next/font/google`.
135
- *
136
- * Returns the list of imported font names (e.g. ['Inter', 'JetBrains_Mono']).
137
- */
138
- export function parseGoogleFontImports(source: string): string[] {
139
- const importPattern = new RegExp(GOOGLE_FONT_IMPORT_RE.source, 'g');
140
- const names: string[] = [];
141
-
142
- let match;
143
- while ((match = importPattern.exec(source)) !== null) {
144
- const specifiers = match[1]
145
- .split(',')
146
- .map((s) => s.trim())
147
- .filter(Boolean);
148
- for (const spec of specifiers) {
149
- // Handle `Inter as MyInter` — we want the local name
150
- const parts = spec.split(/\s+as\s+/);
151
- names.push(parts[parts.length - 1].trim());
152
- }
153
- }
154
-
155
- return names;
156
- }
157
-
158
- /**
159
- * Parse the original (remote) font family names from imports.
160
- *
161
- * Returns a map of local name → family name.
162
- * e.g. { Inter: 'Inter', JetBrains_Mono: 'JetBrains Mono' }
163
- */
164
- export function parseGoogleFontFamilies(source: string): Map<string, string> {
165
- const importPattern = new RegExp(GOOGLE_FONT_IMPORT_RE.source, 'g');
166
- const families = new Map<string, string>();
167
-
168
- let match;
169
- while ((match = importPattern.exec(source)) !== null) {
170
- const specifiers = match[1]
171
- .split(',')
172
- .map((s) => s.trim())
173
- .filter(Boolean);
174
- for (const spec of specifiers) {
175
- const parts = spec.split(/\s+as\s+/);
176
- const originalName = parts[0].trim();
177
- const localName = parts[parts.length - 1].trim();
178
- // Convert export name back to family name: JetBrains_Mono → JetBrains Mono
179
- const family = originalName.replace(/_/g, ' ');
180
- families.set(localName, family);
181
- }
182
- }
183
-
184
- return families;
185
- }
186
-
187
- /**
188
- * Generate the virtual module source for `@timber/fonts/google`.
189
- *
190
- * Each Google Font family gets a named export that returns a FontResult.
191
- * In this base implementation, the functions return static data.
192
- * The Google Fonts download task (timber-nk5) will add real font file URLs.
193
- */
194
- function generateGoogleVirtualModule(registry: FontRegistry): string {
195
- // Collect unique families from the registry
196
- const families = new Set<string>();
197
- for (const font of registry.values()) {
198
- if (font.provider === 'google') families.add(font.family);
199
- }
200
-
201
- const lines = [
202
- '// Auto-generated virtual module: @timber/fonts/google',
203
- '// Each export is a font loader function that returns a FontResult.',
204
- '',
205
- ];
206
-
207
- // If no fonts registered yet, export a generic loader for any font
208
- // This is the initial load — the transform hook will process actual calls
209
- lines.push('function createFontResult(family, config) {');
210
- lines.push(' return {');
211
- lines.push(' className: `timber-font-${family.toLowerCase().replace(/\\s+/g, "-")}`,');
212
- lines.push(' style: { fontFamily: family },');
213
- lines.push(' variable: config?.variable,');
214
- lines.push(' };');
215
- lines.push('}');
216
- lines.push('');
217
-
218
- // Export a Proxy-based default that handles any font name import
219
- lines.push('export default new Proxy({}, {');
220
- lines.push(' get(_, prop) {');
221
- lines.push(' if (typeof prop === "string") {');
222
- lines.push(' return (config) => createFontResult(prop.replace(/_/g, " "), config);');
223
- lines.push(' }');
224
- lines.push(' }');
225
- lines.push('});');
226
-
227
- // Also export known families as named exports for tree-shaking
228
- for (const family of families) {
229
- const exportName = familyToExportName(family);
230
- lines.push('');
231
- lines.push(`export function ${exportName}(config) {`);
232
- lines.push(` return createFontResult('${family}', config);`);
233
- lines.push('}');
234
- }
235
-
236
- return lines.join('\n');
237
- }
238
-
239
- /**
240
- * Generate the virtual module source for `@timber/fonts/local`.
241
- */
242
- function generateLocalVirtualModule(): string {
243
- return [
244
- '// Auto-generated virtual module: @timber/fonts/local',
245
- '',
246
- 'export default function localFont(config) {',
247
- ' const family = config?.family || "Local Font";',
248
- ' return {',
249
- ' className: `timber-font-${family.toLowerCase().replace(/\\s+/g, "-")}`,',
250
- ' style: { fontFamily: family },',
251
- ' variable: config?.variable,',
252
- ' };',
253
- '}',
254
- ].join('\n');
255
- }
256
-
257
- /**
258
- * Generate CSS for a single extracted font.
259
- *
260
- * Includes @font-face rules (for local fonts), fallback @font-face,
261
- * and the scoped class rule.
262
- */
263
- export function generateFontCss(font: ExtractedFont): string {
264
- const cssParts: string[] = [];
265
-
266
- if (font.provider === 'local' && font.localSources) {
267
- const faces = generateLocalFontFaces(font.family, font.localSources, font.display);
268
- const faceCss = generateFontFaces(faces);
269
- if (faceCss) cssParts.push(faceCss);
270
- }
271
-
272
- const fallbackCss = generateFallbackCss(font.family);
273
- if (fallbackCss) cssParts.push(fallbackCss);
274
-
275
- if (font.variable) {
276
- cssParts.push(generateVariableClass(font.className, font.variable, font.fontFamily));
277
- } else {
278
- cssParts.push(generateFontFamilyClass(font.className, font.fontFamily));
279
- }
280
-
281
- return cssParts.join('\n\n');
282
- }
283
-
284
- /**
285
- * Generate the CSS output for all extracted fonts.
286
- *
287
- * Includes @font-face rules for local fonts, fallback @font-face rules,
288
- * and scoped classes.
289
- */
290
- export function generateAllFontCss(registry: FontRegistry): string {
291
- const cssParts: string[] = [];
292
- for (const font of registry.values()) {
293
- cssParts.push(generateFontCss(font));
294
- }
295
- return cssParts.join('\n\n');
296
- }
297
-
298
- /**
299
- * Parse the local name used for the default import of `@timber/fonts/local`.
300
- *
301
- * Handles:
302
- * import localFont from '@timber/fonts/local'
303
- * import myLoader from '@timber/fonts/local'
304
- */
305
- export function parseLocalFontImportName(source: string): string | null {
306
- const match = source.match(
307
- /import\s+(\w+)\s+from\s*['"](?:@timber\/fonts\/local|next\/font\/local)['"]/
308
- );
309
- return match ? match[1] : null;
310
- }
311
-
312
- /**
313
- * Transform local font calls in source code.
314
- *
315
- * Finds `localFont({ ... })` calls, extracts the config,
316
- * registers the font, and replaces the call with a static FontResult.
317
- */
318
- function transformLocalFonts(
319
- transformedCode: string,
320
- originalCode: string,
321
- importerId: string,
322
- registry: FontRegistry,
323
- emitError: (msg: string) => void
324
- ): string {
325
- const localName = parseLocalFontImportName(originalCode);
326
- if (!localName) return transformedCode;
327
-
328
- // Check for dynamic calls
329
- const dynamicCall = detectDynamicFontCall(originalCode, [localName]);
330
- if (dynamicCall) {
331
- emitError(
332
- `Font function calls must be statically analyzable. ` +
333
- `Found dynamic call: ${dynamicCall}. ` +
334
- `Pass a literal object with string/array values instead.`
335
- );
336
- }
337
-
338
- // Find all calls: const varName = localFont({ ... })
339
- const callPattern = new RegExp(
340
- `(?:const|let|var)\\s+(\\w+)\\s*=\\s*${localName}\\s*\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`,
341
- 'g'
342
- );
343
-
344
- let callMatch;
345
- while ((callMatch = callPattern.exec(originalCode)) !== null) {
346
- const varName = callMatch[1];
347
- const configSource = callMatch[2];
348
- const fullMatch = callMatch[0];
349
-
350
- const config = extractLocalFontConfigAst(`(${configSource})`);
351
- if (!config) {
352
- emitError(
353
- `Could not statically analyze local font config. ` +
354
- `Ensure src is a string or array of { path, weight?, style? } objects.`
355
- );
356
- return transformedCode;
357
- }
358
-
359
- const extracted = processLocalFont(config, importerId);
360
- registry.set(extracted.id, extracted);
361
-
362
- const resultObj = extracted.variable
363
- ? `{ className: "${extracted.className}", style: { fontFamily: "${extracted.fontFamily}" }, variable: "${extracted.variable}" }`
364
- : `{ className: "${extracted.className}", style: { fontFamily: "${extracted.fontFamily}" } }`;
365
-
366
- const replacement = `const ${varName} = ${resultObj}`;
367
- transformedCode = transformedCode.replace(fullMatch, replacement);
368
- }
369
-
370
- // Remove the import statement
371
- transformedCode = transformedCode.replace(
372
- /import\s+\w+\s+from\s*['"](?:@timber\/fonts\/local|next\/font\/local)['"];?\s*\n?/g,
373
- ''
374
- );
375
-
376
- return transformedCode;
377
- }
24
+ downloadAndCacheFonts,
25
+ generateProductionFontFaces,
26
+ resolveDevFontFaces,
27
+ } from '../fonts/google.js';
28
+ import { FontPipeline } from '../fonts/pipeline.js';
29
+ import { runFontsTransform } from '../fonts/transform.js';
30
+ import { installFontDevMiddleware } from '../fonts/dev-middleware.js';
31
+ import { emitFontAssets, writeFontManifest, groupCachedFontsByFamily } from '../fonts/bundle.js';
32
+ import {
33
+ RESOLVED_GOOGLE,
34
+ RESOLVED_LOCAL,
35
+ RESOLVED_FONT_CSS_REGISTER,
36
+ VIRTUAL_GOOGLE,
37
+ VIRTUAL_LOCAL,
38
+ VIRTUAL_FONT_CSS_REGISTER,
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, pruneRegistryEntries, type FontRegistry } from '../fonts/pipeline.js';
51
+ export {
52
+ generateFontId,
53
+ extractFontConfig,
54
+ detectDynamicFontCall,
55
+ parseGoogleFontImports,
56
+ parseGoogleFontFamilies,
57
+ parseLocalFontImportName,
58
+ } from '../fonts/transform.js';
59
+ export { generateFontCss, generateAllFontCss } from '../fonts/virtual-modules.js';
378
60
 
379
61
  /**
380
62
  * Create the timber-fonts Vite plugin.
381
63
  */
382
64
  export function timberFonts(ctx: PluginContext): Plugin {
383
- const registry: FontRegistry = new Map();
384
- /** Fonts downloaded during buildStart (production only). */
385
- let cachedFonts: CachedFont[] = [];
65
+ const pipeline = new FontPipeline();
386
66
 
387
67
  return {
388
68
  name: 'timber-fonts',
389
69
 
390
70
  /**
391
- * Resolve `@timber/fonts/google`, `@timber/fonts/local`,
392
- * and `virtual:timber-font-css` virtual modules.
71
+ * Resolve `@timber/fonts/google`, `@timber/fonts/local`, and
72
+ * `virtual:timber-font-css-register` virtual modules.
73
+ *
74
+ * Strips the `\0` prefix added by the RSC plugin's re-imports and the
75
+ * absolute root prefix added by SSR build entries before comparing
76
+ * against the public IDs.
393
77
  */
394
78
  resolveId(id: string) {
395
- if (id === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
396
- if (id === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
397
- if (id === VIRTUAL_FONT_CSS) return RESOLVED_FONT_CSS;
79
+ let cleanId = id.startsWith('\0') ? id.slice(1) : id;
80
+ if (cleanId.startsWith(ctx.root)) {
81
+ const stripped = cleanId.slice(ctx.root.length);
82
+ if (stripped.startsWith('/') || stripped.startsWith('\\')) {
83
+ cleanId = stripped.slice(1);
84
+ } else {
85
+ cleanId = stripped;
86
+ }
87
+ }
88
+
89
+ if (cleanId === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
90
+ if (cleanId === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
91
+ if (cleanId === VIRTUAL_FONT_CSS_REGISTER) return RESOLVED_FONT_CSS_REGISTER;
398
92
  return null;
399
93
  },
400
94
 
401
95
  /**
402
96
  * Return generated source for font virtual modules.
403
97
  *
404
- * `virtual:timber-font-css` exports the combined @font-face CSS
405
- * as a string. The RSC entry imports it and inlines a <style> tag.
406
- * Because this is loaded lazily (on first request), the font
407
- * registry is always populated by the time it's needed.
98
+ * `virtual:timber-font-css-register` is a side-effect module that sets
99
+ * the combined `@font-face` CSS on `globalThis.__timber_font_css`. The
100
+ * RSC entry imports it transitively via the layout file and reads
101
+ * `globalThis.__timber_font_css` at render time to inline a `<style>`
102
+ * tag. In dev mode we also lazily resolve Google `@font-face`
103
+ * descriptors from the CDN here, since `buildStart` is a no-op in dev.
408
104
  */
409
- load(id: string) {
410
- if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
105
+ async load(id: string) {
106
+ if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(pipeline.fonts());
411
107
  if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
412
108
 
413
- if (id === RESOLVED_FONT_CSS) {
414
- const css = generateAllFontCss(registry);
415
- return `export default ${JSON.stringify(css)};`;
109
+ if (id === RESOLVED_FONT_CSS_REGISTER) {
110
+ if (ctx.dev) {
111
+ for (const font of pipeline.googleFonts()) {
112
+ if (pipeline.hasFaces(font.id)) continue;
113
+ try {
114
+ const faces = await resolveDevFontFaces(font);
115
+ pipeline.attachFaces(font.id, faces);
116
+ } catch (e) {
117
+ // Fail gracefully — fonts fall back to system fonts. Don't
118
+ // cache the failure so transient errors (network blips, rate
119
+ // limits) are retried on the next request. See TIM-636.
120
+ const msg = e instanceof Error ? e.message : String(e);
121
+ console.warn(
122
+ `[timber-fonts] Failed to resolve Google font "${font.family}": ${msg}. Will retry on next request.`
123
+ );
124
+ }
125
+ }
126
+ }
127
+
128
+ return `globalThis.__timber_font_css = ${JSON.stringify(pipeline.getCss())};`;
416
129
  }
417
130
  return null;
418
131
  },
419
132
 
420
133
  /**
421
- * Serve local font files and font CSS in dev mode under `/_timber/fonts/`.
422
- *
423
- * Serves:
424
- * - `/_timber/fonts/fonts.css` — combined @font-face + scoped class CSS
425
- * - `/_timber/fonts/<filename>` — individual font files from the registry
426
- *
427
- * Only files registered in the font registry are served.
428
- * Paths are validated to prevent directory traversal.
134
+ * Serve local font files in dev mode under `/_timber/fonts/<basename>`.
135
+ * Font CSS goes through Vite's CSS pipeline (virtual modules), not
136
+ * this middleware.
429
137
  */
430
138
  configureServer(server: ViteDevServer) {
431
- server.middlewares.use((req, res, next) => {
432
- const url = req.url;
433
- if (!url || !url.startsWith('/_timber/fonts/')) return next();
434
-
435
- const requestedFilename = url.slice('/_timber/fonts/'.length);
436
- // Reject path traversal attempts
437
- if (requestedFilename.includes('..') || requestedFilename.includes('/')) {
438
- res.statusCode = 400;
439
- res.end('Bad request');
440
- return;
441
- }
442
-
443
- // Font CSS is now injected via Vite's CSS pipeline (virtual:timber-font-css modules).
444
- // This middleware only serves font binary files (woff2, etc.).
445
-
446
- // Find the matching font file in the registry
447
- for (const font of registry.values()) {
448
- if (font.provider !== 'local' || !font.localSources) continue;
449
- for (const src of font.localSources) {
450
- const basename = src.path.split('/').pop() ?? '';
451
- if (basename === requestedFilename) {
452
- const absolutePath = normalize(resolve(src.path));
453
- if (!existsSync(absolutePath)) {
454
- res.statusCode = 404;
455
- res.end('Not found');
456
- return;
457
- }
458
- const data = readFileSync(absolutePath);
459
- const ext = absolutePath.split('.').pop()?.toLowerCase();
460
- const mimeMap: Record<string, string> = {
461
- woff2: 'font/woff2',
462
- woff: 'font/woff',
463
- ttf: 'font/ttf',
464
- otf: 'font/otf',
465
- eot: 'application/vnd.ms-fontopen',
466
- };
467
- res.setHeader('Content-Type', mimeMap[ext ?? ''] ?? 'application/octet-stream');
468
- res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
469
- res.setHeader('Access-Control-Allow-Origin', '*');
470
- res.end(data);
471
- return;
472
- }
473
- }
474
- }
475
-
476
- next();
477
- });
139
+ installFontDevMiddleware(server, pipeline);
478
140
  },
479
141
 
480
142
  /**
481
143
  * Download and cache Google Fonts during production builds.
482
144
  *
483
- * In dev mode this is a no-op — fonts point to the Google CDN.
145
+ * In dev mode this is a no-op — fonts point to the Google CDN and are
146
+ * resolved lazily inside `load()` when the side-effect module runs.
484
147
  * The registry is populated by the transform hook which runs before
485
- * buildStart in the build pipeline, so all fonts are known here.
148
+ * `buildStart` in the build pipeline, so all fonts are known here.
486
149
  */
487
150
  async buildStart() {
488
151
  if (ctx.dev) return;
489
152
 
490
- const googleFonts = [...registry.values()].filter((f) => f.provider === 'google');
153
+ const googleFonts = [...pipeline.googleFonts()];
491
154
  if (googleFonts.length === 0) return;
492
155
 
493
- cachedFonts = await downloadAndCacheFonts(googleFonts, ctx.root);
156
+ const cachedFonts = await downloadAndCacheFonts(googleFonts, ctx.root);
157
+
158
+ // Build a family→CachedFont[] lookup, then attach the cached files
159
+ // and resolved @font-face descriptors to each registered Google
160
+ // font. Multiple fonts that share a family hold references to the
161
+ // same `CachedFont` objects; the bundle emitter dedupes by
162
+ // `hashedFilename` so each binary is written to disk exactly once.
163
+ const cachedByFamily = groupCachedFontsByFamily(cachedFonts);
164
+ for (const font of googleFonts) {
165
+ const familyCached = cachedByFamily.get(font.family.toLowerCase()) ?? [];
166
+ pipeline.attachCachedFiles(font.id, familyCached);
167
+ pipeline.attachFaces(font.id, generateProductionFontFaces(familyCached, font.display));
168
+ }
494
169
  },
495
170
 
496
171
  /**
497
172
  * Scan source files for font function calls and extract static config.
498
173
  *
499
- * When a file imports from `@timber/fonts/google`, we:
500
- * 1. Parse the import specifiers to get font family names
501
- * 2. Find each font function call and extract its config
502
- * 3. Validate that all calls are statically analyzable
503
- * 4. Register extracted fonts in the registry
504
- * 5. Replace the function call with a static FontResult object
174
+ * Delegates to `runFontsTransform`. Errors raised through the
175
+ * `this.error` callback are surfaced as Vite plugin errors.
505
176
  */
506
177
  transform(code: string, id: string) {
507
- // Skip virtual modules and node_modules
508
- if (id.startsWith('\0') || id.includes('node_modules')) return null;
509
-
510
- const hasGoogleImport =
511
- code.includes('@timber/fonts/google') || code.includes('next/font/google');
512
- const hasLocalImport =
513
- code.includes('@timber/fonts/local') || code.includes('next/font/local');
514
- if (!hasGoogleImport && !hasLocalImport) return null;
515
-
516
- let transformedCode = code;
517
-
518
- // ── Google font transform ──────────────────────────────────────────
519
- if (hasGoogleImport) {
520
- const families = parseGoogleFontFamilies(code);
521
- if (families.size > 0) {
522
- const importedNames = [...families.keys()];
523
-
524
- const dynamicCall = detectDynamicFontCall(code, importedNames);
525
- if (dynamicCall) {
526
- this.error(
527
- `Font function calls must be statically analyzable. ` +
528
- `Found dynamic call: ${dynamicCall}. ` +
529
- `Pass a literal object with string/array values instead.`
530
- );
531
- }
532
-
533
- for (const [localName, family] of families) {
534
- const callPattern = new RegExp(
535
- `(?:const|let|var)\\s+(\\w+)\\s*=\\s*${localName}\\s*\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`,
536
- 'g'
537
- );
538
-
539
- let callMatch;
540
- while ((callMatch = callPattern.exec(code)) !== null) {
541
- const varName = callMatch[1];
542
- const configSource = callMatch[2];
543
- const fullMatch = callMatch[0];
544
-
545
- const config = extractFontConfig(`(${configSource})`);
546
- if (!config) {
547
- this.error(
548
- `Could not statically analyze font config for ${family}. ` +
549
- `Ensure all config values are string literals or arrays of string literals.`
550
- );
551
- return null;
552
- }
553
-
554
- const fontId = generateFontId(family, config);
555
- const className = familyToClassName(family);
556
- const fontStack = buildFontStack(family);
557
- const display = config.display ?? 'swap';
558
-
559
- const extracted: ExtractedFont = {
560
- id: fontId,
561
- family,
562
- provider: 'google',
563
- weights: normalizeToArray(config.weight),
564
- styles: normalizeStyleArray(config.style),
565
- subsets: config.subsets ?? ['latin'],
566
- display,
567
- variable: config.variable,
568
- className,
569
- fontFamily: fontStack,
570
- importer: id,
571
- };
572
-
573
- registry.set(fontId, extracted);
574
-
575
- const resultObj = config.variable
576
- ? `{ className: "${className}", style: { fontFamily: "${fontStack}" }, variable: "${config.variable}" }`
577
- : `{ className: "${className}", style: { fontFamily: "${fontStack}" } }`;
578
-
579
- const replacement = `const ${varName} = ${resultObj}`;
580
- transformedCode = transformedCode.replace(fullMatch, replacement);
581
- }
582
- }
583
-
584
- transformedCode = transformedCode.replace(
585
- /import\s*\{[^}]+\}\s*from\s*['"](?:@timber\/fonts\/google|next\/font\/google)['"];?\s*\n?/g,
586
- ''
587
- );
588
- }
589
- }
590
-
591
- // ── Local font transform ───────────────────────────────────────────
592
- if (hasLocalImport) {
593
- transformedCode = transformLocalFonts(
594
- transformedCode,
595
- code,
596
- id,
597
- registry,
598
- this.error.bind(this)
599
- );
600
- }
601
-
602
- if (transformedCode !== code) {
603
- return { code: transformedCode, map: null };
604
- }
605
-
606
- return null;
178
+ return runFontsTransform(code, id, pipeline, (msg) => this.error(msg));
607
179
  },
608
180
 
609
181
  /**
610
- * Emit font files and metadata into the build output.
611
- *
612
- * For Google fonts: emits the downloaded, content-hashed woff2 files
613
- * and writes ManifestFontEntry arrays using real hashed URLs.
614
- *
615
- * For local fonts: emits entries using the source file paths.
182
+ * Emit font binaries and build-manifest entries.
616
183
  *
617
- * In dev mode the build manifest is null, so this is a no-op.
184
+ * Google fonts use the content-hashed filenames produced during
185
+ * `buildStart`. Local fonts are emitted by basename. Font CSS is
186
+ * handled by Vite's CSS pipeline via virtual modules — we only emit
187
+ * binaries here.
618
188
  */
619
189
  generateBundle() {
620
- // Emit cached Google Font files into the build output
621
- for (const cf of cachedFonts) {
622
- this.emitFile({
623
- type: 'asset',
624
- fileName: `_timber/fonts/${cf.hashedFilename}`,
625
- source: cf.data,
626
- });
627
- }
628
-
629
- // Emit local font files as assets
630
- for (const font of registry.values()) {
631
- if (font.provider !== 'local' || !font.localSources) continue;
632
- for (const src of font.localSources) {
633
- const absolutePath = normalize(resolve(src.path));
634
- if (!existsSync(absolutePath)) {
635
- this.warn(`Local font file not found: ${absolutePath}`);
636
- continue;
637
- }
638
- const basename = src.path.split('/').pop() ?? src.path;
639
- const data = readFileSync(absolutePath);
640
- this.emitFile({
641
- type: 'asset',
642
- fileName: `_timber/fonts/${basename}`,
643
- source: data,
644
- });
645
- }
646
- }
647
-
648
- // Font CSS is emitted by Vite's CSS pipeline via virtual:timber-font-css modules.
649
- // We only need to emit font binary files and update the build manifest here.
650
-
190
+ emitFontAssets(
191
+ pipeline,
192
+ (asset) => this.emitFile(asset),
193
+ (msg) => this.warn(msg)
194
+ );
651
195
  if (!ctx.buildManifest) return;
652
-
653
- // Build a lookup from font family → cached files for manifest entries
654
- const cachedByFamily = new Map<string, CachedFont[]>();
655
- for (const cf of cachedFonts) {
656
- const key = cf.face.family.toLowerCase();
657
- const arr = cachedByFamily.get(key) ?? [];
658
- arr.push(cf);
659
- cachedByFamily.set(key, arr);
660
- }
661
-
662
- const fontsByImporter = new Map<string, ManifestFontEntry[]>();
663
-
664
- for (const font of registry.values()) {
665
- const entries = fontsByImporter.get(font.importer) ?? [];
666
-
667
- if (font.provider === 'local' && font.localSources) {
668
- // Local fonts: one entry per source file
669
- for (const src of font.localSources) {
670
- const filename = src.path.split('/').pop() ?? src.path;
671
- const format = inferFontFormat(src.path);
672
- entries.push({
673
- href: `/_timber/fonts/${filename}`,
674
- format,
675
- crossOrigin: 'anonymous',
676
- });
677
- }
678
- } else {
679
- // Google fonts: use real content-hashed URLs from cached downloads
680
- const familyKey = font.family.toLowerCase();
681
- const familyCached = cachedByFamily.get(familyKey) ?? [];
682
- for (const cf of familyCached) {
683
- entries.push({
684
- href: `/_timber/fonts/${cf.hashedFilename}`,
685
- format: 'woff2',
686
- crossOrigin: 'anonymous',
687
- });
688
- }
689
- }
690
-
691
- fontsByImporter.set(font.importer, entries);
692
- }
693
-
694
- // Normalize importer paths to be relative to project root (matching
695
- // how Vite's manifest.json keys work for css/js).
696
- for (const [importer, entries] of fontsByImporter) {
697
- const relativePath = importer.startsWith(ctx.root)
698
- ? importer.slice(ctx.root.length + 1)
699
- : importer;
700
- ctx.buildManifest.fonts[relativePath] = entries;
701
- }
196
+ writeFontManifest(pipeline, ctx.buildManifest, ctx.root);
702
197
  },
703
198
  };
704
199
  }