@farm.js/core 0.1.0-beta.97 → 0.1.0-beta.99

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 (269) hide show
  1. package/dist/after.cjs.map +1 -0
  2. package/dist/agent-runtime.cjs +7 -3
  3. package/dist/agent-runtime.cjs.map +1 -0
  4. package/dist/agent-runtime.d.mts +2 -2
  5. package/dist/agent-runtime.d.ts +2 -2
  6. package/dist/agent-runtime.mjs +2 -1
  7. package/dist/agent-runtime.mjs.map +1 -1
  8. package/dist/api/route-manager.cjs.map +1 -0
  9. package/dist/api/route-manager.d.mts +2 -2
  10. package/dist/api/route-manager.d.ts +2 -2
  11. package/dist/api/runtime.cjs.map +1 -0
  12. package/dist/api.cjs +26 -1
  13. package/dist/api.cjs.map +1 -0
  14. package/dist/api.d.mts +3 -3
  15. package/dist/api.d.ts +3 -3
  16. package/dist/api.mjs +2 -2
  17. package/dist/{app-CIOx3LvY.d.ts → app-CGjrKNoN.d.ts} +4 -4
  18. package/dist/{app-DBd6437H.d.mts → app-DOcLs_iq.d.mts} +4 -4
  19. package/dist/app-markdown.cjs +21 -0
  20. package/dist/app-markdown.cjs.map +1 -0
  21. package/dist/app-markdown.d.mts +19 -4
  22. package/dist/app-markdown.d.ts +19 -4
  23. package/dist/app-markdown.mjs +7 -1
  24. package/dist/cache.cjs.map +1 -0
  25. package/dist/{chunk-VMCHLH3Y.mjs → chunk-26BCDVJS.mjs} +19 -1
  26. package/dist/chunk-26BCDVJS.mjs.map +1 -0
  27. package/dist/{chunk-FP5Q67FO.mjs → chunk-2HYYZCCI.mjs} +308 -19
  28. package/dist/chunk-2HYYZCCI.mjs.map +1 -0
  29. package/dist/{chunk-WKDAA6V2.mjs → chunk-3BTAMIQE.mjs} +100 -41
  30. package/dist/chunk-3BTAMIQE.mjs.map +1 -0
  31. package/dist/{chunk-WD2EBM3I.mjs → chunk-3CQJV3NC.mjs} +2 -2
  32. package/dist/{chunk-I3OOUWO5.mjs → chunk-3GDRV7SG.mjs} +2 -2
  33. package/dist/{chunk-YIBV77KZ.mjs → chunk-4WLAVHCY.mjs} +2 -2
  34. package/dist/{chunk-KDP5ZSWP.mjs → chunk-7PS5NKOM.mjs} +26 -11
  35. package/dist/chunk-7PS5NKOM.mjs.map +1 -0
  36. package/dist/{chunk-X4SFHKFH.mjs → chunk-BU65A3LZ.mjs} +10 -6
  37. package/dist/chunk-BU65A3LZ.mjs.map +1 -0
  38. package/dist/{chunk-WMJGA32P.mjs → chunk-BXVOHG6B.mjs} +27 -2
  39. package/dist/{chunk-WMJGA32P.mjs.map → chunk-BXVOHG6B.mjs.map} +1 -1
  40. package/dist/{chunk-BZAIS65C.mjs → chunk-DIHNOVZZ.mjs} +40 -13
  41. package/dist/chunk-DIHNOVZZ.mjs.map +1 -0
  42. package/dist/{chunk-ISSFLGJ5.mjs → chunk-FDWECN3W.mjs} +8 -4
  43. package/dist/chunk-FDWECN3W.mjs.map +1 -0
  44. package/dist/chunk-FDWXXTWR.mjs +114 -0
  45. package/dist/chunk-FDWXXTWR.mjs.map +1 -0
  46. package/dist/{chunk-FSIXEIOB.mjs → chunk-L7FSTPGS.mjs} +2 -2
  47. package/dist/{chunk-J3MPQ4MQ.mjs → chunk-LG4XB6RN.mjs} +2 -2
  48. package/dist/{chunk-J3MPQ4MQ.mjs.map → chunk-LG4XB6RN.mjs.map} +1 -1
  49. package/dist/{chunk-AAC66ILR.mjs → chunk-LXXG3K2Y.mjs} +61 -2
  50. package/dist/chunk-LXXG3K2Y.mjs.map +1 -0
  51. package/dist/{chunk-GJ7W6LNK.mjs → chunk-N5RK4LK6.mjs} +3 -3
  52. package/dist/{chunk-D7F7YZ7L.mjs → chunk-NCVFPT67.mjs} +100 -40
  53. package/dist/{chunk-D7F7YZ7L.mjs.map → chunk-NCVFPT67.mjs.map} +1 -1
  54. package/dist/{chunk-UMUWR5XA.mjs → chunk-PURU7FXR.mjs} +2 -2
  55. package/dist/{chunk-2SKCXYLB.mjs → chunk-QQCCBMTH.mjs} +60 -6
  56. package/dist/chunk-QQCCBMTH.mjs.map +1 -0
  57. package/dist/chunk-RKUPOYQV.mjs +28 -0
  58. package/dist/chunk-RKUPOYQV.mjs.map +1 -0
  59. package/dist/{chunk-52BR7LTX.mjs → chunk-STSPSJUI.mjs} +3 -3
  60. package/dist/{chunk-EPDIF432.mjs → chunk-UOGX6UNO.mjs} +37 -17
  61. package/dist/chunk-UOGX6UNO.mjs.map +1 -0
  62. package/dist/{chunk-IZBX2TEU.mjs → chunk-VQG3QWWK.mjs} +2 -2
  63. package/dist/{chunk-35NPLKQJ.mjs → chunk-XWM2C267.mjs} +21 -105
  64. package/dist/chunk-XWM2C267.mjs.map +1 -0
  65. package/dist/{chunk-7ZVN3YZI.mjs → chunk-Z5ARESQG.mjs} +43 -1
  66. package/dist/chunk-Z5ARESQG.mjs.map +1 -0
  67. package/dist/client/lifecycle.cjs.map +1 -0
  68. package/dist/client/lifecycle.mjs +2 -2
  69. package/dist/{client-plugins-B6-07YmP.d.mts → client-plugins-BqtHoJ9C.d.mts} +91 -3
  70. package/dist/{client-plugins-By6MVUX-.d.ts → client-plugins-DYprkCKN.d.ts} +91 -3
  71. package/dist/client-plugins.cjs +1 -1
  72. package/dist/client-plugins.cjs.map +1 -0
  73. package/dist/client-plugins.d.mts +2 -2
  74. package/dist/client-plugins.d.ts +2 -2
  75. package/dist/client-plugins.mjs +2 -2
  76. package/dist/client.cjs +61 -16
  77. package/dist/client.cjs.map +1 -0
  78. package/dist/client.d.mts +5 -5
  79. package/dist/client.d.ts +5 -5
  80. package/dist/client.mjs +7 -7
  81. package/dist/config.cjs.map +1 -0
  82. package/dist/config.d.mts +2 -2
  83. package/dist/config.d.ts +2 -2
  84. package/dist/cron.cjs +48 -12
  85. package/dist/cron.cjs.map +1 -0
  86. package/dist/cron.mjs +2 -1
  87. package/dist/deferred.cjs.map +1 -0
  88. package/dist/deployment.cjs.map +1 -0
  89. package/dist/{devtools-XWZX6CCL.mjs → devtools-24N3U5IG.mjs} +9 -7
  90. package/dist/{devtools-XWZX6CCL.mjs.map → devtools-24N3U5IG.mjs.map} +1 -1
  91. package/dist/docs.cjs +7 -3
  92. package/dist/docs.cjs.map +1 -0
  93. package/dist/docs.mjs +9 -7
  94. package/dist/env-types.cjs.map +1 -0
  95. package/dist/env.cjs.map +1 -0
  96. package/dist/environment/vite.cjs.map +1 -0
  97. package/dist/environment.cjs.map +1 -0
  98. package/dist/font.cjs.map +1 -0
  99. package/dist/headers.cjs.map +1 -0
  100. package/dist/i18n/client.cjs.map +1 -0
  101. package/dist/i18n/index.cjs.map +1 -0
  102. package/dist/i18n/server.cjs.map +1 -0
  103. package/dist/image/server.cjs +99 -40
  104. package/dist/image/server.cjs.map +1 -0
  105. package/dist/image/server.d.mts +6 -0
  106. package/dist/image/server.d.ts +6 -0
  107. package/dist/image/server.mjs +1 -1
  108. package/dist/image/sharp.cjs +1 -0
  109. package/dist/image/sharp.cjs.map +1 -0
  110. package/dist/image/sharp.d.mts +1 -1
  111. package/dist/image/sharp.d.ts +1 -1
  112. package/dist/image/sharp.mjs +1 -1
  113. package/dist/image/sharp.mjs.map +1 -1
  114. package/dist/image.cjs.map +1 -0
  115. package/dist/index.cjs +943 -231
  116. package/dist/index.cjs.map +1 -0
  117. package/dist/index.d.mts +11 -11
  118. package/dist/index.d.ts +11 -11
  119. package/dist/index.mjs +38 -24
  120. package/dist/index.mjs.map +1 -1
  121. package/dist/instrumentation.cjs.map +1 -0
  122. package/dist/{integration-orm-LLW6WZNK.mjs → integration-orm-G5BPBT5X.mjs} +3 -3
  123. package/dist/integrations.cjs +168 -5
  124. package/dist/integrations.cjs.map +1 -0
  125. package/dist/integrations.d.mts +2 -2
  126. package/dist/integrations.d.ts +2 -2
  127. package/dist/integrations.mjs +10 -3
  128. package/dist/internal/build-runtime.cjs +745 -139
  129. package/dist/internal/build-runtime.cjs.map +1 -0
  130. package/dist/internal/build-runtime.d.mts +4 -4
  131. package/dist/internal/build-runtime.d.ts +4 -4
  132. package/dist/internal/build-runtime.mjs +16 -14
  133. package/dist/internal/client-runtime.cjs +7 -2
  134. package/dist/internal/client-runtime.cjs.map +1 -0
  135. package/dist/internal/client-runtime.mjs +8 -3
  136. package/dist/internal/client-runtime.mjs.map +1 -1
  137. package/dist/internal/config-runtime.cjs +59 -42
  138. package/dist/internal/config-runtime.cjs.map +1 -0
  139. package/dist/internal/config-runtime.d.mts +3 -3
  140. package/dist/internal/config-runtime.d.ts +3 -3
  141. package/dist/internal/config-runtime.mjs +8 -6
  142. package/dist/internal/isolated-boundary.cjs.map +1 -0
  143. package/dist/internal/metadata-image-runtime.cjs.map +1 -0
  144. package/dist/internal/product-telemetry-runtime.cjs +52 -5
  145. package/dist/internal/product-telemetry-runtime.cjs.map +1 -0
  146. package/dist/internal/product-telemetry-runtime.d.mts +12 -1
  147. package/dist/internal/product-telemetry-runtime.d.ts +12 -1
  148. package/dist/internal/product-telemetry-runtime.mjs +50 -5
  149. package/dist/internal/product-telemetry-runtime.mjs.map +1 -1
  150. package/dist/internal/production-node-env.cjs.map +1 -0
  151. package/dist/internal/production-runtime.cjs +56 -10
  152. package/dist/internal/production-runtime.cjs.map +1 -0
  153. package/dist/internal/production-runtime.d.mts +8 -8
  154. package/dist/internal/production-runtime.d.ts +8 -8
  155. package/dist/internal/production-runtime.mjs +2 -2
  156. package/dist/markdown.cjs.map +1 -0
  157. package/dist/{metadata-route-8_V3UonT.d.ts → metadata-route-D2be_0kC.d.ts} +17 -2
  158. package/dist/{metadata-route-CWP_HjGU.d.mts → metadata-route-Dw5CrDIZ.d.mts} +17 -2
  159. package/dist/middleware.cjs.map +1 -0
  160. package/dist/middleware.d.mts +4 -4
  161. package/dist/middleware.d.ts +4 -4
  162. package/dist/navigation.cjs.map +1 -0
  163. package/dist/{nitro-EGRNOB5P.mjs → nitro-YJEP3FWM.mjs} +4 -3
  164. package/dist/{nitro-EGRNOB5P.mjs.map → nitro-YJEP3FWM.mjs.map} +1 -1
  165. package/dist/observability.cjs.map +1 -0
  166. package/dist/plugin.cjs +599 -104
  167. package/dist/plugin.cjs.map +1 -0
  168. package/dist/plugin.d.mts +2 -2
  169. package/dist/plugin.d.ts +2 -2
  170. package/dist/plugin.mjs +13 -11
  171. package/dist/{production-runtime-CdmzsDax.d.ts → production-runtime-CTqpD1C8.d.ts} +2 -2
  172. package/dist/{production-runtime-BGRH1dKG.d.mts → production-runtime-HNqNZd4D.d.mts} +2 -2
  173. package/dist/query/client.cjs.map +1 -0
  174. package/dist/query/index.cjs.map +1 -0
  175. package/dist/query/parsers.cjs.map +1 -0
  176. package/dist/query/server.cjs.map +1 -0
  177. package/dist/{render-plan-DLxJYAA5.d.mts → render-plan-COscpW-i.d.mts} +1 -1
  178. package/dist/{render-plan-0GeHiGVZ.d.ts → render-plan-Z4kSxaT_.d.ts} +1 -1
  179. package/dist/renderer/react/client.cjs.map +1 -0
  180. package/dist/renderer/react/server.cjs.map +1 -0
  181. package/dist/renderer/react/vite.cjs.map +1 -0
  182. package/dist/renderer-client.cjs +26 -1
  183. package/dist/renderer-client.cjs.map +1 -0
  184. package/dist/renderer-client.d.mts +4 -4
  185. package/dist/renderer-client.d.ts +4 -4
  186. package/dist/renderer-client.mjs +2 -2
  187. package/dist/renderer.cjs.map +1 -0
  188. package/dist/{request-BstWbZ6O.d.ts → request-BEDb2jE9.d.ts} +1 -1
  189. package/dist/{request-BCNXSXLh.d.mts → request-CbIAqJY9.d.mts} +1 -1
  190. package/dist/request.cjs.map +1 -0
  191. package/dist/request.d.mts +3 -3
  192. package/dist/request.d.ts +3 -3
  193. package/dist/router.cjs.map +1 -0
  194. package/dist/routes.cjs.map +1 -0
  195. package/dist/routes.d.mts +2 -2
  196. package/dist/routes.d.ts +2 -2
  197. package/dist/server-action-security.cjs +117 -104
  198. package/dist/server-action-security.cjs.map +1 -0
  199. package/dist/server-action-security.mjs +2 -1
  200. package/dist/server-fn-client.cjs.map +1 -0
  201. package/dist/server-fn.cjs.map +1 -0
  202. package/dist/server-fn.mjs +3 -2
  203. package/dist/server-plugins.cjs.map +1 -0
  204. package/dist/server-plugins.d.mts +3 -3
  205. package/dist/server-plugins.d.ts +3 -3
  206. package/dist/server-query-client.cjs +26 -1
  207. package/dist/server-query-client.cjs.map +1 -0
  208. package/dist/server-query-client.mjs +3 -3
  209. package/dist/server-query.cjs.map +1 -0
  210. package/dist/server-query.mjs +4 -3
  211. package/dist/server.cjs +686 -170
  212. package/dist/server.cjs.map +1 -0
  213. package/dist/server.d.mts +8 -8
  214. package/dist/server.d.ts +8 -8
  215. package/dist/server.mjs +16 -14
  216. package/dist/server.mjs.map +1 -1
  217. package/dist/{spa-router-COgu4txb.d.ts → spa-router-CjeQites.d.ts} +1 -1
  218. package/dist/{spa-router-BeyAVSc6.d.mts → spa-router-FJbNou1a.d.mts} +1 -1
  219. package/dist/storage.cjs +7 -3
  220. package/dist/storage.cjs.map +1 -0
  221. package/dist/storage.mjs +1 -1
  222. package/dist/testing.cjs.map +1 -0
  223. package/dist/testing.d.mts +2 -2
  224. package/dist/testing.d.ts +2 -2
  225. package/dist/testing.mjs +2 -1
  226. package/dist/testing.mjs.map +1 -1
  227. package/dist/theme/client.cjs.map +1 -0
  228. package/dist/theme/index.cjs.map +1 -0
  229. package/dist/theme/runtime.cjs.map +1 -0
  230. package/dist/theme/server.cjs.map +1 -0
  231. package/dist/{utils-DL2VwDQl.d.mts → utils-BiMJv9Ys.d.mts} +1 -1
  232. package/dist/{utils-DkU2c_1B.d.ts → utils-BpnKRFv9.d.ts} +1 -1
  233. package/dist/version.cjs +1 -1
  234. package/dist/version.cjs.map +1 -0
  235. package/dist/version.mjs +1 -1
  236. package/dist/vite.cjs +599 -104
  237. package/dist/vite.cjs.map +1 -0
  238. package/dist/vite.d.mts +2 -2
  239. package/dist/vite.d.ts +2 -2
  240. package/dist/vite.mjs +13 -11
  241. package/dist/{workflows-ChyK_oTu.d.mts → workflows-BantWytQ.d.mts} +7 -0
  242. package/dist/{workflows-ChyK_oTu.d.ts → workflows-BantWytQ.d.ts} +7 -0
  243. package/dist/workflows.cjs +73 -5
  244. package/dist/workflows.cjs.map +1 -0
  245. package/dist/workflows.d.mts +1 -1
  246. package/dist/workflows.d.ts +1 -1
  247. package/dist/workflows.mjs +2 -1
  248. package/package.json +17 -17
  249. package/dist/chunk-2SKCXYLB.mjs.map +0 -1
  250. package/dist/chunk-35NPLKQJ.mjs.map +0 -1
  251. package/dist/chunk-7ZVN3YZI.mjs.map +0 -1
  252. package/dist/chunk-AAC66ILR.mjs.map +0 -1
  253. package/dist/chunk-BZAIS65C.mjs.map +0 -1
  254. package/dist/chunk-EPDIF432.mjs.map +0 -1
  255. package/dist/chunk-FP5Q67FO.mjs.map +0 -1
  256. package/dist/chunk-ISSFLGJ5.mjs.map +0 -1
  257. package/dist/chunk-KDP5ZSWP.mjs.map +0 -1
  258. package/dist/chunk-VMCHLH3Y.mjs.map +0 -1
  259. package/dist/chunk-WKDAA6V2.mjs.map +0 -1
  260. package/dist/chunk-X4SFHKFH.mjs.map +0 -1
  261. /package/dist/{chunk-WD2EBM3I.mjs.map → chunk-3CQJV3NC.mjs.map} +0 -0
  262. /package/dist/{chunk-I3OOUWO5.mjs.map → chunk-3GDRV7SG.mjs.map} +0 -0
  263. /package/dist/{chunk-YIBV77KZ.mjs.map → chunk-4WLAVHCY.mjs.map} +0 -0
  264. /package/dist/{chunk-FSIXEIOB.mjs.map → chunk-L7FSTPGS.mjs.map} +0 -0
  265. /package/dist/{chunk-GJ7W6LNK.mjs.map → chunk-N5RK4LK6.mjs.map} +0 -0
  266. /package/dist/{chunk-UMUWR5XA.mjs.map → chunk-PURU7FXR.mjs.map} +0 -0
  267. /package/dist/{chunk-52BR7LTX.mjs.map → chunk-STSPSJUI.mjs.map} +0 -0
  268. /package/dist/{chunk-IZBX2TEU.mjs.map → chunk-VQG3QWWK.mjs.map} +0 -0
  269. /package/dist/{integration-orm-LLW6WZNK.mjs.map → integration-orm-G5BPBT5X.mjs.map} +0 -0
