@farm.js/core 0.1.51-beta.2 → 0.1.60

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 (321) hide show
  1. package/dist/{agent-mcp-handler-WWCC4GLG.mjs → agent-mcp-handler-7QMX2LUY.mjs} +7 -7
  2. package/dist/agent-mcp-handler-OV4WRFBL.cjs +18 -0
  3. package/dist/{agent-mcp.d-Z5DuwrqW.d.mts → agent-mcp.d-C-2S9bnP.d.mts} +1 -1
  4. package/dist/{agent-mcp.d-CR5Ov83o.d.ts → agent-mcp.d-SIoCUP1I.d.ts} +1 -1
  5. package/dist/agent-runtime.cjs +5 -5
  6. package/dist/agent-runtime.d.mts +2 -2
  7. package/dist/agent-runtime.d.ts +2 -2
  8. package/dist/agent-runtime.mjs +4 -4
  9. package/dist/{analyzer-Z6TNEAET.mjs → analyzer-22BEYV7S.mjs} +126 -12
  10. package/dist/{analyzer-T76CN3S7.cjs → analyzer-LCSI3NSH.cjs} +132 -18
  11. package/dist/api/client.cjs +5 -4
  12. package/dist/api/client.d.mts +1 -1
  13. package/dist/api/client.d.ts +1 -1
  14. package/dist/api/client.mjs +3 -2
  15. package/dist/api/client.native.cjs +45 -0
  16. package/dist/api/client.native.d.mts +23 -0
  17. package/dist/api/client.native.d.ts +23 -0
  18. package/dist/api/client.native.mjs +45 -0
  19. package/dist/api/route-manager.cjs +7 -7
  20. package/dist/api/route-manager.d.mts +4 -4
  21. package/dist/api/route-manager.d.ts +4 -4
  22. package/dist/api/route-manager.mjs +6 -6
  23. package/dist/api/runtime.cjs +5 -5
  24. package/dist/api/runtime.d.mts +3 -3
  25. package/dist/api/runtime.d.ts +3 -3
  26. package/dist/api/runtime.mjs +4 -4
  27. package/dist/{api-client.d-CeA6tNA6.d.mts → api-client.d-BNLXNCXJ.d.mts} +1 -1
  28. package/dist/{api-client.d-BWcqZciH.d.ts → api-client.d-ddQBNGtu.d.ts} +1 -1
  29. package/dist/api.cjs +11 -11
  30. package/dist/api.d.mts +5 -5
  31. package/dist/api.d.ts +5 -5
  32. package/dist/api.mjs +10 -10
  33. package/dist/{app-manifest.d-CAHkOBFa.d.mts → app-manifest.d-DrSAHskY.d.mts} +1 -1
  34. package/dist/{app-manifest.d-DiWr_Jfx.d.ts → app-manifest.d-Tb3CJpL4.d.ts} +1 -1
  35. package/dist/app-markdown.cjs +7 -7
  36. package/dist/app-markdown.d.mts +3 -3
  37. package/dist/app-markdown.d.ts +3 -3
  38. package/dist/app-markdown.mjs +6 -6
  39. package/dist/{app.d-DmapqkbV.d.ts → app.d-CmWlYpZJ.d.ts} +9 -4
  40. package/dist/{app.d-BfgJCsTQ.d.mts → app.d-D6QQM_kk.d.mts} +9 -4
  41. package/dist/{chunk-SN5VSO3Q.mjs → chunk-25T5VXOE.mjs} +7 -9
  42. package/dist/{chunk-GUJTVM36.cjs → chunk-2FRLSDBT.cjs} +1 -1
  43. package/dist/{chunk-LM2YOGDK.mjs → chunk-2I6PUKWJ.mjs} +1 -1
  44. package/dist/{chunk-EIMK7D2D.mjs → chunk-2KTYMMWT.mjs} +34 -4
  45. package/dist/{chunk-B5BBTPJQ.cjs → chunk-2OF5RPVU.cjs} +14 -14
  46. package/dist/chunk-37PYUEK5.mjs +533 -0
  47. package/dist/chunk-3HLQTOVU.cjs +6 -0
  48. package/dist/{chunk-VSLM6BHX.cjs → chunk-3OJNNCDL.cjs} +9 -9
  49. package/dist/{chunk-X3JNB2TB.mjs → chunk-3PX4AIXO.mjs} +36 -5
  50. package/dist/{chunk-UQHIWZZ6.cjs → chunk-3TL3AH25.cjs} +12 -6
  51. package/dist/chunk-3YMLUNL2.cjs +251 -0
  52. package/dist/chunk-4JTQPOKO.cjs +137 -0
  53. package/dist/{chunk-QXPSWMUD.cjs → chunk-4P23B7DU.cjs} +5 -5
  54. package/dist/{chunk-YVJV7Q2X.mjs → chunk-55U5QIXQ.mjs} +1 -1
  55. package/dist/{chunk-5N7QAGEA.cjs → chunk-5JNUYGNF.cjs} +37 -7
  56. package/dist/{chunk-NJLTQR5P.cjs → chunk-6BJJYOFL.cjs} +7 -7
  57. package/dist/chunk-6UUH4N4J.mjs +251 -0
  58. package/dist/{chunk-2NHOYYUT.mjs → chunk-7H45IJWO.mjs} +2 -2
  59. package/dist/{chunk-NN3MOPSI.mjs → chunk-A2MN5PQJ.mjs} +7 -7
  60. package/dist/{chunk-KY32FWK7.mjs → chunk-BHJAYPYU.mjs} +2 -2
  61. package/dist/{chunk-VAHBCI6X.mjs → chunk-BQWBHWEW.mjs} +26 -1
  62. package/dist/{chunk-KJMWAUKE.mjs → chunk-C7GJDVN4.mjs} +1 -1
  63. package/dist/{chunk-OYNNA4DD.cjs → chunk-CBKRS3M4.cjs} +9 -9
  64. package/dist/{chunk-I2DQGS56.cjs → chunk-CBOEJ5Z4.cjs} +39 -41
  65. package/dist/{chunk-BOVGCUDZ.cjs → chunk-CI4UNQHO.cjs} +2 -2
  66. package/dist/{chunk-S5AQ7CAC.cjs → chunk-CNNBFGL5.cjs} +39 -14
  67. package/dist/chunk-D2X5MUF5.cjs +1457 -0
  68. package/dist/{chunk-LEIXUFJN.cjs → chunk-D4MRNBVF.cjs} +10 -9
  69. package/dist/{chunk-2KVDHNQS.mjs → chunk-D7LTCK3U.mjs} +2 -2
  70. package/dist/{chunk-J3LBO2O4.cjs → chunk-DPJ66FSI.cjs} +22 -22
  71. package/dist/{chunk-NYQSC4DX.cjs → chunk-DZPR2W6U.cjs} +5 -5
  72. package/dist/{chunk-GW4YUIHW.mjs → chunk-E72UD6ME.mjs} +1 -1
  73. package/dist/chunk-EFZGB7JC.cjs +114 -0
  74. package/dist/{chunk-XXXRRVY6.mjs → chunk-EGVC4LIG.mjs} +5 -5
  75. package/dist/{chunk-72NBDVWQ.mjs → chunk-EXUONJYV.mjs} +3 -3
  76. package/dist/{chunk-VS7EHLLW.mjs → chunk-EZ34EHQP.mjs} +1 -1
  77. package/dist/{chunk-FM2UEKS2.mjs → chunk-F6Y7ZAPQ.mjs} +2 -2
  78. package/dist/{chunk-LMFJCXDD.mjs → chunk-FN5UEC7I.mjs} +1 -1
  79. package/dist/{chunk-E6LTONL4.mjs → chunk-FORSVMEJ.mjs} +2 -2
  80. package/dist/{chunk-6CYQQQGR.mjs → chunk-HPWB57PZ.mjs} +1 -1
  81. package/dist/{chunk-Y2G5SJFB.mjs → chunk-IFHPDLIS.mjs} +1 -1
  82. package/dist/{chunk-GNJIYJMS.cjs → chunk-IFXSBJPN.cjs} +16 -16
  83. package/dist/{chunk-74Z5KX4A.mjs → chunk-ILMTRGBG.mjs} +309 -56
  84. package/dist/{chunk-NXBHYO7S.cjs → chunk-JBK7UJOI.cjs} +14 -11
  85. package/dist/chunk-JI5D7MXY.mjs +137 -0
  86. package/dist/{chunk-QXJADAQB.cjs → chunk-JIBEFLQ7.cjs} +6 -2
  87. package/dist/{chunk-LZ4SB57H.mjs → chunk-JPIUGDK4.mjs} +1 -1
  88. package/dist/{chunk-Y3N5BFRJ.mjs → chunk-JSDV2NUN.mjs} +1 -1
  89. package/dist/{chunk-IRSS4HS4.mjs → chunk-K3RU5MOR.mjs} +1 -1
  90. package/dist/chunk-KPOMS5RO.cjs +237 -0
  91. package/dist/{chunk-LAZK6UV7.mjs → chunk-KVW2M6PI.mjs} +1 -1
  92. package/dist/{chunk-5IONBVJY.cjs → chunk-LB3DPQP6.cjs} +22 -22
  93. package/dist/{chunk-CZ35L6PL.mjs → chunk-LJVNMGE3.mjs} +10 -4
  94. package/dist/chunk-LLZSYFOM.mjs +6 -0
  95. package/dist/{chunk-X2AMN2WV.cjs → chunk-LQNW3ABP.cjs} +10 -10
  96. package/dist/{chunk-6ONBZGVH.cjs → chunk-LRB5OVRT.cjs} +3 -3
  97. package/dist/{chunk-WJFFPXCV.cjs → chunk-LT4VAF5Z.cjs} +12 -10
  98. package/dist/{chunk-F6TLUMH7.mjs → chunk-M53MIIXY.mjs} +1 -1
  99. package/dist/{chunk-HIFIG6HL.cjs → chunk-MEQN6DDA.cjs} +5 -5
  100. package/dist/{chunk-XLRLSTJ6.cjs → chunk-MGKW5XZE.cjs} +7 -7
  101. package/dist/{chunk-B3GZAQSC.cjs → chunk-MHLNWRCJ.cjs} +3 -3
  102. package/dist/{chunk-5ENW27SL.mjs → chunk-MMK4MZUN.mjs} +1 -1
  103. package/dist/{chunk-DTU4PX7V.cjs → chunk-MTWXOEI4.cjs} +927 -629
  104. package/dist/chunk-NHD7BAKD.mjs +1457 -0
  105. package/dist/{chunk-NPQLMP7M.cjs → chunk-NQJDO7K7.cjs} +32 -31
  106. package/dist/{chunk-76GHW3WI.cjs → chunk-O27PLNQZ.cjs} +10 -10
  107. package/dist/{chunk-PIHKO25G.mjs → chunk-OM7WILES.mjs} +1 -1
  108. package/dist/{chunk-7UPCJDB5.mjs → chunk-PCXIJKPM.mjs} +8 -8
  109. package/dist/{chunk-IWFV5ZED.cjs → chunk-PMJSG4JS.cjs} +1 -1
  110. package/dist/{chunk-JATTVAHA.cjs → chunk-PRFNLQSP.cjs} +4 -4
  111. package/dist/{chunk-SBABQKPT.cjs → chunk-QAS7KE7J.cjs} +7 -7
  112. package/dist/chunk-QGOZLGVP.mjs +0 -0
  113. package/dist/{chunk-VQJYGZNX.cjs → chunk-QMNWKQL4.cjs} +1 -1
  114. package/dist/{chunk-XB24LZWI.cjs → chunk-QRX4JRBO.cjs} +3 -3
  115. package/dist/{chunk-LNM57D3H.cjs → chunk-R53QDV6T.cjs} +4 -4
  116. package/dist/{chunk-SUV6YO4Q.cjs → chunk-RAWWCDCT.cjs} +5 -5
  117. package/dist/{chunk-LJDIFIJ2.mjs → chunk-RPUJHJHE.mjs} +4 -4
  118. package/dist/{chunk-G2KTRMWA.mjs → chunk-RSEAX5MW.mjs} +4 -0
  119. package/dist/chunk-SJRCWF4Z.mjs +237 -0
  120. package/dist/{chunk-IBSAYAWB.mjs → chunk-SX7EECTS.mjs} +8 -5
  121. package/dist/{chunk-KBRZAYI7.mjs → chunk-T4TBK5NY.mjs} +2 -2
  122. package/dist/{chunk-4SSRBCBR.mjs → chunk-T7I62A4C.mjs} +619 -321
  123. package/dist/{chunk-E36C43IX.cjs → chunk-U4BJKNIR.cjs} +6 -6
  124. package/dist/{chunk-YU42A5MA.cjs → chunk-UDJY2ZGY.cjs} +533 -280
  125. package/dist/{chunk-SHS6KXOZ.mjs → chunk-UR25Z5Z6.mjs} +1 -1
  126. package/dist/{chunk-WZW6LEHM.cjs → chunk-UYSTTPYJ.cjs} +1590 -1019
  127. package/dist/{chunk-KRRZJ77U.mjs → chunk-UZZ6IEQP.mjs} +3 -3
  128. package/dist/{chunk-EKJYE4Y7.cjs → chunk-VGG74PSU.cjs} +25 -25
  129. package/dist/{chunk-CTM4SPB3.mjs → chunk-VPTWKOCY.mjs} +20 -19
  130. package/dist/{chunk-UN6N623E.mjs → chunk-VQJHT2ND.mjs} +2 -2
  131. package/dist/{chunk-SJ23LJ3N.cjs → chunk-VVTJTMGQ.cjs} +3 -3
  132. package/dist/{chunk-KHXAJ2KA.cjs → chunk-W2RZ73IU.cjs} +12 -12
  133. package/dist/{chunk-JWI5PUO2.mjs → chunk-W2ZXMMHA.mjs} +2 -1
  134. package/dist/{chunk-BLD5GVCG.mjs → chunk-W6QLRQ3V.mjs} +1 -1
  135. package/dist/{chunk-AV26KHTG.mjs → chunk-X2CZTWQA.mjs} +2 -2
  136. package/dist/chunk-XPIPMWY3.cjs +1 -0
  137. package/dist/chunk-XTG73QZA.cjs +533 -0
  138. package/dist/{chunk-XPMC4E2G.cjs → chunk-XVSBALOY.cjs} +3 -3
  139. package/dist/{chunk-XYL4HSVC.cjs → chunk-YI6FKTTN.cjs} +38 -7
  140. package/dist/{chunk-N77JBPLC.mjs → chunk-YSXTNSXS.mjs} +10 -8
  141. package/dist/{chunk-EHB77D5U.cjs → chunk-ZDAEHG2O.cjs} +3 -3
  142. package/dist/{chunk-PMKUU273.mjs → chunk-ZFUKPWFC.mjs} +1226 -655
  143. package/dist/{chunk-E73PGHSR.mjs → chunk-ZMHAFH4R.mjs} +8 -8
  144. package/dist/{chunk-ZOWNWHK6.cjs → chunk-ZNH6NR3H.cjs} +2 -2
  145. package/dist/chunk-ZNXTU4YH.mjs +114 -0
  146. package/dist/{chunk-PFV2KPDZ.cjs → chunk-ZOYKJBP5.cjs} +3 -3
  147. package/dist/{chunk-CECUDGXQ.cjs → chunk-ZP32GNJQ.cjs} +13 -13
  148. package/dist/{chunk-72D2NX77.mjs → chunk-ZZ2QKCKW.mjs} +1 -1
  149. package/dist/{client-plugins.d-Bx3FXpqm.d.mts → client-plugins.d-CgQQ-EAv.d.mts} +25 -4
  150. package/dist/{client-plugins.d-TiLbS5j4.d.ts → client-plugins.d-vXrbcfJ1.d.ts} +25 -4
  151. package/dist/client-plugins.d.mts +2 -2
  152. package/dist/client-plugins.d.ts +2 -2
  153. package/dist/client.cjs +9 -9
  154. package/dist/client.d.mts +9 -9
  155. package/dist/client.d.ts +9 -9
  156. package/dist/client.mjs +9 -9
  157. package/dist/{config.d-iRPI16ku.d.mts → config.d-DqZkLwef.d.mts} +146 -1
  158. package/dist/{config.d-iRPI16ku.d.ts → config.d-DqZkLwef.d.ts} +146 -1
  159. package/dist/config.d.mts +2 -2
  160. package/dist/config.d.ts +2 -2
  161. package/dist/cron.cjs +3 -3
  162. package/dist/cron.d.mts +10 -0
  163. package/dist/cron.d.ts +10 -0
  164. package/dist/cron.mjs +2 -2
  165. package/dist/desktop.d.mts +3 -3
  166. package/dist/desktop.d.ts +3 -3
  167. package/dist/{devtools-UQLDAOEI.mjs → devtools-KQZ6SRCJ.mjs} +16 -16
  168. package/dist/{devtools-6XWCZIGO.cjs → devtools-UF6JYHUN.cjs} +18 -18
  169. package/dist/docs.cjs +19 -19
  170. package/dist/docs.d.mts +3 -3
  171. package/dist/docs.d.ts +3 -3
  172. package/dist/docs.mjs +18 -18
  173. package/dist/index.cjs +99 -95
  174. package/dist/{index.d-yueUNipJ.d.ts → index.d-DlCELfhf.d.ts} +1 -1
  175. package/dist/{index.d-YxJ2AiDF.d.mts → index.d-Dmfb7Kb_.d.mts} +1 -1
  176. package/dist/index.d.mts +18 -18
  177. package/dist/index.d.ts +18 -18
  178. package/dist/index.mjs +139 -135
  179. package/dist/integrations.cjs +5 -5
  180. package/dist/integrations.d.mts +2 -2
  181. package/dist/integrations.d.ts +2 -2
  182. package/dist/integrations.mjs +4 -4
  183. package/dist/internal/app-markdown-runtime.cjs +6 -6
  184. package/dist/internal/app-markdown-runtime.d.mts +3 -3
  185. package/dist/internal/app-markdown-runtime.d.ts +3 -3
  186. package/dist/internal/app-markdown-runtime.mjs +5 -5
  187. package/dist/internal/build-runtime.cjs +52 -50
  188. package/dist/internal/build-runtime.d.mts +4 -4
  189. package/dist/internal/build-runtime.d.ts +4 -4
  190. package/dist/internal/build-runtime.mjs +51 -49
  191. package/dist/internal/cli-runtime.cjs +28 -28
  192. package/dist/internal/cli-runtime.mjs +28 -28
  193. package/dist/internal/client-error-overlay.cjs +4 -4
  194. package/dist/internal/client-error-overlay.mjs +1 -1
  195. package/dist/internal/client-runtime.cjs +20 -15
  196. package/dist/internal/client-runtime.d.mts +5 -5
  197. package/dist/internal/client-runtime.d.ts +5 -5
  198. package/dist/internal/client-runtime.mjs +8 -3
  199. package/dist/internal/compression-runtime.d.mts +2 -2
  200. package/dist/internal/compression-runtime.d.ts +2 -2
  201. package/dist/internal/config-runtime.cjs +18 -18
  202. package/dist/internal/config-runtime.d.mts +119 -7
  203. package/dist/internal/config-runtime.d.ts +119 -7
  204. package/dist/internal/config-runtime.mjs +17 -17
  205. package/dist/internal/infra-analytics-runtime.cjs +11 -11
  206. package/dist/internal/infra-analytics-runtime.mjs +9 -9
  207. package/dist/internal/islands-boot.cjs +211 -0
  208. package/dist/internal/islands-boot.d.mts +8 -0
  209. package/dist/internal/islands-boot.d.ts +8 -0
  210. package/dist/internal/islands-boot.mjs +211 -0
  211. package/dist/internal/product-telemetry-runtime.cjs +2 -2
  212. package/dist/internal/product-telemetry-runtime.mjs +1 -1
  213. package/dist/internal/production-runtime.cjs +42 -28
  214. package/dist/internal/production-runtime.d.mts +50 -12
  215. package/dist/internal/production-runtime.d.ts +50 -12
  216. package/dist/internal/production-runtime.mjs +52 -38
  217. package/dist/markdown.cjs +7 -5
  218. package/dist/markdown.d.mts +2 -2
  219. package/dist/markdown.d.ts +2 -2
  220. package/dist/markdown.mjs +6 -4
  221. package/dist/middleware.cjs +10 -10
  222. package/dist/middleware.d.mts +4 -4
  223. package/dist/middleware.d.ts +4 -4
  224. package/dist/middleware.mjs +9 -9
  225. package/dist/mobile.d.mts +43 -5
  226. package/dist/mobile.d.ts +43 -5
  227. package/dist/modules-VHD7BELU.mjs +13 -0
  228. package/dist/modules-WT5D3AWY.cjs +13 -0
  229. package/dist/native-specs-BD7HOTMJ.mjs +15 -0
  230. package/dist/native-specs-IQQRJOOW.cjs +15 -0
  231. package/dist/native-tree-6G5O53O3.cjs +27 -0
  232. package/dist/native-tree-VWNW2MQ2.mjs +27 -0
  233. package/dist/native.cjs +87 -0
  234. package/dist/native.d.mts +72 -0
  235. package/dist/native.d.ts +72 -0
  236. package/dist/native.mjs +87 -0
  237. package/dist/{navigation-delegate.d-HnDXhlyP.d.mts → navigation-delegate.d-CnOTWOyi.d.mts} +1 -1
  238. package/dist/{navigation-delegate.d-BY1e_Xrh.d.ts → navigation-delegate.d-JXx40JzR.d.ts} +1 -1
  239. package/dist/navigation.cjs +5 -5
  240. package/dist/navigation.d.mts +5 -5
  241. package/dist/navigation.d.ts +5 -5
  242. package/dist/navigation.mjs +4 -4
  243. package/dist/{nitro-R444AF3O.mjs → nitro-FLN6DRGJ.mjs} +7 -7
  244. package/dist/{nitro-CK7M4RMY.cjs → nitro-HXAZZQKY.cjs} +12 -12
  245. package/dist/plugin.cjs +43 -42
  246. package/dist/plugin.d.mts +5 -4
  247. package/dist/plugin.d.ts +5 -4
  248. package/dist/plugin.mjs +42 -41
  249. package/dist/port-C6GBH4C6.cjs +419 -0
  250. package/dist/port-WOOQ3V56.mjs +419 -0
  251. package/dist/{production-runtime.d-BpJUDzP8.d.mts → production-runtime.d-CP5s6RuY.d.mts} +1 -1
  252. package/dist/{production-runtime.d-lMjvE9cf.d.ts → production-runtime.d-N-cE3pmy.d.ts} +1 -1
  253. package/dist/{programmatic-routes-client.d-BlFp5hv4.d.ts → programmatic-routes-client.d-CLG2N1yH.d.ts} +2 -2
  254. package/dist/{programmatic-routes-client.d-6CGQ3TCk.d.mts → programmatic-routes-client.d-CPbNqtIi.d.mts} +2 -2
  255. package/dist/query/client.cjs +6 -6
  256. package/dist/query/client.mjs +2 -2
  257. package/dist/{render-plan.d-DhP0mTHF.d.ts → render-plan.d-B9lAP3uX.d.ts} +1 -1
  258. package/dist/{render-plan.d-BH9edqKs.d.mts → render-plan.d-DZ-qjjdG.d.mts} +1 -1
  259. package/dist/renderer/react/server.cjs +2 -2
  260. package/dist/renderer/react/server.mjs +3 -3
  261. package/dist/renderer-client.cjs +6 -6
  262. package/dist/renderer-client.d.mts +5 -5
  263. package/dist/renderer-client.d.ts +5 -5
  264. package/dist/renderer-client.mjs +2 -2
  265. package/dist/{request.d-BVZrsR1v.d.ts → request.d-BiicaNxb.d.ts} +1 -1
  266. package/dist/{request.d-DJFRdKi8.d.mts → request.d-DV0oeUit.d.mts} +1 -1
  267. package/dist/request.d.mts +3 -3
  268. package/dist/request.d.ts +3 -3
  269. package/dist/{route-rendering.d-Bpmw7PED.d.mts → route-rendering.d-BrIKA51A.d.mts} +1 -1
  270. package/dist/{route-rendering.d-B00JtK_-.d.ts → route-rendering.d-Iss0C7GR.d.ts} +1 -1
  271. package/dist/{router.d-Bd1x9XxQ.d.ts → router.d-DjGn_al7.d.ts} +1 -1
  272. package/dist/{router.d-e0jQ3jQ-.d.mts → router.d-mNTbOGV_.d.mts} +1 -1
  273. package/dist/{routes.d-D96Dq9lz.d.ts → routes.d-BKSjHuH9.d.ts} +27 -4
  274. package/dist/{routes.d-Cmv8TgVq.d.mts → routes.d-qd8Qf4LG.d.mts} +27 -4
  275. package/dist/routes.d.mts +2 -2
  276. package/dist/routes.d.ts +2 -2
  277. package/dist/{rsc-pipeline-DX4OC5FN.cjs → rsc-pipeline-SVLBTY7H.cjs} +21 -21
  278. package/dist/{rsc-pipeline-ZQ4CTVEG.mjs → rsc-pipeline-WBLBDQXA.mjs} +20 -20
  279. package/dist/{runtime-NQ3EDSA7.cjs → runtime-DGUOWSMF.cjs} +307 -48
  280. package/dist/{runtime-NPDRDV6R.mjs → runtime-HFZTVNFF.mjs} +298 -39
  281. package/dist/{runtime.d-CgB3IJDq.d.mts → runtime.d-BNVbojF1.d.mts} +1 -1
  282. package/dist/{runtime.d-D-td-RR3.d.ts → runtime.d-Bm_4hP5T.d.ts} +1 -1
  283. package/dist/{schema-dev-notice-F6QYSOAI.mjs → schema-dev-notice-JMXEQWIQ.mjs} +3 -3
  284. package/dist/{schema-dev-notice-UU7DMZEU.cjs → schema-dev-notice-PLBFDTOF.cjs} +6 -6
  285. package/dist/server-fn-client.d.mts +1 -1
  286. package/dist/server-fn-client.d.ts +1 -1
  287. package/dist/server-plugins.cjs +1 -1
  288. package/dist/server-plugins.d.mts +3 -3
  289. package/dist/server-plugins.d.ts +3 -3
  290. package/dist/server-plugins.mjs +1 -1
  291. package/dist/server.cjs +82 -81
  292. package/dist/server.d.mts +12 -11
  293. package/dist/server.d.ts +12 -11
  294. package/dist/server.mjs +65 -64
  295. package/dist/session-2Q72D4QV.cjs +23 -0
  296. package/dist/{session-IGEDQ5PY.mjs → session-QZXZOPR2.mjs} +2 -2
  297. package/dist/shell-render.d-CG6bPiiA.d.mts +41 -0
  298. package/dist/shell-render.d-CG6bPiiA.d.ts +41 -0
  299. package/dist/{spa-router.d-CO01mVOM.d.ts → spa-router.d-DAtnNoBe.d.ts} +11 -2
  300. package/dist/{spa-router.d-BWDhS0FK.d.mts → spa-router.d-DHDoXxDE.d.mts} +11 -2
  301. package/dist/testing.cjs +7 -7
  302. package/dist/testing.d.mts +2 -2
  303. package/dist/testing.d.ts +2 -2
  304. package/dist/testing.mjs +6 -6
  305. package/dist/{utils.d-B77__yh8.d.ts → utils.d-DwZ-KLSB.d.ts} +7 -1
  306. package/dist/{utils.d-DRDazhCA.d.mts → utils.d-uKZcKJk4.d.mts} +7 -1
  307. package/dist/version.cjs +2 -2
  308. package/dist/version.mjs +1 -1
  309. package/dist/vite.cjs +43 -42
  310. package/dist/vite.d.mts +17 -6
  311. package/dist/vite.d.ts +17 -6
  312. package/dist/vite.mjs +42 -41
  313. package/dist/workflows.cjs +3 -3
  314. package/dist/workflows.mjs +2 -2
  315. package/package.json +17 -3
  316. package/dist/agent-mcp-handler-RT3COCEL.cjs +0 -18
  317. package/dist/session-AAU7RNRO.cjs +0 -23
  318. package/dist/{chunk-7FVVQEVL.cjs → chunk-4BS3HSY7.cjs} +2 -2
  319. package/dist/{chunk-N7JQXQAV.cjs → chunk-5OJVKXFV.cjs} +2 -2
  320. package/dist/{chunk-WSDKXV4E.mjs → chunk-72KABRWN.mjs} +4 -4
  321. package/dist/{chunk-C3BOESDW.mjs → chunk-B4CWYGCG.mjs} +3 -3
