@uploadista/core 0.0.2 → 0.0.3

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