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

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 (183) hide show
  1. package/dist/{agent-mcp-handler-WWCC4GLG.mjs → agent-mcp-handler-7JSKGSOW.mjs} +4 -4
  2. package/dist/{agent-mcp-handler-RT3COCEL.cjs → agent-mcp-handler-YE4AGWHN.cjs} +5 -5
  3. package/dist/{agent-mcp.d-CR5Ov83o.d.ts → agent-mcp.d-BAR9njbJ.d.ts} +1 -1
  4. package/dist/{agent-mcp.d-Z5DuwrqW.d.mts → agent-mcp.d-BJKChOrO.d.mts} +1 -1
  5. package/dist/agent-runtime.d.mts +2 -2
  6. package/dist/agent-runtime.d.ts +2 -2
  7. package/dist/{analyzer-Z6TNEAET.mjs → analyzer-OTPEWH5W.mjs} +14 -3
  8. package/dist/{analyzer-T76CN3S7.cjs → analyzer-TSQXZCZN.cjs} +14 -3
  9. package/dist/api/route-manager.d.mts +4 -4
  10. package/dist/api/route-manager.d.ts +4 -4
  11. package/dist/api/runtime.d.mts +3 -3
  12. package/dist/api/runtime.d.ts +3 -3
  13. package/dist/api.d.mts +4 -4
  14. package/dist/api.d.ts +4 -4
  15. package/dist/{app-manifest.d-DiWr_Jfx.d.ts → app-manifest.d-BLFbaqx8.d.ts} +1 -1
  16. package/dist/{app-manifest.d-CAHkOBFa.d.mts → app-manifest.d-DEQNnNhV.d.mts} +1 -1
  17. package/dist/app-markdown.cjs +4 -4
  18. package/dist/app-markdown.d.mts +3 -3
  19. package/dist/app-markdown.d.ts +3 -3
  20. package/dist/app-markdown.mjs +3 -3
  21. package/dist/{app.d-DmapqkbV.d.ts → app.d-CNPaUYaa.d.ts} +4 -4
  22. package/dist/{app.d-BfgJCsTQ.d.mts → app.d-CT7xDkj2.d.mts} +4 -4
  23. package/dist/{chunk-YVJV7Q2X.mjs → chunk-3BLEXUGE.mjs} +1 -1
  24. package/dist/chunk-3HLQTOVU.cjs +6 -0
  25. package/dist/{chunk-E6LTONL4.mjs → chunk-3SMXQNFD.mjs} +2 -2
  26. package/dist/{chunk-PMKUU273.mjs → chunk-3TLKUBXG.mjs} +411 -166
  27. package/dist/{chunk-74Z5KX4A.mjs → chunk-3WSIYBMG.mjs} +41 -19
  28. package/dist/{chunk-GNJIYJMS.cjs → chunk-3XQ57EFI.cjs} +16 -16
  29. package/dist/{chunk-GW4YUIHW.mjs → chunk-3Z63X45F.mjs} +1 -1
  30. package/dist/{chunk-IBSAYAWB.mjs → chunk-4353ZRE5.mjs} +1 -1
  31. package/dist/{chunk-SBABQKPT.cjs → chunk-46KXZBOG.cjs} +5 -5
  32. package/dist/{chunk-YU42A5MA.cjs → chunk-4CGOMZP3.cjs} +221 -199
  33. package/dist/{chunk-J3LBO2O4.cjs → chunk-4SEHMBL4.cjs} +10 -10
  34. package/dist/{chunk-E73PGHSR.mjs → chunk-4TKAIO2F.mjs} +3 -3
  35. package/dist/{chunk-NJLTQR5P.cjs → chunk-53SACYBY.cjs} +7 -7
  36. package/dist/{chunk-FM2UEKS2.mjs → chunk-5FXPJIOT.mjs} +2 -2
  37. package/dist/{chunk-QXPSWMUD.cjs → chunk-7MD37P5V.cjs} +5 -5
  38. package/dist/{chunk-JATTVAHA.cjs → chunk-B3GM5I6N.cjs} +4 -4
  39. package/dist/{chunk-WJFFPXCV.cjs → chunk-D7UQC4O6.cjs} +10 -8
  40. package/dist/{chunk-KRRZJ77U.mjs → chunk-E5DXF5GE.mjs} +2 -2
  41. package/dist/chunk-EFZGB7JC.cjs +114 -0
  42. package/dist/{chunk-NYQSC4DX.cjs → chunk-FFE2EMF7.cjs} +5 -5
  43. package/dist/{chunk-CTM4SPB3.mjs → chunk-GAO7MS5O.mjs} +4 -3
  44. package/dist/{chunk-HIFIG6HL.cjs → chunk-H33PJEXN.cjs} +5 -5
  45. package/dist/{chunk-NXBHYO7S.cjs → chunk-HLWOWZFX.cjs} +2 -2
  46. package/dist/chunk-JXEPLIXD.cjs +389 -0
  47. package/dist/{chunk-NPQLMP7M.cjs → chunk-KLNFJDFM.cjs} +10 -9
  48. package/dist/{chunk-KBRZAYI7.mjs → chunk-LDNSSHEG.mjs} +2 -2
  49. package/dist/chunk-LLZSYFOM.mjs +6 -0
  50. package/dist/{chunk-N77JBPLC.mjs → chunk-LPDKG6RA.mjs} +9 -7
  51. package/dist/chunk-MIGFX2FN.mjs +758 -0
  52. package/dist/{chunk-72D2NX77.mjs → chunk-MRNDAJEV.mjs} +1 -1
  53. package/dist/{chunk-4SSRBCBR.mjs → chunk-NOTSHVRN.mjs} +355 -218
  54. package/dist/{chunk-GUJTVM36.cjs → chunk-OAMUSC7H.cjs} +1 -1
  55. package/dist/chunk-P6MHI5O2.cjs +758 -0
  56. package/dist/{chunk-6CYQQQGR.mjs → chunk-R4PHCZ3G.mjs} +1 -1
  57. package/dist/{chunk-WZW6LEHM.cjs → chunk-TQMI6BYO.cjs} +675 -430
  58. package/dist/{chunk-76GHW3WI.cjs → chunk-TSFMFPRU.cjs} +4 -4
  59. package/dist/{chunk-5N7QAGEA.cjs → chunk-TWHXBMLJ.cjs} +37 -7
  60. package/dist/{chunk-BOVGCUDZ.cjs → chunk-UJL4JOXV.cjs} +2 -2
  61. package/dist/chunk-UQF3OJVE.mjs +389 -0
  62. package/dist/{chunk-DTU4PX7V.cjs → chunk-WGUHDWT5.cjs} +557 -420
  63. package/dist/{chunk-LAZK6UV7.mjs → chunk-YAJTD3ZG.mjs} +1 -1
  64. package/dist/{chunk-7UPCJDB5.mjs → chunk-YUEYBL35.mjs} +2 -2
  65. package/dist/{chunk-EIMK7D2D.mjs → chunk-ZD2VKAUI.mjs} +34 -4
  66. package/dist/chunk-ZNXTU4YH.mjs +114 -0
  67. package/dist/{client-plugins.d-Bx3FXpqm.d.mts → client-plugins.d-DllmH8eM.d.mts} +17 -4
  68. package/dist/{client-plugins.d-TiLbS5j4.d.ts → client-plugins.d-n3iWY1EJ.d.ts} +17 -4
  69. package/dist/client-plugins.d.mts +2 -2
  70. package/dist/client-plugins.d.ts +2 -2
  71. package/dist/client.d.mts +7 -7
  72. package/dist/client.d.ts +7 -7
  73. package/dist/{config.d-iRPI16ku.d.ts → config.d-DqKaCr1r.d.mts} +8 -1
  74. package/dist/{config.d-iRPI16ku.d.mts → config.d-DqKaCr1r.d.ts} +8 -1
  75. package/dist/config.d.mts +2 -2
  76. package/dist/config.d.ts +2 -2
  77. package/dist/desktop.d.mts +3 -3
  78. package/dist/desktop.d.ts +3 -3
  79. package/dist/{devtools-6XWCZIGO.cjs → devtools-TO6TAO32.cjs} +5 -5
  80. package/dist/{devtools-UQLDAOEI.mjs → devtools-UESYARTF.mjs} +4 -4
  81. package/dist/docs.cjs +7 -7
  82. package/dist/docs.d.mts +3 -3
  83. package/dist/docs.d.ts +3 -3
  84. package/dist/docs.mjs +6 -6
  85. package/dist/index.cjs +22 -18
  86. package/dist/{index.d-YxJ2AiDF.d.mts → index.d-BL7KKiwa.d.mts} +1 -1
  87. package/dist/{index.d-yueUNipJ.d.ts → index.d-BXsAXm1U.d.ts} +1 -1
  88. package/dist/index.d.mts +17 -17
  89. package/dist/index.d.ts +17 -17
  90. package/dist/index.mjs +22 -18
  91. package/dist/integrations.d.mts +2 -2
  92. package/dist/integrations.d.ts +2 -2
  93. package/dist/internal/app-markdown-runtime.cjs +3 -3
  94. package/dist/internal/app-markdown-runtime.d.mts +3 -3
  95. package/dist/internal/app-markdown-runtime.d.ts +3 -3
  96. package/dist/internal/app-markdown-runtime.mjs +2 -2
  97. package/dist/internal/build-runtime.cjs +20 -18
  98. package/dist/internal/build-runtime.d.mts +4 -4
  99. package/dist/internal/build-runtime.d.ts +4 -4
  100. package/dist/internal/build-runtime.mjs +19 -17
  101. package/dist/internal/cli-runtime.cjs +7 -7
  102. package/dist/internal/cli-runtime.mjs +6 -6
  103. package/dist/internal/client-error-overlay.cjs +4 -4
  104. package/dist/internal/client-error-overlay.mjs +1 -1
  105. package/dist/internal/client-runtime.d.mts +5 -5
  106. package/dist/internal/client-runtime.d.ts +5 -5
  107. package/dist/internal/compression-runtime.d.mts +2 -2
  108. package/dist/internal/compression-runtime.d.ts +2 -2
  109. package/dist/internal/config-runtime.cjs +6 -6
  110. package/dist/internal/config-runtime.d.mts +31 -7
  111. package/dist/internal/config-runtime.d.ts +31 -7
  112. package/dist/internal/config-runtime.mjs +5 -5
  113. package/dist/internal/infra-analytics-runtime.cjs +8 -8
  114. package/dist/internal/infra-analytics-runtime.mjs +6 -6
  115. package/dist/internal/product-telemetry-runtime.cjs +2 -2
  116. package/dist/internal/product-telemetry-runtime.mjs +1 -1
  117. package/dist/internal/production-runtime.cjs +87 -9
  118. package/dist/internal/production-runtime.d.mts +44 -12
  119. package/dist/internal/production-runtime.d.ts +44 -12
  120. package/dist/internal/production-runtime.mjs +86 -8
  121. package/dist/markdown.cjs +4 -2
  122. package/dist/markdown.d.mts +2 -2
  123. package/dist/markdown.d.ts +2 -2
  124. package/dist/markdown.mjs +3 -1
  125. package/dist/middleware.d.mts +4 -4
  126. package/dist/middleware.d.ts +4 -4
  127. package/dist/mobile.d.mts +21 -5
  128. package/dist/mobile.d.ts +21 -5
  129. package/dist/native-tree-EBPDFTRW.mjs +25 -0
  130. package/dist/native-tree-MMZS7S6W.cjs +25 -0
  131. package/dist/{navigation-delegate.d-HnDXhlyP.d.mts → navigation-delegate.d-C76gXTmO.d.mts} +1 -1
  132. package/dist/{navigation-delegate.d-BY1e_Xrh.d.ts → navigation-delegate.d-DIyDslxt.d.ts} +1 -1
  133. package/dist/navigation.d.mts +5 -5
  134. package/dist/navigation.d.ts +5 -5
  135. package/dist/plugin.cjs +14 -13
  136. package/dist/plugin.d.mts +5 -4
  137. package/dist/plugin.d.ts +5 -4
  138. package/dist/plugin.mjs +13 -12
  139. package/dist/{production-runtime.d-BpJUDzP8.d.mts → production-runtime.d-CDHztggO.d.mts} +1 -1
  140. package/dist/{production-runtime.d-lMjvE9cf.d.ts → production-runtime.d-tyaGdbk6.d.ts} +1 -1
  141. package/dist/{programmatic-routes-client.d-BlFp5hv4.d.ts → programmatic-routes-client.d-XfmIrCK1.d.ts} +2 -2
  142. package/dist/{programmatic-routes-client.d-6CGQ3TCk.d.mts → programmatic-routes-client.d-aAWiDd64.d.mts} +2 -2
  143. package/dist/{render-plan.d-BH9edqKs.d.mts → render-plan.d-Diwybxo8.d.mts} +1 -1
  144. package/dist/{render-plan.d-DhP0mTHF.d.ts → render-plan.d-Dr5WRjoV.d.ts} +1 -1
  145. package/dist/renderer-client.d.mts +5 -5
  146. package/dist/renderer-client.d.ts +5 -5
  147. package/dist/{request.d-BVZrsR1v.d.ts → request.d-D01fRn--.d.ts} +1 -1
  148. package/dist/{request.d-DJFRdKi8.d.mts → request.d-Dd3AFR79.d.mts} +1 -1
  149. package/dist/request.d.mts +3 -3
  150. package/dist/request.d.ts +3 -3
  151. package/dist/{route-rendering.d-Bpmw7PED.d.mts → route-rendering.d-BQ53lJ_D.d.mts} +1 -1
  152. package/dist/{route-rendering.d-B00JtK_-.d.ts → route-rendering.d-Bhx4QoJt.d.ts} +1 -1
  153. package/dist/{router.d-e0jQ3jQ-.d.mts → router.d-Bi23a6Xc.d.mts} +1 -1
  154. package/dist/{router.d-Bd1x9XxQ.d.ts → router.d-DQ3k7EYn.d.ts} +1 -1
  155. package/dist/{routes.d-Cmv8TgVq.d.mts → routes.d-BgTd7vI4.d.mts} +3 -3
  156. package/dist/{routes.d-D96Dq9lz.d.ts → routes.d-C7jMJFvP.d.ts} +3 -3
  157. package/dist/routes.d.mts +2 -2
  158. package/dist/routes.d.ts +2 -2
  159. package/dist/{rsc-pipeline-ZQ4CTVEG.mjs → rsc-pipeline-K3ER3Q4N.mjs} +5 -5
  160. package/dist/{rsc-pipeline-DX4OC5FN.cjs → rsc-pipeline-OCZIT5OF.cjs} +6 -6
  161. package/dist/{runtime-NQ3EDSA7.cjs → runtime-DKNSIH7V.cjs} +30 -23
  162. package/dist/{runtime-NPDRDV6R.mjs → runtime-MKYDEUZT.mjs} +20 -13
  163. package/dist/{runtime.d-CgB3IJDq.d.mts → runtime.d-B2Js6qZ2.d.mts} +1 -1
  164. package/dist/{runtime.d-D-td-RR3.d.ts → runtime.d-BL-CGwoi.d.ts} +1 -1
  165. package/dist/server-plugins.d.mts +3 -3
  166. package/dist/server-plugins.d.ts +3 -3
  167. package/dist/server.cjs +31 -30
  168. package/dist/server.d.mts +11 -10
  169. package/dist/server.d.ts +11 -10
  170. package/dist/server.mjs +16 -15
  171. package/dist/{spa-router.d-BWDhS0FK.d.mts → spa-router.d-B2rIFGs0.d.mts} +2 -2
  172. package/dist/{spa-router.d-CO01mVOM.d.ts → spa-router.d-DqZ6Lfs0.d.ts} +2 -2
  173. package/dist/testing.d.mts +2 -2
  174. package/dist/testing.d.ts +2 -2
  175. package/dist/{utils.d-B77__yh8.d.ts → utils.d-Bv2MPeLR.d.ts} +1 -1
  176. package/dist/{utils.d-DRDazhCA.d.mts → utils.d-fqXe8lNc.d.mts} +1 -1
  177. package/dist/version.cjs +2 -2
  178. package/dist/version.mjs +1 -1
  179. package/dist/vite.cjs +14 -13
  180. package/dist/vite.d.mts +12 -6
  181. package/dist/vite.d.ts +12 -6
  182. package/dist/vite.mjs +13 -12
  183. package/package.json +1 -1
