@uploadista/core 0.0.17 → 0.0.18-beta.10

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 (117) hide show
  1. package/README.md +102 -0
  2. package/dist/{checksum-DaCqP8Qa.mjs → checksum-COoD-F1l.mjs} +2 -2
  3. package/dist/{checksum-DaCqP8Qa.mjs.map → checksum-COoD-F1l.mjs.map} +1 -1
  4. package/dist/{checksum-BIlVW8bD.cjs → checksum-YLW4hVY7.cjs} +1 -1
  5. package/dist/errors/index.cjs +1 -1
  6. package/dist/errors/index.d.cts +1 -1
  7. package/dist/errors/index.d.mts +1 -1
  8. package/dist/errors/index.mjs +1 -1
  9. package/dist/flow/index.cjs +1 -1
  10. package/dist/flow/index.d.cts +5 -5
  11. package/dist/flow/index.d.mts +5 -5
  12. package/dist/flow/index.mjs +1 -1
  13. package/dist/flow-BLGpxdEm.mjs +2 -0
  14. package/dist/flow-BLGpxdEm.mjs.map +1 -0
  15. package/dist/flow-DaBzRGmY.cjs +1 -0
  16. package/dist/{index-BGi1r_fi.d.mts → index-9gyMMEIB.d.cts} +2 -2
  17. package/dist/{index-BGi1r_fi.d.mts.map → index-9gyMMEIB.d.cts.map} +1 -1
  18. package/dist/{index-B_SvQ0MU.d.cts → index-B9V5SSxl.d.mts} +2 -2
  19. package/dist/{index-B_SvQ0MU.d.cts.map → index-B9V5SSxl.d.mts.map} +1 -1
  20. package/dist/{index-DIWuZlxd.d.mts → index-BFSHumky.d.mts} +2 -2
  21. package/dist/{index-DIWuZlxd.d.mts.map → index-BFSHumky.d.mts.map} +1 -1
  22. package/dist/{index-BQ5luyME.d.cts → index-D7i4bgl3.d.mts} +2747 -828
  23. package/dist/index-D7i4bgl3.d.mts.map +1 -0
  24. package/dist/{index-qIN6ULCb.d.cts → index-DFbu_-zn.d.cts} +2 -2
  25. package/dist/{index-qIN6ULCb.d.cts.map → index-DFbu_-zn.d.cts.map} +1 -1
  26. package/dist/{index-BtnCNLsH.d.mts → index-fF-j_WhY.d.cts} +2747 -828
  27. package/dist/index-fF-j_WhY.d.cts.map +1 -0
  28. package/dist/index.cjs +1 -1
  29. package/dist/index.d.cts +5 -5
  30. package/dist/index.d.mts +5 -5
  31. package/dist/index.mjs +1 -1
  32. package/dist/{stream-limiter-D2Y8Z_Kv.mjs → stream-limiter-B9nsn2gb.mjs} +2 -2
  33. package/dist/{stream-limiter-D2Y8Z_Kv.mjs.map → stream-limiter-B9nsn2gb.mjs.map} +1 -1
  34. package/dist/{stream-limiter-By0fxkAh.cjs → stream-limiter-DyWOdil4.cjs} +1 -1
  35. package/dist/streams/index.cjs +1 -1
  36. package/dist/streams/index.d.cts +2 -2
  37. package/dist/streams/index.d.mts +2 -2
  38. package/dist/streams/index.mjs +1 -1
  39. package/dist/testing/index.cjs +1 -1
  40. package/dist/testing/index.d.cts +4 -4
  41. package/dist/testing/index.d.mts +4 -4
  42. package/dist/testing/index.mjs +1 -1
  43. package/dist/types/index.cjs +1 -1
  44. package/dist/types/index.d.cts +5 -5
  45. package/dist/types/index.d.mts +5 -5
  46. package/dist/types/index.mjs +1 -1
  47. package/dist/types-CH0BgiJN.mjs +2 -0
  48. package/dist/types-CH0BgiJN.mjs.map +1 -0
  49. package/dist/types-DUYVoR13.cjs +1 -0
  50. package/dist/upload/index.cjs +1 -1
  51. package/dist/upload/index.d.cts +4 -4
  52. package/dist/upload/index.d.mts +4 -4
  53. package/dist/upload/index.mjs +1 -1
  54. package/dist/{upload-bBgM3QFI.cjs → upload-CFT-dWPB.cjs} +1 -1
  55. package/dist/{upload-Bq9h95w6.mjs → upload-ggK-0ZBM.mjs} +2 -2
  56. package/dist/{upload-Bq9h95w6.mjs.map → upload-ggK-0ZBM.mjs.map} +1 -1
  57. package/dist/{uploadista-error-DCRIscEv.cjs → uploadista-error-BxBLmQtX.cjs} +4 -1
  58. package/dist/{uploadista-error-Bb-qIIKM.d.cts → uploadista-error-CYCmAtkZ.d.cts} +2 -2
  59. package/dist/uploadista-error-CYCmAtkZ.d.cts.map +1 -0
  60. package/dist/{uploadista-error-djFxVTLh.mjs → uploadista-error-CkSxSyNo.mjs} +4 -1
  61. package/dist/uploadista-error-CkSxSyNo.mjs.map +1 -0
  62. package/dist/{uploadista-error-D7Gubrr1.d.mts → uploadista-error-DR0XimpE.d.mts} +2 -2
  63. package/dist/uploadista-error-DR0XimpE.d.mts.map +1 -0
  64. package/dist/utils/index.cjs +1 -1
  65. package/dist/utils/index.d.cts +2 -2
  66. package/dist/utils/index.d.mts +2 -2
  67. package/dist/utils/index.mjs +1 -1
  68. package/dist/{utils-MQUZyB9S.mjs → utils-B-ZhQ6b0.mjs} +2 -2
  69. package/dist/{utils-MQUZyB9S.mjs.map → utils-B-ZhQ6b0.mjs.map} +1 -1
  70. package/dist/{utils-DxLVhlLd.cjs → utils-Dhq3vPqp.cjs} +1 -1
  71. package/docs/CIRCUIT_BREAKER.md +381 -0
  72. package/docs/DEAD-LETTER-QUEUE.md +374 -0
  73. package/package.json +11 -6
  74. package/src/errors/uploadista-error.ts +16 -1
  75. package/src/flow/README.md +102 -0
  76. package/src/flow/circuit-breaker-store.ts +382 -0
  77. package/src/flow/circuit-breaker.ts +99 -0
  78. package/src/flow/dead-letter-queue.ts +573 -0
  79. package/src/flow/distributed-circuit-breaker.ts +437 -0
  80. package/src/flow/event.ts +105 -1
  81. package/src/flow/flow-server.ts +70 -0
  82. package/src/flow/flow.ts +141 -3
  83. package/src/flow/index.ts +14 -2
  84. package/src/flow/input-type-registry.ts +229 -0
  85. package/src/flow/node-types/index.ts +26 -20
  86. package/src/flow/node.ts +48 -26
  87. package/src/flow/nodes/input-node.ts +4 -2
  88. package/src/flow/nodes/transform-node.ts +64 -6
  89. package/src/flow/output-type-registry.ts +231 -0
  90. package/src/flow/type-guards.ts +38 -22
  91. package/src/flow/typed-flow.ts +26 -0
  92. package/src/flow/types/dead-letter-item.ts +258 -0
  93. package/src/flow/types/flow-types.ts +320 -2
  94. package/src/flow/types/retry-policy.ts +260 -0
  95. package/src/flow/utils/file-naming.ts +308 -0
  96. package/src/types/circuit-breaker-store.ts +222 -0
  97. package/src/types/health-check.ts +204 -0
  98. package/src/types/index.ts +2 -0
  99. package/src/types/kv-store.ts +82 -2
  100. package/tests/flow/dead-letter-item.test.ts +283 -0
  101. package/tests/flow/dead-letter-queue.test.ts +613 -0
  102. package/tests/flow/file-naming.test.ts +390 -0
  103. package/tests/flow/retry-policy.test.ts +284 -0
  104. package/tests/flow/type-registry.test.ts +1 -1
  105. package/tests/flow/type-system.test.ts +17 -14
  106. package/dist/flow-BiUCrFTv.cjs +0 -1
  107. package/dist/flow-vXXjtBBv.mjs +0 -2
  108. package/dist/flow-vXXjtBBv.mjs.map +0 -1
  109. package/dist/index-BQ5luyME.d.cts.map +0 -1
  110. package/dist/index-BtnCNLsH.d.mts.map +0 -1
  111. package/dist/types-B5I4BioZ.cjs +0 -1
  112. package/dist/types-f6w5J3UD.mjs +0 -2
  113. package/dist/types-f6w5J3UD.mjs.map +0 -1
  114. package/dist/uploadista-error-Bb-qIIKM.d.cts.map +0 -1
  115. package/dist/uploadista-error-D7Gubrr1.d.mts.map +0 -1
  116. package/dist/uploadista-error-djFxVTLh.mjs.map +0 -1
  117. package/src/flow/type-registry.ts +0 -379
@@ -1,12 +1,82 @@
1
- import { n as UploadistaError } from "./uploadista-error-Bb-qIIKM.cjs";
2
- import { l as GenerateId, p as GenerateIdShape } from "./index-B_SvQ0MU.cjs";
1
+ import { n as UploadistaError } from "./uploadista-error-DR0XimpE.mjs";
2
+ import { l as GenerateId, p as GenerateIdShape } from "./index-B9V5SSxl.mjs";
3
3
  import { Context, Effect, Layer, Option, Stream } from "effect";
4
4
  import * as zod0 from "zod";
5
5
  import z$1, { z } from "zod";
6
6
  import * as zod_v4_core0 from "zod/v4/core";
7
7
 
8
- //#region src/types/upload-file.d.ts
8
+ //#region src/flow/circuit-breaker.d.ts
9
9
 