@@ -1,3 +1,12 @@
1
+ import {
2
+ FARM_MOBILE_CLIENT_ENTRY_NAME,
3
+ FARM_MOBILE_SHELL_CLIENT_PLACEHOLDER,
4
+ createFarmMobileClientManifestPlugin,
5
+ encodeFarmMobileShellClient,
6
+ finalizeFarmMobileClient,
7
+ hasFarmMobileClientEntry,
8
+ removeFarmMobileClientManifest
9
+ } from "./chunk-ZNXTU4YH.mjs";
1
10
  import {
2
11
  loadFarmProductionVite
3
12
  } from "./chunk-PSUYE5HR.mjs";
@@ -15,14 +24,14 @@ import {
15
24
  } from "./chunk-KQH2COEJ.mjs";
16
25
  import {
17
26
  FARM_MOBILE_SESSION_PLUGIN
18
- } from "./chunk-C3BOESDW.mjs";
27
+ } from "./chunk-B4CWYGCG.mjs";
19
28
  import {
20
29
  assertFarmDocsAdapterServesNoGuardedPages,
21
30
  compileFarmDocsAdapterEdgeManifest,
22
31
  createFarmDocsAPIHandler,
23
32
  hasFarmDocsRuntimeAdapter,
24
33
  listFarmDocsAdapterPages
25
- } from "./chunk-FM2UEKS2.mjs";
34
+ } from "./chunk-F6Y7ZAPQ.mjs";
26
35
  import {
27
36
  FARM_DOCS_LAST_MODIFIED_MANIFEST,
28
37
  createFarmDocsHandler,
@@ -34,7 +43,7 @@ import {
34
43
  loadFarmDocsPage,
35
44
  resolveFarmDocsContentDir,
36
45
  toFarmDocsMarkdownPage
37
- } from "./chunk-EIMK7D2D.mjs";
46
+ } from "./chunk-2KTYMMWT.mjs";
38
47
  import {
39
48
  generateFarmDocsSearchClientRuntime,
40
49
  isFarmDocsSearchEnabled,
@@ -42,13 +51,7 @@ import {
42
51
  } from "./chunk-ALEUMLJN.mjs";
43
52
  import {
44
53
  FARM_PRERENDER_ENV
45
- } from "./chunk-E6LTONL4.mjs";
46
- import {
47
- resolveFarmInstrumentationFile
48
- } from "./chunk-N35YPV4N.mjs";
49
- import {
50
- resolveFarmInstrumentationRuntime
51
- } from "./chunk-WNDAISB7.mjs";
54
+ } from "./chunk-FORSVMEJ.mjs";
52
55
  import {
53
56
  loadFarmDocsEngine
54
57
  } from "./chunk-VE3FWJBO.mjs";