@@ -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";
@@ -22,7 +31,7 @@ import {
22
31
  createFarmDocsAPIHandler,
23
32
  hasFarmDocsRuntimeAdapter,
24
33
  listFarmDocsAdapterPages
25
- } from "./chunk-FM2UEKS2.mjs";
34
+ } from "./chunk-5FXPJIOT.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-ZD2VKAUI.mjs";
38
47
  import {
39
48
  generateFarmDocsSearchClientRuntime,
40
49
  isFarmDocsSearchEnabled,
@@ -42,7 +51,7 @@ import {
42
51
  } from "./chunk-ALEUMLJN.mjs";
43
52
  import {
44
53
  FARM_PRERENDER_ENV
45
- } from "./chunk-E6LTONL4.mjs";
54
+ } from "./chunk-3SMXQNFD.mjs";
46
55
  import {
47
56
  resolveFarmInstrumentationFile
48
57
  } from "./chunk-N35YPV4N.mjs";
@@ -57,7 +66,7 @@ import {
57
66
  getDeployTargetForPreset,
58
67
  hasCustomFarmRouteContext,
59
68
  resolveDeployOutputPath
60
- } from "./chunk-CTM4SPB3.mjs";
69
+ } from "./chunk-GAO7MS5O.mjs";
61
70
  import {
62
71
  DEFAULT_NOT_FOUND_STYLES,
63
72
  FARM_LAYOUT_ELEMENT_CLIENT_SOURCE,
@@ -88,8 +97,10 @@ import {
88
97
  resolveFarmImageServerRuntime,
89
98
  resolveFarmIsolatedClientHydrationMode,
90
99
  resolveFarmNotFoundComponentPath,
91
- usesFarmServerTree
92
- } from "./chunk-PMKUU273.mjs";
100
+ usePackageClientBoundaryCacheFile,
101
+ usesFarmServerTree,
102
+ withPackageClientBoundaryCache
103
+ } from "./chunk-3TLKUBXG.mjs";
93
104
  import {
94
105
  loadTailwindVitePlugin
95
106
  } from "./chunk-PIHKO25G.mjs";