10
+ /**
11
+ * Circuit breaker state machine states.
12
+ *
13
+ * - `closed`: Normal operation, tracking failures in sliding window
14
+ * - `open`: Rejecting all requests immediately, waiting for reset timeout
15
+ * - `half-open`: Allowing limited test requests to probe service health
16
+ */
17
+ type CircuitBreakerState = "closed" | "open" | "half-open";
18
+ /**
19
+ * Configuration for a circuit breaker.
20
+ *
21
+ * @property enabled - Whether circuit breaker is active (default: false for backward compatibility)
22
+ * @property failureThreshold - Number of failures within window to trip circuit (default: 5)
23
+ * @property resetTimeout - Milliseconds to wait in open state before half-open (default: 30000)
24
+ * @property halfOpenRequests - Number of successful requests in half-open to close (default: 3)
25
+ * @property windowDuration - Sliding window duration in milliseconds (default: 60000)
26
+ * @property fallback - Behavior when circuit is open
27
+ */
28
+ interface CircuitBreakerConfig {
29
+ /** Whether circuit breaker is active (default: false) */
30
+ enabled?: boolean;
31
+ /** Number of failures within window to trip circuit (default: 5) */
32
+ failureThreshold?: number;
33
+ /** Milliseconds to wait in open state before half-open (default: 30000) */
34
+ resetTimeout?: number;
35
+ /** Number of successful requests in half-open to close (default: 3) */
36
+ halfOpenRequests?: number;
37
+ /** Sliding window duration in milliseconds (default: 60000) */
38
+ windowDuration?: number;
39
+ /** Behavior when circuit is open */
40
+ fallback?: CircuitBreakerFallback;
41
+ }
42
+ /**
43
+ * Fallback behavior when circuit is open.
44
+ *
45
+ * - `fail`: Fail immediately with CIRCUIT_BREAKER_OPEN error (default)
46
+ * - `skip`: Skip node, pass input through as output
47
+ * - `default`: Return a configured default value
48
+ */
49
+ type CircuitBreakerFallback = {
50
+ type: "fail";
51
+ } | {
52
+ type: "skip";
53
+ passThrough: true;
54
+ } | {
55
+ type: "default";
56
+ value: unknown;
57
+ };
58
+ /**
59
+ * Event emitted when circuit state changes.
60
+ */
61
+ interface CircuitBreakerEvent {
62
+ nodeType: string;
63
+ previousState: CircuitBreakerState;
64
+ newState: CircuitBreakerState;
65
+ timestamp: number;
66
+ failureCount?: number;
67
+ }
68
+ /**
69
+ * Callback type for circuit state change events.
70
+ */
71
+ type CircuitBreakerEventHandler = (event: CircuitBreakerEvent) => Effect.Effect<void, never, never>;
72
+ /**
73
+ * Default circuit breaker configuration values.
74
+ */
75
+ declare const DEFAULT_CIRCUIT_BREAKER_CONFIG: Required<Omit<CircuitBreakerConfig, "fallback">> & {
76
+ fallback: CircuitBreakerFallback;
77
+ };
78
+ //#endregion
79
+ //#region src/types/upload-file.d.ts
10
80
  /**
11
81
  * Zod schema for validating UploadFile objects.
12
82
  *
@@ -50,108 +120,830 @@ declare const uploadFileSchema: z.ZodObject<{
50
120
  * It contains all metadata needed to resume uploads, track progress, and locate files
51
121
  * in storage backends.
52
122
  *
53
- * @property id - Unique identifier for this upload
54
- * @property offset - Current byte offset (how many bytes have been uploaded)
55
- * @property storage - Storage backend information
56
- * @property storage.id - Storage backend identifier (e.g., "s3-production")
57
- * @property storage.type - Storage backend type (e.g., "s3", "azure", "gcs")
58
- * @property storage.path - Optional path prefix within the storage backend
59
- * @property storage.uploadId - Optional backend-specific upload ID (e.g., S3 multipart upload ID)
60
- * @property storage.bucket - Optional bucket or container name
61
- * @property storage.parts - Optional array of uploaded parts (used by data stores that need to track parts locally, like R2)
62
- * @property flow - Optional flow processing information (when file is part of a flow)
63
- * @property flow.flowId - ID of the flow processing this file
64
- * @property flow.nodeId - ID of the flow node that created this file
65
- * @property flow.jobId - ID of the flow job execution
66
- * @property size - Total file size in bytes (undefined if deferred)
67
- * @property metadata - Custom key-value metadata attached to the file
68
- * @property creationDate - ISO 8601 timestamp when upload was created
69
- * @property url - Optional public URL to access the file
70
- * @property sizeIsDeferred - True if file size is not known at upload start
71
- * @property checksum - Optional file checksum/hash value
72
- * @property checksumAlgorithm - Algorithm used for checksum (e.g., "md5", "sha256")
123
+ * @property id - Unique identifier for this upload
124
+ * @property offset - Current byte offset (how many bytes have been uploaded)
125
+ * @property storage - Storage backend information
126
+ * @property storage.id - Storage backend identifier (e.g., "s3-production")
127
+ * @property storage.type - Storage backend type (e.g., "s3", "azure", "gcs")
128
+ * @property storage.path - Optional path prefix within the storage backend
129
+ * @property storage.uploadId - Optional backend-specific upload ID (e.g., S3 multipart upload ID)
130
+ * @property storage.bucket - Optional bucket or container name
131
+ * @property storage.parts - Optional array of uploaded parts (used by data stores that need to track parts locally, like R2)
132
+ * @property flow - Optional flow processing information (when file is part of a flow)
133
+ * @property flow.flowId - ID of the flow processing this file
134
+ * @property flow.nodeId - ID of the flow node that created this file
135
+ * @property flow.jobId - ID of the flow job execution
136
+ * @property size - Total file size in bytes (undefined if deferred)
137
+ * @property metadata - Custom key-value metadata attached to the file
138
+ * @property creationDate - ISO 8601 timestamp when upload was created
139
+ * @property url - Optional public URL to access the file
140
+ * @property sizeIsDeferred - True if file size is not known at upload start
141
+ * @property checksum - Optional file checksum/hash value
142
+ * @property checksumAlgorithm - Algorithm used for checksum (e.g., "md5", "sha256")
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * // Create an UploadFile for a new upload
147
+ * const uploadFile: UploadFile = {
148
+ * id: "upload_abc123",
149
+ * offset: 0,
150
+ * size: 1024000,
151
+ * storage: {
152
+ * id: "s3-production",
153
+ * type: "s3",
154
+ * bucket: "my-uploads",
155
+ * path: "files/"
156
+ * },
157
+ * metadata: {
158
+ * fileName: "image.jpg",
159
+ * contentType: "image/jpeg",
160
+ * userId: "user_123"
161
+ * },
162
+ * creationDate: new Date().toISOString(),
163
+ * checksum: "5d41402abc4b2a76b9719d911017c592",
164
+ * checksumAlgorithm: "md5"
165
+ * };
166
+ *
167
+ * // UploadFile with flow processing
168
+ * const flowFile: UploadFile = {
169
+ * id: "upload_xyz789",
170
+ * offset: 0,
171
+ * size: 2048000,
172
+ * storage: {
173
+ * id: "s3-temp",
174
+ * type: "s3",
175
+ * bucket: "temp-processing"
176
+ * },
177
+ * flow: {
178
+ * flowId: "flow_resize_optimize",
179
+ * nodeId: "input_1",
180
+ * jobId: "job_456"
181
+ * }
182
+ * };
183
+ *
184
+ * // Resume an interrupted upload
185
+ * const resumingFile: UploadFile = {
186
+ * id: "upload_resume",
187
+ * offset: 524288, // Already uploaded 512KB
188
+ * size: 1024000,
189
+ * storage: {
190
+ * id: "s3-production",
191
+ * type: "s3",
192
+ * uploadId: "multipart_xyz" // S3 multipart upload ID
193
+ * }
194
+ * };
195
+ * ```
196
+ */
197
+ type UploadFile = {
198
+ id: string;
199
+ offset: number;
200
+ storage: {
201
+ id: string;
202
+ type: string;
203
+ path?: string | undefined;
204
+ uploadId?: string | undefined;
205
+ bucket?: string | undefined;
206
+ parts?: Array<{
207
+ partNumber: number;
208
+ etag: string;
209
+ size: number;
210
+ }> | undefined;
211
+ };
212
+ flow?: {
213
+ flowId: string;
214
+ nodeId: string;
215
+ jobId: string;
216
+ };
217
+ size?: number | undefined;
218
+ metadata?: Record<string, string | number | boolean> | undefined;
219
+ creationDate?: string | undefined;
220
+ url?: string | undefined;
221
+ sizeIsDeferred?: boolean | undefined;
222
+ checksum?: string | undefined;
223
+ checksumAlgorithm?: string | undefined;
224
+ };
225
+ //#endregion
226
+ //#region src/types/kv-store.d.ts
227
+ /**
228
+ * Base key-value store interface for raw string storage.
229
+ *
230
+ * This is the low-level interface that storage adapters implement.
231
+ * It stores raw string values without type safety or serialization.
232
+ *
233
+ * @property get - Retrieves a value by key, returns null if not found
234
+ * @property set - Stores a value with the given key
235
+ * @property delete - Removes a value by key
236
+ * @property list - Optional operation to list all keys with a given prefix
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * // Implement a BaseKvStore with Redis
241
+ * const redisKvStore: BaseKvStore = {
242
+ * get: (key) => Effect.tryPromise({
243
+ * try: () => redis.get(key),
244
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
245
+ * }),
246
+ *
247
+ * set: (key, value) => Effect.tryPromise({
248
+ * try: () => redis.set(key, value),
249
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
250
+ * }),
251
+ *
252
+ * delete: (key) => Effect.tryPromise({
253
+ * try: () => redis.del(key),
254
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
255
+ * }),
256
+ *
257
+ * list: (prefix) => Effect.tryPromise({
258
+ * try: () => redis.keys(`${prefix}*`),
259
+ * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
260
+ * })
261
+ * };
262
+ * ```
263
+ */
264
+ interface BaseKvStore {
265
+ readonly get: (key: string) => Effect.Effect<string | null, UploadistaError>;
266
+ readonly set: (key: string, value: string) => Effect.Effect<void, UploadistaError>;
267
+ readonly delete: (key: string) => Effect.Effect<void, UploadistaError>;
268
+ readonly list?: (keyPrefix: string) => Effect.Effect<Array<string>, UploadistaError>;
269
+ }
270
+ /**
271
+ * Type-safe key-value store interface with automatic serialization.
272
+ *
273
+ * This wraps a BaseKvStore and handles JSON serialization/deserialization
274
+ * for a specific data type, providing type safety and eliminating the need
275
+ * for manual JSON.stringify/parse calls.
276
+ *
277
+ * @template TData - The type of data stored in this KV store
278
+ *
279
+ * @property get - Retrieves and deserializes a value, fails if not found
280
+ * @property set - Serializes and stores a value
281
+ * @property delete - Removes a value by key
282
+ * @property list - Optional operation to list all keys (without prefix)
283
+ *
284
+ * @example
285
+ * ```typescript
286
+ * // Use a typed KV store
287
+ * const uploadStore: KvStore<UploadFile> = new TypedKvStore(
288
+ * baseStore,
289
+ * "uploads:",
290
+ * jsonSerializer.serialize,
291
+ * jsonSerializer.deserialize
292
+ * );
293
+ *
294
+ * // Store and retrieve typed data
295
+ * const program = Effect.gen(function* () {
296
+ * const file: UploadFile = {
297
+ * id: "file123",
298
+ * offset: 0,
299
+ * storage: { id: "s3", type: "s3" }
300
+ * };
301
+ *
302
+ * // Automatic serialization
303
+ * yield* uploadStore.set("file123", file);
304
+ *
305
+ * // Automatic deserialization with type safety
306
+ * const retrieved = yield* uploadStore.get("file123");
307
+ * console.log(retrieved.offset); // TypeScript knows this is a number
308
+ * });
309
+ * ```
310
+ */
311
+ type KvStore<TData> = {
312
+ readonly get: (key: string) => Effect.Effect<TData, UploadistaError>;
313
+ readonly set: (key: string, value: TData) => Effect.Effect<void, UploadistaError>;
314
+ readonly delete: (key: string) => Effect.Effect<void, UploadistaError>;
315
+ readonly list?: () => Effect.Effect<Array<string>, UploadistaError>;
316
+ };
317
+ /**
318
+ * Typed wrapper class that adds serialization to a BaseKvStore.
319
+ *
320
+ * This class implements the KvStore interface by wrapping a BaseKvStore
321
+ * and handling serialization/deserialization for a specific type. It also
322
+ * adds a key prefix to isolate different data types in the same store.
323
+ *
324
+ * @template TData - The type of data to store
325
+ *
326
+ * @example
327
+ * ```typescript
328
+ * // Create a typed store for UploadFile
329
+ * const uploadFileStore = new TypedKvStore<UploadFile>(
330
+ * baseKvStore,
331
+ * "uploadista:upload-file:", // All keys will be prefixed
332
+ * (data) => JSON.stringify(data),
333
+ * (str) => JSON.parse(str) as UploadFile
334
+ * );
335
+ *
336
+ * // Use the store
337
+ * const effect = Effect.gen(function* () {
338
+ * const file: UploadFile = { ... };
339
+ * yield* uploadFileStore.set("abc123", file);
340
+ * // Internally stores at key "uploadista:upload-file:abc123"
341
+ *
342
+ * const retrieved = yield* uploadFileStore.get("abc123");
343
+ * return retrieved;
344
+ * });
345
+ *
346
+ * // Custom serialization for binary data
347
+ * const binaryStore = new TypedKvStore<Uint8Array>(
348
+ * baseKvStore,
349
+ * "binary:",
350
+ * (data) => btoa(String.fromCharCode(...data)), // Base64 encode
351
+ * (str) => Uint8Array.from(atob(str), c => c.charCodeAt(0)) // Base64 decode
352
+ * );
353
+ * ```
354
+ */
355
+ declare class TypedKvStore<TData> implements KvStore<TData> {
356
+ private baseStore;
357
+ private keyPrefix;
358
+ private serialize;
359
+ private deserialize;
360
+ constructor(baseStore: BaseKvStore, keyPrefix: string, serialize: (data: TData) => string, deserialize: (str: string) => TData);
361
+ get: (key: string) => Effect.Effect<TData, UploadistaError>;
362
+ set: (key: string, value: TData) => Effect.Effect<void, UploadistaError>;
363
+ delete: (key: string) => Effect.Effect<void, UploadistaError>;
364
+ list: () => Effect.Effect<Array<string>, UploadistaError>;
365
+ }
366
+ /**
367
+ * Default JSON serialization helpers.
368
+ *
369
+ * These functions provide standard JSON serialization for use with TypedKvStore.
370
+ * They work with any JSON-serializable type.
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * const store = new TypedKvStore<MyType>(
375
+ * baseStore,
376
+ * "mydata:",
377
+ * jsonSerializer.serialize,
378
+ * jsonSerializer.deserialize
379
+ * );
380
+ * ```
381
+ */
382
+ declare const jsonSerializer: {
383
+ serialize: <T>(data: T) => string;
384
+ deserialize: <T>(str: string) => T;
385
+ };
386
+ declare const BaseKvStoreService_base: Context.TagClass<BaseKvStoreService, "BaseKvStore", BaseKvStore>;
387
+ /**
388
+ * Effect-TS context tag for the base untyped KV store.
389
+ *
390
+ * This is the low-level store that storage adapter implementations provide.
391
+ * Most application code should use typed stores like UploadFileKVStore instead.
392
+ *
393
+ * @example
394
+ * ```typescript
395
+ * // Provide a base store implementation
396
+ * const baseStoreLayer = Layer.succeed(BaseKvStoreService, redisKvStore);
397
+ *
398
+ * // Use in an Effect
399
+ * const effect = Effect.gen(function* () {
400
+ * const baseStore = yield* BaseKvStoreService;
401
+ * yield* baseStore.set("raw-key", "raw-value");
402
+ * });
403
+ * ```
404
+ */
405
+ declare class BaseKvStoreService extends BaseKvStoreService_base {}
406
+ declare const UploadFileKVStore_base: Context.TagClass<UploadFileKVStore, "UploadFileKVStore", KvStore<UploadFile>>;
407
+ /**
408
+ * Effect-TS context tag for the UploadFile typed KV store.
409
+ *
410
+ * This provides type-safe storage for UploadFile metadata. It's the primary
411
+ * way to store and retrieve upload metadata in the system.
412
+ *
413
+ * @example
414
+ * ```typescript
415
+ * const uploadEffect = Effect.gen(function* () {
416
+ * const kvStore = yield* UploadFileKVStore;
417
+ *
418
+ * // Store upload metadata
419
+ * const file: UploadFile = {
420
+ * id: "upload123",
421
+ * offset: 0,
422
+ * storage: { id: "s3", type: "s3" }
423
+ * };
424
+ * yield* kvStore.set("upload123", file);
425
+ *
426
+ * // Retrieve with type safety
427
+ * const retrieved = yield* kvStore.get("upload123");
428
+ * return retrieved;
429
+ * });
430
+ * ```
431
+ */
432
+ declare class UploadFileKVStore extends UploadFileKVStore_base {}
433
+ /**
434
+ * Effect Layer that creates the UploadFileKVStore from a BaseKvStore.
435
+ *
436
+ * This layer automatically wires up JSON serialization for UploadFile objects
437
+ * with the "uploadista:upload-file:" key prefix.
438
+ *
439
+ * @example
440
+ * ```typescript
441
+ * const program = Effect.gen(function* () {
442
+ * const kvStore = yield* UploadFileKVStore;
443
+ * // Use the store...
444
+ * }).pipe(
445
+ * Effect.provide(uploadFileKvStore),
446
+ * Effect.provide(baseStoreLayer)
447
+ * );
448
+ * ```
449
+ */
450
+ declare const uploadFileKvStore: Layer.Layer<UploadFileKVStore, never, BaseKvStoreService>;
451
+ declare const FlowJobKVStore_base: Context.TagClass<FlowJobKVStore, "FlowJobKVStore", KvStore<FlowJob>>;
452
+ /**
453
+ * Effect-TS context tag for the FlowJob typed KV store.
454
+ *
455
+ * This provides type-safe storage for FlowJob metadata, tracking the
456
+ * execution state of flow processing jobs.
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * const flowEffect = Effect.gen(function* () {
461
+ * const jobStore = yield* FlowJobKVStore;
462
+ *
463
+ * // Store job state
464
+ * const job: FlowJob = {
465
+ * id: "job123",
466
+ * flowId: "flow_resize",
467
+ * status: "running",
468
+ * tasks: [],
469
+ * createdAt: new Date(),
470
+ * updatedAt: new Date()
471
+ * };
472
+ * yield* jobStore.set("job123", job);
473
+ *
474
+ * // Retrieve and check status
475
+ * const retrieved = yield* jobStore.get("job123");
476
+ * return retrieved.status;
477
+ * });
478
+ * ```
479
+ */
480
+ declare class FlowJobKVStore extends FlowJobKVStore_base {}
481
+ /**
482
+ * Effect Layer that creates the FlowJobKVStore from a BaseKvStore.
483
+ *
484
+ * This layer automatically wires up JSON serialization for FlowJob objects
485
+ * with the "uploadista:flow-job:" key prefix.
486
+ *
487
+ * @example
488
+ * ```typescript
489
+ * const program = Effect.gen(function* () {
490
+ * const jobStore = yield* FlowJobKVStore;
491
+ * // Use the store...
492
+ * }).pipe(
493
+ * Effect.provide(flowJobKvStore),
494
+ * Effect.provide(baseStoreLayer)
495
+ * );
496
+ * ```
497
+ */
498
+ declare const flowJobKvStore: Layer.Layer<FlowJobKVStore, never, BaseKvStoreService>;
499
+ declare const DeadLetterQueueKVStore_base: Context.TagClass<DeadLetterQueueKVStore, "DeadLetterQueueKVStore", KvStore<DeadLetterItem>>;
500
+ /**
501
+ * Effect-TS context tag for the Dead Letter Queue typed KV store.
502
+ *
503
+ * This provides type-safe storage for DeadLetterItem objects, tracking
504
+ * failed flow jobs for retry, debugging, and manual intervention.
505
+ *
506
+ * @example
507
+ * ```typescript
508
+ * const dlqEffect = Effect.gen(function* () {
509
+ * const dlqStore = yield* DeadLetterQueueKVStore;
510
+ *
511
+ * // Store a DLQ item
512
+ * const item: DeadLetterItem = {
513
+ * id: "dlq_123",
514
+ * jobId: "job_456",
515
+ * flowId: "image-pipeline",
516
+ * storageId: "s3",
517
+ * clientId: "client_789",
518
+ * error: { code: "FLOW_NODE_ERROR", message: "Timeout" },
519
+ * inputs: { input: { uploadId: "upload_abc" } },
520
+ * nodeResults: {},
521
+ * retryCount: 0,
522
+ * maxRetries: 3,
523
+ * retryHistory: [],
524
+ * createdAt: new Date(),
525
+ * updatedAt: new Date(),
526
+ * status: "pending"
527
+ * };
528
+ * yield* dlqStore.set("dlq_123", item);
529
+ *
530
+ * // Retrieve with type safety
531
+ * const retrieved = yield* dlqStore.get("dlq_123");
532
+ * return retrieved.status;
533
+ * });
534
+ * ```
535
+ */
536
+ declare class DeadLetterQueueKVStore extends DeadLetterQueueKVStore_base {}
537
+ /**
538
+ * Effect Layer that creates the DeadLetterQueueKVStore from a BaseKvStore.
539
+ *
540
+ * This layer automatically wires up JSON serialization for DeadLetterItem objects
541
+ * with the "uploadista:dlq:" key prefix.
542
+ *
543
+ * @example
544
+ * ```typescript
545
+ * const program = Effect.gen(function* () {
546
+ * const dlqStore = yield* DeadLetterQueueKVStore;
547
+ * // Use the store...
548
+ * }).pipe(
549
+ * Effect.provide(deadLetterQueueKvStore),
550
+ * Effect.provide(baseStoreLayer)
551
+ * );
552
+ * ```
553
+ */
554
+ declare const deadLetterQueueKvStore: Layer.Layer<DeadLetterQueueKVStore, never, BaseKvStoreService>;
555
+ //#endregion
556
+ //#region src/types/circuit-breaker-store.d.ts
557
+ /**
558
+ * Circuit breaker state values.
559
+ */
560
+ type CircuitBreakerStateValue = "closed" | "open" | "half-open";
561
+ /**
562
+ * Persisted circuit breaker state data.
563
+ *
564
+ * This represents the full state of a circuit breaker that needs to be
565
+ * stored and shared across instances.
566
+ */
567
+ interface CircuitBreakerStateData {
568
+ /** Current circuit state */
569
+ state: CircuitBreakerStateValue;
570
+ /** Number of failures in current window */
571
+ failureCount: number;
572
+ /** Timestamp of last state transition */
573
+ lastStateChange: number;
574
+ /** Number of successful requests in half-open state */
575
+ halfOpenSuccesses: number;
576
+ /** Timestamp when the current failure window started */
577
+ windowStart: number;
578
+ /** Configuration snapshot for consistency */
579
+ config: {
580
+ failureThreshold: number;
581
+ resetTimeout: number;
582
+ halfOpenRequests: number;
583
+ windowDuration: number;
584
+ };
585
+ }
586
+ /**
587
+ * Statistics about a circuit breaker.
588
+ */
589
+ interface CircuitBreakerStats {
590
+ nodeType: string;
591
+ state: CircuitBreakerStateValue;
592
+ failureCount: number;
593
+ halfOpenSuccesses: number;
594
+ timeSinceLastStateChange: number;
595
+ timeUntilHalfOpen?: number;
596
+ }
597
+ /**
598
+ * Interface for circuit breaker state storage.
599
+ *
600
+ * Implementations should handle distributed state for circuit breakers,
601
+ * allowing multiple instances to share circuit state. The interface is
602
+ * designed to work with eventually consistent stores - perfect consistency
603
+ * is not required for circuit breaker functionality.
604
+ *
605
+ * @example
606
+ * ```typescript
607
+ * // Using the store
608
+ * const store: CircuitBreakerStore = yield* CircuitBreakerStoreService;
609
+ *
610
+ * // Record a failure
611
+ * const newCount = yield* store.incrementFailures("describe-image", 60000);
612
+ * if (newCount >= 5) {
613
+ * yield* store.setState("describe-image", {
614
+ * state: "open",
615
+ * failureCount: newCount,
616
+ * lastStateChange: Date.now(),
617
+ * // ...
618
+ * });
619
+ * }
620
+ * ```
621
+ */
622
+ interface CircuitBreakerStore {
623
+ /**
624
+ * Gets the current state data for a circuit breaker.
625
+ *
626
+ * @param nodeType - The node type identifier
627
+ * @returns The state data or null if no state exists
628
+ */
629
+ readonly getState: (nodeType: string) => Effect.Effect<CircuitBreakerStateData | null, UploadistaError>;
630
+ /**
631
+ * Sets the complete state for a circuit breaker.
632
+ *
633
+ * @param nodeType - The node type identifier
634
+ * @param state - The new state data
635
+ */
636
+ readonly setState: (nodeType: string, state: CircuitBreakerStateData) => Effect.Effect<void, UploadistaError>;
637
+ /**
638
+ * Increments the failure count and returns the new count.
639
+ *
640
+ * This operation should be atomic where possible. For stores that don't
641
+ * support atomic increment, a read-modify-write is acceptable as circuit
642
+ * breakers tolerate eventual consistency.
643
+ *
644
+ * The implementation should also handle window expiry - if the window
645
+ * has expired, reset the count before incrementing.
646
+ *
647
+ * @param nodeType - The node type identifier
648
+ * @param windowDuration - Duration of the sliding window in milliseconds
649
+ * @returns The new failure count after incrementing
650
+ */
651
+ readonly incrementFailures: (nodeType: string, windowDuration: number) => Effect.Effect<number, UploadistaError>;
652
+ /**
653
+ * Resets the failure count to zero.
654
+ *
655
+ * Called when circuit closes or on successful requests.
656
+ *
657
+ * @param nodeType - The node type identifier
658
+ */
659
+ readonly resetFailures: (nodeType: string) => Effect.Effect<void, UploadistaError>;
660
+ /**
661
+ * Increments the half-open success count.
662
+ *
663
+ * @param nodeType - The node type identifier
664
+ * @returns The new half-open success count
665
+ */
666
+ readonly incrementHalfOpenSuccesses: (nodeType: string) => Effect.Effect<number, UploadistaError>;
667
+ /**
668
+ * Gets statistics for all tracked circuit breakers.
669
+ *
670
+ * @returns Map of node type to stats
671
+ */
672
+ readonly getAllStats: () => Effect.Effect<Map<string, CircuitBreakerStats>, UploadistaError>;
673
+ /**
674
+ * Deletes circuit breaker state for a node type.
675
+ *
676
+ * @param nodeType - The node type identifier
677
+ */
678
+ readonly delete: (nodeType: string) => Effect.Effect<void, UploadistaError>;
679
+ }
680
+ declare const CircuitBreakerStoreService_base: Context.TagClass<CircuitBreakerStoreService, "CircuitBreakerStoreService", CircuitBreakerStore>;
681
+ /**
682
+ * Effect-TS context tag for the CircuitBreakerStore service.
683
+ *
684
+ * Use this to inject a circuit breaker store into your Effect programs.
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * const program = Effect.gen(function* () {
689
+ * const cbStore = yield* CircuitBreakerStoreService;
690
+ * const state = yield* cbStore.getState("my-node-type");
691
+ * // ...
692
+ * });
693
+ *
694
+ * // Provide the implementation
695
+ * const result = yield* program.pipe(
696
+ * Effect.provide(kvCircuitBreakerStoreLayer)
697
+ * );
698
+ * ```
699
+ */
700
+ declare class CircuitBreakerStoreService extends CircuitBreakerStoreService_base {}
701
+ /**
702
+ * Creates a default initial state for a circuit breaker.
703
+ *
704
+ * @param config - Circuit breaker configuration
705
+ * @returns Initial state data with closed circuit
706
+ */
707
+ declare function createInitialCircuitBreakerState(config: {
708
+ failureThreshold: number;
709
+ resetTimeout: number;
710
+ halfOpenRequests: number;
711
+ windowDuration: number;
712
+ }): CircuitBreakerStateData;
713
+ //#endregion
714
+ //#region src/flow/circuit-breaker-store.d.ts
715
+ /**
716
+ * Creates a CircuitBreakerStore backed by any BaseKvStore.
717
+ *
718
+ * This adapter wraps a generic KV store to provide circuit breaker state
719
+ * storage. It handles:
720
+ * - JSON serialization of state data
721
+ * - Sliding window expiry (checked on read/increment)
722
+ * - Read-modify-write for increment operations
723
+ *
724
+ * Note: This implementation uses read-modify-write for increments, which
725
+ * may have race conditions under high concurrency. This is acceptable for
726
+ * circuit breakers as they tolerate eventual consistency.
727
+ *
728
+ * @param baseStore - The underlying KV store
729
+ * @returns A CircuitBreakerStore implementation
730
+ *
731
+ * @example
732
+ * ```typescript
733
+ * const baseStore = makeRedisBaseKvStore({ redis: redisClient });
734
+ * const cbStore = makeKvCircuitBreakerStore(baseStore);
735
+ *
736
+ * // Use the store
737
+ * yield* cbStore.incrementFailures("describe-image", 60000);
738
+ * ```
739
+ */
740
+ declare function makeKvCircuitBreakerStore(baseStore: BaseKvStore): CircuitBreakerStore;
741
+ /**
742
+ * Creates an in-memory CircuitBreakerStore.
743
+ *
744
+ * This implementation keeps all state in memory and is suitable for:
745
+ * - Single-instance deployments
746
+ * - Development and testing
747
+ * - Serverless functions (where state is ephemeral anyway)
748
+ *
749
+ * @returns A CircuitBreakerStore backed by in-memory Map
750
+ *
751
+ * @example
752
+ * ```typescript
753
+ * const cbStore = makeMemoryCircuitBreakerStore();
754
+ *
755
+ * // Use for testing
756
+ * yield* cbStore.incrementFailures("test-node", 60000);
757
+ * const state = yield* cbStore.getState("test-node");
758
+ * ```
759
+ */
760
+ declare function makeMemoryCircuitBreakerStore(): CircuitBreakerStore;
761
+ /**
762
+ * Effect Layer that provides a CircuitBreakerStore backed by the BaseKvStore.
763
+ *
764
+ * Use this layer when you want circuit breaker state to be distributed
765
+ * across multiple instances (e.g., in a cluster).
766
+ *
767
+ * @example
768
+ * ```typescript
769
+ * const program = Effect.gen(function* () {
770
+ * const cbStore = yield* CircuitBreakerStoreService;
771
+ * // ...
772
+ * }).pipe(
773
+ * Effect.provide(kvCircuitBreakerStoreLayer),
774
+ * Effect.provide(redisKvStore({ redis: redisClient }))
775
+ * );
776
+ * ```
777
+ */
778
+ declare const kvCircuitBreakerStoreLayer: Layer.Layer<CircuitBreakerStoreService, never, BaseKvStoreService>;
779
+ /**
780
+ * Effect Layer that provides an in-memory CircuitBreakerStore.
781
+ *
782
+ * Use this layer for single-instance deployments, development, or testing.
783
+ *
784
+ * @example
785
+ * ```typescript
786
+ * const program = Effect.gen(function* () {
787
+ * const cbStore = yield* CircuitBreakerStoreService;
788
+ * // ...
789
+ * }).pipe(
790
+ * Effect.provide(memoryCircuitBreakerStoreLayer)
791
+ * );
792
+ * ```
793
+ */
794
+ declare const memoryCircuitBreakerStoreLayer: Layer.Layer<CircuitBreakerStoreService, never, never>;
795
+ //#endregion
796
+ //#region src/flow/distributed-circuit-breaker.d.ts
797
+ /**
798
+ * Result of checking if a request is allowed.
799
+ */
800
+ interface AllowRequestResult {
801
+ allowed: boolean;
802
+ state: CircuitBreakerStateValue;
803
+ failureCount: number;
804
+ }
805
+ /**
806
+ * Distributed circuit breaker that uses a store for state persistence.
807
+ *
808
+ * Unlike the in-memory CircuitBreaker, this implementation stores all state
809
+ * in a CircuitBreakerStore, allowing multiple instances to share circuit state.
810
+ *
811
+ * All operations are Effect-based since they may involve I/O.
73
812
  *
74
813
  * @example
75
814
  * ```typescript
76
- * // Create an UploadFile for a new upload
77
- * const uploadFile: UploadFile = {
78
- * id: "upload_abc123",
79
- * offset: 0,
80
- * size: 1024000,
81
- * storage: {
82
- * id: "s3-production",
83
- * type: "s3",
84
- * bucket: "my-uploads",
85
- * path: "files/"
86
- * },
87
- * metadata: {
88
- * fileName: "image.jpg",
89
- * contentType: "image/jpeg",
90
- * userId: "user_123"
91
- * },
92
- * creationDate: new Date().toISOString(),
93
- * checksum: "5d41402abc4b2a76b9719d911017c592",
94
- * checksumAlgorithm: "md5"
95
- * };
815
+ * const breaker = new DistributedCircuitBreaker(
816
+ * "describe-image",
817
+ * { enabled: true, failureThreshold: 5 },
818
+ * store
819
+ * );
96
820
  *
97
- * // UploadFile with flow processing
98
- * const flowFile: UploadFile = {
99
- * id: "upload_xyz789",
100
- * offset: 0,
101
- * size: 2048000,
102
- * storage: {
103
- * id: "s3-temp",
104
- * type: "s3",
105
- * bucket: "temp-processing"
106
- * },
107
- * flow: {
108
- * flowId: "flow_resize_optimize",
109
- * nodeId: "input_1",
110
- * jobId: "job_456"
111
- * }
112
- * };
821
+ * // Check if request is allowed
822
+ * const { allowed, state } = yield* breaker.allowRequest();
823
+ * if (!allowed) {
824
+ * // Handle circuit open
825
+ * }
113
826
  *
114
- * // Resume an interrupted upload
115
- * const resumingFile: UploadFile = {
116
- * id: "upload_resume",
117
- * offset: 524288, // Already uploaded 512KB
118
- * size: 1024000,
119
- * storage: {
120
- * id: "s3-production",
121
- * type: "s3",
122
- * uploadId: "multipart_xyz" // S3 multipart upload ID
123
- * }
124
- * };
827
+ * // Record result
828
+ * try {
829
+ * const result = yield* executeNode();
830
+ * yield* breaker.recordSuccess();
831
+ * return result;
832
+ * } catch (error) {
833
+ * yield* breaker.recordFailure(error.message);
834
+ * throw error;
835
+ * }
125
836
  * ```
126
837
  */
127
- type UploadFile = {
128
- id: string;
129
- offset: number;
130
- storage: {
131
- id: string;
132
- type: string;
133
- path?: string | undefined;
134
- uploadId?: string | undefined;
135
- bucket?: string | undefined;
136
- parts?: Array<{
137
- partNumber: number;
138
- etag: string;
139
- size: number;
140
- }> | undefined;
141
- };
142
- flow?: {
143
- flowId: string;
144
- nodeId: string;
145
- jobId: string;
838
+ declare class DistributedCircuitBreaker {
839
+ private eventHandler?;
840
+ readonly nodeType: string;
841
+ readonly config: Required<Omit<CircuitBreakerConfig, "fallback">> & {
842
+ fallback: CircuitBreakerFallback;
146
843
  };
147
- size?: number | undefined;
148
- metadata?: Record<string, string | number | boolean> | undefined;
149
- creationDate?: string | undefined;
150
- url?: string | undefined;
151
- sizeIsDeferred?: boolean | undefined;
152
- checksum?: string | undefined;
153
- checksumAlgorithm?: string | undefined;
154
- };
844
+ readonly store: CircuitBreakerStore;
845
+ constructor(nodeType: string, config: CircuitBreakerConfig, store: CircuitBreakerStore);
846
+ /**
847
+ * Sets the event handler for state change notifications.
848
+ */
849
+ setEventHandler(handler: CircuitBreakerEventHandler): void;
850
+ /**
851
+ * Checks if a request is allowed through the circuit.
852
+ *
853
+ * This method reads state from the store, checks for time-based transitions,
854
+ * and returns whether the request should proceed.
855
+ */
856
+ allowRequest(): Effect.Effect<AllowRequestResult, UploadistaError>;
857
+ /**
858
+ * Gets the current circuit state from the store.
859
+ */
860
+ getState(): Effect.Effect<CircuitBreakerStateValue, UploadistaError>;
861
+ /**
862
+ * Gets the current failure count from the store.
863
+ */
864
+ getFailureCount(): Effect.Effect<number, UploadistaError>;
865
+ /**
866
+ * Records a successful execution.
867
+ *
868
+ * In half-open state, tracks successes toward closing the circuit.
869
+ * In closed state, resets the failure count.
870
+ */
871
+ recordSuccess(): Effect.Effect<void, UploadistaError>;
872
+ /**
873
+ * Records a failed execution.
874
+ *
875
+ * In closed state, increments failure count and may trip the circuit.
876
+ * In half-open state, immediately reopens the circuit.
877
+ */
878
+ recordFailure(_errorMessage: string): Effect.Effect<void, UploadistaError>;
879
+ /**
880
+ * Gets the fallback configuration.
881
+ */
882
+ getFallback(): CircuitBreakerFallback;
883
+ /**
884
+ * Resets the circuit breaker to closed state.
885
+ */
886
+ reset(): Effect.Effect<void, UploadistaError>;
887
+ /**
888
+ * Transitions to a new state.
889
+ */
890
+ private transitionTo;
891
+ /**
892
+ * Emits a state change event if handler is set.
893
+ */
894
+ private emitEvent;
895
+ }
896
+ /**
897
+ * Registry for managing distributed circuit breakers.
898
+ *
899
+ * Unlike the in-memory CircuitBreakerRegistry, this registry creates
900
+ * DistributedCircuitBreaker instances that share state via a store.
901
+ *
902
+ * @example
903
+ * ```typescript
904
+ * const store = makeKvCircuitBreakerStore(baseKvStore);
905
+ * const registry = new DistributedCircuitBreakerRegistry(store);
906
+ *
907
+ * const breaker = registry.getOrCreate("describe-image", {
908
+ * enabled: true,
909
+ * failureThreshold: 5
910
+ * });
911
+ * ```
912
+ */
913
+ declare class DistributedCircuitBreakerRegistry {
914
+ readonly store: CircuitBreakerStore;
915
+ private breakers;
916
+ private eventHandler?;
917
+ constructor(store: CircuitBreakerStore);
918
+ /**
919
+ * Sets a global event handler for all circuit breakers.
920
+ */
921
+ setEventHandler(handler: CircuitBreakerEventHandler): void;
922
+ /**
923
+ * Gets an existing circuit breaker or creates a new one.
924
+ */
925
+ getOrCreate(nodeType: string, config: CircuitBreakerConfig): DistributedCircuitBreaker;
926
+ /**
927
+ * Gets an existing circuit breaker if it exists.
928
+ */
929
+ get(nodeType: string): DistributedCircuitBreaker | undefined;
930
+ /**
931
+ * Gets statistics for all circuit breakers from the store.
932
+ */
933
+ getAllStats(): Effect.Effect<Map<string, {
934
+ state: CircuitBreakerStateValue;
935
+ failureCount: number;
936
+ }>, UploadistaError>;
937
+ /**
938
+ * Resets all circuit breakers.
939
+ */
940
+ resetAll(): Effect.Effect<void, UploadistaError>;
941
+ /**
942
+ * Clears all circuit breakers from the local cache.
943
+ * Note: This does not clear state from the store.
944
+ */
945
+ clear(): void;
946
+ }
155
947
  //#endregion
156
948
  //#region src/flow/node.d.ts
157
949
  /**
@@ -211,8 +1003,11 @@ type ConditionValue = string | number;
211
1003
  * @param config.retry.maxRetries - Maximum number of retry attempts (default: 0)
212
1004
  * @param config.retry.retryDelay - Base delay in milliseconds between retries (default: 1000)
213
1005
  * @param config.retry.exponentialBackoff - Whether to use exponential backoff for retries (default: true)
214
- * @param config.nodeTypeId - Optional type ID from the registry (e.g., "storage-output-v1"). If provided, the node type must be registered.
1006
+ * @param config.inputTypeId - Optional input type ID from inputTypeRegistry (e.g., "streaming-input-v1"). Used for input nodes to describe external interface.
1007
+ * @param config.outputTypeId - Optional output type ID from outputTypeRegistry (e.g., "storage-output-v1"). Used for result type tagging.
215
1008
  * @param config.keepOutput - If true, preserves this node's output even if it has outgoing edges (default: false). Useful for flows where intermediate results need to be kept (e.g., preserving the original file when also running OCR on it).
1009
+ * @param config.circuitBreaker - Optional circuit breaker configuration for resilience. Overrides flow-level circuit breaker defaults for this node.
1010
+ * @param config.nodeTypeId - Stable node type identifier for circuit breaker configuration. Used to share circuit breaker state across nodes of the same type and for nodeTypeOverrides. Example: "describe-image", "remove-background", "scan-virus"
216
1011
  *
217
1012
  * @returns An Effect that succeeds with the created FlowNode
218
1013
  *
@@ -259,8 +1054,11 @@ declare function createFlowNode<Input, Output, TType extends NodeType = NodeType
259
1054
  multiOutput,
260
1055
  pausable,
261
1056
  retry,
262
- nodeTypeId,
263
- keepOutput
1057
+ inputTypeId,
1058
+ outputTypeId,
1059
+ keepOutput,
1060
+ circuitBreaker,
1061
+ nodeTypeId
264
1062
  }: {
265
1063
  id: string;
266
1064
  name: string;
@@ -288,8 +1086,19 @@ declare function createFlowNode<Input, Output, TType extends NodeType = NodeType
288
1086
  retryDelay?: number;
289
1087
  exponentialBackoff?: boolean;
290
1088
  };
291
- nodeTypeId?: string;
1089
+ /** Input type ID from inputTypeRegistry - for input nodes describing external interface */
1090
+ inputTypeId?: string;
1091
+ /** Output type ID from outputTypeRegistry - for result type tagging */
1092
+ outputTypeId?: string;
292
1093
  keepOutput?: boolean;
1094
+ /** Circuit breaker configuration for resilience (overrides flow defaults) */
1095
+ circuitBreaker?: FlowCircuitBreakerConfig;
1096
+ /**
1097
+ * Stable node type identifier for circuit breaker configuration.
1098
+ * Used to share circuit breaker state across nodes of the same type and for nodeTypeOverrides.
1099
+ * Example: "describe-image", "remove-background", "scan-virus"
1100
+ */
1101
+ nodeTypeId?: string;
293
1102
  }): Effect.Effect<FlowNode<Input, Output, UploadistaError> & {
294
1103
  type: TType;
295
1104
  }, UploadistaError>;
