@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
@@ -59,6 +59,109 @@ function subscribeFarmCacheTask(listener) {
59
59
  }
60
60
  __name(subscribeFarmCacheTask, "subscribeFarmCacheTask");
61
61
 
62
+ // src/request-origin.ts
63
+ function getRequestSourceOrigin(request) {
64
+ const origin = request.headers.get("origin")?.trim();
65
+ if (origin) {
66
+ return parseSourceOrigin(origin);
67
+ }
68
+ const referer = request.headers.get("referer")?.trim();
69
+ if (referer) {
70
+ return parseSourceOrigin(referer);
71
+ }
72
+ return { ok: true, origin: null };
73
+ }
74
+ __name(getRequestSourceOrigin, "getRequestSourceOrigin");
75
+ function parseSourceOrigin(value) {
76
+ if (value === "null") {
77
+ return { ok: false, reason: "opaque-origin" };
78
+ }
79
+ try {
80
+ const parsed = new URL(value);
81
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
82
+ return { ok: false, reason: "invalid-origin" };
83
+ }
84
+ return { ok: true, origin: parsed.origin };
85
+ } catch {
86
+ return { ok: false, reason: "invalid-origin" };
87
+ }
88
+ }
89
+ __name(parseSourceOrigin, "parseSourceOrigin");
90
+ function matchesHostHeader(sourceOrigin, request) {
91
+ const host = request.headers.get("host")?.trim().toLowerCase();
92
+ if (!host) return false;
93
+ try {
94
+ const source = new URL(sourceOrigin);
95
+ const target = new URL(request.url);
96
+ return source.protocol === target.protocol && source.host.toLowerCase() === host;
97
+ } catch {
98
+ return false;
99
+ }
100
+ }
101
+ __name(matchesHostHeader, "matchesHostHeader");
102
+ function matchesAllowedOrigin(sourceOrigin, pattern) {
103
+ const source = new URL(sourceOrigin);
104
+ if (!pattern.includes("*")) {
105
+ return pattern.includes("://") ? source.origin === pattern : source.host === pattern;
106
+ }
107
+ const schemeEnd = pattern.indexOf("://");
108
+ const scheme = schemeEnd === -1 ? null : pattern.slice(0, schemeEnd + 1);
109
+ const hostPattern = pattern.slice(schemeEnd === -1 ? 0 : schemeEnd + 3);
110
+ const [wildcardHost, port] = splitHostAndPort(hostPattern);
111
+ const baseHost = wildcardHost.slice(2);
112
+ if (scheme && source.protocol !== scheme) return false;
113
+ if (port && getEffectivePort(source) !== port) return false;
114
+ if (!port && source.port) return false;
115
+ return source.hostname.endsWith(`.${baseHost}`) && source.hostname !== baseHost;
116
+ }
117
+ __name(matchesAllowedOrigin, "matchesAllowedOrigin");
118
+ function normalizeAllowedOriginPattern(value, label) {
119
+ const pattern = value.trim().toLowerCase();
120
+ if (!pattern) {
121
+ throw new TypeError(`${label} cannot contain empty values`);
122
+ }
123
+ if (pattern.includes("*")) {
124
+ if (!/^(?:https?:\/\/)?\*\.[a-z0-9.-]+(?::\d+)?$/.test(pattern)) {
125
+ throw new TypeError(`Invalid ${label} pattern: ${JSON.stringify(value)}`);
126
+ }
127
+ return pattern;
128
+ }
129
+ if (pattern.includes("://")) {
130
+ let parsed;
131
+ try {
132
+ parsed = new URL(pattern);
133
+ } catch {
134
+ throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);
135
+ }
136
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
137
+ throw new TypeError(`${label} must contain origins without paths: ${JSON.stringify(value)}`);
138
+ }
139
+ return parsed.origin;
140
+ }
141
+ if (/[/@?#]/.test(pattern)) {
142
+ throw new TypeError(`${label} must contain origins or hosts: ${JSON.stringify(value)}`);
143
+ }
144
+ try {
145
+ return new URL(`http://${pattern}`).host;
146
+ } catch {
147
+ throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);
148
+ }
149
+ }
150
+ __name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
151
+ function splitHostAndPort(value) {
152
+ const separator = value.lastIndexOf(":");
153
+ if (separator === -1) return [value, null];
154
+ return [value.slice(0, separator), value.slice(separator + 1)];
155
+ }
156
+ __name(splitHostAndPort, "splitHostAndPort");
157
+ function getEffectivePort(url) {
158
+ if (url.port) return url.port;
159
+ if (url.protocol === "https:") return "443";
160
+ if (url.protocol === "http:") return "80";
161
+ return "";
162
+ }
163
+ __name(getEffectivePort, "getEffectivePort");
164
+
62
165
  // src/server-fn-error.ts
63
166
  var FARM_SERVER_FN_FAILURE_SYMBOL = /* @__PURE__ */ Symbol.for("farm.server-fn.failure");