@@ -113,7 +124,10 @@ import {
113
124
  layoutsCanCoverSamePage,
114
125
  routeBoundaryCoversDirectory,
115
126
  stripRouteGroups
116
- } from "./chunk-7UPCJDB5.mjs";
127
+ } from "./chunk-YUEYBL35.mjs";
128
+ import {
129
+ FARM_NATIVE_TREE_CONTENT_TYPE
130
+ } from "./chunk-LLZSYFOM.mjs";
117
131
  import {
118
132
  farmPluginMayAffectRuntimePath
119
133
  } from "./chunk-UUMKLGUU.mjs";
@@ -127,18 +141,18 @@ import {
127
141
  listFarmBuiltInRoutePaths,
128
142
  resolveFarmApiCatalogInput,
129
143
  resolveFarmAppManifestInput
130
- } from "./chunk-E73PGHSR.mjs";
144
+ } from "./chunk-4TKAIO2F.mjs";
131
145
  import {
132
146
  FARM_DEFAULT_MCP_PATH,
133
147
  createFarmDefaultMCPServer,
134
148
  farmConfigMountsMCP
135
- } from "./chunk-KRRZJ77U.mjs";
149
+ } from "./chunk-E5DXF5GE.mjs";
136
150
  import {
137
151
  farmEnvironmentFunctionsPlugin
138
152
  } from "./chunk-ZQ5BDNKW.mjs";