@@ -301,7 +1110,7 @@ declare function createFlowNode<Input, Output, TType extends NodeType = NodeType
301
1110
  * the executable run function or schemas.
302
1111
  *
303
1112
  * @param node - The flow node to extract data from
304
- * @returns A plain object containing the node's metadata (id, name, description, type)
1113
+ * @returns A plain object containing the node's metadata (id, name, description, type, inputTypeId, outputTypeId)
305
1114
  */
306
1115
  declare const getNodeData: (node: FlowNode<any, any, UploadistaError>) => FlowNodeData;
307
1116
  //#endregion
@@ -351,6 +1160,18 @@ declare enum EventType {
351
1160
  NodeStream = "node-stream",
352
1161
  /** Emitted for node response data */
353
1162
  NodeResponse = "node-response",
1163
+ /** Emitted when a job is added to the Dead Letter Queue */
1164
+ DlqItemAdded = "dlq-item-added",
1165
+ /** Emitted when a DLQ retry attempt starts */
1166
+ DlqRetryStart = "dlq-retry-start",
1167
+ /** Emitted when a DLQ retry succeeds */
1168
+ DlqRetrySuccess = "dlq-retry-success",
1169
+ /** Emitted when a DLQ retry fails */
1170
+ DlqRetryFailed = "dlq-retry-failed",
1171
+ /** Emitted when a DLQ item is exhausted (max retries reached) */
1172
+ DlqItemExhausted = "dlq-item-exhausted",
1173
+ /** Emitted when a DLQ item is resolved */
1174
+ DlqItemResolved = "dlq-item-resolved",
354
1175
  }
355
1176
  /**
356
1177
  * Event emitted when a job starts execution.
@@ -526,6 +1347,77 @@ type FlowEventNodeResponse = {
526
1347
  nodeName: string;
527
1348
  data: unknown;
528
1349
  };
1350
+ /**
1351
+ * Event emitted when a job is added to the Dead Letter Queue.
1352
+ */
1353
+ type FlowEventDlqItemAdded = {
1354
+ eventType: EventType.DlqItemAdded;
1355
+ dlqItemId: string;
1356
+ jobId: string;
1357
+ flowId: string;
1358
+ errorCode: string;
1359
+ errorMessage: string;
1360
+ retryCount: number;
1361
+ maxRetries: number;
1362
+ };
1363
+ /**
1364
+ * Event emitted when a DLQ retry attempt starts.
1365
+ */
1366
+ type FlowEventDlqRetryStart = {
1367
+ eventType: EventType.DlqRetryStart;
1368
+ dlqItemId: string;
1369
+ jobId: string;
1370
+ flowId: string;
1371
+ attemptNumber: number;
1372
+ };
1373
+ /**
1374
+ * Event emitted when a DLQ retry succeeds.
1375
+ */
1376
+ type FlowEventDlqRetrySuccess = {
1377
+ eventType: EventType.DlqRetrySuccess;
1378
+ dlqItemId: string;
1379
+ jobId: string;
1380
+ flowId: string;
1381
+ attemptNumber: number;
1382
+ durationMs: number;
1383
+ };
1384
+ /**
1385
+ * Event emitted when a DLQ retry fails.
1386
+ */
1387
+ type FlowEventDlqRetryFailed = {
1388
+ eventType: EventType.DlqRetryFailed;
1389
+ dlqItemId: string;
1390
+ jobId: string;
1391
+ flowId: string;
1392
+ attemptNumber: number;
1393
+ error: string;
1394
+ durationMs: number;
1395
+ nextRetryAt?: string;
1396
+ };
1397
+ /**
1398
+ * Event emitted when a DLQ item is exhausted (max retries reached).
1399
+ */
1400
+ type FlowEventDlqItemExhausted = {
1401
+ eventType: EventType.DlqItemExhausted;
1402
+ dlqItemId: string;
1403
+ jobId: string;
1404
+ flowId: string;
1405
+ totalAttempts: number;
1406
+ };
1407
+ /**
1408
+ * Event emitted when a DLQ item is resolved.
1409
+ */
1410
+ type FlowEventDlqItemResolved = {
1411
+ eventType: EventType.DlqItemResolved;
1412
+ dlqItemId: string;
1413
+ jobId: string;
1414
+ flowId: string;
1415
+ resolvedBy: "retry" | "manual";
1416
+ };
1417
+ /**
1418
+ * Union of all DLQ-related events.
1419
+ */
1420
+ type DlqEvent = FlowEventDlqItemAdded | FlowEventDlqRetryStart | FlowEventDlqRetrySuccess | FlowEventDlqRetryFailed | FlowEventDlqItemExhausted | FlowEventDlqItemResolved;
529
1421
  /**
530
1422
  * Union of all possible flow execution events.
531
1423
  *
@@ -547,11 +1439,199 @@ type FlowEventNodeResponse = {
547
1439
  * case EventType.FlowCancel:
548
1440
  * console.log("Flow cancelled:", event.flowId);
549
1441
  * break;
1442
+ * case EventType.DlqItemAdded:
1443
+ * console.log("Job added to DLQ:", event.dlqItemId);
1444
+ * break;
550
1445
  * }
551
1446
  * }
552
1447
  * ```
553
1448
  */
554
- type FlowEvent = FlowEventJobStart | FlowEventJobEnd | FlowEventFlowStart | FlowEventFlowEnd | FlowEventFlowError | FlowEventFlowPause | FlowEventFlowCancel | FlowEventNodeStart | FlowEventNodeEnd | FlowEventNodePause | FlowEventNodeResume | FlowEventNodeError;
1449
+ type FlowEvent = FlowEventJobStart | FlowEventJobEnd | FlowEventFlowStart | FlowEventFlowEnd | FlowEventFlowError | FlowEventFlowPause | FlowEventFlowCancel | FlowEventNodeStart | FlowEventNodeEnd | FlowEventNodePause | FlowEventNodeResume | FlowEventNodeError | DlqEvent;
1450
+ //#endregion
1451
+ //#region src/flow/types/retry-policy.d.ts
1452
+ /**
1453
+ * Retry policy types for the Dead Letter Queue.
1454
+ *
1455
+ * Defines configurable retry strategies including immediate, fixed delay,
1456
+ * and exponential backoff with jitter.
1457
+ *
1458
+ * @module flow/types/retry-policy
1459
+ * @see {@link DeadLetterQueueService} for DLQ operations
1460
+ */
1461
+ /**
1462
+ * Immediate retry strategy - retry as soon as possible.
1463
+ *
1464
+ * Use for errors that are likely transient and may succeed on immediate retry.
1465
+ */
1466
+ interface ImmediateBackoff {
1467
+ type: "immediate";
1468
+ }
1469
+ /**
1470
+ * Fixed delay retry strategy - wait a fixed duration between retries.
1471
+ *
1472
+ * @property delayMs - Milliseconds to wait between retries
1473
+ *
1474
+ * @example
1475
+ * ```typescript
1476
+ * const fixedBackoff: FixedBackoff = {
1477
+ * type: "fixed",
1478
+ * delayMs: 5000 // Wait 5 seconds between retries
1479
+ * };
1480
+ * ```
1481
+ */
1482
+ interface FixedBackoff {
1483
+ type: "fixed";
1484
+ /** Milliseconds to wait between retries */
1485
+ delayMs: number;
1486
+ }
1487
+ /**
1488
+ * Exponential backoff retry strategy - progressively longer delays.
1489
+ *
1490
+ * Delay = min(initialDelayMs * (multiplier ^ retryCount), maxDelayMs)
1491
+ * With optional jitter to prevent thundering herd.
1492
+ *
1493
+ * @property initialDelayMs - Starting delay in milliseconds (e.g., 1000)
1494
+ * @property maxDelayMs - Maximum delay cap in milliseconds (e.g., 300000)
1495
+ * @property multiplier - Multiplication factor per retry (e.g., 2)
1496
+ * @property jitter - Add randomness to prevent thundering herd
1497
+ *
1498
+ * @example
1499
+ * ```typescript
1500
+ * const exponentialBackoff: ExponentialBackoff = {
1501
+ * type: "exponential",
1502
+ * initialDelayMs: 1000, // Start with 1 second
1503
+ * maxDelayMs: 300000, // Cap at 5 minutes
1504
+ * multiplier: 2, // Double each time
1505
+ * jitter: true // Add randomness
1506
+ * };
1507
+ * // Delays: ~1s, ~2s, ~4s, ~8s, ..., capped at ~5min
1508
+ * ```
1509
+ */
1510
+ interface ExponentialBackoff {
1511
+ type: "exponential";
1512
+ /** Starting delay in milliseconds */
1513
+ initialDelayMs: number;
1514
+ /** Maximum delay cap in milliseconds */
1515
+ maxDelayMs: number;
1516
+ /** Multiplication factor per retry (e.g., 2 for doubling) */
1517
+ multiplier: number;
1518
+ /** Add randomness to prevent thundering herd */
1519
+ jitter: boolean;
1520
+ }
1521
+ /**
1522
+ * Union type for all backoff strategies.
1523
+ */
1524
+ type BackoffStrategy = ImmediateBackoff | FixedBackoff | ExponentialBackoff;
1525
+ /**
1526
+ * Configuration for automatic retry behavior.
1527
+ *
1528
+ * Defines how failed jobs should be retried, including backoff strategy,
1529
+ * max attempts, and error filtering.
1530
+ *
1531
+ * @property enabled - Whether automatic retry is enabled (default: true)
1532
+ * @property maxRetries - Maximum retry attempts (default: 3)
1533
+ * @property backoff - Backoff strategy configuration
1534
+ * @property retryableErrors - Only retry these error codes (default: all)
1535
+ * @property nonRetryableErrors - Never retry these error codes
1536
+ * @property ttlMs - Auto-delete items after this time (default: 7 days)
1537
+ *
1538
+ * @example
1539
+ * ```typescript
1540
+ * // Conservative retry policy for external APIs
1541
+ * const apiRetryPolicy: RetryPolicy = {
1542
+ * enabled: true,
1543
+ * maxRetries: 5,
1544
+ * backoff: {
1545
+ * type: "exponential",
1546
+ * initialDelayMs: 1000,
1547
+ * maxDelayMs: 60000,
1548
+ * multiplier: 2,
1549
+ * jitter: true
1550
+ * },
1551
+ * nonRetryableErrors: ["VALIDATION_ERROR", "AUTH_ERROR"],
1552
+ * ttlMs: 604800000 // 7 days
1553
+ * };
1554
+ *
1555
+ * // Aggressive retry for transient failures
1556
+ * const transientRetryPolicy: RetryPolicy = {
1557
+ * enabled: true,
1558
+ * maxRetries: 3,
1559
+ * backoff: { type: "immediate" },
1560
+ * retryableErrors: ["NETWORK_ERROR", "TIMEOUT_ERROR"]
1561
+ * };
1562
+ *
1563
+ * // No automatic retry, manual intervention only
1564
+ * const manualPolicy: RetryPolicy = {
1565
+ * enabled: false,
1566
+ * maxRetries: 0,
1567
+ * backoff: { type: "immediate" }
1568
+ * };
1569
+ * ```
1570
+ */
1571
+ interface RetryPolicy {
1572
+ /** Whether automatic retry is enabled (default: true) */
1573
+ enabled: boolean;
1574
+ /** Maximum retry attempts (default: 3) */
1575
+ maxRetries: number;
1576
+ /** Backoff strategy configuration */
1577
+ backoff: BackoffStrategy;
1578
+ /** Only retry these error codes. If undefined, retry all errors. */
1579
+ retryableErrors?: string[];
1580
+ /** Never retry these error codes. Takes precedence over retryableErrors. */
1581
+ nonRetryableErrors?: string[];
1582
+ /** Auto-delete items after this time in milliseconds (default: 7 days) */
1583
+ ttlMs?: number;
1584
+ }
1585
+ /**
1586
+ * Default retry policy values.
1587
+ */
1588
+ declare const DEFAULT_RETRY_POLICY: RetryPolicy;
1589
+ /**
1590
+ * Calculates the next retry delay based on the backoff strategy.
1591
+ *
1592
+ * @param backoff - The backoff strategy configuration
1593
+ * @param retryCount - Current retry attempt number (0-based)
1594
+ * @returns Delay in milliseconds before the next retry
1595
+ *
1596
+ * @example
1597
+ * ```typescript
1598
+ * const delay = calculateBackoffDelay(
1599
+ * { type: "exponential", initialDelayMs: 1000, maxDelayMs: 60000, multiplier: 2, jitter: true },
1600
+ * 2 // Third attempt
1601
+ * );
1602
+ * // Returns approximately 4000ms (1000 * 2^2) with jitter
1603
+ * ```
1604
+ */
1605
+ declare function calculateBackoffDelay(backoff: BackoffStrategy, retryCount: number): number;
1606
+ /**
1607
+ * Determines if an error should be retried based on the retry policy.
1608
+ *
1609
+ * @param errorCode - The error code to check
1610
+ * @param policy - The retry policy configuration
1611
+ * @returns true if the error should be retried
1612
+ *
1613
+ * @example
1614
+ * ```typescript
1615
+ * const policy: RetryPolicy = {
1616
+ * enabled: true,
1617
+ * maxRetries: 3,
1618
+ * backoff: { type: "immediate" },
1619
+ * nonRetryableErrors: ["VALIDATION_ERROR"]
1620
+ * };
1621
+ *
1622
+ * isErrorRetryable("NETWORK_ERROR", policy); // true
1623
+ * isErrorRetryable("VALIDATION_ERROR", policy); // false
1624
+ * ```
1625
+ */
1626
+ declare function isErrorRetryable(errorCode: string, policy: RetryPolicy): boolean;
1627
+ /**
1628
+ * Calculates the expiration date for a DLQ item.
1629
+ *
1630
+ * @param createdAt - When the item was created
1631
+ * @param ttlMs - Time to live in milliseconds
1632
+ * @returns The expiration date, or undefined if no TTL
1633
+ */
1634
+ declare function calculateExpirationDate(createdAt: Date, ttlMs?: number): Date | undefined;
555
1635
  //#endregion
556
1636
  //#region src/flow/types/flow-types.d.ts
557
1637
  /**
@@ -570,6 +1650,8 @@ type NodeTypeMap = Record<string, {
570
1650
  * @property name - Human-readable node name
571
1651
  * @property description - Explanation of what the node does
572
1652
  * @property type - Node category (input, transform, conditional, output, etc.)
1653
+ * @property inputTypeId - Optional input type ID from inputTypeRegistry (for input nodes)
1654
+ * @property outputTypeId - Optional output type ID from outputTypeRegistry (for result typing)
573
1655
  * @property keepOutput - If true, preserves this node's output even if it has outgoing edges (default: false)
574
1656
  */
575
1657
  type FlowNodeData = {
@@ -577,8 +1659,17 @@ type FlowNodeData = {
577
1659
  name: string;
578
1660
  description: string;
579
1661
  type: NodeType;
580
- nodeTypeId: string;
1662
+ /** Input type ID from inputTypeRegistry - describes how external clients interact with this node */
1663
+ inputTypeId?: string;
1664
+ /** Output type ID from outputTypeRegistry - describes the data shape this node produces */
1665
+ outputTypeId?: string;
581
1666
  keepOutput?: boolean;
1667
+ /**
1668
+ * Stable node type identifier for circuit breaker configuration.
1669
+ * Used to share circuit breaker state across nodes of the same type and for nodeTypeOverrides.
1670
+ * Example: "describe-image", "remove-background", "scan-virus"
1671
+ */
1672
+ nodeTypeId?: string;
582
1673
  };
583
1674
  /**
584
1675
  * Built-in typed outputs with automatic TypeScript narrowing.
@@ -710,7 +1801,7 @@ type TypedOutput<T = unknown> = BuiltInTypedOutput | CustomTypedOutput<T>;
710
1801
  *
711
1802
  * Results now include optional type information (`nodeType` and `nodeId`) to
712
1803
  * enable type-safe result consumption. These fields are automatically added
713
- * by the node execution wrapper when a node is created with a `nodeTypeId`.
1804
+ * by the node execution wrapper when a node is created with an `outputTypeId`.
714
1805
  *
715
1806
  * @example
716
1807
  * ```typescript
@@ -847,6 +1938,8 @@ type FlowNode<TInput = unknown, TOutput = unknown, TError$1 = UploadistaError> =
847
1938
  retryDelay?: number;
848
1939
  exponentialBackoff?: boolean;
849
1940
  };
1941
+ /** Circuit breaker configuration for this node (overrides flow defaults) */
1942
+ circuitBreaker?: FlowCircuitBreakerConfig;
850
1943
  };
