@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/plugin.cjs CHANGED
@@ -1127,6 +1127,29 @@ var init_search_params = __esm({
1127
1127
  }
1128
1128
  });
1129
1129
 
1130
+ // src/utils/runtime-env.ts
1131
+ function getFarmRuntimeBindings() {
1132
+ const runtimeBindings = globalThis.__env__;
1133
+ return runtimeBindings && typeof runtimeBindings === "object" ? runtimeBindings : void 0;
1134
+ }
1135
+ function readFarmEnvironmentValue(name2) {
1136
+ const runtimeValue = getFarmRuntimeBindings()?.[name2];
1137
+ if (typeof runtimeValue === "string") return runtimeValue;
1138
+ return typeof process !== "undefined" ? process.env?.[name2] : void 0;
1139
+ }
1140
+ function isFarmDeployedRuntime() {
1141
+ if (getFarmRuntimeBindings()) return true;
1142
+ return readFarmEnvironmentValue("NODE_ENV") === "production";
1143
+ }
1144
+ var init_runtime_env = __esm({
1145
+ "src/utils/runtime-env.ts"() {
1146
+ "use strict";
1147
+ __name(getFarmRuntimeBindings, "getFarmRuntimeBindings");
1148
+ __name(readFarmEnvironmentValue, "readFarmEnvironmentValue");
1149
+ __name(isFarmDeployedRuntime, "isFarmDeployedRuntime");
1150
+ }
1151
+ });
1152
+
1130
1153
  // src/utils/decode.ts