139
153
  import {
140
154
  isFarmMarkdownPageFile
141
- } from "./chunk-GW4YUIHW.mjs";
155
+ } from "./chunk-3Z63X45F.mjs";
142
156
  import {
143
157
  generateFarmDocsAdapterClientRuntime,
144
158
  getFarmDocsAdapterConfigModule
@@ -191,7 +205,7 @@ import {
191
205
  } from "./chunk-FSQMN2MQ.mjs";
192
206
  import {
193
207
  getFarmMarkdownAlternatePath
194
- } from "./chunk-N77JBPLC.mjs";
208
+ } from "./chunk-LPDKG6RA.mjs";
195
209
  import {
196
210
  _collectFarmStorageModules
197
211
  } from "./chunk-TJVUTGED.mjs";
@@ -236,7 +250,7 @@ import {
236
250
  } from "./chunk-LM2YOGDK.mjs";
237
251
  import {
238
252
  FARM_VERSION
239
- } from "./chunk-6CYQQQGR.mjs";
253
+ } from "./chunk-R4PHCZ3G.mjs";
240
254
  import {
241
255
  getFarmPresetRuntime
242
256
  } from "./chunk-UAQD67HM.mjs";
@@ -1615,7 +1629,7 @@ function restoreLiteralModuleSpecifiers(code, fileName, { parseSync, Visitor })
1615
1629
  throw new Error(`Failed to minify ${fileName}: ${parsed.errors[0].message}`);
1616
1630
  }
1617
1631
  const replacements = [];
1618
- let needsAst = hasRequireTemplate;
1632
+ let needsAst = hasRequireTemplate && /(?<![\w$])require\(`/.test(code);
1619
1633
  if (!needsAst) {
1620
1634
  const seenStarts = /* @__PURE__ */ new Set();
1621
1635
  for (const { moduleRequest } of parsed.module.dynamicImports) {
@@ -1909,6 +1923,7 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
1909
1923
  }
1910
1924
  const productionVite = productionViteResult.value;
1911
1925
  logger.info("\u26A1 Building application bundles with Vite Rolldown");
1926
+ const mobileClient = shouldBuildFarmMobileClient(config);
1912
1927
  const buildClientBundle = () => buildClient(
1913
1928
  productionVite,
1914
1929
  config,
@@ -1921,7 +1936,8 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
1921
1936
  isolatedClientBoundaryModules,
1922
1937
  hydrationPlanCache,
1923
1938
  rendererBuildLifetime,
1924
- routeManager.getProgrammaticClientRoutes()
1939
+ routeManager.getProgrammaticClientRoutes(),
1940
+ mobileClient
1925
1941
  );
1926
1942
  const buildSSRBundle = () => buildSSRInMemory(
1927
1943
  productionVite,
@@ -1974,7 +1990,8 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
1974
1990
  isolatedClientBoundaryModules,
1975
1991
  hydrationPlanCache,
1976
1992
  rendererBuildLifetime,
1977
- routeManager.getProgrammaticClientRoutes()
1993
+ routeManager.getProgrammaticClientRoutes(),
1994
+ mobileClient
1978
1995
  );
1979
1996
  } catch (retryError) {
1980
1997
  if (!(retryError instanceof IncompleteClientBuildOutputError)) throw retryError;
@@ -2033,6 +2050,27 @@ ${islandsErrors.map((error) => ` - ${error}`).join("\n")}`
2033
2050
  rendererBuild?.abort();
2034
2051
  }
2035
2052
  }