851
1944
  /**
852
1945
  * Represents a directed edge connecting two nodes in the flow graph.
@@ -913,6 +2006,104 @@ type NodeConnectionValidator = {
913
2006
  validateConnection: (sourceNode: FlowNode<any, any>, targetNode: FlowNode<any, any>, edge: FlowEdge$1) => boolean;
914
2007
  getCompatibleTypes: (sourceSchema: z.ZodSchema<any>, targetSchema: z.ZodSchema<any>) => boolean;
915
2008
  };
2009
+ /**
2010
+ * Fallback behavior when circuit is open.
2011
+ *
2012
+ * - `fail`: Fail immediately with CIRCUIT_BREAKER_OPEN error (default)
2013
+ * - `skip`: Skip node, pass input through as output
2014
+ * - `default`: Return a configured default value
2015
+ */
2016
+ type FlowCircuitBreakerFallback = {
2017
+ type: "fail";
2018
+ } | {
2019
+ type: "skip";
2020
+ passThrough: true;
2021
+ } | {
2022
+ type: "default";
2023
+ value: unknown;
2024
+ };
2025
+ /**
2026
+ * Configuration for a circuit breaker on a flow or node.
2027
+ *
2028
+ * @property enabled - Whether circuit breaker is active (default: false for backward compatibility)
2029
+ * @property failureThreshold - Number of failures within window to trip circuit (default: 5)
2030
+ * @property resetTimeout - Milliseconds to wait in open state before half-open (default: 30000)
2031
+ * @property halfOpenRequests - Number of successful requests in half-open to close (default: 3)
2032
+ * @property windowDuration - Sliding window duration in milliseconds (default: 60000)
2033
+ * @property fallback - Behavior when circuit is open
2034
+ *
2035
+ * @example
2036
+ * ```typescript
2037
+ * const config: FlowCircuitBreakerConfig = {
2038
+ * enabled: true,
2039
+ * failureThreshold: 5,
2040
+ * resetTimeout: 30000,
2041
+ * halfOpenRequests: 3,
2042
+ * windowDuration: 60000,
2043
+ * fallback: { type: "fail" }
2044
+ * };
2045
+ * ```
2046
+ */
2047
+ interface FlowCircuitBreakerConfig {
2048
+ /** Whether circuit breaker is active (default: false) */
2049
+ enabled?: boolean;
2050
+ /** Number of failures within window to trip circuit (default: 5) */
2051
+ failureThreshold?: number;
2052
+ /** Milliseconds to wait in open state before half-open (default: 30000) */
2053
+ resetTimeout?: number;
2054
+ /** Number of successful requests in half-open to close (default: 3) */
2055
+ halfOpenRequests?: number;
2056
+ /** Sliding window duration in milliseconds (default: 60000) */
2057
+ windowDuration?: number;
2058
+ /** Behavior when circuit is open */
2059
+ fallback?: FlowCircuitBreakerFallback;
2060
+ }
2061
+ /**
2062
+ * Configuration for Dead Letter Queue on a flow.
2063
+ *
2064
+ * When enabled, failed flow jobs are captured in the DLQ for later retry,
2065
+ * debugging, or manual intervention.
2066
+ *
2067
+ * @property enabled - Whether DLQ is enabled for this flow (default: true when service is provided)
2068
+ * @property retryPolicy - Retry policy configuration for automatic retries
2069
+ *
2070
+ * @example
2071
+ * ```typescript
2072
+ * // Enable DLQ with custom retry policy
2073
+ * const flowConfig = {
2074
+ * flowId: "image-pipeline",
2075
+ * deadLetterQueue: {
2076
+ * enabled: true,
2077
+ * retryPolicy: {
2078
+ * enabled: true,
2079
+ * maxRetries: 5,
2080
+ * backoff: {
2081
+ * type: "exponential",
2082
+ * initialDelayMs: 1000,
2083
+ * maxDelayMs: 60000,
2084
+ * multiplier: 2,
2085
+ * jitter: true
2086
+ * },
2087
+ * nonRetryableErrors: ["VALIDATION_ERROR"]
2088
+ * }
2089
+ * }
2090
+ * };
2091
+ *
2092
+ * // Disable DLQ for best-effort flows
2093
+ * const bestEffortFlow = {
2094
+ * flowId: "analytics-pipeline",
2095
+ * deadLetterQueue: {
2096
+ * enabled: false
2097
+ * }
2098
+ * };
2099
+ * ```
2100
+ */
2101
+ interface FlowDeadLetterQueueConfig {
2102
+ /** Whether DLQ is enabled for this flow (default: true when service is provided) */
2103
+ enabled?: boolean;
2104
+ /** Retry policy configuration for automatic retries */
2105
+ retryPolicy?: RetryPolicy;
2106
+ }
916
2107
  /**
917
2108
  * Configuration object for creating a new flow.
918
2109
  *
@@ -985,6 +2176,58 @@ type FlowConfig<TFlowInputSchema extends z.ZodSchema<any>, TFlowOutputSchema ext
985
2176
  enabled?: boolean;
986
2177
  maxConcurrency?: number;
987
2178
  };
2179
+ /**
2180
+ * Circuit breaker configuration for the flow.
2181
+ *
2182
+ * When enabled, the circuit breaker monitors node execution failures and
2183
+ * automatically prevents requests to failing services, protecting against
2184
+ * cascade failures.
2185
+ *
2186
+ * @example
2187
+ * ```typescript
2188
+ * circuitBreaker: {
2189
+ * defaults: {
2190
+ * enabled: true,
2191
+ * failureThreshold: 5,
2192
+ * resetTimeout: 30000
2193
+ * },
2194
+ * nodeTypeOverrides: {
2195
+ * "virus-scan": { failureThreshold: 3 }
2196
+ * }
2197
+ * }
2198
+ * ```
2199
+ */
2200
+ circuitBreaker?: {
2201
+ /** Default circuit breaker config for all nodes */
2202
+ defaults?: FlowCircuitBreakerConfig;
2203
+ /** Override circuit breaker config per node type */
2204
+ nodeTypeOverrides?: Record<string, FlowCircuitBreakerConfig>;
2205
+ };
2206
+ /**
2207
+ * Dead Letter Queue configuration for the flow.
2208
+ *
2209
+ * When enabled, failed jobs are captured in the DLQ for later retry,
2210
+ * debugging, or manual intervention.
2211
+ *
2212
+ * @example
2213
+ * ```typescript
2214
+ * deadLetterQueue: {
2215
+ * enabled: true,
2216
+ * retryPolicy: {
2217
+ * enabled: true,
2218
+ * maxRetries: 5,
2219
+ * backoff: {
2220
+ * type: "exponential",
2221
+ * initialDelayMs: 1000,
2222
+ * maxDelayMs: 60000,
2223
+ * multiplier: 2,
2224
+ * jitter: true
2225
+ * }
2226
+ * }
2227
+ * }
2228
+ * ```
2229
+ */
2230
+ deadLetterQueue?: FlowDeadLetterQueueConfig;
988
2231
  hooks?: {
989
2232
  /**
990
2233
  * Called when a sink node (terminal node with no outgoing edges) produces an output.
@@ -1026,345 +2269,208 @@ type FlowConfig<TFlowInputSchema extends z.ZodSchema<any>, TFlowOutputSchema ext
1026
2269
  * // Return output with additional metadata
1027
2270
  * return { ...output, metadata: { ...output.metadata, tracked: true } };
1028
2271
  * }
1029
- * }
1030
- * ```
1031
- */
1032
- onNodeOutput?: <TOutput>(context: {
1033
- output: TOutput;
1034
- nodeId: string;
1035
- flowId: string;
1036
- jobId: string;
1037
- storageId: string;
1038
- clientId: string | null;
1039
- }) => Effect.Effect<TOutput, UploadistaError, never> | Promise<TOutput>;
1040
- };
1041
- };
1042
- //#endregion
1043
- //#region src/flow/edge.d.ts
1044
- /**
1045
- * Represents a connection between two nodes in a flow, defining the data flow direction.
1046
- *
1047
- * Edges connect the output of a source node to the input of a target node,
1048
- * enabling data to flow through the processing pipeline in a directed acyclic graph (DAG).
1049
- */
1050
- type FlowEdge = FlowEdge$1;
1051
- /**
1052
- * Creates a flow edge connecting two nodes in a processing pipeline.
1053
- *
1054
- * Edges define how data flows between nodes. The data output from the source node
1055
- * becomes the input for the target node. For nodes with multiple inputs/outputs,
1056
- * ports can be specified to route data to specific connections.
1057
- *
1058
- * @param config - Edge configuration
1059
- * @param config.source - ID of the source node (data originates here)
1060
- * @param config.target - ID of the target node (data flows to here)
1061
- * @param config.sourcePort - Optional port name on the source node for multi-output nodes
1062
- * @param config.targetPort - Optional port name on the target node for multi-input nodes
1063
- *
1064
- * @returns A FlowEdge object representing the connection
1065
- *
1066
- * @example
1067
- * ```typescript
1068
- * // Simple edge connecting two nodes
1069
- * const edge = createFlowEdge({
1070
- * source: "input-1",
1071
- * target: "process-1"
1072
- * });
1073
- *
1074
- * // Edge with ports for multi-input/output nodes
1075
- * const portEdge = createFlowEdge({
1076
- * source: "multiplex-1",
1077
- * target: "merge-1",
1078
- * sourcePort: "out-a",
1079
- * targetPort: "in-1"
1080
- * });
1081
- * ```
1082
- */
1083
- declare function createFlowEdge({
1084
- source,
1085
- target,
1086
- sourcePort,
1087
- targetPort
1088
- }: {
1089
- source: string;
1090
- target: string;
1091
- sourcePort?: string;
1092
- targetPort?: string;
1093
- }): FlowEdge;
1094
- //#endregion
1095
- //#region src/types/kv-store.d.ts
1096
- /**
1097
- * Base key-value store interface for raw string storage.
1098
- *
1099
- * This is the low-level interface that storage adapters implement.
1100
- * It stores raw string values without type safety or serialization.
1101
- *
1102
- * @property get - Retrieves a value by key, returns null if not found
1103
- * @property set - Stores a value with the given key
1104
- * @property delete - Removes a value by key
1105
- * @property list - Optional operation to list all keys with a given prefix
1106
- *
1107
- * @example
1108
- * ```typescript
1109
- * // Implement a BaseKvStore with Redis
1110
- * const redisKvStore: BaseKvStore = {
1111
- * get: (key) => Effect.tryPromise({
1112
- * try: () => redis.get(key),
1113
- * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1114
- * }),
1115
- *
1116
- * set: (key, value) => Effect.tryPromise({
1117
- * try: () => redis.set(key, value),
1118
- * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1119
- * }),
1120
- *
1121
- * delete: (key) => Effect.tryPromise({
1122
- * try: () => redis.del(key),
1123
- * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1124
- * }),
1125
- *
1126
- * list: (prefix) => Effect.tryPromise({
1127
- * try: () => redis.keys(`${prefix}*`),
1128
- * catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", { cause: error })
1129
- * })
1130
- * };
1131
- * ```
1132
- */
1133
- interface BaseKvStore {
1134
- readonly get: (key: string) => Effect.Effect<string | null, UploadistaError>;
1135
- readonly set: (key: string, value: string) => Effect.Effect<void, UploadistaError>;
1136
- readonly delete: (key: string) => Effect.Effect<void, UploadistaError>;
1137
- readonly list?: (keyPrefix: string) => Effect.Effect<Array<string>, UploadistaError>;
1138
- }
1139
- /**
1140
- * Type-safe key-value store interface with automatic serialization.
1141
- *
1142
- * This wraps a BaseKvStore and handles JSON serialization/deserialization
1143
- * for a specific data type, providing type safety and eliminating the need
1144
- * for manual JSON.stringify/parse calls.
1145
- *
1146
- * @template TData - The type of data stored in this KV store
1147
- *
1148
- * @property get - Retrieves and deserializes a value, fails if not found
1149
- * @property set - Serializes and stores a value
1150
- * @property delete - Removes a value by key
1151
- * @property list - Optional operation to list all keys (without prefix)
1152
- *
1153
- * @example
1154
- * ```typescript
1155
- * // Use a typed KV store
1156
- * const uploadStore: KvStore<UploadFile> = new TypedKvStore(
1157
- * baseStore,
1158
- * "uploads:",
1159
- * jsonSerializer.serialize,
1160
- * jsonSerializer.deserialize
1161
- * );
1162
- *
1163
- * // Store and retrieve typed data
1164
- * const program = Effect.gen(function* () {
1165
- * const file: UploadFile = {
1166
- * id: "file123",
1167
- * offset: 0,
1168
- * storage: { id: "s3", type: "s3" }
1169
- * };
1170
- *
1171
- * // Automatic serialization
1172
- * yield* uploadStore.set("file123", file);
1173
- *
1174
- * // Automatic deserialization with type safety
1175
- * const retrieved = yield* uploadStore.get("file123");
1176
- * console.log(retrieved.offset); // TypeScript knows this is a number
1177
- * });
1178
- * ```
1179
- */
1180
- type KvStore<TData> = {
1181
- readonly get: (key: string) => Effect.Effect<TData, UploadistaError>;
1182
- readonly set: (key: string, value: TData) => Effect.Effect<void, UploadistaError>;
1183
- readonly delete: (key: string) => Effect.Effect<void, UploadistaError>;
1184
- readonly list?: () => Effect.Effect<Array<string>, UploadistaError>;
1185
- };
1186
- /**
1187
- * Typed wrapper class that adds serialization to a BaseKvStore.
1188
- *
1189
- * This class implements the KvStore interface by wrapping a BaseKvStore
1190
- * and handling serialization/deserialization for a specific type. It also
1191
- * adds a key prefix to isolate different data types in the same store.
1192
- *
1193
- * @template TData - The type of data to store
1194
- *
1195
- * @example
1196
- * ```typescript
1197
- * // Create a typed store for UploadFile
1198
- * const uploadFileStore = new TypedKvStore<UploadFile>(
1199
- * baseKvStore,
1200
- * "uploadista:upload-file:", // All keys will be prefixed
1201
- * (data) => JSON.stringify(data),
1202
- * (str) => JSON.parse(str) as UploadFile
1203
- * );
1204
- *
1205
- * // Use the store
1206
- * const effect = Effect.gen(function* () {
1207
- * const file: UploadFile = { ... };
1208
- * yield* uploadFileStore.set("abc123", file);
1209
- * // Internally stores at key "uploadista:upload-file:abc123"
1210
- *
1211
- * const retrieved = yield* uploadFileStore.get("abc123");
1212
- * return retrieved;
1213
- * });
1214
- *
1215
- * // Custom serialization for binary data
1216
- * const binaryStore = new TypedKvStore<Uint8Array>(
1217
- * baseKvStore,
1218
- * "binary:",
1219
- * (data) => btoa(String.fromCharCode(...data)), // Base64 encode
1220
- * (str) => Uint8Array.from(atob(str), c => c.charCodeAt(0)) // Base64 decode
1221
- * );
1222
- * ```
1223
- */
1224
- declare class TypedKvStore<TData> implements KvStore<TData> {
1225
- private baseStore;
1226
- private keyPrefix;
1227
- private serialize;
1228
- private deserialize;
1229
- constructor(baseStore: BaseKvStore, keyPrefix: string, serialize: (data: TData) => string, deserialize: (str: string) => TData);
1230
- get: (key: string) => Effect.Effect<TData, UploadistaError>;
1231
- set: (key: string, value: TData) => Effect.Effect<void, UploadistaError>;
1232
- delete: (key: string) => Effect.Effect<void, UploadistaError>;
1233
- list: () => Effect.Effect<Array<string>, UploadistaError>;
1234
- }
2272
+ * }
2273
+ * ```
2274
+ */
2275
+ onNodeOutput?: <TOutput>(context: {
2276
+ output: TOutput;
2277
+ nodeId: string;
2278
+ flowId: string;
2279
+ jobId: string;
2280
+ storageId: string;
2281
+ clientId: string | null;
2282
+ }) => Effect.Effect<TOutput, UploadistaError, never> | Promise<TOutput>;
2283
+ };
2284
+ };
1235
2285
  /**
1236
- * Default JSON serialization helpers.
2286
+ * Context provided to file naming functions and templates.
1237
2287
  *
1238
- * These functions provide standard JSON serialization for use with TypedKvStore.
1239
- * They work with any JSON-serializable type.
2288
+ * Contains all relevant information about the current file, node, and flow
2289
+ * execution that can be used to generate dynamic file names.
2290
+ *
2291
+ * @property baseName - Filename without extension (e.g., "photo" from "photo.jpg")
2292
+ * @property extension - File extension without dot (e.g., "jpg")
2293
+ * @property fileName - Full original filename (e.g., "photo.jpg")
2294
+ * @property nodeType - Type of processing node (e.g., "resize", "optimize")
2295
+ * @property nodeId - Specific node instance ID
2296
+ * @property flowId - Flow identifier
2297
+ * @property jobId - Execution job ID
2298
+ * @property timestamp - ISO 8601 timestamp of processing
2299
+ * @property width - Output width (image/video nodes only)
2300
+ * @property height - Output height (image/video nodes only)
2301
+ * @property format - Output format (e.g., "webp", "mp4")
2302
+ * @property quality - Quality setting (e.g., 80)
1240
2303
  *
1241
2304
  * @example
1242
2305
  * ```typescript
1243
- * const store = new TypedKvStore<MyType>(
1244
- * baseStore,
1245
- * "mydata:",
1246
- * jsonSerializer.serialize,
1247
- * jsonSerializer.deserialize
1248
- * );
2306
+ * // Available in templates as {{variable}}
2307
+ * const pattern = "{{baseName}}-{{width}}x{{height}}.{{extension}}";
2308
+ * // Result: "photo-800x600.jpg"
1249
2309
  * ```
1250
2310
  */
1251
- declare const jsonSerializer: {
1252
- serialize: <T>(data: T) => string;
1253
- deserialize: <T>(str: string) => T;
2311
+ type NamingContext = {
2312
+ /** Filename without extension */
2313
+ baseName: string;
2314
+ /** File extension without dot */
2315
+ extension: string;
2316
+ /** Full original filename */
2317
+ fileName: string;
2318
+ /** Type of processing node */
2319
+ nodeType: string;
2320
+ /** Specific node instance ID */
2321
+ nodeId: string;
2322
+ /** Flow identifier */
2323
+ flowId: string;
2324
+ /** Execution job ID */
2325
+ jobId: string;
2326
+ /** ISO 8601 timestamp of processing */
2327
+ timestamp: string;
2328
+ /** Output width (image/video nodes) */
2329
+ width?: number;
2330
+ /** Output height (image/video nodes) */
2331
+ height?: number;
2332
+ /** Output format */
2333
+ format?: string;
2334
+ /** Quality setting */
2335
+ quality?: number;
2336
+ /** Page number (document nodes) */
2337
+ pageNumber?: number;
2338
+ /** Additional custom variables */
2339
+ [key: string]: string | number | undefined;
1254
2340
  };
1255
- declare const BaseKvStoreService_base: Context.TagClass<BaseKvStoreService, "BaseKvStore", BaseKvStore>;
1256
2341
  /**
1257
- * Effect-TS context tag for the base untyped KV store.
2342
+ * Function type for custom file naming logic.
1258
2343
  *
1259
- * This is the low-level store that storage adapter implementations provide.
1260
- * Most application code should use typed stores like UploadFileKVStore instead.
2344
+ * @param file - The UploadFile being processed
2345
+ * @param context - Naming context with all available variables
2346
+ * @returns The new filename (including extension)
1261
2347
  *
1262
2348
  * @example
1263
2349
  * ```typescript
1264
- * // Provide a base store implementation
1265
- * const baseStoreLayer = Layer.succeed(BaseKvStoreService, redisKvStore);
1266
- *
1267
- * // Use in an Effect
1268
- * const effect = Effect.gen(function* () {
1269
- * const baseStore = yield* BaseKvStoreService;
1270
- * yield* baseStore.set("raw-key", "raw-value");
1271
- * });
2350
+ * const customRename: FileNamingFunction = (file, ctx) =>
2351
+ * `${ctx.flowId}-${ctx.baseName}-${ctx.timestamp}.${ctx.extension}`;
1272
2352
  * ```
1273
2353
  */
1274
- declare class BaseKvStoreService extends BaseKvStoreService_base {}
1275
- declare const UploadFileKVStore_base: Context.TagClass<UploadFileKVStore, "UploadFileKVStore", KvStore<UploadFile>>;
2354
+ type FileNamingFunction = (file: UploadFile, context: NamingContext) => string;
1276
2355
  /**
1277
- * Effect-TS context tag for the UploadFile typed KV store.
1278
- *
1279
- * This provides type-safe storage for UploadFile metadata. It's the primary
1280
- * way to store and retrieve upload metadata in the system.
1281
- *
1282
- * @example
1283
- * ```typescript
1284
- * const uploadEffect = Effect.gen(function* () {
1285
- * const kvStore = yield* UploadFileKVStore;
1286
- *
1287
- * // Store upload metadata
1288
- * const file: UploadFile = {
1289
- * id: "upload123",
1290
- * offset: 0,
1291
- * storage: { id: "s3", type: "s3" }
1292
- * };
1293
- * yield* kvStore.set("upload123", file);
2356
+ * Function type for generating auto-naming suffixes.
1294
2357
  *
1295
- * // Retrieve with type safety
1296
- * const retrieved = yield* kvStore.get("upload123");
1297
- * return retrieved;
1298
- * });
1299
- * ```
1300
- */
1301
- declare class UploadFileKVStore extends UploadFileKVStore_base {}
1302
- /**
1303
- * Effect Layer that creates the UploadFileKVStore from a BaseKvStore.
2358
+ * Each node type can define its own auto suffix generator that creates
2359
+ * a descriptive suffix based on the processing parameters.
1304
2360
  *
1305
- * This layer automatically wires up JSON serialization for UploadFile objects
1306
- * with the "uploadista:upload-file:" key prefix.
2361
+ * @param context - Naming context with all available variables
2362
+ * @returns The suffix to append (without leading dash)
1307
2363
  *
1308
2364
  * @example
1309
2365
  * ```typescript
1310
- * const program = Effect.gen(function* () {
1311
- * const kvStore = yield* UploadFileKVStore;
1312
- * // Use the store...
1313
- * }).pipe(
1314
- * Effect.provide(uploadFileKvStore),
1315
- * Effect.provide(baseStoreLayer)
1316
- * );
2366
+ * // Resize node auto suffix
2367
+ * const resizeAutoSuffix: AutoNamingSuffixGenerator = (ctx) =>
2368
+ * `${ctx.width}x${ctx.height}`;
2369
+ * // Result: "photo-800x600.jpg"
2370
+ *
2371
+ * // Optimize node auto suffix
2372
+ * const optimizeAutoSuffix: AutoNamingSuffixGenerator = (ctx) =>
2373
+ * ctx.format ?? 'optimized';
2374
+ * // Result: "photo-webp.webp"
1317
2375
  * ```
1318
2376
  */
1319
- declare const uploadFileKvStore: Layer.Layer<UploadFileKVStore, never, BaseKvStoreService>;
1320
- declare const FlowJobKVStore_base: Context.TagClass<FlowJobKVStore, "FlowJobKVStore", KvStore<FlowJob>>;
2377
+ type AutoNamingSuffixGenerator = (context: NamingContext) => string;
1321
2378
  /**
1322
- * Effect-TS context tag for the FlowJob typed KV store.
2379
+ * Configuration for file naming behavior on a node.
1323
2380
  *
1324
- * This provides type-safe storage for FlowJob metadata, tracking the
1325
- * execution state of flow processing jobs.
2381
+ * Supports three modes:
2382
+ * - `undefined` or no config: Preserve original filename (backward compatible)
2383
+ * - `mode: 'auto'`: Generate smart suffix based on node type
2384
+ * - `mode: 'custom'`: Use template pattern or rename function
2385
+ *
2386
+ * @property mode - Naming mode: 'auto' for smart suffixes, 'custom' for templates/functions
2387
+ * @property pattern - Mustache-style template string (for custom mode)
2388
+ * @property rename - Custom function for full control (for custom mode, SDK only)
2389
+ * @property autoSuffix - Generator function for auto mode suffix
1326
2390
  *
1327
2391
  * @example
1328
2392
  * ```typescript
1329
- * const flowEffect = Effect.gen(function* () {
1330
- * const jobStore = yield* FlowJobKVStore;
2393
+ * // Auto mode with smart suffix
2394
+ * const autoNaming: FileNamingConfig = {
2395
+ * mode: 'auto',
2396
+ * autoSuffix: (ctx) => `${ctx.width}x${ctx.height}`
2397
+ * };
1331
2398
  *
1332
- * // Store job state
1333
- * const job: FlowJob = {
1334
- * id: "job123",
1335
- * flowId: "flow_resize",
1336
- * status: "running",
1337
- * tasks: [],
1338
- * createdAt: new Date(),
1339
- * updatedAt: new Date()
1340
- * };
1341
- * yield* jobStore.set("job123", job);
2399
+ * // Custom mode with template
2400
+ * const templateNaming: FileNamingConfig = {
2401
+ * mode: 'custom',
2402
+ * pattern: '{{baseName}}-{{nodeType}}.{{extension}}'
2403
+ * };
1342
2404
  *
1343
- * // Retrieve and check status
1344
- * const retrieved = yield* jobStore.get("job123");
1345
- * return retrieved.status;
1346
- * });
2405
+ * // Custom mode with function
2406
+ * const functionNaming: FileNamingConfig = {
2407
+ * mode: 'custom',
2408
+ * rename: (file, ctx) => `processed-${ctx.fileName}`
2409
+ * };
1347
2410
  * ```
1348
2411
  */
1349
- declare class FlowJobKVStore extends FlowJobKVStore_base {}
2412
+ type FileNamingConfig = {
2413
+ /** Naming mode: 'auto' for smart suffixes, 'custom' for templates/functions */
2414
+ mode: "auto" | "custom";
2415
+ /** Mustache-style template string (for custom mode) */
2416
+ pattern?: string;
2417
+ /** Custom function for full control (for custom mode, SDK only) */
2418
+ rename?: FileNamingFunction;
2419
+ /** Generator function for auto mode suffix */
2420
+ autoSuffix?: AutoNamingSuffixGenerator;
2421
+ };
2422
+ //#endregion
2423
+ //#region src/flow/edge.d.ts
1350
2424
  /**
1351
- * Effect Layer that creates the FlowJobKVStore from a BaseKvStore.
2425
+ * Represents a connection between two nodes in a flow, defining the data flow direction.
1352
2426
  *
1353
- * This layer automatically wires up JSON serialization for FlowJob objects
1354
- * with the "uploadista:flow-job:" key prefix.
2427
+ * Edges connect the output of a source node to the input of a target node,
2428
+ * enabling data to flow through the processing pipeline in a directed acyclic graph (DAG).
2429
+ */
2430
+ type FlowEdge = FlowEdge$1;
2431
+ /**
2432
+ * Creates a flow edge connecting two nodes in a processing pipeline.
2433
+ *
2434
+ * Edges define how data flows between nodes. The data output from the source node
2435
+ * becomes the input for the target node. For nodes with multiple inputs/outputs,
2436
+ * ports can be specified to route data to specific connections.
2437
+ *
2438
+ * @param config - Edge configuration
2439
+ * @param config.source - ID of the source node (data originates here)
2440
+ * @param config.target - ID of the target node (data flows to here)
2441
+ * @param config.sourcePort - Optional port name on the source node for multi-output nodes
2442
+ * @param config.targetPort - Optional port name on the target node for multi-input nodes
2443
+ *
2444
+ * @returns A FlowEdge object representing the connection
1355
2445
  *
1356
2446
  * @example
1357
2447
  * ```typescript
1358
- * const program = Effect.gen(function* () {
1359
- * const jobStore = yield* FlowJobKVStore;
1360
- * // Use the store...
1361
- * }).pipe(
1362
- * Effect.provide(flowJobKvStore),
1363
- * Effect.provide(baseStoreLayer)
1364
- * );
2448
+ * // Simple edge connecting two nodes
2449
+ * const edge = createFlowEdge({
2450
+ * source: "input-1",
2451
+ * target: "process-1"
2452
+ * });
2453
+ *
2454
+ * // Edge with ports for multi-input/output nodes
2455
+ * const portEdge = createFlowEdge({
2456
+ * source: "multiplex-1",
2457
+ * target: "merge-1",
2458
+ * sourcePort: "out-a",
2459
+ * targetPort: "in-1"
2460
+ * });
1365
2461
  * ```
1366
2462
  */
1367
- declare const flowJobKvStore: Layer.Layer<FlowJobKVStore, never, BaseKvStoreService>;
2463
+ declare function createFlowEdge({
2464
+ source,
2465
+ target,
2466
+ sourcePort,
2467
+ targetPort
2468
+ }: {
2469
+ source: string;
2470
+ target: string;
2471
+ sourcePort?: string;
2472
+ targetPort?: string;
2473
+ }): FlowEdge;
1368
2474
  //#endregion
1369
2475
  //#region src/types/data-store.d.ts
1370
2476
  /**
@@ -1900,57 +3006,172 @@ type Flow<TFlowInputSchema extends z.ZodSchema<any>, TFlowOutputSchema extends z
1900
3006
  */
1901
3007
  declare function createFlowWithSchema<TFlowInputSchema extends z.ZodSchema<any>, TFlowOutputSchema extends z.ZodSchema<any>, TRequirements = never, TNodeError = never, TNodeRequirements = never>(config: FlowConfig<TFlowInputSchema, TFlowOutputSchema, TNodeError, TNodeRequirements>): Effect.Effect<Flow<TFlowInputSchema, TFlowOutputSchema, TRequirements>, TNodeError, TNodeRequirements>;
1902
3008
  //#endregion
1903
- //#region src/flow/type-registry.d.ts
3009
+ //#region src/flow/input-type-registry.d.ts
1904
3010
  /**
1905
- * Node type category - determines where the node appears in the flow.
3011
+ * Defines a registered input type with its schema and metadata.
3012
+ *
3013
+ * Input type definitions describe how external clients interact with input nodes.
3014
+ * Unlike output types, input types define the external interface (e.g., init/finalize
3015
+ * operations for streaming uploads).
1906
3016
  *
1907
- * - `input`: Nodes that receive data from external sources (e.g., file uploads)
1908
- * - `output`: Nodes that produce final results (e.g., storage, webhooks, descriptions)
3017
+ * @template TSchema - The Zod schema type for this input's data
3018
+ *
3019
+ * @property id - Unique identifier (e.g., "streaming-input-v1")
3020
+ * @property schema - Zod schema for validating input data from clients
3021
+ * @property version - Semantic version (e.g., "1.0.0") for tracking type evolution
3022
+ * @property description - Human-readable explanation of what this input type does
1909
3023
  */
1910
- type NodeTypeCategory = "input" | "output";
3024
+ interface InputTypeDefinition<TSchema = unknown> {
3025
+ id: string;
3026
+ schema: z.ZodSchema<TSchema>;
3027
+ version: string;
3028
+ description: string;
3029
+ }
1911
3030
  /**
1912
- * Defines a registered node type with its schema and metadata.
3031
+ * Result type for input validation operations.
1913
3032
  *
1914
- * Node type definitions are registered globally and used to validate and type-narrow
1915
- * flow results at runtime. Each definition includes:
1916
- * - A unique identifier with versioning
1917
- * - A category (input or output)
1918
- * - A Zod schema for runtime validation
1919
- * - A semantic version for evolution
1920
- * - A human-readable description
3033
+ * @template T - The expected type on successful validation
3034
+ */
3035
+ type InputValidationResult<T> = {
3036
+ success: true;
3037
+ data: T;
3038
+ } | {
3039
+ success: false;
3040
+ error: UploadistaError;
3041
+ };
3042
+ /**
3043
+ * Registry for input node type definitions.
1921
3044
  *
1922
- * @template TSchema - The Zod schema type for this node's data
3045
+ * The InputTypeRegistry maintains a global registry of input types with their schemas
3046
+ * and metadata. Input types describe how data enters the flow from external sources.
1923
3047
  *
1924
- * @property id - Unique identifier (e.g., "storage-output-v1", "webhook-output-v1")
1925
- * @property category - Whether this is an input or output node type
1926
- * @property schema - Zod schema for validating data produced by this node type
1927
- * @property version - Semantic version (e.g., "1.0.0") for tracking type evolution
1928
- * @property description - Human-readable explanation of what this node type does
3048
+ * @remarks
3049
+ * - Use the exported `inputTypeRegistry` singleton instance
3050
+ * - Types cannot be unregistered or modified after registration
3051
+ * - Duplicate type IDs are rejected
1929
3052
  *
1930
3053
  * @example
1931
3054
  * ```typescript