1131
1154
  function decodeRouteSegment(segment) {
1132
1155
  try {
@@ -1569,7 +1592,8 @@ function resolveWorkflowsConfig(workflows) {
1569
1592
  dirs,
1570
1593
  route: normalizeWorkflowRoute(options.route || DEFAULT_FARM_WORKFLOW_ROUTE),
1571
1594
  secretEnv: options.secretEnv || DEFAULT_FARM_WORKFLOW_SECRET_ENV,
1572
- secret: options.secret
1595
+ secret: options.secret,
1596
+ allowUnsecured: options.allowUnsecured === true
1573
1597
  };
1574
1598
  }
1575
1599
  async function discoverFarmWorkflows(config, options = {}) {
@@ -1695,8 +1719,11 @@ async function prepareFarmWorkflowsForNitro(config) {
1695
1719
  await fs14.mkdir(generatedDir, { recursive: true });
1696
1720
  const tasks = {};
1697
1721
  const scheduledTasks = createScheduledTasks(workflows);
1722
+ const wrapperNames = resolveWorkflowWrapperFileNames(workflows.map((workflow) => workflow.id));
1698
1723
  for (const workflow of workflows) {
1699
- const wrapperPath = toPosixPath(path35.join(generatedDir, `${safeFileName(workflow.id)}.mjs`));
1724
+ const wrapperPath = toPosixPath(
1725
+ path35.join(generatedDir, `${wrapperNames.get(workflow.id)}.mjs`)
1726
+ );
1700
1727
  await fs14.writeFile(wrapperPath, createNitroTaskWrapper(workflow), "utf8");
1701
1728
  tasks[workflow.id] = {
1702
1729
  handler: wrapperPath,
@@ -1934,6 +1961,7 @@ import {
1934
1961
  const route = ${JSON.stringify(config.route)};
1935
1962
  const secretEnv = ${JSON.stringify(config.secretEnv)};
1936
1963
  const inlineSecret = ${JSON.stringify(config.secret || "")};
1964
+ const allowUnsecured = ${JSON.stringify(config.allowUnsecured === true)};
1937
1965
  const bodySizeLimit = ${JSON.stringify(server.bodySizeLimit)};
1938
1966
  const workflows = ${JSON.stringify(workflows.map(toWorkflowMetadata))};
1939
1967
  const workflowIds = new Set(workflows.map((workflow) => workflow.id));
@@ -1963,7 +1991,10 @@ function getSecret() {
1963
1991
 
1964
1992
  function verifySecret(event) {
1965
1993
  const secret = getSecret();
1966
- if (!secret) return null;
1994
+ if (!secret) {
1995
+ if (allowUnsecured) return null;
1996
+ return json({ error: ${JSON.stringify(MISSING_FARM_WORKFLOW_SECRET_ERROR)} }, 401);
1997
+ }
1967
1998
  const authorization = getHeader(event, "authorization") || "";
1968
1999
  const headerSecret = getHeader(event, "x-farm-workflow-secret") || "";
1969
2000
  const bearer = authorization.match(/^Bearer\\s+(.+)$/i)?.[1] || "";
@@ -2057,8 +2088,16 @@ function readScheduledTime(payload) {
2057
2088
  return payload && typeof payload === "object" && "scheduledTime" in payload ? payload.scheduledTime : void 0;
2058
2089
  }
2059
2090
  function verifyWorkflowSecret(request, config) {
2060
- const secret = config.secret || process.env[config.secretEnv] || "";
2061
- if (!secret) return null;
2091
+ const secret = config.secret || readFarmEnvironmentValue(config.secretEnv) || "";
2092
+ if (!secret) {
2093
+ if (config.allowUnsecured === true || !isFarmDeployedRuntime()) return null;
2094
+ return Response.json(
2095
+ {
2096
+ error: MISSING_FARM_WORKFLOW_SECRET_ERROR
2097
+ },
2098
+ { status: 401 }
2099
+ );
2100
+ }
2062
2101
  const authorization = request.headers.get("authorization") || "";
2063
2102
  const bearer = authorization.match(/^Bearer\s+(.+)$/i)?.[1] || "";
2064
2103
  const headerSecret = request.headers.get("x-farm-workflow-secret") || "";
@@ -2071,18 +2110,50 @@ function joinRoute(...parts) {
2071
2110
  function trimSlashes(value) {
2072
2111
  return value.replace(/^\/+|\/+$/g, "");
2073
2112
  }
2113
+ function resolveWorkflowWrapperFileNames(ids) {
2114
+ const groups = /* @__PURE__ */ new Map();
2115
+ for (const id of ids) {
2116
+ const key = safeFileName(id).toLowerCase();
2117
+ groups.set(key, (groups.get(key) ?? 0) + 1);
2118
+ }
2119
+ const resolved = /* @__PURE__ */ new Map();
2120
+ const claimed = /* @__PURE__ */ new Map();
2121
+ for (const id of ids) {
2122
+ const base = safeFileName(id);
2123
+ const key = base.toLowerCase();
2124
+ const fileName = (groups.get(key) ?? 0) > 1 ? `${key}-${workflowIdFingerprint(id)}` : base;
2125
+ const claimedBy = claimed.get(fileName.toLowerCase());
2126
+ if (claimedBy !== void 0) {
2127
+ throw new Error(
2128
+ `Farm workflows ${JSON.stringify(claimedBy)} and ${JSON.stringify(id)} generate the same wrapper file ${JSON.stringify(`${fileName}.mjs`)}. Rename one of them.`
2129
+ );
2130
+ }
2131
+ claimed.set(fileName.toLowerCase(), id);
2132
+ resolved.set(id, fileName);
2133
+ }
2134
+ return resolved;
2135
+ }
2136
+ function workflowIdFingerprint(value) {
2137
+ let hash = 2166136261;
2138
+ for (let index = 0; index < value.length; index += 1) {
2139
+ hash ^= value.charCodeAt(index);
2140
+ hash = Math.imul(hash, 16777619);
2141
+ }
2142
+ return (hash >>> 0).toString(16).padStart(8, "0");
2143
+ }
2074
2144
  function safeFileName(value) {
2075
2145
  return value.replace(/[^a-zA-Z0-9._-]+/g, "-") || "workflow";
2076
2146
  }
2077
2147
  function relativePath(root, filePath) {
2078
2148
  return filePath.replace(/\\/g, "/").replace(`${root.replace(/\\/g, "/")}/`, "");
2079
2149
  }
2080
- var import_node_path, DEFAULT_FARM_WORKFLOW_DIRS, DEFAULT_FARM_WORKFLOW_ROUTE, DEFAULT_FARM_WORKFLOW_SECRET_ENV;
2150
+ var import_node_path, DEFAULT_FARM_WORKFLOW_DIRS, DEFAULT_FARM_WORKFLOW_ROUTE, DEFAULT_FARM_WORKFLOW_SECRET_ENV, MISSING_FARM_WORKFLOW_SECRET_ERROR;
2081
2151
  var init_workflows = __esm({
2082
2152
  "src/workflows.ts"() {
2083
2153
  "use strict";
2084
2154
  init_server_http();
2085
2155
  init_search_params();
2156
+ init_runtime_env();
2086
2157
  init_decode();
2087
2158
  init_utils();
2088
2159
  init_route_pattern();
@@ -2090,6 +2161,7 @@ var init_workflows = __esm({
2090
2161
  DEFAULT_FARM_WORKFLOW_DIRS = ["src/jobs", "src/workflows", "src/cron"];
2091
2162
  DEFAULT_FARM_WORKFLOW_ROUTE = "/api/_farm/workflows";
2092
2163
  DEFAULT_FARM_WORKFLOW_SECRET_ENV = "CRON_SECRET";
2164
+ 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.";
2093
2165
  __name(defineWorkflow, "defineWorkflow");
2094
2166
  __name(defineTask, "defineTask");
2095
2167
  __name(defineCron, "defineCron");
@@ -2122,6 +2194,8 @@ var init_workflows = __esm({
2122
2194
  __name(verifyWorkflowSecret, "verifyWorkflowSecret");
2123
2195
  __name(joinRoute, "joinRoute");
2124
2196
  __name(trimSlashes, "trimSlashes");
2197
+ __name(resolveWorkflowWrapperFileNames, "resolveWorkflowWrapperFileNames");
2198
+ __name(workflowIdFingerprint, "workflowIdFingerprint");
2125
2199
  __name(safeFileName, "safeFileName");
2126
2200
  __name(relativePath, "relativePath");
2127
2201
  }
@@ -2272,6 +2346,7 @@ var init_cron = __esm({
2272
2346
  "src/cron.ts"() {
2273
2347
  "use strict";
2274
2348
  init_utils();
2349
+ init_runtime_env();
2275
2350
  DEFAULT_FARM_CRON_SECRET_ENV = "CRON_SECRET";
2276
2351
  CRON_FIELD_RANGES = [
2277
2352
  [0, 59, "minute"],
@@ -2652,9 +2727,13 @@ function getStorage(namespace) {
2652
2727
  const namespaced = (0, import_unstorage.prefixStorage)(globalStorage, base);
2653
2728
  return {
2654
2729
  ...namespaced,
2655
- async clear() {
2656
- const keys = await namespaced.getKeys();
2657
- await Promise.all(keys.map((key) => namespaced.removeItem(key)));
2730
+ // Scope the wipe to the namespace instead of the whole storage, and keep
2731
+ // the caller's base so `clear("sessions")` cannot take unrelated keys with
2732
+ // it. Dropping the argument silently widens a targeted clear into a
2733
+ // namespace-wide delete.
2734
+ async clear(base2, opts) {
2735
+ const keys = await namespaced.getKeys(base2);
2736
+ await Promise.all(keys.map((key) => namespaced.removeItem(key, opts)));
2658
2737
  }
2659
2738
  };
2660
2739
  }
@@ -3588,6 +3667,46 @@ var init_cache_invalidation = __esm({
3588
3667
  }
3589
3668
  });
3590
3669
 
3670
+ // src/request-origin.ts
3671
+ function normalizeAllowedOriginPattern(value, label) {
3672
+ const pattern = value.trim().toLowerCase();
3673
+ if (!pattern) {
3674
+ throw new TypeError(`${label} cannot contain empty values`);
3675
+ }
3676
+ if (pattern.includes("*")) {
3677
+ if (!/^(?:https?:\/\/)?\*\.[a-z0-9.-]+(?::\d+)?$/.test(pattern)) {
3678
+ throw new TypeError(`Invalid ${label} pattern: ${JSON.stringify(value)}`);
3679
+ }
3680
+ return pattern;
3681
+ }
3682
+ if (pattern.includes("://")) {
3683
+ let parsed;
3684
+ try {
3685
+ parsed = new URL(pattern);
3686
+ } catch {
3687
+ throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);
3688
+ }
3689
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
3690
+ throw new TypeError(`${label} must contain origins without paths: ${JSON.stringify(value)}`);
3691
+ }
3692
+ return parsed.origin;
3693
+ }
3694
+ if (/[/@?#]/.test(pattern)) {
3695
+ throw new TypeError(`${label} must contain origins or hosts: ${JSON.stringify(value)}`);
3696
+ }
3697
+ try {
3698
+ return new URL(`http://${pattern}`).host;
3699
+ } catch {
3700
+ throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);
3701
+ }
3702
+ }
3703
+ var init_request_origin = __esm({
3704
+ "src/request-origin.ts"() {
3705
+ "use strict";
3706
+ __name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
3707
+ }
3708
+ });
3709
+
3591
3710
  // src/server-fn-error.ts
3592
3711
  var init_server_fn_error = __esm({
3593
3712
  "src/server-fn-error.ts"() {
@@ -3597,7 +3716,9 @@ var init_server_fn_error = __esm({
3597
3716
 
3598
3717
  // src/server-action-security.ts
3599
3718
  function resolveServerActionsConfig(config) {
3600
- const allowedOrigins = (config?.allowedOrigins ?? []).map(normalizeAllowedOriginPattern);
3719
+ const allowedOrigins = (config?.allowedOrigins ?? []).map(
3720
+ (value) => normalizeAllowedOriginPattern(value, SERVER_ACTION_ALLOWED_ORIGINS_LABEL)
3721
+ );
3601
3722
  const bodySizeLimit = parseBodySizeLimit(
3602
3723
  config?.bodySizeLimit ?? DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT,
3603
3724
  "serverActions.bodySizeLimit"
@@ -3617,50 +3738,16 @@ function getServerActionStorage() {
3617
3738
  }
3618
3739
  return globalState2[SERVER_ACTION_STORAGE_KEY];
3619
3740
  }
3620
- function normalizeAllowedOriginPattern(value) {
3621
- const pattern = value.trim().toLowerCase();
3622
- if (!pattern) {
3623
- throw new TypeError("serverActions.allowedOrigins cannot contain empty values");
3624
- }
3625
- if (pattern.includes("*")) {
3626
- if (!/^(?:https?:\/\/)?\*\.[a-z0-9.-]+(?::\d+)?$/.test(pattern)) {
3627
- throw new TypeError(`Invalid serverActions.allowedOrigins pattern: ${JSON.stringify(value)}`);
3628
- }
3629
- return pattern;
3630
- }
3631
- if (pattern.includes("://")) {
3632
- let parsed;
3633
- try {
3634
- parsed = new URL(pattern);
3635
- } catch {
3636
- throw new TypeError(`Invalid serverActions.allowedOrigins value: ${JSON.stringify(value)}`);
3637
- }
3638
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
3639
- throw new TypeError(
3640
- `serverActions.allowedOrigins must contain origins without paths: ${JSON.stringify(value)}`
3641
- );
3642
- }
3643
- return parsed.origin;
3644
- }
3645
- if (/[/@?#]/.test(pattern)) {
3646
- throw new TypeError(
3647
- `serverActions.allowedOrigins must contain origins or hosts: ${JSON.stringify(value)}`
3648
- );
3649
- }
3650
- try {
3651
- return new URL(`http://${pattern}`).host;
3652
- } catch {
3653
- throw new TypeError(`Invalid serverActions.allowedOrigins value: ${JSON.stringify(value)}`);
3654
- }
3655
- }
3656
- var import_node_async_hooks, DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT, SERVER_ACTION_STORAGE_KEY;
3741
+ var import_node_async_hooks, SERVER_ACTION_ALLOWED_ORIGINS_LABEL, DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT, SERVER_ACTION_STORAGE_KEY;
3657
3742
  var init_server_action_security = __esm({
3658
3743
  "src/server-action-security.ts"() {
3659
3744
  "use strict";
3660
3745
  import_node_async_hooks = require("async_hooks");
3661
3746
  init_cache_invalidation();
3747
+ init_request_origin();
3662
3748
  init_server_fn_error();
3663
3749
  init_server_http();
3750
+ SERVER_ACTION_ALLOWED_ORIGINS_LABEL = "serverActions.allowedOrigins";
3664
3751
  DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT = 1e6;
3665
3752
  SERVER_ACTION_STORAGE_KEY = /* @__PURE__ */ Symbol.for("farm.serverActionStorage");
3666
3753
  __name(resolveServerActionsConfig, "resolveServerActionsConfig");
@@ -3672,7 +3759,6 @@ var init_server_action_security = __esm({
3672
3759
  getServerActionExecutionContext()?.cacheTasks.add(task);
3673
3760
  });
3674
3761
  __name(getServerActionStorage, "getServerActionStorage");
3675
- __name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
3676
3762
  }
3677
3763
  });
3678
3764
 
@@ -5521,6 +5607,14 @@ var init_routes = __esm({
5521
5607
  }
5522
5608
  });
5523
5609
 
5610
+ // src/integration-request-security.ts
5611
+ var init_integration_request_security = __esm({
5612
+ "src/integration-request-security.ts"() {
5613
+ "use strict";
5614
+ init_request_origin();
5615
+ }
5616
+ });
5617
+
5524
5618
  // src/integration-api.ts
5525
5619
  function defineIntegrationAPIOperation(operation) {
5526
5620
  return {
@@ -6902,6 +6996,7 @@ var init_integrations = __esm({
6902
6996
  "src/integrations.ts"() {
6903
6997
  "use strict";
6904
6998
  init_route_pattern();
6999
+ init_integration_request_security();
6905
7000
  init_integration_api();
6906
7001
  init_plugin_integration_context();
6907
7002
  init_decode();
@@ -7068,6 +7163,45 @@ var init_renderer = __esm({
7068
7163
  }
7069
7164
  });
7070
7165
 
7166
+ // src/agent-config.ts
7167
+ function pruneUndefined(object) {
7168
+ const result = {};
7169
+ for (const [key, value] of Object.entries(object)) {
7170
+ if (value !== void 0 && value !== null && value !== "") result[key] = value;
7171
+ }
7172
+ return result;
7173
+ }
7174
+ function serializeJsonLd(value) {
7175
+ return JSON.stringify(value).replace(/</g, "\\u003c");
7176
+ }
7177
+ function renderFarmAgentJsonLd(config, context2) {
7178
+ const base = pruneUndefined({
7179
+ name: config.name ?? context2.siteName ?? context2.title,
7180
+ url: config.url ?? context2.metadataBase,
7181
+ description: config.description ?? context2.description,
7182
+ logo: config.logo,
7183
+ sameAs: config.sameAs && config.sameAs.length > 0 ? config.sameAs : void 0
7184
+ });
7185
+ const object = {
7186
+ "@context": "https://schema.org",
7187
+ "@type": config.type || "Organization",
7188
+ ...base,
7189
+ ...config.properties || {}
7190
+ };
7191
+ if (Object.keys(object).length <= 2 && !config.properties) {
7192
+ return "";
7193
+ }
7194
+ return `<script type="application/ld+json">${serializeJsonLd(object)}</script>`;
7195
+ }
7196
+ var init_agent_config = __esm({
7197
+ "src/agent-config.ts"() {
7198
+ "use strict";
7199
+ __name(pruneUndefined, "pruneUndefined");
7200
+ __name(serializeJsonLd, "serializeJsonLd");
7201
+ __name(renderFarmAgentJsonLd, "renderFarmAgentJsonLd");
7202
+ }
7203
+ });
7204
+
7071
7205
  // src/deployment.ts
7072
7206
  function getFarmRequestDeploymentId(request) {
7073
7207
  const headerValue = request.headers.get(FARM_DEPLOYMENT_ID_HEADER)?.trim();
@@ -8372,6 +8506,7 @@ export const apiRoutes = ${manifestSource} as const;
8372
8506
  function createFarmImageHandler(config, options) {
8373
8507
  const fetcher = options.fetch ?? globalThis.fetch;
8374
8508
  const cache = new FarmImageMemoryCache(options.cacheEntries ?? 100);
8509
+ const inflight = /* @__PURE__ */ new Map();
8375
8510
  const allowedWidths = /* @__PURE__ */ new Set([...config.deviceSizes, ...config.imageSizes]);
8376
8511
  const allowedQualities = new Set(config.qualities);
8377
8512
  return /* @__PURE__ */ __name(async function handleFarmImage(request) {
@@ -8400,50 +8535,55 @@ function createFarmImageHandler(config, options) {
8400
8535
  "quality"
8401
8536
  );
8402
8537
  const accept = request.headers.get("accept") ?? "";
8538
+ const negotiatedFormat = selectOutputFormat(accept, config.formats) ?? "";
8403
8539
  const cacheKey = `${sourceUrl.href}
8404
8540
  ${width}
8405
8541
  ${quality}
8406
- ${accept}`;
8542
+ ${negotiatedFormat}`;
8407
8543
  let optimized = cache.get(cacheKey);
8408
8544
  if (!optimized) {
8409
- const fetchedSource = await fetchImageSource(
8410
- sourceUrl,
8411
- requestUrl.origin,
8412
- config,
8413
- fetcher,
8414
- options.fetchRemote,
8415
- options.validateRemoteUrl,
8416
- request.signal
8417
- );
8418
- const source = await readResponseWithLimit(
8419
- fetchedSource.response,
8420
- config.maximumResponseBody
8421
- );
8422
- const sourceType = detectImageContentType(source);
8423
- validateSourceType(sourceType, config);
8424
- throwIfAborted2(request.signal);
8425
- const result = await options.transform({
8426
- source,
8427
- sourceUrl: fetchedSource.url,
8428
- sourceType,
8429
- width,
8430
- quality,
8431
- accept,
8432
- formats: config.formats,
8433
- signal: request.signal
8545
+ optimized = await runCoalesced(inflight, cacheKey, request.signal, async (signal) => {
8546
+ const fetchedSource = await fetchImageSource(
8547
+ sourceUrl,
8548
+ requestUrl.origin,
8549
+ config,
8550
+ fetcher,
8551
+ options.fetchRemote,
8552
+ options.validateRemoteUrl,
8553
+ signal
8554
+ );
8555
+ const source = await readResponseWithLimit(
8556
+ fetchedSource.response,
8557
+ config.maximumResponseBody
8558
+ );
8559
+ const sourceType = detectImageContentType(source);
8560
+ validateSourceType(sourceType, config);
8561
+ throwIfAborted2(signal);
8562
+ const result = await options.transform({
8563
+ source,
8564
+ sourceUrl: fetchedSource.url,
8565
+ sourceType,
8566
+ width,
8567
+ quality,
8568
+ accept,
8569
+ formats: config.formats,
8570
+ signal,
8571
+ maximumResponseBody: config.maximumResponseBody
8572
+ });
8573
+ throwIfAborted2(signal);
8574
+ validateTransformedResult(result, config);
8575
+ const entry = {
8576
+ ...result,
8577
+ etag: createImageEtag(result.body),
8578
+ cacheControl: `public, max-age=${config.minimumCacheTTL}, stale-while-revalidate=${Math.max(
8579
+ config.minimumCacheTTL,
8580
+ 60
8581
+ )}`,
8582
+ expiresAt: Date.now() + config.minimumCacheTTL * 1e3
8583
+ };
8584
+ cache.set(cacheKey, entry);
8585
+ return entry;
8434
8586
  });
8435
- throwIfAborted2(request.signal);
8436
- validateTransformedResult(result, config);
8437
- optimized = {
8438
- ...result,
8439
- etag: createImageEtag(result.body),
8440
- cacheControl: `public, max-age=${config.minimumCacheTTL}, stale-while-revalidate=${Math.max(
8441
- config.minimumCacheTTL,
8442
- 60
8443
- )}`,
8444
- expiresAt: Date.now() + config.minimumCacheTTL * 1e3
8445
- };
8446
- cache.set(cacheKey, optimized);
8447
8587
  }
8448
8588
  return createOptimizedImageResponse(request, optimized, config);
8449
8589
  } catch (error) {
@@ -8594,6 +8734,44 @@ async function fetchImageSource(initialUrl, requestOrigin, config, fetcher, fetc
8594
8734
  await validateImageSourceUrl(currentUrl, requestOrigin, config, validateRemoteUrl);
8595
8735
  }
8596
8736
  }
8737
+ async function runCoalesced(inflight, key, requestSignal, run) {
8738
+ let entry = inflight.get(key);
8739
+ if (!entry) {
8740
+ const controller = new AbortController();
8741
+ const created = {
8742
+ controller,
8743
+ waiters: 0,
8744
+ promise: void 0
8745
+ };
8746
+ created.promise = run(controller.signal).finally(() => {
8747
+ if (inflight.get(key) === created) inflight.delete(key);
8748
+ });
8749
+ created.promise.catch(() => {
8750
+ });
8751
+ inflight.set(key, created);
8752
+ entry = created;
8753
+ }
8754
+ const pending = entry;
8755
+ pending.waiters += 1;
8756
+ try {
8757
+ return await raceRequestAbort(pending.promise, requestSignal);
8758
+ } finally {
8759
+ pending.waiters -= 1;
8760
+ if (pending.waiters === 0 && inflight.get(key) === pending) {
8761
+ inflight.delete(key);
8762
+ pending.controller.abort();
8763
+ }
8764
+ }
8765
+ }
8766
+ function raceRequestAbort(promise, signal) {
8767
+ if (!signal) return promise;
8768
+ if (signal.aborted) return Promise.reject(signal.reason ?? new Error("Aborted"));
8769
+ return new Promise((resolve10, reject) => {
8770
+ const onAbort = /* @__PURE__ */ __name(() => reject(signal.reason ?? new Error("Aborted")), "onAbort");
8771
+ signal.addEventListener("abort", onAbort, { once: true });
8772
+ promise.then(resolve10, reject).finally(() => signal.removeEventListener("abort", onAbort));
8773
+ });
8774
+ }
8597
8775
  async function readResponseWithLimit(response, limit) {
8598
8776
  const contentLength = response.headers.get("content-length");
8599
8777
  if (contentLength && Number(contentLength) > limit) {
@@ -8761,7 +8939,7 @@ function throwIfAborted2(signal) {
8761
8939
  function isAbortError(error) {
8762
8940
  return error instanceof Error && error.name === "AbortError";
8763
8941
  }
8764
- var _FarmImageRequestError, FarmImageRequestError, _FarmImageMemoryCache, FarmImageMemoryCache;
8942
+ var _FarmImageRequestError, FarmImageRequestError, DEFAULT_IMAGE_TRANSFORM_BODY_LIMIT, _FarmImageMemoryCache, FarmImageMemoryCache;
8765
8943
  var init_image_server = __esm({
8766
8944
  "src/image-server.ts"() {
8767
8945
  "use strict";
@@ -8777,12 +8955,15 @@ var init_image_server = __esm({
8777
8955
  __name(_FarmImageRequestError, "FarmImageRequestError");
8778
8956
  FarmImageRequestError = _FarmImageRequestError;
8779
8957
  __name(createFarmImageHandler, "createFarmImageHandler");
8958
+ DEFAULT_IMAGE_TRANSFORM_BODY_LIMIT = 10 * 1024 * 1024;
8780
8959
  __name(selectOutputFormat, "selectOutputFormat");
8781
8960
  __name(isPrivateImageAddress, "isPrivateImageAddress");
8782
8961
  __name(parseAllowedInteger, "parseAllowedInteger");
8783
8962
  __name(resolveImageSourceUrl, "resolveImageSourceUrl");
8784
8963
  __name(validateImageSourceUrl, "validateImageSourceUrl");
8785
8964
  __name(fetchImageSource, "fetchImageSource");
8965
+ __name(runCoalesced, "runCoalesced");
8966
+ __name(raceRequestAbort, "raceRequestAbort");
8786
8967
  __name(readResponseWithLimit, "readResponseWithLimit");
8787
8968
  __name(cancelResponseBody, "cancelResponseBody");
8788
8969
  __name(detectImageContentType, "detectImageContentType");
@@ -11398,6 +11579,7 @@ var init_config4 = __esm({
11398
11579
  init_security();
11399
11580
  init_navigation_errors();
11400
11581
  init_config2();
11582
+ init_agent_config();
11401
11583
  init_renderer();
11402
11584
  init_framework_detect();
11403
11585
  init_config3();
@@ -15440,6 +15622,21 @@ function isFarmMarkdownPageFile(filePath) {
15440
15622
  return /(^|[/\\])page\.mdx?$/i.test(filePath);
15441
15623
  }
15442
15624
  __name(isFarmMarkdownPageFile, "isFarmMarkdownPageFile");
15625
+ var FARM_MARKDOWN_CONTENT_TYPE = "text/markdown; charset=utf-8";
15626
+ function farmRequestWantsMarkdown(pathname, accept) {
15627
+ return pathname.toLowerCase().endsWith(".md") || requestAcceptsMarkdown(accept);
15628
+ }
15629
+ __name(farmRequestWantsMarkdown, "farmRequestWantsMarkdown");
15630
+ function createFarmMarkdownErrorBody(status, pathname, homeHref = "/") {
15631
+ const heading = status === 404 ? "Page not found" : `Request failed (${status})`;
15632
+ return `# ${heading}
15633
+
15634
+ No page is available at \`${pathname}\`. The URL may be incorrect, or the page has not been published.
15635
+
15636
+ Browse [the site homepage](${homeHref}) to find available pages.
15637
+ `;
15638
+ }
15639
+ __name(createFarmMarkdownErrorBody, "createFarmMarkdownErrorBody");
15443
15640
  function normalizeFarmMarkdownRoutePath(pathname) {
15444
15641
  const withoutExtension = pathname.replace(/\.md$/i, "");
15445
15642
  const normalized = withoutExtension.startsWith("/") ? withoutExtension : `/${withoutExtension}`;
@@ -16160,6 +16357,50 @@ function getStaticImportBindings(content) {
16160
16357
  return bindings;
16161
16358
  }
16162
16359
  __name(getStaticImportBindings, "getStaticImportBindings");
16360
+ var PARSER_SENSITIVE_JSX_CONTAINERS = /* @__PURE__ */ new Set([
16361
+ "table",
16362
+ "thead",
16363
+ "tbody",
16364
+ "tfoot",
16365
+ "tr",
16366
+ "select",
16367
+ "optgroup",
16368
+ "svg"
16369
+ ]);
16370
+ function findParserSensitiveJsxContainer(content, localBindings) {
16371
+ if (!content || localBindings.length === 0) return void 0;
16372
+ const names = new Set(localBindings);
16373
+ const tokens = tokenizeModuleSource(content);
16374
+ const openDepth = /* @__PURE__ */ new Map();
16375
+ const isSelfClosing = /* @__PURE__ */ __name((openingIndex) => {
16376
+ for (let index = openingIndex; index < tokens.length; index++) {
16377
+ if (tokens[index].value === ">") return tokens[index - 1]?.value === "/";
16378
+ }
16379
+ return false;
16380
+ }, "isSelfClosing");
16381
+ for (let index = 0; index < tokens.length - 1; index++) {
16382
+ if (tokens[index].value !== "<") continue;
16383
+ if (tokens[index + 1].value === "/") {
16384
+ const closing = tokens[index + 2]?.value;
16385
+ if (closing && openDepth.has(closing)) {
16386
+ openDepth.set(closing, Math.max(0, (openDepth.get(closing) ?? 0) - 1));
16387
+ }
16388
+ continue;
16389
+ }
16390
+ const tag = tokens[index + 1].value;
16391
+ if (names.has(tag)) {
16392
+ for (const [container, depth] of openDepth) {
16393
+ if (depth > 0) return container;
16394
+ }
16395
+ continue;
16396
+ }
16397
+ if (PARSER_SENSITIVE_JSX_CONTAINERS.has(tag) && !isSelfClosing(index)) {
16398
+ openDepth.set(tag, (openDepth.get(tag) ?? 0) + 1);
16399
+ }
16400
+ }
16401
+ return void 0;
16402
+ }
16403
+ __name(findParserSensitiveJsxContainer, "findParserSensitiveJsxContainer");
16163
16404
  function countStaticJsxUses(content, localBindings) {
16164
16405
  if (!content || localBindings.length === 0) return 0;
16165
16406
  const names = new Set(localBindings);
@@ -16273,6 +16514,37 @@ function getClientRenderingHelpers(tokens, clientBindings) {
16273
16514
  return helpers;
16274
16515
  }
16275
16516
  __name(getClientRenderingHelpers, "getClientRenderingHelpers");
16517
+ function passesElementValuedProps(content, localBindings) {
16518
+ if (!content || localBindings.length === 0) return false;
16519
+ const names = new Set(localBindings);
16520
+ const tokens = tokenizeModuleSource(content);
16521
+ for (let index = 0; index < tokens.length - 1; index++) {
16522
+ if (tokens[index].value !== "<" || !names.has(tokens[index + 1].value)) continue;
16523
+ const name2 = tokens[index + 1].value;
16524
+ let cursor = index + 2;
16525
+ let braceDepth = 0;
16526
+ let selfClosing = false;
16527
+ for (; cursor < tokens.length; cursor++) {
16528
+ const value = tokens[cursor].value;
16529
+ if (value === "{") braceDepth++;
16530
+ else if (value === "}") braceDepth--;
16531
+ else if (value === "<" && braceDepth > 0) return true;
16532
+ else if (value === ">" && braceDepth === 0) {
16533
+ selfClosing = tokens[cursor - 1]?.value === "/";
16534
+ break;
16535
+ }
16536
+ }
16537
+ if (selfClosing || cursor >= tokens.length) continue;
16538
+ for (let child = cursor + 1; child < tokens.length; child++) {
16539
+ if (tokens[child].value !== "<") continue;
16540
+ const closesBoundary = tokens[child + 1]?.value === "/" && tokens[child + 2]?.value === name2;
16541
+ if (!closesBoundary) return true;
16542
+ break;
16543
+ }
16544
+ }
16545
+ return false;
16546
+ }
16547
+ __name(passesElementValuedProps, "passesElementValuedProps");
16276
16548
  function hasDynamicJsxCardinality(content, localBindings) {
16277
16549
  if (!content || localBindings.length === 0) return false;
16278
16550
  const clientBindings = new Set(localBindings);
@@ -16355,6 +16627,17 @@ function collectIsolatedClientBoundaries(ownerPath, root) {
16355
16627
  if (fallbackReason || importedBoundaryCount === 0) continue;
16356
16628
  const localBindings = importedBindings.get(specifier) ?? [];
16357
16629
  const staticUses = countStaticJsxUses(content, localBindings);
16630
+ if (staticUses > 0) {
16631
+ const container = findParserSensitiveJsxContainer(content, localBindings);
16632
+ if (container) {
16633
+ fallbackReason = `the client boundary imported from ${specifier} renders inside <${container}>, where the HTML parser relocates its hydration marker`;
16634
+ return 0;
16635
+ }
16636
+ if (passesElementValuedProps(content, localBindings)) {
16637
+ fallbackReason = `the client boundary imported from ${specifier} receives React elements, which cannot cross the boundary as serialized props`;
16638
+ return 0;
16639
+ }
16640
+ }
16358
16641
  if (staticUses > 0 && hasDynamicJsxCardinality(content, localBindings)) {
16359
16642
  fallbackReason = `the client boundary count imported from ${specifier} is data-dependent`;
16360
16643
  costGuardExceeded = true;
@@ -18185,6 +18468,7 @@ init_observability();
18185
18468
  init_navigation_errors();
18186
18469
 
18187
18470
  // src/metadata.ts
18471
+ init_agent_config();
18188
18472
  function mergeMetadata(base, next) {
18189
18473
  if (!base) return next ? { ...next } : {};
18190
18474
  if (!next) return { ...base };
@@ -18247,7 +18531,7 @@ function addMetadataImageReference(metadata, reference) {
18247
18531
  };
18248
18532
  }
18249
18533
  __name(addMetadataImageReference, "addMetadataImageReference");
18250
- function renderMetadataHead(metadata) {
18534
+ function renderMetadataHead(metadata, options = {}) {
18251
18535
  const resolvedMetadata = metadata || {};
18252
18536
  const metadataBase = resolveMetadataBase(resolvedMetadata);
18253
18537
  const explicitTitle = resolveMetadataTitle(resolvedMetadata.title);
@@ -18268,14 +18552,16 @@ function renderMetadataHead(metadata) {
18268
18552
  appendMetaName(tags, "publisher", resolvedMetadata.publisher);
18269
18553
  appendMetaName(tags, "robots", normalizeRobots(resolvedMetadata.robots));
18270
18554
  const alternates = resolvedMetadata.alternates;
18271
- if (isRecord2(alternates)) {
18272
- appendLink(tags, "canonical", resolveMetadataUrl(alternates.canonical, metadataBase));
18273
- if (isRecord2(alternates.languages)) {
18274
- for (const [language, href] of Object.entries(alternates.languages)) {
18275
- appendLink(tags, "alternate", resolveMetadataUrl(href, metadataBase), {
18276
- hreflang: language
18277
- });
18278
- }
18555
+ const explicitCanonical = isRecord2(alternates) ? alternates.canonical : void 0;
18556
+ const canonicalHref = explicitCanonical != null ? resolveMetadataUrl(explicitCanonical, metadataBase) : options.pathname ? resolveMetadataUrl(options.pathname, metadataBase) : void 0;
18557
+ if (canonicalHref) {
18558
+ appendLink(tags, "canonical", canonicalHref);
18559
+ }
18560
+ if (isRecord2(alternates) && isRecord2(alternates.languages)) {
18561
+ for (const [language, href] of Object.entries(alternates.languages)) {
18562
+ appendLink(tags, "alternate", resolveMetadataUrl(href, metadataBase), {
18563
+ hreflang: language
18564
+ });
18279
18565
  }
18280
18566
  }
18281
18567
  const hasFavicon = appendIcons(tags, resolvedMetadata.icons, metadataBase);
@@ -18288,6 +18574,16 @@ function renderMetadataHead(metadata) {
18288
18574
  }
18289
18575
  appendOpenGraph(tags, resolvedMetadata.openGraph, metadataBase);
18290
18576
  appendTwitter(tags, resolvedMetadata.twitter, metadataBase);
18577
+ if (options.jsonLd) {
18578
+ const jsonLdConfig = options.jsonLd === true ? {} : options.jsonLd;
18579
+ const jsonLdScript = renderFarmAgentJsonLd(jsonLdConfig, {
18580
+ metadataBase,
18581
+ siteName: isRecord2(resolvedMetadata.openGraph) ? normalizeContent(resolvedMetadata.openGraph.siteName) : void 0,
18582
+ title: explicitTitle,
18583
+ description: normalizeContent(resolvedMetadata.description)
18584
+ });
18585
+ if (jsonLdScript) tags.push(jsonLdScript);
18586
+ }
18291
18587
  return {
18292
18588
  title: escapeText(title),
18293
18589
  tags: tags.length > 0 ? `
@@ -18313,7 +18609,7 @@ function appendOpenGraph(tags, openGraph, metadataBase) {
18313
18609
  appendMetaProperty(tags, "og:description", openGraph.description);
18314
18610
  appendMetaProperty(tags, "og:url", resolveMetadataUrl(openGraph.url, metadataBase));
18315
18611
  appendMetaProperty(tags, "og:site_name", openGraph.siteName);
18316
- appendMetaProperty(tags, "og:type", openGraph.type);
18612
+ appendMetaProperty(tags, "og:type", openGraph.type ?? "website");
18317
18613
  appendMetaProperty(tags, "og:locale", openGraph.locale);
18318
18614
  const images = normalizeMetadataImages(
18319
18615
  openGraph.images ?? openGraph.image,
@@ -21468,7 +21764,7 @@ _setFarmThemeServerSnapshotResolver(() => {
21468
21764
  });
21469
21765
 
21470
21766
  // package.json
21471
- var version = "0.1.0-beta.97";
21767
+ var version = "0.1.0-beta.99";
21472
21768
 
21473
21769
  // src/version.ts
21474
21770
  var FARM_VERSION = version;
@@ -21638,6 +21934,13 @@ function hasRequestHeader(req, name2) {
21638
21934
  return Array.isArray(value) ? value.length > 0 : Boolean(value);
21639
21935
  }
21640
21936
  __name(hasRequestHeader, "hasRequestHeader");
21937
+ function getFarmMetadataPathname(req) {
21938
+ const raw = req.__FARM_ROUTE__ || req.url;
21939
+ if (typeof raw !== "string" || raw.length === 0) return void 0;
21940
+ const boundary = raw.search(/[?#]/);
21941
+ return boundary === -1 ? raw : raw.slice(0, boundary);
21942
+ }
21943
+ __name(getFarmMetadataPathname, "getFarmMetadataPathname");
21641
21944
  function serializeInlineValue2(value) {
21642
21945
  return JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
21643
21946
  }
@@ -22171,7 +22474,21 @@ var _ServerRenderer = class _ServerRenderer {
22171
22474
  const html = await this.rendererRuntime.renderToString(
22172
22475
  await this.wrapWithIntegrationProviders(pageElement)
22173
22476
  );
22174
- await this.cacheSSGPage(page2, html, { document: false });
22477
+ const mergedMetadata = await this.resolveRouteMetadata({
22478
+ layoutModules,
22479
+ routeModule: mod,
22480
+ pageProps,
22481
+ pathname: page2.urlPath
22482
+ });
22483
+ const { title, tags, hasFavicon } = renderMetadataHead(mergedMetadata);
22484
+ const metadataHead = `${hasFavicon ? "" : '<link rel="icon" href="data:,">\n '}<title>${title}</title>${tags}`;
22485
+ const fullDocument = this.createFullHTML(
22486
+ html,
22487
+ pageMetadata.shouldHydrate === true,
22488
+ page2.urlPath,
22489
+ metadataHead
22490
+ );
22491
+ await this.cacheSSGPage(page2, fullDocument, { document: true });
22175
22492
  logger.info(`ISR: Regenerated ${page2.urlPath}`);
22176
22493
  } catch (error) {
22177
22494
  logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
@@ -23211,7 +23528,10 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
23211
23528
  tags: metaTags,
23212
23529
  hasFavicon,
23213
23530
  hasExplicitTitle
23214
- } = renderMetadataHead(req.__FARM_METADATA__);
23531
+ } = renderMetadataHead(req.__FARM_METADATA__, {
23532
+ pathname: getFarmMetadataPathname(req),
23533
+ jsonLd: this.config.agent?.jsonLd
23534
+ });
23215
23535
  const documentTitleTag = !hasExplicitTitle && /<title[\s>]/i.test(rendererHead) ? "" : `<title>${title}</title>`;
23216
23536
  const i18nSnapshot = getFarmI18nClientSnapshot();
23217
23537
  const alternateTags = i18nSnapshot ? renderI18nAlternateLinks(req.__FARM_ROUTE__ || req.url || "/", i18nSnapshot) : "";
@@ -23396,7 +23716,10 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
23396
23716
  title,
23397
23717
  tags: metaTags,
23398
23718
  hasFavicon
23399
- } = renderMetadataHead(req.__FARM_METADATA__);
23719
+ } = renderMetadataHead(req.__FARM_METADATA__, {
23720
+ pathname: getFarmMetadataPathname(req),
23721
+ jsonLd: this.config.agent?.jsonLd
23722
+ });
23400
23723
  const i18nSnapshot = getFarmI18nClientSnapshot();
23401
23724
  const i18nAlternateTags = i18nSnapshot ? renderI18nAlternateLinks(req.__FARM_ROUTE__ || req.url || "/", i18nSnapshot) : "";
23402
23725
  const fontHead = renderFarmFontDevHead(this.config.root || process.cwd());
@@ -23554,6 +23877,15 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
23554
23877
  const pathname = resolveFarmRequestURL(req, {
23555
23878
  trustProxy: this.config.server?.trustProxy
23556
23879
  }).pathname;
23880
+ const acceptHeader = req.headers.accept;
23881
+ const accept = Array.isArray(acceptHeader) ? acceptHeader.join(",") : acceptHeader;
23882
+ if (farmRequestWantsMarkdown(pathname, accept)) {
23883
+ res.setHeader("Content-Type", FARM_MARKDOWN_CONTENT_TYPE);
23884
+ res.setHeader("X-Farm-Markdown-Error", "404");
23885
+ res.setHeader("Cache-Control", "no-store");
23886
+ res.end(createFarmMarkdownErrorBody(404, pathname, this.config.basePath || "/"));
23887
+ return;
23888
+ }
23557
23889
  try {
23558
23890
  const appDir = path12.join(this.config.root, this.config.srcDir, "app");
23559
23891
  const notFoundExtensions = getFarmRendererComponentExtensions(this.config.renderer);
@@ -23639,7 +23971,7 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue2(
23639
23971
  res.write(html);
23640
23972
  res.end();
23641
23973
  }
23642
- createFullHTML(content, isClientComponent = false, requestPath = "/", documentTitle = "Farm.js App") {
23974
+ createFullHTML(content, isClientComponent = false, requestPath = "/", metadataHead) {
23643
23975
  const i18nSnapshot = getFarmI18nClientSnapshot();
23644
23976
  const clientScript = isClientComponent ? ` <script type="module" src="/@farm/client.js"></script>` : "";
23645
23977
  const integrationManifestScript = `<script>
@@ -23663,6 +23995,7 @@ ${i18nSnapshot ? `window.__FARM_I18N__ = ${serializeInlineValue2(i18nSnapshot)};
23663
23995
  headAssets: [
23664
23996
  themeDocument.head,
23665
23997
  `<meta name="farm-deployment-id" content="${escapeHtmlAttribute2(this.getDeploymentId())}">`,
23998
+ metadataHead,
23666
23999
  alternateLinks,
23667
24000
  fontHead,
23668
24001
  `<link rel="stylesheet" href="/src/app/globals.css" />`,
@@ -23681,8 +24014,7 @@ ${i18nSnapshot ? `window.__FARM_I18N__ = ${serializeInlineValue2(i18nSnapshot)};
23681
24014
  <meta charset="utf-8">
23682
24015
  <meta name="viewport" content="width=device-width, initial-scale=1">
23683
24016
  <meta name="farm-deployment-id" content="${escapeHtmlAttribute2(this.getDeploymentId())}">
23684
- <link rel="icon" href="data:,">
23685
- <title>${escapeHtmlAttribute2(documentTitle)}</title>${alternateLinks}
24017
+ ${metadataHead ?? '<link rel="icon" href="data:,">\n <title>Farm.js App</title>'}${alternateLinks}
23686
24018
  ${fontHead}
23687
24019
  <link rel="stylesheet" href="/src/app/globals.css" />${this.collectDevStyleLinks().map((l) => `
23688
24020
  ${l}`).join("")}
@@ -23847,6 +24179,7 @@ var _FarmApp = class _FarmApp {
23847
24179
  ppr: config.experimental?.ppr ?? false,
23848
24180
  ...config.experimental
23849
24181
  },
24182
+ agent: config.agent ?? {},
23850
24183
  vite: config.vite || {}
23851
24184
  };
23852
24185
  }
@@ -27113,6 +27446,110 @@ function formatServerFnBoundaryError(violation, id) {
27113
27446
  }
27114
27447
  __name(formatServerFnBoundaryError, "formatServerFnBoundaryError");
27115
27448
 
27449
+ // src/client-boundary-env.ts
27450
+ var FUNCTION_BODY_TYPES = /* @__PURE__ */ new Set([
27451
+ "FunctionDeclaration",
27452
+ "FunctionExpression",
27453
+ "ArrowFunctionExpression"
27454
+ ]);
27455
+ function shouldInspectClientBoundary(id, code) {
27456
+ if (id.startsWith("\0") || id.startsWith("virtual:") || id.includes("node_modules")) return false;
27457
+ return code.includes("process.env") || code.includes("node:");
27458
+ }
27459
+ __name(shouldInspectClientBoundary, "shouldInspectClientBoundary");
27460
+ function analyzeClientBoundary(program, publicKeys) {
27461
+ const envKeys = /* @__PURE__ */ new Set();
27462
+ const publicEnvKeys = /* @__PURE__ */ new Set();
27463
+ const builtinImports = /* @__PURE__ */ new Set();
27464
+ const visit = /* @__PURE__ */ __name((node, inFunction) => {
27465
+ if (!node || typeof node !== "object") return;
27466
+ if (Array.isArray(node)) {
27467
+ for (const entry of node) visit(entry, inFunction);
27468
+ return;
27469
+ }
27470
+ const estree = node;
27471
+ if (typeof estree.type !== "string") return;
27472
+ if (!inFunction) {
27473
+ const builtin = readNodeBuiltinSource(estree);
27474
+ if (builtin !== void 0) builtinImports.add(builtin);
27475
+ const key = readProcessEnvKey(estree);
27476
+ if (key !== void 0) {
27477
+ if (key !== "NODE_ENV") {
27478
+ (publicKeys.has(key) ? publicEnvKeys : envKeys).add(key);
27479
+ }
27480
+ return;
27481
+ }
27482
+ }
27483
+ const nextInFunction = inFunction || FUNCTION_BODY_TYPES.has(estree.type);
27484
+ for (const [childKey, value] of Object.entries(estree)) {
27485
+ if (childKey === "type") continue;
27486
+ visit(value, nextInFunction);
27487
+ }
27488
+ }, "visit");
27489
+ visit(program.body, false);
27490
+ return {
27491
+ envKeys: [...envKeys],
27492
+ publicEnvKeys: [...publicEnvKeys],
27493
+ builtinImports: [...builtinImports]
27494
+ };
27495
+ }
27496
+ __name(analyzeClientBoundary, "analyzeClientBoundary");
27497
+ function readNodeBuiltinSource(node) {
27498
+ if (node.type === "ImportDeclaration" || node.type === "ExportNamedDeclaration" || node.type === "ExportAllDeclaration" || node.type === "ImportExpression") {
27499
+ const value = node.source?.value;
27500
+ return typeof value === "string" && value.startsWith("node:") ? value : void 0;
27501
+ }
27502
+ if (node.type === "CallExpression") {
27503
+ const callee = node.callee;
27504
+ if (callee?.type === "Identifier" && callee.name === "require") {
27505
+ const arg = node.arguments?.[0];
27506
+ const value = arg?.type === "Literal" ? arg.value : void 0;
27507
+ return typeof value === "string" && value.startsWith("node:") ? value : void 0;
27508
+ }
27509
+ }
27510
+ return void 0;
27511
+ }
27512
+ __name(readNodeBuiltinSource, "readNodeBuiltinSource");
27513
+ function readProcessEnvKey(node) {
27514
+ if (node.type !== "MemberExpression") return void 0;
27515
+ const object = node.object;
27516
+ if (!object || object.type !== "MemberExpression" || object.object?.type !== "Identifier" || object.object.name !== "process" || object.property?.name !== "env") {
27517
+ return void 0;
27518
+ }
27519
+ const property = node.property;
27520
+ if (!property) return void 0;
27521
+ if (!node.computed && property.type === "Identifier") {
27522
+ return property.name;
27523
+ }
27524
+ if (node.computed && property.type === "Literal") {
27525
+ const value = property.value;
27526
+ return typeof value === "string" ? value : void 0;
27527
+ }
27528
+ return void 0;
27529
+ }
27530
+ __name(readProcessEnvKey, "readProcessEnvKey");
27531
+ function formatClientBoundaryWarning(id, findings) {
27532
+ const { envKeys, publicEnvKeys, builtinImports } = findings;
27533
+ const lines = [`${id} is compiled for the client but uses server-only APIs:`];
27534
+ if (envKeys.length > 0) {
27535
+ lines.push(
27536
+ `- 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.`
27537
+ );
27538
+ }
27539
+ if (publicEnvKeys.length > 0) {
27540
+ lines.push(
27541
+ `- 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".`
27542
+ );
27543
+ }
27544
+ if (builtinImports.length > 0) {
27545
+ lines.push(
27546
+ `- import of ${builtinImports.join(", ")} \u2014 stubbed with an empty object in the browser. Move the import into server-only code.`
27547
+ );
27548
+ }
27549
+ return lines.join("\n");
27550
+ }
27551
+ __name(formatClientBoundaryWarning, "formatClientBoundaryWarning");
27552
+
27116
27553
  // src/vite.ts
27117
27554
  init_deployment();
27118
27555
  init_image_config();
@@ -27897,6 +28334,24 @@ function isFarmConfigFile(file, root) {
27897
28334
  return FARM_CONFIG_FILENAMES.has(relative6);
27898
28335
  }
27899
28336
  __name(isFarmConfigFile, "isFarmConfigFile");
28337
+ var warnedClientBoundaryIds = /* @__PURE__ */ new Set();
28338
+ function warnClientBoundaryOnce(context2, id, code, config) {
28339
+ if (warnedClientBoundaryIds.has(id)) return;
28340
+ let program;
28341
+ try {
28342
+ program = context2.parse(code);
28343
+ } catch {
28344
+ return;
28345
+ }
28346
+ const publicKeys = new Set(Object.keys(config.env?.public ?? {}));
28347
+ const findings = analyzeClientBoundary(program, publicKeys);
28348
+ if (findings.envKeys.length === 0 && findings.publicEnvKeys.length === 0 && findings.builtinImports.length === 0) {
28349
+ return;
28350
+ }
28351
+ warnedClientBoundaryIds.add(id);
28352
+ logger.warn(formatClientBoundaryWarning(id, findings));
28353
+ }
28354
+ __name(warnClientBoundaryOnce, "warnClientBoundaryOnce");
27900
28355
  function farmPlugin(options = {}, initialPluginManager) {
27901
28356
  const imageImports = farmImageImportsPlugin();
27902
28357
  const fontImports = farmFontImportsPlugin({
@@ -28507,6 +28962,22 @@ window.__FARM_MANIFEST__ = ${inlineValue({
28507
28962
  }
28508
28963
  return;
28509
28964
  }
28965
+ if (openAPIManager && options.openapi?.specRoute && requestPathname === options.openapi.specRoute) {
28966
+ if (requestMethod !== "GET" && requestMethod !== "HEAD") {
28967
+ res.statusCode = 405;
28968
+ res.setHeader("Allow", "GET, HEAD");
28969
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
28970
+ res.end("Method Not Allowed");
28971
+ return;
28972
+ }
28973
+ const spec = await openAPIManager.getSpec();
28974
+ const body = JSON.stringify(spec);
28975
+ res.statusCode = 200;
28976
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
28977
+ res.setHeader("Cache-Control", "no-store");
28978
+ res.end(requestMethod === "HEAD" ? void 0 : body);
28979
+ return;
28980
+ }
28510
28981
  if (openAPIManager && requestPathname === options.openapi?.route) {
28511
28982
  const docsHandler = openAPIManager.getDocsRouteHandler();
28512
28983
  return docsHandler(req, res);
@@ -28517,6 +28988,11 @@ window.__FARM_MANIFEST__ = ${inlineValue({
28517
28988
  docsHeaders.set(key, Array.isArray(value) ? value.join(", ") : value);
28518
28989
  }
28519
28990
  }
28991
+ const runAppMiddlewareForContentRoute = /* @__PURE__ */ __name(async () => {
28992
+ if (!middlewareManager?.hasMiddleware()) return false;
28993
+ const middlewareRequest = createRequestFromNodeRequest(req, new URL(fullUrl));
28994
+ return farmApp.getServerRenderer().runWithRequestContext(middlewareRequest, () => middlewareManager.execute(req, res));
28995
+ }, "runAppMiddlewareForContentRoute");
28520
28996
  if (farmDocsHandler) {
28521
28997
  const docsRequest = new Request(fullUrl, {
28522
28998
  method: requestMethod,
@@ -28524,6 +29000,7 @@ window.__FARM_MANIFEST__ = ${inlineValue({
28524
29000
  });
28525
29001
  const docsResponse = await farmDocsHandler(docsRequest.clone());
28526
29002
  if (docsResponse) {
29003
+ if (await runAppMiddlewareForContentRoute()) return;
28527
29004
  await sendWebResponse(
28528
29005
  res,
28529
29006
  await wrapFarmDocsResponseWithLayouts(docsRequest, docsResponse)
@@ -28550,6 +29027,7 @@ window.__FARM_MANIFEST__ = ${inlineValue({
28550
29027
  }, "resolveSource")
28551
29028
  });
28552
29029
  if (markdownSourceResponse) {
29030
+ if (await runAppMiddlewareForContentRoute()) return;
28553
29031
  await sendWebResponse(res, markdownSourceResponse);
28554
29032
  return;
28555
29033
  }
@@ -28563,9 +29041,23 @@ window.__FARM_MANIFEST__ = ${inlineValue({
28563
29041
  renderPage: /* @__PURE__ */ __name(async (request) => fetch(request), "renderPage")
28564
29042
  });
28565
29043
  if (markdownResponse) {
29044
+ if (await runAppMiddlewareForContentRoute()) return;
28566
29045
  await sendWebResponse(res, markdownResponse);
28567
29046
  return;
28568
29047
  }
29048
+ if (farmRequestWantsMarkdown(requestPathname, req.headers.accept)) {
29049
+ const markdownRoute = farmApp.getRouteManager().matchRoute(normalizeFarmMarkdownRoutePath(requestPathname));
29050
+ if (!markdownRoute.route) {
29051
+ res.statusCode = 404;
29052
+ res.setHeader("Content-Type", FARM_MARKDOWN_CONTENT_TYPE);
29053
+ res.setHeader("X-Farm-Markdown-Error", "404");
29054
+ res.setHeader("Cache-Control", "no-store");
29055
+ res.end(
29056
+ createFarmMarkdownErrorBody(404, requestPathname, farmConfig.basePath || "/")
29057
+ );
29058
+ return;
29059
+ }
29060
+ }
28569
29061
  const markdownPageTarget = resolveMarkdownMirrorTarget(
28570
29062
  farmApp.getConfig().md,
28571
29063
  requestPathname,
@@ -29514,6 +30006,9 @@ export const manifest = getManifest();
29514
30006
  }
29515
30007
  }
29516
30008
  }
30009
+ if (!transformOptions?.ssr && shouldInspectClientBoundary(id, code)) {
30010
+ warnClientBoundaryOnce(this, id, code, farmApp?.getConfig() ?? options);
30011
+ }
29517
30012
  if (typeof imageImports.transform === "function") {
29518
30013
  const imageModule = await imageImports.transform.call(this, code, id, transformOptions);
29519
30014
  if (imageModule) return imageModule;