@farm.js/core 0.1.0-beta.1 → 0.1.0-beta.11

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 (310) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-runtime.d.mts +3 -2
  3. package/dist/agent-runtime.d.ts +3 -2
  4. package/dist/api/route-manager.cjs +410 -15
  5. package/dist/api/route-manager.cjs.map +1 -1
  6. package/dist/api/route-manager.d.mts +7 -5
  7. package/dist/api/route-manager.d.ts +7 -5
  8. package/dist/api/route-manager.mjs +9 -8
  9. package/dist/api/runtime.cjs +748 -9
  10. package/dist/api/runtime.cjs.map +1 -1
  11. package/dist/api/runtime.d.mts +3 -16
  12. package/dist/api/runtime.d.ts +3 -16
  13. package/dist/api/runtime.mjs +8 -1
  14. package/dist/api.cjs +1243 -342
  15. package/dist/api.cjs.map +1 -1
  16. package/dist/api.d.mts +8 -150
  17. package/dist/api.d.ts +8 -150
  18. package/dist/api.mjs +51 -21
  19. package/dist/{app-BiX4qb-d.d.mts → app-BNE2FoZ4.d.mts} +42 -5
  20. package/dist/{app-CFRNJXP1.d.ts → app-DRGUmJ3s.d.ts} +42 -5
  21. package/dist/app-markdown.cjs +32 -8
  22. package/dist/app-markdown.cjs.map +1 -1
  23. package/dist/app-markdown.d.mts +3 -2
  24. package/dist/app-markdown.d.ts +3 -2
  25. package/dist/app-markdown.mjs +2 -1
  26. package/dist/cache.cjs +414 -12
  27. package/dist/cache.cjs.map +1 -1
  28. package/dist/cache.d.mts +120 -6
  29. package/dist/cache.d.ts +120 -6
  30. package/dist/cache.mjs +11 -3
  31. package/dist/{chunk-QF4PHCMA.mjs → chunk-2ED5Q2GH.mjs} +3 -3
  32. package/dist/chunk-2ED5Q2GH.mjs.map +1 -0
  33. package/dist/{chunk-GZP5W4K3.mjs → chunk-32W4QEJP.mjs} +1 -1
  34. package/dist/chunk-32W4QEJP.mjs.map +1 -0
  35. package/dist/{chunk-G3B5BRDY.mjs → chunk-4677KXB7.mjs} +646 -86
  36. package/dist/chunk-4677KXB7.mjs.map +1 -0
  37. package/dist/{chunk-3QJO55ZF.mjs → chunk-4LND3PXF.mjs} +30 -38
  38. package/dist/chunk-4LND3PXF.mjs.map +1 -0
  39. package/dist/chunk-5EVQFRL2.mjs +10 -0
  40. package/dist/chunk-5EVQFRL2.mjs.map +1 -0
  41. package/dist/{chunk-25D7G34K.mjs → chunk-65A7QIKI.mjs} +5 -5
  42. package/dist/{chunk-25D7G34K.mjs.map → chunk-65A7QIKI.mjs.map} +1 -1
  43. package/dist/{chunk-CHFHNEMO.mjs → chunk-77BOAQHI.mjs} +1972 -188
  44. package/dist/chunk-77BOAQHI.mjs.map +1 -0
  45. package/dist/{chunk-LLC7BNXW.mjs → chunk-7FBJLMQH.mjs} +73 -10
  46. package/dist/chunk-7FBJLMQH.mjs.map +1 -0
  47. package/dist/{chunk-TRORP7E4.mjs → chunk-7N62DNSO.mjs} +2 -2
  48. package/dist/chunk-ALCLXXTY.mjs +187 -0
  49. package/dist/chunk-ALCLXXTY.mjs.map +1 -0
  50. package/dist/chunk-AW6I64AP.mjs +25 -0
  51. package/dist/chunk-AW6I64AP.mjs.map +1 -0
  52. package/dist/{chunk-B6N4ZB2H.mjs → chunk-C2ROET2V.mjs} +3 -3
  53. package/dist/{chunk-BHG3LVHH.mjs → chunk-CGIXMLSY.mjs} +15 -7
  54. package/dist/chunk-CGIXMLSY.mjs.map +1 -0
  55. package/dist/{chunk-C3DLZMBU.mjs → chunk-DJSGLHCN.mjs} +2 -2
  56. package/dist/{chunk-JN3UU635.mjs → chunk-EJ7T4TPB.mjs} +2 -2
  57. package/dist/chunk-EJ7T4TPB.mjs.map +1 -0
  58. package/dist/{chunk-ZJQNATYV.mjs → chunk-FRPWCMMG.mjs} +3 -3
  59. package/dist/chunk-FRPWCMMG.mjs.map +1 -0
  60. package/dist/{chunk-QM6VV26B.mjs → chunk-GQVGIUSN.mjs} +3 -3
  61. package/dist/{chunk-QM6VV26B.mjs.map → chunk-GQVGIUSN.mjs.map} +1 -1
  62. package/dist/{chunk-UREJA4GZ.mjs → chunk-GXASWWJU.mjs} +1 -1
  63. package/dist/{chunk-UREJA4GZ.mjs.map → chunk-GXASWWJU.mjs.map} +1 -1
  64. package/dist/chunk-I4CUBGVF.mjs +93 -0
  65. package/dist/chunk-I4CUBGVF.mjs.map +1 -0
  66. package/dist/{chunk-HXP3ZSPC.mjs → chunk-J5YWQVI5.mjs} +4 -4
  67. package/dist/chunk-J5YWQVI5.mjs.map +1 -0
  68. package/dist/{chunk-PRNYWD7K.mjs → chunk-JDEOUK5V.mjs} +67 -239
  69. package/dist/chunk-JDEOUK5V.mjs.map +1 -0
  70. package/dist/{chunk-UHE2TTLK.mjs → chunk-K5ZTUF22.mjs} +34 -17
  71. package/dist/chunk-K5ZTUF22.mjs.map +1 -0
  72. package/dist/{chunk-O3HADRW6.mjs → chunk-MIUW47JX.mjs} +2 -2
  73. package/dist/{chunk-O3HADRW6.mjs.map → chunk-MIUW47JX.mjs.map} +1 -1
  74. package/dist/chunk-PFE6GMNE.mjs +603 -0
  75. package/dist/chunk-PFE6GMNE.mjs.map +1 -0
  76. package/dist/{chunk-RKI6TN3A.mjs → chunk-QM746KUO.mjs} +9 -2
  77. package/dist/chunk-QM746KUO.mjs.map +1 -0
  78. package/dist/{chunk-TU4YJICB.mjs → chunk-QTZZ2ISQ.mjs} +41 -16
  79. package/dist/chunk-QTZZ2ISQ.mjs.map +1 -0
  80. package/dist/chunk-RBRLLZL5.mjs +81 -0
  81. package/dist/chunk-RBRLLZL5.mjs.map +1 -0
  82. package/dist/{chunk-RSKVYESE.mjs → chunk-RQ633A5I.mjs} +1 -1
  83. package/dist/chunk-RQ633A5I.mjs.map +1 -0
  84. package/dist/{chunk-6XDUHOEM.mjs → chunk-TQAEEJB4.mjs} +3 -3
  85. package/dist/{chunk-AGS7UJ52.mjs → chunk-UB5UOSHB.mjs} +24 -12
  86. package/dist/chunk-UB5UOSHB.mjs.map +1 -0
  87. package/dist/{chunk-SXZTEK3V.mjs → chunk-UXUAWNO5.mjs} +2 -2
  88. package/dist/chunk-V3XURYJO.mjs +756 -0
  89. package/dist/chunk-V3XURYJO.mjs.map +1 -0
  90. package/dist/{chunk-JLWMCADZ.mjs → chunk-VY2UYN5R.mjs} +24 -4
  91. package/dist/chunk-VY2UYN5R.mjs.map +1 -0
  92. package/dist/{chunk-QFQRHRZS.mjs → chunk-W2CRQFF6.mjs} +151 -23
  93. package/dist/chunk-W2CRQFF6.mjs.map +1 -0
  94. package/dist/{chunk-Y7A27276.mjs → chunk-WDU6QXNK.mjs} +349 -15
  95. package/dist/chunk-WDU6QXNK.mjs.map +1 -0
  96. package/dist/{chunk-Y2OJJD7R.mjs → chunk-XIVV5IWN.mjs} +7 -9
  97. package/dist/chunk-XIVV5IWN.mjs.map +1 -0
  98. package/dist/{chunk-OYXO65LI.mjs → chunk-YW7OBE6Q.mjs} +4 -4
  99. package/dist/chunk-YW7OBE6Q.mjs.map +1 -0
  100. package/dist/{chunk-YHU7SS6L.mjs → chunk-Z5CQMP54.mjs} +11 -11
  101. package/dist/{chunk-S2XHZS7W.mjs → chunk-ZVWA4ZQ3.mjs} +18 -9
  102. package/dist/chunk-ZVWA4ZQ3.mjs.map +1 -0
  103. package/dist/{chunk-SOU3Q3ZA.mjs → chunk-ZZ57EH5Z.mjs} +1 -1
  104. package/dist/chunk-ZZ57EH5Z.mjs.map +1 -0
  105. package/dist/{client-D_yUjVhe.d.mts → client-BT1mFQas.d.mts} +55 -10
  106. package/dist/{client-Dkc03WP8.d.ts → client-Nn0q4eO4.d.ts} +55 -10
  107. package/dist/{client-plugins-BZnpeTGA.d.ts → client-plugins-Bc5jHcNr.d.ts} +85 -6
  108. package/dist/{client-plugins-g4bzuCmo.d.mts → client-plugins-jsk-ZLzJ.d.mts} +85 -6
  109. package/dist/client-plugins.d.mts +3 -2
  110. package/dist/client-plugins.d.ts +3 -2
  111. package/dist/client.cjs +922 -91
  112. package/dist/client.cjs.map +1 -1
  113. package/dist/client.d.mts +124 -6
  114. package/dist/client.d.ts +124 -6
  115. package/dist/client.mjs +23 -16
  116. package/dist/config.d.mts +3 -2
  117. package/dist/config.d.ts +3 -2
  118. package/dist/cron.cjs.map +1 -1
  119. package/dist/cron.mjs +1 -1
  120. package/dist/{devtools-AE4RVXCM.mjs → devtools-A22KUJZT.mjs} +13 -12
  121. package/dist/{devtools-AE4RVXCM.mjs.map → devtools-A22KUJZT.mjs.map} +1 -1
  122. package/dist/{devtools-client-6WPY2AQU.mjs → devtools-client-3XRTBND5.mjs} +2 -11
  123. package/dist/devtools-client-3XRTBND5.mjs.map +1 -0
  124. package/dist/docs.cjs +65 -58
  125. package/dist/docs.cjs.map +1 -1
  126. package/dist/docs.mjs +13 -12
  127. package/dist/env-types.cjs +14 -5
  128. package/dist/env-types.cjs.map +1 -1
  129. package/dist/env-types.d.mts +2 -1
  130. package/dist/env-types.d.ts +2 -1
  131. package/dist/env-types.mjs +3 -1
  132. package/dist/env.cjs.map +1 -1
  133. package/dist/env.d.mts +1 -1
  134. package/dist/env.d.ts +1 -1
  135. package/dist/env.mjs +1 -1
  136. package/dist/font.cjs +47 -0
  137. package/dist/font.cjs.map +1 -0
  138. package/dist/font.d.mts +70 -0
  139. package/dist/font.d.ts +70 -0
  140. package/dist/font.mjs +10 -0
  141. package/dist/font.mjs.map +1 -0
  142. package/dist/i18n/client.d.mts +2 -2
  143. package/dist/i18n/client.d.ts +2 -2
  144. package/dist/i18n/index.d.mts +3 -3
  145. package/dist/i18n/index.d.ts +3 -3
  146. package/dist/i18n/server.cjs +2 -2
  147. package/dist/i18n/server.cjs.map +1 -1
  148. package/dist/i18n/server.d.mts +5 -5
  149. package/dist/i18n/server.d.ts +5 -5
  150. package/dist/i18n/server.mjs +1 -1
  151. package/dist/index.cjs +5016 -1108
  152. package/dist/index.cjs.map +1 -1
  153. package/dist/index.d.mts +23 -19
  154. package/dist/index.d.ts +23 -19
  155. package/dist/index.mjs +177 -121
  156. package/dist/index.mjs.map +1 -1
  157. package/dist/integrations.d.mts +3 -2
  158. package/dist/integrations.d.ts +3 -2
  159. package/dist/internal/build-runtime.cjs +3504 -581
  160. package/dist/internal/build-runtime.cjs.map +1 -1
  161. package/dist/internal/build-runtime.d.mts +5 -4
  162. package/dist/internal/build-runtime.d.ts +5 -4
  163. package/dist/internal/build-runtime.mjs +32 -29
  164. package/dist/internal/client-runtime.cjs.map +1 -1
  165. package/dist/internal/client-runtime.mjs +1 -1
  166. package/dist/internal/config-runtime.cjs +148 -41
  167. package/dist/internal/config-runtime.cjs.map +1 -1
  168. package/dist/internal/config-runtime.d.mts +4 -3
  169. package/dist/internal/config-runtime.d.ts +4 -3
  170. package/dist/internal/config-runtime.mjs +12 -11
  171. package/dist/internal/production-runtime.cjs +300 -9
  172. package/dist/internal/production-runtime.cjs.map +1 -1
  173. package/dist/internal/production-runtime.d.mts +10 -8
  174. package/dist/internal/production-runtime.d.ts +10 -8
  175. package/dist/internal/production-runtime.mjs +27 -9
  176. package/dist/internal/production-runtime.mjs.map +1 -1
  177. package/dist/markdown.cjs +73 -8
  178. package/dist/markdown.cjs.map +1 -1
  179. package/dist/markdown.d.mts +19 -2
  180. package/dist/markdown.d.ts +19 -2
  181. package/dist/markdown.mjs +5 -1
  182. package/dist/{metadata-C9NZxMDW.d.mts → metadata-7ffpT3jr.d.mts} +1 -1
  183. package/dist/{metadata-DAXRaOHx.d.ts → metadata-JHn-8eht.d.ts} +1 -1
  184. package/dist/middleware.cjs +2 -2
  185. package/dist/middleware.cjs.map +1 -1
  186. package/dist/middleware.d.mts +5 -4
  187. package/dist/middleware.d.ts +5 -4
  188. package/dist/middleware.mjs +3 -3
  189. package/dist/navigation.cjs +40 -15
  190. package/dist/navigation.cjs.map +1 -1
  191. package/dist/navigation.mjs +3 -3
  192. package/dist/{nitro-KME62MWG.mjs → nitro-QO5LV6QK.mjs} +11 -13
  193. package/dist/{nitro-KME62MWG.mjs.map → nitro-QO5LV6QK.mjs.map} +1 -1
  194. package/dist/plugin.cjs +2854 -590
  195. package/dist/plugin.cjs.map +1 -1
  196. package/dist/plugin.d.mts +3 -2
  197. package/dist/plugin.d.ts +3 -2
  198. package/dist/plugin.mjs +28 -25
  199. package/dist/{production-runtime-DRkCHUvJ.d.ts → production-runtime-9KG7GuvW.d.ts} +2 -2
  200. package/dist/{production-runtime-flrjp_nC.d.mts → production-runtime-B-fweKts.d.mts} +2 -2
  201. package/dist/{request-BrFBuc8G.d.mts → request-Dsq4kGW0.d.mts} +1 -1
  202. package/dist/{request-BslSZIRz.d.ts → request-udtobOLv.d.ts} +1 -1
  203. package/dist/request.d.mts +2 -2
  204. package/dist/request.d.ts +2 -2
  205. package/dist/{resolver-DlOPpjkB.d.mts → resolver-DJqjLMg_.d.mts} +1 -1
  206. package/dist/{resolver-C6iecsDV.d.ts → resolver-IH4RmPEl.d.ts} +1 -1
  207. package/dist/routes.cjs +276 -6
  208. package/dist/routes.cjs.map +1 -1
  209. package/dist/routes.d.mts +2 -2
  210. package/dist/routes.d.ts +2 -2
  211. package/dist/routes.mjs +4 -4
  212. package/dist/runtime-9nQjVM7X.d.mts +206 -0
  213. package/dist/{runtime-DeAAZ6gO.d.mts → runtime-Cxpq6xZN.d.mts} +2 -2
  214. package/dist/runtime-DgeS2skB.d.ts +206 -0
  215. package/dist/{runtime-B6GvwDS1.d.ts → runtime-bv63eUiO.d.ts} +2 -2
  216. package/dist/server-action-security.cjs +28 -10
  217. package/dist/server-action-security.cjs.map +1 -1
  218. package/dist/server-action-security.d.mts +2 -1
  219. package/dist/server-action-security.d.ts +2 -1
  220. package/dist/server-action-security.mjs +2 -2
  221. package/dist/server-fn-client.cjs.map +1 -1
  222. package/dist/server-fn-client.d.mts +1 -0
  223. package/dist/server-fn-client.d.ts +1 -0
  224. package/dist/server-fn-client.mjs +1 -1
  225. package/dist/server-fn.cjs +785 -3
  226. package/dist/server-fn.cjs.map +1 -1
  227. package/dist/server-fn.d.mts +10 -1
  228. package/dist/server-fn.d.ts +10 -1
  229. package/dist/server-fn.mjs +6 -3
  230. package/dist/server-plugins.d.mts +4 -3
  231. package/dist/server-plugins.d.ts +4 -3
  232. package/dist/server-query-client.cjs +279 -8
  233. package/dist/server-query-client.cjs.map +1 -1
  234. package/dist/server-query-client.mjs +4 -4
  235. package/dist/server-query.cjs +381 -10
  236. package/dist/server-query.cjs.map +1 -1
  237. package/dist/server-query.mjs +5 -5
  238. package/dist/server.cjs +3319 -841
  239. package/dist/server.cjs.map +1 -1
  240. package/dist/server.d.mts +12 -11
  241. package/dist/server.d.ts +12 -11
  242. package/dist/server.mjs +57 -36
  243. package/dist/server.mjs.map +1 -1
  244. package/dist/testing.cjs +436 -25
  245. package/dist/testing.cjs.map +1 -1
  246. package/dist/testing.d.mts +5 -4
  247. package/dist/testing.d.ts +5 -4
  248. package/dist/testing.mjs +19 -18
  249. package/dist/testing.mjs.map +1 -1
  250. package/dist/transport-BmbGTXA5.d.mts +49 -0
  251. package/dist/transport-BmbGTXA5.d.ts +49 -0
  252. package/dist/{types-BH1lhg5G.d.ts → types-BMxWr97v.d.mts} +2 -2
  253. package/dist/{types-BH1lhg5G.d.mts → types-BMxWr97v.d.ts} +2 -2
  254. package/dist/{utils-DA1yo54_.d.ts → utils-CA0z0c-2.d.ts} +1 -1
  255. package/dist/{utils-DOXXivjL.d.mts → utils-mYVkSOt2.d.mts} +1 -1
  256. package/dist/version.cjs +36 -0
  257. package/dist/version.cjs.map +1 -0
  258. package/dist/version.d.mts +3 -0
  259. package/dist/version.d.ts +3 -0
  260. package/dist/version.mjs +8 -0
  261. package/dist/version.mjs.map +1 -0
  262. package/dist/vite.cjs +2938 -668
  263. package/dist/vite.cjs.map +1 -1
  264. package/dist/vite.d.mts +3 -2
  265. package/dist/vite.d.ts +3 -2
  266. package/dist/vite.mjs +26 -23
  267. package/dist/workflows.cjs +6 -8
  268. package/dist/workflows.cjs.map +1 -1
  269. package/dist/workflows.mjs +1 -1
  270. package/package.json +22 -6
  271. package/types/api.d.ts +44 -0
  272. package/types/client.d.ts +221 -17
  273. package/types/image.d.ts +4 -0
  274. package/types/images.d.ts +59 -0
  275. package/dist/chunk-3QJO55ZF.mjs.map +0 -1
  276. package/dist/chunk-4PTK6KT4.mjs +0 -364
  277. package/dist/chunk-4PTK6KT4.mjs.map +0 -1
  278. package/dist/chunk-AGS7UJ52.mjs.map +0 -1
  279. package/dist/chunk-BHG3LVHH.mjs.map +0 -1
  280. package/dist/chunk-CHFHNEMO.mjs.map +0 -1
  281. package/dist/chunk-EVGBEZDF.mjs +0 -215
  282. package/dist/chunk-EVGBEZDF.mjs.map +0 -1
  283. package/dist/chunk-G3B5BRDY.mjs.map +0 -1
  284. package/dist/chunk-GZP5W4K3.mjs.map +0 -1
  285. package/dist/chunk-HXP3ZSPC.mjs.map +0 -1
  286. package/dist/chunk-JLWMCADZ.mjs.map +0 -1
  287. package/dist/chunk-JN3UU635.mjs.map +0 -1
  288. package/dist/chunk-LLC7BNXW.mjs.map +0 -1
  289. package/dist/chunk-OYXO65LI.mjs.map +0 -1
  290. package/dist/chunk-PRNYWD7K.mjs.map +0 -1
  291. package/dist/chunk-QF4PHCMA.mjs.map +0 -1
  292. package/dist/chunk-QFQRHRZS.mjs.map +0 -1
  293. package/dist/chunk-RKI6TN3A.mjs.map +0 -1
  294. package/dist/chunk-RSKVYESE.mjs.map +0 -1
  295. package/dist/chunk-S2XHZS7W.mjs.map +0 -1
  296. package/dist/chunk-SOU3Q3ZA.mjs.map +0 -1
  297. package/dist/chunk-TU4YJICB.mjs.map +0 -1
  298. package/dist/chunk-TXCFGOHW.mjs +0 -42
  299. package/dist/chunk-TXCFGOHW.mjs.map +0 -1
  300. package/dist/chunk-UHE2TTLK.mjs.map +0 -1
  301. package/dist/chunk-Y2OJJD7R.mjs.map +0 -1
  302. package/dist/chunk-Y7A27276.mjs.map +0 -1
  303. package/dist/chunk-ZJQNATYV.mjs.map +0 -1
  304. package/dist/devtools-client-6WPY2AQU.mjs.map +0 -1
  305. /package/dist/{chunk-TRORP7E4.mjs.map → chunk-7N62DNSO.mjs.map} +0 -0
  306. /package/dist/{chunk-B6N4ZB2H.mjs.map → chunk-C2ROET2V.mjs.map} +0 -0
  307. /package/dist/{chunk-C3DLZMBU.mjs.map → chunk-DJSGLHCN.mjs.map} +0 -0
  308. /package/dist/{chunk-6XDUHOEM.mjs.map → chunk-TQAEEJB4.mjs.map} +0 -0
  309. /package/dist/{chunk-SXZTEK3V.mjs.map → chunk-UXUAWNO5.mjs.map} +0 -0
  310. /package/dist/{chunk-YHU7SS6L.mjs.map → chunk-Z5CQMP54.mjs.map} +0 -0