64
167
  function isServerFnFailure(value) {
@@ -111,6 +214,7 @@ function parseBodySizeLimit(value, optionName = "bodySizeLimit") {
111
214
  __name(parseBodySizeLimit, "parseBodySizeLimit");
112
215
 
113
216
  // src/server-action-security.ts
217
+ var SERVER_ACTION_ALLOWED_ORIGINS_LABEL = "serverActions.allowedOrigins";
114
218
  var DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT = 1e6;
115
219
  var _ServerActionRequestError = class _ServerActionRequestError extends Error {
116
220
  constructor(code, status, message) {
@@ -135,7 +239,9 @@ var JAVASCRIPT_ACTION_CONTENT_TYPES = /* @__PURE__ */ new Set([
135
239
  "text/plain"
136
240
  ]);
137
241
  function resolveServerActionsConfig(config) {
138
- const allowedOrigins = (config?.allowedOrigins ?? []).map(normalizeAllowedOriginPattern);
242
+ const allowedOrigins = (config?.allowedOrigins ?? []).map(
243
+ (value) => normalizeAllowedOriginPattern(value, SERVER_ACTION_ALLOWED_ORIGINS_LABEL)
244
+ );
139
245
  const bodySizeLimit = parseBodySizeLimit(
140
246
  config?.bodySizeLimit ?? DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT,
141
247
  "serverActions.bodySizeLimit"
@@ -155,7 +261,7 @@ function validateServerActionRequest(request, config) {
155
261
  );
156
262
  }
157
263
  const requestUrl = new URL(request.url);
158
- const sourceOrigin = getRequestSourceOrigin(request);
264
+ const sourceOrigin = resolveSourceOrigin(request);
159
265
  const fetchSite = request.headers.get("sec-fetch-site")?.trim().toLowerCase();
160
266
  if (!sourceOrigin) {
161
267
  if (fetchSite !== "same-origin") {
@@ -287,111 +393,18 @@ function getFallbackAbortController() {
287
393
  return globalState2[FALLBACK_ABORT_CONTROLLER_KEY];
288
394
  }
289
395
  __name(getFallbackAbortController, "getFallbackAbortController");
290
- function normalizeAllowedOriginPattern(value) {
291
- const pattern = value.trim().toLowerCase();
292
- if (!pattern) {
293
- throw new TypeError("serverActions.allowedOrigins cannot contain empty values");
294
- }
295
- if (pattern.includes("*")) {
296
- if (!/^(?:https?:\/\/)?\*\.[a-z0-9.-]+(?::\d+)?$/.test(pattern)) {
297
- throw new TypeError(`Invalid serverActions.allowedOrigins pattern: ${JSON.stringify(value)}`);
298
- }
299
- return pattern;
300
- }
301
- if (pattern.includes("://")) {
302
- let parsed;
303
- try {
304
- parsed = new URL(pattern);
305
- } catch {
306
- throw new TypeError(`Invalid serverActions.allowedOrigins value: ${JSON.stringify(value)}`);
307
- }
308
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
309
- throw new TypeError(
310
- `serverActions.allowedOrigins must contain origins without paths: ${JSON.stringify(value)}`
311
- );
312
- }
313
- return parsed.origin;
314
- }
315
- if (/[/@?#]/.test(pattern)) {
316
- throw new TypeError(
317
- `serverActions.allowedOrigins must contain origins or hosts: ${JSON.stringify(value)}`
396
+ function resolveSourceOrigin(request) {
397
+ const result = getRequestSourceOrigin(request);
398
+ if (!result.ok) {
399
+ throw new ServerActionRequestError(
400
+ "INVALID_ORIGIN",
401
+ 403,
402
+ result.reason === "opaque-origin" ? "Opaque origins are not allowed" : "Invalid request origin"
318
403
  );
319
404
  }
320
- try {
321
- return new URL(`http://${pattern}`).host;
322
- } catch {
323
- throw new TypeError(`Invalid serverActions.allowedOrigins value: ${JSON.stringify(value)}`);
324
- }
405
+ return result.origin;
325
406
  }
326
- __name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
327
- function getRequestSourceOrigin(request) {
328
- const origin = request.headers.get("origin")?.trim();
329
- if (origin) {
330
- return parseSourceOrigin(origin);
331
- }
332
- const referer = request.headers.get("referer")?.trim();
333
- if (referer) {
334
- return parseSourceOrigin(referer);
335
- }
336
- return null;
337
- }
338
- __name(getRequestSourceOrigin, "getRequestSourceOrigin");
339
- function parseSourceOrigin(value) {
340
- if (value === "null") {
341
- throw new ServerActionRequestError("INVALID_ORIGIN", 403, "Opaque origins are not allowed");
342
- }
343
- try {
344
- const parsed = new URL(value);
345
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
346
- throw new Error("Unsupported protocol");
347
- }
348
- return parsed.origin;
349
- } catch {
350
- throw new ServerActionRequestError("INVALID_ORIGIN", 403, "Invalid request origin");
351
- }
352
- }
353
- __name(parseSourceOrigin, "parseSourceOrigin");
354
- function matchesHostHeader(sourceOrigin, request) {
355
- const host = request.headers.get("host")?.trim().toLowerCase();
356
- if (!host) return false;
357
- try {
358
- const source = new URL(sourceOrigin);
359
- const target = new URL(request.url);
360
- return source.protocol === target.protocol && source.host.toLowerCase() === host;
361
- } catch {
362
- return false;
363
- }
364
- }
365
- __name(matchesHostHeader, "matchesHostHeader");
366
- function matchesAllowedOrigin(sourceOrigin, pattern) {
367
- const source = new URL(sourceOrigin);
368
- if (!pattern.includes("*")) {
369
- return pattern.includes("://") ? source.origin === pattern : source.host === pattern;
370
- }
371
- const schemeEnd = pattern.indexOf("://");
372
- const scheme = schemeEnd === -1 ? null : pattern.slice(0, schemeEnd + 1);
373
- const hostPattern = pattern.slice(schemeEnd === -1 ? 0 : schemeEnd + 3);
374
- const [wildcardHost, port] = splitHostAndPort(hostPattern);
375
- const baseHost = wildcardHost.slice(2);
376
- if (scheme && source.protocol !== scheme) return false;
377
- if (port && getEffectivePort(source) !== port) return false;
378
- if (!port && source.port) return false;
379
- return source.hostname.endsWith(`.${baseHost}`) && source.hostname !== baseHost;
380
- }
381
- __name(matchesAllowedOrigin, "matchesAllowedOrigin");
382
- function splitHostAndPort(value) {
383
- const separator = value.lastIndexOf(":");
384
- if (separator === -1) return [value, null];
385
- return [value.slice(0, separator), value.slice(separator + 1)];
386
- }
387
- __name(splitHostAndPort, "splitHostAndPort");
388
- function getEffectivePort(url) {
389
- if (url.port) return url.port;
390
- if (url.protocol === "https:") return "443";
391
- if (url.protocol === "http:") return "80";
392
- return "";
393
- }
394
- __name(getEffectivePort, "getEffectivePort");
407
+ __name(resolveSourceOrigin, "resolveSourceOrigin");
395
408
  function validateActionId(actionId) {
396
409
  if (!actionId || actionId.length > 4096 || hasControlCharacters(actionId)) {
397
410
  throw new ServerActionRequestError("INVALID_ACTION_ID", 400, "Invalid server action id");
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server-action-security.ts","../src/cache-invalidation.ts","../src/request-origin.ts","../src/server-fn-error.ts","../src/server-http.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { subscribeFarmCacheInvalidation, subscribeFarmCacheTask } from \"./cache-invalidation\";\nimport {\n getRequestSourceOrigin,\n matchesAllowedOrigin,\n matchesHostHeader,\n normalizeAllowedOriginPattern,\n} from \"./request-origin\";\nimport { serializeServerFnFailure, type SerializedServerFnFailure } from \"./server-fn-error\";\nimport { parseBodySizeLimit } from \"./server-http\";\n\nconst SERVER_ACTION_ALLOWED_ORIGINS_LABEL = \"serverActions.allowedOrigins\";\n\nexport const DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT = 1_000_000;\n\nexport interface FarmServerActionsConfig {\n /** Additional trusted origins or host patterns, such as https://app.example.com. */\n allowedOrigins?: readonly string[];\n /** Maximum encoded request body size in bytes or as a size string such as \"1mb\". */\n bodySizeLimit?: number | string;\n}\n\nexport interface ResolvedFarmServerActionsConfig {\n allowedOrigins: readonly string[];\n bodySizeLimit: number;\n}\n\nexport type ServerActionRequestKind = \"javascript\" | \"form\";\n\nexport interface PreparedServerActionRequest {\n body: string | FormData;\n contentType: string;\n}\n\nexport type SanitizedServerActionError =\n | {\n name: \"ServerActionError\";\n message: \"Server function failed\";\n }\n | SerializedServerFnFailure;\n\ntype ServerActionRequestErrorCode =\n | \"BODY_TOO_LARGE\"\n | \"INVALID_ACTION_ID\"\n | \"INVALID_BODY\"\n | \"INVALID_CONTENT_LENGTH\"\n | \"INVALID_METHOD\"\n | \"INVALID_ORIGIN\"\n | \"MISSING_ORIGIN\"\n | \"UNSUPPORTED_CONTENT_TYPE\";\n\nexport class ServerActionRequestError extends Error {\n readonly code: ServerActionRequestErrorCode;\n readonly status: number;\n\n constructor(code: ServerActionRequestErrorCode, status: number, message: string) {\n super(message);\n this.name = \"ServerActionRequestError\";\n this.code = code;\n this.status = status;\n }\n}\n\ntype ServerActionExecutionContext = {\n request: Request;\n signal: AbortSignal;\n invalidations: Set<string>;\n cacheTasks: Set<Promise<void>>;\n};\n\nconst SERVER_ACTION_STORAGE_KEY = Symbol.for(\"farm.serverActionStorage\");\nconst FALLBACK_ABORT_CONTROLLER_KEY = Symbol.for(\"farm.serverActionFallbackAbortController\");\nconst FORM_ACTION_CONTENT_TYPES = new Set([\n \"application/x-www-form-urlencoded\",\n \"multipart/form-data\",\n]);\nconst JAVASCRIPT_ACTION_CONTENT_TYPES = new Set([\n \"application/octet-stream\",\n \"application/x-www-form-urlencoded\",\n \"multipart/form-data\",\n \"text/plain\",\n]);\n\ntype GlobalWithServerActionStorage = typeof globalThis & {\n [SERVER_ACTION_STORAGE_KEY]?: AsyncLocalStorage<ServerActionExecutionContext>;\n [FALLBACK_ABORT_CONTROLLER_KEY]?: AbortController;\n};\n\nexport function resolveServerActionsConfig(\n config: FarmServerActionsConfig | undefined,\n): ResolvedFarmServerActionsConfig {\n const allowedOrigins = (config?.allowedOrigins ?? []).map((value) =>\n normalizeAllowedOriginPattern(value, SERVER_ACTION_ALLOWED_ORIGINS_LABEL),\n );\n const bodySizeLimit = parseBodySizeLimit(\n config?.bodySizeLimit ?? DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT,\n \"serverActions.bodySizeLimit\",\n );\n\n return Object.freeze({\n allowedOrigins: Object.freeze(allowedOrigins),\n bodySizeLimit,\n });\n}\n\nexport function validateServerActionRequest(\n request: Request,\n config: ResolvedFarmServerActionsConfig,\n): void {\n if (request.method.toUpperCase() !== \"POST\") {\n throw new ServerActionRequestError(\n \"INVALID_METHOD\",\n 405,\n \"Server actions only accept POST requests\",\n );\n }\n\n const requestUrl = new URL(request.url);\n const sourceOrigin = resolveSourceOrigin(request);\n const fetchSite = request.headers.get(\"sec-fetch-site\")?.trim().toLowerCase();\n\n if (!sourceOrigin) {\n if (fetchSite !== \"same-origin\") {\n throw new ServerActionRequestError(\n \"MISSING_ORIGIN\",\n 403,\n \"Server action request is missing same-origin metadata\",\n );\n }\n return;\n }\n\n const matchesRequest =\n sourceOrigin === requestUrl.origin || matchesHostHeader(sourceOrigin, request);\n const matchesConfiguredOrigin = config.allowedOrigins.some((pattern) =>\n matchesAllowedOrigin(sourceOrigin, pattern),\n );\n\n if (!matchesRequest && !matchesConfiguredOrigin) {\n throw new ServerActionRequestError(\n \"INVALID_ORIGIN\",\n 403,\n \"Server action origin does not match the request origin\",\n );\n }\n\n if (fetchSite === \"cross-site\" && !matchesConfiguredOrigin) {\n throw new ServerActionRequestError(\n \"INVALID_ORIGIN\",\n 403,\n \"Cross-site server action request was rejected\",\n );\n }\n}\n\nexport async function prepareServerActionRequest(\n request: Request,\n config: ResolvedFarmServerActionsConfig,\n kind: ServerActionRequestKind,\n actionId?: string | null,\n): Promise<PreparedServerActionRequest> {\n validateServerActionRequest(request, config);\n\n if (kind === \"javascript\") {\n validateActionId(actionId);\n }\n\n const contentType = getSupportedContentType(request, kind);\n const bytes = await readBodyWithLimit(request, config.bodySizeLimit);\n\n if (kind === \"form\" || contentType === \"multipart/form-data\") {\n return {\n body: await parseFormData(request, bytes),\n contentType,\n };\n }\n\n return {\n body: new TextDecoder().decode(bytes),\n contentType,\n };\n}\n\nexport function createServerActionRequestErrorResponse(error: unknown): Response | null {\n if (!(error instanceof ServerActionRequestError)) {\n return null;\n }\n\n const headers = new Headers({\n \"cache-control\": \"no-store\",\n \"content-type\": \"text/plain; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\",\n });\n if (error.status === 405) {\n headers.set(\"allow\", \"POST\");\n }\n\n return new Response(getPublicErrorMessage(error.status), {\n status: error.status,\n headers,\n });\n}\n\nexport function sanitizeServerActionError(error: unknown): SanitizedServerActionError {\n const declaredFailure = serializeServerFnFailure(error);\n if (declaredFailure) return declaredFailure;\n\n return {\n name: \"ServerActionError\",\n message: \"Server function failed\",\n };\n}\n\nexport async function runWithServerActionRequest<T>(\n request: Request,\n callback: () => T | Promise<T>,\n): Promise<T> {\n throwIfAborted(request.signal);\n const context: ServerActionExecutionContext = {\n request,\n signal: request.signal,\n invalidations: new Set(),\n cacheTasks: new Set(),\n };\n\n return getServerActionStorage().run(context, async () => {\n try {\n const result = await callback();\n await Promise.all(context.cacheTasks);\n return result;\n } catch (error) {\n await Promise.allSettled(context.cacheTasks);\n throw error;\n }\n });\n}\n\nexport function getServerActionExecutionContext(): ServerActionExecutionContext | undefined {\n return getServerActionStorage().getStore();\n}\n\nexport function getServerActionSignal(): AbortSignal {\n return getServerActionExecutionContext()?.signal ?? getFallbackAbortController().signal;\n}\n\nexport function getServerActionInvalidations(): readonly string[] {\n return Array.from(getServerActionExecutionContext()?.invalidations ?? []);\n}\n\nsubscribeFarmCacheInvalidation((key) => {\n getServerActionExecutionContext()?.invalidations.add(key);\n});\n\nsubscribeFarmCacheTask((task) => {\n getServerActionExecutionContext()?.cacheTasks.add(task);\n});\n\nfunction getServerActionStorage(): AsyncLocalStorage<ServerActionExecutionContext> {\n const globalState = globalThis as GlobalWithServerActionStorage;\n if (!globalState[SERVER_ACTION_STORAGE_KEY]) {\n globalState[SERVER_ACTION_STORAGE_KEY] = new AsyncLocalStorage<ServerActionExecutionContext>();\n }\n return globalState[SERVER_ACTION_STORAGE_KEY]!;\n}\n\nfunction getFallbackAbortController(): AbortController {\n const globalState = globalThis as GlobalWithServerActionStorage;\n if (!globalState[FALLBACK_ABORT_CONTROLLER_KEY]) {\n globalState[FALLBACK_ABORT_CONTROLLER_KEY] = new AbortController();\n }\n return globalState[FALLBACK_ABORT_CONTROLLER_KEY]!;\n}\n\n/**\n * Adapt the shared origin resolution onto the server-action error contract:\n * an unusable Origin/Referer is a 403 here, while a request that simply\n * carried neither header returns null for the caller to judge.\n */\nfunction resolveSourceOrigin(request: Request): string | null {\n const result = getRequestSourceOrigin(request);\n\n if (!result.ok) {\n throw new ServerActionRequestError(\n \"INVALID_ORIGIN\",\n 403,\n result.reason === \"opaque-origin\"\n ? \"Opaque origins are not allowed\"\n : \"Invalid request origin\",\n );\n }\n\n return result.origin;\n}\n\nfunction validateActionId(actionId?: string | null): asserts actionId is string {\n if (!actionId || actionId.length > 4096 || hasControlCharacters(actionId)) {\n throw new ServerActionRequestError(\"INVALID_ACTION_ID\", 400, \"Invalid server action id\");\n }\n}\n\nfunction hasControlCharacters(value: string): boolean {\n for (let index = 0; index < value.length; index++) {\n const code = value.charCodeAt(index);\n if (code <= 31 || code === 127) return true;\n }\n return false;\n}\n\nfunction getSupportedContentType(request: Request, kind: ServerActionRequestKind): string {\n const header = request.headers.get(\"content-type\")?.trim().toLowerCase();\n const contentType = header?.split(\";\", 1)[0]?.trim() ?? \"\";\n const supported = kind === \"form\" ? FORM_ACTION_CONTENT_TYPES : JAVASCRIPT_ACTION_CONTENT_TYPES;\n\n if (!supported.has(contentType)) {\n throw new ServerActionRequestError(\n \"UNSUPPORTED_CONTENT_TYPE\",\n 415,\n \"Unsupported server action content type\",\n );\n }\n\n return contentType;\n}\n\nasync function readBodyWithLimit(request: Request, limit: number): Promise<Uint8Array> {\n const contentLength = request.headers.get(\"content-length\")?.trim();\n if (contentLength) {\n if (!/^\\d+$/.test(contentLength)) {\n throw new ServerActionRequestError(\n \"INVALID_CONTENT_LENGTH\",\n 400,\n \"Invalid content-length header\",\n );\n }\n if (Number(contentLength) > limit) {\n throw new ServerActionRequestError(\"BODY_TOO_LARGE\", 413, \"Server action body is too large\");\n }\n }\n\n throwIfAborted(request.signal);\n if (!request.body) return new Uint8Array();\n\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n const cancelBodyRead = () => {\n void reader.cancel(request.signal.reason).catch(() => {});\n };\n\n request.signal.addEventListener(\"abort\", cancelBodyRead, { once: true });\n\n try {\n while (true) {\n throwIfAborted(request.signal);\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n total += value.byteLength;\n if (total > limit) {\n const error = new ServerActionRequestError(\n \"BODY_TOO_LARGE\",\n 413,\n \"Server action body is too large\",\n );\n // As with API bodies, a cloned stream may wait for its untouched tee\n // branch. Cleanup must neither delay rejection nor replace its error.\n void reader.cancel(error).catch(() => {});\n throw error;\n }\n chunks.push(value);\n }\n } catch (error) {\n if (request.signal.aborted) throwIfAborted(request.signal);\n throw error;\n } finally {\n request.signal.removeEventListener(\"abort\", cancelBodyRead);\n reader.releaseLock();\n }\n\n throwIfAborted(request.signal);\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return body;\n}\n\nasync function parseFormData(request: Request, bytes: Uint8Array): Promise<FormData> {\n const body = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(body).set(bytes);\n const copy = new Request(request.url, {\n method: \"POST\",\n headers: request.headers,\n body,\n });\n\n try {\n return await copy.formData();\n } catch {\n throw new ServerActionRequestError(\"INVALID_BODY\", 400, \"Invalid server action form body\");\n }\n}\n\nfunction getPublicErrorMessage(status: number): string {\n switch (status) {\n case 400:\n return \"Bad Request\";\n case 403:\n return \"Forbidden\";\n case 405:\n return \"Method Not Allowed\";\n case 413:\n return \"Payload Too Large\";\n case 415:\n return \"Unsupported Media Type\";\n default:\n return \"Server Action Request Failed\";\n }\n}\n\nfunction throwIfAborted(signal: AbortSignal): void {\n if (!signal.aborted) return;\n if (signal.reason !== undefined) throw signal.reason;\n throw new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n","export type FarmCacheInvalidationListener = (key: string) => void;\nexport type FarmCacheTaskListener = (task: Promise<void>) => void;\n\nexport const FARM_CACHE_INVALIDATION_HEADER = \"x-farm-cache-invalidations\";\n\ntype FarmCacheInvalidationState = {\n listeners: Set<FarmCacheInvalidationListener>;\n taskListeners: Set<FarmCacheTaskListener>;\n};\n\nconst FARM_CACHE_INVALIDATION_STATE = Symbol.for(\"farm.cacheInvalidationState\");\nconst globalState = globalThis as typeof globalThis & {\n [FARM_CACHE_INVALIDATION_STATE]?: FarmCacheInvalidationState;\n};\n\nfunction getFarmCacheInvalidationState(): FarmCacheInvalidationState {\n return (globalState[FARM_CACHE_INVALIDATION_STATE] ??= {\n listeners: new Set(),\n taskListeners: new Set(),\n });\n}\n\nfunction warnFarmCacheListenerError(scope: string, error: unknown): void {\n const detail = error instanceof Error ? (error.stack ?? error.message) : String(error);\n console.warn(`[farm:cache] ${scope} listener failed: ${detail}`);\n}\n\nexport function notifyFarmCacheInvalidation(key: string): void {\n if (typeof key !== \"string\" || key.length === 0) return;\n\n for (const listener of getFarmCacheInvalidationState().listeners) {\n // Isolate listeners: one throwing observer must not abort the remaining\n // listeners (or the rest of a multi-key batch in applyFarmCacheInvalidations)\n // and must not surface as a 500 when invalidation runs inside a request.\n try {\n listener(key);\n } catch (error) {\n warnFarmCacheListenerError(\"invalidation\", error);\n }\n }\n}\n\nexport function notifyFarmCacheTask(task: Promise<void>): void {\n for (const listener of getFarmCacheInvalidationState().taskListeners) {\n try {\n listener(task);\n } catch (error) {\n warnFarmCacheListenerError(\"task\", error);\n }\n }\n}\n\nexport function applyFarmCacheInvalidations(keys: unknown): void {\n if (!Array.isArray(keys)) return;\n\n for (const key of keys) {\n if (typeof key === \"string\") {\n notifyFarmCacheInvalidation(key);\n }\n }\n}\n\nexport function encodeFarmCacheInvalidations(keys: readonly string[]): string | null {\n const normalized = Array.from(\n new Set(keys.filter((key) => typeof key === \"string\" && key.length > 0)),\n );\n if (normalized.length === 0) return null;\n return encodeURIComponent(JSON.stringify(normalized));\n}\n\nexport function decodeFarmCacheInvalidations(value: string | null | undefined): readonly string[] {\n if (!value) return [];\n\n try {\n const parsed = JSON.parse(decodeURIComponent(value));\n return Array.isArray(parsed)\n ? Array.from(\n new Set(parsed.filter((key): key is string => typeof key === \"string\" && key.length > 0)),\n )\n : [];\n } catch {\n return [];\n }\n}\n\nexport function subscribeFarmCacheInvalidation(\n listener: FarmCacheInvalidationListener,\n): () => void {\n const state = getFarmCacheInvalidationState();\n state.listeners.add(listener);\n return () => state.listeners.delete(listener);\n}\n\nexport function subscribeFarmCacheTask(listener: FarmCacheTaskListener): () => void {\n const state = getFarmCacheInvalidationState();\n state.taskListeners.add(listener);\n return () => state.taskListeners.delete(listener);\n}\n","/**\n * Shared request-origin primitives.\n *\n * Server actions and integration auth routes both need to decide whether a\n * state-changing request actually came from the app's own origin. The matching\n * rules (Origin/Referer resolution, Host fallback, wildcard subdomain patterns)\n * are security-sensitive and must not drift between the two, so they live here\n * and are consumed by both rather than reimplemented.\n *\n * These helpers never throw for untrusted input: callers map the failure\n * reasons onto their own error shapes.\n */\n\nexport type RequestOriginFailureReason = \"opaque-origin\" | \"invalid-origin\";\n\nexport type RequestSourceOriginResult =\n /** `origin` is null when the request carried no Origin or Referer header. */\n { ok: true; origin: string | null } | { ok: false; reason: RequestOriginFailureReason };\n\n/** Resolve the origin a request claims to come from, preferring Origin over Referer. */\nexport function getRequestSourceOrigin(request: Request): RequestSourceOriginResult {\n const origin = request.headers.get(\"origin\")?.trim();\n if (origin) {\n return parseSourceOrigin(origin);\n }\n\n const referer = request.headers.get(\"referer\")?.trim();\n if (referer) {\n return parseSourceOrigin(referer);\n }\n\n return { ok: true, origin: null };\n}\n\nfunction parseSourceOrigin(value: string): RequestSourceOriginResult {\n if (value === \"null\") {\n return { ok: false, reason: \"opaque-origin\" };\n }\n\n try {\n const parsed = new URL(value);\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return { ok: false, reason: \"invalid-origin\" };\n }\n return { ok: true, origin: parsed.origin };\n } catch {\n return { ok: false, reason: \"invalid-origin\" };\n }\n}\n\n/**\n * Accept a source origin that matches the Host header even when `request.url`\n * was rebuilt behind a proxy with a different visible origin.\n */\nexport function matchesHostHeader(sourceOrigin: string, request: Request): boolean {\n const host = request.headers.get(\"host\")?.trim().toLowerCase();\n if (!host) return false;\n\n try {\n const source = new URL(sourceOrigin);\n const target = new URL(request.url);\n return source.protocol === target.protocol && source.host.toLowerCase() === host;\n } catch {\n return false;\n }\n}\n\nexport function matchesAllowedOrigin(sourceOrigin: string, pattern: string): boolean {\n const source = new URL(sourceOrigin);\n if (!pattern.includes(\"*\")) {\n return pattern.includes(\"://\") ? source.origin === pattern : source.host === pattern;\n }\n\n const schemeEnd = pattern.indexOf(\"://\");\n const scheme = schemeEnd === -1 ? null : pattern.slice(0, schemeEnd + 1);\n const hostPattern = pattern.slice(schemeEnd === -1 ? 0 : schemeEnd + 3);\n const [wildcardHost, port] = splitHostAndPort(hostPattern);\n const baseHost = wildcardHost.slice(2);\n\n if (scheme && source.protocol !== scheme) return false;\n if (port && getEffectivePort(source) !== port) return false;\n if (!port && source.port) return false;\n\n return source.hostname.endsWith(`.${baseHost}`) && source.hostname !== baseHost;\n}\n\n/**\n * Validate and canonicalize a configured origin pattern. `label` names the\n * configuration field so the thrown message points at the user's own setting.\n */\nexport function normalizeAllowedOriginPattern(value: string, label: string): string {\n const pattern = value.trim().toLowerCase();\n if (!pattern) {\n throw new TypeError(`${label} cannot contain empty values`);\n }\n\n if (pattern.includes(\"*\")) {\n if (!/^(?:https?:\\/\\/)?\\*\\.[a-z0-9.-]+(?::\\d+)?$/.test(pattern)) {\n throw new TypeError(`Invalid ${label} pattern: ${JSON.stringify(value)}`);\n }\n return pattern;\n }\n\n if (pattern.includes(\"://\")) {\n let parsed: URL;\n try {\n parsed = new URL(pattern);\n } catch {\n throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);\n }\n\n if (\n (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n parsed.username ||\n parsed.password ||\n parsed.pathname !== \"/\" ||\n parsed.search ||\n parsed.hash\n ) {\n throw new TypeError(`${label} must contain origins without paths: ${JSON.stringify(value)}`);\n }\n return parsed.origin;\n }\n\n if (/[/@?#]/.test(pattern)) {\n throw new TypeError(`${label} must contain origins or hosts: ${JSON.stringify(value)}`);\n }\n\n try {\n return new URL(`http://${pattern}`).host;\n } catch {\n throw new TypeError(`Invalid ${label} value: ${JSON.stringify(value)}`);\n }\n}\n\nfunction splitHostAndPort(value: string): [string, string | null] {\n const separator = value.lastIndexOf(\":\");\n if (separator === -1) return [value, null];\n return [value.slice(0, separator), value.slice(separator + 1)];\n}\n\nfunction getEffectivePort(url: URL): string {\n if (url.port) return url.port;\n if (url.protocol === \"https:\") return \"443\";\n if (url.protocol === \"http:\") return \"80\";\n return \"\";\n}\n","export const FARM_SERVER_FN_FAILURE_SYMBOL = Symbol.for(\"farm.server-fn.failure\");\n\nexport type SerializedServerFnFailure = {\n name: \"ServerFnFailure\";\n message: string;\n code: string;\n status: number;\n data: unknown;\n};\n\nexport class ServerFnFailure<\n TCode extends string = string,\n TData = unknown,\n TStatus extends number = number,\n> extends Error {\n readonly name = \"ServerFnFailure\" as const;\n readonly code: TCode;\n readonly data: TData;\n readonly status: TStatus;\n\n constructor(\n code: TCode,\n data: TData,\n options: {\n status: TStatus;\n message: string;\n },\n ) {\n super(options.message);\n this.code = code;\n this.data = data;\n this.status = options.status;\n\n Object.defineProperty(this, FARM_SERVER_FN_FAILURE_SYMBOL, {\n value: true,\n enumerable: false,\n });\n }\n}\n\nexport class ServerActionError extends Error {\n readonly name = \"ServerActionError\" as const;\n\n constructor(message = \"Server function failed\") {\n super(message);\n }\n}\n\nexport function isServerFnFailure(value: unknown): value is ServerFnFailure {\n if (!value || typeof value !== \"object\") return false;\n\n const candidate = value as Partial<ServerFnFailure> & {\n [FARM_SERVER_FN_FAILURE_SYMBOL]?: unknown;\n };\n return (\n candidate[FARM_SERVER_FN_FAILURE_SYMBOL] === true &&\n candidate.name === \"ServerFnFailure\" &&\n typeof candidate.code === \"string\" &&\n Number.isInteger(candidate.status) &&\n (candidate.status ?? 0) >= 400 &&\n (candidate.status ?? 0) <= 599\n );\n}\n\nexport function serializeServerFnFailure(value: unknown): SerializedServerFnFailure | null {\n if (!isServerFnFailure(value)) return null;\n\n return {\n name: \"ServerFnFailure\",\n message: value.message,\n code: value.code,\n status: value.status,\n data: value.data,\n };\n}\n\nexport function createServerFnTransportError(value: unknown): ServerFnFailure | ServerActionError {\n if (isSerializedServerFnFailure(value)) {\n return new ServerFnFailure(value.code, value.data, {\n status: value.status,\n message: value.message,\n });\n }\n\n const message =\n value && typeof value === \"object\" && \"message\" in value && typeof value.message === \"string\"\n ? value.message\n : \"Server function failed\";\n return new ServerActionError(message);\n}\n\nfunction isSerializedServerFnFailure(value: unknown): value is SerializedServerFnFailure {\n if (!value || typeof value !== \"object\") return false;\n\n const candidate = value as Partial<SerializedServerFnFailure>;\n return (\n candidate.name === \"ServerFnFailure\" &&\n typeof candidate.message === \"string\" &&\n typeof candidate.code === \"string\" &&\n Number.isInteger(candidate.status) &&\n (candidate.status ?? 0) >= 400 &&\n (candidate.status ?? 0) <= 599 &&\n \"data\" in candidate\n );\n}\n","import { assertBrowserStableRoutePath } from \"./routing/specificity\";\n\ninterface FarmNodeAbortRequest {\n aborted?: boolean;\n once(event: \"aborted\", listener: () => void): unknown;\n off(event: \"aborted\", listener: () => void): unknown;\n}\n\ninterface FarmNodeAbortResponse {\n writableEnded: boolean;\n once(event: \"close\" | \"finish\", listener: () => void): unknown;\n off(event: \"close\" | \"finish\", listener: () => void): unknown;\n}\n\n/** Share disconnect semantics between development and production Node requests. */\nexport function createFarmNodeRequestAbortSignal(\n req: FarmNodeAbortRequest,\n res: FarmNodeAbortResponse,\n): AbortSignal {\n const controller = new AbortController();\n let disposed = false;\n const dispose = () => {\n if (disposed) return;\n disposed = true;\n req.off(\"aborted\", abort);\n res.off(\"close\", abortOnEarlyClose);\n res.off(\"finish\", dispose);\n controller.signal.removeEventListener(\"abort\", dispose);\n };\n const abort = () => controller.abort();\n const abortOnEarlyClose = () => {\n if (!res.writableEnded) abort();\n dispose();\n };\n\n if (req.aborted) {\n controller.abort();\n return controller.signal;\n }\n\n req.once(\"aborted\", abort);\n res.once(\"close\", abortOnEarlyClose);\n res.once(\"finish\", dispose);\n controller.signal.addEventListener(\"abort\", dispose, { once: true });\n return controller.signal;\n}\n\nexport const DEFAULT_FARM_SERVER_BODY_SIZE_LIMIT = 10_000_000;\nexport const DEFAULT_FARM_SERVER_HEADERS_TIMEOUT = 60_000;\nexport const DEFAULT_FARM_SERVER_REQUEST_TIMEOUT = 300_000;\nexport const DEFAULT_FARM_SERVER_KEEP_ALIVE_TIMEOUT = 5_000;\nexport const DEFAULT_FARM_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT = 30_000;\nconst MAX_FARM_SERVER_TIMEOUT = 2_147_483_647;\n\nexport type FarmServerDuration = number | `${number}${\"ms\" | \"s\" | \"m\" | \"h\"}`;\n\nexport interface FarmServerHealthConfig {\n /** Liveness endpoint. It remains healthy while a production process drains. */\n livenessPath?: string;\n /** Readiness endpoint. It returns 503 until startup completes and while draining. */\n readinessPath?: string;\n}\n\nexport interface ResolvedFarmServerHealthConfig {\n enabled: boolean;\n livenessPath: string;\n readinessPath: string;\n}\n\nexport interface FarmServerConfig {\n /** Maximum request body size for API routes, integrations, workflows, and uploads. */\n bodySizeLimit?: number | string;\n /** Trust proxy-provided client address and request authority headers. Enable only behind a trusted proxy. */\n trustProxy?: boolean;\n /** Maximum time for a Node client to send complete request headers. */\n headersTimeout?: FarmServerDuration;\n /** Maximum time for a Node client to send the complete request. */\n requestTimeout?: FarmServerDuration;\n /** How long an idle Node keep-alive connection remains open after a response. */\n keepAliveTimeout?: FarmServerDuration;\n /** Maximum time the Node adapter drains traffic before forcing shutdown. */\n gracefulShutdownTimeout?: FarmServerDuration;\n /** Production liveness and readiness endpoints. Set to false to disable them. */\n health?: false | FarmServerHealthConfig;\n}\n\nexport interface ResolvedFarmServerConfig {\n bodySizeLimit: number;\n trustProxy: boolean;\n headersTimeout: number;\n requestTimeout: number;\n keepAliveTimeout: number;\n gracefulShutdownTimeout: number;\n health: ResolvedFarmServerHealthConfig;\n}\n\nexport type FarmRequestBodyErrorCode = \"BODY_TOO_LARGE\" | \"INVALID_CONTENT_LENGTH\";\n\n/** Apply the weak entity-tag comparison required by If-None-Match. */\nexport function matchesFarmIfNoneMatch(\n value: string | readonly string[] | null | undefined,\n etag: string,\n): boolean {\n const expected = parseEntityTag(trimOptionalWhitespace(etag));\n if (!expected) return false;\n\n const values = Array.isArray(value) ? value : [value];\n const combined = values\n .filter((header): header is string => typeof header === \"string\")\n .join(\",\");\n const fieldValue = trimOptionalWhitespace(combined);\n if (!fieldValue) return false;\n if (fieldValue === \"*\") return true;\n\n let matched = false;\n let hasEntityTag = false;\n for (const candidate of splitEntityTags(fieldValue)) {\n const token = trimOptionalWhitespace(candidate);\n if (!token) continue;\n\n const parsed = parseEntityTag(token);\n if (!parsed) return false;\n hasEntityTag = true;\n if (parsed === expected) matched = true;\n }\n\n return hasEntityTag && matched;\n}\n\nfunction trimOptionalWhitespace(value: string): string {\n return value.replace(/^[\\t ]+|[\\t ]+$/g, \"\");\n}\n\nfunction parseEntityTag(value: string): string | null {\n const opaqueTag = value.startsWith(\"W/\") ? value.slice(2) : value;\n if (opaqueTag.length < 2 || opaqueTag[0] !== '\"' || opaqueTag.at(-1) !== '\"') return null;\n\n for (let index = 1; index < opaqueTag.length - 1; index++) {\n const code = opaqueTag.charCodeAt(index);\n if (code === 0x21 || (code >= 0x23 && code <= 0x7e) || code >= 0x80) continue;\n return null;\n }\n\n return opaqueTag;\n}\n\nfunction splitEntityTags(value: string): string[] {\n const tags: string[] = [];\n let start = 0;\n let quoted = false;\n\n for (let index = 0; index < value.length; index++) {\n const character = value[index];\n if (character === '\"') {\n quoted = !quoted;\n } else if (character === \",\" && !quoted) {\n tags.push(value.slice(start, index));\n start = index + 1;\n }\n }\n\n tags.push(value.slice(start));\n return tags;\n}\n\nexport class FarmRequestBodyError extends Error {\n readonly code: FarmRequestBodyErrorCode;\n readonly status: number;\n\n constructor(code: FarmRequestBodyErrorCode, status: number, message: string) {\n super(message);\n this.name = \"FarmRequestBodyError\";\n this.code = code;\n this.status = status;\n }\n}\n\nexport function resolveFarmServerConfig(\n config: FarmServerConfig | ResolvedFarmServerConfig | undefined,\n): ResolvedFarmServerConfig {\n const headersTimeout = parseFarmServerDuration(\n config?.headersTimeout ?? DEFAULT_FARM_SERVER_HEADERS_TIMEOUT,\n \"server.headersTimeout\",\n );\n const requestTimeout = parseFarmServerDuration(\n config?.requestTimeout ?? DEFAULT_FARM_SERVER_REQUEST_TIMEOUT,\n \"server.requestTimeout\",\n );\n if (headersTimeout > requestTimeout) {\n throw new TypeError(\"server.headersTimeout must not exceed server.requestTimeout\");\n }\n\n return Object.freeze({\n bodySizeLimit: parseBodySizeLimit(\n config?.bodySizeLimit ?? DEFAULT_FARM_SERVER_BODY_SIZE_LIMIT,\n \"server.bodySizeLimit\",\n ),\n trustProxy: config?.trustProxy === true,\n headersTimeout,\n requestTimeout,\n keepAliveTimeout: parseFarmServerDuration(\n config?.keepAliveTimeout ?? DEFAULT_FARM_SERVER_KEEP_ALIVE_TIMEOUT,\n \"server.keepAliveTimeout\",\n ),\n gracefulShutdownTimeout: parseFarmServerDuration(\n config?.gracefulShutdownTimeout ?? DEFAULT_FARM_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT,\n \"server.gracefulShutdownTimeout\",\n ),\n health: resolveFarmServerHealthConfig(config?.health),\n });\n}\n\nexport function parseFarmServerDuration(\n value: FarmServerDuration,\n optionName = \"duration\",\n): number {\n if (typeof value === \"number\") {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new TypeError(`${optionName} must be a positive safe integer`);\n }\n if (value > MAX_FARM_SERVER_TIMEOUT) {\n throw new TypeError(`${optionName} must not exceed ${MAX_FARM_SERVER_TIMEOUT} milliseconds`);\n }\n return value;\n }\n\n const match = value\n .trim()\n .toLowerCase()\n .match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)$/);\n if (!match) {\n throw new TypeError(`${optionName} must be milliseconds or a duration such as \"30s\" or \"2m\"`);\n }\n\n const amount = Number(match[1]);\n const unit = match[2];\n const multiplier = unit === \"ms\" ? 1 : unit === \"s\" ? 1_000 : unit === \"m\" ? 60_000 : 3_600_000;\n const milliseconds = Math.floor(amount * multiplier);\n if (!Number.isSafeInteger(milliseconds) || milliseconds <= 0) {\n throw new TypeError(`${optionName} must resolve to a positive safe integer`);\n }\n if (milliseconds > MAX_FARM_SERVER_TIMEOUT) {\n throw new TypeError(`${optionName} must not exceed ${MAX_FARM_SERVER_TIMEOUT} milliseconds`);\n }\n return milliseconds;\n}\n\nfunction resolveFarmServerHealthConfig(\n config: false | FarmServerHealthConfig | ResolvedFarmServerHealthConfig | undefined,\n): ResolvedFarmServerHealthConfig {\n if (config === false || (config && \"enabled\" in config && config.enabled === false)) {\n return Object.freeze({\n enabled: false,\n livenessPath: \"/_farm/health/live\",\n readinessPath: \"/_farm/health/ready\",\n });\n }\n\n const livenessPath = normalizeHealthPath(\n config?.livenessPath ?? \"/_farm/health/live\",\n \"server.health.livenessPath\",\n );\n const readinessPath = normalizeHealthPath(\n config?.readinessPath ?? \"/_farm/health/ready\",\n \"server.health.readinessPath\",\n );\n if (livenessPath === readinessPath) {\n throw new TypeError(\"server.health livenessPath and readinessPath must be different\");\n }\n\n return Object.freeze({ enabled: true, livenessPath, readinessPath });\n}\n\nfunction normalizeHealthPath(value: string, optionName: string): string {\n const path = value.trim();\n if (!path.startsWith(\"/\") || path.includes(\"?\") || path.includes(\"#\") || path.includes(\"*\")) {\n throw new TypeError(`${optionName} must be an absolute pathname without a query or wildcard`);\n }\n const normalized = path.length > 1 ? path.replace(/\\/+$/, \"\") || \"/\" : path;\n assertBrowserStableRoutePath(normalized);\n return normalized;\n}\n\nexport function parseBodySizeLimit(value: number | string, optionName = \"bodySizeLimit\"): number {\n if (typeof value === \"number\") {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new TypeError(`${optionName} must be a positive safe integer`);\n }\n return value;\n }\n\n const match = value\n .trim()\n .toLowerCase()\n .match(/^(\\d+(?:\\.\\d+)?)\\s*(b|kb|mb|gb|kib|mib|gib)?$/);\n if (!match) {\n throw new TypeError(`${optionName} must be bytes or a size string such as \"500kb\" or \"10mb\"`);\n }\n\n const amount = Number(match[1]);\n const unit = match[2] ?? \"b\";\n const multiplier: Record<string, number> = {\n b: 1,\n kb: 1_000,\n mb: 1_000_000,\n gb: 1_000_000_000,\n kib: 1_024,\n mib: 1_048_576,\n gib: 1_073_741_824,\n };\n const bytes = Math.floor(amount * multiplier[unit]);\n\n if (!Number.isSafeInteger(bytes) || bytes <= 0) {\n throw new TypeError(`${optionName} must resolve to a positive safe integer`);\n }\n\n return bytes;\n}\n\nexport async function bufferFarmRequestBody(request: Request, limit: number): Promise<Request> {\n if (request.method === \"GET\" || request.method === \"HEAD\" || request.body === null) {\n return request;\n }\n\n const bytes = await readFarmRequestBody(request, limit);\n const body = new Uint8Array(bytes.byteLength);\n body.set(bytes);\n return new Request(request, {\n // oxlint-disable-next-line unicorn/no-invalid-fetch-options -- GET and HEAD return above.\n body: body.buffer,\n });\n}\n\nexport async function readFarmRequestBody(request: Request, limit: number): Promise<Uint8Array> {\n try {\n validateContentLength(request.headers.get(\"content-length\"), limit);\n } catch (error) {\n // A cloned Request is a tee branch: its cancellation may wait for the\n // untouched branch. Rejection must not wait for producer-owned cleanup.\n void request.body?.cancel(error).catch(() => {});\n throw error;\n }\n throwIfAborted(request.signal);\n if (!request.body) return new Uint8Array();\n\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n const cancelBodyRead = () => {\n void reader.cancel(request.signal.reason).catch(() => {});\n };\n request.signal.addEventListener(\"abort\", cancelBodyRead, { once: true });\n\n try {\n while (true) {\n throwIfAborted(request.signal);\n const { done, value } = await reader.read();\n // Cancellation resolves a pending read as EOF, not necessarily an error.\n throwIfAborted(request.signal);\n if (done) break;\n if (!value) continue;\n\n total += value.byteLength;\n if (total > limit) {\n const error = new FarmRequestBodyError(\"BODY_TOO_LARGE\", 413, \"Request body is too large\");\n void reader.cancel(error).catch(() => {});\n throw error;\n }\n chunks.push(value);\n }\n } catch (error) {\n if (request.signal.aborted) throwIfAborted(request.signal);\n throw error;\n } finally {\n request.signal.removeEventListener(\"abort\", cancelBodyRead);\n reader.releaseLock();\n }\n\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return body;\n}\n\nexport async function readNodeRequestBody(\n request: {\n headers: Record<string, string | string[] | undefined>;\n on(event: \"data\", listener: (chunk: unknown) => void): unknown;\n on(event: \"end\", listener: () => void): unknown;\n on(event: \"error\", listener: (error: Error) => void): unknown;\n removeListener?(event: string, listener: (...args: any[]) => void): unknown;\n resume?(): unknown;\n },\n limit: number,\n): Promise<Buffer> {\n const rawContentLength = request.headers[\"content-length\"];\n const contentLength = Array.isArray(rawContentLength) ? rawContentLength[0] : rawContentLength;\n try {\n validateContentLength(contentLength, limit);\n } catch (error) {\n request.resume?.();\n throw error;\n }\n\n return await new Promise<Buffer>((resolve, reject) => {\n const chunks: Buffer[] = [];\n let total = 0;\n let settled = false;\n\n const cleanup = () => {\n request.removeListener?.(\"data\", onData);\n request.removeListener?.(\"end\", onEnd);\n request.removeListener?.(\"error\", onError);\n };\n const rejectOnce = (error: Error) => {\n if (settled) return;\n settled = true;\n cleanup();\n request.resume?.();\n reject(error);\n };\n const onData = (chunk: unknown) => {\n const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as any);\n total += bytes.byteLength;\n if (total > limit) {\n rejectOnce(new FarmRequestBodyError(\"BODY_TOO_LARGE\", 413, \"Request body is too large\"));\n return;\n }\n chunks.push(bytes);\n };\n const onEnd = () => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(Buffer.concat(chunks, total));\n };\n const onError = (error: Error) => rejectOnce(error);\n\n request.on(\"data\", onData);\n request.on(\"end\", onEnd);\n request.on(\"error\", onError);\n });\n}\n\nexport function createFarmRequestBodyErrorResponse(error: unknown): Response | null {\n if (!(error instanceof FarmRequestBodyError)) return null;\n\n return new Response(error.status === 413 ? \"Payload Too Large\" : \"Bad Request\", {\n status: error.status,\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"text/plain; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\",\n },\n });\n}\n\nfunction validateContentLength(value: string | null | undefined, limit: number): void {\n const contentLength = value?.trim();\n if (!contentLength) return;\n if (!/^\\d+$/.test(contentLength)) {\n throw new FarmRequestBodyError(\"INVALID_CONTENT_LENGTH\", 400, \"Invalid content-length header\");\n }\n if (Number(contentLength) > limit) {\n throw new FarmRequestBodyError(\"BODY_TOO_LARGE\", 413, \"Request body is too large\");\n }\n}\n\nfunction throwIfAborted(signal: AbortSignal): void {\n if (!signal.aborted) return;\n if (signal.reason !== undefined) throw signal.reason;\n throw new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n"],"mappings":"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","names":["globalState"]}
@@ -10,7 +10,8 @@ import {
10
10
  runWithServerActionRequest,
11
11
  sanitizeServerActionError,
12
12
  validateServerActionRequest
13
- } from "./chunk-35NPLKQJ.mjs";
13
+ } from "./chunk-XWM2C267.mjs";
14
+ import "./chunk-FDWXXTWR.mjs";
14
15
  import "./chunk-ZHQMHJAV.mjs";
15
16
  import "./chunk-34IAPZBG.mjs";
16
17
  import "./chunk-DZU3EKQP.mjs";
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server-fn-client.ts","../src/client-observers.ts","../src/mutation-retry.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createElement,\n useCallback,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type FormHTMLAttributes,\n} from \"react\";\nimport type { ServerFn } from \"./server-fn\";\nimport type { RetryOptions } from \"./api/client\";\nimport { notifyClientObserver } from \"./client-observers\";\nimport { invokeMutationWithRetry } from \"./mutation-retry\";\n\nexport type ServerFnActionStatus = \"idle\" | \"pending\" | \"success\" | \"error\";\n\nexport type ServerFnSubmit<TInput, TResult> = [unknown] extends [TInput]\n ? (input?: TInput | FormData) => Promise<TResult>\n : (input: TInput | FormData) => Promise<TResult>;\n\nexport type ServerFnOptimisticContext<TInput, TResult> = {\n input: TInput | FormData | undefined;\n formData?: FormData;\n current: TResult | null;\n};\n\nexport type UseServerFnOptions<TResult, TError extends Error = Error, TInput = unknown> = {\n initialResult?: TResult | null;\n resetOnSubmit?: boolean;\n throwOnFormError?: boolean;\n optimistic?: (context: ServerFnOptimisticContext<TInput, TResult>) => TResult | null | undefined;\n rollbackOnError?: boolean;\n /** Retry failed submissions with the API client's retry shape. Defaults to no retries. */\n retry?: RetryOptions;\n onSuccess?: (result: TResult) => void;\n onError?: (error: TError) => void;\n onSettled?: (result: TResult | null, error: TError | null) => void;\n};\n\nexport type UseServerFnReturn<TInput, TResult, TError extends Error = Error> = {\n pending: boolean;\n status: ServerFnActionStatus;\n result: TResult | null;\n error: TError | null;\n submit: ServerFnSubmit<TInput, TResult>;\n formAction: (formData: FormData) => Promise<void>;\n reset: () => void;\n};\n\nexport type UseActionFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, \"action\">;\n\nexport type RouteActionTarget<TServerFn extends ServerFn<any, any, any>> = {\n readonly action: TServerFn;\n};\n\nexport type UseActionReturn<TInput, TResult, TError extends Error = Error> = ServerFnSubmit<\n TInput,\n TResult\n> & {\n pending: boolean;\n status: ServerFnActionStatus;\n data: TResult | null;\n result: TResult | null;\n error: TError | null;\n formAction: (formData: FormData) => Promise<void>;\n Form: ComponentType<UseActionFormProps>;\n reset: () => void;\n};\n\ntype ServerFnActionState<TResult, TError extends Error> = {\n pendingCount: number;\n status: ServerFnActionStatus;\n result: TResult | null;\n error: TError | null;\n};\n\ntype ServerFnActionCallbacks<TResult, TError extends Error> = Pick<\n UseServerFnOptions<TResult, TError, unknown>,\n \"onError\" | \"onSettled\" | \"onSuccess\" | \"throwOnFormError\"\n>;\n\nexport function useServerFn<TInput, TResult, TError extends Error = Error>(\n serverFn: ServerFn<TInput, TResult, TError>,\n options: UseServerFnOptions<TResult, TError, TInput> = {},\n): UseServerFnReturn<TInput, TResult, TError> {\n const { initialResult = null, resetOnSubmit = true } = options;\n const callbacksRef = useRef<ServerFnActionCallbacks<TResult, TError>>({});\n const requestIdRef = useRef(0);\n const lastResetIdRef = useRef(0);\n const initialState: ServerFnActionState<TResult, TError> = {\n pendingCount: 0,\n status: \"idle\",\n result: initialResult,\n error: null,\n };\n const stateRef = useRef<ServerFnActionState<TResult, TError>>(initialState);\n const [state, setState] = useState<ServerFnActionState<TResult, TError>>(initialState);\n const setActionState = useCallback(\n (\n value:\n | ServerFnActionState<TResult, TError>\n | ((current: ServerFnActionState<TResult, TError>) => ServerFnActionState<TResult, TError>),\n ) => {\n // Later submissions in the same React batch must see this transition.\n const next = typeof value === \"function\" ? value(stateRef.current) : value;\n stateRef.current = next;\n setState(next);\n },\n [],\n );\n\n callbacksRef.current = {\n onError: options.onError,\n onSettled: options.onSettled,\n onSuccess: options.onSuccess,\n throwOnFormError: options.throwOnFormError,\n };\n\n const submit = useCallback(\n async (input?: TInput | FormData) => {\n const requestId = ++requestIdRef.current;\n const formData = isFormData(input) ? input : undefined;\n const previousResult = stateRef.current.result;\n const optimisticResult = options.optimistic?.({\n input,\n formData,\n current: previousResult,\n });\n const hasOptimisticResult = optimisticResult !== undefined;\n\n setActionState((current) => {\n // Optimistic callbacks are app code and may reset or submit again.\n if (requestId < lastResetIdRef.current) return current;\n const pendingCount = current.pendingCount + 1;\n if (requestId !== requestIdRef.current) return { ...current, pendingCount };\n return {\n pendingCount,\n status: \"pending\",\n result: hasOptimisticResult ? optimisticResult : resetOnSubmit ? null : current.result,\n error: null,\n };\n });\n\n try {\n const result = await invokeMutationWithRetry(\n () => serverFn(input as TInput | FormData),\n options.retry,\n // A reset disowns this submission; stop scheduling retries then.\n () => requestId >= lastResetIdRef.current,\n );\n const isLatestRequest = requestId === requestIdRef.current;\n\n setActionState((current) => {\n // Reset starts a new pending-count generation, not just a new result.\n if (requestId < lastResetIdRef.current) return current;\n const pendingCount = Math.max(0, current.pendingCount - 1);\n\n if (!isLatestRequest) {\n return {\n ...current,\n pendingCount,\n };\n }\n\n return {\n pendingCount,\n status: \"success\",\n result,\n error: null,\n };\n });\n\n if (isLatestRequest) {\n notifyClientObserver(callbacksRef.current.onSuccess, [result], \"Action onSuccess\");\n if (requestId === requestIdRef.current) {\n notifyClientObserver(\n callbacksRef.current.onSettled,\n [result, null],\n \"Action onSettled\",\n );\n }\n }\n\n return result;\n } catch (cause) {\n const error = normalizeServerFnError(cause) as TError;\n const isLatestRequest = requestId === requestIdRef.current;\n\n setActionState((current) => {\n if (requestId < lastResetIdRef.current) return current;\n const pendingCount = Math.max(0, current.pendingCount - 1);\n\n if (!isLatestRequest) {\n return {\n ...current,\n pendingCount,\n };\n }\n\n return {\n pendingCount,\n status: \"error\",\n result:\n hasOptimisticResult && options.rollbackOnError\n ? previousResult\n : resetOnSubmit\n ? null\n : current.result,\n error,\n };\n });\n\n if (isLatestRequest) {\n notifyClientObserver(callbacksRef.current.onError, [error], \"Action onError\");\n if (requestId === requestIdRef.current) {\n notifyClientObserver(callbacksRef.current.onSettled, [null, error], \"Action onSettled\");\n }\n }\n\n throw error;\n }\n },\n [\n options.optimistic,\n options.retry,\n options.rollbackOnError,\n resetOnSubmit,\n serverFn,\n setActionState,\n ],\n ) as ServerFnSubmit<TInput, TResult>;\n\n const formAction = useCallback(\n async (formData: FormData) => {\n try {\n await submit(formData as TInput | FormData);\n } catch (error) {\n if (callbacksRef.current.throwOnFormError) {\n throw error;\n }\n }\n },\n [submit],\n );\n\n const reset = useCallback(() => {\n lastResetIdRef.current = ++requestIdRef.current;\n setActionState({\n pendingCount: 0,\n status: \"idle\",\n result: initialResult,\n error: null,\n });\n }, [initialResult, setActionState]);\n\n return useMemo(\n () => ({\n pending: state.pendingCount > 0,\n status: state.status,\n result: state.result,\n error: state.error,\n submit,\n formAction,\n reset,\n }),\n [formAction, reset, state.error, state.pendingCount, state.result, state.status, submit],\n );\n}\n\n/**\n * Wrap a server function, or a route's default server function, as a callable\n * RPC with React mutation state.\n */\nexport function useAction<TInput, TResult, TError extends Error = Error>(\n route: RouteActionTarget<ServerFn<TInput, TResult, TError>>,\n options?: UseServerFnOptions<TResult, TError, TInput>,\n): UseActionReturn<TInput, TResult, TError>;\nexport function useAction<TInput, TResult, TError extends Error = Error>(\n serverFn: ServerFn<TInput, TResult, TError>,\n options?: UseServerFnOptions<TResult, TError, TInput>,\n): UseActionReturn<TInput, TResult, TError>;\nexport function useAction<TInput, TResult, TError extends Error = Error>(\n target: ServerFn<TInput, TResult, TError> | RouteActionTarget<ServerFn<TInput, TResult, TError>>,\n options: UseServerFnOptions<TResult, TError, TInput> = {},\n): UseActionReturn<TInput, TResult, TError> {\n const serverFn = resolveServerFnTarget(target);\n const action = useServerFn(serverFn, options);\n const formActionRef = useRef(action.formAction);\n formActionRef.current = action.formAction;\n\n const Form = useMemo(() => {\n // Keep both the component and its action stable, even when a parent caches\n // the form element. Resolve the latest target/options at submission time.\n const submitForm = (formData: FormData) => formActionRef.current(formData);\n const ActionForm = (props: UseActionFormProps) =>\n createElement(\"form\", {\n ...props,\n action: submitForm,\n });\n\n ActionForm.displayName = \"FarmActionForm\";\n return ActionForm;\n }, []);\n\n return useMemo(() => {\n const call = ((input?: TInput | FormData) =>\n action.submit(input as TInput | FormData)) as ServerFnSubmit<TInput, TResult>;\n\n return Object.assign(call, {\n pending: action.pending,\n status: action.status,\n data: action.result,\n result: action.result,\n error: action.error,\n formAction: action.formAction,\n Form,\n reset: action.reset,\n });\n }, [\n Form,\n action.error,\n action.formAction,\n action.pending,\n action.reset,\n action.result,\n action.status,\n action.submit,\n ]);\n}\n\nfunction resolveServerFnTarget<TInput, TResult, TError extends Error>(\n target: ServerFn<TInput, TResult, TError> | RouteActionTarget<ServerFn<TInput, TResult, TError>>,\n): ServerFn<TInput, TResult, TError> {\n if (typeof target === \"function\") return target;\n if (target && typeof target.action === \"function\") return target.action;\n\n throw new TypeError(\n \"useAction requires a server function or a route with at least one declared action\",\n );\n}\n\nfunction normalizeServerFnError(error: unknown) {\n if (error instanceof Error) return error;\n\n const normalized = new Error(typeof error === \"string\" ? error : \"Server function failed\");\n (normalized as Error & { cause?: unknown }).cause = error;\n return normalized;\n}\n\nfunction isFormData(value: unknown): value is FormData {\n if (!value || typeof value !== \"object\") return false;\n\n if (typeof FormData !== \"undefined\" && value instanceof FormData) {\n return true;\n }\n\n return (\n Object.prototype.toString.call(value) === \"[object FormData]\" &&\n typeof (value as { entries?: unknown }).entries === \"function\"\n );\n}\n","/** Metadata shared by app-route and integration execution attempts. */\nexport type ClientRequestEvent = {\n requestId: string;\n method: string;\n path: string;\n attempt: number;\n timestamp: number;\n};\n\nexport type ClientResponseEvent<TData = unknown> = ClientRequestEvent & {\n response?: Response;\n data?: TData;\n error?: Error;\n ok?: boolean;\n status?: number;\n};\n\n/** Observers compose with per-call hooks; return values never replace the result. */\nexport type ClientLifecycleHooks<TData = unknown> = {\n onRequest?: (event: ClientRequestEvent) => void;\n onResponse?: (\n data: TData | undefined,\n error: Error | null,\n event: ClientResponseEvent<TData>,\n ) => void;\n onError?: (error: Error) => void;\n};\n\nexport function notifyClientObserver(\n observer: ((...args: any[]) => unknown) | undefined,\n args: unknown[],\n label = \"Client lifecycle\",\n): void {\n if (!observer) return;\n const report = (error: unknown) => {\n const reportError = (\n globalThis as typeof globalThis & { reportError?: (error: unknown) => void }\n ).reportError;\n if (typeof reportError === \"function\") {\n try {\n reportError.call(globalThis, error);\n return;\n } catch {\n /* Try the console fallback. */\n }\n }\n try {\n console.error(`[Farm.js] ${label} callback failed:`, error);\n } catch {\n /* Reporting must not affect a call. */\n }\n };\n try {\n const result = observer(...args);\n if (result && typeof (result as PromiseLike<unknown>).then === \"function\")\n void Promise.resolve(result).catch(report);\n } catch (error) {\n report(error);\n }\n}\n","import type { RetryOptions } from \"./api/client\";\n\n/**\n * Retry a server-function mutation with the API client's retry shape.\n *\n * Attempts run until success, until `count` retries are exhausted, or until\n * `shouldContinue` reports that the owning lifecycle was reset. The delay\n * callback receives the upcoming attempt number starting at 1, matching the\n * API client. Defaults to zero retries so existing behavior is unchanged.\n */\nexport async function invokeMutationWithRetry<T>(\n invoke: () => Promise<T>,\n retry: RetryOptions | undefined,\n shouldContinue: () => boolean,\n): Promise<T> {\n const maxRetries = Math.max(0, retry?.count ?? 0);\n let attempt = 0;\n\n while (true) {\n try {\n return await invoke();\n } catch (error) {\n if (attempt >= maxRetries || !shouldContinue()) throw error;\n\n attempt += 1;\n const delay = typeof retry?.delay === \"function\" ? retry.delay(attempt) : (retry?.delay ?? 0);\n if (delay > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n // The lifecycle may have been reset while this attempt waited.\n if (!shouldContinue()) throw error;\n }\n }\n }\n}\n"],"mappings":"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","names":[]}