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

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 (238) hide show
  1. package/dist/chunk-53MVSX3R.mjs +168 -0
  2. package/dist/chunk-53MVSX3R.mjs.map +1 -0
  3. package/dist/{chunk-AW6I64AP.mjs → chunk-6ZXIQSXE.mjs} +16 -1
  4. package/dist/chunk-6ZXIQSXE.mjs.map +1 -0
  5. package/dist/chunk-7ZVN3YZI.mjs +333 -0
  6. package/dist/chunk-7ZVN3YZI.mjs.map +1 -0
  7. package/dist/{chunk-5EVQFRL2.mjs → chunk-ARCGE2VT.mjs} +2 -2
  8. package/dist/chunk-ARCGE2VT.mjs.map +1 -0
  9. package/dist/{chunk-7N62DNSO.mjs → chunk-H3TE3LOV.mjs} +2 -2
  10. package/dist/{chunk-QTZZ2ISQ.mjs → chunk-KLA67WKG.mjs} +1 -1
  11. package/dist/chunk-KLA67WKG.mjs.map +1 -0
  12. package/dist/{chunk-K5ZTUF22.mjs → chunk-L2PE36GQ.mjs} +7 -3
  13. package/dist/chunk-L2PE36GQ.mjs.map +1 -0
  14. package/dist/{chunk-4LND3PXF.mjs → chunk-OPHK6OJN.mjs} +513 -48
  15. package/dist/chunk-OPHK6OJN.mjs.map +1 -0
  16. package/dist/{chunk-77BOAQHI.mjs → chunk-PNFQQSRA.mjs} +754 -156
  17. package/dist/chunk-PNFQQSRA.mjs.map +1 -0
  18. package/dist/chunk-USLFXFFH.mjs +46 -0
  19. package/dist/chunk-USLFXFFH.mjs.map +1 -0
  20. package/dist/{chunk-4677KXB7.mjs → chunk-VUL55IAX.mjs} +368 -103
  21. package/dist/chunk-VUL55IAX.mjs.map +1 -0
  22. package/dist/client.cjs.map +1 -1
  23. package/dist/client.mjs +1 -1
  24. package/dist/{devtools-A22KUJZT.mjs → devtools-GAZ7F3KL.mjs} +4 -3
  25. package/dist/{devtools-A22KUJZT.mjs.map → devtools-GAZ7F3KL.mjs.map} +1 -1
  26. package/dist/docs.cjs +622 -124
  27. package/dist/docs.cjs.map +1 -1
  28. package/dist/docs.mjs +5 -3
  29. package/dist/font.cjs +19 -2
  30. package/dist/font.cjs.map +1 -1
  31. package/dist/font.mjs +7 -3
  32. package/dist/index.cjs +2235 -689
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.mjs +27 -19
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/internal/build-runtime.cjs +2062 -525
  37. package/dist/internal/build-runtime.cjs.map +1 -1
  38. package/dist/internal/build-runtime.mjs +13 -10
  39. package/dist/internal/client-runtime.cjs +169 -2
  40. package/dist/internal/client-runtime.cjs.map +1 -1
  41. package/dist/internal/client-runtime.mjs +170 -2
  42. package/dist/internal/client-runtime.mjs.map +1 -1
  43. package/dist/internal/config-runtime.cjs +22 -0
  44. package/dist/internal/config-runtime.cjs.map +1 -1
  45. package/dist/internal/config-runtime.mjs +3 -2
  46. package/dist/internal/metadata-image-runtime.cjs +199 -0
  47. package/dist/internal/metadata-image-runtime.cjs.map +1 -0
  48. package/dist/internal/metadata-image-runtime.mjs +8 -0
  49. package/dist/internal/metadata-image-runtime.mjs.map +1 -0
  50. package/dist/internal/production-runtime.cjs +310 -0
  51. package/dist/internal/production-runtime.cjs.map +1 -1
  52. package/dist/internal/production-runtime.mjs +10 -0
  53. package/dist/internal/production-runtime.mjs.map +1 -1
  54. package/dist/navigation.cjs.map +1 -1
  55. package/dist/navigation.mjs +2 -2
  56. package/dist/plugin.cjs +1550 -348
  57. package/dist/plugin.cjs.map +1 -1
  58. package/dist/plugin.mjs +9 -5
  59. package/dist/server.cjs +1663 -419
  60. package/dist/server.cjs.map +1 -1
  61. package/dist/server.mjs +17 -19
  62. package/dist/server.mjs.map +1 -1
  63. package/dist/version.cjs +1 -1
  64. package/dist/version.cjs.map +1 -1
  65. package/dist/version.mjs +1 -1
  66. package/dist/vite.cjs +1604 -358
  67. package/dist/vite.cjs.map +1 -1
  68. package/dist/vite.mjs +9 -5
  69. package/package.json +10 -1
  70. package/types/client.d.ts +115 -4
  71. package/dist/after.d.mts +0 -25
  72. package/dist/after.d.ts +0 -25
  73. package/dist/agent-runtime.d.mts +0 -94
  74. package/dist/agent-runtime.d.ts +0 -94
  75. package/dist/api/route-manager.d.mts +0 -66
  76. package/dist/api/route-manager.d.ts +0 -66
  77. package/dist/api/runtime.d.mts +0 -3
  78. package/dist/api/runtime.d.ts +0 -3
  79. package/dist/api.d.mts +0 -48
  80. package/dist/api.d.ts +0 -48
  81. package/dist/app-BNE2FoZ4.d.mts +0 -302
  82. package/dist/app-DRGUmJ3s.d.ts +0 -302
  83. package/dist/app-markdown.d.mts +0 -22
  84. package/dist/app-markdown.d.ts +0 -22
  85. package/dist/cache.d.mts +0 -192
  86. package/dist/cache.d.ts +0 -192
  87. package/dist/chunk-4677KXB7.mjs.map +0 -1
  88. package/dist/chunk-4LND3PXF.mjs.map +0 -1
  89. package/dist/chunk-5EVQFRL2.mjs.map +0 -1
  90. package/dist/chunk-77BOAQHI.mjs.map +0 -1
  91. package/dist/chunk-AW6I64AP.mjs.map +0 -1
  92. package/dist/chunk-K5ZTUF22.mjs.map +0 -1
  93. package/dist/chunk-QM746KUO.mjs +0 -56
  94. package/dist/chunk-QM746KUO.mjs.map +0 -1
  95. package/dist/chunk-QTZZ2ISQ.mjs.map +0 -1
  96. package/dist/client-BT1mFQas.d.mts +0 -447
  97. package/dist/client-Nn0q4eO4.d.ts +0 -447
  98. package/dist/client-cache-CIlyBlmx.d.ts +0 -6
  99. package/dist/client-cache-D-EZ7XVW.d.mts +0 -6
  100. package/dist/client-plugins-Bc5jHcNr.d.ts +0 -1927
  101. package/dist/client-plugins-jsk-ZLzJ.d.mts +0 -1927
  102. package/dist/client-plugins.d.mts +0 -22
  103. package/dist/client-plugins.d.ts +0 -22
  104. package/dist/client.d.mts +0 -447
  105. package/dist/client.d.ts +0 -447
  106. package/dist/config.d.mts +0 -29
  107. package/dist/config.d.ts +0 -29
  108. package/dist/cron.d.mts +0 -78
  109. package/dist/cron.d.ts +0 -78
  110. package/dist/deferred.d.mts +0 -42
  111. package/dist/deferred.d.ts +0 -42
  112. package/dist/deployment.d.mts +0 -34
  113. package/dist/deployment.d.ts +0 -34
  114. package/dist/docs.d.mts +0 -69
  115. package/dist/docs.d.ts +0 -69
  116. package/dist/env-types.d.mts +0 -12
  117. package/dist/env-types.d.ts +0 -12
  118. package/dist/env.d.mts +0 -45
  119. package/dist/env.d.ts +0 -45
  120. package/dist/environment/vite.d.mts +0 -22
  121. package/dist/environment/vite.d.ts +0 -22
  122. package/dist/environment.d.mts +0 -18
  123. package/dist/environment.d.ts +0 -18
  124. package/dist/font.d.mts +0 -70
  125. package/dist/font.d.ts +0 -70
  126. package/dist/headers.d.mts +0 -22
  127. package/dist/headers.d.ts +0 -22
  128. package/dist/i18n/client.d.mts +0 -32
  129. package/dist/i18n/client.d.ts +0 -32
  130. package/dist/i18n/index.d.mts +0 -20
  131. package/dist/i18n/index.d.ts +0 -20
  132. package/dist/i18n/server.d.mts +0 -30
  133. package/dist/i18n/server.d.ts +0 -30
  134. package/dist/image/server.d.mts +0 -37
  135. package/dist/image/server.d.ts +0 -37
  136. package/dist/image/sharp.d.mts +0 -7
  137. package/dist/image/sharp.d.ts +0 -7
  138. package/dist/image-config-Duob7wER.d.mts +0 -50
  139. package/dist/image-config-Duob7wER.d.ts +0 -50
  140. package/dist/image.d.mts +0 -39
  141. package/dist/image.d.ts +0 -39
  142. package/dist/index.d.mts +0 -455
  143. package/dist/index.d.ts +0 -455
  144. package/dist/integration-api-CHT2OKAf.d.mts +0 -93
  145. package/dist/integration-api-CHT2OKAf.d.ts +0 -93
  146. package/dist/integrations.d.mts +0 -22
  147. package/dist/integrations.d.ts +0 -22
  148. package/dist/internal/build-runtime.d.mts +0 -39
  149. package/dist/internal/build-runtime.d.ts +0 -39
  150. package/dist/internal/client-runtime.d.mts +0 -2
  151. package/dist/internal/client-runtime.d.ts +0 -2
  152. package/dist/internal/config-runtime.d.mts +0 -39
  153. package/dist/internal/config-runtime.d.ts +0 -39
  154. package/dist/internal/production-node-env.d.mts +0 -12
  155. package/dist/internal/production-node-env.d.ts +0 -12
  156. package/dist/internal/production-runtime.d.mts +0 -41
  157. package/dist/internal/production-runtime.d.ts +0 -41
  158. package/dist/markdown.d.mts +0 -60
  159. package/dist/markdown.d.ts +0 -60
  160. package/dist/metadata-7ffpT3jr.d.mts +0 -22
  161. package/dist/metadata-JHn-8eht.d.ts +0 -22
  162. package/dist/middleware.d.mts +0 -164
  163. package/dist/middleware.d.ts +0 -164
  164. package/dist/navigation-errors-Dvwpzaer.d.mts +0 -13
  165. package/dist/navigation-errors-Dvwpzaer.d.ts +0 -13
  166. package/dist/navigation.d.mts +0 -14
  167. package/dist/navigation.d.ts +0 -14
  168. package/dist/observability.d.mts +0 -335
  169. package/dist/observability.d.ts +0 -335
  170. package/dist/params-BALtrRim.d.ts +0 -15
  171. package/dist/params-ry-lxqmy.d.mts +0 -15
  172. package/dist/plugin-BJDf43dc.d.mts +0 -165
  173. package/dist/plugin-BJDf43dc.d.ts +0 -165
  174. package/dist/plugin.d.mts +0 -22
  175. package/dist/plugin.d.ts +0 -22
  176. package/dist/production-runtime-9KG7GuvW.d.ts +0 -79
  177. package/dist/production-runtime-B-fweKts.d.mts +0 -79
  178. package/dist/production-runtime-C_B79w2P.d.mts +0 -28
  179. package/dist/production-runtime-DDEM1D2q.d.ts +0 -28
  180. package/dist/query/client.d.mts +0 -61
  181. package/dist/query/client.d.ts +0 -61
  182. package/dist/query/index.d.mts +0 -90
  183. package/dist/query/index.d.ts +0 -90
  184. package/dist/query/parsers.d.mts +0 -25
  185. package/dist/query/parsers.d.ts +0 -25
  186. package/dist/query/server.d.mts +0 -55
  187. package/dist/query/server.d.ts +0 -55
  188. package/dist/request-Dsq4kGW0.d.mts +0 -6
  189. package/dist/request-udtobOLv.d.ts +0 -6
  190. package/dist/request.d.mts +0 -2
  191. package/dist/request.d.ts +0 -2
  192. package/dist/resolver-DJqjLMg_.d.mts +0 -14
  193. package/dist/resolver-IH4RmPEl.d.ts +0 -14
  194. package/dist/route-runtime-DoOHzCAD.d.mts +0 -38
  195. package/dist/route-runtime-DoOHzCAD.d.ts +0 -38
  196. package/dist/router.d.mts +0 -36
  197. package/dist/router.d.ts +0 -36
  198. package/dist/routes.d.mts +0 -224
  199. package/dist/routes.d.ts +0 -224
  200. package/dist/runtime-9nQjVM7X.d.mts +0 -206
  201. package/dist/runtime-Cxpq6xZN.d.mts +0 -27
  202. package/dist/runtime-DgeS2skB.d.ts +0 -206
  203. package/dist/runtime-bv63eUiO.d.ts +0 -27
  204. package/dist/server-action-security.d.mts +0 -43
  205. package/dist/server-action-security.d.ts +0 -43
  206. package/dist/server-fn-client.d.mts +0 -32
  207. package/dist/server-fn-client.d.ts +0 -32
  208. package/dist/server-fn.d.mts +0 -93
  209. package/dist/server-fn.d.ts +0 -93
  210. package/dist/server-plugins.d.mts +0 -55
  211. package/dist/server-plugins.d.ts +0 -55
  212. package/dist/server-query-client.d.mts +0 -50
  213. package/dist/server-query-client.d.ts +0 -50
  214. package/dist/server-query.d.mts +0 -36
  215. package/dist/server-query.d.ts +0 -36
  216. package/dist/server.d.mts +0 -48
  217. package/dist/server.d.ts +0 -48
  218. package/dist/storage.d.mts +0 -52
  219. package/dist/storage.d.ts +0 -52
  220. package/dist/testing.d.mts +0 -101
  221. package/dist/testing.d.ts +0 -101
  222. package/dist/transport-BmbGTXA5.d.mts +0 -49
  223. package/dist/transport-BmbGTXA5.d.ts +0 -49
  224. package/dist/types-BMxWr97v.d.mts +0 -81
  225. package/dist/types-BMxWr97v.d.ts +0 -81
  226. package/dist/types-C9N-nk5R.d.mts +0 -53
  227. package/dist/types-C9N-nk5R.d.ts +0 -53
  228. package/dist/types-D1A6-XvH.d.mts +0 -73
  229. package/dist/types-D1A6-XvH.d.ts +0 -73
  230. package/dist/utils-CA0z0c-2.d.ts +0 -23
  231. package/dist/utils-mYVkSOt2.d.mts +0 -23
  232. package/dist/version.d.mts +0 -3
  233. package/dist/version.d.ts +0 -3
  234. package/dist/vite.d.mts +0 -22
  235. package/dist/vite.d.ts +0 -22
  236. package/dist/workflows.d.mts +0 -110
  237. package/dist/workflows.d.ts +0 -110
  238. /package/dist/{chunk-7N62DNSO.mjs.map → chunk-H3TE3LOV.mjs.map} +0 -0
@@ -784,9 +784,9 @@ function getFarmIntegrationPluginServerRuntime(plugin) {
784
784
  const value = plugin[FARM_INTEGRATION_PLUGIN_SERVER_RUNTIME];
785
785
  return typeof value === "boolean" ? value : void 0;
786
786
  }