package/dist/vite.cjs CHANGED
@@ -922,6 +922,29 @@ var init_search_params = __esm({
922
922
  }
923
923
  });
924
924
 
925
+ // src/utils/runtime-env.ts
926
+ function getFarmRuntimeBindings() {
927
+ const runtimeBindings = globalThis.__env__;
928
+ return runtimeBindings && typeof runtimeBindings === "object" ? runtimeBindings : void 0;
929
+ }
930
+ function readFarmEnvironmentValue(name2) {
931
+ const runtimeValue = getFarmRuntimeBindings()?.[name2];
932
+ if (typeof runtimeValue === "string") return runtimeValue;
933
+ return typeof process !== "undefined" ? process.env?.[name2] : void 0;
934
+ }
935
+ function isFarmDeployedRuntime() {
936
+ if (getFarmRuntimeBindings()) return true;
937
+ return readFarmEnvironmentValue("NODE_ENV") === "production";
938
+ }
939
+ var init_runtime_env = __esm({
940
+ "src/utils/runtime-env.ts"() {
941
+ "use strict";
942
+ __name(getFarmRuntimeBindings, "getFarmRuntimeBindings");
943
+ __name(readFarmEnvironmentValue, "readFarmEnvironmentValue");
944
+ __name(isFarmDeployedRuntime, "isFarmDeployedRuntime");
945
+ }
946
+ });
947
+
925
948
  // src/utils/decode.ts