1932
- * const storageOutputDef: NodeTypeDefinition<z.infer<typeof uploadFileSchema>> = {
1933
- * id: "storage-output-v1",
1934
- * category: "output",
1935
- * schema: uploadFileSchema,
3055
+ * // Register a new input type
3056
+ * inputTypeRegistry.register({
3057
+ * id: "form-input-v1",
3058
+ * schema: formInputSchema,
1936
3059
  * version: "1.0.0",
1937
- * description: "Storage output node that saves files to configured storage backend",
1938
- * };
3060
+ * description: "Form-based file input",
3061
+ * });
3062
+ *
3063
+ * // Check if type exists
3064
+ * if (inputTypeRegistry.has("streaming-input-v1")) {
3065
+ * const def = inputTypeRegistry.get("streaming-input-v1");
3066
+ * }
3067
+ * ```
3068
+ */
3069
+ declare class InputTypeRegistry {
3070
+ private readonly types;
3071
+ constructor();
3072
+ /**
3073
+ * Register a new input type in the registry.
3074
+ *
3075
+ * @template T - The TypeScript type inferred from the Zod schema
3076
+ * @param definition - The complete type definition including schema and metadata
3077
+ * @throws {UploadistaError} If a type with the same ID is already registered
3078
+ */
3079
+ register<T>(definition: InputTypeDefinition<T>): void;
3080
+ /**
3081
+ * Retrieve a registered type definition by its ID.
3082
+ *
3083
+ * @param id - The unique type identifier (e.g., "streaming-input-v1")
3084
+ * @returns The type definition if found, undefined otherwise
3085
+ */
3086
+ get(id: string): InputTypeDefinition<unknown> | undefined;
3087
+ /**
3088
+ * List all registered input types.
3089
+ *
3090
+ * @returns Array of all input type definitions
3091
+ */
3092
+ list(): InputTypeDefinition<unknown>[];
3093
+ /**
3094
+ * Validate data against a registered type's schema.
3095
+ *
3096
+ * @template T - The expected TypeScript type after validation
3097
+ * @param typeId - The ID of the registered type to validate against
3098
+ * @param data - The data to validate
3099
+ * @returns A result object with either the validated data or an error
3100
+ */
3101
+ validate<T>(typeId: string, data: unknown): InputValidationResult<T>;
3102
+ /**
3103
+ * Check if a type is registered.
3104
+ *
3105
+ * @param id - The unique type identifier to check
3106
+ * @returns True if the type is registered, false otherwise
3107
+ */
3108
+ has(id: string): boolean;
3109
+ /**
3110
+ * Get the total number of registered types.
3111
+ *
3112
+ * @returns The count of registered types
3113
+ */
3114
+ size(): number;
3115
+ }
3116
+ /**
3117
+ * Global singleton instance of the input type registry.
3118
+ *
3119
+ * Use this instance to register and access input node type definitions.
3120
+ * Input types describe how data enters the flow from external sources.
3121
+ *
3122
+ * @example
3123
+ * ```typescript
3124
+ * import { inputTypeRegistry } from "@uploadista/core/flow";
3125
+ *
3126
+ * // Register a type
3127
+ * inputTypeRegistry.register({
3128
+ * id: "my-input-v1",
3129
+ * schema: myInputSchema,
3130
+ * version: "1.0.0",
3131
+ * description: "My custom input type",
3132
+ * });
3133
+ *
3134
+ * // Validate data
3135
+ * const result = inputTypeRegistry.validate("my-input-v1", data);
1939
3136
  * ```
1940
3137
  */
1941
- interface NodeTypeDefinition<TSchema = unknown> {
3138
+ declare const inputTypeRegistry: InputTypeRegistry;
3139
+ /**
3140
+ * Validates flow input data against a registered input type.
3141
+ *
3142
+ * @param typeId - The registered type ID (e.g., "streaming-input-v1")
3143
+ * @param data - The input data to validate
3144
+ * @returns A validation result with either the typed data or an error
3145
+ */
3146
+ declare function validateFlowInput<T = unknown>(typeId: string, data: unknown): InputValidationResult<T>;
3147
+ //#endregion
3148
+ //#region src/flow/output-type-registry.d.ts
3149
+ /**
3150
+ * Defines a registered output type with its schema and metadata.
3151
+ *
3152
+ * Output type definitions describe the data shapes produced by nodes. This enables
3153
+ * type-safe result consumption where clients can narrow types based on the
3154
+ * `nodeType` field in results.
3155
+ *
3156
+ * @template TSchema - The Zod schema type for this output's data
3157
+ *
3158
+ * @property id - Unique identifier (e.g., "storage-output-v1", "ocr-output-v1")
3159
+ * @property schema - Zod schema for validating output data
3160
+ * @property version - Semantic version (e.g., "1.0.0") for tracking type evolution
3161
+ * @property description - Human-readable explanation of what this output type contains
3162
+ */
3163
+ interface OutputTypeDefinition<TSchema = unknown> {
1942
3164
  id: string;
1943
- category: NodeTypeCategory;
1944
3165
  schema: z.ZodSchema<TSchema>;
1945
3166
  version: string;
1946
3167
  description: string;
1947
3168
  }
1948
3169
  /**
1949
- * Result type for validation operations.
3170
+ * Result type for output validation operations.
1950
3171
  *
1951
3172
  * @template T - The expected type on successful validation
1952
3173
  */
1953
- type ValidationResult<T> = {
3174
+ type OutputValidationResult<T> = {
1954
3175
  success: true;
1955
3176
  data: T;
1956
3177
  } | {
@@ -1958,221 +3179,112 @@ type ValidationResult<T> = {
1958
3179
  error: UploadistaError;
1959
3180
  };
1960
3181
  /**
1961
- * Central registry for node type definitions.
3182
+ * Registry for output node type definitions.
1962
3183
  *
1963
- * The FlowTypeRegistry maintains a global registry of node types with their schemas
1964
- * and metadata. It provides methods for:
1965
- * - Registering new node types
1966
- * - Retrieving type definitions
1967
- * - Listing types by category
1968
- * - Validating data against registered schemas
1969
- *
1970
- * The registry is immutable after registration - types cannot be modified or removed
1971
- * once registered to prevent runtime errors.
3184
+ * The OutputTypeRegistry maintains a global registry of output types with their schemas
3185
+ * and metadata. Output types describe the data shapes that flow through the system
3186
+ * and appear in results.
1972
3187
  *
1973
3188
  * @remarks
1974
- * - This is a singleton - use the exported `flowTypeRegistry` instance
3189
+ * - Use the exported `outputTypeRegistry` singleton instance
1975
3190
  * - Types cannot be unregistered or modified after registration
1976
3191
  * - Duplicate type IDs are rejected
1977
- * - Version strings should follow semantic versioning
1978
3192
  *
1979
3193
  * @example
1980
3194
  * ```typescript
