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

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 (237) hide show
  1. package/dist/{chunk-5EVQFRL2.mjs → chunk-3WIRO3N7.mjs} +2 -2
  2. package/dist/chunk-3WIRO3N7.mjs.map +1 -0
  3. package/dist/chunk-53MVSX3R.mjs +168 -0
  4. package/dist/chunk-53MVSX3R.mjs.map +1 -0
  5. package/dist/{chunk-AW6I64AP.mjs → chunk-6ZXIQSXE.mjs} +16 -1
  6. package/dist/chunk-6ZXIQSXE.mjs.map +1 -0
  7. package/dist/chunk-7ZVN3YZI.mjs +333 -0
  8. package/dist/chunk-7ZVN3YZI.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-USLFXFFH.mjs +46 -0
  17. package/dist/chunk-USLFXFFH.mjs.map +1 -0
  18. package/dist/{chunk-4677KXB7.mjs → chunk-VSDZEB5M.mjs} +368 -103
  19. package/dist/chunk-VSDZEB5M.mjs.map +1 -0
  20. package/dist/{chunk-77BOAQHI.mjs → chunk-Z3YG4OZT.mjs} +725 -147
  21. package/dist/chunk-Z3YG4OZT.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 +2206 -680
  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 +2033 -516
  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 +1521 -339
  57. package/dist/plugin.cjs.map +1 -1
  58. package/dist/plugin.mjs +9 -5
  59. package/dist/server.cjs +1634 -410
  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 +1575 -349
  67. package/dist/vite.cjs.map +1 -1
  68. package/dist/vite.mjs +9 -5
  69. package/package.json +10 -1
  70. package/dist/after.d.mts +0 -25
  71. package/dist/after.d.ts +0 -25
  72. package/dist/agent-runtime.d.mts +0 -94
  73. package/dist/agent-runtime.d.ts +0 -94
  74. package/dist/api/route-manager.d.mts +0 -66
  75. package/dist/api/route-manager.d.ts +0 -66
  76. package/dist/api/runtime.d.mts +0 -3
  77. package/dist/api/runtime.d.ts +0 -3
  78. package/dist/api.d.mts +0 -48
  79. package/dist/api.d.ts +0 -48
  80. package/dist/app-BNE2FoZ4.d.mts +0 -302
  81. package/dist/app-DRGUmJ3s.d.ts +0 -302
  82. package/dist/app-markdown.d.mts +0 -22
  83. package/dist/app-markdown.d.ts +0 -22
  84. package/dist/cache.d.mts +0 -192
  85. package/dist/cache.d.ts +0 -192
  86. package/dist/chunk-4677KXB7.mjs.map +0 -1
  87. package/dist/chunk-4LND3PXF.mjs.map +0 -1
  88. package/dist/chunk-5EVQFRL2.mjs.map +0 -1
  89. package/dist/chunk-77BOAQHI.mjs.map +0 -1
  90. package/dist/chunk-AW6I64AP.mjs.map +0 -1
  91. package/dist/chunk-K5ZTUF22.mjs.map +0 -1
  92. package/dist/chunk-QM746KUO.mjs +0 -56
  93. package/dist/chunk-QM746KUO.mjs.map +0 -1
  94. package/dist/chunk-QTZZ2ISQ.mjs.map +0 -1
  95. package/dist/client-BT1mFQas.d.mts +0 -447
  96. package/dist/client-Nn0q4eO4.d.ts +0 -447
  97. package/dist/client-cache-CIlyBlmx.d.ts +0 -6
  98. package/dist/client-cache-D-EZ7XVW.d.mts +0 -6
  99. package/dist/client-plugins-Bc5jHcNr.d.ts +0 -1927
  100. package/dist/client-plugins-jsk-ZLzJ.d.mts +0 -1927
  101. package/dist/client-plugins.d.mts +0 -22
  102. package/dist/client-plugins.d.ts +0 -22
  103. package/dist/client.d.mts +0 -447
  104. package/dist/client.d.ts +0 -447
  105. package/dist/config.d.mts +0 -29
  106. package/dist/config.d.ts +0 -29
  107. package/dist/cron.d.mts +0 -78
  108. package/dist/cron.d.ts +0 -78
  109. package/dist/deferred.d.mts +0 -42
  110. package/dist/deferred.d.ts +0 -42
  111. package/dist/deployment.d.mts +0 -34
  112. package/dist/deployment.d.ts +0 -34
  113. package/dist/docs.d.mts +0 -69
  114. package/dist/docs.d.ts +0 -69
  115. package/dist/env-types.d.mts +0 -12
  116. package/dist/env-types.d.ts +0 -12
  117. package/dist/env.d.mts +0 -45
  118. package/dist/env.d.ts +0 -45
  119. package/dist/environment/vite.d.mts +0 -22
  120. package/dist/environment/vite.d.ts +0 -22
  121. package/dist/environment.d.mts +0 -18
  122. package/dist/environment.d.ts +0 -18
  123. package/dist/font.d.mts +0 -70
  124. package/dist/font.d.ts +0 -70
  125. package/dist/headers.d.mts +0 -22
  126. package/dist/headers.d.ts +0 -22
  127. package/dist/i18n/client.d.mts +0 -32
  128. package/dist/i18n/client.d.ts +0 -32
  129. package/dist/i18n/index.d.mts +0 -20
  130. package/dist/i18n/index.d.ts +0 -20
  131. package/dist/i18n/server.d.mts +0 -30
  132. package/dist/i18n/server.d.ts +0 -30
  133. package/dist/image/server.d.mts +0 -37
  134. package/dist/image/server.d.ts +0 -37
  135. package/dist/image/sharp.d.mts +0 -7
  136. package/dist/image/sharp.d.ts +0 -7
  137. package/dist/image-config-Duob7wER.d.mts +0 -50
  138. package/dist/image-config-Duob7wER.d.ts +0 -50
  139. package/dist/image.d.mts +0 -39
  140. package/dist/image.d.ts +0 -39
  141. package/dist/index.d.mts +0 -455
  142. package/dist/index.d.ts +0 -455
  143. package/dist/integration-api-CHT2OKAf.d.mts +0 -93
  144. package/dist/integration-api-CHT2OKAf.d.ts +0 -93
  145. package/dist/integrations.d.mts +0 -22
  146. package/dist/integrations.d.ts +0 -22
  147. package/dist/internal/build-runtime.d.mts +0 -39
  148. package/dist/internal/build-runtime.d.ts +0 -39
  149. package/dist/internal/client-runtime.d.mts +0 -2
  150. package/dist/internal/client-runtime.d.ts +0 -2
  151. package/dist/internal/config-runtime.d.mts +0 -39
  152. package/dist/internal/config-runtime.d.ts +0 -39
  153. package/dist/internal/production-node-env.d.mts +0 -12
  154. package/dist/internal/production-node-env.d.ts +0 -12
  155. package/dist/internal/production-runtime.d.mts +0 -41
  156. package/dist/internal/production-runtime.d.ts +0 -41
  157. package/dist/markdown.d.mts +0 -60
  158. package/dist/markdown.d.ts +0 -60
  159. package/dist/metadata-7ffpT3jr.d.mts +0 -22
  160. package/dist/metadata-JHn-8eht.d.ts +0 -22
  161. package/dist/middleware.d.mts +0 -164
  162. package/dist/middleware.d.ts +0 -164
  163. package/dist/navigation-errors-Dvwpzaer.d.mts +0 -13
  164. package/dist/navigation-errors-Dvwpzaer.d.ts +0 -13
  165. package/dist/navigation.d.mts +0 -14
  166. package/dist/navigation.d.ts +0 -14
  167. package/dist/observability.d.mts +0 -335
  168. package/dist/observability.d.ts +0 -335
  169. package/dist/params-BALtrRim.d.ts +0 -15
  170. package/dist/params-ry-lxqmy.d.mts +0 -15
  171. package/dist/plugin-BJDf43dc.d.mts +0 -165
  172. package/dist/plugin-BJDf43dc.d.ts +0 -165
  173. package/dist/plugin.d.mts +0 -22
  174. package/dist/plugin.d.ts +0 -22
  175. package/dist/production-runtime-9KG7GuvW.d.ts +0 -79
  176. package/dist/production-runtime-B-fweKts.d.mts +0 -79
  177. package/dist/production-runtime-C_B79w2P.d.mts +0 -28
  178. package/dist/production-runtime-DDEM1D2q.d.ts +0 -28
  179. package/dist/query/client.d.mts +0 -61
  180. package/dist/query/client.d.ts +0 -61
  181. package/dist/query/index.d.mts +0 -90
  182. package/dist/query/index.d.ts +0 -90
  183. package/dist/query/parsers.d.mts +0 -25
  184. package/dist/query/parsers.d.ts +0 -25
  185. package/dist/query/server.d.mts +0 -55
  186. package/dist/query/server.d.ts +0 -55
  187. package/dist/request-Dsq4kGW0.d.mts +0 -6
  188. package/dist/request-udtobOLv.d.ts +0 -6
  189. package/dist/request.d.mts +0 -2
  190. package/dist/request.d.ts +0 -2
  191. package/dist/resolver-DJqjLMg_.d.mts +0 -14
  192. package/dist/resolver-IH4RmPEl.d.ts +0 -14
  193. package/dist/route-runtime-DoOHzCAD.d.mts +0 -38
  194. package/dist/route-runtime-DoOHzCAD.d.ts +0 -38
  195. package/dist/router.d.mts +0 -36
  196. package/dist/router.d.ts +0 -36
  197. package/dist/routes.d.mts +0 -224
  198. package/dist/routes.d.ts +0 -224
  199. package/dist/runtime-9nQjVM7X.d.mts +0 -206
  200. package/dist/runtime-Cxpq6xZN.d.mts +0 -27
  201. package/dist/runtime-DgeS2skB.d.ts +0 -206
  202. package/dist/runtime-bv63eUiO.d.ts +0 -27
  203. package/dist/server-action-security.d.mts +0 -43
  204. package/dist/server-action-security.d.ts +0 -43
  205. package/dist/server-fn-client.d.mts +0 -32
  206. package/dist/server-fn-client.d.ts +0 -32
  207. package/dist/server-fn.d.mts +0 -93
  208. package/dist/server-fn.d.ts +0 -93
  209. package/dist/server-plugins.d.mts +0 -55
  210. package/dist/server-plugins.d.ts +0 -55
  211. package/dist/server-query-client.d.mts +0 -50
  212. package/dist/server-query-client.d.ts +0 -50
  213. package/dist/server-query.d.mts +0 -36
  214. package/dist/server-query.d.ts +0 -36
  215. package/dist/server.d.mts +0 -48
  216. package/dist/server.d.ts +0 -48
  217. package/dist/storage.d.mts +0 -52
  218. package/dist/storage.d.ts +0 -52
  219. package/dist/testing.d.mts +0 -101
  220. package/dist/testing.d.ts +0 -101
  221. package/dist/transport-BmbGTXA5.d.mts +0 -49
  222. package/dist/transport-BmbGTXA5.d.ts +0 -49
  223. package/dist/types-BMxWr97v.d.mts +0 -81
  224. package/dist/types-BMxWr97v.d.ts +0 -81
  225. package/dist/types-C9N-nk5R.d.mts +0 -53
  226. package/dist/types-C9N-nk5R.d.ts +0 -53
  227. package/dist/types-D1A6-XvH.d.mts +0 -73
  228. package/dist/types-D1A6-XvH.d.ts +0 -73
  229. package/dist/utils-CA0z0c-2.d.ts +0 -23
  230. package/dist/utils-mYVkSOt2.d.mts +0 -23
  231. package/dist/version.d.mts +0 -3
  232. package/dist/version.d.ts +0 -3
  233. package/dist/vite.d.mts +0 -22
  234. package/dist/vite.d.ts +0 -22
  235. package/dist/workflows.d.mts +0 -110
  236. package/dist/workflows.d.ts +0 -110
  237. /package/dist/{chunk-7N62DNSO.mjs.map → chunk-H3TE3LOV.mjs.map} +0 -0
