@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.
- package/README.md +102 -0
- package/dist/{checksum-DaCqP8Qa.mjs → checksum-COoD-F1l.mjs} +2 -2
- package/dist/{checksum-DaCqP8Qa.mjs.map → checksum-COoD-F1l.mjs.map} +1 -1
- package/dist/{checksum-BIlVW8bD.cjs → checksum-YLW4hVY7.cjs} +1 -1
- package/dist/errors/index.cjs +1 -1
- package/dist/errors/index.d.cts +1 -1
- package/dist/errors/index.d.mts +1 -1
- package/dist/errors/index.mjs +1 -1
- package/dist/flow/index.cjs +1 -1
- package/dist/flow/index.d.cts +5 -5
- package/dist/flow/index.d.mts +5 -5
- package/dist/flow/index.mjs +1 -1
- package/dist/flow-BLGpxdEm.mjs +2 -0
- package/dist/flow-BLGpxdEm.mjs.map +1 -0
- package/dist/flow-DaBzRGmY.cjs +1 -0
- package/dist/{index-BGi1r_fi.d.mts → index-9gyMMEIB.d.cts} +2 -2
- package/dist/{index-BGi1r_fi.d.mts.map → index-9gyMMEIB.d.cts.map} +1 -1
- package/dist/{index-B_SvQ0MU.d.cts → index-B9V5SSxl.d.mts} +2 -2
- package/dist/{index-B_SvQ0MU.d.cts.map → index-B9V5SSxl.d.mts.map} +1 -1
- package/dist/{index-DIWuZlxd.d.mts → index-BFSHumky.d.mts} +2 -2
- package/dist/{index-DIWuZlxd.d.mts.map → index-BFSHumky.d.mts.map} +1 -1
- package/dist/{index-BQ5luyME.d.cts → index-D7i4bgl3.d.mts} +2747 -828
- package/dist/index-D7i4bgl3.d.mts.map +1 -0
- package/dist/{index-qIN6ULCb.d.cts → index-DFbu_-zn.d.cts} +2 -2
- package/dist/{index-qIN6ULCb.d.cts.map → index-DFbu_-zn.d.cts.map} +1 -1
- package/dist/{index-BtnCNLsH.d.mts → index-fF-j_WhY.d.cts} +2747 -828
- package/dist/index-fF-j_WhY.d.cts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +1 -1
- package/dist/{stream-limiter-D2Y8Z_Kv.mjs → stream-limiter-B9nsn2gb.mjs} +2 -2
- package/dist/{stream-limiter-D2Y8Z_Kv.mjs.map → stream-limiter-B9nsn2gb.mjs.map} +1 -1
- package/dist/{stream-limiter-By0fxkAh.cjs → stream-limiter-DyWOdil4.cjs} +1 -1
- package/dist/streams/index.cjs +1 -1
- package/dist/streams/index.d.cts +2 -2
- package/dist/streams/index.d.mts +2 -2
- package/dist/streams/index.mjs +1 -1
- package/dist/testing/index.cjs +1 -1
- package/dist/testing/index.d.cts +4 -4
- package/dist/testing/index.d.mts +4 -4
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.cjs +1 -1
- package/dist/types/index.d.cts +5 -5
- package/dist/types/index.d.mts +5 -5
- package/dist/types/index.mjs +1 -1
- package/dist/types-CH0BgiJN.mjs +2 -0
- package/dist/types-CH0BgiJN.mjs.map +1 -0
- package/dist/types-DUYVoR13.cjs +1 -0
- package/dist/upload/index.cjs +1 -1
- package/dist/upload/index.d.cts +4 -4
- package/dist/upload/index.d.mts +4 -4
- package/dist/upload/index.mjs +1 -1
- package/dist/{upload-bBgM3QFI.cjs → upload-CFT-dWPB.cjs} +1 -1
- package/dist/{upload-Bq9h95w6.mjs → upload-ggK-0ZBM.mjs} +2 -2
- package/dist/{upload-Bq9h95w6.mjs.map → upload-ggK-0ZBM.mjs.map} +1 -1
- package/dist/{uploadista-error-DCRIscEv.cjs → uploadista-error-BxBLmQtX.cjs} +4 -1
- package/dist/{uploadista-error-Bb-qIIKM.d.cts → uploadista-error-CYCmAtkZ.d.cts} +2 -2
- package/dist/uploadista-error-CYCmAtkZ.d.cts.map +1 -0
- package/dist/{uploadista-error-djFxVTLh.mjs → uploadista-error-CkSxSyNo.mjs} +4 -1
- package/dist/uploadista-error-CkSxSyNo.mjs.map +1 -0
- package/dist/{uploadista-error-D7Gubrr1.d.mts → uploadista-error-DR0XimpE.d.mts} +2 -2
- package/dist/uploadista-error-DR0XimpE.d.mts.map +1 -0
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.d.cts +2 -2
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/{utils-MQUZyB9S.mjs → utils-B-ZhQ6b0.mjs} +2 -2
- package/dist/{utils-MQUZyB9S.mjs.map → utils-B-ZhQ6b0.mjs.map} +1 -1
- package/dist/{utils-DxLVhlLd.cjs → utils-Dhq3vPqp.cjs} +1 -1
- package/docs/CIRCUIT_BREAKER.md +381 -0
- package/docs/DEAD-LETTER-QUEUE.md +374 -0
- package/package.json +11 -6
- package/src/errors/uploadista-error.ts +16 -1
- package/src/flow/README.md +102 -0
- package/src/flow/circuit-breaker-store.ts +382 -0
- package/src/flow/circuit-breaker.ts +99 -0
- package/src/flow/dead-letter-queue.ts +573 -0
- package/src/flow/distributed-circuit-breaker.ts +437 -0
- package/src/flow/event.ts +105 -1
- package/src/flow/flow-server.ts +70 -0
- package/src/flow/flow.ts +141 -3
- package/src/flow/index.ts +14 -2
- package/src/flow/input-type-registry.ts +229 -0
- package/src/flow/node-types/index.ts +26 -20
- package/src/flow/node.ts +48 -26
- package/src/flow/nodes/input-node.ts +4 -2
- package/src/flow/nodes/transform-node.ts +64 -6
- package/src/flow/output-type-registry.ts +231 -0
- package/src/flow/type-guards.ts +38 -22
- package/src/flow/typed-flow.ts +26 -0
- package/src/flow/types/dead-letter-item.ts +258 -0
- package/src/flow/types/flow-types.ts +320 -2
- package/src/flow/types/retry-policy.ts +260 -0
- package/src/flow/utils/file-naming.ts +308 -0
- package/src/types/circuit-breaker-store.ts +222 -0
- package/src/types/health-check.ts +204 -0
- package/src/types/index.ts +2 -0
- package/src/types/kv-store.ts +82 -2
- package/tests/flow/dead-letter-item.test.ts +283 -0
- package/tests/flow/dead-letter-queue.test.ts +613 -0
- package/tests/flow/file-naming.test.ts +390 -0
- package/tests/flow/retry-policy.test.ts +284 -0
- package/tests/flow/type-registry.test.ts +1 -1
- package/tests/flow/type-system.test.ts +17 -14
- package/dist/flow-BiUCrFTv.cjs +0 -1
- package/dist/flow-vXXjtBBv.mjs +0 -2
- package/dist/flow-vXXjtBBv.mjs.map +0 -1
- package/dist/index-BQ5luyME.d.cts.map +0 -1
- package/dist/index-BtnCNLsH.d.mts.map +0 -1
- package/dist/types-B5I4BioZ.cjs +0 -1
- package/dist/types-f6w5J3UD.mjs +0 -2
- package/dist/types-f6w5J3UD.mjs.map +0 -1
- package/dist/uploadista-error-Bb-qIIKM.d.cts.map +0 -1
- package/dist/uploadista-error-D7Gubrr1.d.mts.map +0 -1
- package/dist/uploadista-error-djFxVTLh.mjs.map +0 -1
- package/src/flow/type-registry.ts +0 -379
|
@@ -1,12 +1,82 @@
|
|
|
1
|
-
import { n as UploadistaError } from "./uploadista-error-
|
|
2
|
-
import { l as GenerateId, p as GenerateIdShape } from "./index-
|
|
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/
|
|
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
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
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
|
-
* //
|
|
98
|
-
* const
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
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
|
-
* //
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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.
|
|
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
|
-
|
|
263
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
2286
|
+
* Context provided to file naming functions and templates.
|
|
1237
2287
|
*
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
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
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
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
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
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
|
-
*
|
|
2342
|
+
* Function type for custom file naming logic.
|
|
1258
2343
|
*
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
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
|
-
*
|
|
1265
|
-
*
|
|
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
|
-
|
|
1275
|
-
declare const UploadFileKVStore_base: Context.TagClass<UploadFileKVStore, "UploadFileKVStore", KvStore<UploadFile>>;
|
|
2354
|
+
type FileNamingFunction = (file: UploadFile, context: NamingContext) => string;
|
|
1276
2355
|
/**
|
|
1277
|
-
*
|
|
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
|
-
*
|
|
1296
|
-
*
|
|
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
|
-
*
|
|
1306
|
-
*
|
|
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
|
-
*
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1313
|
-
*
|
|
1314
|
-
*
|
|
1315
|
-
*
|
|
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
|
-
|
|
1320
|
-
declare const FlowJobKVStore_base: Context.TagClass<FlowJobKVStore, "FlowJobKVStore", KvStore<FlowJob>>;
|
|
2377
|
+
type AutoNamingSuffixGenerator = (context: NamingContext) => string;
|
|
1321
2378
|
/**
|
|
1322
|
-
*
|
|
2379
|
+
* Configuration for file naming behavior on a node.
|
|
1323
2380
|
*
|
|
1324
|
-
*
|
|
1325
|
-
*
|
|
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
|
-
*
|
|
1330
|
-
*
|
|
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
|
-
*
|
|
1333
|
-
*
|
|
1334
|
-
*
|
|
1335
|
-
*
|
|
1336
|
-
*
|
|
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
|
-
*
|
|
1344
|
-
*
|
|
1345
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
2425
|
+
* Represents a connection between two nodes in a flow, defining the data flow direction.
|
|
1352
2426
|
*
|
|
1353
|
-
*
|
|
1354
|
-
*
|
|
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
|
-
*
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
1908
|
-
*
|
|
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
|
-
|
|
3024
|
+
interface InputTypeDefinition<TSchema = unknown> {
|
|
3025
|
+
id: string;
|
|
3026
|
+
schema: z.ZodSchema<TSchema>;
|
|
3027
|
+
version: string;
|
|
3028
|
+
description: string;
|
|
3029
|
+
}
|
|
1911
3030
|
/**
|
|
1912
|
-
*
|
|
3031
|
+
* Result type for input validation operations.
|
|
1913
3032
|
*
|
|
1914
|
-
*
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
1925
|
-
*
|
|
1926
|
-
*
|
|
1927
|
-
*
|
|
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
|
-
*
|
|
1933
|
-
*
|
|
1934
|
-
*
|
|
1935
|
-
* schema:
|
|
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: "
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
3182
|
+
* Registry for output node type definitions.
|
|
1962
3183
|
*
|
|
1963
|
-
* The
|
|
1964
|
-
* and metadata.
|
|
1965
|
-
*
|
|
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
|
-
* -
|
|
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
|
-
*
|
|
1983
|
-
* id: "
|
|
1984
|
-
*
|
|
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: "
|
|
3200
|
+
* description: "File metadata extraction output",
|
|
1988
3201
|
* });
|
|
1989
3202
|
*
|
|
1990
|
-
* //
|
|
1991
|
-
* const
|
|
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
|
-
*
|
|
2004
|
-
* processWebhookResponse(result.data);
|
|
3206
|
+
* console.log(result.data.url);
|
|
2005
3207
|
* }
|
|
2006
3208
|
* ```
|
|
2007
3209
|
*/
|
|
2008
|
-
declare class
|
|
3210
|
+
declare class OutputTypeRegistry {
|
|
2009
3211
|
private readonly types;
|
|
2010
3212
|
constructor();
|
|
2011
3213
|
/**
|
|
2012
|
-
* Register a new
|
|
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:
|
|
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):
|
|
3227
|
+
get(id: string): OutputTypeDefinition<unknown> | undefined;
|
|
2056
3228
|
/**
|
|
2057
|
-
* List all registered types
|
|
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
|
-
* @
|
|
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
|
-
|
|
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):
|
|
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
|
|
3258
|
+
* Global singleton instance of the output type registry.
|
|
2126
3259
|
*
|
|
2127
|
-
* Use this instance to register and access node type definitions
|
|
2128
|
-
*
|
|
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 {
|
|
3265
|
+
* import { outputTypeRegistry } from "@uploadista/core/flow";
|
|
2133
3266
|
*
|
|
2134
3267
|
* // Register a type
|
|
2135
|
-
*
|
|
3268
|
+
* outputTypeRegistry.register({
|
|
2136
3269
|
* id: "my-output-v1",
|
|
2137
|
-
*
|
|
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 =
|
|
3275
|
+
* // Validate result data
|
|
3276
|
+
* const result = outputTypeRegistry.validate("my-output-v1", data);
|
|
2145
3277
|
* ```
|
|
2146
3278
|
*/
|
|
2147
|
-
declare const
|
|
3279
|
+
declare const outputTypeRegistry: OutputTypeRegistry;
|
|
2148
3280
|
/**
|
|
2149
|
-
* Validates flow
|
|
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., "
|
|
2156
|
-
* @param data - The
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
|
3950
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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<
|
|
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
|
|
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<
|
|
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
|
|
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<
|
|
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
|
|
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<
|
|
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
|
-
|
|
7211
|
+
declare function isFinalizeOperation(data: InputData): data is Extract<InputData, {
|
|
7212
|
+
operation: "finalize";
|
|
7213
|
+
}>;
|
|
5914
7214
|
/**
|
|
5915
|
-
*
|
|
7215
|
+
* Type guard for URL operation (direct file fetch from URL).
|
|
5916
7216
|
*
|
|
5917
|
-
*
|
|
5918
|
-
*
|
|
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
|
-
* @
|
|
5922
|
-
* @returns
|
|
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
|
-
*
|
|
5927
|
-
*
|
|
5928
|
-
*
|
|
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
|
-
*
|
|
5934
|
-
*
|
|
5935
|
-
*
|
|
5936
|
-
*
|
|
5937
|
-
*
|
|
5938
|
-
*
|
|
5939
|
-
*
|
|
5940
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
6231
|
-
|
|
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
|