1981
- * // Register a new type
1982
- * flowTypeRegistry.register({
1983
- * id: "webhook-output-v1",
1984
- * category: "output",
1985
- * schema: webhookResponseSchema,
3195
+ * // Register a new output type
3196
+ * outputTypeRegistry.register({
3197
+ * id: "metadata-output-v1",
3198
+ * schema: metadataSchema,
1986
3199
  * version: "1.0.0",
1987
- * description: "HTTP webhook notification output",
3200
+ * description: "File metadata extraction output",
1988
3201
  * });
1989
3202
  *
1990
- * // Retrieve a type definition
1991
- * const def = flowTypeRegistry.get("webhook-output-v1");
1992
- * if (def) {
1993
- * console.log(def.description);
1994
- * }
1995
- *
1996
- * // List all output types
1997
- * const outputTypes = flowTypeRegistry.listByCategory("output");
1998
- * console.log(outputTypes.map(t => t.id));
1999
- *
2000
- * // Validate data
2001
- * const result = flowTypeRegistry.validate("webhook-output-v1", data);
3203
+ * // Validate result data
3204
+ * const result = outputTypeRegistry.validate("storage-output-v1", data);
2002
3205
  * if (result.success) {
2003
- * // data is now typed according to the schema
2004
- * processWebhookResponse(result.data);
3206
+ * console.log(result.data.url);
2005
3207
  * }
2006
3208
  * ```
2007
3209
  */
2008
- declare class FlowTypeRegistry {
3210
+ declare class OutputTypeRegistry {
2009
3211
  private readonly types;
2010
3212
  constructor();
2011
3213
  /**
2012
- * Register a new node type in the registry.
2013
- *
2014
- * Once registered, a type cannot be modified or removed. Attempting to register
2015
- * a type with a duplicate ID will throw an error.
3214
+ * Register a new output type in the registry.
2016
3215
  *
2017
3216
  * @template T - The TypeScript type inferred from the Zod schema
2018
3217
  * @param definition - The complete type definition including schema and metadata
2019
3218
  * @throws {UploadistaError} If a type with the same ID is already registered
2020
- *
2021
- * @example
2022
- * ```typescript
2023
- * import { z } from "zod";
2024
- *
2025
- * flowTypeRegistry.register({
2026
- * id: "description-output-v1",
2027
- * category: "output",
2028
- * schema: z.object({
2029
- * description: z.string(),
2030
- * confidence: z.number().min(0).max(1),
2031
- * tags: z.array(z.string()).optional(),
2032
- * }),
2033
- * version: "1.0.0",
2034
- * description: "AI-generated image description with confidence score",
2035
- * });
2036
- * ```
2037
3219
  */
2038
- register<T>(definition: NodeTypeDefinition<T>): void;
3220
+ register<T>(definition: OutputTypeDefinition<T>): void;
2039
3221
  /**
2040
3222
  * Retrieve a registered type definition by its ID.
2041
3223
  *
2042
3224
  * @param id - The unique type identifier (e.g., "storage-output-v1")
2043
3225
  * @returns The type definition if found, undefined otherwise
2044
- *
2045
- * @example
2046
- * ```typescript
2047
- * const def = flowTypeRegistry.get("storage-output-v1");
2048
- * if (def) {
2049
- * console.log(`Found ${def.description} (v${def.version})`);
2050
- * } else {
2051
- * console.warn("Type not registered");
2052
- * }
2053
- * ```
2054
3226
  */
2055
- get(id: string): NodeTypeDefinition<unknown> | undefined;
3227
+ get(id: string): OutputTypeDefinition<unknown> | undefined;
2056
3228
  /**
2057
- * List all registered types in a specific category.
2058
- *
2059
- * @param category - The node category to filter by ("input" or "output")
2060
- * @returns Array of type definitions in the specified category
3229
+ * List all registered output types.
2061
3230
  *
2062
- * @example
2063
- * ```typescript
2064
- * // List all registered output types
2065
- * const outputTypes = flowTypeRegistry.listByCategory("output");
2066
- * console.log("Available output types:");
2067
- * for (const type of outputTypes) {
2068
- * console.log(`- ${type.id}: ${type.description}`);
2069
- * }
2070
- * ```
3231
+ * @returns Array of all output type definitions
2071
3232
  */
2072
- listByCategory(category: NodeTypeCategory): NodeTypeDefinition<unknown>[];
3233
+ list(): OutputTypeDefinition<unknown>[];
2073
3234
  /**
2074
3235
  * Validate data against a registered type's schema.
2075
3236
  *
2076
- * This method performs runtime validation using the Zod schema associated with
2077
- * the type. If validation succeeds, the data is returned with proper typing.
2078
- * If validation fails, an UploadistaError is returned with details.
2079
- *
2080
3237
  * @template T - The expected TypeScript type after validation
2081
3238
  * @param typeId - The ID of the registered type to validate against
2082
3239
  * @param data - The data to validate
2083
3240
  * @returns A result object with either the validated data or an error
2084
- *
2085
- * @example
2086
- * ```typescript
2087
- * const result = flowTypeRegistry.validate("storage-output-v1", unknownData);
2088
- *
2089
- * if (result.success) {
2090
- * // TypeScript knows result.data is an UploadFile
2091
- * console.log(`File stored at: ${result.data.url}`);
2092
- * } else {
2093
- * console.error(`Validation failed: ${result.error.body}`);
2094
- * }
2095
- * ```
2096
3241
  */
2097
- validate<T>(typeId: string, data: unknown): ValidationResult<T>;
3242
+ validate<T>(typeId: string, data: unknown): OutputValidationResult<T>;
2098
3243
  /**
2099
3244
  * Check if a type is registered.
2100
3245
  *
2101
3246
  * @param id - The unique type identifier to check
2102
3247
  * @returns True if the type is registered, false otherwise
2103
- *
2104
- * @example
2105
- * ```typescript
2106
- * if (flowTypeRegistry.has("custom-output-v1")) {
2107
- * console.log("Custom output type is available");
2108
- * }
2109
- * ```
2110
3248
  */
2111
3249
  has(id: string): boolean;
2112
3250
  /**
2113
3251
  * Get the total number of registered types.
2114
3252
  *
2115
3253
  * @returns The count of registered types
2116
- *
2117
- * @example
2118
- * ```typescript
2119
- * console.log(`Registry contains ${flowTypeRegistry.size()} types`);
2120
- * ```
2121
3254
  */
2122
3255
  size(): number;
2123
3256
  }
2124
3257
  /**
2125
- * Global singleton instance of the flow type registry.
3258
+ * Global singleton instance of the output type registry.
2126
3259
  *
2127
- * Use this instance to register and access node type definitions throughout
2128
- * your application. The registry is initialized once and shared globally.
3260
+ * Use this instance to register and access output node type definitions.
3261
+ * Output types describe the data shapes produced by nodes and used in results.
2129
3262
  *
2130
3263
  * @example
2131
3264
  * ```typescript
2132
- * import { flowTypeRegistry } from "@uploadista/core/flow";
3265
+ * import { outputTypeRegistry } from "@uploadista/core/flow";
2133
3266
  *
2134
3267
  * // Register a type
2135
- * flowTypeRegistry.register({
3268
+ * outputTypeRegistry.register({
2136
3269
  * id: "my-output-v1",
2137
- * category: "output",
2138
- * schema: mySchema,
3270
+ * schema: myOutputSchema,
2139
3271
  * version: "1.0.0",
2140
3272
  * description: "My custom output type",
2141
3273
  * });
2142
3274
  *
2143
- * // Validate data
2144
- * const result = flowTypeRegistry.validate("my-output-v1", data);
3275
+ * // Validate result data
3276
+ * const result = outputTypeRegistry.validate("my-output-v1", data);
2145
3277
  * ```
2146
3278
  */
2147
- declare const flowTypeRegistry: FlowTypeRegistry;
3279
+ declare const outputTypeRegistry: OutputTypeRegistry;
2148
3280
  /**
2149
- * Validates flow input data against a registered node type.
2150
- *
2151
- * This helper function looks up the node type by ID and validates the provided
2152
- * data against its schema. It's specifically designed for input validation
2153
- * before flow execution.
3281
+ * Validates flow output data against a registered output type.
2154
3282
  *
2155
- * @param typeId - The registered type ID (e.g., "streaming-input-v1")
2156
- * @param data - The input data to validate
3283
+ * @param typeId - The registered type ID (e.g., "storage-output-v1")
3284
+ * @param data - The output data to validate
2157
3285
  * @returns A validation result with either the typed data or an error
2158
- *
2159
- * @example
2160
- * ```typescript
2161
- * import { validateFlowInput } from "@uploadista/core/flow";
2162
- *
2163
- * const result = validateFlowInput("streaming-input-v1", {
2164
- * operation: "url",
2165
- * url: "https://example.com/image.jpg"
2166
- * });
2167
- *
2168
- * if (result.success) {
2169
- * console.log("Valid input:", result.data);
2170
- * } else {
2171
- * console.error("Validation error:", result.error);
2172
- * }
2173
- * ```
2174
3286
  */
2175
- declare function validateFlowInput<T = unknown>(typeId: string, data: unknown): ValidationResult<T>;
3287
+ declare function validateFlowOutput<T = unknown>(typeId: string, data: unknown): OutputValidationResult<T>;
2176
3288
  //#endregion
2177
3289
  //#region src/flow/node-types/index.d.ts
2178
3290
  /**
@@ -2183,11 +3295,12 @@ declare function validateFlowInput<T = unknown>(typeId: string, data: unknown):
2183
3295
  *
2184
3296
  * @example
2185
3297
  * ```typescript
2186
- * import { STREAMING_INPUT_TYPE_ID } from "@uploadista/core/flow";
3298
+ * import { STREAMING_INPUT_TYPE_ID, STORAGE_OUTPUT_TYPE_ID } from "@uploadista/core/flow";
2187
3299
  *
2188
3300
  * const inputNode = createFlowNode({
2189
3301
  * // ... other config
2190
- * nodeTypeId: STREAMING_INPUT_TYPE_ID
3302
+ * inputTypeId: STREAMING_INPUT_TYPE_ID,
3303
+ * outputTypeId: STORAGE_OUTPUT_TYPE_ID,
2191
3304
  * });
2192
3305
  * ```
2193
3306
  */
@@ -2893,6 +4006,154 @@ declare class FlowEventEmitter extends FlowEventEmitter_base {}
2893
4006
  */
2894
4007
  declare const flowEventEmitter: Layer.Layer<FlowEventEmitter, never, BaseEventEmitterService>;
2895
4008
  //#endregion
4009
+ //#region src/types/health-check.d.ts
4010
+ /**
4011
+ * Health Check Types for Uploadista SDK.
4012
+ *
4013
+ * This module provides types for the health monitoring system including:
4014
+ * - Liveness probes (`/health`)
4015
+ * - Readiness probes (`/ready`)
4016
+ * - Component health details (`/health/components`)
4017
+ *
4018
+ * @module types/health-check
4019
+ */
4020
+ /**
4021
+ * Health status values for components and overall system health.
4022
+ *
4023
+ * - `healthy`: All checks passed, system is fully operational
4024
+ * - `degraded`: Some non-critical issues detected, but system is functional
4025
+ * - `unhealthy`: Critical components unavailable, system cannot serve requests
4026
+ */
4027
+ type HealthStatus = "healthy" | "degraded" | "unhealthy";
4028
+ /**
4029
+ * Health status for an individual component (storage, KV store, etc.).
4030
+ */
4031
+ interface ComponentHealth {
4032
+ /** Current health status of the component */
4033
+ status: HealthStatus;
4034
+ /** Latency of the last health check in milliseconds */
4035
+ latency?: number;
4036
+ /** Human-readable status message */
4037
+ message?: string;
4038
+ /** ISO 8601 timestamp of the last health check */
4039
+ lastCheck?: string;
4040
+ }
4041
+ /**
4042
+ * Circuit breaker health summary aggregating all circuit states.
4043
+ */
4044
+ interface CircuitBreakerHealthSummary {
4045
+ /** Overall circuit breaker system status */
4046
+ status: HealthStatus;
4047
+ /** Number of circuits currently in open state */
4048
+ openCircuits: number;
4049
+ /** Total number of tracked circuits */
4050
+ totalCircuits: number;
4051
+ /** Detailed stats for each circuit (optional, for debugging) */
4052
+ circuits?: Array<{
4053
+ nodeType: string;
4054
+ state: "closed" | "open" | "half-open";
4055
+ failureCount: number;
4056
+ timeSinceLastStateChange: number;
4057
+ }>;
4058
+ }
4059
+ /**
4060
+ * Dead Letter Queue health summary.
4061
+ */
4062
+ interface DlqHealthSummary {
4063
+ /** Overall DLQ status */
4064
+ status: HealthStatus;
4065
+ /** Number of items pending retry */
4066
+ pendingItems: number;
4067
+ /** Number of items that have exhausted all retries */
4068
+ exhaustedItems: number;
4069
+ /** ISO 8601 timestamp of the oldest item in the queue */
4070
+ oldestItem?: string;
4071
+ }
4072
+ /**
4073
+ * Components health map for detailed health responses.
4074
+ */
4075
+ interface HealthComponents {
4076
+ /** Storage backend health */
4077
+ storage?: ComponentHealth;
4078
+ /** KV store health */
4079
+ kvStore?: ComponentHealth;
4080
+ /** Event broadcaster health */
4081
+ eventBroadcaster?: ComponentHealth;
4082
+ /** Circuit breaker summary (if enabled) */
4083
+ circuitBreaker?: CircuitBreakerHealthSummary;
4084
+ /** Dead letter queue summary (if enabled) */
4085
+ deadLetterQueue?: DlqHealthSummary;
4086
+ }
4087
+ /**
4088
+ * Standard health response structure.
4089
+ *
4090
+ * Used for all health endpoints with varying levels of detail.
4091
+ */
4092
+ interface HealthResponse {
4093
+ /** Overall health status */
4094
+ status: HealthStatus;
4095
+ /** ISO 8601 timestamp of the response */
4096
+ timestamp: string;
4097
+ /** Optional version string for deployment identification */
4098
+ version?: string;
4099
+ /** Server uptime in milliseconds */
4100
+ uptime?: number;
4101
+ /** Component-level health details (for /health/components) */
4102
+ components?: HealthComponents;
4103
+ }
4104
+ /**
4105
+ * Configuration options for health check behavior.
4106
+ */
4107
+ interface HealthCheckConfig {
4108
+ /**
4109
+ * Timeout for dependency health checks in milliseconds.
4110
+ * @default 5000
4111
+ */
4112
+ timeout?: number;
4113
+ /**
4114
+ * Whether to check storage backend health.
4115
+ * @default true
4116
+ */
4117
+ checkStorage?: boolean;
4118
+ /**
4119
+ * Whether to check KV store health.
4120
+ * @default true
4121
+ */
4122
+ checkKvStore?: boolean;
4123
+ /**
4124
+ * Whether to check event broadcaster health.
4125
+ * @default true
4126
+ */
4127
+ checkEventBroadcaster?: boolean;
4128
+ /**
4129
+ * Optional version string to include in health responses.
4130
+ * Useful for identifying deployed versions.
4131
+ */
4132
+ version?: string;
4133
+ }
4134
+ /**
4135
+ * Default health check configuration values.
4136
+ */
4137
+ declare const DEFAULT_HEALTH_CHECK_CONFIG: Required<Omit<HealthCheckConfig, "version">>;
4138
+ /**
4139
+ * Supported response formats for health endpoints.
4140
+ */
4141
+ type HealthResponseFormat = "json" | "text";
4142
+ /**
4143
+ * Determines the response format based on Accept header.
4144
+ *
4145
+ * @param acceptHeader - The Accept header value from the request
4146
+ * @returns The response format to use
4147
+ */
4148
+ declare function getHealthResponseFormat(acceptHeader?: string | null): HealthResponseFormat;
4149
+ /**
4150
+ * Formats a health response as plain text.
4151
+ *
4152
+ * @param status - The health status
4153
+ * @returns Plain text representation
4154
+ */
4155
+ declare function formatHealthAsText(status: HealthStatus): string;
4156
+ //#endregion
2896
4157
  //#region src/types/input-file.d.ts
2897
4158
  /**
2898
4159
  * Zod schema for validating InputFile objects.
@@ -3218,7 +4479,7 @@ declare function createUploadServer(): Effect.Effect<{
3218
4479
  getCapabilities: (storageId: string, clientId: string | null) => Effect.Effect<DataStoreCapabilities, UploadistaError, never>;
3219
4480
  subscribeToUploadEvents: (uploadId: string, connection: WebSocketConnection) => Effect.Effect<void, UploadistaError, never>;
3220
4481
  unsubscribeFromUploadEvents: (uploadId: string) => Effect.Effect<void, UploadistaError, never>;
3221
- }, never, UploadFileDataStores | UploadFileKVStore | UploadEventEmitter | GenerateId>;
4482
+ }, never, GenerateId | UploadFileDataStores | UploadFileKVStore | UploadEventEmitter>;
3222
4483
  /**
3223
4484
  * Pre-built UploadServer Effect Layer.
3224
4485
  *
@@ -3249,7 +4510,7 @@ declare function createUploadServer(): Effect.Effect<{
3249
4510
  * }).pipe(Effect.provide(fullUploadSystem));
3250
4511
  * ```
3251
4512
  */
3252
- declare const uploadServer: Layer.Layer<UploadServer, never, UploadFileDataStores | UploadFileKVStore | UploadEventEmitter | GenerateId>;
4513
+ declare const uploadServer: Layer.Layer<UploadServer, never, GenerateId | UploadFileDataStores | UploadFileKVStore | UploadEventEmitter>;
3253
4514
  //#endregion
3254
4515
  //#region src/upload/upload-strategy-negotiator.d.ts
3255
4516
  /**
@@ -3931,10 +5192,200 @@ declare function createInputNode(id: string, params?: InputNodeParams, options?:
3931
5192
  retryDelay?: number;
3932
5193
  exponentialBackoff?: boolean;
3933
5194
  };
5195
+ circuitBreaker?: FlowCircuitBreakerConfig;
3934
5196
  } & {
3935
5197
  type: NodeType.input;
3936
5198
  }, UploadistaError, UploadServer>;
3937
5199
  //#endregion
5200
+ //#region src/flow/types/flow-file.d.ts
5201
+ /**
5202
+ * Conditional execution rules for flow nodes.
5203
+ *
5204
+ * Conditions allow nodes to execute conditionally based on file properties or metadata.
5205
+ * They are evaluated before node execution and can skip nodes that don't match.
5206
+ *
5207
+ * @module flow/types/flow-file
5208
+ * @see {@link FlowNode} for how conditions are used in nodes
5209
+ *
5210
+ * @example
5211
+ * ```typescript
5212
+ * // Only process images larger than 1MB
5213
+ * const condition: FlowCondition = {
5214
+ * field: "size",
5215
+ * operator: "greaterThan",
5216
+ * value: 1024 * 1024
5217
+ * };
5218
+ *
5219
+ * // Only process JPEG images
5220
+ * const jpegCondition: FlowCondition = {
5221
+ * field: "mimeType",
5222
+ * operator: "startsWith",
5223
+ * value: "image/jpeg"
5224
+ * };
5225
+ * ```
5226
+ */
5227
+ /**
5228
+ * Represents a conditional rule for node execution.
5229
+ *
5230
+ * @property field - The file property to check
5231
+ * @property operator - The comparison operator to apply
5232
+ * @property value - The value to compare against
5233
+ *
5234
+ * @remarks
5235
+ * - Fields can check file metadata (mimeType, size) or image properties (width, height)
5236
+ * - String operators (contains, startsWith) work with string values
5237
+ * - Numeric operators (greaterThan, lessThan) work with numeric values
5238
+ * - The extension field checks the file extension without the dot
5239
+ */
5240
+ type FlowCondition = {
5241
+ field: "mimeType" | "size" | "width" | "height" | "extension";
5242
+ operator: "equals" | "notEquals" | "greaterThan" | "lessThan" | "contains" | "startsWith";
5243
+ value: string | number;
5244
+ };
5245
+ //#endregion
5246
+ //#region src/flow/types/type-utils.d.ts
5247
+ /**
5248
+ * Extracts the service type from an Effect Layer.
5249
+ *
5250
+ * Given a Layer that provides a service, this type utility extracts
5251
+ * the service type from the Layer's type signature.
5252
+ *
5253
+ * @template T - The Layer type to extract from
5254
+ * @returns The service type provided by the layer, or never if T is not a Layer
5255
+ *
5256
+ * @example
5257
+ * ```typescript
5258
+ * type MyLayer = Layer.Layer<ServiceA, never, never>;
5259
+ * type Service = ExtractLayerService<MyLayer>;
5260
+ * // Service = ServiceA
5261
+ * ```
5262
+ *
5263
+ * @example
5264
+ * ```typescript
5265
+ * import { ImagePluginLayer } from '@uploadista/core';
5266
+ *
5267
+ * type ImageService = ExtractLayerService<ImagePluginLayer>;
5268
+ * // ImageService = ImagePlugin
5269
+ * ```
5270
+ */
5271
+ type ExtractLayerService<T, TError$1 = never, TRequirements = never> = T extends Layer.Layer<infer S, TError$1, TRequirements> ? S : never;
5272
+ /**
5273
+ * Extracts all service types from a tuple of layers and returns them as a union.
5274
+ *
5275
+ * This type recursively processes a tuple of Layer types and extracts all
5276
+ * the services they provide, combining them into a single union type.
5277
+ *
5278
+ * @template T - A readonly tuple of Layer types
5279
+ * @returns A union of all service types provided by the layers, or never for empty tuples
5280
+ *
5281
+ * @example
5282
+ * ```typescript
5283
+ * type Layers = [
5284
+ * Layer.Layer<ServiceA, never, never>,
5285
+ * Layer.Layer<ServiceB, never, never>,
5286
+ * Layer.Layer<ServiceC, never, never>
5287
+ * ];
5288
+ * type Services = ExtractLayerServices<Layers>;
5289
+ * // Services = ServiceA | ServiceB | ServiceC
5290
+ * ```
5291
+ *
5292
+ * @example
5293
+ * ```typescript
5294
+ * import { ImagePluginLayer, ZipPluginLayer } from '@uploadista/core';
5295
+ *
5296
+ * type PluginLayers = [ImagePluginLayer, ZipPluginLayer];
5297
+ * type AllServices = ExtractLayerServices<PluginLayers>;
5298
+ * // AllServices = ImagePlugin | ZipPlugin
5299
+ * ```
5300
+ *
5301
+ * @example
5302
+ * ```typescript
5303
+ * type EmptyLayers = [];
5304
+ * type NoServices = ExtractLayerServices<EmptyLayers>;
5305
+ * // NoServices = never
5306
+ * ```
5307
+ */
5308
+ type ExtractLayerServices<T extends readonly Layer.Layer<any, any, any>[]> = T extends readonly [] ? never : { [K in keyof T]: T[K] extends Layer.Layer<infer S, any, any> ? S : never }[number];
5309
+ /**
5310
+ * Unwraps an Effect type to extract its success value type.
5311
+ *
5312
+ * If the input type is an Effect, this extracts the success type (first type parameter).
5313
+ * If the input is not an Effect, it returns the type unchanged.
5314
+ *
5315
+ * @template T - The type to resolve, potentially an Effect
5316
+ * @returns The success type if T is an Effect, otherwise T
5317
+ *
5318
+ * @example
5319
+ * ```typescript
5320
+ * type MyEffect = Effect.Effect<string, Error, never>;
5321
+ * type Result = ResolveEffect<MyEffect>;
5322
+ * // Result = string
5323
+ * ```
5324
+ *
5325
+ * @example
5326
+ * ```typescript
5327
+ * type NonEffect = { data: string };
5328
+ * type Result = ResolveEffect<NonEffect>;
5329
+ * // Result = { data: string }
5330
+ * ```
5331
+ */
5332
+ type ResolveEffect<T> = T extends Effect.Effect<infer S, any, any> ? S : T;
5333
+ /**
5334
+ * Extracts the error type from an Effect.
5335
+ *
5336
+ * Given an Effect type, this utility extracts the error type
5337
+ * (second type parameter) from the Effect's type signature.
5338
+ *
5339
+ * @template T - The Effect type to extract from
5340
+ * @returns The error type of the Effect, or never if T is not an Effect
5341
+ *
5342
+ * @example
5343
+ * ```typescript
5344
+ * type MyEffect = Effect.Effect<string, ValidationError, never>;
5345
+ * type ErrorType = ExtractEffectError<MyEffect>;
5346
+ * // ErrorType = ValidationError
5347
+ * ```
5348
+ *
5349
+ * @example
5350
+ * ```typescript
5351
+ * type SafeEffect = Effect.Effect<number, never, SomeService>;
5352
+ * type ErrorType = ExtractEffectError<SafeEffect>;
5353
+ * // ErrorType = never (no errors possible)
5354
+ * ```
5355
+ */
5356
+ type ExtractEffectError<T> = T extends Effect.Effect<any, infer E, any> ? E : never;
5357
+ /**
5358
+ * Extracts the requirements (context) type from an Effect.
5359
+ *
5360
+ * Given an Effect type, this utility extracts the requirements type
5361
+ * (third type parameter) from the Effect's type signature. This represents
5362
+ * the services that must be provided for the Effect to run.
5363
+ *
5364
+ * @template T - The Effect type to extract from
5365
+ * @returns The requirements type of the Effect, or never if T is not an Effect
5366
+ *
5367
+ * @example
5368
+ * ```typescript
5369
+ * type MyEffect = Effect.Effect<string, Error, Database | Logger>;
5370
+ * type Requirements = ExtractEffectRequirements<MyEffect>;
5371
+ * // Requirements = Database | Logger
5372
+ * ```
5373
+ *
5374
+ * @example
5375
+ * ```typescript
5376
+ * import { ImagePlugin, ZipPlugin } from '@uploadista/core';
5377
+ *
5378
+ * type ProcessEffect = Effect.Effect<
5379
+ * ProcessedImage,
5380
+ * ProcessError,
5381
+ * ImagePlugin | ZipPlugin
5382
+ * >;
5383
+ * type Needed = ExtractEffectRequirements<ProcessEffect>;
5384
+ * // Needed = ImagePlugin | ZipPlugin
5385
+ * ```
5386
+ */
5387
+ type ExtractEffectRequirements<T> = T extends Effect.Effect<any, any, infer R> ? R : never;
5388
+ //#endregion
3938
5389
  //#region src/flow/nodes/transform-node.d.ts
3939
5390
  /**
3940
5391
  * Configuration object for creating a transform node.
@@ -3946,14 +5397,44 @@ interface TransformNodeConfig {
3946
5397
  name: string;
3947
5398
  /** Description of what the node does */
3948
5399
  description: string;
3949
- /** Optional node type ID for result type registration */
3950
- nodeTypeId?: string;
5400
+ /** Optional output type ID from outputTypeRegistry for result type registration */
5401
+ outputTypeId?: string;
3951
5402
  /**
3952
5403
  * Whether to keep this node's output as a flow result even if it has outgoing edges.
3953
5404
  * When true, the node's output will be included in the final flow outputs alongside topology sinks.
3954
5405
  * Defaults to false.
3955
5406
  */
3956
5407
  keepOutput?: boolean;
5408
+ /**
5409
+ * Optional file naming configuration.
5410
+ * - undefined: Preserve original filename (backward compatible)
5411
+ * - mode: 'auto': Generate smart suffix based on node type
5412
+ * - mode: 'custom': Use template pattern or rename function
5413
+ */
5414
+ naming?: FileNamingConfig;
5415
+ /**
5416
+ * Node type identifier used for auto-naming context.
5417
+ * Defaults to "transform" if not specified.
5418
+ */
5419
+ nodeType?: string;
5420
+ /**
5421
+ * Stable node type identifier for circuit breaker configuration.
5422
+ * Used to share circuit breaker state across nodes of the same type
5423
+ * and for nodeTypeOverrides in flow config.
5424
+ * Example: "describe-image", "remove-background", "scan-virus"
5425
+ */
5426
+ nodeTypeId?: string;
5427
+ /**
5428
+ * Additional variables to include in the naming context.
5429
+ * These are merged with the base context (flowId, jobId, etc.)
5430
+ * and can be used in templates.
5431
+ */
5432
+ namingVars?: Record<string, string | number | undefined>;
5433
+ /**
5434
+ * Circuit breaker configuration for resilience against external service failures.
5435
+ * Overrides flow-level circuit breaker defaults for this node.
5436
+ */
5437
+ circuitBreaker?: FlowCircuitBreakerConfig;
3957
5438
  /** Function that transforms file bytes */
3958
5439
  transform: (bytes: Uint8Array, file: UploadFile) => Effect.Effect<Uint8Array | {
3959
5440
  bytes: Uint8Array;
@@ -4016,8 +5497,13 @@ declare function createTransformNode({
4016
5497
  id,
4017
5498
  name,
4018
5499
  description,
4019
- nodeTypeId,
5500
+ outputTypeId,
4020
5501
  keepOutput,
5502
+ naming,
5503
+ nodeType: namingNodeType,
5504
+ nodeTypeId,
5505
+ namingVars,
5506
+ circuitBreaker,
4021
5507
  transform
4022
5508
  }: TransformNodeConfig): Effect.Effect<FlowNodeData & {
4023
5509
  inputSchema: zod0.ZodType<UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<UploadFile, unknown>>;
@@ -4043,6 +5529,7 @@ declare function createTransformNode({
4043
5529
  retryDelay?: number;
4044
5530
  exponentialBackoff?: boolean;
4045
5531
  };
5532
+ circuitBreaker?: FlowCircuitBreakerConfig;
4046
5533
  } & {
4047
5534
  type: NodeType;
4048
5535
  }, UploadistaError, UploadServer>;
@@ -5405,6 +6892,20 @@ declare const removeBackgroundParamsSchema: z.ZodObject<{
5405
6892
  type RemoveBackgroundParams = z.infer<typeof removeBackgroundParamsSchema>;
5406
6893
  //#endregion
5407
6894
  //#region src/flow/type-guards.d.ts
6895
+ /**
6896
+ * A narrowed typed output with a specific node type and data type.
6897
+ * Unlike TypedOutput<T>, this type has a required nodeType field and
6898
+ * excludes BuiltInTypedOutput from the union, providing better type narrowing.
6899
+ *
6900
+ * @template T - The TypeScript type of the output data
6901
+ * @template TNodeType - The literal string type of the node type ID
6902
+ */
6903
+ type NarrowedTypedOutput<T, TNodeType extends string = string> = {
6904
+ nodeType: TNodeType;
6905
+ data: T;
6906
+ nodeId: string;
6907
+ timestamp: string;
6908
+ };
5408
6909
  /**
5409
6910
  * Factory function to create type guards for specific node types.
5410
6911
  *
@@ -5413,8 +6914,9 @@ type RemoveBackgroundParams = z.infer<typeof removeBackgroundParamsSchema>;
5413
6914
  * narrowing of TypedOutput objects in TypeScript.
5414
6915
  *
5415
6916
  * @template T - The expected TypeScript type after narrowing
6917
+ * @template TNodeType - The literal string type of the node type ID
5416
6918
  * @param typeId - The registered type ID to check against (e.g., "storage-output-v1")
5417
- * @returns A type guard function that narrows TypedOutput to TypedOutput<T>
6919
+ * @returns A type guard function that narrows TypedOutput to NarrowedTypedOutput<T, TNodeType>
5418
6920
  *
5419
6921
  * @example
5420
6922
  * ```typescript
@@ -5439,7 +6941,7 @@ type RemoveBackgroundParams = z.infer<typeof removeBackgroundParamsSchema>;
5439
6941
  * }
5440
6942
  * ```
5441
6943
  */
5442
- declare function createTypeGuard<T>(typeId: string): (output: TypedOutput) => output is TypedOutput<T>;
6944
+ declare function createTypeGuard<T, TNodeType extends string = string>(typeId: TNodeType): (output: TypedOutput) => output is NarrowedTypedOutput<T, TNodeType>;
5443
6945
  /**
5444
6946
  * Type guard for UploadFile objects.
5445
6947
  *
@@ -5481,7 +6983,7 @@ declare function isUploadFile(value: unknown): value is UploadFile;
5481
6983
  * }
5482
6984
  * ```
5483
6985
  */
5484
- declare const isStorageOutput: (output: TypedOutput) => output is TypedOutput<UploadFile>;
6986
+ declare const isStorageOutput: (output: TypedOutput) => output is NarrowedTypedOutput<UploadFile, string>;
5485
6987
  /**
5486
6988
  * Type guard for OCR output nodes.
5487
6989
  *
@@ -5502,12 +7004,12 @@ declare const isStorageOutput: (output: TypedOutput) => output is TypedOutput<Up
5502
7004
  * }
5503
7005
  * ```
5504
7006
  */
5505
- declare const isOcrOutput: (output: TypedOutput) => output is TypedOutput<{
7007
+ declare const isOcrOutput: (output: TypedOutput) => output is NarrowedTypedOutput<{
5506
7008
  extractedText: string;
5507
7009
  format: "markdown" | "plain" | "structured";
5508
7010
  taskType: "convertToMarkdown" | "freeOcr" | "parseFigure" | "locateObject";
5509
7011
  confidence?: number | undefined;
5510
- }>;
7012
+ }, string>;
5511
7013
  /**
5512
7014
  * Type guard for image description output nodes.
5513
7015
  *
@@ -5527,11 +7029,11 @@ declare const isOcrOutput: (output: TypedOutput) => output is TypedOutput<{
5527
7029
  * }
5528
7030
  * ```
5529
7031
  */
5530
- declare const isImageDescriptionOutput: (output: TypedOutput) => output is TypedOutput<{
7032
+ declare const isImageDescriptionOutput: (output: TypedOutput) => output is NarrowedTypedOutput<{
5531
7033
  description: string;
5532
7034
  confidence?: number | undefined;
5533
7035
  metadata?: Record<string, unknown> | undefined;
5534
- }>;
7036
+ }, string>;
5535
7037
  /**
5536
7038
  * Filter an array of outputs to only those matching a specific type.
5537
7039
  *
@@ -5539,7 +7041,7 @@ declare const isImageDescriptionOutput: (output: TypedOutput) => output is Typed
5539
7041
  * properly typed array of results. It's useful for extracting specific
5540
7042
  * output types from multi-output flows.
5541
7043
  *
5542
- * @template T - The expected output data type
7044
+ * @template TOutput - The expected narrowed output type
5543
7045
  * @param outputs - Array of typed outputs to filter
5544
7046
  * @param typeGuard - Type guard function to use for filtering
5545
7047
  * @returns Array of outputs that match the type guard, properly typed
@@ -5560,7 +7062,7 @@ declare const isImageDescriptionOutput: (output: TypedOutput) => output is Typed
5560
7062
  * }
5561
7063
  * ```
5562
7064
  */
5563
- declare function filterOutputsByType<T>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TypedOutput<T>): TypedOutput<T>[];
7065
+ declare function filterOutputsByType<TOutput extends TypedOutput>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TOutput): TOutput[];
5564
7066
  /**
5565
7067
  * Get a single output of a specific type from an array of outputs.
5566
7068
  *
@@ -5568,7 +7070,7 @@ declare function filterOutputsByType<T>(outputs: TypedOutput[], typeGuard: (outp
5568
7070
  * It throws an error if no outputs match or if multiple outputs match,
5569
7071
  * ensuring the caller receives exactly the expected result.
5570
7072
  *
5571
- * @template T - The expected output data type
7073
+ * @template TOutput - The expected narrowed output type
5572
7074
  * @param outputs - Array of typed outputs to search
5573
7075
  * @param typeGuard - Type guard function to use for matching
5574
7076
  * @returns The single matching output, properly typed
@@ -5595,7 +7097,7 @@ declare function filterOutputsByType<T>(outputs: TypedOutput[], typeGuard: (outp
5595
7097
  * }
5596
7098
  * ```
5597
7099
  */
5598
- declare function getSingleOutputByType<T>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TypedOutput<T>): Effect.Effect<TypedOutput<T>, UploadistaError>;
7100
+ declare function getSingleOutputByType<TOutput extends TypedOutput>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TOutput): Effect.Effect<TOutput, UploadistaError>;
5599
7101
  /**
5600
7102
  * Get the first output of a specific type, if any exists.
5601
7103
  *
@@ -5603,7 +7105,7 @@ declare function getSingleOutputByType<T>(outputs: TypedOutput[], typeGuard: (ou
5603
7105
  * match, and returns the first match if multiple outputs exist. This is useful
5604
7106
  * when you want a more lenient matching strategy.
5605
7107
  *
5606
- * @template T - The expected output data type
7108
+ * @template TOutput - The expected narrowed output type
5607
7109
  * @param outputs - Array of typed outputs to search
5608
7110
  * @param typeGuard - Type guard function to use for matching
5609
7111
  * @returns The first matching output, or undefined if none match
@@ -5624,7 +7126,7 @@ declare function getSingleOutputByType<T>(outputs: TypedOutput[], typeGuard: (ou
5624
7126
  * }
5625
7127
  * ```
5626
7128
  */
5627
- declare function getFirstOutputByType<T>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TypedOutput<T>): TypedOutput<T> | undefined;
7129
+ declare function getFirstOutputByType<TOutput extends TypedOutput>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TOutput): TOutput | undefined;
5628
7130
  /**
5629
7131
  * Get an output by its node ID.
5630
7132
  *
@@ -5653,7 +7155,7 @@ declare function getOutputByNodeId(outputs: TypedOutput[], nodeId: string): Type
5653
7155
  * Simple predicate function to check if at least one output of a given
5654
7156
  * type exists in the results.
5655
7157
  *
5656
- * @template T - The expected output data type
7158
+ * @template TOutput - The expected narrowed output type
5657
7159
  * @param outputs - Array of typed outputs to check
5658
7160
  * @param typeGuard - Type guard function to use for checking
5659
7161
  * @returns True if at least one output matches the type guard
@@ -5669,7 +7171,7 @@ declare function getOutputByNodeId(outputs: TypedOutput[], nodeId: string): Type
5669
7171
  * }
5670
7172
  * ```
5671
7173
  */
5672
- declare function hasOutputOfType<T>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TypedOutput<T>): boolean;
7174
+ declare function hasOutputOfType<TOutput extends TypedOutput>(outputs: TypedOutput[], typeGuard: (output: TypedOutput) => output is TOutput): boolean;
5673
7175
  /**
5674
7176
  * Type guard for init operation (streaming file upload initialization).
5675
7177
  *
@@ -5701,247 +7203,58 @@ declare function isInitOperation(data: InputData): data is Extract<InputData, {
5701
7203
  *
5702
7204
  * @example
5703
7205
  * ```typescript
5704
- * if (isFinalizeOperation(inputData)) {
5705
- * console.log("Upload ID:", inputData.uploadId);
5706
- * }
5707
- * ```
5708
- */
5709
- declare function isFinalizeOperation(data: InputData): data is Extract<InputData, {
5710
- operation: "finalize";
5711
- }>;
5712
- /**
5713
- * Type guard for URL operation (direct file fetch from URL).
5714
- *
5715
- * Checks if the input data is a URL operation that fetches a file
5716
- * directly from an external URL.
5717
- *
5718
- * @param data - Input data to check
5719
- * @returns True if data is a URL operation
5720
- *
5721
- * @example
5722
- * ```typescript
5723
- * if (isUrlOperation(inputData)) {
5724
- * console.log("Fetching from:", inputData.url);
5725
- * console.log("Optional storage:", inputData.storageId);
5726
- * }
5727
- * ```
5728
- */
5729
- declare function isUrlOperation(data: InputData): data is Extract<InputData, {
5730
- operation: "url";
5731
- }>;
5732
- /**
5733
- * Type guard for upload operations (init or url).
5734
- *
5735
- * Checks if the input data is either an init or URL operation (i.e., operations
5736
- * that trigger new uploads, as opposed to finalize which completes an existing upload).
5737
- *
5738
- * @param data - Input data to check
5739
- * @returns True if data is an init or URL operation
5740
- *
5741
- * @example
5742
- * ```typescript
5743
- * if (isUploadOperation(inputData)) {
5744
- * // This is a new upload, not a finalization
5745
- * if (isInitOperation(inputData)) {
5746
- * console.log("Streaming upload");
5747
- * } else {
5748
- * console.log("URL fetch");
5749
- * }
5750
- * }
5751
- * ```
5752
- */
5753
- declare function isUploadOperation(data: InputData): data is Extract<InputData, {
5754
- operation: "init" | "url";
5755
- }>;
5756
- //#endregion
5757
- //#region src/flow/types/flow-file.d.ts
5758
- /**
5759
- * Conditional execution rules for flow nodes.
5760
- *
5761
- * Conditions allow nodes to execute conditionally based on file properties or metadata.
5762
- * They are evaluated before node execution and can skip nodes that don't match.
5763
- *
5764
- * @module flow/types/flow-file
5765
- * @see {@link FlowNode} for how conditions are used in nodes
5766
- *
5767
- * @example
5768
- * ```typescript
5769
- * // Only process images larger than 1MB
5770
- * const condition: FlowCondition = {
5771
- * field: "size",
5772
- * operator: "greaterThan",
5773
- * value: 1024 * 1024
5774
- * };
5775
- *
5776
- * // Only process JPEG images
5777
- * const jpegCondition: FlowCondition = {
5778
- * field: "mimeType",
5779
- * operator: "startsWith",
5780
- * value: "image/jpeg"
5781
- * };
5782
- * ```
5783
- */
5784
- /**
5785
- * Represents a conditional rule for node execution.
5786
- *
5787
- * @property field - The file property to check
5788
- * @property operator - The comparison operator to apply
5789
- * @property value - The value to compare against
5790
- *
5791
- * @remarks
5792
- * - Fields can check file metadata (mimeType, size) or image properties (width, height)
5793
- * - String operators (contains, startsWith) work with string values
5794
- * - Numeric operators (greaterThan, lessThan) work with numeric values
5795
- * - The extension field checks the file extension without the dot
5796
- */
5797
- type FlowCondition = {
5798
- field: "mimeType" | "size" | "width" | "height" | "extension";
5799
- operator: "equals" | "notEquals" | "greaterThan" | "lessThan" | "contains" | "startsWith";
5800
- value: string | number;
5801
- };
5802
- //#endregion
5803
- //#region src/flow/types/type-utils.d.ts
5804
- /**
5805
- * Extracts the service type from an Effect Layer.
5806
- *
5807
- * Given a Layer that provides a service, this type utility extracts
5808
- * the service type from the Layer's type signature.
5809
- *
5810
- * @template T - The Layer type to extract from
5811
- * @returns The service type provided by the layer, or never if T is not a Layer
5812
- *
5813
- * @example
5814
- * ```typescript
5815
- * type MyLayer = Layer.Layer<ServiceA, never, never>;
5816
- * type Service = ExtractLayerService<MyLayer>;
5817
- * // Service = ServiceA
5818
- * ```
5819
- *
5820
- * @example
5821
- * ```typescript
5822
- * import { ImagePluginLayer } from '@uploadista/core';
5823
- *
5824
- * type ImageService = ExtractLayerService<ImagePluginLayer>;
5825
- * // ImageService = ImagePlugin
5826
- * ```
5827
- */
5828
- type ExtractLayerService<T, TError$1 = never, TRequirements = never> = T extends Layer.Layer<infer S, TError$1, TRequirements> ? S : never;
5829
- /**
5830
- * Extracts all service types from a tuple of layers and returns them as a union.
5831
- *
5832
- * This type recursively processes a tuple of Layer types and extracts all
5833
- * the services they provide, combining them into a single union type.
5834
- *
5835
- * @template T - A readonly tuple of Layer types
5836
- * @returns A union of all service types provided by the layers, or never for empty tuples
5837
- *
5838
- * @example
5839
- * ```typescript
5840
- * type Layers = [
5841
- * Layer.Layer<ServiceA, never, never>,
5842
- * Layer.Layer<ServiceB, never, never>,
5843
- * Layer.Layer<ServiceC, never, never>
5844
- * ];
5845
- * type Services = ExtractLayerServices<Layers>;
5846
- * // Services = ServiceA | ServiceB | ServiceC
5847
- * ```
5848
- *
5849
- * @example
5850
- * ```typescript
5851
- * import { ImagePluginLayer, ZipPluginLayer } from '@uploadista/core';
5852
- *
5853
- * type PluginLayers = [ImagePluginLayer, ZipPluginLayer];
5854
- * type AllServices = ExtractLayerServices<PluginLayers>;
5855
- * // AllServices = ImagePlugin | ZipPlugin
5856
- * ```
5857
- *
5858
- * @example
5859
- * ```typescript
5860
- * type EmptyLayers = [];
5861
- * type NoServices = ExtractLayerServices<EmptyLayers>;
5862
- * // NoServices = never
5863
- * ```
5864
- */
5865
- type ExtractLayerServices<T extends readonly Layer.Layer<any, any, any>[]> = T extends readonly [] ? never : { [K in keyof T]: T[K] extends Layer.Layer<infer S, any, any> ? S : never }[number];
5866
- /**
5867
- * Unwraps an Effect type to extract its success value type.
5868
- *
5869
- * If the input type is an Effect, this extracts the success type (first type parameter).
5870
- * If the input is not an Effect, it returns the type unchanged.
5871
- *
5872
- * @template T - The type to resolve, potentially an Effect
5873
- * @returns The success type if T is an Effect, otherwise T
5874
- *
5875
- * @example
5876
- * ```typescript
5877
- * type MyEffect = Effect.Effect<string, Error, never>;
5878
- * type Result = ResolveEffect<MyEffect>;
5879
- * // Result = string
5880
- * ```
5881
- *
5882
- * @example
5883
- * ```typescript
5884
- * type NonEffect = { data: string };
5885
- * type Result = ResolveEffect<NonEffect>;
5886
- * // Result = { data: string }
5887
- * ```
5888
- */
5889
- type ResolveEffect<T> = T extends Effect.Effect<infer S, any, any> ? S : T;
5890
- /**
5891
- * Extracts the error type from an Effect.
5892
- *
5893
- * Given an Effect type, this utility extracts the error type
5894
- * (second type parameter) from the Effect's type signature.
5895
- *
5896
- * @template T - The Effect type to extract from
5897
- * @returns The error type of the Effect, or never if T is not an Effect
5898
- *
5899
- * @example
5900
- * ```typescript
5901
- * type MyEffect = Effect.Effect<string, ValidationError, never>;
5902
- * type ErrorType = ExtractEffectError<MyEffect>;
5903
- * // ErrorType = ValidationError
5904
- * ```
5905
- *
5906
- * @example
5907
- * ```typescript
5908
- * type SafeEffect = Effect.Effect<number, never, SomeService>;
5909
- * type ErrorType = ExtractEffectError<SafeEffect>;
5910
- * // ErrorType = never (no errors possible)
7206
+ * if (isFinalizeOperation(inputData)) {
7207
+ * console.log("Upload ID:", inputData.uploadId);
7208
+ * }
5911
7209
  * ```
5912
7210
  */