@@ -57,12 +60,21 @@ import {
57
60
  getDeployTargetForPreset,
58
61
  hasCustomFarmRouteContext,
59
62
  resolveDeployOutputPath
60
- } from "./chunk-CTM4SPB3.mjs";
63
+ } from "./chunk-VPTWKOCY.mjs";
64
+ import {
65
+ resolveFarmInstrumentationFile
66
+ } from "./chunk-N35YPV4N.mjs";
67
+ import {
68
+ resolveFarmInstrumentationRuntime
69
+ } from "./chunk-WNDAISB7.mjs";
61
70
  import {
62
71
  DEFAULT_NOT_FOUND_STYLES,
63
72
  FARM_LAYOUT_ELEMENT_CLIENT_SOURCE,
73
+ FARM_NAVIGATION_STREAM_READER_SOURCE,
64
74
  FARM_SERVER_TREE_LAYOUT_CLIENT_SOURCE,
65
75
  SHARP_INSTALL_HINT,
76
+ canBootFarmIslandsClient,
77
+ collectFarmServerStylesheets,
66
78
  collectFarmWebMCPTools,
67
79
  createFarmApp,
68
80
  createFarmSourceAlias,
@@ -88,11 +100,14 @@ import {
88
100
  resolveFarmImageServerRuntime,
89
101
  resolveFarmIsolatedClientHydrationMode,
90
102
  resolveFarmNotFoundComponentPath,
91
- usesFarmServerTree
92
- } from "./chunk-PMKUU273.mjs";
103
+ resolveFarmRouteRootStrategy,
104
+ usePackageClientBoundaryCacheFile,
105
+ usesFarmServerTree,
106
+ withPackageClientBoundaryCache
107
+ } from "./chunk-ZFUKPWFC.mjs";
93
108
  import {
94
109
  loadTailwindVitePlugin
95
- } from "./chunk-PIHKO25G.mjs";
110
+ } from "./chunk-OM7WILES.mjs";
96
111
  import {
97
112
  PluginManager
98
113
  } from "./chunk-GHNW564E.mjs";
@@ -100,7 +115,7 @@ import {
100
115
  generateFarmTypeArtifacts,
101
116
  readRouteRenderingDirectiveFromFile,
102
117
  resolveRouteRenderingConfigFromFile
103
- } from "./chunk-CZ35L6PL.mjs";
118
+ } from "./chunk-LJVNMGE3.mjs";
104
119
  import {
105
120
  HOISTED_HEAD_ELEMENT,
106
121
  appMiddlewareMayHandlePath,
@@ -113,7 +128,10 @@ import {
113
128
  layoutsCanCoverSamePage,
114
129
  routeBoundaryCoversDirectory,
115
130
  stripRouteGroups
116
- } from "./chunk-7UPCJDB5.mjs";
131
+ } from "./chunk-PCXIJKPM.mjs";
132
+ import {
133
+ FARM_NATIVE_TREE_CONTENT_TYPE
134
+ } from "./chunk-LLZSYFOM.mjs";
117
135
  import {
118
136
  farmPluginMayAffectRuntimePath
119
137
  } from "./chunk-UUMKLGUU.mjs";
@@ -127,18 +145,15 @@ import {
127
145
  listFarmBuiltInRoutePaths,
128
146
  resolveFarmApiCatalogInput,
129
147
  resolveFarmAppManifestInput
130
- } from "./chunk-E73PGHSR.mjs";
148
+ } from "./chunk-ZMHAFH4R.mjs";
131
149
  import {
132
150
  FARM_DEFAULT_MCP_PATH,
133
151
  createFarmDefaultMCPServer,
134
152
  farmConfigMountsMCP
135
- } from "./chunk-KRRZJ77U.mjs";
153
+ } from "./chunk-UZZ6IEQP.mjs";
136
154
  import {
137
155
  farmEnvironmentFunctionsPlugin
138
156
  } from "./chunk-ZQ5BDNKW.mjs";
139
- import {
140
- isFarmMarkdownPageFile
141
- } from "./chunk-GW4YUIHW.mjs";
142
157
  import {
143
158
  generateFarmDocsAdapterClientRuntime,
144
159
  getFarmDocsAdapterConfigModule
@@ -166,50 +181,53 @@ import {
166
181
  applyFarmCspHashesToHtml,
167
182
  createFarmCspNonce
168
183
  } from "./chunk-22W4FNTG.mjs";
184
+ import {
185
+ getFarmAppDirectories
186
+ } from "./chunk-52Y3C3HG.mjs";
169
187
  import {
170
188
  createBundledEnv
171
189
  } from "./chunk-N33DLJBC.mjs";
172
190
  import {
173
- getFarmAppDirectories
174
- } from "./chunk-52Y3C3HG.mjs";
191
+ isFarmMarkdownPageFile
192
+ } from "./chunk-E72UD6ME.mjs";
175
193
  import {
176
194
  resolveFarmMdxComponentsModulePath,
177
195
  resolveMdxConfig
178
196
  } from "./chunk-UIJOLBUL.mjs";
197
+ import {
198
+ getFarmMarkdownAlternatePath
199
+ } from "./chunk-YSXTNSXS.mjs";
179
200
  import {
180
201
  applyFarmWorkflowVercelCrons,
181
202
  prepareFarmWorkflowsForNitro
182
- } from "./chunk-LZ4SB57H.mjs";
203
+ } from "./chunk-JPIUGDK4.mjs";
183
204
  import {
184
205
  applyFarmCronVercelCrons,
185
206
  createFarmCronCloudflareConfig,
186
207
  mergeScheduledTasks,
187
208
  prepareFarmCronForNitro
188
- } from "./chunk-X3JNB2TB.mjs";
209
+ } from "./chunk-3PX4AIXO.mjs";
189
210
  import {
190
211
  resolveServerActionsConfig
191
212
  } from "./chunk-FSQMN2MQ.mjs";
192
- import {
193
- getFarmMarkdownAlternatePath
194
- } from "./chunk-N77JBPLC.mjs";
195
213
  import {
196
214
  _collectFarmStorageModules
197
215
  } from "./chunk-TJVUTGED.mjs";
198
216
  import {
199
217
  getFarmIntegrationPluginServerRuntime,
200
218
  getIntegrationProviders
201
- } from "./chunk-Y2G5SJFB.mjs";
219
+ } from "./chunk-IFHPDLIS.mjs";
202
220
  import {
203
221
  FARM_INTEGRATION_API_BASE_PATH_KEY
204
- } from "./chunk-F6TLUMH7.mjs";
222
+ } from "./chunk-M53MIIXY.mjs";
205
223
  import {
206
224
  appendMiddlewareDirectory,
207
225
  appendMiddlewareRoutePath,
208
226
  compareMiddlewareRouteLocations
209
- } from "./chunk-5ENW27SL.mjs";
227
+ } from "./chunk-MMK4MZUN.mjs";
210
228
  import {
211
229
  APIRouteManager
212
- } from "./chunk-KY32FWK7.mjs";
230
+ } from "./chunk-BHJAYPYU.mjs";
213
231
  import {
214
232
  readFarmI18nCatalogs
215
233
  } from "./chunk-DU4VHHPJ.mjs";
@@ -229,14 +247,14 @@ import {
229
247
  logger,
230
248
  toPosixPath,
231
249
  toViteModuleId
232
- } from "./chunk-Y3N5BFRJ.mjs";
250
+ } from "./chunk-JSDV2NUN.mjs";
233
251
  import {
234
252
  resolveFarmAPIServerBasePath,
235
253
  resolveFarmAPIServerRoutePath
236
- } from "./chunk-LM2YOGDK.mjs";
254
+ } from "./chunk-2I6PUKWJ.mjs";
237
255
  import {
238
256
  FARM_VERSION
239
- } from "./chunk-6CYQQQGR.mjs";
257
+ } from "./chunk-HPWB57PZ.mjs";
240
258
  import {
241
259
  getFarmPresetRuntime
242
260
  } from "./chunk-UAQD67HM.mjs";
@@ -258,6 +276,7 @@ import { randomBytes } from "crypto";
258
276
  import path from "path";
259
277
  var FARM_CLIENT_CSS_HREF_PLACEHOLDER = "/__farm_client_css_href__";
260
278
  var FARM_CLIENT_JS_SRC_PLACEHOLDER = "/__farm_client_js_src__";