@@ -5,7 +5,7 @@ import {
5
5
  addMetadataImageReference,
6
6
  mergeMetadata,
7
7
  renderMetadataHead
8
- } from "./chunk-ZJQNATYV.mjs";
8
+ } from "./chunk-FRPWCMMG.mjs";
9
9
  import {
10
10
  farmEnvironmentFunctionsPlugin
11
11
  } from "./chunk-V6WE6JSZ.mjs";
@@ -13,11 +13,23 @@ import {
13
13
  createFarmImageHandler
14
14
  } from "./chunk-3XNTL3FQ.mjs";
15
15
  import {
16
+ createEnvTypeDeclarations,
16
17
  generateEnvTypes
17
- } from "./chunk-BHG3LVHH.mjs";
18
+ } from "./chunk-CGIXMLSY.mjs";
18
19
  import {
19
20
  writeFileIfChanged
20
21
  } from "./chunk-USWZZUEH.mjs";
22
+ import {
23
+ getFarmRedirectError,
24
+ isFarmNotFoundError,
25
+ isFarmRedirectError
26
+ } from "./chunk-7HO6AEOP.mjs";
27
+ import {
28
+ resolveFarmAuthConfig
29
+ } from "./chunk-I4CUBGVF.mjs";
30
+ import {
31
+ normalizeRouteRules
32
+ } from "./chunk-YW7OBE6Q.mjs";
21
33
  import {
22
34
  getFarmAppDirectories,
23
35
  getFarmLayerAliases,
@@ -28,33 +40,31 @@ import {
28
40
  FARM_DEVTOOLS_PATH,
29
41
  resolveFarmDevtoolsConfig
30
42
  } from "./chunk-7MABZJIM.mjs";
31
- import {
32
- normalizeRouteRules
33
- } from "./chunk-OYXO65LI.mjs";
34
43
  import {
35
44
  getPublicFarmImageConfig,
36
45
  resolveFarmImageConfig
37
46
  } from "./chunk-GY2STC2S.mjs";
38
47
  import {
39
- createMarkdownMirrorResponse,
40
- resolveMarkdownConfig
41
- } from "./chunk-LLC7BNXW.mjs";
48
+ resolveServerActionsConfig
49
+ } from "./chunk-UB5UOSHB.mjs";
42
50
  import {
43
51
  createFarmMarkdownRouteModuleFromFile,
44
52
  createFarmMarkdownSourceResponse,
45
53
  isFarmMarkdownPageFile,
46
54
  loadFarmMdxComponents,
47
55
  resolveMdxConfig
48
- } from "./chunk-S2XHZS7W.mjs";
56
+ } from "./chunk-ZVWA4ZQ3.mjs";
57
+ import {
58
+ createMarkdownMirrorResponse,
59
+ resolveMarkdownConfig,
60
+ resolveMarkdownMirrorTarget
61
+ } from "./chunk-7FBJLMQH.mjs";
49
62
  import {
50
63
  resolveWorkflowsConfig
51
- } from "./chunk-Y2OJJD7R.mjs";
64
+ } from "./chunk-XIVV5IWN.mjs";
52
65
  import {
53
66
  resolveCronConfig
54
- } from "./chunk-UREJA4GZ.mjs";
55
- import {
56
- resolveServerActionsConfig
57
- } from "./chunk-AGS7UJ52.mjs";
67
+ } from "./chunk-GXASWWJU.mjs";
58
68
  import {
59
69
  dispatchIntegrationRequest,
60
70
  getIntegrationDocumentNavigationMatchers,
@@ -63,14 +73,9 @@ import {
63
73
  getRequestContextSnapshot,
64
74
  matchIntegrationRoute
65
75
  } from "./chunk-K4667E2Q.mjs";
66
- import {
67
- getFarmRedirectError,
68
- isFarmNotFoundError,
69
- isFarmRedirectError
70
- } from "./chunk-7HO6AEOP.mjs";
71
76
  import {
72
77
  MiddlewareManager
73
- } from "./chunk-O3HADRW6.mjs";
78
+ } from "./chunk-MIUW47JX.mjs";
74
79
  import {
75
80
  _clearCurrentMiddlewareContext,
76
81
  _clearCurrentMiddlewareData,
@@ -91,14 +96,14 @@ import {
91
96
  discoverProgrammaticRoutePaths,
92
97
  findProgrammaticRouteFiles,
93
98
  loadProgrammaticRouteManifests
94
- } from "./chunk-YHU7SS6L.mjs";
99
+ } from "./chunk-Z5CQMP54.mjs";
95
100
  import {
96
101
  _runWithFarmI18nRequest,
97
102
  _setDefaultFarmI18nRuntime,
98
103
  createFarmI18nRuntime,
99
104
  getFarmI18nClientSnapshot,
100
105
  readFarmI18nCatalogs
101
- } from "./chunk-QF4PHCMA.mjs";
106
+ } from "./chunk-2ED5Q2GH.mjs";
102
107
  import {
103
108
  createFarmLocaleCookie,
104
109
  getFarmLocaleVaryHeaders
@@ -106,19 +111,6 @@ import {
106
111
  import {
107
112
  resolveFarmI18nConfig
108
113
  } from "./chunk-FQYDHKKU.mjs";
109
- import {
110
- fileExists,
111
- globFiles,
112
- logger,
113
- matchRoute,
114
- parseRoutePath,
115
- resolveAppPath,
116
- toViteModuleId
117
- } from "./chunk-J4FNJ5IU.mjs";
118
- import {
119
- _runWithCurrentRequest,
120
- createWebRequestFromFarmRequest
121
- } from "./chunk-RHIFZZUI.mjs";
122
114
  import {
123
115
  createLayoutModuleFromProgrammaticLayout,
124
116
  createProgrammaticRouteModuleId,
@@ -128,7 +120,7 @@ import {
128
120
  parseProgrammaticRouteModuleId,
129
121
  parseProgrammaticRoutePath,
130
122
  scanProgrammaticPagePaths
131
- } from "./chunk-B6N4ZB2H.mjs";
123
+ } from "./chunk-C2ROET2V.mjs";
132
124
  import {
133
125
  resolveFarmRouteContext,
134
126
  withFarmRouteContext
@@ -139,7 +131,23 @@ import {
139
131
  normalizeFarmRouteRuntimeConfig,
140
132
  resolveFarmRouteRuleRuntimeConfig,
141
133
  resolveFarmRouteRuntimeConfig
142
- } from "./chunk-QM6VV26B.mjs";
134
+ } from "./chunk-GQVGIUSN.mjs";
135
+ import {
136
+ fileExists,
137
+ globFiles,
138
+ logger,
139
+ matchRoute,
140
+ parseRoutePath,
141
+ resolveAppPath,
142
+ toViteModuleId
143
+ } from "./chunk-J4FNJ5IU.mjs";
144
+ import {
145
+ _runWithCurrentRequest,
146
+ createWebRequestFromFarmRequest
147
+ } from "./chunk-RHIFZZUI.mjs";
148
+ import {
149
+ FARM_VERSION
150
+ } from "./chunk-5EVQFRL2.mjs";
143
151
  import {
144
152
  FARM_DEPLOYMENT_ID_HEADER,
145
153
  createFarmDeploymentCookie,
@@ -158,10 +166,11 @@ import {
158
166
  stripFarmLocaleFromPathname
159
167
  } from "./chunk-44ZCFSKE.mjs";
160
168
  import {
169
+ configureFarmCache,
161
170
  createFarmCacheKey,
162
171
  getFarmDataCache,
163
172
  normalizeRevalidatePath
164
- } from "./chunk-4PTK6KT4.mjs";
173
+ } from "./chunk-V3XURYJO.mjs";
165
174
  import {
166
175
  configureFarmObservability,
167
176
  emitFarmEvent
@@ -775,6 +784,76 @@ async function readAltText(filePath) {
775
784
  }
776
785
  __name(readAltText, "readAltText");
777
786
 
787
+ // src/routing/route-slots.ts
788
+ var SLOT_SEGMENT = /^@([A-Za-z][A-Za-z0-9_-]*)$/;
789
+ function parseRouteSlotFile(filePath) {
790
+ const normalized = filePath.replace(/\\/g, "/");
791
+ const parts = normalized.split("/").filter(Boolean);
792
+ const fileName = parts.at(-1) ?? "";
793
+ const baseName = fileName.replace(/\.(tsx?|jsx?)$/, "");
794
+ if (baseName !== "page" && baseName !== "default") return null;
795
+ const slotIndex = parts.findIndex((part) => SLOT_SEGMENT.test(part));
796
+ if (slotIndex < 0) return null;
797
+ if (parts.slice(slotIndex + 1, -1).some((part) => SLOT_SEGMENT.test(part))) {
798
+ throw new Error(`Nested route slots are not supported in "${filePath}"`);
799
+ }
800
+ const slotMatch = parts[slotIndex].match(SLOT_SEGMENT);
801
+ const name = slotMatch?.[1];
802
+ if (!name) return null;
803
+ const ownerParts = parts.slice(0, slotIndex);
804
+ const contentParts = parts.slice(slotIndex + 1, -1);
805
+ const marker = parseInterceptionMarker(contentParts[0]);
806
+ let targetBase = ownerParts;
807
+ let targetParts = contentParts;
808
+ if (marker) {
809
+ targetBase = marker.root === true ? [] : ownerParts.slice(0, Math.max(0, ownerParts.length - marker.up));
810
+ targetParts = [...marker.remainder ? [marker.remainder] : [], ...contentParts.slice(1)];
811
+ }
812
+ const ownerFile = [...ownerParts, "layout.tsx"].join("/");
813
+ const routeFile = [
814
+ ...baseName === "default" ? ownerParts : targetBase,
815
+ ...baseName === "default" ? [] : targetParts,
816
+ "page.tsx"
817
+ ].join("/");
818
+ return {
819
+ name,
820
+ ownerRoute: parseRoutePath(ownerFile || "layout.tsx"),
821
+ route: parseRoutePath(routeFile || "page.tsx"),
822
+ interception: marker !== null,
823
+ fallback: baseName === "default"
824
+ };
825
+ }
826
+ __name(parseRouteSlotFile, "parseRouteSlotFile");
827
+ function createRouteSlotContainerId(name, ownerPattern) {
828
+ const owner = ownerPattern === "/" ? "root" : ownerPattern.replace(/^\//, "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
829
+ return `__farm_slot_${name}_${owner || "root"}__`;
830
+ }
831
+ __name(createRouteSlotContainerId, "createRouteSlotContainerId");
832
+ function parseInterceptionMarker(segment) {
833
+ if (!segment) return null;
834
+ if (segment.startsWith("(...)")) {
835
+ return {
836
+ up: 0,
837
+ root: true,
838
+ remainder: segment.slice(5)
839
+ };
840
+ }
841
+ if (segment.startsWith("(.)")) {
842
+ return {
843
+ up: 0,
844
+ remainder: segment.slice(3)
845
+ };
846
+ }
847
+ let remainder = segment;
848
+ let up = 0;
849
+ while (remainder.startsWith("(..)")) {
850
+ up += 1;
851
+ remainder = remainder.slice(4);
852
+ }
853
+ return up > 0 ? { up, remainder } : null;
854
+ }
855
+ __name(parseInterceptionMarker, "parseInterceptionMarker");
856
+
778
857
  // src/routing/route-manager.ts
779
858
  function routeSpecificity(entry) {
780
859
  return entry.route.segments.reduce((score, segment) => {
@@ -788,6 +867,7 @@ var _RouteManager = class _RouteManager {
788
867
  constructor(config, viteServer) {
789
868
  this.routes = /* @__PURE__ */ new Map();
790
869
  this.layouts = /* @__PURE__ */ new Map();
870
+ this.routeSlots = /* @__PURE__ */ new Map();
791
871
  this.loadings = /* @__PURE__ */ new Map();
792
872
  this.errors = /* @__PURE__ */ new Map();
793
873
  this.metadataImages = /* @__PURE__ */ new Map();
@@ -803,6 +883,7 @@ var _RouteManager = class _RouteManager {
803
883
  async discoverRoutes() {
804
884
  this.routes.clear();
805
885
  this.layouts.clear();
886
+ this.routeSlots.clear();
806
887
  this.loadings.clear();
807
888
  this.errors.clear();
808
889
  this.metadataImages.clear();
@@ -813,6 +894,13 @@ var _RouteManager = class _RouteManager {
813
894
  await this.discoverFileRoutes(source);
814
895
  await this.discoverProgrammaticRoutes(source);
815
896
  }
897
+ for (const slot of this.routeSlots.values()) {
898
+ if (slot.interception && !this.routes.has(slot.pattern)) {
899
+ throw new Error(
900
+ `Intercepting route slot "${slot.name}" targets "${slot.pattern}", but no canonical page exists for that URL`
901
+ );
902
+ }
903
+ }
816
904
  this.routes = new Map(
817
905
  Array.from(this.routes.entries()).sort(
818
906
  ([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
@@ -828,7 +916,7 @@ var _RouteManager = class _RouteManager {
828
916
  /**
829
917
  * Find matching route for a given URL path
830
918
  */
831
- matchRoute(pathname) {
919
+ matchRoute(pathname, options = {}) {
832
920
  const routePathname = this.toRoutePathname(pathname);
833
921
  const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
834
922
  let matchedRoute = null;
@@ -842,10 +930,12 @@ var _RouteManager = class _RouteManager {
842
930
  }
843
931
  }
844
932
  const layouts = this.findMatchingLayouts(normalizedPath);
933
+ const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
845
934
  return {
846
935
  route: matchedRoute,
847
936
  params,
848
- layouts
937
+ layouts,
938
+ slots
849
939
  };
850
940
  }
851
941
  /**
@@ -860,6 +950,9 @@ var _RouteManager = class _RouteManager {
860
950
  getLayouts() {
861
951
  return new Map(this.layouts);
862
952
  }
953
+ getRouteSlots() {
954
+ return new Map(this.routeSlots);
955
+ }
863
956
  /** Resolve route rules, inherited layouts, and the page export in precedence order. */
864
957
  async resolveRouteRuntimeConfig(pattern) {
865
958
  const routeEntry = this.routes.get(pattern);
@@ -1018,7 +1111,22 @@ var _RouteManager = class _RouteManager {
1018
1111
  pattern: entry.pattern,
1019
1112
  modulePath: toUrlPath(entry.modulePath)
1020
1113
  }));
1021
- return { routes, layouts };
1114
+ const slots = Array.from(this.routeSlots.values()).map((entry) => {
1115
+ const metadata = getClientModuleMetadata(entry.modulePath, projectRoot);
1116
+ return {
1117
+ name: entry.name,
1118
+ ownerPattern: entry.ownerPattern,
1119
+ pattern: entry.pattern,
1120
+ modulePath: toUrlPath(entry.modulePath),
1121
+ containerId: entry.containerId,
1122
+ interception: entry.interception,
1123
+ fallback: entry.fallback,
1124
+ shouldHydrate: metadata.shouldHydrate,
1125
+ isClientComponent: metadata.isClientComponent,
1126
+ segments: entry.route.segments
1127
+ };
1128
+ });
1129
+ return { routes, layouts, slots };
1022
1130
  }
1023
1131
  /**
1024
1132
  * Load a route module dynamically
@@ -1095,6 +1203,7 @@ var _RouteManager = class _RouteManager {
1095
1203
  async discoverFileRoutes(source) {
1096
1204
  const appDir = resolveAppPath(source.root, source.srcDir, "app");
1097
1205
  const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
1206
+ const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
1098
1207
  const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
1099
1208
  const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
1100
1209
  const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
@@ -1102,8 +1211,56 @@ var _RouteManager = class _RouteManager {
1102
1211
  "**/{opengraph-image,twitter-image}.{ts,tsx,js,jsx,png,jpg,jpeg,gif,webp}",
1103
1212
  appDir
1104
1213
  );
1214
+ const canonicalPageGroups = /* @__PURE__ */ new Map();
1215
+ for (const file of pageFiles.filter((candidate) => parseRouteSlotFile(candidate) === null)) {
1216
+ const route = parseRoutePath(file);
1217
+ const pattern = this.createRoutePattern(route);
1218
+ const group = canonicalPageGroups.get(pattern);
1219
+ if (group) {
1220
+ group.files.push(file);
1221
+ } else {
1222
+ canonicalPageGroups.set(pattern, {
1223
+ route,
1224
+ files: [file]
1225
+ });
1226
+ }
1227
+ }
1228
+ for (const [pattern, group] of canonicalPageGroups) {
1229
+ const componentFiles = group.files.filter((file) => !isFarmMarkdownPageFile(file));
1230
+ const markdownFiles = group.files.filter(isFarmMarkdownPageFile);
1231
+ if (componentFiles.length > 1) {
1232
+ throw new Error(
1233
+ `Duplicate page route "${pattern}". Found ${componentFiles.map((file) => path3.join(appDir, file)).join(" and ")}.`
1234
+ );
1235
+ }
1236
+ if (markdownFiles.length > 1) {
1237
+ throw new Error(
1238
+ `Duplicate markdown representation for page route "${pattern}". Found ${markdownFiles.map((file) => path3.join(appDir, file)).join(" and ")}.`
1239
+ );
1240
+ }
1241
+ const componentFile = componentFiles[0];
1242
+ const markdownFile = markdownFiles[0];
1243
+ const primaryFile = componentFile || markdownFile;
1244
+ if (!primaryFile) continue;
1245
+ const modulePath = path3.join(appDir, primaryFile);
1246
+ const existing = this.routes.get(pattern);
1247
+ if (existing?.sourceRoot === source.root) {
1248
+ throw new Error(
1249
+ `Duplicate page route "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
1250
+ );
1251
+ }
1252
+ this.routes.set(pattern, {
1253
+ route: group.route,
1254
+ modulePath,
1255
+ ...markdownFile ? {
1256
+ markdownSourcePath: path3.join(appDir, markdownFile)
1257
+ } : {},
1258
+ pattern,
1259
+ source: "file",
1260
+ sourceRoot: source.root
1261
+ });
1262
+ }
1105
1263
  for (const [kind, files, target] of [
1106
- ["page", pageFiles, this.routes],
1107
1264
  ["layout", layoutFiles, this.layouts],
1108
1265
  ["loading", loadingFiles, this.loadings],
1109
1266
  ["error", errorFiles, this.errors]
@@ -1127,6 +1284,32 @@ var _RouteManager = class _RouteManager {
1127
1284
  });
1128
1285
  }
1129
1286
  }
1287
+ for (const file of [...pageFiles, ...slotDefaultFiles]) {
1288
+ const slot = parseRouteSlotFile(file);
1289
+ if (!slot) continue;
1290
+ const modulePath = path3.join(appDir, file);
1291
+ const pattern = this.createRoutePattern(slot.route);
1292
+ const ownerPattern = this.createRoutePattern(slot.ownerRoute);
1293
+ const key = `${ownerPattern}:${slot.name}:${slot.interception ? "intercept" : "slot"}:${slot.fallback ? "default" : pattern}`;
1294
+ const existing = this.routeSlots.get(key);
1295
+ if (existing?.sourceRoot === source.root) {
1296
+ throw new Error(
1297
+ `Duplicate route slot "${slot.name}" for "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
1298
+ );
1299
+ }
1300
+ this.routeSlots.set(key, {
1301
+ route: slot.route,
1302
+ modulePath,
1303
+ pattern,
1304
+ source: "file",
1305
+ sourceRoot: source.root,
1306
+ name: slot.name,
1307
+ ownerPattern,
1308
+ interception: slot.interception,
1309
+ fallback: slot.fallback,
1310
+ containerId: createRouteSlotContainerId(slot.name, ownerPattern)
1311
+ });
1312
+ }
1130
1313
  for (const file of metadataImageFiles) {
1131
1314
  const fileBase = path3.basename(file, path3.extname(file));
1132
1315
  const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
@@ -1252,6 +1435,71 @@ var _RouteManager = class _RouteManager {
1252
1435
  }
1253
1436
  return matchingLayouts;
1254
1437
  }
1438
+ findMatchingRouteSlots(pathname, interceptFrom) {
1439
+ const groups = /* @__PURE__ */ new Map();
1440
+ for (const entry of this.routeSlots.values()) {
1441
+ if (!this.matchesRoutePrefix(pathname, entry.ownerPattern)) continue;
1442
+ const key = `${entry.ownerPattern}:${entry.name}`;
1443
+ const entries = groups.get(key) ?? [];
1444
+ entries.push(entry);
1445
+ groups.set(key, entries);
1446
+ }
1447
+ const normalizedFrom = interceptFrom ? this.toRoutePathname(new URL(interceptFrom, "http://farm.local").pathname) : void 0;
1448
+ const matches = [];
1449
+ for (const entries of groups.values()) {
1450
+ const candidates = entries.filter((entry) => !entry.fallback).filter(
1451
+ (entry) => !entry.interception || normalizedFrom !== void 0 && this.matchesRoutePrefix(normalizedFrom, entry.ownerPattern)
1452
+ ).map((entry) => ({
1453
+ entry,
1454
+ match: matchRoute(pathname, entry.route.segments)
1455
+ })).filter((candidate) => candidate.match.matches).sort((left, right) => {
1456
+ if (left.entry.interception !== right.entry.interception) {
1457
+ return left.entry.interception ? -1 : 1;
1458
+ }
1459
+ return routeSpecificity(right.entry) - routeSpecificity(left.entry);
1460
+ });
1461
+ const selected = candidates[0];
1462
+ if (selected) {
1463
+ matches.push({
1464
+ name: selected.entry.name,
1465
+ ownerPattern: selected.entry.ownerPattern,
1466
+ containerId: selected.entry.containerId,
1467
+ interception: selected.entry.interception,
1468
+ fallback: false,
1469
+ route: selected.entry,
1470
+ params: selected.match.params
1471
+ });
1472
+ continue;
1473
+ }
1474
+ const fallback = entries.find((entry) => entry.fallback);
1475
+ if (fallback) {
1476
+ matches.push({
1477
+ name: fallback.name,
1478
+ ownerPattern: fallback.ownerPattern,
1479
+ containerId: fallback.containerId,
1480
+ interception: false,
1481
+ fallback: true,
1482
+ route: fallback,
1483
+ params: {}
1484
+ });
1485
+ }
1486
+ }
1487
+ return matches.sort((left, right) => {
1488
+ const ownerDifference = left.route.route.segments.length - right.route.route.segments.length;
1489
+ return ownerDifference || left.name.localeCompare(right.name);
1490
+ });
1491
+ }
1492
+ matchesRoutePrefix(pathname, pattern) {
1493
+ if (pattern === "/") return true;
1494
+ const patternSegments = parseRoutePath(`${pattern}/page.tsx`).segments;
1495
+ const pathSegments = pathname.split("/").filter(Boolean);
1496
+ if (patternSegments.length > pathSegments.length) return false;
1497
+ for (let index = 0; index < patternSegments.length; index++) {
1498
+ const segment = patternSegments[index];
1499
+ if (!segment.isDynamic && segment.segment !== pathSegments[index]) return false;
1500
+ }
1501
+ return true;
1502
+ }
1255
1503
  findNearestBoundary(pathname, boundaries) {
1256
1504
  const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
1257
1505
  const pathSegments = normalizedPath.split("/").filter(Boolean);
@@ -1447,8 +1695,1052 @@ __name(safeGlobFiles, "safeGlobFiles");
1447
1695
  import React from "react";
1448
1696
  import { renderToPipeableStream, renderToStaticMarkup } from "react-dom/server";
1449
1697
  import * as fs2 from "fs";
1450
- import * as path4 from "path";
1698
+ import * as path5 from "path";
1451
1699
  import { Writable } from "stream";
1700
+
1701
+ // src/font-vite.ts
1702
+ import { createHash as createHash2, timingSafeEqual } from "crypto";
1703
+ import { existsSync } from "fs";
1704
+ import { readFile as readFile3 } from "fs/promises";
1705
+ import path4 from "path";
1706
+ import { createRequire } from "module";
1707
+ import { pathToFileURL } from "url";
1708
+ var FONT_IMPORTS = /* @__PURE__ */ new Set(["@farm.js/core", "@farm.js/core/font"]);
1709
+ var FONT_FUNCTIONS = /* @__PURE__ */ new Set(["localFont", "remoteFont"]);
1710
+ var FONT_CSS_PREFIX = "\0farm:font-css:";
1711
+ var FONT_RUNTIME_ID = "\0farm:font-runtime";
1712
+ var PUBLIC_FONT_RUNTIME_ID = "virtual:farm-font-runtime";
1713
+ var PRELOAD_HEADER_MARKER = "__FARM_FONT_PRELOAD_HEADER__";
1714
+ var FONT_SECTION_START = "/* farm-fonts:start */";
1715
+ var FONT_SECTION_END = "/* farm-fonts:end */";
1716
+ var MODULE_EXTENSION_RE = /\.[cm]?[jt]sx?$/;
1717
+ var FONT_EXTENSION_RE = /\.(woff2?|ttf|otf)$/i;
1718
+ var MAX_REMOTE_FONT_BYTES = 20 * 1024 * 1024;
1719
+ var FONT_REGISTRIES_KEY = /* @__PURE__ */ Symbol.for("farm.fontRegistries");
1720
+ var FONT_REMOTE_BYTES_KEY = /* @__PURE__ */ Symbol.for("farm.fontRemoteBytes");
1721
+ var registries = getGlobalMap(FONT_REGISTRIES_KEY);
1722
+ var remoteBytes = getGlobalMap(FONT_REMOTE_BYTES_KEY);
1723
+ function farmFontImportsPlugin(options = {}) {
1724
+ let root = normalizeRoot(options.root || process.cwd());
1725
+ let production = process.env.NODE_ENV === "production";
1726
+ let registry = getOrCreateRegistry(root, options.basePath, options.publicDir);
1727
+ const updateRoot = /* @__PURE__ */ __name((nextRoot, basePath, publicDir) => {
1728
+ const normalized = normalizeRoot(nextRoot);
1729
+ root = normalized;
1730
+ registry = getOrCreateRegistry(root, basePath, publicDir);
1731
+ }, "updateRoot");
1732
+ return {
1733
+ name: "farm:font-imports",
1734
+ enforce: "post",
1735
+ configResolved(config) {
1736
+ production = config.command === "build";
1737
+ updateRoot(
1738
+ config.root,
1739
+ options.basePath || config.base,
1740
+ options.publicDir === void 0 ? config.publicDir : options.publicDir
1741
+ );
1742
+ registry.production = production;
1743
+ },
1744
+ configureServer(server) {
1745
+ updateRoot(
1746
+ server.config.root,
1747
+ options.basePath || server.config.base,
1748
+ options.publicDir === void 0 ? server.config.publicDir : options.publicDir
1749
+ );
1750
+ registry.production = false;
1751
+ server.middlewares.use(async (req, res, next) => {
1752
+ const pathname = new URL(req.url || "/", "http://farm.local").pathname;
1753
+ if (pathname === "/@farm/fonts.css") {
1754
+ res.statusCode = 200;
1755
+ res.setHeader("Content-Type", "text/css; charset=utf-8");
1756
+ res.setHeader("Cache-Control", "no-store");
1757
+ res.end(registry.renderCss(false));
1758
+ return;
1759
+ }
1760
+ const resource = registry.getDevResource(pathname);
1761
+ if (!resource?.bytes) {
1762
+ next();
1763
+ return;
1764
+ }
1765
+ res.statusCode = 200;
1766
+ res.setHeader("Content-Type", fontContentType(resource.extension));
1767
+ res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
1768
+ res.end(resource.bytes);
1769
+ });
1770
+ },
1771
+ resolveId(id) {
1772
+ if (id === PUBLIC_FONT_RUNTIME_ID || id === FONT_RUNTIME_ID) return FONT_RUNTIME_ID;
1773
+ if (id.startsWith("virtual:farm-font-css/")) {
1774
+ return `${FONT_CSS_PREFIX}${id.slice("virtual:farm-font-css/".length)}`;
1775
+ }
1776
+ if (id.startsWith(FONT_CSS_PREFIX)) return id;
1777
+ return null;
1778
+ },
1779
+ load(id) {
1780
+ if (id === FONT_RUNTIME_ID) {
1781
+ return `export const farmFontPreloadHeader = decodeURIComponent(${JSON.stringify(PRELOAD_HEADER_MARKER)});`;
1782
+ }
1783
+ if (!id.startsWith(FONT_CSS_PREFIX)) return null;
1784
+ return registry.renderFontCss(
1785
+ id.slice(FONT_CSS_PREFIX.length).replace(/\.css$/, ""),
1786
+ production
1787
+ );
1788
+ },
1789
+ async transform(code, id) {
1790
+ const result = await transformFarmFontCalls({
1791
+ code,
1792
+ id,
1793
+ root,
1794
+ production,
1795
+ parse: /* @__PURE__ */ __name((source) => this.parse(source), "parse"),
1796
+ register: /* @__PURE__ */ __name((moduleId, calls) => registry.register(moduleId, calls, production), "register")
1797
+ });
1798
+ if (!result) registry.clearModule(id.split("?", 1)[0]);
1799
+ return result ? { code: result.code, map: null } : null;
1800
+ },
1801
+ async generateBundle(_options, bundle) {
1802
+ registry.emitAssets(this, bundle);
1803
+ }
1804
+ };
1805
+ }
1806
+ __name(farmFontImportsPlugin, "farmFontImportsPlugin");
1807
+ async function transformFarmFontCalls(options) {
1808
+ const cleanId = options.id.split("?", 1)[0];
1809
+ if (!MODULE_EXTENSION_RE.test(cleanId) || /\.d\.[cm]?ts$/.test(cleanId) || !containsFontFunction(options.code)) {
1810
+ return null;
1811
+ }
1812
+ const ast = options.parse(options.code);
1813
+ const bindings = findFontBindings(ast);
1814
+ if (bindings.named.size === 0 && bindings.namespaces.size === 0) return null;
1815
+ const calls = findFontCalls(ast, bindings);
1816
+ if (calls.length === 0) return null;
1817
+ validateFontBindingReferences(ast, calls, cleanId);
1818
+ const registeredCalls = calls.map((call) => ({
1819
+ kind: call.kind,
1820
+ options: readFontOptions(options.code, cleanId, call)
1821
+ }));
1822
+ const fonts = await options.register(cleanId, registeredCalls);
1823
+ const replacements = calls.map((call, index) => ({
1824
+ start: call.node.start,
1825
+ end: call.node.end,
1826
+ code: serializeFontResult(fonts[index])
1827
+ }));
1828
+ replacements.push(
1829
+ ...createFontImportReplacements(
1830
+ options.code,
1831
+ ast,
1832
+ new Set(calls.map((call) => call.binding).filter((value) => Boolean(value)))
1833
+ )
1834
+ );
1835
+ const imports = options.production ? "" : Array.from(new Set(fonts.map((font) => font.id))).map((id) => `import ${JSON.stringify(`virtual:farm-font-css/${id}.css`)};`).join("\n");
1836
+ return {
1837
+ code: `${applyReplacements(options.code, replacements)}
1838
+ ${imports}
1839
+ `,
1840
+ fonts
1841
+ };
1842
+ }
1843
+ __name(transformFarmFontCalls, "transformFarmFontCalls");
1844
+ function renderFarmFontDevHead(root) {
1845
+ const registry = registries.get(normalizeRoot(root));
1846
+ if (!registry || registry.production || registry.size === 0) return "";
1847
+ return `${registry.renderPreloadTags(false)}
1848
+ <link rel="stylesheet" href="/@farm/fonts.css">`;
1849
+ }
1850
+ __name(renderFarmFontDevHead, "renderFarmFontDevHead");
1851
+ var _FarmFontRegistry = class _FarmFontRegistry {
1852
+ constructor(root, basePath = "/", publicDir) {
1853
+ this.production = false;
1854
+ this.modules = /* @__PURE__ */ new Map();
1855
+ this.definitions = /* @__PURE__ */ new Map();
1856
+ this.resources = /* @__PURE__ */ new Map();
1857
+ this.root = root;
1858
+ this.basePath = normalizeBasePath(basePath);
1859
+ this.publicDir = normalizePublicDir(root, publicDir);
1860
+ }
1861
+ get size() {
1862
+ return this.getDefinitions().length;
1863
+ }
1864
+ async register(moduleId, calls, production) {
1865
+ const definitions = [];
1866
+ for (const call of calls) {
1867
+ definitions.push(await this.createDefinition(moduleId, call.kind, call.options, production));
1868
+ }
1869
+ this.modules.set(moduleId, definitions);
1870
+ for (const definition of definitions) this.definitions.set(definition.id, definition);
1871
+ return definitions;
1872
+ }
1873
+ clearModule(moduleId) {
1874
+ this.modules.delete(moduleId);
1875
+ }
1876
+ renderFontCss(id, production) {
1877
+ const definition = this.definitions.get(id);
1878
+ return definition ? renderFontDefinitionCss(definition, production, this.basePath) : "";
1879
+ }
1880
+ renderCss(production) {
1881
+ const css = this.getDefinitions().map((definition) => renderFontDefinitionCss(definition, production, this.basePath)).join("\n\n");
1882
+ return css ? `${FONT_SECTION_START}
1883
+ ${css}
1884
+ ${FONT_SECTION_END}
1885
+ ` : "";
1886
+ }
1887
+ renderPreloadHeader(production) {
1888
+ return this.getPreloadResources(production).map(
1889
+ ({ url, resource }) => `<${url}>; rel=preload; as=font; type=${fontContentType(resource.extension)}; crossorigin`
1890
+ ).join(", ");
1891
+ }
1892
+ renderPreloadTags(production) {
1893
+ return this.getPreloadResources(production).map(
1894
+ ({ url, resource }) => `<link rel="preload" href="${escapeHtmlAttribute(url)}" as="font" type="${fontContentType(resource.extension)}" crossorigin>`
1895
+ ).join("\n ");
1896
+ }
1897
+ getDevResource(pathname) {
1898
+ for (const resource of this.getActiveResources()) {
1899
+ if (resource.bytes && resourceUrl(resource, false, this.basePath) === pathname) {
1900
+ return resource;
1901
+ }
1902
+ }
1903
+ return void 0;
1904
+ }
1905
+ emitAssets(context, bundle) {
1906
+ for (const resource of this.getActiveResources()) {
1907
+ if (!resource.bytes || !resource.outputFileName) continue;
1908
+ if (bundle[resource.outputFileName]) continue;
1909
+ context.emitFile({
1910
+ type: "asset",
1911
+ fileName: resource.outputFileName,
1912
+ source: resource.bytes
1913
+ });
1914
+ }
1915
+ const css = this.renderCss(true);
1916
+ if (css) {
1917
+ const cssAssets = Object.values(bundle).filter(
1918
+ (entry) => entry.type === "asset" && entry.fileName.endsWith(".css")
1919
+ );
1920
+ const clientCss = cssAssets.find(
1921
+ (entry) => entry.type === "asset" && entry.fileName === "farm-client.css"
1922
+ ) ?? (cssAssets.length === 1 ? cssAssets[0] : void 0);
1923
+ if (clientCss) {
1924
+ clientCss.source = replaceFontSection(assetSourceToString(clientCss.source), css);
1925
+ } else if (!bundle["farm-fonts.css"]) {
1926
+ context.emitFile({
1927
+ type: "asset",
1928
+ fileName: "farm-fonts.css",
1929
+ source: css
1930
+ });
1931
+ }
1932
+ }
1933
+ const preloadHeader = encodeURIComponent(this.renderPreloadHeader(true));
1934
+ for (const entry of Object.values(bundle)) {
1935
+ if (entry.type === "chunk" && entry.code.includes(PRELOAD_HEADER_MARKER)) {
1936
+ entry.code = entry.code.split(PRELOAD_HEADER_MARKER).join(preloadHeader);
1937
+ }
1938
+ }
1939
+ }
1940
+ getDefinitions() {
1941
+ const active = /* @__PURE__ */ new Map();
1942
+ for (const definitions of this.modules.values()) {
1943
+ for (const definition of definitions) active.set(definition.id, definition);
1944
+ }
1945
+ return Array.from(active.values()).sort((left, right) => left.id.localeCompare(right.id));
1946
+ }
1947
+ getActiveResources() {
1948
+ const active = /* @__PURE__ */ new Set();
1949
+ for (const definition of this.getDefinitions()) {
1950
+ for (const source of definition.sources) active.add(source.resource);
1951
+ }
1952
+ return Array.from(active);
1953
+ }
1954
+ getPreloadResources(production) {
1955
+ const seen = /* @__PURE__ */ new Set();
1956
+ const resources = [];
1957
+ for (const definition of this.getDefinitions()) {
1958
+ if (!definition.preload) continue;
1959
+ for (const source of definition.sources) {
1960
+ const url = resourceUrl(source.resource, production, this.basePath);
1961
+ if (seen.has(url)) continue;
1962
+ seen.add(url);
1963
+ resources.push({ url, resource: source.resource });
1964
+ }
1965
+ }
1966
+ return resources;
1967
+ }
1968
+ async createDefinition(moduleId, kind, raw, production) {
1969
+ validateOptionKeys(moduleId, kind, raw);
1970
+ const family = requireString(raw.family, moduleId, `${kind}() family`);
1971
+ const display = raw.display ?? "swap";
1972
+ if (!["auto", "block", "swap", "fallback", "optional"].includes(display)) {
1973
+ throw fontError(moduleId, `invalid font-display value ${JSON.stringify(display)}`);
1974
+ }
1975
+ const variable = optionalString(raw.variable, moduleId, `${kind}() variable`);
1976
+ if (variable && !/^--[A-Za-z_][\w-]*$/.test(variable)) {
1977
+ throw fontError(moduleId, `font variable must be a CSS custom property such as --font-sans`);
1978
+ }
1979
+ const fallback = readStringArray(raw.fallback, moduleId, `${kind}() fallback`);
1980
+ const defaultWeight = optionalWeight(raw.weight, moduleId);
1981
+ const defaultStyle = optionalCssDescriptor(raw.style, moduleId, "style") || "normal";
1982
+ const sources = readSources(raw.src, moduleId, kind, defaultWeight, defaultStyle);
1983
+ const strategy = kind === "remoteFont" ? raw.strategy ?? "self-host" : "self-host";
1984
+ if (strategy !== "self-host" && strategy !== "external") {
1985
+ throw fontError(moduleId, `remoteFont() strategy must be "self-host" or "external"`);
1986
+ }
1987
+ const integrity = optionalString(raw.integrity, moduleId, `${kind}() integrity`);
1988
+ const normalizedSources = [];
1989
+ for (const source of sources) {
1990
+ const resource = await this.resolveResource({
1991
+ kind,
1992
+ moduleId,
1993
+ source: source.path,
1994
+ strategy,
1995
+ integrity: source.integrity ?? integrity,
1996
+ production
1997
+ });
1998
+ normalizedSources.push({
1999
+ source: source.path,
2000
+ weight: String(source.weight ?? defaultWeight ?? "400"),
2001
+ style: source.style || defaultStyle,
2002
+ unicodeRange: source.unicodeRange,
2003
+ resource
2004
+ });
2005
+ }
2006
+ const identity = JSON.stringify({
2007
+ family,
2008
+ display,
2009
+ variable,
2010
+ fallback,
2011
+ preload: raw.preload !== false,
2012
+ sources: normalizedSources.map((source) => ({
2013
+ hash: source.resource.hash,
2014
+ url: source.resource.publicUrl,
2015
+ weight: source.weight,
2016
+ style: source.style,
2017
+ unicodeRange: source.unicodeRange
2018
+ }))
2019
+ });
2020
+ const id = createHash2("sha256").update(identity).digest("hex").slice(0, 10);
2021
+ return {
2022
+ id,
2023
+ family,
2024
+ className: `farm-font-${id}`,
2025
+ variableClassName: variable ? `farm-font-variable-${id}` : "",
2026
+ variable,
2027
+ fallback,
2028
+ display,
2029
+ preload: raw.preload !== false,
2030
+ weight: defaultWeight,
2031
+ style: raw.style === void 0 ? void 0 : defaultStyle,
2032
+ sources: normalizedSources
2033
+ };
2034
+ }
2035
+ async resolveResource(input) {
2036
+ if (input.kind === "remoteFont") {
2037
+ let url;
2038
+ try {
2039
+ url = new URL(input.source);
2040
+ } catch {
2041
+ throw fontError(input.moduleId, `remoteFont() source must be an absolute HTTPS URL`);
2042
+ }
2043
+ if (url.protocol !== "https:") {
2044
+ throw fontError(input.moduleId, `remoteFont() only accepts HTTPS URLs`);
2045
+ }
2046
+ const extension = extensionFromPath(url.pathname);
2047
+ if (input.strategy === "external") {
2048
+ const hash = createHash2("sha256").update(url.href).digest("hex").slice(0, 12);
2049
+ const resource = {
2050
+ extension,
2051
+ format: fontFormat(extension),
2052
+ hash,
2053
+ publicUrl: url.href
2054
+ };
2055
+ this.resources.set(`external:${url.href}`, resource);
2056
+ return resource;
2057
+ }
2058
+ const bytes2 = await fetchRemoteFont(url, input.integrity);
2059
+ return this.createSelfHostedResource(bytes2, extension, path4.basename(url.pathname));
2060
+ }
2061
+ if (input.source.startsWith("/")) {
2062
+ return this.createPublicResource(input.moduleId, input.source);
2063
+ }
2064
+ const resolvedPath = resolveLocalFontPath(input.source, input.moduleId, this.root);
2065
+ if (!FONT_EXTENSION_RE.test(resolvedPath)) {
2066
+ throw fontError(
2067
+ input.moduleId,
2068
+ `unsupported local font file ${JSON.stringify(input.source)}`
2069
+ );
2070
+ }
2071
+ let bytes;
2072
+ try {
2073
+ bytes = await readFile3(resolvedPath);
2074
+ } catch (error) {
2075
+ throw fontError(
2076
+ input.moduleId,
2077
+ `could not read ${JSON.stringify(input.source)}: ${error.message}`
2078
+ );
2079
+ }
2080
+ return this.createSelfHostedResource(
2081
+ bytes,
2082
+ path4.extname(resolvedPath),
2083
+ path4.basename(resolvedPath)
2084
+ );
2085
+ }
2086
+ async createPublicResource(moduleId, source) {
2087
+ if (!this.publicDir) {
2088
+ throw fontError(
2089
+ moduleId,
2090
+ `cannot resolve ${JSON.stringify(source)} because publicDir is disabled`
2091
+ );
2092
+ }
2093
+ const publicPath = normalizePublicFontPath(source, moduleId);
2094
+ const resolvedPath = path4.resolve(this.publicDir, `.${publicPath}`);
2095
+ if (!isPathInside(this.publicDir, resolvedPath)) {
2096
+ throw fontError(moduleId, `public font path must stay inside publicDir`);
2097
+ }
2098
+ if (!FONT_EXTENSION_RE.test(resolvedPath)) {
2099
+ throw fontError(moduleId, `unsupported public font file ${JSON.stringify(source)}`);
2100
+ }
2101
+ let bytes;
2102
+ try {
2103
+ bytes = await readFile3(resolvedPath);
2104
+ } catch (error) {
2105
+ throw fontError(
2106
+ moduleId,
2107
+ `could not read ${JSON.stringify(source)} from publicDir: ${error.message}`
2108
+ );
2109
+ }
2110
+ const extension = path4.extname(resolvedPath).toLowerCase();
2111
+ const hash = createHash2("sha256").update(bytes).digest("hex").slice(0, 12);
2112
+ const resource = {
2113
+ extension,
2114
+ format: fontFormat(extension),
2115
+ hash,
2116
+ publicPath,
2117
+ publicUrl: ""
2118
+ };
2119
+ this.resources.set(`public:${publicPath}`, resource);
2120
+ return resource;
2121
+ }
2122
+ createSelfHostedResource(bytes, extension, fileName) {
2123
+ const normalizedExtension = extension.toLowerCase();
2124
+ const hash = createHash2("sha256").update(bytes).digest("hex").slice(0, 12);
2125
+ const baseName = sanitizeFileName(path4.basename(fileName, extension)) || "font";
2126
+ const outputFileName = `assets/fonts/${baseName}-${hash}${normalizedExtension}`;
2127
+ const key = `${hash}${normalizedExtension}`;
2128
+ const existing = this.resources.get(key);
2129
+ if (existing) return existing;
2130
+ const resource = {
2131
+ bytes,
2132
+ extension: normalizedExtension,
2133
+ format: fontFormat(normalizedExtension),
2134
+ hash,
2135
+ outputFileName,
2136
+ publicUrl: ""
2137
+ };
2138
+ this.resources.set(key, resource);
2139
+ return resource;
2140
+ }
2141
+ };
2142
+ __name(_FarmFontRegistry, "FarmFontRegistry");
2143
+ var FarmFontRegistry = _FarmFontRegistry;
2144
+ function findFontBindings(ast) {
2145
+ const named = /* @__PURE__ */ new Map();
2146
+ const namespaces = /* @__PURE__ */ new Set();
2147
+ const body = Array.isArray(ast.body) ? ast.body : [];
2148
+ for (const statement of body) {
2149
+ if (!isAstNode(statement) || statement.type !== "ImportDeclaration") continue;
2150
+ const source = isAstNode(statement.source) ? statement.source.value : void 0;
2151
+ if (typeof source !== "string" || !FONT_IMPORTS.has(source)) continue;
2152
+ const specifiers = Array.isArray(statement.specifiers) ? statement.specifiers : [];
2153
+ for (const specifier of specifiers) {
2154
+ if (!isAstNode(specifier) || !isAstNode(specifier.local)) continue;
2155
+ const localName = specifier.local.name;
2156
+ if (typeof localName !== "string") continue;
2157
+ if (specifier.type === "ImportNamespaceSpecifier") {
2158
+ namespaces.add(localName);
2159
+ continue;
2160
+ }
2161
+ if (specifier.type !== "ImportSpecifier" || !isAstNode(specifier.imported)) continue;
2162
+ const importedName = specifier.imported.name ?? specifier.imported.value;
2163
+ if (isFontLoaderKind(importedName)) named.set(localName, importedName);
2164
+ }
2165
+ }
2166
+ return { named, namespaces };
2167
+ }
2168
+ __name(findFontBindings, "findFontBindings");
2169
+ function findFontCalls(ast, bindings) {
2170
+ const calls = [];
2171
+ walkAst(ast, (node, ancestors) => {
2172
+ if (node.type !== "CallExpression" || !isAstNode(node.callee)) return;
2173
+ let kind;
2174
+ if (node.callee.type === "Identifier" && typeof node.callee.name === "string") {
2175
+ kind = bindings.named.get(node.callee.name);
2176
+ if (kind) calls.push({ kind, binding: node.callee.name, node, ancestors });
2177
+ } else if (node.callee.type === "MemberExpression" && node.callee.computed !== true && isAstNode(node.callee.object) && isAstNode(node.callee.property) && node.callee.object.type === "Identifier" && node.callee.property.type === "Identifier" && typeof node.callee.object.name === "string" && typeof node.callee.property.name === "string" && bindings.namespaces.has(node.callee.object.name) && isFontLoaderKind(node.callee.property.name)) {
2178
+ kind = node.callee.property.name;
2179
+ }
2180
+ if (kind && node.callee.type !== "Identifier") calls.push({ kind, node, ancestors });
2181
+ });
2182
+ return calls;
2183
+ }
2184
+ __name(findFontCalls, "findFontCalls");
2185
+ function validateFontBindingReferences(ast, calls, id) {
2186
+ const calledBindings = new Set(
2187
+ calls.map((call) => call.binding).filter((binding) => Boolean(binding))
2188
+ );
2189
+ const transformedCallees = new Set(
2190
+ calls.flatMap((call) => {
2191
+ const callee = call.node.callee;
2192
+ return call.binding && isAstNode(callee) ? [`${callee.start}:${callee.end}`] : [];
2193
+ })
2194
+ );
2195
+ walkAst(ast, (node, ancestors) => {
2196
+ if (node.type !== "Identifier" || typeof node.name !== "string" || !calledBindings.has(node.name)) {
2197
+ return;
2198
+ }
2199
+ const parent = ancestors.at(-1);
2200
+ if (!parent || isNonReferenceIdentifier(node, parent)) return;
2201
+ if (transformedCallees.has(`${node.start}:${node.end}`)) return;
2202
+ throw fontError(
2203
+ id,
2204
+ `${node.name} can only be referenced by statically compiled font declarations`
2205
+ );
2206
+ });
2207
+ }
2208
+ __name(validateFontBindingReferences, "validateFontBindingReferences");
2209
+ function isNonReferenceIdentifier(node, parent) {
2210
+ if (parent.type === "ImportSpecifier") return true;
2211
+ if ((parent.type === "MemberExpression" || parent.type === "OptionalMemberExpression") && parent.property === node && parent.computed !== true) {
2212
+ return true;
2213
+ }
2214
+ if ((parent.type === "Property" || parent.type === "PropertyDefinition") && parent.key === node && parent.computed !== true && parent.shorthand !== true) {
2215
+ return true;
2216
+ }
2217
+ return false;
2218
+ }
2219
+ __name(isNonReferenceIdentifier, "isNonReferenceIdentifier");
2220
+ function createFontImportReplacements(code, ast, calledBindings) {
2221
+ if (calledBindings.size === 0) return [];
2222
+ const replacements = [];
2223
+ const body = Array.isArray(ast.body) ? ast.body : [];
2224
+ for (const statement of body) {
2225
+ if (!isAstNode(statement) || statement.type !== "ImportDeclaration") continue;
2226
+ const source = isAstNode(statement.source) ? statement.source.value : void 0;
2227
+ if (typeof source !== "string" || !FONT_IMPORTS.has(source)) continue;
2228
+ const specifiers = (Array.isArray(statement.specifiers) ? statement.specifiers : []).filter(
2229
+ isAstNode
2230
+ );
2231
+ const retained = specifiers.filter((specifier) => {
2232
+ if (specifier.type !== "ImportSpecifier" || !isAstNode(specifier.local)) return true;
2233
+ return typeof specifier.local.name !== "string" || !calledBindings.has(specifier.local.name);
2234
+ });
2235
+ if (retained.length === specifiers.length) continue;
2236
+ replacements.push({
2237
+ start: statement.start,
2238
+ end: statement.end,
2239
+ code: renderImportDeclaration(code, source, retained)
2240
+ });
2241
+ }
2242
+ return replacements;
2243
+ }
2244
+ __name(createFontImportReplacements, "createFontImportReplacements");
2245
+ function renderImportDeclaration(code, source, specifiers) {
2246
+ if (specifiers.length === 0) return "";
2247
+ const defaultSpecifier = specifiers.find(
2248
+ (specifier) => specifier.type === "ImportDefaultSpecifier"
2249
+ );
2250
+ const namespaceSpecifier = specifiers.find(
2251
+ (specifier) => specifier.type === "ImportNamespaceSpecifier"
2252
+ );
2253
+ const namedSpecifiers = specifiers.filter((specifier) => specifier.type === "ImportSpecifier");
2254
+ const parts = [];
2255
+ if (defaultSpecifier && isAstNode(defaultSpecifier.local)) {
2256
+ parts.push(code.slice(defaultSpecifier.local.start, defaultSpecifier.local.end));
2257
+ }
2258
+ if (namespaceSpecifier && isAstNode(namespaceSpecifier.local)) {
2259
+ parts.push(`* as ${code.slice(namespaceSpecifier.local.start, namespaceSpecifier.local.end)}`);
2260
+ }
2261
+ if (namedSpecifiers.length > 0) {
2262
+ parts.push(
2263
+ `{ ${namedSpecifiers.map((specifier) => code.slice(specifier.start, specifier.end)).join(", ")} }`
2264
+ );
2265
+ }
2266
+ return parts.length > 0 ? `import ${parts.join(", ")} from ${JSON.stringify(source)};` : "";
2267
+ }
2268
+ __name(renderImportDeclaration, "renderImportDeclaration");
2269
+ function readFontOptions(code, id, call) {
2270
+ if (!call.binding) {
2271
+ throw fontError(id, `${call.kind}() must use a named import from @farm.js/core/font`);
2272
+ }
2273
+ const args = Array.isArray(call.node.arguments) ? call.node.arguments : [];
2274
+ if (args.length !== 1 || !isAstNode(args[0]) || args[0].type !== "ObjectExpression") {
2275
+ throw fontError(id, `${call.kind}() requires one inline options object`);
2276
+ }
2277
+ const parent = call.ancestors.at(-1);
2278
+ if (!parent || parent.type !== "VariableDeclarator" || parent.init !== call.node) {
2279
+ throw fontError(id, `${call.kind}() must initialize a module-scope variable`);
2280
+ }
2281
+ const declaration = call.ancestors.at(-2);
2282
+ const statement = call.ancestors.at(-3);
2283
+ const statementParent = call.ancestors.at(-4);
2284
+ const isModuleScope = declaration?.type === "VariableDeclaration" && (statement?.type === "Program" || statement?.type === "ExportNamedDeclaration" && statementParent?.type === "Program");
2285
+ if (!isModuleScope || call.ancestors.some((ancestor) => isFunctionNode(ancestor))) {
2286
+ throw fontError(id, `${call.kind}() must be declared directly at module scope`);
2287
+ }
2288
+ return evaluateStaticObject(code, id, args[0]);
2289
+ }
2290
+ __name(readFontOptions, "readFontOptions");
2291
+ function evaluateStaticObject(code, id, node) {
2292
+ const result = {};
2293
+ const properties = Array.isArray(node.properties) ? node.properties : [];
2294
+ for (const property of properties) {
2295
+ if (!isAstNode(property) || property.type !== "Property" || property.computed === true) {
2296
+ throw fontError(id, "font options do not support spreads or computed properties");
2297
+ }
2298
+ const key = readPropertyName(property.key);
2299
+ if (!key || !isAstNode(property.value)) {
2300
+ throw fontError(id, "font options must use static property names and values");
2301
+ }
2302
+ result[key] = evaluateStaticValue(code, id, property.value);
2303
+ }
2304
+ return result;
2305
+ }
2306
+ __name(evaluateStaticObject, "evaluateStaticObject");
2307
+ function evaluateStaticValue(code, id, node) {
2308
+ if (node.type === "Literal") return node.value;
2309
+ if (node.type === "TemplateLiteral") {
2310
+ const expressions = Array.isArray(node.expressions) ? node.expressions : [];
2311
+ const quasis = Array.isArray(node.quasis) ? node.quasis : [];
2312
+ if (expressions.length === 0 && quasis.length === 1 && isAstNode(quasis[0])) {
2313
+ const templateValue = quasis[0].value;
2314
+ const value = templateValue && typeof templateValue === "object" ? templateValue.cooked : void 0;
2315
+ if (typeof value === "string") return value;
2316
+ }
2317
+ }
2318
+ if (node.type === "ArrayExpression") {
2319
+ const elements = Array.isArray(node.elements) ? node.elements : [];
2320
+ return elements.map((element) => {
2321
+ if (!isAstNode(element) || element.type === "SpreadElement") {
2322
+ throw fontError(id, "font option arrays must contain static values");
2323
+ }
2324
+ return evaluateStaticValue(code, id, element);
2325
+ });
2326
+ }
2327
+ if (node.type === "ObjectExpression") return evaluateStaticObject(code, id, node);
2328
+ if (node.type === "UnaryExpression" && (node.operator === "+" || node.operator === "-") && isAstNode(node.argument)) {
2329
+ const value = evaluateStaticValue(code, id, node.argument);
2330
+ if (typeof value === "number") return node.operator === "-" ? -value : value;
2331
+ }
2332
+ throw fontError(
2333
+ id,
2334
+ `font options must be statically analyzable near ${code.slice(node.start, node.end)}`
2335
+ );
2336
+ }
2337
+ __name(evaluateStaticValue, "evaluateStaticValue");
2338
+ function readSources(value, id, kind, weight, style) {
2339
+ if (typeof value === "string") return [{ path: value, weight, style }];
2340
+ if (!Array.isArray(value) || value.length === 0) {
2341
+ throw fontError(id, `${kind}() src must be a string or a non-empty source array`);
2342
+ }
2343
+ return value.map((entry, index) => {
2344
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
2345
+ throw fontError(id, `${kind}() src[${index}] must be an object`);
2346
+ }
2347
+ const source = entry;
2348
+ const unknown = Object.keys(source).filter(
2349
+ (key) => ![
2350
+ "path",
2351
+ "weight",
2352
+ "style",
2353
+ "unicodeRange",
2354
+ ...kind === "remoteFont" ? ["integrity"] : []
2355
+ ].includes(key)
2356
+ );
2357
+ if (unknown.length) throw fontError(id, `unknown src[${index}] option ${unknown[0]}`);
2358
+ return {
2359
+ path: requireString(source.path, id, `${kind}() src[${index}].path`),
2360
+ weight: optionalWeight(source.weight, id) ?? weight,
2361
+ style: optionalCssDescriptor(source.style, id, "style") || style,
2362
+ unicodeRange: optionalUnicodeRange(source.unicodeRange, id),
2363
+ integrity: optionalString(source.integrity, id, `${kind}() src[${index}].integrity`)
2364
+ };
2365
+ });
2366
+ }
2367
+ __name(readSources, "readSources");
2368
+ function validateOptionKeys(id, kind, raw) {
2369
+ const allowed = /* @__PURE__ */ new Set([
2370
+ "src",
2371
+ "family",
2372
+ "weight",
2373
+ "style",
2374
+ "display",
2375
+ "variable",
2376
+ "fallback",
2377
+ "preload",
2378
+ ...kind === "remoteFont" ? ["strategy", "integrity"] : []
2379
+ ]);
2380
+ const unknown = Object.keys(raw).find((key) => !allowed.has(key));
2381
+ if (unknown) throw fontError(id, `unknown ${kind}() option ${JSON.stringify(unknown)}`);
2382
+ if (typeof raw.preload !== "undefined" && typeof raw.preload !== "boolean") {
2383
+ throw fontError(id, `${kind}() preload must be a boolean`);
2384
+ }
2385
+ }
2386
+ __name(validateOptionKeys, "validateOptionKeys");
2387
+ function serializeFontResult(font) {
2388
+ const stack = renderFamilyStack(font.family, font.fallback);
2389
+ return JSON.stringify({
2390
+ className: font.className,
2391
+ variable: font.variableClassName,
2392
+ style: {
2393
+ fontFamily: stack,
2394
+ ...font.style ? { fontStyle: font.style } : {},
2395
+ ...font.weight !== void 0 && !String(font.weight).includes(" ") ? { fontWeight: font.weight } : {}
2396
+ }
2397
+ });
2398
+ }
2399
+ __name(serializeFontResult, "serializeFontResult");
2400
+ function renderFontDefinitionCss(font, production, basePath) {
2401
+ const faces = font.sources.map((source) => {
2402
+ const descriptors = [
2403
+ ` font-family: ${quoteCssString(font.family)};`,
2404
+ ` src: url(${quoteCssString(resourceUrl(source.resource, production, basePath))}) format(${quoteCssString(source.resource.format)});`,
2405
+ ` font-display: ${font.display};`,
2406
+ ` font-weight: ${source.weight};`,
2407
+ ` font-style: ${source.style};`,
2408
+ ...source.unicodeRange ? [` unicode-range: ${source.unicodeRange};`] : []
2409
+ ];
2410
+ return `@font-face {
2411
+ ${descriptors.join("\n")}
2412
+ }`;
2413
+ });
2414
+ const stack = renderFamilyStack(font.family, font.fallback);
2415
+ faces.push(`.${font.className} {
2416
+ font-family: ${stack};
2417
+ }`);
2418
+ if (font.variable && font.variableClassName) {
2419
+ faces.push(`.${font.variableClassName} {
2420
+ ${font.variable}: ${stack};
2421
+ }`);
2422
+ }
2423
+ return faces.join("\n\n");
2424
+ }
2425
+ __name(renderFontDefinitionCss, "renderFontDefinitionCss");
2426
+ function resourceUrl(resource, production, basePath) {
2427
+ if (resource.publicPath) {
2428
+ return production ? joinBasePath(basePath, resource.publicPath) : resource.publicPath;
2429
+ }
2430
+ if (!resource.bytes) return resource.publicUrl;
2431
+ if (!production) {
2432
+ return joinBasePath(basePath, `/@farm/font/${resource.hash}${resource.extension}`);
2433
+ }
2434
+ return joinBasePath(basePath, `/${resource.outputFileName}`);
2435
+ }
2436
+ __name(resourceUrl, "resourceUrl");
2437
+ async function fetchRemoteFont(url, integrity) {
2438
+ const key = `${url.href}\0${integrity || ""}`;
2439
+ let pending = remoteBytes.get(key);
2440
+ if (!pending) {
2441
+ pending = (async () => {
2442
+ const response = await fetch(url, {
2443
+ headers: { "User-Agent": "Farm.js font compiler" },
2444
+ redirect: "follow"
2445
+ });
2446
+ if (!response.ok)
2447
+ throw new Error(`request returned ${response.status} ${response.statusText}`);
2448
+ const length = Number(response.headers.get("content-length") || 0);
2449
+ if (length > MAX_REMOTE_FONT_BYTES) throw new Error("font exceeds the 20 MB limit");
2450
+ const bytes = await readResponseBodyWithLimit(response, MAX_REMOTE_FONT_BYTES);
2451
+ if (integrity) verifyIntegrity(bytes, integrity);
2452
+ return bytes;
2453
+ })().catch((error) => {
2454
+ throw new Error(`[Farm fonts] Failed to download ${url.href}: ${error.message}`);
2455
+ });
2456
+ remoteBytes.set(key, pending);
2457
+ const clearPending = /* @__PURE__ */ __name(() => {
2458
+ if (remoteBytes.get(key) === pending) remoteBytes.delete(key);
2459
+ }, "clearPending");
2460
+ void pending.then(clearPending, clearPending);
2461
+ }
2462
+ return pending;
2463
+ }
2464
+ __name(fetchRemoteFont, "fetchRemoteFont");
2465
+ async function readResponseBodyWithLimit(response, limit) {
2466
+ if (!response.body) return Buffer.alloc(0);
2467
+ const reader = response.body.getReader();
2468
+ const chunks = [];
2469
+ let total = 0;
2470
+ while (true) {
2471
+ const chunk = await reader.read();
2472
+ if (chunk.done) break;
2473
+ total += chunk.value.byteLength;
2474
+ if (total > limit) {
2475
+ await reader.cancel("font exceeds the configured byte limit");
2476
+ throw new Error("font exceeds the 20 MB limit");
2477
+ }
2478
+ chunks.push(chunk.value);
2479
+ }
2480
+ return Buffer.concat(chunks, total);
2481
+ }
2482
+ __name(readResponseBodyWithLimit, "readResponseBodyWithLimit");
2483
+ function verifyIntegrity(bytes, integrity) {
2484
+ const entries = integrity.trim().split(/\s+/);
2485
+ const supported = entries.map((entry) => entry.match(/^(sha(?:256|384|512))-(.+)$/)).filter((entry) => Boolean(entry));
2486
+ if (supported.length === 0) throw new Error("integrity must use sha256, sha384, or sha512");
2487
+ const matches = supported.some((entry) => {
2488
+ const actual = createHash2(entry[1]).update(bytes).digest();
2489
+ const expected = Buffer.from(entry[2], "base64");
2490
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
2491
+ });
2492
+ if (!matches) throw new Error("downloaded font did not match its integrity value");
2493
+ }
2494
+ __name(verifyIntegrity, "verifyIntegrity");
2495
+ function resolveLocalFontPath(source, importer, root) {
2496
+ if (source.startsWith(".")) return path4.resolve(path4.dirname(importer), source);
2497
+ if (path4.isAbsolute(source)) {
2498
+ return source;
2499
+ }
2500
+ try {
2501
+ return createRequire(pathToFileURL(importer)).resolve(source);
2502
+ } catch {
2503
+ const segments = source.replace(/\\/g, "/").split("/");
2504
+ if (segments.includes("..")) return path4.resolve(root, source);
2505
+ let current = path4.dirname(importer);
2506
+ const filesystemRoot = path4.parse(current).root;
2507
+ while (true) {
2508
+ const candidate = path4.join(current, "node_modules", ...segments);
2509
+ if (existsSync(candidate)) return candidate;
2510
+ if (current === filesystemRoot) break;
2511
+ current = path4.dirname(current);
2512
+ }
2513
+ return path4.resolve(root, "node_modules", ...segments);
2514
+ }
2515
+ }
2516
+ __name(resolveLocalFontPath, "resolveLocalFontPath");
2517
+ function replaceFontSection(css, section) {
2518
+ const start = css.indexOf(FONT_SECTION_START);
2519
+ const end = css.indexOf(FONT_SECTION_END);
2520
+ const withoutExisting = start >= 0 && end >= start ? `${css.slice(0, start)}${css.slice(end + FONT_SECTION_END.length)}`.trimEnd() : css.trimEnd();
2521
+ return `${withoutExisting}${withoutExisting ? "\n\n" : ""}${section}`;
2522
+ }
2523
+ __name(replaceFontSection, "replaceFontSection");
2524
+ function mergeFarmFontCss(clientCss, fontCss) {
2525
+ return replaceFontSection(clientCss, fontCss);
2526
+ }
2527
+ __name(mergeFarmFontCss, "mergeFarmFontCss");
2528
+ function getOrCreateRegistry(root, basePath = "/", publicDir) {
2529
+ const normalized = normalizeRoot(root);
2530
+ const existing = registries.get(normalized);
2531
+ if (existing) {
2532
+ existing.basePath = normalizeBasePath(basePath);
2533
+ existing.publicDir = normalizePublicDir(normalized, publicDir);
2534
+ return existing;
2535
+ }
2536
+ const registry = new FarmFontRegistry(normalized, basePath, publicDir);
2537
+ registries.set(normalized, registry);
2538
+ return registry;
2539
+ }
2540
+ __name(getOrCreateRegistry, "getOrCreateRegistry");
2541
+ function getGlobalMap(key) {
2542
+ const runtime = globalThis;
2543
+ const existing = runtime[key];
2544
+ if (existing instanceof Map) return existing;
2545
+ const created = /* @__PURE__ */ new Map();
2546
+ runtime[key] = created;
2547
+ return created;
2548
+ }
2549
+ __name(getGlobalMap, "getGlobalMap");
2550
+ function normalizeRoot(root) {
2551
+ return path4.resolve(root).replace(/\\/g, "/");
2552
+ }
2553
+ __name(normalizeRoot, "normalizeRoot");
2554
+ function normalizePublicDir(root, publicDir) {
2555
+ if (publicDir === false || publicDir === "") return false;
2556
+ return path4.resolve(root, publicDir || "public");
2557
+ }
2558
+ __name(normalizePublicDir, "normalizePublicDir");
2559
+ function normalizePublicFontPath(source, moduleId) {
2560
+ if (source.includes("?") || source.includes("#")) {
2561
+ throw fontError(moduleId, `public font paths cannot contain a query string or fragment`);
2562
+ }
2563
+ return `/${source.replace(/\\/g, "/").replace(/^\/+/, "")}`;
2564
+ }
2565
+ __name(normalizePublicFontPath, "normalizePublicFontPath");
2566
+ function isPathInside(parent, child) {
2567
+ const relative = path4.relative(parent, child);
2568
+ return relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative);
2569
+ }
2570
+ __name(isPathInside, "isPathInside");
2571
+ function normalizeBasePath(value) {
2572
+ if (!value || value === "/") return "/";
2573
+ return `/${value.replace(/^\/+|\/+$/g, "")}/`;
2574
+ }
2575
+ __name(normalizeBasePath, "normalizeBasePath");
2576
+ function joinBasePath(basePath, value) {
2577
+ return basePath === "/" ? value : `${basePath.replace(/\/$/, "")}${value}`;
2578
+ }
2579
+ __name(joinBasePath, "joinBasePath");
2580
+ function extensionFromPath(pathname) {
2581
+ const extension = path4.extname(pathname).toLowerCase();
2582
+ if (!FONT_EXTENSION_RE.test(extension)) {
2583
+ throw new Error(`[Farm fonts] Remote font URL must end in .woff2, .woff, .ttf, or .otf`);
2584
+ }
2585
+ return extension;
2586
+ }
2587
+ __name(extensionFromPath, "extensionFromPath");
2588
+ function fontFormat(extension) {
2589
+ switch (extension.toLowerCase()) {
2590
+ case ".woff2":
2591
+ return "woff2";
2592
+ case ".woff":
2593
+ return "woff";
2594
+ case ".ttf":
2595
+ return "truetype";
2596
+ case ".otf":
2597
+ return "opentype";
2598
+ default:
2599
+ throw new Error(`[Farm fonts] Unsupported font extension ${extension}`);
2600
+ }
2601
+ }
2602
+ __name(fontFormat, "fontFormat");
2603
+ function fontContentType(extension) {
2604
+ switch (extension.toLowerCase()) {
2605
+ case ".woff2":
2606
+ return "font/woff2";
2607
+ case ".woff":
2608
+ return "font/woff";
2609
+ case ".ttf":
2610
+ return "font/ttf";
2611
+ case ".otf":
2612
+ return "font/otf";
2613
+ default:
2614
+ return "application/octet-stream";
2615
+ }
2616
+ }
2617
+ __name(fontContentType, "fontContentType");
2618
+ function renderFamilyStack(family, fallback) {
2619
+ return [quoteCssString(family), ...fallback.map(formatFallbackFamily)].join(", ");
2620
+ }
2621
+ __name(renderFamilyStack, "renderFamilyStack");
2622
+ function formatFallbackFamily(value) {
2623
+ return /^(?:serif|sans-serif|monospace|cursive|fantasy|system-ui|ui-serif|ui-sans-serif|ui-monospace|emoji|math|fangsong)$/.test(
2624
+ value
2625
+ ) ? value : quoteCssString(value);
2626
+ }
2627
+ __name(formatFallbackFamily, "formatFallbackFamily");
2628
+ function quoteCssString(value) {
2629
+ return JSON.stringify(value.replace(/[\n\r\f]/g, " "));
2630
+ }
2631
+ __name(quoteCssString, "quoteCssString");
2632
+ function sanitizeFileName(value) {
2633
+ return value.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
2634
+ }
2635
+ __name(sanitizeFileName, "sanitizeFileName");
2636
+ function assetSourceToString(source) {
2637
+ return typeof source === "string" ? source : Buffer.from(source).toString("utf8");
2638
+ }
2639
+ __name(assetSourceToString, "assetSourceToString");
2640
+ function applyReplacements(code, replacements) {
2641
+ let output = code;
2642
+ for (const replacement of replacements.sort((left, right) => right.start - left.start)) {
2643
+ output = output.slice(0, replacement.start) + replacement.code + output.slice(replacement.end);
2644
+ }
2645
+ return output;
2646
+ }
2647
+ __name(applyReplacements, "applyReplacements");
2648
+ function walkAst(node, visit, ancestors = []) {
2649
+ visit(node, ancestors);
2650
+ const childAncestors = [...ancestors, node];
2651
+ for (const [key, value] of Object.entries(node)) {
2652
+ if (["start", "end", "loc", "range"].includes(key)) continue;
2653
+ if (isAstNode(value)) walkAst(value, visit, childAncestors);
2654
+ else if (Array.isArray(value)) {
2655
+ for (const item of value) if (isAstNode(item)) walkAst(item, visit, childAncestors);
2656
+ }
2657
+ }
2658
+ }
2659
+ __name(walkAst, "walkAst");
2660
+ function readPropertyName(value) {
2661
+ if (!isAstNode(value)) return void 0;
2662
+ if (value.type === "Identifier" && typeof value.name === "string") return value.name;
2663
+ if (value.type === "Literal" && typeof value.value === "string") return value.value;
2664
+ return void 0;
2665
+ }
2666
+ __name(readPropertyName, "readPropertyName");
2667
+ function isAstNode(value) {
2668
+ return Boolean(value) && typeof value === "object" && typeof value.type === "string" && typeof value.start === "number" && typeof value.end === "number";
2669
+ }
2670
+ __name(isAstNode, "isAstNode");
2671
+ function isFunctionNode(node) {
2672
+ return node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
2673
+ }
2674
+ __name(isFunctionNode, "isFunctionNode");
2675
+ function isFontLoaderKind(value) {
2676
+ return typeof value === "string" && FONT_FUNCTIONS.has(value);
2677
+ }
2678
+ __name(isFontLoaderKind, "isFontLoaderKind");
2679
+ function containsFontFunction(code) {
2680
+ return Array.from(FONT_FUNCTIONS).some((name) => code.includes(name));
2681
+ }
2682
+ __name(containsFontFunction, "containsFontFunction");
2683
+ function requireString(value, id, label) {
2684
+ if (typeof value !== "string" || value.trim() === "") {
2685
+ throw fontError(id, `${label} must be a non-empty string`);
2686
+ }
2687
+ return value;
2688
+ }
2689
+ __name(requireString, "requireString");
2690
+ function optionalString(value, id, label) {
2691
+ if (value === void 0) return void 0;
2692
+ return requireString(value, id, label);
2693
+ }
2694
+ __name(optionalString, "optionalString");
2695
+ function readStringArray(value, id, label) {
2696
+ if (value === void 0) return [];
2697
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
2698
+ throw fontError(id, `${label} must be an array of family names`);
2699
+ }
2700
+ return value;
2701
+ }
2702
+ __name(readStringArray, "readStringArray");
2703
+ function optionalWeight(value, id) {
2704
+ if (value === void 0) return void 0;
2705
+ if (typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 1e3) {
2706
+ return value;
2707
+ }
2708
+ if (typeof value === "string" && /^(?:[1-9]\d{0,2}|1000)(?:\s+(?:[1-9]\d{0,2}|1000))?$/.test(value)) {
2709
+ const bounds = value.split(/\s+/).map(Number);
2710
+ if (bounds.length === 2 && bounds[0] > bounds[1]) {
2711
+ throw fontError(id, `font weight range must be ordered from lowest to highest`);
2712
+ }
2713
+ return value;
2714
+ }
2715
+ throw fontError(id, `font weight must be a number or range such as "100 900"`);
2716
+ }
2717
+ __name(optionalWeight, "optionalWeight");
2718
+ function optionalCssDescriptor(value, id, label) {
2719
+ if (value === void 0) return void 0;
2720
+ if (typeof value !== "string" || !/^[A-Za-z0-9 .-]+$/.test(value)) {
2721
+ throw fontError(id, `font ${label} contains unsupported characters`);
2722
+ }
2723
+ return value;
2724
+ }
2725
+ __name(optionalCssDescriptor, "optionalCssDescriptor");
2726
+ function optionalUnicodeRange(value, id) {
2727
+ if (value === void 0) return void 0;
2728
+ if (typeof value !== "string" || !/^[Uu+0-9A-Fa-f?*, -]+$/.test(value)) {
2729
+ throw fontError(id, `font unicodeRange contains unsupported characters`);
2730
+ }
2731
+ return value;
2732
+ }
2733
+ __name(optionalUnicodeRange, "optionalUnicodeRange");
2734
+ function escapeHtmlAttribute(value) {
2735
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
2736
+ }
2737
+ __name(escapeHtmlAttribute, "escapeHtmlAttribute");
2738
+ function fontError(id, message) {
2739
+ return new Error(`[Farm fonts] ${message} in ${id.split("?", 1)[0]}`);
2740
+ }
2741
+ __name(fontError, "fontError");
2742
+
2743
+ // src/server/renderer.ts
1452
2744
  var cachedClerkProvider = null;
1453
2745
  var importRuntimeModule = new Function("specifier", "return import(specifier);");
1454
2746
  function hasRequestHeader(req, name) {
@@ -1460,10 +2752,10 @@ function serializeInlineValue(value) {
1460
2752
  return JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1461
2753
  }
1462
2754
  __name(serializeInlineValue, "serializeInlineValue");
1463
- function escapeHtmlAttribute(value) {
2755
+ function escapeHtmlAttribute2(value) {
1464
2756
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1465
2757
  }
1466
- __name(escapeHtmlAttribute, "escapeHtmlAttribute");
2758
+ __name(escapeHtmlAttribute2, "escapeHtmlAttribute");
1467
2759
  function appendResponseHeader(res, name, value) {
1468
2760
  const current = res.getHeader(name);
1469
2761
  if (current === void 0) {
@@ -1489,10 +2781,10 @@ function renderI18nAlternateLinks(requestPath, snapshot) {
1489
2781
  const url = new URL(requestPath, "http://farm.local");
1490
2782
  const links = snapshot.locales.map((locale) => {
1491
2783
  const href = localizeFarmPathname(url.pathname, locale, snapshot);
1492
- return `<link rel="alternate" hreflang="${escapeHtmlAttribute(locale)}" href="${escapeHtmlAttribute(href)}">`;
2784
+ return `<link rel="alternate" hreflang="${escapeHtmlAttribute2(locale)}" href="${escapeHtmlAttribute2(href)}">`;
1493
2785
  });
1494
2786
  links.push(
1495
- `<link rel="alternate" hreflang="x-default" href="${escapeHtmlAttribute(
2787
+ `<link rel="alternate" hreflang="x-default" href="${escapeHtmlAttribute2(
1496
2788
  localizeFarmPathname(url.pathname, snapshot.defaultLocale, snapshot)
1497
2789
  )}">`
1498
2790
  );
@@ -1656,7 +2948,9 @@ var _ServerRenderer = class _ServerRenderer {
1656
2948
  async runWithRequestContext(request, fn) {
1657
2949
  return _runWithCurrentRequest(
1658
2950
  request,
1659
- () => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, { redirect: false }) : fn()
2951
+ () => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
2952
+ redirect: false
2953
+ }) : fn()
1660
2954
  );
1661
2955
  }
1662
2956
  async resolveRouteContext(input) {
@@ -1667,7 +2961,7 @@ var _ServerRenderer = class _ServerRenderer {
1667
2961
  */
1668
2962
  loadSSGManifest() {
1669
2963
  try {
1670
- const manifestPath = path4.join(this.config.root, this.config.outDir, "__ssg_manifest.json");
2964
+ const manifestPath = path5.join(this.config.root, this.config.outDir, "__ssg_manifest.json");
1671
2965
  if (fs2.existsSync(manifestPath)) {
1672
2966
  const content = fs2.readFileSync(manifestPath, "utf-8");
1673
2967
  this.ssgManifest = JSON.parse(content);
@@ -1679,11 +2973,11 @@ var _ServerRenderer = class _ServerRenderer {
1679
2973
  /**
1680
2974
  * Check if a path should be served from SSG cache
1681
2975
  */
1682
- shouldServeSSG(pathname) {
2976
+ async shouldServeSSG(pathname) {
1683
2977
  const ssgPage = matchSSGPage(pathname, this.ssgManifest);
1684
2978
  if (!ssgPage) return null;
1685
- const cached = this.getCachedSSGPage(pathname);
1686
- if (cached && this.dataCache.isStale(cached)) {
2979
+ const cached = await this.getCachedSSGPage(pathname);
2980
+ if (cached && await this.dataCache.isStaleAsync(cached)) {
1687
2981
  this.regenerateSSGPage(ssgPage);
1688
2982
  }
1689
2983
  return ssgPage;
@@ -1695,12 +2989,12 @@ var _ServerRenderer = class _ServerRenderer {
1695
2989
  return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
1696
2990
  }
1697
2991
  getCachedSSGPage(urlPath) {
1698
- return this.dataCache.getEntry(this.getSSGCacheKey(urlPath), {
2992
+ return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
1699
2993
  allowStale: true
1700
2994
  });
1701
2995
  }
1702
- cacheSSGPage(page, html, options) {
1703
- this.dataCache.set(
2996
+ async cacheSSGPage(page, html, options) {
2997
+ await this.dataCache.setAsync(
1704
2998
  this.getSSGCacheKey(page.urlPath),
1705
2999
  { html, document: options.document },
1706
3000
  {
@@ -1712,11 +3006,11 @@ var _ServerRenderer = class _ServerRenderer {
1712
3006
  );
1713
3007
  }
1714
3008
  getCachedPPRShell(pathname, search) {
1715
- return this.dataCache.getEntry(this.getPPRCacheKey(pathname, search));
3009
+ return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
1716
3010
  }
1717
- cachePPRShell(options, html) {
3011
+ async cachePPRShell(options, html) {
1718
3012
  const key = this.getPPRCacheKey(options.pathname, options.search);
1719
- this.dataCache.set(
3013
+ await this.dataCache.setAsync(
1720
3014
  key,
1721
3015
  { html },
1722
3016
  {
@@ -1814,7 +3108,7 @@ var _ServerRenderer = class _ServerRenderer {
1814
3108
  }
1815
3109
  const { renderToString } = await import("react-dom/server");
1816
3110
  const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
1817
- this.cacheSSGPage(page, html, { document: false });
3111
+ await this.cacheSSGPage(page, html, { document: false });
1818
3112
  logger.info(`ISR: Regenerated ${page.urlPath}`);
1819
3113
  } catch (error) {
1820
3114
  logger.error(`ISR regeneration failed for ${page.urlPath}: ${error}`);
@@ -1828,7 +3122,7 @@ var _ServerRenderer = class _ServerRenderer {
1828
3122
  * Serve a pre-rendered SSG page
1829
3123
  */
1830
3124
  async serveSSGPage(req, res, page) {
1831
- const cached = this.getCachedSSGPage(page.urlPath);
3125
+ const cached = await this.getCachedSSGPage(page.urlPath);
1832
3126
  if (cached) {
1833
3127
  res.setHeader("Content-Type", "text/html; charset=utf-8");
1834
3128
  res.setHeader("X-Farm-SSG", "cached");
@@ -1842,13 +3136,16 @@ var _ServerRenderer = class _ServerRenderer {
1842
3136
  return true;
1843
3137
  }
1844
3138
  try {
1845
- const htmlPath = page.urlPath === "/" ? path4.join(this.config.root, this.config.outDir, "client", "index.html") : path4.join(this.config.root, this.config.outDir, "client", page.urlPath + ".html");
3139
+ const htmlPath = page.urlPath === "/" ? path5.join(this.config.root, this.config.outDir, "client", "index.html") : path5.join(this.config.root, this.config.outDir, "client", page.urlPath + ".html");
1846
3140
  if (fs2.existsSync(htmlPath)) {
1847
3141
  const stat = fs2.statSync(htmlPath);
1848
3142
  const html = fs2.readFileSync(htmlPath, "utf-8");
1849
- this.cacheSSGPage(page, html, { document: true, createdAt: stat.mtimeMs });
1850
- const fileCacheEntry = this.getCachedSSGPage(page.urlPath);
1851
- if (fileCacheEntry && this.dataCache.isStale(fileCacheEntry)) {
3143
+ await this.cacheSSGPage(page, html, {
3144
+ document: true,
3145
+ createdAt: stat.mtimeMs
3146
+ });
3147
+ const fileCacheEntry = await this.getCachedSSGPage(page.urlPath);
3148
+ if (fileCacheEntry && await this.dataCache.isStaleAsync(fileCacheEntry)) {
1852
3149
  this.regenerateSSGPage(page);
1853
3150
  }
1854
3151
  res.setHeader("Content-Type", "text/html; charset=utf-8");
@@ -1894,6 +3191,7 @@ var _ServerRenderer = class _ServerRenderer {
1894
3191
  let pathname = "/";
1895
3192
  let params = {};
1896
3193
  let layouts = [];
3194
+ let routeSlots = [];
1897
3195
  let searchParamsObject = {};
1898
3196
  let middlewareMap = /* @__PURE__ */ new Map();
1899
3197
  let middlewareContext = /* @__PURE__ */ new Map();
@@ -1926,7 +3224,7 @@ var _ServerRenderer = class _ServerRenderer {
1926
3224
  }
1927
3225
  this.applyDeploymentHeaders(req, res);
1928
3226
  if (process.env.NODE_ENV === "production") {
1929
- const ssgPage = this.shouldServeSSG(pathname);
3227
+ const ssgPage = await this.shouldServeSSG(pathname);
1930
3228
  if (ssgPage) {
1931
3229
  const served = await this.serveSSGPage(req, res, ssgPage);
1932
3230
  if (served) {
@@ -1939,6 +3237,7 @@ var _ServerRenderer = class _ServerRenderer {
1939
3237
  const route = match.route;
1940
3238
  params = match.params;
1941
3239
  layouts = match.layouts;
3240
+ routeSlots = match.slots ?? [];
1942
3241
  if (!route) {
1943
3242
  emitFarmEvent({ type: "route.notFound", pathname });
1944
3243
  await this.render404(req, res);
@@ -1955,7 +3254,9 @@ var _ServerRenderer = class _ServerRenderer {
1955
3254
  errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
1956
3255
  middlewareMap = toMiddlewareMap(req.__FARM_MIDDLEWARE_DATA__);
1957
3256
  middlewareContext = toMiddlewareMap(req.__FARM_MIDDLEWARE_CONTEXT__);
1958
- pluginExposedContext = getRequestContextSnapshot(req, { exposedOnly: true });
3257
+ pluginExposedContext = getRequestContextSnapshot(req, {
3258
+ exposedOnly: true
3259
+ });
1959
3260
  const currentRequest = createWebRequestFromFarmRequest(req);
1960
3261
  const routeContext = await this.resolveRouteContext({
1961
3262
  request: currentRequest,
@@ -2019,8 +3320,16 @@ var _ServerRenderer = class _ServerRenderer {
2019
3320
  revalidate: renderingConfig.revalidate
2020
3321
  } : void 0;
2021
3322
  if (renderingConfig.ppr && pprBypassReason) {
2022
- emitFarmEvent({ type: "ppr.shell.bypass", route: pathname, reason: pprBypassReason });
2023
- emitFarmEvent({ type: "cache.bypass", route: pathname, reason: pprBypassReason });
3323
+ emitFarmEvent({
3324
+ type: "ppr.shell.bypass",
3325
+ route: pathname,
3326
+ reason: pprBypassReason
3327
+ });
3328
+ emitFarmEvent({
3329
+ type: "cache.bypass",
3330
+ route: pathname,
3331
+ reason: pprBypassReason
3332
+ });
2024
3333
  if (pprBypassReason === "refresh") {
2025
3334
  pprRefreshRoute = pathname;
2026
3335
  emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
@@ -2028,14 +3337,22 @@ var _ServerRenderer = class _ServerRenderer {
2028
3337
  }
2029
3338
  if (pprShellOptions) {
2030
3339
  const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
2031
- const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
3340
+ const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
2032
3341
  if (cachedPPRShell) {
2033
- emitFarmEvent({ type: "ppr.shell.hit", route: pathname, key: pprCacheKey });
3342
+ emitFarmEvent({
3343
+ type: "ppr.shell.hit",
3344
+ route: pathname,
3345
+ key: pprCacheKey
3346
+ });
2034
3347
  this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
2035
3348
  completeRender(res.statusCode || 200, pathname);
2036
3349
  return;
2037
3350
  }
2038
- emitFarmEvent({ type: "ppr.shell.miss", route: pathname, key: pprCacheKey });
3351
+ emitFarmEvent({
3352
+ type: "ppr.shell.miss",
3353
+ route: pathname,
3354
+ key: pprCacheKey
3355
+ });
2039
3356
  }
2040
3357
  let LoadingFallbackComponent = null;
2041
3358
  if (loadingBoundaryEntry) {
@@ -2059,14 +3376,77 @@ var _ServerRenderer = class _ServerRenderer {
2059
3376
  );
2060
3377
  const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route.modulePath, this.config.root);
2061
3378
  const isClientComponent = moduleMetadata.isClientComponent;
3379
+ const renderedRouteSlots = await Promise.all(
3380
+ routeSlots.map(async (slot) => {
3381
+ const slotModule = await this.routeManager.loadRouteModule(slot.route.modulePath);
3382
+ if (!slotModule.default) {
3383
+ throw new Error(
3384
+ `Route slot "${slot.name}" module ${slot.route.modulePath} does not export a default component`
3385
+ );
3386
+ }
3387
+ const slotContext = await this.resolveRouteContext({
3388
+ request: currentRequest,
3389
+ rawRequest: req,
3390
+ params: slot.params,
3391
+ search: searchParamsObject,
3392
+ path: pathname
3393
+ });
3394
+ const rawSlotProps = withFarmRouteContext(
3395
+ {
3396
+ params: slot.params,
3397
+ searchParams: Promise.resolve(searchParamsObject),
3398
+ path: pathname,
3399
+ middleware: middlewareMap.size > 0 ? { data: middlewareMap } : void 0,
3400
+ context: pluginExposedContext.size > 0 ? { data: pluginExposedContext } : void 0
3401
+ },
3402
+ slotContext
3403
+ );
3404
+ const slotProps = await parseRouteModuleProps(slotModule, {
3405
+ props: rawSlotProps,
3406
+ search: searchParamsObject,
3407
+ routePath: slot.route.pattern
3408
+ });
3409
+ const metadata = getClientModuleMetadata(slot.route.modulePath, this.config.root);
3410
+ return {
3411
+ ...slot,
3412
+ module: slotModule,
3413
+ props: slotProps,
3414
+ isClientComponent: metadata.isClientComponent,
3415
+ shouldHydrate: metadata.shouldHydrate
3416
+ };
3417
+ })
3418
+ );
2062
3419
  const shouldHydrate = moduleMetadata.shouldHydrate;
3420
+ const hasHydratableRouteSlots = renderedRouteSlots.some(
3421
+ (slot) => slot.isClientComponent || slot.shouldHydrate
3422
+ );
2063
3423
  req.__FARM_PAGE_PATH__ = route.modulePath;
2064
3424
  req.__FARM_ROUTE__ = pathname;
2065
3425
  req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
2066
3426
  req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
3427
+ req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
2067
3428
  req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
2068
3429
  loadingBoundaryEntry.modulePath.indexOf("/src/app/")
2069
3430
  ) : null;
3431
+ req.__FARM_ROUTE_SLOTS__ = renderedRouteSlots.map((slot) => ({
3432
+ name: slot.name,
3433
+ ownerPattern: slot.ownerPattern,
3434
+ containerId: slot.containerId,
3435
+ interception: slot.interception,
3436
+ fallback: slot.fallback,
3437
+ modulePath: slot.route.modulePath,
3438
+ isClientComponent: slot.isClientComponent,
3439
+ shouldHydrate: slot.shouldHydrate,
3440
+ props: {
3441
+ params: slot.props.params,
3442
+ search: slot.props.search,
3443
+ searchParams: slot.props.search,
3444
+ ..."data" in slot.props ? { data: slot.props.data } : {},
3445
+ ...slot.props.__farmCanonicalPath ? { __farmCanonicalPath: slot.props.__farmCanonicalPath } : {},
3446
+ ...slot.props.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
3447
+ path: pathname
3448
+ }
3449
+ }));
2070
3450
  req.__FARM_PROPS__ = {
2071
3451
  params: pageProps.params,
2072
3452
  search: pageProps.search,
@@ -2126,12 +3506,32 @@ var _ServerRenderer = class _ServerRenderer {
2126
3506
  let wrappedElement = pageElement;
2127
3507
  for (let i = layoutModules.length - 1; i >= 0; i--) {
2128
3508
  const layoutModule = layoutModules[i];
3509
+ const layoutEntry = layouts[i];
2129
3510
  const LayoutComponent = layoutModule.default;
3511
+ const slotProps = {};
3512
+ for (const slot of renderedRouteSlots) {
3513
+ if (slot.ownerPattern !== layoutEntry.pattern) continue;
3514
+ let slotElement = React.createElement(
3515
+ slot.module.default,
3516
+ slot.props
3517
+ );
3518
+ slotElement = React.createElement(
3519
+ "div",
3520
+ {
3521
+ id: slot.containerId,
3522
+ "data-farm-route-slot": slot.name,
3523
+ "data-farm-slot-owner": slot.ownerPattern
3524
+ },
3525
+ slotElement
3526
+ );
3527
+ slotProps[slot.name] = slotElement;
3528
+ }
2130
3529
  wrappedElement = React.createElement(
2131
3530
  LayoutComponent,
2132
3531
  {
2133
3532
  children: wrappedElement,
2134
- params
3533
+ params,
3534
+ ...slotProps
2135
3535
  }
2136
3536
  );
2137
3537
  }
@@ -2168,7 +3568,10 @@ var _ServerRenderer = class _ServerRenderer {
2168
3568
  routeManifest,
2169
3569
  captureStaticShell: Boolean(pprShellOptions),
2170
3570
  observabilityRoute: pathname,
2171
- onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({ type: "ppr.suspense.holeDetected", route: pathname }) : void 0,
3571
+ onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
3572
+ type: "ppr.suspense.holeDetected",
3573
+ route: pathname
3574
+ }) : void 0,
2172
3575
  onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
2173
3576
  }
2174
3577
  );
@@ -2184,6 +3587,15 @@ var _ServerRenderer = class _ServerRenderer {
2184
3587
  });
2185
3588
  });
2186
3589
  } catch (error) {
3590
+ if (isWebResponse(error)) {
3591
+ if (!res.headersSent && !res.writableEnded) {
3592
+ await sendWebResponse(res, error);
3593
+ } else if (!res.writableEnded) {
3594
+ res.end();
3595
+ }
3596
+ completeRender(error.status, pathname);
3597
+ return;
3598
+ }
2187
3599
  if (isFarmRedirectError(error)) {
2188
3600
  const redirect = getFarmRedirectError(error);
2189
3601
  const snapshot = getFarmI18nClientSnapshot();
@@ -2216,7 +3628,11 @@ var _ServerRenderer = class _ServerRenderer {
2216
3628
  }
2217
3629
  emitFarmEvent({ type: "render.error", route: pathname, error });
2218
3630
  if (pprRefreshRoute) {
2219
- emitFarmEvent({ type: "ppr.refresh.error", route: pprRefreshRoute, error });
3631
+ emitFarmEvent({
3632
+ type: "ppr.refresh.error",
3633
+ route: pprRefreshRoute,
3634
+ error
3635
+ });
2220
3636
  }
2221
3637
  logger.error(`Error rendering page: ${error}`);
2222
3638
  if (res.headersSent || res.writableEnded) {
@@ -2269,7 +3685,9 @@ var _ServerRenderer = class _ServerRenderer {
2269
3685
  if (typeof layoutModule.generateMetadata === "function") {
2270
3686
  metadata = mergeMetadata(
2271
3687
  metadata,
2272
- await layoutModule.generateMetadata({ params: options.pageProps.params })
3688
+ await layoutModule.generateMetadata({
3689
+ params: options.pageProps.params
3690
+ })
2273
3691
  );
2274
3692
  }
2275
3693
  }
@@ -2478,7 +3896,7 @@ var _ServerRenderer = class _ServerRenderer {
2478
3896
  }
2479
3897
  }
2480
3898
  async renderWithSSR(element, req, res, clearMiddlewareData, options = {}) {
2481
- return new Promise((resolve4, reject) => {
3899
+ return new Promise((resolve5, reject) => {
2482
3900
  const streamStartTime = Date.now();
2483
3901
  const observabilityRoute = options.observabilityRoute || req.__FARM_ROUTE__ || req.url || "/";
2484
3902
  const deploymentId = this.getDeploymentId();
@@ -2500,7 +3918,13 @@ var _ServerRenderer = class _ServerRenderer {
2500
3918
  clientEntry: "/@farm/client.js",
2501
3919
  routes: {},
2502
3920
  layouts: {},
2503
- sharedAssets: [{ tag: "link", attrs: { rel: "stylesheet", href: "/src/app/globals.css" } }]
3921
+ slots: [],
3922
+ sharedAssets: [
3923
+ {
3924
+ tag: "link",
3925
+ attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
3926
+ }
3927
+ ]
2504
3928
  };
2505
3929
  for (const routeEntry of manifest.routes) {
2506
3930
  clientManifest.routes[routeEntry.pattern] = {
@@ -2522,9 +3946,26 @@ var _ServerRenderer = class _ServerRenderer {
2522
3946
  assets: []
2523
3947
  };
2524
3948
  }
2525
- const deferredProps = prepareDeferredData(req.__FARM_PROPS__ || {});
3949
+ for (const slotEntry of manifest.slots ?? []) {
3950
+ clientManifest.slots.push({
3951
+ ...slotEntry,
3952
+ preloads: [slotEntry.modulePath],
3953
+ assets: []
3954
+ });
3955
+ }
3956
+ const routeSlotPayload = (req.__FARM_ROUTE_SLOTS__ || []).map(
3957
+ (slot) => ({
3958
+ ...slot,
3959
+ modulePath: typeof slot.modulePath === "string" && slot.modulePath.startsWith(this.config.root) ? slot.modulePath.slice(this.config.root.length) : slot.modulePath
3960
+ })
3961
+ );
3962
+ const deferredProps = prepareDeferredData({
3963
+ page: req.__FARM_PROPS__ || {},
3964
+ slots: routeSlotPayload
3965
+ });
2526
3966
  const propsScript = `<script>
2527
- window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
3967
+ window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
3968
+ window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
2528
3969
  window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
2529
3970
  window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
2530
3971
  window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
@@ -2537,7 +3978,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
2537
3978
  window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
2538
3979
  ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
2539
3980
  </script>`;
2540
- const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true ? createPreHydrationClickQueueScript() : "";
3981
+ const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true || req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ === true ? createPreHydrationClickQueueScript() : "";
2541
3982
  const {
2542
3983
  title,
2543
3984
  tags: metaTags,
@@ -2545,6 +3986,7 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
2545
3986
  } = renderMetadataHead(req.__FARM_METADATA__);
2546
3987
  const i18nSnapshot = getFarmI18nClientSnapshot();
2547
3988
  const i18nAlternateTags = i18nSnapshot ? renderI18nAlternateLinks(req.__FARM_ROUTE__ || req.url || "/", i18nSnapshot) : "";
3989
+ const fontHead = renderFarmFontDevHead(this.config.root || process.cwd());
2548
3990
  const streamRoot = React.createElement("div", { style: { display: "contents" } }, element);
2549
3991
  const { pipe, abort } = renderToPipeableStream(streamRoot, {
2550
3992
  onShellReady() {
@@ -2558,13 +4000,14 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
2558
4000
  console.log(`[FARM STREAM] onShellReady at ${shellReadyMs}ms`);
2559
4001
  }
2560
4002
  const shell = `<!DOCTYPE html>
2561
- <html lang="${escapeHtmlAttribute(i18nSnapshot?.locale || "en")}"${i18nSnapshot ? ` dir="${i18nSnapshot.direction}"` : ""}>
4003
+ <html lang="${escapeHtmlAttribute2(i18nSnapshot?.locale || "en")}"${i18nSnapshot ? ` dir="${i18nSnapshot.direction}"` : ""}>
2562
4004
  <head>
2563
4005
  <meta charset="utf-8">
2564
4006
  <meta name="viewport" content="width=device-width, initial-scale=1">
2565
- <meta name="farm-deployment-id" content="${escapeHtmlAttribute(deploymentId)}">
4007
+ <meta name="farm-deployment-id" content="${escapeHtmlAttribute2(deploymentId)}">
2566
4008
  ${hasFavicon ? "" : '<link rel="icon" href="data:,">'}
2567
4009
  <title>${title}</title>${metaTags}${i18nAlternateTags}
4010
+ ${fontHead}
2568
4011
  <link rel="stylesheet" href="/src/app/globals.css" />
2569
4012
  <script type="module" src="/@vite/client"></script>
2570
4013
  ${propsScript}
@@ -2635,7 +4078,7 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
2635
4078
  route: observabilityRoute,
2636
4079
  durationMs: Date.now() - streamStartTime
2637
4080
  });
2638
- resolve4();
4081
+ resolve5();
2639
4082
  }
2640
4083
  });
2641
4084
  res.write(shell);
@@ -2646,9 +4089,13 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
2646
4089
  },
2647
4090
  onShellError(error) {
2648
4091
  didError = true;
2649
- if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
4092
+ if (!isWebResponse(error) && !isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
2650
4093
  logger.error(`SSR shell error: ${error}`);
2651
- emitFarmEvent({ type: "render.error", route: observabilityRoute, error });
4094
+ emitFarmEvent({
4095
+ type: "render.error",
4096
+ route: observabilityRoute,
4097
+ error
4098
+ });
2652
4099
  }
2653
4100
  if (clearMiddlewareData) {
2654
4101
  clearMiddlewareData();
@@ -2657,9 +4104,13 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
2657
4104
  },
2658
4105
  onError(error) {
2659
4106
  didError = true;
2660
- if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
4107
+ if (!isWebResponse(error) && !isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
2661
4108
  logger.error(`SSR streaming error: ${error}`);
2662
- emitFarmEvent({ type: "render.error", route: observabilityRoute, error });
4109
+ emitFarmEvent({
4110
+ type: "render.error",
4111
+ route: observabilityRoute,
4112
+ error
4113
+ });
2663
4114
  }
2664
4115
  }
2665
4116
  });
@@ -2669,11 +4120,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
2669
4120
  res.statusCode = 404;
2670
4121
  const pathname = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`).pathname;
2671
4122
  try {
2672
- const appDir = path4.join(this.config.root, this.config.srcDir, "app");
4123
+ const appDir = path5.join(this.config.root, this.config.srcDir, "app");
2673
4124
  const notFoundExtensions = [".tsx", ".jsx", ".ts", ".js"];
2674
4125
  let notFoundPath = null;
2675
4126
  for (const ext of notFoundExtensions) {
2676
- const checkPath = path4.join(appDir, `not-found${ext}`);
4127
+ const checkPath = path5.join(appDir, `not-found${ext}`);
2677
4128
  if (fs2.existsSync(checkPath)) {
2678
4129
  notFoundPath = checkPath;
2679
4130
  break;
@@ -2685,7 +4136,7 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
2685
4136
  if (NotFoundComponent) {
2686
4137
  let LayoutComponent = null;
2687
4138
  for (const ext of notFoundExtensions) {
2688
- const layoutPath = path4.join(appDir, `layout${ext}`);
4139
+ const layoutPath = path5.join(appDir, `layout${ext}`);
2689
4140
  if (fs2.existsSync(layoutPath)) {
2690
4141
  try {
2691
4142
  const layoutModule = await this.routeManager.loadLayoutModule(layoutPath);
@@ -2766,14 +4217,16 @@ window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegra
2766
4217
  ${i18nSnapshot ? `window.__FARM_I18N__ = ${serializeInlineValue(i18nSnapshot)};` : ""}
2767
4218
  </script>`;
2768
4219
  const alternateLinks = i18nSnapshot ? renderI18nAlternateLinks(requestPath, i18nSnapshot) : "";
4220
+ const fontHead = renderFarmFontDevHead(this.config.root || process.cwd());
2769
4221
  return `<!DOCTYPE html>
2770
- <html lang="${escapeHtmlAttribute(i18nSnapshot?.locale || "en")}"${i18nSnapshot ? ` dir="${i18nSnapshot.direction}"` : ""}>
4222
+ <html lang="${escapeHtmlAttribute2(i18nSnapshot?.locale || "en")}"${i18nSnapshot ? ` dir="${i18nSnapshot.direction}"` : ""}>
2771
4223
  <head>
2772
4224
  <meta charset="utf-8">
2773
4225
  <meta name="viewport" content="width=device-width, initial-scale=1">
2774
- <meta name="farm-deployment-id" content="${escapeHtmlAttribute(this.getDeploymentId())}">
4226
+ <meta name="farm-deployment-id" content="${escapeHtmlAttribute2(this.getDeploymentId())}">
2775
4227
  <link rel="icon" href="data:,">
2776
4228
  <title>Farm.js App</title>${alternateLinks}
4229
+ ${fontHead}
2777
4230
  <link rel="stylesheet" href="/src/app/globals.css" />
2778
4231
  <script type="module" src="/@vite/client"></script>
2779
4232
  ${integrationManifestScript}
@@ -2808,7 +4261,7 @@ __name(_ServerRenderer, "ServerRenderer");
2808
4261
  var ServerRenderer = _ServerRenderer;
2809
4262
 
2810
4263
  // src/app.ts
2811
- import path5 from "path";
4264
+ import path6 from "path";
2812
4265
  var defaultDocsConfig = {
2813
4266
  enabled: false,
2814
4267
  entry: "/docs",
@@ -2826,17 +4279,14 @@ var _FarmApp = class _FarmApp {
2826
4279
  _setDefaultFarmI18nRuntime(this.i18nRuntime);
2827
4280
  this.viteServer = viteServer;
2828
4281
  this.routeManager = new RouteManager(this.config, viteServer);
2829
- this.serverRenderer = new ServerRenderer(
2830
- this.config,
2831
- this.routeManager,
2832
- this.i18nRuntime
2833
- );
4282
+ this.serverRenderer = new ServerRenderer(this.config, this.routeManager, this.i18nRuntime);
2834
4283
  }
2835
4284
  async initialize() {
2836
4285
  if (process.env.FARM_VERBOSE) {
2837
4286
  logger.info("Initializing Farm.js application...");
2838
4287
  }
2839
4288
  await initStorage(this.config.storage);
4289
+ await configureFarmCache(this.config.cache);
2840
4290
  await this.i18nRuntime.initialize();
2841
4291
  await this.verifyAppStructure();
2842
4292
  await this.routeManager.discoverRoutes();
@@ -2868,6 +4318,8 @@ var _FarmApp = class _FarmApp {
2868
4318
  preset: config.preset ?? "node-server",
2869
4319
  deploy: config.deploy || {},
2870
4320
  storage: config.storage || {},
4321
+ cache: config.cache || {},
4322
+ auth: isResolvedAuthConfig(config.auth) ? config.auth : resolveFarmAuthConfig(config.auth),
2871
4323
  integrations: config.integrations || {},
2872
4324
  plugins: config.plugins || [],
2873
4325
  migrations: config.migrations || { commands: [] },
@@ -2919,10 +4371,10 @@ var _FarmApp = class _FarmApp {
2919
4371
  );
2920
4372
  }
2921
4373
  const rootLayoutPaths = appDirs.flatMap((appDir) => [
2922
- path5.join(appDir, "layout.tsx"),
2923
- path5.join(appDir, "layout.ts"),
2924
- path5.join(appDir, "layout.jsx"),
2925
- path5.join(appDir, "layout.js")
4374
+ path6.join(appDir, "layout.tsx"),
4375
+ path6.join(appDir, "layout.ts"),
4376
+ path6.join(appDir, "layout.jsx"),
4377
+ path6.join(appDir, "layout.js")
2926
4378
  ]);
2927
4379
  const hasRootLayout = await Promise.all(rootLayoutPaths.map((p) => fileExists(p))).then(
2928
4380
  (results) => results.some(Boolean)
@@ -2940,6 +4392,12 @@ function isResolvedI18nConfig(value) {
2940
4392
  return Boolean(value && typeof value === "object" && "enabled" in value);
2941
4393
  }
2942
4394
  __name(isResolvedI18nConfig, "isResolvedI18nConfig");
4395
+ function isResolvedAuthConfig(value) {
4396
+ return Boolean(
4397
+ value && typeof value === "object" && "enabled" in value && "emailAndPassword" in value && "database" in value
4398
+ );
4399
+ }
4400
+ __name(isResolvedAuthConfig, "isResolvedAuthConfig");
2943
4401
  function createFarmApp(config, viteServer) {
2944
4402
  return new FarmApp(config, viteServer);
2945
4403
  }
@@ -3275,11 +4733,11 @@ __name(_HMRManager, "HMRManager");
3275
4733
  var HMRManager = _HMRManager;
3276
4734
 
3277
4735
  // src/type-artifacts.ts
3278
- import { mkdirSync as mkdirSync4 } from "fs";
3279
- import { dirname as dirname3, join as join4, resolve as resolve2 } from "path";
4736
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync2, unlinkSync } from "fs";
4737
+ import { dirname as dirname3, join as join4, resolve as resolve3 } from "path";
3280
4738
 
3281
4739
  // src/routing/generate-route-types.ts
3282
- import * as path6 from "path";
4740
+ import * as path7 from "path";
3283
4741
  import * as fs3 from "fs";
3284
4742
  function routeSegmentsToTsTypeLiteral(segments) {
3285
4743
  if (segments.length === 0) return '"/"';
@@ -3321,25 +4779,30 @@ function createRoutePattern(route) {
3321
4779
  __name(createRoutePattern, "createRoutePattern");
3322
4780
  var DEFAULT_OUT_FILE = "farm-routes.d.ts";
3323
4781
  async function generateRouteTypes(options) {
3324
- const {
3325
- root,
3326
- srcDir = "src",
3327
- outFile = DEFAULT_OUT_FILE,
3328
- extraRoutes = [],
3329
- suppressLintOnLink = false
3330
- } = options;
4782
+ const root = path7.resolve(options.root);
4783
+ const srcDir = options.srcDir || "src";
4784
+ const outFile = options.outFile || DEFAULT_OUT_FILE;
4785
+ const outPath = path7.isAbsolute(outFile) ? outFile : path7.join(root, srcDir, outFile);
4786
+ const content = await createRouteTypeDeclarations(options, outPath);
4787
+ fs3.mkdirSync(path7.dirname(outPath), { recursive: true });
4788
+ writeFileIfChanged(outPath, content);
4789
+ return outPath;
4790
+ }
4791
+ __name(generateRouteTypes, "generateRouteTypes");
4792
+ async function createRouteTypeDeclarations(options, outPath) {
4793
+ const { root, srcDir = "src", extraRoutes = [], suppressLintOnLink = false } = options;
3331
4794
  const sourceRoots = options.sourceRoots ?? [{ name: "project", root, srcDir, layer: false }];
3332
- const outPath = path6.join(root, srcDir, outFile);
3333
4795
  const patterns = /* @__PURE__ */ new Set();
3334
4796
  const glob = await import("fast-glob");
3335
4797
  for (const source of sourceRoots) {
3336
- const appDir = path6.join(source.root, source.srcDir, "app");
4798
+ const appDir = path7.join(source.root, source.srcDir, "app");
3337
4799
  if (fs3.existsSync(appDir)) {
3338
4800
  const pageFiles = await glob.default("**/page.{ts,tsx,js,jsx,md,mdx}", {
3339
4801
  cwd: appDir,
3340
4802
  absolute: false
3341
4803
  });
3342
4804
  for (const file of pageFiles) {
4805
+ if (parseRouteSlotFile(file)) continue;
3343
4806
  const route = parseRoutePath(file);
3344
4807
  if (route.type === "page") {
3345
4808
  const pattern = createRoutePattern(route);
@@ -3361,18 +4824,19 @@ async function generateRouteTypes(options) {
3361
4824
  const patternLiterals = sortedPatterns.map(routePatternToRouteLiteral);
3362
4825
  const routePathType = suppressLintOnLink ? "string" : typeLiterals.length ? typeLiterals.join(" | ") : "never";
3363
4826
  const routePatternType = suppressLintOnLink ? "string" : patternLiterals.length ? patternLiterals.join(" | ") : "never";
4827
+ const routeTypesImportPath = `./${path7.basename(outPath).replace(/\.d\.ts$/, "")}`;
3364
4828
  const augmentationBlock = suppressLintOnLink ? "" : `
3365
4829
  declare module "@farm.js/core/client" {
3366
4830
  interface LinkDefaultRoute {
3367
- _: import("./farm-routes").RoutePath;
3368
- pattern: import("./farm-routes").RoutePattern;
4831
+ _: import(${JSON.stringify(routeTypesImportPath)}).RoutePath;
4832
+ pattern: import(${JSON.stringify(routeTypesImportPath)}).RoutePattern;
3369
4833
  }
3370
4834
  }
3371
4835
 
3372
4836
  declare module "@farm.js/core" {
3373
4837
  interface LinkDefaultRoute {
3374
- _: import("./farm-routes").RoutePath;
3375
- pattern: import("./farm-routes").RoutePattern;
4838
+ _: import(${JSON.stringify(routeTypesImportPath)}).RoutePath;
4839
+ pattern: import(${JSON.stringify(routeTypesImportPath)}).RoutePattern;
3376
4840
  }
3377
4841
  // Ensure root import ("@farm.js/core") uses the same typed Link signature as client entry.
3378
4842
  const Link: typeof import("@farm.js/core/client").Link;
@@ -3381,8 +4845,8 @@ declare module "@farm.js/core" {
3381
4845
  // Internal declaration path used by @farm.js/core root type re-exports.
3382
4846
  declare module "@farm.js/core/dist/client.js" {
3383
4847
  interface LinkDefaultRoute {
3384
- _: import("./farm-routes").RoutePath;
3385
- pattern: import("./farm-routes").RoutePattern;
4848
+ _: import(${JSON.stringify(routeTypesImportPath)}).RoutePath;
4849
+ pattern: import(${JSON.stringify(routeTypesImportPath)}).RoutePattern;
3386
4850
  }
3387
4851
  }
3388
4852
  `;
@@ -3394,19 +4858,17 @@ declare module "@farm.js/core/dist/client.js" {
3394
4858
  export type RoutePath = ${routePathType};
3395
4859
  export type RoutePattern = ${routePatternType};${augmentationBlock}
3396
4860
  `;
3397
- fs3.mkdirSync(path6.dirname(outPath), { recursive: true });
3398
- writeFileIfChanged(outPath, content);
3399
- return outPath;
4861
+ return content;
3400
4862
  }
3401
- __name(generateRouteTypes, "generateRouteTypes");
4863
+ __name(createRouteTypeDeclarations, "createRouteTypeDeclarations");
3402
4864
 
3403
4865
  // src/image-types.ts
3404
4866
  import { mkdirSync as mkdirSync2 } from "fs";
3405
- import path7 from "path";
4867
+ import path8 from "path";
3406
4868
  var FARM_STATIC_IMAGE_EXTENSIONS = ["avif", "gif", "jpeg", "jpg", "png", "webp"];
3407
4869
  function generateFarmImageTypes(options) {
3408
- const outputPath = options.outFile ? path7.resolve(options.root, options.outFile) : path7.join(options.root, options.srcDir || "src", "farm-images.d.ts");
3409
- mkdirSync2(path7.dirname(outputPath), { recursive: true });
4870
+ const outputPath = options.outFile ? path8.resolve(options.root, options.outFile) : path8.join(options.root, options.srcDir || "src", "farm-images.d.ts");
4871
+ mkdirSync2(path8.dirname(outputPath), { recursive: true });
3410
4872
  writeFileIfChanged(outputPath, createFarmImageTypeDeclarations());
3411
4873
  return outputPath;
3412
4874
  }
@@ -3435,11 +4897,11 @@ __name(createFarmImageTypeDeclarations, "createFarmImageTypeDeclarations");
3435
4897
 
3436
4898
  // src/i18n/type-generator.ts
3437
4899
  import { mkdirSync as mkdirSync3 } from "fs";
3438
- import { dirname as dirname2, join as join3, resolve } from "path";
4900
+ import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
3439
4901
  async function generateFarmI18nTypes(options) {
3440
4902
  if (!options.config.enabled) return void 0;
3441
4903
  const { signatures } = await readFarmI18nCatalogs(options.config);
3442
- const outFile = options.outFile ? resolve(options.root, options.outFile) : join3(resolve(options.root), options.srcDir || "src", "farm-i18n.d.ts");
4904
+ const outFile = options.outFile ? resolve2(options.root, options.outFile) : join3(resolve2(options.root), options.srcDir || "src", "farm-i18n.d.ts");
3443
4905
  const content = renderFarmI18nTypes(options.config.locales, signatures);
3444
4906
  mkdirSync3(dirname2(outFile), { recursive: true });
3445
4907
  writeFileIfChanged(outFile, content);
@@ -3489,7 +4951,7 @@ __name(argumentType, "argumentType");
3489
4951
 
3490
4952
  // src/type-artifacts.ts
3491
4953
  async function generateFarmTypeArtifacts(options) {
3492
- const root = resolve2(options.root);
4954
+ const root = resolve3(options.root);
3493
4955
  const srcDir = options.srcDir || "src";
3494
4956
  const shouldGenerateRoutes = options.routes !== false;
3495
4957
  const shouldGenerateApi = options.api !== false;
@@ -3501,7 +4963,10 @@ async function generateFarmTypeArtifacts(options) {
3501
4963
  const result = {
3502
4964
  apiRoutes: []
3503
4965
  };
3504
- if (shouldGenerateRoutes) {
4966
+ const unifiedTypesPath = join4(root, srcDir, "farm.d.ts");
4967
+ const shouldRefreshUnifiedTypes = shouldGenerateRoutes && !options.routeTypesOutFile || shouldGenerateEnv && !options.envTypesOutFile || shouldGenerateI18n && !options.i18nTypesOutFile;
4968
+ const unifiedSections = [];
4969
+ if (shouldRefreshUnifiedTypes && !options.routeTypesOutFile) {
3505
4970
  const routeOptions = {
3506
4971
  root,
3507
4972
  srcDir,
@@ -3509,37 +4974,62 @@ async function generateFarmTypeArtifacts(options) {
3509
4974
  suppressLintOnLink: options.suppressLintOnLink,
3510
4975
  sourceRoots
3511
4976
  };
3512
- if (options.routeTypesOutFile) {
3513
- routeOptions.outFile = options.routeTypesOutFile;
3514
- }
3515
- result.routeTypesPath = await generateRouteTypes(routeOptions);
4977
+ unifiedSections.push(await createRouteTypeDeclarations(routeOptions, unifiedTypesPath));
4978
+ result.routeTypesPath = unifiedTypesPath;
4979
+ } else if (shouldGenerateRoutes) {
4980
+ result.routeTypesPath = await generateRouteTypes({
4981
+ root,
4982
+ srcDir,
4983
+ outFile: options.routeTypesOutFile,
4984
+ extraRoutes: options.extraRoutes || [],
4985
+ suppressLintOnLink: options.suppressLintOnLink,
4986
+ sourceRoots
4987
+ });
3516
4988
  }
3517
4989
  if (shouldGenerateApi) {
3518
4990
  const generator = new APITypeGenerator(appDirs);
3519
4991
  const apiRoutes = generator.scanAPIRoutes();
3520
- const apiTypesPath = options.apiTypesOutFile ? resolve2(root, options.apiTypesOutFile) : join4(root, srcDir, "lib", "api.generated.ts");
4992
+ const apiTypesPath = options.apiTypesOutFile ? resolve3(root, options.apiTypesOutFile) : join4(root, srcDir, "lib", "api.generated.ts");
3521
4993
  const content = generator.generateAPIRouter(apiRoutes, { outFile: apiTypesPath });
3522
4994
  mkdirSync4(dirname3(apiTypesPath), { recursive: true });
3523
4995
  writeFileIfChanged(apiTypesPath, content);
3524
4996
  result.apiTypesPath = apiTypesPath;
3525
4997
  result.apiRoutes = apiRoutes;
3526
4998
  }
3527
- if (shouldGenerateEnv) {
4999
+ if (shouldRefreshUnifiedTypes && !options.envTypesOutFile) {
5000
+ unifiedSections.push(
5001
+ createEnvTypeDeclarations(
5002
+ {
5003
+ root,
5004
+ srcDir,
5005
+ configPath: options.configPath,
5006
+ layerConfigPaths: (options.layers ?? []).map((layer) => layer.configFile).filter((configFile) => Boolean(configFile))
5007
+ },
5008
+ unifiedTypesPath
5009
+ )
5010
+ );
5011
+ result.envTypesPath = unifiedTypesPath;
5012
+ } else if (shouldGenerateEnv) {
3528
5013
  result.envTypesPath = await generateEnvTypes({
3529
5014
  root,
3530
5015
  srcDir,
3531
5016
  outFile: options.envTypesOutFile,
5017
+ configPath: options.configPath,
3532
5018
  layerConfigPaths: (options.layers ?? []).map((layer) => layer.configFile).filter((configFile) => Boolean(configFile))
3533
5019
  });
3534
5020
  }
3535
- if (shouldGenerateImages) {
5021
+ if (shouldGenerateImages && options.imageTypesOutFile) {
3536
5022
  result.imageTypesPath = generateFarmImageTypes({
3537
5023
  root,
3538
5024
  srcDir,
3539
5025
  outFile: options.imageTypesOutFile
3540
5026
  });
3541
5027
  }
3542
- if (shouldGenerateI18n && options.i18nConfig) {
5028
+ if (shouldRefreshUnifiedTypes && options.i18nConfig?.enabled && !options.i18nTypesOutFile) {
5029
+ const { signatures } = await readFarmI18nCatalogs(options.i18nConfig);
5030
+ unifiedSections.push(renderFarmI18nTypes(options.i18nConfig.locales, signatures));
5031
+ result.i18nTypesPath = unifiedTypesPath;
5032
+ } else if (shouldGenerateI18n && options.i18nConfig) {
3543
5033
  result.i18nTypesPath = await generateFarmI18nTypes({
3544
5034
  root,
3545
5035
  srcDir,
@@ -3547,17 +5037,50 @@ async function generateFarmTypeArtifacts(options) {
3547
5037
  outFile: options.i18nTypesOutFile
3548
5038
  });
3549
5039
  }
5040
+ if (shouldRefreshUnifiedTypes) {
5041
+ mkdirSync4(dirname3(unifiedTypesPath), { recursive: true });
5042
+ writeFileIfChanged(
5043
+ unifiedTypesPath,
5044
+ `/**
5045
+ * Generated by Farm.js. Do not edit.
5046
+ * Contains project-specific route, environment, and internationalization types.
5047
+ */
5048
+
5049
+ import "@farm.js/core/image";
5050
+
5051
+ ${unifiedSections.join("\n")}`
5052
+ );
5053
+ result.typesPath = unifiedTypesPath;
5054
+ removeLegacyTypeArtifacts(root, srcDir);
5055
+ }
3550
5056
  return result;
3551
5057
  }
3552
5058
  __name(generateFarmTypeArtifacts, "generateFarmTypeArtifacts");
5059
+ var LEGACY_TYPE_ARTIFACTS = [
5060
+ ["farm-routes.d.ts", "Auto-generated route types"],
5061
+ ["farm-env.d.ts", "Auto-generated env types"],
5062
+ ["farm-images.d.ts", "Generated by Farm.js"],
5063
+ ["farm-i18n.d.ts", "Generated by Farm.js"]
5064
+ ];
5065
+ function removeLegacyTypeArtifacts(root, srcDir) {
5066
+ for (const [fileName, marker] of LEGACY_TYPE_ARTIFACTS) {
5067
+ const filePath = join4(root, srcDir, fileName);
5068
+ if (!existsSync4(filePath)) continue;
5069
+ const source = readFileSync2(filePath, "utf8");
5070
+ if (source.includes(marker)) {
5071
+ unlinkSync(filePath);
5072
+ }
5073
+ }
5074
+ }
5075
+ __name(removeLegacyTypeArtifacts, "removeLegacyTypeArtifacts");
3553
5076
 
3554
5077
  // src/vite.ts
3555
5078
  import * as fs4 from "fs";
3556
- import * as path9 from "path";
5079
+ import * as path10 from "path";
3557
5080
 
3558
5081
  // src/image-vite.ts
3559
- import { readFile as readFile3 } from "fs/promises";
3560
- import path8 from "path";
5082
+ import { readFile as readFile4 } from "fs/promises";
5083
+ import path9 from "path";
3561
5084
  import { imageSize as imageSize2 } from "image-size";
3562
5085
  var FARM_IMAGE_ID_PREFIX = "\0farm:image:";
3563
5086
  var STATIC_IMAGE_RE = /\.(?:avif|gif|jpe?g|png|webp)$/i;
@@ -3591,7 +5114,7 @@ function farmImageImportsPlugin() {
3591
5114
  }
3592
5115
  __name(farmImageImportsPlugin, "farmImageImportsPlugin");
3593
5116
  async function createStaticImageModule(filePath, sourceDeclaration) {
3594
- const bytes = await readFile3(filePath);
5117
+ const bytes = await readFile4(filePath);
3595
5118
  const dimensions = imageSize2(bytes);
3596
5119
  if (!dimensions.width || !dimensions.height) {
3597
5120
  throw new Error(`Could not determine image dimensions for ${filePath}`);
@@ -3629,7 +5152,7 @@ var ALL_TYPE_ARTIFACTS = {
3629
5152
  routes: true,
3630
5153
  api: true,
3631
5154
  env: true,
3632
- images: true,
5155
+ images: false,
3633
5156
  i18n: true
3634
5157
  };
3635
5158
  var createEmptyTypeArtifactSelection = /* @__PURE__ */ __name(() => ({
@@ -3666,7 +5189,7 @@ function loadFarmWorkflowsDevRuntime() {
3666
5189
  }
3667
5190
  __name(loadFarmWorkflowsDevRuntime, "loadFarmWorkflowsDevRuntime");
3668
5191
  function loadFarmDevtoolsSnapshotRuntime() {
3669
- return import("./devtools-AE4RVXCM.mjs");
5192
+ return import("./devtools-A22KUJZT.mjs");
3670
5193
  }
3671
5194
  __name(loadFarmDevtoolsSnapshotRuntime, "loadFarmDevtoolsSnapshotRuntime");
3672
5195
  function loadFarmDevtoolsUIRuntime() {
@@ -3674,7 +5197,7 @@ function loadFarmDevtoolsUIRuntime() {
3674
5197
  }
3675
5198
  __name(loadFarmDevtoolsUIRuntime, "loadFarmDevtoolsUIRuntime");
3676
5199
  function loadFarmDevtoolsClientRuntime() {
3677
- return import("./devtools-client-6WPY2AQU.mjs");
5200
+ return import("./devtools-client-3XRTBND5.mjs");
3678
5201
  }
3679
5202
  __name(loadFarmDevtoolsClientRuntime, "loadFarmDevtoolsClientRuntime");
3680
5203
  function farmI18nClientBridgePlugin() {
@@ -3829,7 +5352,7 @@ function isResolvedEnvScope(value) {
3829
5352
  }
3830
5353
  __name(isResolvedEnvScope, "isResolvedEnvScope");
3831
5354
  function isPotentialProgrammaticRouteSourceFile(normalizedFile, srcDirSlug) {
3832
- return normalizedFile.startsWith(`${srcDirSlug}/`) && /\.(ts|tsx|js|jsx)$/.test(normalizedFile) && !/\.d\.ts$/.test(normalizedFile) && !normalizedFile.endsWith("/farm-routes.d.ts") && !normalizedFile.endsWith("/farm-env.d.ts") && !normalizedFile.endsWith("/lib/api.generated.ts");
5355
+ return normalizedFile.startsWith(`${srcDirSlug}/`) && /\.(ts|tsx|js|jsx)$/.test(normalizedFile) && !normalizedFile.endsWith(".d.ts") && !normalizedFile.endsWith("/farm-routes.d.ts") && !normalizedFile.endsWith("/farm-env.d.ts") && !normalizedFile.endsWith("/lib/api.generated.ts");
3833
5356
  }
3834
5357
  __name(isPotentialProgrammaticRouteSourceFile, "isPotentialProgrammaticRouteSourceFile");
3835
5358
  function fileContainsProgrammaticPageRoute(file) {
@@ -3845,7 +5368,7 @@ function fileContainsProgrammaticPageRoute(file) {
3845
5368
  __name(fileContainsProgrammaticPageRoute, "fileContainsProgrammaticPageRoute");
3846
5369
  function rewriteEarlySsrRelativeImports(options) {
3847
5370
  const cleanId = options.id.split("?", 1)[0];
3848
- if (!path9.isAbsolute(cleanId) || cleanId.replace(/\\/g, "/").includes("/node_modules/")) {
5371
+ if (!path10.isAbsolute(cleanId) || cleanId.replace(/\\/g, "/").includes("/node_modules/")) {
3849
5372
  return null;
3850
5373
  }
3851
5374
  const replacements = [];
@@ -3865,7 +5388,7 @@ function rewriteEarlySsrRelativeImports(options) {
3865
5388
  const suffixIndex = source.value.search(/[?#]/);
3866
5389
  const sourcePath = suffixIndex === -1 ? source.value : source.value.slice(0, suffixIndex);
3867
5390
  const suffix = suffixIndex === -1 ? "" : source.value.slice(suffixIndex);
3868
- const resolvedPath = path9.resolve(path9.dirname(cleanId), sourcePath);
5391
+ const resolvedPath = path10.resolve(path10.dirname(cleanId), sourcePath);
3869
5392
  replacements.push({
3870
5393
  start: source.start,
3871
5394
  end: source.end,
@@ -3909,6 +5432,11 @@ function isFarmConfigFile(file, root) {
3909
5432
  __name(isFarmConfigFile, "isFarmConfigFile");
3910
5433
  function farmPlugin(options = {}, initialPluginManager) {
3911
5434
  const imageImports = farmImageImportsPlugin();
5435
+ const fontImports = farmFontImportsPlugin({
5436
+ root: options.root,
5437
+ basePath: options.basePath,
5438
+ publicDir: options.publicDir
5439
+ });
3912
5440
  let farmApp;
3913
5441
  let server;
3914
5442
  let hmrManager;
@@ -3945,15 +5473,21 @@ function farmPlugin(options = {}, initialPluginManager) {
3945
5473
  ...layerRoots.length ? {
3946
5474
  server: {
3947
5475
  fs: {
3948
- allow: [path9.resolve(options.root || process.cwd()), ...layerRoots]
5476
+ allow: [path10.resolve(options.root || process.cwd()), ...layerRoots]
3949
5477
  }
3950
5478
  }
3951
5479
  } : {}
3952
5480
  };
3953
5481
  },
3954
5482
  async configResolved(config) {
5483
+ if (typeof fontImports.configResolved === "function") {
5484
+ await fontImports.configResolved.call(this, config);
5485
+ }
3955
5486
  },
3956
5487
  async configureServer(viteServer) {
5488
+ if (typeof fontImports.configureServer === "function") {
5489
+ await fontImports.configureServer.call(this, viteServer);
5490
+ }
3957
5491
  server = viteServer;
3958
5492
  const pm = initialPluginManager;
3959
5493
  const emitPluginError = /* @__PURE__ */ __name(async (phase, error, meta) => {
@@ -3970,9 +5504,9 @@ function farmPlugin(options = {}, initialPluginManager) {
3970
5504
  },
3971
5505
  server
3972
5506
  );
3973
- const globalsCSSPath = path9.join(server.config.root, "src/app/globals.css");
5507
+ const globalsCSSPath = path10.join(server.config.root, "src/app/globals.css");
3974
5508
  if (!fs4.existsSync(globalsCSSPath)) {
3975
- const appDir = path9.join(server.config.root, "src/app");
5509
+ const appDir = path10.join(server.config.root, "src/app");
3976
5510
  if (!fs4.existsSync(appDir)) {
3977
5511
  fs4.mkdirSync(appDir, { recursive: true });
3978
5512
  }
@@ -3994,10 +5528,10 @@ function farmPlugin(options = {}, initialPluginManager) {
3994
5528
  });
3995
5529
  }
3996
5530
  const sourceRoots = getFarmSourceRoots(farmConfig);
3997
- server.watcher.add(sourceRoots.map((source) => path9.join(source.root, source.srcDir)));
5531
+ server.watcher.add(sourceRoots.map((source) => path10.join(source.root, source.srcDir)));
3998
5532
  if (farmConfig.i18n.enabled) {
3999
5533
  server.watcher.add(
4000
- farmConfig.i18n.messages.includes("{locale}") ? path9.dirname(farmConfig.i18n.messages) : farmConfig.i18n.messages
5534
+ farmConfig.i18n.messages.includes("{locale}") ? path10.dirname(farmConfig.i18n.messages) : farmConfig.i18n.messages
4001
5535
  );
4002
5536
  }
4003
5537
  const workflowConfig = farmConfig.workflows;
@@ -4007,7 +5541,7 @@ function farmPlugin(options = {}, initialPluginManager) {
4007
5541
  ...farmDocsDevRuntime?.getFarmDocsRouteTypeEntries(farmConfig.docs) ?? []
4008
5542
  ], "getExtraRouteTypes");
4009
5543
  const appDirSlugs = sourceRoots.map(
4010
- (source) => path9.join(source.root, source.srcDir, "app").replace(/\\/g, "/")
5544
+ (source) => path10.join(source.root, source.srcDir, "app").replace(/\\/g, "/")
4011
5545
  );
4012
5546
  const generateTypeArtifacts = /* @__PURE__ */ __name(async (reason, selection = ALL_TYPE_ARTIFACTS, log = false) => {
4013
5547
  try {
@@ -4047,7 +5581,7 @@ function farmPlugin(options = {}, initialPluginManager) {
4047
5581
  }, "generateTypeArtifacts");
4048
5582
  await generateTypeArtifacts("startup");
4049
5583
  const srcDirSlugs = sourceRoots.map(
4050
- (source) => path9.join(source.root, source.srcDir).replace(/\\/g, "/")
5584
+ (source) => path10.join(source.root, source.srcDir).replace(/\\/g, "/")
4051
5585
  );
4052
5586
  const layerConfigFiles = new Set(
4053
5587
  farmConfig.layers.map((layer) => layer.configFile?.replace(/\\/g, "/")).filter((file) => Boolean(file))
@@ -4072,7 +5606,7 @@ function farmPlugin(options = {}, initialPluginManager) {
4072
5606
  }, "isProgrammaticRouteSourceFile");
4073
5607
  const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
4074
5608
  const normalized = file.replace(/\\/g, "/");
4075
- return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
5609
+ return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|default|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
4076
5610
  normalized
4077
5611
  );
4078
5612
  }, "isAppRuntimeFile");
@@ -4165,7 +5699,7 @@ function farmPlugin(options = {}, initialPluginManager) {
4165
5699
  await apiRouteManager.discoverRoutes();
4166
5700
  let discoveredWorkflows = [];
4167
5701
  const hasWorkflowDirectory = workflowConfig.enabled && workflowConfig.dirs.some(
4168
- (dir) => fs4.existsSync(path9.isAbsolute(dir) ? dir : path9.join(farmConfig.root, dir))
5702
+ (dir) => fs4.existsSync(path10.isAbsolute(dir) ? dir : path10.join(farmConfig.root, dir))
4169
5703
  );
4170
5704
  if (hasWorkflowDirectory) {
4171
5705
  const { createFarmWorkflowRequestHandler, discoverFarmWorkflows } = await loadFarmWorkflowsDevRuntime();
@@ -4243,14 +5777,14 @@ function farmPlugin(options = {}, initialPluginManager) {
4243
5777
  farmDocsDevRuntime ? [
4244
5778
  [
4245
5779
  "/assets/Geist-Variable-CrgPqtmy.woff2",
4246
- path9.join(
5780
+ path10.join(
4247
5781
  farmConfig.root,
4248
5782
  "node_modules/geist/dist/fonts/geist-sans/Geist-Variable.woff2"
4249
5783
  )
4250
5784
  ],
4251
5785
  [
4252
5786
  "/assets/GeistMono-Variable-BNLlm6Cd.woff2",
4253
- path9.join(
5787
+ path10.join(
4254
5788
  farmConfig.root,
4255
5789
  "node_modules/geist/dist/fonts/geist-mono/GeistMono-Variable.woff2"
4256
5790
  )
@@ -4414,12 +5948,13 @@ function farmPlugin(options = {}, initialPluginManager) {
4414
5948
  config: farmApp.getConfig().mdx,
4415
5949
  resolveSource: /* @__PURE__ */ __name(async (pathname2) => {
4416
5950
  const match = farmApp.getRouteManager().matchRoute(pathname2);
4417
- if (!match.route || !isFarmMarkdownPageFile(match.route.modulePath)) {
5951
+ const sourcePath = match.route?.markdownSourcePath || (match.route && isFarmMarkdownPageFile(match.route.modulePath) ? match.route.modulePath : null);
5952
+ if (!sourcePath) {
4418
5953
  return null;
4419
5954
  }
4420
5955
  return {
4421
- source: await fs4.promises.readFile(match.route.modulePath, "utf8"),
4422
- filePath: match.route.modulePath
5956
+ source: await fs4.promises.readFile(sourcePath, "utf8"),
5957
+ filePath: sourcePath
4423
5958
  };
4424
5959
  }, "resolveSource")
4425
5960
  });
@@ -4440,16 +5975,37 @@ function farmPlugin(options = {}, initialPluginManager) {
4440
5975
  await sendWebResponse(res, markdownResponse);
4441
5976
  return;
4442
5977
  }
5978
+ const markdownPageTarget = resolveMarkdownMirrorTarget(
5979
+ farmApp.getConfig().md,
5980
+ requestPathname,
5981
+ {
5982
+ accept: "text/markdown"
5983
+ }
5984
+ );
5985
+ if (markdownPageTarget && farmApp.getRouteManager().matchRoute(markdownPageTarget.pathname).route) {
5986
+ const vary = res.getHeader("Vary");
5987
+ const varyValues = String(vary || "").split(",").map((value) => value.trim()).filter(Boolean);
5988
+ if (!varyValues.some((value) => value.toLowerCase() === "accept")) {
5989
+ res.setHeader("Vary", [...varyValues, "Accept"].join(", "));
5990
+ }
5991
+ const alternatePath = markdownPageTarget.pathname === "/" ? "/index.md" : `${markdownPageTarget.pathname}.md`;
5992
+ const alternateLink = `<${alternatePath}>; rel="alternate"; type="text/markdown"`;
5993
+ const currentLink = res.getHeader("Link");
5994
+ res.setHeader(
5995
+ "Link",
5996
+ currentLink ? `${String(currentLink)}, ${alternateLink}` : alternateLink
5997
+ );
5998
+ }
4443
5999
  if (workflowHandler && (requestPathname === workflowConfig.route || requestPathname.startsWith(`${workflowConfig.route}/`))) {
4444
6000
  let workflowBody;
4445
6001
  if (requestMethod !== "GET" && requestMethod !== "HEAD") {
4446
- workflowBody = await new Promise((resolve4) => {
6002
+ workflowBody = await new Promise((resolve5) => {
4447
6003
  let data = "";
4448
6004
  req.on("data", (chunk) => {
4449
6005
  data += chunk;
4450
6006
  });
4451
6007
  req.on("end", () => {
4452
- resolve4(data);
6008
+ resolve5(data);
4453
6009
  });
4454
6010
  });
4455
6011
  }
@@ -4492,13 +6048,13 @@ function farmPlugin(options = {}, initialPluginManager) {
4492
6048
  }
4493
6049
  let body;
4494
6050
  if (req.method !== "GET" && req.method !== "HEAD") {
4495
- body = await new Promise((resolve4) => {
6051
+ body = await new Promise((resolve5) => {
4496
6052
  let data = "";
4497
6053
  req.on("data", (chunk) => {
4498
6054
  data += chunk;
4499
6055
  });
4500
6056
  req.on("end", () => {
4501
- resolve4(data);
6057
+ resolve5(data);
4502
6058
  });
4503
6059
  });
4504
6060
  }
@@ -4604,13 +6160,13 @@ function farmPlugin(options = {}, initialPluginManager) {
4604
6160
  }
4605
6161
  let body;
4606
6162
  if (req.method !== "GET" && req.method !== "HEAD") {
4607
- body = await new Promise((resolve4) => {
6163
+ body = await new Promise((resolve5) => {
4608
6164
  let data = "";
4609
6165
  req.on("data", (chunk) => {
4610
6166
  data += chunk;
4611
6167
  });
4612
6168
  req.on("end", () => {
4613
- resolve4(data);
6169
+ resolve5(data);
4614
6170
  });
4615
6171
  });
4616
6172
  }
@@ -4667,13 +6223,13 @@ function farmPlugin(options = {}, initialPluginManager) {
4667
6223
  }
4668
6224
  let body;
4669
6225
  if (req.method !== "GET" && req.method !== "HEAD") {
4670
- body = await new Promise((resolve4) => {
6226
+ body = await new Promise((resolve5) => {
4671
6227
  let data = "";
4672
6228
  req.on("data", (chunk) => {
4673
6229
  data += chunk;
4674
6230
  });
4675
6231
  req.on("end", () => {
4676
- resolve4(data);
6232
+ resolve5(data);
4677
6233
  });
4678
6234
  });
4679
6235
  }
@@ -4763,7 +6319,10 @@ function farmPlugin(options = {}, initialPluginManager) {
4763
6319
  method: req.method || "GET"
4764
6320
  });
4765
6321
  }
4766
- const match = routeManager3.matchRoute(targetPath);
6322
+ const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
6323
+ const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
6324
+ interceptFrom: interceptFromHeader
6325
+ });
4767
6326
  if (pm) {
4768
6327
  await pm.runHookParallel("afterRouteMatch", {
4769
6328
  pathname: targetPath,
@@ -4779,7 +6338,7 @@ function farmPlugin(options = {}, initialPluginManager) {
4779
6338
  res.end(JSON.stringify({ error: "Route not found" }));
4780
6339
  return;
4781
6340
  }
4782
- const { route, params, layouts } = match;
6341
+ const { route, params, layouts, slots } = match;
4783
6342
  if (!route) {
4784
6343
  res.statusCode = 404;
4785
6344
  res.setHeader("Content-Type", "application/json");
@@ -4834,6 +6393,54 @@ function farmPlugin(options = {}, initialPluginManager) {
4834
6393
  search: searchParams,
4835
6394
  routePath: route.pattern
4836
6395
  });
6396
+ const routeSlots = await Promise.all(
6397
+ slots.map(async (slot) => {
6398
+ const slotModule = await routeManager3.loadRouteModule(slot.route.modulePath);
6399
+ const slotMetadata = getClientModuleMetadata(
6400
+ slot.route.modulePath,
6401
+ server.config.root
6402
+ );
6403
+ const slotContext = await resolveFarmRouteContext(farmApp.getConfig(), {
6404
+ request,
6405
+ params: slot.params,
6406
+ search: searchParams,
6407
+ path: targetUrl.pathname
6408
+ });
6409
+ const slotProps = await parseRouteModuleProps2(slotModule, {
6410
+ props: withFarmRouteContext(
6411
+ {
6412
+ params: slot.params,
6413
+ searchParams: Promise.resolve(searchParams),
6414
+ path: targetUrl.pathname
6415
+ },
6416
+ slotContext
6417
+ ),
6418
+ search: searchParams,
6419
+ routePath: slot.route.pattern
6420
+ });
6421
+ return {
6422
+ name: slot.name,
6423
+ ownerPattern: slot.ownerPattern,
6424
+ containerId: slot.containerId,
6425
+ interception: slot.interception,
6426
+ fallback: slot.fallback,
6427
+ modulePath: slot.route.modulePath,
6428
+ isClientComponent: slotMetadata.isClientComponent,
6429
+ shouldHydrate: slotMetadata.shouldHydrate,
6430
+ props: {
6431
+ params: slotProps.params,
6432
+ search: slotProps.search,
6433
+ searchParams: slotProps.search,
6434
+ ..."data" in slotProps ? { data: slotProps.data } : {},
6435
+ ...slotProps.__farmCanonicalPath ? {
6436
+ __farmCanonicalPath: slotProps.__farmCanonicalPath
6437
+ } : {},
6438
+ ...slotProps.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
6439
+ path: targetUrl.pathname
6440
+ }
6441
+ };
6442
+ })
6443
+ );
4837
6444
  const projectRoot = server.config.root;
4838
6445
  const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
4839
6446
  if (absolutePath.startsWith(projectRoot)) {
@@ -4854,13 +6461,21 @@ function farmPlugin(options = {}, initialPluginManager) {
4854
6461
  },
4855
6462
  canonicalPath: routeProps.__farmCanonicalPath,
4856
6463
  modulePath: toUrlPath(route.modulePath),
4857
- isClientComponent,
4858
- shouldHydrate,
6464
+ isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
6465
+ shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
4859
6466
  metadata: {
4860
6467
  title: mergedMetadata.title,
4861
6468
  description: mergedMetadata.description
4862
6469
  },
4863
6470
  layoutModules: layouts.map((l) => toUrlPath(l.modulePath)),
6471
+ routeSlots: routeSlots.map((slot) => ({
6472
+ ...slot,
6473
+ modulePath: toUrlPath(slot.modulePath)
6474
+ })),
6475
+ interception: routeSlots.some((slot) => slot.interception) ? {
6476
+ from: interceptFromHeader,
6477
+ slots: routeSlots.filter((slot) => slot.interception).map((slot) => slot.name)
6478
+ } : void 0,
4864
6479
  i18n: getFarmI18nClientSnapshot()
4865
6480
  };
4866
6481
  await sendWebResponse(
@@ -5132,6 +6747,10 @@ function farmPlugin(options = {}, initialPluginManager) {
5132
6747
  );
5133
6748
  },
5134
6749
  async resolveId(id, importer, resolveOptions) {
6750
+ if (typeof fontImports.resolveId === "function") {
6751
+ const fontId = await fontImports.resolveId.call(this, id, importer, resolveOptions);
6752
+ if (fontId) return fontId;
6753
+ }
5135
6754
  if (typeof imageImports.resolveId === "function") {
5136
6755
  const imageId = await imageImports.resolveId.call(this, id, importer, resolveOptions);
5137
6756
  if (imageId) return imageId;
@@ -5150,6 +6769,10 @@ function farmPlugin(options = {}, initialPluginManager) {
5150
6769
  }
5151
6770
  },
5152
6771
  async load(id) {
6772
+ if (typeof fontImports.load === "function") {
6773
+ const fontModule = await fontImports.load.call(this, id);
6774
+ if (fontModule) return fontModule;
6775
+ }
5153
6776
  if (typeof imageImports.load === "function") {
5154
6777
  const imageModule = await imageImports.load.call(this, id);
5155
6778
  if (imageModule) return imageModule;
@@ -5196,6 +6819,7 @@ function farmPlugin(options = {}, initialPluginManager) {
5196
6819
  export const getManifest = () => ({
5197
6820
  routes: {},
5198
6821
  layouts: {},
6822
+ slots: [],
5199
6823
  clientEntry: "/@farm/client.js",
5200
6824
  sharedAssets: []
5201
6825
  });
@@ -5206,6 +6830,7 @@ export const getManifest = () => ({
5206
6830
  clientEntry: "/@farm/client.js",
5207
6831
  routes: {},
5208
6832
  layouts: {},
6833
+ slots: [],
5209
6834
  sharedAssets: [
5210
6835
  {
5211
6836
  tag: "link",
@@ -5235,6 +6860,13 @@ export const getManifest = () => ({
5235
6860
  assets: []
5236
6861
  };
5237
6862
  }
6863
+ for (const slot of manifest.slots) {
6864
+ fullManifest.slots.push({
6865
+ ...slot,
6866
+ preloads: [slot.modulePath],
6867
+ assets: []
6868
+ });
6869
+ }
5238
6870
  return `
5239
6871
  // Auto-generated manifest for SPA navigation (TanStack Start pattern)
5240
6872
  // This manifest is inlined in the server bundle - no file on disk
@@ -5251,6 +6883,19 @@ export const manifest = getManifest();
5251
6883
  }
5252
6884
  let transformedCode = code;
5253
6885
  let transformed = false;
6886
+ if (typeof fontImports.transform === "function") {
6887
+ const fontResult = await fontImports.transform.call(
6888
+ this,
6889
+ transformedCode,
6890
+ id,
6891
+ transformOptions
6892
+ );
6893
+ const fontCode = typeof fontResult === "string" ? fontResult : fontResult?.code;
6894
+ if (fontCode) {
6895
+ transformedCode = fontCode;
6896
+ transformed = true;
6897
+ }
6898
+ }
5254
6899
  if (transformOptions?.ssr && server) {
5255
6900
  const rewrittenImports = rewriteEarlySsrRelativeImports({
5256
6901
  code: transformedCode,
@@ -5305,7 +6950,10 @@ if (import.meta.hot) {
5305
6950
  }
5306
6951
  return transformed ? { code: transformedCode, map: null } : null;
5307
6952
  },
5308
- generateBundle(options2, bundle) {
6953
+ async generateBundle(options2, bundle) {
6954
+ if (typeof fontImports.generateBundle === "function") {
6955
+ await fontImports.generateBundle.call(this, options2, bundle, false);
6956
+ }
5309
6957
  const clientManifest = generateClientManifest(bundle);
5310
6958
  this.emitFile({
5311
6959
  type: "asset",
@@ -5325,8 +6973,8 @@ if (import.meta.hot) {
5325
6973
  }
5326
6974
  logger.info(`Found ${ssgPages.length} SSG pages, ${ssrRoutes.length} SSR routes`);
5327
6975
  logger.info("Pre-rendering SSG pages...");
5328
- const outDir = path9.join(server?.config.root || process.cwd(), options.outDir || "dist");
5329
- const clientDir = path9.join(outDir, "client");
6976
+ const outDir = path10.join(server?.config.root || process.cwd(), options.outDir || "dist");
6977
+ const clientDir = path10.join(outDir, "client");
5330
6978
  for (const page of ssgPages) {
5331
6979
  try {
5332
6980
  const staticRequest = new Request(new URL(page.urlPath, "http://farm.static"));
@@ -5378,8 +7026,8 @@ if (import.meta.hot) {
5378
7026
  <script type="module" src="/assets/client.js"></script>
5379
7027
  </body>
5380
7028
  </html>`;
5381
- const outputPath = page.urlPath === "/" ? path9.join(clientDir, "index.html") : path9.join(clientDir, page.urlPath + ".html");
5382
- fs4.mkdirSync(path9.dirname(outputPath), { recursive: true });
7029
+ const outputPath = page.urlPath === "/" ? path10.join(clientDir, "index.html") : path10.join(clientDir, page.urlPath + ".html");
7030
+ fs4.mkdirSync(path10.dirname(outputPath), { recursive: true });
5383
7031
  fs4.writeFileSync(outputPath, fullHtml);
5384
7032
  const revalidateInfo = page.revalidate ? ` (revalidate: ${page.revalidate}s)` : "";
5385
7033
  logger.success(` \u2713 ${page.urlPath}${revalidateInfo}`);
@@ -5388,7 +7036,7 @@ if (import.meta.hot) {
5388
7036
  logger.error(` \u2717 ${page.urlPath}: ${error}`);
5389
7037
  }
5390
7038
  }
5391
- const manifestPath = path9.join(outDir, "__ssg_manifest.json");
7039
+ const manifestPath = path10.join(outDir, "__ssg_manifest.json");
5392
7040
  fs4.writeFileSync(
5393
7041
  manifestPath,
5394
7042
  JSON.stringify(
@@ -5424,9 +7072,9 @@ if (import.meta.hot) {
5424
7072
  }
5425
7073
  const currentFarmConfig = farmApp?.getConfig();
5426
7074
  const normalizedFile = file.replace(/\\/g, "/");
5427
- const currentSrcRoot = currentFarmConfig ? getFarmSourceRoots(currentFarmConfig).map((source) => path9.join(source.root, source.srcDir).replace(/\\/g, "/")).find((sourceRoot) => normalizedFile.startsWith(`${sourceRoot}/`)) || null : null;
7075
+ const currentSrcRoot = currentFarmConfig ? getFarmSourceRoots(currentFarmConfig).map((source) => path10.join(source.root, source.srcDir).replace(/\\/g, "/")).find((sourceRoot) => normalizedFile.startsWith(`${sourceRoot}/`)) || null : null;
5428
7076
  if (currentSrcRoot && normalizedFile.startsWith(`${currentSrcRoot}/`) && isProgrammaticRoutesFileName(normalizedFile)) {
5429
- logUpdate("PAGE", `updated ${path9.basename(file)}`);
7077
+ logUpdate("PAGE", `updated ${path10.basename(file)}`);
5430
7078
  for (const mod of modules) {
5431
7079
  server2.moduleGraph.invalidateModule(mod);
5432
7080
  }
@@ -5877,7 +7525,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
5877
7525
 
5878
7526
  // Get manifest from window (inlined by server in HTML)
5879
7527
  // Fallback to empty manifest if not available yet
5880
- const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
7528
+ const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
5881
7529
 
5882
7530
  // ====== CLIENT-SIDE ROUTE MATCHING ======
5883
7531
  // Matches URL to route using manifest (no server request!)
@@ -6216,6 +7864,9 @@ let LayoutComponent = null;
6216
7864
 
6217
7865
  // Track if we've taken over rendering from SSR
6218
7866
  let hasClientTakenOver = false;
7867
+ const routeSlotRoots = new Map();
7868
+ const routeSlotDefinitions = new Map();
7869
+ let activeRouteInterception = null;
6219
7870
 
6220
7871
  function normalizeServerProps(rawProps) {
6221
7872
  const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
@@ -6228,6 +7879,123 @@ function normalizeServerProps(rawProps) {
6228
7879
  return props;
6229
7880
  }
6230
7881
 
7882
+ function getRouteSlotKey(slot) {
7883
+ return slot.ownerPattern + ':' + slot.name;
7884
+ }
7885
+
7886
+ async function renderRouteSlot(slot, mode = 'render') {
7887
+ const container = document.getElementById(slot.containerId);
7888
+ if (!container || !slot.modulePath) return false;
7889
+ if (mode === 'intercept' && !slot.isClientComponent && !slot.shouldHydrate) {
7890
+ return false;
7891
+ }
7892
+
7893
+ let slotModule = pageModuleCache.get(slot.modulePath);
7894
+ if (!slotModule) {
7895
+ slotModule = await import(/* @vite-ignore */ slot.modulePath);
7896
+ pageModuleCache.set(slot.modulePath, slotModule);
7897
+ }
7898
+ const SlotComponent = slotModule?.default;
7899
+ if (!SlotComponent) return false;
7900
+
7901
+ const props = reviveDeferredData(
7902
+ normalizeServerProps(slot.props || {}),
7903
+ window.__FARM_DEFERRED_DATA__ || {},
7904
+ );
7905
+ const element = wrapWithIntegrationProviders(
7906
+ React.createElement(SlotComponent, props),
7907
+ );
7908
+ const key = getRouteSlotKey(slot);
7909
+ const existingRoot = routeSlotRoots.get(key);
7910
+
7911
+ if (mode === 'hydrate') {
7912
+ if (existingRoot) return true;
7913
+ const root = hydrateRoot(container, element);
7914
+ routeSlotRoots.set(key, root);
7915
+ } else {
7916
+ if (existingRoot) {
7917
+ try { existingRoot.unmount(); } catch (error) {}
7918
+ }
7919
+ const root = createRoot(container);
7920
+ root.render(element);
7921
+ routeSlotRoots.set(key, root);
7922
+ }
7923
+
7924
+ routeSlotDefinitions.set(key, slot);
7925
+ return true;
7926
+ }
7927
+
7928
+ async function hydrateInitialRouteSlots() {
7929
+ const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
7930
+ ? window.__FARM_ROUTE_SLOTS__
7931
+ : [];
7932
+ let hydrated = false;
7933
+
7934
+ for (const slot of slots) {
7935
+ routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
7936
+ if (!slot.isClientComponent && !slot.shouldHydrate) continue;
7937
+ try {
7938
+ hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
7939
+ } catch (error) {
7940
+ console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
7941
+ }
7942
+ }
7943
+
7944
+ return hydrated;
7945
+ }
7946
+
7947
+ async function renderRouteInterception(pageData) {
7948
+ const slots = Array.isArray(pageData.routeSlots)
7949
+ ? pageData.routeSlots.filter((slot) => slot.interception)
7950
+ : [];
7951
+ if (!pageData.interception || slots.length === 0) return false;
7952
+
7953
+ const previous = new Map();
7954
+ for (const slot of slots) {
7955
+ const key = getRouteSlotKey(slot);
7956
+ previous.set(key, routeSlotDefinitions.get(key) || null);
7957
+ if (!(await renderRouteSlot(slot, 'intercept'))) {
7958
+ return false;
7959
+ }
7960
+ }
7961
+
7962
+ activeRouteInterception = {
7963
+ from: pageData.interception.from,
7964
+ slots,
7965
+ previous,
7966
+ };
7967
+ return true;
7968
+ }
7969
+
7970
+ async function clearRouteInterception(destination) {
7971
+ if (!activeRouteInterception) return false;
7972
+ const active = activeRouteInterception;
7973
+ activeRouteInterception = null;
7974
+
7975
+ for (const slot of active.slots) {
7976
+ const key = getRouteSlotKey(slot);
7977
+ const root = routeSlotRoots.get(key);
7978
+ if (root) {
7979
+ try { root.unmount(); } catch (error) {}
7980
+ routeSlotRoots.delete(key);
7981
+ }
7982
+
7983
+ const previous = active.previous.get(key);
7984
+ if (previous && (previous.isClientComponent || previous.shouldHydrate)) {
7985
+ await renderRouteSlot(previous, 'render');
7986
+ } else {
7987
+ const container = document.getElementById(slot.containerId);
7988
+ if (container) container.replaceChildren();
7989
+ if (previous) routeSlotDefinitions.set(key, previous);
7990
+ else routeSlotDefinitions.delete(key);
7991
+ }
7992
+ }
7993
+
7994
+ if (!active.from) return false;
7995
+ const background = new URL(active.from, window.location.origin);
7996
+ return destination === background.pathname + background.search;
7997
+ }
7998
+
6231
7999
  function applyCanonicalPathFromProps(props) {
6232
8000
  const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
6233
8001
  ? props.__farmCanonicalPath
@@ -6349,6 +8117,7 @@ async function buildRouteComponentProps(pageModule, params, searchParams, path,
6349
8117
  const parsedSearch = parseClientRouteSchema(schemas?.search, searchParams, 'search');
6350
8118
 
6351
8119
  return {
8120
+ ...(existingProps || {}),
6352
8121
  params: parsedParams,
6353
8122
  search: parsedSearch,
6354
8123
  searchParams: schemas ? Promise.resolve(parsedSearch) : parsedSearch,
@@ -6462,6 +8231,17 @@ async function tryHydrateImportedPage(
6462
8231
  async function renderPage(pageData) {
6463
8232
  const container = document.getElementById('root');
6464
8233
  if (!container) return;
8234
+ const destination = window.location.pathname + window.location.search;
8235
+
8236
+ if (pageData.interception) {
8237
+ if (await renderRouteInterception(pageData)) return;
8238
+ window.location.assign(destination);
8239
+ return;
8240
+ }
8241
+
8242
+ if (await clearRouteInterception(destination)) {
8243
+ return;
8244
+ }
6465
8245
 
6466
8246
  const route = {
6467
8247
  modulePath: pageData.modulePath,
@@ -6690,7 +8470,9 @@ async function hydrate() {
6690
8470
  window.__FARM_SHOULD_HYDRATE__ === true ||
6691
8471
  isClientComponent ||
6692
8472
  await moduleLooksClient(modulePath);
8473
+ const hydratedSlots = await hydrateInitialRouteSlots();
6693
8474
  if (!shouldHydrate) {
8475
+ if (hydratedSlots) replayPreHydrationClicks();
6694
8476
  console.log('[Farm.js] Server component - SPA router ready')
6695
8477
  return
6696
8478
  }
@@ -6852,7 +8634,7 @@ function generateClientManifest(bundle) {
6852
8634
  __name(generateClientManifest, "generateClientManifest");
6853
8635
  async function defineConfig(config = {}) {
6854
8636
  const tailwindcss = (await import("@tailwindcss/vite")).default;
6855
- const appRoot = path9.resolve(config.root || process.cwd());
8637
+ const appRoot = path10.resolve(config.root || process.cwd());
6856
8638
  if (config.extends?.length) {
6857
8639
  const { config: layeredConfig } = await import("./layers-VWVDTPUZ.mjs").then(
6858
8640
  ({ resolveFarmLayers }) => resolveFarmLayers(config, {
@@ -6955,7 +8737,7 @@ async function defineConfig(config = {}) {
6955
8737
  const isExposed = hostConfig === true || hostConfig === "0.0.0.0";
6956
8738
  console.log("");
6957
8739
  console.log(
6958
- ` ${pc.bold(pc.green("Farm.js"))} ${pc.dim("v1.0.0")} ${pc.dim(`ready in ${elapsed}ms`)}`
8740
+ ` ${pc.bold(pc.green("Farm.js"))} ${pc.dim(`v${FARM_VERSION}`)} ${pc.dim(`ready in ${elapsed}ms`)}`
6959
8741
  );
6960
8742
  console.log("");
6961
8743
  console.log(
@@ -7038,7 +8820,7 @@ async function defineConfig(config = {}) {
7038
8820
  // Stub out problematic server-only modules during dev mode
7039
8821
  alias: {
7040
8822
  ...getFarmLayerAliases(config.layers),
7041
- "@": path9.resolve(appRoot, "src"),
8823
+ "@": path10.resolve(appRoot, "src"),
7042
8824
  // Nitro internals that should not be resolved in browser
7043
8825
  "supports-color": "data:text/javascript,export default false; export const supportsColor = false; export const stdout = false; export const stderr = false;",
7044
8826
  "@poppinss/dumper": "data:text/javascript,export default {};",
@@ -7070,6 +8852,8 @@ export {
7070
8852
  matchSSGPage,
7071
8853
  getClientModuleMetadata,
7072
8854
  RouteManager,
8855
+ farmFontImportsPlugin,
8856
+ mergeFarmFontCss,
7073
8857
  ServerRenderer,
7074
8858
  FarmApp,
7075
8859
  createFarmApp,
@@ -7085,4 +8869,4 @@ export {
7085
8869
  farmPlugin,
7086
8870
  defineConfig
7087
8871
  };
7088
- //# sourceMappingURL=chunk-CHFHNEMO.mjs.map
8872
+ //# sourceMappingURL=chunk-77BOAQHI.mjs.map