2053
+ function shouldBuildFarmMobileClient(config, options = {}) {
2054
+ if (!config.mobileClient || config.desktop) return false;
2055
+ const mode = resolveFarmServerComponentsMode(config.experimental?.serverComponents);
2056
+ if (mode === void 0) return true;
2057
+ if (!options.quiet)
2058
+ logger.info(
2059
+ `\u{1F4F1} No mobile client for experimental.serverComponents (${mode}) yet; a mobile shell loads the web client.`
2060
+ );
2061
+ return false;
2062
+ }
2063
+ function varyFarmNitroCacheRulesByShell(rules) {
2064
+ return Object.fromEntries(
2065
+ Object.entries(rules).map(([source, rule]) => {
2066
+ const cached = rule?.swr !== void 0 && rule.swr !== false || rule?.cache !== void 0 && rule.cache !== false;
2067
+ if (!cached || rule.cache === false) return [source, rule];
2068
+ const cache = rule.cache && typeof rule.cache === "object" ? rule.cache : {};
2069
+ const varies = [...Array.isArray(cache.varies) ? cache.varies : [], "x-farm-shell"];
2070
+ return [source, { ...rule, cache: { ...cache, varies } }];
2071
+ })
2072
+ );
2073
+ }
2036
2074
  async function writeSSRAssetsToClient(bundle, outputDir) {
2037
2075
  const fs4 = await import("fs/promises");
2038
2076
  for (const [fileName, output] of Object.entries(bundle)) {
@@ -2126,7 +2164,8 @@ function getCachedClientModuleHydrationPlan(modulePath, root, mode, cache, optio
2126
2164
  }
2127
2165
  return { ...plan, isolatedBoundaries: [...plan.isolatedBoundaries] };
2128
2166
  }
2129
- async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = [], routeSlots = [], isolatedClientBoundaryModules = /* @__PURE__ */ new Set(), hydrationPlanCache = /* @__PURE__ */ new Map(), rendererBuildLifetime, programmaticClientRoutes) {
2167
+ async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = [], routeSlots = [], isolatedClientBoundaryModules = /* @__PURE__ */ new Set(), hydrationPlanCache = /* @__PURE__ */ new Map(), rendererBuildLifetime, programmaticClientRoutes, mobile = false) {
2168
+ if (!mobile) await removeFarmMobileClientManifest(path10.dirname(outputDir));
2130
2169
  const viteBuild = productionVite.build;
2131
2170
  const { farmPlugin, farmServerOnlyEntriesPlugin } = await import("./vite.mjs");
2132
2171
  const { PluginManager: PluginManager2 } = await import("./plugin-53SY5YBS.mjs");
@@ -2369,206 +2408,229 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
2369
2408
  logger.info(
2370
2409
  `\u{1F4F1} Total hydratable routes detected: ${clientPages.length} pages, ${clientLayouts.filter((layout) => layout.shouldHydrate || layout.hasIsolatedClientBoundaries).length} layouts, and ${clientRouteSlots.length} slots`
2371
2410
  );
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 = {
2411
+ const buildTarget = async (platform) => {
2412
+ const clientEntryRoot = path10.join(root, ".farm", "tmp");
2413
+ await fs4.mkdir(clientEntryRoot, { recursive: true });
2414
+ const clientEntryDir = await fs4.mkdtemp(path10.join(clientEntryRoot, "client-entry-"));
2415
+ const clientEntryPath = path10.join(clientEntryDir, "farm-client-entry.tsx");
2416
+ const clientHydrationCode = generateClientHydrationEntry(
2417
+ clientPages,
2418
+ clientLayouts,
2419
+ clientRouteSlots,
2418
2420
  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";
2421
+ srcDir,
2422
+ adapterOwnsDocsRuntime ? false : isFarmDocsSearchEnabled(config.docs),
2423
+ adapterOwnsDocsRuntime ? void 0 : resolveFarmDocsSearchClientModule(root),
2424
+ config.docs?.enabled ? getFarmDocsRoots(config.docs).map((docsRoot) => docsRoot.entry) : void 0,
2425
+ adapterOwnsDocsRuntime ? config.docs.adapter?.react : void 0,
2426
+ config.i18n,
2427
+ config.plugins,
2428
+ config.renderer,
2429
+ config.publicRuntimeConfig,
2430
+ config.trailingSlash,
2431
+ getIntegrationProviders(config.integrations),
2432
+ config.basePath,
2433
+ generateClientCachePersistenceCode(resolveFarmClientCacheAdapterEntry(root, config.cache)),
2434
+ adapterOwnsDocsRuntime ? getFarmDocsAdapterConfigModule(config.docs) : void 0,
2435
+ resolveFarmServerComponentsMode(config.experimental?.serverComponents) === "islands",
2436
+ platform
2437
+ );
2438
+ const entryName = platform === "mobile" ? FARM_MOBILE_CLIENT_ENTRY_NAME : "farm-client";
2439
+ await fs4.writeFile(clientEntryPath, clientHydrationCode);
2440
+ const hasScopedPostcssConfig = hasProjectPostcssConfig(root);
2441
+ let postcssSearchPath;
2442
+ let tailwindVitePlugin = void 0;
2443
+ const rendererVitePlugins = await loadFarmRendererVitePlugins(config.renderer, root, {
2444
+ ssr: false,
2445
+ buildLifetime: rendererBuildLifetime
2446
+ });
2447
+ if (hasScopedPostcssConfig) {
2448
+ logger.info("\u{1F4E6} Using project PostCSS/Tailwind configuration");
2449
+ } else {
2450
+ const postcssConfigPath = path10.join(clientEntryDir, "postcss.config.cjs");
2451
+ await fs4.writeFile(postcssConfigPath, "module.exports = { plugins: [] };\n");
2452
+ postcssSearchPath = clientEntryDir;
2453
+ tailwindVitePlugin = await loadTailwindVitePlugin({
2454
+ builder: productionVite.builder,
2455
+ announce: true
2456
+ });
2457
+ }
2458
+ try {
2459
+ const clientViteConfig = {
2460
+ root,
2461
+ // Vite otherwise falls back to <root>/public, silently dropping every
2462
+ // asset in a custom config.publicDir from the production client output.
2463
+ // The mobile client adds to the web client's output; public files are copied once.
2464
+ publicDir: platform === "mobile" ? false : config.publicDir,
2465
+ esbuild: {
2466
+ jsxDev: false
2467
+ },
2468
+ build: {
2469
+ // Preserve Farm's Vite 5 browser baseline when the production builder
2470
+ // uses Vite 8, whose default target only covers newer browsers.
2471
+ target: FARM_CLIENT_BUILD_TARGET,
2472
+ outDir: outputDir,
2473
+ emptyOutDir: platform === "web",
2474
+ // Never public: see resolveFarmClientSourcemap.
2475
+ sourcemap: resolveFarmClientSourcemap(config.vite?.build?.sourcemap),
2476
+ assetsInlineLimit: 0,
2477
+ cssCodeSplit: false,
2478
+ // Bundle all CSS into one file
2479
+ rollupOptions: {
2480
+ input: {
2481
+ [entryName]: clientEntryPath
2482
+ },
2483
+ output: {
2484
+ entryFileNames: "[name]-h[hash].js",
2485
+ chunkFileNames: "chunks/[name]-h[hash].js",
2486
+ hashCharacters: "hex",
2487
+ // Use predictable name for CSS so we can reference it in SSR HTML
2488
+ assetFileNames: (assetInfo) => {
2489
+ if (assetInfo.name?.endsWith(".css")) {
2490
+ return `${entryName}.css`;
2491
+ }
2492
+ return "assets/[name]-h[hash][extname]";
2448
2493
  }
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;
2494
+ },
2495
+ // A browser cannot load a Node builtin: farmServerOnlyEntriesPlugin
2496
+ // resolves one to Farm's browser module for it instead.
2497
+ external: (id) => {
2498
+ if (id === "fsevents" || id.includes("fsevents") || id.endsWith(".node")) {
2499
+ return true;
2500
+ }
2501
+ return false;
2457
2502
  }
2458
- return false;
2459
2503
  }
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({
2504
+ },
2505
+ plugins: [
2506
+ createFarmThemeCssPlugin(config.theme, config.basePath),
2507
+ createFarmPrivateClientSourcemapsPlugin({
2508
+ outDir: path10.join(
2509
+ path10.dirname(outputDir),
2510
+ platform === "mobile" ? `${FARM_CLIENT_SOURCEMAPS_DIR}-mobile` : FARM_CLIENT_SOURCEMAPS_DIR
2511
+ )
2512
+ }),
2513
+ // The web client's preload manifests; the mobile client records its files instead.
2514
+ platform === "mobile" ? createFarmMobileClientManifestPlugin({
2515
+ buildDir: path10.dirname(outputDir),
2516
+ entryName
2517
+ }) : createFarmClientModulePreloadPlugin({
2474
2518
  root,
2475
2519
  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 };
2520
+ entryName: "farm-client"
2521
+ }),
2522
+ ...adapterOwnsDocsRuntime && platform === "web" ? [
2523
+ createFarmDocsModulePreloadPlugin({
2524
+ root,
2525
+ buildDir: path10.dirname(outputDir),
2526
+ importer: clientEntryPath,
2527
+ entryName: "farm-client",
2528
+ modules: [
2529
+ config.docs.adapter.react,
2530
+ getFarmDocsAdapterConfigModule(config.docs)
2531
+ ].filter((specifier) => Boolean(specifier))
2532
+ })
2533
+ ] : [],
2534
+ ...tailwindVitePlugin ? [tailwindVitePlugin] : [],
2535
+ ...rendererVitePlugins,
2536
+ ...config.vite.plugins || [],
2537
+ farmServerOnlyEntriesPlugin({ platform }),
2538
+ farmDocsClientConfigPlugin(
2539
+ adapterOwnsDocsRuntime ? getFarmDocsAdapterConfigModule(config.docs) : void 0
2540
+ ),
2541
+ // Plugin to redirect @farm.js/core imports to client-only exports
2542
+ {
2543
+ name: "farm-client-only-imports",
2544
+ enforce: "pre",
2545
+ resolveId(id) {
2546
+ if (id === "@farm.js/core") {
2547
+ return { id: "\0farm-client-exports", external: false };
2548
+ }
2549
+ if (id === "@farm.js/core/i18n/server") {
2550
+ return { id: "\0farm-i18n-client-bridge", external: false };
2551
+ }
2552
+ 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")) {
2553
+ return { id: "\0empty-module", external: false };
2554
+ }
2555
+ if (id.includes("/api/") && id.includes("/route")) {
2556
+ return { id: "\0empty-api-route", external: false };
2557
+ }
2558
+ 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")) {
2559
+ return { id: "\0empty-module", external: false };
2560
+ }
2561
+ return null;
2562
+ },
2563
+ load(id) {
2564
+ if (id === "\0empty-module") {
2565
+ return "const emptyMiddlewareStore = new Map(); export default {}; export const getMiddlewareContext = () => emptyMiddlewareStore; export const getMiddlewareData = () => emptyMiddlewareStore; export const getMiddlewareValue = () => undefined; export const middleware = () => ({});";
2566
+ }
2567
+ if (id === "\0empty-api-route") {
2568
+ 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 {};";
2569
+ }
2570
+ if (id === "\0farm-i18n-client-bridge") {
2571
+ return 'export { createTranslator, format, getLocale, getLocaleSource, t } from "@farm.js/core/i18n/client";';
2572
+ }
2573
+ if (id === "\0farm-client-exports") {
2574
+ return [
2575
+ "// Farm.js Client Exports - Safe for browser bundling",
2576
+ 'export { Link } from "@farm.js/core/client";',
2577
+ 'export { useRouter } from "@farm.js/core/client";',
2578
+ 'export { usePathname, useSearchParams } from "@farm.js/core/navigation";',
2579
+ // A page that hydrates ships to the browser with its notFound()/redirect() calls.
2580
+ 'export { getFarmRedirectError, isFarmNotFoundError, isFarmRedirectError, notFound, permanentRedirect, redirect } from "@farm.js/core/navigation";',
2581
+ 'export { createAPIClient } from "@farm.js/core/client";',
2582
+ 'export { localFont, remoteFont } from "@farm.js/core/font";'
2583
+ ].join("\n");
2584
+ }
2585
+ return null;
2510
2586
  }
2511
- return null;
2512
2587
  },
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
- }
2588
+ farmPlugin(
2589
+ { ...config, isolatedClientBoundaryModules, programmaticClientRoutes },
2590
+ pluginManager
2591
+ ),
2592
+ farmEnvironmentFunctionsPlugin(config)
2593
+ ],
2594
+ mode: "production",
2595
+ css: postcssSearchPath ? {
2596
+ postcss: postcssSearchPath
2597
+ } : void 0,
2598
+ // Ensure React is bundled for client
2599
+ resolve: {
2600
+ alias: createFarmSourceAlias(root, config.srcDir),
2601
+ dedupe: [...config.renderer.dedupe || []]
2537
2602
  },
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
- ]
2603
+ // Optimize dependencies - exclude server-side code from client bundle
2604
+ optimizeDeps: {
2605
+ exclude: [
2606
+ "@farm.js/core/server",
2607
+ "@farm.js/core/api",
2608
+ "@farm.js/core/middleware",
2609
+ "@farm.js/core/headers"
2610
+ ]
2611
+ }
2612
+ };
2613
+ await viteBuild(mergeFarmProductionViteConfig(clientViteConfig, config.vite));
2614
+ if (platform === "mobile") {
2615
+ await fs4.rm(path10.join(outputDir, `${entryName}.css`), { force: true });
2616
+ if (!await hasFarmMobileClientEntry(path10.dirname(outputDir), outputDir)) {
2617
+ throw new IncompleteClientBuildOutputError(
2618
+ `${FARM_MOBILE_CLIENT_ENTRY_NAME}.js is missing or empty`
2619
+ );
2620
+ }
2621
+ } else {
2622
+ await mergeBuiltFontCss(outputDir);
2623
+ await validateClientBuildOutput(root, srcDir, outputDir);
2624
+ }
2625
+ } finally {
2626
+ try {
2627
+ await fs4.rm(clientEntryDir, { recursive: true, force: true });
2628
+ } catch {
2561
2629
  }
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
2630
  }