5913
- type ExtractEffectError<T> = T extends Effect.Effect<any, infer E, any> ? E : never;
7211
+ declare function isFinalizeOperation(data: InputData): data is Extract<InputData, {
7212
+ operation: "finalize";
7213
+ }>;
5914
7214
  /**
5915
- * Extracts the requirements (context) type from an Effect.
7215
+ * Type guard for URL operation (direct file fetch from URL).
5916
7216
  *
5917
- * Given an Effect type, this utility extracts the requirements type
5918
- * (third type parameter) from the Effect's type signature. This represents
5919
- * the services that must be provided for the Effect to run.
7217
+ * Checks if the input data is a URL operation that fetches a file
7218
+ * directly from an external URL.
5920
7219
  *
5921
- * @template T - The Effect type to extract from
5922
- * @returns The requirements type of the Effect, or never if T is not an Effect
7220
+ * @param data - Input data to check
7221
+ * @returns True if data is a URL operation
5923
7222
  *
5924
7223
  * @example
5925
7224
  * ```typescript
5926
- * type MyEffect = Effect.Effect<string, Error, Database | Logger>;
5927
- * type Requirements = ExtractEffectRequirements<MyEffect>;
5928
- * // Requirements = Database | Logger
7225
+ * if (isUrlOperation(inputData)) {
7226
+ * console.log("Fetching from:", inputData.url);
7227
+ * console.log("Optional storage:", inputData.storageId);
7228
+ * }
5929
7229
  * ```
7230
+ */
7231
+ declare function isUrlOperation(data: InputData): data is Extract<InputData, {
7232
+ operation: "url";
7233
+ }>;
7234
+ /**
7235
+ * Type guard for upload operations (init or url).
7236
+ *
7237
+ * Checks if the input data is either an init or URL operation (i.e., operations
7238
+ * that trigger new uploads, as opposed to finalize which completes an existing upload).
7239
+ *
7240
+ * @param data - Input data to check
7241
+ * @returns True if data is an init or URL operation
5930
7242
  *
5931
7243
  * @example
5932
7244
  * ```typescript
5933
- * import { ImagePlugin, ZipPlugin } from '@uploadista/core';
5934
- *
5935
- * type ProcessEffect = Effect.Effect<
5936
- * ProcessedImage,
5937
- * ProcessError,
5938
- * ImagePlugin | ZipPlugin
5939
- * >;
5940
- * type Needed = ExtractEffectRequirements<ProcessEffect>;
5941
- * // Needed = ImagePlugin | ZipPlugin
7245
+ * if (isUploadOperation(inputData)) {
7246
+ * // This is a new upload, not a finalization
7247
+ * if (isInitOperation(inputData)) {
7248
+ * console.log("Streaming upload");
7249
+ * } else {
7250
+ * console.log("URL fetch");
7251
+ * }
7252
+ * }
5942
7253
  * ```
5943
7254
  */
5944
- type ExtractEffectRequirements<T> = T extends Effect.Effect<any, any, infer R> ? R : never;
7255
+ declare function isUploadOperation(data: InputData): data is Extract<InputData, {
7256
+ operation: "init" | "url";
7257
+ }>;
5945
7258
  //#endregion
5946
7259
  //#region src/flow/typed-flow.d.ts
5947
7260
  /**
@@ -6127,6 +7440,30 @@ type TypedFlowConfig<TNodes extends NodeDefinitionsRecord> = {
6127
7440
  clientId: string | null;
6128
7441
  }) => Effect.Effect<TOutput, UploadistaError, never> | Promise<TOutput>;
6129
7442
  };
7443
+ /**
7444
+ * Circuit breaker configuration for resilience against external service failures.
7445
+ *
7446
+ * @example
7447
+ * ```typescript
7448
+ * circuitBreaker: {
7449
+ * defaults: { enabled: false },
7450
+ * nodeTypeOverrides: {
7451
+ * "Describe Image": {
7452
+ * enabled: true,
7453
+ * failureThreshold: 5,
7454
+ * resetTimeout: 60000,
7455
+ * fallback: { type: "skip", passThrough: true }
7456
+ * }
7457
+ * }
7458
+ * }
7459
+ * ```
7460
+ */
7461
+ circuitBreaker?: {
7462
+ /** Default circuit breaker config for all nodes */
7463
+ defaults?: FlowCircuitBreakerConfig;
7464
+ /** Override circuit breaker config per node type (node name) */
7465
+ nodeTypeOverrides?: Record<string, FlowCircuitBreakerConfig>;
7466
+ };
6130
7467
  };
6131
7468
  declare const typedFlowInputsSymbol: unique symbol;
6132
7469
  declare const typedFlowOutputsSymbol: unique symbol;