279
+ var FARM_CLIENT_BOOT_SRC_PLACEHOLDER = "/__farm_client_boot_src__";
261
280
  async function hashAndCopy(sourcePath, destinationDir, hashedName) {
262
281
  const fs4 = await import("fs/promises");
263
282
  try {
@@ -290,6 +309,16 @@ async function findFingerprintedClientEntry(clientOutputDir) {
290
309
  return null;
291
310
  }
292
311
  }
312
+ async function resolveClientBootSrc(clientOutputDir) {
313
+ const fs4 = await import("fs/promises");
314
+ try {
315
+ const entries = await fs4.readdir(clientOutputDir);
316
+ const name = entries.find((entry) => /^farm-client-boot-h[0-9a-f]+\.js$/.test(entry));
317
+ return name ? `/${name}` : null;
318
+ } catch {
319
+ return null;
320
+ }
321
+ }
293
322
  async function resolveHashedClientJsSrc(clientOutputDir) {
294
323
  const entryName = await findFingerprintedClientEntry(clientOutputDir);
295
324
  if (!entryName) return "/farm-client.js";
@@ -1155,6 +1184,20 @@ async function readMiddlewareFileConfig(filePath) {
1155
1184
  }
1156
1185
 
1157
1186
  // src/nitro/universal-build.ts
1187
+ var FARM_NATIVE_STYLESHEETS_PLACEHOLDER = "__FARM_NATIVE_STYLESHEETS__";
1188
+ async function readFarmNativeStylesheets(clientOutputDir, clientCssHref) {
1189
+ const fs4 = await import("fs/promises");
1190
+ try {
1191
+ return {
1192
+ [clientCssHref]: await fs4.readFile(
1193
+ path10.join(clientOutputDir, clientCssHref.slice(1)),
1194
+ "utf8"
1195
+ )
1196
+ };
1197
+ } catch {
1198
+ return {};
1199
+ }
1200
+ }
1158
1201
  function preloadFarmNitroBuilder() {
1159
1202
  return import("nitro/builder").then(
1160
1203
  (value) => ({ status: "fulfilled", value }),
@@ -1615,7 +1658,7 @@ function restoreLiteralModuleSpecifiers(code, fileName, { parseSync, Visitor })
1615
1658
  throw new Error(`Failed to minify ${fileName}: ${parsed.errors[0].message}`);
1616
1659
  }
1617
1660
  const replacements = [];
1618
- let needsAst = hasRequireTemplate;
1661
+ let needsAst = hasRequireTemplate && /(?<![\w$])require\(`/.test(code);
1619
1662
  if (!needsAst) {
1620
1663
  const seenStarts = /* @__PURE__ */ new Set();
1621
1664
  for (const { moduleRequest } of parsed.module.dynamicImports) {
@@ -1909,6 +1952,7 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
1909
1952
  }
1910
1953
  const productionVite = productionViteResult.value;
1911
1954
  logger.info("\u26A1 Building application bundles with Vite Rolldown");
1955
+ const mobileClient = shouldBuildFarmMobileClient(config);
1912
1956
  const buildClientBundle = () => buildClient(
1913
1957
  productionVite,
1914
1958
  config,
@@ -1921,7 +1965,8 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
1921
1965
  isolatedClientBoundaryModules,
1922
1966
  hydrationPlanCache,
1923
1967
  rendererBuildLifetime,
1924
- routeManager.getProgrammaticClientRoutes()
1968
+ routeManager.getProgrammaticClientRoutes(),
1969
+ mobileClient
1925
1970
  );
1926
1971
  const buildSSRBundle = () => buildSSRInMemory(
1927
1972
  productionVite,
@@ -1974,7 +2019,8 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
1974
2019
  isolatedClientBoundaryModules,
1975
2020
  hydrationPlanCache,
1976
2021
  rendererBuildLifetime,
1977
- routeManager.getProgrammaticClientRoutes()
2022
+ routeManager.getProgrammaticClientRoutes(),
2023
+ mobileClient
1978
2024
  );
1979
2025
  } catch (retryError) {
1980
2026
  if (!(retryError instanceof IncompleteClientBuildOutputError)) throw retryError;
@@ -2033,6 +2079,20 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
2033
2079
  rendererBuild?.abort();
2034
2080
  }
2035
2081
  }
2082
+ function shouldBuildFarmMobileClient(config) {
2083
+ return Boolean(config.mobileClient) && !config.desktop;
2084
+ }
2085
+ function varyFarmNitroCacheRulesByShell(rules) {
2086
+ return Object.fromEntries(
2087
+ Object.entries(rules).map(([source, rule]) => {
2088
+ const cached = rule?.swr !== void 0 && rule.swr !== false || rule?.cache !== void 0 && rule.cache !== false;
2089
+ if (!cached || rule.cache === false) return [source, rule];
2090
+ const cache = rule.cache && typeof rule.cache === "object" ? rule.cache : {};
2091
+ const varies = [...Array.isArray(cache.varies) ? cache.varies : [], "x-farm-shell"];
2092
+ return [source, { ...rule, cache: { ...cache, varies } }];
2093
+ })
2094
+ );
2095
+ }
2036
2096
  async function writeSSRAssetsToClient(bundle, outputDir) {
2037
2097
  const fs4 = await import("fs/promises");
2038
2098
  for (const [fileName, output] of Object.entries(bundle)) {
@@ -2126,7 +2186,8 @@ function getCachedClientModuleHydrationPlan(modulePath, root, mode, cache, optio
2126
2186
  }
2127
2187
  return { ...plan, isolatedBoundaries: [...plan.isolatedBoundaries] };
2128
2188
  }
2129
- async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = [], routeSlots = [], isolatedClientBoundaryModules = /* @__PURE__ */ new Set(), hydrationPlanCache = /* @__PURE__ */ new Map(), rendererBuildLifetime, programmaticClientRoutes) {
2189
+ async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = [], routeSlots = [], isolatedClientBoundaryModules = /* @__PURE__ */ new Set(), hydrationPlanCache = /* @__PURE__ */ new Map(), rendererBuildLifetime, programmaticClientRoutes, mobile = false) {
2190
+ if (!mobile) await removeFarmMobileClientManifest(path10.dirname(outputDir));
2130
2191
  const viteBuild = productionVite.build;
2131
2192
  const { farmPlugin, farmServerOnlyEntriesPlugin } = await import("./vite.mjs");
2132
2193
  const { PluginManager: PluginManager2 } = await import("./plugin-53SY5YBS.mjs");
@@ -2215,6 +2276,7 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
2215
2276
  });
2216
2277
  const layoutAppliesToRoute = routeBoundaryCoversDirectory;
2217
2278
  const routeDirectory = (route) => route.directory ?? route.pattern;
2279
+ const islandsMode = resolveFarmServerComponentsMode(config.experimental?.serverComponents) === "islands";
2218
2280
  const adapterOwnsDocsRuntime = Boolean(
2219
2281
  isReactRenderer(config.renderer) && config.docs?.enabled && config.docs.adapter?.server && config.docs.adapter.react
2220
2282
  );
@@ -2270,7 +2332,8 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
2270
2332
  }
2271
2333
  }))
2272
2334
  ],
2273
- layoutAppliesToRoute
2335
+ layoutAppliesToRoute,
2336
+ { serverOwners: islandsMode }
2274
2337
  );
2275
2338
  for (const layout of clientLayouts) {
2276
2339
  const matchesBuiltRoute = pageRoutes.some((route) => layoutAppliesToRoute(layout.pattern, routeDirectory(route))) || docsEntries.some((docsEntry) => layoutAppliesToRoute(layout.pattern, docsEntry));
@@ -2304,15 +2367,13 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
2304
2367
  }
2305
2368
  if (metadata.shouldHydrate || metadata.hasIsolatedClientBoundaries || applicableClientLayouts.length > 0) {
2306
2369
  const relativePath = route.modulePath.replace(root, "").replace(/^\//, "");
2307
- const hydrationStrategies = [
2308
- ...metadata.islandStrategy ? [metadata.islandStrategy] : [],
2309
- ...applicableClientLayouts.flatMap(
2310
- (layout) => layout.islandStrategy ? [layout.islandStrategy] : []
2311
- )
2312
- ];
2313
- const islandStrategy = hydrationStrategies.every(
2314
- (strategy) => strategy === hydrationStrategies[0]
2315
- ) ? hydrationStrategies[0] ?? "load" : "load";
2370
+ const islandStrategy = resolveFarmRouteRootStrategy(
2371
+ route,
2372
+ metadata,
2373
+ clientLayouts,
2374
+ root,
2375
+ islandsMode
2376
+ );
2316
2377
  clientPages.push({
2317
2378
  ...route,
2318
2379
  relativePath,
@@ -2369,206 +2430,243 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
2369
2430
  logger.info(
2370
2431
  `\u{1F4F1} Total hydratable routes detected: ${clientPages.length} pages, ${clientLayouts.filter((layout) => layout.shouldHydrate || layout.hasIsolatedClientBoundaries).length} layouts, and ${clientRouteSlots.length} slots`
2371
2432
  );
2372
- const clientEntryRoot = path10.join(root, ".farm", "tmp");
2373
- await fs4.mkdir(clientEntryRoot, { recursive: true });
2374
- const clientEntryDir = await fs4.mkdtemp(path10.join(clientEntryRoot, "client-entry-"));
2375
- const clientEntryPath = path10.join(clientEntryDir, "farm-client-entry.tsx");
2376
- const clientHydrationCode = generateClientHydrationEntry(
2377
- clientPages,
2378
- clientLayouts,
2379
- clientRouteSlots,
2380
- root,
2381
- srcDir,
2382
- adapterOwnsDocsRuntime ? false : isFarmDocsSearchEnabled(config.docs),
2383
- adapterOwnsDocsRuntime ? void 0 : resolveFarmDocsSearchClientModule(root),
2384
- config.docs?.enabled ? getFarmDocsRoots(config.docs).map((docsRoot) => docsRoot.entry) : void 0,
2385
- adapterOwnsDocsRuntime ? config.docs.adapter?.react : void 0,
2386
- config.i18n,
2387
- config.plugins,
2388
- config.renderer,
2389
- config.publicRuntimeConfig,
2390
- config.trailingSlash,
2391
- getIntegrationProviders(config.integrations),
2392
- config.basePath,
2393
- generateClientCachePersistenceCode(resolveFarmClientCacheAdapterEntry(root, config.cache)),
2394
- adapterOwnsDocsRuntime ? getFarmDocsAdapterConfigModule(config.docs) : void 0,
2395
- resolveFarmServerComponentsMode(config.experimental?.serverComponents) === "islands"
2396
- );
2397
- await fs4.writeFile(clientEntryPath, clientHydrationCode);
2398
- const hasScopedPostcssConfig = hasProjectPostcssConfig(root);
2399
- let postcssSearchPath;
2400
- let tailwindVitePlugin = void 0;
2401
- const rendererVitePlugins = await loadFarmRendererVitePlugins(config.renderer, root, {
2402
- ssr: false,
2403
- buildLifetime: rendererBuildLifetime
2404
- });
2405
- if (hasScopedPostcssConfig) {
2406
- logger.info("\u{1F4E6} Using project PostCSS/Tailwind configuration");
2407
- } else {
2408
- const postcssConfigPath = path10.join(clientEntryDir, "postcss.config.cjs");
2409
- await fs4.writeFile(postcssConfigPath, "module.exports = { plugins: [] };\n");
2410
- postcssSearchPath = clientEntryDir;
2411
- tailwindVitePlugin = await loadTailwindVitePlugin({
2412
- builder: productionVite.builder,
2413
- announce: true
2414
- });
2415
- }
2416
- try {
2417
- const clientViteConfig = {
2433
+ const buildTarget = async (platform) => {
2434
+ const clientEntryRoot = path10.join(root, ".farm", "tmp");
2435
+ await fs4.mkdir(clientEntryRoot, { recursive: true });
2436
+ const clientEntryDir = await fs4.mkdtemp(path10.join(clientEntryRoot, "client-entry-"));
2437
+ const clientEntryPath = path10.join(clientEntryDir, "farm-client-entry.tsx");
2438
+ const clientHydrationCode = generateClientHydrationEntry(
2439
+ clientPages,
2440
+ clientLayouts,
2441
+ clientRouteSlots,
2418
2442
  root,
2419
- // Vite otherwise falls back to <root>/public, silently dropping every
2420
- // asset in a custom config.publicDir from the production client output.
2421
- publicDir: config.publicDir,
2422
- esbuild: {
2423
- jsxDev: false
2424
- },
2425
- build: {
2426
- // Preserve Farm's Vite 5 browser baseline when the production builder
2427
- // uses Vite 8, whose default target only covers newer browsers.
2428
- target: FARM_CLIENT_BUILD_TARGET,
2429
- outDir: outputDir,
2430
- emptyOutDir: true,
2431
- // Never public: see resolveFarmClientSourcemap.
2432
- sourcemap: resolveFarmClientSourcemap(config.vite?.build?.sourcemap),
2433
- assetsInlineLimit: 0,
2434
- cssCodeSplit: false,
2435
- // Bundle all CSS into one file
2436
- rollupOptions: {
2437
- input: {
2438
- "farm-client": clientEntryPath
2439
- },
2440
- output: {
2441
- entryFileNames: "[name]-h[hash].js",
2442
- chunkFileNames: "chunks/[name]-h[hash].js",
2443
- hashCharacters: "hex",
2444
- // Use predictable name for CSS so we can reference it in SSR HTML
2445
- assetFileNames: (assetInfo) => {
2446
- if (assetInfo.name?.endsWith(".css")) {
2447
- return "farm-client.css";
2443
+ srcDir,
2444
+ adapterOwnsDocsRuntime ? false : isFarmDocsSearchEnabled(config.docs),
2445
+ adapterOwnsDocsRuntime ? void 0 : resolveFarmDocsSearchClientModule(root),
2446
+ config.docs?.enabled ? getFarmDocsRoots(config.docs).map((docsRoot) => docsRoot.entry) : void 0,
2447
+ adapterOwnsDocsRuntime ? config.docs.adapter?.react : void 0,
2448
+ config.i18n,
2449
+ config.plugins,
2450
+ config.renderer,
2451
+ config.publicRuntimeConfig,
2452
+ config.trailingSlash,
2453
+ getIntegrationProviders(config.integrations),
2454
+ config.basePath,
2455
+ generateClientCachePersistenceCode(resolveFarmClientCacheAdapterEntry(root, config.cache)),
2456
+ adapterOwnsDocsRuntime ? getFarmDocsAdapterConfigModule(config.docs) : void 0,
2457
+ resolveFarmServerComponentsMode(config.experimental?.serverComponents) === "islands",
2458
+ platform,
2459
+ islandsMode ? collectFarmServerStylesheets(
2460
+ [
2461
+ ...layoutRoutes.map((layout) => layout.modulePath),
2462
+ ...pageRoutes.filter((route) => !isAdapterDocsRoute(route.pattern)).map((route) => route.modulePath)
2463
+ ],
2464
+ root
2465
+ ) : []
2466
+ );
2467
+ const entryName = platform === "mobile" ? FARM_MOBILE_CLIENT_ENTRY_NAME : "farm-client";
2468
+ await fs4.writeFile(clientEntryPath, clientHydrationCode);
2469
+ const clientInput = { [entryName]: clientEntryPath };
2470
+ if (platform === "web" && canBootFarmIslandsClient(config)) {
2471
+ const clientBootPath = path10.join(clientEntryDir, "farm-client-boot.tsx");
2472
+ await fs4.writeFile(
2473
+ clientBootPath,
2474
+ 'import { startFarmIslandsBoot } from "@farm.js/core/internal/islands-boot";\nstartFarmIslandsBoot();\n'
2475
+ );
2476
+ clientInput[`${entryName}-boot`] = clientBootPath;
2477
+ }
2478
+ const hasScopedPostcssConfig = hasProjectPostcssConfig(root);
2479
+ let postcssSearchPath;
2480
+ let tailwindVitePlugin = void 0;
2481
+ const rendererVitePlugins = await loadFarmRendererVitePlugins(config.renderer, root, {
2482
+ ssr: false,
2483
+ buildLifetime: rendererBuildLifetime
2484
+ });
2485
+ if (hasScopedPostcssConfig) {
2486
+ logger.info("\u{1F4E6} Using project PostCSS/Tailwind configuration");
2487
+ } else {
2488
+ const postcssConfigPath = path10.join(clientEntryDir, "postcss.config.cjs");
2489
+ await fs4.writeFile(postcssConfigPath, "module.exports = { plugins: [] };\n");
2490
+ postcssSearchPath = clientEntryDir;
2491
+ tailwindVitePlugin = await loadTailwindVitePlugin({
2492
+ builder: productionVite.builder,
2493
+ announce: true
2494
+ });
2495
+ }
2496
+ try {
2497
+ const clientViteConfig = {
2498
+ root,
2499
+ // Vite otherwise falls back to <root>/public, silently dropping every
2500
+ // asset in a custom config.publicDir from the production client output.
2501
+ // The mobile client adds to the web client's output; public files are copied once.
2502
+ publicDir: platform === "mobile" ? false : config.publicDir,
2503
+ esbuild: {
2504
+ jsxDev: false
2505
+ },
2506
+ build: {
2507
+ // Preserve Farm's Vite 5 browser baseline when the production builder
2508
+ // uses Vite 8, whose default target only covers newer browsers.
2509
+ target: FARM_CLIENT_BUILD_TARGET,
2510
+ outDir: outputDir,
2511
+ emptyOutDir: platform === "web",
2512
+ // Never public: see resolveFarmClientSourcemap.
2513
+ sourcemap: resolveFarmClientSourcemap(config.vite?.build?.sourcemap),
2514
+ assetsInlineLimit: 0,
2515
+ cssCodeSplit: false,
2516
+ // Bundle all CSS into one file
2517
+ rollupOptions: {
2518
+ input: clientInput,
2519
+ output: {
2520
+ entryFileNames: "[name]-h[hash].js",
2521
+ chunkFileNames: "chunks/[name]-h[hash].js",
2522
+ hashCharacters: "hex",
2523
+ // Use predictable name for CSS so we can reference it in SSR HTML
2524
+ assetFileNames: (assetInfo) => {
2525
+ if (assetInfo.name?.endsWith(".css")) {
2526
+ return `${entryName}.css`;
2527
+ }
2528
+ return "assets/[name]-h[hash][extname]";
2448
2529
  }
2449
- return "assets/[name]-h[hash][extname]";
2450
- }
2451
- },
2452
- // A browser cannot load a Node builtin: farmServerOnlyEntriesPlugin
2453
- // resolves one to Farm's browser module for it instead.
2454
- external: (id) => {
2455
- if (id === "fsevents" || id.includes("fsevents") || id.endsWith(".node")) {
2456
- return true;
2530
+ },
2531
+ // A browser cannot load a Node builtin: farmServerOnlyEntriesPlugin
2532
+ // resolves one to Farm's browser module for it instead.
2533
+ external: (id) => {
2534
+ if (id === "fsevents" || id.includes("fsevents") || id.endsWith(".node")) {
2535
+ return true;
2536
+ }
2537
+ return false;
2457
2538
  }
2458
- return false;
2459
2539
  }
2460
- }
2461
- },
2462
- plugins: [
2463
- createFarmThemeCssPlugin(config.theme, config.basePath),
2464
- createFarmPrivateClientSourcemapsPlugin({
2465
- outDir: path10.join(path10.dirname(outputDir), FARM_CLIENT_SOURCEMAPS_DIR)
2466
- }),
2467
- createFarmClientModulePreloadPlugin({
2468
- root,
2469
- buildDir: path10.dirname(outputDir),
2470
- entryName: "farm-client"
2471
- }),
2472
- ...adapterOwnsDocsRuntime ? [
2473
- createFarmDocsModulePreloadPlugin({
2540
+ },
2541
+ plugins: [
2542
+ createFarmThemeCssPlugin(config.theme, config.basePath),
2543
+ createFarmPrivateClientSourcemapsPlugin({
2544
+ outDir: path10.join(
2545
+ path10.dirname(outputDir),
2546
+ platform === "mobile" ? `${FARM_CLIENT_SOURCEMAPS_DIR}-mobile` : FARM_CLIENT_SOURCEMAPS_DIR
2547
+ )
2548
+ }),
2549
+ // The web client's preload manifests; the mobile client records its files instead.
2550
+ platform === "mobile" ? createFarmMobileClientManifestPlugin({
2551
+ buildDir: path10.dirname(outputDir),
2552
+ entryName
2553
+ }) : createFarmClientModulePreloadPlugin({
2474
2554
  root,
2475
2555
  buildDir: path10.dirname(outputDir),
2476
- importer: clientEntryPath,
2477
- entryName: "farm-client",
2478
- modules: [
2479
- config.docs.adapter.react,
2480
- getFarmDocsAdapterConfigModule(config.docs)
2481
- ].filter((specifier) => Boolean(specifier))
2482
- })
2483
- ] : [],
2484
- ...tailwindVitePlugin ? [tailwindVitePlugin] : [],
2485
- ...rendererVitePlugins,
2486
- ...config.vite.plugins || [],
2487
- farmServerOnlyEntriesPlugin(),
2488
- farmDocsClientConfigPlugin(
2489
- adapterOwnsDocsRuntime ? getFarmDocsAdapterConfigModule(config.docs) : void 0
2490
- ),
2491
- // Plugin to redirect @farm.js/core imports to client-only exports
2492
- {
2493
- name: "farm-client-only-imports",
2494
- enforce: "pre",
2495
- resolveId(id) {
2496
- if (id === "@farm.js/core") {
2497
- return { id: "\0farm-client-exports", external: false };
2498
- }
2499
- if (id === "@farm.js/core/i18n/server") {
2500
- return { id: "\0farm-i18n-client-bridge", external: false };
2501
- }
2502
- if (id === "@farm.js/core/server" || id === "@farm.js/core/api" || id === "@farm.js/core/middleware" || id === "@farm.js/core/headers" || id === "@farm.js/core/config" || id.includes("@farm.js/core/middleware") || id.includes("@farm.js/core/query/server")) {
2503
- return { id: "\0empty-module", external: false };
2504
- }
2505
- if (id.includes("/api/") && id.includes("/route")) {
2506
- return { id: "\0empty-api-route", external: false };
2507
- }
2508
- if (id === "fsevents" || id.includes("fsevents") || id.endsWith(".node") || id === "nitro" || id === "vite" || id === "esbuild" || id === "rolldown" || id.startsWith("rolldown/") || id === "rollup" || id.startsWith("nitro/") || id.includes("node-pre-gyp") || id.includes("nf3")) {
2509
- return { id: "\0empty-module", external: false };
2556
+ entryName: "farm-client"
2557
+ }),
2558
+ ...adapterOwnsDocsRuntime && platform === "web" ? [
2559
+ createFarmDocsModulePreloadPlugin({
2560
+ root,
2561
+ buildDir: path10.dirname(outputDir),
2562
+ importer: clientEntryPath,
2563
+ entryName: "farm-client",
2564
+ modules: [
2565
+ config.docs.adapter.react,
2566
+ getFarmDocsAdapterConfigModule(config.docs)
2567
+ ].filter((specifier) => Boolean(specifier))
2568
+ })
2569
+ ] : [],
2570
+ ...tailwindVitePlugin ? [tailwindVitePlugin] : [],
2571
+ ...rendererVitePlugins,
2572
+ ...config.vite.plugins || [],
2573
+ farmServerOnlyEntriesPlugin({ platform }),
2574
+ farmDocsClientConfigPlugin(
2575
+ adapterOwnsDocsRuntime ? getFarmDocsAdapterConfigModule(config.docs) : void 0
2576
+ ),
2577
+ // Plugin to redirect @farm.js/core imports to client-only exports
2578
+ {
2579
+ name: "farm-client-only-imports",
2580
+ enforce: "pre",
2581
+ resolveId(id) {
2582
+ if (id === "@farm.js/core") {
2583
+ return { id: "\0farm-client-exports", external: false };
2584
+ }
2585
+ if (id === "@farm.js/core/i18n/server") {
2586
+ return { id: "\0farm-i18n-client-bridge", external: false };
2587
+ }
2588
+ if (id === "@farm.js/core/server" || id === "@farm.js/core/api" || id === "@farm.js/core/middleware" || id === "@farm.js/core/headers" || id === "@farm.js/core/config" || id.includes("@farm.js/core/middleware") || id.includes("@farm.js/core/query/server")) {
2589
+ return { id: "\0empty-module", external: false };
2590
+ }
2591
+ if (id.includes("/api/") && id.includes("/route")) {
2592
+ return { id: "\0empty-api-route", external: false };
2593
+ }
2594
+ if (id === "fsevents" || id.includes("fsevents") || id.endsWith(".node") || id === "nitro" || id === "vite" || id === "esbuild" || id === "rolldown" || id.startsWith("rolldown/") || id === "rollup" || id.startsWith("nitro/") || id.includes("node-pre-gyp") || id.includes("nf3")) {
2595
+ return { id: "\0empty-module", external: false };
2596
+ }
2597
+ return null;
2598
+ },
2599
+ load(id) {
2600
+ if (id === "\0empty-module") {
2601
+ return "const emptyMiddlewareStore = new Map(); export default {}; export const getMiddlewareContext = () => emptyMiddlewareStore; export const getMiddlewareData = () => emptyMiddlewareStore; export const getMiddlewareValue = () => undefined; export const middleware = () => ({});";
2602
+ }
2603
+ if (id === "\0empty-api-route") {
2604
+ return "export const GET = () => {}; export const HEAD = () => {}; export const QUERY = () => {}; export const POST = () => {}; export const PUT = () => {}; export const DELETE = () => {}; export const PATCH = () => {}; export const OPTIONS = () => {}; export default {};";
2605
+ }
2606
+ if (id === "\0farm-i18n-client-bridge") {
2607
+ return 'export { createTranslator, format, getLocale, getLocaleSource, t } from "@farm.js/core/i18n/client";';
2608
+ }
2609
+ if (id === "\0farm-client-exports") {
2610
+ return [
2611
+ "// Farm.js Client Exports - Safe for browser bundling",
2612
+ 'export { Link } from "@farm.js/core/client";',
2613
+ 'export { useRouter } from "@farm.js/core/client";',
2614
+ 'export { usePathname, useSearchParams } from "@farm.js/core/navigation";',
2615
+ // A page that hydrates ships to the browser with its notFound()/redirect() calls.
2616
+ 'export { getFarmRedirectError, isFarmNotFoundError, isFarmRedirectError, notFound, permanentRedirect, redirect } from "@farm.js/core/navigation";',
2617
+ 'export { createAPIClient } from "@farm.js/core/client";',
2618
+ 'export { localFont, remoteFont } from "@farm.js/core/font";'
2619
+ ].join("\n");
2620
+ }
2621
+ return null;
2510
2622
  }
2511
- return null;
2512
2623
  },
2513
- load(id) {
2514
- if (id === "\0empty-module") {
2515
- return "const emptyMiddlewareStore = new Map(); export default {}; export const getMiddlewareContext = () => emptyMiddlewareStore; export const getMiddlewareData = () => emptyMiddlewareStore; export const getMiddlewareValue = () => undefined; export const middleware = () => ({});";
2516
- }
2517
- if (id === "\0empty-api-route") {
2518
- return "export const GET = () => {}; export const HEAD = () => {}; export const QUERY = () => {}; export const POST = () => {}; export const PUT = () => {}; export const DELETE = () => {}; export const PATCH = () => {}; export const OPTIONS = () => {}; export default {};";
2519
- }
2520
- if (id === "\0farm-i18n-client-bridge") {
2521
- return 'export { createTranslator, format, getLocale, getLocaleSource, t } from "@farm.js/core/i18n/client";';
2522
- }
2523
- if (id === "\0farm-client-exports") {
2524
- return [
2525
- "// Farm.js Client Exports - Safe for browser bundling",
2526
- 'export { Link } from "@farm.js/core/client";',
2527
- 'export { useRouter } from "@farm.js/core/client";',
2528
- 'export { usePathname, useSearchParams } from "@farm.js/core/navigation";',
2529
- // A page that hydrates ships to the browser with its notFound()/redirect() calls.
2530
- 'export { getFarmRedirectError, isFarmNotFoundError, isFarmRedirectError, notFound, permanentRedirect, redirect } from "@farm.js/core/navigation";',
2531
- 'export { createAPIClient } from "@farm.js/core/client";',
2532
- 'export { localFont, remoteFont } from "@farm.js/core/font";'
2533
- ].join("\n");
2534
- }
2535
- return null;
2536
- }
2624
+ farmPlugin(
2625
+ { ...config, isolatedClientBoundaryModules, programmaticClientRoutes },
2626
+ pluginManager
2627
+ ),
2628
+ farmEnvironmentFunctionsPlugin(config)
2629
+ ],
2630
+ mode: "production",
2631
+ css: postcssSearchPath ? {
2632
+ postcss: postcssSearchPath
2633
+ } : void 0,
2634
+ // Ensure React is bundled for client
2635
+ resolve: {
2636
+ alias: createFarmSourceAlias(root, config.srcDir),
2637
+ dedupe: [...config.renderer.dedupe || []]
2537
2638
  },
2538
- farmPlugin(
2539
- { ...config, isolatedClientBoundaryModules, programmaticClientRoutes },
2540
- pluginManager
2541
- ),
2542
- farmEnvironmentFunctionsPlugin(config)
2543
- ],
2544
- mode: "production",
2545
- css: postcssSearchPath ? {
2546
- postcss: postcssSearchPath
2547
- } : void 0,
2548
- // Ensure React is bundled for client
2549
- resolve: {
2550
- alias: createFarmSourceAlias(root, config.srcDir),
2551
- dedupe: [...config.renderer.dedupe || []]
2552
- },
2553
- // Optimize dependencies - exclude server-side code from client bundle
2554
- optimizeDeps: {
2555
- exclude: [
2556
- "@farm.js/core/server",
2557
- "@farm.js/core/api",
2558
- "@farm.js/core/middleware",
2559
- "@farm.js/core/headers"
2560
- ]
2639
+ // Optimize dependencies - exclude server-side code from client bundle
2640
+ optimizeDeps: {
2641
+ exclude: [
2642
+ "@farm.js/core/server",
2643
+ "@farm.js/core/api",
2644
+ "@farm.js/core/middleware",
2645
+ "@farm.js/core/headers"
2646
+ ]
2647
+ }
2648
+ };
2649
+ await viteBuild(mergeFarmProductionViteConfig(clientViteConfig, config.vite));
2650
+ if (platform === "mobile") {
2651
+ await fs4.rm(path10.join(outputDir, `${entryName}.css`), { force: true });
2652
+ if (!await hasFarmMobileClientEntry(path10.dirname(outputDir), outputDir)) {
2653
+ throw new IncompleteClientBuildOutputError(
2654
+ `${FARM_MOBILE_CLIENT_ENTRY_NAME}.js is missing or empty`
2655
+ );
2656
+ }
2657
+ } else {
2658
+ await mergeBuiltFontCss(outputDir);
2659
+ await validateClientBuildOutput(root, srcDir, outputDir);
2660
+ }
2661
+ } finally {
2662
+ try {
2663
+ await fs4.rm(clientEntryDir, { recursive: true, force: true });
2664
+ } catch {
2561
2665
  }
2562
- };
2563
- await viteBuild(mergeFarmProductionViteConfig(clientViteConfig, config.vite));
2564
- await mergeBuiltFontCss(outputDir);
2565
- await validateClientBuildOutput(root, srcDir, outputDir);
2566
- } finally {
2567
- try {
2568
- await fs4.rm(clientEntryDir, { recursive: true, force: true });
2569
- } catch {
2570
2666
  }
2571
- }
2667
+ };
2668
+ await buildTarget("web");
2669
+ if (mobile) await buildTarget("mobile");
2572
2670
  }
2573
2671
  function toBakedMarkdownSourcePath(root, filePath) {
2574
2672
  if (!filePath) return "";
@@ -2647,48 +2745,7 @@ async function fetchFarmNavigationDocument(url, headers, recover = true, signal)
2647
2745
  return response;
2648
2746
  }
2649
2747
 
2650
- ${streamNavigations ? `// Reads a streamed navigation (F-Stream) up to the end of React's shell. \`next\` then resolves
2651
- // with each later flush as it ends, and null at the end; a document without a marker is all shell.
2652
- // The marker carries the random token the server sent in the F-Flush header, so page content
2653
- // cannot forge a boundary; a response without a valid token is all shell.
2654
- async function readFarmNavigationStream(body, flushToken) {
2655
- const reader = body.getReader();
2656
- const decoder = new TextDecoder();
2657
- const marker = typeof flushToken === "string" && /^[0-9a-f]{32}$/.test(flushToken)
2658
- ? "<!--farm-flush:" + flushToken + "-->"
2659
- : "";
2660
- let text = "";
2661
- let done = false;
2662
- const next = async function() {
2663
- for (;;) {
2664
- const at = marker ? text.indexOf(marker) : -1;
2665
- if (at !== -1) {
2666
- const flush = text.slice(0, at);
2667
- text = text.slice(at + marker.length);
2668
- return flush;
2669
- }
2670
- if (done) {
2671
- const flush = text;
2672
- text = "";
2673
- return flush ? flush : null;
2674
- }
2675
- const result = await reader.read();
2676
- if (result.done) {
2677
- done = true;
2678
- text += decoder.decode();
2679
- } else {
2680
- text += decoder.decode(result.value, { stream: true });
2681
- }
2682
- }
2683
- };
2684
- const shell = await next();
2685
- if (done && !text) return { shell: shell || "" };
2686
- return {
2687
- shell: shell,
2688
- next: next,
2689
- cancel: function() { reader.cancel().catch(function() {}); },
2690
- };
2691
- }` : ""}
2748
+ ${streamNavigations ? FARM_NAVIGATION_STREAM_READER_SOURCE : ""}
2692
2749
 
2693
2750
  function clearFarmPrefetchCacheOnDeploymentMismatch(router, error) {
2694
2751
  if (error?.name === "FarmDeploymentMismatchError") {
@@ -3444,13 +3501,14 @@ function generateClientHydrationEntry(clientPages, layoutRoutes, clientRouteSlot
3444
3501
  secure: false
3445
3502
  },
3446
3503
  direction: {}
3447
- }, plugins = [], renderer = REACT_RENDERER, publicRuntimeConfig = void 0, trailingSlash = false, integrationProviders = [], basePath = "/", clientCachePersistence = { imports: "", init: "" }, docsConfigModule, islandValues = false) {
3504
+ }, plugins = [], renderer = REACT_RENDERER, publicRuntimeConfig = void 0, trailingSlash = false, integrationProviders = [], basePath = "/", clientCachePersistence = { imports: "", init: "" }, docsConfigModule, islandValues = false, platform, serverStylesheets = []) {
3448
3505
  const toImportPath = (targetPath) => targetPath.replace(/\\/g, "/");
3449
3506
  const clientPluginEntry = generateFarmClientPluginEntryCode(
3450
3507
  plugins,
3451
3508
  root,
3452
3509
  srcDir,
3453
- publicRuntimeConfig
3510
+ publicRuntimeConfig,
3511
+ platform
3454
3512
  );
3455
3513
  const appSetupPath = resolveFarmRendererAppSetup(root, renderer);
3456
3514
  const rendererClientImports = isReactRenderer(renderer) ? `import React from "react";
@@ -3463,7 +3521,20 @@ __farmConfigureApp(__farmAppSetup);` : `import React, { createRoot, hydrateRoot
3463
3521
  renderer.componentExtensions ?? []
3464
3522
  );
3465
3523
  const globalsCssPath = path10.join(root, srcDir, "app", "globals.css");
3466
- const cssImport = existsSync2(globalsCssPath) ? `import ${JSON.stringify(toImportPath(globalsCssPath))};` : "";
3524
+ const serverStyleModules = [];
3525
+ const cssImport = [
3526
+ ...existsSync2(globalsCssPath) ? [globalsCssPath] : [],
3527
+ ...serverStylesheets.filter((stylesheet) => stylesheet !== globalsCssPath)
3528
+ ].map((stylesheet) => {
3529
+ if (!/\.module\.[a-z]+$/.test(stylesheet)) {
3530
+ return `import ${JSON.stringify(toImportPath(stylesheet))};`;
3531
+ }
3532
+ const binding = `__farmServerStyle${serverStyleModules.length}`;
3533
+ serverStyleModules.push(binding);
3534
+ return `import * as ${binding} from ${JSON.stringify(toImportPath(stylesheet))};`;
3535
+ }).concat(
3536
+ serverStyleModules.length > 0 ? [`globalThis.__FARM_SERVER_STYLES__ = [${serverStyleModules.join(", ")}];`] : []
3537
+ ).join("\n");
3467
3538
  const layoutImportStatements = [];
3468
3539
  const layoutRegistrations = [];
3469
3540
  const hydratingLayoutPatterns = layoutRoutes.filter((layout) => layout.shouldHydrate).map((layout) => layout.pattern);
@@ -4403,9 +4474,9 @@ async function hydrate() {
4403
4474
  !matched.route.pageShouldHydrate &&
4404
4475
  !hasHydratableLayout(pathname)
4405
4476
  ) {
4406
- const hydrationController = new AbortController();
4407
- pendingPageHydrationController = hydrationController;
4408
- await hydrateFarmIsolatedClientBoundaries(document, hydrationController.signal);
4477
+ // Not cancelled by a navigation: an island it removes is disposed with its DOM, and one in a
4478
+ // layout it keeps still waits for its trigger, with any click it already holds.
4479
+ await hydrateFarmIsolatedClientBoundaries(document);
4409
4480
  return;
4410
4481
  }` : ""}
4411
4482
 
@@ -5240,6 +5311,10 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
5240
5311
  modulePath: entry.modulePath
5241
5312
  })
5242
5313
  );
5314
+ const mobileShellLoadingRoutes = config.mobileShells ? Array.from(routeManager.getLoadings().values(), (entry) => ({
5315
+ pattern: entry.pattern,
5316
+ modulePath: entry.modulePath
5317
+ })) : [];
5243
5318
  const i18nCatalogs = config.i18n.enabled ? (await readFarmI18nCatalogs(config.i18n)).catalogs : {};
5244
5319
  const appDirs = getFarmAppDirectories(config);
5245
5320
  let openAPIReference = null;
@@ -5353,7 +5428,8 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
5353
5428
  preset,
5354
5429
  i18nCatalogs,
5355
5430
  isolatedClientBoundaryModules,
5356
- hydrationPlanCache
5431
+ hydrationPlanCache,
5432
+ mobileShellLoadingRoutes
5357
5433
  );
5358
5434
  const virtualEntryId = "\0virtual:farm-ssr-entry";
5359
5435
  const useExternalMetadataImageRuntime = shouldUseExternalMetadataImageRuntime(preset, true);
@@ -5959,8 +6035,11 @@ if (typeof ReactDOMServer.configureApp !== "function") {
5959
6035
  }
5960
6036
  ReactDOMServer.configureApp(__farmAppSetup);`;
5961
6037
  }
5962
- function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlots, errorRoutes, metadataImageRoutes, applicationMetadataRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, openAPIReference, notFoundPath, instrumentationPath, config, farmDocsPrecompiledManifest, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, hasServerRuntimePlugins, preset, i18nCatalogs, isolatedClientBoundaryModules, hydrationPlanCache) {
6038
+ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlots, errorRoutes, metadataImageRoutes, applicationMetadataRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, openAPIReference, notFoundPath, instrumentationPath, config, farmDocsPrecompiledManifest, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, hasServerRuntimePlugins, preset, i18nCatalogs, isolatedClientBoundaryModules, hydrationPlanCache, mobileShellLoadingRoutes = []) {
5963
6039
  const farmIslandsMode = resolveFarmServerComponentsMode(config.experimental?.serverComponents) === "islands";
6040
+ const farmClientBoot = canBootFarmIslandsClient(config);
6041
+ const farmMobileClient = shouldBuildFarmMobileClient(config);
6042
+ const farmMobileShells = farmMobileClient && config.mobileShells ? config.mobileShells : null;
5964
6043
  const hasCompressionRuntime = config.compress && resolveFarmInstrumentationRuntime(preset) === "nodejs";
5965
6044
  const servesAgentRobotsTxt = Boolean(config.agent?.crawlers?.enabled) && !applicationMetadataRoutes.some(
5966
6045
  (metadata) => metadata.kind === "robots" && metadata.pattern === "/"
@@ -6111,7 +6190,8 @@ function renderFarmServerTreeLayout(Layout, props, outlets) {
6111
6190
  depth: getRouteDirectoryDepth(route.directory ?? route.pattern),
6112
6191
  metadata: pageHydrationPlans.get(route.modulePath)
6113
6192
  })),
6114
- routeBoundaryCoversDirectory
6193
+ routeBoundaryCoversDirectory,
6194
+ { serverOwners: pageHydrationPlanOptions.serverOwners }
6115
6195
  );
6116
6196
  const providerServerImports = [
6117
6197
  providerServerModules.hasClerkProvider ? `import { ClerkProvider as FarmClerkProvider } from "@clerk/react";` : "",
@@ -6173,7 +6253,17 @@ function renderFarmServerTreeLayout(Layout, props, outlets) {
6173
6253
  module: ${varName},
6174
6254
  shouldHydrate: ${JSON.stringify(clientMetadata.shouldHydrate)},${clientMetadata.shouldHydrate ? `
6175
6255
  clientModule: ${JSON.stringify(toViteModuleId(route.modulePath, config.root))},` : ""}
6176
- islandStrategy: ${JSON.stringify(clientMetadata.islandStrategy)},${usesFarmServerTree(clientMetadata) ? "\n serverTree: true," : ""}${renderingDirective ? `
6256
+ islandStrategy: ${JSON.stringify(clientMetadata.islandStrategy)},${usesFarmServerTree(clientMetadata) ? "\n serverTree: true," : ""}${(() => {
6257
+ const rootStrategy = resolveFarmRouteRootStrategy(
6258
+ route,
6259
+ clientMetadata,
6260
+ layoutHydrationPlans.map((layout) => ({ ...layout, ...layout.hydration })),
6261
+ config.root,
6262
+ pageHydrationPlanOptions.serverOwners
6263
+ );
6264
+ return rootStrategy === "load" ? "" : `
6265
+ rootStrategy: ${JSON.stringify(rootStrategy)},`;
6266
+ })()}${renderingDirective ? `
6177
6267
  rendering: ${JSON.stringify(renderingDirective)},` : ""}
6178
6268
  ${route.source !== void 0 ? `markdownSource: {
6179
6269
  source: ${JSON.stringify(route.source)},
@@ -6246,6 +6336,24 @@ function renderFarmServerTreeLayout(Layout, props, outlets) {
6246
6336
  module: ${varName},
6247
6337
  }`);
6248
6338
  });
6339
+ const loadingImports = [];
6340
+ const loadingRegistrations = [];
6341
+ if (farmMobileShells) {
6342
+ mobileShellLoadingRoutes.forEach((loadingRoute, index) => {
6343
+ const varName = `loadingRoute${index}`;
6344
+ loadingImports.push(
6345
+ `import * as ${varName} from ${toVirtualEntryImportSpecifier(loadingRoute.modulePath)};`
6346
+ );
6347
+ const groupScope = getRouteGroupScope(loadingRoute.pattern);
6348
+ loadingRegistrations.push(`
6349
+ {
6350
+ pattern: ${JSON.stringify(stripRouteGroups(loadingRoute.pattern))},${groupScope ? `
6351
+ groupScope: ${JSON.stringify(groupScope)},
6352
+ directoryDepth: ${getRouteDirectoryDepth(loadingRoute.pattern)},` : ""}
6353
+ module: ${varName},
6354
+ }`);
6355
+ });
6356
+ }
6249
6357
  const metadataImageImports = [];
6250
6358
  const metadataImageRegistrations = [];
6251
6359
  metadataImageRoutes.forEach((image, index) => {
@@ -6389,8 +6497,60 @@ function renderFarmServerTreeLayout(Layout, props, outlets) {
6389
6497
  stripFarmLocaleFromPathname,
6390
6498
  withFarmRouteContext,
6391
6499
  createLateNotFoundRecovery,
6392
- createLateRedirectRecovery,${hasInfraAnalyticsRuntime ? "\n resolveFarmDocsEngineRouteLabel,\n resolveFarmDocsRouteLabel,\n resolveFarmMarkdownRouteLabel,\n resolveFarmMCPRouteLabel,\n setFarmRouteLabel," : ""}${hasFarmServerStorageConfig(config.storage) ? "\n _registerFarmStorageModules,\n disposeFarmStorage,\n initFarmStorage," : ""}
6393
- } from "@farm.js/core/internal/production-runtime";${farmIslandsMode ? `
6500
+ createLateRedirectRecovery,${config.mobileClient ? "\n createFarmNativeTreeResponse," : ""}${hasInfraAnalyticsRuntime ? "\n resolveFarmDocsEngineRouteLabel,\n resolveFarmDocsRouteLabel,\n resolveFarmMarkdownRouteLabel,\n resolveFarmMCPRouteLabel,\n setFarmRouteLabel," : ""}${hasFarmServerStorageConfig(config.storage) ? "\n _registerFarmStorageModules,\n disposeFarmStorage,\n initFarmStorage," : ""}
6501
+ } from "@farm.js/core/internal/production-runtime";${farmMobileClient ? `
6502
+ import { _applyFarmMobileShellClient } from "@farm.js/core/internal/production-runtime";
6503
+ // The mobile client documents load when a mobile shell asks for them (RFC 0004, 7.2), filled in
6504
+ // once the client build has finished (see buildNitroUniversal). A shell's document stays out of
6505
+ // shared caches, which the adapter learns as it does for a guarded response.
6506
+ const farmMobileShellClient = JSON.parse("${FARM_MOBILE_SHELL_CLIENT_PLACEHOLDER}");
6507
+ function applyFarmMobileShellResponse(request, response, context) {
6508
+ return _applyFarmMobileShellClient(request, response, farmMobileShellClient, () =>
6509
+ context?.onGuardedResponse?.()
6510
+ );
6511
+ }` : `
6512
+ // No mobile block: no mobile client, and documents ignore X-Farm-Shell.
6513
+ function applyFarmMobileShellResponse(request, response) {
6514
+ return response;
6515
+ }`}${farmMobileShells ? `
6516
+ import {
6517
+ _checkFarmMobileShellRoute,
6518
+ _isFarmMobileShellRenderRequest,
6519
+ } from "@farm.js/core/internal/production-runtime";
6520
+ // farm build --mobile with mobile.shells (RFC 0004, 7.2): this server renders a page shell, the
6521
+ // route's layouts around its loading file, for requests that carry this build's token. A web
6522
+ // build has no token and none of this.
6523
+ const farmMobileShellToken = ${JSON.stringify(farmMobileShells.token)};
6524
+ const loadingRoutes = [${loadingRegistrations.join(",")}
6525
+ ];
6526
+
6527
+ /**
6528
+ * A request for a page shell: the loading component it renders in place of the page, or a
6529
+ * Response saying why the route has none. Null for every other request.
6530
+ */
6531
+ function resolveFarmMobileShellRender(request, route, routePathname) {
6532
+ if (!_isFarmMobileShellRenderRequest(request, farmMobileShellToken)) return null;
6533
+ const loading = getMatchingErrorBoundary(routePathname, loadingRoutes);
6534
+ const reason = _checkFarmMobileShellRoute({
6535
+ requested: request.headers.get("x-farm-shell-route"),
6536
+ route: route.pattern,
6537
+ layouts: getApplicableLayouts(routePathname, route.directory || route.pattern).map(
6538
+ (layout) => layout.pattern,
6539
+ ),
6540
+ loading: loading && loading.route.module.default ? loading.route.pattern : null,
6541
+ });
6542
+ if (reason) {
6543
+ return farmOwnedResponse(reason, {
6544
+ status: 404,
6545
+ headers: {
6546
+ "Content-Type": "text/plain; charset=utf-8",
6547
+ "Cache-Control": "private, no-store",
6548
+ "X-Farm-Shell-Render": "none",
6549
+ },
6550
+ });
6551
+ }
6552
+ return loading.route.module.default;
6553
+ }` : ""}${farmIslandsMode ? `
6394
6554
  import { getSharedLayoutPrefixLength, handleFarmFormActionRequest, ignoreFarmHeldValues, installFarmIslandValues, parseFarmLayoutChainHeader } from "@farm.js/core/internal/production-runtime";
6395
6555
  import { installFarmIslandsServer } from "@farm.js/core/internal/islands-server";
6396
6556
  installFarmIslandsServer();
@@ -6552,7 +6712,8 @@ ${apiImports.join("\n")}
6552
6712
  ${pageImports.join("\n")}
6553
6713
  ${layoutImports.join("\n")}
6554
6714
  ${routeSlotImports.join("\n")}
6555
- ${errorImports.join("\n")}
6715
+ ${errorImports.join("\n")}${loadingImports.length > 0 ? `
6716
+ ${loadingImports.join("\n")}` : ""}
6556
6717
  ${metadataImageImports.join("\n")}
6557
6718
  ${applicationMetadataImports.join("\n")}
6558
6719
  ${middlewareImports.join("\n")}
@@ -7079,6 +7240,32 @@ function renderFarmClientEntryScript(early) {
7079
7240
  return stampFarmCspNonce('<script type="module"' + (early ? ' async' : '') + ' src="/__farm_client_js_src__"></script>');
7080
7241
  }
7081
7242
 
7243
+ // Islands mode: a whole document in which nothing hydrates at load (no island with \`load\`, and no
7244
+ // page, layout or route slot hydrating as a root) starts with the boot entry, which loads the
7245
+ // client runtime on an island's own trigger, a link or a form (RFC 0003, section 10).
7246
+ const FARM_CLIENT_BOOT = ${JSON.stringify(farmClientBoot)};
7247
+ const FARM_ISLAND_OPENING_TAG = /<f-island\\b[^>]*>/g;
7248
+ const FARM_DEFERRED_ISLAND_STRATEGY = /\\sstrategy="(?:interaction|visible|idle)"/;
7249
+
7250
+ function farmDocumentBootsClient(markup, hydratesAtLoad, routeSlots) {
7251
+ if (!FARM_CLIENT_BOOT || hydratesAtLoad || typeof markup !== "string") return false;
7252
+ if (routeSlots && routeSlots.length > 0) return false;
7253
+ // A Suspense boundary the server gave up on, which the browser renders.
7254
+ if (markup.includes("<!--$!-->") || markup.includes("<!--$?-->")) return false;
7255
+ for (const match of markup.matchAll(FARM_ISLAND_OPENING_TAG)) {
7256
+ if (!FARM_DEFERRED_ISLAND_STRATEGY.test(match[0])) return false;
7257
+ }
7258
+ return true;
7259
+ }
7260
+
7261
+ // The boot entry runs the client entry from the URL on its script. A root that waits (the element
7262
+ // a hydrating layout or client page hydrates) is named with its strategy, for the boot to watch.
7263
+ function renderFarmClientBootScript(root, rootStrategy) {
7264
+ return stampFarmCspNonce('<script type="module" src="${farmClientBoot ? FARM_CLIENT_BOOT_SRC_PLACEHOLDER : ""}" data-farm-runtime="/__farm_client_js_src__"' +
7265
+ (root ? ' data-farm-root="' + root + '" data-farm-root-strategy="' + rootStrategy + '"' : '') +
7266
+ '></script>');
7267
+ }
7268
+
7082
7269
  // Renderer options for the response being rendered: its CSP nonce, which the
7083
7270
  // renderer puts on the inline scripts it emits.
7084
7271
  function getFarmRendererRenderOptions() {
@@ -7849,12 +8036,13 @@ function withFarmDocsRequestCache(response, request, farmLocaleResolution, middl
7849
8036
 
7850
8037
  ${generateRuntimePathMatcherSource()}
7851
8038
 
7852
- function getMatchingErrorBoundary(pathname) {
8039
+ // The nearest boundary file for a page path. Page shells pass their loading files.
8040
+ function getMatchingErrorBoundary(pathname, boundaries = errorRoutes) {
7853
8041
  const pathSegments = splitRuntimePath(pathname);
7854
8042
  let bestMatch = null;
7855
8043
  let directory;
7856
8044
 
7857
- for (const errorRoute of errorRoutes) {
8045
+ for (const errorRoute of boundaries) {
7858
8046
  const patternDepth = splitRuntimePath(errorRoute.pattern).length;
7859
8047
  if (patternDepth > pathSegments.length) continue;
7860
8048
  const candidatePath = patternDepth === 0
@@ -9125,6 +9313,24 @@ ${hasServerRuntimeIntegrations ? `
9125
9313
  }
9126
9314
  ` : ""}
9127
9315
 
9316
+ ${config.mobileClient ? `
9317
+ // The mobile app's native-tier screens: the page, rendered as for a browser, read into a
9318
+ // tree of native views.
9319
+ const farmNativeStylesheets = JSON.parse(${JSON.stringify(FARM_NATIVE_STYLESHEETS_PLACEHOLDER)});
9320
+ if (
9321
+ (request.method === "GET" || request.method === "HEAD") &&
9322
+ request.headers.get("accept")?.includes(${JSON.stringify(FARM_NATIVE_TREE_CONTENT_TYPE)})
9323
+ ) {
9324
+ const treeResponse = await createFarmNativeTreeResponse({
9325
+ request,
9326
+ renderPage: (targetRequest) => fetchFarmInnerRequest(targetRequest, adapterContext),
9327
+ // The client CSS this build emitted, embedded once it settled (FARM_NATIVE_STYLESHEETS).
9328
+ loadStylesheet: (href) => farmNativeStylesheets[href],
9329
+ });
9330
+ return applyProductionMiddlewareHeaders(treeResponse, middlewareHeaders);
9331
+ }
9332
+ ` : ""}
9333
+
9128
9334
  ${config.md?.enabled ? `
9129
9335
  if (farmMarkdownConfig?.enabled) {
9130
9336
  const markdownResponse = await createMarkdownMirrorResponse({
@@ -9330,8 +9536,12 @@ ${hasServerRuntimeIntegrations ? `
9330
9536
  const actionResponse = await handleFarmFormActionRequest(request, farmFormActionsConfig);
9331
9537
  if (actionResponse) return applyProductionMiddlewareHeaders(actionResponse, middlewareHeaders);
9332
9538
  }` : ""}
9333
- if (matchedRoute) {
9334
- const trailingSlashLocation = resolveFarmTrailingSlashRedirect(
9539
+ if (matchedRoute) {${farmMobileShells ? `
9540
+ // A page shell request renders the route's loading file in place of its page, with no params,
9541
+ // data, slots, or page metadata; a route without a shell answers why.
9542
+ const farmShellLoading = resolveFarmMobileShellRender(request, matchedRoute.route, routePathname);
9543
+ if (farmShellLoading instanceof Response) return farmShellLoading;` : ""}
9544
+ const trailingSlashLocation = ${farmMobileShells ? "farmShellLoading ? null : " : ""}resolveFarmTrailingSlashRedirect(
9335
9545
  url,
9336
9546
  ${JSON.stringify(config.trailingSlash)}
9337
9547
  );
@@ -9344,7 +9554,19 @@ ${hasServerRuntimeIntegrations ? `
9344
9554
  middlewareHeaders
9345
9555
  );
9346
9556
  }
9347
- const { route, params } = matchedRoute;
9557
+ const { route, params } = ${farmMobileShells ? `farmShellLoading
9558
+ ? {
9559
+ route: {
9560
+ ...matchedRoute.route,
9561
+ module: { default: farmShellLoading, viewport: matchedRoute.route.module.viewport },
9562
+ shouldHydrate: false,
9563
+ serverTree: false,
9564
+ rendering: undefined,
9565
+ markdownSource: undefined,
9566
+ },
9567
+ params: {},
9568
+ }
9569
+ : matchedRoute` : "matchedRoute"};
9348
9570
  emitFarmEvent({ type: "route.matched", pathname, route: route.pattern, params });
9349
9571
 
9350
9572
  try {
@@ -9363,7 +9585,7 @@ ${hasServerRuntimeIntegrations ? `
9363
9585
  : countFarmKeptLayouts(request, farmSegmentLayouts, params);
9364
9586
  // The root layout always renders, so keeping one layout keeps nothing.
9365
9587
  const farmKeptLayouts = farmKeptLayoutCount > 1 ? farmKeptLayoutCount : 0;` : `const farmKeptLayouts = 0;`}
9366
- const pprConfig = resolvePPRConfig(route);
9588
+ ${farmMobileShells ? "const pprConfig = farmShellLoading ? { enabled: false } : resolvePPRConfig(route);" : "const pprConfig = resolvePPRConfig(route);"}
9367
9589
  const pprBypassReason = pprConfig.enabled
9368
9590
  ? getPPRShellBypassReason(request, middlewareData, middlewareContext)
9369
9591
  : undefined;
@@ -9434,12 +9656,13 @@ ${hasServerRuntimeIntegrations ? `
9434
9656
  layout.shouldHydrate && layout.islandStrategy ? [layout.islandStrategy] : [],
9435
9657
  ),
9436
9658
  ];
9437
- const hydrationIslandStrategy = hydrationStrategies.every(
9659
+ // A root that waits carries its resolved strategy, inferred ones included.
9660
+ const hydrationIslandStrategy = route.rootStrategy || (hydrationStrategies.every(
9438
9661
  (strategy) => strategy === hydrationStrategies[0],
9439
9662
  )
9440
9663
  ? (hydrationStrategies[0] || "load")
9441
- : "load";
9442
- const selectedRouteSlots = matchRouteSlots(
9664
+ : "load");
9665
+ const selectedRouteSlots = ${farmMobileShells ? "farmShellLoading ? [] : " : ""}matchRouteSlots(
9443
9666
  routePathname,
9444
9667
  request.headers.get("x-farm-intercept-from"),
9445
9668
  );
@@ -9760,9 +9983,12 @@ ${hasServerRuntimeIntegrations ? `
9760
9983
  {
9761
9984
  "data-farm-layout-boundary": "true",
9762
9985
  "data-farm-layout-pattern": layout.pattern,
9763
- "data-farm-layout-key": farmLayoutKeyOf
9764
- ? farmLayoutKeyOf(layout.pattern, params)
9765
- : undefined,
9986
+ // A layout chain that hydrates is drawn by React in the browser
9987
+ // (document-layout-client.ts), without a key; it renders whole anyway.
9988
+ "data-farm-layout-key":
9989
+ farmLayoutKeyOf && !shouldHydrateLayout
9990
+ ? farmLayoutKeyOf(layout.pattern, params)
9991
+ : undefined,
9766
9992
  style: { display: "contents" },
9767
9993
  },
9768
9994
  wrappedElement,
@@ -9911,6 +10137,9 @@ ${hasServerRuntimeIntegrations ? `
9911
10137
  // renderer-emitted one; explicit metadata titles still come first.
9912
10138
  const suppressDefaultTitle =
9913
10139
  !renderedMetadata.hasExplicitTitle && rendererHasTitle;
10140
+ // Set once the whole document is rendered: whether it starts with the boot entry, which
10141
+ // preloads nothing.
10142
+ let farmBootsClient = false;
9914
10143
  // A layout's own <html> document with Farm's head assets merged in and the #root the client
9915
10144
  // hydrates opening its body: the whole document, or a streamed one's opening.
9916
10145
  const composeFarmFullDocument = function(markup) {
@@ -9920,7 +10149,7 @@ ${hasServerRuntimeIntegrations ? `
9920
10149
  );
9921
10150
  composed = composed
9922
10151
  // Inject CSS link after opening head tag or first meta tag
9923
- .replace(/<head([^>]*)>/i, function(match, attrs) { return '<head' + attrs + '>\\n <link rel="stylesheet" href="/__farm_client_css_href__">' + renderFarmClientModulePreloads(composed, route.clientModule); })
10152
+ .replace(/<head([^>]*)>/i, function(match, attrs) { return '<head' + attrs + '>\\n <link rel="stylesheet" href="/__farm_client_css_href__">' + (farmBootsClient ? "" : renderFarmClientModulePreloads(composed, route.clientModule)); })
9924
10153
  .replace(/<\\/head>/i, () => renderFarmRendererHydrationScript() + '\\n</head>')
9925
10154
  // Explicit metadata wins over renderer and layout titles. Without
9926
10155
  // explicit metadata, a renderer title wins over the layout title.
@@ -10096,7 +10325,20 @@ ${hasServerRuntimeIntegrations ? `
10096
10325
  throw renderedPage.streamErrors[0];
10097
10326
  }
10098
10327
  }
10099
-
10328
+ // A route that hydrates as one root starts with the boot entry only when that root waits.
10329
+ const farmHydratesRoot = route.shouldHydrate || shouldHydrateLayout;
10330
+ farmBootsClient = farmDocumentBootsClient(
10331
+ html,
10332
+ (farmHydratesRoot && !route.rootStrategy) || Boolean(pprCacheKey),
10333
+ routeSlotPayload
10334
+ );
10335
+ const farmEntryScript = farmBootsClient
10336
+ ? renderFarmClientBootScript(
10337
+ farmHydratesRoot ? (shouldHydrateLayout ? "root" : "__farm_page__") : "",
10338
+ route.rootStrategy
10339
+ )
10340
+ : renderFarmClientEntryScript();
10341
+
10100
10342
  let fullHtml;
10101
10343
  if (hasFullDocument) {
10102
10344
  // Layout provides full HTML structure - inject CSS and client script
@@ -10112,7 +10354,7 @@ ${hasServerRuntimeIntegrations ? `
10112
10354
  routeSlotPayload,
10113
10355
  clientPageProps
10114
10356
  ) + '\\n' +
10115
- ' ' + renderFarmClientEntryScript() + '\\n</body>',
10357
+ ' ' + farmEntryScript + '\\n</body>',
10116
10358
  );
10117
10359
  } else {
10118
10360
  // No layout with full document - wrap in HTML structure
@@ -10123,13 +10365,13 @@ ${hasServerRuntimeIntegrations ? `
10123
10365
  \${viewportTags}
10124
10366
  \${hasFavicon ? "" : '<link rel="icon" href="data:,">'}
10125
10367
  \${suppressDefaultTitle ? "" : "<title>" + title + "</title>"}\${metaTags}\${rendererHead ? "\\n " + rendererHead : ""}
10126
- <link rel="stylesheet" href="/__farm_client_css_href__">\${renderFarmClientModulePreloads(html, route.clientModule)}
10368
+ <link rel="stylesheet" href="/__farm_client_css_href__">\${farmBootsClient ? "" : renderFarmClientModulePreloads(html, route.clientModule)}
10127
10369
  \${renderFarmRendererHydrationScript()}
10128
10370
  </head>
10129
10371
  <body>
10130
10372
  <div id="root">\${html}</div>
10131
10373
  \${renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath, routeSlotPayload, clientPageProps)}
10132
- \${renderFarmClientEntryScript()}
10374
+ \${farmEntryScript}
10133
10375
  </body>
10134
10376
  </html>\`;
10135
10377
  }
@@ -10611,10 +10853,11 @@ async function handleFarmFetch(request, context) {
10611
10853
  ? getFarmRoutePathname(new URL(runtimeRequest.url).pathname)
10612
10854
  : undefined;
10613
10855
  const configured = applyConfiguredResponseHeaders(response, routePathname);
10856
+ // Configured headers may edit the response in place, so check it either way.
10857
+ const guarded = farmGuardedResponse ? _withFarmGuardedResponseCache(configured) : configured;
10614
10858
  return applyFarmPreloadBudget(
10615
10859
  applyFarmCspNonceToResponse(
10616
- // Configured headers may edit the response in place, so check it either way.
10617
- farmGuardedResponse ? _withFarmGuardedResponseCache(configured) : configured,
10860
+ applyFarmMobileShellResponse(runtimeRequest, guarded, context),
10618
10861
  farmSecurityConfig,
10619
10862
  cspNonce,
10620
10863
  ),
@@ -10913,16 +11156,30 @@ async function buildNitroUniversal(config, routeManager, apiRouteManager, server
10913
11156
  }
10914
11157
  const scheduledTasks = mergeScheduledTasks(farmWorkflows.scheduledTasks, farmCron.scheduledTasks);
10915
11158
  const cloudflareCronConfig = createFarmCronCloudflareConfig(farmCron.jobs);
10916
- const [clientCssHref, clientJsSrc, docsModulePreloads, clientModulePreloads] = await Promise.all([
11159
+ const [clientCssHref, clientJsSrc, clientBootSrc, docsModulePreloads, clientModulePreloads] = await Promise.all([
10917
11160
  resolveHashedClientCssHref(clientOutputDir),
10918
11161
  resolveHashedClientJsSrc(clientOutputDir),
11162
+ resolveClientBootSrc(clientOutputDir),
10919
11163
  readFarmDocsModulePreloads(path10.join(root, distDir)),
10920
11164
  readFarmClientModulePreloads(path10.join(root, distDir))
10921
11165
  ]);
11166
+ let nativeStylesheets;
10922
11167
  const encodedDocsModulePreloads = encodeFarmDocsModulePreloads(docsModulePreloads);
10923
11168
  const encodedClientModulePreloads = encodeFarmClientModulePreloads(clientModulePreloads);
11169
+ const encodedMobileShellClient = shouldBuildFarmMobileClient(config) ? encodeFarmMobileShellClient(
11170
+ await finalizeFarmMobileClient({
11171
+ buildDir: path10.join(root, distDir),
11172
+ clientOutputDir,
11173
+ webEntry: clientJsSrc,
11174
+ stylesheet: clientCssHref,
11175
+ webFiles: clientModulePreloads?.files ?? []
11176
+ })
11177
+ ) : null;
10924
11178
  for (const output of Object.values(ssrBundle)) {
10925
11179
  if (output.type !== "chunk") continue;
11180
+ if (encodedMobileShellClient && output.code.includes(FARM_MOBILE_SHELL_CLIENT_PLACEHOLDER)) {
11181
+ output.code = output.code.split(FARM_MOBILE_SHELL_CLIENT_PLACEHOLDER).join(encodedMobileShellClient);
11182
+ }
10926
11183
  if (output.code.includes(FARM_DOCS_MODULE_PRELOADS_PLACEHOLDER)) {
10927
11184
  output.code = output.code.split(FARM_DOCS_MODULE_PRELOADS_PLACEHOLDER).join(encodedDocsModulePreloads);
10928
11185
  }
@@ -10935,13 +11192,25 @@ async function buildNitroUniversal(config, routeManager, apiRouteManager, server
10935
11192
  if (output.code.includes(FARM_CLIENT_JS_SRC_PLACEHOLDER)) {
10936
11193
  output.code = output.code.split(FARM_CLIENT_JS_SRC_PLACEHOLDER).join(clientJsSrc);
10937
11194
  }
11195
+ if (output.code.includes(FARM_CLIENT_BOOT_SRC_PLACEHOLDER)) {
11196
+ if (!clientBootSrc) {
11197
+ throw new IncompleteClientBuildOutputError("farm-client-boot is missing");
11198
+ }
11199
+ output.code = output.code.split(FARM_CLIENT_BOOT_SRC_PLACEHOLDER).join(clientBootSrc);
11200
+ }
11201
+ if (config.mobileClient && output.code.includes(JSON.stringify(FARM_NATIVE_STYLESHEETS_PLACEHOLDER))) {
11202
+ nativeStylesheets ?? (nativeStylesheets = await readFarmNativeStylesheets(clientOutputDir, clientCssHref));
11203
+ output.code = output.code.split(JSON.stringify(FARM_NATIVE_STYLESHEETS_PLACEHOLDER)).join(JSON.stringify(JSON.stringify(nativeStylesheets)));
11204
+ }
10938
11205
  }
10939
11206
  await fs4.mkdir(ssrOutputDir, { recursive: true });
10940
- for (const [fileName, output] of Object.entries(ssrBundle)) {
10941
- const filePath = path10.join(ssrOutputDir, fileName);
10942
- await fs4.mkdir(path10.dirname(filePath), { recursive: true });
10943
- await fs4.writeFile(filePath, output.type === "chunk" ? output.code : output.source);
10944
- }
11207
+ await Promise.all(
11208
+ Object.entries(ssrBundle).map(async ([fileName, output]) => {
11209
+ const filePath = path10.join(ssrOutputDir, fileName);
11210
+ await fs4.mkdir(path10.dirname(filePath), { recursive: true });
11211
+ await fs4.writeFile(filePath, output.type === "chunk" ? output.code : output.source);
11212
+ })
11213
+ );
10945
11214
  const nitroEntryPath = path10.join(ssrOutputDir, "nitro-entry.mjs");
10946
11215
  const nodeAdapterModule = preset === "node-server" ? resolveNitroRuntimeDependency(root, "srvx/node") : null;
10947
11216
  const hasNitroCacheRouteRules = hasFarmNitroCacheRouteRule(config.routeRules);
@@ -11198,7 +11467,7 @@ function toFarmNodeResponse(request, response) {
11198
11467
  ssrOutputDir,
11199
11468
  ssrEntryFile
11200
11469
  );
11201
- const configuredNitroRouteRules = routeRulesToNitroRouteRules(config.routeRules);
11470
+ const configuredNitroRouteRules = shouldBuildFarmMobileClient(config) ? varyFarmNitroCacheRulesByShell(routeRulesToNitroRouteRules(config.routeRules)) : routeRulesToNitroRouteRules(config.routeRules);
11202
11471
  const prerenderNitroRouteRules = Object.fromEntries(
11203
11472
  prerenderRoutes.map((route) => {
11204
11473
  const configuredRule = configuredNitroRouteRules[route] || {};
@@ -11245,10 +11514,18 @@ function toFarmNodeResponse(request, response) {
11245
11514
  // fixed top quality cost a docs app ~20 s of build CPU for a small further
11246
11515
  // saving. Serverless and edge targets sit behind a CDN that compresses.
11247
11516
  ...preset === "node-server" ? { compressPublicAssets: { gzip: true } } : {},
11517
+ // Nitro gzips every server output file at level 9, node_modules included, to
11518
+ // print sizes after the build. A self-hosted server is never shipped compressed,
11519
+ // so list plain sizes; zipped serverless and edge bundles keep the gzip column.
11520
+ ...preset === "node-server" || preset === "bun" ? { logging: { compressedSizes: false } } : {},
11248
11521
  ...prerenderRoutes.length > 0 ? {
11249
11522
  prerender: {
11250
11523
  crawlLinks: false,
11251
11524
  failOnError: true,
11525
+ // Nitro's default renders one route at a time. Each prerender request is
11526
+ // answered independently, as by the production server, so keeping several
11527
+ // in flight overlaps the worker's rendering with this thread's per-route work.
11528
+ concurrency: Math.min(os.availableParallelism(), 8),
11252
11529
  routes: prerenderRoutes
11253
11530
  }
11254
11531
  } : {},
@@ -11346,6 +11623,22 @@ function toFarmNodeResponse(request, response) {
11346
11623
  }
11347
11624
  nitroConfig.minify = useFarmServerMinifier ? false : shouldMinify;
11348
11625
  const nitroInstance = await nitroBuilder.createNitro(nitroConfig);
11626
+ let prerenderOrder = /* @__PURE__ */ new Map();
11627
+ nitroInstance.hooks.hook("prerender:routes", (routes) => {
11628
+ prerenderOrder = new Map(
11629
+ Array.from(routes, (route, index) => {
11630
+ try {
11631
+ return [decodeURI(route), index];
11632
+ } catch {
11633
+ return [route, index];
11634
+ }
11635
+ })
11636
+ );
11637
+ });
11638
+ nitroInstance.hooks.hook("prerender:done", ({ prerenderedRoutes }) => {
11639
+ const orderOf = (route) => prerenderOrder.get(route) ?? Number.MAX_SAFE_INTEGER;
11640
+ prerenderedRoutes.sort((a, b) => orderOf(a.route) - orderOf(b.route));
11641
+ });
11349
11642
  if (config.md?.enabled) {
11350
11643
  nitroInstance.hooks.hook("prerender:generate", (route) => {
11351
11644
  if (!route.contents || !route.contentType?.toLowerCase().includes("html")) return;
@@ -11953,7 +12246,9 @@ async function createFarmProjectModuleSsrEnvironment() {
11953
12246
 
11954
12247
  // src/build/index.ts
11955
12248
  async function build(config, options = {}) {
11956
- return withProductionNodeEnv(() => buildWithProductionNodeEnv(config, options));
12249
+ return withProductionNodeEnv(
12250
+ () => withPackageClientBoundaryCache(() => buildWithProductionNodeEnv(config, options))
12251
+ );
11957
12252
  }
11958
12253
  function createBuildTargetBaseline(config) {
11959
12254
  const preset = config.preset || "node-server";
@@ -12026,6 +12321,9 @@ async function buildWithProductionNodeEnv(inputConfig, options) {
12026
12321
  if (config.docs?.enabled) await loadFarmDocsEngine();
12027
12322
  pluginManager.updateContext({ config });
12028
12323
  const { root, preset, srcDir, distDir, deployOutputDir } = targets;
12324
+ usePackageClientBoundaryCacheFile(
12325
+ path11.resolve(root, distDir, "cache", "client-boundaries.json")
12326
+ );
12029
12327
  logger.info(`\u{1F69C} Building Farm.js application with preset: ${preset}...`);
12030
12328
  await pluginManager.setupPlugins();
12031
12329
  await pluginManager.runHookParallel("beforeBundle", {
@@ -12288,7 +12586,7 @@ function resolveLegacyPageEntry(config, root, srcDir) {
12288
12586
  }
12289
12587
  async function buildNitro(config, routeManager, apiRouteManager, serverRenderer, preset, root, distDir, pluginManager) {
12290
12588
  const [{ createNitroConfig }, { createNitro, build: nitroBuild }] = await Promise.all([
12291
- import("./nitro-R444AF3O.mjs"),
12589
+ import("./nitro-FLN6DRGJ.mjs"),
12292
12590
  import("nitro/builder")
12293
12591
  ]);
12294
12592
  let nitroConfig = await createNitroConfig(