2571
- }
2631
+ };
2632
+ await buildTarget("web");
2633
+ if (mobile) await buildTarget("mobile");
2572
2634
  }
2573
2635
  function toBakedMarkdownSourcePath(root, filePath) {
2574
2636
  if (!filePath) return "";
@@ -3444,13 +3506,14 @@ function generateClientHydrationEntry(clientPages, layoutRoutes, clientRouteSlot
3444
3506
  secure: false
3445
3507
  },
3446
3508
  direction: {}
3447
- }, plugins = [], renderer = REACT_RENDERER, publicRuntimeConfig = void 0, trailingSlash = false, integrationProviders = [], basePath = "/", clientCachePersistence = { imports: "", init: "" }, docsConfigModule, islandValues = false) {
3509
+ }, plugins = [], renderer = REACT_RENDERER, publicRuntimeConfig = void 0, trailingSlash = false, integrationProviders = [], basePath = "/", clientCachePersistence = { imports: "", init: "" }, docsConfigModule, islandValues = false, platform) {
3448
3510
  const toImportPath = (targetPath) => targetPath.replace(/\\/g, "/");
3449
3511
  const clientPluginEntry = generateFarmClientPluginEntryCode(
3450
3512
  plugins,
3451
3513
  root,
3452
3514
  srcDir,
3453
- publicRuntimeConfig
3515
+ publicRuntimeConfig,
3516
+ platform
3454
3517
  );
3455
3518
  const appSetupPath = resolveFarmRendererAppSetup(root, renderer);
3456
3519
  const rendererClientImports = isReactRenderer(renderer) ? `import React from "react";
@@ -5961,6 +6024,7 @@ ReactDOMServer.configureApp(__farmAppSetup);`;
5961
6024
  }