@@ -6217,6 +7554,391 @@ declare const runArgsSchema: z.ZodObject<{
6217
7554
  */
6218
7555
  type RunArgs = z.infer<typeof runArgsSchema>;
6219
7556
  //#endregion
7557
+ //#region src/flow/types/dead-letter-item.d.ts
7558
+ /**
7559
+ * Dead Letter Queue item types and definitions.
7560
+ *
7561
+ * A DeadLetterItem represents a failed flow job that has been captured
7562
+ * for later retry, debugging, or manual intervention.
7563
+ *
7564
+ * @module flow/types/dead-letter-item
7565
+ * @see {@link DeadLetterQueueService} for DLQ operations
7566
+ */
7567
+ /**
7568
+ * Status of a Dead Letter Queue item.
7569
+ *
7570
+ * Item lifecycle: pending → retrying → (pending | exhausted | resolved)
7571
+ *
7572
+ * - `pending`: Awaiting retry (either scheduled or manual)
7573
+ * - `retrying`: Currently being retried
7574
+ * - `exhausted`: Max retries reached, requires manual intervention
7575
+ * - `resolved`: Successfully retried or manually resolved
7576
+ */
7577
+ type DeadLetterItemStatus = "pending" | "retrying" | "exhausted" | "resolved";
7578
+ /**
7579
+ * Error details captured when a flow job fails.
7580
+ *
7581
+ * Contains comprehensive error information for debugging and retry decisions.
7582
+ *
7583
+ * @property code - Error code (e.g., "FLOW_NODE_ERROR", "VALIDATION_ERROR")
7584
+ * @property message - Human-readable error message
7585
+ * @property nodeId - ID of the node that failed (if applicable)
7586
+ * @property stack - Stack trace (included in development mode)
7587
+ */
7588
+ interface DeadLetterError {
7589
+ /** Error code for categorization and retry filtering */
7590
+ code: string;
7591
+ /** Human-readable error message */
7592
+ message: string;
7593
+ /** Node that failed (if applicable) */
7594
+ nodeId?: string;
7595
+ /** Stack trace (in dev mode only) */
7596
+ stack?: string;
7597
+ }
7598
+ /**
7599
+ * Record of a single retry attempt.
7600
+ *
7601
+ * @property attemptedAt - When the retry was attempted
7602
+ * @property error - Error message if the retry failed
7603
+ * @property durationMs - How long the retry took
7604
+ */
7605
+ interface DeadLetterRetryAttempt {
7606
+ /** When the retry was attempted */
7607
+ attemptedAt: Date;
7608
+ /** Error message if the retry failed */
7609
+ error: string;
7610
+ /** Duration of the retry attempt in milliseconds */
7611
+ durationMs: number;
7612
+ }
7613
+ /**
7614
+ * Represents a failed flow job captured in the Dead Letter Queue.
7615
+ *
7616
+ * Contains all information needed to debug, retry, or manually resolve
7617
+ * a failed flow execution.
7618
+ *
7619
+ * @property id - Unique DLQ item identifier
7620
+ * @property jobId - Original flow job ID that failed
7621
+ * @property flowId - Flow definition that was being executed
7622
+ * @property storageId - Target storage for the flow
7623
+ * @property clientId - Client who initiated the job
7624
+ * @property error - Comprehensive error details
7625
+ * @property inputs - Original inputs passed to the flow
7626
+ * @property nodeResults - Partial results from nodes that completed before failure
7627
+ * @property failedAtNodeId - Node where execution failed (if applicable)
7628
+ * @property retryCount - Number of retry attempts made
7629
+ * @property maxRetries - Maximum retries allowed from retry policy
7630
+ * @property nextRetryAt - Scheduled time for next automatic retry
7631
+ * @property retryHistory - History of all retry attempts
7632
+ * @property createdAt - When the item was added to DLQ
7633
+ * @property updatedAt - When the item was last modified
7634
+ * @property expiresAt - TTL for automatic cleanup
7635
+ * @property status - Current status of the DLQ item
7636
+ *
7637
+ * @example
7638
+ * ```typescript
7639
+ * const dlqItem: DeadLetterItem = {
7640
+ * id: "dlq_abc123",
7641
+ * jobId: "job_xyz789",
7642
+ * flowId: "image-resize-pipeline",
7643
+ * storageId: "s3-production",
7644
+ * clientId: "client_456",
7645
+ * error: {
7646
+ * code: "FLOW_NODE_ERROR",
7647
+ * message: "External service timeout",
7648
+ * nodeId: "resize-node"
7649
+ * },
7650
+ * inputs: { input: { uploadId: "upload_123" } },
7651
+ * nodeResults: { "input-node": { file: {...} } },
7652
+ * failedAtNodeId: "resize-node",
7653
+ * retryCount: 2,
7654
+ * maxRetries: 3,
7655
+ * nextRetryAt: new Date("2024-01-15T10:35:00Z"),
7656
+ * retryHistory: [
7657
+ * { attemptedAt: new Date("2024-01-15T10:30:00Z"), error: "Timeout", durationMs: 5000 },
7658
+ * { attemptedAt: new Date("2024-01-15T10:32:00Z"), error: "Timeout", durationMs: 5000 }
7659
+ * ],
7660
+ * createdAt: new Date("2024-01-15T10:30:00Z"),
7661
+ * updatedAt: new Date("2024-01-15T10:32:00Z"),
7662
+ * expiresAt: new Date("2024-01-22T10:30:00Z"),
7663
+ * status: "pending"
7664
+ * };
7665
+ * ```
7666
+ */
7667
+ interface DeadLetterItem {
7668
+ /** Unique DLQ item identifier */
7669
+ id: string;
7670
+ /** Original flow job ID that failed */
7671
+ jobId: string;
7672
+ /** Flow definition ID that was being executed */
7673
+ flowId: string;
7674
+ /** Target storage for the flow */
7675
+ storageId: string;
7676
+ /** Client who initiated the job (null for anonymous) */
7677
+ clientId: string | null;
7678
+ /** Comprehensive error details */
7679
+ error: DeadLetterError;
7680
+ /** Original inputs passed to the flow */
7681
+ inputs: Record<string, unknown>;
7682
+ /** Partial results from nodes that completed before failure */
7683
+ nodeResults: Record<string, unknown>;
7684
+ /** Node where execution failed (if applicable) */
7685
+ failedAtNodeId?: string;
7686
+ /** Number of retry attempts made */
7687
+ retryCount: number;
7688
+ /** Maximum retries allowed from retry policy */
7689
+ maxRetries: number;
7690
+ /** Scheduled time for next automatic retry */
7691
+ nextRetryAt?: Date;
7692
+ /** History of all retry attempts */
7693
+ retryHistory: DeadLetterRetryAttempt[];
7694
+ /** When the item was added to DLQ */
7695
+ createdAt: Date;
7696
+ /** When the item was last modified */
7697
+ updatedAt: Date;
7698
+ /** TTL for automatic cleanup */
7699
+ expiresAt?: Date;
7700
+ /** Current status of the DLQ item */
7701
+ status: DeadLetterItemStatus;
7702
+ }
7703
+ /**
7704
+ * Statistics about the Dead Letter Queue.
7705
+ *
7706
+ * Provides aggregate information for monitoring and alerting.
7707
+ *
7708
+ * @property totalItems - Total number of items in the DLQ
7709
+ * @property byStatus - Count of items by status
7710
+ * @property byFlow - Count of items by flow ID
7711
+ * @property oldestItem - Timestamp of the oldest item
7712
+ * @property averageRetryCount - Average number of retries across all items
7713
+ */
7714
+ interface DeadLetterQueueStats {
7715
+ /** Total number of items in the DLQ */
7716
+ totalItems: number;
7717
+ /** Count of items by status */
7718
+ byStatus: Record<DeadLetterItemStatus, number>;
7719
+ /** Count of items by flow ID */
7720
+ byFlow: Record<string, number>;
7721
+ /** Timestamp of the oldest item */
7722
+ oldestItem?: Date;
7723
+ /** Average number of retries across all items */
7724
+ averageRetryCount: number;
7725
+ }
7726
+ /**
7727
+ * Options for listing DLQ items.
7728
+ *
7729
+ * @property status - Filter by status
7730
+ * @property flowId - Filter by flow ID
7731
+ * @property clientId - Filter by client ID
7732
+ * @property limit - Maximum items to return (default: 50)
7733
+ * @property offset - Number of items to skip (default: 0)
7734
+ */
7735
+ interface DeadLetterListOptions {
7736
+ /** Filter by status */
7737
+ status?: DeadLetterItemStatus;
7738
+ /** Filter by flow ID */
7739
+ flowId?: string;
7740
+ /** Filter by client ID */
7741
+ clientId?: string;
7742
+ /** Maximum items to return (default: 50) */
7743
+ limit?: number;
7744
+ /** Number of items to skip for pagination (default: 0) */
7745
+ offset?: number;
7746
+ }
7747
+ /**
7748
+ * Result of a batch retry operation.
7749
+ *
7750
+ * @property retried - Number of items that were retried
7751
+ * @property succeeded - Number of retries that succeeded
7752
+ * @property failed - Number of retries that failed
7753
+ */
7754
+ interface DeadLetterRetryAllResult {
7755
+ /** Number of items that were retried */
7756
+ retried: number;
7757
+ /** Number of retries that succeeded */
7758
+ succeeded: number;
7759
+ /** Number of retries that failed */
7760
+ failed: number;
7761
+ }
7762
+ /**
7763
+ * Result of a cleanup operation.
7764
+ *
7765
+ * @property deleted - Number of items that were deleted
7766
+ */
7767
+ interface DeadLetterCleanupResult {
7768
+ /** Number of items that were deleted */
7769
+ deleted: number;
7770
+ }
7771
+ /**
7772
+ * Options for cleanup operation.
7773
+ *
7774
+ * @property olderThan - Delete items older than this date
7775
+ * @property status - Only delete items with this status
7776
+ */
7777
+ interface DeadLetterCleanupOptions {
7778
+ /** Delete items older than this date */
7779
+ olderThan?: Date;
7780
+ /** Only delete items with this status */
7781
+ status?: "exhausted" | "resolved";
7782
+ }
7783
+ /**
7784
+ * Result of processing scheduled retries.
7785
+ *
7786
+ * @property processed - Total items processed
7787
+ * @property succeeded - Number that succeeded
7788
+ * @property failed - Number that failed
7789
+ */
7790
+ interface DeadLetterProcessResult {
7791
+ /** Total items processed */
7792
+ processed: number;
7793
+ /** Number of successful retries */
7794
+ succeeded: number;
7795
+ /** Number of failed retries */
7796
+ failed: number;
7797
+ }
7798
+ //#endregion
7799
+ //#region src/flow/dead-letter-queue.d.ts
7800
+ /**
7801
+ * Shape of the Dead Letter Queue service.
7802
+ *
7803
+ * Provides all operations for managing failed flow jobs including
7804
+ * adding items, querying, retrying, and cleanup.
7805
+ */
7806
+ interface DeadLetterQueueServiceShape {
7807
+ /**
7808
+ * Add a failed job to the DLQ with full failure context.
7809
+ *
7810
+ * @param job - The failed flow job
7811
+ * @param error - The error that caused the failure
7812
+ * @param retryPolicy - Optional retry policy (uses default if not provided)
7813
+ * @returns The created DLQ item
7814
+ */
7815
+ add(job: FlowJob, error: UploadistaError, retryPolicy?: RetryPolicy): Effect.Effect<DeadLetterItem, UploadistaError>;
7816
+ /**
7817
+ * Get a specific DLQ item by ID.
7818
+ *
7819
+ * @param itemId - The DLQ item ID
7820
+ * @returns The DLQ item
7821
+ */
7822
+ get(itemId: string): Effect.Effect<DeadLetterItem, UploadistaError>;
7823
+ /**
7824
+ * Get a DLQ item by ID, returning None if not found.
7825
+ *
7826
+ * @param itemId - The DLQ item ID
7827
+ * @returns Option of the DLQ item
7828
+ */
7829
+ getOption(itemId: string): Effect.Effect<Option.Option<DeadLetterItem>, UploadistaError>;
7830
+ /**
7831
+ * Delete a DLQ item.
7832
+ *
7833
+ * @param itemId - The DLQ item ID to delete
7834
+ */
7835
+ delete(itemId: string): Effect.Effect<void, UploadistaError>;
7836
+ /**
7837
+ * List DLQ items with optional filtering and pagination.
7838
+ *
7839
+ * @param options - Filter and pagination options
7840
+ * @returns List of items and total count
7841
+ */
7842
+ list(options?: DeadLetterListOptions): Effect.Effect<{
7843
+ items: DeadLetterItem[];
7844
+ total: number;
7845
+ }, UploadistaError>;
7846
+ /**
7847
+ * Update a DLQ item.
7848
+ *
7849
+ * @param itemId - The DLQ item ID
7850
+ * @param updates - Partial updates to apply
7851
+ * @returns The updated item
7852
+ */
7853
+ update(itemId: string, updates: Partial<DeadLetterItem>): Effect.Effect<DeadLetterItem, UploadistaError>;
7854
+ /**
7855
+ * Mark a DLQ item as being retried.
7856
+ *
7857
+ * @param itemId - The DLQ item ID
7858
+ * @returns The updated item with status "retrying"
7859
+ */
7860
+ markRetrying(itemId: string): Effect.Effect<DeadLetterItem, UploadistaError>;
7861
+ /**
7862
+ * Record a failed retry attempt.
7863
+ *
7864
+ * @param itemId - The DLQ item ID
7865
+ * @param error - Error message from the failed retry
7866
+ * @param durationMs - Duration of the retry attempt
7867
+ * @returns The updated item
7868
+ */
7869
+ recordRetryFailure(itemId: string, error: string, durationMs: number): Effect.Effect<DeadLetterItem, UploadistaError>;
7870
+ /**
7871
+ * Mark a DLQ item as resolved (successfully retried or manually resolved).
7872
+ *
7873
+ * @param itemId - The DLQ item ID
7874
+ * @returns The updated item with status "resolved"
7875
+ */
7876
+ markResolved(itemId: string): Effect.Effect<DeadLetterItem, UploadistaError>;
7877
+ /**
7878
+ * Get items that are due for scheduled retry.
7879
+ *
7880
+ * @param limit - Maximum number of items to return
7881
+ * @returns List of items ready for retry
7882
+ */
7883
+ getScheduledRetries(limit?: number): Effect.Effect<DeadLetterItem[], UploadistaError>;
7884
+ /**
7885
+ * Cleanup old DLQ items based on options.
7886
+ *
7887
+ * @param options - Cleanup criteria
7888
+ * @returns Number of items deleted
7889
+ */
7890
+ cleanup(options?: DeadLetterCleanupOptions): Effect.Effect<DeadLetterCleanupResult, UploadistaError>;
7891
+ /**
7892
+ * Get DLQ statistics.
7893
+ *
7894
+ * @returns Aggregate statistics about the DLQ
7895
+ */
7896
+ getStats(): Effect.Effect<DeadLetterQueueStats, UploadistaError>;
7897
+ }
7898
+ declare const DeadLetterQueueService_base: Context.TagClass<DeadLetterQueueService, "DeadLetterQueueService", DeadLetterQueueServiceShape>;
7899
+ /**
7900
+ * Effect-TS context tag for the Dead Letter Queue service.
7901
+ *
7902
+ * @example
7903
+ * ```typescript
7904
+ * const effect = Effect.gen(function* () {
7905
+ * const dlq = yield* DeadLetterQueueService;
7906
+ * const stats = yield* dlq.getStats();
7907
+ * console.log(`DLQ has ${stats.totalItems} items`);
7908
+ * });
7909
+ * ```
7910
+ */
7911
+ declare class DeadLetterQueueService extends DeadLetterQueueService_base {
7912
+ /**
7913
+ * Access the DLQ service optionally (for integration in FlowServer).
7914
+ * Returns Option.none if the service is not provided.
7915
+ */
7916
+ static optional: Effect.Effect<Option.Option<DeadLetterQueueServiceShape>, never, never>;
7917
+ }
7918
+ /**
7919
+ * Creates the Dead Letter Queue service implementation.
7920
+ *
7921
+ * @returns Effect that creates the DLQ service
7922
+ */
7923
+ declare function createDeadLetterQueueService(): Effect.Effect<DeadLetterQueueServiceShape, never, DeadLetterQueueKVStore>;
7924
+ /**
7925
+ * Effect Layer that creates the DeadLetterQueueService.
7926
+ *
7927
+ * @example
7928
+ * ```typescript
7929
+ * const program = Effect.gen(function* () {
7930
+ * const dlq = yield* DeadLetterQueueService;
7931
+ * const stats = yield* dlq.getStats();
7932
+ * return stats;
7933
+ * }).pipe(
7934
+ * Effect.provide(deadLetterQueueService),
7935
+ * Effect.provide(deadLetterQueueKvStore),
7936
+ * Effect.provide(baseStoreLayer)
7937
+ * );
7938
+ * ```
7939
+ */
7940
+ declare const deadLetterQueueService: Layer.Layer<DeadLetterQueueService, never, DeadLetterQueueKVStore>;
7941
+ //#endregion
6220
7942
  //#region src/flow/utils/resolve-upload-metadata.d.ts
6221
7943
  type FileMetadata = UploadFile["metadata"];
6222
7944
  type ResolvedUploadMetadata = {
@@ -6227,5 +7949,202 @@ type ResolvedUploadMetadata = {
6227
7949
  };
6228
7950
  declare function resolveUploadMetadata(metadata: FileMetadata): ResolvedUploadMetadata;
6229
7951
  //#endregion
6230
- export { VideoPluginShape as $, MiddlewareServiceLive as $n, TypedKvStore as $r, DocumentPluginLayer as $t, isOcrOutput as A, FlowEventNodeResponse as Ai, FlowServerShape as An, ValidationResult as Ar, brightnessTransformSchema as At, PluginLayer as B, uploadFileSchema as Bi, UploadStrategyNegotiator as Bn, DataStoreCapabilities as Br, transformImageParamsSchema as Bt, getFirstOutputByType as C, FlowEventFlowPause as Ci, inputDataSchema as Cn, STORAGE_OUTPUT_TYPE_ID as Cr, SharpenTransform as Ct, isFinalizeOperation as D, FlowEventNodeEnd as Di, FlowServer as Dn, FlowTypeRegistry as Dr, TransformationType as Dt, hasOutputOfType as E, FlowEventJobStart as Ei, FlowProviderShape as En, ocrOutputSchema as Er, Transformation as Et, RemoveBackgroundParams as F, ConditionValue as Fi, FlowJob as Fn, FlowExecutionResult as Fr, resizeTransformSchema as Ft, ZipPluginShape as G, createUploadServer as Gn, UploadFileDataStoresShape as Gr, OptimizeParams as Gt, ZipParams as H, UploadServer as Hn, DataStoreWriteOptions as Hr, watermarkTransformSchema as Ht, removeBackgroundParamsSchema as I, NodeType as Ii, FlowJobStatus as In, createFlowWithSchema as Ir, rotateTransformSchema as It, VirusScanPlugin as J, detectMimeType as Jn, isDataStore as Jr, ImageAiPlugin as Jt, ScanMetadata as K, uploadServer as Kn, UploadStrategy as Kr, optimizeParamsSchema as Kt, DescribeImageParams as L, createFlowNode as Li, FlowJobTask as Ln, getFlowData as Lr, sepiaTransformSchema as Lt, isUploadFile as M, FlowEventNodeStart as Mi, WaitUntilCallback as Mn, validateFlowInput as Mr, flipTransformSchema as Mt, isUploadOperation as N, ConditionField as Ni, createFlowServer as Nn, Flow as Nr, grayscaleTransformSchema as Nt, isImageDescriptionOutput as O, FlowEventNodeError as Oi, FlowServerLayer as On, NodeTypeCategory as Or, WatermarkTransform as Ot, isUrlOperation as P, ConditionOperator as Pi, flowServer as Pn, FlowData as Pr, logoTransformSchema as Pt, VideoPluginLayer as Q, MiddlewareService as Qn, KvStore as Qr, DocumentPlugin as Qt, describeImageParamsSchema as R, getNodeData as Ri, FlowJobTaskStatus as Rn, BufferedUploadFileDataStore as Rr, sharpenTransformSchema as Rt, filterOutputsByType as S, FlowEventFlowError as Si, createInputNode as Sn, OcrOutput as Sr, SepiaTransform as St, getSingleOutputByType as T, FlowEventJobEnd as Ti, FlowProvider as Tn, imageDescriptionOutputSchema as Tr, TransformImageParams as Tt, ZipPlugin as U, UploadServerOptions as Un, UploadFileDataStore as Ur, ResizeParams as Ut, ZipInput as V, UploadStrategyOptions as Vn, DataStoreConfig as Vr, transformationSchema as Vt, ZipPluginLayer as W, UploadServerShape as Wn, UploadFileDataStores as Wr, resizeParamsSchema as Wt, VirusScanPluginShape as X, MiddlewareContext as Xn, BaseKvStoreService as Xr, ImageAiPluginShape as Xt, VirusScanPluginLayer as Y, Middleware as Yn, BaseKvStore as Yr, ImageAiPluginLayer as Yt, VideoPlugin as Z, MiddlewareNext as Zn, FlowJobKVStore as Zr, DocumentMetadata as Zt, ExtractLayerService as _, waitingNodeExecution as _i, ParallelSchedulerConfig as _n, EventBroadcaster as _r, GrayscaleTransform as _t, FlowInputMap as a, createFlowEdge as ai, DocumentAiPlugin as an, FlowEventEmitter as ar, resizeVideoParamsSchema as at, FlowCondition as b, FlowEventFlowCancel as bi, InputData as bn, ImageDescriptionOutput as br, ResizeTransform as bt, FlowRequirements as c, FlowConfig as ci, OcrParams as cn, eventToMessageSerializer as cr, DescribeVideoMetadata as ct, TypedFlow as d, NodeConnectionValidator as di, OcrTaskType as dn, WebSocketConnection as dr, ImagePluginLayer as dt, UploadFileKVStore as ei, DocumentPluginShape as en, InputFile as er, TrimVideoParams as et, TypedFlowConfig as f, NodeExecutionResult as fi, CredentialProvider as fn, WebSocketMessage as fr, ImagePluginShape as ft, ExtractEffectRequirements as g, completeNodeExecution as gi, ParallelScheduler as gn, uploadEventSchema as gr, FlipTransform as gt, ExtractEffectError as h, TypedOutput as hi, ExecutionLevel as hn, UploadEventType as hr, ContrastTransform as ht, runArgsSchema as i, FlowEdge as ii, DocumentAiContext as in, EventEmitter as ir, ResizeVideoParams as it, isStorageOutput as j, FlowEventNodeResume as ji, FlowWaitUntil as jn, flowTypeRegistry as jr, contrastTransformSchema as jt, isInitOperation as k, FlowEventNodePause as ki, FlowServerOptions as kn, NodeTypeDefinition as kr, blurTransformSchema as kt, NodeDefinition as l, FlowNode as li, OcrResolution as ln, flowEventEmitter as lr, describeVideoMetadataSchema as lt, createFlow as m, TypeCompatibilityChecker as mi, CredentialProviderShape as mn, UploadEvent as mr, BrightnessTransform as mt, resolveUploadMetadata as n, jsonSerializer as ni, SplitPdfParams as nn, BaseEventEmitter as nr, TranscodeVideoParams as nt, FlowOutputMap as o, BuiltInTypedOutput as oi, DocumentAiPluginLayer as on, TypedEventEmitter as or, ExtractFrameVideoParams as ot, TypedFlowEdge as p, NodeTypeMap as pi, CredentialProviderLayer as pn, webSocketMessageSchema as pr, BlurTransform as pt, ScanResult as q, compareMimeTypes as qn, createDataStoreLayer as qr, ImageAiContext as qt, RunArgs as r, uploadFileKvStore as ri, SplitPdfResult as rn, BaseEventEmitterService as rr, transcodeVideoParamsSchema as rt, FlowPluginRequirements as s, CustomTypedOutput as si, DocumentAiPluginShape as sn, UploadEventEmitter as sr, extractFrameVideoParamsSchema as st, ResolvedUploadMetadata as t, flowJobKvStore as ti, MergePdfParams as tn, inputFileSchema as tr, trimVideoParamsSchema as tt, NodeDefinitionsRecord as u, FlowNodeData as ui, OcrResult as un, uploadEventEmitter as ur, ImagePlugin as ut, ExtractLayerServices as v, EventType as vi, TransformNodeConfig as vn, EventBroadcasterService as vr, LogoTransform as vt, getOutputByNodeId as w, FlowEventFlowStart as wi, inputNodeParamsSchema as wn, STREAMING_INPUT_TYPE_ID as wr, TextTransform as wt, createTypeGuard as x, FlowEventFlowEnd as xi, InputNodeParams as xn, OCR_OUTPUT_TYPE_ID as xr, RotateTransform as xt, ResolveEffect as y, FlowEvent as yi, createTransformNode as yn, IMAGE_DESCRIPTION_OUTPUT_TYPE_ID as yr, OverlayPosition as yt, Plugin as z, UploadFile as zi, NegotiatedStrategy as zn, DataStore as zr, textTransformSchema as zt };
6231
- //# sourceMappingURL=index-BQ5luyME.d.cts.map
7952
+ //#region src/flow/utils/file-naming.d.ts
7953
+ /**
7954
+ * Extracts the base name (without extension) from a filename.
7955
+ *
7956
+ * @param fileName - The full filename
7957
+ * @returns The filename without extension
7958
+ *
7959
+ * @example
7960
+ * ```typescript
7961
+ * getBaseName("photo.jpg") // "photo"
7962
+ * getBaseName("document.tar.gz") // "document.tar"
7963
+ * getBaseName("noextension") // "noextension"
7964
+ * ```
7965
+ */
7966
+ declare function getBaseName(fileName: string): string;
7967
+ /**
7968
+ * Extracts the extension (without dot) from a filename.
7969
+ *
7970
+ * @param fileName - The full filename
7971
+ * @returns The extension without leading dot, or empty string if none
7972
+ *
7973
+ * @example
7974
+ * ```typescript
7975
+ * getExtension("photo.jpg") // "jpg"
7976
+ * getExtension("document.tar.gz") // "gz"
7977
+ * getExtension("noextension") // ""
7978
+ * ```
7979
+ */
7980
+ declare function getExtension(fileName: string): string;
7981
+ /**
7982
+ * Builds a naming context from file and flow execution information.
7983
+ *
7984
+ * @param file - The UploadFile being processed
7985
+ * @param flowContext - Flow execution context (flowId, jobId, nodeId, nodeType)
7986
+ * @param extraVars - Additional variables to include (width, height, format, etc.)
7987
+ * @returns Complete naming context for template interpolation
7988
+ *
7989
+ * @example
7990
+ * ```typescript
7991
+ * const context = buildNamingContext(
7992
+ * uploadFile,
7993
+ * { flowId: "flow-1", jobId: "job-1", nodeId: "resize-1", nodeType: "resize" },
7994
+ * { width: 800, height: 600 }
7995
+ * );
7996
+ * // context.baseName = "photo"
7997
+ * // context.extension = "jpg"
7998
+ * // context.width = 800
7999
+ * // context.height = 600
8000
+ * ```
8001
+ */
8002
+ declare function buildNamingContext(file: UploadFile, flowContext: {
8003
+ flowId: string;
8004
+ jobId: string;
8005
+ nodeId: string;
8006
+ nodeType: string;
8007
+ }, extraVars?: Record<string, string | number | undefined>): NamingContext;
8008
+ /**
8009
+ * Interpolates a mustache-style template with the given context.
8010
+ *
8011
+ * Uses micromustache for fast, secure template rendering.
8012
+ * Unknown variables are preserved as-is (e.g., {{unknown}} stays {{unknown}}).
8013
+ *
8014
+ * @param pattern - Mustache-style template string
8015
+ * @param context - Variables to interpolate
8016
+ * @returns Interpolated string
8017
+ *
8018
+ * @example
8019
+ * ```typescript
8020
+ * interpolateFileName(
8021
+ * "{{baseName}}-{{width}}x{{height}}.{{extension}}",
8022
+ * { baseName: "photo", width: 800, height: 600, extension: "jpg" }
8023
+ * );
8024
+ * // Returns: "photo-800x600.jpg"
8025
+ * ```
8026
+ */
8027
+ declare function interpolateFileName(pattern: string, context: NamingContext): string;
8028
+ /**
8029
+ * Applies file naming configuration to generate a new filename.
8030
+ *
8031
+ * Handles three modes:
8032
+ * - No config: Returns original filename (backward compatible)
8033
+ * - Auto mode: Appends auto-generated suffix based on node type
8034
+ * - Custom mode: Uses template pattern or rename function
8035
+ *
8036
+ * On any error, falls back to the original filename to prevent flow failures.
8037
+ *
8038
+ * @param file - The UploadFile being processed
8039
+ * @param context - Naming context with all available variables
8040
+ * @param config - Optional naming configuration
8041
+ * @returns The new filename (or original on error/no config)
8042
+ *
8043
+ * @example
8044
+ * ```typescript
8045
+ * // Auto mode
8046
+ * applyFileNaming(file, context, {
8047
+ * mode: 'auto',
8048
+ * autoSuffix: (ctx) => `${ctx.width}x${ctx.height}`
8049
+ * });
8050
+ * // Returns: "photo-800x600.jpg"
8051
+ *
8052
+ * // Custom mode with template
8053
+ * applyFileNaming(file, context, {
8054
+ * mode: 'custom',
8055
+ * pattern: '{{baseName}}-processed.{{extension}}'
8056
+ * });
8057
+ * // Returns: "photo-processed.jpg"
8058
+ *
8059
+ * // Custom mode with function
8060
+ * applyFileNaming(file, context, {
8061
+ * mode: 'custom',
8062
+ * rename: (file, ctx) => `${ctx.flowId}-${ctx.fileName}`
8063
+ * });
8064
+ * // Returns: "flow-1-photo.jpg"
8065
+ * ```
8066
+ */
8067
+ declare function applyFileNaming(file: UploadFile, context: NamingContext, config?: FileNamingConfig): string;
8068
+ /**
8069
+ * Validates a template pattern for common issues.
8070
+ *
8071
+ * Checks for:
8072
+ * - Balanced braces
8073
+ * - Non-empty pattern
8074
+ * - Valid variable names
8075
+ *
8076
+ * @param pattern - Template pattern to validate
8077
+ * @returns Object with isValid flag and optional error message
8078
+ *
8079
+ * @example
8080
+ * ```typescript
8081
+ * validatePattern("{{baseName}}.{{extension}}");
8082
+ * // { isValid: true }
8083
+ *
8084
+ * validatePattern("{{baseName");
8085
+ * // { isValid: false, error: "Unbalanced braces: missing closing }}" }
8086
+ * ```
8087
+ */
8088
+ declare function validatePattern(pattern: string): {
8089
+ isValid: boolean;
8090
+ error?: string;
8091
+ };
8092
+ /**
8093
+ * List of available template variables for documentation and UI.
8094
+ */
8095
+ declare const AVAILABLE_TEMPLATE_VARIABLES: readonly [{
8096
+ readonly name: "baseName";
8097
+ readonly description: "Filename without extension";
8098
+ readonly example: "photo";
8099
+ }, {
8100
+ readonly name: "extension";
8101
+ readonly description: "File extension without dot";
8102
+ readonly example: "jpg";
8103
+ }, {
8104
+ readonly name: "fileName";
8105
+ readonly description: "Full original filename";
8106
+ readonly example: "photo.jpg";
8107
+ }, {
8108
+ readonly name: "nodeType";
8109
+ readonly description: "Type of processing node";
8110
+ readonly example: "resize";
8111
+ }, {
8112
+ readonly name: "nodeId";
8113
+ readonly description: "Specific node instance ID";
8114
+ readonly example: "resize-1";
8115
+ }, {
8116
+ readonly name: "flowId";
8117
+ readonly description: "Flow identifier";
8118
+ readonly example: "flow-abc";
8119
+ }, {
8120
+ readonly name: "jobId";
8121
+ readonly description: "Execution job ID";
8122
+ readonly example: "job-123";
8123
+ }, {
8124
+ readonly name: "timestamp";
8125
+ readonly description: "ISO 8601 processing time";
8126
+ readonly example: "2024-01-15T10:30:00Z";
8127
+ }, {
8128
+ readonly name: "width";
8129
+ readonly description: "Output width (image/video)";
8130
+ readonly example: "800";
8131
+ }, {
8132
+ readonly name: "height";
8133
+ readonly description: "Output height (image/video)";
8134
+ readonly example: "600";
8135
+ }, {
8136
+ readonly name: "format";
8137
+ readonly description: "Output format";
8138
+ readonly example: "webp";
8139
+ }, {
8140
+ readonly name: "quality";
8141
+ readonly description: "Quality setting";
8142
+ readonly example: "80";
8143
+ }, {
8144
+ readonly name: "pageNumber";
8145
+ readonly description: "Page number (documents)";
8146
+ readonly example: "1";
8147
+ }];
8148
+ //#endregion
8149
+ export { DescribeImageParams as $, KvStore as $a, BackoffStrategy as $i, FlowWaitUntil as $n, ImageDescriptionOutput as $r, sepiaTransformSchema as $t, NodeDefinition as A, ConditionField as Aa, createDataStoreLayer as Ai, CredentialProviderShape as An, HealthResponse as Ar, BrightnessTransform as At, getOutputByNodeId as B, makeKvCircuitBreakerStore as Ba, FlowCircuitBreakerFallback as Bi, ResolveEffect as Bn, UploadEventEmitter as Br, TextTransform as Bt, DeadLetterRetryAttempt as C, FlowEventJobStart as Ca, DataStoreCapabilities as Ci, DocumentAiPluginShape as Cn, inputFileSchema as Cr, extractFrameVideoParamsSchema as Ct, FlowOutputMap as D, FlowEventNodeResponse as Da, UploadFileDataStores as Di, OcrTaskType as Dn, DlqHealthSummary as Dr, ImagePluginLayer as Dt, FlowInputMap as E, FlowEventNodePause as Ea, UploadFileDataStore as Ei, OcrResult as En, DEFAULT_HEALTH_CHECK_CONFIG as Er, ImagePlugin as Et, createFlow as F, getNodeData as Fa, BuiltInTypedOutput as Fi, createTransformNode as Fn, BaseEventEmitter as Fr, OverlayPosition as Ft, isInitOperation as G, CircuitBreakerStats as Ga, NamingContext as Gi, inputDataSchema as Gn, WebSocketMessage as Gr, blurTransformSchema as Gt, hasOutputOfType as H, memoryCircuitBreakerStoreLayer as Ha, FlowDeadLetterQueueConfig as Hi, InputData as Hn, flowEventEmitter as Hr, Transformation as Ht, NarrowedTypedOutput as I, AllowRequestResult as Ia, CustomTypedOutput as Ii, ExtractEffectError as In, BaseEventEmitterService as Ir, ResizeTransform as It, isUploadFile as J, createInitialCircuitBreakerState as Ja, NodeTypeMap as Ji, FlowProviderShape as Jn, UploadEventType as Jr, flipTransformSchema as Jt, isOcrOutput as K, CircuitBreakerStore as Ka, NodeConnectionValidator as Ki, inputNodeParamsSchema as Kn, webSocketMessageSchema as Kr, brightnessTransformSchema as Kt, createTypeGuard as L, DistributedCircuitBreaker as La, FileNamingConfig as Li, ExtractEffectRequirements as Ln, EventEmitter as Lr, RotateTransform as Lt, TypedFlow as M, ConditionValue as Ma, FlowEdge as Mi, ParallelScheduler as Mn, HealthStatus as Mr, FlipTransform as Mt, TypedFlowConfig as N, NodeType as Na, createFlowEdge as Ni, ParallelSchedulerConfig as Nn, formatHealthAsText as Nr, GrayscaleTransform as Nt, FlowPluginRequirements as O, FlowEventNodeResume as Oa, UploadFileDataStoresShape as Oi, CredentialProvider as On, HealthCheckConfig as Or, ImagePluginShape as Ot, TypedFlowEdge as P, createFlowNode as Pa, AutoNamingSuffixGenerator as Pi, TransformNodeConfig as Pn, getHealthResponseFormat as Pr, LogoTransform as Pt, removeBackgroundParamsSchema as Q, FlowJobKVStore as Qa, waitingNodeExecution as Qi, FlowServerShape as Qn, IMAGE_DESCRIPTION_OUTPUT_TYPE_ID as Qr, rotateTransformSchema as Qt, filterOutputsByType as R, DistributedCircuitBreakerRegistry as Ra, FileNamingFunction as Ri, ExtractLayerService as Rn, FlowEventEmitter as Rr, SepiaTransform as Rt, DeadLetterRetryAllResult as S, FlowEventJobEnd as Sa, DataStore as Si, DocumentAiPluginLayer as Sn, InputFile as Sr, ExtractFrameVideoParams as St, runArgsSchema as T, FlowEventNodeError as Ta, DataStoreWriteOptions as Ti, OcrResolution as Tn, ComponentHealth as Tr, describeVideoMetadataSchema as Tt, isFinalizeOperation as U, CircuitBreakerStateData as Ua, FlowNode as Ui, InputNodeParams as Un, uploadEventEmitter as Ur, TransformationType as Ut, getSingleOutputByType as V, makeMemoryCircuitBreakerStore as Va, FlowConfig as Vi, FlowCondition as Vn, eventToMessageSerializer as Vr, TransformImageParams as Vt, isImageDescriptionOutput as W, CircuitBreakerStateValue as Wa, FlowNodeData as Wi, createInputNode as Wn, WebSocketConnection as Wr, WatermarkTransform as Wt, isUrlOperation as X, BaseKvStoreService as Xa, TypedOutput as Xi, FlowServerLayer as Xn, EventBroadcaster as Xr, logoTransformSchema as Xt, isUploadOperation as Y, BaseKvStore as Ya, TypeCompatibilityChecker as Yi, FlowServer as Yn, uploadEventSchema as Yr, grayscaleTransformSchema as Yt, RemoveBackgroundParams as Z, DeadLetterQueueKVStore as Za, completeNodeExecution as Zi, FlowServerOptions as Zn, EventBroadcasterService as Zr, resizeTransformSchema as Zt, DeadLetterItem as _, FlowEventFlowCancel as _a, FlowData as _i, MergePdfParams as _n, Middleware as _r, trimVideoParamsSchema as _t, getExtension as a, calculateBackoffDelay as aa, ocrOutputSchema as ai, ResizeParams as an, uploadFileKvStore as ao, FlowJobTask as ar, ZipPlugin as at, DeadLetterProcessResult as b, FlowEventFlowPause as ba, getFlowData as bi, DocumentAiContext as bn, MiddlewareService as br, ResizeVideoParams as bt, ResolvedUploadMetadata as c, DlqEvent as ca, OutputValidationResult as ci, optimizeParamsSchema as cn, CircuitBreakerConfig as co, UploadStrategyNegotiator as cr, ScanMetadata as ct, DeadLetterQueueServiceShape as d, FlowEventDlqItemAdded as da, InputTypeDefinition as di, ImageAiPluginLayer as dn, CircuitBreakerFallback as do, UploadServerOptions as dr, VirusScanPluginLayer as dt, DEFAULT_RETRY_POLICY as ea, OCR_OUTPUT_TYPE_ID as ei, sharpenTransformSchema as en, TypedKvStore as eo, WaitUntilCallback as er, describeImageParamsSchema as et, createDeadLetterQueueService as f, FlowEventDlqItemExhausted as fa, InputTypeRegistry as fi, ImageAiPluginShape as fn, CircuitBreakerState as fo, UploadServerShape as fr, VirusScanPluginShape as ft, DeadLetterError as g, FlowEventDlqRetrySuccess as ga, Flow as gi, DocumentPluginShape as gn, detectMimeType as gr, TrimVideoParams as gt, DeadLetterCleanupResult as h, FlowEventDlqRetryStart as ha, validateFlowInput as hi, DocumentPluginLayer as hn, compareMimeTypes as hr, VideoPluginShape as ht, getBaseName as i, RetryPolicy as ia, imageDescriptionOutputSchema as ii, watermarkTransformSchema as in, jsonSerializer as io, FlowJobStatus as ir, ZipParams as it, NodeDefinitionsRecord as j, ConditionOperator as ja, isDataStore as ji, ExecutionLevel as jn, HealthResponseFormat as jr, ContrastTransform as jt, FlowRequirements as k, FlowEventNodeStart as ka, UploadStrategy as ki, CredentialProviderLayer as kn, HealthComponents as kr, BlurTransform as kt, resolveUploadMetadata as l, EventType as la, outputTypeRegistry as li, ImageAiContext as ln, CircuitBreakerEvent as lo, UploadStrategyOptions as lr, ScanResult as lt, DeadLetterCleanupOptions as m, FlowEventDlqRetryFailed as ma, inputTypeRegistry as mi, DocumentPlugin as mn, uploadServer as mr, VideoPluginLayer as mt, applyFileNaming as n, FixedBackoff as na, STORAGE_OUTPUT_TYPE_ID as ni, transformImageParamsSchema as nn, deadLetterQueueKvStore as no, flowServer as nr, PluginLayer as nt, interpolateFileName as o, calculateExpirationDate as oa, OutputTypeDefinition as oi, resizeParamsSchema as on, UploadFile as oo, FlowJobTaskStatus as or, ZipPluginLayer as ot, deadLetterQueueService as p, FlowEventDlqItemResolved as pa, InputValidationResult as pi, DocumentMetadata as pn, DEFAULT_CIRCUIT_BREAKER_CONFIG as po, createUploadServer as pr, VideoPlugin as pt, isStorageOutput as q, CircuitBreakerStoreService as qa, NodeExecutionResult as qi, FlowProvider as qn, UploadEvent as qr, contrastTransformSchema as qt, buildNamingContext as r, ImmediateBackoff as ra, STREAMING_INPUT_TYPE_ID as ri, transformationSchema as rn, flowJobKvStore as ro, FlowJob as rr, ZipInput as rt, validatePattern as s, isErrorRetryable as sa, OutputTypeRegistry as si, OptimizeParams as sn, uploadFileSchema as so, NegotiatedStrategy as sr, ZipPluginShape as st, AVAILABLE_TEMPLATE_VARIABLES as t, ExponentialBackoff as ta, OcrOutput as ti, textTransformSchema as tn, UploadFileKVStore as to, createFlowServer as tr, Plugin as tt, DeadLetterQueueService as u, FlowEvent as ua, validateFlowOutput as ui, ImageAiPlugin as un, CircuitBreakerEventHandler as uo, UploadServer as ur, VirusScanPlugin as ut, DeadLetterItemStatus as v, FlowEventFlowEnd as va, FlowExecutionResult as vi, SplitPdfParams as vn, MiddlewareContext as vr, TranscodeVideoParams as vt, RunArgs as w, FlowEventNodeEnd as wa, DataStoreConfig as wi, OcrParams as wn, CircuitBreakerHealthSummary as wr, DescribeVideoMetadata as wt, DeadLetterQueueStats as x, FlowEventFlowStart as xa, BufferedUploadFileDataStore as xi, DocumentAiPlugin as xn, MiddlewareServiceLive as xr, resizeVideoParamsSchema as xt, DeadLetterListOptions as y, FlowEventFlowError as ya, createFlowWithSchema as yi, SplitPdfResult as yn, MiddlewareNext as yr, transcodeVideoParamsSchema as yt, getFirstOutputByType as z, kvCircuitBreakerStoreLayer as za, FlowCircuitBreakerConfig as zi, ExtractLayerServices as zn, TypedEventEmitter as zr, SharpenTransform as zt };
8150
+ //# sourceMappingURL=index-D7i4bgl3.d.mts.map