@uploadista/core 0.0.2 → 0.0.4

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 (331) hide show
  1. package/README.md +6 -20
  2. package/dist/checksum-C5qE-5eg.js +2 -0
  3. package/dist/checksum-C5qE-5eg.js.map +1 -0
  4. package/dist/checksum-wSBuXX84.cjs +1 -0
  5. package/dist/errors/index.cjs +1 -1
  6. package/dist/errors/index.d.cts +2 -2
  7. package/dist/errors/index.d.ts +3 -3
  8. package/dist/errors/index.js +1 -2
  9. package/dist/flow/index.cjs +1 -1
  10. package/dist/flow/index.d.cts +5 -5
  11. package/dist/flow/index.d.ts +6 -24
  12. package/dist/flow/index.js +1 -24
  13. package/dist/flow-B0mMJM5Y.js +2 -0
  14. package/dist/flow-B0mMJM5Y.js.map +1 -0
  15. package/dist/flow-s5bgJsdb.cjs +1 -0
  16. package/dist/index-B46hb7yB.d.cts +36 -0
  17. package/dist/index-B46hb7yB.d.cts.map +1 -0
  18. package/dist/index-BnGZO47X.d.ts +3952 -0
  19. package/dist/index-BnGZO47X.d.ts.map +1 -0
  20. package/dist/{streams/stream-limiter.d.cts → index-C1mxuUxK.d.ts} +3 -3
  21. package/dist/index-C1mxuUxK.d.ts.map +1 -0
  22. package/dist/index-DM69UMgG.d.cts +4132 -0
  23. package/dist/index-DM69UMgG.d.cts.map +1 -0
  24. package/dist/index-DMJv8Tvo.d.ts +168 -0
  25. package/dist/index-DMJv8Tvo.d.ts.map +1 -0
  26. package/dist/index-GLPiXqj4.d.cts +168 -0
  27. package/dist/index-GLPiXqj4.d.cts.map +1 -0
  28. package/dist/index.cjs +1 -1
  29. package/dist/index.d.cts +5 -5
  30. package/dist/index.d.ts +6 -5
  31. package/dist/index.js +1 -5
  32. package/dist/stream-limiter-CTuiXkcq.js +2 -0
  33. package/dist/{stream-limiter-CoWKv39w.js.map → stream-limiter-CTuiXkcq.js.map} +1 -1
  34. package/dist/stream-limiter-DYGG4t9f.cjs +1 -0
  35. package/dist/streams/index.cjs +1 -0
  36. package/dist/streams/index.d.cts +3 -0
  37. package/dist/streams/index.d.ts +3 -0
  38. package/dist/streams/index.js +1 -0
  39. package/dist/streams-BiD_pOPH.cjs +0 -0
  40. package/dist/streams-Bs3GDNKJ.js +1 -0
  41. package/dist/types/index.cjs +1 -1
  42. package/dist/types/index.d.cts +5 -5
  43. package/dist/types/index.d.ts +6 -10
  44. package/dist/types/index.js +1 -9
  45. package/dist/types-Dj9g8ocl.cjs +1 -0
  46. package/dist/types-m26wrG-Z.js +2 -0
  47. package/dist/types-m26wrG-Z.js.map +1 -0
  48. package/dist/upload/index.cjs +1 -1
  49. package/dist/upload/index.d.cts +5 -5
  50. package/dist/upload/index.d.ts +6 -4
  51. package/dist/upload/index.js +1 -3
  52. package/dist/upload-BzU7ifyH.js +2 -0
  53. package/dist/upload-BzU7ifyH.js.map +1 -0
  54. package/dist/upload-DvLp6TXO.cjs +1 -0
  55. package/dist/uploadista-error-CAtkQiAv.d.cts +221 -0
  56. package/dist/uploadista-error-CAtkQiAv.d.cts.map +1 -0
  57. package/dist/{uploadista-error-BVsVxqvz.js → uploadista-error-CjfcFnVa.js} +9 -2
  58. package/dist/uploadista-error-CjfcFnVa.js.map +1 -0
  59. package/dist/uploadista-error-D9SONF9K.d.ts +221 -0
  60. package/dist/uploadista-error-D9SONF9K.d.ts.map +1 -0
  61. package/dist/{uploadista-error-BB-Wdiz9.cjs → uploadista-error-DdTP-Rjx.cjs} +9 -2
  62. package/dist/utils/index.cjs +1 -0
  63. package/dist/utils/index.d.cts +3 -0
  64. package/dist/utils/index.d.ts +3 -0
  65. package/dist/utils/index.js +1 -0
  66. package/dist/utils-BILytQlb.js +2 -0
  67. package/dist/utils-BILytQlb.js.map +1 -0
  68. package/dist/utils-BLsIUd8c.cjs +1 -0
  69. package/package.json +13 -17
  70. package/src/index.ts +2 -0
  71. package/src/streams/index.ts +1 -0
  72. package/src/utils/index.ts +5 -0
  73. package/tsdown.config.ts +2 -10
  74. package/.turbo/turbo-build.log +0 -5
  75. package/.turbo/turbo-check.log +0 -231
  76. package/.turbo/turbo-format.log +0 -5
  77. package/dist/chunk-CUT6urMc.cjs +0 -1
  78. package/dist/debounce-C2SeqcxD.js +0 -2
  79. package/dist/debounce-C2SeqcxD.js.map +0 -1
  80. package/dist/debounce-LZK7yS7Z.cjs +0 -1
  81. package/dist/errors/index.d.ts.map +0 -1
  82. package/dist/errors/uploadista-error.d.ts +0 -209
  83. package/dist/errors/uploadista-error.d.ts.map +0 -1
  84. package/dist/errors/uploadista-error.js +0 -322
  85. package/dist/flow/edge.d.ts +0 -47
  86. package/dist/flow/edge.d.ts.map +0 -1
  87. package/dist/flow/edge.js +0 -40
  88. package/dist/flow/event.d.ts +0 -206
  89. package/dist/flow/event.d.ts.map +0 -1
  90. package/dist/flow/event.js +0 -53
  91. package/dist/flow/flow-server.d.ts +0 -223
  92. package/dist/flow/flow-server.d.ts.map +0 -1
  93. package/dist/flow/flow-server.js +0 -614
  94. package/dist/flow/flow.d.ts +0 -238
  95. package/dist/flow/flow.d.ts.map +0 -1
  96. package/dist/flow/flow.js +0 -629
  97. package/dist/flow/index.d.ts.map +0 -1
  98. package/dist/flow/node.d.ts +0 -136
  99. package/dist/flow/node.d.ts.map +0 -1
  100. package/dist/flow/node.js +0 -153
  101. package/dist/flow/nodes/index.d.ts +0 -8
  102. package/dist/flow/nodes/index.d.ts.map +0 -1
  103. package/dist/flow/nodes/index.js +0 -7
  104. package/dist/flow/nodes/input-node.d.ts +0 -78
  105. package/dist/flow/nodes/input-node.d.ts.map +0 -1
  106. package/dist/flow/nodes/input-node.js +0 -233
  107. package/dist/flow/nodes/storage-node.d.ts +0 -67
  108. package/dist/flow/nodes/storage-node.d.ts.map +0 -1
  109. package/dist/flow/nodes/storage-node.js +0 -94
  110. package/dist/flow/nodes/streaming-input-node.d.ts +0 -69
  111. package/dist/flow/nodes/streaming-input-node.d.ts.map +0 -1
  112. package/dist/flow/nodes/streaming-input-node.js +0 -156
  113. package/dist/flow/nodes/transform-node.d.ts +0 -85
  114. package/dist/flow/nodes/transform-node.d.ts.map +0 -1
  115. package/dist/flow/nodes/transform-node.js +0 -107
  116. package/dist/flow/parallel-scheduler.d.ts +0 -175
  117. package/dist/flow/parallel-scheduler.d.ts.map +0 -1
  118. package/dist/flow/parallel-scheduler.js +0 -193
  119. package/dist/flow/plugins/credential-provider.d.ts +0 -47
  120. package/dist/flow/plugins/credential-provider.d.ts.map +0 -1
  121. package/dist/flow/plugins/credential-provider.js +0 -24
  122. package/dist/flow/plugins/image-ai-plugin.d.ts +0 -61
  123. package/dist/flow/plugins/image-ai-plugin.d.ts.map +0 -1
  124. package/dist/flow/plugins/image-ai-plugin.js +0 -21
  125. package/dist/flow/plugins/image-plugin.d.ts +0 -52
  126. package/dist/flow/plugins/image-plugin.d.ts.map +0 -1
  127. package/dist/flow/plugins/image-plugin.js +0 -22
  128. package/dist/flow/plugins/types/describe-image-node.d.ts +0 -16
  129. package/dist/flow/plugins/types/describe-image-node.d.ts.map +0 -1
  130. package/dist/flow/plugins/types/describe-image-node.js +0 -9
  131. package/dist/flow/plugins/types/index.d.ts +0 -9
  132. package/dist/flow/plugins/types/index.d.ts.map +0 -1
  133. package/dist/flow/plugins/types/index.js +0 -8
  134. package/dist/flow/plugins/types/optimize-node.d.ts +0 -20
  135. package/dist/flow/plugins/types/optimize-node.d.ts.map +0 -1
  136. package/dist/flow/plugins/types/optimize-node.js +0 -11
  137. package/dist/flow/plugins/types/remove-background-node.d.ts +0 -16
  138. package/dist/flow/plugins/types/remove-background-node.d.ts.map +0 -1
  139. package/dist/flow/plugins/types/remove-background-node.js +0 -9
  140. package/dist/flow/plugins/types/resize-node.d.ts +0 -21
  141. package/dist/flow/plugins/types/resize-node.d.ts.map +0 -1
  142. package/dist/flow/plugins/types/resize-node.js +0 -16
  143. package/dist/flow/plugins/zip-plugin.d.ts +0 -62
  144. package/dist/flow/plugins/zip-plugin.d.ts.map +0 -1
  145. package/dist/flow/plugins/zip-plugin.js +0 -21
  146. package/dist/flow/typed-flow.d.ts +0 -90
  147. package/dist/flow/typed-flow.d.ts.map +0 -1
  148. package/dist/flow/typed-flow.js +0 -59
  149. package/dist/flow/types/flow-file.d.ts +0 -45
  150. package/dist/flow/types/flow-file.d.ts.map +0 -1
  151. package/dist/flow/types/flow-file.js +0 -27
  152. package/dist/flow/types/flow-job.d.ts +0 -118
  153. package/dist/flow/types/flow-job.d.ts.map +0 -1
  154. package/dist/flow/types/flow-job.js +0 -11
  155. package/dist/flow/types/flow-types.d.ts +0 -321
  156. package/dist/flow/types/flow-types.d.ts.map +0 -1
  157. package/dist/flow/types/flow-types.js +0 -52
  158. package/dist/flow/types/index.d.ts +0 -4
  159. package/dist/flow/types/index.d.ts.map +0 -1
  160. package/dist/flow/types/index.js +0 -3
  161. package/dist/flow/types/run-args.d.ts +0 -38
  162. package/dist/flow/types/run-args.d.ts.map +0 -1
  163. package/dist/flow/types/run-args.js +0 -30
  164. package/dist/flow/types/type-validator.d.ts +0 -26
  165. package/dist/flow/types/type-validator.d.ts.map +0 -1
  166. package/dist/flow/types/type-validator.js +0 -134
  167. package/dist/flow/utils/resolve-upload-metadata.d.ts +0 -11
  168. package/dist/flow/utils/resolve-upload-metadata.d.ts.map +0 -1
  169. package/dist/flow/utils/resolve-upload-metadata.js +0 -28
  170. package/dist/flow-2zXnEiWL.cjs +0 -1
  171. package/dist/flow-CRaKy7Vj.js +0 -2
  172. package/dist/flow-CRaKy7Vj.js.map +0 -1
  173. package/dist/generate-id-Dm-Vboxq.d.ts +0 -34
  174. package/dist/generate-id-Dm-Vboxq.d.ts.map +0 -1
  175. package/dist/generate-id-LjJRLD6N.d.cts +0 -34
  176. package/dist/generate-id-LjJRLD6N.d.cts.map +0 -1
  177. package/dist/generate-id-xHp_Z7Cl.cjs +0 -1
  178. package/dist/generate-id-yohS1ZDk.js +0 -2
  179. package/dist/generate-id-yohS1ZDk.js.map +0 -1
  180. package/dist/index-BO8GZlbD.d.cts +0 -1040
  181. package/dist/index-BO8GZlbD.d.cts.map +0 -1
  182. package/dist/index-D-CoVpkZ.d.ts +0 -1004
  183. package/dist/index-D-CoVpkZ.d.ts.map +0 -1
  184. package/dist/index.d.ts.map +0 -1
  185. package/dist/logger/logger.cjs +0 -1
  186. package/dist/logger/logger.d.cts +0 -8
  187. package/dist/logger/logger.d.cts.map +0 -1
  188. package/dist/logger/logger.d.ts +0 -5
  189. package/dist/logger/logger.d.ts.map +0 -1
  190. package/dist/logger/logger.js +0 -10
  191. package/dist/logger/logger.js.map +0 -1
  192. package/dist/semaphore-0ZwjVpyF.js +0 -2
  193. package/dist/semaphore-0ZwjVpyF.js.map +0 -1
  194. package/dist/semaphore-BHprIjFI.d.cts +0 -37
  195. package/dist/semaphore-BHprIjFI.d.cts.map +0 -1
  196. package/dist/semaphore-DThupBkc.d.ts +0 -37
  197. package/dist/semaphore-DThupBkc.d.ts.map +0 -1
  198. package/dist/semaphore-DVrONiAV.cjs +0 -1
  199. package/dist/stream-limiter-CoWKv39w.js +0 -2
  200. package/dist/stream-limiter-JgOwmkMa.cjs +0 -1
  201. package/dist/streams/multi-stream.cjs +0 -1
  202. package/dist/streams/multi-stream.d.cts +0 -91
  203. package/dist/streams/multi-stream.d.cts.map +0 -1
  204. package/dist/streams/multi-stream.d.ts +0 -86
  205. package/dist/streams/multi-stream.d.ts.map +0 -1
  206. package/dist/streams/multi-stream.js +0 -149
  207. package/dist/streams/multi-stream.js.map +0 -1
  208. package/dist/streams/stream-limiter.cjs +0 -1
  209. package/dist/streams/stream-limiter.d.cts.map +0 -1
  210. package/dist/streams/stream-limiter.d.ts +0 -27
  211. package/dist/streams/stream-limiter.d.ts.map +0 -1
  212. package/dist/streams/stream-limiter.js +0 -49
  213. package/dist/streams/stream-splitter.cjs +0 -1
  214. package/dist/streams/stream-splitter.d.cts +0 -68
  215. package/dist/streams/stream-splitter.d.cts.map +0 -1
  216. package/dist/streams/stream-splitter.d.ts +0 -51
  217. package/dist/streams/stream-splitter.d.ts.map +0 -1
  218. package/dist/streams/stream-splitter.js +0 -175
  219. package/dist/streams/stream-splitter.js.map +0 -1
  220. package/dist/types/data-store-registry.d.ts +0 -13
  221. package/dist/types/data-store-registry.d.ts.map +0 -1
  222. package/dist/types/data-store-registry.js +0 -4
  223. package/dist/types/data-store.d.ts +0 -316
  224. package/dist/types/data-store.d.ts.map +0 -1
  225. package/dist/types/data-store.js +0 -157
  226. package/dist/types/event-broadcaster.d.ts +0 -28
  227. package/dist/types/event-broadcaster.d.ts.map +0 -1
  228. package/dist/types/event-broadcaster.js +0 -6
  229. package/dist/types/event-emitter.d.ts +0 -378
  230. package/dist/types/event-emitter.d.ts.map +0 -1
  231. package/dist/types/event-emitter.js +0 -223
  232. package/dist/types/index.d.ts.map +0 -1
  233. package/dist/types/input-file.d.ts +0 -104
  234. package/dist/types/input-file.d.ts.map +0 -1
  235. package/dist/types/input-file.js +0 -27
  236. package/dist/types/kv-store.d.ts +0 -281
  237. package/dist/types/kv-store.d.ts.map +0 -1
  238. package/dist/types/kv-store.js +0 -234
  239. package/dist/types/middleware.d.ts +0 -17
  240. package/dist/types/middleware.d.ts.map +0 -1
  241. package/dist/types/middleware.js +0 -21
  242. package/dist/types/upload-event.d.ts +0 -105
  243. package/dist/types/upload-event.d.ts.map +0 -1
  244. package/dist/types/upload-event.js +0 -71
  245. package/dist/types/upload-file.d.ts +0 -136
  246. package/dist/types/upload-file.d.ts.map +0 -1
  247. package/dist/types/upload-file.js +0 -34
  248. package/dist/types/websocket.d.ts +0 -144
  249. package/dist/types/websocket.d.ts.map +0 -1
  250. package/dist/types/websocket.js +0 -40
  251. package/dist/types-BT-cvi7T.cjs +0 -1
  252. package/dist/types-DhU2j-XF.js +0 -2
  253. package/dist/types-DhU2j-XF.js.map +0 -1
  254. package/dist/upload/convert-to-stream.d.ts +0 -38
  255. package/dist/upload/convert-to-stream.d.ts.map +0 -1
  256. package/dist/upload/convert-to-stream.js +0 -43
  257. package/dist/upload/convert-upload-to-flow-file.d.ts +0 -14
  258. package/dist/upload/convert-upload-to-flow-file.d.ts.map +0 -1
  259. package/dist/upload/convert-upload-to-flow-file.js +0 -21
  260. package/dist/upload/create-upload.d.ts +0 -68
  261. package/dist/upload/create-upload.d.ts.map +0 -1
  262. package/dist/upload/create-upload.js +0 -157
  263. package/dist/upload/index.d.ts.map +0 -1
  264. package/dist/upload/mime.d.ts +0 -24
  265. package/dist/upload/mime.d.ts.map +0 -1
  266. package/dist/upload/mime.js +0 -351
  267. package/dist/upload/upload-chunk.d.ts +0 -58
  268. package/dist/upload/upload-chunk.d.ts.map +0 -1
  269. package/dist/upload/upload-chunk.js +0 -277
  270. package/dist/upload/upload-server.d.ts +0 -221
  271. package/dist/upload/upload-server.d.ts.map +0 -1
  272. package/dist/upload/upload-server.js +0 -181
  273. package/dist/upload/upload-strategy-negotiator.d.ts +0 -148
  274. package/dist/upload/upload-strategy-negotiator.d.ts.map +0 -1
  275. package/dist/upload/upload-strategy-negotiator.js +0 -217
  276. package/dist/upload/upload-url.d.ts +0 -68
  277. package/dist/upload/upload-url.d.ts.map +0 -1
  278. package/dist/upload/upload-url.js +0 -142
  279. package/dist/upload/write-to-store.d.ts +0 -77
  280. package/dist/upload/write-to-store.d.ts.map +0 -1
  281. package/dist/upload/write-to-store.js +0 -147
  282. package/dist/upload-DLuICjpP.cjs +0 -1
  283. package/dist/upload-DaXO34dE.js +0 -2
  284. package/dist/upload-DaXO34dE.js.map +0 -1
  285. package/dist/uploadista-error-BVsVxqvz.js.map +0 -1
  286. package/dist/uploadista-error-CwxYs4EB.d.ts +0 -52
  287. package/dist/uploadista-error-CwxYs4EB.d.ts.map +0 -1
  288. package/dist/uploadista-error-kKlhLRhY.d.cts +0 -52
  289. package/dist/uploadista-error-kKlhLRhY.d.cts.map +0 -1
  290. package/dist/utils/checksum.d.ts +0 -22
  291. package/dist/utils/checksum.d.ts.map +0 -1
  292. package/dist/utils/checksum.js +0 -49
  293. package/dist/utils/debounce.cjs +0 -1
  294. package/dist/utils/debounce.d.cts +0 -38
  295. package/dist/utils/debounce.d.cts.map +0 -1
  296. package/dist/utils/debounce.d.ts +0 -36
  297. package/dist/utils/debounce.d.ts.map +0 -1
  298. package/dist/utils/debounce.js +0 -73
  299. package/dist/utils/generate-id.cjs +0 -1
  300. package/dist/utils/generate-id.d.cts +0 -2
  301. package/dist/utils/generate-id.d.ts +0 -32
  302. package/dist/utils/generate-id.d.ts.map +0 -1
  303. package/dist/utils/generate-id.js +0 -23
  304. package/dist/utils/md5.cjs +0 -1
  305. package/dist/utils/md5.d.cts +0 -73
  306. package/dist/utils/md5.d.cts.map +0 -1
  307. package/dist/utils/md5.d.ts +0 -71
  308. package/dist/utils/md5.d.ts.map +0 -1
  309. package/dist/utils/md5.js +0 -417
  310. package/dist/utils/md5.js.map +0 -1
  311. package/dist/utils/once.cjs +0 -1
  312. package/dist/utils/once.d.cts +0 -25
  313. package/dist/utils/once.d.cts.map +0 -1
  314. package/dist/utils/once.d.ts +0 -21
  315. package/dist/utils/once.d.ts.map +0 -1
  316. package/dist/utils/once.js +0 -54
  317. package/dist/utils/once.js.map +0 -1
  318. package/dist/utils/semaphore.cjs +0 -1
  319. package/dist/utils/semaphore.d.cts +0 -3
  320. package/dist/utils/semaphore.d.ts +0 -78
  321. package/dist/utils/semaphore.d.ts.map +0 -1
  322. package/dist/utils/semaphore.js +0 -134
  323. package/dist/utils/throttle.cjs +0 -1
  324. package/dist/utils/throttle.d.cts +0 -24
  325. package/dist/utils/throttle.d.cts.map +0 -1
  326. package/dist/utils/throttle.d.ts +0 -18
  327. package/dist/utils/throttle.d.ts.map +0 -1
  328. package/dist/utils/throttle.js +0 -20
  329. package/dist/utils/throttle.js.map +0 -1
  330. package/src/logger/logger.ts +0 -14
  331. /package/dist/{errors-CRm1FHHT.cjs → errors-D-K-vxsP.cjs} +0 -0