787
- function defineTypedIntegrationRoute(method, path29, input) {
787
+ function defineTypedIntegrationRoute(method, path31, input) {
788
788
  return {
789
- path: path29,
789
+ path: path31,
790
790
  method,
791
791
  middleware: input.middleware,
792
792
  before: input.before,
@@ -796,7 +796,7 @@ function defineTypedIntegrationRoute(method, path29, input) {
796
796
  input: normalizeIntegrationRouteInputSchemas(input),
797
797
  handler: input.handler,
798
798
  __operation: defineIntegrationAPIOperation({
799
- path: path29,
799
+ path: path31,
800
800
  method,
801
801
  bodyFormat: input.bodyFormat,
802
802
  responseFormat: input.responseFormat,
@@ -808,52 +808,52 @@ function defineTypedIntegrationRoute(method, path29, input) {
808
808
  }
809
809
  function createIntegrationRouteFactory() {
810
810
  return {
811
- get(path29, input) {
811
+ get(path31, input) {
812
812
  return defineTypedIntegrationRoute(
813
813
  "GET",
814
- path29,
814
+ path31,
815
815
  input
816
816
  );
817
817
  },
818
- post(path29, input) {
818
+ post(path31, input) {
819
819
  return defineTypedIntegrationRoute(
820
820
  "POST",
821
- path29,
821
+ path31,
822
822
  {
823
823
  bodyFormat: "json",
824
824
  ...input
825
825
  }
826
826
  );
827
827
  },
828
- put(path29, input) {
828
+ put(path31, input) {
829
829
  return defineTypedIntegrationRoute(
830
830
  "PUT",
831
- path29,
831
+ path31,
832
832
  {
833
833
  bodyFormat: "json",
834
834
  ...input
835
835
  }
836
836
  );
837
837
  },
838
- patch(path29, input) {
839
- return defineTypedIntegrationRoute("PATCH", path29, {
838
+ patch(path31, input) {
839
+ return defineTypedIntegrationRoute("PATCH", path31, {
840
840
  bodyFormat: "json",
841
841
  ...input
842
842
  });
843
843
  },
844
- delete(path29, input) {
845
- return defineTypedIntegrationRoute("DELETE", path29, {
844
+ delete(path31, input) {
845
+ return defineTypedIntegrationRoute("DELETE", path31, {
846
846
  bodyFormat: "json",
847
847
  ...input
848
848
  });
849
849
  },
850
- options(path29, input) {
851
- return defineTypedIntegrationRoute("OPTIONS", path29, input);
850
+ options(path31, input) {
851
+ return defineTypedIntegrationRoute("OPTIONS", path31, input);
852
852
  },
853
- head(path29, input) {
853
+ head(path31, input) {
854
854
  return defineTypedIntegrationRoute(
855
855
  "HEAD",
856
- path29,
856
+ path31,
857
857
  input
858
858
  );
859
859
  }
@@ -1070,8 +1070,8 @@ async function parseIntegrationConfigSchema(integration, schema, value) {
1070
1070
  function createIntegrationConfigValidationError(integration, error) {
1071
1071
  const issues = Array.isArray(error.issues) && error.issues.length > 0 ? error.issues.map((issue) => {
1072
1072
  const normalizedPath = normalizeIntegrationValidationPath(issue.path);
1073
- const path29 = normalizedPath.length ? `${normalizedPath.join(".")}: ` : "";
1074
- return `${path29}${issue.message || "Invalid config"}`;
1073
+ const path31 = normalizedPath.length ? `${normalizedPath.join(".")}: ` : "";
1074
+ return `${path31}${issue.message || "Invalid config"}`;
1075
1075
  }).join("; ") : error.message || "Invalid config";
1076
1076
  return new Error(`Integration "${integration.type}" config validation failed: ${issues}`);
1077
1077
  }
@@ -1756,8 +1756,8 @@ function normalizeIntegrationValidationIssues(source, error) {
1756
1756
  }
1757
1757
  ];
1758
1758
  }
1759
- function normalizeIntegrationValidationPath(path29) {
1760
- return (path29 || []).map((segment) => {
1759
+ function normalizeIntegrationValidationPath(path31) {
1760
+ return (path31 || []).map((segment) => {
1761
1761
  const key = typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment;
1762
1762
  return typeof key === "symbol" ? key.description || key.toString() : key;
1763
1763
  });
@@ -2956,26 +2956,26 @@ async function prepareFarmWorkflowsForNitro(config) {
2956
2956
  const root = config.root || process.cwd();
2957
2957
  const distDir = config.distDir || ".farm";
2958
2958
  const fs8 = await import("fs/promises");
2959
- const path29 = await import("path");
2960
- const generatedDir = path29.join(root, distDir, ".nitro", "farm-workflows");
2959
+ const path31 = await import("path");
2960
+ const generatedDir = path31.join(root, distDir, ".nitro", "farm-workflows");
2961
2961
  await fs8.mkdir(generatedDir, { recursive: true });
2962
2962
  const tasks = {};
2963
2963
  const scheduledTasks = createScheduledTasks(workflows);
2964
2964
  for (const workflow of workflows) {
2965
- const wrapperPath = path29.join(generatedDir, `${safeFileName(workflow.id)}.mjs`);
2965
+ const wrapperPath = path31.join(generatedDir, `${safeFileName(workflow.id)}.mjs`);
2966
2966
  await fs8.writeFile(wrapperPath, createNitroTaskWrapper(workflow), "utf8");
2967
2967
  tasks[workflow.id] = {
2968
2968
  handler: wrapperPath,
2969
2969
  description: workflow.description || `Farm workflow ${workflow.id}`
2970
2970
  };
2971
2971
  }
2972
- const handlerPath = path29.join(generatedDir, "http-handler.mjs");
2972
+ const handlerPath = path31.join(generatedDir, "http-handler.mjs");
2973
2973
  await fs8.writeFile(
2974
2974
  handlerPath,
2975
2975
  createNitroWorkflowHTTPHandler(workflowConfig, workflows),
2976
2976
  "utf8"
2977
2977
  );
2978
- const manifestPath = path29.join(generatedDir, "manifest.json");
2978
+ const manifestPath = path31.join(generatedDir, "manifest.json");
2979
2979
  await fs8.writeFile(
2980
2980
  manifestPath,
2981
2981
  JSON.stringify(
@@ -3058,10 +3058,10 @@ function resolveWorkflowDefinition(module2) {
3058
3058
  }
3059
3059
  async function findWorkflowFiles(root, dirs) {
3060
3060
  const fs8 = await import("fs/promises");
3061
- const path29 = await import("path");
3061
+ const path31 = await import("path");
3062
3062
  const files = [];
3063
3063
  for (const dir of dirs) {
3064
- const absoluteDir = path29.isAbsolute(dir) ? dir : path29.join(root, dir);
3064
+ const absoluteDir = path31.isAbsolute(dir) ? dir : path31.join(root, dir);
3065
3065
  if (!await pathExists(absoluteDir)) continue;
3066
3066
  await walkWorkflowDir(absoluteDir, files);
3067
3067
  }
@@ -3069,10 +3069,10 @@ async function findWorkflowFiles(root, dirs) {
3069
3069
  }
3070
3070
  async function walkWorkflowDir(dir, files) {
3071
3071
  const fs8 = await import("fs/promises");
3072
- const path29 = await import("path");
3072
+ const path31 = await import("path");
3073
3073
  const entries = await fs8.readdir(dir, { withFileTypes: true });
3074
3074
  for (const entry of entries) {
3075
- const filePath = path29.join(dir, entry.name);
3075
+ const filePath = path31.join(dir, entry.name);
3076
3076
  if (entry.isDirectory()) {
3077
3077
  if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
3078
3078
  await walkWorkflowDir(filePath, files);
@@ -3092,12 +3092,12 @@ function isWorkflowFile(fileName) {
3092
3092
  }
3093
3093
  async function loadWorkflowModule(filePath, root) {
3094
3094
  const fs8 = await import("fs/promises");
3095
- const path29 = await import("path");
3095
+ const path31 = await import("path");
3096
3096
  const { pathToFileURL: pathToFileURL5 } = await import("url");
3097
3097
  const { build: build2 } = await import("esbuild");
3098
- const outDir = path29.join(root, ".farm", ".workflow-loader");
3098
+ const outDir = path31.join(root, ".farm", ".workflow-loader");
3099
3099
  await fs8.mkdir(outDir, { recursive: true });
3100
- const outfile = path29.join(
3100
+ const outfile = path31.join(
3101
3101
  outDir,
3102
3102
  `workflow-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`
3103
3103
  );
@@ -3376,9 +3376,9 @@ async function prepareFarmCronForNitro(config) {
3376
3376
  const root = config.root || process.cwd();
3377
3377
  const distDir = config.distDir || ".farm";
3378
3378
  const fs8 = await import("fs/promises");
3379
- const path29 = await import("path");
3380
- const manifestPath = path29.join(root, distDir, FARM_CRON_MANIFEST);
3381
- const generatedDir = path29.join(root, distDir, ".nitro", "farm-cron");
3379
+ const path31 = await import("path");
3380
+ const manifestPath = path31.join(root, distDir, FARM_CRON_MANIFEST);
3381
+ const generatedDir = path31.join(root, distDir, ".nitro", "farm-cron");
3382
3382
  if (!cron.enabled) {
3383
3383
  await Promise.all([
3384
3384
  fs8.rm(manifestPath, { force: true }),
@@ -3395,7 +3395,7 @@ async function prepareFarmCronForNitro(config) {
3395
3395
  const tasks = {};
3396
3396
  for (const job of cron.jobs) {
3397
3397
  const taskName = getFarmCronTaskName(job.name);
3398
- const wrapperPath = path29.join(generatedDir, `${safeFileName2(job.name)}.mjs`);
3398
+ const wrapperPath = path31.join(generatedDir, `${safeFileName2(job.name)}.mjs`);
3399
3399
  await fs8.writeFile(wrapperPath, createNitroCronTaskWrapper(job, cron.secretEnv), "utf8");
3400
3400
  tasks[taskName] = {
3401
3401
  handler: wrapperPath,
@@ -3403,7 +3403,7 @@ async function prepareFarmCronForNitro(config) {
3403
3403
  };
3404
3404
  }
3405
3405
  const manifest = createFarmCronManifest(cron);
3406
- await fs8.mkdir(path29.dirname(manifestPath), { recursive: true });
3406
+ await fs8.mkdir(path31.dirname(manifestPath), { recursive: true });
3407
3407
  await fs8.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
3408
3408
  `, "utf8");
3409
3409
  return {
@@ -3485,7 +3485,7 @@ function normalizeCronJob(name, job) {
3485
3485
  if (!job || typeof job !== "object" || Array.isArray(job)) {
3486
3486
  throw new TypeError(`Farm cron ${JSON.stringify(name)} must be a configuration object.`);
3487
3487
  }
3488
- const path29 = normalizeCronPath(name, job.path);
3488
+ const path31 = normalizeCronPath(name, job.path);
3489
3489
  const rawSchedule = Array.isArray(job.schedule) ? job.schedule : [job.schedule];
3490
3490
  const schedule = [...new Set(rawSchedule.map((value) => normalizeCronExpression(name, value)))];
3491
3491
  if (schedule.length === 0) {
@@ -3494,7 +3494,7 @@ function normalizeCronJob(name, job) {
3494
3494
  return {
3495
3495
  name,
3496
3496
  schedule,
3497
- path: path29,
3497
+ path: path31,
3498
3498
  description: job.description?.trim() || void 0
3499
3499
  };
3500
3500
  }
@@ -3502,13 +3502,13 @@ function normalizeCronPath(name, value) {
3502
3502
  if (typeof value !== "string" || !value.trim().startsWith("/")) {
3503
3503
  throw new TypeError(`Farm cron ${JSON.stringify(name)} path must start with "/".`);
3504
3504
  }
3505
- const path29 = value.trim();
3506
- if (path29.startsWith("//") || path29.includes("?") || path29.includes("#")) {
3505
+ const path31 = value.trim();
3506
+ if (path31.startsWith("//") || path31.includes("?") || path31.includes("#")) {
3507
3507
  throw new TypeError(
3508
3508
  `Farm cron ${JSON.stringify(name)} path must be an application pathname without a host, query, or hash.`
3509
3509
  );
3510
3510
  }
3511
- return path29.length > 1 ? path29.replace(/\/+$/, "") : path29;
3511
+ return path31.length > 1 ? path31.replace(/\/+$/, "") : path31;
3512
3512
  }
3513
3513
  function normalizeCronExpression(name, value) {
3514
3514
  if (typeof value !== "string") {
@@ -4904,8 +4904,8 @@ function createFarmDeploymentMismatchResponse(mismatch) {
4904
4904
  }
4905
4905
  );
4906
4906
  }
4907
- function createFarmDeploymentCookie(deploymentId, path29 = "/", secure = false) {
4908
- const normalizedPath = path29.startsWith("/") ? path29 : `/${path29}`;
4907
+ function createFarmDeploymentCookie(deploymentId, path31 = "/", secure = false) {
4908
+ const normalizedPath = path31.startsWith("/") ? path31 : `/${path31}`;
4909
4909
  return [
4910
4910
  `${FARM_DEPLOYMENT_COOKIE}=${encodeURIComponent(deploymentId)}`,
4911
4911
  `Path=${normalizedPath}`,
@@ -4976,7 +4976,7 @@ var init_devtools_config = __esm({
4976
4976
 
4977
4977
  // src/image-config.ts
4978
4978
  function resolveFarmImageConfig(config) {
4979
- const path29 = normalizeImagePath(config?.path ?? DEFAULT_FARM_IMAGE_PATH);
4979
+ const path31 = normalizeImagePath(config?.path ?? DEFAULT_FARM_IMAGE_PATH);
4980
4980
  const deviceSizes = normalizeIntegerList(
4981
4981
  config?.deviceSizes ?? DEFAULT_FARM_IMAGE_DEVICE_SIZES,
4982
4982
  "images.deviceSizes"
@@ -5004,7 +5004,7 @@ function resolveFarmImageConfig(config) {
5004
5004
  );
5005
5005
  return Object.freeze({
5006
5006
  provider: config?.provider ?? "auto",
5007
- path: path29,
5007
+ path: path31,
5008
5008
  domains: Object.freeze([
5009
5009
  ...new Set(
5010
5010
  (config?.domains ?? []).map((domain) => domain.trim().toLowerCase()).filter(Boolean)
@@ -5043,11 +5043,11 @@ function getPublicFarmImageConfig(config) {
5043
5043
  };
5044
5044
  }
5045
5045
  function normalizeImagePath(value) {
5046
- const path29 = value.trim().replace(/\/+$/, "") || "/";
5047
- if (!path29.startsWith("/") || path29.includes("?") || path29.includes("#")) {
5046
+ const path31 = value.trim().replace(/\/+$/, "") || "/";
5047
+ if (!path31.startsWith("/") || path31.includes("?") || path31.includes("#")) {
5048
5048
  throw new TypeError("images.path must be an absolute pathname without a query or hash");
5049
5049
  }
5050
- return path29;
5050
+ return path31;
5051
5051
  }
5052
5052
  function normalizeIntegerList(values, name, max) {
5053
5053
  if (values.length === 0) {
@@ -5361,6 +5361,33 @@ var init_auth_config = __esm({
5361
5361
  }
5362
5362
  });
5363
5363
 
5364
+ // src/preload.ts
5365
+ function resolveFarmPerformanceConfig(config) {
5366
+ return {
5367
+ preload: {
5368
+ mode: config?.preload?.mode === "warn" ? "warn" : "enforce",
5369
+ maxImages: normalizeBudget(config?.preload?.maxImages, DEFAULT_PRELOAD_CONFIG.maxImages),
5370
+ maxFonts: normalizeBudget(config?.preload?.maxFonts, DEFAULT_PRELOAD_CONFIG.maxFonts)
5371
+ }
5372
+ };
5373
+ }
5374
+ function normalizeBudget(value, fallback) {
5375
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
5376
+ }
5377
+ var DEFAULT_PRELOAD_CONFIG;
5378
+ var init_preload = __esm({
5379
+ "src/preload.ts"() {
5380
+ "use strict";
5381
+ DEFAULT_PRELOAD_CONFIG = {
5382
+ mode: "enforce",
5383
+ maxImages: 1,
5384
+ maxFonts: 2
5385
+ };
5386
+ __name(resolveFarmPerformanceConfig, "resolveFarmPerformanceConfig");
5387
+ __name(normalizeBudget, "normalizeBudget");
5388
+ }
5389
+ });
5390
+
5364
5391
  // src/config-entry.ts
5365
5392
  var init_config_entry = __esm({
5366
5393
  "src/config-entry.ts"() {
@@ -5481,18 +5508,18 @@ function sanitizeDocsConfig(config) {
5481
5508
  return cloneSerializable(config) || {};
5482
5509
  }
5483
5510
  async function findDocsConfigPath(rootDir, configPath) {
5484
- const { existsSync: existsSync16 } = await import("fs");
5511
+ const { existsSync: existsSync17 } = await import("fs");
5485
5512
  const root = import_path2.default.resolve(rootDir || process.cwd());
5486
5513
  if (configPath) {
5487
5514
  const resolvedPath = import_path2.default.isAbsolute(configPath) ? configPath : import_path2.default.join(root, configPath);
5488
- if (!existsSync16(resolvedPath)) {
5515
+ if (!existsSync17(resolvedPath)) {
5489
5516
  throw new Error(`Could not find docs config at ${configPath}.`);
5490
5517
  }
5491
5518
  return import_path2.default.resolve(resolvedPath);
5492
5519
  }
5493
5520
  for (const filename of DOCS_CONFIG_FILENAMES) {
5494
5521
  const resolvedPath = import_path2.default.join(root, filename);
5495
- if (existsSync16(resolvedPath)) {
5522
+ if (existsSync17(resolvedPath)) {
5496
5523
  return resolvedPath;
5497
5524
  }
5498
5525
  }
@@ -5680,6 +5707,7 @@ async function resolveConfig(userConfig, mode) {
5680
5707
  headers: /* @__PURE__ */ __name(() => [...headers, ...routeRuleHeaders], "headers"),
5681
5708
  routeRules,
5682
5709
  images: resolveFarmImageConfig(userConfig.images),
5710
+ performance: resolveFarmPerformanceConfig(userConfig.performance),
5683
5711
  publicDir: userConfig.publicDir || "public",
5684
5712
  i18n: resolveFarmI18nConfig(userConfig.i18n, { root, mode }),
5685
5713
  openapi: {
@@ -5718,7 +5746,7 @@ async function resolveConfig(userConfig, mode) {
5718
5746
  return resolved;
5719
5747
  }
5720
5748
  async function loadConfig(rootDir, configPath, mode = process.env.NODE_ENV === "production" ? "production" : "development", loadEnvironment) {
5721
- const { existsSync: existsSync16 } = await import("fs");
5749
+ const { existsSync: existsSync17 } = await import("fs");
5722
5750
  const loadEnv = loadEnvironment || (await import("vite")).loadEnv;
5723
5751
  const root = rootDir || process.cwd();
5724
5752
  const loadedEnv = loadEnv(mode, root, "");
@@ -5742,7 +5770,7 @@ async function loadConfig(rootDir, configPath, mode = process.env.NODE_ENV === "
5742
5770
  try {
5743
5771
  const absolutePath = relativePath2.startsWith("/") ? relativePath2 : import_path2.default.join(root, relativePath2);
5744
5772
  const normalizedPath = import_path2.default.resolve(absolutePath);
5745
- if (!existsSync16(normalizedPath)) {
5773
+ if (!existsSync17(normalizedPath)) {
5746
5774
  continue;
5747
5775
  }
5748
5776
  const loadedConfig = await loadFarmConfigFile(normalizedPath, { root });
@@ -5773,6 +5801,7 @@ var init_config2 = __esm({
5773
5801
  init_image_config();
5774
5802
  init_config();
5775
5803
  init_auth_config();
5804
+ init_preload();
5776
5805
  init_config_entry();
5777
5806
  FARM_RESOLVED_CUSTOM_CONTEXT = /* @__PURE__ */ Symbol.for("farm.resolvedCustomContext");
5778
5807
  __name(hasCustomFarmRouteContext, "hasCustomFarmRouteContext");
@@ -6140,6 +6169,210 @@ async function resolveRouteRenderingConfigFromFile(mod, filePath) {
6140
6169
  const source = await (0, import_promises3.readFile)(filePath, "utf8").catch(() => void 0);
6141
6170
  return resolveRouteRenderingConfig(mod, source);
6142
6171
  }
6172
+ function analyzeStaticRouteCandidate(mod, source, options = {}) {
6173
+ const blockers = [];
6174
+ if (!source) {
6175
+ blockers.push("route source is unavailable");
6176
+ }
6177
+ if (options.isDynamic) {
6178
+ blockers.push("the route has dynamic path segments");
6179
+ }
6180
+ if (hasExplicitRenderingConfig(mod, source)) {
6181
+ blockers.push("the route already has explicit rendering config");
6182
+ }
6183
+ if (source) {
6184
+ blockers.push(...findRequestBoundSourceBlockers(source));
6185
+ }
6186
+ return {
6187
+ candidate: blockers.length === 0,
6188
+ blockers
6189
+ };
6190
+ }
6191
+ function findRequestBoundSourceBlockers(source) {
6192
+ const blockers = /* @__PURE__ */ new Set();
6193
+ const code = stripCommentsAndLiteralContents(source);
6194
+ const sourceWithoutComments = stripComments(source);
6195
+ for (const binding of readRequestApiImportBindings(sourceWithoutComments)) {
6196
+ if (new RegExp(`\\b${escapeRegExp2(binding.local)}\\s*(?:\\?\\.\\s*)?\\(`).test(code)) {
6197
+ blockers.add(`the route reads ${binding.label}`);
6198
+ }
6199
+ }
6200
+ for (const namespace of readNamespaceImportBindings(sourceWithoutComments)) {
6201
+ for (const [name, label] of REQUEST_API_LABELS) {
6202
+ if (new RegExp(
6203
+ `\\b${escapeRegExp2(namespace)}\\s*(?:\\?\\.\\s*|\\.\\s*)${name}\\s*(?:\\?\\.\\s*)?\\(`
6204
+ ).test(code)) {
6205
+ blockers.add(`the route reads ${label}`);
6206
+ }
6207
+ }
6208
+ }
6209
+ const params = readDefaultRouteParameters(code);
6210
+ if (params) {
6211
+ for (const [name, label] of ROUTE_PROP_LABELS) {
6212
+ if (new RegExp(`\\b${name}\\b`).test(params)) {
6213
+ blockers.add(`the route reads ${label}`);
6214
+ }
6215
+ }
6216
+ const propsName = params.match(/^\s*([A-Za-z_$][\w$]*)\s*(?::|,|$)/)?.[1];
6217
+ if (propsName) {
6218
+ for (const [name, label] of ROUTE_PROP_LABELS) {
6219
+ if (new RegExp(`\\b${escapeRegExp2(propsName)}\\s*\\.\\s*${name}\\b`).test(code)) {
6220
+ blockers.add(`the route reads ${label}`);
6221
+ }
6222
+ if (new RegExp(`\\{[^}]*\\b${name}\\b[^}]*\\}\\s*=\\s*${escapeRegExp2(propsName)}\\b`).test(
6223
+ code
6224
+ )) {
6225
+ blockers.add(`the route reads ${label}`);
6226
+ }
6227
+ }
6228
+ }
6229
+ }
6230
+ return [...blockers];
6231
+ }
6232
+ function readRequestApiImportBindings(source) {
6233
+ const bindings = [];
6234
+ for (const clause of readStaticImportClauses(source)) {
6235
+ const namedGroup = clause.match(/\{([\s\S]*?)\}/)?.[1];
6236
+ for (const rawSpecifier of (namedGroup ?? "").split(",")) {
6237
+ const specifier = rawSpecifier.trim().replace(/^type\s+/, "");
6238
+ const imported = specifier.match(/^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/);
6239
+ if (!imported?.[1]) continue;
6240
+ const label = REQUEST_API_LABELS.get(imported[1]);
6241
+ if (label) bindings.push({ local: imported[2] ?? imported[1], label });
6242
+ }
6243
+ const local = clause.match(/^\s*([A-Za-z_$][\w$]*)\s*(?:,|$)/)?.[1];
6244
+ if (local) {
6245
+ const label = REQUEST_API_LABELS.get(local);
6246
+ if (label) bindings.push({ local, label });
6247
+ }
6248
+ }
6249
+ return bindings;
6250
+ }
6251
+ function readNamespaceImportBindings(source) {
6252
+ return readStaticImportClauses(source).map((clause) => clause.match(/\*\s*as\s*([A-Za-z_$][\w$]*)/)?.[1]).filter((binding) => Boolean(binding));
6253
+ }
6254
+ function readStaticImportClauses(source) {
6255
+ return [...source.matchAll(/\bimport\s+(?!\()([\s\S]*?)\s+from\s*["'][^"']+["']/g)].map((match) => match[1]).filter((clause) => Boolean(clause));
6256
+ }
6257
+ function readDefaultRouteParameters(code) {
6258
+ const inlineParams = code.match(/\bexport\s+default\s+(?:async\s+)?function\b[^(]*\(([^)]*)\)/)?.[1] ?? code.match(/\bexport\s+default\s+(?:async\s+)?\(([^)]*)\)\s*=>/)?.[1];
6259
+ if (inlineParams !== void 0) return inlineParams;
6260
+ const binding = code.match(/\bexport\s+default\s+([A-Za-z_$][\w$]*)\s*;?/)?.[1] ?? code.match(/\bexport\s*\{\s*([A-Za-z_$][\w$]*)\s+as\s+default\s*\}/)?.[1];
6261
+ if (!binding) return void 0;
6262
+ const escapedBinding = escapeRegExp2(binding);
6263
+ return code.match(new RegExp(`\\bfunction\\s+${escapedBinding}\\s*\\(([^)]*)\\)`))?.[1] ?? code.match(
6264
+ new RegExp(
6265
+ `\\b(?:const|let|var)\\s+${escapedBinding}\\s*=\\s*(?:async\\s+)?\\(([^)]*)\\)\\s*=>`
6266
+ )
6267
+ )?.[1] ?? code.match(
6268
+ new RegExp(`\\b(?:const|let|var)\\s+${escapedBinding}\\s*=\\s*function\\s*\\(([^)]*)\\)`)
6269
+ )?.[1];
6270
+ }
6271
+ function stripCommentsAndLiteralContents(source) {
6272
+ return sanitizeSource(source, true);
6273
+ }
6274
+ function stripComments(source) {
6275
+ return sanitizeSource(source, false);
6276
+ }
6277
+ function sanitizeSource(source, maskLiterals) {
6278
+ const output = [...source];
6279
+ const mask = /* @__PURE__ */ __name((index) => {
6280
+ if (output[index] !== "\n" && output[index] !== "\r") output[index] = " ";
6281
+ }, "mask");
6282
+ const scanQuoted = /* @__PURE__ */ __name((start, quote) => {
6283
+ let index = start;
6284
+ if (maskLiterals) mask(index);
6285
+ index += 1;
6286
+ while (index < source.length) {
6287
+ if (source[index] === "\\") {
6288
+ if (maskLiterals) mask(index);
6289
+ if (index + 1 < source.length && maskLiterals) mask(index + 1);
6290
+ index += 2;
6291
+ continue;
6292
+ }
6293
+ const character = source[index];
6294
+ if (maskLiterals) mask(index);
6295
+ index += 1;
6296
+ if (character === quote) break;
6297
+ }
6298
+ return index;
6299
+ }, "scanQuoted");
6300
+ const scanCode = /* @__PURE__ */ __name((start, stopAtTemplateBrace) => {
6301
+ let index = start;
6302
+ let braceDepth = 0;
6303
+ while (index < source.length) {
6304
+ const character = source[index];
6305
+ const next = source[index + 1];
6306
+ if (character === "/" && next === "/") {
6307
+ while (index < source.length && source[index] !== "\n" && source[index] !== "\r") {
6308
+ mask(index++);
6309
+ }
6310
+ continue;
6311
+ }
6312
+ if (character === "/" && next === "*") {
6313
+ mask(index++);
6314
+ mask(index++);
6315
+ while (index < source.length) {
6316
+ const closesComment = source[index] === "*" && source[index + 1] === "/";
6317
+ mask(index++);
6318
+ if (closesComment) {
6319
+ mask(index++);
6320
+ break;
6321
+ }
6322
+ }
6323
+ continue;
6324
+ }
6325
+ if (character === "'" || character === '"') {
6326
+ index = scanQuoted(index, character);
6327
+ continue;
6328
+ }
6329
+ if (character === "`") {
6330
+ if (maskLiterals) mask(index);
6331
+ index += 1;
6332
+ while (index < source.length) {
6333
+ if (source[index] === "\\") {
6334
+ if (maskLiterals) mask(index);
6335
+ if (index + 1 < source.length && maskLiterals) mask(index + 1);
6336
+ index += 2;
6337
+ } else if (source[index] === "`") {
6338
+ if (maskLiterals) mask(index);
6339
+ index += 1;
6340
+ break;
6341
+ } else if (source[index] === "$" && source[index + 1] === "{") {
6342
+ if (maskLiterals) {
6343
+ mask(index);
6344
+ mask(index + 1);
6345
+ }
6346
+ index = scanCode(index + 2, true);
6347
+ } else {
6348
+ if (maskLiterals) mask(index);
6349
+ index += 1;
6350
+ }
6351
+ }
6352
+ continue;
6353
+ }
6354
+ if (character === "{") {
6355
+ braceDepth += 1;
6356
+ } else if (character === "}") {
6357
+ if (stopAtTemplateBrace && braceDepth === 0) {
6358
+ if (maskLiterals) mask(index);
6359
+ return index + 1;
6360
+ }
6361
+ braceDepth = Math.max(0, braceDepth - 1);
6362
+ }
6363
+ index += 1;
6364
+ }
6365
+ return index;
6366
+ }, "scanCode");
6367
+ scanCode(0, false);
6368
+ return output.join("");
6369
+ }
6370
+ function escapeRegExp2(value) {
6371
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6372
+ }
6373
+ function hasExplicitRenderingConfig(mod, source) {
6374
+ return typeof mod?.ssg === "boolean" || typeof mod?.ppr === "boolean" || typeof mod?.experimental_ppr === "boolean" || typeof mod?.revalidate !== "undefined" || typeof mod?.dynamic !== "undefined" || typeof parseRouteRenderingDirective(source) !== "undefined";
6375
+ }
6143
6376
  function parseRouteRenderingDirective(source) {
6144
6377
  if (!source) {
6145
6378
  return void 0;
@@ -6264,9 +6497,10 @@ function skipHorizontalWhitespace(source, start) {
6264
6497
  }
6265
6498
  return index;
6266
6499
  }
6267
- async function collectSSGPages(routes, loadModule2) {
6500
+ async function collectSSGPages(routes, loadModule2, options = {}) {
6268
6501
  const ssgPages = [];
6269
6502
  const ssrRoutes = [];
6503
+ const staticCandidateRoutes = [];
6270
6504
  for (const route of routes) {
6271
6505
  try {
6272
6506
  const mod = await loadModule2(route.filePath);
@@ -6274,7 +6508,8 @@ async function collectSSGPages(routes, loadModule2) {
6274
6508
  ssrRoutes.push(route.path);
6275
6509
  continue;
6276
6510
  }
6277
- const rendering = await resolveRouteRenderingConfigFromFile(mod, route.filePath);
6511
+ const source = await (0, import_promises3.readFile)(route.filePath, "utf8").catch(() => void 0);
6512
+ const rendering = resolveRouteRenderingConfig(mod, source);
6278
6513
  if (rendering.ssg) {
6279
6514
  if (route.isDynamic) {
6280
6515
  const getStaticPaths = mod.getStaticPaths || mod.generateStaticParams;
@@ -6301,12 +6536,26 @@ async function collectSSGPages(routes, loadModule2) {
6301
6536
  }
6302
6537
  } else {
6303
6538
  ssrRoutes.push(route.path);
6539
+ if (options.suggestStaticRendering !== false && analyzeStaticRouteCandidate(mod, source, { isDynamic: route.isDynamic }).candidate) {
6540
+ staticCandidateRoutes.push(route.path);
6541
+ }
6304
6542
  }
6305
6543
  } catch (error) {
6306
6544
  console.error(`Error processing route ${route.path}:`, error);
6307
6545
  ssrRoutes.push(route.path);
6308
6546
  }
6309
6547
  }
6548
+ if (staticCandidateRoutes.length > 0) {
6549
+ const visibleRoutes = staticCandidateRoutes.slice(0, 10);
6550
+ const remainingCount = staticCandidateRoutes.length - visibleRoutes.length;
6551
+ const remainingSuffix = remainingCount > 0 ? `
6552
+ \u2026and ${remainingCount} more` : "";
6553
+ console.warn(
6554
+ `[Farm.js] ${staticCandidateRoutes.length} route${staticCandidateRoutes.length === 1 ? " appears" : "s appear"} eligible for static rendering:
6555
+ ${visibleRoutes.join("\n ")}${remainingSuffix}
6556
+ Add \`export const dynamic = "force-static";\` after verifying that imported code does not read cookies, headers, authentication, or other request data.`
6557
+ );
6558
+ }
6310
6559
  return { ssg: ssgPages, ssr: ssrRoutes };
6311
6560
  }
6312
6561
  function materializeSSGRoutePath(routePattern, params) {
@@ -6408,7 +6657,7 @@ function matchSSGPage(urlPath, ssgPages) {
6408
6657
  const normalizedPath = urlPath === "/" ? "/" : urlPath.replace(/\/$/, "");
6409
6658
  return ssgPages.find((page2) => page2.urlPath === normalizedPath);
6410
6659
  }
6411
- var import_promises3, OPTIONAL_CATCH_ALL_SEGMENT, REQUIRED_CATCH_ALL_SEGMENT, REQUIRED_DYNAMIC_SEGMENT;
6660
+ var import_promises3, OPTIONAL_CATCH_ALL_SEGMENT, REQUIRED_CATCH_ALL_SEGMENT, REQUIRED_DYNAMIC_SEGMENT, REQUEST_API_LABELS, ROUTE_PROP_LABELS;
6412
6661
  var init_ssg = __esm({
6413
6662
  "src/ssg.ts"() {
6414
6663
  "use strict";
@@ -6416,8 +6665,35 @@ var init_ssg = __esm({
6416
6665
  OPTIONAL_CATCH_ALL_SEGMENT = /^\[\[\.\.\.([^\]]+)\]\]$/;
6417
6666
  REQUIRED_CATCH_ALL_SEGMENT = /^\[\.\.\.([^\]]+)\]$/;
6418
6667
  REQUIRED_DYNAMIC_SEGMENT = /^\[([^\]]+)\]$/;
6668
+ REQUEST_API_LABELS = /* @__PURE__ */ new Map([
6669
+ ["cookies", "request cookies"],
6670
+ ["headers", "request headers"],
6671
+ ["getCurrentRequest", "the current Request"],
6672
+ ["useSearchParams", "URL search parameters"],
6673
+ ["auth", "request authentication"],
6674
+ ["getServerSession", "request authentication"],
6675
+ ["getSession", "request authentication"],
6676
+ ["currentUser", "request authentication"]
6677
+ ]);
6678
+ ROUTE_PROP_LABELS = /* @__PURE__ */ new Map([
6679
+ ["searchParams", "URL search parameters"],
6680
+ ["middleware", "middleware request data"],
6681
+ ["middlewareData", "middleware request data"],
6682
+ ["context", "request context"]
6683
+ ]);
6419
6684
  __name(resolveRouteRenderingConfig, "resolveRouteRenderingConfig");
6420
6685
  __name(resolveRouteRenderingConfigFromFile, "resolveRouteRenderingConfigFromFile");
6686
+ __name(analyzeStaticRouteCandidate, "analyzeStaticRouteCandidate");
6687
+ __name(findRequestBoundSourceBlockers, "findRequestBoundSourceBlockers");
6688
+ __name(readRequestApiImportBindings, "readRequestApiImportBindings");
6689
+ __name(readNamespaceImportBindings, "readNamespaceImportBindings");
6690
+ __name(readStaticImportClauses, "readStaticImportClauses");
6691
+ __name(readDefaultRouteParameters, "readDefaultRouteParameters");
6692
+ __name(stripCommentsAndLiteralContents, "stripCommentsAndLiteralContents");
6693
+ __name(stripComments, "stripComments");
6694
+ __name(sanitizeSource, "sanitizeSource");
6695
+ __name(escapeRegExp2, "escapeRegExp");
6696
+ __name(hasExplicitRenderingConfig, "hasExplicitRenderingConfig");
6421
6697
  __name(parseRouteRenderingDirective, "parseRouteRenderingDirective");
6422
6698
  __name(parseKnownRenderingDirective, "parseKnownRenderingDirective");
6423
6699
  __name(normalizeDynamicMode, "normalizeDynamicMode");
@@ -7098,7 +7374,7 @@ function getProgrammaticRouteSearchClientOptions(search) {
7098
7374
  if (search.temporary?.length) options.temporary = [...search.temporary];
7099
7375
  return Object.keys(options).length > 0 ? options : void 0;
7100
7376
  }
7101
- function resolveProgrammaticRouteSearch(searchConfig, rawSearch, path29, routePath) {
7377
+ function resolveProgrammaticRouteSearch(searchConfig, rawSearch, path31, routePath) {
7102
7378
  const schema = getProgrammaticRouteSearchSchema(searchConfig);
7103
7379
  const search = parseProgrammaticSchema(schema, rawSearch, "search", routePath);
7104
7380
  const options = getProgrammaticRouteSearchOptions(searchConfig);
@@ -7107,7 +7383,7 @@ function resolveProgrammaticRouteSearch(searchConfig, rawSearch, path29, routePa
7107
7383
  schema,
7108
7384
  rawSearch,
7109
7385
  parsedSearch: search,
7110
- path: path29
7386
+ path: path31
7111
7387
  });
7112
7388
  return { search, canonicalPath };
7113
7389
  }
@@ -7274,7 +7550,7 @@ function createRouteModuleFromProgrammaticPage(route) {
7274
7550
  mod.__farmRouteData = route.data;
7275
7551
  mod.__farmRouteParsesProps = true;
7276
7552
  mod.__farmResolveRouteProps = (props) => resolveProgrammaticRouteProps(route, props);
7277
- mod.__farmResolveRouteCanonicalPath = (rawSearch, path29) => resolveProgrammaticRouteSearch(route.search, rawSearch, path29, route.path).canonicalPath;
7553
+ mod.__farmResolveRouteCanonicalPath = (rawSearch, path31) => resolveProgrammaticRouteSearch(route.search, rawSearch, path31, route.path).canonicalPath;
7278
7554
  }
7279
7555
  if (route.pending || route.error || route.notFound) {
7280
7556
  mod.__farmRouteComponents = {
@@ -7672,25 +7948,25 @@ var init_routes = __esm({
7672
7948
  ];
7673
7949
  __name(defineRoutes, "defineRoutes");
7674
7950
  routesBuilder = {
7675
- page(path29, options) {
7951
+ page(path31, options) {
7676
7952
  return normalizeProgrammaticRoute({
7677
7953
  kind: "page",
7678
- path: path29,
7954
+ path: path31,
7679
7955
  ...options
7680
7956
  });
7681
7957
  },
7682
- layout(path29, options) {
7958
+ layout(path31, options) {
7683
7959
  return normalizeProgrammaticRoute({
7684
7960
  kind: "layout",
7685
- path: path29,
7961
+ path: path31,
7686
7962
  ...options
7687
7963
  });
7688
7964
  },
7689
- api(path29, options) {
7965
+ api(path31, options) {
7690
7966
  const { render, runtime, regions, maxDuration, ...methods } = options;
7691
7967
  return normalizeProgrammaticRoute({
7692
7968
  kind: "api",
7693
- path: path29,
7969
+ path: path31,
7694
7970
  render,
7695
7971
  runtime,
7696
7972
  regions,
@@ -7833,6 +8109,19 @@ var init_routes_server = __esm({
7833
8109
  }
7834
8110
  });
7835
8111
 
8112
+ // src/island.ts
8113
+ function isFarmIslandStrategy(value) {
8114
+ return FARM_ISLAND_STRATEGIES.includes(value);
8115
+ }
8116
+ var FARM_ISLAND_STRATEGIES;
8117
+ var init_island = __esm({
8118
+ "src/island.ts"() {
8119
+ "use strict";
8120
+ FARM_ISLAND_STRATEGIES = ["load", "interaction", "visible", "idle"];
8121
+ __name(isFarmIslandStrategy, "isFarmIslandStrategy");
8122
+ }
8123
+ });
8124
+
7836
8125
  // src/utils/client-component.ts
7837
8126
  function readIfExists(filePath) {
7838
8127
  try {
@@ -7890,53 +8179,180 @@ function hasHydrateExport(content) {
7890
8179
  }
7891
8180
  return /\bexport\s+const\s+hydrate\s*=\s*true\b/.test(content) || /\bexport\s*\{\s*hydrate\s*\}\b/.test(content);
7892
8181
  }
8182
+ function tokenizeModuleSource(content) {
8183
+ const tokens = [];
8184
+ let index = 0;
8185
+ let line = 1;
8186
+ while (index < content.length) {
8187
+ const character = content[index];
8188
+ if (/\s/.test(character)) {
8189
+ if (character === "\n") line++;
8190
+ index++;
8191
+ continue;
8192
+ }
8193
+ if (character === "/" && content[index + 1] === "/") {
8194
+ index += 2;
8195
+ while (index < content.length && content[index] !== "\n") index++;
8196
+ continue;
8197
+ }
8198
+ if (character === "/" && content[index + 1] === "*") {
8199
+ index += 2;
8200
+ while (index < content.length) {
8201
+ if (content[index] === "\n") line++;
8202
+ if (content[index] === "*" && content[index + 1] === "/") {
8203
+ index += 2;
8204
+ break;
8205
+ }
8206
+ index++;
8207
+ }
8208
+ continue;
8209
+ }
8210
+ if (character === '"' || character === "'") {
8211
+ const quote = character;
8212
+ const tokenLine = line;
8213
+ let value = "";
8214
+ index++;
8215
+ while (index < content.length) {
8216
+ const next = content[index];
8217
+ if (next === "\\") {
8218
+ value += next;
8219
+ if (index + 1 < content.length) value += content[index + 1];
8220
+ index += 2;
8221
+ continue;
8222
+ }
8223
+ if (next === quote) {
8224
+ index++;
8225
+ break;
8226
+ }
8227
+ if (next === "\n") line++;
8228
+ value += next;
8229
+ index++;
8230
+ }
8231
+ tokens.push({ kind: "string", value, line: tokenLine });
8232
+ continue;
8233
+ }
8234
+ if (character === "`") {
8235
+ index++;
8236
+ while (index < content.length) {
8237
+ const next = content[index];
8238
+ if (next === "\\") {
8239
+ index += 2;
8240
+ continue;
8241
+ }
8242
+ if (next === "`") {
8243
+ index++;
8244
+ break;
8245
+ }
8246
+ if (next === "\n") line++;
8247
+ index++;
8248
+ }
8249
+ continue;
8250
+ }
8251
+ if (/[A-Za-z_$]/.test(character)) {
8252
+ const start = index++;
8253
+ while (index < content.length && /[\w$]/.test(content[index])) index++;
8254
+ tokens.push({ kind: "identifier", value: content.slice(start, index), line });
8255
+ continue;
8256
+ }
8257
+ tokens.push({ kind: "punctuation", value: character, line });
8258
+ index++;
8259
+ }
8260
+ return tokens;
8261
+ }
8262
+ function isIslandExportStart(tokens, index) {
8263
+ const token = tokens[index];
8264
+ const previous = tokens[index - 1];
8265
+ const startsStatement = !previous || previous.value === ";" || previous.value === "{" || previous.value === "}" || token.line > previous.line;
8266
+ return startsStatement && token.value === "export" && tokens[index + 1]?.value === "const" && tokens[index + 2]?.value === "island";
8267
+ }
8268
+ function getIslandStrategyExport(content) {
8269
+ if (!content) return null;
8270
+ const tokens = tokenizeModuleSource(content);
8271
+ for (let index = 0; index < tokens.length - 2; index++) {
8272
+ if (!isIslandExportStart(tokens, index)) continue;
8273
+ let valueIndex = index + 3;
8274
+ if (tokens[valueIndex]?.value === ":") {
8275
+ while (valueIndex < tokens.length && tokens[valueIndex].value !== "=") valueIndex++;
8276
+ }
8277
+ if (tokens[valueIndex]?.value !== "=") break;
8278
+ valueIndex++;
8279
+ const literal = tokens[valueIndex];
8280
+ if (!literal || literal.kind !== "string" || !isFarmIslandStrategy(literal.value)) break;
8281
+ let trailingIndex = valueIndex + 1;
8282
+ if (tokens[trailingIndex]?.value === "as" && tokens[trailingIndex + 1]?.value === "const") {
8283
+ trailingIndex += 2;
8284
+ }
8285
+ const trailing = tokens[trailingIndex];
8286
+ if (trailing && trailing.value !== ";" && trailing.line === literal.line) break;
8287
+ return literal.value;
8288
+ }
8289
+ if (tokens.some((_token, index) => isIslandExportStart(tokens, index))) {
8290
+ throw new Error(
8291
+ 'Farm island configuration must be a static "load", "interaction", "visible", or "idle" string literal.'
8292
+ );
8293
+ }
8294
+ return null;
8295
+ }
7893
8296
  function stripUseClientDirective(content) {
7894
8297
  return content.replace(/^\s*(["'])use client\1\s*;?\s*/, "");
7895
8298
  }
7896
- function parseClientModuleMetadata(content) {
8299
+ function parseClientModuleMetadata(content, inspectIslandExport) {
7897
8300
  if (!content) {
7898
8301
  return {
7899
8302
  isClientComponent: false,
7900
- hasHydrateExport: false
8303
+ hasHydrateExport: false,
8304
+ islandStrategy: null
7901
8305
  };
7902
8306
  }
8307
+ const isClientComponent = hasUseClientDirective(content);
8308
+ const hasHydrate = hasHydrateExport(content);
7903
8309
  return {
7904
- isClientComponent: hasUseClientDirective(content),
7905
- hasHydrateExport: hasHydrateExport(content)
8310
+ isClientComponent,
8311
+ hasHydrateExport: hasHydrate,
8312
+ islandStrategy: inspectIslandExport || isClientComponent || hasHydrate ? getIslandStrategyExport(content) : null
7906
8313
  };
7907
8314
  }
7908
8315
  function getClientModuleMetadata(modulePath, root) {
7909
8316
  const resolvedPath = resolveModuleSourcePath(modulePath, root);
7910
- return inspectClientModuleMetadata(resolvedPath, root, /* @__PURE__ */ new Set());
8317
+ return inspectClientModuleMetadata(resolvedPath, root, /* @__PURE__ */ new Set(), true);
7911
8318
  }
7912
- function inspectClientModuleMetadata(resolvedPath, root, visited) {
8319
+ function inspectClientModuleMetadata(resolvedPath, root, visited, inspectIslandExport) {
7913
8320
  if (!resolvedPath || visited.has(resolvedPath)) {
7914
8321
  return {
7915
8322
  isClientComponent: false,
7916
- shouldHydrate: false
8323
+ shouldHydrate: false,
8324
+ islandStrategy: null
7917
8325
  };
7918
8326
  }
7919
8327
  visited.add(resolvedPath);
7920
8328
  const content = readIfExists(resolvedPath);
7921
- const parsed = parseClientModuleMetadata(content);
8329
+ const parsed = parseClientModuleMetadata(content, inspectIslandExport);
7922
8330
  if (parsed.isClientComponent) {
7923
8331
  return {
7924
8332
  isClientComponent: true,
7925
- shouldHydrate: true
8333
+ shouldHydrate: true,
8334
+ islandStrategy: parsed.islandStrategy ?? "load"
7926
8335
  };
7927
8336
  }
7928
8337
  let importsClientBoundary = false;
8338
+ let importedIslandStrategy = null;
7929
8339
  for (const specifier of getRelativeImportSpecifiers(content)) {
7930
8340
  const importedPath = resolveImportedModuleSourcePath(resolvedPath, specifier, root);
7931
- const importedMetadata = inspectClientModuleMetadata(importedPath, root, visited);
8341
+ const importedMetadata = inspectClientModuleMetadata(importedPath, root, visited, false);
7932
8342
  if (importedMetadata.isClientComponent || importedMetadata.shouldHydrate) {
7933
8343
  importsClientBoundary = true;
7934
- break;
8344
+ if (importedIslandStrategy === null) {
8345
+ importedIslandStrategy = importedMetadata.islandStrategy;
8346
+ } else if (importedIslandStrategy !== importedMetadata.islandStrategy) {
8347
+ importedIslandStrategy = "load";
8348
+ }
7935
8349
  }
7936
8350
  }
8351
+ const shouldHydrate = parsed.hasHydrateExport || importsClientBoundary;
7937
8352
  return {
7938
8353
  isClientComponent: false,
7939
- shouldHydrate: parsed.hasHydrateExport || importsClientBoundary
8354
+ shouldHydrate,
8355
+ islandStrategy: shouldHydrate ? parsed.islandStrategy ?? importedIslandStrategy ?? "load" : null
7940
8356
  };
7941
8357
  }
7942
8358
  function getRelativeImportSpecifiers(content) {
@@ -7976,6 +8392,7 @@ var init_client_component = __esm({
7976
8392
  import_fs2 = __toESM(require("fs"));
7977
8393
  import_path5 = __toESM(require("path"));
7978
8394
  import_url2 = require("url");
8395
+ init_island();
7979
8396
  __name(readIfExists, "readIfExists");
7980
8397
  __name(resolveModuleSourcePath, "resolveModuleSourcePath");
7981
8398
  RESOLVABLE_SOURCE_EXTENSIONS = [
@@ -7990,6 +8407,9 @@ var init_client_component = __esm({
7990
8407
  ];
7991
8408
  __name(hasUseClientDirective, "hasUseClientDirective");
7992
8409
  __name(hasHydrateExport, "hasHydrateExport");
8410
+ __name(tokenizeModuleSource, "tokenizeModuleSource");
8411
+ __name(isIslandExportStart, "isIslandExportStart");
8412
+ __name(getIslandStrategyExport, "getIslandStrategyExport");
7993
8413
  __name(stripUseClientDirective, "stripUseClientDirective");
7994
8414
  __name(parseClientModuleMetadata, "parseClientModuleMetadata");
7995
8415
  __name(getClientModuleMetadata, "getClientModuleMetadata");
@@ -8231,6 +8651,9 @@ var init_route_slots = __esm({
8231
8651
  });
8232
8652
 
8233
8653
  // src/routing/route-manager.ts
8654
+ function shouldSuggestStaticRenderingForI18n(i18n) {
8655
+ return !i18n || i18n.routing === "prefix-always" || i18n.routing === "prefix-except-default" && i18n.detection.every((signal) => signal === "url");
8656
+ }
8234
8657
  function routeSpecificity(entry) {
8235
8658
  return entry.route.segments.reduce((score, segment) => {
8236
8659
  if (!segment.isDynamic) return score + 100;
@@ -8302,6 +8725,7 @@ var init_route_manager = __esm({
8302
8725
  init_route_runtime();
8303
8726
  init_routing();
8304
8727
  init_route_slots();
8728
+ __name(shouldSuggestStaticRenderingForI18n, "shouldSuggestStaticRenderingForI18n");
8305
8729
  __name(routeSpecificity, "routeSpecificity");
8306
8730
  _RouteManager = class _RouteManager {
8307
8731
  constructor(config, viteServer) {
@@ -8538,6 +8962,7 @@ var init_route_manager = __esm({
8538
8962
  modulePath: toUrlPath(entry.modulePath),
8539
8963
  shouldHydrate: metadata.shouldHydrate,
8540
8964
  isClientComponent: metadata.isClientComponent,
8965
+ islandStrategy: metadata.islandStrategy,
8541
8966
  search: getProgrammaticRouteSearchClientOptions(programmaticPage?.search),
8542
8967
  segments: entry.route.segments.map((seg) => ({
8543
8968
  segment: seg.segment,
@@ -9000,8 +9425,10 @@ var init_route_manager = __esm({
9000
9425
  isDynamic: entry.route.segments.some((seg) => seg.isDynamic),
9001
9426
  pattern: entry.pattern
9002
9427
  }));
9003
- const result = await collectSSGPages(routes, (filePath) => this.loadRouteModule(filePath));
9004
9428
  const i18n = this.getI18nConfig();
9429
+ const result = await collectSSGPages(routes, (filePath) => this.loadRouteModule(filePath), {
9430
+ suggestStaticRendering: shouldSuggestStaticRenderingForI18n(i18n)
9431
+ });
9005
9432
  if (!i18n) {
9006
9433
  return result;
9007
9434
  }
@@ -10667,7 +11094,8 @@ function serializeFontResult(font) {
10667
11094
  fontFamily: stack,
10668
11095
  ...font.style ? { fontStyle: font.style } : {},
10669
11096
  ...font.weight !== void 0 && !String(font.weight).includes(" ") ? { fontWeight: font.weight } : {}
10670
- }
11097
+ },
11098
+ preloads: font.preloadResources
10671
11099
  });
10672
11100
  }
10673
11101
  function renderFontDefinitionCss(font, production, basePath) {
@@ -11180,6 +11608,10 @@ ${FONT_SECTION_END}
11180
11608
  fallback,
11181
11609
  display,
11182
11610
  preload: raw.preload !== false,
11611
+ preloadResources: raw.preload === false ? [] : normalizedSources.map(({ resource }) => ({
11612
+ href: resourceUrl(resource, production, this.basePath),
11613
+ type: fontContentType(resource.extension)
11614
+ })),
11183
11615
  weight: defaultWeight,
11184
11616
  style: raw.style === void 0 ? void 0 : defaultStyle,
11185
11617
  sources: normalizedSources
@@ -11276,7 +11708,7 @@ ${FONT_SECTION_END}
11276
11708
  const normalizedExtension = extension.toLowerCase();
11277
11709
  const hash = (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex").slice(0, 12);
11278
11710
  const baseName = sanitizeFileName(import_node_path5.default.basename(fileName, extension)) || "font";
11279
- const outputFileName = `assets/fonts/${baseName}-${hash}${normalizedExtension}`;
11711
+ const outputFileName = `assets/fonts/${baseName}-h${hash}${normalizedExtension}`;
11280
11712
  const key = `${hash}${normalizedExtension}`;
11281
11713
  const existing = this.resources.get(key);
11282
11714
  if (existing) return existing;
@@ -11348,6 +11780,172 @@ ${FONT_SECTION_END}
11348
11780
  }
11349
11781
  });
11350
11782
 
11783
+ // src/metadata-image.ts
11784
+ function isResponse(value) {
11785
+ return typeof Response !== "undefined" && (value instanceof Response || Boolean(
11786
+ value && typeof value === "object" && typeof value.arrayBuffer === "function" && value.headers
11787
+ ));
11788
+ }
11789
+ function isThenable(value) {
11790
+ return Boolean(
11791
+ value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function"
11792
+ );
11793
+ }
11794
+ async function prepareMetadataImageNode(node) {
11795
+ if (isThenable(node)) {
11796
+ return prepareMetadataImageNode(await node);
11797
+ }
11798
+ if (Array.isArray(node)) {
11799
+ return Promise.all(node.map((child) => prepareMetadataImageNode(child)));
11800
+ }
11801
+ if (!import_react4.default.isValidElement(node)) {
11802
+ return node;
11803
+ }
11804
+ const element = node;
11805
+ const type = element.type;
11806
+ const props = element.props || {};
11807
+ if (typeof type === "function") {
11808
+ if (type.prototype?.isReactComponent) {
11809
+ throw new Error(
11810
+ "Metadata image components must be stateless function components; React class components are not supported."
11811
+ );
11812
+ }
11813
+ return prepareMetadataImageNode(await type(props));
11814
+ }
11815
+ if (type && typeof type === "object") {
11816
+ if (type.$$typeof === REACT_MEMO_TYPE) {
11817
+ return prepareMetadataImageNode(import_react4.default.createElement(type.type, props));
11818
+ }
11819
+ if (type.$$typeof === REACT_FORWARD_REF_TYPE) {
11820
+ return prepareMetadataImageNode(await type.render(props, null));
11821
+ }
11822
+ if (type.$$typeof === REACT_LAZY_TYPE) {
11823
+ return prepareMetadataImageNode(import_react4.default.createElement(type._init(type._payload), props));
11824
+ }
11825
+ }
11826
+ const preparedChildren = await prepareMetadataImageNode(props.children);
11827
+ const preparedProps = { ...props };
11828
+ if (typeof preparedProps.className === "string") {
11829
+ preparedProps.tw = [preparedProps.tw, preparedProps.className].filter(Boolean).join(" ");
11830
+ delete preparedProps.className;
11831
+ }
11832
+ delete preparedProps.children;
11833
+ return import_react4.default.createElement(type, {
11834
+ ...preparedProps,
11835
+ key: element.key,
11836
+ children: preparedChildren
11837
+ });
11838
+ }
11839
+ async function normalizeFonts(fonts) {
11840
+ if (!fonts?.length) return void 0;
11841
+ return Promise.all(
11842
+ fonts.map(async (font) => {
11843
+ const data = await font.data;
11844
+ const arrayBuffer = ArrayBuffer.isView(data) ? toArrayBuffer(data) : data;
11845
+ return { ...font, data: arrayBuffer };
11846
+ })
11847
+ );
11848
+ }
11849
+ function resolveCacheControl(revalidate) {
11850
+ if (revalidate === false) {
11851
+ return "public, max-age=31536000, immutable";
11852
+ }
11853
+ if (typeof revalidate === "number" && Number.isFinite(revalidate) && revalidate > 0) {
11854
+ return `public, s-maxage=${Math.floor(revalidate)}, stale-while-revalidate=300`;
11855
+ }
11856
+ return "public, max-age=0, must-revalidate";
11857
+ }
11858
+ function toArrayBuffer(value) {
11859
+ if (value instanceof ArrayBuffer) return value;
11860
+ const bytes = new Uint8Array(value.byteLength);
11861
+ bytes.set(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
11862
+ return bytes.buffer;
11863
+ }
11864
+ async function createEntityTag(body) {
11865
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", body);
11866
+ const hash = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 32);
11867
+ return `"${hash}"`;
11868
+ }
11869
+ async function finalizeMetadataImageResponse(body, headers, options) {
11870
+ const responseHeaders = new Headers(headers);
11871
+ const etag = await createEntityTag(body);
11872
+ responseHeaders.set("ETag", etag);
11873
+ responseHeaders.set("Content-Length", String(body.byteLength));
11874
+ responseHeaders.set("X-Content-Type-Options", "nosniff");
11875
+ const matchesEntityTag = options.ifNoneMatch?.trim() === "*" || options.ifNoneMatch?.split(",").some((candidate) => candidate.trim().replace(/^W\//, "") === etag);
11876
+ if (matchesEntityTag) {
11877
+ return new Response(null, { status: 304, headers: responseHeaders });
11878
+ }
11879
+ return new Response(options.method?.toUpperCase() === "HEAD" ? null : body, {
11880
+ status: 200,
11881
+ headers: responseHeaders
11882
+ });
11883
+ }
11884
+ async function createFarmMetadataImageResponse(value, imageModule, options = {}) {
11885
+ const method = (options.method || "GET").toUpperCase();
11886
+ if (method !== "GET" && method !== "HEAD") {
11887
+ return new Response(null, { status: 405, headers: { Allow: "GET, HEAD" } });
11888
+ }
11889
+ if (isResponse(value)) {
11890
+ return method === "HEAD" ? new Response(null, { status: value.status, headers: value.headers }) : value;
11891
+ }
11892
+ const cacheControl = resolveCacheControl(imageModule.revalidate);
11893
+ const explicitContentType = imageModule.contentType?.split(";", 1)[0]?.trim().toLowerCase();
11894
+ if (import_react4.default.isValidElement(value) && explicitContentType !== "image/svg+xml") {
11895
+ const { ImageResponse } = await import("@vercel/og");
11896
+ const element = await prepareMetadataImageNode(value);
11897
+ const response = new ImageResponse(element, {
11898
+ width: imageModule.size?.width || 1200,
11899
+ height: imageModule.size?.height || 630,
11900
+ fonts: await normalizeFonts(imageModule.fonts),
11901
+ emoji: imageModule.emoji,
11902
+ debug: imageModule.debug,
11903
+ headers: { "cache-control": cacheControl }
11904
+ });
11905
+ const headers = new Headers(response.headers);
11906
+ headers.set("Cache-Control", cacheControl);
11907
+ return finalizeMetadataImageResponse(await response.arrayBuffer(), headers, options);
11908
+ }
11909
+ let body;
11910
+ if (typeof value === "string") {
11911
+ body = toArrayBuffer(new TextEncoder().encode(value));
11912
+ } else if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
11913
+ body = toArrayBuffer(value);
11914
+ } else if (import_react4.default.isValidElement(value)) {
11915
+ body = toArrayBuffer(new TextEncoder().encode((0, import_server.renderToStaticMarkup)(value)));
11916
+ } else {
11917
+ throw new Error("Metadata image must return a Response, string, bytes, or React element");
11918
+ }
11919
+ return finalizeMetadataImageResponse(
11920
+ body,
11921
+ {
11922
+ "Content-Type": imageModule.contentType || "image/svg+xml; charset=utf-8",
11923
+ "Cache-Control": cacheControl
11924
+ },
11925
+ options
11926
+ );
11927
+ }
11928
+ var import_react4, import_server, REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE, REACT_LAZY_TYPE;
11929
+ var init_metadata_image = __esm({
11930
+ "src/metadata-image.ts"() {
11931
+ "use strict";
11932
+ import_react4 = __toESM(require("react"));
11933
+ import_server = require("react-dom/server");
11934
+ REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref");
11935
+ REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo");
11936
+ REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy");
11937
+ __name(isResponse, "isResponse");
11938
+ __name(isThenable, "isThenable");
11939
+ __name(prepareMetadataImageNode, "prepareMetadataImageNode");
11940
+ __name(normalizeFonts, "normalizeFonts");
11941
+ __name(resolveCacheControl, "resolveCacheControl");
11942
+ __name(toArrayBuffer, "toArrayBuffer");
11943
+ __name(createEntityTag, "createEntityTag");
11944
+ __name(finalizeMetadataImageResponse, "finalizeMetadataImageResponse");
11945
+ __name(createFarmMetadataImageResponse, "createFarmMetadataImageResponse");
11946
+ }
11947
+ });
11948
+
11351
11949
  // src/server/renderer.ts
11352
11950
  function hasRequestHeader(req, name) {
11353
11951
  const value = req.headers[name.toLowerCase()];
@@ -11411,7 +12009,7 @@ function createPPRRefreshScript() {
11411
12009
  return `<script>(function(){if(window.__FARM_PPR_REFRESHING__)return;window.__FARM_PPR_REFRESHING__=true;function replaceRoot(html){var doc=new DOMParser().parseFromString(html,"text/html");var next=doc.getElementById("root");var current=document.getElementById("root");if(!next||!current)return;current.innerHTML=next.innerHTML;}fetch(window.location.href,{credentials:"same-origin",headers:{"x-farm-ppr-refresh":"1"}}).then(function(response){return response.ok?response.text():null;}).then(function(html){if(html)replaceRoot(html);}).catch(function(){});})();</script>`;
11412
12010
  }
11413
12011
  function createPreHydrationClickQueueScript() {
11414
- return `<script>(function(){if(window.__FARM_PREHYDRATION_CLICK_QUEUE__)return;var queue=[];window.__FARM_PREHYDRATION_CLICK_QUEUE__=queue;window.__FARM_HYDRATED__=false;document.documentElement.dataset.farmHydrated="false";function isModified(event){return !!(event.metaKey||event.altKey||event.ctrlKey||event.shiftKey)}function closestQueuedTarget(target){while(target&&target!==document.documentElement){if(target.matches&&target.matches('button,[role="button"],input[type="button"],input[type="submit"],input[type="reset"]'))return target;target=target.parentElement}return null}document.addEventListener("click",function(event){if(window.__FARM_HYDRATED__)return;if(event.defaultPrevented||event.button!==0||isModified(event))return;var target=closestQueuedTarget(event.target);if(!target||target.closest&&target.closest("a[href]"))return;if(queue.some(function(item){return item.target===target}))return;queue.push({target:target,createdAt:Date.now()});event.preventDefault();event.stopImmediatePropagation()},true);})();</script>`;
12012
+ return `<script>(function(){if(window.__FARM_PREHYDRATION_CLICK_QUEUE__)return;var queue=[];window.__FARM_PREHYDRATION_CLICK_QUEUE__=queue;window.__FARM_HYDRATED__=false;document.documentElement.dataset.farmHydrated="false";function isModified(event){return !!(event.metaKey||event.altKey||event.ctrlKey||event.shiftKey)}function closestQueuedTarget(target){while(target&&target!==document.documentElement){if(target.matches&&target.matches('button,[role="button"],input[type="button"],input[type="submit"],input[type="reset"]'))return target;target=target.parentElement}return null}document.addEventListener("click",function(event){if(window.__FARM_HYDRATED__)return;if(event.defaultPrevented||event.button!==0||isModified(event))return;var target=closestQueuedTarget(event.target);if(!target||target.closest&&target.closest("a[href]")||target.closest&&target.closest('[data-farm-island-hydrated="true"]'))return;if(queue.some(function(item){return item.target===target}))return;queue.push({target:target,createdAt:Date.now()});document.dispatchEvent(new CustomEvent("farm:island-interaction",{detail:{target:target}}));event.preventDefault();event.stopImmediatePropagation()},true);})();</script>`;
11415
12013
  }
11416
12014
  function searchParamsToObject(searchParams) {
11417
12015
  const output = {};
@@ -11503,12 +12101,12 @@ function createRouteStateProps(input) {
11503
12101
  context: input.pluginExposedContext.size > 0 ? { data: input.pluginExposedContext } : void 0
11504
12102
  };
11505
12103
  }
11506
- var import_react4, import_server, fs2, path11, import_stream, cachedClerkProvider, importRuntimeModule, _FarmRouteErrorBoundary, FarmRouteErrorBoundary, _ServerRenderer, ServerRenderer;
12104
+ var import_react5, import_server2, fs2, path11, import_stream, cachedClerkProvider, importRuntimeModule, _FarmRouteErrorBoundary, FarmRouteErrorBoundary, _ServerRenderer, ServerRenderer;
11507
12105
  var init_renderer = __esm({
11508
12106
  "src/server/renderer.ts"() {
11509
12107
  "use strict";
11510
- import_react4 = __toESM(require("react"));
11511
- import_server = require("react-dom/server");
12108
+ import_react5 = __toESM(require("react"));
12109
+ import_server2 = require("react-dom/server");
11512
12110
  fs2 = __toESM(require("fs"));
11513
12111
  path11 = __toESM(require("path"));
11514
12112
  init_utils();
@@ -11531,6 +12129,7 @@ var init_renderer = __esm({
11531
12129
  init_routing();
11532
12130
  init_response();
11533
12131
  init_font_vite();
12132
+ init_metadata_image();
11534
12133
  cachedClerkProvider = null;
11535
12134
  importRuntimeModule = new Function("specifier", "return import(specifier);");
11536
12135
  __name(hasRequestHeader, "hasRequestHeader");
@@ -11547,7 +12146,7 @@ var init_renderer = __esm({
11547
12146
  __name(createDeferredHydrationScript, "createDeferredHydrationScript");
11548
12147
  __name(toMiddlewareMap2, "toMiddlewareMap");
11549
12148
  __name(isWebResponse, "isWebResponse");
11550
- _FarmRouteErrorBoundary = class _FarmRouteErrorBoundary extends import_react4.default.Component {
12149
+ _FarmRouteErrorBoundary = class _FarmRouteErrorBoundary extends import_react5.default.Component {
11551
12150
  constructor(props) {
11552
12151
  super(props);
11553
12152
  this.state = { hasError: false, error: null };
@@ -11558,7 +12157,7 @@ var init_renderer = __esm({
11558
12157
  render() {
11559
12158
  if (this.state.hasError) {
11560
12159
  const Fallback = this.props.Fallback;
11561
- return import_react4.default.createElement(Fallback, {
12160
+ return import_react5.default.createElement(Fallback, {
11562
12161
  ...this.props.fallbackProps,
11563
12162
  error: this.state.error,
11564
12163
  reset: /* @__PURE__ */ __name(() => this.setState({ hasError: false, error: null }), "reset")
@@ -11727,14 +12326,14 @@ var init_renderer = __esm({
11727
12326
  searchParams: Promise.resolve({}),
11728
12327
  path: page2.urlPath
11729
12328
  };
11730
- let pageElement = import_react4.default.createElement(
12329
+ let pageElement = import_react5.default.createElement(
11731
12330
  PageComponent,
11732
12331
  pageProps
11733
12332
  );
11734
12333
  for (let i = layoutModules.length - 1; i >= 0; i--) {
11735
12334
  const layoutModule = layoutModules[i];
11736
12335
  const LayoutComponent = layoutModule.default;
11737
- pageElement = import_react4.default.createElement(
12336
+ pageElement = import_react5.default.createElement(
11738
12337
  LayoutComponent,
11739
12338
  {
11740
12339
  children: pageElement,
@@ -12060,6 +12659,7 @@ var init_renderer = __esm({
12060
12659
  req.__FARM_ROUTE__ = pathname;
12061
12660
  req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
12062
12661
  req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
12662
+ req.__FARM_ISLAND_STRATEGY__ = moduleMetadata.islandStrategy;
12063
12663
  req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
12064
12664
  req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
12065
12665
  loadingBoundaryEntry.modulePath.indexOf("/src/app/")
@@ -12112,12 +12712,12 @@ var init_renderer = __esm({
12112
12712
  await _runWithMiddlewareData(middlewareDataForContext, async () => {
12113
12713
  await _runWithMiddlewareContext(middlewareContext, async () => {
12114
12714
  await _runWithCurrentRequest(currentRequest, async () => {
12115
- let pageElement = import_react4.default.createElement(
12715
+ let pageElement = import_react5.default.createElement(
12116
12716
  PageComponent,
12117
12717
  pageProps
12118
12718
  );
12119
12719
  if (LoadingFallbackComponent) {
12120
- const loadingFallback = import_react4.default.createElement(LoadingFallbackComponent, {
12720
+ const loadingFallback = import_react5.default.createElement(LoadingFallbackComponent, {
12121
12721
  ...createRouteStateProps({
12122
12722
  params,
12123
12723
  searchParamsObject,
@@ -12126,16 +12726,21 @@ var init_renderer = __esm({
12126
12726
  pluginExposedContext
12127
12727
  })
12128
12728
  });
12129
- pageElement = import_react4.default.createElement(
12130
- import_react4.default.Suspense,
12729
+ pageElement = import_react5.default.createElement(
12730
+ import_react5.default.Suspense,
12131
12731
  { fallback: loadingFallback },
12132
12732
  pageElement
12133
12733
  );
12134
12734
  }
12135
12735
  if (isClientComponent || shouldHydrate) {
12136
- pageElement = import_react4.default.createElement(
12736
+ pageElement = import_react5.default.createElement(
12137
12737
  "div",
12138
- { id: "__farm_page__", "data-farm-client": "true" },
12738
+ {
12739
+ id: "__farm_page__",
12740
+ "data-farm-client": "true",
12741
+ "data-farm-island": "page",
12742
+ "data-farm-island-strategy": moduleMetadata.islandStrategy ?? "load"
12743
+ },
12139
12744
  pageElement
12140
12745
  );
12141
12746
  }
@@ -12147,11 +12752,11 @@ var init_renderer = __esm({
12147
12752
  const slotProps = {};
12148
12753
  for (const slot of renderedRouteSlots) {
12149
12754
  if (slot.ownerPattern !== layoutEntry.pattern) continue;
12150
- let slotElement = import_react4.default.createElement(
12755
+ let slotElement = import_react5.default.createElement(
12151
12756
  slot.module.default,
12152
12757
  slot.props
12153
12758
  );
12154
- slotElement = import_react4.default.createElement(
12759
+ slotElement = import_react5.default.createElement(
12155
12760
  "div",
12156
12761
  {
12157
12762
  id: slot.containerId,
@@ -12162,7 +12767,7 @@ var init_renderer = __esm({
12162
12767
  );
12163
12768
  slotProps[slot.name] = slotElement;
12164
12769
  }
12165
- wrappedElement = import_react4.default.createElement(
12770
+ wrappedElement = import_react5.default.createElement(
12166
12771
  LayoutComponent,
12167
12772
  {
12168
12773
  children: wrappedElement,
@@ -12172,7 +12777,7 @@ var init_renderer = __esm({
12172
12777
  );
12173
12778
  }
12174
12779
  if (ErrorFallbackComponent) {
12175
- wrappedElement = import_react4.default.createElement(
12780
+ wrappedElement = import_react5.default.createElement(
12176
12781
  FarmRouteErrorBoundary,
12177
12782
  {
12178
12783
  Fallback: ErrorFallbackComponent,
@@ -12305,7 +12910,7 @@ var init_renderer = __esm({
12305
12910
  if (!cachedClerkProvider) {
12306
12911
  cachedClerkProvider = await importRuntimeModule("@clerk/react");
12307
12912
  }
12308
- wrapped = import_react4.default.createElement(
12913
+ wrapped = import_react5.default.createElement(
12309
12914
  cachedClerkProvider.ClerkProvider,
12310
12915
  provider.props || {},
12311
12916
  wrapped
@@ -12380,6 +12985,13 @@ var init_renderer = __esm({
12380
12985
  return reference;
12381
12986
  }
12382
12987
  async renderMetadataImage(req, res, options) {
12988
+ const method = (req.method || "GET").toUpperCase();
12989
+ if (method !== "GET" && method !== "HEAD") {
12990
+ res.statusCode = 405;
12991
+ res.setHeader("Allow", "GET, HEAD");
12992
+ res.end();
12993
+ return;
12994
+ }
12383
12995
  if (options.image.sourceType === "static") {
12384
12996
  if (!options.image.staticInfo) {
12385
12997
  throw new Error(`Static metadata image ${options.image.modulePath} is missing file info`);
@@ -12405,42 +13017,12 @@ var init_renderer = __esm({
12405
13017
  await this.writeMetadataImageResponse(req, res, handlerResult, imageModule);
12406
13018
  }
12407
13019
  async writeMetadataImageResponse(req, res, value, imageModule) {
12408
- if (isWebResponse(value)) {
12409
- res.statusCode = value.status;
12410
- value.headers.forEach((headerValue, key) => {
12411
- res.setHeader(key, headerValue);
12412
- });
12413
- if (req.method === "HEAD") {
12414
- res.end();
12415
- return;
12416
- }
12417
- const body2 = Buffer.from(await value.arrayBuffer());
12418
- res.write(body2);
12419
- res.end();
12420
- return;
12421
- }
12422
- const contentType = imageModule.contentType || "image/svg+xml; charset=utf-8";
12423
- let body;
12424
- if (typeof value === "string") {
12425
- body = value;
12426
- } else if (value instanceof ArrayBuffer) {
12427
- body = Buffer.from(value);
12428
- } else if (ArrayBuffer.isView(value)) {
12429
- body = Buffer.from(value.buffer, value.byteOffset, value.byteLength);
12430
- } else if (import_react4.default.isValidElement(value)) {
12431
- body = (0, import_server.renderToStaticMarkup)(value);
12432
- } else {
12433
- throw new Error("Metadata image must return a Response, string, bytes, or React element");
12434
- }
12435
- res.statusCode = res.statusCode || 200;
12436
- res.setHeader("Content-Type", contentType);
12437
- res.setHeader("Cache-Control", "public, max-age=0, must-revalidate");
12438
- if (req.method === "HEAD") {
12439
- res.end();
12440
- return;
12441
- }
12442
- res.write(body);
12443
- res.end();
13020
+ const ifNoneMatch = req.headers["if-none-match"];
13021
+ const response = await createFarmMetadataImageResponse(value, imageModule, {
13022
+ method: req.method,
13023
+ ifNoneMatch: Array.isArray(ifNoneMatch) ? ifNoneMatch[0] : ifNoneMatch
13024
+ });
13025
+ await sendWebResponse(res, response);
12444
13026
  }
12445
13027
  async writeStaticMetadataImageResponse(req, res, image) {
12446
13028
  const method = (req.method || "GET").toUpperCase();
@@ -12487,7 +13069,7 @@ var init_renderer = __esm({
12487
13069
  return false;
12488
13070
  }
12489
13071
  const ErrorComponent = errorModule.default;
12490
- const errorElement = import_react4.default.createElement(ErrorComponent, {
13072
+ const errorElement = import_react5.default.createElement(ErrorComponent, {
12491
13073
  ...createRouteStateProps({
12492
13074
  params: options.params,
12493
13075
  searchParamsObject: options.searchParamsObject,
@@ -12505,7 +13087,7 @@ var init_renderer = __esm({
12505
13087
  );
12506
13088
  for (let i = layoutModules.length - 1; i >= 0; i--) {
12507
13089
  const LayoutComponent = layoutModules[i].default;
12508
- wrapped = import_react4.default.createElement(
13090
+ wrapped = import_react5.default.createElement(
12509
13091
  LayoutComponent,
12510
13092
  {
12511
13093
  children: wrapped,
@@ -12570,6 +13152,7 @@ var init_renderer = __esm({
12570
13152
  search: routeEntry.search,
12571
13153
  isClientComponent: routeEntry.isClientComponent,
12572
13154
  shouldHydrate: routeEntry.shouldHydrate,
13155
+ islandStrategy: routeEntry.islandStrategy,
12573
13156
  preloads: [routeEntry.modulePath],
12574
13157
  assets: []
12575
13158
  };
@@ -12606,6 +13189,7 @@ window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
12606
13189
  window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
12607
13190
  window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
12608
13191
  window.__FARM_SHOULD_HYDRATE__ = ${JSON.stringify(req.__FARM_SHOULD_HYDRATE__ === true)};
13192
+ window.__FARM_ISLAND_STRATEGY__ = ${JSON.stringify(req.__FARM_ISLAND_STRATEGY__ || "load")};
12609
13193
  window.__FARM_PAGE_MODULE__ = ${JSON.stringify(relativePath2)};
12610
13194
  window.__FARM_LOADING_MODULE__ = ${JSON.stringify(
12611
13195
  req.__FARM_LOADING_MODULE_PATH__ || null
@@ -12623,8 +13207,8 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
12623
13207
  const i18nSnapshot = getFarmI18nClientSnapshot();
12624
13208
  const i18nAlternateTags = i18nSnapshot ? renderI18nAlternateLinks(req.__FARM_ROUTE__ || req.url || "/", i18nSnapshot) : "";
12625
13209
  const fontHead = renderFarmFontDevHead(this.config.root || process.cwd());
12626
- const streamRoot = import_react4.default.createElement("div", { style: { display: "contents" } }, element);
12627
- const { pipe, abort } = (0, import_server.renderToPipeableStream)(streamRoot, {
13210
+ const streamRoot = import_react5.default.createElement("div", { style: { display: "contents" } }, element);
13211
+ const { pipe, abort } = (0, import_server2.renderToPipeableStream)(streamRoot, {
12628
13212
  onShellReady() {
12629
13213
  const shellReadyMs = Date.now() - streamStartTime;
12630
13214
  emitFarmEvent({
@@ -12782,12 +13366,12 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
12782
13366
  break;
12783
13367
  }
12784
13368
  }
12785
- let element = import_react4.default.createElement(
13369
+ let element = import_react5.default.createElement(
12786
13370
  NotFoundComponent,
12787
13371
  { pathname }
12788
13372
  );
12789
13373
  if (LayoutComponent) {
12790
- element = import_react4.default.createElement(
13374
+ element = import_react5.default.createElement(
12791
13375
  LayoutComponent,
12792
13376
  { children: element }
12793
13377
  );
@@ -12937,6 +13521,7 @@ var init_app = __esm({
12937
13521
  init_server2();
12938
13522
  init_cache();
12939
13523
  init_auth_config();
13524
+ init_preload();
12940
13525
  defaultDocsConfig = {
12941
13526
  enabled: false,
12942
13527
  entry: "/docs",
@@ -13002,6 +13587,7 @@ var init_app = __esm({
13002
13587
  context: config.context || (() => void 0),
13003
13588
  serverActions: resolveServerActionsConfig(config.serverActions),
13004
13589
  images: resolveFarmImageConfig(config.images),
13590
+ performance: resolveFarmPerformanceConfig(config.performance),
13005
13591
  i18n: isResolvedI18nConfig(config.i18n) ? config.i18n : resolveFarmI18nConfig(config.i18n, {
13006
13592
  root,
13007
13593
  mode: process.env.NODE_ENV === "production" ? "production" : "development"
@@ -14595,6 +15181,49 @@ var init_search_client = __esm({
14595
15181
  }
14596
15182
  });
14597
15183
 
15184
+ // src/docs/fonts.ts
15185
+ function resolveFarmDocsFontAssets(root) {
15186
+ return FARM_DOCS_FONT_SOURCES.flatMap(({ family, packagePath }) => {
15187
+ const sourcePath = import_node_path8.default.join(root, "node_modules", packagePath);
15188
+ if (!(0, import_node_fs5.existsSync)(sourcePath)) return [];
15189
+ const source = (0, import_node_fs5.readFileSync)(sourcePath);
15190
+ const fingerprint = (0, import_node_crypto3.createHash)("sha256").update(source).digest("hex").slice(0, 12);
15191
+ const extension = import_node_path8.default.extname(packagePath);
15192
+ const baseName = import_node_path8.default.basename(packagePath, extension);
15193
+ return [
15194
+ {
15195
+ family,
15196
+ sourcePath,
15197
+ url: `/assets/fonts/${baseName}-h${fingerprint}${extension}`
15198
+ }
15199
+ ];
15200
+ });
15201
+ }
15202
+ function toFarmDocsPublicFontAssets(assets) {
15203
+ return assets.map(({ family, url }) => ({ family, url }));
15204
+ }
15205
+ var import_node_crypto3, import_node_fs5, import_node_path8, FARM_DOCS_FONT_SOURCES;
15206
+ var init_fonts = __esm({
15207
+ "src/docs/fonts.ts"() {
15208
+ "use strict";
15209
+ import_node_crypto3 = require("crypto");
15210
+ import_node_fs5 = require("fs");
15211
+ import_node_path8 = __toESM(require("path"));
15212
+ FARM_DOCS_FONT_SOURCES = [
15213
+ {
15214
+ family: "Geist Sans",
15215
+ packagePath: "geist/dist/fonts/geist-sans/Geist-Variable.woff2"
15216
+ },
15217
+ {
15218
+ family: "Geist Mono",
15219
+ packagePath: "geist/dist/fonts/geist-mono/GeistMono-Variable.woff2"
15220
+ }
15221
+ ];
15222
+ __name(resolveFarmDocsFontAssets, "resolveFarmDocsFontAssets");
15223
+ __name(toFarmDocsPublicFontAssets, "toFarmDocsPublicFontAssets");
15224
+ }
15225
+ });
15226
+
14598
15227
  // src/default-styles.ts
14599
15228
  var defaultGlobalCSS;
14600
15229
  var init_default_styles = __esm({
@@ -15002,12 +15631,12 @@ var init_module = __esm({
15002
15631
  function isMiddlewareResponse(value) {
15003
15632
  return value instanceof Response;
15004
15633
  }
15005
- var fs4, path18, _MiddlewareManager, MiddlewareManager;
15634
+ var fs4, path19, _MiddlewareManager, MiddlewareManager;
15006
15635
  var init_manager = __esm({
15007
15636
  "src/middleware/manager.ts"() {
15008
15637
  "use strict";
15009
15638
  fs4 = __toESM(require("fs"));
15010
- path18 = __toESM(require("path"));
15639
+ path19 = __toESM(require("path"));
15011
15640
  init_context();
15012
15641
  init_module();
15013
15642
  init_utils();
@@ -15087,8 +15716,8 @@ var init_manager = __esm({
15087
15716
  const entries = fs4.readdirSync(dir, { withFileTypes: true });
15088
15717
  for (const entry of entries) {
15089
15718
  if (entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.startsWith("_")) {
15090
- const subPath = path18.join(dir, entry.name);
15091
- const subRoutePath = path18.posix.join(routePath, entry.name);
15719
+ const subPath = path19.join(dir, entry.name);
15720
+ const subRoutePath = path19.posix.join(routePath, entry.name);
15092
15721
  await this.discoverInDirectory(subPath, subRoutePath, discovered);
15093
15722
  }
15094
15723
  }
@@ -15099,7 +15728,7 @@ var init_manager = __esm({
15099
15728
  findMiddlewareFile(dir) {
15100
15729
  const extensions = [".ts", ".tsx", ".js", ".jsx"];
15101
15730
  for (const ext of extensions) {
15102
- const filePath = path18.join(dir, `middleware${ext}`);
15731
+ const filePath = path19.join(dir, `middleware${ext}`);
15103
15732
  if (fs4.existsSync(filePath)) {
15104
15733
  return filePath;
15105
15734
  }
@@ -15450,7 +16079,7 @@ var init_manager = __esm({
15450
16079
  // src/write-file-if-changed.ts
15451
16080
  function writeFileIfChanged(filePath, content) {
15452
16081
  try {
15453
- if ((0, import_node_fs5.readFileSync)(filePath, "utf8") === content) {
16082
+ if ((0, import_node_fs6.readFileSync)(filePath, "utf8") === content) {
15454
16083
  return false;
15455
16084
  }
15456
16085
  } catch (error) {
@@ -15458,14 +16087,14 @@ function writeFileIfChanged(filePath, content) {
15458
16087
  throw error;
15459
16088
  }
15460
16089
  }
15461
- (0, import_node_fs5.writeFileSync)(filePath, content, "utf8");
16090
+ (0, import_node_fs6.writeFileSync)(filePath, content, "utf8");
15462
16091
  return true;
15463
16092
  }
15464
- var import_node_fs5;
16093
+ var import_node_fs6;
15465
16094
  var init_write_file_if_changed = __esm({
15466
16095
  "src/write-file-if-changed.ts"() {
15467
16096
  "use strict";
15468
- import_node_fs5 = require("fs");
16097
+ import_node_fs6 = require("fs");
15469
16098
  __name(writeFileIfChanged, "writeFileIfChanged");
15470
16099
  }
15471
16100
  });
@@ -15566,11 +16195,11 @@ var init_type_generator = __esm({
15566
16195
  routeGroups.get(key).push(route);
15567
16196
  }
15568
16197
  const nestedStructure = {};
15569
- for (const [path29, routeList] of routeGroups) {
16198
+ for (const [path31, routeList] of routeGroups) {
15570
16199
  const route = routeList[0];
15571
16200
  const importPath = this.getRouteImportPath(route, options.outFile);
15572
16201
  const routeName = this.pathToRouteName(route.path);
15573
- const cleanPath = path29 === "/api" ? "" : path29.replace(/^\/api\//, "");
16202
+ const cleanPath = path31 === "/api" ? "" : path31.replace(/^\/api\//, "");
15574
16203
  const parts = cleanPath ? cleanPath.split("/") : [];
15575
16204
  const allMethods = routeList.flatMap((r) => r.methods);
15576
16205
  for (const method of allMethods) {
@@ -15629,8 +16258,8 @@ ${typeExports}
15629
16258
  const relativeImport = (0, import_path10.relative)((0, import_path10.dirname)(outFile), route.filePath).replace(/\\/g, "/").replace(/\.(ts|tsx|js|jsx)$/, "");
15630
16259
  return relativeImport.startsWith(".") ? relativeImport : `./${relativeImport}`;
15631
16260
  }
15632
- pathToRouteName(path29) {
15633
- return (path29 === "/api" ? "root" : path29.replace(/^\/api\//, "")).replace(/\//g, "_").replace(/[^a-zA-Z0-9_]/g, "");
16261
+ pathToRouteName(path31) {
16262
+ return (path31 === "/api" ? "root" : path31.replace(/^\/api\//, "")).replace(/\//g, "_").replace(/[^a-zA-Z0-9_]/g, "");
15634
16263
  }
15635
16264
  structureToTypeString(obj, indent) {
15636
16265
  const spaces = " ".repeat(indent);
@@ -15650,15 +16279,15 @@ ${typeExports}
15650
16279
  toTypePropertyKey(key) {
15651
16280
  return /^[$A-Z_][0-9A-Z_$]*$/i.test(key) ? key : JSON.stringify(key);
15652
16281
  }
15653
- getBaseExportName(path29) {
15654
- const cleanPath = path29.replace(/^\/api\//, "");
16282
+ getBaseExportName(path31) {
16283
+ const cleanPath = path31.replace(/^\/api\//, "");
15655
16284
  if (cleanPath === "") {
15656
16285
  return "api";
15657
16286
  }
15658
16287
  return cleanPath;
15659
16288
  }
15660
- getExportName(path29, method) {
15661
- const cleanPath = path29.replace(/^\/api\//, "");
16289
+ getExportName(path31, method) {
16290
+ const cleanPath = path31.replace(/^\/api\//, "");
15662
16291
  if (cleanPath === "") {
15663
16292
  return method.toLowerCase();
15664
16293
  }
@@ -15720,12 +16349,12 @@ function createRoutePattern(route) {
15720
16349
  }).join("/");
15721
16350
  }
15722
16351
  async function generateRouteTypes(options) {
15723
- const root = path19.resolve(options.root);
16352
+ const root = path20.resolve(options.root);
15724
16353
  const srcDir = options.srcDir || "src";
15725
16354
  const outFile = options.outFile || DEFAULT_OUT_FILE;
15726
- const outPath = path19.isAbsolute(outFile) ? outFile : path19.join(root, srcDir, outFile);
16355
+ const outPath = path20.isAbsolute(outFile) ? outFile : path20.join(root, srcDir, outFile);
15727
16356
  const content = await createRouteTypeDeclarations(options, outPath);
15728
- fs5.mkdirSync(path19.dirname(outPath), { recursive: true });
16357
+ fs5.mkdirSync(path20.dirname(outPath), { recursive: true });
15729
16358
  writeFileIfChanged(outPath, content);
15730
16359
  return outPath;
15731
16360
  }
@@ -15733,39 +16362,48 @@ async function createRouteTypeDeclarations(options, outPath) {
15733
16362
  const { root, srcDir = "src", extraRoutes = [], suppressLintOnLink = false } = options;
15734
16363
  const sourceRoots = options.sourceRoots ?? [{ name: "project", root, srcDir, layer: false }];
15735
16364
  const patterns = /* @__PURE__ */ new Set();
16365
+ const routeModulePatterns = /* @__PURE__ */ new Set();
15736
16366
  const glob = await import("fast-glob");
15737
16367
  for (const source of sourceRoots) {
15738
- const appDir = path19.join(source.root, source.srcDir, "app");
16368
+ const appDir = path20.join(source.root, source.srcDir, "app");
15739
16369
  if (fs5.existsSync(appDir)) {
15740
- const pageFiles = await glob.default("**/page.{ts,tsx,js,jsx,md,mdx}", {
15741
- cwd: appDir,
15742
- absolute: false
15743
- });
15744
- for (const file of pageFiles) {
16370
+ const routeModuleFiles = await glob.default(
16371
+ "**/{page,layout,loading,error}.{ts,tsx,js,jsx,md,mdx}",
16372
+ {
16373
+ cwd: appDir,
16374
+ absolute: false
16375
+ }
16376
+ );
16377
+ for (const file of routeModuleFiles) {
15745
16378
  if (parseRouteSlotFile(file)) continue;
15746
16379
  const route = parseRoutePath(file);
16380
+ const pattern = createRoutePattern(route);
16381
+ routeModulePatterns.add(pattern);
15747
16382
  if (route.type === "page") {
15748
- const pattern = createRoutePattern(route);
15749
16383
  patterns.add(pattern);
15750
16384
  }
15751
16385
  }
15752
16386
  }
15753
16387
  for (const route of await discoverProgrammaticRoutePaths(source.root, source.srcDir)) {
15754
16388
  patterns.add(route);
16389
+ routeModulePatterns.add(route);
15755
16390
  }
15756
16391
  }
15757
16392
  for (const route of extraRoutes) {
15758
16393
  if (route.startsWith("/")) {
15759
16394
  patterns.add(route);
16395
+ routeModulePatterns.add(route);
15760
16396
  }
15761
16397
  }
15762
16398
  const sortedPatterns = Array.from(patterns).sort();
15763
16399
  const typeLiterals = Array.from(new Set(sortedPatterns.flatMap(routePatternToTsTypeLiterals)));
15764
16400
  const patternLiterals = sortedPatterns.map(routePatternToRouteLiteral);
16401
+ const routeModulePatternLiterals = Array.from(routeModulePatterns).sort().map(routePatternToRouteLiteral);
15765
16402
  const routePathType = suppressLintOnLink ? "string" : typeLiterals.length ? typeLiterals.join(" | ") : "never";
15766
16403
  const routePatternType = suppressLintOnLink ? "string" : patternLiterals.length ? patternLiterals.join(" | ") : "never";
15767
- const routeTypesImportPath = `./${path19.basename(outPath).replace(/\.d\.ts$/, "")}`;
15768
- const augmentationBlock = suppressLintOnLink ? "" : `
16404
+ const routeModulePatternType = routeModulePatternLiterals.length ? routeModulePatternLiterals.join(" | ") : "never";
16405
+ const routeTypesImportPath = `./${path20.basename(outPath).replace(/\.d\.ts$/, "")}`;
16406
+ const linkAugmentationBlock = suppressLintOnLink ? "" : `
15769
16407
  declare module "@farm.js/core/client" {
15770
16408
  interface LinkDefaultRoute {
15771
16409
  _: import(${JSON.stringify(routeTypesImportPath)}).RoutePath;
@@ -15789,22 +16427,33 @@ declare module "@farm.js/core/dist/client.js" {
15789
16427
  pattern: import(${JSON.stringify(routeTypesImportPath)}).RoutePattern;
15790
16428
  }
15791
16429
  }
16430
+ `;
16431
+ const routeModuleAugmentationBlock = `
16432
+ declare global {
16433
+ namespace FarmJS {
16434
+ interface RouteRegistry {
16435
+ pattern: import(${JSON.stringify(routeTypesImportPath)}).RouteModulePattern;
16436
+ }
16437
+ }
16438
+ }
15792
16439
  `;
15793
16440
  const content = `/**
15794
16441
  * Auto-generated route types from src/app.
15795
- * Link href is typed automatically via module augmentation. Regenerated on dev start and when routes change.
16442
+ * Link href and route component props are typed automatically from generated declarations.
16443
+ * Regenerated on dev start and when routes change.
15796
16444
  * Set suppressLintOnLink: true in farm.config.ts to accept any string on Link href.
15797
16445
  */
15798
16446
  export type RoutePath = ${routePathType};
15799
- export type RoutePattern = ${routePatternType};${augmentationBlock}
16447
+ export type RoutePattern = ${routePatternType};
16448
+ export type RouteModulePattern = ${routeModulePatternType};${linkAugmentationBlock}${routeModuleAugmentationBlock}
15800
16449
  `;
15801
16450
  return content;
15802
16451
  }
15803
- var path19, fs5, DEFAULT_OUT_FILE;
16452
+ var path20, fs5, DEFAULT_OUT_FILE;
15804
16453
  var init_generate_route_types = __esm({
15805
16454
  "src/routing/generate-route-types.ts"() {
15806
16455
  "use strict";
15807
- path19 = __toESM(require("path"));
16456
+ path20 = __toESM(require("path"));
15808
16457
  fs5 = __toESM(require("fs"));
15809
16458
  init_utils();
15810
16459
  init_route_slots();
@@ -15822,17 +16471,17 @@ var init_generate_route_types = __esm({
15822
16471
 
15823
16472
  // src/env-types.ts
15824
16473
  async function generateEnvTypes(options) {
15825
- const root = path20.resolve(options.root);
16474
+ const root = path21.resolve(options.root);
15826
16475
  const srcDir = options.srcDir || "src";
15827
16476
  const outFile = options.outFile || DEFAULT_OUT_FILE2;
15828
- const outPath = path20.isAbsolute(outFile) ? outFile : path20.join(root, srcDir, outFile);
16477
+ const outPath = path21.isAbsolute(outFile) ? outFile : path21.join(root, srcDir, outFile);
15829
16478
  const content = createEnvTypeDeclarations(options, outPath);
15830
- fs6.mkdirSync(path20.dirname(outPath), { recursive: true });
16479
+ fs6.mkdirSync(path21.dirname(outPath), { recursive: true });
15831
16480
  writeFileIfChanged(outPath, content);
15832
16481
  return outPath;
15833
16482
  }
15834
16483
  function createEnvTypeDeclarations(options, outPath) {
15835
- const root = path20.resolve(options.root);
16484
+ const root = path21.resolve(options.root);
15836
16485
  const configPath = findConfigPath(root, options.configPath);
15837
16486
  const configPaths = [
15838
16487
  ...(options.layerConfigPaths ?? []).filter((value) => fs6.existsSync(value)),
@@ -15895,11 +16544,11 @@ export {};
15895
16544
  }
15896
16545
  function findConfigPath(root, configPath) {
15897
16546
  if (configPath) {
15898
- const resolvedPath = path20.isAbsolute(configPath) ? configPath : path20.join(root, configPath);
16547
+ const resolvedPath = path21.isAbsolute(configPath) ? configPath : path21.join(root, configPath);
15899
16548
  return fs6.existsSync(resolvedPath) ? resolvedPath : null;
15900
16549
  }
15901
16550
  for (const filename of CONFIG_FILENAMES2) {
15902
- const resolvedPath = path20.join(root, filename);
16551
+ const resolvedPath = path21.join(root, filename);
15903
16552
  if (fs6.existsSync(resolvedPath)) {
15904
16553
  return resolvedPath;
15905
16554
  }
@@ -15960,15 +16609,15 @@ export {};
15960
16609
  `;
15961
16610
  }
15962
16611
  function toTypeImportPath(outPath, targetPath) {
15963
- const relativePath2 = path20.relative(path20.dirname(outPath), targetPath).replace(/\\/g, "/").replace(/\.(tsx?|jsx?|mjs|cjs|mts|cts)$/, "");
16612
+ const relativePath2 = path21.relative(path21.dirname(outPath), targetPath).replace(/\\/g, "/").replace(/\.(tsx?|jsx?|mjs|cjs|mts|cts)$/, "");
15964
16613
  return relativePath2.startsWith(".") ? relativePath2 : `./${relativePath2}`;
15965
16614
  }
15966
- var fs6, path20, DEFAULT_OUT_FILE2, CONFIG_FILENAMES2;
16615
+ var fs6, path21, DEFAULT_OUT_FILE2, CONFIG_FILENAMES2;
15967
16616
  var init_env_types = __esm({
15968
16617
  "src/env-types.ts"() {
15969
16618
  "use strict";
15970
16619
  fs6 = __toESM(require("fs"));
15971
- path20 = __toESM(require("path"));
16620
+ path21 = __toESM(require("path"));
15972
16621
  init_write_file_if_changed();
15973
16622
  DEFAULT_OUT_FILE2 = "farm-env.d.ts";
15974
16623
  CONFIG_FILENAMES2 = [
@@ -16001,8 +16650,8 @@ var init_env_types = __esm({
16001
16650
 
16002
16651
  // src/image-types.ts
16003
16652
  function generateFarmImageTypes(options) {
16004
- const outputPath = options.outFile ? import_node_path8.default.resolve(options.root, options.outFile) : import_node_path8.default.join(options.root, options.srcDir || "src", "farm-images.d.ts");
16005
- (0, import_node_fs6.mkdirSync)(import_node_path8.default.dirname(outputPath), { recursive: true });
16653
+ const outputPath = options.outFile ? import_node_path9.default.resolve(options.root, options.outFile) : import_node_path9.default.join(options.root, options.srcDir || "src", "farm-images.d.ts");
16654
+ (0, import_node_fs7.mkdirSync)(import_node_path9.default.dirname(outputPath), { recursive: true });
16006
16655
  writeFileIfChanged(outputPath, createFarmImageTypeDeclarations());
16007
16656
  return outputPath;
16008
16657
  }
@@ -16026,12 +16675,12 @@ declare module "*?url" {
16026
16675
  }
16027
16676
  `;
16028
16677
  }
16029
- var import_node_fs6, import_node_path8, FARM_STATIC_IMAGE_EXTENSIONS;
16678
+ var import_node_fs7, import_node_path9, FARM_STATIC_IMAGE_EXTENSIONS;
16030
16679
  var init_image_types = __esm({
16031
16680
  "src/image-types.ts"() {
16032
16681
  "use strict";
16033
- import_node_fs6 = require("fs");
16034
- import_node_path8 = __toESM(require("path"));
16682
+ import_node_fs7 = require("fs");
16683
+ import_node_path9 = __toESM(require("path"));
16035
16684
  init_write_file_if_changed();
16036
16685
  FARM_STATIC_IMAGE_EXTENSIONS = ["avif", "gif", "jpeg", "jpg", "png", "webp"];
16037
16686
  __name(generateFarmImageTypes, "generateFarmImageTypes");
@@ -16043,9 +16692,9 @@ var init_image_types = __esm({
16043
16692
  async function generateFarmI18nTypes(options) {
16044
16693
  if (!options.config.enabled) return void 0;
16045
16694
  const { signatures } = await readFarmI18nCatalogs(options.config);
16046
- const outFile = options.outFile ? (0, import_node_path9.resolve)(options.root, options.outFile) : (0, import_node_path9.join)((0, import_node_path9.resolve)(options.root), options.srcDir || "src", "farm-i18n.d.ts");
16695
+ const outFile = options.outFile ? (0, import_node_path10.resolve)(options.root, options.outFile) : (0, import_node_path10.join)((0, import_node_path10.resolve)(options.root), options.srcDir || "src", "farm-i18n.d.ts");
16047
16696
  const content = renderFarmI18nTypes(options.config.locales, signatures);
16048
- (0, import_node_fs7.mkdirSync)((0, import_node_path9.dirname)(outFile), { recursive: true });
16697
+ (0, import_node_fs8.mkdirSync)((0, import_node_path10.dirname)(outFile), { recursive: true });
16049
16698
  writeFileIfChanged(outFile, content);
16050
16699
  return outFile;
16051
16700
  }
@@ -16086,12 +16735,12 @@ function argumentType(kind) {
16086
16735
  return "string";
16087
16736
  }
16088
16737
  }
16089
- var import_node_fs7, import_node_path9;
16738
+ var import_node_fs8, import_node_path10;
16090
16739
  var init_type_generator2 = __esm({
16091
16740
  "src/i18n/type-generator.ts"() {
16092
16741
  "use strict";
16093
- import_node_fs7 = require("fs");
16094
- import_node_path9 = require("path");
16742
+ import_node_fs8 = require("fs");
16743
+ import_node_path10 = require("path");
16095
16744
  init_catalog();
16096
16745
  init_write_file_if_changed();
16097
16746
  __name(generateFarmI18nTypes, "generateFarmI18nTypes");
@@ -16246,7 +16895,7 @@ var init_type_artifacts = __esm({
16246
16895
  var version;
16247
16896
  var init_package = __esm({
16248
16897
  "package.json"() {
16249
- version = "0.1.0-beta.11";
16898
+ version = "0.1.0-beta.14";
16250
16899
  }
16251
16900
  });
16252
16901
 
@@ -16426,12 +17075,12 @@ async function createBlurDataURL(bytes) {
16426
17075
  return void 0;
16427
17076
  }
16428
17077
  }
16429
- var import_promises7, import_node_path10, import_image_size2, FARM_IMAGE_ID_PREFIX, STATIC_IMAGE_RE, SCRIPT_IMPORTER_RE;
17078
+ var import_promises7, import_node_path11, import_image_size2, FARM_IMAGE_ID_PREFIX, STATIC_IMAGE_RE, SCRIPT_IMPORTER_RE;
16430
17079
  var init_image_vite = __esm({
16431
17080
  "src/image-vite.ts"() {
16432
17081
  "use strict";
16433
17082
  import_promises7 = require("fs/promises");
16434
- import_node_path10 = __toESM(require("path"));
17083
+ import_node_path11 = __toESM(require("path"));
16435
17084
  import_image_size2 = require("image-size");
16436
17085
  FARM_IMAGE_ID_PREFIX = "\0farm:image:";
16437
17086
  STATIC_IMAGE_RE = /\.(?:avif|gif|jpe?g|png|webp)$/i;
@@ -16442,6 +17091,22 @@ var init_image_vite = __esm({
16442
17091
  }
16443
17092
  });
16444
17093
 
17094
+ // src/font.ts
17095
+ function resolveFarmLayoutFonts(layouts) {
17096
+ let resolved;
17097
+ for (const layout2 of layouts) {
17098
+ if (!layout2.fonts) continue;
17099
+ resolved = { ...resolved, ...layout2.fonts };
17100
+ }
17101
+ return resolved;
17102
+ }
17103
+ var init_font = __esm({
17104
+ "src/font.ts"() {
17105
+ "use strict";
17106
+ __name(resolveFarmLayoutFonts, "resolveFarmLayoutFonts");
17107
+ }
17108
+ });
17109
+
16445
17110
  // src/image-server.ts
16446
17111
  function createFarmImageHandler(config, options) {
16447
17112
  const fetcher = options.fetch ?? globalThis.fetch;
@@ -16858,6 +17523,106 @@ var init_image_server = __esm({
16858
17523
  }
16859
17524
  });
16860
17525
 
17526
+ // src/server/vite-config.ts
17527
+ function createFarmClientOptimizeDepsEntries(projectRoot, appDirectories) {
17528
+ const resolvedProjectRoot = import_node_path12.default.resolve(projectRoot);
17529
+ return appDirectories.map((appDirectory) => {
17530
+ const relativeAppDirectory = import_node_path12.default.relative(resolvedProjectRoot, import_node_path12.default.resolve(appDirectory)).replace(/\\/g, "/");
17531
+ const prefix = relativeAppDirectory || ".";
17532
+ return `${prefix}/${FARM_CLIENT_ENTRY_PATTERN}`;
17533
+ });
17534
+ }
17535
+ function createFarmClientOptimizeDepsConfig(entries) {
17536
+ return {
17537
+ // Keep normal application dependency discovery for CJS-only packages, but
17538
+ // seed every Farm browser runtime so React is present in the first crawl.
17539
+ noDiscovery: false,
17540
+ // Waiting for the crawl avoids serving a partial optimizer generation and
17541
+ // then changing browser hashes while hydration is already in progress.
17542
+ holdUntilCrawlEnd: true,
17543
+ include: [...FARM_CLIENT_OPTIMIZE_DEPS_INCLUDE],
17544
+ // Farm's HTML boots through a virtual module and imports route UI lazily.
17545
+ // Explicit entries let Vite finish that crawl before a navigation can
17546
+ // rotate the optimizer hash underneath a hydrated React runtime.
17547
+ ...entries?.length ? { entries: [...entries] } : {}
17548
+ };
17549
+ }
17550
+ function mergeNoExternal(farmValue, userValue) {
17551
+ if (farmValue === true || userValue === true) return true;
17552
+ const normalize = /* @__PURE__ */ __name((value) => value == null || value === true ? [] : Array.isArray(value) ? value : [value], "normalize");
17553
+ return Array.from(/* @__PURE__ */ new Set([...normalize(farmValue), ...normalize(userValue)]));
17554
+ }
17555
+ function mergeFarmViteConfig(farmConfig, userConfig = {}) {
17556
+ const noDiscovery = userConfig.optimizeDeps?.noDiscovery ?? farmConfig.optimizeDeps?.noDiscovery;
17557
+ const holdUntilCrawlEnd = userConfig.optimizeDeps?.holdUntilCrawlEnd ?? (userConfig.optimizeDeps?.noDiscovery === true ? false : farmConfig.optimizeDeps?.holdUntilCrawlEnd);
17558
+ return {
17559
+ ...farmConfig,
17560
+ ...userConfig,
17561
+ plugins: [...farmConfig.plugins || [], ...userConfig.plugins || []],
17562
+ server: {
17563
+ ...farmConfig.server,
17564
+ ...userConfig.server
17565
+ },
17566
+ resolve: {
17567
+ ...farmConfig.resolve,
17568
+ ...userConfig.resolve,
17569
+ dedupe: Array.from(
17570
+ /* @__PURE__ */ new Set([...farmConfig.resolve?.dedupe || [], ...userConfig.resolve?.dedupe || []])
17571
+ )
17572
+ },
17573
+ optimizeDeps: {
17574
+ ...farmConfig.optimizeDeps,
17575
+ ...userConfig.optimizeDeps,
17576
+ noDiscovery,
17577
+ holdUntilCrawlEnd,
17578
+ include: Array.from(
17579
+ /* @__PURE__ */ new Set([
17580
+ ...farmConfig.optimizeDeps?.include || [],
17581
+ ...userConfig.optimizeDeps?.include || []
17582
+ ])
17583
+ ),
17584
+ exclude: Array.from(
17585
+ /* @__PURE__ */ new Set([
17586
+ ...farmConfig.optimizeDeps?.exclude || [],
17587
+ ...userConfig.optimizeDeps?.exclude || []
17588
+ ])
17589
+ )
17590
+ },
17591
+ ssr: {
17592
+ ...farmConfig.ssr,
17593
+ ...userConfig.ssr,
17594
+ noExternal: mergeNoExternal(farmConfig.ssr?.noExternal, userConfig.ssr?.noExternal)
17595
+ }
17596
+ };
17597
+ }
17598
+ var import_node_path12, FARM_CLIENT_ENTRY_PATTERN, FARM_CLIENT_OPTIMIZE_DEPS_INCLUDE;
17599
+ var init_vite_config = __esm({
17600
+ "src/server/vite-config.ts"() {
17601
+ "use strict";
17602
+ import_node_path12 = __toESM(require("path"));
17603
+ FARM_CLIENT_ENTRY_PATTERN = "**/{page,layout,loading,error,not-found,default}.{js,jsx,ts,tsx}";
17604
+ FARM_CLIENT_OPTIMIZE_DEPS_INCLUDE = [
17605
+ "react",
17606
+ "react-dom",
17607
+ "react-dom/client",
17608
+ "react/jsx-runtime",
17609
+ "react/jsx-dev-runtime",
17610
+ "@farm.js/core/client",
17611
+ "@farm.js/core/plugin/client",
17612
+ "@farm.js/core/deferred",
17613
+ "@farm.js/core/deployment",
17614
+ "@farm.js/core/i18n/client",
17615
+ "@farm.js/core/query/client",
17616
+ "@farm.js/core/server-fn/client",
17617
+ "@farm.js/core/server-query/client"
17618
+ ];
17619
+ __name(createFarmClientOptimizeDepsEntries, "createFarmClientOptimizeDepsEntries");
17620
+ __name(createFarmClientOptimizeDepsConfig, "createFarmClientOptimizeDepsConfig");
17621
+ __name(mergeNoExternal, "mergeNoExternal");
17622
+ __name(mergeFarmViteConfig, "mergeFarmViteConfig");
17623
+ }
17624
+ });
17625
+
16861
17626
  // src/docs/pixel-border-css.ts
16862
17627
  var farmDocsPixelBorderCss;
16863
17628
  var init_pixel_border_css = __esm({
@@ -16903,8 +17668,8 @@ var init_pixel_border_css = __esm({
16903
17668
  --scrollbar-thumb-hover: var(--color-fd-ring);
16904
17669
  --scrollbar-track: transparent;
16905
17670
  --radius: 0px;
16906
- --font-geist-sans: "Geist Sans";
16907
- --font-geist-mono: "Geist Mono";
17671
+ --font-geist-sans: ui-sans-serif, system-ui, sans-serif;
17672
+ --font-geist-mono: ui-monospace, monospace;
16908
17673
  }
16909
17674
 
16910
17675
  .dark {
@@ -16917,28 +17682,6 @@ body,
16917
17682
  background-color: var(--color-fd-background) !important;
16918
17683
  }
16919
17684
 
16920
- @font-face {
16921
- font-family: "Geist Sans";
16922
- font-display: block;
16923
- font-style: normal;
16924
- font-weight: 100 900;
16925
- src:
16926
- local("Geist Sans"),
16927
- url("/assets/Geist-Variable-CrgPqtmy.woff2") format("woff2"),
16928
- url("/node_modules/geist/dist/fonts/geist-sans/Geist-Variable.woff2") format("woff2");
16929
- }
16930
-
16931
- @font-face {
16932
- font-family: "Geist Mono";
16933
- font-display: block;
16934
- font-style: normal;
16935
- font-weight: 100 900;
16936
- src:
16937
- local("Geist Mono"),
16938
- url("/assets/GeistMono-Variable-BNLlm6Cd.woff2") format("woff2"),
16939
- url("/node_modules/geist/dist/fonts/geist-mono/GeistMono-Variable.woff2") format("woff2");
16940
- }
16941
-
16942
17685
  * {
16943
17686
  scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
16944
17687
  scrollbar-width: thin;
@@ -18129,11 +18872,418 @@ code:not(pre code) {
18129
18872
  }
18130
18873
  });
18131
18874
 
18875
+ // src/docs/social-image.ts
18876
+ function normalizeEntry(entry) {
18877
+ if (!entry || entry === "/") return "";
18878
+ return `/${entry.replace(/^\/+|\/+$/g, "")}`;
18879
+ }
18880
+ function encodeSlugPath(slug) {
18881
+ return slug.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
18882
+ }
18883
+ function getSocialImageConfig(docs) {
18884
+ return typeof docs.config.socialImage === "object" && docs.config.socialImage ? docs.config.socialImage : void 0;
18885
+ }
18886
+ function getNavTitle(docs) {
18887
+ if (typeof docs.config.nav !== "object" || !docs.config.nav || !("title" in docs.config.nav)) {
18888
+ return "Farm.js";
18889
+ }
18890
+ return String(docs.config.nav.title || "Farm.js");
18891
+ }
18892
+ function isFalse(value) {
18893
+ return value ? /^(false|no|none|off|disabled)$/i.test(value.trim()) : false;
18894
+ }
18895
+ function isExternalOrRootPath(value) {
18896
+ return /^(https?:)?\/\//i.test(value) || value.startsWith("/");
18897
+ }
18898
+ function isFarmDocsSocialImageEnabled(page2, docs) {
18899
+ if (docs.config.socialImage === false || getSocialImageConfig(docs)?.enabled === false) {
18900
+ return false;
18901
+ }
18902
+ return !isFalse(page2.frontmatter.socialImage);
18903
+ }
18904
+ function getFarmDocsCustomSocialImage(page2) {
18905
+ const value = page2.frontmatter.socialImage || page2.frontmatter.openGraphImage || page2.frontmatter.ogImage;
18906
+ return value && !isFalse(value) && isExternalOrRootPath(value) ? value : void 0;
18907
+ }
18908
+ function resolveIllustration(page2) {
18909
+ const explicit = page2.frontmatter.socialIllustration?.toLowerCase();
18910
+ if (explicit === "auth" || explicit === "cache" || explicit === "cli" || explicit === "integrations" || explicit === "project" || explicit === "routing" || explicit === "runtime") {
18911
+ return explicit;
18912
+ }
18913
+ const source = `${page2.slug} ${page2.title} ${page2.section || ""}`.toLowerCase();
18914
+ if (/auth|session|security|csrf/.test(source)) return "auth";
18915
+ if (/cache|ppr|render|static|revalid|stream/.test(source)) return "cache";
18916
+ if (/integration|stripe|prisma|better.auth|email|job|workflow/.test(source)) {
18917
+ return "integrations";
18918
+ }
18919
+ if (/cli|test|deploy|preview|upgrade|migration|install/.test(source)) return "cli";
18920
+ if (/project|structure|config|environment|markdown|docs.engine/.test(source)) {
18921
+ return "project";
18922
+ }
18923
+ if (/rout|endpoint|middleware|navigation|server.function|server.action|api/.test(source)) {
18924
+ return "routing";
18925
+ }
18926
+ return "runtime";
18927
+ }
18928
+ function createHashValue(value) {
18929
+ return (0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 16);
18930
+ }
18931
+ function resolveBaseUrl(requestUrl, config) {
18932
+ return config?.baseUrl ? new URL(config.baseUrl) : new URL(requestUrl.origin);
18933
+ }
18934
+ function createFarmDocsSocialImageDescriptor(page2, docs, requestUrl) {
18935
+ const config = getSocialImageConfig(docs);
18936
+ const siteName = config?.siteName || getNavTitle(docs);
18937
+ const brand = config?.brand || siteName;
18938
+ const title = page2.frontmatter.socialTitle || page2.title;
18939
+ const description = page2.frontmatter.socialDescription || page2.description || docs.config.metadata?.description || `Documentation for ${siteName}`;
18940
+ const section = page2.frontmatter.section || page2.section || "Documentation";
18941
+ const illustration = resolveIllustration(page2);
18942
+ const entry = normalizeEntry(docs.entry);
18943
+ const slugPath = encodeSlugPath(page2.slug) || "index";
18944
+ const imagePath = `${entry}/_social/${slugPath}/opengraph-image.svg`;
18945
+ const baseUrl = resolveBaseUrl(requestUrl, config);
18946
+ const pageUrl = new URL(page2.href, baseUrl).href;
18947
+ const imageAlt = `${title} \u2014 ${siteName} documentation`;
18948
+ const hash = createHashValue({
18949
+ version: FARM_DOCS_SOCIAL_IMAGE_VERSION,
18950
+ title,
18951
+ description,
18952
+ section,
18953
+ siteName,
18954
+ brand,
18955
+ pageHref: page2.href,
18956
+ illustration,
18957
+ fonts: config?.fonts
18958
+ });
18959
+ return {
18960
+ title,
18961
+ description,
18962
+ section,
18963
+ siteName,
18964
+ brand,
18965
+ pageHref: page2.href,
18966
+ pageUrl,
18967
+ imagePath,
18968
+ imageUrl: new URL(`${imagePath}?v=${hash}`, baseUrl).href,
18969
+ imageAlt,
18970
+ illustration,
18971
+ fonts: config?.fonts,
18972
+ hash
18973
+ };
18974
+ }
18975
+ function getFarmDocsSocialImageSlug(docs, requestUrl) {
18976
+ const entry = normalizeEntry(docs.entry);
18977
+ const prefix = `${entry}/_social/`;
18978
+ const suffix = "/opengraph-image.svg";
18979
+ if (!requestUrl.pathname.startsWith(prefix) || !requestUrl.pathname.endsWith(suffix)) {
18980
+ return null;
18981
+ }
18982
+ const rawSlug = requestUrl.pathname.slice(prefix.length, -suffix.length);
18983
+ if (!rawSlug) return null;
18984
+ try {
18985
+ const slug = rawSlug.split("/").map((segment) => decodeURIComponent(segment)).join("/");
18986
+ if (slug.split("/").some((segment) => !segment || segment === ".." || segment === ".")) {
18987
+ return null;
18988
+ }
18989
+ return slug === "index" ? "" : slug;
18990
+ } catch {
18991
+ return null;
18992
+ }
18993
+ }
18994
+ function escapeXml(value) {
18995
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
18996
+ }
18997
+ function truncate(value, length) {
18998
+ if (value.length <= length) return value;
18999
+ return `${value.slice(0, Math.max(0, length - 1)).trimEnd()}\u2026`;
19000
+ }
19001
+ function wrapText(value, maxCharacters, maxLines) {
19002
+ const words = value.trim().split(/\s+/).filter(Boolean);
19003
+ const lines = [];
19004
+ let current = "";
19005
+ let consumedWords = 0;
19006
+ for (const word of words) {
19007
+ const candidate = current ? `${current} ${word}` : word;
19008
+ if (candidate.length <= maxCharacters || !current) {
19009
+ current = candidate;
19010
+ consumedWords += 1;
19011
+ continue;
19012
+ }
19013
+ lines.push(current);
19014
+ if (lines.length === maxLines) break;
19015
+ current = word;
19016
+ consumedWords += 1;
19017
+ }
19018
+ if (current && lines.length < maxLines) lines.push(current);
19019
+ if (consumedWords < words.length && lines.length) {
19020
+ lines[lines.length - 1] = truncate(`${lines[lines.length - 1]}\u2026`, maxCharacters);
19021
+ }
19022
+ return lines;
19023
+ }
19024
+ function renderTextLines(lines, x, y, lineHeight, attributes) {
19025
+ return lines.map(
19026
+ (line, index) => `<text x="${x}" y="${y + index * lineHeight}" ${attributes}>${escapeXml(line)}</text>`
19027
+ ).join("");
19028
+ }
19029
+ function renderEmbeddedFont(name, source, weight) {
19030
+ if (!source) return "";
19031
+ return `@font-face{font-family:"${name}";src:url("${escapeXml(source)}") format("woff2");font-style:normal;font-weight:${weight};font-display:block;}`;
19032
+ }
19033
+ function renderArrow(x1, y, x2, color = "#8b8b8b") {
19034
+ return `<path d="M${x1} ${y}H${x2 - 9}" fill="none" stroke="${color}"/><path d="m${x2 - 9} ${y - 5} 9 5-9 5" fill="none" stroke="${color}"/>`;
19035
+ }
19036
+ function renderPanelHeader(label, status) {
19037
+ return `<text x="819" y="171" class="label">${escapeXml(label)}</text><text x="1134" y="171" class="label bright" text-anchor="end">${escapeXml(status)}</text>`;
19038
+ }
19039
+ function renderRoutingIllustration() {
19040
+ return `${renderPanelHeader("ROUTE BLUEPRINT", "TYPED")}
19041
+ <rect x="819" y="296" width="92" height="54" fill="#a3a3a3"/>
19042
+ <text x="832" y="327" class="diagram-title ink">src/app</text>
19043
+ <path d="M911 323h41M952 232v181M952 232h44M952 323h44M952 413h44" fill="none" stroke="#696969"/>
19044
+ <rect x="996" y="205" width="138" height="54" fill="#0a0a0a" stroke="#414141"/>
19045
+ <text x="1010" y="228" class="diagram-title">/</text><text x="1010" y="246" class="micro">STATIC</text>
19046
+ <rect x="996" y="296" width="138" height="54" fill="#0a0a0a" stroke="#414141"/>
19047
+ <text x="1010" y="319" class="diagram-title">/blog/:slug</text><text x="1010" y="337" class="micro">DYNAMIC</text>
19048
+ <rect x="996" y="386" width="138" height="55" fill="#f0f0f0"/>
19049
+ <text x="1010" y="410" class="diagram-title ink">/docs/:path*</text><text x="1010" y="428" class="micro ink-muted">CATCH-ALL</text>
19050
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
19051
+ <text x="819" y="475" class="label bright">FILE ROUTES</text><text x="1134" y="475" class="label" text-anchor="end">TYPES INCLUDED</text>`;
19052
+ }
19053
+ function renderAuthIllustration() {
19054
+ return `${renderPanelHeader("REQUEST GUARD", "SERVER VERIFIED")}
19055
+ <rect x="819" y="269" width="86" height="54" fill="#0a0a0a" stroke="#454545"/>
19056
+ <text x="837" y="292" class="micro bright">REQUEST</text><text x="837" y="310" class="diagram-title">GET /app</text>
19057
+ ${renderArrow(905, 296, 943)}
19058
+ <rect x="943" y="224" width="104" height="118" fill="#f0f0f0"/>
19059
+ <path d="M974 271v-12a21 21 0 0 1 42 0v12M968 271h54v45h-54z" fill="#050505"/>
19060
+ <circle cx="995" cy="292" r="4" fill="#f0f0f0"/><path d="M995 296v8" stroke="#f0f0f0" stroke-width="3"/>
19061
+ <text x="995" y="332" class="micro ink" text-anchor="middle">auth()</text>
19062
+ ${renderArrow(1047, 296, 1071)}
19063
+ <rect x="1071" y="269" width="63" height="54" fill="#0a0a0a" stroke="#454545"/>
19064
+ <text x="1082" y="292" class="micro bright">ALLOW</text><text x="1082" y="310" class="micro">/app</text>
19065
+ <rect x="819" y="372" width="315" height="38" fill="#090909" stroke="#3d3d3d"/>
19066
+ <rect x="832" y="385" width="11" height="11" fill="#a3a3a3"/>
19067
+ <text x="856" y="395" class="code">session.user / verified</text>
19068
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
19069
+ <text x="819" y="475" class="label bright">SESSION TYPED</text><text x="1134" y="475" class="label" text-anchor="end">CSRF PROTECTED</text>`;
19070
+ }
19071
+ function renderCacheIllustration() {
19072
+ return `${renderPanelHeader("PAGE / PRODUCT", "CACHE + PPR")}
19073
+ <rect x="819" y="204" width="315" height="54" fill="#f0f0f0"/>
19074
+ <text x="836" y="235" class="diagram-title ink">STATIC SHELL</text><text x="1116" y="235" class="micro ink-muted" text-anchor="end">BUILD</text>
19075
+ <rect x="819" y="271" width="198" height="76" fill="#a3a3a3"/>
19076
+ <text x="836" y="301" class="diagram-title ink">CACHED DATA</text><text x="836" y="326" class="micro ink-muted">tag: products</text>
19077
+ <rect x="1029" y="271" width="105" height="76" fill="#0a0a0a" stroke="#555"/>
19078
+ <text x="1045" y="301" class="diagram-title">LIVE</text><text x="1045" y="326" class="micro">stream</text>
19079
+ <path d="M1081 347v43m-8-9 8 9 8-9" fill="none" stroke="#d4d4d4"/>
19080
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
19081
+ <text x="819" y="475" class="label bright">STATIC FIRST</text><text x="1134" y="475" class="label" text-anchor="end">DYNAMIC WHERE NEEDED</text>`;
19082
+ }
19083
+ function renderIntegrationsIllustration() {
19084
+ return `${renderPanelHeader("INTEGRATION GRAPH", "ONE PRODUCT")}
19085
+ <path d="M976 309H879V247M976 309H879v87M1030 309h93V247M1030 309h93v87" fill="none" stroke="#4a4a4a"/>
19086
+ <rect x="819" y="214" width="120" height="57" fill="#0a0a0a" stroke="#4b4b4b"/><text x="839" y="247" class="diagram-title">BETTER AUTH</text>
19087
+ <rect x="819" y="368" width="120" height="57" fill="#0a0a0a" stroke="#4b4b4b"/><text x="851" y="401" class="diagram-title">PRISMA</text>
19088
+ <rect x="1061" y="214" width="73" height="57" fill="#0a0a0a" stroke="#4b4b4b"/><text x="1077" y="247" class="diagram-title">STRIPE</text>
19089
+ <rect x="1061" y="368" width="73" height="57" fill="#a3a3a3"/><text x="1075" y="401" class="diagram-title ink">VERCEL</text>
19090
+ <rect x="976" y="277" width="94" height="64" fill="#f0f0f0"/>
19091
+ <text x="994" y="304" class="diagram-title ink">FARM.JS</text><text x="994" y="324" class="micro ink-muted">CORE</text>
19092
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
19093
+ <text x="819" y="475" class="label bright">BRING YOUR STACK</text><text x="1134" y="475" class="label" text-anchor="end">CONNECTED ONCE</text>`;
19094
+ }
19095
+ function renderCliIllustration() {
19096
+ return `${renderPanelHeader("TERMINAL", "PRODUCTION OUTPUT")}
19097
+ <rect x="819" y="203" width="315" height="213" fill="#050505" stroke="#555"/>
19098
+ <line x1="819" y1="236" x2="1134" y2="236" stroke="#555"/>
19099
+ <circle cx="837" cy="220" r="4" fill="#5d5d5d"/><circle cx="850" cy="220" r="4" fill="#7a7a7a"/><circle cx="863" cy="220" r="4" fill="#a3a3a3"/>
19100
+ <text x="837" y="273" class="code bright"><tspan fill="#7a7a7a">$</tspan> farm build</text>
19101
+ <rect x="837" y="293" width="11" height="11" fill="#a3a3a3"/><path d="m839 298 3 3 6-7" fill="none" stroke="#050505" stroke-width="1.5"/>
19102
+ <text x="861" y="303" class="code">64 routes discovered</text>
19103
+ <rect x="837" y="320" width="11" height="11" fill="#a3a3a3"/><path d="m839 325 3 3 6-7" fill="none" stroke="#050505" stroke-width="1.5"/>
19104
+ <text x="861" y="330" class="code">client + server bundles</text>
19105
+ <rect x="837" y="355" width="126" height="30" fill="#f0f0f0"/><text x="853" y="374" class="micro ink">BUILD COMPLETE</text>
19106
+ <text x="1115" y="374" class="micro" text-anchor="end">/dist</text>
19107
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
19108
+ <text x="819" y="475" class="label bright">REAL COMMANDS</text><text x="1134" y="475" class="label" text-anchor="end">842MS</text>`;
19109
+ }
19110
+ function renderProjectIllustration() {
19111
+ return `${renderPanelHeader("PROJECT MAP", "CONVENTION TYPED")}
19112
+ <rect x="819" y="202" width="315" height="216" fill="#050505" stroke="#555"/>
19113
+ <text x="837" y="227" class="diagram-title bright">my-app/</text>
19114
+ <path d="M847 243v143M847 259h23M847 293h23M847 327h23M847 361h23" fill="none" stroke="#666"/>
19115
+ <rect x="870" y="243" width="246" height="33" fill="#0a0a0a" stroke="#444"/><text x="886" y="264" class="code">src/app</text><text x="1098" y="264" class="micro" text-anchor="end">ROUTES</text>
19116
+ <rect x="870" y="277" width="246" height="33" fill="#f0f0f0"/><text x="886" y="298" class="code ink">src/app/page.tsx</text>
19117
+ <rect x="870" y="311" width="246" height="33" fill="#0a0a0a" stroke="#444"/><text x="886" y="332" class="code">src/app/api/users/route.ts</text><text x="1098" y="332" class="micro" text-anchor="end">API</text>
19118
+ <rect x="870" y="345" width="246" height="33" fill="#0a0a0a" stroke="#444"/><text x="886" y="366" class="code">farm.config.ts</text><text x="1098" y="366" class="micro" text-anchor="end">CONFIG</text>
19119
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
19120
+ <text x="819" y="475" class="label bright">FILES BECOME FEATURES</text><text x="1134" y="475" class="label" text-anchor="end">ONE CONFIG</text>`;
19121
+ }
19122
+ function renderRuntimeIllustration() {
19123
+ return `${renderPanelHeader("PRODUCT ARCHITECTURE", "FULL STACK")}
19124
+ <rect x="819" y="211" width="315" height="55" fill="#f0f0f0"/>
19125
+ <text x="836" y="244" class="diagram-title ink">PRODUCT SURFACE</text><text x="1116" y="244" class="micro ink-muted" text-anchor="end">UI + ROUTES</text>
19126
+ <path d="M976 266v20m0 61v20" stroke="#727272"/>
19127
+ <rect x="855" y="286" width="242" height="61" fill="#a3a3a3"/>
19128
+ <text x="874" y="314" class="diagram-title ink">APPLICATION CORE</text><text x="874" y="334" class="micro ink-muted">APIS \xB7 MIDDLEWARE</text>
19129
+ <rect x="819" y="367" width="315" height="55" fill="#4c4c4c"/>
19130
+ <text x="836" y="400" class="diagram-title bright">CONNECTED STACK</text><text x="1116" y="400" class="micro" text-anchor="end">DATA \xB7 AUTH \xB7 DEPLOY</text>
19131
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
19132
+ <text x="819" y="475" class="label bright">ONE FRAMEWORK</text><text x="1134" y="475" class="label" text-anchor="end">ONE DEPLOYMENT MODEL</text>`;
19133
+ }
19134
+ function renderIllustration(type) {
19135
+ switch (type) {
19136
+ case "auth":
19137
+ return renderAuthIllustration();
19138
+ case "cache":
19139
+ return renderCacheIllustration();
19140
+ case "cli":
19141
+ return renderCliIllustration();
19142
+ case "integrations":
19143
+ return renderIntegrationsIllustration();
19144
+ case "project":
19145
+ return renderProjectIllustration();
19146
+ case "routing":
19147
+ return renderRoutingIllustration();
19148
+ default:
19149
+ return renderRuntimeIllustration();
19150
+ }
19151
+ }
19152
+ function renderFarmDocsSocialImageSvg(descriptor) {
19153
+ const titleLines = wrapText(descriptor.title, 22, 2);
19154
+ const longestTitleLine = Math.max(...titleLines.map((line) => line.length));
19155
+ const titleSize = titleLines.length === 1 ? longestTitleLine > 17 ? 62 : 74 : 56;
19156
+ const titleLineHeight = Math.round(titleSize * 0.98);
19157
+ const titleY = titleLines.length === 1 ? 294 : 266;
19158
+ const descriptionY = titleY + (titleLines.length - 1) * titleLineHeight + 59;
19159
+ const descriptionLines = wrapText(descriptor.description, 68, 2);
19160
+ const routeY = Math.max(418, descriptionY + descriptionLines.length * 29 + 24);
19161
+ const section = truncate(descriptor.section.toUpperCase(), 27);
19162
+ const route = truncate(descriptor.pageHref, 42);
19163
+ const footerUrl = truncate(descriptor.pageUrl.replace(/^https?:\/\//, ""), 70);
19164
+ const brand = truncate(descriptor.brand.toUpperCase(), 25);
19165
+ const titleId = `farm-docs-og-${descriptor.hash}`;
19166
+ return `<?xml version="1.0" encoding="UTF-8"?>
19167
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${FARM_DOCS_SOCIAL_IMAGE_WIDTH}" height="${FARM_DOCS_SOCIAL_IMAGE_HEIGHT}" viewBox="0 0 ${FARM_DOCS_SOCIAL_IMAGE_WIDTH} ${FARM_DOCS_SOCIAL_IMAGE_HEIGHT}" role="img" aria-labelledby="${titleId}-title ${titleId}-description">
19168
+ <title id="${titleId}-title">${escapeXml(descriptor.imageAlt)}</title>
19169
+ <desc id="${titleId}-description">${escapeXml(descriptor.description)}</desc>
19170
+ <metadata>${escapeXml(JSON.stringify({ generator: "Farm.js docs", page: descriptor.pageUrl, illustration: descriptor.illustration }))}</metadata>
19171
+ <style type="text/css">
19172
+ ${renderEmbeddedFont("Farm Sans", descriptor.fonts?.sans, "100 900")}
19173
+ ${renderEmbeddedFont("Farm Mono", descriptor.fonts?.mono, "100 900")}
19174
+ ${renderEmbeddedFont("Farm Pixel", descriptor.fonts?.display, "400 700")}
19175
+ .sans{font-family:"Farm Sans","Arial",sans-serif}.mono,.label,.code,.diagram-title,.micro{font-family:"Farm Mono","Menlo","DejaVu Sans Mono",monospace}.pixel{font-family:"Farm Pixel","Farm Mono",monospace}.label{fill:#8b8b8b;font-size:10px;font-weight:600;letter-spacing:1.2px}.code{fill:#8b8b8b;font-size:11px}.diagram-title{fill:#e7e7e7;font-size:11px;font-weight:650}.micro{fill:#777;font-size:8px;letter-spacing:.45px}.bright{fill:#f5f5f4}.ink{fill:#050505}.ink-muted{fill:#4c4c4c}
19176
+ </style>
19177
+ <defs>
19178
+ <pattern id="canvas-grid" width="40" height="40" patternUnits="userSpaceOnUse"><path d="M40 0H0V40" fill="none" stroke="#151515"/></pattern>
19179
+ <pattern id="diagonal" width="12" height="12" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><line x1="0" y1="0" x2="0" y2="12" stroke="#171717" stroke-width="2"/></pattern>
19180
+ <clipPath id="frame-clip"><rect x="28" y="28" width="1144" height="574"/></clipPath>
19181
+ </defs>
19182
+ <rect width="1200" height="630" fill="#050505"/>
19183
+ <rect width="1200" height="630" fill="url(#canvas-grid)"/>
19184
+ <g clip-path="url(#frame-clip)">
19185
+ <rect x="28" y="28" width="1144" height="574" fill="#020202"/>
19186
+ <rect x="782" y="114" width="390" height="411" fill="url(#diagonal)"/>
19187
+ </g>
19188
+ <rect x="28.5" y="28.5" width="1143" height="573" fill="none" stroke="#323232"/>
19189
+ <path d="M28 114.5h1144M28 525.5h1144M781.5 114v411" fill="none" stroke="#303030"/>
19190
+
19191
+ <g transform="translate(71 51)">
19192
+ <rect width="11" height="11" rx="1" fill="#f5f5f4"/><rect x="15" width="28" height="11" rx="1" fill="#f5f5f4"/>
19193
+ <rect y="15" width="11" height="11" rx="1" fill="#9b9b9b"/><rect x="15" y="15" width="28" height="11" rx="1" fill="#9b9b9b"/>
19194
+ <rect y="30" width="11" height="11" rx="1" fill="#5f5f5f"/><rect x="15" y="30" width="20" height="11" rx="1" fill="#5f5f5f"/>
19195
+ <text x="61" y="24" class="mono bright" font-size="24" font-weight="550">FARM<tspan fill="#777">.JS</tspan></text>
19196
+ <text x="61" y="43" class="label">BY FARMING LABS</text>
19197
+ </g>
19198
+ <text x="1134" y="72" class="label" text-anchor="end">${escapeXml(brand)} \xB7 DOCUMENTATION</text>
19199
+
19200
+ <text x="71" y="198" class="mono bright" font-size="13" font-weight="650">DOCS</text>
19201
+ <line x1="117" y1="193" x2="155" y2="193" stroke="#696969"/>
19202
+ <text x="166" y="198" class="mono" fill="#9b9b9b" font-size="13">${escapeXml(section)}</text>
19203
+ ${renderTextLines(titleLines, 71, titleY, titleLineHeight, `class="pixel bright" font-size="${titleSize}" font-weight="500" letter-spacing="-2.4"`)}
19204
+ ${renderTextLines(descriptionLines, 71, descriptionY, 29, 'class="sans" fill="#a3a3a3" font-size="20" font-weight="430" letter-spacing="-.3"')}
19205
+ <rect x="71" y="${routeY}" width="${Math.min(390, 56 + route.length * 8)}" height="36" fill="#050505" stroke="#3c3c3c"/>
19206
+ <text x="85" y="${routeY + 23}" class="mono bright" font-size="11" font-weight="600">GET</text>
19207
+ <text x="119" y="${routeY + 23}" class="mono" fill="#898989" font-size="11">${escapeXml(route)}</text>
19208
+
19209
+ ${renderIllustration(descriptor.illustration)}
19210
+
19211
+ <text x="71" y="570" class="mono bright" font-size="13" font-weight="550">${escapeXml(footerUrl)}</text>
19212
+ <text x="1134" y="570" class="mono" fill="#9b9b9b" font-size="12" text-anchor="end">FARM.JS DOCUMENTATION</text>
19213
+ <path d="M20 20h10M20 20v10M1180 20h-10M1180 20v10M20 610h10M20 610v-10M1180 610h-10M1180 610v-10" fill="none" stroke="#9b9b9b"/>
19214
+ </svg>`;
19215
+ }
19216
+ function renderFarmDocsSocialMetadata(descriptor, customImage) {
19217
+ const imageUrl = customImage ? new URL(customImage, descriptor.pageUrl).href : descriptor.imageUrl;
19218
+ const customExtension = customImage?.toLowerCase().split(/[?#]/, 1)[0];
19219
+ const imageType = customExtension?.endsWith(".webp") ? "image/webp" : customExtension?.endsWith(".png") ? "image/png" : customExtension?.match(/\.jpe?g$/) ? "image/jpeg" : "image/svg+xml";
19220
+ const tag = /* @__PURE__ */ __name((property, content, name = false) => `<meta ${name ? "name" : "property"}="${property}" content="${escapeXml(content)}">`, "tag");
19221
+ return [
19222
+ tag("og:type", "article"),
19223
+ tag("og:site_name", descriptor.siteName),
19224
+ tag("og:title", descriptor.title),
19225
+ tag("og:description", descriptor.description),
19226
+ tag("og:url", descriptor.pageUrl),
19227
+ tag("og:image", imageUrl),
19228
+ tag("og:image:type", imageType),
19229
+ ...customImage ? [] : [
19230
+ tag("og:image:width", String(FARM_DOCS_SOCIAL_IMAGE_WIDTH)),
19231
+ tag("og:image:height", String(FARM_DOCS_SOCIAL_IMAGE_HEIGHT))
19232
+ ],
19233
+ tag("og:image:alt", descriptor.imageAlt),
19234
+ tag("twitter:card", "summary_large_image", true),
19235
+ tag("twitter:title", descriptor.title, true),
19236
+ tag("twitter:description", descriptor.description, true),
19237
+ tag("twitter:image", imageUrl, true),
19238
+ tag("twitter:image:alt", descriptor.imageAlt, true)
19239
+ ].join("\n ");
19240
+ }
19241
+ var import_node_crypto4, FARM_DOCS_SOCIAL_IMAGE_WIDTH, FARM_DOCS_SOCIAL_IMAGE_HEIGHT, FARM_DOCS_SOCIAL_IMAGE_VERSION;
19242
+ var init_social_image = __esm({
19243
+ "src/docs/social-image.ts"() {
19244
+ "use strict";
19245
+ import_node_crypto4 = require("crypto");
19246
+ FARM_DOCS_SOCIAL_IMAGE_WIDTH = 1200;
19247
+ FARM_DOCS_SOCIAL_IMAGE_HEIGHT = 630;
19248
+ FARM_DOCS_SOCIAL_IMAGE_VERSION = 3;
19249
+ __name(normalizeEntry, "normalizeEntry");
19250
+ __name(encodeSlugPath, "encodeSlugPath");
19251
+ __name(getSocialImageConfig, "getSocialImageConfig");
19252
+ __name(getNavTitle, "getNavTitle");
19253
+ __name(isFalse, "isFalse");
19254
+ __name(isExternalOrRootPath, "isExternalOrRootPath");
19255
+ __name(isFarmDocsSocialImageEnabled, "isFarmDocsSocialImageEnabled");
19256
+ __name(getFarmDocsCustomSocialImage, "getFarmDocsCustomSocialImage");
19257
+ __name(resolveIllustration, "resolveIllustration");
19258
+ __name(createHashValue, "createHashValue");
19259
+ __name(resolveBaseUrl, "resolveBaseUrl");
19260
+ __name(createFarmDocsSocialImageDescriptor, "createFarmDocsSocialImageDescriptor");
19261
+ __name(getFarmDocsSocialImageSlug, "getFarmDocsSocialImageSlug");
19262
+ __name(escapeXml, "escapeXml");
19263
+ __name(truncate, "truncate");
19264
+ __name(wrapText, "wrapText");
19265
+ __name(renderTextLines, "renderTextLines");
19266
+ __name(renderEmbeddedFont, "renderEmbeddedFont");
19267
+ __name(renderArrow, "renderArrow");
19268
+ __name(renderPanelHeader, "renderPanelHeader");
19269
+ __name(renderRoutingIllustration, "renderRoutingIllustration");
19270
+ __name(renderAuthIllustration, "renderAuthIllustration");
19271
+ __name(renderCacheIllustration, "renderCacheIllustration");
19272
+ __name(renderIntegrationsIllustration, "renderIntegrationsIllustration");
19273
+ __name(renderCliIllustration, "renderCliIllustration");
19274
+ __name(renderProjectIllustration, "renderProjectIllustration");
19275
+ __name(renderRuntimeIllustration, "renderRuntimeIllustration");
19276
+ __name(renderIllustration, "renderIllustration");
19277
+ __name(renderFarmDocsSocialImageSvg, "renderFarmDocsSocialImageSvg");
19278
+ __name(renderFarmDocsSocialMetadata, "renderFarmDocsSocialMetadata");
19279
+ }
19280
+ });
19281
+
18132
19282
  // src/docs/handler.ts
18133
19283
  function trimSlashes2(value) {
18134
19284
  return value.replace(/^\/+|\/+$/g, "");
18135
19285
  }
18136
- function normalizeEntry(entry) {
19286
+ function normalizeEntry2(entry) {
18137
19287
  if (!entry || entry === "/") return "/";
18138
19288
  return `/${trimSlashes2(entry)}`;
18139
19289
  }
@@ -18145,10 +19295,10 @@ function resolveFarmDocsFavicon(docs, options) {
18145
19295
  if (typeof configuredFavicon === "string" && configuredFavicon.trim()) {
18146
19296
  return configuredFavicon.trim();
18147
19297
  }
18148
- const publicDir = import_node_path11.default.join(import_node_path11.default.resolve(options.root), "public");
19298
+ const publicDir = import_node_path13.default.join(import_node_path13.default.resolve(options.root), "public");
18149
19299
  for (const fileName of FARM_DOCS_FAVICON_FILES) {
18150
- const faviconPath = import_node_path11.default.join(publicDir, fileName);
18151
- if ((0, import_node_fs8.existsSync)(faviconPath) && (0, import_node_fs8.statSync)(faviconPath).isFile()) {
19300
+ const faviconPath = import_node_path13.default.join(publicDir, fileName);
19301
+ if ((0, import_node_fs9.existsSync)(faviconPath) && (0, import_node_fs9.statSync)(faviconPath).isFile()) {
18152
19302
  return `/${fileName}`;
18153
19303
  }
18154
19304
  }
@@ -18182,10 +19332,10 @@ function isSafeSegment(segment) {
18182
19332
  return segment !== ".." && !segment.includes("/") && !segment.includes("\\");
18183
19333
  }
18184
19334
  function resolveInside(root, target) {
18185
- const resolvedRoot = import_node_path11.default.resolve(root);
18186
- const resolvedTarget = import_node_path11.default.resolve(target);
18187
- const relative4 = import_node_path11.default.relative(resolvedRoot, resolvedTarget);
18188
- if (relative4 === "" || !relative4.startsWith("..") && !import_node_path11.default.isAbsolute(relative4)) {
19335
+ const resolvedRoot = import_node_path13.default.resolve(root);
19336
+ const resolvedTarget = import_node_path13.default.resolve(target);
19337
+ const relative4 = import_node_path13.default.relative(resolvedRoot, resolvedTarget);
19338
+ if (relative4 === "" || !relative4.startsWith("..") && !import_node_path13.default.isAbsolute(relative4)) {
18189
19339
  return resolvedTarget;
18190
19340
  }
18191
19341
  return null;
@@ -18194,36 +19344,36 @@ function isFarmDocsRequest(docs, request) {
18194
19344
  if (!docs?.enabled) return false;
18195
19345
  if (request.method !== "GET" && request.method !== "HEAD") return false;
18196
19346
  const pathname = new URL(request.url).pathname;
18197
- const entry = normalizeEntry(docs.entry);
19347
+ const entry = normalizeEntry2(docs.entry);
18198
19348
  if (entry === "/") return true;
18199
19349
  return pathname === entry || pathname === `${entry}.md` || pathname.startsWith(`${entry}/`);
18200
19350
  }
18201
19351
  function resolveFarmDocsContentDir(docs, options) {
18202
- const root = import_node_path11.default.resolve(options.root);
19352
+ const root = import_node_path13.default.resolve(options.root);
18203
19353
  const srcDir = options.srcDir || "src";
18204
19354
  const configuredContentDir = docs.contentDir || docs.config.contentDir;
18205
19355
  if (configuredContentDir) {
18206
- return import_node_path11.default.isAbsolute(configuredContentDir) ? configuredContentDir : import_node_path11.default.join(root, configuredContentDir);
19356
+ return import_node_path13.default.isAbsolute(configuredContentDir) ? configuredContentDir : import_node_path13.default.join(root, configuredContentDir);
18207
19357
  }
18208
19358
  const entryDir = docs.config.entry || trimSlashes2(docs.entry) || "docs";
18209
- const appDocsDir = import_node_path11.default.join(root, srcDir, "app", entryDir);
18210
- if ((0, import_node_fs8.existsSync)(appDocsDir)) return appDocsDir;
18211
- return import_node_path11.default.join(root, entryDir);
19359
+ const appDocsDir = import_node_path13.default.join(root, srcDir, "app", entryDir);
19360
+ if ((0, import_node_fs9.existsSync)(appDocsDir)) return appDocsDir;
19361
+ return import_node_path13.default.join(root, entryDir);
18212
19362
  }
18213
19363
  function getFarmDocsRouteTypeEntries(docs) {
18214
19364
  if (!docs?.enabled) return [];
18215
- const entry = normalizeEntry(docs.entry);
19365
+ const entry = normalizeEntry2(docs.entry);
18216
19366
  if (entry === "/") return ["/", "/[...docs]"];
18217
19367
  return [entry, `${entry}/[...docs]`];
18218
19368
  }
18219
19369
  function getFarmDocsDocumentNavigationMatchers(docs) {
18220
19370
  if (!docs?.enabled) return [];
18221
- const entry = normalizeEntry(docs.entry);
19371
+ const entry = normalizeEntry2(docs.entry);
18222
19372
  return [entry === "/" ? "/(.*)" : `${entry}(.*)`];
18223
19373
  }
18224
19374
  function getRequestSlug(docs, request) {
18225
19375
  const pathname = new URL(request.url).pathname;
18226
- const entry = normalizeEntry(docs.entry);
19376
+ const entry = normalizeEntry2(docs.entry);
18227
19377
  if (entry === "/") return normalizeSlug(pathname);
18228
19378
  if (pathname === entry || pathname === `${entry}.md`) return "";
18229
19379
  return normalizeSlug(pathname.slice(entry.length));
@@ -18231,14 +19381,14 @@ function getRequestSlug(docs, request) {
18231
19381
  function findDocsPageFile(contentDir, slug) {
18232
19382
  const segments = slug ? slug.split("/").filter(Boolean) : [];
18233
19383
  if (!segments.every(isSafeSegment)) return null;
18234
- const slugDir = import_node_path11.default.join(contentDir, ...segments);
18235
- const candidates = segments.length === 0 ? DOCS_FILE_NAMES.map((filename) => import_node_path11.default.join(contentDir, filename)) : [
18236
- ...DOCS_FILE_NAMES.map((filename) => import_node_path11.default.join(slugDir, filename)),
18237
- ...DOCS_FILE_EXTENSIONS2.map((extension) => import_node_path11.default.join(contentDir, `${slug}${extension}`))
19384
+ const slugDir = import_node_path13.default.join(contentDir, ...segments);
19385
+ const candidates = segments.length === 0 ? DOCS_FILE_NAMES.map((filename) => import_node_path13.default.join(contentDir, filename)) : [
19386
+ ...DOCS_FILE_NAMES.map((filename) => import_node_path13.default.join(slugDir, filename)),
19387
+ ...DOCS_FILE_EXTENSIONS2.map((extension) => import_node_path13.default.join(contentDir, `${slug}${extension}`))
18238
19388
  ];
18239
19389
  for (const candidate of candidates) {
18240
19390
  const safePath = resolveInside(contentDir, candidate);
18241
- if (safePath && (0, import_node_fs8.existsSync)(safePath) && (0, import_node_fs8.statSync)(safePath).isFile()) {
19391
+ if (safePath && (0, import_node_fs9.existsSync)(safePath) && (0, import_node_fs9.statSync)(safePath).isFile()) {
18242
19392
  return safePath;
18243
19393
  }
18244
19394
  }
@@ -18273,7 +19423,7 @@ function titleFromMarkdown2(body, fallback) {
18273
19423
  function loadFarmDocsPage(contentDir, docs, slug) {
18274
19424
  const sourcePath = findDocsPageFile(contentDir, slug);
18275
19425
  if (!sourcePath) return null;
18276
- const source = (0, import_node_fs8.readFileSync)(sourcePath, "utf8");
19426
+ const source = (0, import_node_fs9.readFileSync)(sourcePath, "utf8");
18277
19427
  const { frontmatter, body } = parseFrontmatter(source);
18278
19428
  const title = frontmatter.title || titleFromMarkdown2(body, titleFromSlug(slug));
18279
19429
  const href = createDocsHref(docs.entry, slug);
@@ -18281,6 +19431,7 @@ function loadFarmDocsPage(contentDir, docs, slug) {
18281
19431
  slug,
18282
19432
  title,
18283
19433
  description: frontmatter.description,
19434
+ section: frontmatter.section,
18284
19435
  href,
18285
19436
  sourcePath,
18286
19437
  lastModified: resolveFarmDocsPageLastModified(contentDir, sourcePath, frontmatter),
@@ -18289,15 +19440,15 @@ function loadFarmDocsPage(contentDir, docs, slug) {
18289
19440
  };
18290
19441
  }
18291
19442
  function createDocsHref(entry, slug) {
18292
- const normalizedEntry = normalizeEntry(entry);
19443
+ const normalizedEntry = normalizeEntry2(entry);
18293
19444
  const normalizedSlug = trimSlashes2(slug);
18294
19445
  if (normalizedEntry === "/") return normalizedSlug ? `/${normalizedSlug}` : "/";
18295
19446
  return normalizedSlug ? `${normalizedEntry}/${normalizedSlug}` : normalizedEntry;
18296
19447
  }
18297
19448
  function pathToSlug(contentDir, filePath) {
18298
- const relative4 = import_node_path11.default.relative(contentDir, filePath).replace(/\\/g, "/");
19449
+ const relative4 = import_node_path13.default.relative(contentDir, filePath).replace(/\\/g, "/");
18299
19450
  if (relative4.startsWith("..")) return null;
18300
- const extension = import_node_path11.default.extname(relative4);
19451
+ const extension = import_node_path13.default.extname(relative4);
18301
19452
  if (!DOCS_FILE_EXTENSIONS2.includes(extension)) return null;
18302
19453
  const withoutExtension = relative4.slice(0, -extension.length);
18303
19454
  if (withoutExtension === "page" || withoutExtension === "index") return "";
@@ -18310,12 +19461,12 @@ function loadPage(contentDir, docs, request) {
18310
19461
  return loadFarmDocsPage(contentDir, docs, getRequestSlug(docs, request));
18311
19462
  }
18312
19463
  function discoverFarmDocsPages(contentDir, docs) {
18313
- if (!(0, import_node_fs8.existsSync)(contentDir)) return [];
19464
+ if (!(0, import_node_fs9.existsSync)(contentDir)) return [];
18314
19465
  const pages = [];
18315
19466
  const visit = /* @__PURE__ */ __name((dir) => {
18316
- for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
19467
+ for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
18317
19468
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
18318
- const absolutePath = import_node_path11.default.join(dir, entry.name);
19469
+ const absolutePath = import_node_path13.default.join(dir, entry.name);
18319
19470
  if (entry.isDirectory()) {
18320
19471
  visit(absolutePath);
18321
19472
  continue;
@@ -18323,7 +19474,7 @@ function discoverFarmDocsPages(contentDir, docs) {
18323
19474
  if (!entry.isFile()) continue;
18324
19475
  const slug = pathToSlug(contentDir, absolutePath);
18325
19476
  if (slug === null) continue;
18326
- const source = (0, import_node_fs8.readFileSync)(absolutePath, "utf8");
19477
+ const source = (0, import_node_fs9.readFileSync)(absolutePath, "utf8");
18327
19478
  const { frontmatter, body } = parseFrontmatter(source);
18328
19479
  pages.push({
18329
19480
  slug,
@@ -19101,7 +20252,7 @@ function renderPixelBreadcrumb(page2, docs) {
19101
20252
  const parentSegments = segments.slice(0, -1);
19102
20253
  const parentSegment = parentSegments[parentSegments.length - 1];
19103
20254
  const currentSegment = segments[segments.length - 1];
19104
- const entry = normalizeEntry(docs.entry);
20255
+ const entry = normalizeEntry2(docs.entry);
19105
20256
  const parentPath = parentSegments.join("/");
19106
20257
  const parentHref = entry === "/" ? `/${parentPath}` : `${entry}/${parentPath}`;
19107
20258
  return `<nav class="fd-breadcrumb" aria-label="Breadcrumb">
@@ -19139,7 +20290,7 @@ ${items.map(
19139
20290
  </div>`;
19140
20291
  }
19141
20292
  function renderDocsRuntimeScript(docs) {
19142
- const docsEntry = JSON.stringify(normalizeEntry(docs.entry));
20293
+ const docsEntry = JSON.stringify(normalizeEntry2(docs.entry));
19143
20294
  return `<script>(()=>{if(window.__farmDocsRuntime)return;window.__farmDocsRuntime=true;document.documentElement.dataset.farmDocsRuntime="true";document.documentElement.dataset.farmDocsRuntimeId=Math.random().toString(36).slice(2);const docsEntry=${docsEntry};let cleanupToc=()=>{};let closeMobileSidebar=()=>{};const normalizePath=(path)=>path.length>1?path.replace(/\\/+$/,""):path;const isDocsPath=(path)=>{const next=normalizePath(path);const entry=normalizePath(docsEntry);if(next.endsWith(".md"))return false;if(entry==="/")return true;return next===entry||next.startsWith(entry+"/")};const initToc=()=>{cleanupToc();const toc=document.getElementById("nd-toc");if(!toc){cleanupToc=()=>{};return}const links=Array.from(toc.querySelectorAll("[data-toc-item]"));const thumb=toc.querySelector("[data-toc-thumb]");const pairs=links.map((link)=>{let id=link.hash.slice(1);try{id=decodeURIComponent(id)}catch{}return{link,heading:document.getElementById(id)}}).filter((item)=>item.heading);const setActive=(active)=>{for(const {link} of pairs)link.dataset.active=link===active.link?"true":"false";if(!thumb)return;const styles=getComputedStyle(active.link);const top=active.link.offsetTop+parseFloat(styles.paddingTop||"0");const bottom=active.link.offsetTop+active.link.clientHeight-parseFloat(styles.paddingBottom||"0");thumb.style.clipPath="polygon(0 "+top+"px,100% "+top+"px,100% "+bottom+"px,0 "+bottom+"px)"};const update=()=>{if(pairs.length===0)return;const offset=Math.min(window.innerHeight*0.3,160);let active=pairs[0];for(const pair of pairs){if(pair.heading.getBoundingClientRect().top<=offset)active=pair;else break}setActive(active)};let frame=0;const schedule=()=>{if(frame)return;frame=requestAnimationFrame(()=>{frame=0;update()})};const onHashChange=()=>setTimeout(schedule,0);window.addEventListener("scroll",schedule,{passive:true});window.addEventListener("resize",schedule);window.addEventListener("hashchange",onHashChange);cleanupToc=()=>{window.removeEventListener("scroll",schedule);window.removeEventListener("resize",schedule);window.removeEventListener("hashchange",onHashChange);if(frame)cancelAnimationFrame(frame);frame=0};update()};const getSidebar=()=>document.getElementById("nd-sidebar");const ensureActiveVisible=()=>{const sidebar=getSidebar();if(!sidebar)return;const active=sidebar.querySelector('a[data-active="true"]');if(!(active instanceof HTMLElement))return;const activeRect=active.getBoundingClientRect();const sidebarRect=sidebar.getBoundingClientRect();if(activeRect.top<sidebarRect.top||activeRect.bottom>sidebarRect.bottom)sidebar.scrollTop+=activeRect.top-sidebarRect.top-(sidebar.clientHeight-activeRect.height)/2};const setSidebarActive=(path)=>{const sidebar=getSidebar();if(!sidebar)return;const current=normalizePath(path);for(const link of Array.from(sidebar.querySelectorAll("a[href]"))){try{link.dataset.active=normalizePath(new URL(link.href,location.href).pathname)===current?"true":"false"}catch{}}ensureActiveVisible()};const initMobileSidebar=()=>{const layout=document.getElementById("nd-docs-layout");const sidebar=getSidebar();const toggle=document.querySelector("[data-sidebar-toggle]");const backdrop=document.querySelector("[data-sidebar-backdrop]");if(!layout||!sidebar||!(toggle instanceof HTMLButtonElement))return;const setOpen=(open)=>{layout.dataset.sidebarOpen=open?"true":"false";document.documentElement.dataset.farmDocsSidebar=open?"open":"closed";toggle.setAttribute("aria-expanded",open?"true":"false");toggle.setAttribute("aria-label",open?"Close menu":"Open menu")};const toggleOpen=()=>setOpen(layout.dataset.sidebarOpen!=="true");closeMobileSidebar=()=>setOpen(false);toggle.addEventListener("click",(event)=>{event.preventDefault();toggleOpen()});backdrop?.addEventListener("click",()=>closeMobileSidebar());document.addEventListener("keydown",(event)=>{if(event.key==="Escape")closeMobileSidebar()});sidebar.addEventListener("click",(event)=>{const target=event.target instanceof Element?event.target.closest("a[href]"):null;if(target)closeMobileSidebar()});closeMobileSidebar()};const initSidebarScroll=()=>{const sidebar=getSidebar();if(!sidebar)return;const key="farmdocs:sidebar-scroll:"+location.origin;const getStorage=()=>{try{return window.sessionStorage}catch{return null}};const readSaved=()=>{try{const raw=getStorage()?.getItem(key);if(!raw)return null;const parsed=JSON.parse(raw);return parsed&&typeof parsed==="object"?parsed:null}catch{return null}};const save=(path=location.pathname)=>{try{getStorage()?.setItem(key,JSON.stringify({path,scrollTop:sidebar.scrollTop}))}catch{}};const saved=readSaved();if(saved?.path===location.pathname&&Number.isFinite(Number(saved.scrollTop)))sidebar.scrollTop=Number(saved.scrollTop);ensureActiveVisible();save();sidebar.addEventListener("scroll",()=>save(),{passive:true});sidebar.addEventListener("click",(event)=>{const target=event.target instanceof Element?event.target.closest("a[href]"):null;if(!target)return;try{save(new URL(target.href,location.href).pathname)}catch{save()}});window.addEventListener("beforeunload",()=>save())};let navigateController=null;const getPageKey=(root)=>{const article=root.getElementById("nd-page");if(!article)return"";return article.querySelector("h1")?.textContent?.trim()||article.textContent?.replace(/\\s+/g," ").trim().slice(0,160)||""};const swapDocsPage=(html,url)=>{const nextDoc=new DOMParser().parseFromString(html,"text/html");const nextArticle=nextDoc.getElementById("nd-page");const currentArticle=document.getElementById("nd-page");if(!nextArticle||!currentArticle)return false;const nextKey=getPageKey(nextDoc);const importedArticle=document.importNode(nextArticle,true);currentArticle.replaceWith(importedArticle);const renderedArticle=document.getElementById("nd-page");if(!renderedArticle||renderedArticle===currentArticle||(nextKey&&getPageKey(document)!==nextKey))return false;const nextToc=nextDoc.getElementById("nd-toc");const currentToc=document.getElementById("nd-toc");if(nextToc&&currentToc)currentToc.replaceWith(document.importNode(nextToc,true));if(nextDoc.title)document.title=nextDoc.title;const nextDescription=nextDoc.querySelector('meta[name="description"]');const currentDescription=document.querySelector('meta[name="description"]');if(nextDescription&&currentDescription)currentDescription.setAttribute("content",nextDescription.getAttribute("content")||"");setSidebarActive(url.pathname);initToc();closeMobileSidebar();return true};const navigateDocs=async(url,{replace=false,scroll=true}={})=>{if(!isDocsPath(url.pathname))return false;if(navigateController)navigateController.abort();const controller=new AbortController();navigateController=controller;document.documentElement.dataset.farmDocsNavigating="true";try{const response=await fetch(url.href,{cache:"no-store",headers:{accept:"text/html","x-farm-docs-navigate":"1"},signal:controller.signal});if(!response.ok||!((response.headers.get("content-type")||"").includes("text/html")))return false;const html=await response.text();if(!swapDocsPage(html,url))return false;if(replace)history.replaceState({farmDocs:true},"",url.href);else history.pushState({farmDocs:true},"",url.href);if(scroll){if(url.hash){let id=url.hash.slice(1);try{id=decodeURIComponent(id)}catch{}document.getElementById(id)?.scrollIntoView({block:"start"})}else window.scrollTo({top:0,left:0})}return true}catch(error){if(error?.name==="AbortError")return true;return false}finally{if(navigateController===controller){delete document.documentElement.dataset.farmDocsNavigating;navigateController=null}}};const initClientNavigation=()=>{document.addEventListener("click",(event)=>{if(event.defaultPrevented||event.button!==0||event.metaKey||event.ctrlKey||event.shiftKey||event.altKey)return;const target=event.target instanceof Element?event.target.closest("a[href]"):null;if(!target||target.target||target.hasAttribute("download"))return;let url;try{url=new URL(target.href,location.href)}catch{return}if(url.origin!==location.origin||!isDocsPath(url.pathname))return;if(normalizePath(url.pathname)===normalizePath(location.pathname)&&url.hash)return;event.preventDefault();navigateDocs(url).then((handled)=>{if(!handled)location.href=url.href})});window.addEventListener("popstate",()=>{navigateDocs(new URL(location.href),{replace:true,scroll:false}).then((handled)=>{if(!handled)location.reload()})})};const init=()=>{initToc();initMobileSidebar();initSidebarScroll();initClientNavigation()};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",init,{once:true});else init()})();</script>`;
19144
20295
  }
19145
20296
  function renderDocsPageActionsRuntimeScript() {
@@ -19154,13 +20305,13 @@ ${renderDocsHashRuntimeScript()}
19154
20305
  ${renderDocsPageActionsRuntimeScript()}`;
19155
20306
  }
19156
20307
  function readCssWithImports(filePath, seen = /* @__PURE__ */ new Set()) {
19157
- const resolved = import_node_path11.default.resolve(filePath);
20308
+ const resolved = import_node_path13.default.resolve(filePath);
19158
20309
  if (seen.has(resolved)) return "";
19159
20310
  seen.add(resolved);
19160
- const source = (0, import_node_fs8.readFileSync)(resolved, "utf8");
20311
+ const source = (0, import_node_fs9.readFileSync)(resolved, "utf8");
19161
20312
  return source.replace(/@import\s+["']([^"']+)["'];?/g, (_match, importPath) => {
19162
20313
  try {
19163
- const importedPath = importPath.startsWith(".") ? import_node_path11.default.resolve(import_node_path11.default.dirname(resolved), importPath) : (0, import_node_module5.createRequire)(resolved).resolve(importPath);
20314
+ const importedPath = importPath.startsWith(".") ? import_node_path13.default.resolve(import_node_path13.default.dirname(resolved), importPath) : (0, import_node_module5.createRequire)(resolved).resolve(importPath);
19164
20315
  return readCssWithImports(importedPath, seen);
19165
20316
  } catch {
19166
20317
  return "";
@@ -19168,11 +20319,11 @@ function readCssWithImports(filePath, seen = /* @__PURE__ */ new Set()) {
19168
20319
  });
19169
20320
  }
19170
20321
  function resolvePixelBorderThemeCss(options) {
19171
- const cacheKey = import_node_path11.default.resolve(options.root);
20322
+ const cacheKey = import_node_path13.default.resolve(options.root);
19172
20323
  const cached = themeCssCache.get(cacheKey);
19173
20324
  if (cached !== void 0) return cached;
19174
20325
  try {
19175
- const requireFromApp = (0, import_node_module5.createRequire)(import_node_path11.default.join(cacheKey, "package.json"));
20326
+ const requireFromApp = (0, import_node_module5.createRequire)(import_node_path13.default.join(cacheKey, "package.json"));
19176
20327
  const themeCssPath = requireFromApp.resolve("@farming-labs/theme/pixel-border/css");
19177
20328
  const requireFromTheme = (0, import_node_module5.createRequire)(themeCssPath);
19178
20329
  const fumadocsCssPath = requireFromTheme.resolve("fumadocs-ui/style.css");
@@ -19185,17 +20336,28 @@ ${readCssWithImports(themeCssPath)}`;
19185
20336
  return "";
19186
20337
  }
19187
20338
  }
19188
- function renderFarmDocsBridgeCss(docs) {
20339
+ function renderFarmDocsBridgeCss(docs, fontAssets, layoutFonts) {
19189
20340
  const sidebarWidth = getThemeLayoutValue(docs, "sidebarWidth", 320);
19190
20341
  const contentWidth = getThemeLayoutValue(docs, "contentWidth", 860);
20342
+ const fontFaces = fontAssets.map(
20343
+ ({ family, url }) => `@font-face { font-family: "${family}"; src: url("${url}") format("woff2"); font-style: normal; font-weight: 100 900; font-display: block; }`
20344
+ ).join("\n");
20345
+ const fontVariables = [
20346
+ fontAssets.some(({ family }) => family === "Geist Sans") ? '--font-geist-sans: "Geist Sans", ui-sans-serif, system-ui, sans-serif;' : "",
20347
+ fontAssets.some(({ family }) => family === "Geist Mono") ? '--font-geist-mono: "Geist Mono", ui-monospace, monospace;' : ""
20348
+ ].filter(Boolean).join(" ");
20349
+ const fontCss = fontFaces ? `${fontFaces}
20350
+ :root { ${fontVariables} }` : "";
20351
+ const layoutFontVariables = [
20352
+ renderFarmDocsLayoutFontVariable("--fd-layout-font-body", layoutFonts?.body),
20353
+ renderFarmDocsLayoutFontVariable("--fd-layout-font-code", layoutFonts?.code)
20354
+ ].filter(Boolean).join(" ");
19191
20355
  return `
19192
- @font-face { font-family: "Geist Sans"; src: local("Geist Sans"), url("${GEIST_SANS_FONT_URL}") format("woff2"), url("/node_modules/geist/dist/fonts/geist-sans/Geist-Variable.woff2") format("woff2"); font-display: block; font-style: normal; font-weight: 100 900; }
19193
- @font-face { font-family: "Geist Mono"; src: local("Geist Mono"), url("${GEIST_MONO_FONT_URL}") format("woff2"), url("/node_modules/geist/dist/fonts/geist-mono/GeistMono-Variable.woff2") format("woff2"); font-display: block; font-style: normal; font-weight: 100 900; }
19194
- :root { color-scheme: dark; --font-geist-sans: "Geist Sans"; --font-geist-mono: "Geist Mono"; --fd-sidebar-width: ${sidebarWidth}px; --fd-content-width: ${contentWidth}px; --fd-toc-width: 240px; --fd-docs-height: 100vh; --fd-docs-row-1: var(--fd-nav-height, 44px); --fd-docs-font-sans: var(--font-geist-sans, "Geist Sans", var(--font-sans, system-ui, -apple-system, sans-serif)); --fd-docs-font-mono: var(--font-geist-mono, "Geist Mono", var(--font-mono, ui-monospace, monospace)); --fd-font-sans: var(--fd-docs-font-sans); --fd-font-mono: var(--fd-docs-font-mono); --fd-pixel-rail-width: 12px; --fd-sidebar-edge: calc(var(--fd-pixel-rail-width) + 18px); --fd-sidebar-guide-x: calc(var(--fd-sidebar-edge) + 16px); --fd-sidebar-link-x: calc(var(--fd-sidebar-guide-x) + 22px); --fd-sidebar-sub-guide-x: calc(var(--fd-sidebar-link-x) + 7px); --fd-sidebar-sub-link-x: calc(var(--fd-sidebar-sub-guide-x) + 28px); --fd-sidebar-branch-gap: 0px; --fd-sidebar-nested-icon-gap: 0px; --fd-sidebar-line-color: color-mix(in srgb, var(--color-fd-border, hsl(0 0% 15%)) 88%, transparent); }
20356
+ :root { color-scheme: dark; --font-geist-sans: ui-sans-serif, system-ui, sans-serif; --font-geist-mono: ui-monospace, monospace; ${layoutFontVariables} --fd-sidebar-width: ${sidebarWidth}px; --fd-content-width: ${contentWidth}px; --fd-toc-width: 240px; --fd-docs-height: 100vh; --fd-docs-row-1: var(--fd-nav-height, 44px); --fd-docs-font-sans: var(--fd-layout-font-body, var(--font-geist-sans, var(--font-sans, system-ui, -apple-system, sans-serif))); --fd-docs-font-mono: var(--fd-layout-font-code, var(--font-geist-mono, var(--font-mono, ui-monospace, monospace))); --fd-font-sans: var(--fd-docs-font-sans); --fd-font-mono: var(--fd-docs-font-mono); --fd-pixel-rail-width: 12px; --fd-sidebar-edge: calc(var(--fd-pixel-rail-width) + 18px); --fd-sidebar-guide-x: calc(var(--fd-sidebar-edge) + 16px); --fd-sidebar-link-x: calc(var(--fd-sidebar-guide-x) + 22px); --fd-sidebar-sub-guide-x: calc(var(--fd-sidebar-link-x) + 7px); --fd-sidebar-sub-link-x: calc(var(--fd-sidebar-sub-guide-x) + 28px); --fd-sidebar-branch-gap: 0px; --fd-sidebar-nested-icon-gap: 0px; --fd-sidebar-line-color: color-mix(in srgb, var(--color-fd-border, hsl(0 0% 15%)) 88%, transparent); }
19195
20357
  * { box-sizing: border-box; }
19196
20358
  html { background: var(--color-fd-background, hsl(0 0% 2%)); scroll-padding-top: calc(var(--fd-nav-height, 44px) + 24px); }
19197
20359
  html[data-farm-docs-sidebar="open"], html[data-farm-docs-sidebar="open"] body { overflow: hidden; }
19198
- body { margin: 0; min-height: 100vh; background: var(--color-fd-background, hsl(0 0% 2%)); color: var(--color-fd-foreground, oklch(0.985 0.001 106.423)); font-family: var(--fd-docs-font-sans); text-rendering: optimizeLegibility; }
20360
+ body { margin: 0; min-height: 100vh; background: var(--color-fd-background, hsl(0 0% 2%)); color: var(--color-fd-foreground, oklch(0.985 0.001 106.423)); font-family: var(--fd-docs-font-sans); font-synthesis: none; text-rendering: optimizeLegibility; }
19199
20361
  ::selection { background: var(--color-fd-foreground, #fff); color: var(--color-fd-background, #000); }
19200
20362
  a { color: inherit; }
19201
20363
  #nd-docs-layout { --fd-sidebar-col: var(--fd-sidebar-width); display: grid; grid-template: "sidebar header header" var(--fd-nav-height, 44px) "sidebar main toc" 1fr / var(--fd-sidebar-width) minmax(0, 1fr) var(--fd-toc-width) !important; min-height: 100vh; border-top: 1px solid var(--color-fd-border, hsl(0 0% 15%)); background: var(--color-fd-background, hsl(0 0% 2%)); }
@@ -19375,14 +20537,45 @@ function renderFarmDocsBridgeCss(docs) {
19375
20537
  .sh__line { min-height: 1.6em; }
19376
20538
  }
19377
20539
  ${farmDocsPixelBorderCss}
20540
+ ${fontCss}
19378
20541
  `;
19379
20542
  }
19380
- function renderPixelDocsHtml(page2, pages, docs, themeCss, clientEntry, faviconHref) {
20543
+ function renderFarmDocsLayoutFontVariable(name, font) {
20544
+ const family = font?.style.fontFamily;
20545
+ if (!family || /[;{}<>]/.test(family)) return "";
20546
+ return `${name}: ${family};`;
20547
+ }
20548
+ function renderFarmDocsFontPreloads(fontAssets) {
20549
+ return fontAssets.map(
20550
+ ({ url }) => `<link rel="preload" href="${escapeAttribute2(url)}" as="font" type="font/woff2" crossorigin>`
20551
+ ).join("\n ");
20552
+ }
20553
+ function renderFarmDocsFontPreloadHeader(fontAssets) {
20554
+ return fontAssets.map(({ url }) => `<${url}>; rel=preload; as=font; type=font/woff2; crossorigin`).join(", ");
20555
+ }
20556
+ function getFarmLayoutFontPreloads(layoutFonts) {
20557
+ const seen = /* @__PURE__ */ new Set();
20558
+ return [layoutFonts?.body, layoutFonts?.code].flatMap(
20559
+ (font) => (font?.preloads || []).filter(({ href }) => {
20560
+ if (seen.has(href)) return false;
20561
+ seen.add(href);
20562
+ return true;
20563
+ })
20564
+ );
20565
+ }
20566
+ function renderFarmLayoutFontPreloadHeader(layoutFonts) {
20567
+ return getFarmLayoutFontPreloads(layoutFonts).map(({ href, type }) => `<${href}>; rel=preload; as=font; type=${type}; crossorigin`).join(", ");
20568
+ }
20569
+ function renderPixelDocsHtml(page2, pages, docs, themeCss, clientEntry, faviconHref, requestUrl, fontAssets, layoutFonts, fontStylesheetHref) {
19381
20570
  const navTitle = typeof docs.config.nav === "object" && docs.config.nav && "title" in docs.config.nav ? String(docs.config.nav.title || "Docs") : "Docs";
19382
20571
  const description = page2.description || docs.config.metadata?.description || "";
19383
20572
  const tocItems = extractTocItems(page2.body, getThemeTocDepth(docs));
19384
20573
  const themeName = getThemeName(docs);
19385
20574
  const searchEnabled = isFarmDocsSearchEnabled(docs);
20575
+ const socialMetadata = isFarmDocsSocialImageEnabled(page2, docs) ? renderFarmDocsSocialMetadata(
20576
+ createFarmDocsSocialImageDescriptor(page2, docs, requestUrl),
20577
+ getFarmDocsCustomSocialImage(page2)
20578
+ ) : "";
19386
20579
  return `<!DOCTYPE html>
19387
20580
  <html class="dark" lang="en" data-docs-theme="${escapeAttribute2(themeName)}">
19388
20581
  <head>
@@ -19391,11 +20584,12 @@ function renderPixelDocsHtml(page2, pages, docs, themeCss, clientEntry, faviconH
19391
20584
  <meta name="generator" content="@farming-labs/docs via Farm.js">
19392
20585
  <title>${escapeHtml(page2.title)}</title>
19393
20586
  ${renderFarmDocsFaviconLink(faviconHref)}
19394
- <link rel="preload" href="${GEIST_SANS_FONT_URL}" as="font" type="font/woff2" crossorigin>
19395
- <link rel="preload" href="${GEIST_MONO_FONT_URL}" as="font" type="font/woff2" crossorigin>
20587
+ ${renderFarmDocsFontPreloads(fontAssets)}
20588
+ ${fontStylesheetHref ? `<link rel="stylesheet" href="${escapeAttribute2(fontStylesheetHref)}">` : ""}
19396
20589
  ${description ? `<meta name="description" content="${escapeHtml(description)}">` : ""}
20590
+ ${socialMetadata}
19397
20591
  <style>${themeCss}
19398
- ${renderFarmDocsBridgeCss(docs)}</style>
20592
+ ${renderFarmDocsBridgeCss(docs, fontAssets, layoutFonts)}</style>
19399
20593
  ${searchEnabled ? renderDocsSearchBootstrapScript() : ""}
19400
20594
  </head>
19401
20595
  <body>
@@ -19447,9 +20641,34 @@ ${renderMarkdownHtmlWithTitleMeta(page2, docs)}
19447
20641
  }
19448
20642
  function createFarmDocsHandler(docs, options) {
19449
20643
  const faviconHref = resolveFarmDocsFavicon(docs, options);
20644
+ const fontAssets = options.fontAssets ?? toFarmDocsPublicFontAssets(resolveFarmDocsFontAssets(options.root));
20645
+ const fallbackFontPreloadHeader = renderFarmDocsFontPreloadHeader(fontAssets);
19450
20646
  return /* @__PURE__ */ __name(async function handleFarmDocsRequest(request) {
19451
20647
  if (!docs?.enabled || request.method !== "GET" && request.method !== "HEAD") return null;
19452
20648
  const contentDir = resolveFarmDocsContentDir(docs, options);
20649
+ const requestUrl = new URL(request.url);
20650
+ const socialImageSlug = getFarmDocsSocialImageSlug(docs, requestUrl);
20651
+ if (socialImageSlug !== null) {
20652
+ const socialImagePage = loadFarmDocsPage(contentDir, docs, socialImageSlug);
20653
+ if (!socialImagePage || !isFarmDocsSocialImageEnabled(socialImagePage, docs) || getFarmDocsCustomSocialImage(socialImagePage)) {
20654
+ return null;
20655
+ }
20656
+ const descriptor = createFarmDocsSocialImageDescriptor(socialImagePage, docs, requestUrl);
20657
+ if (requestUrl.pathname !== descriptor.imagePath) return null;
20658
+ const etag = `"${descriptor.hash}"`;
20659
+ const immutable = requestUrl.searchParams.get("v") === descriptor.hash;
20660
+ const headers = new Headers({
20661
+ "Content-Type": "image/svg+xml; charset=utf-8",
20662
+ "Cache-Control": immutable ? "public, max-age=31536000, immutable" : "public, max-age=0, must-revalidate",
20663
+ ETag: etag,
20664
+ "X-Content-Type-Options": "nosniff"
20665
+ });
20666
+ if (request.headers.get("if-none-match") === etag) {
20667
+ return new Response(null, { status: 304, headers });
20668
+ }
20669
+ if (request.method === "HEAD") return new Response(null, { status: 200, headers });
20670
+ return new Response(renderFarmDocsSocialImageSvg(descriptor), { status: 200, headers });
20671
+ }
19453
20672
  const publicResponse = createFarmDocsPublicResponse(contentDir, docs, request);
19454
20673
  if (publicResponse) return publicResponse;
19455
20674
  if (!isFarmDocsRequest(docs, request)) return null;
@@ -19472,6 +20691,11 @@ function createFarmDocsHandler(docs, options) {
19472
20691
  }
19473
20692
  );
19474
20693
  }
20694
+ const pathname = new URL(request.url).pathname;
20695
+ const layoutFonts = await options.resolveLayoutFonts?.(pathname);
20696
+ const usesLayoutFonts = Boolean(layoutFonts?.body || layoutFonts?.code);
20697
+ const activeFontAssets = usesLayoutFonts ? [] : fontAssets;
20698
+ const fontPreloadHeader = usesLayoutFonts ? renderFarmLayoutFontPreloadHeader(layoutFonts) : fallbackFontPreloadHeader;
19475
20699
  return new Response(
19476
20700
  renderPixelDocsHtml(
19477
20701
  page2,
@@ -19479,39 +20703,44 @@ function createFarmDocsHandler(docs, options) {
19479
20703
  docs,
19480
20704
  resolvePixelBorderThemeCss(options),
19481
20705
  options.clientEntry || "/farm-client.js",
19482
- faviconHref
20706
+ faviconHref,
20707
+ requestUrl,
20708
+ activeFontAssets,
20709
+ layoutFonts,
20710
+ usesLayoutFonts ? options.fontStylesheetHref : void 0
19483
20711
  ),
19484
20712
  {
19485
20713
  status: 200,
19486
20714
  headers: {
19487
20715
  "Content-Type": "text/html; charset=utf-8",
19488
- "Cache-Control": "public, s-maxage=60, stale-while-revalidate=300"
20716
+ "Cache-Control": "public, s-maxage=60, stale-while-revalidate=300",
20717
+ ...fontPreloadHeader ? { Link: fontPreloadHeader } : {}
19489
20718
  }
19490
20719
  }
19491
20720
  );
19492
20721
  }, "handleFarmDocsRequest");
19493
20722
  }
19494
- var import_node_fs8, import_node_module5, import_node_path11, import_docs, import_marked, import_sugar_high, DOCS_FILE_NAMES, DOCS_FILE_EXTENSIONS2, FARM_DOCS_FALLBACK_FAVICON, FARM_DOCS_FAVICON_FILES, GEIST_SANS_FONT_URL, GEIST_MONO_FONT_URL, CODE_LANGUAGE_LABELS, EXTENSIONLESS_CODE_FILENAMES, SIDEBAR_SECTION_ORDER, SIDEBAR_PAGE_ORDER, themeCssCache;
20723
+ var import_node_fs9, import_node_module5, import_node_path13, import_docs, import_marked, import_sugar_high, DOCS_FILE_NAMES, DOCS_FILE_EXTENSIONS2, FARM_DOCS_FALLBACK_FAVICON, FARM_DOCS_FAVICON_FILES, CODE_LANGUAGE_LABELS, EXTENSIONLESS_CODE_FILENAMES, SIDEBAR_SECTION_ORDER, SIDEBAR_PAGE_ORDER, themeCssCache;
19495
20724
  var init_handler = __esm({
19496
20725
  "src/docs/handler.ts"() {
19497
20726
  "use strict";
19498
- import_node_fs8 = require("fs");
20727
+ import_node_fs9 = require("fs");
19499
20728
  import_node_module5 = require("module");
19500
- import_node_path11 = __toESM(require("path"));
20729
+ import_node_path13 = __toESM(require("path"));
19501
20730
  import_docs = require("@farming-labs/docs");
19502
20731
  import_marked = require("marked");
19503
20732
  import_sugar_high = require("sugar-high");
20733
+ init_fonts();
19504
20734
  init_last_modified();
19505
20735
  init_pixel_border_css();
19506
20736
  init_search_client();
20737
+ init_social_image();
19507
20738
  DOCS_FILE_NAMES = ["page.mdx", "page.md", "index.mdx", "index.md"];
19508
20739
  DOCS_FILE_EXTENSIONS2 = [".mdx", ".md"];
19509
20740
  FARM_DOCS_FALLBACK_FAVICON = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='black'/%3E%3Cpath d='M7 8h18v3H10v5h12v3H10v5H7z' fill='white'/%3E%3C/svg%3E";
19510
20741
  FARM_DOCS_FAVICON_FILES = ["favicon.svg", "favicon.ico", "favicon.png"];
19511
- GEIST_SANS_FONT_URL = "/assets/Geist-Variable-CrgPqtmy.woff2";
19512
- GEIST_MONO_FONT_URL = "/assets/GeistMono-Variable-BNLlm6Cd.woff2";
19513
20742
  __name(trimSlashes2, "trimSlashes");
19514
- __name(normalizeEntry, "normalizeEntry");
20743
+ __name(normalizeEntry2, "normalizeEntry");
19515
20744
  __name(normalizeSlug, "normalizeSlug");
19516
20745
  __name(resolveFarmDocsFavicon, "resolveFarmDocsFavicon");
19517
20746
  __name(renderFarmDocsFaviconLink, "renderFarmDocsFaviconLink");
@@ -19701,6 +20930,11 @@ var init_handler = __esm({
19701
20930
  __name(readCssWithImports, "readCssWithImports");
19702
20931
  __name(resolvePixelBorderThemeCss, "resolvePixelBorderThemeCss");
19703
20932
  __name(renderFarmDocsBridgeCss, "renderFarmDocsBridgeCss");
20933
+ __name(renderFarmDocsLayoutFontVariable, "renderFarmDocsLayoutFontVariable");
20934
+ __name(renderFarmDocsFontPreloads, "renderFarmDocsFontPreloads");
20935
+ __name(renderFarmDocsFontPreloadHeader, "renderFarmDocsFontPreloadHeader");
20936
+ __name(getFarmLayoutFontPreloads, "getFarmLayoutFontPreloads");
20937
+ __name(renderFarmLayoutFontPreloadHeader, "renderFarmLayoutFontPreloadHeader");
19704
20938
  __name(renderPixelDocsHtml, "renderPixelDocsHtml");
19705
20939
  __name(createFarmDocsHandler, "createFarmDocsHandler");
19706
20940
  }
@@ -20469,8 +21703,8 @@ var init_generator = __esm({
20469
21703
  }
20470
21704
  routeGroups.get(key).push(route);
20471
21705
  }
20472
- for (const [path29, routeList] of routeGroups) {
20473
- const openAPIPath = this.convertToOpenAPIPath(path29);
21706
+ for (const [path31, routeList] of routeGroups) {
21707
+ const openAPIPath = this.convertToOpenAPIPath(path31);
20474
21708
  spec.paths[openAPIPath] = {};
20475
21709
  for (const route of routeList) {
20476
21710
  for (const method of route.methods) {
@@ -20484,8 +21718,8 @@ var init_generator = __esm({
20484
21718
  /**
20485
21719
  * Convert Farm.js API path to OpenAPI path format
20486
21720
  */
20487
- convertToOpenAPIPath(path29) {
20488
- return path29.replace(/^\/api/, "");
21721
+ convertToOpenAPIPath(path31) {
21722
+ return path31.replace(/^\/api/, "");
20489
21723
  }
20490
21724
  /**
20491
21725
  * Extract request body schema from endpoint
@@ -20647,8 +21881,8 @@ var init_generator = __esm({
20647
21881
  /**
20648
21882
  * Generate operation summary
20649
21883
  */
20650
- generateSummary(path29, method) {
20651
- const cleanPath = path29.replace(/^\/api\//, "");
21884
+ generateSummary(path31, method) {
21885
+ const cleanPath = path31.replace(/^\/api\//, "");
20652
21886
  const pathParts = cleanPath.split("/");
20653
21887
  const lastPart = pathParts[pathParts.length - 1];
20654
21888
  const action = method === "GET" ? "Get" : method === "POST" ? "Create" : method === "PUT" ? "Update" : method === "DELETE" ? "Delete" : method === "PATCH" ? "Update" : method;
@@ -20657,22 +21891,22 @@ var init_generator = __esm({
20657
21891
  /**
20658
21892
  * Generate operation description
20659
21893
  */
20660
- generateDescription(path29, method) {
20661
- const cleanPath = path29.replace(/^\/api\//, "");
21894
+ generateDescription(path31, method) {
21895
+ const cleanPath = path31.replace(/^\/api\//, "");
20662
21896
  return `${method} ${cleanPath} endpoint`;
20663
21897
  }
20664
21898
  /**
20665
21899
  * Generate operation ID
20666
21900
  */
20667
- generateOperationId(path29, method) {
20668
- const cleanPath = path29.replace(/^\/api\//, "").replace(/\//g, "_");
21901
+ generateOperationId(path31, method) {
21902
+ const cleanPath = path31.replace(/^\/api\//, "").replace(/\//g, "_");
20669
21903
  return `${method.toLowerCase()}_${cleanPath}`;
20670
21904
  }
20671
21905
  /**
20672
21906
  * Generate tags for grouping operations
20673
21907
  */
20674
- generateTags(path29) {
20675
- const cleanPath = path29.replace(/^\/api\//, "");
21908
+ generateTags(path31) {
21909
+ const cleanPath = path31.replace(/^\/api\//, "");
20676
21910
  const pathParts = cleanPath.split("/");
20677
21911
  if (pathParts.length > 1) {
20678
21912
  return [pathParts[0]];
@@ -20685,8 +21919,8 @@ var init_generator = __esm({
20685
21919
  async generateSpecFile(routes, outputPath) {
20686
21920
  const spec = await this.generateSpec(routes);
20687
21921
  const fs8 = require("fs");
20688
- const path29 = require("path");
20689
- const dir = path29.dirname(outputPath);
21922
+ const path31 = require("path");
21923
+ const dir = path31.dirname(outputPath);
20690
21924
  if (!fs8.existsSync(dir)) {
20691
21925
  fs8.mkdirSync(dir, { recursive: true });
20692
21926
  }
@@ -21106,7 +22340,7 @@ async function createFarmDevtoolsSnapshot(input) {
21106
22340
  generatedAt: (input.now?.() || /* @__PURE__ */ new Date()).toISOString(),
21107
22341
  health: resolveHealth(diagnostics),
21108
22342
  project: {
21109
- name: import_node_path12.default.basename(import_node_path12.default.resolve(input.root)),
22343
+ name: import_node_path14.default.basename(import_node_path14.default.resolve(input.root)),
21110
22344
  root: input.root,
21111
22345
  srcDir: input.srcDir,
21112
22346
  basePath: config.basePath || "/",
@@ -21155,11 +22389,11 @@ async function createFarmDevtoolsSnapshot(input) {
21155
22389
  diagnostics
21156
22390
  };
21157
22391
  }
21158
- var import_node_path12;
22392
+ var import_node_path14;
21159
22393
  var init_devtools = __esm({
21160
22394
  "src/devtools.ts"() {
21161
22395
  "use strict";
21162
- import_node_path12 = __toESM(require("path"));
22396
+ import_node_path14 = __toESM(require("path"));
21163
22397
  init_config2();
21164
22398
  init_cron();
21165
22399
  init_route_runtime();
@@ -22983,7 +24217,7 @@ function fileContainsProgrammaticPageRoute(file) {
22983
24217
  }
22984
24218
  function rewriteEarlySsrRelativeImports(options) {
22985
24219
  const cleanId = options.id.split("?", 1)[0];
22986
- if (!path25.isAbsolute(cleanId) || cleanId.replace(/\\/g, "/").includes("/node_modules/")) {
24220
+ if (!path27.isAbsolute(cleanId) || cleanId.replace(/\\/g, "/").includes("/node_modules/")) {
22987
24221
  return null;
22988
24222
  }
22989
24223
  const replacements = [];
@@ -23003,7 +24237,7 @@ function rewriteEarlySsrRelativeImports(options) {
23003
24237
  const suffixIndex = source.value.search(/[?#]/);
23004
24238
  const sourcePath = suffixIndex === -1 ? source.value : source.value.slice(0, suffixIndex);
23005
24239
  const suffix = suffixIndex === -1 ? "" : source.value.slice(suffixIndex);
23006
- const resolvedPath = path25.resolve(path25.dirname(cleanId), sourcePath);
24240
+ const resolvedPath = path27.resolve(path27.dirname(cleanId), sourcePath);
23007
24241
  replacements.push({
23008
24242
  start: source.start,
23009
24243
  end: source.end,
@@ -23084,7 +24318,7 @@ function farmPlugin(options = {}, initialPluginManager) {
23084
24318
  ...layerRoots.length ? {
23085
24319
  server: {
23086
24320
  fs: {
23087
- allow: [path25.resolve(options.root || process.cwd()), ...layerRoots]
24321
+ allow: [path27.resolve(options.root || process.cwd()), ...layerRoots]
23088
24322
  }
23089
24323
  }
23090
24324
  } : {}
@@ -23115,9 +24349,9 @@ function farmPlugin(options = {}, initialPluginManager) {
23115
24349
  },
23116
24350
  server
23117
24351
  );
23118
- const globalsCSSPath = path25.join(server.config.root, "src/app/globals.css");
24352
+ const globalsCSSPath = path27.join(server.config.root, "src/app/globals.css");
23119
24353
  if (!fs7.existsSync(globalsCSSPath)) {
23120
- const appDir = path25.join(server.config.root, "src/app");
24354
+ const appDir = path27.join(server.config.root, "src/app");
23121
24355
  if (!fs7.existsSync(appDir)) {
23122
24356
  fs7.mkdirSync(appDir, { recursive: true });
23123
24357
  }
@@ -23139,10 +24373,10 @@ function farmPlugin(options = {}, initialPluginManager) {
23139
24373
  });
23140
24374
  }
23141
24375
  const sourceRoots = getFarmSourceRoots(farmConfig);
23142
- server.watcher.add(sourceRoots.map((source) => path25.join(source.root, source.srcDir)));
24376
+ server.watcher.add(sourceRoots.map((source) => path27.join(source.root, source.srcDir)));
23143
24377
  if (farmConfig.i18n.enabled) {
23144
24378
  server.watcher.add(
23145
- farmConfig.i18n.messages.includes("{locale}") ? path25.dirname(farmConfig.i18n.messages) : farmConfig.i18n.messages
24379
+ farmConfig.i18n.messages.includes("{locale}") ? path27.dirname(farmConfig.i18n.messages) : farmConfig.i18n.messages
23146
24380
  );
23147
24381
  }
23148
24382
  const workflowConfig = farmConfig.workflows;
@@ -23152,7 +24386,7 @@ function farmPlugin(options = {}, initialPluginManager) {
23152
24386
  ...farmDocsDevRuntime?.getFarmDocsRouteTypeEntries(farmConfig.docs) ?? []
23153
24387
  ], "getExtraRouteTypes");
23154
24388
  const appDirSlugs = sourceRoots.map(
23155
- (source) => path25.join(source.root, source.srcDir, "app").replace(/\\/g, "/")
24389
+ (source) => path27.join(source.root, source.srcDir, "app").replace(/\\/g, "/")
23156
24390
  );
23157
24391
  const generateTypeArtifacts = /* @__PURE__ */ __name(async (reason, selection = ALL_TYPE_ARTIFACTS, log = false) => {
23158
24392
  try {
@@ -23192,7 +24426,7 @@ function farmPlugin(options = {}, initialPluginManager) {
23192
24426
  }, "generateTypeArtifacts");
23193
24427
  await generateTypeArtifacts("startup");
23194
24428
  const srcDirSlugs = sourceRoots.map(
23195
- (source) => path25.join(source.root, source.srcDir).replace(/\\/g, "/")
24429
+ (source) => path27.join(source.root, source.srcDir).replace(/\\/g, "/")
23196
24430
  );
23197
24431
  const layerConfigFiles = new Set(
23198
24432
  farmConfig.layers.map((layer) => layer.configFile?.replace(/\\/g, "/")).filter((file) => Boolean(file))
@@ -23310,7 +24544,7 @@ function farmPlugin(options = {}, initialPluginManager) {
23310
24544
  await apiRouteManager.discoverRoutes();
23311
24545
  let discoveredWorkflows = [];
23312
24546
  const hasWorkflowDirectory = workflowConfig.enabled && workflowConfig.dirs.some(
23313
- (dir) => fs7.existsSync(path25.isAbsolute(dir) ? dir : path25.join(farmConfig.root, dir))
24547
+ (dir) => fs7.existsSync(path27.isAbsolute(dir) ? dir : path27.join(farmConfig.root, dir))
23314
24548
  );
23315
24549
  if (hasWorkflowDirectory) {
23316
24550
  const { createFarmWorkflowRequestHandler: createFarmWorkflowRequestHandler2, discoverFarmWorkflows: discoverFarmWorkflows2 } = await loadFarmWorkflowsDevRuntime();
@@ -23374,10 +24608,20 @@ function farmPlugin(options = {}, initialPluginManager) {
23374
24608
  logger.info(`Refreshed routes: ${reason}`);
23375
24609
  }
23376
24610
  }, "refreshRouteDiscovery");
24611
+ const farmDocsFontAssetList = farmDocsDevRuntime ? resolveFarmDocsFontAssets(farmConfig.root) : [];
23377
24612
  const farmDocsHandler = farmDocsDevRuntime ? farmDocsDevRuntime.createFarmDocsHandler(farmConfig.docs, {
23378
24613
  root: farmConfig.root,
23379
24614
  srcDir: farmConfig.srcDir,
23380
- clientEntry: "/@farm/client.js"
24615
+ clientEntry: "/@farm/client.js",
24616
+ fontAssets: toFarmDocsPublicFontAssets(farmDocsFontAssetList),
24617
+ resolveLayoutFonts: /* @__PURE__ */ __name(async (pathname) => {
24618
+ const layouts = routeManager.matchRoute(pathname).layouts;
24619
+ const layoutModules = await Promise.all(
24620
+ layouts.map((layout2) => routeManager.loadLayoutModule(layout2.modulePath))
24621
+ );
24622
+ return resolveFarmLayoutFonts(layoutModules);
24623
+ }, "resolveLayoutFonts"),
24624
+ fontStylesheetHref: "/@farm/fonts.css"
23381
24625
  }) : null;
23382
24626
  const farmDocsAPIHandler = farmDocsDevRuntime ? farmDocsDevRuntime.createFarmDocsAPIHandler({
23383
24627
  rootDir: farmConfig.root,
@@ -23385,22 +24629,7 @@ function farmPlugin(options = {}, initialPluginManager) {
23385
24629
  docs: farmConfig.docs
23386
24630
  }) : null;
23387
24631
  const farmDocsFontAssets = new Map(
23388
- farmDocsDevRuntime ? [
23389
- [
23390
- "/assets/Geist-Variable-CrgPqtmy.woff2",
23391
- path25.join(
23392
- farmConfig.root,
23393
- "node_modules/geist/dist/fonts/geist-sans/Geist-Variable.woff2"
23394
- )
23395
- ],
23396
- [
23397
- "/assets/GeistMono-Variable-BNLlm6Cd.woff2",
23398
- path25.join(
23399
- farmConfig.root,
23400
- "node_modules/geist/dist/fonts/geist-mono/GeistMono-Variable.woff2"
23401
- )
23402
- ]
23403
- ] : []
24632
+ farmDocsFontAssetList.map(({ url, sourcePath }) => [url, sourcePath])
23404
24633
  );
23405
24634
  const logRequest = /* @__PURE__ */ __name((method, urlPath, tag) => {
23406
24635
  try {
@@ -23464,11 +24693,12 @@ function farmPlugin(options = {}, initialPluginManager) {
23464
24693
  }
23465
24694
  }
23466
24695
  const farmDocsFontPath = farmDocsFontAssets.get(requestPathname);
23467
- if (farmDocsFontPath && fs7.existsSync(farmDocsFontPath)) {
24696
+ if ((requestMethod === "GET" || requestMethod === "HEAD") && farmDocsFontPath && fs7.existsSync(farmDocsFontPath)) {
23468
24697
  res.statusCode = 200;
23469
24698
  res.setHeader("Content-Type", "font/woff2");
23470
24699
  res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
23471
- fs7.createReadStream(farmDocsFontPath).pipe(res);
24700
+ if (requestMethod === "HEAD") res.end();
24701
+ else fs7.createReadStream(farmDocsFontPath).pipe(res);
23472
24702
  return;
23473
24703
  }
23474
24704
  if (requestMethod === "GET" && (requestPathname === FARM_DEVTOOLS_PATH || requestPathname === `${FARM_DEVTOOLS_PATH}.json`)) {
@@ -24074,6 +25304,7 @@ function farmPlugin(options = {}, initialPluginManager) {
24074
25304
  modulePath: toUrlPath(route.modulePath),
24075
25305
  isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
24076
25306
  shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
25307
+ islandStrategy: moduleMetadata.islandStrategy,
24077
25308
  metadata: {
24078
25309
  title: mergedMetadata.title,
24079
25310
  description: mergedMetadata.description
@@ -24458,6 +25689,7 @@ export const getManifest = () => ({
24458
25689
  search: route.search,
24459
25690
  isClientComponent: moduleMetadata.isClientComponent,
24460
25691
  shouldHydrate: moduleMetadata.shouldHydrate,
25692
+ islandStrategy: moduleMetadata.islandStrategy,
24461
25693
  preloads: [route.modulePath],
24462
25694
  // In dev, preload is just the module
24463
25695
  assets: []
@@ -24584,8 +25816,8 @@ if (import.meta.hot) {
24584
25816
  }
24585
25817
  logger.info(`Found ${ssgPages.length} SSG pages, ${ssrRoutes.length} SSR routes`);
24586
25818
  logger.info("Pre-rendering SSG pages...");
24587
- const outDir = path25.join(server?.config.root || process.cwd(), options.outDir || "dist");
24588
- const clientDir = path25.join(outDir, "client");
25819
+ const outDir = path27.join(server?.config.root || process.cwd(), options.outDir || "dist");
25820
+ const clientDir = path27.join(outDir, "client");
24589
25821
  for (const page2 of ssgPages) {
24590
25822
  try {
24591
25823
  const staticRequest = new Request(new URL(page2.urlPath, "http://farm.static"));
@@ -24596,7 +25828,7 @@ if (import.meta.hot) {
24596
25828
  const layoutModules = await Promise.all(
24597
25829
  layouts.map((l) => routeManager.loadLayoutModule(l.modulePath))
24598
25830
  );
24599
- const React3 = await import("react");
25831
+ const React4 = await import("react");
24600
25832
  const { renderToString } = await import("react-dom/server");
24601
25833
  const PageComponent = mod.default;
24602
25834
  const pageProps = {
@@ -24604,14 +25836,14 @@ if (import.meta.hot) {
24604
25836
  searchParams: Promise.resolve({}),
24605
25837
  path: page2.urlPath
24606
25838
  };
24607
- let pageElement = React3.createElement(
25839
+ let pageElement = React4.createElement(
24608
25840
  PageComponent,
24609
25841
  pageProps
24610
25842
  );
24611
25843
  for (let i = layoutModules.length - 1; i >= 0; i--) {
24612
25844
  const layoutModule = layoutModules[i];
24613
25845
  const LayoutComponent = layoutModule.default;
24614
- pageElement = React3.createElement(
25846
+ pageElement = React4.createElement(
24615
25847
  LayoutComponent,
24616
25848
  {
24617
25849
  children: pageElement,
@@ -24637,8 +25869,8 @@ if (import.meta.hot) {
24637
25869
  <script type="module" src="/assets/client.js"></script>
24638
25870
  </body>
24639
25871
  </html>`;
24640
- const outputPath = page2.urlPath === "/" ? path25.join(clientDir, "index.html") : path25.join(clientDir, page2.urlPath + ".html");
24641
- fs7.mkdirSync(path25.dirname(outputPath), { recursive: true });
25872
+ const outputPath = page2.urlPath === "/" ? path27.join(clientDir, "index.html") : path27.join(clientDir, page2.urlPath + ".html");
25873
+ fs7.mkdirSync(path27.dirname(outputPath), { recursive: true });
24642
25874
  fs7.writeFileSync(outputPath, fullHtml);
24643
25875
  const revalidateInfo = page2.revalidate ? ` (revalidate: ${page2.revalidate}s)` : "";
24644
25876
  logger.success(` \u2713 ${page2.urlPath}${revalidateInfo}`);
@@ -24647,7 +25879,7 @@ if (import.meta.hot) {
24647
25879
  logger.error(` \u2717 ${page2.urlPath}: ${error}`);
24648
25880
  }
24649
25881
  }
24650
- const manifestPath = path25.join(outDir, "__ssg_manifest.json");
25882
+ const manifestPath = path27.join(outDir, "__ssg_manifest.json");
24651
25883
  fs7.writeFileSync(
24652
25884
  manifestPath,
24653
25885
  JSON.stringify(
@@ -24683,9 +25915,9 @@ if (import.meta.hot) {
24683
25915
  }
24684
25916
  const currentFarmConfig = farmApp?.getConfig();
24685
25917
  const normalizedFile = file.replace(/\\/g, "/");
24686
- const currentSrcRoot = currentFarmConfig ? getFarmSourceRoots(currentFarmConfig).map((source) => path25.join(source.root, source.srcDir).replace(/\\/g, "/")).find((sourceRoot) => normalizedFile.startsWith(`${sourceRoot}/`)) || null : null;
25918
+ const currentSrcRoot = currentFarmConfig ? getFarmSourceRoots(currentFarmConfig).map((source) => path27.join(source.root, source.srcDir).replace(/\\/g, "/")).find((sourceRoot) => normalizedFile.startsWith(`${sourceRoot}/`)) || null : null;
24687
25919
  if (currentSrcRoot && normalizedFile.startsWith(`${currentSrcRoot}/`) && isProgrammaticRoutesFileName(normalizedFile)) {
24688
- logUpdate("PAGE", `updated ${path25.basename(file)}`);
25920
+ logUpdate("PAGE", `updated ${path27.basename(file)}`);
24689
25921
  for (const mod of modules) {
24690
25922
  server2.moduleGraph.invalidateModule(mod);
24691
25923
  }
@@ -25076,6 +26308,7 @@ import React from 'react'
25076
26308
  import { hydrateRoot, createRoot } from 'react-dom/client'
25077
26309
  import { installChunkErrorRecovery, SPARouter } from '@farm.js/core/client'
25078
26310
  import { createClientPluginManager } from '@farm.js/core/plugin/client'
26311
+ import { scheduleFarmIslandHydration } from '@farm.js/core/internal/client-runtime'
25079
26312
  import { reviveDeferredData } from '@farm.js/core/deferred'
25080
26313
  import {
25081
26314
  createFarmDeploymentMismatchError,
@@ -25328,6 +26561,7 @@ class LegacyManifestSPARouter {
25328
26561
 
25329
26562
  // Only prefetch routes that will hydrate on the client.
25330
26563
  if (!match.route.isClientComponent && !match.route.shouldHydrate) return;
26564
+ if (match.route.islandStrategy && match.route.islandStrategy !== 'load') return;
25331
26565
 
25332
26566
  const modulePath = match.route.modulePath;
25333
26567
  if (this.moduleCache.has(modulePath)) return;
@@ -25472,6 +26706,12 @@ let hasClientTakenOver = false;
25472
26706
  const routeSlotRoots = new Map();
25473
26707
  const routeSlotDefinitions = new Map();
25474
26708
  let activeRouteInterception = null;
26709
+ let pendingPageHydrationController = null;
26710
+
26711
+ function cancelPendingPageHydration() {
26712
+ pendingPageHydrationController?.abort();
26713
+ pendingPageHydrationController = null;
26714
+ }
25475
26715
 
25476
26716
  function normalizeServerProps(rawProps) {
25477
26717
  const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
@@ -25540,7 +26780,11 @@ async function hydrateInitialRouteSlots() {
25540
26780
  routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
25541
26781
  if (!slot.isClientComponent && !slot.shouldHydrate) continue;
25542
26782
  try {
25543
- hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
26783
+ const slotHydrated = await renderRouteSlot(slot, 'hydrate');
26784
+ hydrated = slotHydrated || hydrated;
26785
+ if (slotHydrated) {
26786
+ replayPreHydrationClicks(document.getElementById(slot.containerId));
26787
+ }
25544
26788
  } catch (error) {
25545
26789
  console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
25546
26790
  }
@@ -25611,16 +26855,29 @@ function applyCanonicalPathFromProps(props) {
25611
26855
  window.history.replaceState({ ...(window.history.state || {}), path: canonicalPath }, '', canonicalPath);
25612
26856
  }
25613
26857
 
25614
- function replayPreHydrationClicks() {
25615
- window.__FARM_HYDRATED__ = true;
25616
- document.documentElement.dataset.farmHydrated = 'true';
26858
+ function replayPreHydrationClicks(container = null) {
26859
+ if (!container) {
26860
+ markFarmHydrated();
26861
+ } else {
26862
+ container.dataset.farmIslandHydrated = 'true';
26863
+ }
25617
26864
 
25618
26865
  const queue = Array.isArray(window.__FARM_PREHYDRATION_CLICK_QUEUE__)
25619
26866
  ? window.__FARM_PREHYDRATION_CLICK_QUEUE__
25620
26867
  : [];
25621
26868
  if (queue.length === 0) return;
25622
26869
 
25623
- const queuedClicks = queue.splice(0, queue.length);
26870
+ const queuedClicks = [];
26871
+ const remainingClicks = [];
26872
+ for (const queuedClick of queue) {
26873
+ const target = queuedClick?.target;
26874
+ if (!container || (target instanceof Node && container.contains(target))) {
26875
+ queuedClicks.push(queuedClick);
26876
+ } else {
26877
+ remainingClicks.push(queuedClick);
26878
+ }
26879
+ }
26880
+ queue.splice(0, queue.length, ...remainingClicks);
25624
26881
  for (const queuedClick of queuedClicks) {
25625
26882
  const target = queuedClick?.target;
25626
26883
  if (!target || typeof target.click !== 'function') continue;
@@ -25629,6 +26886,11 @@ function replayPreHydrationClicks() {
25629
26886
  }
25630
26887
  }
25631
26888
 
26889
+ function markFarmHydrated() {
26890
+ window.__FARM_HYDRATED__ = true;
26891
+ document.documentElement.dataset.farmHydrated = 'true';
26892
+ }
26893
+
25632
26894
  async function buildClientHydrationElement(PageComponent, pageProps) {
25633
26895
  let element = React.createElement(PageComponent, pageProps);
25634
26896
  const loadingModulePath = window.__FARM_LOADING_MODULE__;
@@ -25771,9 +27033,10 @@ async function tryHydrateImportedPage(
25771
27033
  layouts,
25772
27034
  useHydrate = false,
25773
27035
  existingProps = null,
27036
+ signal = null,
25774
27037
  ) {
25775
27038
  const modulePath = route?.modulePath;
25776
- if (!modulePath) {
27039
+ if (!modulePath || signal?.aborted) {
25777
27040
  return false;
25778
27041
  }
25779
27042
 
@@ -25782,6 +27045,7 @@ async function tryHydrateImportedPage(
25782
27045
  pageModule = await import(/* @vite-ignore */ modulePath);
25783
27046
  pageModuleCache.set(modulePath, pageModule);
25784
27047
  }
27048
+ if (signal?.aborted || !container?.isConnected) return false;
25785
27049
 
25786
27050
  const PageComponent = pageModule?.default;
25787
27051
  if (!PageComponent) {
@@ -25796,6 +27060,7 @@ async function tryHydrateImportedPage(
25796
27060
  window.location.pathname,
25797
27061
  existingProps,
25798
27062
  );
27063
+ if (signal?.aborted || !container?.isConnected) return false;
25799
27064
 
25800
27065
  const wrappedElement = useHydrate && container?.id === '__farm_page__'
25801
27066
  ? wrapWithIntegrationProviders(
@@ -25806,6 +27071,7 @@ async function tryHydrateImportedPage(
25806
27071
  currentPageProps,
25807
27072
  layouts,
25808
27073
  );
27074
+ if (signal?.aborted || !container?.isConnected) return false;
25809
27075
 
25810
27076
  if (useHydrate) {
25811
27077
  try {
@@ -25836,6 +27102,7 @@ async function tryHydrateImportedPage(
25836
27102
  async function renderPage(pageData) {
25837
27103
  const container = document.getElementById('root');
25838
27104
  if (!container) return;
27105
+ cancelPendingPageHydration();
25839
27106
  const destination = window.location.pathname + window.location.search;
25840
27107
 
25841
27108
  if (pageData.interception) {
@@ -25852,6 +27119,7 @@ async function renderPage(pageData) {
25852
27119
  modulePath: pageData.modulePath,
25853
27120
  isClientComponent: pageData.isClientComponent === true,
25854
27121
  shouldHydrate: pageData.shouldHydrate === true,
27122
+ islandStrategy: pageData.islandStrategy || 'load',
25855
27123
  };
25856
27124
  const params = pageData.props?.params || {};
25857
27125
  const layouts = (pageData.layoutModules || []).map((modulePath, index) => ({
@@ -26051,14 +27319,6 @@ async function hydrate() {
26051
27319
  }
26052
27320
 
26053
27321
  try {
26054
- // Pre-load layout for SPA navigation
26055
- try {
26056
- const layoutModule = await import(/* @vite-ignore */ '/src/app/layout.tsx');
26057
- LayoutComponent = layoutModule.default;
26058
- } catch (e) {
26059
- console.warn('[Farm.js] Could not preload layout:', e);
26060
- }
26061
-
26062
27322
  // Check if this is a client component (set by SSR)
26063
27323
  const isClientComponent = window.__FARM_IS_CLIENT__ === true;
26064
27324
  const modulePath = window.__FARM_PAGE_MODULE__;
@@ -26106,34 +27366,88 @@ async function hydrate() {
26106
27366
  return
26107
27367
  }
26108
27368
 
26109
- const hydrationSession = await farmClientRuntime.beginHydration({
26110
- container: pageContainer,
26111
- mode: shouldHydrate ? 'hydrate' : 'render',
26112
- });
27369
+ const currentRoute = findRoute(window.location.pathname)?.route;
27370
+ const islandStrategy = window.__FARM_ISLAND_STRATEGY__ || currentRoute?.islandStrategy || 'load';
27371
+ pageContainer.dataset.farmIsland = 'page';
27372
+ pageContainer.dataset.farmIslandStrategy = islandStrategy;
26113
27373
 
26114
- let hydrated = false;
27374
+ const hydrationPathname = window.location.pathname;
27375
+ const hydrationController = new AbortController();
27376
+ pendingPageHydrationController = hydrationController;
26115
27377
  try {
26116
- hydrated = await tryHydrateImportedPage(
26117
- pageContainer,
26118
- { modulePath },
26119
- currentPageProps.params || {},
26120
- layouts,
26121
- shouldHydrate,
26122
- currentPageProps,
26123
- );
26124
- await farmClientRuntime.completeHydration(hydrationSession);
26125
- } catch (error) {
26126
- await farmClientRuntime.failHydration(hydrationSession, error);
26127
- throw error;
26128
- }
27378
+ await scheduleFarmIslandHydration({
27379
+ container: pageContainer,
27380
+ strategy: islandStrategy,
27381
+ signal: hydrationController.signal,
27382
+ hydrate: async () => {
27383
+ if (
27384
+ hydrationController.signal.aborted ||
27385
+ !pageContainer.isConnected ||
27386
+ window.location.pathname !== hydrationPathname
27387
+ ) {
27388
+ return;
27389
+ }
26129
27390
 
26130
- if (hydrated) {
26131
- replayPreHydrationClicks();
26132
- console.log('[Farm.js] \u2705 Hydrated:', modulePath);
26133
- return;
26134
- }
27391
+ // Layout code is only needed when this route boundary actually hydrates.
27392
+ try {
27393
+ const layoutModule = await import(/* @vite-ignore */ '/src/app/layout.tsx');
27394
+ LayoutComponent = layoutModule.default;
27395
+ } catch (e) {
27396
+ console.warn('[Farm.js] Could not preload layout:', e);
27397
+ }
27398
+ if (hydrationController.signal.aborted || !pageContainer.isConnected) return;
27399
+
27400
+ const hydrationSession = await farmClientRuntime.beginHydration({
27401
+ container: pageContainer,
27402
+ mode: shouldHydrate ? 'hydrate' : 'render',
27403
+ });
27404
+
27405
+ let hydrated = false;
27406
+ try {
27407
+ if (hydrationController.signal.aborted || !pageContainer.isConnected) {
27408
+ await farmClientRuntime.failHydration(
27409
+ hydrationSession,
27410
+ new DOMException('Route hydration was cancelled', 'AbortError'),
27411
+ );
27412
+ return;
27413
+ }
27414
+ hydrated = await tryHydrateImportedPage(
27415
+ pageContainer,
27416
+ { modulePath },
27417
+ currentPageProps.params || {},
27418
+ layouts,
27419
+ shouldHydrate,
27420
+ currentPageProps,
27421
+ hydrationController.signal,
27422
+ );
27423
+ if (hydrationController.signal.aborted || !pageContainer.isConnected) {
27424
+ await farmClientRuntime.failHydration(
27425
+ hydrationSession,
27426
+ new DOMException('Route hydration was cancelled', 'AbortError'),
27427
+ );
27428
+ return;
27429
+ }
27430
+ await farmClientRuntime.completeHydration(hydrationSession);
27431
+ } catch (error) {
27432
+ await farmClientRuntime.failHydration(hydrationSession, error);
27433
+ throw error;
27434
+ }
26135
27435
 
26136
- console.log('[Farm.js] Server component - SPA router ready')
27436
+ if (hydrated) {
27437
+ // The scheduler owns queue draining and exactly-once click replay.
27438
+ markFarmHydrated();
27439
+ console.log('[Farm.js] \u2705 Hydrated:', modulePath, '(' + islandStrategy + ')');
27440
+ return;
27441
+ }
27442
+
27443
+ console.log('[Farm.js] Server component - SPA router ready')
27444
+ },
27445
+ });
27446
+ } finally {
27447
+ if (pendingPageHydrationController === hydrationController) {
27448
+ pendingPageHydrationController = null;
27449
+ }
27450
+ }
26137
27451
  } catch (error) {
26138
27452
  console.error('[Farm.js] Hydration error:', error)
26139
27453
  }
@@ -26236,7 +27550,7 @@ function generateClientManifest(bundle) {
26236
27550
  }
26237
27551
  async function defineConfig2(config = {}) {
26238
27552
  const tailwindcss = (await import("@tailwindcss/vite")).default;
26239
- const appRoot = path25.resolve(config.root || process.cwd());
27553
+ const appRoot = path27.resolve(config.root || process.cwd());
26240
27554
  if (config.extends?.length) {
26241
27555
  const { config: layeredConfig } = await Promise.resolve().then(() => (init_layers(), layers_exports)).then(
26242
27556
  ({ resolveFarmLayers: resolveFarmLayers2 }) => resolveFarmLayers2(config, {
@@ -26381,13 +27695,16 @@ async function defineConfig2(config = {}) {
26381
27695
  customLogger: farmLogger,
26382
27696
  clearScreen: false,
26383
27697
  optimizeDeps: {
26384
- include: [
26385
- "react",
26386
- "react-dom",
26387
- "react-dom/client",
26388
- "react/jsx-runtime",
26389
- "react/jsx-dev-runtime"
26390
- ],
27698
+ ...createFarmClientOptimizeDepsConfig(
27699
+ createFarmClientOptimizeDepsEntries(
27700
+ appRoot,
27701
+ getFarmAppDirectories({ ...config, root: appRoot })
27702
+ )
27703
+ ),
27704
+ // Pre-bundle every framework client-runtime entry with React. Without
27705
+ // this, Vite can discover a linked Farm entry after the page has loaded,
27706
+ // regenerate the optimizer browser hash, and leave React DOM holding a
27707
+ // different React module instance from a client component.
26391
27708
  // Exclude server-side packages from browser bundling
26392
27709
  exclude: [
26393
27710
  "@farm.js/core/server",
@@ -26422,7 +27739,7 @@ async function defineConfig2(config = {}) {
26422
27739
  // Stub out problematic server-only modules during dev mode
26423
27740
  alias: {
26424
27741
  ...getFarmLayerAliases(config.layers),
26425
- "@": path25.resolve(appRoot, "src"),
27742
+ "@": path27.resolve(appRoot, "src"),
26426
27743
  // Nitro internals that should not be resolved in browser
26427
27744
  "supports-color": "data:text/javascript,export default false; export const supportsColor = false; export const stdout = false; export const stderr = false;",
26428
27745
  "@poppinss/dumper": "data:text/javascript,export default {};",
@@ -26439,7 +27756,7 @@ async function defineConfig2(config = {}) {
26439
27756
  }
26440
27757
  };
26441
27758
  }
26442
- var fs7, path25, ALL_TYPE_ARTIFACTS, createEmptyTypeArtifactSelection, FARM_I18N_CLIENT_BRIDGE_ID, EMPTY_FARM_DOCS_SEARCH_CLIENT_RUNTIME, FARM_CONFIG_FILENAMES;
27759
+ var fs7, path27, ALL_TYPE_ARTIFACTS, createEmptyTypeArtifactSelection, FARM_I18N_CLIENT_BRIDGE_ID, EMPTY_FARM_DOCS_SEARCH_CLIENT_RUNTIME, FARM_CONFIG_FILENAMES;
26443
27760
  var init_vite = __esm({
26444
27761
  "src/vite.ts"() {
26445
27762
  "use strict";
@@ -26460,7 +27777,7 @@ var init_vite = __esm({
26460
27777
  init_route_context();
26461
27778
  init_devtools_config();
26462
27779
  fs7 = __toESM(require("fs"));
26463
- path25 = __toESM(require("path"));
27780
+ path27 = __toESM(require("path"));
26464
27781
  init_layers();
26465
27782
  init_environment_vite();
26466
27783
  init_version();
@@ -26470,9 +27787,12 @@ var init_vite = __esm({
26470
27787
  init_image_config();
26471
27788
  init_image_vite();
26472
27789
  init_font_vite();
27790
+ init_font();
26473
27791
  init_image_server();
26474
27792
  init_server2();
26475
27793
  init_routing();
27794
+ init_vite_config();
27795
+ init_fonts();
26476
27796
  ALL_TYPE_ARTIFACTS = {
26477
27797
  routes: true,
26478
27798
  api: true,
@@ -27866,6 +29186,7 @@ init_layers();
27866
29186
  init_environment_vite();
27867
29187
  init_last_modified();
27868
29188
  init_search_client();
29189
+ init_fonts();
27869
29190
 
27870
29191
  // src/route-runtime-manifest.ts
27871
29192
  var import_path8 = __toESM(require("path"));
@@ -28047,7 +29368,7 @@ function farmRoutePatternToVercelSource(pattern) {
28047
29368
  } else if (segment === "*" || /^\[.+\]$/.test(segment)) {
28048
29369
  source += "/([^/]+)";
28049
29370
  } else {
28050
- source += `/${escapeRegExp2(segment)}`;
29371
+ source += `/${escapeRegExp3(segment)}`;
28051
29372
  }
28052
29373
  }
28053
29374
  return source || "/";
@@ -28092,10 +29413,35 @@ function normalizePattern(value) {
28092
29413
  return withSlash.length > 1 ? withSlash.replace(/\/+$/, "") : withSlash;
28093
29414
  }
28094
29415
  __name(normalizePattern, "normalizePattern");
28095
- function escapeRegExp2(value) {
29416
+ function escapeRegExp3(value) {
29417
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29418
+ }
29419
+ __name(escapeRegExp3, "escapeRegExp");
29420
+
29421
+ // src/nitro/vercel-assets.ts
29422
+ var FARM_IMMUTABLE_ASSET_CACHE_CONTROL = "public, max-age=31536000, immutable";
29423
+ function createFarmVercelImmutableAssetRoute(basePath = "/") {
29424
+ const normalizedBasePath = normalizeBasePath3(basePath);
29425
+ const escapedBasePath = escapeRegex(normalizedBasePath);
29426
+ const prefix = escapedBasePath ? `/${escapedBasePath}` : "";
29427
+ return {
29428
+ src: `^${prefix}/(?:assets|chunks)/(?:.+/)*[^/]+-h(?:[a-fA-F0-9]{8}|[a-fA-F0-9]{12}|[a-fA-F0-9]{16})\\.(?!(?:[hH][tT][mM][lL]?)$)[^/]+$`,
29429
+ headers: {
29430
+ "Cache-Control": FARM_IMMUTABLE_ASSET_CACHE_CONTROL
29431
+ },
29432
+ continue: true,
29433
+ caseSensitive: true
29434
+ };
29435
+ }
29436
+ __name(createFarmVercelImmutableAssetRoute, "createFarmVercelImmutableAssetRoute");
29437
+ function normalizeBasePath3(basePath) {
29438
+ return basePath.trim().replace(/^\/+|\/+$/g, "");
29439
+ }
29440
+ __name(normalizeBasePath3, "normalizeBasePath");
29441
+ function escapeRegex(value) {
28096
29442
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
28097
29443
  }
28098
- __name(escapeRegExp2, "escapeRegExp");
29444
+ __name(escapeRegex, "escapeRegex");
28099
29445
 
28100
29446
  // src/nitro/universal-build.ts
28101
29447
  init_catalog();
@@ -28304,6 +29650,10 @@ function isCloudflareImagePreset(preset) {
28304
29650
  return preset === "cloudflare" || preset === "cloudflare-pages" || preset === "cloudflare-module";
28305
29651
  }
28306
29652
  __name(isCloudflareImagePreset, "isCloudflareImagePreset");
29653
+ function shouldUseExternalMetadataImageRuntime(preset, hasGeneratedMetadataImages) {
29654
+ return hasGeneratedMetadataImages && preset !== "vercel-edge" && !isCloudflareImagePreset(preset);
29655
+ }
29656
+ __name(shouldUseExternalMetadataImageRuntime, "shouldUseExternalMetadataImageRuntime");
28307
29657
  function resolveImageRuntime(config, preset) {
28308
29658
  if (config.images.provider === "none") return "none";
28309
29659
  const cloudflarePreset = isCloudflareImagePreset(preset);
@@ -28321,6 +29671,31 @@ function isNitroRollupExternal(id) {
28321
29671
  return NODE_BUILTIN_MODULES.has(id) || NITRO_EXTERNAL_MODULES.has(id) || normalizedId.startsWith(".prisma/") || normalizedId.includes("/node_modules/@prisma/client/") || normalizedId.includes("/node_modules/.prisma/client/");
28322
29672
  }
28323
29673
  __name(isNitroRollupExternal, "isNitroRollupExternal");
29674
+ var FARM_METADATA_IMAGE_WASM_PREFIX = "\0farm-metadata-image-wasm:";
29675
+ function createMetadataImageWasmPlugin() {
29676
+ return {
29677
+ name: "farm-metadata-image-wasm",
29678
+ resolveId(source, importer) {
29679
+ if (!source.endsWith(".wasm?module") || !importer?.replace(/\\/g, "/").includes("/@vercel/og/")) {
29680
+ return null;
29681
+ }
29682
+ const requestPath = source.slice(0, -"?module".length);
29683
+ const resolvedPath = import_path12.default.isAbsolute(requestPath) ? requestPath : import_path12.default.resolve(import_path12.default.dirname(importer.split("?", 1)[0]), requestPath);
29684
+ return `${FARM_METADATA_IMAGE_WASM_PREFIX}${resolvedPath}`;
29685
+ },
29686
+ load(id) {
29687
+ if (!id.startsWith(FARM_METADATA_IMAGE_WASM_PREFIX)) return null;
29688
+ const wasmPath = id.slice(FARM_METADATA_IMAGE_WASM_PREFIX.length);
29689
+ const encoded = (0, import_fs5.readFileSync)(wasmPath).toString("base64");
29690
+ return `
29691
+ const encoded = ${JSON.stringify(encoded)};
29692
+ const bytes = Uint8Array.from(atob(encoded), (character) => character.charCodeAt(0));
29693
+ export default new WebAssembly.Module(bytes);
29694
+ `;
29695
+ }
29696
+ };
29697
+ }
29698
+ __name(createMetadataImageWasmPlugin, "createMetadataImageWasmPlugin");
28324
29699
  function collectSSRExternalPackages(ssrBundle) {
28325
29700
  const emittedFiles = new Set(
28326
29701
  Object.keys(ssrBundle).map((fileName) => fileName.replace(/^\.\//, ""))
@@ -28704,6 +30079,9 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
28704
30079
  }
28705
30080
  const { bundle: ssrBundle, entryFile: ssrEntryFile, configuredHeaderRoutes } = ssrResult;
28706
30081
  await writeSSRAssetsToClient(ssrBundle, clientOutputDir);
30082
+ if (config.docs.enabled) {
30083
+ await copyFarmDocsFontAssetsToClient(root, clientOutputDir);
30084
+ }
28707
30085
  logger.info(`\u{1F680} Building server with Nitro (preset: ${preset})...`);
28708
30086
  await buildNitroUniversal(
28709
30087
  config,
@@ -28758,6 +30136,17 @@ async function writeSSRAssetsToClient(bundle, outputDir) {
28758
30136
  }
28759
30137
  }
28760
30138
  __name(writeSSRAssetsToClient, "writeSSRAssetsToClient");
30139
+ async function copyFarmDocsFontAssetsToClient(root, outputDir) {
30140
+ const fs8 = await import("fs/promises");
30141
+ await Promise.all(
30142
+ resolveFarmDocsFontAssets(root).map(async ({ sourcePath, url }) => {
30143
+ const targetPath = import_path12.default.join(outputDir, url.replace(/^\/+/, ""));
30144
+ await fs8.mkdir(import_path12.default.dirname(targetPath), { recursive: true });
30145
+ await fs8.copyFile(sourcePath, targetPath);
30146
+ })
30147
+ );
30148
+ }
30149
+ __name(copyFarmDocsFontAssetsToClient, "copyFarmDocsFontAssetsToClient");
28761
30150
  async function mergeBuiltFontCss(outputDir, fontCssSource) {
28762
30151
  const fs8 = await import("fs/promises");
28763
30152
  const fontCssPath = import_path12.default.join(outputDir, "farm-fonts.css");
@@ -28776,11 +30165,8 @@ async function mergeBuiltFontCss(outputDir, fontCssSource) {
28776
30165
  } catch {
28777
30166
  }
28778
30167
  const normalizedFontCss = typeof fontCss === "string" ? fontCss : Buffer.from(fontCss).toString("utf8");
30168
+ await fs8.writeFile(fontCssPath, normalizedFontCss);
28779
30169
  await fs8.writeFile(clientCssPath, mergeFarmFontCss(clientCss, normalizedFontCss));
28780
- try {
28781
- await fs8.rm(fontCssPath, { force: true });
28782
- } catch {
28783
- }
28784
30170
  }
28785
30171
  __name(mergeBuiltFontCss, "mergeBuiltFontCss");
28786
30172
  var _IncompleteClientBuildOutputError = class _IncompleteClientBuildOutputError extends Error {
@@ -28845,7 +30231,11 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
28845
30231
  const metadata = getClientModuleMetadata(route.modulePath, root);
28846
30232
  if (metadata.shouldHydrate) {
28847
30233
  const relativePath2 = route.modulePath.replace(root, "").replace(/^\//, "");
28848
- clientPages.push({ ...route, relativePath: relativePath2 });
30234
+ clientPages.push({
30235
+ ...route,
30236
+ relativePath: relativePath2,
30237
+ islandStrategy: metadata.islandStrategy ?? "load"
30238
+ });
28849
30239
  logger.info(`\u{1F4F1} Found hydratable route: ${route.pattern} -> ${route.modulePath}`);
28850
30240
  }
28851
30241
  } catch (error) {
@@ -28919,13 +30309,14 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
28919
30309
  },
28920
30310
  output: {
28921
30311
  entryFileNames: "[name].js",
28922
- chunkFileNames: "chunks/[name]-[hash].js",
30312
+ chunkFileNames: "chunks/[name]-h[hash].js",
30313
+ hashCharacters: "hex",
28923
30314
  // Use predictable name for CSS so we can reference it in SSR HTML
28924
30315
  assetFileNames: /* @__PURE__ */ __name((assetInfo) => {
28925
30316
  if (assetInfo.name?.endsWith(".css")) {
28926
30317
  return "farm-client.css";
28927
30318
  }
28928
- return "assets/[name]-[hash][extname]";
30319
+ return "assets/[name]-h[hash][extname]";
28929
30320
  }, "assetFileNames")
28930
30321
  },
28931
30322
  // Externalize Node.js built-ins and server-side modules for client build
@@ -29524,10 +30915,13 @@ document.addEventListener("click", function(e) {
29524
30915
  const imports = [];
29525
30916
  const routeEntries = [];
29526
30917
  const routeSlotEntries = [];
29527
- clientPages.forEach((page2, index) => {
30918
+ clientPages.forEach((page2) => {
29528
30919
  const importPath = toImportPath(page2.modulePath);
29529
- imports.push(`import Page${index} from "${importPath}";`);
29530
- routeEntries.push(` { pattern: ${JSON.stringify(page2.pattern)}, Component: Page${index} }`);
30920
+ routeEntries.push(` {
30921
+ pattern: ${JSON.stringify(page2.pattern)},
30922
+ islandStrategy: ${JSON.stringify(page2.islandStrategy)},
30923
+ load: () => import(${JSON.stringify(importPath)}).then((module) => module.default),
30924
+ }`);
29531
30925
  });
29532
30926
  clientRouteSlots.forEach((slot, index) => {
29533
30927
  const importPath = toImportPath(slot.modulePath);
@@ -29548,7 +30942,7 @@ ${cssImport}
29548
30942
  ${layoutImports}
29549
30943
  import React from "react";
29550
30944
  import { createRoot, hydrateRoot } from "react-dom/client";
29551
- import { createClientPluginManager, installChunkErrorRecovery } from "@farm.js/core/internal/client-runtime";
30945
+ import { createClientPluginManager, installChunkErrorRecovery, scheduleFarmIslandHydration } from "@farm.js/core/internal/client-runtime";
29552
30946
  import { matchFarmRoute } from "@farm.js/core/router";
29553
30947
  ${clientPluginEntry.imports}
29554
30948
  ${i18nClientRuntime}
@@ -29621,6 +31015,12 @@ function matchRoute(pathname) {
29621
31015
  return null;
29622
31016
  }
29623
31017
 
31018
+ async function loadRouteComponent(route) {
31019
+ if (route.Component) return route.Component;
31020
+ route.Component = await route.load();
31021
+ return route.Component;
31022
+ }
31023
+
29624
31024
  function matchesRoutePrefix(pathname, pattern) {
29625
31025
  if (pattern === "/") return true;
29626
31026
  const pathSegments = getFarmRoutePathname(pathname).split("/").filter(Boolean);
@@ -29763,15 +31163,24 @@ function clearRouteInterception(destination) {
29763
31163
 
29764
31164
  // State
29765
31165
  let reactRoot = null;
31166
+ let reactRootContainer = null;
29766
31167
  let currentPathname = null;
29767
31168
  let isHydrated = false;
31169
+ let pendingPageHydrationController = null;
29768
31170
 
29769
31171
  ${generateUniversalRouterStateRuntime()}
29770
31172
 
31173
+ function cancelPendingPageHydration() {
31174
+ pendingPageHydrationController?.abort();
31175
+ pendingPageHydrationController = null;
31176
+ }
31177
+
29771
31178
  function resetReactRoot() {
31179
+ cancelPendingPageHydration();
29772
31180
  if (!reactRoot) return;
29773
31181
  reactRoot.unmount();
29774
31182
  reactRoot = null;
31183
+ reactRootContainer = null;
29775
31184
  isHydrated = false;
29776
31185
  }
29777
31186
 
@@ -29785,49 +31194,77 @@ async function hydrate() {
29785
31194
  return;
29786
31195
  }
29787
31196
 
29788
- const hasRouteSlots =
29789
- Array.isArray(window.__FARM_ROUTE_SLOTS__) && window.__FARM_ROUTE_SLOTS__.length > 0;
29790
31197
  const container =
29791
- (hasRouteSlots ? document.getElementById("__farm_page__") : null) ||
31198
+ document.getElementById("__farm_page__") ||
29792
31199
  document.getElementById("root");
29793
31200
  if (!container) {
29794
31201
  console.error("[Farm.js] No root element found");
29795
31202
  return;
29796
31203
  }
29797
31204
 
29798
- const Component = matched.route.Component;
29799
- const params = matched.params;
29800
- const searchParams = Object.fromEntries(new URLSearchParams(window.location.search));
29801
-
29802
- const props = { params: params, searchParams: Promise.resolve(searchParams) };
29803
-
29804
- // Create page element and wrap with layouts
29805
- const pageElement = React.createElement(Component, props);
29806
- const wrappedElement = hasRouteSlots
29807
- ? pageElement
29808
- : wrapWithLayouts(pageElement, pathname, params);
29809
-
29810
- const shouldHydrate = !isHydrated && Boolean(container.innerHTML.trim());
29811
- const hydrationSession = await farmClientRuntime.beginHydration({
29812
- container,
29813
- mode: shouldHydrate ? "hydrate" : "render",
29814
- });
31205
+ container.dataset.farmIsland = "page";
31206
+ container.dataset.farmIslandStrategy = matched.route.islandStrategy || "load";
29815
31207
 
31208
+ const hydrationController = new AbortController();
31209
+ pendingPageHydrationController = hydrationController;
29816
31210
  try {
29817
- if (shouldHydrate) {
29818
- reactRoot = hydrateRoot(container, wrappedElement);
29819
- isHydrated = true;
29820
- } else {
29821
- if (!reactRoot) {
29822
- reactRoot = createRoot(container);
29823
- }
29824
- reactRoot.render(wrappedElement);
31211
+ await scheduleFarmIslandHydration({
31212
+ container,
31213
+ strategy: matched.route.islandStrategy,
31214
+ signal: hydrationController.signal,
31215
+ hydrate: async function() {
31216
+ const Component = await loadRouteComponent(matched.route);
31217
+ if (
31218
+ hydrationController.signal.aborted ||
31219
+ !container.isConnected ||
31220
+ window.location.pathname !== pathname
31221
+ ) {
31222
+ return;
31223
+ }
31224
+ const params = matched.params;
31225
+ const searchParams = Object.fromEntries(new URLSearchParams(window.location.search));
31226
+ const props = { params: params, searchParams: Promise.resolve(searchParams) };
31227
+ const pageElement = React.createElement(Component, props);
31228
+ const wrappedElement = container.id === "__farm_page__"
31229
+ ? pageElement
31230
+ : wrapWithLayouts(pageElement, pathname, params);
31231
+ const shouldHydrate = !isHydrated && Boolean(container.innerHTML.trim());
31232
+ const hydrationSession = await farmClientRuntime.beginHydration({
31233
+ container,
31234
+ mode: shouldHydrate ? "hydrate" : "render",
31235
+ });
31236
+
31237
+ try {
31238
+ if (hydrationController.signal.aborted || !container.isConnected) {
31239
+ await farmClientRuntime.failHydration(
31240
+ hydrationSession,
31241
+ new DOMException("Route hydration was cancelled", "AbortError"),
31242
+ );
31243
+ return;
31244
+ }
31245
+ if (shouldHydrate) {
31246
+ reactRoot = hydrateRoot(container, wrappedElement);
31247
+ reactRootContainer = container;
31248
+ isHydrated = true;
31249
+ } else {
31250
+ if (!reactRoot) {
31251
+ reactRoot = createRoot(container);
31252
+ reactRootContainer = container;
31253
+ }
31254
+ reactRoot.render(wrappedElement);
31255
+ }
31256
+ currentPathname = pathname;
31257
+ await farmClientRuntime.completeHydration(hydrationSession);
31258
+ } catch (error) {
31259
+ await farmClientRuntime.failHydration(hydrationSession, error);
31260
+ console.error("[Farm.js] Hydration error:", error);
31261
+ }
31262
+ },
31263
+ });
31264
+ } finally {
31265
+ if (pendingPageHydrationController === hydrationController) {
31266
+ pendingPageHydrationController = null;
29825
31267
  }
29826
- currentPathname = pathname;
29827
- await farmClientRuntime.completeHydration(hydrationSession);
29828
- } catch (error) {
29829
- await farmClientRuntime.failHydration(hydrationSession, error);
29830
- console.error("[Farm.js] Hydration error:", error);
29831
31268
  }
29832
31269
  }
29833
31270
 
@@ -29856,6 +31293,8 @@ ${generateUniversalRouterStateProperties()}
29856
31293
  const from = this.currentPath;
29857
31294
  if (await this.shouldBlockNavigation({ from, to, action })) return;
29858
31295
 
31296
+ // A route transition invalidates any trigger waiting on the previous DOM boundary.
31297
+ cancelPendingPageHydration();
29859
31298
  this.saveScrollPosition(window.location.pathname);
29860
31299
  this.startNavigation(from, url, action);
29861
31300
  let clientNavigation;
@@ -29922,7 +31361,9 @@ ${generateUniversalRouterStateProperties()}
29922
31361
  }
29923
31362
 
29924
31363
  if (matched) {
29925
- const Component = matched.route.Component;
31364
+ // Navigation itself signals intent, so destination routes load eagerly even
31365
+ // when their initial document hydration strategy is deferred.
31366
+ const Component = await loadRouteComponent(matched.route);
29926
31367
  const params = matched.params;
29927
31368
  const searchParams = Object.fromEntries(url.searchParams);
29928
31369
  const props = { params: params, searchParams: Promise.resolve(searchParams) };
@@ -29948,8 +31389,10 @@ ${generateUniversalRouterStateProperties()}
29948
31389
 
29949
31390
  const container = document.getElementById("root");
29950
31391
  if (container) {
31392
+ if (reactRoot && reactRootContainer !== container) resetReactRoot();
29951
31393
  if (!reactRoot) {
29952
31394
  reactRoot = createRoot(container);
31395
+ reactRootContainer = container;
29953
31396
  }
29954
31397
  reactRoot.render(wrappedElement);
29955
31398
  currentPathname = pathname;
@@ -29959,7 +31402,7 @@ ${generateUniversalRouterStateProperties()}
29959
31402
  const html = await this.fetchPage(url.pathname + url.search);
29960
31403
  await farmClientRuntime.markNavigationLoaded(clientNavigation, html);
29961
31404
  await this.runViewTransition(options.viewTransition, async () => {
29962
- if (!this.swapContent(html, url.pathname + url.search)) {
31405
+ if (!(await this.swapContent(html, url.pathname + url.search))) {
29963
31406
  throw new Error("Farm could not swap the target document");
29964
31407
  }
29965
31408
  const historyState = createHistoryState(
@@ -30014,7 +31457,7 @@ ${generateUniversalRouterStateProperties()}
30014
31457
  return html;
30015
31458
  },
30016
31459
 
30017
- swapContent: function(html, targetPath) {
31460
+ swapContent: async function(html, targetPath) {
30018
31461
  const parser = new DOMParser();
30019
31462
  const doc = parser.parseFromString(html, "text/html");
30020
31463
  if (isFarmLocaleDocumentChange(doc)) return false;
@@ -30054,18 +31497,18 @@ ${generateUniversalRouterStateProperties()}
30054
31497
  const matched = matchRoute(newPathname);
30055
31498
  if (matched) {
30056
31499
  // Re-hydrate the client component
30057
- const Component = matched.route.Component;
31500
+ const Component = await loadRouteComponent(matched.route);
30058
31501
  const params = matched.params;
30059
31502
  const searchParams = Object.fromEntries(targetUrl.searchParams);
30060
31503
  const props = { params: params, searchParams: Promise.resolve(searchParams) };
30061
31504
  const pageElement = React.createElement(Component, props);
30062
- const hasRouteSlots = nextRouteSlots.length > 0;
30063
31505
  const pageContainer =
30064
- (hasRouteSlots ? document.getElementById("__farm_page__") : null) || currentRoot;
30065
- const wrappedElement = hasRouteSlots
31506
+ document.getElementById("__farm_page__") || currentRoot;
31507
+ const wrappedElement = pageContainer.id === "__farm_page__"
30066
31508
  ? pageElement
30067
31509
  : wrapWithLayouts(pageElement, newPathname, params);
30068
31510
  reactRoot = hydrateRoot(pageContainer, wrappedElement);
31511
+ reactRootContainer = pageContainer;
30069
31512
  isHydrated = true;
30070
31513
  }
30071
31514
  return true;
@@ -30356,6 +31799,10 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
30356
31799
  i18nCatalogs
30357
31800
  );
30358
31801
  const virtualEntryId = "\0virtual:farm-ssr-entry";
31802
+ const useExternalMetadataImageRuntime = shouldUseExternalMetadataImageRuntime(
31803
+ preset,
31804
+ metadataImageRoutes.some((image) => image.sourceType === "module")
31805
+ );
30359
31806
  try {
30360
31807
  await viteBuild({
30361
31808
  root,
@@ -30376,6 +31823,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
30376
31823
  external: [
30377
31824
  "fsevents",
30378
31825
  "sharp",
31826
+ ...useExternalMetadataImageRuntime ? ["@vercel/og"] : [],
30379
31827
  "@prisma/client",
30380
31828
  "@prisma/client/default",
30381
31829
  "@prisma/client/default.js",
@@ -30404,6 +31852,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
30404
31852
  external: [
30405
31853
  "fsevents",
30406
31854
  "sharp",
31855
+ ...useExternalMetadataImageRuntime ? ["@vercel/og"] : [],
30407
31856
  "esbuild",
30408
31857
  "lightningcss",
30409
31858
  "rollup",
@@ -30430,7 +31879,12 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
30430
31879
  // React runtime. Leaving a React component package external can make it
30431
31880
  // resolve a second React instance at runtime and break hooks during SSR.
30432
31881
  // Native and build-only packages above remain explicitly external.
30433
- noExternal: preset === "cloudflare-module" ? ["@farm.js/core", "@farm.js/core/image", "better-call"] : true
31882
+ noExternal: preset === "cloudflare-module" ? [
31883
+ "@farm.js/core",
31884
+ "@farm.js/core/image",
31885
+ "better-call",
31886
+ ...metadataImageRoutes.some((image) => image.sourceType === "module") ? ["@vercel/og"] : []
31887
+ ] : true
30434
31888
  },
30435
31889
  define: {
30436
31890
  __FARM_ENV__: JSON.stringify(config.env || { server: {}, public: {} }),
@@ -30438,6 +31892,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
30438
31892
  },
30439
31893
  plugins: [
30440
31894
  ...tailwindVitePlugin ? [tailwindVitePlugin] : [],
31895
+ ...!useExternalMetadataImageRuntime && metadataImageRoutes.some((image) => image.sourceType === "module") ? [createMetadataImageWasmPlugin()] : [],
30441
31896
  {
30442
31897
  name: "farm-react-production-mode",
30443
31898
  enforce: "pre",
@@ -30516,8 +31971,12 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
30516
31971
  __name(buildSSRInMemory, "buildSSRInMemory");
30517
31972
  function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlots, errorRoutes, metadataImageRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, notFoundPath, config, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, preset, i18nCatalogs) {
30518
31973
  const hasPluginRuntime = hasRuntimeIntegrationConfig || hasConfiguredRuntimePlugins;
31974
+ const hasGeneratedMetadataImages = metadataImageRoutes.some(
31975
+ (image) => image.sourceType === "module"
31976
+ );
30519
31977
  const hasMiddlewareRuntime = middlewareRoutes.length > 0 || hasFarmMiddlewareConfig(config.middleware);
30520
31978
  const farmDocsBaseConfig = config.docs?.enabled ? { ...config.docs, config: void 0 } : void 0;
31979
+ const farmDocsFontAssets = config.docs?.enabled ? toFarmDocsPublicFontAssets(resolveFarmDocsFontAssets(config.root)) : [];
30521
31980
  const apiImports = [];
30522
31981
  const apiRegistrations = [];
30523
31982
  apiRoutes.forEach((route, index) => {
@@ -30556,12 +32015,13 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlot
30556
32015
  return;
30557
32016
  }
30558
32017
  pageImports.push(`import * as ${varName} from "${route.modulePath}";`);
30559
- const shouldHydrate = getClientModuleMetadata(route.modulePath, config.root).shouldHydrate;
32018
+ const clientMetadata = getClientModuleMetadata(route.modulePath, config.root);
30560
32019
  pageRegistrations.push(`
30561
32020
  {
30562
32021
  pattern: ${JSON.stringify(route.pattern)},
30563
32022
  module: ${varName},
30564
- shouldHydrate: ${JSON.stringify(shouldHydrate)},
32023
+ shouldHydrate: ${JSON.stringify(clientMetadata.shouldHydrate)},
32024
+ islandStrategy: ${JSON.stringify(clientMetadata.islandStrategy)},
30565
32025
  ${route.source !== void 0 ? `markdownSource: {
30566
32026
  source: ${JSON.stringify(route.source)},
30567
32027
  filePath: ${JSON.stringify(route.markdownSourcePath)},
@@ -30659,16 +32119,21 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlot
30659
32119
  isFarmRedirectError,
30660
32120
  localizeFarmHref,
30661
32121
  localizeFarmPathname,
32122
+ manageFarmDocumentPreloads,
32123
+ manageFarmLinkHeaderPreloads,
30662
32124
  mergeMetadata,
30663
32125
  normalizeRevalidatePath,
32126
+ reportFarmPreloadWarnings,
30664
32127
  renderMetadataHead,
30665
32128
  resolveFarmRouteContext,
30666
32129
  stripFarmLocaleFromPathname,
30667
32130
  withFarmRouteContext,
30668
32131
  } from "@farm.js/core/internal/production-runtime";`;
32132
+ const metadataImageRuntimeImport = hasGeneratedMetadataImages ? `import { createFarmMetadataImageResponse } from "@farm.js/core/internal/metadata-image-runtime";` : "";
30669
32133
  const pluginRuntimeImport = hasPluginRuntime ? `import { PluginManager } from "@farm.js/core/plugin";` : "";
30670
32134
  const i18nServerImport = config.i18n.enabled ? `import { _runWithFarmI18nRequest, _setDefaultFarmI18nRuntime, createFarmI18nRuntime, getFarmI18nClientSnapshot } from "@farm.js/core/i18n/server";` : "";
30671
32135
  const docsHandlerImport = config.docs?.enabled ? `import { createFarmDocsAPIHandler, createFarmDocsHandler, isFarmDocsAPIRequest } from "@farm.js/core/docs";` : "";
32136
+ const docsFontImport = config.docs?.enabled ? `import { resolveFarmLayoutFonts } from "@farm.js/core/font";` : "";
30672
32137
  const docsRuntimeImport = config.docs?.enabled ? `import { existsSync as farmDocsExistsSync } from "node:fs";
30673
32138
  import { dirname as farmDocsDirname, join as farmDocsJoin } from "node:path";
30674
32139
  import { fileURLToPath as farmDocsFileURLToPath } from "node:url";` : "";
@@ -30756,9 +32221,11 @@ ${middlewareImports.join("\n")}
30756
32221
  ${notFoundImport}
30757
32222
  ${apiRouteHelpersImport}
30758
32223
  ${productionRuntimeImport}
32224
+ ${metadataImageRuntimeImport}
30759
32225
  ${pluginRuntimeImport}
30760
32226
  ${i18nServerImport}
30761
32227
  ${docsHandlerImport}
32228
+ ${docsFontImport}
30762
32229
  ${docsRuntimeImport}
30763
32230
  ${markdownHandlerImport}
30764
32231
  ${appMarkdownImport}
@@ -30770,6 +32237,8 @@ import { farmFontPreloadHeader } from "virtual:farm-font-runtime";
30770
32237
  import * as React from "react";
30771
32238
  import * as ReactDOMServer from "react-dom/server";
30772
32239
 
32240
+ const farmPreloadConfig = ${JSON.stringify(config.performance.preload)};
32241
+
30773
32242
  // Custom 404 page component (if provided)
30774
32243
  const hasCustomNotFound = ${notFoundPath ? "true" : "false"};
30775
32244
  const CustomNotFoundComponent = ${notFoundPath ? "CustomNotFound.default || CustomNotFound" : "null"};
@@ -30861,7 +32330,17 @@ globalThis.__FARM_DOCS_RUNTIME_CONFIG__ = {
30861
32330
  srcDir: ${JSON.stringify(config.srcDir)},
30862
32331
  docs: farmDocsResolvedConfig,
30863
32332
  };
30864
- const farmDocsHandler = ${config.docs?.enabled ? `createFarmDocsHandler(farmDocsResolvedConfig, { root: farmDocsRuntimeRoot, srcDir: ${JSON.stringify(config.srcDir)}, clientEntry: "/farm-client.js" })` : "null"};
32333
+ const farmDocsHandler = ${config.docs?.enabled ? `createFarmDocsHandler(farmDocsResolvedConfig, {
32334
+ root: farmDocsRuntimeRoot,
32335
+ srcDir: ${JSON.stringify(config.srcDir)},
32336
+ clientEntry: "/farm-client.js",
32337
+ fontAssets: ${JSON.stringify(farmDocsFontAssets)},
32338
+ resolveLayoutFonts: (pathname) =>
32339
+ resolveFarmLayoutFonts(
32340
+ getApplicableLayouts(getFarmRoutePathname(pathname)).map((layout) => layout.module),
32341
+ ),
32342
+ fontStylesheetHref: "/farm-fonts.css",
32343
+ })` : "null"};
30865
32344
  const farmDocsAPIHandler = ${config.docs?.enabled ? `createFarmDocsAPIHandler({ rootDir: farmDocsRuntimeRoot, srcDir: ${JSON.stringify(config.srcDir)}, docs: farmDocsResolvedConfig })` : "null"};
30866
32345
 
30867
32346
  // API routes bundled at build time
@@ -31522,30 +33001,10 @@ async function handleMetadataImageRequest(request, routePathname) {
31522
33001
  ? await imageModule.default(props)
31523
33002
  : imageModule.default;
31524
33003
 
31525
- if (value instanceof Response) {
31526
- return method === "HEAD"
31527
- ? new Response(null, { status: value.status, headers: value.headers })
31528
- : value;
31529
- }
31530
-
31531
- let body;
31532
- if (typeof value === "string" || value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
31533
- body = value;
31534
- } else {
31535
- if (!React.isValidElement(value)) {
31536
- throw new Error("Metadata image must return a Response, string, bytes, or React element");
31537
- }
31538
- body = ReactDOMServer.renderToStaticMarkup(value);
31539
- }
31540
-
31541
- return new Response(method === "HEAD" ? null : body, {
31542
- status: 200,
31543
- headers: {
31544
- "Content-Type": imageModule.contentType || "image/svg+xml; charset=utf-8",
31545
- "Cache-Control": "public, max-age=0, must-revalidate",
31546
- "X-Content-Type-Options": "nosniff",
31547
- },
31548
- });
33004
+ ${hasGeneratedMetadataImages ? `return createFarmMetadataImageResponse(value, imageModule, {
33005
+ method,
33006
+ ifNoneMatch: request.headers.get("if-none-match"),
33007
+ });` : 'throw new Error("Generated metadata image runtime is unavailable");'}
31549
33008
  } catch (error) {
31550
33009
  console.error("Metadata image render failed:", error);
31551
33010
  return new Response("Internal Server Error", {
@@ -32081,7 +33540,16 @@ async function handleFarmRequestInContext(
32081
33540
  if (farmDocsHandler) {
32082
33541
  const docsResponse = await farmDocsHandler(request.clone());
32083
33542
  if (docsResponse) {
32084
- return docsResponse;
33543
+ if (!docsResponse.headers.get("content-type")?.toLowerCase().includes("text/html")) {
33544
+ return docsResponse;
33545
+ }
33546
+ const docsHeaders = new Headers(docsResponse.headers);
33547
+ docsHeaders.set("x-farm-preload-buffered", "1");
33548
+ return new Response(docsResponse.body, {
33549
+ status: docsResponse.status,
33550
+ statusText: docsResponse.statusText,
33551
+ headers: docsHeaders,
33552
+ });
32085
33553
  }
32086
33554
  }
32087
33555
  ` : ""}
@@ -32209,6 +33677,7 @@ async function handleFarmRequestInContext(
32209
33677
  status: 200,
32210
33678
  headers: {
32211
33679
  "Content-Type": "text/html; charset=utf-8",
33680
+ "x-farm-preload-buffered": "1",
32212
33681
  ...(farmFontPreloadHeader ? { "Link": farmFontPreloadHeader } : {}),
32213
33682
  ...getPPRHeaders("hit", pprConfig),
32214
33683
  },
@@ -32436,10 +33905,15 @@ async function handleFarmRequestInContext(
32436
33905
  pageElement = React.createElement(PageComponent, pageProps);
32437
33906
  }
32438
33907
 
32439
- if (route.shouldHydrate && renderedRouteSlots.length > 0) {
33908
+ if (route.shouldHydrate) {
32440
33909
  pageElement = React.createElement(
32441
33910
  "div",
32442
- { id: "__farm_page__", "data-farm-client": "true" },
33911
+ {
33912
+ id: "__farm_page__",
33913
+ "data-farm-client": "true",
33914
+ "data-farm-island": "page",
33915
+ "data-farm-island-strategy": route.islandStrategy || "load",
33916
+ },
32443
33917
  pageElement,
32444
33918
  );
32445
33919
  }
@@ -32590,7 +34064,7 @@ async function handleFarmRequestInContext(
32590
34064
  );
32591
34065
  return applyProductionMiddlewareHeaders(new Response(streamedDocument, {
32592
34066
  status: pageStatus,
32593
- headers: responseHeaders,
34067
+ headers: { ...responseHeaders, "x-farm-preload-streaming": "1" },
32594
34068
  }), middlewareHeaders);
32595
34069
  }
32596
34070
 
@@ -32691,7 +34165,7 @@ async function handleFarmRequestInContext(
32691
34165
  fullHtml,
32692
34166
  {
32693
34167
  status: pageStatus,
32694
- headers: responseHeaders
34168
+ headers: { ...responseHeaders, "x-farm-preload-buffered": "1" }
32695
34169
  }
32696
34170
  ), middlewareHeaders);
32697
34171
  }
@@ -32795,6 +34269,7 @@ async function handleFarmRequestInContext(
32795
34269
  headers: {
32796
34270
  "Content-Type": "text/html; charset=utf-8",
32797
34271
  "Cache-Control": "private, no-store",
34272
+ "x-farm-preload-buffered": "1",
32798
34273
  },
32799
34274
  }), middlewareHeaders);
32800
34275
  } catch (boundaryError) {
@@ -32817,6 +34292,7 @@ async function handleFarmRequestInContext(
32817
34292
  headers: {
32818
34293
  "Content-Type": "text/html; charset=utf-8",
32819
34294
  "Cache-Control": "private, no-store",
34295
+ "x-farm-preload-buffered": "1",
32820
34296
  },
32821
34297
  }
32822
34298
  ), middlewareHeaders);
@@ -32963,13 +34439,19 @@ async function handleFarmRequestInContext(
32963
34439
 
32964
34440
  return applyProductionMiddlewareHeaders(new Response(fullHtml, {
32965
34441
  status: 404,
32966
- headers: { "Content-Type": "text/html; charset=utf-8" }
34442
+ headers: {
34443
+ "Content-Type": "text/html; charset=utf-8",
34444
+ "x-farm-preload-buffered": "1",
34445
+ }
32967
34446
  }), middlewareHeaders);
32968
34447
  } catch (error) {
32969
34448
  console.error("404 render error:", error);
32970
34449
  return applyProductionMiddlewareHeaders(new Response(
32971
34450
  \`<!DOCTYPE html><html><head><title>404</title></head><body><h1>404 - Page Not Found</h1><p>The page \${pathname} doesn't exist.</p><a href="/">Go Home</a></body></html>\`,
32972
- { status: 404, headers: { "Content-Type": "text/html" } }
34451
+ {
34452
+ status: 404,
34453
+ headers: { "Content-Type": "text/html", "x-farm-preload-buffered": "1" },
34454
+ }
32973
34455
  ), middlewareHeaders);
32974
34456
  }
32975
34457
  ${hasMiddlewareRuntime ? `
@@ -33011,7 +34493,10 @@ async function handleFarmPluginRequest(request, runtimeOptions) {
33011
34493
  await farmPluginRuntime.runHookParallel("beforeRender", renderPayload);
33012
34494
 
33013
34495
  const response = await handleFarmRequest(request);
33014
- if (!hasFarmPluginHTMLTransforms || !response.headers.get("content-type")?.includes("text/html")) {
34496
+ if (
34497
+ !hasFarmPluginHTMLTransforms ||
34498
+ !response.headers.get("content-type")?.toLowerCase().includes("text/html")
34499
+ ) {
33015
34500
  return response;
33016
34501
  }
33017
34502
 
@@ -33021,6 +34506,8 @@ async function handleFarmPluginRequest(request, runtimeOptions) {
33021
34506
 
33022
34507
  const headers = new Headers(response.headers);
33023
34508
  headers.delete("content-length");
34509
+ headers.delete("x-farm-preload-streaming");
34510
+ headers.set("x-farm-preload-buffered", "1");
33024
34511
  return new Response(html, {
33025
34512
  status: response.status,
33026
34513
  statusText: response.statusText,
@@ -33028,6 +34515,49 @@ async function handleFarmPluginRequest(request, runtimeOptions) {
33028
34515
  });
33029
34516
  }
33030
34517
 
34518
+ async function applyFarmPreloadBudget(response, pathname) {
34519
+ const headers = new Headers(response.headers);
34520
+ const linkHeader = headers.get("Link") || "";
34521
+ const isHtml = headers.get("Content-Type")?.toLowerCase().includes("text/html");
34522
+ const isStreaming = headers.get("x-farm-preload-streaming") === "1";
34523
+ const isBuffered = headers.get("x-farm-preload-buffered") === "1";
34524
+ headers.delete("x-farm-preload-streaming");
34525
+ headers.delete("x-farm-preload-buffered");
34526
+
34527
+ if (!isHtml) {
34528
+ if (!isStreaming && !isBuffered) return response;
34529
+ return new Response(response.body, {
34530
+ status: response.status,
34531
+ statusText: response.statusText,
34532
+ headers,
34533
+ });
34534
+ }
34535
+
34536
+ if (isStreaming || !isBuffered || response.body === null) {
34537
+ const managed = manageFarmLinkHeaderPreloads(linkHeader, farmPreloadConfig);
34538
+ if (managed.value) headers.set("Link", managed.value);
34539
+ else headers.delete("Link");
34540
+ reportFarmPreloadWarnings(managed.warnings, "route " + pathname);
34541
+ return new Response(response.body, {
34542
+ status: response.status,
34543
+ statusText: response.statusText,
34544
+ headers,
34545
+ });
34546
+ }
34547
+
34548
+ const html = await response.text();
34549
+ const managed = manageFarmDocumentPreloads(html, linkHeader, farmPreloadConfig);
34550
+ if (managed.linkHeader) headers.set("Link", managed.linkHeader);
34551
+ else headers.delete("Link");
34552
+ if (managed.html !== html) headers.delete("Content-Length");
34553
+ reportFarmPreloadWarnings(managed.warnings, "route " + pathname);
34554
+ return new Response(managed.html, {
34555
+ status: response.status,
34556
+ statusText: response.statusText,
34557
+ headers,
34558
+ });
34559
+ }
34560
+
33031
34561
  // Export as Web Standard fetch API
33032
34562
  export async function fetch(request, context) {
33033
34563
  const runtimeOptions = farmPluginRuntime ? getFarmPluginRequestOptions(request) : null;
@@ -33050,7 +34580,8 @@ export async function fetch(request, context) {
33050
34580
  const response = await _runWithCurrentRequest(request, () =>
33051
34581
  _runWithAfterRequest(request, runRequest, context),
33052
34582
  );
33053
- return applyConfiguredResponseHeaders(response, new URL(request.url).pathname);
34583
+ const pathname = new URL(request.url).pathname;
34584
+ return applyFarmPreloadBudget(applyConfiguredResponseHeaders(response, pathname), pathname);
33054
34585
  }
33055
34586
  export default { fetch };
33056
34587
  `.trim();
@@ -33206,8 +34737,19 @@ async function buildNitroUniversal(config, routeManager, apiRouteManager, server
33206
34737
  const outputDir = resolveDeployOutputPath(root, config.deploy.outputDir);
33207
34738
  const ssrOutputDir = import_path12.default.join(root, distDir, "ssr");
33208
34739
  const imageRuntime = resolveImageRuntime(config, preset);
34740
+ const hasGeneratedMetadataImages = Array.from(routeManager.getMetadataImages().values()).some(
34741
+ (image) => image.sourceType === "module"
34742
+ );
34743
+ const useExternalMetadataImageRuntime = shouldUseExternalMetadataImageRuntime(
34744
+ preset,
34745
+ hasGeneratedMetadataImages
34746
+ );
34747
+ const nitroRollupExternal = /* @__PURE__ */ __name((id) => useExternalMetadataImageRuntime && id === "@vercel/og" || isNitroRollupExternal(id), "nitroRollupExternal");
33209
34748
  const ssrExternalPackages = collectSSRExternalPackages(ssrBundle);
33210
- const copiedRuntimePackages = new Set(imageRuntime === "node" ? ["sharp"] : []);
34749
+ const copiedRuntimePackages = /* @__PURE__ */ new Set([
34750
+ ...imageRuntime === "node" ? ["sharp"] : [],
34751
+ ...useExternalMetadataImageRuntime ? ["@vercel/og"] : []
34752
+ ]);
33211
34753
  const isPrebuiltSSRCandidate = preset === "node-server" && [...ssrExternalPackages].every((packageName) => copiedRuntimePackages.has(packageName));
33212
34754
  logger.info(`\u{1F4E6} Nitro output directory: ${outputDir}`);
33213
34755
  logger.info(`\u{1F4E6} SSR entry file: ${ssrEntryFile}`);
@@ -33423,11 +34965,13 @@ export default async function farmNitroEventHandler(event) {
33423
34965
  ".prisma/client",
33424
34966
  ".prisma/client/default",
33425
34967
  "better-sqlite3",
33426
- "sharp"
34968
+ "sharp",
34969
+ ...useExternalMetadataImageRuntime ? ["@vercel/og"] : []
33427
34970
  ]
33428
34971
  },
33429
34972
  rollupConfig: {
33430
- external: isNitroRollupExternal
34973
+ external: nitroRollupExternal,
34974
+ plugins: hasGeneratedMetadataImages && !useExternalMetadataImageRuntime ? [createMetadataImageWasmPlugin()] : []
33431
34975
  },
33432
34976
  // Keep the public Nitro boolean intact for build hooks. It is translated to
33433
34977
  // Nitro's existing esbuild pass after hooks run, avoiding a second Terser pass.
@@ -33455,7 +34999,7 @@ export default async function farmNitroEventHandler(event) {
33455
34999
  snapshotSSRRebundleOptions(nitroConfig)
33456
35000
  );
33457
35001
  const requestedBuilder = nitroConfig.builder ?? process.env.NITRO_BUILDER;
33458
- const canReusePrebuiltSSR = isPrebuiltSSRCandidate && nitroConfig.preset === "node-server" && (requestedBuilder === void 0 || requestedBuilder === "rollup" || requestedBuilder === "rolldown") && nitroConfig.sourceMap === false && !hasUnsupportedEsbuildOverrides && !hasLateBuildMutationConfig && !hasUnsupportedSSRRebundleOverrides && nitroConfig.rollupConfig?.external === isNitroRollupExternal && !hasRollupPlugins(nitroConfig.rollupConfig?.plugins) && customRollupKeys.length === 0 && import_path12.default.resolve(nitroConfig.output?.serverDir || "") === import_path12.default.resolve(expectedServerDir) && Boolean(
35002
+ const canReusePrebuiltSSR = isPrebuiltSSRCandidate && nitroConfig.preset === "node-server" && (requestedBuilder === void 0 || requestedBuilder === "rollup" || requestedBuilder === "rolldown") && nitroConfig.sourceMap === false && !hasUnsupportedEsbuildOverrides && !hasLateBuildMutationConfig && !hasUnsupportedSSRRebundleOverrides && nitroConfig.rollupConfig?.external === nitroRollupExternal && !hasRollupPlugins(nitroConfig.rollupConfig?.plugins) && customRollupKeys.length === 0 && import_path12.default.resolve(nitroConfig.output?.serverDir || "") === import_path12.default.resolve(expectedServerDir) && Boolean(
33459
35003
  nitroConfig.handlers?.some(
33460
35004
  (handler) => import_path12.default.resolve(handler?.handler || "") === nitroEntryPath
33461
35005
  )
@@ -33543,7 +35087,8 @@ export default async function farmNitroEventHandler(event) {
33543
35087
  effectiveMinify,
33544
35088
  fs8
33545
35089
  ) : Promise.resolve(),
33546
- imageRuntime === "node" ? copySharpRuntime(config, root, import_path12.default.join(outputDir, "server"), fs8) : Promise.resolve()
35090
+ imageRuntime === "node" ? copySharpRuntime(config, root, import_path12.default.join(outputDir, "server"), fs8) : Promise.resolve(),
35091
+ useExternalMetadataImageRuntime ? copyMetadataImageRuntime(root, import_path12.default.join(outputDir, "server"), fs8) : Promise.resolve()
33547
35092
  ]);
33548
35093
  const failedCopy = copyResults.find(
33549
35094
  (result) => result.status === "rejected"
@@ -33655,6 +35200,9 @@ async function postProcessVercelOutput(root, outputDir, fs8, config, farmWorkflo
33655
35200
  fs8
33656
35201
  );
33657
35202
  vercelConfig.routes = [
35203
+ // Apply the header before the filesystem handler. `continue` lets Vercel
35204
+ // serve the matching file while preserving the immutable cache policy.
35205
+ createFarmVercelImmutableAssetRoute(config.basePath),
33658
35206
  // Serve static files first
33659
35207
  {
33660
35208
  handle: "filesystem"
@@ -33772,6 +35320,42 @@ async function copySharpRuntime(config, root, nitroFuncDir, fs8) {
33772
35320
  logger.info(`\u{1F5BC}\uFE0F Bundled Sharp image runtime (${copiedPackages.size} packages)`);
33773
35321
  }
33774
35322
  __name(copySharpRuntime, "copySharpRuntime");
35323
+ async function copyMetadataImageRuntime(root, nitroFuncDir, fs8) {
35324
+ const projectRequire = (0, import_module2.createRequire)(import_path12.default.join(root, "package.json"));
35325
+ let runtimeRequire = projectRequire;
35326
+ let packageJsonPath = resolvePackageJson(runtimeRequire, "@vercel/og");
35327
+ if (!packageJsonPath) {
35328
+ try {
35329
+ runtimeRequire = (0, import_module2.createRequire)(projectRequire.resolve("@farm.js/core"));
35330
+ packageJsonPath = resolvePackageJson(runtimeRequire, "@vercel/og");
35331
+ } catch {
35332
+ }
35333
+ }
35334
+ if (!packageJsonPath) {
35335
+ throw new Error(
35336
+ "Generated metadata images require @vercel/og. Reinstall @farm.js/core with production dependencies."
35337
+ );
35338
+ }
35339
+ const packageJson = JSON.parse(await fs8.readFile(packageJsonPath, "utf8"));
35340
+ const packageDir = import_path12.default.dirname(packageJsonPath);
35341
+ const targetDir = import_path12.default.join(nitroFuncDir, "node_modules", "@vercel", "og");
35342
+ await fs8.mkdir(import_path12.default.dirname(targetDir), { recursive: true });
35343
+ await fs8.cp(packageDir, targetDir, {
35344
+ recursive: true,
35345
+ force: true,
35346
+ dereference: true,
35347
+ mode: import_fs5.constants.COPYFILE_FICLONE
35348
+ });
35349
+ const functionPackagePath = import_path12.default.join(nitroFuncDir, "package.json");
35350
+ const functionPackage = JSON.parse(await fs8.readFile(functionPackagePath, "utf8"));
35351
+ functionPackage.dependencies = {
35352
+ ...functionPackage.dependencies,
35353
+ "@vercel/og": String(packageJson.version || "0.11.1")
35354
+ };
35355
+ await fs8.writeFile(functionPackagePath, JSON.stringify(functionPackage, null, 2));
35356
+ logger.info("\u{1F5BC}\uFE0F Bundled generated metadata image runtime");
35357
+ }
35358
+ __name(copyMetadataImageRuntime, "copyMetadataImageRuntime");
33775
35359
  function resolvePackageJson(parentRequire, packageName) {
33776
35360
  for (const request of [`${packageName}/package.json`, `${packageName}/package`]) {
33777
35361
  try {
@@ -33831,54 +35415,7 @@ init_type_artifacts();
33831
35415
  init_plugin();
33832
35416
  init_environment_vite();
33833
35417
  init_font_vite();
33834
-
33835
- // src/server/vite-config.ts
33836
- function mergeNoExternal(farmValue, userValue) {
33837
- if (farmValue === true || userValue === true) return true;
33838
- const normalize = /* @__PURE__ */ __name((value) => value == null || value === true ? [] : Array.isArray(value) ? value : [value], "normalize");
33839
- return Array.from(/* @__PURE__ */ new Set([...normalize(farmValue), ...normalize(userValue)]));
33840
- }
33841
- __name(mergeNoExternal, "mergeNoExternal");
33842
- function mergeFarmViteConfig(farmConfig, userConfig = {}) {
33843
- return {
33844
- ...farmConfig,
33845
- ...userConfig,
33846
- plugins: [...farmConfig.plugins || [], ...userConfig.plugins || []],
33847
- server: {
33848
- ...farmConfig.server,
33849
- ...userConfig.server
33850
- },
33851
- resolve: {
33852
- ...farmConfig.resolve,
33853
- ...userConfig.resolve,
33854
- dedupe: Array.from(
33855
- /* @__PURE__ */ new Set([...farmConfig.resolve?.dedupe || [], ...userConfig.resolve?.dedupe || []])
33856
- )
33857
- },
33858
- optimizeDeps: {
33859
- ...farmConfig.optimizeDeps,
33860
- ...userConfig.optimizeDeps,
33861
- include: Array.from(
33862
- /* @__PURE__ */ new Set([
33863
- ...farmConfig.optimizeDeps?.include || [],
33864
- ...userConfig.optimizeDeps?.include || []
33865
- ])
33866
- ),
33867
- exclude: Array.from(
33868
- /* @__PURE__ */ new Set([
33869
- ...farmConfig.optimizeDeps?.exclude || [],
33870
- ...userConfig.optimizeDeps?.exclude || []
33871
- ])
33872
- )
33873
- },
33874
- ssr: {
33875
- ...farmConfig.ssr,
33876
- ...userConfig.ssr,
33877
- noExternal: mergeNoExternal(farmConfig.ssr?.noExternal, userConfig.ssr?.noExternal)
33878
- }
33879
- };
33880
- }
33881
- __name(mergeFarmViteConfig, "mergeFarmViteConfig");
35418
+ init_vite_config();
33882
35419
 
33883
35420
  // src/build/production-node-env.ts
33884
35421
  var productionNodeEnvStateKey = /* @__PURE__ */ Symbol.for("@farm.js/core/production-node-env-state");