926
949
  function decodeRouteSegment(segment) {
927
950
  try {
@@ -1364,7 +1387,8 @@ function resolveWorkflowsConfig(workflows) {
1364
1387
  dirs,
1365
1388
  route: normalizeWorkflowRoute(options.route || DEFAULT_FARM_WORKFLOW_ROUTE),
1366
1389
  secretEnv: options.secretEnv || DEFAULT_FARM_WORKFLOW_SECRET_ENV,
1367
- secret: options.secret
1390
+ secret: options.secret,
1391
+ allowUnsecured: options.allowUnsecured === true
1368
1392
  };
1369
1393
  }
1370
1394
  async function discoverFarmWorkflows(config, options = {}) {
@@ -1490,8 +1514,11 @@ async function prepareFarmWorkflowsForNitro(config) {
1490
1514
  await fs14.mkdir(generatedDir, { recursive: true });
1491
1515
  const tasks = {};
1492
1516
  const scheduledTasks = createScheduledTasks(workflows);
1517
+ const wrapperNames = resolveWorkflowWrapperFileNames(workflows.map((workflow) => workflow.id));
1493
1518
  for (const workflow of workflows) {
1494
- const wrapperPath = toPosixPath(path35.join(generatedDir, `${safeFileName(workflow.id)}.mjs`));
1519
+ const wrapperPath = toPosixPath(
1520
+ path35.join(generatedDir, `${wrapperNames.get(workflow.id)}.mjs`)
1521
+ );
1495
1522
  await fs14.writeFile(wrapperPath, createNitroTaskWrapper(workflow), "utf8");
1496
1523
  tasks[workflow.id] = {
1497
1524
  handler: wrapperPath,
@@ -1729,6 +1756,7 @@ import {
1729
1756
  const route = ${JSON.stringify(config.route)};
1730
1757
  const secretEnv = ${JSON.stringify(config.secretEnv)};
1731
1758
  const inlineSecret = ${JSON.stringify(config.secret || "")};
1759
+ const allowUnsecured = ${JSON.stringify(config.allowUnsecured === true)};
1732
1760
  const bodySizeLimit = ${JSON.stringify(server.bodySizeLimit)};
1733
1761
  const workflows = ${JSON.stringify(workflows.map(toWorkflowMetadata))};
1734
1762
  const workflowIds = new Set(workflows.map((workflow) => workflow.id));
@@ -1758,7 +1786,10 @@ function getSecret() {
1758
1786
 
1759
1787
  function verifySecret(event) {
1760
1788
  const secret = getSecret();
1761
- if (!secret) return null;
1789
+ if (!secret) {
1790
+ if (allowUnsecured) return null;
1791
+ return json({ error: ${JSON.stringify(MISSING_FARM_WORKFLOW_SECRET_ERROR)} }, 401);
1792
+ }
1762
1793
  const authorization = getHeader(event, "authorization") || "";
1763
1794
  const headerSecret = getHeader(event, "x-farm-workflow-secret") || "";
1764
1795
  const bearer = authorization.match(/^Bearer\\s+(.+)$/i)?.[1] || "";
@@ -1852,8 +1883,16 @@ function readScheduledTime(payload) {
1852
1883
  return payload && typeof payload === "object" && "scheduledTime" in payload ? payload.scheduledTime : void 0;
1853
1884
  }
1854
1885
  function verifyWorkflowSecret(request, config) {
1855
- const secret = config.secret || process.env[config.secretEnv] || "";
1856
- if (!secret) return null;
1886
+ const secret = config.secret || readFarmEnvironmentValue(config.secretEnv) || "";
1887
+ if (!secret) {
1888
+ if (config.allowUnsecured === true || !isFarmDeployedRuntime()) return null;
1889
+ return Response.json(
1890
+ {
1891
+ error: MISSING_FARM_WORKFLOW_SECRET_ERROR
1892
+ },
1893
+ { status: 401 }
1894
+ );
1895
+ }
1857
1896
  const authorization = request.headers.get("authorization") || "";
1858
1897
  const bearer = authorization.match(/^Bearer\s+(.+)$/i)?.[1] || "";
1859
1898
  const headerSecret = request.headers.get("x-farm-workflow-secret") || "";
@@ -1866,18 +1905,50 @@ function joinRoute(...parts) {
1866
1905
  function trimSlashes(value) {
1867
1906
  return value.replace(/^\/+|\/+$/g, "");
1868
1907
  }
1908
+ function resolveWorkflowWrapperFileNames(ids) {
1909
+ const groups = /* @__PURE__ */ new Map();
1910
+ for (const id of ids) {
1911
+ const key = safeFileName(id).toLowerCase();
1912
+ groups.set(key, (groups.get(key) ?? 0) + 1);
1913
+ }
1914
+ const resolved = /* @__PURE__ */ new Map();
1915
+ const claimed = /* @__PURE__ */ new Map();
1916
+ for (const id of ids) {
1917
+ const base = safeFileName(id);
1918
+ const key = base.toLowerCase();
1919
+ const fileName = (groups.get(key) ?? 0) > 1 ? `${key}-${workflowIdFingerprint(id)}` : base;
1920
+ const claimedBy = claimed.get(fileName.toLowerCase());
1921
+ if (claimedBy !== void 0) {
1922
+ throw new Error(
1923
+ `Farm workflows ${JSON.stringify(claimedBy)} and ${JSON.stringify(id)} generate the same wrapper file ${JSON.stringify(`${fileName}.mjs`)}. Rename one of them.`
1924
+ );
1925
+ }
1926
+ claimed.set(fileName.toLowerCase(), id);
1927
+ resolved.set(id, fileName);
1928
+ }
1929
+ return resolved;
1930
+ }
1931
+ function workflowIdFingerprint(value) {
1932
+ let hash = 2166136261;
1933
+ for (let index = 0; index < value.length; index += 1) {
1934
+ hash ^= value.charCodeAt(index);
1935
+ hash = Math.imul(hash, 16777619);
1936
+ }
1937
+ return (hash >>> 0).toString(16).padStart(8, "0");
1938
+ }
1869
1939
  function safeFileName(value) {
1870
1940
  return value.replace(/[^a-zA-Z0-9._-]+/g, "-") || "workflow";
1871
1941
  }
1872
1942
  function relativePath(root, filePath) {
1873
1943
  return filePath.replace(/\\/g, "/").replace(`${root.replace(/\\/g, "/")}/`, "");
1874
1944
  }
1875
- var import_node_path, DEFAULT_FARM_WORKFLOW_DIRS, DEFAULT_FARM_WORKFLOW_ROUTE, DEFAULT_FARM_WORKFLOW_SECRET_ENV;
1945
+ var import_node_path, DEFAULT_FARM_WORKFLOW_DIRS, DEFAULT_FARM_WORKFLOW_ROUTE, DEFAULT_FARM_WORKFLOW_SECRET_ENV, MISSING_FARM_WORKFLOW_SECRET_ERROR;
1876
1946
  var init_workflows = __esm({
1877
1947
  "src/workflows.ts"() {
1878
1948
  "use strict";
1879
1949
  init_server_http();
1880
1950
  init_search_params();
1951
+ init_runtime_env();
1881
1952
  init_decode();
1882
1953
  init_utils();
1883
1954
  init_route_pattern();
@@ -1885,6 +1956,7 @@ var init_workflows = __esm({
1885
1956
  DEFAULT_FARM_WORKFLOW_DIRS = ["src/jobs", "src/workflows", "src/cron"];
1886
1957
  DEFAULT_FARM_WORKFLOW_ROUTE = "/api/_farm/workflows";
1887
1958
  DEFAULT_FARM_WORKFLOW_SECRET_ENV = "CRON_SECRET";
1959
+ MISSING_FARM_WORKFLOW_SECRET_ERROR = "Workflow route requires a secret. Set the CRON_SECRET environment variable, configure workflows.secret, or set workflows.allowUnsecured to true.";
1888
1960
  __name(defineWorkflow, "defineWorkflow");
1889
1961
  __name(defineTask, "defineTask");
1890
1962
  __name(defineCron, "defineCron");
@@ -1917,6 +1989,8 @@ var init_workflows = __esm({
1917
1989
  __name(verifyWorkflowSecret, "verifyWorkflowSecret");
1918
1990
  __name(joinRoute, "joinRoute");
1919
1991
  __name(trimSlashes, "trimSlashes");
1992
+ __name(resolveWorkflowWrapperFileNames, "resolveWorkflowWrapperFileNames");
1993
+ __name(workflowIdFingerprint, "workflowIdFingerprint");
1920
1994
  __name(safeFileName, "safeFileName");
1921
1995
  __name(relativePath, "relativePath");
1922
1996
  }
@@ -2067,6 +2141,7 @@ var init_cron = __esm({
2067
2141
  "src/cron.ts"() {
2068
2142
  "use strict";
2069
2143
  init_utils();
2144
+ init_runtime_env();
2070
2145
  DEFAULT_FARM_CRON_SECRET_ENV = "CRON_SECRET";
2071
2146
  CRON_FIELD_RANGES = [
2072
2147
  [0, 59, "minute"],
@@ -2447,9 +2522,13 @@ function getStorage(namespace) {
2447
2522
  const namespaced = (0, import_unstorage.prefixStorage)(globalStorage, base);
2448
2523
  return {
2449
2524
  ...namespaced,
2450
- async clear() {
2451
- const keys = await namespaced.getKeys();
2452
- await Promise.all(keys.map((key) => namespaced.removeItem(key)));
2525
+ // Scope the wipe to the namespace instead of the whole storage, and keep
2526
+ // the caller's base so `clear("sessions")` cannot take unrelated keys with
2527
+ // it. Dropping the argument silently widens a targeted clear into a
2528
+ // namespace-wide delete.
2529
+ async clear(base2, opts) {
2530
+ const keys = await namespaced.getKeys(base2);
2531
+ await Promise.all(keys.map((key) => namespaced.removeItem(key, opts)));
2453
2532
  }
2454
2533
  };
2455
2534
  }
@@ -3383,6 +3462,46 @@ var init_cache_invalidation = __esm({
3383
3462
  }
3384
3463
  });
3385
3464
 
3465
+ // src/request-origin.ts
3466
+ function normalizeAllowedOriginPattern(value, label) {
3467
+ const pattern = value.trim().toLowerCase();
3468
+ if (!pattern) {
3469
+ throw new TypeError(`${label} cannot contain empty values`);
3470
+ }
3471
+ if (pattern.includes("*")) {
3472
+ if (!/^(?:https?:\/\/)?\*\.[a-z0-9.-]+(?::\d+)?$/.test(pattern)) {
3473
+ throw new TypeError(`Invalid ${label} pattern: ${JSON.stringify(value)}`);
3474
+ }
3475
+ return pattern;
3476
+ }
3477
+ if (pattern.includes("://")) {
3478
+ let parsed;
3479
+ try {
3480
+ parsed = new URL(pattern);
3481
+ } catch {
3482
+ throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);
3483
+ }
3484
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
3485
+ throw new TypeError(`${label} must contain origins without paths: ${JSON.stringify(value)}`);
3486
+ }
3487
+ return parsed.origin;
3488
+ }
3489
+ if (/[/@?#]/.test(pattern)) {
3490
+ throw new TypeError(`${label} must contain origins or hosts: ${JSON.stringify(value)}`);
3491
+ }
3492
+ try {
3493
+ return new URL(`http://${pattern}`).host;
3494
+ } catch {
3495
+ throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);
3496
+ }
3497
+ }
3498
+ var init_request_origin = __esm({
3499
+ "src/request-origin.ts"() {
3500
+ "use strict";
3501
+ __name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
3502
+ }
3503
+ });
3504
+
3386
3505
  // src/server-fn-error.ts
3387
3506
  var init_server_fn_error = __esm({
3388
3507
  "src/server-fn-error.ts"() {
@@ -3392,7 +3511,9 @@ var init_server_fn_error = __esm({
3392
3511
 
3393
3512
  // src/server-action-security.ts
3394
3513
  function resolveServerActionsConfig(config) {
3395
- const allowedOrigins = (config?.allowedOrigins ?? []).map(normalizeAllowedOriginPattern);
3514
+ const allowedOrigins = (config?.allowedOrigins ?? []).map(
3515
+ (value) => normalizeAllowedOriginPattern(value, SERVER_ACTION_ALLOWED_ORIGINS_LABEL)
3516
+ );
3396
3517
  const bodySizeLimit = parseBodySizeLimit(
3397
3518
  config?.bodySizeLimit ?? DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT,
3398
3519
  "serverActions.bodySizeLimit"
@@ -3412,50 +3533,16 @@ function getServerActionStorage() {
3412
3533
  }
3413
3534
  return globalState2[SERVER_ACTION_STORAGE_KEY];
3414
3535
  }
3415
- function normalizeAllowedOriginPattern(value) {
3416
- const pattern = value.trim().toLowerCase();
3417
- if (!pattern) {
3418
- throw new TypeError("serverActions.allowedOrigins cannot contain empty values");
3419
- }
3420
- if (pattern.includes("*")) {
3421
- if (!/^(?:https?:\/\/)?\*\.[a-z0-9.-]+(?::\d+)?$/.test(pattern)) {
3422
- throw new TypeError(`Invalid serverActions.allowedOrigins pattern: ${JSON.stringify(value)}`);
3423
- }
3424
- return pattern;
3425
- }
3426
- if (pattern.includes("://")) {
3427
- let parsed;
3428
- try {
3429
- parsed = new URL(pattern);
3430
- } catch {
3431
- throw new TypeError(`Invalid serverActions.allowedOrigins value: ${JSON.stringify(value)}`);
3432
- }
3433
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
3434
- throw new TypeError(
3435
- `serverActions.allowedOrigins must contain origins without paths: ${JSON.stringify(value)}`
3436
- );
3437
- }
3438
- return parsed.origin;
3439
- }
3440
- if (/[/@?#]/.test(pattern)) {
3441
- throw new TypeError(
3442
- `serverActions.allowedOrigins must contain origins or hosts: ${JSON.stringify(value)}`
3443
- );
3444
- }
3445
- try {
3446
- return new URL(`http://${pattern}`).host;
3447
- } catch {
3448
- throw new TypeError(`Invalid serverActions.allowedOrigins value: ${JSON.stringify(value)}`);
3449
- }
3450
- }
3451
- var import_node_async_hooks, DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT, SERVER_ACTION_STORAGE_KEY;
3536
+ var import_node_async_hooks, SERVER_ACTION_ALLOWED_ORIGINS_LABEL, DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT, SERVER_ACTION_STORAGE_KEY;
3452
3537
  var init_server_action_security = __esm({
3453
3538
  "src/server-action-security.ts"() {
3454
3539
  "use strict";
3455
3540
  import_node_async_hooks = require("async_hooks");
3456
3541
  init_cache_invalidation();
3542
+ init_request_origin();
3457
3543
  init_server_fn_error();
3458
3544
  init_server_http();
3545
+ SERVER_ACTION_ALLOWED_ORIGINS_LABEL = "serverActions.allowedOrigins";
3459
3546
  DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT = 1e6;
3460
3547
  SERVER_ACTION_STORAGE_KEY = /* @__PURE__ */ Symbol.for("farm.serverActionStorage");
3461
3548
  __name(resolveServerActionsConfig, "resolveServerActionsConfig");
@@ -3467,7 +3554,6 @@ var init_server_action_security = __esm({
3467
3554
  getServerActionExecutionContext()?.cacheTasks.add(task);
3468
3555
  });
3469
3556
  __name(getServerActionStorage, "getServerActionStorage");
3470
- __name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
3471
3557
  }
3472
3558
  });
3473
3559
 
@@ -5740,6 +5826,14 @@ var init_routes = __esm({
5740
5826
  }
5741
5827
  });
5742
5828
 
5829
+ // src/integration-request-security.ts
5830
+ var init_integration_request_security = __esm({
5831
+ "src/integration-request-security.ts"() {
5832
+ "use strict";
5833
+ init_request_origin();
5834
+ }
5835
+ });
5836
+
5743
5837
  // src/integration-api.ts
5744
5838
  function defineIntegrationAPIOperation(operation) {
5745
5839
  return {
@@ -7205,6 +7299,7 @@ var init_integrations = __esm({
7205
7299
  "src/integrations.ts"() {
7206
7300
  "use strict";
7207
7301
  init_route_pattern();
7302
+ init_integration_request_security();
7208
7303
  init_integration_api();
7209
7304
  init_plugin_integration_context();
7210
7305
  init_decode();
@@ -7388,6 +7483,45 @@ var init_renderer = __esm({
7388
7483
  }
7389
7484
  });
7390
7485
 
7486
+ // src/agent-config.ts
7487
+ function pruneUndefined(object) {
7488
+ const result = {};
7489
+ for (const [key, value] of Object.entries(object)) {
7490
+ if (value !== void 0 && value !== null && value !== "") result[key] = value;
7491
+ }
7492
+ return result;
7493
+ }
7494
+ function serializeJsonLd(value) {
7495
+ return JSON.stringify(value).replace(/</g, "\\u003c");
7496
+ }
7497
+ function renderFarmAgentJsonLd(config, context2) {
7498
+ const base = pruneUndefined({
7499
+ name: config.name ?? context2.siteName ?? context2.title,
7500
+ url: config.url ?? context2.metadataBase,
7501
+ description: config.description ?? context2.description,
7502
+ logo: config.logo,
7503
+ sameAs: config.sameAs && config.sameAs.length > 0 ? config.sameAs : void 0
7504
+ });
7505
+ const object = {
7506
+ "@context": "https://schema.org",
7507
+ "@type": config.type || "Organization",
7508
+ ...base,
7509
+ ...config.properties || {}
7510
+ };
7511
+ if (Object.keys(object).length <= 2 && !config.properties) {
7512
+ return "";
7513
+ }
7514
+ return `<script type="application/ld+json">${serializeJsonLd(object)}</script>`;
7515
+ }
7516
+ var init_agent_config = __esm({
7517
+ "src/agent-config.ts"() {
7518
+ "use strict";
7519
+ __name(pruneUndefined, "pruneUndefined");
7520
+ __name(serializeJsonLd, "serializeJsonLd");
7521
+ __name(renderFarmAgentJsonLd, "renderFarmAgentJsonLd");
7522
+ }
7523
+ });
7524
+
7391
7525
  // src/deployment.ts
7392
7526
  function getFarmRequestDeploymentId(request) {
7393
7527
  const headerValue = request.headers.get(FARM_DEPLOYMENT_ID_HEADER)?.trim();
@@ -8802,6 +8936,7 @@ export const apiRoutes = ${manifestSource} as const;
8802
8936
  function createFarmImageHandler(config, options) {
8803
8937
  const fetcher = options.fetch ?? globalThis.fetch;
8804
8938
  const cache = new FarmImageMemoryCache(options.cacheEntries ?? 100);
8939
+ const inflight = /* @__PURE__ */ new Map();
8805
8940
  const allowedWidths = /* @__PURE__ */ new Set([...config.deviceSizes, ...config.imageSizes]);
8806
8941
  const allowedQualities = new Set(config.qualities);
8807
8942
  return /* @__PURE__ */ __name(async function handleFarmImage(request) {
@@ -8830,50 +8965,55 @@ function createFarmImageHandler(config, options) {
8830
8965
  "quality"
8831
8966
  );
8832
8967
  const accept = request.headers.get("accept") ?? "";
8968
+ const negotiatedFormat = selectOutputFormat(accept, config.formats) ?? "";
8833
8969
  const cacheKey = `${sourceUrl.href}
8834
8970
  ${width}
8835
8971
  ${quality}
8836
- ${accept}`;
8972
+ ${negotiatedFormat}`;
8837
8973
  let optimized = cache.get(cacheKey);
8838
8974
  if (!optimized) {
8839
- const fetchedSource = await fetchImageSource(
8840
- sourceUrl,
8841
- requestUrl.origin,
8842
- config,
8843
- fetcher,
8844
- options.fetchRemote,
8845
- options.validateRemoteUrl,
8846
- request.signal
8847
- );
8848
- const source = await readResponseWithLimit(
8849
- fetchedSource.response,
8850
- config.maximumResponseBody
8851
- );
8852
- const sourceType = detectImageContentType(source);
8853
- validateSourceType(sourceType, config);
8854
- throwIfAborted2(request.signal);
8855
- const result = await options.transform({
8856
- source,
8857
- sourceUrl: fetchedSource.url,
8858
- sourceType,
8859
- width,
8860
- quality,
8861
- accept,
8862
- formats: config.formats,
8863
- signal: request.signal
8975
+ optimized = await runCoalesced(inflight, cacheKey, request.signal, async (signal) => {
8976
+ const fetchedSource = await fetchImageSource(
8977
+ sourceUrl,
8978
+ requestUrl.origin,
8979
+ config,
8980
+ fetcher,
8981
+ options.fetchRemote,
8982
+ options.validateRemoteUrl,
8983
+ signal
8984
+ );
8985
+ const source = await readResponseWithLimit(
8986
+ fetchedSource.response,
8987
+ config.maximumResponseBody
8988
+ );
8989
+ const sourceType = detectImageContentType(source);
8990
+ validateSourceType(sourceType, config);
8991
+ throwIfAborted2(signal);
8992
+ const result = await options.transform({
8993
+ source,
8994
+ sourceUrl: fetchedSource.url,
8995
+ sourceType,
8996
+ width,
8997
+ quality,
8998
+ accept,
8999
+ formats: config.formats,
9000
+ signal,
9001
+ maximumResponseBody: config.maximumResponseBody
9002
+ });
9003
+ throwIfAborted2(signal);
9004
+ validateTransformedResult(result, config);
9005
+ const entry = {
9006
+ ...result,
9007
+ etag: createImageEtag(result.body),
9008
+ cacheControl: `public, max-age=${config.minimumCacheTTL}, stale-while-revalidate=${Math.max(
9009
+ config.minimumCacheTTL,
9010
+ 60
9011
+ )}`,
9012
+ expiresAt: Date.now() + config.minimumCacheTTL * 1e3
9013
+ };
9014
+ cache.set(cacheKey, entry);
9015
+ return entry;
8864
9016
  });
8865
- throwIfAborted2(request.signal);
8866
- validateTransformedResult(result, config);
8867
- optimized = {
8868
- ...result,
8869
- etag: createImageEtag(result.body),
8870
- cacheControl: `public, max-age=${config.minimumCacheTTL}, stale-while-revalidate=${Math.max(
8871
- config.minimumCacheTTL,
8872
- 60
8873
- )}`,
8874
- expiresAt: Date.now() + config.minimumCacheTTL * 1e3
8875
- };
8876
- cache.set(cacheKey, optimized);
8877
9017
  }
8878
9018
  return createOptimizedImageResponse(request, optimized, config);
8879
9019
  } catch (error) {
@@ -9024,6 +9164,44 @@ async function fetchImageSource(initialUrl, requestOrigin, config, fetcher, fetc
9024
9164
  await validateImageSourceUrl(currentUrl, requestOrigin, config, validateRemoteUrl);
9025
9165
  }
9026
9166
  }
9167
+ async function runCoalesced(inflight, key, requestSignal, run) {
9168
+ let entry = inflight.get(key);
9169
+ if (!entry) {
9170
+ const controller = new AbortController();
9171
+ const created = {
9172
+ controller,
9173
+ waiters: 0,
9174
+ promise: void 0
9175
+ };
9176
+ created.promise = run(controller.signal).finally(() => {
9177
+ if (inflight.get(key) === created) inflight.delete(key);
9178
+ });
9179
+ created.promise.catch(() => {
9180
+ });
9181
+ inflight.set(key, created);
9182
+ entry = created;
9183
+ }
9184
+ const pending = entry;
9185
+ pending.waiters += 1;
9186
+ try {
9187
+ return await raceRequestAbort(pending.promise, requestSignal);
9188
+ } finally {
9189
+ pending.waiters -= 1;
9190
+ if (pending.waiters === 0 && inflight.get(key) === pending) {
9191
+ inflight.delete(key);
9192
+ pending.controller.abort();
9193
+ }
9194
+ }
9195
+ }
9196
+ function raceRequestAbort(promise, signal) {
9197
+ if (!signal) return promise;
9198
+ if (signal.aborted) return Promise.reject(signal.reason ?? new Error("Aborted"));
9199
+ return new Promise((resolve10, reject) => {
9200
+ const onAbort = /* @__PURE__ */ __name(() => reject(signal.reason ?? new Error("Aborted")), "onAbort");
9201
+ signal.addEventListener("abort", onAbort, { once: true });
9202
+ promise.then(resolve10, reject).finally(() => signal.removeEventListener("abort", onAbort));
9203
+ });
9204
+ }
9027
9205
  async function readResponseWithLimit(response, limit) {
9028
9206
  const contentLength = response.headers.get("content-length");
9029
9207
  if (contentLength && Number(contentLength) > limit) {
@@ -9191,7 +9369,7 @@ function throwIfAborted2(signal) {
9191
9369
  function isAbortError(error) {
9192
9370
  return error instanceof Error && error.name === "AbortError";
9193
9371
  }
9194
- var _FarmImageRequestError, FarmImageRequestError, _FarmImageMemoryCache, FarmImageMemoryCache;
9372
+ var _FarmImageRequestError, FarmImageRequestError, DEFAULT_IMAGE_TRANSFORM_BODY_LIMIT, _FarmImageMemoryCache, FarmImageMemoryCache;
9195
9373
  var init_image_server = __esm({
9196
9374
  "src/image-server.ts"() {
9197
9375
  "use strict";
@@ -9207,12 +9385,15 @@ var init_image_server = __esm({
9207
9385
  __name(_FarmImageRequestError, "FarmImageRequestError");
9208
9386
  FarmImageRequestError = _FarmImageRequestError;
9209
9387
  __name(createFarmImageHandler, "createFarmImageHandler");
9388
+ DEFAULT_IMAGE_TRANSFORM_BODY_LIMIT = 10 * 1024 * 1024;
9210
9389
  __name(selectOutputFormat, "selectOutputFormat");
9211
9390
  __name(isPrivateImageAddress, "isPrivateImageAddress");
9212
9391
  __name(parseAllowedInteger, "parseAllowedInteger");
9213
9392
  __name(resolveImageSourceUrl, "resolveImageSourceUrl");
9214
9393
  __name(validateImageSourceUrl, "validateImageSourceUrl");
9215
9394
  __name(fetchImageSource, "fetchImageSource");
9395
+ __name(runCoalesced, "runCoalesced");
9396
+ __name(raceRequestAbort, "raceRequestAbort");
9216
9397
  __name(readResponseWithLimit, "readResponseWithLimit");
9217
9398
  __name(cancelResponseBody, "cancelResponseBody");
9218
9399
  __name(detectImageContentType, "detectImageContentType");
@@ -11828,6 +12009,7 @@ var init_config4 = __esm({
11828
12009
  init_security();
11829
12010
  init_navigation_errors();
11830
12011
  init_config2();
12012
+ init_agent_config();
11831
12013
  init_renderer();
11832
12014
  init_framework_detect();
11833
12015
  init_config3();
@@ -15871,6 +16053,21 @@ function isFarmMarkdownPageFile(filePath) {
15871
16053
  return /(^|[/\\])page\.mdx?$/i.test(filePath);
15872
16054
  }
15873
16055
  __name(isFarmMarkdownPageFile, "isFarmMarkdownPageFile");
16056
+ var FARM_MARKDOWN_CONTENT_TYPE = "text/markdown; charset=utf-8";
16057
+ function farmRequestWantsMarkdown(pathname, accept) {
16058
+ return pathname.toLowerCase().endsWith(".md") || requestAcceptsMarkdown(accept);
16059
+ }
16060
+ __name(farmRequestWantsMarkdown, "farmRequestWantsMarkdown");
16061
+ function createFarmMarkdownErrorBody(status, pathname, homeHref = "/") {
16062
+ const heading = status === 404 ? "Page not found" : `Request failed (${status})`;
16063
+ return `# ${heading}
16064
+
16065
+ No page is available at \`${pathname}\`. The URL may be incorrect, or the page has not been published.
16066
+
16067
+ Browse [the site homepage](${homeHref}) to find available pages.
16068
+ `;
16069
+ }
16070
+ __name(createFarmMarkdownErrorBody, "createFarmMarkdownErrorBody");
15874
16071
  function normalizeFarmMarkdownRoutePath(pathname) {
15875
16072
  const withoutExtension = pathname.replace(/\.md$/i, "");
15876
16073
  const normalized = withoutExtension.startsWith("/") ? withoutExtension : `/${withoutExtension}`;
@@ -16591,6 +16788,50 @@ function getStaticImportBindings(content) {
16591
16788
  return bindings;
16592
16789
  }
16593
16790
  __name(getStaticImportBindings, "getStaticImportBindings");
16791
+ var PARSER_SENSITIVE_JSX_CONTAINERS = /* @__PURE__ */ new Set([
16792
+ "table",
16793
+ "thead",
16794
+ "tbody",
16795
+ "tfoot",
16796
+ "tr",
16797
+ "select",
16798
+ "optgroup",
16799
+ "svg"
16800
+ ]);
16801
+ function findParserSensitiveJsxContainer(content, localBindings) {
16802
+ if (!content || localBindings.length === 0) return void 0;
16803
+ const names = new Set(localBindings);
16804
+ const tokens = tokenizeModuleSource(content);
16805
+ const openDepth = /* @__PURE__ */ new Map();
16806
+ const isSelfClosing = /* @__PURE__ */ __name((openingIndex) => {
16807
+ for (let index = openingIndex; index < tokens.length; index++) {
16808
+ if (tokens[index].value === ">") return tokens[index - 1]?.value === "/";
16809
+ }
16810
+ return false;
16811
+ }, "isSelfClosing");
16812
+ for (let index = 0; index < tokens.length - 1; index++) {
16813
+ if (tokens[index].value !== "<") continue;
16814
+ if (tokens[index + 1].value === "/") {
16815
+ const closing = tokens[index + 2]?.value;
16816
+ if (closing && openDepth.has(closing)) {
16817
+ openDepth.set(closing, Math.max(0, (openDepth.get(closing) ?? 0) - 1));
16818
+ }
16819
+ continue;
16820
+ }
16821
+ const tag = tokens[index + 1].value;
16822
+ if (names.has(tag)) {
16823
+ for (const [container, depth] of openDepth) {
16824
+ if (depth > 0) return container;
16825
+ }
16826
+ continue;
16827
+ }
16828
+ if (PARSER_SENSITIVE_JSX_CONTAINERS.has(tag) && !isSelfClosing(index)) {
16829
+ openDepth.set(tag, (openDepth.get(tag) ?? 0) + 1);
16830
+ }
16831
+ }
16832
+ return void 0;
16833
+ }
16834
+ __name(findParserSensitiveJsxContainer, "findParserSensitiveJsxContainer");
16594
16835
  function countStaticJsxUses(content, localBindings) {
16595
16836
  if (!content || localBindings.length === 0) return 0;
16596
16837
  const names = new Set(localBindings);
@@ -16704,6 +16945,37 @@ function getClientRenderingHelpers(tokens, clientBindings) {
16704
16945
  return helpers;
16705
16946
  }
16706
16947
  __name(getClientRenderingHelpers, "getClientRenderingHelpers");
16948
+ function passesElementValuedProps(content, localBindings) {
16949
+ if (!content || localBindings.length === 0) return false;
16950
+ const names = new Set(localBindings);
16951
+ const tokens = tokenizeModuleSource(content);
16952
+ for (let index = 0; index < tokens.length - 1; index++) {
16953
+ if (tokens[index].value !== "<" || !names.has(tokens[index + 1].value)) continue;
16954
+ const name2 = tokens[index + 1].value;
16955
+ let cursor = index + 2;
16956
+ let braceDepth = 0;
16957
+ let selfClosing = false;
16958
+ for (; cursor < tokens.length; cursor++) {
16959
+ const value = tokens[cursor].value;
16960
+ if (value === "{") braceDepth++;
16961
+ else if (value === "}") braceDepth--;
16962
+ else if (value === "<" && braceDepth > 0) return true;
16963
+ else if (value === ">" && braceDepth === 0) {
16964
+ selfClosing = tokens[cursor - 1]?.value === "/";
16965
+ break;
16966
+ }
16967
+ }
16968
+ if (selfClosing || cursor >= tokens.length) continue;
16969
+ for (let child = cursor + 1; child < tokens.length; child++) {
16970
+ if (tokens[child].value !== "<") continue;
16971
+ const closesBoundary = tokens[child + 1]?.value === "/" && tokens[child + 2]?.value === name2;
16972
+ if (!closesBoundary) return true;
16973
+ break;
16974
+ }
16975
+ }
16976
+ return false;
16977
+ }
16978
+ __name(passesElementValuedProps, "passesElementValuedProps");
16707
16979
  function hasDynamicJsxCardinality(content, localBindings) {
16708
16980
  if (!content || localBindings.length === 0) return false;
16709
16981
  const clientBindings = new Set(localBindings);
@@ -16786,6 +17058,17 @@ function collectIsolatedClientBoundaries(ownerPath, root) {
16786
17058
  if (fallbackReason || importedBoundaryCount === 0) continue;
16787
17059
  const localBindings = importedBindings.get(specifier) ?? [];
16788
17060
  const staticUses = countStaticJsxUses(content, localBindings);
17061
+ if (staticUses > 0) {
17062
+ const container = findParserSensitiveJsxContainer(content, localBindings);
17063
+ if (container) {
17064
+ fallbackReason = `the client boundary imported from ${specifier} renders inside <${container}>, where the HTML parser relocates its hydration marker`;
17065
+ return 0;
17066
+ }
17067
+ if (passesElementValuedProps(content, localBindings)) {
17068
+ fallbackReason = `the client boundary imported from ${specifier} receives React elements, which cannot cross the boundary as serialized props`;
17069
+ return 0;
17070
+ }
17071
+ }
16789
17072
  if (staticUses > 0 && hasDynamicJsxCardinality(content, localBindings)) {
16790
17073
  fallbackReason = `the client boundary count imported from ${specifier} is data-dependent`;
16791
17074
  costGuardExceeded = true;
@@ -18616,6 +18899,7 @@ init_observability();
18616
18899
  init_navigation_errors();
18617
18900
 
18618
18901
  // src/metadata.ts
18902
+ init_agent_config();
18619
18903
  function mergeMetadata(base, next) {
18620
18904
  if (!base) return next ? { ...next } : {};
18621
18905
  if (!next) return { ...base };
@@ -18678,7 +18962,7 @@ function addMetadataImageReference(metadata, reference) {
18678
18962
  };
18679
18963
  }
18680
18964
  __name(addMetadataImageReference, "addMetadataImageReference");
18681
- function renderMetadataHead(metadata) {
18965
+ function renderMetadataHead(metadata, options = {}) {
18682
18966
  const resolvedMetadata = metadata || {};
18683
18967
  const metadataBase = resolveMetadataBase(resolvedMetadata);
18684
18968
  const explicitTitle = resolveMetadataTitle(resolvedMetadata.title);
@@ -18699,14 +18983,16 @@ function renderMetadataHead(metadata) {
18699
18983
  appendMetaName(tags, "publisher", resolvedMetadata.publisher);
18700
18984
  appendMetaName(tags, "robots", normalizeRobots(resolvedMetadata.robots));
18701
18985
  const alternates = resolvedMetadata.alternates;
18702
- if (isRecord(alternates)) {
18703
- appendLink(tags, "canonical", resolveMetadataUrl(alternates.canonical, metadataBase));
18704
- if (isRecord(alternates.languages)) {
18705
- for (const [language, href] of Object.entries(alternates.languages)) {
18706
- appendLink(tags, "alternate", resolveMetadataUrl(href, metadataBase), {
18707
- hreflang: language
18708
- });
18709
- }
18986
+ const explicitCanonical = isRecord(alternates) ? alternates.canonical : void 0;
18987
+ const canonicalHref = explicitCanonical != null ? resolveMetadataUrl(explicitCanonical, metadataBase) : options.pathname ? resolveMetadataUrl(options.pathname, metadataBase) : void 0;
18988
+ if (canonicalHref) {
18989
+ appendLink(tags, "canonical", canonicalHref);
18990
+ }
18991
+ if (isRecord(alternates) && isRecord(alternates.languages)) {
18992
+ for (const [language, href] of Object.entries(alternates.languages)) {
18993
+ appendLink(tags, "alternate", resolveMetadataUrl(href, metadataBase), {
18994
+ hreflang: language
18995
+ });
18710
18996
  }
18711
18997
  }
18712
18998
  const hasFavicon = appendIcons(tags, resolvedMetadata.icons, metadataBase);
@@ -18719,6 +19005,16 @@ function renderMetadataHead(metadata) {
18719
19005
  }
18720
19006
  appendOpenGraph(tags, resolvedMetadata.openGraph, metadataBase);
18721
19007
  appendTwitter(tags, resolvedMetadata.twitter, metadataBase);
19008
+ if (options.jsonLd) {
19009
+ const jsonLdConfig = options.jsonLd === true ? {} : options.jsonLd;
19010
+ const jsonLdScript = renderFarmAgentJsonLd(jsonLdConfig, {
19011
+ metadataBase,
19012
+ siteName: isRecord(resolvedMetadata.openGraph) ? normalizeContent(resolvedMetadata.openGraph.siteName) : void 0,
19013
+ title: explicitTitle,
19014
+ description: normalizeContent(resolvedMetadata.description)
19015
+ });
19016
+ if (jsonLdScript) tags.push(jsonLdScript);
19017
+ }
18722
19018
  return {
18723
19019
  title: escapeText(title),
18724
19020
  tags: tags.length > 0 ? `
@@ -18744,7 +19040,7 @@ function appendOpenGraph(tags, openGraph, metadataBase) {
18744
19040
  appendMetaProperty(tags, "og:description", openGraph.description);
18745
19041
  appendMetaProperty(tags, "og:url", resolveMetadataUrl(openGraph.url, metadataBase));
18746
19042
  appendMetaProperty(tags, "og:site_name", openGraph.siteName);
18747
- appendMetaProperty(tags, "og:type", openGraph.type);
19043
+ appendMetaProperty(tags, "og:type", openGraph.type ?? "website");
18748
19044
  appendMetaProperty(tags, "og:locale", openGraph.locale);
18749
19045
  const images = normalizeMetadataImages(
18750
19046
  openGraph.images ?? openGraph.image,
@@ -21899,7 +22195,7 @@ _setFarmThemeServerSnapshotResolver(() => {
21899
22195
  });
21900
22196
 
21901
22197
  // package.json
21902
- var version = "0.1.0-beta.97";
22198
+ var version = "0.1.0-beta.99";
21903
22199
 
21904
22200
  // src/version.ts
21905
22201
  var FARM_VERSION = version;
@@ -22069,6 +22365,13 @@ function hasRequestHeader(req, name2) {
22069
22365
  return Array.isArray(value) ? value.length > 0 : Boolean(value);
22070
22366
  }
22071
22367
  __name(hasRequestHeader, "hasRequestHeader");
22368
+ function getFarmMetadataPathname(req) {
22369
+ const raw = req.__FARM_ROUTE__ || req.url;
22370
+ if (typeof raw !== "string" || raw.length === 0) return void 0;
22371
+ const boundary = raw.search(/[?#]/);
22372
+ return boundary === -1 ? raw : raw.slice(0, boundary);
22373
+ }
22374
+ __name(getFarmMetadataPathname, "getFarmMetadataPathname");
22072
22375
  function serializeInlineValue2(value) {
22073
22376
  return JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
22074
22377
  }
@@ -22602,7 +22905,21 @@ var _ServerRenderer = class _ServerRenderer {
22602
22905
  const html = await this.rendererRuntime.renderToString(
22603
22906
  await this.wrapWithIntegrationProviders(pageElement)
22604
22907
  );
22605
- await this.cacheSSGPage(page2, html, { document: false });
22908
+ const mergedMetadata = await this.resolveRouteMetadata({
22909
+ layoutModules,
22910
+ routeModule: mod,
22911
+ pageProps,
22912
+ pathname: page2.urlPath
22913
+ });
22914
+ const { title, tags, hasFavicon } = renderMetadataHead(mergedMetadata);
22915
+ const metadataHead = `${hasFavicon ? "" : '<link rel="icon" href="data:,">\n '}<title>${title}</title>${tags}`;
22916
+ const fullDocument = this.createFullHTML(
22917
+ html,
22918
+ pageMetadata.shouldHydrate === true,
22919
+ page2.urlPath,
22920
+ metadataHead
22921
+ );
22922
+ await this.cacheSSGPage(page2, fullDocument, { document: true });
22606
22923
  logger.info(`ISR: Regenerated ${page2.urlPath}`);
22607
22924
  } catch (error) {
22608
22925
  logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
@@ -23642,7 +23959,10 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
23642
23959
  tags: metaTags,
23643
23960
  hasFavicon,
23644
23961
  hasExplicitTitle
23645
- } = renderMetadataHead(req.__FARM_METADATA__);
23962
+ } = renderMetadataHead(req.__FARM_METADATA__, {
23963
+ pathname: getFarmMetadataPathname(req),
23964
+ jsonLd: this.config.agent?.jsonLd
23965
+ });
23646
23966
  const documentTitleTag = !hasExplicitTitle && /<title[\s>]/i.test(rendererHead) ? "" : `<title>${title}</title>`;
23647
23967
  const i18nSnapshot = getFarmI18nClientSnapshot();
23648
23968
  const alternateTags = i18nSnapshot ? renderI18nAlternateLinks(req.__FARM_ROUTE__ || req.url || "/", i18nSnapshot) : "";
@@ -23827,7 +24147,10 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
23827
24147
  title,
23828
24148
  tags: metaTags,
23829
24149
  hasFavicon
23830
- } = renderMetadataHead(req.__FARM_METADATA__);
24150
+ } = renderMetadataHead(req.__FARM_METADATA__, {
24151
+ pathname: getFarmMetadataPathname(req),
24152
+ jsonLd: this.config.agent?.jsonLd
24153
+ });
23831
24154
  const i18nSnapshot = getFarmI18nClientSnapshot();
23832
24155
  const i18nAlternateTags = i18nSnapshot ? renderI18nAlternateLinks(req.__FARM_ROUTE__ || req.url || "/", i18nSnapshot) : "";
23833
24156
  const fontHead = renderFarmFontDevHead(this.config.root || process.cwd());
@@ -23985,6 +24308,15 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
23985
24308
  const pathname = resolveFarmRequestURL(req, {
23986
24309
  trustProxy: this.config.server?.trustProxy
23987
24310
  }).pathname;
24311
+ const acceptHeader = req.headers.accept;
24312
+ const accept = Array.isArray(acceptHeader) ? acceptHeader.join(",") : acceptHeader;
24313
+ if (farmRequestWantsMarkdown(pathname, accept)) {
24314
+ res.setHeader("Content-Type", FARM_MARKDOWN_CONTENT_TYPE);
24315
+ res.setHeader("X-Farm-Markdown-Error", "404");
24316
+ res.setHeader("Cache-Control", "no-store");
24317
+ res.end(createFarmMarkdownErrorBody(404, pathname, this.config.basePath || "/"));
24318
+ return;
24319
+ }
23988
24320
  try {
23989
24321
  const appDir = path12.join(this.config.root, this.config.srcDir, "app");
23990
24322
  const notFoundExtensions = getFarmRendererComponentExtensions(this.config.renderer);
@@ -24070,7 +24402,7 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
24070
24402
  res.write(html);
24071
24403
  res.end();
24072
24404
  }
24073
- createFullHTML(content, isClientComponent = false, requestPath = "/", documentTitle = "Farm.js App") {
24405
+ createFullHTML(content, isClientComponent = false, requestPath = "/", metadataHead) {
24074
24406
  const i18nSnapshot = getFarmI18nClientSnapshot();
24075
24407
  const clientScript = isClientComponent ? ` <script type="module" src="/@farm/client.js"></script>` : "";
24076
24408
  const integrationManifestScript = `<script>
@@ -24094,6 +24426,7 @@ ${i18nSnapshot ? `window.__FARM_I18N__ = ${serializeInlineValue2(i18nSnapshot)};
24094
24426
  headAssets: [
24095
24427
  themeDocument.head,
24096
24428
  `<meta name="farm-deployment-id" content="${escapeHtmlAttribute2(this.getDeploymentId())}">`,
24429
+ metadataHead,
24097
24430
  alternateLinks,
24098
24431
  fontHead,
24099
24432
  `<link rel="stylesheet" href="/src/app/globals.css" />`,
@@ -24112,8 +24445,7 @@ ${i18nSnapshot ? `window.__FARM_I18N__ = ${serializeInlineValue2(i18nSnapshot)};
24112
24445
  <meta charset="utf-8">
24113
24446
  <meta name="viewport" content="width=device-width, initial-scale=1">
24114
24447
  <meta name="farm-deployment-id" content="${escapeHtmlAttribute2(this.getDeploymentId())}">
24115
- <link rel="icon" href="data:,">
24116
- <title>${escapeHtmlAttribute2(documentTitle)}</title>${alternateLinks}
24448
+ ${metadataHead ?? '<link rel="icon" href="data:,">\n <title>Farm.js App</title>'}${alternateLinks}
24117
24449
  ${fontHead}
24118
24450
  <link rel="stylesheet" href="/src/app/globals.css" />${this.collectDevStyleLinks().map((l) => `
24119
24451
  ${l}`).join("")}
@@ -24278,6 +24610,7 @@ var _FarmApp = class _FarmApp {
24278
24610
  ppr: config.experimental?.ppr ?? false,
24279
24611
  ...config.experimental
24280
24612
  },
24613
+ agent: config.agent ?? {},
24281
24614
  vite: config.vite || {}
24282
24615
  };
24283
24616
  }
@@ -27906,6 +28239,110 @@ function formatServerFnBoundaryError(violation, id) {
27906
28239
  }
27907
28240
  __name(formatServerFnBoundaryError, "formatServerFnBoundaryError");
27908
28241
 
28242
+ // src/client-boundary-env.ts
28243
+ var FUNCTION_BODY_TYPES = /* @__PURE__ */ new Set([
28244
+ "FunctionDeclaration",
28245
+ "FunctionExpression",
28246
+ "ArrowFunctionExpression"
28247
+ ]);
28248
+ function shouldInspectClientBoundary(id, code) {
28249
+ if (id.startsWith("\0") || id.startsWith("virtual:") || id.includes("node_modules")) return false;
28250
+ return code.includes("process.env") || code.includes("node:");
28251
+ }
28252
+ __name(shouldInspectClientBoundary, "shouldInspectClientBoundary");
28253
+ function analyzeClientBoundary(program, publicKeys) {
28254
+ const envKeys = /* @__PURE__ */ new Set();
28255
+ const publicEnvKeys = /* @__PURE__ */ new Set();
28256
+ const builtinImports = /* @__PURE__ */ new Set();
28257
+ const visit = /* @__PURE__ */ __name((node, inFunction) => {
28258
+ if (!node || typeof node !== "object") return;
28259
+ if (Array.isArray(node)) {
28260
+ for (const entry of node) visit(entry, inFunction);
28261
+ return;
28262
+ }
28263
+ const estree = node;
28264
+ if (typeof estree.type !== "string") return;
28265
+ if (!inFunction) {
28266
+ const builtin = readNodeBuiltinSource(estree);
28267
+ if (builtin !== void 0) builtinImports.add(builtin);
28268
+ const key = readProcessEnvKey(estree);
28269
+ if (key !== void 0) {
28270
+ if (key !== "NODE_ENV") {
28271
+ (publicKeys.has(key) ? publicEnvKeys : envKeys).add(key);
28272
+ }
28273
+ return;
28274
+ }
28275
+ }
28276
+ const nextInFunction = inFunction || FUNCTION_BODY_TYPES.has(estree.type);
28277
+ for (const [childKey, value] of Object.entries(estree)) {
28278
+ if (childKey === "type") continue;
28279
+ visit(value, nextInFunction);
28280
+ }
28281
+ }, "visit");
28282
+ visit(program.body, false);
28283
+ return {
28284
+ envKeys: [...envKeys],
28285
+ publicEnvKeys: [...publicEnvKeys],
28286
+ builtinImports: [...builtinImports]
28287
+ };
28288
+ }
28289
+ __name(analyzeClientBoundary, "analyzeClientBoundary");
28290
+ function readNodeBuiltinSource(node) {
28291
+ if (node.type === "ImportDeclaration" || node.type === "ExportNamedDeclaration" || node.type === "ExportAllDeclaration" || node.type === "ImportExpression") {
28292
+ const value = node.source?.value;
28293
+ return typeof value === "string" && value.startsWith("node:") ? value : void 0;
28294
+ }
28295
+ if (node.type === "CallExpression") {
28296
+ const callee = node.callee;
28297
+ if (callee?.type === "Identifier" && callee.name === "require") {
28298
+ const arg = node.arguments?.[0];
28299
+ const value = arg?.type === "Literal" ? arg.value : void 0;
28300
+ return typeof value === "string" && value.startsWith("node:") ? value : void 0;
28301
+ }
28302
+ }
28303
+ return void 0;
28304
+ }
28305
+ __name(readNodeBuiltinSource, "readNodeBuiltinSource");
28306
+ function readProcessEnvKey(node) {
28307
+ if (node.type !== "MemberExpression") return void 0;
28308
+ const object = node.object;
28309
+ if (!object || object.type !== "MemberExpression" || object.object?.type !== "Identifier" || object.object.name !== "process" || object.property?.name !== "env") {
28310
+ return void 0;
28311
+ }
28312
+ const property = node.property;
28313
+ if (!property) return void 0;
28314
+ if (!node.computed && property.type === "Identifier") {
28315
+ return property.name;
28316
+ }
28317
+ if (node.computed && property.type === "Literal") {
28318
+ const value = property.value;
28319
+ return typeof value === "string" ? value : void 0;
28320
+ }
28321
+ return void 0;
28322
+ }
28323
+ __name(readProcessEnvKey, "readProcessEnvKey");
28324
+ function formatClientBoundaryWarning(id, findings) {
28325
+ const { envKeys, publicEnvKeys, builtinImports } = findings;
28326
+ const lines = [`${id} is compiled for the client but uses server-only APIs:`];
28327
+ if (envKeys.length > 0) {
28328
+ lines.push(
28329
+ `- module-scope read of process.env.${envKeys.join(", process.env.")} \u2014 undefined in the browser. Move the read behind a server boundary, or expose it through env.public in farm.config.ts.`
28330
+ );
28331
+ }
28332
+ if (publicEnvKeys.length > 0) {
28333
+ lines.push(
28334
+ `- module-scope read of process.env.${publicEnvKeys.join(", process.env.")} \u2014 process.env is not populated in the browser even for public keys. Read it through publicEnv from "@farm.js/core/env".`
28335
+ );
28336
+ }
28337
+ if (builtinImports.length > 0) {
28338
+ lines.push(
28339
+ `- import of ${builtinImports.join(", ")} \u2014 stubbed with an empty object in the browser. Move the import into server-only code.`
28340
+ );
28341
+ }
28342
+ return lines.join("\n");
28343
+ }
28344
+ __name(formatClientBoundaryWarning, "formatClientBoundaryWarning");
28345
+
27909
28346
  // src/vite.ts
27910
28347
  init_deployment();
27911
28348
  init_image_config();
@@ -28782,6 +29219,24 @@ function isFarmConfigFile(file, root) {
28782
29219
  return FARM_CONFIG_FILENAMES.has(relative6);
28783
29220
  }
28784
29221
  __name(isFarmConfigFile, "isFarmConfigFile");
29222
+ var warnedClientBoundaryIds = /* @__PURE__ */ new Set();
29223
+ function warnClientBoundaryOnce(context2, id, code, config) {
29224
+ if (warnedClientBoundaryIds.has(id)) return;
29225
+ let program;
29226
+ try {
29227
+ program = context2.parse(code);
29228
+ } catch {
29229
+ return;
29230
+ }
29231
+ const publicKeys = new Set(Object.keys(config.env?.public ?? {}));
29232
+ const findings = analyzeClientBoundary(program, publicKeys);
29233
+ if (findings.envKeys.length === 0 && findings.publicEnvKeys.length === 0 && findings.builtinImports.length === 0) {
29234
+ return;
29235
+ }
29236
+ warnedClientBoundaryIds.add(id);
29237
+ logger.warn(formatClientBoundaryWarning(id, findings));
29238
+ }
29239
+ __name(warnClientBoundaryOnce, "warnClientBoundaryOnce");
28785
29240
  function farmPlugin(options = {}, initialPluginManager) {
28786
29241
  const imageImports = farmImageImportsPlugin();
28787
29242
  const fontImports = farmFontImportsPlugin({
@@ -29392,6 +29847,22 @@ window.__FARM_MANIFEST__ = ${inlineValue({
29392
29847
  }
29393
29848
  return;
29394
29849
  }
29850
+ if (openAPIManager && options.openapi?.specRoute && requestPathname === options.openapi.specRoute) {
29851
+ if (requestMethod !== "GET" && requestMethod !== "HEAD") {
29852
+ res.statusCode = 405;
29853
+ res.setHeader("Allow", "GET, HEAD");
29854
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
29855
+ res.end("Method Not Allowed");
29856
+ return;
29857
+ }
29858
+ const spec = await openAPIManager.getSpec();
29859
+ const body = JSON.stringify(spec);
29860
+ res.statusCode = 200;
29861
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
29862
+ res.setHeader("Cache-Control", "no-store");
29863
+ res.end(requestMethod === "HEAD" ? void 0 : body);
29864
+ return;
29865
+ }
29395
29866
  if (openAPIManager && requestPathname === options.openapi?.route) {
29396
29867
  const docsHandler = openAPIManager.getDocsRouteHandler();
29397
29868
  return docsHandler(req, res);
@@ -29402,6 +29873,11 @@ window.__FARM_MANIFEST__ = ${inlineValue({
29402
29873
  docsHeaders.set(key, Array.isArray(value) ? value.join(", ") : value);
29403
29874
  }
29404
29875
  }
29876
+ const runAppMiddlewareForContentRoute = /* @__PURE__ */ __name(async () => {
29877
+ if (!middlewareManager?.hasMiddleware()) return false;
29878
+ const middlewareRequest = createRequestFromNodeRequest(req, new URL(fullUrl));
29879
+ return farmApp.getServerRenderer().runWithRequestContext(middlewareRequest, () => middlewareManager.execute(req, res));
29880
+ }, "runAppMiddlewareForContentRoute");
29405
29881
  if (farmDocsHandler) {
29406
29882
  const docsRequest = new Request(fullUrl, {
29407
29883
  method: requestMethod,
@@ -29409,6 +29885,7 @@ window.__FARM_MANIFEST__ = ${inlineValue({
29409
29885
  });
29410
29886
  const docsResponse = await farmDocsHandler(docsRequest.clone());
29411
29887
  if (docsResponse) {
29888
+ if (await runAppMiddlewareForContentRoute()) return;
29412
29889
  await sendWebResponse(
29413
29890
  res,
29414
29891
  await wrapFarmDocsResponseWithLayouts(docsRequest, docsResponse)
@@ -29435,6 +29912,7 @@ window.__FARM_MANIFEST__ = ${inlineValue({
29435
29912
  }, "resolveSource")
29436
29913
  });
29437
29914
  if (markdownSourceResponse) {
29915
+ if (await runAppMiddlewareForContentRoute()) return;
29438
29916
  await sendWebResponse(res, markdownSourceResponse);
29439
29917
  return;
29440
29918
  }
@@ -29448,9 +29926,23 @@ window.__FARM_MANIFEST__ = ${inlineValue({
29448
29926
  renderPage: /* @__PURE__ */ __name(async (request) => fetch(request), "renderPage")
29449
29927
  });
29450
29928
  if (markdownResponse) {
29929
+ if (await runAppMiddlewareForContentRoute()) return;
29451
29930
  await sendWebResponse(res, markdownResponse);
29452
29931
  return;
29453
29932
  }
29933
+ if (farmRequestWantsMarkdown(requestPathname, req.headers.accept)) {
29934
+ const markdownRoute = farmApp.getRouteManager().matchRoute(normalizeFarmMarkdownRoutePath(requestPathname));
29935
+ if (!markdownRoute.route) {
29936
+ res.statusCode = 404;
29937
+ res.setHeader("Content-Type", FARM_MARKDOWN_CONTENT_TYPE);
29938
+ res.setHeader("X-Farm-Markdown-Error", "404");
29939
+ res.setHeader("Cache-Control", "no-store");
29940
+ res.end(
29941
+ createFarmMarkdownErrorBody(404, requestPathname, farmConfig.basePath || "/")
29942
+ );
29943
+ return;
29944
+ }
29945
+ }
29454
29946
  const markdownPageTarget = resolveMarkdownMirrorTarget(
29455
29947
  farmApp.getConfig().md,
29456
29948
  requestPathname,
@@ -30399,6 +30891,9 @@ export const manifest = getManifest();
30399
30891
  }
30400
30892
  }
30401
30893
  }
30894
+ if (!transformOptions?.ssr && shouldInspectClientBoundary(id, code)) {
30895
+ warnClientBoundaryOnce(this, id, code, farmApp?.getConfig() ?? options);
30896
+ }
30402
30897
  if (typeof imageImports.transform === "function") {
30403
30898
  const imageModule = await imageImports.transform.call(this, code, id, transformOptions);
30404
30899
  if (imageModule) return imageModule;