@@ -0,0 +1,3952 @@
1
+ import { n as UploadistaError$1 } from "./uploadista-error-D9SONF9K.js";
2
+ import { l as GenerateId, p as GenerateIdShape } from "./index-DMJv8Tvo.js";
3
+ import { Context, Effect, Layer, Stream } from "effect";
4
+ import z$1, { z } from "zod";
5
+ import { UploadistaError } from "@uploadista/core/errors";
6
+
7
+ //#region src/flow/node.d.ts
8
+ /**
9
+ * Defines the type of node in a flow, determining its role in the processing pipeline.
10
+ */
11
+ declare enum NodeType {
12
+ /** Entry point for data into the flow */
13
+ input = "input",
14
+ /** Transforms data during flow execution */
15
+ process = "process",
16
+ /** Saves data to storage backends */
17
+ output = "output",
18
+ /** Routes data based on conditions */
19
+ conditional = "conditional",
20
+ /** Splits data to multiple outputs */
21
+ multiplex = "multiplex",
22
+ /** Combines multiple inputs into one output */
23
+ merge = "merge",
24
+ }
25
+ /**
26
+ * Fields that can be evaluated in conditional node conditions.
27
+ * These fields are typically found in file metadata.
28
+ */
29
+ type ConditionField = "mimeType" | "size" | "width" | "height" | "extension";
30
+ /**
31
+ * Operators available for comparing values in conditional node conditions.
32
+ */
33
+ type ConditionOperator = "equals" | "notEquals" | "greaterThan" | "lessThan" | "contains" | "startsWith";
34
+ /**
35
+ * Value used in conditional node comparisons.
36
+ * Can be either a string or number depending on the field being evaluated.
37
+ */
38
+ type ConditionValue = string | number;
39
+ /**
40
+ * Creates a flow node with automatic input/output validation and retry logic.
41
+ *
42
+ * Flow nodes are the building blocks of processing pipelines. Each node:
43
+ * - Validates its input against a Zod schema
44
+ * - Executes its processing logic
45
+ * - Validates its output against a Zod schema
46
+ * - Can optionally retry on failure with exponential backoff
47
+ *
48
+ * @template Input - The expected input type for this node
49
+ * @template Output - The output type produced by this node
50
+ *
51
+ * @param config - Node configuration
52
+ * @param config.id - Unique identifier for this node in the flow
53
+ * @param config.name - Human-readable name for the node
54
+ * @param config.description - Description of what this node does
55
+ * @param config.type - The type of node (input, process, output, conditional, multiplex, merge)
56
+ * @param config.inputSchema - Zod schema for validating input data
57
+ * @param config.outputSchema - Zod schema for validating output data
58
+ * @param config.run - The processing function to execute for this node
59
+ * @param config.condition - Optional condition for conditional nodes to determine if they should execute
60
+ * @param config.multiInput - If true, node receives all inputs as a record instead of a single input
61
+ * @param config.multiOutput - If true, node can output to multiple targets
62
+ * @param config.pausable - If true, node can pause execution and wait for additional data
63
+ * @param config.retry - Optional retry configuration for handling transient failures
64
+ * @param config.retry.maxRetries - Maximum number of retry attempts (default: 0)
65
+ * @param config.retry.retryDelay - Base delay in milliseconds between retries (default: 1000)
66
+ * @param config.retry.exponentialBackoff - Whether to use exponential backoff for retries (default: true)
67
+ *
68
+ * @returns An Effect that succeeds with the created FlowNode
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const resizeNode = createFlowNode({
73
+ * id: "resize-1",
74
+ * name: "Resize Image",
75
+ * description: "Resizes images to 800x600",
76
+ * type: NodeType.process,
77
+ * inputSchema: z.object({
78
+ * stream: z.instanceof(Uint8Array),
79
+ * metadata: z.object({ width: z.number(), height: z.number() })
80
+ * }),
81
+ * outputSchema: z.object({
82
+ * stream: z.instanceof(Uint8Array),
83
+ * metadata: z.object({ width: z.literal(800), height: z.literal(600) })
84
+ * }),
85
+ * run: ({ data }) => Effect.gen(function* () {
86
+ * const resized = yield* resizeImage(data.stream, 800, 600);
87
+ * return {
88
+ * type: "complete",
89
+ * data: { stream: resized, metadata: { width: 800, height: 600 } }
90
+ * };
91
+ * }),
92
+ * retry: {
93
+ * maxRetries: 3,
94
+ * retryDelay: 1000,
95
+ * exponentialBackoff: true
96
+ * }
97
+ * });
98
+ * ```
99
+ */
100
+ declare function createFlowNode<Input, Output>({
101
+ id,
102
+ name,
103
+ description,
104
+ type,
105
+ inputSchema,
106
+ outputSchema,
107
+ run,
108
+ condition,
109
+ multiInput,
110
+ multiOutput,
111
+ pausable,
112
+ retry
113
+ }: {
114
+ id: string;
115
+ name: string;
116
+ description: string;
117
+ type: NodeType;
118
+ inputSchema: z.ZodSchema<Input>;
119
+ outputSchema: z.ZodSchema<Output>;
120
+ run: (args: {
121
+ data: Input;
122
+ jobId: string;
123
+ storageId: string;
124
+ flowId: string;
125
+ clientId: string | null;
126
+ }) => Effect.Effect<NodeExecutionResult<Output>, UploadistaError$1>;
127
+ condition?: {
128
+ field: ConditionField;
129
+ operator: ConditionOperator;
130
+ value: ConditionValue;
131
+ };
132
+ multiInput?: boolean;
133
+ multiOutput?: boolean;
134
+ pausable?: boolean;
135
+ retry?: {
136
+ maxRetries?: number;
137
+ retryDelay?: number;
138
+ exponentialBackoff?: boolean;
139
+ };
140
+ }): Effect.Effect<FlowNode<Input, Output, UploadistaError$1>>;
141
+ /**
142
+ * Extracts serializable node metadata from a FlowNode instance.
143
+ *
144
+ * This function is useful for serializing flow configurations or
145
+ * transmitting node information over the network without including
146
+ * the executable run function or schemas.
147
+ *
148
+ * @param node - The flow node to extract data from
149
+ * @returns A plain object containing the node's metadata (id, name, description, type)
150
+ */
151
+ declare const getNodeData: (node: FlowNode<any, any, UploadistaError$1>) => FlowNodeData;
152
+ //#endregion
153
+ //#region src/flow/event.d.ts
154
+ /**
155
+ * Enumeration of all possible flow and node execution event types.
156
+ *
157
+ * Events follow a lifecycle pattern:
158
+ * - Job level: JobStart → ... → JobEnd
159
+ * - Flow level: FlowStart → ... → (FlowEnd | FlowError)
160
+ * - Node level: NodeStart → ... → (NodeEnd | NodePause | NodeError)
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * // Listen for flow completion
165
+ * if (event.eventType === EventType.FlowEnd) {
166
+ * console.log("Flow completed:", event.result);
167
+ * }
168
+ * ```
169
+ */
170
+ declare enum EventType {
171
+ /** Emitted when a job starts execution */
172
+ JobStart = "job-start",
173
+ /** Emitted when a job completes (success or failure) */
174
+ JobEnd = "job-end",
175
+ /** Emitted when a flow begins execution */
176
+ FlowStart = "flow-start",
177
+ /** Emitted when a flow completes successfully */
178
+ FlowEnd = "flow-end",
179
+ /** Emitted when a flow encounters an error */
180
+ FlowError = "flow-error",
181
+ /** Emitted when a node starts processing */
182
+ NodeStart = "node-start",
183
+ /** Emitted when a node completes successfully */
184
+ NodeEnd = "node-end",
185
+ /** Emitted when a node pauses (waiting for additional data) */
186
+ NodePause = "node-pause",
187
+ /** Emitted when a paused node resumes execution */
188
+ NodeResume = "node-resume",
189
+ /** Emitted when a node encounters an error */
190
+ NodeError = "node-error",
191
+ /** Emitted for streaming node data (e.g., progress updates) */
192
+ NodeStream = "node-stream",
193
+ /** Emitted for node response data */
194
+ NodeResponse = "node-response",
195
+ }
196
+ /**
197
+ * Event emitted when a job starts execution.
198
+ */
199
+ type FlowEventJobStart = {
200
+ jobId: string;
201
+ eventType: EventType.JobStart;
202
+ };
203
+ /**
204
+ * Event emitted when a job completes (either successfully or with failure).
205
+ */
206
+ type FlowEventJobEnd = {
207
+ jobId: string;
208
+ eventType: EventType.JobEnd;
209
+ };
210
+ /**
211
+ * Event emitted when a flow begins execution.
212
+ * This is the first event after JobStart in the execution lifecycle.
213
+ */
214
+ type FlowEventFlowStart = {
215
+ jobId: string;
216
+ flowId: string;
217
+ eventType: EventType.FlowStart;
218
+ };
219
+ /**
220
+ * Event emitted when a flow completes successfully.
221
+ *
222
+ * @property result - The final output from all output nodes in the flow
223
+ */
224
+ type FlowEventFlowEnd = {
225
+ jobId: string;
226
+ flowId: string;
227
+ eventType: EventType.FlowEnd;
228
+ result?: unknown;
229
+ };
230
+ /**
231
+ * Event emitted when a flow encounters an unrecoverable error.
232
+ *
233
+ * @property error - Error message describing what went wrong
234
+ */
235
+ type FlowEventFlowError = {
236
+ jobId: string;
237
+ flowId: string;
238
+ eventType: EventType.FlowError;
239
+ error: string;
240
+ };
241
+ /**
242
+ * Event emitted when a node begins processing.
243
+ *
244
+ * @property nodeName - Human-readable node name
245
+ * @property nodeType - Type of node (input, transform, conditional, output, etc.)
246
+ */
247
+ type FlowEventNodeStart = {
248
+ jobId: string;
249
+ flowId: string;
250
+ nodeId: string;
251
+ eventType: EventType.NodeStart;
252
+ nodeName: string;
253
+ nodeType: NodeType;
254
+ };
255
+ /**
256
+ * Event emitted when a node fails after all retry attempts.
257
+ *
258
+ * @property error - Error message from the failed execution
259
+ * @property retryCount - Number of retry attempts made before giving up
260
+ */
261
+ type FlowEventNodeError = {
262
+ jobId: string;
263
+ flowId: string;
264
+ nodeId: string;
265
+ nodeName: string;
266
+ eventType: EventType.NodeError;
267
+ error: string;
268
+ retryCount?: number;
269
+ };
270
+ /**
271
+ * Event emitted when a node completes successfully.
272
+ *
273
+ * @property result - The output data produced by the node
274
+ */
275
+ type FlowEventNodeEnd = {
276
+ jobId: string;
277
+ flowId: string;
278
+ nodeId: string;
279
+ eventType: EventType.NodeEnd;
280
+ nodeName: string;
281
+ result?: unknown;
282
+ };
283
+ /**
284
+ * Event emitted when a node pauses execution, waiting for additional data.
285
+ *
286
+ * This typically occurs with input nodes that need more chunks or nodes
287
+ * waiting for external services.
288
+ *
289
+ * @property partialData - Any partial result available before pausing
290
+ */
291
+ type FlowEventNodePause = {
292
+ jobId: string;
293
+ flowId: string;
294
+ nodeId: string;
295
+ eventType: EventType.NodePause;
296
+ nodeName: string;
297
+ partialData?: unknown;
298
+ };
299
+ /**
300
+ * Event emitted when a paused node resumes execution.
301
+ *
302
+ * This occurs after providing the additional data needed by a paused node.
303
+ */
304
+ type FlowEventNodeResume = {
305
+ jobId: string;
306
+ flowId: string;
307
+ nodeId: string;
308
+ eventType: EventType.NodeResume;
309
+ nodeName: string;
310
+ nodeType: NodeType;
311
+ };
312
+ /**
313
+ * Event emitted for node-specific response data.
314
+ *
315
+ * Used for streaming intermediate results or progress updates.
316
+ */
317
+ type FlowEventNodeResponse = {
318
+ jobId: string;
319
+ flowId: string;
320
+ nodeId: string;
321
+ eventType: EventType.NodeResponse;
322
+ nodeName: string;
323
+ data: unknown;
324
+ };
325
+ /**
326
+ * Union of all possible flow execution events.
327
+ *
328
+ * This discriminated union allows type-safe event handling based on eventType.
329
+ *
330
+ * @example
331
+ * ```typescript
332
+ * function handleFlowEvent(event: FlowEvent) {
333
+ * switch (event.eventType) {
334
+ * case EventType.FlowStart:
335
+ * console.log("Flow started:", event.flowId);
336
+ * break;
337
+ * case EventType.NodeEnd:
338
+ * console.log("Node completed:", event.nodeName, event.result);
339
+ * break;
340
+ * case EventType.FlowError:
341
+ * console.error("Flow failed:", event.error);
342
+ * break;
343
+ * }
344
+ * }
345
+ * ```
346
+ */
347
+ type FlowEvent = FlowEventJobStart | FlowEventJobEnd | FlowEventFlowStart | FlowEventFlowEnd | FlowEventFlowError | FlowEventNodeStart | FlowEventNodeEnd | FlowEventNodePause | FlowEventNodeResume | FlowEventNodeError;
348
+ //#endregion
349
+ //#region src/flow/types/flow-types.d.ts
350
+ /**
351
+ * Type mapping for node input/output schemas.
352
+ * Used for type-safe node connections in typed flows.
353
+ */
354
+ type NodeTypeMap = Record<string, {
355
+ input: unknown;
356
+ output: unknown;
357
+ }>;
358
+ /**
359
+ * Minimal node data without execution logic.
360
+ * Used for serialization and UI display.
361
+ *
362
+ * @property id - Unique node identifier
363
+ * @property name - Human-readable node name
364
+ * @property description - Explanation of what the node does
365
+ * @property type - Node category (input, transform, conditional, output, etc.)
366
+ */
367
+ type FlowNodeData = {
368
+ id: string;
369
+ name: string;
370
+ description: string;
371
+ type: NodeType;
372
+ };
373
+ /**
374
+ * Result of a node execution - either complete or waiting for more data.
375
+ *
376
+ * @template TOutput - Type of the node's output data
377
+ *
378
+ * @remarks
379
+ * Nodes can return "waiting" to pause flow execution when they need additional
380
+ * data (e.g., chunked uploads, external service responses). The flow can be
381
+ * resumed later with the missing data.
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * // Node completes immediately
386
+ * return completeNodeExecution({ processedData });
387
+ *
388
+ * // Node waits for more chunks
389
+ * if (needsMoreData) {
390
+ * return waitingNodeExecution({ receivedChunks: 3, totalChunks: 10 });
391
+ * }
392
+ * ```
393
+ */
394
+ type NodeExecutionResult<TOutput$1> = {
395
+ type: "complete";
396
+ data: TOutput$1;
397
+ } | {
398
+ type: "waiting";
399
+ partialData?: unknown;
400
+ };
401
+ /**
402
+ * Helper function to create a complete node execution result.
403
+ *
404
+ * @template TOutput - Type of the output data
405
+ * @param data - The output data from the node
406
+ * @returns A complete execution result
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * return completeNodeExecution({
411
+ * url: uploadedFile.url,
412
+ * size: uploadedFile.size
413
+ * });
414
+ * ```
415
+ */
416
+ declare const completeNodeExecution: <TOutput>(data: TOutput) => {
417
+ type: "complete";
418
+ data: TOutput;
419
+ };
420
+ /**
421
+ * Helper function to create a waiting node execution result.
422
+ *
423
+ * @param partialData - Optional partial data available so far
424
+ * @returns A waiting execution result that pauses the flow
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * // Wait for more upload chunks
429
+ * return waitingNodeExecution({
430
+ * receivedBytes: currentSize,
431
+ * totalBytes: expectedSize
432
+ * });
433
+ * ```
434
+ */
435
+ declare const waitingNodeExecution: (partialData?: unknown) => {
436
+ type: "waiting";
437
+ partialData: unknown;
438
+ };
439
+ /**
440
+ * A flow node represents a single processing step in the DAG.
441
+ *
442
+ * Nodes are the building blocks of flows. Each node has typed inputs/outputs,
443
+ * execution logic, and optional features like conditions, retries, and pausing.
444
+ *
445
+ * @template TInput - Type of data the node accepts
446
+ * @template TOutput - Type of data the node produces
447
+ * @template TError - Type of errors the node can throw
448
+ *
449
+ * @property inputSchema - Zod schema for validating input data
450
+ * @property outputSchema - Zod schema for validating output data
451
+ * @property run - Effect-based execution function
452
+ * @property condition - Optional conditional execution rule
453
+ * @property multiInput - Whether node accepts multiple inputs (default: false)
454
+ * @property multiOutput - Whether node produces multiple outputs (default: false)
455
+ * @property pausable - Whether node can pause execution (default: false)
456
+ * @property retry - Optional retry configuration
457
+ *
458
+ * @remarks
459
+ * - Nodes use Effect for composable error handling and dependency injection
460
+ * - Input/output schemas ensure type safety at runtime
461
+ * - Conditions are evaluated before execution
462
+ * - Retry logic supports exponential backoff
463
+ * - Pausable nodes can halt flow execution and resume later
464
+ *
465
+ * @example
466
+ * ```typescript
467
+ * const resizeNode: FlowNode<InputFile, UploadFile> = {
468
+ * id: "resize",
469
+ * name: "Resize Image",
470
+ * description: "Resize image to specified dimensions",
471
+ * type: NodeType.transform,
472
+ * inputSchema: inputFileSchema,
473
+ * outputSchema: uploadFileSchema,
474
+ * run: ({ data, storageId }) => Effect.gen(function* () {
475
+ * const resized = yield* resizeImage(data, { width: 1920, height: 1080 });
476
+ * return completeNodeExecution(resized);
477
+ * }),
478
+ * retry: {
479
+ * maxRetries: 3,
480
+ * retryDelay: 1000,
481
+ * exponentialBackoff: true
482
+ * }
483
+ * };
484
+ * ```
485
+ *
486
+ * @see {@link NodeExecutionResult} for return type options
487
+ * @see {@link FlowCondition} for conditional execution
488
+ */
489
+ type FlowNode<TInput = unknown, TOutput$1 = unknown, TError$1 = UploadistaError$1> = FlowNodeData & {
490
+ inputSchema: z.ZodSchema<TInput>;
491
+ outputSchema: z.ZodSchema<TOutput$1>;
492
+ run: (args: {
493
+ data: TInput;
494
+ jobId: string;
495
+ storageId: string;
496
+ flowId: string;
497
+ inputs?: Record<string, unknown>;
498
+ clientId: string | null;
499
+ }) => Effect.Effect<NodeExecutionResult<TOutput$1>, TError$1>;
500
+ condition?: {
501
+ field: string;
502
+ operator: string;
503
+ value: unknown;
504
+ };
505
+ multiInput?: boolean;
506
+ multiOutput?: boolean;
507
+ pausable?: boolean;
508
+ retry?: {
509
+ maxRetries?: number;
510
+ retryDelay?: number;
511
+ exponentialBackoff?: boolean;
512
+ };
513
+ };
514
+ /**
515
+ * Represents a directed edge connecting two nodes in the flow graph.
516
+ *
517
+ * Edges define the data flow direction and can specify ports for multi-input/output nodes.
518
+ *
519
+ * @property source - ID of the source node
520
+ * @property target - ID of the target node
521
+ * @property sourcePort - Optional output port name for multi-output nodes
522
+ * @property targetPort - Optional input port name for multi-input nodes
523
+ *
524
+ * @remarks
525
+ * - Edges must not create cycles (DAG constraint)
526
+ * - Source node's output type should be compatible with target node's input type
527
+ * - Ports allow routing specific outputs to specific inputs
528
+ *
529
+ * @example
530
+ * ```typescript
531
+ * // Simple edge
532
+ * const edge: FlowEdge = {
533
+ * source: "resize-node",
534
+ * target: "optimize-node"
535
+ * };
536
+ *
537
+ * // Edge with ports (for multiplex nodes)
538
+ * const multiplexEdge: FlowEdge = {
539
+ * source: "multiplex-node",
540
+ * target: "output-node",
541
+ * sourcePort: "image",
542
+ * targetPort: "primary"
543
+ * };
544
+ * ```
545
+ */
546
+ type FlowEdge$1 = {
547
+ source: string;
548
+ target: string;
549
+ sourcePort?: string;
550
+ targetPort?: string;
551
+ };
552
+ /**
553
+ * Function type for checking schema compatibility between nodes.
554
+ *
555
+ * @param from - Source node's output schema
556
+ * @param to - Target node's input schema
557
+ * @returns true if schemas are compatible
558
+ *
559
+ * @remarks
560
+ * Custom type checkers can implement more sophisticated compatibility rules
561
+ * than the default checker.
562
+ *
563
+ * @see {@link FlowTypeValidator} for the default implementation
564
+ */
565
+ type TypeCompatibilityChecker = (from: z.ZodSchema<any>, to: z.ZodSchema<any>) => boolean;
566
+ /**
567
+ * Interface for validating node connections and schema compatibility.
568
+ *
569
+ * @remarks
570
+ * Validators ensure that connected nodes have compatible types,
571
+ * preventing runtime type errors in flow execution.
572
+ *
573
+ * @see {@link FlowTypeValidator} for the implementation
574
+ */
575
+ type NodeConnectionValidator = {
576
+ validateConnection: (sourceNode: FlowNode<any, any>, targetNode: FlowNode<any, any>, edge: FlowEdge$1) => boolean;
577
+ getCompatibleTypes: (sourceSchema: z.ZodSchema<any>, targetSchema: z.ZodSchema<any>) => boolean;
578
+ };
579
+ /**
580
+ * Configuration object for creating a new flow.
581
+ *
582
+ * FlowConfig defines all aspects of a flow including its nodes, connections,
583
+ * schemas, and optional features like event handlers and parallel execution.
584
+ *
585
+ * @template TFlowInputSchema - Zod schema for flow inputs
586
+ * @template TFlowOutputSchema - Zod schema for flow outputs
587
+ * @template TNodeError - Union of possible errors from node Effects
588
+ * @template TNodeRequirements - Union of requirements from node Effects
589
+ *
590
+ * @property flowId - Unique identifier for the flow
591
+ * @property name - Human-readable flow name
592
+ * @property nodes - Array of nodes (can be plain nodes or Effects resolving to nodes)
593
+ * @property edges - Array of edges connecting the nodes
594
+ * @property inputSchema - Zod schema for validating flow inputs
595
+ * @property outputSchema - Zod schema for validating flow outputs
596
+ * @property typeChecker - Optional custom type compatibility checker
597
+ * @property onEvent - Optional event handler for monitoring execution
598
+ * @property parallelExecution - Optional parallel execution configuration
599
+ *
600
+ * @remarks
601
+ * - Nodes can be provided as plain objects or Effect-wrapped for lazy initialization
602
+ * - Event handlers receive all flow and node events
603
+ * - Parallel execution is experimental and disabled by default
604
+ * - Type checker allows custom schema compatibility rules
605
+ *
606
+ * @example
607
+ * ```typescript
608
+ * const config: FlowConfig<
609
+ * z.ZodObject<{ file: z.ZodType<File> }>,
610
+ * z.ZodType<UploadFile>,
611
+ * never,
612
+ * never
613
+ * > = {
614
+ * flowId: "image-upload",
615
+ * name: "Image Upload Pipeline",
616
+ * nodes: [inputNode, resizeNode, optimizeNode, storageNode],
617
+ * edges: [
618
+ * { source: "input", target: "resize" },
619
+ * { source: "resize", target: "optimize" },
620
+ * { source: "optimize", target: "storage" }
621
+ * ],
622
+ * inputSchema: z.object({ file: z.instanceof(File) }),
623
+ * outputSchema: uploadFileSchema,
624
+ * onEvent: (event) => Effect.gen(function* () {
625
+ * yield* logEvent(event);
626
+ * return { eventId: event.jobId };
627
+ * })
628
+ * };
629
+ * ```
630
+ *
631
+ * @see {@link createFlowWithSchema} for creating flows from config
632
+ * @see {@link FlowNode} for node specifications
633
+ * @see {@link FlowEdge} for edge specifications
634
+ */
635
+ type FlowConfig<TFlowInputSchema extends z.ZodSchema<any>, TFlowOutputSchema extends z.ZodSchema<any>, TNodeError = never, TNodeRequirements = never> = {
636
+ flowId: string;
637
+ name: string;
638
+ nodes: Array<FlowNode<any, any, UploadistaError$1> | Effect.Effect<FlowNode<any, any, UploadistaError$1>, TNodeError, TNodeRequirements>>;
639
+ edges: FlowEdge$1[];
640
+ inputSchema: TFlowInputSchema;
641
+ outputSchema: TFlowOutputSchema;
642
+ typeChecker?: TypeCompatibilityChecker;
643
+ onEvent?: (event: FlowEvent) => Effect.Effect<{
644
+ eventId: string | null;
645
+ }, UploadistaError$1>;
646
+ parallelExecution?: {
647
+ enabled?: boolean;
648
+ maxConcurrency?: number;
649
+ };
650
+ };
651
+ //#endregion
652
+ //#region src/flow/edge.d.ts
653
+ /**
654
+ * Represents a connection between two nodes in a flow, defining the data flow direction.
655
+ *
656
+ * Edges connect the output of a source node to the input of a target node,
657
+ * enabling data to flow through the processing pipeline in a directed acyclic graph (DAG).
658
+ */
659
+ type FlowEdge = FlowEdge$1;
660
+ /**
661
+ * Creates a flow edge connecting two nodes in a processing pipeline.
662
+ *
663
+ * Edges define how data flows between nodes. The data output from the source node
664
+ * becomes the input for the target node. For nodes with multiple inputs/outputs,
665
+ * ports can be specified to route data to specific connections.
666
+ *
667
+ * @param config - Edge configuration
668
+ * @param config.source - ID of the source node (data originates here)
669
+ * @param config.target - ID of the target node (data flows to here)
670
+ * @param config.sourcePort - Optional port name on the source node for multi-output nodes
671
+ * @param config.targetPort - Optional port name on the target node for multi-input nodes
672
+ *
673
+ * @returns A FlowEdge object representing the connection
674
+ *
675
+ * @example
676
+ * ```typescript
677
+ * // Simple edge connecting two nodes
678
+ * const edge = createFlowEdge({
679
+ * source: "input-1",
680
+ * target: "process-1"
681
+ * });
682
+ *
683
+ * // Edge with ports for multi-input/output nodes
684
+ * const portEdge = createFlowEdge({
685
+ * source: "multiplex-1",
686
+ * target: "merge-1",
687
+ * sourcePort: "out-a",
688
+ * targetPort: "in-1"
689
+ * });
690
+ * ```
691
+ */
692
+ declare function createFlowEdge({
693
+ source,
694
+ target,
695
+ sourcePort,
696
+ targetPort
697
+ }: {
698
+ source: string;
699
+ target: string;
700
+ sourcePort?: string;
701
+ targetPort?: string;
702
+ }): FlowEdge;
703
+ //#endregion
704
+ //#region src/flow/flow.d.ts
705
+ /**
706
+ * Serialized flow data for storage and transport.
707
+ * Contains the minimal information needed to reconstruct a flow.
708
+ *
709
+ * @property id - Unique flow identifier
710
+ * @property name - Human-readable flow name
711
+ * @property nodes - Array of node data (without execution logic)
712
+ * @property edges - Connections between nodes defining data flow
713
+ */
714
+ type FlowData = {
715
+ id: string;
716
+ name: string;
717
+ nodes: FlowNodeData[];
718
+ edges: FlowEdge[];
719
+ };
720
+ /**
721
+ * Extracts serializable flow data from a Flow instance.
722
+ * Useful for storing flow definitions or sending them over the network.
723
+ *
724
+ * @template TRequirements - Effect requirements for the flow
725
+ * @param flow - Flow instance to extract data from
726
+ * @returns Serializable flow data without execution logic
727
+ *
728
+ * @example
729
+ * ```typescript
730
+ * const flowData = getFlowData(myFlow);
731
+ * // Store in database or send to client
732
+ * await db.flows.save(flowData);
733
+ * ```
734
+ */
735
+ declare const getFlowData: <TRequirements>(flow: Flow<any, any, TRequirements>) => FlowData;
736
+ /**
737
+ * Result of a flow execution - either completed or paused.
738
+ *
739
+ * @template TOutput - Type of the flow's output data
740
+ *
741
+ * @remarks
742
+ * Flows can pause when a node needs additional data (e.g., waiting for user input
743
+ * or external service). The execution state allows resuming from where it paused.
744
+ *
745
+ * @example
746
+ * ```typescript
747
+ * const result = await Effect.runPromise(flow.run({ inputs, storageId, jobId }));
748
+ *
749
+ * if (result.type === "completed") {
750
+ * console.log("Flow completed:", result.result);
751
+ * } else {
752
+ * console.log("Flow paused at node:", result.nodeId);
753
+ * // Can resume later with: flow.resume({ jobId, executionState: result.executionState, ... })
754
+ * }
755
+ * ```
756
+ */
757
+ type FlowExecutionResult<TOutput$1> = {
758
+ type: "completed";
759
+ result: TOutput$1;
760
+ } | {
761
+ type: "paused";
762
+ nodeId: string;
763
+ executionState: {
764
+ executionOrder: string[];
765
+ currentIndex: number;
766
+ inputs: Record<string, unknown>;
767
+ };
768
+ };
769
+ /**
770
+ * A Flow represents a directed acyclic graph (DAG) of processing nodes.
771
+ *
772
+ * Flows execute nodes in topological order, passing data between nodes through edges.
773
+ * They support conditional execution, retry logic, pausable nodes, and event emission.
774
+ *
775
+ * @template TFlowInputSchema - Zod schema defining the shape of input data
776
+ * @template TFlowOutputSchema - Zod schema defining the shape of output data
777
+ * @template TRequirements - Effect requirements (services/contexts) needed by nodes
778
+ *
779
+ * @property id - Unique flow identifier
780
+ * @property name - Human-readable flow name
781
+ * @property nodes - Array of nodes in the flow
782
+ * @property edges - Connections between nodes
783
+ * @property inputSchema - Zod schema for validating flow inputs
784
+ * @property outputSchema - Zod schema for validating flow outputs
785
+ * @property onEvent - Optional callback for flow execution events
786
+ * @property run - Executes the flow from the beginning
787
+ * @property resume - Resumes a paused flow execution
788
+ * @property validateTypes - Validates node type compatibility
789
+ * @property validateInputs - Validates input data against schema
790
+ * @property validateOutputs - Validates output data against schema
791
+ *
792
+ * @remarks
793
+ * Flows are created using {@link createFlowWithSchema}. The Effect-based design
794
+ * allows for composable error handling, resource management, and dependency injection.
795
+ *
796
+ * @example
797
+ * ```typescript
798
+ * const flow = yield* createFlowWithSchema({
799
+ * flowId: "image-pipeline",
800
+ * name: "Image Processing Pipeline",
801
+ * nodes: [inputNode, resizeNode, optimizeNode, storageNode],
802
+ * edges: [
803
+ * { source: "input", target: "resize" },
804
+ * { source: "resize", target: "optimize" },
805
+ * { source: "optimize", target: "storage" }
806
+ * ],
807
+ * inputSchema: z.object({ file: z.instanceof(File) }),
808
+ * outputSchema: uploadFileSchema
809
+ * });
810
+ *
811
+ * const result = yield* flow.run({
812
+ * inputs: { input: { file: myFile } },
813
+ * storageId: "storage-1",
814
+ * jobId: "job-123"
815
+ * });
816
+ * ```
817
+ */
818
+ type Flow<TFlowInputSchema extends z.ZodSchema<any>, TFlowOutputSchema extends z.ZodSchema<any>, TRequirements$1> = {
819
+ id: string;
820
+ name: string;
821
+ nodes: FlowNode<any, any, UploadistaError$1>[];
822
+ edges: FlowEdge[];
823
+ inputSchema: TFlowInputSchema;
824
+ outputSchema: TFlowOutputSchema;
825
+ onEvent?: FlowConfig<TFlowInputSchema, TFlowOutputSchema, TRequirements$1>["onEvent"];
826
+ run: (args: {
827
+ inputs?: Record<string, z.infer<TFlowInputSchema>>;
828
+ storageId: string;
829
+ jobId: string;
830
+ clientId: string | null;
831
+ }) => Effect.Effect<FlowExecutionResult<Record<string, z.infer<TFlowOutputSchema>>>, UploadistaError$1, TRequirements$1>;
832
+ resume: (args: {
833
+ jobId: string;
834
+ storageId: string;
835
+ nodeResults: Record<string, unknown>;
836
+ executionState: {
837
+ executionOrder: string[];
838
+ currentIndex: number;
839
+ inputs: Record<string, z.infer<TFlowInputSchema>>;
840
+ };
841
+ clientId: string | null;
842
+ }) => Effect.Effect<FlowExecutionResult<Record<string, z.infer<TFlowOutputSchema>>>, UploadistaError$1, TRequirements$1>;
843
+ validateTypes: () => {
844
+ isValid: boolean;
845
+ errors: string[];
846
+ };
847
+ validateInputs: (inputs: unknown) => {
848
+ isValid: boolean;
849
+ errors: string[];
850
+ };
851
+ validateOutputs: (outputs: unknown) => {
852
+ isValid: boolean;
853
+ errors: string[];
854
+ };
855
+ };
856
+ /**
857
+ * Creates a new Flow with Zod schema-based type validation.
858
+ *
859
+ * This is the primary way to create flows in Uploadista. It constructs a Flow
860
+ * instance that validates inputs/outputs, executes nodes in topological order,
861
+ * handles errors with retries, and emits events during execution.
862
+ *
863
+ * @template TFlowInputSchema - Zod schema for flow input validation
864
+ * @template TFlowOutputSchema - Zod schema for flow output validation
865
+ * @template TRequirements - Effect requirements/services needed by the flow
866
+ * @template TNodeError - Union of possible errors from nodes
867
+ * @template TNodeRequirements - Union of requirements from nodes
868
+ *
869
+ * @param config - Flow configuration object
870
+ * @param config.flowId - Unique identifier for the flow
871
+ * @param config.name - Human-readable flow name
872
+ * @param config.nodes - Array of nodes (can be plain nodes or Effects resolving to nodes)
873
+ * @param config.edges - Array of edges connecting nodes
874
+ * @param config.inputSchema - Zod schema for validating inputs
875
+ * @param config.outputSchema - Zod schema for validating outputs
876
+ * @param config.typeChecker - Optional custom type compatibility checker
877
+ * @param config.onEvent - Optional event callback for monitoring execution
878
+ *
879
+ * @returns Effect that resolves to a Flow instance
880
+ *
881
+ * @throws {UploadistaError} FLOW_CYCLE_ERROR if the graph contains cycles
882
+ * @throws {UploadistaError} FLOW_NODE_NOT_FOUND if a node is referenced but missing
883
+ * @throws {UploadistaError} FLOW_NODE_ERROR if node execution fails
884
+ * @throws {UploadistaError} FLOW_OUTPUT_VALIDATION_ERROR if outputs don't match schema
885
+ *
886
+ * @remarks
887
+ * - Nodes can be provided as plain objects or as Effects that resolve to nodes
888
+ * - The flow performs topological sorting to determine execution order
889
+ * - Conditional nodes are evaluated before execution
890
+ * - Nodes can specify retry configuration with exponential backoff
891
+ * - Pausable nodes can halt execution and resume later
892
+ *
893
+ * @example
894
+ * ```typescript
895
+ * const flow = yield* createFlowWithSchema({
896
+ * flowId: "image-upload",
897
+ * name: "Image Upload with Processing",
898
+ * nodes: [
899
+ * inputNode,
900
+ * yield* createResizeNode({ width: 1920, height: 1080 }),
901
+ * optimizeNode,
902
+ * storageNode
903
+ * ],
904
+ * edges: [
905
+ * { source: "input", target: "resize" },
906
+ * { source: "resize", target: "optimize" },
907
+ * { source: "optimize", target: "storage" }
908
+ * ],
909
+ * inputSchema: z.object({
910
+ * file: z.instanceof(File),
911
+ * metadata: z.record(z.string(), z.any()).optional()
912
+ * }),
913
+ * outputSchema: uploadFileSchema,
914
+ * onEvent: (event) => Effect.gen(function* () {
915
+ * console.log("Flow event:", event);
916
+ * return { eventId: event.jobId };
917
+ * })
918
+ * });
919
+ * ```
920
+ *
921
+ * @see {@link Flow} for the returned flow type
922
+ * @see {@link FlowConfig} for configuration options
923
+ */
924
+ declare function createFlowWithSchema<TFlowInputSchema extends z.ZodSchema<any>, TFlowOutputSchema extends z.ZodSchema<any>, TRequirements$1 = never, TNodeError = never, TNodeRequirements = never>(config: FlowConfig<TFlowInputSchema, TFlowOutputSchema, TNodeError, TNodeRequirements>): Effect.Effect<Flow<TFlowInputSchema, TFlowOutputSchema, TRequirements$1>, TNodeError, TNodeRequirements>;
925
+ //#endregion
926
+ //#region src/types/upload-file.d.ts
927
+ /**
928
+ * Zod schema for validating UploadFile objects.
929
+ *
930
+ * This schema defines the structure and validation rules for upload file metadata.
931
+ * Use this schema to parse and validate UploadFile data from external sources.
932
+ *
933
+ * @see {@link UploadFile} for the TypeScript type
934
+ */
935
+ declare const uploadFileSchema: z.ZodObject<{
936
+ id: z.ZodString;
937
+ size: z.ZodOptional<z.ZodNumber>;
938
+ offset: z.ZodNumber;
939
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
940
+ creationDate: z.ZodOptional<z.ZodString>;
941
+ url: z.ZodOptional<z.ZodString>;
942
+ sizeIsDeferred: z.ZodOptional<z.ZodBoolean>;
943
+ checksum: z.ZodOptional<z.ZodString>;
944
+ checksumAlgorithm: z.ZodOptional<z.ZodString>;
945
+ storage: z.ZodObject<{
946
+ id: z.ZodString;
947
+ type: z.ZodString;
948
+ path: z.ZodOptional<z.ZodString>;
949
+ uploadId: z.ZodOptional<z.ZodString>;
950
+ bucket: z.ZodOptional<z.ZodString>;
951
+ }, z.core.$strip>;
952
+ flow: z.ZodOptional<z.ZodObject<{
953
+ flowId: z.ZodString;
954
+ nodeId: z.ZodString;
955
+ jobId: z.ZodString;
956
+ }, z.core.$strip>>;
957
+ }, z.core.$strip>;
958
+ /**
959
+ * Represents an uploaded file with its metadata and storage information.
960
+ *
961
+ * This is the core data structure that tracks file uploads throughout their lifecycle.
962
+ * It contains all metadata needed to resume uploads, track progress, and locate files
963
+ * in storage backends.
964
+ *
965
+ * @property id - Unique identifier for this upload
966
+ * @property offset - Current byte offset (how many bytes have been uploaded)
967
+ * @property storage - Storage backend information
968
+ * @property storage.id - Storage backend identifier (e.g., "s3-production")
969
+ * @property storage.type - Storage backend type (e.g., "s3", "azure", "gcs")
970
+ * @property storage.path - Optional path prefix within the storage backend
971
+ * @property storage.uploadId - Optional backend-specific upload ID (e.g., S3 multipart upload ID)
972
+ * @property storage.bucket - Optional bucket or container name
973
+ * @property flow - Optional flow processing information (when file is part of a flow)
974
+ * @property flow.flowId - ID of the flow processing this file
975
+ * @property flow.nodeId - ID of the flow node that created this file
976
+ * @property flow.jobId - ID of the flow job execution
977
+ * @property size - Total file size in bytes (undefined if deferred)
978
+ * @property metadata - Custom key-value metadata attached to the file
979
+ * @property creationDate - ISO 8601 timestamp when upload was created
980
+ * @property url - Optional public URL to access the file
981
+ * @property sizeIsDeferred - True if file size is not known at upload start
982
+ * @property checksum - Optional file checksum/hash value
983
+ * @property checksumAlgorithm - Algorithm used for checksum (e.g., "md5", "sha256")
984
+ *
985
+ * @example
986
+ * ```typescript
987
+ * // Create an UploadFile for a new upload
988
+ * const uploadFile: UploadFile = {
989
+ * id: "upload_abc123",
990
+ * offset: 0,
991
+ * size: 1024000,
992
+ * storage: {
993
+ * id: "s3-production",
994
+ * type: "s3",
995
+ * bucket: "my-uploads",
996
+ * path: "files/"
997
+ * },
998
+ * metadata: {
999
+ * fileName: "image.jpg",
1000
+ * contentType: "image/jpeg",
1001
+ * userId: "user_123"
1002
+ * },
1003
+ * creationDate: new Date().toISOString(),
1004
+ * checksum: "5d41402abc4b2a76b9719d911017c592",
1005
+ * checksumAlgorithm: "md5"
1006
+ * };
1007
+ *
1008
+ * // UploadFile with flow processing
1009
+ * const flowFile: UploadFile = {
1010
+ * id: "upload_xyz789",
1011
+ * offset: 0,
1012
+ * size: 2048000,
1013
+ * storage: {
1014
+ * id: "s3-temp",
1015
+ * type: "s3",
1016
+ * bucket: "temp-processing"
1017
+ * },
1018
+ * flow: {
1019
+ * flowId: "flow_resize_optimize",
1020
+ * nodeId: "input_1",
1021
+ * jobId: "job_456"
1022
+ * }
1023
+ * };
1024
+ *
1025
+ * // Resume an interrupted upload
1026
+ * const resumingFile: UploadFile = {
1027
+ * id: "upload_resume",
1028
+ * offset: 524288, // Already uploaded 512KB
1029
+ * size: 1024000,
1030
+ * storage: {
1031
+ * id: "s3-production",
1032
+ * type: "s3",
1033
+ * uploadId: "multipart_xyz" // S3 multipart upload ID
1034
+ * }
1035
+ * };
1036
+ * ```
1037
+ */
1038
+ type UploadFile = {
1039
+ id: string;
1040
+ offset: number;
1041
+ storage: {
1042
+ id: string;
1043
+ type: string;
1044
+ path?: string | undefined;
1045
+ uploadId?: string | undefined;
1046
+ bucket?: string | undefined;
1047
+ };
1048
+ flow?: {
1049
+ flowId: string;
1050
+ nodeId: string;
1051
+ jobId: string;
1052
+ };
1053
+ size?: number | undefined;
1054
+ metadata?: Record<string, string | number | boolean> | undefined;
1055
+ creationDate?: string | undefined;
1056
+ url?: string | undefined;
1057
+ sizeIsDeferred?: boolean | undefined;
1058
+ checksum?: string | undefined;
1059
+ checksumAlgorithm?: string | undefined;
1060
+ };
1061
+ //#endregion
1062
+ //#region src/types/kv-store.d.ts
1063
+ /**
1064
+ * Base key-value store interface for raw string storage.
1065
+ *
1066
+ * This is the low-level interface that storage adapters implement.
1067
+ * It stores raw string values without type safety or serialization.
1068
+ *
1069
+ * @property get - Retrieves a value by key, returns null if not found
1070
+ * @property set - Stores a value with the given key
1071
+ * @property delete - Removes a value by key
1072
+ * @property list - Optional operation to list all keys with a given prefix
1073
+ *
1074
+ * @example
1075
+ * ```typescript
1076
+ * // Implement a BaseKvStore with Redis
1077
+ * const redisKvStore: BaseKvStore = {
1078
+ * get: (key) => Effect.tryPromise({
1079
+ * try: () => redis.get(key),
1080
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1081
+ * }),
1082
+ *
1083
+ * set: (key, value) => Effect.tryPromise({
1084
+ * try: () => redis.set(key, value),
1085
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1086
+ * }),
1087
+ *
1088
+ * delete: (key) => Effect.tryPromise({
1089
+ * try: () => redis.del(key),
1090
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1091
+ * }),
1092
+ *
1093
+ * list: (prefix) => Effect.tryPromise({
1094
+ * try: () => redis.keys(`${prefix}*`),
1095
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1096
+ * })
1097
+ * };
1098
+ * ```
1099
+ */
1100
+ interface BaseKvStore {
1101
+ readonly get: (key: string) => Effect.Effect<string | null, UploadistaError$1>;
1102
+ readonly set: (key: string, value: string) => Effect.Effect<void, UploadistaError$1>;
1103
+ readonly delete: (key: string) => Effect.Effect<void, UploadistaError$1>;
1104
+ readonly list?: (keyPrefix: string) => Effect.Effect<Array<string>, UploadistaError$1>;
1105
+ }
1106
+ /**
1107
+ * Type-safe key-value store interface with automatic serialization.
1108
+ *
1109
+ * This wraps a BaseKvStore and handles JSON serialization/deserialization
1110
+ * for a specific data type, providing type safety and eliminating the need
1111
+ * for manual JSON.stringify/parse calls.
1112
+ *
1113
+ * @template TData - The type of data stored in this KV store
1114
+ *
1115
+ * @property get - Retrieves and deserializes a value, fails if not found
1116
+ * @property set - Serializes and stores a value
1117
+ * @property delete - Removes a value by key
1118
+ * @property list - Optional operation to list all keys (without prefix)
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * // Use a typed KV store
1123
+ * const uploadStore: KvStore<UploadFile> = new TypedKvStore(
1124
+ * baseStore,
1125
+ * "uploads:",
1126
+ * jsonSerializer.serialize,
1127
+ * jsonSerializer.deserialize
1128
+ * );
1129
+ *
1130
+ * // Store and retrieve typed data
1131
+ * const program = Effect.gen(function* () {
1132
+ * const file: UploadFile = {
1133
+ * id: "file123",
1134
+ * offset: 0,
1135
+ * storage: { id: "s3", type: "s3" }
1136
+ * };
1137
+ *
1138
+ * // Automatic serialization
1139
+ * yield* uploadStore.set("file123", file);
1140
+ *
1141
+ * // Automatic deserialization with type safety
1142
+ * const retrieved = yield* uploadStore.get("file123");
1143
+ * console.log(retrieved.offset); // TypeScript knows this is a number
1144
+ * });
1145
+ * ```
1146
+ */
1147
+ type KvStore<TData> = {
1148
+ readonly get: (key: string) => Effect.Effect<TData, UploadistaError$1>;
1149
+ readonly set: (key: string, value: TData) => Effect.Effect<void, UploadistaError$1>;
1150
+ readonly delete: (key: string) => Effect.Effect<void, UploadistaError$1>;
1151
+ readonly list?: () => Effect.Effect<Array<string>, UploadistaError$1>;
1152
+ };
1153
+ /**
1154
+ * Typed wrapper class that adds serialization to a BaseKvStore.
1155
+ *
1156
+ * This class implements the KvStore interface by wrapping a BaseKvStore
1157
+ * and handling serialization/deserialization for a specific type. It also
1158
+ * adds a key prefix to isolate different data types in the same store.
1159
+ *
1160
+ * @template TData - The type of data to store
1161
+ *
1162
+ * @example
1163
+ * ```typescript
1164
+ * // Create a typed store for UploadFile
1165
+ * const uploadFileStore = new TypedKvStore<UploadFile>(
1166
+ * baseKvStore,
1167
+ * "uploadista:upload-file:", // All keys will be prefixed
1168
+ * (data) => JSON.stringify(data),
1169
+ * (str) => JSON.parse(str) as UploadFile
1170
+ * );
1171
+ *
1172
+ * // Use the store
1173
+ * const effect = Effect.gen(function* () {
1174
+ * const file: UploadFile = { ... };
1175
+ * yield* uploadFileStore.set("abc123", file);
1176
+ * // Internally stores at key "uploadista:upload-file:abc123"
1177
+ *
1178
+ * const retrieved = yield* uploadFileStore.get("abc123");
1179
+ * return retrieved;
1180
+ * });
1181
+ *
1182
+ * // Custom serialization for binary data
1183
+ * const binaryStore = new TypedKvStore<Uint8Array>(
1184
+ * baseKvStore,
1185
+ * "binary:",
1186
+ * (data) => btoa(String.fromCharCode(...data)), // Base64 encode
1187
+ * (str) => Uint8Array.from(atob(str), c => c.charCodeAt(0)) // Base64 decode
1188
+ * );
1189
+ * ```
1190
+ */
1191
+ declare class TypedKvStore<TData> implements KvStore<TData> {
1192
+ private baseStore;
1193
+ private keyPrefix;
1194
+ private serialize;
1195
+ private deserialize;
1196
+ constructor(baseStore: BaseKvStore, keyPrefix: string, serialize: (data: TData) => string, deserialize: (str: string) => TData);
1197
+ get: (key: string) => Effect.Effect<TData, UploadistaError$1>;
1198
+ set: (key: string, value: TData) => Effect.Effect<void, UploadistaError$1>;
1199
+ delete: (key: string) => Effect.Effect<void, UploadistaError$1>;
1200
+ list: () => Effect.Effect<Array<string>, UploadistaError$1>;
1201
+ }
1202
+ /**
1203
+ * Default JSON serialization helpers.
1204
+ *
1205
+ * These functions provide standard JSON serialization for use with TypedKvStore.
1206
+ * They work with any JSON-serializable type.
1207
+ *
1208
+ * @example
1209
+ * ```typescript
1210
+ * const store = new TypedKvStore<MyType>(
1211
+ * baseStore,
1212
+ * "mydata:",
1213
+ * jsonSerializer.serialize,
1214
+ * jsonSerializer.deserialize
1215
+ * );
1216
+ * ```
1217
+ */
1218
+ declare const jsonSerializer: {
1219
+ serialize: <T>(data: T) => string;
1220
+ deserialize: <T>(str: string) => T;
1221
+ };
1222
+ declare const BaseKvStoreService_base: Context.TagClass<BaseKvStoreService, "BaseKvStore", BaseKvStore>;
1223
+ /**
1224
+ * Effect-TS context tag for the base untyped KV store.
1225
+ *
1226
+ * This is the low-level store that storage adapter implementations provide.
1227
+ * Most application code should use typed stores like UploadFileKVStore instead.
1228
+ *
1229
+ * @example
1230
+ * ```typescript
1231
+ * // Provide a base store implementation
1232
+ * const baseStoreLayer = Layer.succeed(BaseKvStoreService, redisKvStore);
1233
+ *
1234
+ * // Use in an Effect
1235
+ * const effect = Effect.gen(function* () {
1236
+ * const baseStore = yield* BaseKvStoreService;
1237
+ * yield* baseStore.set("raw-key", "raw-value");
1238
+ * });
1239
+ * ```
1240
+ */
1241
+ declare class BaseKvStoreService extends BaseKvStoreService_base {}
1242
+ declare const UploadFileKVStore_base: Context.TagClass<UploadFileKVStore, "UploadFileKVStore", KvStore<UploadFile>>;
1243
+ /**
1244
+ * Effect-TS context tag for the UploadFile typed KV store.
1245
+ *
1246
+ * This provides type-safe storage for UploadFile metadata. It's the primary
1247
+ * way to store and retrieve upload metadata in the system.
1248
+ *
1249
+ * @example
1250
+ * ```typescript
1251
+ * const uploadEffect = Effect.gen(function* () {
1252
+ * const kvStore = yield* UploadFileKVStore;
1253
+ *
1254
+ * // Store upload metadata
1255
+ * const file: UploadFile = {
1256
+ * id: "upload123",
1257
+ * offset: 0,
1258
+ * storage: { id: "s3", type: "s3" }
1259
+ * };
1260
+ * yield* kvStore.set("upload123", file);
1261
+ *
1262
+ * // Retrieve with type safety
1263
+ * const retrieved = yield* kvStore.get("upload123");
1264
+ * return retrieved;
1265
+ * });
1266
+ * ```
1267
+ */
1268
+ declare class UploadFileKVStore extends UploadFileKVStore_base {}
1269
+ /**
1270
+ * Effect Layer that creates the UploadFileKVStore from a BaseKvStore.
1271
+ *
1272
+ * This layer automatically wires up JSON serialization for UploadFile objects
1273
+ * with the "uploadista:upload-file:" key prefix.
1274
+ *
1275
+ * @example
1276
+ * ```typescript
1277
+ * const program = Effect.gen(function* () {
1278
+ * const kvStore = yield* UploadFileKVStore;
1279
+ * // Use the store...
1280
+ * }).pipe(
1281
+ * Effect.provide(uploadFileKvStore),
1282
+ * Effect.provide(baseStoreLayer)
1283
+ * );
1284
+ * ```
1285
+ */
1286
+ declare const uploadFileKvStore: Layer.Layer<UploadFileKVStore, never, BaseKvStoreService>;
1287
+ declare const FlowJobKVStore_base: Context.TagClass<FlowJobKVStore, "FlowJobKVStore", KvStore<FlowJob>>;
1288
+ /**
1289
+ * Effect-TS context tag for the FlowJob typed KV store.
1290
+ *
1291
+ * This provides type-safe storage for FlowJob metadata, tracking the
1292
+ * execution state of flow processing jobs.
1293
+ *
1294
+ * @example
1295
+ * ```typescript
1296
+ * const flowEffect = Effect.gen(function* () {
1297
+ * const jobStore = yield* FlowJobKVStore;
1298
+ *
1299
+ * // Store job state
1300
+ * const job: FlowJob = {
1301
+ * id: "job123",
1302
+ * flowId: "flow_resize",
1303
+ * status: "running",
1304
+ * tasks: [],
1305
+ * createdAt: new Date(),
1306
+ * updatedAt: new Date()
1307
+ * };
1308
+ * yield* jobStore.set("job123", job);
1309
+ *
1310
+ * // Retrieve and check status
1311
+ * const retrieved = yield* jobStore.get("job123");
1312
+ * return retrieved.status;
1313
+ * });
1314
+ * ```
1315
+ */
1316
+ declare class FlowJobKVStore extends FlowJobKVStore_base {}
1317
+ /**
1318
+ * Effect Layer that creates the FlowJobKVStore from a BaseKvStore.
1319
+ *
1320
+ * This layer automatically wires up JSON serialization for FlowJob objects
1321
+ * with the "uploadista:flow-job:" key prefix.
1322
+ *
1323
+ * @example
1324
+ * ```typescript
1325
+ * const program = Effect.gen(function* () {
1326
+ * const jobStore = yield* FlowJobKVStore;
1327
+ * // Use the store...
1328
+ * }).pipe(
1329
+ * Effect.provide(flowJobKvStore),
1330
+ * Effect.provide(baseStoreLayer)
1331
+ * );
1332
+ * ```
1333
+ */
1334
+ declare const flowJobKvStore: Layer.Layer<FlowJobKVStore, never, BaseKvStoreService>;
1335
+ //#endregion
1336
+ //#region src/types/data-store.d.ts
1337
+ /**
1338
+ * Options for writing data to a DataStore.
1339
+ *
1340
+ * @property file_id - Unique identifier for the file being written
1341
+ * @property stream - Stream of byte chunks to write to storage
1342
+ * @property offset - Byte offset where writing should begin (for resumable uploads)
1343
+ */
1344
+ type DataStoreWriteOptions = {
1345
+ file_id: string;
1346
+ stream: Stream.Stream<Uint8Array, UploadistaError$1>;
1347
+ offset: number;
1348
+ };
1349
+ /**
1350
+ * Upload strategy type indicating how chunks are uploaded.
1351
+ *
1352
+ * - `single`: Upload file in a single request (traditional upload)
1353
+ * - `parallel`: Upload file chunks in parallel (for large files)
1354
+ */
1355
+ type UploadStrategy = "single" | "parallel";
1356
+ /**
1357
+ * Capabilities and constraints of a DataStore implementation.
1358
+ *
1359
+ * This type describes what features a storage backend supports and what
1360
+ * limitations it has. Use this to determine the optimal upload strategy
1361
+ * and validate client requests.
1362
+ *
1363
+ * @property supportsParallelUploads - Can upload chunks in parallel (e.g., S3 multipart)
1364
+ * @property supportsConcatenation - Can concatenate multiple uploads into one file
1365
+ * @property supportsDeferredLength - Can start upload without knowing final size
1366
+ * @property supportsResumableUploads - Can resume interrupted uploads from last offset
1367
+ * @property supportsTransactionalUploads - Guarantees atomic upload success/failure
1368
+ * @property maxConcurrentUploads - Maximum parallel upload parts (if parallel supported)
1369
+ * @property minChunkSize - Minimum size in bytes for each chunk (except last)
1370
+ * @property maxChunkSize - Maximum size in bytes for each chunk
1371
+ * @property maxParts - Maximum number of parts in a multipart upload
1372
+ * @property optimalChunkSize - Recommended chunk size for best performance
1373
+ * @property requiresOrderedChunks - Must receive chunks in sequential order
1374
+ * @property requiresMimeTypeValidation - Validates file MIME type matches declaration
1375
+ * @property maxValidationSize - Maximum file size for MIME type validation
1376
+ *
1377
+ * @example
1378
+ * ```typescript
1379
+ * const capabilities = dataStore.getCapabilities();
1380
+ *
1381
+ * if (capabilities.supportsParallelUploads && fileSize > 10_000_000) {
1382
+ * // Use parallel upload for large files
1383
+ * const chunkSize = capabilities.optimalChunkSize || 5_242_880; // 5MB default
1384
+ * uploadInParallel(file, chunkSize);
1385
+ * } else {
1386
+ * // Use single upload
1387
+ * uploadAsSingleChunk(file);
1388
+ * }
1389
+ * ```
1390
+ */
1391
+ type DataStoreCapabilities = {
1392
+ supportsParallelUploads: boolean;
1393
+ supportsConcatenation: boolean;
1394
+ supportsDeferredLength: boolean;
1395
+ supportsResumableUploads: boolean;
1396
+ supportsTransactionalUploads: boolean;
1397
+ maxConcurrentUploads?: number;
1398
+ minChunkSize?: number;
1399
+ maxChunkSize?: number;
1400
+ maxParts?: number;
1401
+ optimalChunkSize?: number;
1402
+ requiresOrderedChunks: boolean;
1403
+ requiresMimeTypeValidation?: boolean;
1404
+ maxValidationSize?: number;
1405
+ };
1406
+ /**
1407
+ * Core interface for all storage backend implementations.
1408
+ *
1409
+ * DataStore abstracts file storage operations across different backends
1410
+ * (S3, Azure Blob, GCS, local filesystem, etc.). All storage adapters
1411
+ * must implement this interface.
1412
+ *
1413
+ * @template TData - The data type stored (typically UploadFile)
1414
+ *
1415
+ * @property bucket - Optional storage bucket or container name
1416
+ * @property path - Optional base path prefix for all stored files
1417
+ * @property create - Creates a new file record in storage
1418
+ * @property remove - Deletes a file from storage
1419
+ * @property read - Reads complete file contents as bytes
1420
+ * @property write - Writes data stream to storage at specified offset
1421
+ * @property deleteExpired - Optional cleanup of expired files
1422
+ * @property getCapabilities - Returns storage backend capabilities
1423
+ * @property validateUploadStrategy - Validates if strategy is supported
1424
+ *
1425
+ * @example
1426
+ * ```typescript
1427
+ * // Implement a custom DataStore
1428
+ * const myDataStore: DataStore<UploadFile> = {
1429
+ * bucket: "my-uploads",
1430
+ * path: "files/",
1431
+ *
1432
+ * create: (file) => Effect.gen(function* () {
1433
+ * // Store file metadata
1434
+ * yield* saveMetadata(file);
1435
+ * return file;
1436
+ * }),
1437
+ *
1438
+ * write: ({ file_id, stream, offset }, { onProgress }) => Effect.gen(function* () {
1439
+ * // Write chunks to storage
1440
+ * let bytesWritten = offset;
1441
+ * yield* Stream.runForEach(stream, (chunk) => Effect.sync(() => {
1442
+ * writeChunk(file_id, chunk, bytesWritten);
1443
+ * bytesWritten += chunk.byteLength;
1444
+ * onProgress?.(chunk.byteLength);
1445
+ * }));
1446
+ * return bytesWritten;
1447
+ * }),
1448
+ *
1449
+ * read: (file_id) => Effect.gen(function* () {
1450
+ * // Read complete file
1451
+ * const data = yield* readFromStorage(file_id);
1452
+ * return data;
1453
+ * }),
1454
+ *
1455
+ * remove: (file_id) => Effect.gen(function* () {
1456
+ * yield* deleteFromStorage(file_id);
1457
+ * }),
1458
+ *
1459
+ * getCapabilities: () => ({
1460
+ * supportsParallelUploads: true,
1461
+ * supportsConcatenation: false,
1462
+ * supportsDeferredLength: true,
1463
+ * supportsResumableUploads: true,
1464
+ * supportsTransactionalUploads: false,
1465
+ * maxConcurrentUploads: 10,
1466
+ * optimalChunkSize: 5_242_880, // 5MB
1467
+ * requiresOrderedChunks: false,
1468
+ * }),
1469
+ *
1470
+ * validateUploadStrategy: (strategy) =>
1471
+ * Effect.succeed(strategy === "parallel" || strategy === "single"),
1472
+ * };
1473
+ * ```
1474
+ */
1475
+ type DataStore<TData = unknown> = {
1476
+ readonly bucket?: string;
1477
+ readonly path?: string;
1478
+ readonly create: (file: TData) => Effect.Effect<TData, UploadistaError$1>;
1479
+ readonly remove: (file_id: string) => Effect.Effect<void, UploadistaError$1>;
1480
+ readonly read: (file_id: string) => Effect.Effect<Uint8Array, UploadistaError$1>;
1481
+ readonly write: (options: DataStoreWriteOptions, dependencies: {
1482
+ onProgress?: (chunkSize: number) => void;
1483
+ }) => Effect.Effect<number, UploadistaError$1>;
1484
+ readonly deleteExpired?: Effect.Effect<number, UploadistaError$1>;
1485
+ readonly getCapabilities: () => DataStoreCapabilities;
1486
+ readonly validateUploadStrategy: (strategy: UploadStrategy) => Effect.Effect<boolean, never>;
1487
+ };
1488
+ declare const UploadFileDataStore_base: Context.TagClass<UploadFileDataStore, "UploadFileDataStore", DataStore<UploadFile>>;
1489
+ /**
1490
+ * Effect-TS context tag for UploadFile DataStore.
1491
+ *
1492
+ * Use this tag to access the primary DataStore in an Effect context.
1493
+ * This is the standard storage backend for uploaded files.
1494
+ *
1495
+ * @example
1496
+ * ```typescript
1497
+ * const uploadEffect = Effect.gen(function* () {
1498
+ * const dataStore = yield* UploadFileDataStore;
1499
+ * const file = yield* dataStore.create(uploadFile);
1500
+ * return file;
1501
+ * });
1502
+ * ```
1503
+ */
1504
+ declare class UploadFileDataStore extends UploadFileDataStore_base {}
1505
+ declare const BufferedUploadFileDataStore_base: Context.TagClass<BufferedUploadFileDataStore, "BufferedUploadFileDataStore", DataStore<UploadFile>>;
1506
+ /**
1507
+ * Effect-TS context tag for buffered/temporary DataStore.
1508
+ *
1509
+ * This is an optional storage backend used for temporary or intermediate files
1510
+ * during flow processing. Not all implementations provide a buffered store.
1511
+ *
1512
+ * @example
1513
+ * ```typescript
1514
+ * const processEffect = Effect.gen(function* () {
1515
+ * const bufferedStore = yield* BufferedUploadFileDataStore;
1516
+ * // Store intermediate processing results
1517
+ * const tempFile = yield* bufferedStore.create(intermediateFile);
1518
+ * return tempFile;
1519
+ * });
1520
+ * ```
1521
+ */
1522
+ declare class BufferedUploadFileDataStore extends BufferedUploadFileDataStore_base {}
1523
+ /**
1524
+ * Service interface for managing multiple DataStore instances.
1525
+ *
1526
+ * This allows routing files to different storage backends based on
1527
+ * storageId (e.g., different S3 buckets, Azure containers, or storage tiers).
1528
+ *
1529
+ * @property getDataStore - Retrieves the appropriate DataStore for a given storage ID
1530
+ * @property bufferedDataStore - Optional temporary storage for intermediate files
1531
+ */
1532
+ type UploadFileDataStoresShape = {
1533
+ getDataStore: (storageId: string, clientId: string | null) => Effect.Effect<DataStore<UploadFile>, UploadistaError$1>;
1534
+ bufferedDataStore: Effect.Effect<DataStore<UploadFile> | undefined, UploadistaError$1>;
1535
+ };
1536
+ declare const UploadFileDataStores_base: Context.TagClass<UploadFileDataStores, "UploadFileDataStores", UploadFileDataStoresShape>;
1537
+ /**
1538
+ * Effect-TS context tag for the DataStore routing service.
1539
+ *
1540
+ * Provides access to multiple DataStore instances with routing logic.
1541
+ *
1542
+ * @example
1543
+ * ```typescript
1544
+ * const uploadEffect = Effect.gen(function* () {
1545
+ * const dataStores = yield* UploadFileDataStores;
1546
+ * // Route to specific storage based on storageId
1547
+ * const dataStore = yield* dataStores.getDataStore("s3-production", clientId);
1548
+ * const file = yield* dataStore.create(uploadFile);
1549
+ * return file;
1550
+ * });
1551
+ * ```
1552
+ */
1553
+ declare class UploadFileDataStores extends UploadFileDataStores_base {}
1554
+ /**
1555
+ * Simplified DataStore configuration for easy setup.
1556
+ *
1557
+ * This type allows flexible configuration:
1558
+ * - Single DataStore instance
1559
+ * - Multiple named stores with routing
1560
+ * - Effect that resolves to a DataStore
1561
+ * - Pre-built Effect Layer
1562
+ *
1563
+ * @example
1564
+ * ```typescript
1565
+ * // Single store
1566
+ * const config: DataStoreConfig = s3DataStore;
1567
+ *
1568
+ * // Multiple stores with routing
1569
+ * const config: DataStoreConfig = {
1570
+ * stores: {
1571
+ * "s3-prod": s3ProdStore,
1572
+ * "s3-dev": s3DevStore,
1573
+ * "local": localFileStore,
1574
+ * },
1575
+ * default: "s3-prod"
1576
+ * };
1577
+ *
1578
+ * // Effect that creates a store
1579
+ * const config: DataStoreConfig = Effect.gen(function* () {
1580
+ * const kvStore = yield* UploadFileKVStore;
1581
+ * return createS3Store(kvStore);
1582
+ * });
1583
+ *
1584
+ * // Pre-built Layer
1585
+ * const config: DataStoreConfig = Layer.succeed(UploadFileDataStores, {...});
1586
+ * ```
1587
+ */
1588
+ type DataStoreConfig = DataStore<UploadFile> | Effect.Effect<DataStore<UploadFile>, never, UploadFileKVStore> | {
1589
+ stores: Record<string, DataStore<UploadFile> | Effect.Effect<DataStore<UploadFile>, never, UploadFileKVStore>>;
1590
+ default?: string;
1591
+ } | Layer.Layer<UploadFileDataStores, never, UploadFileKVStore>;
1592
+ /**
1593
+ * Type guard to check if a value is a DataStore instance.
1594
+ *
1595
+ * @param config - The value to check
1596
+ * @returns True if the value is a DataStore
1597
+ *
1598
+ * @example
1599
+ * ```typescript
1600
+ * if (isDataStore(config)) {
1601
+ * const capabilities = config.getCapabilities();
1602
+ * }
1603
+ * ```
1604
+ */
1605
+ declare const isDataStore: (config: DataStoreConfig) => config is DataStore<UploadFile>;
1606
+ /**
1607
+ * Creates an Effect Layer from simplified DataStoreConfig.
1608
+ *
1609
+ * This function converts any DataStoreConfig format into a proper Effect Layer
1610
+ * that can be provided to the UploadFileDataStores context tag.
1611
+ *
1612
+ * It handles:
1613
+ * - Single DataStore: Wraps in a Layer that always returns that store
1614
+ * - Multiple stores: Creates routing logic with optional default
1615
+ * - Effect<DataStore>: Executes the Effect and wraps the result
1616
+ * - Layer: Returns as-is
1617
+ *
1618
+ * @param config - The DataStore configuration
1619
+ * @returns A Layer that provides UploadFileDataStores service
1620
+ *
1621
+ * @example
1622
+ * ```typescript
1623
+ * // Create from single store
1624
+ * const layer = await createDataStoreLayer(s3DataStore);
1625
+ *
1626
+ * // Create from multiple stores
1627
+ * const layer = await createDataStoreLayer({
1628
+ * stores: {
1629
+ * "production": s3Store,
1630
+ * "development": localStore,
1631
+ * },
1632
+ * default: "development"
1633
+ * });
1634
+ *
1635
+ * // Use the layer
1636
+ * const program = Effect.gen(function* () {
1637
+ * const stores = yield* UploadFileDataStores;
1638
+ * const store = yield* stores.getDataStore("production", null);
1639
+ * return store;
1640
+ * }).pipe(Effect.provide(layer));
1641
+ * ```
1642
+ */
1643
+ declare const createDataStoreLayer: (config: DataStoreConfig) => Promise<Layer.Layer<UploadFileDataStores, never, UploadFileKVStore>>;
1644
+ //#endregion
1645
+ //#region src/types/event-broadcaster.d.ts
1646
+ /**
1647
+ * Event broadcaster interface for pub/sub messaging across distributed instances.
1648
+ * Used by WebSocketManager to broadcast upload events to all connected instances.
1649
+ */
1650
+ interface EventBroadcaster {
1651
+ /**
1652
+ * Publish a message to a channel
1653
+ */
1654
+ readonly publish: (channel: string, message: string) => Effect.Effect<void, UploadistaError$1>;
1655
+ /**
1656
+ * Subscribe to messages on a channel
1657
+ */
1658
+ readonly subscribe: (channel: string, handler: (message: string) => void) => Effect.Effect<void, UploadistaError$1>;
1659
+ /**
1660
+ * Unsubscribe from a channel (optional - not all implementations may support)
1661
+ */
1662
+ readonly unsubscribe?: (channel: string) => Effect.Effect<void, UploadistaError$1>;
1663
+ }
1664
+ declare const EventBroadcasterService_base: Context.TagClass<EventBroadcasterService, "EventBroadcaster", EventBroadcaster>;
1665
+ /**
1666
+ * Context tag for EventBroadcaster service
1667
+ */
1668
+ declare class EventBroadcasterService extends EventBroadcasterService_base {}
1669
+ //#endregion
1670
+ //#region src/types/upload-event.d.ts
1671
+ declare enum UploadEventType {
1672
+ UPLOAD_STARTED = "upload-started",
1673
+ UPLOAD_PROGRESS = "upload-progress",
1674
+ UPLOAD_COMPLETE = "upload-complete",
1675
+ UPLOAD_FAILED = "upload-failed",
1676
+ UPLOAD_VALIDATION_SUCCESS = "upload-validation-success",
1677
+ UPLOAD_VALIDATION_FAILED = "upload-validation-failed",
1678
+ UPLOAD_VALIDATION_WARNING = "upload-validation-warning",
1679
+ }
1680
+ declare const uploadEventSchema: z.ZodUnion<readonly [z.ZodObject<{
1681
+ type: z.ZodUnion<readonly [z.ZodLiteral<UploadEventType.UPLOAD_STARTED>, z.ZodLiteral<UploadEventType.UPLOAD_COMPLETE>]>;
1682
+ data: z.ZodObject<{
1683
+ id: z.ZodString;
1684
+ size: z.ZodOptional<z.ZodNumber>;
1685
+ offset: z.ZodNumber;
1686
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
1687
+ creationDate: z.ZodOptional<z.ZodString>;
1688
+ url: z.ZodOptional<z.ZodString>;
1689
+ sizeIsDeferred: z.ZodOptional<z.ZodBoolean>;
1690
+ checksum: z.ZodOptional<z.ZodString>;
1691
+ checksumAlgorithm: z.ZodOptional<z.ZodString>;
1692
+ storage: z.ZodObject<{
1693
+ id: z.ZodString;
1694
+ type: z.ZodString;
1695
+ path: z.ZodOptional<z.ZodString>;
1696
+ uploadId: z.ZodOptional<z.ZodString>;
1697
+ bucket: z.ZodOptional<z.ZodString>;
1698
+ }, z.core.$strip>;
1699
+ flow: z.ZodOptional<z.ZodObject<{
1700
+ flowId: z.ZodString;
1701
+ nodeId: z.ZodString;
1702
+ jobId: z.ZodString;
1703
+ }, z.core.$strip>>;
1704
+ }, z.core.$strip>;
1705
+ flow: z.ZodOptional<z.ZodObject<{
1706
+ flowId: z.ZodString;
1707
+ nodeId: z.ZodString;
1708
+ jobId: z.ZodString;
1709
+ }, z.core.$strip>>;
1710
+ }, z.core.$strip>, z.ZodObject<{
1711
+ type: z.ZodLiteral<UploadEventType.UPLOAD_PROGRESS>;
1712
+ data: z.ZodObject<{
1713
+ id: z.ZodString;
1714
+ progress: z.ZodNumber;
1715
+ total: z.ZodNumber;
1716
+ }, z.core.$strip>;
1717
+ flow: z.ZodOptional<z.ZodObject<{
1718
+ flowId: z.ZodString;
1719
+ nodeId: z.ZodString;
1720
+ jobId: z.ZodString;
1721
+ }, z.core.$strip>>;
1722
+ }, z.core.$strip>, z.ZodObject<{
1723
+ type: z.ZodLiteral<UploadEventType.UPLOAD_FAILED>;
1724
+ data: z.ZodObject<{
1725
+ id: z.ZodString;
1726
+ error: z.ZodString;
1727
+ }, z.core.$strip>;
1728
+ flow: z.ZodOptional<z.ZodObject<{
1729
+ flowId: z.ZodString;
1730
+ nodeId: z.ZodString;
1731
+ jobId: z.ZodString;
1732
+ }, z.core.$strip>>;
1733
+ }, z.core.$strip>, z.ZodObject<{
1734
+ type: z.ZodLiteral<UploadEventType.UPLOAD_VALIDATION_SUCCESS>;
1735
+ data: z.ZodObject<{
1736
+ id: z.ZodString;
1737
+ validationType: z.ZodEnum<{
1738
+ checksum: "checksum";
1739
+ mimetype: "mimetype";
1740
+ }>;
1741
+ algorithm: z.ZodOptional<z.ZodString>;
1742
+ }, z.core.$strip>;
1743
+ flow: z.ZodOptional<z.ZodObject<{
1744
+ flowId: z.ZodString;
1745
+ nodeId: z.ZodString;
1746
+ jobId: z.ZodString;
1747
+ }, z.core.$strip>>;
1748
+ }, z.core.$strip>, z.ZodObject<{
1749
+ type: z.ZodLiteral<UploadEventType.UPLOAD_VALIDATION_FAILED>;
1750
+ data: z.ZodObject<{
1751
+ id: z.ZodString;
1752
+ reason: z.ZodString;
1753
+ expected: z.ZodString;
1754
+ actual: z.ZodString;
1755
+ }, z.core.$strip>;
1756
+ flow: z.ZodOptional<z.ZodObject<{
1757
+ flowId: z.ZodString;
1758
+ nodeId: z.ZodString;
1759
+ jobId: z.ZodString;
1760
+ }, z.core.$strip>>;
1761
+ }, z.core.$strip>, z.ZodObject<{
1762
+ type: z.ZodLiteral<UploadEventType.UPLOAD_VALIDATION_WARNING>;
1763
+ data: z.ZodObject<{
1764
+ id: z.ZodString;
1765
+ message: z.ZodString;
1766
+ }, z.core.$strip>;
1767
+ flow: z.ZodOptional<z.ZodObject<{
1768
+ flowId: z.ZodString;
1769
+ nodeId: z.ZodString;
1770
+ jobId: z.ZodString;
1771
+ }, z.core.$strip>>;
1772
+ }, z.core.$strip>]>;
1773
+ type UploadEvent = z.infer<typeof uploadEventSchema>;
1774
+ //#endregion
1775
+ //#region src/types/websocket.d.ts
1776
+ /**
1777
+ * Platform-agnostic WebSocket connection interface
1778
+ */
1779
+ interface WebSocketConnection {
1780
+ send(data: string): void;
1781
+ close(code?: number, reason?: string): void;
1782
+ readonly readyState: number;
1783
+ readonly id: string;
1784
+ }
1785
+ /**
1786
+ * WebSocket message that can be sent/received
1787
+ */
1788
+ declare const webSocketMessageSchema: z$1.ZodUnion<readonly [z$1.ZodObject<{
1789
+ type: z$1.ZodLiteral<"upload_event">;
1790
+ payload: z$1.ZodUnion<readonly [z$1.ZodObject<{
1791
+ type: z$1.ZodUnion<readonly [z$1.ZodLiteral<UploadEventType.UPLOAD_STARTED>, z$1.ZodLiteral<UploadEventType.UPLOAD_COMPLETE>]>;
1792
+ data: z$1.ZodObject<{
1793
+ id: z$1.ZodString;
1794
+ size: z$1.ZodOptional<z$1.ZodNumber>;
1795
+ offset: z$1.ZodNumber;
1796
+ metadata: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodNumber, z$1.ZodBoolean]>>>;
1797
+ creationDate: z$1.ZodOptional<z$1.ZodString>;
1798
+ url: z$1.ZodOptional<z$1.ZodString>;
1799
+ sizeIsDeferred: z$1.ZodOptional<z$1.ZodBoolean>;
1800
+ checksum: z$1.ZodOptional<z$1.ZodString>;
1801
+ checksumAlgorithm: z$1.ZodOptional<z$1.ZodString>;
1802
+ storage: z$1.ZodObject<{
1803
+ id: z$1.ZodString;
1804
+ type: z$1.ZodString;
1805
+ path: z$1.ZodOptional<z$1.ZodString>;
1806
+ uploadId: z$1.ZodOptional<z$1.ZodString>;
1807
+ bucket: z$1.ZodOptional<z$1.ZodString>;
1808
+ }, z$1.core.$strip>;
1809
+ flow: z$1.ZodOptional<z$1.ZodObject<{
1810
+ flowId: z$1.ZodString;
1811
+ nodeId: z$1.ZodString;
1812
+ jobId: z$1.ZodString;
1813
+ }, z$1.core.$strip>>;
1814
+ }, z$1.core.$strip>;
1815
+ flow: z$1.ZodOptional<z$1.ZodObject<{
1816
+ flowId: z$1.ZodString;
1817
+ nodeId: z$1.ZodString;
1818
+ jobId: z$1.ZodString;
1819
+ }, z$1.core.$strip>>;
1820
+ }, z$1.core.$strip>, z$1.ZodObject<{
1821
+ type: z$1.ZodLiteral<UploadEventType.UPLOAD_PROGRESS>;
1822
+ data: z$1.ZodObject<{
1823
+ id: z$1.ZodString;
1824
+ progress: z$1.ZodNumber;
1825
+ total: z$1.ZodNumber;
1826
+ }, z$1.core.$strip>;
1827
+ flow: z$1.ZodOptional<z$1.ZodObject<{
1828
+ flowId: z$1.ZodString;
1829
+ nodeId: z$1.ZodString;
1830
+ jobId: z$1.ZodString;
1831
+ }, z$1.core.$strip>>;
1832
+ }, z$1.core.$strip>, z$1.ZodObject<{
1833
+ type: z$1.ZodLiteral<UploadEventType.UPLOAD_FAILED>;
1834
+ data: z$1.ZodObject<{
1835
+ id: z$1.ZodString;
1836
+ error: z$1.ZodString;
1837
+ }, z$1.core.$strip>;
1838
+ flow: z$1.ZodOptional<z$1.ZodObject<{
1839
+ flowId: z$1.ZodString;
1840
+ nodeId: z$1.ZodString;
1841
+ jobId: z$1.ZodString;
1842
+ }, z$1.core.$strip>>;
1843
+ }, z$1.core.$strip>, z$1.ZodObject<{
1844
+ type: z$1.ZodLiteral<UploadEventType.UPLOAD_VALIDATION_SUCCESS>;
1845
+ data: z$1.ZodObject<{
1846
+ id: z$1.ZodString;
1847
+ validationType: z$1.ZodEnum<{
1848
+ checksum: "checksum";
1849
+ mimetype: "mimetype";
1850
+ }>;
1851
+ algorithm: z$1.ZodOptional<z$1.ZodString>;
1852
+ }, z$1.core.$strip>;
1853
+ flow: z$1.ZodOptional<z$1.ZodObject<{
1854
+ flowId: z$1.ZodString;
1855
+ nodeId: z$1.ZodString;
1856
+ jobId: z$1.ZodString;
1857
+ }, z$1.core.$strip>>;
1858
+ }, z$1.core.$strip>, z$1.ZodObject<{
1859
+ type: z$1.ZodLiteral<UploadEventType.UPLOAD_VALIDATION_FAILED>;
1860
+ data: z$1.ZodObject<{
1861
+ id: z$1.ZodString;
1862
+ reason: z$1.ZodString;
1863
+ expected: z$1.ZodString;
1864
+ actual: z$1.ZodString;
1865
+ }, z$1.core.$strip>;
1866
+ flow: z$1.ZodOptional<z$1.ZodObject<{
1867
+ flowId: z$1.ZodString;
1868
+ nodeId: z$1.ZodString;
1869
+ jobId: z$1.ZodString;
1870
+ }, z$1.core.$strip>>;
1871
+ }, z$1.core.$strip>, z$1.ZodObject<{
1872
+ type: z$1.ZodLiteral<UploadEventType.UPLOAD_VALIDATION_WARNING>;
1873
+ data: z$1.ZodObject<{
1874
+ id: z$1.ZodString;
1875
+ message: z$1.ZodString;
1876
+ }, z$1.core.$strip>;
1877
+ flow: z$1.ZodOptional<z$1.ZodObject<{
1878
+ flowId: z$1.ZodString;
1879
+ nodeId: z$1.ZodString;
1880
+ jobId: z$1.ZodString;
1881
+ }, z$1.core.$strip>>;
1882
+ }, z$1.core.$strip>]>;
1883
+ timestamp: z$1.ZodOptional<z$1.ZodString>;
1884
+ }, z$1.core.$strip>, z$1.ZodObject<{
1885
+ type: z$1.ZodLiteral<"flow_event">;
1886
+ payload: z$1.ZodAny;
1887
+ timestamp: z$1.ZodOptional<z$1.ZodString>;
1888
+ }, z$1.core.$strip>, z$1.ZodObject<{
1889
+ type: z$1.ZodLiteral<"subscribed">;
1890
+ payload: z$1.ZodObject<{
1891
+ eventKey: z$1.ZodString;
1892
+ }, z$1.core.$strip>;
1893
+ timestamp: z$1.ZodOptional<z$1.ZodString>;
1894
+ }, z$1.core.$strip>, z$1.ZodObject<{
1895
+ type: z$1.ZodLiteral<"error">;
1896
+ message: z$1.ZodOptional<z$1.ZodString>;
1897
+ }, z$1.core.$strip>, z$1.ZodObject<{
1898
+ type: z$1.ZodLiteral<"pong">;
1899
+ timestamp: z$1.ZodOptional<z$1.ZodString>;
1900
+ }, z$1.core.$strip>, z$1.ZodObject<{
1901
+ type: z$1.ZodLiteral<"ping">;
1902
+ timestamp: z$1.ZodOptional<z$1.ZodString>;
1903
+ }, z$1.core.$strip>, z$1.ZodObject<{
1904
+ type: z$1.ZodLiteral<"connection">;
1905
+ message: z$1.ZodOptional<z$1.ZodString>;
1906
+ uploadId: z$1.ZodOptional<z$1.ZodString>;
1907
+ timestamp: z$1.ZodOptional<z$1.ZodString>;
1908
+ }, z$1.core.$strip>]>;
1909
+ type WebSocketMessage<TEvent = unknown> = z$1.infer<typeof webSocketMessageSchema> | {
1910
+ type: "upload_event";
1911
+ payload: TEvent;
1912
+ timestamp?: string;
1913
+ } | {
1914
+ type: "flow_event";
1915
+ payload: TEvent;
1916
+ timestamp?: string;
1917
+ };
1918
+ //#endregion
1919
+ //#region src/types/event-emitter.d.ts
1920
+ /**
1921
+ * Base event emitter interface for raw string message broadcasting.
1922
+ *
1923
+ * This is the low-level interface that event broadcasting implementations
1924
+ * (WebSocket, Server-Sent Events, etc.) implement. It emits raw string messages
1925
+ * without type safety or serialization.
1926
+ *
1927
+ * @property subscribe - Registers a WebSocket connection to receive events for a key
1928
+ * @property unsubscribe - Removes subscription for a key
1929
+ * @property emit - Broadcasts a string message to all subscribers of a key
1930
+ *
1931
+ * @example
1932
+ * ```typescript
1933
+ * // Implement BaseEventEmitter with WebSocket broadcast
1934
+ * const websocketEmitter: BaseEventEmitter = {
1935
+ * subscribe: (key, connection) => Effect.sync(() => {
1936
+ * connections.set(key, [...(connections.get(key) || []), connection]);
1937
+ * }),
1938
+ *
1939
+ * unsubscribe: (key) => Effect.sync(() => {
1940
+ * connections.delete(key);
1941
+ * }),
1942
+ *
1943
+ * emit: (key, event) => Effect.sync(() => {
1944
+ * const subs = connections.get(key) || [];
1945
+ * subs.forEach(conn => conn.send(event));
1946
+ * })
1947
+ * };
1948
+ * ```
1949
+ */
1950
+ interface BaseEventEmitter {
1951
+ readonly subscribe: (key: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError$1>;
1952
+ readonly unsubscribe: (key: string) => Effect.Effect<void, UploadistaError$1>;
1953
+ readonly emit: (key: string, event: string) => Effect.Effect<void, UploadistaError$1>;
1954
+ }
1955
+ /**
1956
+ * Type-safe event emitter interface with automatic serialization.
1957
+ *
1958
+ * This wraps a BaseEventEmitter and handles event serialization to JSON messages,
1959
+ * providing type safety for events and ensuring consistent message format.
1960
+ *
1961
+ * @template TEvent - The type of events emitted by this emitter
1962
+ *
1963
+ * @property subscribe - Registers a WebSocket connection to receive typed events
1964
+ * @property unsubscribe - Removes subscription
1965
+ * @property emit - Serializes and broadcasts a typed event
1966
+ *
1967
+ * @example
1968
+ * ```typescript
1969
+ * // Use a typed event emitter
1970
+ * const uploadEmitter: EventEmitter<UploadEvent> = new TypedEventEmitter(
1971
+ * baseEmitter,
1972
+ * (event) => JSON.stringify({ type: 'upload', payload: event })
1973
+ * );
1974
+ *
1975
+ * // Emit type-safe events
1976
+ * const program = Effect.gen(function* () {
1977
+ * const event: UploadEvent = {
1978
+ * uploadId: "upload123",
1979
+ * type: "progress",
1980
+ * offset: 1024,
1981
+ * size: 2048
1982
+ * };
1983
+ *
1984
+ * // Automatic serialization
1985
+ * yield* uploadEmitter.emit("upload123", event);
1986
+ * });
1987
+ * ```
1988
+ */
1989
+ type EventEmitter<TEvent> = {
1990
+ readonly subscribe: (key: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError$1>;
1991
+ readonly unsubscribe: (key: string) => Effect.Effect<void, UploadistaError$1>;
1992
+ readonly emit: (key: string, event: TEvent) => Effect.Effect<void, UploadistaError$1>;
1993
+ };
1994
+ /**
1995
+ * Typed wrapper class that adds event serialization to a BaseEventEmitter.
1996
+ *
1997
+ * This class implements the EventEmitter interface by wrapping a BaseEventEmitter
1998
+ * and handling serialization for a specific event type. It converts typed events
1999
+ * to JSON message strings before broadcasting.
2000
+ *
2001
+ * @template TEvent - The type of events to emit
2002
+ *
2003
+ * @example
2004
+ * ```typescript
2005
+ * // Create a typed emitter for UploadEvent
2006
+ * const uploadEmitter = new TypedEventEmitter<UploadEvent>(
2007
+ * baseEmitter,
2008
+ * (event) => JSON.stringify({
2009
+ * type: "upload_event",
2010
+ * payload: event,
2011
+ * timestamp: new Date().toISOString()
2012
+ * })
2013
+ * );
2014
+ *
2015
+ * // Use the emitter
2016
+ * const effect = Effect.gen(function* () {
2017
+ * // Subscribe a WebSocket connection
2018
+ * yield* uploadEmitter.subscribe("upload123", websocket);
2019
+ *
2020
+ * // Emit an event (automatically serialized)
2021
+ * yield* uploadEmitter.emit("upload123", {
2022
+ * uploadId: "upload123",
2023
+ * type: "completed",
2024
+ * offset: 2048,
2025
+ * size: 2048
2026
+ * });
2027
+ *
2028
+ * // Unsubscribe when done
2029
+ * yield* uploadEmitter.unsubscribe("upload123");
2030
+ * });
2031
+ *
2032
+ * // Custom message format
2033
+ * const customEmitter = new TypedEventEmitter<MyEvent>(
2034
+ * baseEmitter,
2035
+ * (event) => `EVENT:${event.type}:${JSON.stringify(event.data)}`
2036
+ * );
2037
+ * ```
2038
+ */
2039
+ declare class TypedEventEmitter<TEvent> implements EventEmitter<TEvent> {
2040
+ private baseEmitter;
2041
+ private eventToMessage;
2042
+ constructor(baseEmitter: BaseEventEmitter, eventToMessage: (event: TEvent) => string);
2043
+ subscribe: (key: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError$1>;
2044
+ unsubscribe: (key: string) => Effect.Effect<void, UploadistaError$1>;
2045
+ emit: (key: string, event: TEvent) => Effect.Effect<void, UploadistaError$1>;
2046
+ }
2047
+ /**
2048
+ * Default event-to-message serialization helper.
2049
+ *
2050
+ * Creates a standardized JSON message format with type, payload, and timestamp.
2051
+ * This is the recommended way to serialize events for WebSocket transmission.
2052
+ *
2053
+ * @param messageType - The message type identifier ("upload_event" or "flow_event")
2054
+ * @returns An object with an eventToMessage function
2055
+ *
2056
+ * @example
2057
+ * ```typescript
2058
+ * // Create emitter with standard serialization
2059
+ * const emitter = new TypedEventEmitter<UploadEvent>(
2060
+ * baseEmitter,
2061
+ * eventToMessageSerializer("upload_event").eventToMessage
2062
+ * );
2063
+ *
2064
+ * // Messages will be formatted as:
2065
+ * // {
2066
+ * // "type": "upload_event",
2067
+ * // "payload": { ...event data... },
2068
+ * // "timestamp": "2024-01-15T10:30:00.000Z"
2069
+ * // }
2070
+ * ```
2071
+ */
2072
+ declare const eventToMessageSerializer: (messageType: "upload_event" | "flow_event") => {
2073
+ eventToMessage: <T>(event: T) => string;
2074
+ };
2075
+ declare const BaseEventEmitterService_base: Context.TagClass<BaseEventEmitterService, "BaseEventEmitter", BaseEventEmitter>;
2076
+ /**
2077
+ * Effect-TS context tag for the base untyped event emitter.
2078
+ *
2079
+ * This is the low-level emitter that broadcasting implementations provide.
2080
+ * Most application code should use typed emitters like UploadEventEmitter instead.
2081
+ *
2082
+ * @example
2083
+ * ```typescript
2084
+ * // Provide a base emitter implementation
2085
+ * const baseEmitterLayer = Layer.succeed(BaseEventEmitterService, websocketEmitter);
2086
+ *
2087
+ * // Use in an Effect
2088
+ * const effect = Effect.gen(function* () {
2089
+ * const baseEmitter = yield* BaseEventEmitterService;
2090
+ * yield* baseEmitter.emit("channel1", "raw message");
2091
+ * });
2092
+ * ```
2093
+ */
2094
+ declare class BaseEventEmitterService extends BaseEventEmitterService_base {}
2095
+ declare const UploadEventEmitter_base: Context.TagClass<UploadEventEmitter, "UploadEventEmitter", EventEmitter<{
2096
+ type: UploadEventType.UPLOAD_STARTED | UploadEventType.UPLOAD_COMPLETE;
2097
+ data: {
2098
+ id: string;
2099
+ offset: number;
2100
+ storage: {
2101
+ id: string;
2102
+ type: string;
2103
+ path?: string | undefined;
2104
+ uploadId?: string | undefined;
2105
+ bucket?: string | undefined;
2106
+ };
2107
+ size?: number | undefined;
2108
+ metadata?: Record<string, string | number | boolean> | undefined;
2109
+ creationDate?: string | undefined;
2110
+ url?: string | undefined;
2111
+ sizeIsDeferred?: boolean | undefined;
2112
+ checksum?: string | undefined;
2113
+ checksumAlgorithm?: string | undefined;
2114
+ flow?: {
2115
+ flowId: string;
2116
+ nodeId: string;
2117
+ jobId: string;
2118
+ } | undefined;
2119
+ };
2120
+ flow?: {
2121
+ flowId: string;
2122
+ nodeId: string;
2123
+ jobId: string;
2124
+ } | undefined;
2125
+ } | {
2126
+ type: UploadEventType.UPLOAD_PROGRESS;
2127
+ data: {
2128
+ id: string;
2129
+ progress: number;
2130
+ total: number;
2131
+ };
2132
+ flow?: {
2133
+ flowId: string;
2134
+ nodeId: string;
2135
+ jobId: string;
2136
+ } | undefined;
2137
+ } | {
2138
+ type: UploadEventType.UPLOAD_FAILED;
2139
+ data: {
2140
+ id: string;
2141
+ error: string;
2142
+ };
2143
+ flow?: {
2144
+ flowId: string;
2145
+ nodeId: string;
2146
+ jobId: string;
2147
+ } | undefined;
2148
+ } | {
2149
+ type: UploadEventType.UPLOAD_VALIDATION_SUCCESS;
2150
+ data: {
2151
+ id: string;
2152
+ validationType: "checksum" | "mimetype";
2153
+ algorithm?: string | undefined;
2154
+ };
2155
+ flow?: {
2156
+ flowId: string;
2157
+ nodeId: string;
2158
+ jobId: string;
2159
+ } | undefined;
2160
+ } | {
2161
+ type: UploadEventType.UPLOAD_VALIDATION_FAILED;
2162
+ data: {
2163
+ id: string;
2164
+ reason: string;
2165
+ expected: string;
2166
+ actual: string;
2167
+ };
2168
+ flow?: {
2169
+ flowId: string;
2170
+ nodeId: string;
2171
+ jobId: string;
2172
+ } | undefined;
2173
+ } | {
2174
+ type: UploadEventType.UPLOAD_VALIDATION_WARNING;
2175
+ data: {
2176
+ id: string;
2177
+ message: string;
2178
+ };
2179
+ flow?: {
2180
+ flowId: string;
2181
+ nodeId: string;
2182
+ jobId: string;
2183
+ } | undefined;
2184
+ }>>;
2185
+ /**
2186
+ * Effect-TS context tag for the UploadEvent typed emitter.
2187
+ *
2188
+ * This provides type-safe event emission for upload progress and lifecycle events.
2189
+ * It's the primary way to broadcast upload events to connected clients.
2190
+ *
2191
+ * @example
2192
+ * ```typescript
2193
+ * const uploadEffect = Effect.gen(function* () {
2194
+ * const emitter = yield* UploadEventEmitter;
2195
+ *
2196
+ * // Subscribe a client to upload events
2197
+ * yield* emitter.subscribe("upload123", websocketConnection);
2198
+ *
2199
+ * // Emit progress event
2200
+ * yield* emitter.emit("upload123", {
2201
+ * uploadId: "upload123",
2202
+ * type: "progress",
2203
+ * offset: 512000,
2204
+ * size: 1024000
2205
+ * });
2206
+ *
2207
+ * // Emit completion event
2208
+ * yield* emitter.emit("upload123", {
2209
+ * uploadId: "upload123",
2210
+ * type: "completed",
2211
+ * offset: 1024000,
2212
+ * size: 1024000
2213
+ * });
2214
+ * });
2215
+ * ```
2216
+ */
2217
+ declare class UploadEventEmitter extends UploadEventEmitter_base {}
2218
+ /**
2219
+ * Effect Layer that creates the UploadEventEmitter from a BaseEventEmitter.
2220
+ *
2221
+ * This layer automatically wires up JSON serialization for UploadEvent objects
2222
+ * with the standard "upload_event" message format.
2223
+ *
2224
+ * @example
2225
+ * ```typescript
2226
+ * const program = Effect.gen(function* () {
2227
+ * const emitter = yield* UploadEventEmitter;
2228
+ * // Use the emitter...
2229
+ * }).pipe(
2230
+ * Effect.provide(uploadEventEmitter),
2231
+ * Effect.provide(baseEmitterLayer)
2232
+ * );
2233
+ * ```
2234
+ */
2235
+ declare const uploadEventEmitter: Layer.Layer<UploadEventEmitter, never, BaseEventEmitterService>;
2236
+ declare const FlowEventEmitter_base: Context.TagClass<FlowEventEmitter, "FlowEventEmitter", EventEmitter<FlowEvent>>;
2237
+ /**
2238
+ * Effect-TS context tag for the FlowEvent typed emitter.
2239
+ *
2240
+ * This provides type-safe event emission for flow processing lifecycle events.
2241
+ * It's used to broadcast flow execution progress, node completion, and errors.
2242
+ *
2243
+ * @example
2244
+ * ```typescript
2245
+ * const flowEffect = Effect.gen(function* () {
2246
+ * const emitter = yield* FlowEventEmitter;
2247
+ *
2248
+ * // Subscribe a client to flow job events
2249
+ * yield* emitter.subscribe("job123", websocketConnection);
2250
+ *
2251
+ * // Emit node start event
2252
+ * yield* emitter.emit("job123", {
2253
+ * jobId: "job123",
2254
+ * eventType: "NodeStart",
2255
+ * flowId: "flow_resize",
2256
+ * nodeId: "resize_1"
2257
+ * });
2258
+ *
2259
+ * // Emit node completion event
2260
+ * yield* emitter.emit("job123", {
2261
+ * jobId: "job123",
2262
+ * eventType: "NodeEnd",
2263
+ * flowId: "flow_resize",
2264
+ * nodeId: "resize_1",
2265
+ * result: { width: 800, height: 600 }
2266
+ * });
2267
+ * });
2268
+ * ```
2269
+ */
2270
+ declare class FlowEventEmitter extends FlowEventEmitter_base {}
2271
+ /**
2272
+ * Effect Layer that creates the FlowEventEmitter from a BaseEventEmitter.
2273
+ *
2274
+ * This layer automatically wires up JSON serialization for FlowEvent objects
2275
+ * with the standard "flow_event" message format.
2276
+ *
2277
+ * @example
2278
+ * ```typescript
2279
+ * const program = Effect.gen(function* () {
2280
+ * const emitter = yield* FlowEventEmitter;
2281
+ * // Use the emitter...
2282
+ * }).pipe(
2283
+ * Effect.provide(flowEventEmitter),
2284
+ * Effect.provide(baseEmitterLayer)
2285
+ * );
2286
+ * ```
2287
+ */
2288
+ declare const flowEventEmitter: Layer.Layer<FlowEventEmitter, never, BaseEventEmitterService>;
2289
+ //#endregion
2290
+ //#region src/types/input-file.d.ts
2291
+ /**
2292
+ * Zod schema for validating InputFile objects.
2293
+ *
2294
+ * This schema defines the structure and validation rules for file upload requests.
2295
+ * Use this schema to parse and validate input data when creating new uploads.
2296
+ *
2297
+ * @see {@link InputFile} for the TypeScript type
2298
+ */
2299
+ declare const inputFileSchema: z.ZodObject<{
2300
+ uploadLengthDeferred: z.ZodOptional<z.ZodBoolean>;
2301
+ storageId: z.ZodString;
2302
+ size: z.ZodNumber;
2303
+ type: z.ZodString;
2304
+ fileName: z.ZodOptional<z.ZodString>;
2305
+ lastModified: z.ZodOptional<z.ZodNumber>;
2306
+ metadata: z.ZodOptional<z.ZodString>;
2307
+ checksum: z.ZodOptional<z.ZodString>;
2308
+ checksumAlgorithm: z.ZodOptional<z.ZodString>;
2309
+ flow: z.ZodOptional<z.ZodObject<{
2310
+ flowId: z.ZodString;
2311
+ nodeId: z.ZodString;
2312
+ jobId: z.ZodString;
2313
+ }, z.core.$strip>>;
2314
+ }, z.core.$strip>;
2315
+ /**
2316
+ * Represents the input data for creating a new file upload.
2317
+ *
2318
+ * This type defines the information required to initiate an upload.
2319
+ * It's used by clients to provide upload metadata before sending file data.
2320
+ *
2321
+ * @property storageId - Target storage backend identifier (e.g., "s3-production", "azure-blob")
2322
+ * @property size - File size in bytes
2323
+ * @property type - MIME type of the file (e.g., "image/jpeg", "application/pdf")
2324
+ * @property uploadLengthDeferred - If true, file size is not known upfront (streaming upload)
2325
+ * @property fileName - Original filename from the client
2326
+ * @property lastModified - File's last modified timestamp in milliseconds since epoch
2327
+ * @property metadata - Base64-encoded metadata string (as per tus protocol)
2328
+ * @property checksum - Expected file checksum for validation
2329
+ * @property checksumAlgorithm - Algorithm used for checksum (e.g., "md5", "sha256")
2330
+ * @property flow - Optional flow processing configuration
2331
+ * @property flow.flowId - ID of the flow to execute on this file
2332
+ * @property flow.nodeId - Starting node ID in the flow
2333
+ * @property flow.jobId - Flow job execution ID
2334
+ *
2335
+ * @example
2336
+ * ```typescript
2337
+ * // Basic file upload
2338
+ * const inputFile: InputFile = {
2339
+ * storageId: "s3-production",
2340
+ * size: 1024000,
2341
+ * type: "image/jpeg",
2342
+ * fileName: "photo.jpg",
2343
+ * lastModified: Date.now()
2344
+ * };
2345
+ *
2346
+ * // Upload with metadata (base64 encoded as per tus protocol)
2347
+ * const metadata = btoa(JSON.stringify({
2348
+ * userId: "user_123",
2349
+ * albumId: "album_456"
2350
+ * }));
2351
+ * const inputWithMetadata: InputFile = {
2352
+ * storageId: "s3-production",
2353
+ * size: 2048000,
2354
+ * type: "image/png",
2355
+ * fileName: "screenshot.png",
2356
+ * metadata
2357
+ * };
2358
+ *
2359
+ * // Upload with checksum validation
2360
+ * const inputWithChecksum: InputFile = {
2361
+ * storageId: "s3-production",
2362
+ * size: 512000,
2363
+ * type: "application/pdf",
2364
+ * fileName: "document.pdf",
2365
+ * checksum: "5d41402abc4b2a76b9719d911017c592",
2366
+ * checksumAlgorithm: "md5"
2367
+ * };
2368
+ *
2369
+ * // Upload that triggers a flow
2370
+ * const inputWithFlow: InputFile = {
2371
+ * storageId: "s3-temp",
2372
+ * size: 4096000,
2373
+ * type: "image/jpeg",
2374
+ * fileName: "large-image.jpg",
2375
+ * flow: {
2376
+ * flowId: "resize-and-optimize",
2377
+ * nodeId: "input_1",
2378
+ * jobId: "job_789"
2379
+ * }
2380
+ * };
2381
+ *
2382
+ * // Streaming upload (size unknown)
2383
+ * const streamingInput: InputFile = {
2384
+ * storageId: "s3-production",
2385
+ * size: 0, // Will be updated as data arrives
2386
+ * type: "video/mp4",
2387
+ * uploadLengthDeferred: true,
2388
+ * fileName: "live-stream.mp4"
2389
+ * };
2390
+ * ```
2391
+ */
2392
+ type InputFile = z.infer<typeof inputFileSchema>;
2393
+ //#endregion
2394
+ //#region src/types/middleware.d.ts
2395
+ type MiddlewareContext = {
2396
+ request: Request;
2397
+ uploadId?: string;
2398
+ metadata?: Record<string, string>;
2399
+ };
2400
+ type MiddlewareNext = () => Promise<Response>;
2401
+ type Middleware = (context: MiddlewareContext, next: MiddlewareNext) => Promise<Response>;
2402
+ declare const MiddlewareService_base: Context.TagClass<MiddlewareService, "MiddlewareService", {
2403
+ readonly execute: (middlewares: Middleware[], context: MiddlewareContext, handler: MiddlewareNext) => Effect.Effect<Response, UploadistaError$1>;
2404
+ }>;
2405
+ declare class MiddlewareService extends MiddlewareService_base {}
2406
+ declare const MiddlewareServiceLive: Layer.Layer<MiddlewareService, never, never>;
2407
+ //#endregion
2408
+ //#region src/upload/mime.d.ts
2409
+ /**
2410
+ * Detect MIME type from buffer using magic bytes (file signatures).
2411
+ * Supports a wide range of common file types including images, videos, audio, documents, and archives.
2412
+ *
2413
+ * @param buffer - File content as Uint8Array
2414
+ * @param filename - Optional filename for extension-based fallback
2415
+ * @returns Detected MIME type or "application/octet-stream" if unknown
2416
+ */
2417
+ declare const detectMimeType: (buffer: Uint8Array, filename?: string) => string;
2418
+ /**
2419
+ * Compare two MIME types with lenient matching.
2420
+ * Matches on major type (e.g., "image/*") to allow for minor variations.
2421
+ *
2422
+ * @param declared - MIME type provided by client
2423
+ * @param detected - MIME type detected from file content
2424
+ * @returns true if MIME types are compatible
2425
+ *
2426
+ * @example
2427
+ * compareMimeTypes("image/png", "image/apng") // true
2428
+ * compareMimeTypes("image/jpeg", "image/png") // true (both images)
2429
+ * compareMimeTypes("image/png", "application/pdf") // false
2430
+ */
2431
+ declare function compareMimeTypes(declared: string, detected: string): boolean;
2432
+ //#endregion
2433
+ //#region src/upload/upload-server.d.ts
2434
+ /**
2435
+ * Legacy configuration options for UploadServer.
2436
+ *
2437
+ * @deprecated Use Effect Layers instead of this configuration object.
2438
+ * This type is kept for backward compatibility.
2439
+ *
2440
+ * @property dataStore - DataStore instance or factory function
2441
+ * @property kvStore - KV store for upload metadata
2442
+ * @property eventEmitter - Event emitter for upload progress
2443
+ * @property generateId - Optional ID generator (defaults to UUID)
2444
+ * @property middlewares - Optional request middlewares
2445
+ * @property withTracing - Enable Effect tracing for debugging
2446
+ */
2447
+ type UploadServerOptions = {
2448
+ dataStore: ((storageId: string) => Promise<DataStore<UploadFile>>) | DataStore<UploadFile>;
2449
+ kvStore: KvStore<UploadFile>;
2450
+ eventEmitter: EventEmitter<UploadEvent>;
2451
+ generateId?: GenerateIdShape;
2452
+ middlewares?: Middleware[];
2453
+ withTracing?: boolean;
2454
+ };
2455
+ /**
2456
+ * UploadServer service interface.
2457
+ *
2458
+ * This is the core upload handling service that provides all file upload operations.
2459
+ * It manages upload lifecycle, resumable uploads, progress tracking, and storage integration.
2460
+ *
2461
+ * All operations return Effect types for composable, type-safe error handling.
2462
+ *
2463
+ * @property createUpload - Initiates a new upload and returns metadata
2464
+ * @property uploadChunk - Uploads a chunk of data for an existing upload
2465
+ * @property getCapabilities - Returns storage backend capabilities
2466
+ * @property upload - Complete upload in one operation (create + upload data)
2467
+ * @property uploadFromUrl - Uploads a file from a remote URL
2468
+ * @property getUpload - Retrieves upload metadata by ID
2469
+ * @property read - Reads the complete uploaded file data
2470
+ * @property delete - Deletes an upload and its data
2471
+ * @property subscribeToUploadEvents - Subscribes WebSocket to upload progress events
2472
+ * @property unsubscribeFromUploadEvents - Unsubscribes from upload events
2473
+ *
2474
+ * @example
2475
+ * ```typescript
2476
+ * // Basic upload flow
2477
+ * const program = Effect.gen(function* () {
2478
+ * const server = yield* UploadServer;
2479
+ *
2480
+ * // 1. Create upload
2481
+ * const inputFile: InputFile = {
2482
+ * storageId: "s3-production",
2483
+ * size: 1024000,
2484
+ * type: "image/jpeg",
2485
+ * fileName: "photo.jpg"
2486
+ * };
2487
+ * const upload = yield* server.createUpload(inputFile, "client123");
2488
+ *
2489
+ * // 2. Upload chunks
2490
+ * const chunk = new ReadableStream(...);
2491
+ * const updated = yield* server.uploadChunk(upload.id, "client123", chunk);
2492
+ *
2493
+ * // 3. Read the uploaded file
2494
+ * const data = yield* server.read(upload.id, "client123");
2495
+ *
2496
+ * return upload;
2497
+ * });
2498
+ *
2499
+ * // Upload with WebSocket progress tracking
2500
+ * const uploadWithProgress = Effect.gen(function* () {
2501
+ * const server = yield* UploadServer;
2502
+ *
2503
+ * // Subscribe to progress events
2504
+ * yield* server.subscribeToUploadEvents(uploadId, websocket);
2505
+ *
2506
+ * // Upload (events will be emitted automatically)
2507
+ * const result = yield* server.upload(inputFile, clientId, stream);
2508
+ *
2509
+ * // Unsubscribe when done
2510
+ * yield* server.unsubscribeFromUploadEvents(uploadId);
2511
+ *
2512
+ * return result;
2513
+ * });
2514
+ *
2515
+ * // Upload from URL
2516
+ * const urlUpload = Effect.gen(function* () {
2517
+ * const server = yield* UploadServer;
2518
+ *
2519
+ * const inputFile: InputFile = {
2520
+ * storageId: "s3-production",
2521
+ * size: 0, // Unknown initially
2522
+ * type: "image/png",
2523
+ * fileName: "remote-image.png"
2524
+ * };
2525
+ *
2526
+ * const upload = yield* server.uploadFromUrl(
2527
+ * inputFile,
2528
+ * "client123",
2529
+ * "https://example.com/image.png"
2530
+ * );
2531
+ *
2532
+ * return upload;
2533
+ * });
2534
+ * ```
2535
+ */
2536
+ type UploadServerShape = {
2537
+ createUpload: (inputFile: InputFile, clientId: string | null) => Effect.Effect<UploadFile, UploadistaError$1>;
2538
+ uploadChunk: (uploadId: string, clientId: string | null, chunk: ReadableStream) => Effect.Effect<UploadFile, UploadistaError$1>;
2539
+ getCapabilities: (storageId: string, clientId: string | null) => Effect.Effect<DataStoreCapabilities, UploadistaError$1>;
2540
+ upload: (file: InputFile, clientId: string | null, stream: ReadableStream) => Effect.Effect<UploadFile, UploadistaError$1>;
2541
+ uploadFromUrl: (inputFile: InputFile, clientId: string | null, url: string) => Effect.Effect<UploadFile, UploadistaError$1>;
2542
+ getUpload: (uploadId: string) => Effect.Effect<UploadFile, UploadistaError$1>;
2543
+ read: (uploadId: string, clientId: string | null) => Effect.Effect<Uint8Array, UploadistaError$1>;
2544
+ delete: (uploadId: string, clientId: string | null) => Effect.Effect<void, UploadistaError$1>;
2545
+ subscribeToUploadEvents: (uploadId: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError$1>;
2546
+ unsubscribeFromUploadEvents: (uploadId: string) => Effect.Effect<void, UploadistaError$1>;
2547
+ };
2548
+ declare const UploadServer_base: Context.TagClass<UploadServer, "UploadServer", UploadServerShape>;
2549
+ /**
2550
+ * Effect-TS context tag for the UploadServer service.
2551
+ *
2552
+ * Use this tag to access the UploadServer in an Effect context.
2553
+ * The server must be provided via a Layer or dependency injection.
2554
+ *
2555
+ * @example
2556
+ * ```typescript
2557
+ * // Access UploadServer in an Effect
2558
+ * const uploadEffect = Effect.gen(function* () {
2559
+ * const server = yield* UploadServer;
2560
+ * const upload = yield* server.createUpload(inputFile, clientId);
2561
+ * return upload;
2562
+ * });
2563
+ *
2564
+ * // Provide UploadServer layer
2565
+ * const program = uploadEffect.pipe(
2566
+ * Effect.provide(uploadServer),
2567
+ * Effect.provide(uploadFileKvStore),
2568
+ * Effect.provide(dataStoreLayer),
2569
+ * Effect.provide(eventEmitterLayer)
2570
+ * );
2571
+ * ```
2572
+ */
2573
+ declare class UploadServer extends UploadServer_base {}
2574
+ /**
2575
+ * Creates the UploadServer implementation.
2576
+ *
2577
+ * This function constructs the UploadServer service by composing all required
2578
+ * dependencies (KV store, data stores, event emitter, ID generator). It implements
2579
+ * all upload operations defined in UploadServerShape.
2580
+ *
2581
+ * The server automatically handles:
2582
+ * - Upload lifecycle management (create, resume, complete)
2583
+ * - Progress tracking and event emission
2584
+ * - Storage backend routing based on storageId
2585
+ * - Error handling with proper UploadistaError types
2586
+ *
2587
+ * @returns An Effect that yields the UploadServerShape implementation
2588
+ *
2589
+ * @example
2590
+ * ```typescript
2591
+ * // Create a custom UploadServer layer
2592
+ * const myUploadServer = Layer.effect(
2593
+ * UploadServer,
2594
+ * createUploadServer()
2595
+ * );
2596
+ *
2597
+ * // Use in a program
2598
+ * const program = Effect.gen(function* () {
2599
+ * const server = yield* UploadServer;
2600
+ * // Use server operations...
2601
+ * }).pipe(Effect.provide(myUploadServer));
2602
+ * ```
2603
+ */
2604
+ declare function createUploadServer(): Effect.Effect<{
2605
+ upload: (inputFile: InputFile, clientId: string | null, stream: ReadableStream) => Effect.Effect<UploadFile, UploadistaError$1, never>;
2606
+ uploadFromUrl: (inputFile: InputFile, clientId: string | null, url: string) => Effect.Effect<UploadFile, UploadistaError$1, never>;
2607
+ createUpload: (inputFile: InputFile, clientId: string | null) => Effect.Effect<UploadFile, UploadistaError$1, never>;
2608
+ uploadChunk: (uploadId: string, clientId: string | null, chunk: ReadableStream) => Effect.Effect<UploadFile, UploadistaError$1, never>;
2609
+ getUpload: (uploadId: string) => Effect.Effect<UploadFile, UploadistaError$1, never>;
2610
+ read: (uploadId: string, clientId: string | null) => Effect.Effect<Uint8Array<ArrayBufferLike>, UploadistaError$1, never>;
2611
+ delete: (uploadId: string, clientId: string | null) => Effect.Effect<void, UploadistaError$1, never>;
2612
+ getCapabilities: (storageId: string, clientId: string | null) => Effect.Effect<DataStoreCapabilities, UploadistaError$1, never>;
2613
+ subscribeToUploadEvents: (uploadId: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError$1, never>;
2614
+ unsubscribeFromUploadEvents: (uploadId: string) => Effect.Effect<void, UploadistaError$1, never>;
2615
+ }, never, GenerateId | UploadFileDataStores | UploadFileKVStore | UploadEventEmitter>;
2616
+ /**
2617
+ * Pre-built UploadServer Effect Layer.
2618
+ *
2619
+ * This layer provides a ready-to-use UploadServer implementation that can be
2620
+ * composed with other layers to build a complete upload system.
2621
+ *
2622
+ * Required dependencies:
2623
+ * - UploadFileKVStore: For storing upload metadata
2624
+ * - UploadFileDataStores: For routing to storage backends
2625
+ * - UploadEventEmitter: For progress events
2626
+ * - GenerateId: For creating upload IDs
2627
+ *
2628
+ * @example
2629
+ * ```typescript
2630
+ * // Compose a complete upload system
2631
+ * const fullUploadSystem = Layer.mergeAll(
2632
+ * uploadServer,
2633
+ * uploadFileKvStore,
2634
+ * dataStoreLayer,
2635
+ * uploadEventEmitter,
2636
+ * generateIdLayer
2637
+ * );
2638
+ *
2639
+ * // Use in application
2640
+ * const app = Effect.gen(function* () {
2641
+ * const server = yield* UploadServer;
2642
+ * // Perform uploads...
2643
+ * }).pipe(Effect.provide(fullUploadSystem));
2644
+ * ```
2645
+ */
2646
+ declare const uploadServer: Layer.Layer<UploadServer, never, GenerateId | UploadFileDataStores | UploadFileKVStore | UploadEventEmitter>;
2647
+ //#endregion
2648
+ //#region src/upload/upload-strategy-negotiator.d.ts
2649
+ /**
2650
+ * Configuration options for upload strategy negotiation.
2651
+ *
2652
+ * @property fileSize - Size of the file to be uploaded in bytes
2653
+ * @property preferredStrategy - Preferred upload strategy (single, parallel, resumable)
2654
+ * @property preferredChunkSize - Preferred chunk size in bytes
2655
+ * @property parallelUploads - Number of parallel upload connections
2656
+ * @property minChunkSizeForParallel - Minimum file size to consider parallel uploads
2657
+ */
2658
+ type UploadStrategyOptions = {
2659
+ fileSize: number;
2660
+ preferredStrategy?: UploadStrategy;
2661
+ preferredChunkSize?: number;
2662
+ parallelUploads?: number;
2663
+ minChunkSizeForParallel?: number;
2664
+ };
2665
+ /**
2666
+ * Result of upload strategy negotiation.
2667
+ *
2668
+ * @property strategy - The negotiated upload strategy
2669
+ * @property chunkSize - The negotiated chunk size in bytes
2670
+ * @property parallelUploads - The negotiated number of parallel uploads
2671
+ * @property reasoning - Array of reasoning strings explaining the decisions
2672
+ * @property warnings - Array of warning messages about adjustments made
2673
+ */
2674
+ type NegotiatedStrategy = {
2675
+ strategy: UploadStrategy;
2676
+ chunkSize: number;
2677
+ parallelUploads: number;
2678
+ reasoning: string[];
2679
+ warnings: string[];
2680
+ };
2681
+ /**
2682
+ * Negotiates the optimal upload strategy based on data store capabilities and file characteristics.
2683
+ *
2684
+ * This class analyzes data store capabilities, file size, and user preferences to determine
2685
+ * the best upload strategy (single, parallel, resumable) and optimal parameters like chunk size
2686
+ * and parallel connection count.
2687
+ *
2688
+ * The negotiator considers:
2689
+ * - Data store capabilities (parallel uploads, resumable uploads, concatenation)
2690
+ * - File size and chunk size constraints
2691
+ * - User preferences and requirements
2692
+ * - Performance optimization opportunities
2693
+ *
2694
+ * @example
2695
+ * ```typescript
2696
+ * // Create negotiator for S3 data store
2697
+ * const negotiator = new UploadStrategyNegotiator(
2698
+ * s3Capabilities,
2699
+ * (strategy) => s3Capabilities.supportsStrategy(strategy)
2700
+ * );
2701
+ *
2702
+ * // Negotiate strategy for large file
2703
+ * const result = negotiator.negotiateStrategy({
2704
+ * fileSize: 100_000_000, // 100MB
2705
+ * preferredStrategy: "parallel",
2706
+ * preferredChunkSize: 5_000_000, // 5MB chunks
2707
+ * parallelUploads: 4
2708
+ * });
2709
+ *
2710
+ * console.log(result.strategy); // "parallel"
2711
+ * console.log(result.chunkSize); // 5_000_000
2712
+ * console.log(result.reasoning); // ["Using preferred strategy: parallel", ...]
2713
+ * ```
2714
+ */
2715
+ declare class UploadStrategyNegotiator {
2716
+ private capabilities;
2717
+ private validateUploadStrategy;
2718
+ /**
2719
+ * Creates a new upload strategy negotiator.
2720
+ *
2721
+ * @param capabilities - Data store capabilities and constraints
2722
+ * @param validateUploadStrategy - Function to validate if a strategy is supported
2723
+ */
2724
+ constructor(capabilities: DataStoreCapabilities, validateUploadStrategy: (strategy: UploadStrategy) => boolean);
2725
+ /**
2726
+ * Negotiates the optimal upload strategy based on options and data store capabilities.
2727
+ *
2728
+ * This method analyzes the provided options and data store capabilities to determine
2729
+ * the best upload strategy, chunk size, and parallel upload settings. It considers
2730
+ * user preferences, file size, and data store constraints to make optimal decisions.
2731
+ *
2732
+ * The negotiation process:
2733
+ * 1. Validates preferred strategy against data store capabilities
2734
+ * 2. Automatically selects strategy based on file size and capabilities
2735
+ * 3. Adjusts chunk size to fit within data store constraints
2736
+ * 4. Validates parallel upload settings
2737
+ * 5. Ensures final strategy is supported by the data store
2738
+ *
2739
+ * @param options - Upload strategy options including file size and preferences
2740
+ * @returns Negotiated strategy with reasoning and warnings
2741
+ *
2742
+ * @example
2743
+ * ```typescript
2744
+ * const result = negotiator.negotiateStrategy({
2745
+ * fileSize: 50_000_000, // 50MB
2746
+ * preferredStrategy: "parallel",
2747
+ * preferredChunkSize: 5_000_000, // 5MB
2748
+ * parallelUploads: 3
2749
+ * });
2750
+ *
2751
+ * console.log(result.strategy); // "parallel"
2752
+ * console.log(result.chunkSize); // 5_000_000
2753
+ * console.log(result.parallelUploads); // 3
2754
+ * console.log(result.reasoning); // ["Using preferred strategy: parallel", ...]
2755
+ * console.log(result.warnings); // [] (no warnings)
2756
+ * ```
2757
+ */
2758
+ negotiateStrategy(options: UploadStrategyOptions): NegotiatedStrategy;
2759
+ /**
2760
+ * Gets the data store capabilities used by this negotiator.
2761
+ *
2762
+ * @returns The data store capabilities and constraints
2763
+ */
2764
+ getDataStoreCapabilities(): DataStoreCapabilities;
2765
+ /**
2766
+ * Validates upload strategy configuration against data store capabilities.
2767
+ *
2768
+ * This method checks if the provided configuration is valid for the current
2769
+ * data store capabilities without performing the actual negotiation. It's
2770
+ * useful for pre-validation before attempting to negotiate a strategy.
2771
+ *
2772
+ * @param options - Upload strategy options to validate
2773
+ * @returns Validation result with validity flag and error messages
2774
+ *
2775
+ * @example
2776
+ * ```typescript
2777
+ * const validation = negotiator.validateConfiguration({
2778
+ * fileSize: 10_000_000,
2779
+ * preferredStrategy: "parallel",
2780
+ * preferredChunkSize: 1_000_000,
2781
+ * parallelUploads: 5
2782
+ * });
2783
+ *
2784
+ * if (!validation.valid) {
2785
+ * console.log("Configuration errors:", validation.errors);
2786
+ * // Handle validation errors
2787
+ * }
2788
+ * ```
2789
+ */
2790
+ validateConfiguration(options: UploadStrategyOptions): {
2791
+ valid: boolean;
2792
+ errors: string[];
2793
+ };
2794
+ }
2795
+ //#endregion
2796
+ //#region src/flow/types/flow-job.d.ts
2797
+ /**
2798
+ * Flow job tracking and state management types.
2799
+ *
2800
+ * A FlowJob represents a single execution instance of a flow, tracking its progress,
2801
+ * node results, and execution state. Jobs can be paused and resumed, making them
2802
+ * suitable for long-running or interactive flows.
2803
+ *
2804
+ * @module flow/types/flow-job
2805
+ * @see {@link FlowServer} for job management operations
2806
+ */
2807
+ /**
2808
+ * Status of an individual node within a flow job.
2809
+ *
2810
+ * Node tasks follow this lifecycle:
2811
+ * started → pending → running → (completed | paused | failed)
2812
+ */
2813
+ type FlowJobTaskStatus = "started" | "pending" | "running" | "completed" | "paused" | "failed";
2814
+ /**
2815
+ * Represents a single node's execution within a flow job.
2816
+ *
2817
+ * Tasks track individual node execution, storing results, errors, and retry information.
2818
+ * They allow monitoring of which nodes have completed and accessing intermediate results.
2819
+ *
2820
+ * @property nodeId - Unique identifier of the node this task represents
2821
+ * @property status - Current execution status of the node
2822
+ * @property result - Output data from the node (if completed successfully)
2823
+ * @property error - Error message if the node failed
2824
+ * @property retryCount - Number of retry attempts made before success or final failure
2825
+ * @property createdAt - When the task was created
2826
+ * @property updatedAt - When the task was last updated
2827
+ */
2828
+ type FlowJobTask = {
2829
+ nodeId: string;
2830
+ status: FlowJobTaskStatus;
2831
+ result?: unknown;
2832
+ error?: string;
2833
+ retryCount?: number;
2834
+ createdAt: Date;
2835
+ updatedAt: Date;
2836
+ };
2837
+ /**
2838
+ * Represents a flow execution job with full state tracking.
2839
+ *
2840
+ * Jobs are created when a flow is executed and track the entire execution lifecycle.
2841
+ * They store node results, handle paused states, and manage cleanup of intermediate files.
2842
+ *
2843
+ * @property id - Unique job identifier (UUID)
2844
+ * @property flowId - The flow being executed
2845
+ * @property storageId - Storage location for file outputs
2846
+ * @property clientId - Client that initiated the job (for authorization)
2847
+ * @property status - Overall job status
2848
+ * @property createdAt - When the job was created
2849
+ * @property updatedAt - When the job was last updated
2850
+ * @property tasks - Array of node execution tasks
2851
+ * @property error - Error message if the job failed
2852
+ * @property endedAt - When the job completed or failed
2853
+ * @property result - Final output from the flow (only set when completed)
2854
+ * @property pausedAt - Node ID where execution is paused (if applicable)
2855
+ * @property executionState - State needed to resume a paused flow
2856
+ * @property intermediateFiles - File IDs to cleanup after completion
2857
+ *
2858
+ * @remarks
2859
+ * - Jobs can be paused at nodes that return `{ type: "waiting" }`
2860
+ * - Paused jobs store execution state and can be resumed with new data
2861
+ * - Intermediate files from non-output nodes are automatically cleaned up
2862
+ * - Tasks are updated as nodes progress through their lifecycle
2863
+ *
2864
+ * @example
2865
+ * ```typescript
2866
+ * // Create and monitor a job
2867
+ * const job = yield* flowServer.runFlow({
2868
+ * flowId: "image-pipeline",
2869
+ * storageId: "storage-1",
2870
+ * inputs: { input: myFile }
2871
+ * });
2872
+ *
2873
+ * // Poll for status
2874
+ * const status = yield* flowServer.getJobStatus(job.id);
2875
+ * if (status.status === "completed") {
2876
+ * console.log("Final result:", status.result);
2877
+ * } else if (status.status === "paused") {
2878
+ * // Resume with additional data
2879
+ * yield* flowServer.continueFlow({
2880
+ * jobId: job.id,
2881
+ * nodeId: status.pausedAt,
2882
+ * newData: additionalChunk
2883
+ * });
2884
+ * }
2885
+ * ```
2886
+ */
2887
+ type FlowJob = {
2888
+ id: string;
2889
+ flowId: string;
2890
+ storageId: string;
2891
+ clientId: string | null;
2892
+ status: FlowJobStatus;
2893
+ createdAt: Date;
2894
+ updatedAt: Date;
2895
+ tasks: FlowJobTask[];
2896
+ error?: string;
2897
+ endedAt?: Date;
2898
+ result?: unknown;
2899
+ pausedAt?: string;
2900
+ executionState?: {
2901
+ executionOrder: string[];
2902
+ currentIndex: number;
2903
+ inputs: Record<string, unknown>;
2904
+ };
2905
+ intermediateFiles?: string[];
2906
+ };
2907
+ /**
2908
+ * Overall status of a flow job.
2909
+ *
2910
+ * Job lifecycle: started → running → (completed | failed)
2911
+ * Or with pauses: started → running → paused → running → (completed | failed)
2912
+ */
2913
+ type FlowJobStatus = "pending" | "running" | "completed" | "failed" | "started" | "paused";
2914
+ //#endregion
2915
+ //#region src/flow/flow-server.d.ts
2916
+ /**
2917
+ * Flow provider interface that applications must implement.
2918
+ *
2919
+ * This interface defines how the FlowServer retrieves flow definitions.
2920
+ * Applications provide their own implementation to load flows from a database,
2921
+ * configuration files, or any other source.
2922
+ *
2923
+ * @template TRequirements - Additional Effect requirements for flow execution
2924
+ *
2925
+ * @property getFlow - Retrieves a flow definition by ID with authorization check
2926
+ *
2927
+ * @example
2928
+ * ```typescript
2929
+ * // Implement a flow provider from database
2930
+ * const dbFlowProvider: FlowProviderShape = {
2931
+ * getFlow: (flowId, clientId) => Effect.gen(function* () {
2932
+ * // Load flow from database
2933
+ * const flowData = yield* db.getFlow(flowId);
2934
+ *
2935
+ * // Check authorization
2936
+ * if (flowData.ownerId !== clientId) {
2937
+ * return yield* Effect.fail(
2938
+ * UploadistaError.fromCode("FLOW_NOT_AUTHORIZED")
2939
+ * );
2940
+ * }
2941
+ *
2942
+ * // Create flow instance
2943
+ * return createFlow(flowData);
2944
+ * })
2945
+ * };
2946
+ *
2947
+ * // Provide to FlowServer
2948
+ * const flowProviderLayer = Layer.succeed(FlowProvider, dbFlowProvider);
2949
+ * ```
2950
+ */
2951
+ type FlowProviderShape<TRequirements$1 = any> = {
2952
+ getFlow: (flowId: string, clientId: string | null) => Effect.Effect<Flow<any, any, TRequirements$1>, UploadistaError$1>;
2953
+ };
2954
+ declare const FlowProvider_base: Context.TagClass<FlowProvider, "FlowProvider", FlowProviderShape<any>>;
2955
+ /**
2956
+ * Effect-TS context tag for the FlowProvider service.
2957
+ *
2958
+ * Applications must provide an implementation of FlowProviderShape
2959
+ * to enable the FlowServer to retrieve flow definitions.
2960
+ *
2961
+ * @example
2962
+ * ```typescript
2963
+ * // Access FlowProvider in an Effect
2964
+ * const effect = Effect.gen(function* () {
2965
+ * const provider = yield* FlowProvider;
2966
+ * const flow = yield* provider.getFlow("flow123", "client456");
2967
+ * return flow;
2968
+ * });
2969
+ * ```
2970
+ */
2971
+ declare class FlowProvider extends FlowProvider_base {}
2972
+ /**
2973
+ * FlowServer service interface.
2974
+ *
2975
+ * This is the core flow processing service that executes DAG-based file processing pipelines.
2976
+ * It manages flow execution, job tracking, node processing, pause/resume functionality,
2977
+ * and real-time event broadcasting.
2978
+ *
2979
+ * All operations return Effect types for composable, type-safe error handling.
2980
+ *
2981
+ * @property getFlow - Retrieves a flow definition by ID
2982
+ * @property getFlowData - Retrieves flow metadata (nodes, edges) without full flow instance
2983
+ * @property runFlow - Starts a new flow execution and returns immediately with job ID
2984
+ * @property continueFlow - Resumes a paused flow with new data for a specific node
2985
+ * @property getJobStatus - Retrieves current status and results of a flow job
2986
+ * @property subscribeToFlowEvents - Subscribes WebSocket to flow execution events
2987
+ * @property unsubscribeFromFlowEvents - Unsubscribes from flow events
2988
+ *
2989
+ * @example
2990
+ * ```typescript
2991
+ * // Execute a flow
2992
+ * const program = Effect.gen(function* () {
2993
+ * const server = yield* FlowServer;
2994
+ *
2995
+ * // Start flow execution (returns immediately)
2996
+ * const job = yield* server.runFlow({
2997
+ * flowId: "resize-optimize",
2998
+ * storageId: "s3-production",
2999
+ * clientId: "client123",
3000
+ * inputs: {
3001
+ * input_1: { uploadId: "upload_abc123" }
3002
+ * }
3003
+ * });
3004
+ *
3005
+ * // Subscribe to events
3006
+ * yield* server.subscribeToFlowEvents(job.id, websocket);
3007
+ *
3008
+ * // Poll for status
3009
+ * const status = yield* server.getJobStatus(job.id);
3010
+ * console.log(status.status); // "running", "paused", "completed", or "failed"
3011
+ *
3012
+ * return job;
3013
+ * });
3014
+ *
3015
+ * // Resume a paused flow
3016
+ * const resume = Effect.gen(function* () {
3017
+ * const server = yield* FlowServer;
3018
+ *
3019
+ * // Flow paused waiting for user input at node "approval_1"
3020
+ * const job = yield* server.continueFlow({
3021
+ * jobId: "job123",
3022
+ * nodeId: "approval_1",
3023
+ * newData: { approved: true },
3024
+ * clientId: "client123"
3025
+ * });
3026
+ *
3027
+ * return job;
3028
+ * });
3029
+ *
3030
+ * // Check flow structure before execution
3031
+ * const inspect = Effect.gen(function* () {
3032
+ * const server = yield* FlowServer;
3033
+ *
3034
+ * const flowData = yield* server.getFlowData("resize-optimize", "client123");
3035
+ * console.log("Nodes:", flowData.nodes);
3036
+ * console.log("Edges:", flowData.edges);
3037
+ *
3038
+ * return flowData;
3039
+ * });
3040
+ * ```
3041
+ */
3042
+ type FlowServerShape = {
3043
+ getFlow: <TRequirements>(flowId: string, clientId: string | null) => Effect.Effect<Flow<any, any, TRequirements>, UploadistaError$1>;
3044
+ getFlowData: (flowId: string, clientId: string | null) => Effect.Effect<FlowData, UploadistaError$1>;
3045
+ runFlow: <TRequirements>({
3046
+ flowId,
3047
+ storageId,
3048
+ clientId,
3049
+ inputs
3050
+ }: {
3051
+ flowId: string;
3052
+ storageId: string;
3053
+ clientId: string | null;
3054
+ inputs: any;
3055
+ }) => Effect.Effect<FlowJob, UploadistaError$1, TRequirements>;
3056
+ continueFlow: <TRequirements>({
3057
+ jobId,
3058
+ nodeId,
3059
+ newData,
3060
+ clientId
3061
+ }: {
3062
+ jobId: string;
3063
+ nodeId: string;
3064
+ newData: unknown;
3065
+ clientId: string | null;
3066
+ }) => Effect.Effect<FlowJob, UploadistaError$1, TRequirements>;
3067
+ getJobStatus: (jobId: string) => Effect.Effect<FlowJob, UploadistaError$1>;
3068
+ subscribeToFlowEvents: (jobId: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError$1>;
3069
+ unsubscribeFromFlowEvents: (jobId: string) => Effect.Effect<void, UploadistaError$1>;
3070
+ };
3071
+ declare const FlowServer_base: Context.TagClass<FlowServer, "FlowServer", FlowServerShape>;
3072
+ /**
3073
+ * Effect-TS context tag for the FlowServer service.
3074
+ *
3075
+ * Use this tag to access the FlowServer in an Effect context.
3076
+ * The server must be provided via a Layer or dependency injection.
3077
+ *
3078
+ * @example
3079
+ * ```typescript
3080
+ * // Access FlowServer in an Effect
3081
+ * const flowEffect = Effect.gen(function* () {
3082
+ * const server = yield* FlowServer;
3083
+ * const job = yield* server.runFlow({
3084
+ * flowId: "my-flow",
3085
+ * storageId: "s3",
3086
+ * clientId: null,
3087
+ * inputs: {}
3088
+ * });
3089
+ * return job;
3090
+ * });
3091
+ *
3092
+ * // Provide FlowServer layer
3093
+ * const program = flowEffect.pipe(
3094
+ * Effect.provide(flowServer),
3095
+ * Effect.provide(flowProviderLayer),
3096
+ * Effect.provide(flowJobKvStore)
3097
+ * );
3098
+ * ```
3099
+ */
3100
+ declare class FlowServer extends FlowServer_base {}
3101
+ /**
3102
+ * Legacy configuration options for FlowServer.
3103
+ *
3104
+ * @deprecated Use Effect Layers and FlowProvider instead.
3105
+ * This type is kept for backward compatibility.
3106
+ *
3107
+ * @property getFlow - Function to retrieve flow definitions
3108
+ * @property kvStore - KV store for flow job metadata
3109
+ */
3110
+ type FlowServerOptions = {
3111
+ getFlow: <TRequirements>({
3112
+ flowId,
3113
+ storageId
3114
+ }: {
3115
+ flowId: string;
3116
+ storageId: string;
3117
+ }) => Promise<Flow<any, any, TRequirements>>;
3118
+ kvStore: KvStore<FlowJob>;
3119
+ };
3120
+ declare function createFlowServer(): Effect.Effect<{
3121
+ getFlow: <TRequirements>(flowId: string, clientId: string | null) => Effect.Effect<Flow<any, any, any>, UploadistaError$1, never>;
3122
+ getFlowData: (flowId: string, clientId: string | null) => Effect.Effect<FlowData, UploadistaError$1, never>;
3123
+ runFlow: ({
3124
+ flowId,
3125
+ storageId,
3126
+ clientId,
3127
+ inputs
3128
+ }: {
3129
+ flowId: string;
3130
+ storageId: string;
3131
+ clientId: string | null;
3132
+ inputs: unknown;
3133
+ }) => Effect.Effect<FlowJob, UploadistaError$1, any>;
3134
+ getJobStatus: (jobId: string) => Effect.Effect<FlowJob, UploadistaError$1, never>;
3135
+ continueFlow: ({
3136
+ jobId,
3137
+ nodeId,
3138
+ newData,
3139
+ clientId
3140
+ }: {
3141
+ jobId: string;
3142
+ nodeId: string;
3143
+ newData: unknown;
3144
+ clientId: string | null;
3145
+ }) => Effect.Effect<FlowJob, UploadistaError$1, any>;
3146
+ subscribeToFlowEvents: (jobId: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError$1, never>;
3147
+ unsubscribeFromFlowEvents: (jobId: string) => Effect.Effect<void, UploadistaError$1, never>;
3148
+ }, never, FlowEventEmitter | FlowJobKVStore | UploadServer | FlowProvider>;
3149
+ declare const flowServer: Layer.Layer<FlowServer, never, FlowEventEmitter | FlowJobKVStore | UploadServer | FlowProvider>;
3150
+ type FlowServerLayer = typeof flowServer;
3151
+ //#endregion
3152
+ //#region src/flow/nodes/input-node.d.ts
3153
+ /**
3154
+ * Union schema for all input operations.
3155
+ * Defines the possible input data structures for the input node.
3156
+ */
3157
+ declare const inputDataSchema: z.ZodUnion<readonly [z.ZodObject<{
3158
+ operation: z.ZodLiteral<"init">;
3159
+ storageId: z.ZodString;
3160
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
3161
+ }, z.core.$strip>, z.ZodObject<{
3162
+ operation: z.ZodLiteral<"finalize">;
3163
+ uploadId: z.ZodString;
3164
+ }, z.core.$strip>, z.ZodObject<{
3165
+ operation: z.ZodLiteral<"url">;
3166
+ url: z.ZodString;
3167
+ storageId: z.ZodOptional<z.ZodString>;
3168
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
3169
+ }, z.core.$strip>]>;
3170
+ /**
3171
+ * Type representing the input data for the input node.
3172
+ * Can be one of three operation types: init, finalize, or url.
3173
+ */
3174
+ type InputData = z.infer<typeof inputDataSchema>;
3175
+ /**
3176
+ * Schema for input node filtering parameters.
3177
+ * Defines validation rules for incoming files.
3178
+ */
3179
+ declare const inputNodeParamsSchema: z.ZodObject<{
3180
+ allowedMimeTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
3181
+ minSize: z.ZodOptional<z.ZodNumber>;
3182
+ maxSize: z.ZodOptional<z.ZodNumber>;
3183
+ }, z.core.$strip>;
3184
+ /**
3185
+ * Parameters for configuring input node validation.
3186
+ * Controls which files are accepted based on type and size constraints.
3187
+ */
3188
+ type InputNodeParams = z.infer<typeof inputNodeParamsSchema>;
3189
+ /**
3190
+ * Creates an input node for handling file input through multiple methods.
3191
+ *
3192
+ * The input node supports three operation types:
3193
+ * - `init`: Initialize a streaming upload session
3194
+ * - `finalize`: Complete a streaming upload after all chunks are uploaded
3195
+ * - `url`: Fetch a file directly from a URL
3196
+ *
3197
+ * @param id - Unique identifier for the node
3198
+ * @param params - Optional validation parameters for filtering incoming files
3199
+ * @returns An Effect that creates a flow node configured for file input
3200
+ *
3201
+ * @example
3202
+ * ```typescript
3203
+ * // Create input node with validation
3204
+ * const inputNode = yield* createInputNode("file-input", {
3205
+ * allowedMimeTypes: ["image/*", "application/pdf"],
3206
+ * maxSize: 10 * 1024 * 1024, // 10MB
3207
+ * });
3208
+ *
3209
+ * // Create input node without validation
3210
+ * const openInputNode = yield* createInputNode("open-input");
3211
+ * ```
3212
+ */
3213
+ declare function createInputNode(id: string, params?: InputNodeParams): Effect.Effect<FlowNode<{
3214
+ operation: "init";
3215
+ storageId: string;
3216
+ metadata?: Record<string, any> | undefined;
3217
+ } | {
3218
+ operation: "finalize";
3219
+ uploadId: string;
3220
+ } | {
3221
+ operation: "url";
3222
+ url: string;
3223
+ storageId?: string | undefined;
3224
+ metadata?: Record<string, any> | undefined;
3225
+ }, UploadFile, UploadistaError$1>, never, UploadServer>;
3226
+ //#endregion
3227
+ //#region src/flow/nodes/storage-node.d.ts
3228
+ /**
3229
+ * Schema for storage node parameters.
3230
+ * Currently empty but can be extended for storage-specific configuration.
3231
+ */
3232
+ declare const storageParamsSchema: z.ZodObject<{}, z.core.$strip>;
3233
+ /**
3234
+ * Parameters for the storage node.
3235
+ * Currently no parameters are required, but the schema is available for future extensions.
3236
+ */
3237
+ type StorageParams = z.infer<typeof storageParamsSchema>;
3238
+ /**
3239
+ * Creates a storage node for storing files in the specified storage.
3240
+ *
3241
+ * The storage node handles the process of:
3242
+ * 1. Reading the input file from the upload server
3243
+ * 2. Checking if the file is already in the target storage
3244
+ * 3. If not, transferring the file to the target storage
3245
+ * 4. Applying optional post-processing
3246
+ * 5. Returning the final stored file
3247
+ *
3248
+ * @param id - Unique identifier for the node
3249
+ * @param postProcessFile - Optional function to process the file after storage
3250
+ * @returns An Effect that creates a flow node configured for file storage
3251
+ *
3252
+ * @example
3253
+ * ```typescript
3254
+ * // Create basic storage node
3255
+ * const storageNode = yield* createStorageNode("store-file");
3256
+ *
3257
+ * // Create storage node with post-processing
3258
+ * const storageWithProcessing = yield* createStorageNode("store-and-process", (file) => {
3259
+ * return Effect.succeed({
3260
+ * ...file,
3261
+ * metadata: { ...file.metadata, processed: true }
3262
+ * });
3263
+ * });
3264
+ * ```
3265
+ */
3266
+ declare function createStorageNode(id: string, postProcessFile?: (file: UploadFile) => Effect.Effect<UploadFile>): Effect.Effect<FlowNode<{
3267
+ id: string;
3268
+ offset: number;
3269
+ storage: {
3270
+ id: string;
3271
+ type: string;
3272
+ path?: string | undefined;
3273
+ uploadId?: string | undefined;
3274
+ bucket?: string | undefined;
3275
+ };
3276
+ size?: number | undefined;
3277
+ metadata?: Record<string, string | number | boolean> | undefined;
3278
+ creationDate?: string | undefined;
3279
+ url?: string | undefined;
3280
+ sizeIsDeferred?: boolean | undefined;
3281
+ checksum?: string | undefined;
3282
+ checksumAlgorithm?: string | undefined;
3283
+ flow?: {
3284
+ flowId: string;
3285
+ nodeId: string;
3286
+ jobId: string;
3287
+ } | undefined;
3288
+ }, UploadFile, UploadistaError$1>, never, UploadServer>;
3289
+ //#endregion
3290
+ //#region src/flow/nodes/transform-node.d.ts
3291
+ /**
3292
+ * Configuration object for creating a transform node.
3293
+ */
3294
+ interface TransformNodeConfig {
3295
+ /** Unique identifier for the node */
3296
+ id: string;
3297
+ /** Human-readable name for the node */
3298
+ name: string;
3299
+ /** Description of what the node does */
3300
+ description: string;
3301
+ /** Function that transforms file bytes */
3302
+ transform: (bytes: Uint8Array, file: UploadFile) => Effect.Effect<Uint8Array | {
3303
+ bytes: Uint8Array;
3304
+ type?: string;
3305
+ fileName?: string;
3306
+ }, UploadistaError$1>;
3307
+ }
3308
+ /**
3309
+ * Creates a transform node that handles the common pattern of:
3310
+ * 1. Reading bytes from an UploadFile
3311
+ * 2. Transforming the bytes
3312
+ * 3. Uploading the result as a new UploadFile
3313
+ *
3314
+ * This simplifies nodes that just need to transform file bytes without
3315
+ * worrying about upload server interactions.
3316
+ *
3317
+ * @param config - Configuration object for the transform node
3318
+ * @returns An Effect that creates a flow node configured for file transformation
3319
+ *
3320
+ * @example
3321
+ * ```typescript
3322
+ * // Create an image resize transform node
3323
+ * const resizeNode = yield* createTransformNode({
3324
+ * id: "resize-image",
3325
+ * name: "Resize Image",
3326
+ * description: "Resizes images to specified dimensions",
3327
+ * transform: (bytes, file) => {
3328
+ * // Your transformation logic here
3329
+ * return Effect.succeed(transformedBytes);
3330
+ * }
3331
+ * });
3332
+ *
3333
+ * // Create a transform node that changes file metadata
3334
+ * const metadataTransformNode = yield* createTransformNode({
3335
+ * id: "add-metadata",
3336
+ * name: "Add Metadata",
3337
+ * description: "Adds custom metadata to files",
3338
+ * transform: (bytes, file) => {
3339
+ * return Effect.succeed({
3340
+ * bytes,
3341
+ * type: "application/custom",
3342
+ * fileName: `processed-${file.fileName}`
3343
+ * });
3344
+ * }
3345
+ * });
3346
+ * ```
3347
+ */
3348
+ declare function createTransformNode({
3349
+ id,
3350
+ name,
3351
+ description,
3352
+ transform
3353
+ }: TransformNodeConfig): Effect.Effect<FlowNode<{
3354
+ id: string;
3355
+ offset: number;
3356
+ storage: {
3357
+ id: string;
3358
+ type: string;
3359
+ path?: string | undefined;
3360
+ uploadId?: string | undefined;
3361
+ bucket?: string | undefined;
3362
+ };
3363
+ size?: number | undefined;
3364
+ metadata?: Record<string, string | number | boolean> | undefined;
3365
+ creationDate?: string | undefined;
3366
+ url?: string | undefined;
3367
+ sizeIsDeferred?: boolean | undefined;
3368
+ checksum?: string | undefined;
3369
+ checksumAlgorithm?: string | undefined;
3370
+ flow?: {
3371
+ flowId: string;
3372
+ nodeId: string;
3373
+ jobId: string;
3374
+ } | undefined;
3375
+ }, UploadFile, UploadistaError$1>, never, UploadServer>;
3376
+ //#endregion
3377
+ //#region src/flow/parallel-scheduler.d.ts
3378
+ /**
3379
+ * Represents a level in the execution hierarchy where all nodes can run in parallel.
3380
+ *
3381
+ * @property level - The execution level (0 = first to execute, higher = later)
3382
+ * @property nodes - Array of node IDs that can execute in parallel at this level
3383
+ *
3384
+ * @example
3385
+ * ```
3386
+ * Level 0: [input_node] (no dependencies)
3387
+ * Level 1: [resize, optimize] (all depend on level 0)
3388
+ * Level 2: [storage] (depends on level 1)
3389
+ * ```
3390
+ */
3391
+ interface ExecutionLevel {
3392
+ level: number;
3393
+ nodes: string[];
3394
+ }
3395
+ /**
3396
+ * Configuration options for the ParallelScheduler.
3397
+ *
3398
+ * @property maxConcurrency - Maximum number of nodes to execute in parallel (default: 4)
3399
+ * Controls how many nodes run simultaneously within a level
3400
+ *
3401
+ * @example
3402
+ * ```typescript
3403
+ * const scheduler = new ParallelScheduler({ maxConcurrency: 8 });
3404
+ * ```
3405
+ */
3406
+ interface ParallelSchedulerConfig {
3407
+ maxConcurrency?: number;
3408
+ }
3409
+ /**
3410
+ * Scheduler for executing flow nodes in parallel while respecting dependencies.
3411
+ *
3412
+ * The scheduler performs topological sorting to identify nodes that can run
3413
+ * concurrently, groups them into execution levels, and provides methods to
3414
+ * execute them with controlled concurrency using Effect.
3415
+ *
3416
+ * Key responsibilities:
3417
+ * - Analyze flow dependencies and detect cycles
3418
+ * - Group nodes into parallel execution levels
3419
+ * - Execute levels in parallel with concurrency limits
3420
+ * - Provide utilities to check parallel execution feasibility
3421
+ */
3422
+ declare class ParallelScheduler {
3423
+ private maxConcurrency;
3424
+ /**
3425
+ * Creates a new ParallelScheduler instance.
3426
+ *
3427
+ * @param config - Configuration for the scheduler
3428
+ * @example
3429
+ * ```typescript
3430
+ * const scheduler = new ParallelScheduler({ maxConcurrency: 4 });
3431
+ * ```
3432
+ */
3433
+ constructor(config?: ParallelSchedulerConfig);
3434
+ /**
3435
+ * Groups nodes into execution levels where nodes in the same level can run in parallel.
3436
+ *
3437
+ * Uses Kahn's algorithm to perform topological sorting with level identification.
3438
+ * Nodes are grouped by their distance from source nodes (input nodes with no dependencies).
3439
+ *
3440
+ * @param nodes - Array of flow nodes to analyze
3441
+ * @param edges - Array of edges defining dependencies between nodes
3442
+ * @returns Array of execution levels, ordered from 0 (no dependencies) onwards
3443
+ * @throws Error if a cycle is detected in the flow graph
3444
+ *
3445
+ * @example
3446
+ * ```typescript
3447
+ * const levels = scheduler.groupNodesByExecutionLevel(nodes, edges);
3448
+ * // levels = [
3449
+ * // { level: 0, nodes: ['input_1'] },
3450
+ * // { level: 1, nodes: ['resize_1', 'optimize_1'] },
3451
+ * // { level: 2, nodes: ['output_1'] }
3452
+ * // ]
3453
+ * ```
3454
+ */
3455
+ groupNodesByExecutionLevel(nodes: FlowNode<unknown, unknown>[], edges: Array<{
3456
+ source: string;
3457
+ target: string;
3458
+ }>): ExecutionLevel[];
3459
+ /**
3460
+ * Executes a batch of Effect-based node executors in parallel with concurrency control.
3461
+ *
3462
+ * All executors are run in parallel, but the number of concurrent executions is limited
3463
+ * by maxConcurrency. This prevents resource exhaustion while maximizing parallelism.
3464
+ *
3465
+ * @template T - The return type of each executor
3466
+ * @template E - The error type of the Effects
3467
+ * @template R - The requirements type of the Effects
3468
+ *
3469
+ * @param nodeExecutors - Array of Effect-returning functions to execute in parallel
3470
+ * @returns Effect that resolves to array of results in the same order as input
3471
+ *
3472
+ * @example
3473
+ * ```typescript
3474
+ * const results = yield* scheduler.executeNodesInParallel([
3475
+ * () => executeNode("node1"),
3476
+ * () => executeNode("node2"),
3477
+ * () => executeNode("node3")
3478
+ * ]);
3479
+ * // results will be in order: [result1, result2, result3]
3480
+ * ```
3481
+ */
3482
+ executeNodesInParallel<T, E, R>(nodeExecutors: Array<() => Effect.Effect<T, E, R>>): Effect.Effect<T[], E, R>;
3483
+ /**
3484
+ * Determines if a set of nodes can be safely executed in parallel.
3485
+ *
3486
+ * Nodes can execute in parallel if all their dependencies have been completed.
3487
+ * This is typically called to verify that nodes in an execution level are ready
3488
+ * to run given the current node results.
3489
+ *
3490
+ * @param nodeIds - Array of node IDs to check
3491
+ * @param nodeResults - Map of completed node IDs to their results
3492
+ * @param reverseGraph - Dependency graph mapping node IDs to their incoming dependencies
3493
+ * @returns true if all dependencies for all nodes are in nodeResults, false otherwise
3494
+ *
3495
+ * @example
3496
+ * ```typescript
3497
+ * const canRun = scheduler.canExecuteInParallel(
3498
+ * ['resize_1', 'optimize_1'],
3499
+ * nodeResults,
3500
+ * reverseGraph
3501
+ * );
3502
+ * ```
3503
+ */
3504
+ canExecuteInParallel(nodeIds: string[], nodeResults: Map<string, unknown>, reverseGraph: Record<string, string[]>): boolean;
3505
+ /**
3506
+ * Gets execution statistics for monitoring and debugging.
3507
+ *
3508
+ * @returns Object containing current scheduler configuration
3509
+ *
3510
+ * @example
3511
+ * ```typescript
3512
+ * const stats = scheduler.getStats();
3513
+ * console.log(`Max concurrency: ${stats.maxConcurrency}`);
3514
+ * ```
3515
+ */
3516
+ getStats(): {
3517
+ maxConcurrency: number;
3518
+ };
3519
+ }
3520
+ //#endregion
3521
+ //#region src/flow/plugins/credential-provider.d.ts
3522
+ /**
3523
+ * Shape definition for the Credential Provider interface.
3524
+ * Defines the contract for retrieving credentials for various services.
3525
+ */
3526
+ interface CredentialProviderShape {
3527
+ /**
3528
+ * Retrieves credentials for a specific service and client.
3529
+ *
3530
+ * @param params - Parameters for credential retrieval
3531
+ * @param params.clientId - Unique identifier for the client, or null if not available
3532
+ * @param params.serviceType - Optional service type to get specific credentials for
3533
+ * @returns An Effect that resolves to a record of credential key-value pairs
3534
+ * @throws {UploadistaError} When credential retrieval fails
3535
+ */
3536
+ getCredential: (params: {
3537
+ clientId: string | null;
3538
+ serviceType?: string;
3539
+ }) => Effect.Effect<Record<string, unknown>, UploadistaError$1>;
3540
+ }
3541
+ declare const CredentialProvider_base: Context.TagClass<CredentialProvider, "CredentialProvider", CredentialProviderShape>;
3542
+ /**
3543
+ * Context tag for the Credential Provider.
3544
+ *
3545
+ * This tag provides a type-safe way to access credential functionality
3546
+ * throughout the application using Effect's dependency injection system.
3547
+ *
3548
+ * @example
3549
+ * ```typescript
3550
+ * import { CredentialProvider } from "@uploadista/core/flow/plugins";
3551
+ *
3552
+ * // In your flow node
3553
+ * const program = Effect.gen(function* () {
3554
+ * const credentialProvider = yield* CredentialProvider;
3555
+ * const credentials = yield* credentialProvider.getCredential({
3556
+ * clientId: "user123",
3557
+ * serviceType: "replicate"
3558
+ * });
3559
+ * return credentials;
3560
+ * });
3561
+ * ```
3562
+ */
3563
+ declare class CredentialProvider extends CredentialProvider_base {}
3564
+ //#endregion
3565
+ //#region src/flow/plugins/image-ai-plugin.d.ts
3566
+ /**
3567
+ * Context information for AI image processing operations.
3568
+ * Contains client identification for tracking and billing purposes.
3569
+ */
3570
+ type ImageAiContext = {
3571
+ /** Unique identifier for the client making the request, or null if not available */
3572
+ clientId: string | null;
3573
+ };
3574
+ /**
3575
+ * Shape definition for the Image AI Plugin interface.
3576
+ * Defines the contract that all image AI implementations must follow.
3577
+ */
3578
+ type ImageAiPluginShape = {
3579
+ /**
3580
+ * Removes the background from an image using AI processing.
3581
+ *
3582
+ * @param inputUrl - The URL of the input image to process
3583
+ * @param context - Context information including client ID for tracking
3584
+ * @returns An Effect that resolves to an object containing the output image URL
3585
+ * @throws {UploadistaError} When the background removal fails
3586
+ */
3587
+ removeBackground: (inputUrl: string, context: ImageAiContext) => Effect.Effect<{
3588
+ outputUrl: string;
3589
+ }, UploadistaError>;
3590
+ /**
3591
+ * Generates a textual description of an image using AI analysis.
3592
+ *
3593
+ * @param inputUrl - The URL of the input image to analyze
3594
+ * @param context - Context information including client ID for tracking
3595
+ * @returns An Effect that resolves to an object containing the image description
3596
+ * @throws {UploadistaError} When the image analysis fails
3597
+ */
3598
+ describeImage: (inputUrl: string, context: ImageAiContext) => Effect.Effect<{
3599
+ description: string;
3600
+ }, UploadistaError>;
3601
+ };
3602
+ declare const ImageAiPlugin_base: Context.TagClass<ImageAiPlugin, "ImageAiPlugin", ImageAiPluginShape>;
3603
+ /**
3604
+ * Context tag for the Image AI Plugin.
3605
+ *
3606
+ * This tag provides a type-safe way to access image AI functionality
3607
+ * throughout the application using Effect's dependency injection system.
3608
+ *
3609
+ * @example
3610
+ * ```typescript
3611
+ * import { ImageAiPlugin } from "@uploadista/core/flow/plugins";
3612
+ *
3613
+ * // In your flow node
3614
+ * const program = Effect.gen(function* () {
3615
+ * const imageAi = yield* ImageAiPlugin;
3616
+ * const result = yield* imageAi.removeBackground(imageUrl, { clientId: "user123" });
3617
+ * return result.outputUrl;
3618
+ * });
3619
+ * ```
3620
+ */
3621
+ declare class ImageAiPlugin extends ImageAiPlugin_base {}
3622
+ //#endregion
3623
+ //#region src/flow/plugins/types/optimize-node.d.ts
3624
+ /**
3625
+ * Zod schema for validating image optimization parameters.
3626
+ * Defines the structure and validation rules for image optimization requests.
3627
+ */
3628
+ declare const optimizeParamsSchema: z.ZodObject<{
3629
+ quality: z.ZodNumber;
3630
+ format: z.ZodEnum<{
3631
+ jpeg: "jpeg";
3632
+ webp: "webp";
3633
+ png: "png";
3634
+ avif: "avif";
3635
+ }>;
3636
+ }, z.core.$strip>;
3637
+ /**
3638
+ * Parameters for the image optimization node.
3639
+ * Controls quality and format settings for image optimization.
3640
+ */
3641
+ type OptimizeParams = z.infer<typeof optimizeParamsSchema>;
3642
+ //#endregion
3643
+ //#region src/flow/plugins/types/resize-node.d.ts
3644
+ /**
3645
+ * Zod schema for validating image resize parameters.
3646
+ * Defines the structure and validation rules for image resizing requests.
3647
+ * Requires at least one dimension (width or height) to be specified.
3648
+ */
3649
+ declare const resizeParamsSchema: z.ZodObject<{
3650
+ width: z.ZodOptional<z.ZodNumber>;
3651
+ height: z.ZodOptional<z.ZodNumber>;
3652
+ fit: z.ZodEnum<{
3653
+ fill: "fill";
3654
+ contain: "contain";
3655
+ cover: "cover";
3656
+ }>;
3657
+ }, z.core.$strip>;
3658
+ /**
3659
+ * Parameters for the image resize node.
3660
+ * Controls the target dimensions and fitting behavior for image resizing.
3661
+ */
3662
+ type ResizeParams = z.infer<typeof resizeParamsSchema>;
3663
+ //#endregion
3664
+ //#region src/flow/plugins/image-plugin.d.ts
3665
+ /**
3666
+ * Shape definition for the Image Plugin interface.
3667
+ * Defines the contract that all image processing implementations must follow.
3668
+ */
3669
+ type ImagePluginShape = {
3670
+ /**
3671
+ * Optimizes an image by adjusting quality and format.
3672
+ *
3673
+ * @param input - The input image as a Uint8Array
3674
+ * @param options - Optimization parameters including quality and format
3675
+ * @returns An Effect that resolves to the optimized image as a Uint8Array
3676
+ * @throws {UploadistaError} When image optimization fails
3677
+ */
3678
+ optimize: (input: Uint8Array, options: OptimizeParams) => Effect.Effect<Uint8Array, UploadistaError>;
3679
+ /**
3680
+ * Resizes an image to specified dimensions.
3681
+ *
3682
+ * @param input - The input image as a Uint8Array
3683
+ * @param options - Resize parameters including width, height, and fit mode
3684
+ * @returns An Effect that resolves to the resized image as a Uint8Array
3685
+ * @throws {UploadistaError} When image resizing fails
3686
+ */
3687
+ resize: (input: Uint8Array, options: ResizeParams) => Effect.Effect<Uint8Array, UploadistaError>;
3688
+ };
3689
+ declare const ImagePlugin_base: Context.TagClass<ImagePlugin, "ImagePlugin", ImagePluginShape>;
3690
+ /**
3691
+ * Context tag for the Image Plugin.
3692
+ *
3693
+ * This tag provides a type-safe way to access image processing functionality
3694
+ * throughout the application using Effect's dependency injection system.
3695
+ *
3696
+ * @example
3697
+ * ```typescript
3698
+ * import { ImagePlugin } from "@uploadista/core/flow/plugins";
3699
+ *
3700
+ * // In your flow node
3701
+ * const program = Effect.gen(function* () {
3702
+ * const imagePlugin = yield* ImagePlugin;
3703
+ * const optimized = yield* imagePlugin.optimize(imageData, { quality: 80, format: "webp" });
3704
+ * const resized = yield* imagePlugin.resize(optimized, { width: 800, height: 600, fit: "cover" });
3705
+ * return resized;
3706
+ * });
3707
+ * ```
3708
+ */
3709
+ declare class ImagePlugin extends ImagePlugin_base {}
3710
+ //#endregion
3711
+ //#region src/flow/plugins/types/describe-image-node.d.ts
3712
+ /**
3713
+ * Zod schema for validating describe image node parameters.
3714
+ * Defines the structure and validation rules for image description requests.
3715
+ */
3716
+ declare const describeImageParamsSchema: z.ZodObject<{
3717
+ serviceType: z.ZodOptional<z.ZodEnum<{
3718
+ replicate: "replicate";
3719
+ }>>;
3720
+ }, z.core.$strip>;
3721
+ /**
3722
+ * Parameters for the describe image node.
3723
+ * Controls which AI service to use for generating image descriptions.
3724
+ */
3725
+ type DescribeImageParams = z.infer<typeof describeImageParamsSchema>;
3726
+ //#endregion
3727
+ //#region src/flow/plugins/types/remove-background-node.d.ts
3728
+ /**
3729
+ * Zod schema for validating remove background node parameters.
3730
+ * Defines the structure and validation rules for background removal requests.
3731
+ */
3732
+ declare const removeBackgroundParamsSchema: z.ZodObject<{
3733
+ serviceType: z.ZodOptional<z.ZodEnum<{
3734
+ replicate: "replicate";
3735
+ }>>;
3736
+ }, z.core.$strip>;
3737
+ /**
3738
+ * Parameters for the remove background node.
3739
+ * Controls which AI service to use for background removal processing.
3740
+ */
3741
+ type RemoveBackgroundParams = z.infer<typeof removeBackgroundParamsSchema>;
3742
+ //#endregion
3743
+ //#region src/flow/plugins/zip-plugin.d.ts
3744
+ /**
3745
+ * Parameters for creating a ZIP archive.
3746
+ */
3747
+ type ZipParams = {
3748
+ /** Name of the ZIP file to create */
3749
+ zipName: string;
3750
+ /** Whether to include file metadata in the ZIP archive */
3751
+ includeMetadata: boolean;
3752
+ };
3753
+ /**
3754
+ * Input data structure for ZIP operations.
3755
+ * Represents a single file to be included in the ZIP archive.
3756
+ */
3757
+ type ZipInput = {
3758
+ /** Unique identifier for the file */
3759
+ id: string;
3760
+ /** Binary data of the file */
3761
+ data: Uint8Array;
3762
+ /** File metadata including name, size, type, etc. */
3763
+ metadata: UploadFile["metadata"];
3764
+ };
3765
+ /**
3766
+ * Shape definition for the ZIP Plugin interface.
3767
+ * Defines the contract that all ZIP implementations must follow.
3768
+ */
3769
+ type ZipPluginShape = {
3770
+ /**
3771
+ * Creates a ZIP archive from multiple input files.
3772
+ *
3773
+ * @param inputs - Array of files to include in the ZIP archive
3774
+ * @param options - Configuration options for the ZIP creation
3775
+ * @returns An Effect that resolves to the ZIP file as a Uint8Array
3776
+ * @throws {UploadistaError} When ZIP creation fails
3777
+ */
3778
+ zip: (inputs: ZipInput[], options: ZipParams) => Effect.Effect<Uint8Array, UploadistaError>;
3779
+ };
3780
+ declare const ZipPlugin_base: Context.TagClass<ZipPlugin, "ZipPlugin", ZipPluginShape>;
3781
+ /**
3782
+ * Context tag for the ZIP Plugin.
3783
+ *
3784
+ * This tag provides a type-safe way to access ZIP functionality
3785
+ * throughout the application using Effect's dependency injection system.
3786
+ *
3787
+ * @example
3788
+ * ```typescript
3789
+ * import { ZipPlugin } from "@uploadista/core/flow/plugins";
3790
+ *
3791
+ * // In your flow node
3792
+ * const program = Effect.gen(function* () {
3793
+ * const zipPlugin = yield* ZipPlugin;
3794
+ * const zipData = yield* zipPlugin.zip(files, { zipName: "archive.zip", includeMetadata: true });
3795
+ * return zipData;
3796
+ * });
3797
+ * ```
3798
+ */
3799
+ declare class ZipPlugin extends ZipPlugin_base {}
3800
+ //#endregion
3801
+ //#region src/flow/typed-flow.d.ts
3802
+ type NodeDefinition<TNodeError = never, TNodeRequirements = never> = FlowNode<any, any, UploadistaError$1> | Effect.Effect<FlowNode<any, any, UploadistaError$1>, TNodeError, TNodeRequirements>;
3803
+ type NodeDefinitionsRecord = Record<string, NodeDefinition<any, any>>;
3804
+ type NodeDefinitionError<T$1> = T$1 extends Effect.Effect<FlowNode<any, any, UploadistaError$1>, infer TError, any> ? TError : never;
3805
+ type NodeDefinitionRequirements<T$1> = T$1 extends Effect.Effect<FlowNode<any, any, UploadistaError$1>, any, infer TRequirements> ? TRequirements : never;
3806
+ type NodesErrorUnion<TNodes extends NodeDefinitionsRecord> = { [K in keyof TNodes]: NodeDefinitionError<TNodes[K]> }[keyof TNodes];
3807
+ type NodesRequirementsUnion<TNodes extends NodeDefinitionsRecord> = { [K in keyof TNodes]: NodeDefinitionRequirements<TNodes[K]> }[keyof TNodes];
3808
+ type FlowRequirements<TNodes extends NodeDefinitionsRecord> = NodesRequirementsUnion<TNodes>;
3809
+ type FlowPluginRequirements<TNodes extends NodeDefinitionsRecord> = Exclude<FlowRequirements<TNodes>, UploadServer>;
3810
+ type InferNode<T$1> = T$1 extends FlowNode<any, any, UploadistaError$1> ? T$1 : T$1 extends Effect.Effect<infer R, any, any> ? R extends FlowNode<any, any, UploadistaError$1> ? R : never : never;
3811
+ type ExtractKeysByNodeType<TNodes extends NodeDefinitionsRecord, TType extends NodeType> = { [K in keyof TNodes]: InferNode<TNodes[K]>["type"] extends TType ? K : never }[keyof TNodes];
3812
+ type SchemaInfer<T$1> = T$1 extends z.ZodTypeAny ? z.infer<T$1> : never;
3813
+ type FlowInputMap<TNodes extends NodeDefinitionsRecord> = { [K in Extract<ExtractKeysByNodeType<TNodes, NodeType.input>, string>]: SchemaInfer<InferNode<TNodes[K]>["inputSchema"]> };
3814
+ type FlowOutputMap<TNodes extends NodeDefinitionsRecord> = { [K in Extract<ExtractKeysByNodeType<TNodes, NodeType.output>, string>]: SchemaInfer<InferNode<TNodes[K]>["outputSchema"]> };
3815
+ type FlowInputUnion<TNodes extends NodeDefinitionsRecord> = { [K in Extract<ExtractKeysByNodeType<TNodes, NodeType.input>, string>]: SchemaInfer<InferNode<TNodes[K]>["inputSchema"]> }[Extract<ExtractKeysByNodeType<TNodes, NodeType.input>, string>];
3816
+ type FlowOutputUnion<TNodes extends NodeDefinitionsRecord> = { [K in Extract<ExtractKeysByNodeType<TNodes, NodeType.output>, string>]: SchemaInfer<InferNode<TNodes[K]>["outputSchema"]> }[Extract<ExtractKeysByNodeType<TNodes, NodeType.output>, string>];
3817
+ type NodeKey<TNodes extends NodeDefinitionsRecord> = Extract<keyof TNodes, string>;
3818
+ type TypedFlowEdge<TNodes extends NodeDefinitionsRecord> = {
3819
+ source: NodeKey<TNodes>;
3820
+ target: NodeKey<TNodes>;
3821
+ sourcePort?: string;
3822
+ targetPort?: string;
3823
+ };
3824
+ type TypedFlowConfig<TNodes extends NodeDefinitionsRecord> = {
3825
+ flowId: string;
3826
+ name: string;
3827
+ nodes: TNodes;
3828
+ edges: Array<TypedFlowEdge<TNodes>>;
3829
+ typeChecker?: TypeCompatibilityChecker;
3830
+ onEvent?: (event: FlowEvent) => Effect.Effect<{
3831
+ eventId: string | null;
3832
+ }, UploadistaError$1>;
3833
+ parallelExecution?: {
3834
+ enabled?: boolean;
3835
+ maxConcurrency?: number;
3836
+ };
3837
+ inputSchema?: z.ZodTypeAny;
3838
+ outputSchema?: z.ZodTypeAny;
3839
+ };
3840
+ declare const typedFlowInputsSymbol: unique symbol;
3841
+ declare const typedFlowOutputsSymbol: unique symbol;
3842
+ declare const typedFlowPluginsSymbol: unique symbol;
3843
+ type TypedFlow<TNodes extends NodeDefinitionsRecord, TInputSchema extends z.ZodTypeAny, TOutputSchema extends z.ZodTypeAny> = Flow<TInputSchema, TOutputSchema, FlowRequirements<TNodes>> & {
3844
+ run: (args: {
3845
+ inputs?: Partial<FlowInputMap<TNodes>>;
3846
+ storageId: string;
3847
+ jobId: string;
3848
+ }) => Effect.Effect<FlowExecutionResult<FlowOutputMap<TNodes>>, UploadistaError$1, FlowRequirements<TNodes>>;
3849
+ resume: (args: {
3850
+ jobId: string;
3851
+ storageId: string;
3852
+ nodeResults: Record<string, unknown>;
3853
+ executionState: {
3854
+ executionOrder: string[];
3855
+ currentIndex: number;
3856
+ inputs: Partial<FlowInputMap<TNodes>>;
3857
+ };
3858
+ }) => Effect.Effect<FlowExecutionResult<FlowOutputMap<TNodes>>, UploadistaError$1, FlowRequirements<TNodes>>;
3859
+ readonly [typedFlowInputsSymbol]?: FlowInputMap<TNodes>;
3860
+ readonly [typedFlowOutputsSymbol]?: FlowOutputMap<TNodes>;
3861
+ readonly [typedFlowPluginsSymbol]?: FlowPluginRequirements<TNodes>;
3862
+ };
3863
+ declare function createFlow<TNodes extends NodeDefinitionsRecord>(config: TypedFlowConfig<TNodes>): Effect.Effect<TypedFlow<TNodes, z.ZodType<FlowInputUnion<TNodes>>, z.ZodType<FlowOutputUnion<TNodes>>>, NodesErrorUnion<TNodes> | UploadistaError$1, FlowRequirements<TNodes>>;
3864
+ //#endregion
3865
+ //#region src/flow/types/flow-file.d.ts
3866
+ /**
3867
+ * Conditional execution rules for flow nodes.
3868
+ *
3869
+ * Conditions allow nodes to execute conditionally based on file properties or metadata.
3870
+ * They are evaluated before node execution and can skip nodes that don't match.
3871
+ *
3872
+ * @module flow/types/flow-file
3873
+ * @see {@link FlowNode} for how conditions are used in nodes
3874
+ *
3875
+ * @example
3876
+ * ```typescript
3877
+ * // Only process images larger than 1MB
3878
+ * const condition: FlowCondition = {
3879
+ * field: "size",
3880
+ * operator: "greaterThan",
3881
+ * value: 1024 * 1024
3882
+ * };
3883
+ *
3884
+ * // Only process JPEG images
3885
+ * const jpegCondition: FlowCondition = {
3886
+ * field: "mimeType",
3887
+ * operator: "startsWith",
3888
+ * value: "image/jpeg"
3889
+ * };
3890
+ * ```
3891
+ */
3892
+ /**
3893
+ * Represents a conditional rule for node execution.
3894
+ *
3895
+ * @property field - The file property to check
3896
+ * @property operator - The comparison operator to apply
3897
+ * @property value - The value to compare against
3898
+ *
3899
+ * @remarks
3900
+ * - Fields can check file metadata (mimeType, size) or image properties (width, height)
3901
+ * - String operators (contains, startsWith) work with string values
3902
+ * - Numeric operators (greaterThan, lessThan) work with numeric values
3903
+ * - The extension field checks the file extension without the dot
3904
+ */
3905
+ type FlowCondition = {
3906
+ field: "mimeType" | "size" | "width" | "height" | "extension";
3907
+ operator: "equals" | "notEquals" | "greaterThan" | "lessThan" | "contains" | "startsWith";
3908
+ value: string | number;
3909
+ };
3910
+ //#endregion
3911
+ //#region src/flow/types/run-args.d.ts
3912
+ /**
3913
+ * Zod schema for validating flow run arguments.
3914
+ *
3915
+ * @property inputs - Record mapping input node IDs to their input data
3916
+ *
3917
+ * @example
3918
+ * ```typescript
3919
+ * const args = {
3920
+ * inputs: {
3921
+ * "input-node-1": { file: myFile, metadata: { ... } },
3922
+ * "input-node-2": { file: anotherFile }
3923
+ * }
3924
+ * };
3925
+ *
3926
+ * // Validate before running
3927
+ * const validated = runArgsSchema.parse(args);
3928
+ * ```
3929
+ */
3930
+ declare const runArgsSchema: z.ZodObject<{
3931
+ inputs: z.ZodRecord<z.ZodString, z.ZodAny>;
3932
+ }, z.core.$strip>;
3933
+ /**
3934
+ * Type representing validated flow run arguments.
3935
+ *
3936
+ * This type is inferred from the runArgsSchema and ensures type safety
3937
+ * when passing inputs to flow execution.
3938
+ */
3939
+ type RunArgs = z.infer<typeof runArgsSchema>;
3940
+ //#endregion
3941
+ //#region src/flow/utils/resolve-upload-metadata.d.ts
3942
+ type FileMetadata = UploadFile["metadata"];
3943
+ type ResolvedUploadMetadata = {
3944
+ type: string;
3945
+ fileName: string;
3946
+ metadata: FileMetadata;
3947
+ metadataJson: string | undefined;
3948
+ };
3949
+ declare function resolveUploadMetadata(metadata: FileMetadata): ResolvedUploadMetadata;
3950
+ //#endregion
3951
+ export { FlowServerShape as $, FlowJobKVStore as $t, ImageAiContext as A, FlowEventJobStart as An, flowEventEmitter as At, StorageParams as B, NodeType as Bn, BufferedUploadFileDataStore as Bt, describeImageParamsSchema as C, waitingNodeExecution as Cn, BaseEventEmitter as Ct, resizeParamsSchema as D, FlowEventFlowError as Dn, TypedEventEmitter as Dt, ResizeParams as E, FlowEventFlowEnd as En, FlowEventEmitter as Et, ExecutionLevel as F, FlowEventNodeResume as Fn, UploadEvent as Ft, createInputNode as G, UploadFileDataStore as Gt, storageParamsSchema as H, getNodeData as Hn, DataStoreCapabilities as Ht, ParallelScheduler as I, FlowEventNodeStart as In, UploadEventType as It, FlowProvider as J, UploadStrategy as Jt, inputDataSchema as K, UploadFileDataStores as Kt, ParallelSchedulerConfig as L, ConditionField as Ln, uploadEventSchema as Lt, ImageAiPluginShape as M, FlowEventNodeError as Mn, WebSocketConnection as Mt, CredentialProvider as N, FlowEventNodePause as Nn, WebSocketMessage as Nt, OptimizeParams as O, FlowEventFlowStart as On, UploadEventEmitter as Ot, CredentialProviderShape as P, FlowEventNodeResponse as Pn, webSocketMessageSchema as Pt, FlowServerOptions as Q, BaseKvStoreService as Qt, TransformNodeConfig as R, ConditionOperator as Rn, EventBroadcaster as Rt, DescribeImageParams as S, completeNodeExecution as Sn, inputFileSchema as St, ImagePluginShape as T, FlowEvent as Tn, EventEmitter as Tt, InputData as U, DataStoreConfig as Ut, createStorageNode as V, createFlowNode as Vn, DataStore as Vt, InputNodeParams as W, DataStoreWriteOptions as Wt, FlowServer as X, isDataStore as Xt, FlowProviderShape as Y, createDataStoreLayer as Yt, FlowServerLayer as Z, BaseKvStore as Zt, ZipParams as _, FlowNodeData as _n, MiddlewareContext as _t, FlowCondition as a, uploadFileKvStore as an, FlowJobTaskStatus as at, RemoveBackgroundParams as b, NodeTypeMap as bn, MiddlewareServiceLive as bt, FlowPluginRequirements as c, Flow as cn, UploadStrategyOptions as ct, NodeDefinitionsRecord as d, createFlowWithSchema as dn, UploadServerShape as dt, KvStore as en, createFlowServer as et, TypedFlow as f, getFlowData as fn, createUploadServer as ft, ZipInput as g, FlowNode as gn, Middleware as gt, createFlow as h, FlowConfig as hn, detectMimeType as ht, runArgsSchema as i, jsonSerializer as in, FlowJobTask as it, ImageAiPlugin as j, FlowEventNodeEnd as jn, uploadEventEmitter as jt, optimizeParamsSchema as k, FlowEventJobEnd as kn, eventToMessageSerializer as kt, FlowRequirements as l, FlowData as ln, UploadServer as lt, TypedFlowEdge as m, createFlowEdge as mn, compareMimeTypes as mt, resolveUploadMetadata as n, UploadFileKVStore as nn, FlowJob as nt, FlowInputMap as o, UploadFile as on, NegotiatedStrategy as ot, TypedFlowConfig as p, FlowEdge as pn, uploadServer as pt, inputNodeParamsSchema as q, UploadFileDataStoresShape as qt, RunArgs as r, flowJobKvStore as rn, FlowJobStatus as rt, FlowOutputMap as s, uploadFileSchema as sn, UploadStrategyNegotiator as st, ResolvedUploadMetadata as t, TypedKvStore as tn, flowServer as tt, NodeDefinition as u, FlowExecutionResult as un, UploadServerOptions as ut, ZipPlugin as v, NodeConnectionValidator as vn, MiddlewareNext as vt, ImagePlugin as w, EventType as wn, BaseEventEmitterService as wt, removeBackgroundParamsSchema as x, TypeCompatibilityChecker as xn, InputFile as xt, ZipPluginShape as y, NodeExecutionResult as yn, MiddlewareService as yt, createTransformNode as z, ConditionValue as zn, EventBroadcasterService as zt };
3952
+ //# sourceMappingURL=index-BnGZO47X.d.ts.map