5962
6025
  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) {
5963
6026
  const farmIslandsMode = resolveFarmServerComponentsMode(config.experimental?.serverComponents) === "islands";
6027
+ const farmMobileClient = shouldBuildFarmMobileClient(config, { quiet: true });
5964
6028
  const hasCompressionRuntime = config.compress && resolveFarmInstrumentationRuntime(preset) === "nodejs";
5965
6029
  const servesAgentRobotsTxt = Boolean(config.agent?.crawlers?.enabled) && !applicationMetadataRoutes.some(
5966
6030
  (metadata) => metadata.kind === "robots" && metadata.pattern === "/"
@@ -6389,8 +6453,22 @@ function renderFarmServerTreeLayout(Layout, props, outlets) {
6389
6453
  stripFarmLocaleFromPathname,
6390
6454
  withFarmRouteContext,
6391
6455
  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 ? `
6456
+ 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," : ""}
6457
+ } from "@farm.js/core/internal/production-runtime";${farmMobileClient ? `
6458
+ import { _applyFarmMobileShellClient } from "@farm.js/core/internal/production-runtime";
6459
+ // The mobile client documents load when a mobile shell asks for them (RFC 0004, 7.2), filled in
6460
+ // once the client build has finished (see buildNitroUniversal). A shell's document stays out of
6461
+ // shared caches, which the adapter learns as it does for a guarded response.
6462
+ const farmMobileShellClient = JSON.parse("${FARM_MOBILE_SHELL_CLIENT_PLACEHOLDER}");
6463
+ function applyFarmMobileShellResponse(request, response, context) {
6464
+ return _applyFarmMobileShellClient(request, response, farmMobileShellClient, () =>
6465
+ context?.onGuardedResponse?.()
6466
+ );
6467
+ }` : `
6468
+ // No mobile block: no mobile client, and documents ignore X-Farm-Shell.
6469
+ function applyFarmMobileShellResponse(request, response) {
6470
+ return response;
6471
+ }`}${farmIslandsMode ? `
6394
6472
  import { getSharedLayoutPrefixLength, handleFarmFormActionRequest, ignoreFarmHeldValues, installFarmIslandValues, parseFarmLayoutChainHeader } from "@farm.js/core/internal/production-runtime";
6395
6473
  import { installFarmIslandsServer } from "@farm.js/core/internal/islands-server";
6396
6474
  installFarmIslandsServer();
@@ -9125,6 +9203,21 @@ ${hasServerRuntimeIntegrations ? `
9125
9203
  }
9126
9204
  ` : ""}
9127
9205
 
9206
+ ${config.mobileClient ? `
9207
+ // The mobile app's native-tier screens: the page, rendered as for a browser, read into a
9208
+ // tree of native views.
9209
+ if (
9210
+ (request.method === "GET" || request.method === "HEAD") &&
9211
+ request.headers.get("accept")?.includes(${JSON.stringify(FARM_NATIVE_TREE_CONTENT_TYPE)})
9212
+ ) {
9213
+ const treeResponse = await createFarmNativeTreeResponse({
9214
+ request,
9215
+ renderPage: (targetRequest) => fetchFarmInnerRequest(targetRequest, adapterContext),
9216
+ });
9217
+ return applyProductionMiddlewareHeaders(treeResponse, middlewareHeaders);
9218
+ }
9219
+ ` : ""}
9220
+
9128
9221
  ${config.md?.enabled ? `
9129
9222
  if (farmMarkdownConfig?.enabled) {
9130
9223
  const markdownResponse = await createMarkdownMirrorResponse({
@@ -10611,10 +10704,11 @@ async function handleFarmFetch(request, context) {
10611
10704
  ? getFarmRoutePathname(new URL(runtimeRequest.url).pathname)
10612
10705
  : undefined;
10613
10706
  const configured = applyConfiguredResponseHeaders(response, routePathname);
10707
+ // Configured headers may edit the response in place, so check it either way.
10708
+ const guarded = farmGuardedResponse ? _withFarmGuardedResponseCache(configured) : configured;
10614
10709
  return applyFarmPreloadBudget(
10615
10710
  applyFarmCspNonceToResponse(
10616
- // Configured headers may edit the response in place, so check it either way.
10617
- farmGuardedResponse ? _withFarmGuardedResponseCache(configured) : configured,
10711
+ applyFarmMobileShellResponse(runtimeRequest, guarded, context),
10618
10712
  farmSecurityConfig,
10619
10713
  cspNonce,
10620
10714
  ),
@@ -10921,8 +11015,20 @@ async function buildNitroUniversal(config, routeManager, apiRouteManager, server
10921
11015
  ]);
10922
11016
  const encodedDocsModulePreloads = encodeFarmDocsModulePreloads(docsModulePreloads);
10923
11017
  const encodedClientModulePreloads = encodeFarmClientModulePreloads(clientModulePreloads);
11018
+ const encodedMobileShellClient = shouldBuildFarmMobileClient(config, { quiet: true }) ? encodeFarmMobileShellClient(
11019
+ await finalizeFarmMobileClient({
11020
+ buildDir: path10.join(root, distDir),
11021
+ clientOutputDir,
11022
+ webEntry: clientJsSrc,
11023
+ stylesheet: clientCssHref,
11024
+ webFiles: clientModulePreloads?.files ?? []
11025
+ })
11026
+ ) : null;
10924
11027
  for (const output of Object.values(ssrBundle)) {
10925
11028
  if (output.type !== "chunk") continue;
11029
+ if (encodedMobileShellClient && output.code.includes(FARM_MOBILE_SHELL_CLIENT_PLACEHOLDER)) {
11030
+ output.code = output.code.split(FARM_MOBILE_SHELL_CLIENT_PLACEHOLDER).join(encodedMobileShellClient);
11031
+ }
10926
11032
  if (output.code.includes(FARM_DOCS_MODULE_PRELOADS_PLACEHOLDER)) {
10927
11033
  output.code = output.code.split(FARM_DOCS_MODULE_PRELOADS_PLACEHOLDER).join(encodedDocsModulePreloads);
10928
11034
  }
@@ -10937,11 +11043,13 @@ async function buildNitroUniversal(config, routeManager, apiRouteManager, server
10937
11043
  }
10938
11044
  }
10939
11045
  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
- }
11046
+ await Promise.all(
11047
+ Object.entries(ssrBundle).map(async ([fileName, output]) => {
11048
+ const filePath = path10.join(ssrOutputDir, fileName);
11049
+ await fs4.mkdir(path10.dirname(filePath), { recursive: true });
11050
+ await fs4.writeFile(filePath, output.type === "chunk" ? output.code : output.source);
11051
+ })
11052
+ );
10945
11053
  const nitroEntryPath = path10.join(ssrOutputDir, "nitro-entry.mjs");
10946
11054
  const nodeAdapterModule = preset === "node-server" ? resolveNitroRuntimeDependency(root, "srvx/node") : null;
10947
11055
  const hasNitroCacheRouteRules = hasFarmNitroCacheRouteRule(config.routeRules);
@@ -11198,7 +11306,7 @@ function toFarmNodeResponse(request, response) {
11198
11306
  ssrOutputDir,
11199
11307
  ssrEntryFile
11200
11308
  );
11201
- const configuredNitroRouteRules = routeRulesToNitroRouteRules(config.routeRules);
11309
+ const configuredNitroRouteRules = shouldBuildFarmMobileClient(config, { quiet: true }) ? varyFarmNitroCacheRulesByShell(routeRulesToNitroRouteRules(config.routeRules)) : routeRulesToNitroRouteRules(config.routeRules);
11202
11310
  const prerenderNitroRouteRules = Object.fromEntries(
11203
11311
  prerenderRoutes.map((route) => {
11204
11312
  const configuredRule = configuredNitroRouteRules[route] || {};
@@ -11245,10 +11353,18 @@ function toFarmNodeResponse(request, response) {
11245
11353
  // fixed top quality cost a docs app ~20 s of build CPU for a small further
11246
11354
  // saving. Serverless and edge targets sit behind a CDN that compresses.
11247
11355
  ...preset === "node-server" ? { compressPublicAssets: { gzip: true } } : {},
11356
+ // Nitro gzips every server output file at level 9, node_modules included, to
11357
+ // print sizes after the build. A self-hosted server is never shipped compressed,
11358
+ // so list plain sizes; zipped serverless and edge bundles keep the gzip column.
11359
+ ...preset === "node-server" || preset === "bun" ? { logging: { compressedSizes: false } } : {},
11248
11360
  ...prerenderRoutes.length > 0 ? {
11249
11361
  prerender: {
11250
11362
  crawlLinks: false,
11251
11363
  failOnError: true,
11364
+ // Nitro's default renders one route at a time. Each prerender request is
11365
+ // answered independently, as by the production server, so keeping several
11366
+ // in flight overlaps the worker's rendering with this thread's per-route work.
11367
+ concurrency: Math.min(os.availableParallelism(), 8),
11252
11368
  routes: prerenderRoutes
11253
11369
  }
11254
11370
  } : {},
@@ -11346,6 +11462,22 @@ function toFarmNodeResponse(request, response) {
11346
11462
  }
11347
11463
  nitroConfig.minify = useFarmServerMinifier ? false : shouldMinify;
11348
11464
  const nitroInstance = await nitroBuilder.createNitro(nitroConfig);
11465
+ let prerenderOrder = /* @__PURE__ */ new Map();
11466
+ nitroInstance.hooks.hook("prerender:routes", (routes) => {
11467
+ prerenderOrder = new Map(
11468
+ Array.from(routes, (route, index) => {
11469
+ try {
11470
+ return [decodeURI(route), index];
11471
+ } catch {
11472
+ return [route, index];
11473
+ }
11474
+ })
11475
+ );
11476
+ });
11477
+ nitroInstance.hooks.hook("prerender:done", ({ prerenderedRoutes }) => {
11478
+ const orderOf = (route) => prerenderOrder.get(route) ?? Number.MAX_SAFE_INTEGER;
11479
+ prerenderedRoutes.sort((a, b) => orderOf(a.route) - orderOf(b.route));
11480
+ });
11349
11481
  if (config.md?.enabled) {
11350
11482
  nitroInstance.hooks.hook("prerender:generate", (route) => {
11351
11483
  if (!route.contents || !route.contentType?.toLowerCase().includes("html")) return;
@@ -11953,7 +12085,9 @@ async function createFarmProjectModuleSsrEnvironment() {
11953
12085
 
11954
12086
  // src/build/index.ts
11955
12087
  async function build(config, options = {}) {
11956
- return withProductionNodeEnv(() => buildWithProductionNodeEnv(config, options));
12088
+ return withProductionNodeEnv(
12089
+ () => withPackageClientBoundaryCache(() => buildWithProductionNodeEnv(config, options))
12090
+ );
11957
12091
  }
11958
12092
  function createBuildTargetBaseline(config) {
11959
12093
  const preset = config.preset || "node-server";
@@ -12026,6 +12160,9 @@ async function buildWithProductionNodeEnv(inputConfig, options) {
12026
12160
  if (config.docs?.enabled) await loadFarmDocsEngine();
12027
12161
  pluginManager.updateContext({ config });
12028
12162
  const { root, preset, srcDir, distDir, deployOutputDir } = targets;
12163
+ usePackageClientBoundaryCacheFile(
12164
+ path11.resolve(root, distDir, "cache", "client-boundaries.json")
12165
+ );
12029
12166
  logger.info(`\u{1F69C} Building Farm.js application with preset: ${preset}...`);
12030
12167
  await pluginManager.setupPlugins();
12031
12168
  await pluginManager.runHookParallel("beforeBundle", {