package/dist/vite.cjs CHANGED
@@ -652,26 +652,26 @@ async function prepareFarmWorkflowsForNitro(config) {
652
652
  const root = config.root || process.cwd();
653
653
  const distDir = config.distDir || ".farm";
654
654
  const fs8 = await import("fs/promises");
655
- const path24 = await import("path");
656
- const generatedDir = path24.join(root, distDir, ".nitro", "farm-workflows");
655
+ const path26 = await import("path");
656
+ const generatedDir = path26.join(root, distDir, ".nitro", "farm-workflows");
657
657
  await fs8.mkdir(generatedDir, { recursive: true });
658
658
  const tasks = {};
659
659
  const scheduledTasks = createScheduledTasks(workflows);
660
660
  for (const workflow of workflows) {
661
- const wrapperPath = path24.join(generatedDir, `${safeFileName(workflow.id)}.mjs`);
661
+ const wrapperPath = path26.join(generatedDir, `${safeFileName(workflow.id)}.mjs`);
662
662
  await fs8.writeFile(wrapperPath, createNitroTaskWrapper(workflow), "utf8");
663
663
  tasks[workflow.id] = {
664
664
  handler: wrapperPath,
665
665
  description: workflow.description || `Farm workflow ${workflow.id}`
666
666
  };
667
667
  }
668
- const handlerPath = path24.join(generatedDir, "http-handler.mjs");
668
+ const handlerPath = path26.join(generatedDir, "http-handler.mjs");
669
669
  await fs8.writeFile(
670
670
  handlerPath,
671
671
  createNitroWorkflowHTTPHandler(workflowConfig, workflows),
672
672
  "utf8"
673
673
  );
674
- const manifestPath = path24.join(generatedDir, "manifest.json");
674
+ const manifestPath = path26.join(generatedDir, "manifest.json");
675
675
  await fs8.writeFile(
676
676
  manifestPath,
677
677
  JSON.stringify(
@@ -754,10 +754,10 @@ function resolveWorkflowDefinition(module2) {
754
754
  }
755
755
  async function findWorkflowFiles(root, dirs) {
756
756
  const fs8 = await import("fs/promises");
757
- const path24 = await import("path");
757
+ const path26 = await import("path");
758
758
  const files = [];
759
759
  for (const dir of dirs) {
760
- const absoluteDir = path24.isAbsolute(dir) ? dir : path24.join(root, dir);
760
+ const absoluteDir = path26.isAbsolute(dir) ? dir : path26.join(root, dir);
761
761
  if (!await pathExists(absoluteDir)) continue;
762
762
  await walkWorkflowDir(absoluteDir, files);
763
763
  }
@@ -765,10 +765,10 @@ async function findWorkflowFiles(root, dirs) {
765
765
  }
766
766
  async function walkWorkflowDir(dir, files) {
767
767
  const fs8 = await import("fs/promises");
768
- const path24 = await import("path");
768
+ const path26 = await import("path");
769
769
  const entries = await fs8.readdir(dir, { withFileTypes: true });
770
770
  for (const entry of entries) {
771
- const filePath = path24.join(dir, entry.name);
771
+ const filePath = path26.join(dir, entry.name);
772
772
  if (entry.isDirectory()) {
773
773
  if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
774
774
  await walkWorkflowDir(filePath, files);
@@ -788,12 +788,12 @@ function isWorkflowFile(fileName) {
788
788
  }
789
789
  async function loadWorkflowModule(filePath, root) {
790
790
  const fs8 = await import("fs/promises");
791
- const path24 = await import("path");
791
+ const path26 = await import("path");
792
792
  const { pathToFileURL: pathToFileURL5 } = await import("url");
793
793
  const { build } = await import("esbuild");
794
- const outDir = path24.join(root, ".farm", ".workflow-loader");
794
+ const outDir = path26.join(root, ".farm", ".workflow-loader");
795
795
  await fs8.mkdir(outDir, { recursive: true });
796
- const outfile = path24.join(
796
+ const outfile = path26.join(
797
797
  outDir,
798
798
  `workflow-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`
799
799
  );
@@ -1076,7 +1076,7 @@ function normalizeCronJob(name, job) {
1076
1076
  if (!job || typeof job !== "object" || Array.isArray(job)) {
1077
1077
  throw new TypeError(`Farm cron ${JSON.stringify(name)} must be a configuration object.`);
1078
1078
  }
1079
- const path24 = normalizeCronPath(name, job.path);
1079
+ const path26 = normalizeCronPath(name, job.path);
1080
1080
  const rawSchedule = Array.isArray(job.schedule) ? job.schedule : [job.schedule];
1081
1081
  const schedule = [...new Set(rawSchedule.map((value) => normalizeCronExpression(name, value)))];
1082
1082
  if (schedule.length === 0) {
@@ -1085,7 +1085,7 @@ function normalizeCronJob(name, job) {
1085
1085
  return {
1086
1086
  name,
1087
1087
  schedule,
1088
- path: path24,
1088
+ path: path26,
1089
1089
  description: job.description?.trim() || void 0
1090
1090
  };
1091
1091
  }
@@ -1093,13 +1093,13 @@ function normalizeCronPath(name, value) {
1093
1093
  if (typeof value !== "string" || !value.trim().startsWith("/")) {
1094
1094
  throw new TypeError(`Farm cron ${JSON.stringify(name)} path must start with "/".`);
1095
1095
  }
1096
- const path24 = value.trim();
1097
- if (path24.startsWith("//") || path24.includes("?") || path24.includes("#")) {
1096
+ const path26 = value.trim();
1097
+ if (path26.startsWith("//") || path26.includes("?") || path26.includes("#")) {
1098
1098
  throw new TypeError(
1099
1099
  `Farm cron ${JSON.stringify(name)} path must be an application pathname without a host, query, or hash.`
1100
1100
  );
1101
1101
  }
1102
- return path24.length > 1 ? path24.replace(/\/+$/, "") : path24;
1102
+ return path26.length > 1 ? path26.replace(/\/+$/, "") : path26;
1103
1103
  }
1104
1104
  function normalizeCronExpression(name, value) {
1105
1105
  if (typeof value !== "string") {
@@ -1956,7 +1956,7 @@ var init_server_action_security = __esm({
1956
1956
 
1957
1957
  // src/image-config.ts
1958
1958
  function resolveFarmImageConfig(config) {
1959
- const path24 = normalizeImagePath(config?.path ?? DEFAULT_FARM_IMAGE_PATH);
1959
+ const path26 = normalizeImagePath(config?.path ?? DEFAULT_FARM_IMAGE_PATH);
1960
1960
  const deviceSizes = normalizeIntegerList(
1961
1961
  config?.deviceSizes ?? DEFAULT_FARM_IMAGE_DEVICE_SIZES,
1962
1962
  "images.deviceSizes"
@@ -1984,7 +1984,7 @@ function resolveFarmImageConfig(config) {
1984
1984
  );
1985
1985
  return Object.freeze({
1986
1986
  provider: config?.provider ?? "auto",
1987
- path: path24,
1987
+ path: path26,
1988
1988
  domains: Object.freeze([
1989
1989
  ...new Set(
1990
1990
  (config?.domains ?? []).map((domain) => domain.trim().toLowerCase()).filter(Boolean)
@@ -2023,11 +2023,11 @@ function getPublicFarmImageConfig(config) {
2023
2023
  };
2024
2024
  }
2025
2025
  function normalizeImagePath(value) {
2026
- const path24 = value.trim().replace(/\/+$/, "") || "/";
2027
- if (!path24.startsWith("/") || path24.includes("?") || path24.includes("#")) {
2026
+ const path26 = value.trim().replace(/\/+$/, "") || "/";
2027
+ if (!path26.startsWith("/") || path26.includes("?") || path26.includes("#")) {
2028
2028
  throw new TypeError("images.path must be an absolute pathname without a query or hash");
2029
2029
  }
2030
- return path24;
2030
+ return path26;
2031
2031
  }
2032
2032
  function normalizeIntegerList(values, name, max) {
2033
2033
  if (values.length === 0) {
@@ -2866,9 +2866,9 @@ var init_integration_orm = __esm({
2866
2866
  });
2867
2867
 
2868
2868
  // src/integrations.ts
2869
- function defineTypedIntegrationRoute(method, path24, input) {
2869
+ function defineTypedIntegrationRoute(method, path26, input) {
2870
2870
  return {
2871
- path: path24,
2871
+ path: path26,
2872
2872
  method,
2873
2873
  middleware: input.middleware,
2874
2874
  before: input.before,
@@ -2878,7 +2878,7 @@ function defineTypedIntegrationRoute(method, path24, input) {
2878
2878
  input: normalizeIntegrationRouteInputSchemas(input),
2879
2879
  handler: input.handler,
2880
2880
  __operation: defineIntegrationAPIOperation({
2881
- path: path24,
2881
+ path: path26,
2882
2882
  method,
2883
2883
  bodyFormat: input.bodyFormat,
2884
2884
  responseFormat: input.responseFormat,
@@ -2890,52 +2890,52 @@ function defineTypedIntegrationRoute(method, path24, input) {
2890
2890
  }
2891
2891
  function createIntegrationRouteFactory() {
2892
2892
  return {
2893
- get(path24, input) {
2893
+ get(path26, input) {
2894
2894
  return defineTypedIntegrationRoute(
2895
2895
  "GET",
2896
- path24,
2896
+ path26,
2897
2897
  input
2898
2898
  );
2899
2899
  },
2900
- post(path24, input) {
2900
+ post(path26, input) {
2901
2901
  return defineTypedIntegrationRoute(
2902
2902
  "POST",
2903
- path24,
2903
+ path26,
2904
2904
  {
2905
2905
  bodyFormat: "json",
2906
2906
  ...input
2907
2907
  }
2908
2908
  );
2909
2909
  },
2910
- put(path24, input) {
2910
+ put(path26, input) {
2911
2911
  return defineTypedIntegrationRoute(
2912
2912
  "PUT",
2913
- path24,
2913
+ path26,
2914
2914
  {
2915
2915
  bodyFormat: "json",
2916
2916
  ...input
2917
2917
  }
2918
2918
  );
2919
2919
  },
2920
- patch(path24, input) {
2921
- return defineTypedIntegrationRoute("PATCH", path24, {
2920
+ patch(path26, input) {
2921
+ return defineTypedIntegrationRoute("PATCH", path26, {
2922
2922
  bodyFormat: "json",
2923
2923
  ...input
2924
2924
  });
2925
2925
  },
2926
- delete(path24, input) {
2927
- return defineTypedIntegrationRoute("DELETE", path24, {
2926
+ delete(path26, input) {
2927
+ return defineTypedIntegrationRoute("DELETE", path26, {
2928
2928
  bodyFormat: "json",
2929
2929
  ...input
2930
2930
  });
2931
2931
  },
2932
- options(path24, input) {
2933
- return defineTypedIntegrationRoute("OPTIONS", path24, input);
2932
+ options(path26, input) {
2933
+ return defineTypedIntegrationRoute("OPTIONS", path26, input);
2934
2934
  },
2935
- head(path24, input) {
2935
+ head(path26, input) {
2936
2936
  return defineTypedIntegrationRoute(
2937
2937
  "HEAD",
2938
- path24,
2938
+ path26,
2939
2939
  input
2940
2940
  );
2941
2941
  }
@@ -3272,8 +3272,8 @@ function normalizeIntegrationValidationIssues(source, error) {
3272
3272
  }
3273
3273
  ];
3274
3274
  }
3275
- function normalizeIntegrationValidationPath(path24) {
3276
- return (path24 || []).map((segment) => {
3275
+ function normalizeIntegrationValidationPath(path26) {
3276
+ return (path26 || []).map((segment) => {
3277
3277
  const key = typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment;
3278
3278
  return typeof key === "symbol" ? key.description || key.toString() : key;
3279
3279
  });
@@ -3962,8 +3962,8 @@ function createFarmDeploymentMismatchResponse(mismatch) {
3962
3962
  }
3963
3963
  );
3964
3964
  }
3965
- function createFarmDeploymentCookie(deploymentId, path24 = "/", secure = false) {
3966
- const normalizedPath = path24.startsWith("/") ? path24 : `/${path24}`;
3965
+ function createFarmDeploymentCookie(deploymentId, path26 = "/", secure = false) {
3966
+ const normalizedPath = path26.startsWith("/") ? path26 : `/${path26}`;
3967
3967
  return [
3968
3968
  `${FARM_DEPLOYMENT_COOKIE}=${encodeURIComponent(deploymentId)}`,
3969
3969
  `Path=${normalizedPath}`,
@@ -4219,6 +4219,33 @@ var init_auth_config = __esm({
4219
4219
  }
4220
4220
  });
4221
4221
 
4222
+ // src/preload.ts
4223
+ function resolveFarmPerformanceConfig(config) {
4224
+ return {
4225
+ preload: {
4226
+ mode: config?.preload?.mode === "warn" ? "warn" : "enforce",
4227
+ maxImages: normalizeBudget(config?.preload?.maxImages, DEFAULT_PRELOAD_CONFIG.maxImages),
4228
+ maxFonts: normalizeBudget(config?.preload?.maxFonts, DEFAULT_PRELOAD_CONFIG.maxFonts)
4229
+ }
4230
+ };
4231
+ }
4232
+ function normalizeBudget(value, fallback) {
4233
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
4234
+ }
4235
+ var DEFAULT_PRELOAD_CONFIG;
4236
+ var init_preload = __esm({
4237
+ "src/preload.ts"() {
4238
+ "use strict";
4239
+ DEFAULT_PRELOAD_CONFIG = {
4240
+ mode: "enforce",
4241
+ maxImages: 1,
4242
+ maxFonts: 2
4243
+ };
4244
+ __name(resolveFarmPerformanceConfig, "resolveFarmPerformanceConfig");
4245
+ __name(normalizeBudget, "normalizeBudget");
4246
+ }
4247
+ });
4248
+
4222
4249
  // src/write-file-if-changed.ts
4223
4250
  function writeFileIfChanged(filePath, content) {
4224
4251
  try {
@@ -4338,11 +4365,11 @@ var init_type_generator = __esm({
4338
4365
  routeGroups.get(key).push(route);
4339
4366
  }
4340
4367
  const nestedStructure = {};
4341
- for (const [path24, routeList] of routeGroups) {
4368
+ for (const [path26, routeList] of routeGroups) {
4342
4369
  const route = routeList[0];
4343
4370
  const importPath = this.getRouteImportPath(route, options.outFile);
4344
4371
  const routeName = this.pathToRouteName(route.path);
4345
- const cleanPath = path24 === "/api" ? "" : path24.replace(/^\/api\//, "");
4372
+ const cleanPath = path26 === "/api" ? "" : path26.replace(/^\/api\//, "");
4346
4373
  const parts = cleanPath ? cleanPath.split("/") : [];
4347
4374
  const allMethods = routeList.flatMap((r) => r.methods);
4348
4375
  for (const method of allMethods) {
@@ -4401,8 +4428,8 @@ ${typeExports}
4401
4428
  const relativeImport = (0, import_path7.relative)((0, import_path7.dirname)(outFile), route.filePath).replace(/\\/g, "/").replace(/\.(ts|tsx|js|jsx)$/, "");
4402
4429
  return relativeImport.startsWith(".") ? relativeImport : `./${relativeImport}`;
4403
4430
  }
4404
- pathToRouteName(path24) {
4405
- return (path24 === "/api" ? "root" : path24.replace(/^\/api\//, "")).replace(/\//g, "_").replace(/[^a-zA-Z0-9_]/g, "");
4431
+ pathToRouteName(path26) {
4432
+ return (path26 === "/api" ? "root" : path26.replace(/^\/api\//, "")).replace(/\//g, "_").replace(/[^a-zA-Z0-9_]/g, "");
4406
4433
  }
4407
4434
  structureToTypeString(obj, indent) {
4408
4435
  const spaces = " ".repeat(indent);
@@ -4422,15 +4449,15 @@ ${typeExports}
4422
4449
  toTypePropertyKey(key) {
4423
4450
  return /^[$A-Z_][0-9A-Z_$]*$/i.test(key) ? key : JSON.stringify(key);
4424
4451
  }
4425
- getBaseExportName(path24) {
4426
- const cleanPath = path24.replace(/^\/api\//, "");
4452
+ getBaseExportName(path26) {
4453
+ const cleanPath = path26.replace(/^\/api\//, "");
4427
4454
  if (cleanPath === "") {
4428
4455
  return "api";
4429
4456
  }
4430
4457
  return cleanPath;
4431
4458
  }
4432
- getExportName(path24, method) {
4433
- const cleanPath = path24.replace(/^\/api\//, "");
4459
+ getExportName(path26, method) {
4460
+ const cleanPath = path26.replace(/^\/api\//, "");
4434
4461
  if (cleanPath === "") {
4435
4462
  return method.toLowerCase();
4436
4463
  }
@@ -4872,28 +4899,71 @@ var init_image_server = __esm({
4872
4899
  }
4873
4900
  });
4874
4901
 
4902
+ // src/docs/fonts.ts
4903
+ function resolveFarmDocsFontAssets(root) {
4904
+ return FARM_DOCS_FONT_SOURCES.flatMap(({ family, packagePath }) => {
4905
+ const sourcePath = import_node_path10.default.join(root, "node_modules", packagePath);
4906
+ if (!(0, import_node_fs6.existsSync)(sourcePath)) return [];
4907
+ const source = (0, import_node_fs6.readFileSync)(sourcePath);
4908
+ const fingerprint = (0, import_node_crypto3.createHash)("sha256").update(source).digest("hex").slice(0, 12);
4909
+ const extension = import_node_path10.default.extname(packagePath);
4910
+ const baseName = import_node_path10.default.basename(packagePath, extension);
4911
+ return [
4912
+ {
4913
+ family,
4914
+ sourcePath,
4915
+ url: `/assets/fonts/${baseName}-h${fingerprint}${extension}`
4916
+ }
4917
+ ];
4918
+ });
4919
+ }
4920
+ function toFarmDocsPublicFontAssets(assets) {
4921
+ return assets.map(({ family, url }) => ({ family, url }));
4922
+ }
4923
+ var import_node_crypto3, import_node_fs6, import_node_path10, FARM_DOCS_FONT_SOURCES;
4924
+ var init_fonts = __esm({
4925
+ "src/docs/fonts.ts"() {
4926
+ "use strict";
4927
+ import_node_crypto3 = require("crypto");
4928
+ import_node_fs6 = require("fs");
4929
+ import_node_path10 = __toESM(require("path"));
4930
+ FARM_DOCS_FONT_SOURCES = [
4931
+ {
4932
+ family: "Geist Sans",
4933
+ packagePath: "geist/dist/fonts/geist-sans/Geist-Variable.woff2"
4934
+ },
4935
+ {
4936
+ family: "Geist Mono",
4937
+ packagePath: "geist/dist/fonts/geist-mono/GeistMono-Variable.woff2"
4938
+ }
4939
+ ];
4940
+ __name(resolveFarmDocsFontAssets, "resolveFarmDocsFontAssets");
4941
+ __name(toFarmDocsPublicFontAssets, "toFarmDocsPublicFontAssets");
4942
+ }
4943
+ });
4944
+
4875
4945
  // src/docs/last-modified.ts
4876
4946
  function normalizeRelativePath(value) {
4877
4947
  return value.replace(/\\/g, "/").replace(/^\.\/+/, "");
4878
4948
  }
4879
4949
  function resolveExistingPath(filePath) {
4880
4950
  try {
4881
- return (0, import_node_fs6.realpathSync)(filePath);
4951
+ return (0, import_node_fs7.realpathSync)(filePath);
4882
4952
  } catch {
4883
- return import_node_path9.default.resolve(filePath);
4953
+ return import_node_path11.default.resolve(filePath);
4884
4954
  }
4885
4955
  }
4886
4956
  function isDocsSourceFile(filePath) {
4887
- return DOCS_FILE_EXTENSIONS.has(import_node_path9.default.extname(filePath).toLowerCase());
4957
+ return DOCS_FILE_EXTENSIONS.has(import_node_path11.default.extname(filePath).toLowerCase());
4888
4958
  }
4889
4959
  function discoverDocsSourceFiles(contentDir) {
4890
4960
  const files = [];
4891
4961
  const visit = /* @__PURE__ */ __name((dir) => {
4892
- for (const entry of (0, import_node_fs6.readdirSync)(dir, { withFileTypes: true }).sort(
4962
+ for (const entry of (0, import_node_fs7.readdirSync)(dir, { withFileTypes: true }).sort(
4893
4963
  (a, b) => a.name.localeCompare(b.name)
4894
4964
  )) {
4895
4965
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
4896
- const absolutePath = import_node_path9.default.join(dir, entry.name);
4966
+ const absolutePath = import_node_path11.default.join(dir, entry.name);
4897
4967
  if (entry.isDirectory()) {
4898
4968
  visit(absolutePath);
4899
4969
  } else if (entry.isFile() && isDocsSourceFile(absolutePath)) {
@@ -4901,7 +4971,7 @@ function discoverDocsSourceFiles(contentDir) {
4901
4971
  }
4902
4972
  }
4903
4973
  }, "visit");
4904
- if ((0, import_node_fs6.existsSync)(contentDir)) visit(contentDir);
4974
+ if ((0, import_node_fs7.existsSync)(contentDir)) visit(contentDir);
4905
4975
  return files;
4906
4976
  }
4907
4977
  function getGitLastModifiedDates(contentDir) {
@@ -4911,7 +4981,7 @@ function getGitLastModifiedDates(contentDir) {
4911
4981
  stdio: ["ignore", "pipe", "ignore"]
4912
4982
  }).trim();
4913
4983
  if (!gitRoot) return {};
4914
- const contentPathspec = normalizeRelativePath(import_node_path9.default.relative(gitRoot, contentDir)) || ".";
4984
+ const contentPathspec = normalizeRelativePath(import_node_path11.default.relative(gitRoot, contentDir)) || ".";
4915
4985
  const contentPrefix = contentPathspec === "." ? "" : `${contentPathspec}/`;
4916
4986
  const history = (0, import_node_child_process.execFileSync)(
4917
4987
  "git",
@@ -4953,11 +5023,11 @@ function getGitLastModifiedDates(contentDir) {
4953
5023
  }
4954
5024
  }
4955
5025
  function readManifest(contentDir) {
4956
- const manifestPath = import_node_path9.default.join(contentDir, FARM_DOCS_LAST_MODIFIED_MANIFEST);
4957
- if (!(0, import_node_fs6.existsSync)(manifestPath)) return null;
5026
+ const manifestPath = import_node_path11.default.join(contentDir, FARM_DOCS_LAST_MODIFIED_MANIFEST);
5027
+ if (!(0, import_node_fs7.existsSync)(manifestPath)) return null;
4958
5028
  try {
4959
5029
  const parsed = JSON.parse(
4960
- (0, import_node_fs6.readFileSync)(manifestPath, "utf8")
5030
+ (0, import_node_fs7.readFileSync)(manifestPath, "utf8")
4961
5031
  );
4962
5032
  if (parsed.version !== 1 || !parsed.pages || typeof parsed.pages !== "object") return null;
4963
5033
  const pages = Object.fromEntries(
@@ -4976,15 +5046,15 @@ function createFarmDocsLastModifiedManifest(contentDir, options = {}) {
4976
5046
  const fallbackDate = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
4977
5047
  const pages = {};
4978
5048
  for (const sourcePath of discoverDocsSourceFiles(resolvedContentDir)) {
4979
- const relativePath2 = normalizeRelativePath(import_node_path9.default.relative(resolvedContentDir, sourcePath));
4980
- pages[relativePath2] = gitDates[relativePath2] || (options.fallback === "now" ? fallbackDate : (0, import_node_fs6.statSync)(sourcePath).mtime.toISOString());
5049
+ const relativePath2 = normalizeRelativePath(import_node_path11.default.relative(resolvedContentDir, sourcePath));
5050
+ pages[relativePath2] = gitDates[relativePath2] || (options.fallback === "now" ? fallbackDate : (0, import_node_fs7.statSync)(sourcePath).mtime.toISOString());
4981
5051
  }
4982
5052
  return { version: 1, pages };
4983
5053
  }
4984
5054
  function getLastModifiedManifest(contentDir) {
4985
5055
  const resolvedContentDir = resolveExistingPath(contentDir);
4986
- const manifestPath = import_node_path9.default.join(resolvedContentDir, FARM_DOCS_LAST_MODIFIED_MANIFEST);
4987
- const manifestStat = (0, import_node_fs6.existsSync)(manifestPath) ? (0, import_node_fs6.statSync)(manifestPath) : null;
5056
+ const manifestPath = import_node_path11.default.join(resolvedContentDir, FARM_DOCS_LAST_MODIFIED_MANIFEST);
5057
+ const manifestStat = (0, import_node_fs7.existsSync)(manifestPath) ? (0, import_node_fs7.statSync)(manifestPath) : null;
4988
5058
  const signature = manifestStat ? `file:${manifestStat.mtimeMs}:${manifestStat.size}` : "generated";
4989
5059
  const cached = manifestCache.get(resolvedContentDir);
4990
5060
  if (cached?.signature === signature) return cached.manifest;
@@ -4997,21 +5067,21 @@ function resolveFarmDocsPageLastModified(contentDir, sourcePath, frontmatter) {
4997
5067
  if (configured) return configured;
4998
5068
  const resolvedContentDir = resolveExistingPath(contentDir);
4999
5069
  const resolvedSourcePath = resolveExistingPath(sourcePath);
5000
- const relativePath2 = normalizeRelativePath(import_node_path9.default.relative(resolvedContentDir, resolvedSourcePath));
5001
- const isInsideContentDir = relativePath2 !== ".." && !relativePath2.startsWith("../") && !import_node_path9.default.isAbsolute(relativePath2);
5070
+ const relativePath2 = normalizeRelativePath(import_node_path11.default.relative(resolvedContentDir, resolvedSourcePath));
5071
+ const isInsideContentDir = relativePath2 !== ".." && !relativePath2.startsWith("../") && !import_node_path11.default.isAbsolute(relativePath2);
5002
5072
  if (isInsideContentDir) {
5003
5073
  const generated = getLastModifiedManifest(resolvedContentDir).pages[relativePath2];
5004
5074
  if (generated) return generated;
5005
5075
  }
5006
- return (0, import_node_fs6.statSync)(resolvedSourcePath).mtime.toISOString();
5076
+ return (0, import_node_fs7.statSync)(resolvedSourcePath).mtime.toISOString();
5007
5077
  }
5008
- var import_node_child_process, import_node_fs6, import_node_path9, FARM_DOCS_LAST_MODIFIED_MANIFEST, COMMIT_MARKER, DOCS_FILE_EXTENSIONS, manifestCache;
5078
+ var import_node_child_process, import_node_fs7, import_node_path11, FARM_DOCS_LAST_MODIFIED_MANIFEST, COMMIT_MARKER, DOCS_FILE_EXTENSIONS, manifestCache;
5009
5079
  var init_last_modified = __esm({
5010
5080
  "src/docs/last-modified.ts"() {
5011
5081
  "use strict";
5012
5082
  import_node_child_process = require("child_process");
5013
- import_node_fs6 = require("fs");
5014
- import_node_path9 = __toESM(require("path"));
5083
+ import_node_fs7 = require("fs");
5084
+ import_node_path11 = __toESM(require("path"));
5015
5085
  FARM_DOCS_LAST_MODIFIED_MANIFEST = ".farm-docs-last-modified.json";
5016
5086
  COMMIT_MARKER = "__FARM_DOCS_COMMIT__";
5017
5087
  DOCS_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdx"]);
@@ -5073,8 +5143,8 @@ var init_pixel_border_css = __esm({
5073
5143
  --scrollbar-thumb-hover: var(--color-fd-ring);
5074
5144
  --scrollbar-track: transparent;
5075
5145
  --radius: 0px;
5076
- --font-geist-sans: "Geist Sans";
5077
- --font-geist-mono: "Geist Mono";
5146
+ --font-geist-sans: ui-sans-serif, system-ui, sans-serif;
5147
+ --font-geist-mono: ui-monospace, monospace;
5078
5148
  }
5079
5149
 
5080
5150
  .dark {
@@ -5087,28 +5157,6 @@ body,
5087
5157
  background-color: var(--color-fd-background) !important;
5088
5158
  }
5089
5159
 
5090
- @font-face {
5091
- font-family: "Geist Sans";
5092
- font-display: block;
5093
- font-style: normal;
5094
- font-weight: 100 900;
5095
- src:
5096
- local("Geist Sans"),
5097
- url("/assets/Geist-Variable-CrgPqtmy.woff2") format("woff2"),
5098
- url("/node_modules/geist/dist/fonts/geist-sans/Geist-Variable.woff2") format("woff2");
5099
- }
5100
-
5101
- @font-face {
5102
- font-family: "Geist Mono";
5103
- font-display: block;
5104
- font-style: normal;
5105
- font-weight: 100 900;
5106
- src:
5107
- local("Geist Mono"),
5108
- url("/assets/GeistMono-Variable-BNLlm6Cd.woff2") format("woff2"),
5109
- url("/node_modules/geist/dist/fonts/geist-mono/GeistMono-Variable.woff2") format("woff2");
5110
- }
5111
-
5112
5160
  * {
5113
5161
  scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
5114
5162
  scrollbar-width: thin;
@@ -6315,10 +6363,10 @@ function isFarmDocsSearchEnabled(docs) {
6315
6363
  }
6316
6364
  function resolveFarmDocsSearchClientModule(root) {
6317
6365
  try {
6318
- const requireFromApp = (0, import_node_module4.createRequire)(import_node_path10.default.join(import_node_path10.default.resolve(root), "package.json"));
6366
+ const requireFromApp = (0, import_node_module4.createRequire)(import_node_path12.default.join(import_node_path12.default.resolve(root), "package.json"));
6319
6367
  const themeEntry = requireFromApp.resolve("@farming-labs/theme");
6320
- const commandSearchModule = import_node_path10.default.join(import_node_path10.default.dirname(themeEntry), "docs-command-search.mjs");
6321
- if ((0, import_node_fs7.existsSync)(commandSearchModule)) return commandSearchModule;
6368
+ const commandSearchModule = import_node_path12.default.join(import_node_path12.default.dirname(themeEntry), "docs-command-search.mjs");
6369
+ if ((0, import_node_fs8.existsSync)(commandSearchModule)) return commandSearchModule;
6322
6370
  } catch {
6323
6371
  }
6324
6372
  return void 0;
@@ -6457,13 +6505,13 @@ async function mountFarmDocsSearch() {
6457
6505
  window.__FARM_MOUNT_DOCS_SEARCH__ = mountFarmDocsSearch;
6458
6506
  `;
6459
6507
  }
6460
- var import_node_fs7, import_node_module4, import_node_path10;
6508
+ var import_node_fs8, import_node_module4, import_node_path12;
6461
6509
  var init_search_client = __esm({
6462
6510
  "src/docs/search-client.ts"() {
6463
6511
  "use strict";
6464
- import_node_fs7 = require("fs");
6512
+ import_node_fs8 = require("fs");
6465
6513
  import_node_module4 = require("module");
6466
- import_node_path10 = __toESM(require("path"));
6514
+ import_node_path12 = __toESM(require("path"));
6467
6515
  __name(isFarmDocsSearchEnabled, "isFarmDocsSearchEnabled");
6468
6516
  __name(resolveFarmDocsSearchClientModule, "resolveFarmDocsSearchClientModule");
6469
6517
  __name(generateFarmDocsSearchBootstrapRuntime, "generateFarmDocsSearchBootstrapRuntime");
@@ -6471,11 +6519,418 @@ var init_search_client = __esm({
6471
6519
  }
6472
6520
  });
6473
6521
 
6522
+ // src/docs/social-image.ts
6523
+ function normalizeEntry(entry) {
6524
+ if (!entry || entry === "/") return "";
6525
+ return `/${entry.replace(/^\/+|\/+$/g, "")}`;
6526
+ }
6527
+ function encodeSlugPath(slug) {
6528
+ return slug.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
6529
+ }
6530
+ function getSocialImageConfig(docs) {
6531
+ return typeof docs.config.socialImage === "object" && docs.config.socialImage ? docs.config.socialImage : void 0;
6532
+ }
6533
+ function getNavTitle(docs) {
6534
+ if (typeof docs.config.nav !== "object" || !docs.config.nav || !("title" in docs.config.nav)) {
6535
+ return "Farm.js";
6536
+ }
6537
+ return String(docs.config.nav.title || "Farm.js");
6538
+ }
6539
+ function isFalse(value) {
6540
+ return value ? /^(false|no|none|off|disabled)$/i.test(value.trim()) : false;
6541
+ }
6542
+ function isExternalOrRootPath(value) {
6543
+ return /^(https?:)?\/\//i.test(value) || value.startsWith("/");
6544
+ }
6545
+ function isFarmDocsSocialImageEnabled(page2, docs) {
6546
+ if (docs.config.socialImage === false || getSocialImageConfig(docs)?.enabled === false) {
6547
+ return false;
6548
+ }
6549
+ return !isFalse(page2.frontmatter.socialImage);
6550
+ }
6551
+ function getFarmDocsCustomSocialImage(page2) {
6552
+ const value = page2.frontmatter.socialImage || page2.frontmatter.openGraphImage || page2.frontmatter.ogImage;
6553
+ return value && !isFalse(value) && isExternalOrRootPath(value) ? value : void 0;
6554
+ }
6555
+ function resolveIllustration(page2) {
6556
+ const explicit = page2.frontmatter.socialIllustration?.toLowerCase();
6557
+ if (explicit === "auth" || explicit === "cache" || explicit === "cli" || explicit === "integrations" || explicit === "project" || explicit === "routing" || explicit === "runtime") {
6558
+ return explicit;
6559
+ }
6560
+ const source = `${page2.slug} ${page2.title} ${page2.section || ""}`.toLowerCase();
6561
+ if (/auth|session|security|csrf/.test(source)) return "auth";
6562
+ if (/cache|ppr|render|static|revalid|stream/.test(source)) return "cache";
6563
+ if (/integration|stripe|prisma|better.auth|email|job|workflow/.test(source)) {
6564
+ return "integrations";
6565
+ }
6566
+ if (/cli|test|deploy|preview|upgrade|migration|install/.test(source)) return "cli";
6567
+ if (/project|structure|config|environment|markdown|docs.engine/.test(source)) {
6568
+ return "project";
6569
+ }
6570
+ if (/rout|endpoint|middleware|navigation|server.function|server.action|api/.test(source)) {
6571
+ return "routing";
6572
+ }
6573
+ return "runtime";
6574
+ }
6575
+ function createHashValue(value) {
6576
+ return (0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 16);
6577
+ }
6578
+ function resolveBaseUrl(requestUrl, config) {
6579
+ return config?.baseUrl ? new URL(config.baseUrl) : new URL(requestUrl.origin);
6580
+ }
6581
+ function createFarmDocsSocialImageDescriptor(page2, docs, requestUrl) {
6582
+ const config = getSocialImageConfig(docs);
6583
+ const siteName = config?.siteName || getNavTitle(docs);
6584
+ const brand = config?.brand || siteName;
6585
+ const title = page2.frontmatter.socialTitle || page2.title;
6586
+ const description = page2.frontmatter.socialDescription || page2.description || docs.config.metadata?.description || `Documentation for ${siteName}`;
6587
+ const section = page2.frontmatter.section || page2.section || "Documentation";
6588
+ const illustration = resolveIllustration(page2);
6589
+ const entry = normalizeEntry(docs.entry);
6590
+ const slugPath = encodeSlugPath(page2.slug) || "index";
6591
+ const imagePath = `${entry}/_social/${slugPath}/opengraph-image.svg`;
6592
+ const baseUrl = resolveBaseUrl(requestUrl, config);
6593
+ const pageUrl = new URL(page2.href, baseUrl).href;
6594
+ const imageAlt = `${title} \u2014 ${siteName} documentation`;
6595
+ const hash = createHashValue({
6596
+ version: FARM_DOCS_SOCIAL_IMAGE_VERSION,
6597
+ title,
6598
+ description,
6599
+ section,
6600
+ siteName,
6601
+ brand,
6602
+ pageHref: page2.href,
6603
+ illustration,
6604
+ fonts: config?.fonts
6605
+ });
6606
+ return {
6607
+ title,
6608
+ description,
6609
+ section,
6610
+ siteName,
6611
+ brand,
6612
+ pageHref: page2.href,
6613
+ pageUrl,
6614
+ imagePath,
6615
+ imageUrl: new URL(`${imagePath}?v=${hash}`, baseUrl).href,
6616
+ imageAlt,
6617
+ illustration,
6618
+ fonts: config?.fonts,
6619
+ hash
6620
+ };
6621
+ }
6622
+ function getFarmDocsSocialImageSlug(docs, requestUrl) {
6623
+ const entry = normalizeEntry(docs.entry);
6624
+ const prefix = `${entry}/_social/`;
6625
+ const suffix = "/opengraph-image.svg";
6626
+ if (!requestUrl.pathname.startsWith(prefix) || !requestUrl.pathname.endsWith(suffix)) {
6627
+ return null;
6628
+ }
6629
+ const rawSlug = requestUrl.pathname.slice(prefix.length, -suffix.length);
6630
+ if (!rawSlug) return null;
6631
+ try {
6632
+ const slug = rawSlug.split("/").map((segment) => decodeURIComponent(segment)).join("/");
6633
+ if (slug.split("/").some((segment) => !segment || segment === ".." || segment === ".")) {
6634
+ return null;
6635
+ }
6636
+ return slug === "index" ? "" : slug;
6637
+ } catch {
6638
+ return null;
6639
+ }
6640
+ }
6641
+ function escapeXml(value) {
6642
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
6643
+ }
6644
+ function truncate(value, length) {
6645
+ if (value.length <= length) return value;
6646
+ return `${value.slice(0, Math.max(0, length - 1)).trimEnd()}\u2026`;
6647
+ }
6648
+ function wrapText(value, maxCharacters, maxLines) {
6649
+ const words = value.trim().split(/\s+/).filter(Boolean);
6650
+ const lines = [];
6651
+ let current = "";
6652
+ let consumedWords = 0;
6653
+ for (const word of words) {
6654
+ const candidate = current ? `${current} ${word}` : word;
6655
+ if (candidate.length <= maxCharacters || !current) {
6656
+ current = candidate;
6657
+ consumedWords += 1;
6658
+ continue;
6659
+ }
6660
+ lines.push(current);
6661
+ if (lines.length === maxLines) break;
6662
+ current = word;
6663
+ consumedWords += 1;
6664
+ }
6665
+ if (current && lines.length < maxLines) lines.push(current);
6666
+ if (consumedWords < words.length && lines.length) {
6667
+ lines[lines.length - 1] = truncate(`${lines[lines.length - 1]}\u2026`, maxCharacters);
6668
+ }
6669
+ return lines;
6670
+ }
6671
+ function renderTextLines(lines, x, y, lineHeight, attributes) {
6672
+ return lines.map(
6673
+ (line, index) => `<text x="${x}" y="${y + index * lineHeight}" ${attributes}>${escapeXml(line)}</text>`
6674
+ ).join("");
6675
+ }
6676
+ function renderEmbeddedFont(name, source, weight) {
6677
+ if (!source) return "";
6678
+ return `@font-face{font-family:"${name}";src:url("${escapeXml(source)}") format("woff2");font-style:normal;font-weight:${weight};font-display:block;}`;
6679
+ }
6680
+ function renderArrow(x1, y, x2, color = "#8b8b8b") {
6681
+ 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}"/>`;
6682
+ }
6683
+ function renderPanelHeader(label, status) {
6684
+ 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>`;
6685
+ }
6686
+ function renderRoutingIllustration() {
6687
+ return `${renderPanelHeader("ROUTE BLUEPRINT", "TYPED")}
6688
+ <rect x="819" y="296" width="92" height="54" fill="#a3a3a3"/>
6689
+ <text x="832" y="327" class="diagram-title ink">src/app</text>
6690
+ <path d="M911 323h41M952 232v181M952 232h44M952 323h44M952 413h44" fill="none" stroke="#696969"/>
6691
+ <rect x="996" y="205" width="138" height="54" fill="#0a0a0a" stroke="#414141"/>
6692
+ <text x="1010" y="228" class="diagram-title">/</text><text x="1010" y="246" class="micro">STATIC</text>
6693
+ <rect x="996" y="296" width="138" height="54" fill="#0a0a0a" stroke="#414141"/>
6694
+ <text x="1010" y="319" class="diagram-title">/blog/:slug</text><text x="1010" y="337" class="micro">DYNAMIC</text>
6695
+ <rect x="996" y="386" width="138" height="55" fill="#f0f0f0"/>
6696
+ <text x="1010" y="410" class="diagram-title ink">/docs/:path*</text><text x="1010" y="428" class="micro ink-muted">CATCH-ALL</text>
6697
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
6698
+ <text x="819" y="475" class="label bright">FILE ROUTES</text><text x="1134" y="475" class="label" text-anchor="end">TYPES INCLUDED</text>`;
6699
+ }
6700
+ function renderAuthIllustration() {
6701
+ return `${renderPanelHeader("REQUEST GUARD", "SERVER VERIFIED")}
6702
+ <rect x="819" y="269" width="86" height="54" fill="#0a0a0a" stroke="#454545"/>
6703
+ <text x="837" y="292" class="micro bright">REQUEST</text><text x="837" y="310" class="diagram-title">GET /app</text>
6704
+ ${renderArrow(905, 296, 943)}
6705
+ <rect x="943" y="224" width="104" height="118" fill="#f0f0f0"/>
6706
+ <path d="M974 271v-12a21 21 0 0 1 42 0v12M968 271h54v45h-54z" fill="#050505"/>
6707
+ <circle cx="995" cy="292" r="4" fill="#f0f0f0"/><path d="M995 296v8" stroke="#f0f0f0" stroke-width="3"/>
6708
+ <text x="995" y="332" class="micro ink" text-anchor="middle">auth()</text>
6709
+ ${renderArrow(1047, 296, 1071)}
6710
+ <rect x="1071" y="269" width="63" height="54" fill="#0a0a0a" stroke="#454545"/>
6711
+ <text x="1082" y="292" class="micro bright">ALLOW</text><text x="1082" y="310" class="micro">/app</text>
6712
+ <rect x="819" y="372" width="315" height="38" fill="#090909" stroke="#3d3d3d"/>
6713
+ <rect x="832" y="385" width="11" height="11" fill="#a3a3a3"/>
6714
+ <text x="856" y="395" class="code">session.user / verified</text>
6715
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
6716
+ <text x="819" y="475" class="label bright">SESSION TYPED</text><text x="1134" y="475" class="label" text-anchor="end">CSRF PROTECTED</text>`;
6717
+ }
6718
+ function renderCacheIllustration() {
6719
+ return `${renderPanelHeader("PAGE / PRODUCT", "CACHE + PPR")}
6720
+ <rect x="819" y="204" width="315" height="54" fill="#f0f0f0"/>
6721
+ <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>
6722
+ <rect x="819" y="271" width="198" height="76" fill="#a3a3a3"/>
6723
+ <text x="836" y="301" class="diagram-title ink">CACHED DATA</text><text x="836" y="326" class="micro ink-muted">tag: products</text>
6724
+ <rect x="1029" y="271" width="105" height="76" fill="#0a0a0a" stroke="#555"/>
6725
+ <text x="1045" y="301" class="diagram-title">LIVE</text><text x="1045" y="326" class="micro">stream</text>
6726
+ <path d="M1081 347v43m-8-9 8 9 8-9" fill="none" stroke="#d4d4d4"/>
6727
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
6728
+ <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>`;
6729
+ }
6730
+ function renderIntegrationsIllustration() {
6731
+ return `${renderPanelHeader("INTEGRATION GRAPH", "ONE PRODUCT")}
6732
+ <path d="M976 309H879V247M976 309H879v87M1030 309h93V247M1030 309h93v87" fill="none" stroke="#4a4a4a"/>
6733
+ <rect x="819" y="214" width="120" height="57" fill="#0a0a0a" stroke="#4b4b4b"/><text x="839" y="247" class="diagram-title">BETTER AUTH</text>
6734
+ <rect x="819" y="368" width="120" height="57" fill="#0a0a0a" stroke="#4b4b4b"/><text x="851" y="401" class="diagram-title">PRISMA</text>
6735
+ <rect x="1061" y="214" width="73" height="57" fill="#0a0a0a" stroke="#4b4b4b"/><text x="1077" y="247" class="diagram-title">STRIPE</text>
6736
+ <rect x="1061" y="368" width="73" height="57" fill="#a3a3a3"/><text x="1075" y="401" class="diagram-title ink">VERCEL</text>
6737
+ <rect x="976" y="277" width="94" height="64" fill="#f0f0f0"/>
6738
+ <text x="994" y="304" class="diagram-title ink">FARM.JS</text><text x="994" y="324" class="micro ink-muted">CORE</text>
6739
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
6740
+ <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>`;
6741
+ }
6742
+ function renderCliIllustration() {
6743
+ return `${renderPanelHeader("TERMINAL", "PRODUCTION OUTPUT")}
6744
+ <rect x="819" y="203" width="315" height="213" fill="#050505" stroke="#555"/>
6745
+ <line x1="819" y1="236" x2="1134" y2="236" stroke="#555"/>
6746
+ <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"/>
6747
+ <text x="837" y="273" class="code bright"><tspan fill="#7a7a7a">$</tspan> farm build</text>
6748
+ <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"/>
6749
+ <text x="861" y="303" class="code">64 routes discovered</text>
6750
+ <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"/>
6751
+ <text x="861" y="330" class="code">client + server bundles</text>
6752
+ <rect x="837" y="355" width="126" height="30" fill="#f0f0f0"/><text x="853" y="374" class="micro ink">BUILD COMPLETE</text>
6753
+ <text x="1115" y="374" class="micro" text-anchor="end">/dist</text>
6754
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
6755
+ <text x="819" y="475" class="label bright">REAL COMMANDS</text><text x="1134" y="475" class="label" text-anchor="end">842MS</text>`;
6756
+ }
6757
+ function renderProjectIllustration() {
6758
+ return `${renderPanelHeader("PROJECT MAP", "CONVENTION TYPED")}
6759
+ <rect x="819" y="202" width="315" height="216" fill="#050505" stroke="#555"/>
6760
+ <text x="837" y="227" class="diagram-title bright">my-app/</text>
6761
+ <path d="M847 243v143M847 259h23M847 293h23M847 327h23M847 361h23" fill="none" stroke="#666"/>
6762
+ <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>
6763
+ <rect x="870" y="277" width="246" height="33" fill="#f0f0f0"/><text x="886" y="298" class="code ink">src/app/page.tsx</text>
6764
+ <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>
6765
+ <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>
6766
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
6767
+ <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>`;
6768
+ }
6769
+ function renderRuntimeIllustration() {
6770
+ return `${renderPanelHeader("PRODUCT ARCHITECTURE", "FULL STACK")}
6771
+ <rect x="819" y="211" width="315" height="55" fill="#f0f0f0"/>
6772
+ <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>
6773
+ <path d="M976 266v20m0 61v20" stroke="#727272"/>
6774
+ <rect x="855" y="286" width="242" height="61" fill="#a3a3a3"/>
6775
+ <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>
6776
+ <rect x="819" y="367" width="315" height="55" fill="#4c4c4c"/>
6777
+ <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>
6778
+ <line x1="819" y1="450" x2="1134" y2="450" stroke="#343434"/>
6779
+ <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>`;
6780
+ }
6781
+ function renderIllustration(type) {
6782
+ switch (type) {
6783
+ case "auth":
6784
+ return renderAuthIllustration();
6785
+ case "cache":
6786
+ return renderCacheIllustration();
6787
+ case "cli":
6788
+ return renderCliIllustration();
6789
+ case "integrations":
6790
+ return renderIntegrationsIllustration();
6791
+ case "project":
6792
+ return renderProjectIllustration();
6793
+ case "routing":
6794
+ return renderRoutingIllustration();
6795
+ default:
6796
+ return renderRuntimeIllustration();
6797
+ }
6798
+ }
6799
+ function renderFarmDocsSocialImageSvg(descriptor) {
6800
+ const titleLines = wrapText(descriptor.title, 22, 2);
6801
+ const longestTitleLine = Math.max(...titleLines.map((line) => line.length));
6802
+ const titleSize = titleLines.length === 1 ? longestTitleLine > 17 ? 62 : 74 : 56;
6803
+ const titleLineHeight = Math.round(titleSize * 0.98);
6804
+ const titleY = titleLines.length === 1 ? 294 : 266;
6805
+ const descriptionY = titleY + (titleLines.length - 1) * titleLineHeight + 59;
6806
+ const descriptionLines = wrapText(descriptor.description, 68, 2);
6807
+ const routeY = Math.max(418, descriptionY + descriptionLines.length * 29 + 24);
6808
+ const section = truncate(descriptor.section.toUpperCase(), 27);
6809
+ const route = truncate(descriptor.pageHref, 42);
6810
+ const footerUrl = truncate(descriptor.pageUrl.replace(/^https?:\/\//, ""), 70);
6811
+ const brand = truncate(descriptor.brand.toUpperCase(), 25);
6812
+ const titleId = `farm-docs-og-${descriptor.hash}`;
6813
+ return `<?xml version="1.0" encoding="UTF-8"?>
6814
+ <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">
6815
+ <title id="${titleId}-title">${escapeXml(descriptor.imageAlt)}</title>
6816
+ <desc id="${titleId}-description">${escapeXml(descriptor.description)}</desc>
6817
+ <metadata>${escapeXml(JSON.stringify({ generator: "Farm.js docs", page: descriptor.pageUrl, illustration: descriptor.illustration }))}</metadata>
6818
+ <style type="text/css">
6819
+ ${renderEmbeddedFont("Farm Sans", descriptor.fonts?.sans, "100 900")}
6820
+ ${renderEmbeddedFont("Farm Mono", descriptor.fonts?.mono, "100 900")}
6821
+ ${renderEmbeddedFont("Farm Pixel", descriptor.fonts?.display, "400 700")}
6822
+ .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}
6823
+ </style>
6824
+ <defs>
6825
+ <pattern id="canvas-grid" width="40" height="40" patternUnits="userSpaceOnUse"><path d="M40 0H0V40" fill="none" stroke="#151515"/></pattern>
6826
+ <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>
6827
+ <clipPath id="frame-clip"><rect x="28" y="28" width="1144" height="574"/></clipPath>
6828
+ </defs>
6829
+ <rect width="1200" height="630" fill="#050505"/>
6830
+ <rect width="1200" height="630" fill="url(#canvas-grid)"/>
6831
+ <g clip-path="url(#frame-clip)">
6832
+ <rect x="28" y="28" width="1144" height="574" fill="#020202"/>
6833
+ <rect x="782" y="114" width="390" height="411" fill="url(#diagonal)"/>
6834
+ </g>
6835
+ <rect x="28.5" y="28.5" width="1143" height="573" fill="none" stroke="#323232"/>
6836
+ <path d="M28 114.5h1144M28 525.5h1144M781.5 114v411" fill="none" stroke="#303030"/>
6837
+
6838
+ <g transform="translate(71 51)">
6839
+ <rect width="11" height="11" rx="1" fill="#f5f5f4"/><rect x="15" width="28" height="11" rx="1" fill="#f5f5f4"/>
6840
+ <rect y="15" width="11" height="11" rx="1" fill="#9b9b9b"/><rect x="15" y="15" width="28" height="11" rx="1" fill="#9b9b9b"/>
6841
+ <rect y="30" width="11" height="11" rx="1" fill="#5f5f5f"/><rect x="15" y="30" width="20" height="11" rx="1" fill="#5f5f5f"/>
6842
+ <text x="61" y="24" class="mono bright" font-size="24" font-weight="550">FARM<tspan fill="#777">.JS</tspan></text>
6843
+ <text x="61" y="43" class="label">BY FARMING LABS</text>
6844
+ </g>
6845
+ <text x="1134" y="72" class="label" text-anchor="end">${escapeXml(brand)} \xB7 DOCUMENTATION</text>
6846
+
6847
+ <text x="71" y="198" class="mono bright" font-size="13" font-weight="650">DOCS</text>
6848
+ <line x1="117" y1="193" x2="155" y2="193" stroke="#696969"/>
6849
+ <text x="166" y="198" class="mono" fill="#9b9b9b" font-size="13">${escapeXml(section)}</text>
6850
+ ${renderTextLines(titleLines, 71, titleY, titleLineHeight, `class="pixel bright" font-size="${titleSize}" font-weight="500" letter-spacing="-2.4"`)}
6851
+ ${renderTextLines(descriptionLines, 71, descriptionY, 29, 'class="sans" fill="#a3a3a3" font-size="20" font-weight="430" letter-spacing="-.3"')}
6852
+ <rect x="71" y="${routeY}" width="${Math.min(390, 56 + route.length * 8)}" height="36" fill="#050505" stroke="#3c3c3c"/>
6853
+ <text x="85" y="${routeY + 23}" class="mono bright" font-size="11" font-weight="600">GET</text>
6854
+ <text x="119" y="${routeY + 23}" class="mono" fill="#898989" font-size="11">${escapeXml(route)}</text>
6855
+
6856
+ ${renderIllustration(descriptor.illustration)}
6857
+
6858
+ <text x="71" y="570" class="mono bright" font-size="13" font-weight="550">${escapeXml(footerUrl)}</text>
6859
+ <text x="1134" y="570" class="mono" fill="#9b9b9b" font-size="12" text-anchor="end">FARM.JS DOCUMENTATION</text>
6860
+ <path d="M20 20h10M20 20v10M1180 20h-10M1180 20v10M20 610h10M20 610v-10M1180 610h-10M1180 610v-10" fill="none" stroke="#9b9b9b"/>
6861
+ </svg>`;
6862
+ }
6863
+ function renderFarmDocsSocialMetadata(descriptor, customImage) {
6864
+ const imageUrl = customImage ? new URL(customImage, descriptor.pageUrl).href : descriptor.imageUrl;
6865
+ const customExtension = customImage?.toLowerCase().split(/[?#]/, 1)[0];
6866
+ const imageType = customExtension?.endsWith(".webp") ? "image/webp" : customExtension?.endsWith(".png") ? "image/png" : customExtension?.match(/\.jpe?g$/) ? "image/jpeg" : "image/svg+xml";
6867
+ const tag = /* @__PURE__ */ __name((property, content, name = false) => `<meta ${name ? "name" : "property"}="${property}" content="${escapeXml(content)}">`, "tag");
6868
+ return [
6869
+ tag("og:type", "article"),
6870
+ tag("og:site_name", descriptor.siteName),
6871
+ tag("og:title", descriptor.title),
6872
+ tag("og:description", descriptor.description),
6873
+ tag("og:url", descriptor.pageUrl),
6874
+ tag("og:image", imageUrl),
6875
+ tag("og:image:type", imageType),
6876
+ ...customImage ? [] : [
6877
+ tag("og:image:width", String(FARM_DOCS_SOCIAL_IMAGE_WIDTH)),
6878
+ tag("og:image:height", String(FARM_DOCS_SOCIAL_IMAGE_HEIGHT))
6879
+ ],
6880
+ tag("og:image:alt", descriptor.imageAlt),
6881
+ tag("twitter:card", "summary_large_image", true),
6882
+ tag("twitter:title", descriptor.title, true),
6883
+ tag("twitter:description", descriptor.description, true),
6884
+ tag("twitter:image", imageUrl, true),
6885
+ tag("twitter:image:alt", descriptor.imageAlt, true)
6886
+ ].join("\n ");
6887
+ }
6888
+ var import_node_crypto4, FARM_DOCS_SOCIAL_IMAGE_WIDTH, FARM_DOCS_SOCIAL_IMAGE_HEIGHT, FARM_DOCS_SOCIAL_IMAGE_VERSION;
6889
+ var init_social_image = __esm({
6890
+ "src/docs/social-image.ts"() {
6891
+ "use strict";
6892
+ import_node_crypto4 = require("crypto");
6893
+ FARM_DOCS_SOCIAL_IMAGE_WIDTH = 1200;
6894
+ FARM_DOCS_SOCIAL_IMAGE_HEIGHT = 630;
6895
+ FARM_DOCS_SOCIAL_IMAGE_VERSION = 3;
6896
+ __name(normalizeEntry, "normalizeEntry");
6897
+ __name(encodeSlugPath, "encodeSlugPath");
6898
+ __name(getSocialImageConfig, "getSocialImageConfig");
6899
+ __name(getNavTitle, "getNavTitle");
6900
+ __name(isFalse, "isFalse");
6901
+ __name(isExternalOrRootPath, "isExternalOrRootPath");
6902
+ __name(isFarmDocsSocialImageEnabled, "isFarmDocsSocialImageEnabled");
6903
+ __name(getFarmDocsCustomSocialImage, "getFarmDocsCustomSocialImage");
6904
+ __name(resolveIllustration, "resolveIllustration");
6905
+ __name(createHashValue, "createHashValue");
6906
+ __name(resolveBaseUrl, "resolveBaseUrl");
6907
+ __name(createFarmDocsSocialImageDescriptor, "createFarmDocsSocialImageDescriptor");
6908
+ __name(getFarmDocsSocialImageSlug, "getFarmDocsSocialImageSlug");
6909
+ __name(escapeXml, "escapeXml");
6910
+ __name(truncate, "truncate");
6911
+ __name(wrapText, "wrapText");
6912
+ __name(renderTextLines, "renderTextLines");
6913
+ __name(renderEmbeddedFont, "renderEmbeddedFont");
6914
+ __name(renderArrow, "renderArrow");
6915
+ __name(renderPanelHeader, "renderPanelHeader");
6916
+ __name(renderRoutingIllustration, "renderRoutingIllustration");
6917
+ __name(renderAuthIllustration, "renderAuthIllustration");
6918
+ __name(renderCacheIllustration, "renderCacheIllustration");
6919
+ __name(renderIntegrationsIllustration, "renderIntegrationsIllustration");
6920
+ __name(renderCliIllustration, "renderCliIllustration");
6921
+ __name(renderProjectIllustration, "renderProjectIllustration");
6922
+ __name(renderRuntimeIllustration, "renderRuntimeIllustration");
6923
+ __name(renderIllustration, "renderIllustration");
6924
+ __name(renderFarmDocsSocialImageSvg, "renderFarmDocsSocialImageSvg");
6925
+ __name(renderFarmDocsSocialMetadata, "renderFarmDocsSocialMetadata");
6926
+ }
6927
+ });
6928
+
6474
6929
  // src/docs/handler.ts
6475
6930
  function trimSlashes2(value) {
6476
6931
  return value.replace(/^\/+|\/+$/g, "");
6477
6932
  }
6478
- function normalizeEntry(entry) {
6933
+ function normalizeEntry2(entry) {
6479
6934
  if (!entry || entry === "/") return "/";
6480
6935
  return `/${trimSlashes2(entry)}`;
6481
6936
  }
@@ -6487,10 +6942,10 @@ function resolveFarmDocsFavicon(docs, options) {
6487
6942
  if (typeof configuredFavicon === "string" && configuredFavicon.trim()) {
6488
6943
  return configuredFavicon.trim();
6489
6944
  }
6490
- const publicDir = import_node_path11.default.join(import_node_path11.default.resolve(options.root), "public");
6945
+ const publicDir = import_node_path13.default.join(import_node_path13.default.resolve(options.root), "public");
6491
6946
  for (const fileName of FARM_DOCS_FAVICON_FILES) {
6492
- const faviconPath = import_node_path11.default.join(publicDir, fileName);
6493
- if ((0, import_node_fs8.existsSync)(faviconPath) && (0, import_node_fs8.statSync)(faviconPath).isFile()) {
6947
+ const faviconPath = import_node_path13.default.join(publicDir, fileName);
6948
+ if ((0, import_node_fs9.existsSync)(faviconPath) && (0, import_node_fs9.statSync)(faviconPath).isFile()) {
6494
6949
  return `/${fileName}`;
6495
6950
  }
6496
6951
  }
@@ -6524,10 +6979,10 @@ function isSafeSegment(segment) {
6524
6979
  return segment !== ".." && !segment.includes("/") && !segment.includes("\\");
6525
6980
  }
6526
6981
  function resolveInside(root, target) {
6527
- const resolvedRoot = import_node_path11.default.resolve(root);
6528
- const resolvedTarget = import_node_path11.default.resolve(target);
6529
- const relative4 = import_node_path11.default.relative(resolvedRoot, resolvedTarget);
6530
- if (relative4 === "" || !relative4.startsWith("..") && !import_node_path11.default.isAbsolute(relative4)) {
6982
+ const resolvedRoot = import_node_path13.default.resolve(root);
6983
+ const resolvedTarget = import_node_path13.default.resolve(target);
6984
+ const relative4 = import_node_path13.default.relative(resolvedRoot, resolvedTarget);
6985
+ if (relative4 === "" || !relative4.startsWith("..") && !import_node_path13.default.isAbsolute(relative4)) {
6531
6986
  return resolvedTarget;
6532
6987
  }
6533
6988
  return null;
@@ -6536,36 +6991,36 @@ function isFarmDocsRequest(docs, request) {
6536
6991
  if (!docs?.enabled) return false;
6537
6992
  if (request.method !== "GET" && request.method !== "HEAD") return false;
6538
6993
  const pathname = new URL(request.url).pathname;
6539
- const entry = normalizeEntry(docs.entry);
6994
+ const entry = normalizeEntry2(docs.entry);
6540
6995
  if (entry === "/") return true;
6541
6996
  return pathname === entry || pathname === `${entry}.md` || pathname.startsWith(`${entry}/`);
6542
6997
  }
6543
6998
  function resolveFarmDocsContentDir(docs, options) {
6544
- const root = import_node_path11.default.resolve(options.root);
6999
+ const root = import_node_path13.default.resolve(options.root);
6545
7000
  const srcDir = options.srcDir || "src";
6546
7001
  const configuredContentDir = docs.contentDir || docs.config.contentDir;
6547
7002
  if (configuredContentDir) {
6548
- return import_node_path11.default.isAbsolute(configuredContentDir) ? configuredContentDir : import_node_path11.default.join(root, configuredContentDir);
7003
+ return import_node_path13.default.isAbsolute(configuredContentDir) ? configuredContentDir : import_node_path13.default.join(root, configuredContentDir);
6549
7004
  }
6550
7005
  const entryDir = docs.config.entry || trimSlashes2(docs.entry) || "docs";
6551
- const appDocsDir = import_node_path11.default.join(root, srcDir, "app", entryDir);
6552
- if ((0, import_node_fs8.existsSync)(appDocsDir)) return appDocsDir;
6553
- return import_node_path11.default.join(root, entryDir);
7006
+ const appDocsDir = import_node_path13.default.join(root, srcDir, "app", entryDir);
7007
+ if ((0, import_node_fs9.existsSync)(appDocsDir)) return appDocsDir;
7008
+ return import_node_path13.default.join(root, entryDir);
6554
7009
  }
6555
7010
  function getFarmDocsRouteTypeEntries(docs) {
6556
7011
  if (!docs?.enabled) return [];
6557
- const entry = normalizeEntry(docs.entry);
7012
+ const entry = normalizeEntry2(docs.entry);
6558
7013
  if (entry === "/") return ["/", "/[...docs]"];
6559
7014
  return [entry, `${entry}/[...docs]`];
6560
7015
  }
6561
7016
  function getFarmDocsDocumentNavigationMatchers(docs) {
6562
7017
  if (!docs?.enabled) return [];
6563
- const entry = normalizeEntry(docs.entry);
7018
+ const entry = normalizeEntry2(docs.entry);
6564
7019
  return [entry === "/" ? "/(.*)" : `${entry}(.*)`];
6565
7020
  }
6566
7021
  function getRequestSlug(docs, request) {
6567
7022
  const pathname = new URL(request.url).pathname;
6568
- const entry = normalizeEntry(docs.entry);
7023
+ const entry = normalizeEntry2(docs.entry);
6569
7024
  if (entry === "/") return normalizeSlug(pathname);
6570
7025
  if (pathname === entry || pathname === `${entry}.md`) return "";
6571
7026
  return normalizeSlug(pathname.slice(entry.length));
@@ -6573,14 +7028,14 @@ function getRequestSlug(docs, request) {
6573
7028
  function findDocsPageFile(contentDir, slug) {
6574
7029
  const segments = slug ? slug.split("/").filter(Boolean) : [];
6575
7030
  if (!segments.every(isSafeSegment)) return null;
6576
- const slugDir = import_node_path11.default.join(contentDir, ...segments);
6577
- const candidates = segments.length === 0 ? DOCS_FILE_NAMES.map((filename) => import_node_path11.default.join(contentDir, filename)) : [
6578
- ...DOCS_FILE_NAMES.map((filename) => import_node_path11.default.join(slugDir, filename)),
6579
- ...DOCS_FILE_EXTENSIONS2.map((extension) => import_node_path11.default.join(contentDir, `${slug}${extension}`))
7031
+ const slugDir = import_node_path13.default.join(contentDir, ...segments);
7032
+ const candidates = segments.length === 0 ? DOCS_FILE_NAMES.map((filename) => import_node_path13.default.join(contentDir, filename)) : [
7033
+ ...DOCS_FILE_NAMES.map((filename) => import_node_path13.default.join(slugDir, filename)),
7034
+ ...DOCS_FILE_EXTENSIONS2.map((extension) => import_node_path13.default.join(contentDir, `${slug}${extension}`))
6580
7035
  ];
6581
7036
  for (const candidate of candidates) {
6582
7037
  const safePath = resolveInside(contentDir, candidate);
6583
- if (safePath && (0, import_node_fs8.existsSync)(safePath) && (0, import_node_fs8.statSync)(safePath).isFile()) {
7038
+ if (safePath && (0, import_node_fs9.existsSync)(safePath) && (0, import_node_fs9.statSync)(safePath).isFile()) {
6584
7039
  return safePath;
6585
7040
  }
6586
7041
  }
@@ -6615,7 +7070,7 @@ function titleFromMarkdown2(body, fallback) {
6615
7070
  function loadFarmDocsPage(contentDir, docs, slug) {
6616
7071
  const sourcePath = findDocsPageFile(contentDir, slug);
6617
7072
  if (!sourcePath) return null;
6618
- const source = (0, import_node_fs8.readFileSync)(sourcePath, "utf8");
7073
+ const source = (0, import_node_fs9.readFileSync)(sourcePath, "utf8");
6619
7074
  const { frontmatter, body } = parseFrontmatter(source);
6620
7075
  const title = frontmatter.title || titleFromMarkdown2(body, titleFromSlug(slug));
6621
7076
  const href = createDocsHref(docs.entry, slug);
@@ -6623,6 +7078,7 @@ function loadFarmDocsPage(contentDir, docs, slug) {
6623
7078
  slug,
6624
7079
  title,
6625
7080
  description: frontmatter.description,
7081
+ section: frontmatter.section,
6626
7082
  href,
6627
7083
  sourcePath,
6628
7084
  lastModified: resolveFarmDocsPageLastModified(contentDir, sourcePath, frontmatter),
@@ -6631,15 +7087,15 @@ function loadFarmDocsPage(contentDir, docs, slug) {
6631
7087
  };
6632
7088
  }
6633
7089
  function createDocsHref(entry, slug) {
6634
- const normalizedEntry = normalizeEntry(entry);
7090
+ const normalizedEntry = normalizeEntry2(entry);
6635
7091
  const normalizedSlug = trimSlashes2(slug);
6636
7092
  if (normalizedEntry === "/") return normalizedSlug ? `/${normalizedSlug}` : "/";
6637
7093
  return normalizedSlug ? `${normalizedEntry}/${normalizedSlug}` : normalizedEntry;
6638
7094
  }
6639
7095
  function pathToSlug(contentDir, filePath) {
6640
- const relative4 = import_node_path11.default.relative(contentDir, filePath).replace(/\\/g, "/");
7096
+ const relative4 = import_node_path13.default.relative(contentDir, filePath).replace(/\\/g, "/");
6641
7097
  if (relative4.startsWith("..")) return null;
6642
- const extension = import_node_path11.default.extname(relative4);
7098
+ const extension = import_node_path13.default.extname(relative4);
6643
7099
  if (!DOCS_FILE_EXTENSIONS2.includes(extension)) return null;
6644
7100
  const withoutExtension = relative4.slice(0, -extension.length);
6645
7101
  if (withoutExtension === "page" || withoutExtension === "index") return "";
@@ -6652,12 +7108,12 @@ function loadPage(contentDir, docs, request) {
6652
7108
  return loadFarmDocsPage(contentDir, docs, getRequestSlug(docs, request));
6653
7109
  }
6654
7110
  function discoverFarmDocsPages(contentDir, docs) {
6655
- if (!(0, import_node_fs8.existsSync)(contentDir)) return [];
7111
+ if (!(0, import_node_fs9.existsSync)(contentDir)) return [];
6656
7112
  const pages = [];
6657
7113
  const visit = /* @__PURE__ */ __name((dir) => {
6658
- for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
7114
+ for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
6659
7115
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
6660
- const absolutePath = import_node_path11.default.join(dir, entry.name);
7116
+ const absolutePath = import_node_path13.default.join(dir, entry.name);
6661
7117
  if (entry.isDirectory()) {
6662
7118
  visit(absolutePath);
6663
7119
  continue;
@@ -6665,7 +7121,7 @@ function discoverFarmDocsPages(contentDir, docs) {
6665
7121
  if (!entry.isFile()) continue;
6666
7122
  const slug = pathToSlug(contentDir, absolutePath);
6667
7123
  if (slug === null) continue;
6668
- const source = (0, import_node_fs8.readFileSync)(absolutePath, "utf8");
7124
+ const source = (0, import_node_fs9.readFileSync)(absolutePath, "utf8");
6669
7125
  const { frontmatter, body } = parseFrontmatter(source);
6670
7126
  pages.push({
6671
7127
  slug,
@@ -7443,7 +7899,7 @@ function renderPixelBreadcrumb(page2, docs) {
7443
7899
  const parentSegments = segments.slice(0, -1);
7444
7900
  const parentSegment = parentSegments[parentSegments.length - 1];
7445
7901
  const currentSegment = segments[segments.length - 1];
7446
- const entry = normalizeEntry(docs.entry);
7902
+ const entry = normalizeEntry2(docs.entry);
7447
7903
  const parentPath = parentSegments.join("/");
7448
7904
  const parentHref = entry === "/" ? `/${parentPath}` : `${entry}/${parentPath}`;
7449
7905
  return `<nav class="fd-breadcrumb" aria-label="Breadcrumb">
@@ -7481,7 +7937,7 @@ ${items.map(
7481
7937
  </div>`;
7482
7938
  }
7483
7939
  function renderDocsRuntimeScript(docs) {
7484
- const docsEntry = JSON.stringify(normalizeEntry(docs.entry));
7940
+ const docsEntry = JSON.stringify(normalizeEntry2(docs.entry));
7485
7941
  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>`;
7486
7942
  }
7487
7943
  function renderDocsPageActionsRuntimeScript() {
@@ -7496,13 +7952,13 @@ ${renderDocsHashRuntimeScript()}
7496
7952
  ${renderDocsPageActionsRuntimeScript()}`;
7497
7953
  }
7498
7954
  function readCssWithImports(filePath, seen = /* @__PURE__ */ new Set()) {
7499
- const resolved = import_node_path11.default.resolve(filePath);
7955
+ const resolved = import_node_path13.default.resolve(filePath);
7500
7956
  if (seen.has(resolved)) return "";
7501
7957
  seen.add(resolved);
7502
- const source = (0, import_node_fs8.readFileSync)(resolved, "utf8");
7958
+ const source = (0, import_node_fs9.readFileSync)(resolved, "utf8");
7503
7959
  return source.replace(/@import\s+["']([^"']+)["'];?/g, (_match, importPath) => {
7504
7960
  try {
7505
- const importedPath = importPath.startsWith(".") ? import_node_path11.default.resolve(import_node_path11.default.dirname(resolved), importPath) : (0, import_node_module5.createRequire)(resolved).resolve(importPath);
7961
+ const importedPath = importPath.startsWith(".") ? import_node_path13.default.resolve(import_node_path13.default.dirname(resolved), importPath) : (0, import_node_module5.createRequire)(resolved).resolve(importPath);
7506
7962
  return readCssWithImports(importedPath, seen);
7507
7963
  } catch {
7508
7964
  return "";
@@ -7510,11 +7966,11 @@ function readCssWithImports(filePath, seen = /* @__PURE__ */ new Set()) {
7510
7966
  });
7511
7967
  }
7512
7968
  function resolvePixelBorderThemeCss(options) {
7513
- const cacheKey = import_node_path11.default.resolve(options.root);
7969
+ const cacheKey = import_node_path13.default.resolve(options.root);
7514
7970
  const cached = themeCssCache.get(cacheKey);
7515
7971
  if (cached !== void 0) return cached;
7516
7972
  try {
7517
- const requireFromApp = (0, import_node_module5.createRequire)(import_node_path11.default.join(cacheKey, "package.json"));
7973
+ const requireFromApp = (0, import_node_module5.createRequire)(import_node_path13.default.join(cacheKey, "package.json"));
7518
7974
  const themeCssPath = requireFromApp.resolve("@farming-labs/theme/pixel-border/css");
7519
7975
  const requireFromTheme = (0, import_node_module5.createRequire)(themeCssPath);
7520
7976
  const fumadocsCssPath = requireFromTheme.resolve("fumadocs-ui/style.css");
@@ -7527,17 +7983,28 @@ ${readCssWithImports(themeCssPath)}`;
7527
7983
  return "";
7528
7984
  }
7529
7985
  }
7530
- function renderFarmDocsBridgeCss(docs) {
7986
+ function renderFarmDocsBridgeCss(docs, fontAssets, layoutFonts) {
7531
7987
  const sidebarWidth = getThemeLayoutValue(docs, "sidebarWidth", 320);
7532
7988
  const contentWidth = getThemeLayoutValue(docs, "contentWidth", 860);
7989
+ const fontFaces = fontAssets.map(
7990
+ ({ family, url }) => `@font-face { font-family: "${family}"; src: url("${url}") format("woff2"); font-style: normal; font-weight: 100 900; font-display: block; }`
7991
+ ).join("\n");
7992
+ const fontVariables = [
7993
+ fontAssets.some(({ family }) => family === "Geist Sans") ? '--font-geist-sans: "Geist Sans", ui-sans-serif, system-ui, sans-serif;' : "",
7994
+ fontAssets.some(({ family }) => family === "Geist Mono") ? '--font-geist-mono: "Geist Mono", ui-monospace, monospace;' : ""
7995
+ ].filter(Boolean).join(" ");
7996
+ const fontCss = fontFaces ? `${fontFaces}
7997
+ :root { ${fontVariables} }` : "";
7998
+ const layoutFontVariables = [
7999
+ renderFarmDocsLayoutFontVariable("--fd-layout-font-body", layoutFonts?.body),
8000
+ renderFarmDocsLayoutFontVariable("--fd-layout-font-code", layoutFonts?.code)
8001
+ ].filter(Boolean).join(" ");
7533
8002
  return `
7534
- @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; }
7535
- @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; }
7536
- :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); }
8003
+ :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); }
7537
8004
  * { box-sizing: border-box; }
7538
8005
  html { background: var(--color-fd-background, hsl(0 0% 2%)); scroll-padding-top: calc(var(--fd-nav-height, 44px) + 24px); }
7539
8006
  html[data-farm-docs-sidebar="open"], html[data-farm-docs-sidebar="open"] body { overflow: hidden; }
7540
- 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; }
8007
+ 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; }
7541
8008
  ::selection { background: var(--color-fd-foreground, #fff); color: var(--color-fd-background, #000); }
7542
8009
  a { color: inherit; }
7543
8010
  #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%)); }
@@ -7717,14 +8184,45 @@ function renderFarmDocsBridgeCss(docs) {
7717
8184
  .sh__line { min-height: 1.6em; }
7718
8185
  }
7719
8186
  ${farmDocsPixelBorderCss}
8187
+ ${fontCss}
7720
8188
  `;
7721
8189
  }
7722
- function renderPixelDocsHtml(page2, pages, docs, themeCss, clientEntry, faviconHref) {
8190
+ function renderFarmDocsLayoutFontVariable(name, font) {
8191
+ const family = font?.style.fontFamily;
8192
+ if (!family || /[;{}<>]/.test(family)) return "";
8193
+ return `${name}: ${family};`;
8194
+ }
8195
+ function renderFarmDocsFontPreloads(fontAssets) {
8196
+ return fontAssets.map(
8197
+ ({ url }) => `<link rel="preload" href="${escapeAttribute2(url)}" as="font" type="font/woff2" crossorigin>`
8198
+ ).join("\n ");
8199
+ }
8200
+ function renderFarmDocsFontPreloadHeader(fontAssets) {
8201
+ return fontAssets.map(({ url }) => `<${url}>; rel=preload; as=font; type=font/woff2; crossorigin`).join(", ");
8202
+ }
8203
+ function getFarmLayoutFontPreloads(layoutFonts) {
8204
+ const seen = /* @__PURE__ */ new Set();
8205
+ return [layoutFonts?.body, layoutFonts?.code].flatMap(
8206
+ (font) => (font?.preloads || []).filter(({ href }) => {
8207
+ if (seen.has(href)) return false;
8208
+ seen.add(href);
8209
+ return true;
8210
+ })
8211
+ );
8212
+ }
8213
+ function renderFarmLayoutFontPreloadHeader(layoutFonts) {
8214
+ return getFarmLayoutFontPreloads(layoutFonts).map(({ href, type }) => `<${href}>; rel=preload; as=font; type=${type}; crossorigin`).join(", ");
8215
+ }
8216
+ function renderPixelDocsHtml(page2, pages, docs, themeCss, clientEntry, faviconHref, requestUrl, fontAssets, layoutFonts, fontStylesheetHref) {
7723
8217
  const navTitle = typeof docs.config.nav === "object" && docs.config.nav && "title" in docs.config.nav ? String(docs.config.nav.title || "Docs") : "Docs";
7724
8218
  const description = page2.description || docs.config.metadata?.description || "";
7725
8219
  const tocItems = extractTocItems(page2.body, getThemeTocDepth(docs));
7726
8220
  const themeName = getThemeName(docs);
7727
8221
  const searchEnabled = isFarmDocsSearchEnabled(docs);
8222
+ const socialMetadata = isFarmDocsSocialImageEnabled(page2, docs) ? renderFarmDocsSocialMetadata(
8223
+ createFarmDocsSocialImageDescriptor(page2, docs, requestUrl),
8224
+ getFarmDocsCustomSocialImage(page2)
8225
+ ) : "";
7728
8226
  return `<!DOCTYPE html>
7729
8227
  <html class="dark" lang="en" data-docs-theme="${escapeAttribute2(themeName)}">
7730
8228
  <head>
@@ -7733,11 +8231,12 @@ function renderPixelDocsHtml(page2, pages, docs, themeCss, clientEntry, faviconH
7733
8231
  <meta name="generator" content="@farming-labs/docs via Farm.js">
7734
8232
  <title>${escapeHtml(page2.title)}</title>
7735
8233
  ${renderFarmDocsFaviconLink(faviconHref)}
7736
- <link rel="preload" href="${GEIST_SANS_FONT_URL}" as="font" type="font/woff2" crossorigin>
7737
- <link rel="preload" href="${GEIST_MONO_FONT_URL}" as="font" type="font/woff2" crossorigin>
8234
+ ${renderFarmDocsFontPreloads(fontAssets)}
8235
+ ${fontStylesheetHref ? `<link rel="stylesheet" href="${escapeAttribute2(fontStylesheetHref)}">` : ""}
7738
8236
  ${description ? `<meta name="description" content="${escapeHtml(description)}">` : ""}
8237
+ ${socialMetadata}
7739
8238
  <style>${themeCss}
7740
- ${renderFarmDocsBridgeCss(docs)}</style>
8239
+ ${renderFarmDocsBridgeCss(docs, fontAssets, layoutFonts)}</style>
7741
8240
  ${searchEnabled ? renderDocsSearchBootstrapScript() : ""}
7742
8241
  </head>
7743
8242
  <body>
@@ -7789,9 +8288,34 @@ ${renderMarkdownHtmlWithTitleMeta(page2, docs)}
7789
8288
  }
7790
8289
  function createFarmDocsHandler(docs, options) {
7791
8290
  const faviconHref = resolveFarmDocsFavicon(docs, options);
8291
+ const fontAssets = options.fontAssets ?? toFarmDocsPublicFontAssets(resolveFarmDocsFontAssets(options.root));
8292
+ const fallbackFontPreloadHeader = renderFarmDocsFontPreloadHeader(fontAssets);
7792
8293
  return /* @__PURE__ */ __name(async function handleFarmDocsRequest(request) {
7793
8294
  if (!docs?.enabled || request.method !== "GET" && request.method !== "HEAD") return null;
7794
8295
  const contentDir = resolveFarmDocsContentDir(docs, options);
8296
+ const requestUrl = new URL(request.url);
8297
+ const socialImageSlug = getFarmDocsSocialImageSlug(docs, requestUrl);
8298
+ if (socialImageSlug !== null) {
8299
+ const socialImagePage = loadFarmDocsPage(contentDir, docs, socialImageSlug);
8300
+ if (!socialImagePage || !isFarmDocsSocialImageEnabled(socialImagePage, docs) || getFarmDocsCustomSocialImage(socialImagePage)) {
8301
+ return null;
8302
+ }
8303
+ const descriptor = createFarmDocsSocialImageDescriptor(socialImagePage, docs, requestUrl);
8304
+ if (requestUrl.pathname !== descriptor.imagePath) return null;
8305
+ const etag = `"${descriptor.hash}"`;
8306
+ const immutable = requestUrl.searchParams.get("v") === descriptor.hash;
8307
+ const headers = new Headers({
8308
+ "Content-Type": "image/svg+xml; charset=utf-8",
8309
+ "Cache-Control": immutable ? "public, max-age=31536000, immutable" : "public, max-age=0, must-revalidate",
8310
+ ETag: etag,
8311
+ "X-Content-Type-Options": "nosniff"
8312
+ });
8313
+ if (request.headers.get("if-none-match") === etag) {
8314
+ return new Response(null, { status: 304, headers });
8315
+ }
8316
+ if (request.method === "HEAD") return new Response(null, { status: 200, headers });
8317
+ return new Response(renderFarmDocsSocialImageSvg(descriptor), { status: 200, headers });
8318
+ }
7795
8319
  const publicResponse = createFarmDocsPublicResponse(contentDir, docs, request);
7796
8320
  if (publicResponse) return publicResponse;
7797
8321
  if (!isFarmDocsRequest(docs, request)) return null;
@@ -7814,6 +8338,11 @@ function createFarmDocsHandler(docs, options) {
7814
8338
  }
7815
8339
  );
7816
8340
  }
8341
+ const pathname = new URL(request.url).pathname;
8342
+ const layoutFonts = await options.resolveLayoutFonts?.(pathname);
8343
+ const usesLayoutFonts = Boolean(layoutFonts?.body || layoutFonts?.code);
8344
+ const activeFontAssets = usesLayoutFonts ? [] : fontAssets;
8345
+ const fontPreloadHeader = usesLayoutFonts ? renderFarmLayoutFontPreloadHeader(layoutFonts) : fallbackFontPreloadHeader;
7817
8346
  return new Response(
7818
8347
  renderPixelDocsHtml(
7819
8348
  page2,
@@ -7821,39 +8350,44 @@ function createFarmDocsHandler(docs, options) {
7821
8350
  docs,
7822
8351
  resolvePixelBorderThemeCss(options),
7823
8352
  options.clientEntry || "/farm-client.js",
7824
- faviconHref
8353
+ faviconHref,
8354
+ requestUrl,
8355
+ activeFontAssets,
8356
+ layoutFonts,
8357
+ usesLayoutFonts ? options.fontStylesheetHref : void 0
7825
8358
  ),
7826
8359
  {
7827
8360
  status: 200,
7828
8361
  headers: {
7829
8362
  "Content-Type": "text/html; charset=utf-8",
7830
- "Cache-Control": "public, s-maxage=60, stale-while-revalidate=300"
8363
+ "Cache-Control": "public, s-maxage=60, stale-while-revalidate=300",
8364
+ ...fontPreloadHeader ? { Link: fontPreloadHeader } : {}
7831
8365
  }
7832
8366
  }
7833
8367
  );
7834
8368
  }, "handleFarmDocsRequest");
7835
8369
  }
7836
- 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;
8370
+ 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;
7837
8371
  var init_handler = __esm({
7838
8372
  "src/docs/handler.ts"() {
7839
8373
  "use strict";
7840
- import_node_fs8 = require("fs");
8374
+ import_node_fs9 = require("fs");
7841
8375
  import_node_module5 = require("module");
7842
- import_node_path11 = __toESM(require("path"));
8376
+ import_node_path13 = __toESM(require("path"));
7843
8377
  import_docs = require("@farming-labs/docs");
7844
8378
  import_marked = require("marked");
7845
8379
  import_sugar_high = require("sugar-high");
8380
+ init_fonts();
7846
8381
  init_last_modified();
7847
8382
  init_pixel_border_css();
7848
8383
  init_search_client();
8384
+ init_social_image();
7849
8385
  DOCS_FILE_NAMES = ["page.mdx", "page.md", "index.mdx", "index.md"];
7850
8386
  DOCS_FILE_EXTENSIONS2 = [".mdx", ".md"];
7851
8387
  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";
7852
8388
  FARM_DOCS_FAVICON_FILES = ["favicon.svg", "favicon.ico", "favicon.png"];
7853
- GEIST_SANS_FONT_URL = "/assets/Geist-Variable-CrgPqtmy.woff2";
7854
- GEIST_MONO_FONT_URL = "/assets/GeistMono-Variable-BNLlm6Cd.woff2";
7855
8389
  __name(trimSlashes2, "trimSlashes");
7856
- __name(normalizeEntry, "normalizeEntry");
8390
+ __name(normalizeEntry2, "normalizeEntry");
7857
8391
  __name(normalizeSlug, "normalizeSlug");
7858
8392
  __name(resolveFarmDocsFavicon, "resolveFarmDocsFavicon");
7859
8393
  __name(renderFarmDocsFaviconLink, "renderFarmDocsFaviconLink");
@@ -8043,6 +8577,11 @@ var init_handler = __esm({
8043
8577
  __name(readCssWithImports, "readCssWithImports");
8044
8578
  __name(resolvePixelBorderThemeCss, "resolvePixelBorderThemeCss");
8045
8579
  __name(renderFarmDocsBridgeCss, "renderFarmDocsBridgeCss");
8580
+ __name(renderFarmDocsLayoutFontVariable, "renderFarmDocsLayoutFontVariable");
8581
+ __name(renderFarmDocsFontPreloads, "renderFarmDocsFontPreloads");
8582
+ __name(renderFarmDocsFontPreloadHeader, "renderFarmDocsFontPreloadHeader");
8583
+ __name(getFarmLayoutFontPreloads, "getFarmLayoutFontPreloads");
8584
+ __name(renderFarmLayoutFontPreloadHeader, "renderFarmLayoutFontPreloadHeader");
8046
8585
  __name(renderPixelDocsHtml, "renderPixelDocsHtml");
8047
8586
  __name(createFarmDocsHandler, "createFarmDocsHandler");
8048
8587
  }
@@ -8227,18 +8766,18 @@ function sanitizeDocsConfig(config) {
8227
8766
  return cloneSerializable(config) || {};
8228
8767
  }
8229
8768
  async function findDocsConfigPath(rootDir, configPath) {
8230
- const { existsSync: existsSync15 } = await import("fs");
8769
+ const { existsSync: existsSync16 } = await import("fs");
8231
8770
  const root = import_path9.default.resolve(rootDir || process.cwd());
8232
8771
  if (configPath) {
8233
8772
  const resolvedPath = import_path9.default.isAbsolute(configPath) ? configPath : import_path9.default.join(root, configPath);
8234
- if (!existsSync15(resolvedPath)) {
8773
+ if (!existsSync16(resolvedPath)) {
8235
8774
  throw new Error(`Could not find docs config at ${configPath}.`);
8236
8775
  }
8237
8776
  return import_path9.default.resolve(resolvedPath);
8238
8777
  }
8239
8778
  for (const filename of DOCS_CONFIG_FILENAMES) {
8240
8779
  const resolvedPath = import_path9.default.join(root, filename);
8241
- if (existsSync15(resolvedPath)) {
8780
+ if (existsSync16(resolvedPath)) {
8242
8781
  return resolvedPath;
8243
8782
  }
8244
8783
  }
@@ -8374,6 +8913,7 @@ var init_config2 = __esm({
8374
8913
  init_image_config();
8375
8914
  init_config();
8376
8915
  init_auth_config();
8916
+ init_preload();
8377
8917
  init_config_entry();
8378
8918
  __name(getDeployTargetForPreset, "getDeployTargetForPreset");
8379
8919
  DOCS_CONFIG_FILENAMES = [
@@ -9162,8 +9702,8 @@ var init_generator = __esm({
9162
9702
  }
9163
9703
  routeGroups.get(key).push(route);
9164
9704
  }
9165
- for (const [path24, routeList] of routeGroups) {
9166
- const openAPIPath = this.convertToOpenAPIPath(path24);
9705
+ for (const [path26, routeList] of routeGroups) {
9706
+ const openAPIPath = this.convertToOpenAPIPath(path26);
9167
9707
  spec.paths[openAPIPath] = {};
9168
9708
  for (const route of routeList) {
9169
9709
  for (const method of route.methods) {
@@ -9177,8 +9717,8 @@ var init_generator = __esm({
9177
9717
  /**
9178
9718
  * Convert Farm.js API path to OpenAPI path format
9179
9719
  */
9180
- convertToOpenAPIPath(path24) {
9181
- return path24.replace(/^\/api/, "");
9720
+ convertToOpenAPIPath(path26) {
9721
+ return path26.replace(/^\/api/, "");
9182
9722
  }
9183
9723
  /**
9184
9724
  * Extract request body schema from endpoint
@@ -9340,8 +9880,8 @@ var init_generator = __esm({
9340
9880
  /**
9341
9881
  * Generate operation summary
9342
9882
  */
9343
- generateSummary(path24, method) {
9344
- const cleanPath = path24.replace(/^\/api\//, "");
9883
+ generateSummary(path26, method) {
9884
+ const cleanPath = path26.replace(/^\/api\//, "");
9345
9885
  const pathParts = cleanPath.split("/");
9346
9886
  const lastPart = pathParts[pathParts.length - 1];
9347
9887
  const action = method === "GET" ? "Get" : method === "POST" ? "Create" : method === "PUT" ? "Update" : method === "DELETE" ? "Delete" : method === "PATCH" ? "Update" : method;
@@ -9350,22 +9890,22 @@ var init_generator = __esm({
9350
9890
  /**
9351
9891
  * Generate operation description
9352
9892
  */
9353
- generateDescription(path24, method) {
9354
- const cleanPath = path24.replace(/^\/api\//, "");
9893
+ generateDescription(path26, method) {
9894
+ const cleanPath = path26.replace(/^\/api\//, "");
9355
9895
  return `${method} ${cleanPath} endpoint`;
9356
9896
  }
9357
9897
  /**
9358
9898
  * Generate operation ID
9359
9899
  */
9360
- generateOperationId(path24, method) {
9361
- const cleanPath = path24.replace(/^\/api\//, "").replace(/\//g, "_");
9900
+ generateOperationId(path26, method) {
9901
+ const cleanPath = path26.replace(/^\/api\//, "").replace(/\//g, "_");
9362
9902
  return `${method.toLowerCase()}_${cleanPath}`;
9363
9903
  }
9364
9904
  /**
9365
9905
  * Generate tags for grouping operations
9366
9906
  */
9367
- generateTags(path24) {
9368
- const cleanPath = path24.replace(/^\/api\//, "");
9907
+ generateTags(path26) {
9908
+ const cleanPath = path26.replace(/^\/api\//, "");
9369
9909
  const pathParts = cleanPath.split("/");
9370
9910
  if (pathParts.length > 1) {
9371
9911
  return [pathParts[0]];
@@ -9378,8 +9918,8 @@ var init_generator = __esm({
9378
9918
  async generateSpecFile(routes, outputPath) {
9379
9919
  const spec = await this.generateSpec(routes);
9380
9920
  const fs8 = require("fs");
9381
- const path24 = require("path");
9382
- const dir = path24.dirname(outputPath);
9921
+ const path26 = require("path");
9922
+ const dir = path26.dirname(outputPath);
9383
9923
  if (!fs8.existsSync(dir)) {
9384
9924
  fs8.mkdirSync(dir, { recursive: true });
9385
9925
  }
@@ -9799,7 +10339,7 @@ async function createFarmDevtoolsSnapshot(input) {
9799
10339
  generatedAt: (input.now?.() || /* @__PURE__ */ new Date()).toISOString(),
9800
10340
  health: resolveHealth(diagnostics),
9801
10341
  project: {
9802
- name: import_node_path12.default.basename(import_node_path12.default.resolve(input.root)),
10342
+ name: import_node_path14.default.basename(import_node_path14.default.resolve(input.root)),
9803
10343
  root: input.root,
9804
10344
  srcDir: input.srcDir,
9805
10345
  basePath: config.basePath || "/",
@@ -9848,11 +10388,11 @@ async function createFarmDevtoolsSnapshot(input) {
9848
10388
  diagnostics
9849
10389
  };
9850
10390
  }
9851
- var import_node_path12;
10391
+ var import_node_path14;
9852
10392
  var init_devtools = __esm({
9853
10393
  "src/devtools.ts"() {
9854
10394
  "use strict";
9855
- import_node_path12 = __toESM(require("path"));
10395
+ import_node_path14 = __toESM(require("path"));
9856
10396
  init_config2();
9857
10397
  init_cron();
9858
10398
  init_route_runtime();
@@ -11810,6 +12350,22 @@ var import_promises3 = require("fs/promises");
11810
12350
  var OPTIONAL_CATCH_ALL_SEGMENT = /^\[\[\.\.\.([^\]]+)\]\]$/;
11811
12351
  var REQUIRED_CATCH_ALL_SEGMENT = /^\[\.\.\.([^\]]+)\]$/;
11812
12352
  var REQUIRED_DYNAMIC_SEGMENT = /^\[([^\]]+)\]$/;
12353
+ var REQUEST_API_LABELS = /* @__PURE__ */ new Map([
12354
+ ["cookies", "request cookies"],
12355
+ ["headers", "request headers"],
12356
+ ["getCurrentRequest", "the current Request"],
12357
+ ["useSearchParams", "URL search parameters"],
12358
+ ["auth", "request authentication"],
12359
+ ["getServerSession", "request authentication"],
12360
+ ["getSession", "request authentication"],
12361
+ ["currentUser", "request authentication"]
12362
+ ]);
12363
+ var ROUTE_PROP_LABELS = /* @__PURE__ */ new Map([
12364
+ ["searchParams", "URL search parameters"],
12365
+ ["middleware", "middleware request data"],
12366
+ ["middlewareData", "middleware request data"],
12367
+ ["context", "request context"]
12368
+ ]);
11813
12369
  function resolveRouteRenderingConfig(mod, source) {
11814
12370
  const directiveConfig = parseRouteRenderingDirective(source);
11815
12371
  let ssg = directiveConfig?.ssg ?? false;
@@ -11862,6 +12418,221 @@ async function resolveRouteRenderingConfigFromFile(mod, filePath) {
11862
12418
  return resolveRouteRenderingConfig(mod, source);
11863
12419
  }
11864
12420
  __name(resolveRouteRenderingConfigFromFile, "resolveRouteRenderingConfigFromFile");
12421
+ function analyzeStaticRouteCandidate(mod, source, options = {}) {
12422
+ const blockers = [];
12423
+ if (!source) {
12424
+ blockers.push("route source is unavailable");
12425
+ }
12426
+ if (options.isDynamic) {
12427
+ blockers.push("the route has dynamic path segments");
12428
+ }
12429
+ if (hasExplicitRenderingConfig(mod, source)) {
12430
+ blockers.push("the route already has explicit rendering config");
12431
+ }
12432
+ if (source) {
12433
+ blockers.push(...findRequestBoundSourceBlockers(source));
12434
+ }
12435
+ return {
12436
+ candidate: blockers.length === 0,
12437
+ blockers
12438
+ };
12439
+ }
12440
+ __name(analyzeStaticRouteCandidate, "analyzeStaticRouteCandidate");
12441
+ function findRequestBoundSourceBlockers(source) {
12442
+ const blockers = /* @__PURE__ */ new Set();
12443
+ const code = stripCommentsAndLiteralContents(source);
12444
+ const sourceWithoutComments = stripComments(source);
12445
+ for (const binding of readRequestApiImportBindings(sourceWithoutComments)) {
12446
+ if (new RegExp(`\\b${escapeRegExp2(binding.local)}\\s*(?:\\?\\.\\s*)?\\(`).test(code)) {
12447
+ blockers.add(`the route reads ${binding.label}`);
12448
+ }
12449
+ }
12450
+ for (const namespace of readNamespaceImportBindings(sourceWithoutComments)) {
12451
+ for (const [name, label] of REQUEST_API_LABELS) {
12452
+ if (new RegExp(
12453
+ `\\b${escapeRegExp2(namespace)}\\s*(?:\\?\\.\\s*|\\.\\s*)${name}\\s*(?:\\?\\.\\s*)?\\(`
12454
+ ).test(code)) {
12455
+ blockers.add(`the route reads ${label}`);
12456
+ }
12457
+ }
12458
+ }
12459
+ const params = readDefaultRouteParameters(code);
12460
+ if (params) {
12461
+ for (const [name, label] of ROUTE_PROP_LABELS) {
12462
+ if (new RegExp(`\\b${name}\\b`).test(params)) {
12463
+ blockers.add(`the route reads ${label}`);
12464
+ }
12465
+ }
12466
+ const propsName = params.match(/^\s*([A-Za-z_$][\w$]*)\s*(?::|,|$)/)?.[1];
12467
+ if (propsName) {
12468
+ for (const [name, label] of ROUTE_PROP_LABELS) {
12469
+ if (new RegExp(`\\b${escapeRegExp2(propsName)}\\s*\\.\\s*${name}\\b`).test(code)) {
12470
+ blockers.add(`the route reads ${label}`);
12471
+ }
12472
+ if (new RegExp(`\\{[^}]*\\b${name}\\b[^}]*\\}\\s*=\\s*${escapeRegExp2(propsName)}\\b`).test(
12473
+ code
12474
+ )) {
12475
+ blockers.add(`the route reads ${label}`);
12476
+ }
12477
+ }
12478
+ }
12479
+ }
12480
+ return [...blockers];
12481
+ }
12482
+ __name(findRequestBoundSourceBlockers, "findRequestBoundSourceBlockers");
12483
+ function readRequestApiImportBindings(source) {
12484
+ const bindings = [];
12485
+ for (const clause of readStaticImportClauses(source)) {
12486
+ const namedGroup = clause.match(/\{([\s\S]*?)\}/)?.[1];
12487
+ for (const rawSpecifier of (namedGroup ?? "").split(",")) {
12488
+ const specifier = rawSpecifier.trim().replace(/^type\s+/, "");
12489
+ const imported = specifier.match(/^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/);
12490
+ if (!imported?.[1]) continue;
12491
+ const label = REQUEST_API_LABELS.get(imported[1]);
12492
+ if (label) bindings.push({ local: imported[2] ?? imported[1], label });
12493
+ }
12494
+ const local = clause.match(/^\s*([A-Za-z_$][\w$]*)\s*(?:,|$)/)?.[1];
12495
+ if (local) {
12496
+ const label = REQUEST_API_LABELS.get(local);
12497
+ if (label) bindings.push({ local, label });
12498
+ }
12499
+ }
12500
+ return bindings;
12501
+ }
12502
+ __name(readRequestApiImportBindings, "readRequestApiImportBindings");
12503
+ function readNamespaceImportBindings(source) {
12504
+ return readStaticImportClauses(source).map((clause) => clause.match(/\*\s*as\s*([A-Za-z_$][\w$]*)/)?.[1]).filter((binding) => Boolean(binding));
12505
+ }
12506
+ __name(readNamespaceImportBindings, "readNamespaceImportBindings");
12507
+ function readStaticImportClauses(source) {
12508
+ return [...source.matchAll(/\bimport\s+(?!\()([\s\S]*?)\s+from\s*["'][^"']+["']/g)].map((match) => match[1]).filter((clause) => Boolean(clause));
12509
+ }
12510
+ __name(readStaticImportClauses, "readStaticImportClauses");
12511
+ function readDefaultRouteParameters(code) {
12512
+ const inlineParams = code.match(/\bexport\s+default\s+(?:async\s+)?function\b[^(]*\(([^)]*)\)/)?.[1] ?? code.match(/\bexport\s+default\s+(?:async\s+)?\(([^)]*)\)\s*=>/)?.[1];
12513
+ if (inlineParams !== void 0) return inlineParams;
12514
+ 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];
12515
+ if (!binding) return void 0;
12516
+ const escapedBinding = escapeRegExp2(binding);
12517
+ return code.match(new RegExp(`\\bfunction\\s+${escapedBinding}\\s*\\(([^)]*)\\)`))?.[1] ?? code.match(
12518
+ new RegExp(
12519
+ `\\b(?:const|let|var)\\s+${escapedBinding}\\s*=\\s*(?:async\\s+)?\\(([^)]*)\\)\\s*=>`
12520
+ )
12521
+ )?.[1] ?? code.match(
12522
+ new RegExp(`\\b(?:const|let|var)\\s+${escapedBinding}\\s*=\\s*function\\s*\\(([^)]*)\\)`)
12523
+ )?.[1];
12524
+ }
12525
+ __name(readDefaultRouteParameters, "readDefaultRouteParameters");
12526
+ function stripCommentsAndLiteralContents(source) {
12527
+ return sanitizeSource(source, true);
12528
+ }
12529
+ __name(stripCommentsAndLiteralContents, "stripCommentsAndLiteralContents");
12530
+ function stripComments(source) {
12531
+ return sanitizeSource(source, false);
12532
+ }
12533
+ __name(stripComments, "stripComments");
12534
+ function sanitizeSource(source, maskLiterals) {
12535
+ const output = [...source];
12536
+ const mask = /* @__PURE__ */ __name((index) => {
12537
+ if (output[index] !== "\n" && output[index] !== "\r") output[index] = " ";
12538
+ }, "mask");
12539
+ const scanQuoted = /* @__PURE__ */ __name((start, quote) => {
12540
+ let index = start;
12541
+ if (maskLiterals) mask(index);
12542
+ index += 1;
12543
+ while (index < source.length) {
12544
+ if (source[index] === "\\") {
12545
+ if (maskLiterals) mask(index);
12546
+ if (index + 1 < source.length && maskLiterals) mask(index + 1);
12547
+ index += 2;
12548
+ continue;
12549
+ }
12550
+ const character = source[index];
12551
+ if (maskLiterals) mask(index);
12552
+ index += 1;
12553
+ if (character === quote) break;
12554
+ }
12555
+ return index;
12556
+ }, "scanQuoted");
12557
+ const scanCode = /* @__PURE__ */ __name((start, stopAtTemplateBrace) => {
12558
+ let index = start;
12559
+ let braceDepth = 0;
12560
+ while (index < source.length) {
12561
+ const character = source[index];
12562
+ const next = source[index + 1];
12563
+ if (character === "/" && next === "/") {
12564
+ while (index < source.length && source[index] !== "\n" && source[index] !== "\r") {
12565
+ mask(index++);
12566
+ }
12567
+ continue;
12568
+ }
12569
+ if (character === "/" && next === "*") {
12570
+ mask(index++);
12571
+ mask(index++);
12572
+ while (index < source.length) {
12573
+ const closesComment = source[index] === "*" && source[index + 1] === "/";
12574
+ mask(index++);
12575
+ if (closesComment) {
12576
+ mask(index++);
12577
+ break;
12578
+ }
12579
+ }
12580
+ continue;
12581
+ }
12582
+ if (character === "'" || character === '"') {
12583
+ index = scanQuoted(index, character);
12584
+ continue;
12585
+ }
12586
+ if (character === "`") {
12587
+ if (maskLiterals) mask(index);
12588
+ index += 1;
12589
+ while (index < source.length) {
12590
+ if (source[index] === "\\") {
12591
+ if (maskLiterals) mask(index);
12592
+ if (index + 1 < source.length && maskLiterals) mask(index + 1);
12593
+ index += 2;
12594
+ } else if (source[index] === "`") {
12595
+ if (maskLiterals) mask(index);
12596
+ index += 1;
12597
+ break;
12598
+ } else if (source[index] === "$" && source[index + 1] === "{") {
12599
+ if (maskLiterals) {
12600
+ mask(index);
12601
+ mask(index + 1);
12602
+ }
12603
+ index = scanCode(index + 2, true);
12604
+ } else {
12605
+ if (maskLiterals) mask(index);
12606
+ index += 1;
12607
+ }
12608
+ }
12609
+ continue;
12610
+ }
12611
+ if (character === "{") {
12612
+ braceDepth += 1;
12613
+ } else if (character === "}") {
12614
+ if (stopAtTemplateBrace && braceDepth === 0) {
12615
+ if (maskLiterals) mask(index);
12616
+ return index + 1;
12617
+ }
12618
+ braceDepth = Math.max(0, braceDepth - 1);
12619
+ }
12620
+ index += 1;
12621
+ }
12622
+ return index;
12623
+ }, "scanCode");
12624
+ scanCode(0, false);
12625
+ return output.join("");
12626
+ }
12627
+ __name(sanitizeSource, "sanitizeSource");
12628
+ function escapeRegExp2(value) {
12629
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12630
+ }
12631
+ __name(escapeRegExp2, "escapeRegExp");
12632
+ function hasExplicitRenderingConfig(mod, source) {
12633
+ 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";
12634
+ }
12635
+ __name(hasExplicitRenderingConfig, "hasExplicitRenderingConfig");
11865
12636
  function parseRouteRenderingDirective(source) {
11866
12637
  if (!source) {
11867
12638
  return void 0;
@@ -11993,9 +12764,10 @@ function skipHorizontalWhitespace(source, start) {
11993
12764
  return index;
11994
12765
  }
11995
12766
  __name(skipHorizontalWhitespace, "skipHorizontalWhitespace");
11996
- async function collectSSGPages(routes, loadModule2) {
12767
+ async function collectSSGPages(routes, loadModule2, options = {}) {
11997
12768
  const ssgPages = [];
11998
12769
  const ssrRoutes = [];
12770
+ const staticCandidateRoutes = [];
11999
12771
  for (const route of routes) {
12000
12772
  try {
12001
12773
  const mod = await loadModule2(route.filePath);
@@ -12003,7 +12775,8 @@ async function collectSSGPages(routes, loadModule2) {
12003
12775
  ssrRoutes.push(route.path);
12004
12776
  continue;
12005
12777
  }
12006
- const rendering = await resolveRouteRenderingConfigFromFile(mod, route.filePath);
12778
+ const source = await (0, import_promises3.readFile)(route.filePath, "utf8").catch(() => void 0);
12779
+ const rendering = resolveRouteRenderingConfig(mod, source);
12007
12780
  if (rendering.ssg) {
12008
12781
  if (route.isDynamic) {
12009
12782
  const getStaticPaths = mod.getStaticPaths || mod.generateStaticParams;
@@ -12030,12 +12803,26 @@ async function collectSSGPages(routes, loadModule2) {
12030
12803
  }
12031
12804
  } else {
12032
12805
  ssrRoutes.push(route.path);
12806
+ if (options.suggestStaticRendering !== false && analyzeStaticRouteCandidate(mod, source, { isDynamic: route.isDynamic }).candidate) {
12807
+ staticCandidateRoutes.push(route.path);
12808
+ }
12033
12809
  }
12034
12810
  } catch (error) {
12035
12811
  console.error(`Error processing route ${route.path}:`, error);
12036
12812
  ssrRoutes.push(route.path);
12037
12813
  }
12038
12814
  }
12815
+ if (staticCandidateRoutes.length > 0) {
12816
+ const visibleRoutes = staticCandidateRoutes.slice(0, 10);
12817
+ const remainingCount = staticCandidateRoutes.length - visibleRoutes.length;
12818
+ const remainingSuffix = remainingCount > 0 ? `
12819
+ \u2026and ${remainingCount} more` : "";
12820
+ console.warn(
12821
+ `[Farm.js] ${staticCandidateRoutes.length} route${staticCandidateRoutes.length === 1 ? " appears" : "s appear"} eligible for static rendering:
12822
+ ${visibleRoutes.join("\n ")}${remainingSuffix}
12823
+ Add \`export const dynamic = "force-static";\` after verifying that imported code does not read cookies, headers, authentication, or other request data.`
12824
+ );
12825
+ }
12039
12826
  return { ssg: ssgPages, ssr: ssrRoutes };
12040
12827
  }
12041
12828
  __name(collectSSGPages, "collectSSGPages");
@@ -12798,25 +13585,25 @@ function defineRoutes(input) {
12798
13585
  }
12799
13586
  __name(defineRoutes, "defineRoutes");
12800
13587
  var routesBuilder = {
12801
- page(path24, options) {
13588
+ page(path26, options) {
12802
13589
  return normalizeProgrammaticRoute({
12803
13590
  kind: "page",
12804
- path: path24,
13591
+ path: path26,
12805
13592
  ...options
12806
13593
  });
12807
13594
  },
12808
- layout(path24, options) {
13595
+ layout(path26, options) {
12809
13596
  return normalizeProgrammaticRoute({
12810
13597
  kind: "layout",
12811
- path: path24,
13598
+ path: path26,
12812
13599
  ...options
12813
13600
  });
12814
13601
  },
12815
- api(path24, options) {
13602
+ api(path26, options) {
12816
13603
  const { render, runtime, regions, maxDuration, ...methods } = options;
12817
13604
  return normalizeProgrammaticRoute({
12818
13605
  kind: "api",
12819
- path: path24,
13606
+ path: path26,
12820
13607
  render,
12821
13608
  runtime,
12822
13609
  regions,
@@ -12852,7 +13639,7 @@ function getProgrammaticRouteSearchClientOptions(search) {
12852
13639
  return Object.keys(options).length > 0 ? options : void 0;
12853
13640
  }
12854
13641
  __name(getProgrammaticRouteSearchClientOptions, "getProgrammaticRouteSearchClientOptions");
12855
- function resolveProgrammaticRouteSearch(searchConfig, rawSearch, path24, routePath) {
13642
+ function resolveProgrammaticRouteSearch(searchConfig, rawSearch, path26, routePath) {
12856
13643
  const schema = getProgrammaticRouteSearchSchema(searchConfig);
12857
13644
  const search = parseProgrammaticSchema(schema, rawSearch, "search", routePath);
12858
13645
  const options = getProgrammaticRouteSearchOptions(searchConfig);
@@ -12861,7 +13648,7 @@ function resolveProgrammaticRouteSearch(searchConfig, rawSearch, path24, routePa
12861
13648
  schema,
12862
13649
  rawSearch,
12863
13650
  parsedSearch: search,
12864
- path: path24
13651
+ path: path26
12865
13652
  });
12866
13653
  return { search, canonicalPath };
12867
13654
  }
@@ -13044,7 +13831,7 @@ function createRouteModuleFromProgrammaticPage(route) {
13044
13831
  mod.__farmRouteData = route.data;
13045
13832
  mod.__farmRouteParsesProps = true;
13046
13833
  mod.__farmResolveRouteProps = (props) => resolveProgrammaticRouteProps(route, props);
13047
- mod.__farmResolveRouteCanonicalPath = (rawSearch, path24) => resolveProgrammaticRouteSearch(route.search, rawSearch, path24, route.path).canonicalPath;
13834
+ mod.__farmResolveRouteCanonicalPath = (rawSearch, path26) => resolveProgrammaticRouteSearch(route.search, rawSearch, path26, route.path).canonicalPath;
13048
13835
  }
13049
13836
  if (route.pending || route.error || route.notFound) {
13050
13837
  mod.__farmRouteComponents = {
@@ -13520,6 +14307,15 @@ var import_path5 = __toESM(require("path"));
13520
14307
  var import_fs2 = __toESM(require("fs"));
13521
14308
  var import_path4 = __toESM(require("path"));
13522
14309
  var import_url2 = require("url");
14310
+
14311
+ // src/island.ts
14312
+ var FARM_ISLAND_STRATEGIES = ["load", "interaction", "visible", "idle"];
14313
+ function isFarmIslandStrategy(value) {
14314
+ return FARM_ISLAND_STRATEGIES.includes(value);
14315
+ }
14316
+ __name(isFarmIslandStrategy, "isFarmIslandStrategy");
14317
+
14318
+ // src/utils/client-component.ts
13523
14319
  function readIfExists(filePath) {
13524
14320
  try {
13525
14321
  if (!filePath || !import_fs2.default.existsSync(filePath)) {
@@ -13590,56 +14386,186 @@ function hasHydrateExport(content) {
13590
14386
  return /\bexport\s+const\s+hydrate\s*=\s*true\b/.test(content) || /\bexport\s*\{\s*hydrate\s*\}\b/.test(content);
13591
14387
  }
13592
14388
  __name(hasHydrateExport, "hasHydrateExport");
14389
+ function tokenizeModuleSource(content) {
14390
+ const tokens = [];
14391
+ let index = 0;
14392
+ let line = 1;
14393
+ while (index < content.length) {
14394
+ const character = content[index];
14395
+ if (/\s/.test(character)) {
14396
+ if (character === "\n") line++;
14397
+ index++;
14398
+ continue;
14399
+ }
14400
+ if (character === "/" && content[index + 1] === "/") {
14401
+ index += 2;
14402
+ while (index < content.length && content[index] !== "\n") index++;
14403
+ continue;
14404
+ }
14405
+ if (character === "/" && content[index + 1] === "*") {
14406
+ index += 2;
14407
+ while (index < content.length) {
14408
+ if (content[index] === "\n") line++;
14409
+ if (content[index] === "*" && content[index + 1] === "/") {
14410
+ index += 2;
14411
+ break;
14412
+ }
14413
+ index++;
14414
+ }
14415
+ continue;
14416
+ }
14417
+ if (character === '"' || character === "'") {
14418
+ const quote = character;
14419
+ const tokenLine = line;
14420
+ let value = "";
14421
+ index++;
14422
+ while (index < content.length) {
14423
+ const next = content[index];
14424
+ if (next === "\\") {
14425
+ value += next;
14426
+ if (index + 1 < content.length) value += content[index + 1];
14427
+ index += 2;
14428
+ continue;
14429
+ }
14430
+ if (next === quote) {
14431
+ index++;
14432
+ break;
14433
+ }
14434
+ if (next === "\n") line++;
14435
+ value += next;
14436
+ index++;
14437
+ }
14438
+ tokens.push({ kind: "string", value, line: tokenLine });
14439
+ continue;
14440
+ }
14441
+ if (character === "`") {
14442
+ index++;
14443
+ while (index < content.length) {
14444
+ const next = content[index];
14445
+ if (next === "\\") {
14446
+ index += 2;
14447
+ continue;
14448
+ }
14449
+ if (next === "`") {
14450
+ index++;
14451
+ break;
14452
+ }
14453
+ if (next === "\n") line++;
14454
+ index++;
14455
+ }
14456
+ continue;
14457
+ }
14458
+ if (/[A-Za-z_$]/.test(character)) {
14459
+ const start = index++;
14460
+ while (index < content.length && /[\w$]/.test(content[index])) index++;
14461
+ tokens.push({ kind: "identifier", value: content.slice(start, index), line });
14462
+ continue;
14463
+ }
14464
+ tokens.push({ kind: "punctuation", value: character, line });
14465
+ index++;
14466
+ }
14467
+ return tokens;
14468
+ }
14469
+ __name(tokenizeModuleSource, "tokenizeModuleSource");
14470
+ function isIslandExportStart(tokens, index) {
14471
+ const token = tokens[index];
14472
+ const previous = tokens[index - 1];
14473
+ const startsStatement = !previous || previous.value === ";" || previous.value === "{" || previous.value === "}" || token.line > previous.line;
14474
+ return startsStatement && token.value === "export" && tokens[index + 1]?.value === "const" && tokens[index + 2]?.value === "island";
14475
+ }
14476
+ __name(isIslandExportStart, "isIslandExportStart");
14477
+ function getIslandStrategyExport(content) {
14478
+ if (!content) return null;
14479
+ const tokens = tokenizeModuleSource(content);
14480
+ for (let index = 0; index < tokens.length - 2; index++) {
14481
+ if (!isIslandExportStart(tokens, index)) continue;
14482
+ let valueIndex = index + 3;
14483
+ if (tokens[valueIndex]?.value === ":") {
14484
+ while (valueIndex < tokens.length && tokens[valueIndex].value !== "=") valueIndex++;
14485
+ }
14486
+ if (tokens[valueIndex]?.value !== "=") break;
14487
+ valueIndex++;
14488
+ const literal = tokens[valueIndex];
14489
+ if (!literal || literal.kind !== "string" || !isFarmIslandStrategy(literal.value)) break;
14490
+ let trailingIndex = valueIndex + 1;
14491
+ if (tokens[trailingIndex]?.value === "as" && tokens[trailingIndex + 1]?.value === "const") {
14492
+ trailingIndex += 2;
14493
+ }
14494
+ const trailing = tokens[trailingIndex];
14495
+ if (trailing && trailing.value !== ";" && trailing.line === literal.line) break;
14496
+ return literal.value;
14497
+ }
14498
+ if (tokens.some((_token, index) => isIslandExportStart(tokens, index))) {
14499
+ throw new Error(
14500
+ 'Farm island configuration must be a static "load", "interaction", "visible", or "idle" string literal.'
14501
+ );
14502
+ }
14503
+ return null;
14504
+ }
14505
+ __name(getIslandStrategyExport, "getIslandStrategyExport");
13593
14506
  function stripUseClientDirective(content) {
13594
14507
  return content.replace(/^\s*(["'])use client\1\s*;?\s*/, "");
13595
14508
  }
13596
14509
  __name(stripUseClientDirective, "stripUseClientDirective");
13597
- function parseClientModuleMetadata(content) {
14510
+ function parseClientModuleMetadata(content, inspectIslandExport) {
13598
14511
  if (!content) {
13599
14512
  return {
13600
14513
  isClientComponent: false,
13601
- hasHydrateExport: false
14514
+ hasHydrateExport: false,
14515
+ islandStrategy: null
13602
14516
  };
13603
14517
  }
14518
+ const isClientComponent = hasUseClientDirective(content);
14519
+ const hasHydrate = hasHydrateExport(content);
13604
14520
  return {
13605
- isClientComponent: hasUseClientDirective(content),
13606
- hasHydrateExport: hasHydrateExport(content)
14521
+ isClientComponent,
14522
+ hasHydrateExport: hasHydrate,
14523
+ islandStrategy: inspectIslandExport || isClientComponent || hasHydrate ? getIslandStrategyExport(content) : null
13607
14524
  };
13608
14525
  }
13609
14526
  __name(parseClientModuleMetadata, "parseClientModuleMetadata");
13610
14527
  function getClientModuleMetadata(modulePath, root) {
13611
14528
  const resolvedPath = resolveModuleSourcePath(modulePath, root);
13612
- return inspectClientModuleMetadata(resolvedPath, root, /* @__PURE__ */ new Set());
14529
+ return inspectClientModuleMetadata(resolvedPath, root, /* @__PURE__ */ new Set(), true);
13613
14530
  }
13614
14531
  __name(getClientModuleMetadata, "getClientModuleMetadata");
13615
- function inspectClientModuleMetadata(resolvedPath, root, visited) {
14532
+ function inspectClientModuleMetadata(resolvedPath, root, visited, inspectIslandExport) {
13616
14533
  if (!resolvedPath || visited.has(resolvedPath)) {
13617
14534
  return {
13618
14535
  isClientComponent: false,
13619
- shouldHydrate: false
14536
+ shouldHydrate: false,
14537
+ islandStrategy: null
13620
14538
  };
13621
14539
  }
13622
14540
  visited.add(resolvedPath);
13623
14541
  const content = readIfExists(resolvedPath);
13624
- const parsed = parseClientModuleMetadata(content);
14542
+ const parsed = parseClientModuleMetadata(content, inspectIslandExport);
13625
14543
  if (parsed.isClientComponent) {
13626
14544
  return {
13627
14545
  isClientComponent: true,
13628
- shouldHydrate: true
14546
+ shouldHydrate: true,
14547
+ islandStrategy: parsed.islandStrategy ?? "load"
13629
14548
  };
13630
14549
  }
13631
14550
  let importsClientBoundary = false;
14551
+ let importedIslandStrategy = null;
13632
14552
  for (const specifier of getRelativeImportSpecifiers(content)) {
13633
14553
  const importedPath = resolveImportedModuleSourcePath(resolvedPath, specifier, root);
13634
- const importedMetadata = inspectClientModuleMetadata(importedPath, root, visited);
14554
+ const importedMetadata = inspectClientModuleMetadata(importedPath, root, visited, false);
13635
14555
  if (importedMetadata.isClientComponent || importedMetadata.shouldHydrate) {
13636
14556
  importsClientBoundary = true;
13637
- break;
14557
+ if (importedIslandStrategy === null) {
14558
+ importedIslandStrategy = importedMetadata.islandStrategy;
14559
+ } else if (importedIslandStrategy !== importedMetadata.islandStrategy) {
14560
+ importedIslandStrategy = "load";
14561
+ }
13638
14562
  }
13639
14563
  }
14564
+ const shouldHydrate = parsed.hasHydrateExport || importsClientBoundary;
13640
14565
  return {
13641
14566
  isClientComponent: false,
13642
- shouldHydrate: parsed.hasHydrateExport || importsClientBoundary
14567
+ shouldHydrate,
14568
+ islandStrategy: shouldHydrate ? parsed.islandStrategy ?? importedIslandStrategy ?? "load" : null
13643
14569
  };
13644
14570
  }
13645
14571
  __name(inspectClientModuleMetadata, "inspectClientModuleMetadata");
@@ -13895,6 +14821,10 @@ function parseInterceptionMarker(segment) {
13895
14821
  __name(parseInterceptionMarker, "parseInterceptionMarker");
13896
14822
 
13897
14823
  // src/routing/route-manager.ts
14824
+ function shouldSuggestStaticRenderingForI18n(i18n) {
14825
+ return !i18n || i18n.routing === "prefix-always" || i18n.routing === "prefix-except-default" && i18n.detection.every((signal) => signal === "url");
14826
+ }
14827
+ __name(shouldSuggestStaticRenderingForI18n, "shouldSuggestStaticRenderingForI18n");
13898
14828
  function routeSpecificity(entry) {
13899
14829
  return entry.route.segments.reduce((score, segment) => {
13900
14830
  if (!segment.isDynamic) return score + 100;
@@ -14138,6 +15068,7 @@ var _RouteManager = class _RouteManager {
14138
15068
  modulePath: toUrlPath(entry.modulePath),
14139
15069
  shouldHydrate: metadata.shouldHydrate,
14140
15070
  isClientComponent: metadata.isClientComponent,
15071
+ islandStrategy: metadata.islandStrategy,
14141
15072
  search: getProgrammaticRouteSearchClientOptions(programmaticPage?.search),
14142
15073
  segments: entry.route.segments.map((seg) => ({
14143
15074
  segment: seg.segment,
@@ -14600,8 +15531,10 @@ var _RouteManager = class _RouteManager {
14600
15531
  isDynamic: entry.route.segments.some((seg) => seg.isDynamic),
14601
15532
  pattern: entry.pattern
14602
15533
  }));
14603
- const result = await collectSSGPages(routes, (filePath) => this.loadRouteModule(filePath));
14604
15534
  const i18n = this.getI18nConfig();
15535
+ const result = await collectSSGPages(routes, (filePath) => this.loadRouteModule(filePath), {
15536
+ suggestStaticRendering: shouldSuggestStaticRenderingForI18n(i18n)
15537
+ });
14605
15538
  if (!i18n) {
14606
15539
  return result;
14607
15540
  }
@@ -14732,8 +15665,8 @@ async function safeGlobFiles(pattern, cwd) {
14732
15665
  __name(safeGlobFiles, "safeGlobFiles");
14733
15666
 
14734
15667
  // src/server/renderer.ts
14735
- var import_react4 = __toESM(require("react"));
14736
- var import_server = require("react-dom/server");
15668
+ var import_react5 = __toESM(require("react"));
15669
+ var import_server2 = require("react-dom/server");
14737
15670
  var fs2 = __toESM(require("fs"));
14738
15671
  var path9 = __toESM(require("path"));
14739
15672
  var import_stream = require("stream");
@@ -16192,6 +17125,10 @@ ${FONT_SECTION_END}
16192
17125
  fallback,
16193
17126
  display,
16194
17127
  preload: raw.preload !== false,
17128
+ preloadResources: raw.preload === false ? [] : normalizedSources.map(({ resource }) => ({
17129
+ href: resourceUrl(resource, production, this.basePath),
17130
+ type: fontContentType(resource.extension)
17131
+ })),
16195
17132
  weight: defaultWeight,
16196
17133
  style: raw.style === void 0 ? void 0 : defaultStyle,
16197
17134
  sources: normalizedSources
@@ -16288,7 +17225,7 @@ ${FONT_SECTION_END}
16288
17225
  const normalizedExtension = extension.toLowerCase();
16289
17226
  const hash = (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex").slice(0, 12);
16290
17227
  const baseName = sanitizeFileName(import_node_path4.default.basename(fileName, extension)) || "font";
16291
- const outputFileName = `assets/fonts/${baseName}-${hash}${normalizedExtension}`;
17228
+ const outputFileName = `assets/fonts/${baseName}-h${hash}${normalizedExtension}`;
16292
17229
  const key = `${hash}${normalizedExtension}`;
16293
17230
  const existing = this.resources.get(key);
16294
17231
  if (existing) return existing;
@@ -16558,7 +17495,8 @@ function serializeFontResult(font) {
16558
17495
  fontFamily: stack,
16559
17496
  ...font.style ? { fontStyle: font.style } : {},
16560
17497
  ...font.weight !== void 0 && !String(font.weight).includes(" ") ? { fontWeight: font.weight } : {}
16561
- }
17498
+ },
17499
+ preloads: font.preloadResources
16562
17500
  });
16563
17501
  }
16564
17502
  __name(serializeFontResult, "serializeFontResult");
@@ -16901,6 +17839,166 @@ function fontError(id, message) {
16901
17839
  }
16902
17840
  __name(fontError, "fontError");
16903
17841
 
17842
+ // src/metadata-image.ts
17843
+ var import_react4 = __toESM(require("react"));
17844
+ var import_server = require("react-dom/server");
17845
+ var REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref");
17846
+ var REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo");
17847
+ var REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy");
17848
+ function isResponse(value) {
17849
+ return typeof Response !== "undefined" && (value instanceof Response || Boolean(
17850
+ value && typeof value === "object" && typeof value.arrayBuffer === "function" && value.headers
17851
+ ));
17852
+ }
17853
+ __name(isResponse, "isResponse");
17854
+ function isThenable(value) {
17855
+ return Boolean(
17856
+ value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function"
17857
+ );
17858
+ }
17859
+ __name(isThenable, "isThenable");
17860
+ async function prepareMetadataImageNode(node) {
17861
+ if (isThenable(node)) {
17862
+ return prepareMetadataImageNode(await node);
17863
+ }
17864
+ if (Array.isArray(node)) {
17865
+ return Promise.all(node.map((child) => prepareMetadataImageNode(child)));
17866
+ }
17867
+ if (!import_react4.default.isValidElement(node)) {
17868
+ return node;
17869
+ }
17870
+ const element = node;
17871
+ const type = element.type;
17872
+ const props = element.props || {};
17873
+ if (typeof type === "function") {
17874
+ if (type.prototype?.isReactComponent) {
17875
+ throw new Error(
17876
+ "Metadata image components must be stateless function components; React class components are not supported."
17877
+ );
17878
+ }
17879
+ return prepareMetadataImageNode(await type(props));
17880
+ }
17881
+ if (type && typeof type === "object") {
17882
+ if (type.$$typeof === REACT_MEMO_TYPE) {
17883
+ return prepareMetadataImageNode(import_react4.default.createElement(type.type, props));
17884
+ }
17885
+ if (type.$$typeof === REACT_FORWARD_REF_TYPE) {
17886
+ return prepareMetadataImageNode(await type.render(props, null));
17887
+ }
17888
+ if (type.$$typeof === REACT_LAZY_TYPE) {
17889
+ return prepareMetadataImageNode(import_react4.default.createElement(type._init(type._payload), props));
17890
+ }
17891
+ }
17892
+ const preparedChildren = await prepareMetadataImageNode(props.children);
17893
+ const preparedProps = { ...props };
17894
+ if (typeof preparedProps.className === "string") {
17895
+ preparedProps.tw = [preparedProps.tw, preparedProps.className].filter(Boolean).join(" ");
17896
+ delete preparedProps.className;
17897
+ }
17898
+ delete preparedProps.children;
17899
+ return import_react4.default.createElement(type, {
17900
+ ...preparedProps,
17901
+ key: element.key,
17902
+ children: preparedChildren
17903
+ });
17904
+ }
17905
+ __name(prepareMetadataImageNode, "prepareMetadataImageNode");
17906
+ async function normalizeFonts(fonts) {
17907
+ if (!fonts?.length) return void 0;
17908
+ return Promise.all(
17909
+ fonts.map(async (font) => {
17910
+ const data = await font.data;
17911
+ const arrayBuffer = ArrayBuffer.isView(data) ? toArrayBuffer(data) : data;
17912
+ return { ...font, data: arrayBuffer };
17913
+ })
17914
+ );
17915
+ }
17916
+ __name(normalizeFonts, "normalizeFonts");
17917
+ function resolveCacheControl(revalidate) {
17918
+ if (revalidate === false) {
17919
+ return "public, max-age=31536000, immutable";
17920
+ }
17921
+ if (typeof revalidate === "number" && Number.isFinite(revalidate) && revalidate > 0) {
17922
+ return `public, s-maxage=${Math.floor(revalidate)}, stale-while-revalidate=300`;
17923
+ }
17924
+ return "public, max-age=0, must-revalidate";
17925
+ }
17926
+ __name(resolveCacheControl, "resolveCacheControl");
17927
+ function toArrayBuffer(value) {
17928
+ if (value instanceof ArrayBuffer) return value;
17929
+ const bytes = new Uint8Array(value.byteLength);
17930
+ bytes.set(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
17931
+ return bytes.buffer;
17932
+ }
17933
+ __name(toArrayBuffer, "toArrayBuffer");
17934
+ async function createEntityTag(body) {
17935
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", body);
17936
+ const hash = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 32);
17937
+ return `"${hash}"`;
17938
+ }
17939
+ __name(createEntityTag, "createEntityTag");
17940
+ async function finalizeMetadataImageResponse(body, headers, options) {
17941
+ const responseHeaders = new Headers(headers);
17942
+ const etag = await createEntityTag(body);
17943
+ responseHeaders.set("ETag", etag);
17944
+ responseHeaders.set("Content-Length", String(body.byteLength));
17945
+ responseHeaders.set("X-Content-Type-Options", "nosniff");
17946
+ const matchesEntityTag = options.ifNoneMatch?.trim() === "*" || options.ifNoneMatch?.split(",").some((candidate) => candidate.trim().replace(/^W\//, "") === etag);
17947
+ if (matchesEntityTag) {
17948
+ return new Response(null, { status: 304, headers: responseHeaders });
17949
+ }
17950
+ return new Response(options.method?.toUpperCase() === "HEAD" ? null : body, {
17951
+ status: 200,
17952
+ headers: responseHeaders
17953
+ });
17954
+ }
17955
+ __name(finalizeMetadataImageResponse, "finalizeMetadataImageResponse");
17956
+ async function createFarmMetadataImageResponse(value, imageModule, options = {}) {
17957
+ const method = (options.method || "GET").toUpperCase();
17958
+ if (method !== "GET" && method !== "HEAD") {
17959
+ return new Response(null, { status: 405, headers: { Allow: "GET, HEAD" } });
17960
+ }
17961
+ if (isResponse(value)) {
17962
+ return method === "HEAD" ? new Response(null, { status: value.status, headers: value.headers }) : value;
17963
+ }
17964
+ const cacheControl = resolveCacheControl(imageModule.revalidate);
17965
+ const explicitContentType = imageModule.contentType?.split(";", 1)[0]?.trim().toLowerCase();
17966
+ if (import_react4.default.isValidElement(value) && explicitContentType !== "image/svg+xml") {
17967
+ const { ImageResponse } = await import("@vercel/og");
17968
+ const element = await prepareMetadataImageNode(value);
17969
+ const response = new ImageResponse(element, {
17970
+ width: imageModule.size?.width || 1200,
17971
+ height: imageModule.size?.height || 630,
17972
+ fonts: await normalizeFonts(imageModule.fonts),
17973
+ emoji: imageModule.emoji,
17974
+ debug: imageModule.debug,
17975
+ headers: { "cache-control": cacheControl }
17976
+ });
17977
+ const headers = new Headers(response.headers);
17978
+ headers.set("Cache-Control", cacheControl);
17979
+ return finalizeMetadataImageResponse(await response.arrayBuffer(), headers, options);
17980
+ }
17981
+ let body;
17982
+ if (typeof value === "string") {
17983
+ body = toArrayBuffer(new TextEncoder().encode(value));
17984
+ } else if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
17985
+ body = toArrayBuffer(value);
17986
+ } else if (import_react4.default.isValidElement(value)) {
17987
+ body = toArrayBuffer(new TextEncoder().encode((0, import_server.renderToStaticMarkup)(value)));
17988
+ } else {
17989
+ throw new Error("Metadata image must return a Response, string, bytes, or React element");
17990
+ }
17991
+ return finalizeMetadataImageResponse(
17992
+ body,
17993
+ {
17994
+ "Content-Type": imageModule.contentType || "image/svg+xml; charset=utf-8",
17995
+ "Cache-Control": cacheControl
17996
+ },
17997
+ options
17998
+ );
17999
+ }
18000
+ __name(createFarmMetadataImageResponse, "createFarmMetadataImageResponse");
18001
+
16904
18002
  // src/server/renderer.ts
16905
18003
  var cachedClerkProvider = null;
16906
18004
  var importRuntimeModule = new Function("specifier", "return import(specifier);");
@@ -16974,7 +18072,7 @@ function createPPRRefreshScript() {
16974
18072
  }
16975
18073
  __name(createPPRRefreshScript, "createPPRRefreshScript");
16976
18074
  function createPreHydrationClickQueueScript() {
16977
- 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>`;
18075
+ 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>`;
16978
18076
  }
16979
18077
  __name(createPreHydrationClickQueueScript, "createPreHydrationClickQueueScript");
16980
18078
  function searchParamsToObject(searchParams) {
@@ -17025,7 +18123,7 @@ function isWebResponse(value) {
17025
18123
  return typeof Response !== "undefined" && value instanceof Response && typeof value.arrayBuffer === "function";
17026
18124
  }
17027
18125
  __name(isWebResponse, "isWebResponse");
17028
- var _FarmRouteErrorBoundary = class _FarmRouteErrorBoundary extends import_react4.default.Component {
18126
+ var _FarmRouteErrorBoundary = class _FarmRouteErrorBoundary extends import_react5.default.Component {
17029
18127
  constructor(props) {
17030
18128
  super(props);
17031
18129
  this.state = { hasError: false, error: null };
@@ -17036,7 +18134,7 @@ var _FarmRouteErrorBoundary = class _FarmRouteErrorBoundary extends import_react
17036
18134
  render() {
17037
18135
  if (this.state.hasError) {
17038
18136
  const Fallback = this.props.Fallback;
17039
- return import_react4.default.createElement(Fallback, {
18137
+ return import_react5.default.createElement(Fallback, {
17040
18138
  ...this.props.fallbackProps,
17041
18139
  error: this.state.error,
17042
18140
  reset: /* @__PURE__ */ __name(() => this.setState({ hasError: false, error: null }), "reset")
@@ -17252,14 +18350,14 @@ var _ServerRenderer = class _ServerRenderer {
17252
18350
  searchParams: Promise.resolve({}),
17253
18351
  path: page2.urlPath
17254
18352
  };
17255
- let pageElement = import_react4.default.createElement(
18353
+ let pageElement = import_react5.default.createElement(
17256
18354
  PageComponent,
17257
18355
  pageProps
17258
18356
  );
17259
18357
  for (let i = layoutModules.length - 1; i >= 0; i--) {
17260
18358
  const layoutModule = layoutModules[i];
17261
18359
  const LayoutComponent = layoutModule.default;
17262
- pageElement = import_react4.default.createElement(
18360
+ pageElement = import_react5.default.createElement(
17263
18361
  LayoutComponent,
17264
18362
  {
17265
18363
  children: pageElement,
@@ -17585,6 +18683,7 @@ var _ServerRenderer = class _ServerRenderer {
17585
18683
  req.__FARM_ROUTE__ = pathname;
17586
18684
  req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
17587
18685
  req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
18686
+ req.__FARM_ISLAND_STRATEGY__ = moduleMetadata.islandStrategy;
17588
18687
  req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
17589
18688
  req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
17590
18689
  loadingBoundaryEntry.modulePath.indexOf("/src/app/")
@@ -17637,12 +18736,12 @@ var _ServerRenderer = class _ServerRenderer {
17637
18736
  await _runWithMiddlewareData(middlewareDataForContext, async () => {
17638
18737
  await _runWithMiddlewareContext(middlewareContext, async () => {
17639
18738
  await _runWithCurrentRequest(currentRequest, async () => {
17640
- let pageElement = import_react4.default.createElement(
18739
+ let pageElement = import_react5.default.createElement(
17641
18740
  PageComponent,
17642
18741
  pageProps
17643
18742
  );
17644
18743
  if (LoadingFallbackComponent) {
17645
- const loadingFallback = import_react4.default.createElement(LoadingFallbackComponent, {
18744
+ const loadingFallback = import_react5.default.createElement(LoadingFallbackComponent, {
17646
18745
  ...createRouteStateProps({
17647
18746
  params,
17648
18747
  searchParamsObject,
@@ -17651,16 +18750,21 @@ var _ServerRenderer = class _ServerRenderer {
17651
18750
  pluginExposedContext
17652
18751
  })
17653
18752
  });
17654
- pageElement = import_react4.default.createElement(
17655
- import_react4.default.Suspense,
18753
+ pageElement = import_react5.default.createElement(
18754
+ import_react5.default.Suspense,
17656
18755
  { fallback: loadingFallback },
17657
18756
  pageElement
17658
18757
  );
17659
18758
  }
17660
18759
  if (isClientComponent || shouldHydrate) {
17661
- pageElement = import_react4.default.createElement(
18760
+ pageElement = import_react5.default.createElement(
17662
18761
  "div",
17663
- { id: "__farm_page__", "data-farm-client": "true" },
18762
+ {
18763
+ id: "__farm_page__",
18764
+ "data-farm-client": "true",
18765
+ "data-farm-island": "page",
18766
+ "data-farm-island-strategy": moduleMetadata.islandStrategy ?? "load"
18767
+ },
17664
18768
  pageElement
17665
18769
  );
17666
18770
  }
@@ -17672,11 +18776,11 @@ var _ServerRenderer = class _ServerRenderer {
17672
18776
  const slotProps = {};
17673
18777
  for (const slot of renderedRouteSlots) {
17674
18778
  if (slot.ownerPattern !== layoutEntry.pattern) continue;
17675
- let slotElement = import_react4.default.createElement(
18779
+ let slotElement = import_react5.default.createElement(
17676
18780
  slot.module.default,
17677
18781
  slot.props
17678
18782
  );
17679
- slotElement = import_react4.default.createElement(
18783
+ slotElement = import_react5.default.createElement(
17680
18784
  "div",
17681
18785
  {
17682
18786
  id: slot.containerId,
@@ -17687,7 +18791,7 @@ var _ServerRenderer = class _ServerRenderer {
17687
18791
  );
17688
18792
  slotProps[slot.name] = slotElement;
17689
18793
  }
17690
- wrappedElement = import_react4.default.createElement(
18794
+ wrappedElement = import_react5.default.createElement(
17691
18795
  LayoutComponent,
17692
18796
  {
17693
18797
  children: wrappedElement,
@@ -17697,7 +18801,7 @@ var _ServerRenderer = class _ServerRenderer {
17697
18801
  );
17698
18802
  }
17699
18803
  if (ErrorFallbackComponent) {
17700
- wrappedElement = import_react4.default.createElement(
18804
+ wrappedElement = import_react5.default.createElement(
17701
18805
  FarmRouteErrorBoundary,
17702
18806
  {
17703
18807
  Fallback: ErrorFallbackComponent,
@@ -17830,7 +18934,7 @@ var _ServerRenderer = class _ServerRenderer {
17830
18934
  if (!cachedClerkProvider) {
17831
18935
  cachedClerkProvider = await importRuntimeModule("@clerk/react");
17832
18936
  }
17833
- wrapped = import_react4.default.createElement(
18937
+ wrapped = import_react5.default.createElement(
17834
18938
  cachedClerkProvider.ClerkProvider,
17835
18939
  provider.props || {},
17836
18940
  wrapped
@@ -17905,6 +19009,13 @@ var _ServerRenderer = class _ServerRenderer {
17905
19009
  return reference;
17906
19010
  }
17907
19011
  async renderMetadataImage(req, res, options) {
19012
+ const method = (req.method || "GET").toUpperCase();
19013
+ if (method !== "GET" && method !== "HEAD") {
19014
+ res.statusCode = 405;
19015
+ res.setHeader("Allow", "GET, HEAD");
19016
+ res.end();
19017
+ return;
19018
+ }
17908
19019
  if (options.image.sourceType === "static") {
17909
19020
  if (!options.image.staticInfo) {
17910
19021
  throw new Error(`Static metadata image ${options.image.modulePath} is missing file info`);
@@ -17930,42 +19041,12 @@ var _ServerRenderer = class _ServerRenderer {
17930
19041
  await this.writeMetadataImageResponse(req, res, handlerResult, imageModule);
17931
19042
  }
17932
19043
  async writeMetadataImageResponse(req, res, value, imageModule) {
17933
- if (isWebResponse(value)) {
17934
- res.statusCode = value.status;
17935
- value.headers.forEach((headerValue, key) => {
17936
- res.setHeader(key, headerValue);
17937
- });
17938
- if (req.method === "HEAD") {
17939
- res.end();
17940
- return;
17941
- }
17942
- const body2 = Buffer.from(await value.arrayBuffer());
17943
- res.write(body2);
17944
- res.end();
17945
- return;
17946
- }
17947
- const contentType = imageModule.contentType || "image/svg+xml; charset=utf-8";
17948
- let body;
17949
- if (typeof value === "string") {
17950
- body = value;
17951
- } else if (value instanceof ArrayBuffer) {
17952
- body = Buffer.from(value);
17953
- } else if (ArrayBuffer.isView(value)) {
17954
- body = Buffer.from(value.buffer, value.byteOffset, value.byteLength);
17955
- } else if (import_react4.default.isValidElement(value)) {
17956
- body = (0, import_server.renderToStaticMarkup)(value);
17957
- } else {
17958
- throw new Error("Metadata image must return a Response, string, bytes, or React element");
17959
- }
17960
- res.statusCode = res.statusCode || 200;
17961
- res.setHeader("Content-Type", contentType);
17962
- res.setHeader("Cache-Control", "public, max-age=0, must-revalidate");
17963
- if (req.method === "HEAD") {
17964
- res.end();
17965
- return;
17966
- }
17967
- res.write(body);
17968
- res.end();
19044
+ const ifNoneMatch = req.headers["if-none-match"];
19045
+ const response = await createFarmMetadataImageResponse(value, imageModule, {
19046
+ method: req.method,
19047
+ ifNoneMatch: Array.isArray(ifNoneMatch) ? ifNoneMatch[0] : ifNoneMatch
19048
+ });
19049
+ await sendWebResponse(res, response);
17969
19050
  }
17970
19051
  async writeStaticMetadataImageResponse(req, res, image) {
17971
19052
  const method = (req.method || "GET").toUpperCase();
@@ -18012,7 +19093,7 @@ var _ServerRenderer = class _ServerRenderer {
18012
19093
  return false;
18013
19094
  }
18014
19095
  const ErrorComponent = errorModule.default;
18015
- const errorElement = import_react4.default.createElement(ErrorComponent, {
19096
+ const errorElement = import_react5.default.createElement(ErrorComponent, {
18016
19097
  ...createRouteStateProps({
18017
19098
  params: options.params,
18018
19099
  searchParamsObject: options.searchParamsObject,
@@ -18030,7 +19111,7 @@ var _ServerRenderer = class _ServerRenderer {
18030
19111
  );
18031
19112
  for (let i = layoutModules.length - 1; i >= 0; i--) {
18032
19113
  const LayoutComponent = layoutModules[i].default;
18033
- wrapped = import_react4.default.createElement(
19114
+ wrapped = import_react5.default.createElement(
18034
19115
  LayoutComponent,
18035
19116
  {
18036
19117
  children: wrapped,
@@ -18095,6 +19176,7 @@ var _ServerRenderer = class _ServerRenderer {
18095
19176
  search: routeEntry.search,
18096
19177
  isClientComponent: routeEntry.isClientComponent,
18097
19178
  shouldHydrate: routeEntry.shouldHydrate,
19179
+ islandStrategy: routeEntry.islandStrategy,
18098
19180
  preloads: [routeEntry.modulePath],
18099
19181
  assets: []
18100
19182
  };
@@ -18131,6 +19213,7 @@ window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
18131
19213
  window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
18132
19214
  window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
18133
19215
  window.__FARM_SHOULD_HYDRATE__ = ${JSON.stringify(req.__FARM_SHOULD_HYDRATE__ === true)};
19216
+ window.__FARM_ISLAND_STRATEGY__ = ${JSON.stringify(req.__FARM_ISLAND_STRATEGY__ || "load")};
18134
19217
  window.__FARM_PAGE_MODULE__ = ${JSON.stringify(relativePath2)};
18135
19218
  window.__FARM_LOADING_MODULE__ = ${JSON.stringify(
18136
19219
  req.__FARM_LOADING_MODULE_PATH__ || null
@@ -18148,8 +19231,8 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
18148
19231
  const i18nSnapshot = getFarmI18nClientSnapshot();
18149
19232
  const i18nAlternateTags = i18nSnapshot ? renderI18nAlternateLinks(req.__FARM_ROUTE__ || req.url || "/", i18nSnapshot) : "";
18150
19233
  const fontHead = renderFarmFontDevHead(this.config.root || process.cwd());
18151
- const streamRoot = import_react4.default.createElement("div", { style: { display: "contents" } }, element);
18152
- const { pipe, abort } = (0, import_server.renderToPipeableStream)(streamRoot, {
19234
+ const streamRoot = import_react5.default.createElement("div", { style: { display: "contents" } }, element);
19235
+ const { pipe, abort } = (0, import_server2.renderToPipeableStream)(streamRoot, {
18153
19236
  onShellReady() {
18154
19237
  const shellReadyMs = Date.now() - streamStartTime;
18155
19238
  emitFarmEvent({
@@ -18307,12 +19390,12 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
18307
19390
  break;
18308
19391
  }
18309
19392
  }
18310
- let element = import_react4.default.createElement(
19393
+ let element = import_react5.default.createElement(
18311
19394
  NotFoundComponent,
18312
19395
  { pathname }
18313
19396
  );
18314
19397
  if (LayoutComponent) {
18315
- element = import_react4.default.createElement(
19398
+ element = import_react5.default.createElement(
18316
19399
  LayoutComponent,
18317
19400
  { children: element }
18318
19401
  );
@@ -18426,6 +19509,7 @@ var import_path6 = __toESM(require("path"));
18426
19509
  init_devtools_config();
18427
19510
  init_config();
18428
19511
  init_auth_config();
19512
+ init_preload();
18429
19513
  var defaultDocsConfig = {
18430
19514
  enabled: false,
18431
19515
  entry: "/docs",
@@ -18494,6 +19578,7 @@ var _FarmApp = class _FarmApp {
18494
19578
  context: config.context || (() => void 0),
18495
19579
  serverActions: resolveServerActionsConfig(config.serverActions),
18496
19580
  images: resolveFarmImageConfig(config.images),
19581
+ performance: resolveFarmPerformanceConfig(config.performance),
18497
19582
  i18n: isResolvedI18nConfig(config.i18n) ? config.i18n : resolveFarmI18nConfig(config.i18n, {
18498
19583
  root,
18499
19584
  mode: process.env.NODE_ENV === "production" ? "production" : "development"
@@ -20726,7 +21811,7 @@ init_response();
20726
21811
  init_integrations();
20727
21812
  init_devtools_config();
20728
21813
  var fs7 = __toESM(require("fs"));
20729
- var path23 = __toESM(require("path"));
21814
+ var path25 = __toESM(require("path"));
20730
21815
  init_layers();
20731
21816
 
20732
21817
  // src/environment-vite.ts
@@ -21073,7 +22158,7 @@ function transformError(id, message) {
21073
22158
  __name(transformError, "transformError");
21074
22159
 
21075
22160
  // package.json
21076
- var version = "0.1.0-beta.11";
22161
+ var version = "0.1.0-beta.13";
21077
22162
 
21078
22163
  // src/version.ts
21079
22164
  var FARM_VERSION = version;
@@ -21252,8 +22337,66 @@ async function createBlurDataURL(bytes) {
21252
22337
  }
21253
22338
  __name(createBlurDataURL, "createBlurDataURL");
21254
22339
 
22340
+ // src/font.ts
22341
+ function resolveFarmLayoutFonts(layouts) {
22342
+ let resolved;
22343
+ for (const layout2 of layouts) {
22344
+ if (!layout2.fonts) continue;
22345
+ resolved = { ...resolved, ...layout2.fonts };
22346
+ }
22347
+ return resolved;
22348
+ }
22349
+ __name(resolveFarmLayoutFonts, "resolveFarmLayoutFonts");
22350
+
21255
22351
  // src/vite.ts
21256
22352
  init_image_server();
22353
+
22354
+ // src/server/vite-config.ts
22355
+ var import_node_path9 = __toESM(require("path"));
22356
+ var FARM_CLIENT_ENTRY_PATTERN = "**/{page,layout,loading,error,not-found,default}.{js,jsx,ts,tsx}";
22357
+ var FARM_CLIENT_OPTIMIZE_DEPS_INCLUDE = [
22358
+ "react",
22359
+ "react-dom",
22360
+ "react-dom/client",
22361
+ "react/jsx-runtime",
22362
+ "react/jsx-dev-runtime",
22363
+ "@farm.js/core/client",
22364
+ "@farm.js/core/plugin/client",
22365
+ "@farm.js/core/deferred",
22366
+ "@farm.js/core/deployment",
22367
+ "@farm.js/core/i18n/client",
22368
+ "@farm.js/core/query/client",
22369
+ "@farm.js/core/server-fn/client",
22370
+ "@farm.js/core/server-query/client"
22371
+ ];
22372
+ function createFarmClientOptimizeDepsEntries(projectRoot, appDirectories) {
22373
+ const resolvedProjectRoot = import_node_path9.default.resolve(projectRoot);
22374
+ return appDirectories.map((appDirectory) => {
22375
+ const relativeAppDirectory = import_node_path9.default.relative(resolvedProjectRoot, import_node_path9.default.resolve(appDirectory)).replace(/\\/g, "/");
22376
+ const prefix = relativeAppDirectory || ".";
22377
+ return `${prefix}/${FARM_CLIENT_ENTRY_PATTERN}`;
22378
+ });
22379
+ }
22380
+ __name(createFarmClientOptimizeDepsEntries, "createFarmClientOptimizeDepsEntries");
22381
+ function createFarmClientOptimizeDepsConfig(entries) {
22382
+ return {
22383
+ // Keep normal application dependency discovery for CJS-only packages, but
22384
+ // seed every Farm browser runtime so React is present in the first crawl.
22385
+ noDiscovery: false,
22386
+ // Waiting for the crawl avoids serving a partial optimizer generation and
22387
+ // then changing browser hashes while hydration is already in progress.
22388
+ holdUntilCrawlEnd: true,
22389
+ include: [...FARM_CLIENT_OPTIMIZE_DEPS_INCLUDE],
22390
+ // Farm's HTML boots through a virtual module and imports route UI lazily.
22391
+ // Explicit entries let Vite finish that crawl before a navigation can
22392
+ // rotate the optimizer hash underneath a hydrated React runtime.
22393
+ ...entries?.length ? { entries: [...entries] } : {}
22394
+ };
22395
+ }
22396
+ __name(createFarmClientOptimizeDepsConfig, "createFarmClientOptimizeDepsConfig");
22397
+
22398
+ // src/vite.ts
22399
+ init_fonts();
21257
22400
  var ALL_TYPE_ARTIFACTS = {
21258
22401
  routes: true,
21259
22402
  api: true,
@@ -21474,7 +22617,7 @@ function fileContainsProgrammaticPageRoute(file) {
21474
22617
  __name(fileContainsProgrammaticPageRoute, "fileContainsProgrammaticPageRoute");
21475
22618
  function rewriteEarlySsrRelativeImports(options) {
21476
22619
  const cleanId = options.id.split("?", 1)[0];
21477
- if (!path23.isAbsolute(cleanId) || cleanId.replace(/\\/g, "/").includes("/node_modules/")) {
22620
+ if (!path25.isAbsolute(cleanId) || cleanId.replace(/\\/g, "/").includes("/node_modules/")) {
21478
22621
  return null;
21479
22622
  }
21480
22623
  const replacements = [];
@@ -21494,7 +22637,7 @@ function rewriteEarlySsrRelativeImports(options) {
21494
22637
  const suffixIndex = source.value.search(/[?#]/);
21495
22638
  const sourcePath = suffixIndex === -1 ? source.value : source.value.slice(0, suffixIndex);
21496
22639
  const suffix = suffixIndex === -1 ? "" : source.value.slice(suffixIndex);
21497
- const resolvedPath = path23.resolve(path23.dirname(cleanId), sourcePath);
22640
+ const resolvedPath = path25.resolve(path25.dirname(cleanId), sourcePath);
21498
22641
  replacements.push({
21499
22642
  start: source.start,
21500
22643
  end: source.end,
@@ -21579,7 +22722,7 @@ function farmPlugin(options = {}, initialPluginManager) {
21579
22722
  ...layerRoots.length ? {
21580
22723
  server: {
21581
22724
  fs: {
21582
- allow: [path23.resolve(options.root || process.cwd()), ...layerRoots]
22725
+ allow: [path25.resolve(options.root || process.cwd()), ...layerRoots]
21583
22726
  }
21584
22727
  }
21585
22728
  } : {}
@@ -21610,9 +22753,9 @@ function farmPlugin(options = {}, initialPluginManager) {
21610
22753
  },
21611
22754
  server
21612
22755
  );
21613
- const globalsCSSPath = path23.join(server.config.root, "src/app/globals.css");
22756
+ const globalsCSSPath = path25.join(server.config.root, "src/app/globals.css");
21614
22757
  if (!fs7.existsSync(globalsCSSPath)) {
21615
- const appDir = path23.join(server.config.root, "src/app");
22758
+ const appDir = path25.join(server.config.root, "src/app");
21616
22759
  if (!fs7.existsSync(appDir)) {
21617
22760
  fs7.mkdirSync(appDir, { recursive: true });
21618
22761
  }
@@ -21634,10 +22777,10 @@ function farmPlugin(options = {}, initialPluginManager) {
21634
22777
  });
21635
22778
  }
21636
22779
  const sourceRoots = getFarmSourceRoots(farmConfig);
21637
- server.watcher.add(sourceRoots.map((source) => path23.join(source.root, source.srcDir)));
22780
+ server.watcher.add(sourceRoots.map((source) => path25.join(source.root, source.srcDir)));
21638
22781
  if (farmConfig.i18n.enabled) {
21639
22782
  server.watcher.add(
21640
- farmConfig.i18n.messages.includes("{locale}") ? path23.dirname(farmConfig.i18n.messages) : farmConfig.i18n.messages
22783
+ farmConfig.i18n.messages.includes("{locale}") ? path25.dirname(farmConfig.i18n.messages) : farmConfig.i18n.messages
21641
22784
  );
21642
22785
  }
21643
22786
  const workflowConfig = farmConfig.workflows;
@@ -21647,7 +22790,7 @@ function farmPlugin(options = {}, initialPluginManager) {
21647
22790
  ...farmDocsDevRuntime?.getFarmDocsRouteTypeEntries(farmConfig.docs) ?? []
21648
22791
  ], "getExtraRouteTypes");
21649
22792
  const appDirSlugs = sourceRoots.map(
21650
- (source) => path23.join(source.root, source.srcDir, "app").replace(/\\/g, "/")
22793
+ (source) => path25.join(source.root, source.srcDir, "app").replace(/\\/g, "/")
21651
22794
  );
21652
22795
  const generateTypeArtifacts = /* @__PURE__ */ __name(async (reason, selection = ALL_TYPE_ARTIFACTS, log = false) => {
21653
22796
  try {
@@ -21687,7 +22830,7 @@ function farmPlugin(options = {}, initialPluginManager) {
21687
22830
  }, "generateTypeArtifacts");
21688
22831
  await generateTypeArtifacts("startup");
21689
22832
  const srcDirSlugs = sourceRoots.map(
21690
- (source) => path23.join(source.root, source.srcDir).replace(/\\/g, "/")
22833
+ (source) => path25.join(source.root, source.srcDir).replace(/\\/g, "/")
21691
22834
  );
21692
22835
  const layerConfigFiles = new Set(
21693
22836
  farmConfig.layers.map((layer) => layer.configFile?.replace(/\\/g, "/")).filter((file) => Boolean(file))
@@ -21805,7 +22948,7 @@ function farmPlugin(options = {}, initialPluginManager) {
21805
22948
  await apiRouteManager.discoverRoutes();
21806
22949
  let discoveredWorkflows = [];
21807
22950
  const hasWorkflowDirectory = workflowConfig.enabled && workflowConfig.dirs.some(
21808
- (dir) => fs7.existsSync(path23.isAbsolute(dir) ? dir : path23.join(farmConfig.root, dir))
22951
+ (dir) => fs7.existsSync(path25.isAbsolute(dir) ? dir : path25.join(farmConfig.root, dir))
21809
22952
  );
21810
22953
  if (hasWorkflowDirectory) {
21811
22954
  const { createFarmWorkflowRequestHandler: createFarmWorkflowRequestHandler2, discoverFarmWorkflows: discoverFarmWorkflows2 } = await loadFarmWorkflowsDevRuntime();
@@ -21869,10 +23012,20 @@ function farmPlugin(options = {}, initialPluginManager) {
21869
23012
  logger.info(`Refreshed routes: ${reason}`);
21870
23013
  }
21871
23014
  }, "refreshRouteDiscovery");
23015
+ const farmDocsFontAssetList = farmDocsDevRuntime ? resolveFarmDocsFontAssets(farmConfig.root) : [];
21872
23016
  const farmDocsHandler = farmDocsDevRuntime ? farmDocsDevRuntime.createFarmDocsHandler(farmConfig.docs, {
21873
23017
  root: farmConfig.root,
21874
23018
  srcDir: farmConfig.srcDir,
21875
- clientEntry: "/@farm/client.js"
23019
+ clientEntry: "/@farm/client.js",
23020
+ fontAssets: toFarmDocsPublicFontAssets(farmDocsFontAssetList),
23021
+ resolveLayoutFonts: /* @__PURE__ */ __name(async (pathname) => {
23022
+ const layouts = routeManager.matchRoute(pathname).layouts;
23023
+ const layoutModules = await Promise.all(
23024
+ layouts.map((layout2) => routeManager.loadLayoutModule(layout2.modulePath))
23025
+ );
23026
+ return resolveFarmLayoutFonts(layoutModules);
23027
+ }, "resolveLayoutFonts"),
23028
+ fontStylesheetHref: "/@farm/fonts.css"
21876
23029
  }) : null;
21877
23030
  const farmDocsAPIHandler = farmDocsDevRuntime ? farmDocsDevRuntime.createFarmDocsAPIHandler({
21878
23031
  rootDir: farmConfig.root,
@@ -21880,22 +23033,7 @@ function farmPlugin(options = {}, initialPluginManager) {
21880
23033
  docs: farmConfig.docs
21881
23034
  }) : null;
21882
23035
  const farmDocsFontAssets = new Map(
21883
- farmDocsDevRuntime ? [
21884
- [
21885
- "/assets/Geist-Variable-CrgPqtmy.woff2",
21886
- path23.join(
21887
- farmConfig.root,
21888
- "node_modules/geist/dist/fonts/geist-sans/Geist-Variable.woff2"
21889
- )
21890
- ],
21891
- [
21892
- "/assets/GeistMono-Variable-BNLlm6Cd.woff2",
21893
- path23.join(
21894
- farmConfig.root,
21895
- "node_modules/geist/dist/fonts/geist-mono/GeistMono-Variable.woff2"
21896
- )
21897
- ]
21898
- ] : []
23036
+ farmDocsFontAssetList.map(({ url, sourcePath }) => [url, sourcePath])
21899
23037
  );
21900
23038
  const logRequest = /* @__PURE__ */ __name((method, urlPath, tag) => {
21901
23039
  try {
@@ -21959,11 +23097,12 @@ function farmPlugin(options = {}, initialPluginManager) {
21959
23097
  }
21960
23098
  }
21961
23099
  const farmDocsFontPath = farmDocsFontAssets.get(requestPathname);
21962
- if (farmDocsFontPath && fs7.existsSync(farmDocsFontPath)) {
23100
+ if ((requestMethod === "GET" || requestMethod === "HEAD") && farmDocsFontPath && fs7.existsSync(farmDocsFontPath)) {
21963
23101
  res.statusCode = 200;
21964
23102
  res.setHeader("Content-Type", "font/woff2");
21965
23103
  res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
21966
- fs7.createReadStream(farmDocsFontPath).pipe(res);
23104
+ if (requestMethod === "HEAD") res.end();
23105
+ else fs7.createReadStream(farmDocsFontPath).pipe(res);
21967
23106
  return;
21968
23107
  }
21969
23108
  if (requestMethod === "GET" && (requestPathname === FARM_DEVTOOLS_PATH || requestPathname === `${FARM_DEVTOOLS_PATH}.json`)) {
@@ -22569,6 +23708,7 @@ function farmPlugin(options = {}, initialPluginManager) {
22569
23708
  modulePath: toUrlPath(route.modulePath),
22570
23709
  isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
22571
23710
  shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
23711
+ islandStrategy: moduleMetadata.islandStrategy,
22572
23712
  metadata: {
22573
23713
  title: mergedMetadata.title,
22574
23714
  description: mergedMetadata.description
@@ -22953,6 +24093,7 @@ export const getManifest = () => ({
22953
24093
  search: route.search,
22954
24094
  isClientComponent: moduleMetadata.isClientComponent,
22955
24095
  shouldHydrate: moduleMetadata.shouldHydrate,
24096
+ islandStrategy: moduleMetadata.islandStrategy,
22956
24097
  preloads: [route.modulePath],
22957
24098
  // In dev, preload is just the module
22958
24099
  assets: []
@@ -23079,8 +24220,8 @@ if (import.meta.hot) {
23079
24220
  }
23080
24221
  logger.info(`Found ${ssgPages.length} SSG pages, ${ssrRoutes.length} SSR routes`);
23081
24222
  logger.info("Pre-rendering SSG pages...");
23082
- const outDir = path23.join(server?.config.root || process.cwd(), options.outDir || "dist");
23083
- const clientDir = path23.join(outDir, "client");
24223
+ const outDir = path25.join(server?.config.root || process.cwd(), options.outDir || "dist");
24224
+ const clientDir = path25.join(outDir, "client");
23084
24225
  for (const page2 of ssgPages) {
23085
24226
  try {
23086
24227
  const staticRequest = new Request(new URL(page2.urlPath, "http://farm.static"));
@@ -23091,7 +24232,7 @@ if (import.meta.hot) {
23091
24232
  const layoutModules = await Promise.all(
23092
24233
  layouts.map((l) => routeManager.loadLayoutModule(l.modulePath))
23093
24234
  );
23094
- const React3 = await import("react");
24235
+ const React4 = await import("react");
23095
24236
  const { renderToString } = await import("react-dom/server");
23096
24237
  const PageComponent = mod.default;
23097
24238
  const pageProps = {
@@ -23099,14 +24240,14 @@ if (import.meta.hot) {
23099
24240
  searchParams: Promise.resolve({}),
23100
24241
  path: page2.urlPath
23101
24242
  };
23102
- let pageElement = React3.createElement(
24243
+ let pageElement = React4.createElement(
23103
24244
  PageComponent,
23104
24245
  pageProps
23105
24246
  );
23106
24247
  for (let i = layoutModules.length - 1; i >= 0; i--) {
23107
24248
  const layoutModule = layoutModules[i];
23108
24249
  const LayoutComponent = layoutModule.default;
23109
- pageElement = React3.createElement(
24250
+ pageElement = React4.createElement(
23110
24251
  LayoutComponent,
23111
24252
  {
23112
24253
  children: pageElement,
@@ -23132,8 +24273,8 @@ if (import.meta.hot) {
23132
24273
  <script type="module" src="/assets/client.js"></script>
23133
24274
  </body>
23134
24275
  </html>`;
23135
- const outputPath = page2.urlPath === "/" ? path23.join(clientDir, "index.html") : path23.join(clientDir, page2.urlPath + ".html");
23136
- fs7.mkdirSync(path23.dirname(outputPath), { recursive: true });
24276
+ const outputPath = page2.urlPath === "/" ? path25.join(clientDir, "index.html") : path25.join(clientDir, page2.urlPath + ".html");
24277
+ fs7.mkdirSync(path25.dirname(outputPath), { recursive: true });
23137
24278
  fs7.writeFileSync(outputPath, fullHtml);
23138
24279
  const revalidateInfo = page2.revalidate ? ` (revalidate: ${page2.revalidate}s)` : "";
23139
24280
  logger.success(` \u2713 ${page2.urlPath}${revalidateInfo}`);
@@ -23142,7 +24283,7 @@ if (import.meta.hot) {
23142
24283
  logger.error(` \u2717 ${page2.urlPath}: ${error}`);
23143
24284
  }
23144
24285
  }
23145
- const manifestPath = path23.join(outDir, "__ssg_manifest.json");
24286
+ const manifestPath = path25.join(outDir, "__ssg_manifest.json");
23146
24287
  fs7.writeFileSync(
23147
24288
  manifestPath,
23148
24289
  JSON.stringify(
@@ -23178,9 +24319,9 @@ if (import.meta.hot) {
23178
24319
  }
23179
24320
  const currentFarmConfig = farmApp?.getConfig();
23180
24321
  const normalizedFile = file.replace(/\\/g, "/");
23181
- const currentSrcRoot = currentFarmConfig ? getFarmSourceRoots(currentFarmConfig).map((source) => path23.join(source.root, source.srcDir).replace(/\\/g, "/")).find((sourceRoot) => normalizedFile.startsWith(`${sourceRoot}/`)) || null : null;
24322
+ const currentSrcRoot = currentFarmConfig ? getFarmSourceRoots(currentFarmConfig).map((source) => path25.join(source.root, source.srcDir).replace(/\\/g, "/")).find((sourceRoot) => normalizedFile.startsWith(`${sourceRoot}/`)) || null : null;
23182
24323
  if (currentSrcRoot && normalizedFile.startsWith(`${currentSrcRoot}/`) && isProgrammaticRoutesFileName(normalizedFile)) {
23183
- logUpdate("PAGE", `updated ${path23.basename(file)}`);
24324
+ logUpdate("PAGE", `updated ${path25.basename(file)}`);
23184
24325
  for (const mod of modules) {
23185
24326
  server2.moduleGraph.invalidateModule(mod);
23186
24327
  }
@@ -23577,6 +24718,7 @@ import React from 'react'
23577
24718
  import { hydrateRoot, createRoot } from 'react-dom/client'
23578
24719
  import { installChunkErrorRecovery, SPARouter } from '@farm.js/core/client'
23579
24720
  import { createClientPluginManager } from '@farm.js/core/plugin/client'
24721
+ import { scheduleFarmIslandHydration } from '@farm.js/core/internal/client-runtime'
23580
24722
  import { reviveDeferredData } from '@farm.js/core/deferred'
23581
24723
  import {
23582
24724
  createFarmDeploymentMismatchError,
@@ -23829,6 +24971,7 @@ class LegacyManifestSPARouter {
23829
24971
 
23830
24972
  // Only prefetch routes that will hydrate on the client.
23831
24973
  if (!match.route.isClientComponent && !match.route.shouldHydrate) return;
24974
+ if (match.route.islandStrategy && match.route.islandStrategy !== 'load') return;
23832
24975
 
23833
24976
  const modulePath = match.route.modulePath;
23834
24977
  if (this.moduleCache.has(modulePath)) return;
@@ -23973,6 +25116,12 @@ let hasClientTakenOver = false;
23973
25116
  const routeSlotRoots = new Map();
23974
25117
  const routeSlotDefinitions = new Map();
23975
25118
  let activeRouteInterception = null;
25119
+ let pendingPageHydrationController = null;
25120
+
25121
+ function cancelPendingPageHydration() {
25122
+ pendingPageHydrationController?.abort();
25123
+ pendingPageHydrationController = null;
25124
+ }
23976
25125
 
23977
25126
  function normalizeServerProps(rawProps) {
23978
25127
  const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
@@ -24041,7 +25190,11 @@ async function hydrateInitialRouteSlots() {
24041
25190
  routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
24042
25191
  if (!slot.isClientComponent && !slot.shouldHydrate) continue;
24043
25192
  try {
24044
- hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
25193
+ const slotHydrated = await renderRouteSlot(slot, 'hydrate');
25194
+ hydrated = slotHydrated || hydrated;
25195
+ if (slotHydrated) {
25196
+ replayPreHydrationClicks(document.getElementById(slot.containerId));
25197
+ }
24045
25198
  } catch (error) {
24046
25199
  console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
24047
25200
  }
@@ -24112,16 +25265,29 @@ function applyCanonicalPathFromProps(props) {
24112
25265
  window.history.replaceState({ ...(window.history.state || {}), path: canonicalPath }, '', canonicalPath);
24113
25266
  }
24114
25267
 
24115
- function replayPreHydrationClicks() {
24116
- window.__FARM_HYDRATED__ = true;
24117
- document.documentElement.dataset.farmHydrated = 'true';
25268
+ function replayPreHydrationClicks(container = null) {
25269
+ if (!container) {
25270
+ markFarmHydrated();
25271
+ } else {
25272
+ container.dataset.farmIslandHydrated = 'true';
25273
+ }
24118
25274
 
24119
25275
  const queue = Array.isArray(window.__FARM_PREHYDRATION_CLICK_QUEUE__)
24120
25276
  ? window.__FARM_PREHYDRATION_CLICK_QUEUE__
24121
25277
  : [];
24122
25278
  if (queue.length === 0) return;
24123
25279
 
24124
- const queuedClicks = queue.splice(0, queue.length);
25280
+ const queuedClicks = [];
25281
+ const remainingClicks = [];
25282
+ for (const queuedClick of queue) {
25283
+ const target = queuedClick?.target;
25284
+ if (!container || (target instanceof Node && container.contains(target))) {
25285
+ queuedClicks.push(queuedClick);
25286
+ } else {
25287
+ remainingClicks.push(queuedClick);
25288
+ }
25289
+ }
25290
+ queue.splice(0, queue.length, ...remainingClicks);
24125
25291
  for (const queuedClick of queuedClicks) {
24126
25292
  const target = queuedClick?.target;
24127
25293
  if (!target || typeof target.click !== 'function') continue;
@@ -24130,6 +25296,11 @@ function replayPreHydrationClicks() {
24130
25296
  }
24131
25297
  }
24132
25298
 
25299
+ function markFarmHydrated() {
25300
+ window.__FARM_HYDRATED__ = true;
25301
+ document.documentElement.dataset.farmHydrated = 'true';
25302
+ }
25303
+
24133
25304
  async function buildClientHydrationElement(PageComponent, pageProps) {
24134
25305
  let element = React.createElement(PageComponent, pageProps);
24135
25306
  const loadingModulePath = window.__FARM_LOADING_MODULE__;
@@ -24272,9 +25443,10 @@ async function tryHydrateImportedPage(
24272
25443
  layouts,
24273
25444
  useHydrate = false,
24274
25445
  existingProps = null,
25446
+ signal = null,
24275
25447
  ) {
24276
25448
  const modulePath = route?.modulePath;
24277
- if (!modulePath) {
25449
+ if (!modulePath || signal?.aborted) {
24278
25450
  return false;
24279
25451
  }
24280
25452
 
@@ -24283,6 +25455,7 @@ async function tryHydrateImportedPage(
24283
25455
  pageModule = await import(/* @vite-ignore */ modulePath);
24284
25456
  pageModuleCache.set(modulePath, pageModule);
24285
25457
  }
25458
+ if (signal?.aborted || !container?.isConnected) return false;
24286
25459
 
24287
25460
  const PageComponent = pageModule?.default;
24288
25461
  if (!PageComponent) {
@@ -24297,6 +25470,7 @@ async function tryHydrateImportedPage(
24297
25470
  window.location.pathname,
24298
25471
  existingProps,
24299
25472
  );
25473
+ if (signal?.aborted || !container?.isConnected) return false;
24300
25474
 
24301
25475
  const wrappedElement = useHydrate && container?.id === '__farm_page__'
24302
25476
  ? wrapWithIntegrationProviders(
@@ -24307,6 +25481,7 @@ async function tryHydrateImportedPage(
24307
25481
  currentPageProps,
24308
25482
  layouts,
24309
25483
  );
25484
+ if (signal?.aborted || !container?.isConnected) return false;
24310
25485
 
24311
25486
  if (useHydrate) {
24312
25487
  try {
@@ -24337,6 +25512,7 @@ async function tryHydrateImportedPage(
24337
25512
  async function renderPage(pageData) {
24338
25513
  const container = document.getElementById('root');
24339
25514
  if (!container) return;
25515
+ cancelPendingPageHydration();
24340
25516
  const destination = window.location.pathname + window.location.search;
24341
25517
 
24342
25518
  if (pageData.interception) {
@@ -24353,6 +25529,7 @@ async function renderPage(pageData) {
24353
25529
  modulePath: pageData.modulePath,
24354
25530
  isClientComponent: pageData.isClientComponent === true,
24355
25531
  shouldHydrate: pageData.shouldHydrate === true,
25532
+ islandStrategy: pageData.islandStrategy || 'load',
24356
25533
  };
24357
25534
  const params = pageData.props?.params || {};
24358
25535
  const layouts = (pageData.layoutModules || []).map((modulePath, index) => ({
@@ -24552,14 +25729,6 @@ async function hydrate() {
24552
25729
  }
24553
25730
 
24554
25731
  try {
24555
- // Pre-load layout for SPA navigation
24556
- try {
24557
- const layoutModule = await import(/* @vite-ignore */ '/src/app/layout.tsx');
24558
- LayoutComponent = layoutModule.default;
24559
- } catch (e) {
24560
- console.warn('[Farm.js] Could not preload layout:', e);
24561
- }
24562
-
24563
25732
  // Check if this is a client component (set by SSR)
24564
25733
  const isClientComponent = window.__FARM_IS_CLIENT__ === true;
24565
25734
  const modulePath = window.__FARM_PAGE_MODULE__;
@@ -24607,34 +25776,88 @@ async function hydrate() {
24607
25776
  return
24608
25777
  }
24609
25778
 
24610
- const hydrationSession = await farmClientRuntime.beginHydration({
24611
- container: pageContainer,
24612
- mode: shouldHydrate ? 'hydrate' : 'render',
24613
- });
25779
+ const currentRoute = findRoute(window.location.pathname)?.route;
25780
+ const islandStrategy = window.__FARM_ISLAND_STRATEGY__ || currentRoute?.islandStrategy || 'load';
25781
+ pageContainer.dataset.farmIsland = 'page';
25782
+ pageContainer.dataset.farmIslandStrategy = islandStrategy;
24614
25783
 
24615
- let hydrated = false;
25784
+ const hydrationPathname = window.location.pathname;
25785
+ const hydrationController = new AbortController();
25786
+ pendingPageHydrationController = hydrationController;
24616
25787
  try {
24617
- hydrated = await tryHydrateImportedPage(
24618
- pageContainer,
24619
- { modulePath },
24620
- currentPageProps.params || {},
24621
- layouts,
24622
- shouldHydrate,
24623
- currentPageProps,
24624
- );
24625
- await farmClientRuntime.completeHydration(hydrationSession);
24626
- } catch (error) {
24627
- await farmClientRuntime.failHydration(hydrationSession, error);
24628
- throw error;
24629
- }
25788
+ await scheduleFarmIslandHydration({
25789
+ container: pageContainer,
25790
+ strategy: islandStrategy,
25791
+ signal: hydrationController.signal,
25792
+ hydrate: async () => {
25793
+ if (
25794
+ hydrationController.signal.aborted ||
25795
+ !pageContainer.isConnected ||
25796
+ window.location.pathname !== hydrationPathname
25797
+ ) {
25798
+ return;
25799
+ }
24630
25800
 
24631
- if (hydrated) {
24632
- replayPreHydrationClicks();
24633
- console.log('[Farm.js] \u2705 Hydrated:', modulePath);
24634
- return;
24635
- }
25801
+ // Layout code is only needed when this route boundary actually hydrates.
25802
+ try {
25803
+ const layoutModule = await import(/* @vite-ignore */ '/src/app/layout.tsx');
25804
+ LayoutComponent = layoutModule.default;
25805
+ } catch (e) {
25806
+ console.warn('[Farm.js] Could not preload layout:', e);
25807
+ }
25808
+ if (hydrationController.signal.aborted || !pageContainer.isConnected) return;
25809
+
25810
+ const hydrationSession = await farmClientRuntime.beginHydration({
25811
+ container: pageContainer,
25812
+ mode: shouldHydrate ? 'hydrate' : 'render',
25813
+ });
24636
25814
 
24637
- console.log('[Farm.js] Server component - SPA router ready')
25815
+ let hydrated = false;
25816
+ try {
25817
+ if (hydrationController.signal.aborted || !pageContainer.isConnected) {
25818
+ await farmClientRuntime.failHydration(
25819
+ hydrationSession,
25820
+ new DOMException('Route hydration was cancelled', 'AbortError'),
25821
+ );
25822
+ return;
25823
+ }
25824
+ hydrated = await tryHydrateImportedPage(
25825
+ pageContainer,
25826
+ { modulePath },
25827
+ currentPageProps.params || {},
25828
+ layouts,
25829
+ shouldHydrate,
25830
+ currentPageProps,
25831
+ hydrationController.signal,
25832
+ );
25833
+ if (hydrationController.signal.aborted || !pageContainer.isConnected) {
25834
+ await farmClientRuntime.failHydration(
25835
+ hydrationSession,
25836
+ new DOMException('Route hydration was cancelled', 'AbortError'),
25837
+ );
25838
+ return;
25839
+ }
25840
+ await farmClientRuntime.completeHydration(hydrationSession);
25841
+ } catch (error) {
25842
+ await farmClientRuntime.failHydration(hydrationSession, error);
25843
+ throw error;
25844
+ }
25845
+
25846
+ if (hydrated) {
25847
+ // The scheduler owns queue draining and exactly-once click replay.
25848
+ markFarmHydrated();
25849
+ console.log('[Farm.js] \u2705 Hydrated:', modulePath, '(' + islandStrategy + ')');
25850
+ return;
25851
+ }
25852
+
25853
+ console.log('[Farm.js] Server component - SPA router ready')
25854
+ },
25855
+ });
25856
+ } finally {
25857
+ if (pendingPageHydrationController === hydrationController) {
25858
+ pendingPageHydrationController = null;
25859
+ }
25860
+ }
24638
25861
  } catch (error) {
24639
25862
  console.error('[Farm.js] Hydration error:', error)
24640
25863
  }
@@ -24740,7 +25963,7 @@ function generateClientManifest(bundle) {
24740
25963
  __name(generateClientManifest, "generateClientManifest");
24741
25964
  async function defineConfig2(config = {}) {
24742
25965
  const tailwindcss = (await import("@tailwindcss/vite")).default;
24743
- const appRoot = path23.resolve(config.root || process.cwd());
25966
+ const appRoot = path25.resolve(config.root || process.cwd());
24744
25967
  if (config.extends?.length) {
24745
25968
  const { config: layeredConfig } = await Promise.resolve().then(() => (init_layers(), layers_exports)).then(
24746
25969
  ({ resolveFarmLayers: resolveFarmLayers2 }) => resolveFarmLayers2(config, {
@@ -24885,13 +26108,16 @@ async function defineConfig2(config = {}) {
24885
26108
  customLogger: farmLogger,
24886
26109
  clearScreen: false,
24887
26110
  optimizeDeps: {
24888
- include: [
24889
- "react",
24890
- "react-dom",
24891
- "react-dom/client",
24892
- "react/jsx-runtime",
24893
- "react/jsx-dev-runtime"
24894
- ],
26111
+ ...createFarmClientOptimizeDepsConfig(
26112
+ createFarmClientOptimizeDepsEntries(
26113
+ appRoot,
26114
+ getFarmAppDirectories({ ...config, root: appRoot })
26115
+ )
26116
+ ),
26117
+ // Pre-bundle every framework client-runtime entry with React. Without
26118
+ // this, Vite can discover a linked Farm entry after the page has loaded,
26119
+ // regenerate the optimizer browser hash, and leave React DOM holding a
26120
+ // different React module instance from a client component.
24895
26121
  // Exclude server-side packages from browser bundling
24896
26122
  exclude: [
24897
26123
  "@farm.js/core/server",
@@ -24926,7 +26152,7 @@ async function defineConfig2(config = {}) {
24926
26152
  // Stub out problematic server-only modules during dev mode
24927
26153
  alias: {
24928
26154
  ...getFarmLayerAliases(config.layers),
24929
- "@": path23.resolve(appRoot, "src"),
26155
+ "@": path25.resolve(appRoot, "src"),
24930
26156
  // Nitro internals that should not be resolved in browser
24931
26157
  "supports-color": "data:text/javascript,export default false; export const supportsColor = false; export const stdout = false; export const stderr = false;",
24932
26158
  "@poppinss/dumper": "data:text/javascript,export default {};",