@uploadista/core 0.0.2
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/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-check.log +231 -0
- package/.turbo/turbo-format.log +5 -0
- package/LICENSE +21 -0
- package/README.md +1120 -0
- package/dist/chunk-CUT6urMc.cjs +1 -0
- package/dist/debounce-C2SeqcxD.js +2 -0
- package/dist/debounce-C2SeqcxD.js.map +1 -0
- package/dist/debounce-LZK7yS7Z.cjs +1 -0
- package/dist/errors/index.cjs +1 -0
- package/dist/errors/index.d.cts +3 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/uploadista-error.d.ts +209 -0
- package/dist/errors/uploadista-error.d.ts.map +1 -0
- package/dist/errors/uploadista-error.js +322 -0
- package/dist/errors-8i_aMxOE.js +1 -0
- package/dist/errors-CRm1FHHT.cjs +0 -0
- package/dist/flow/edge.d.ts +47 -0
- package/dist/flow/edge.d.ts.map +1 -0
- package/dist/flow/edge.js +40 -0
- package/dist/flow/event.d.ts +206 -0
- package/dist/flow/event.d.ts.map +1 -0
- package/dist/flow/event.js +53 -0
- package/dist/flow/flow-server.d.ts +223 -0
- package/dist/flow/flow-server.d.ts.map +1 -0
- package/dist/flow/flow-server.js +614 -0
- package/dist/flow/flow.d.ts +238 -0
- package/dist/flow/flow.d.ts.map +1 -0
- package/dist/flow/flow.js +629 -0
- package/dist/flow/index.cjs +1 -0
- package/dist/flow/index.d.cts +6 -0
- package/dist/flow/index.d.ts +24 -0
- package/dist/flow/index.d.ts.map +1 -0
- package/dist/flow/index.js +24 -0
- package/dist/flow/node.d.ts +136 -0
- package/dist/flow/node.d.ts.map +1 -0
- package/dist/flow/node.js +153 -0
- package/dist/flow/nodes/index.d.ts +8 -0
- package/dist/flow/nodes/index.d.ts.map +1 -0
- package/dist/flow/nodes/index.js +7 -0
- package/dist/flow/nodes/input-node.d.ts +78 -0
- package/dist/flow/nodes/input-node.d.ts.map +1 -0
- package/dist/flow/nodes/input-node.js +233 -0
- package/dist/flow/nodes/storage-node.d.ts +67 -0
- package/dist/flow/nodes/storage-node.d.ts.map +1 -0
- package/dist/flow/nodes/storage-node.js +94 -0
- package/dist/flow/nodes/streaming-input-node.d.ts +69 -0
- package/dist/flow/nodes/streaming-input-node.d.ts.map +1 -0
- package/dist/flow/nodes/streaming-input-node.js +156 -0
- package/dist/flow/nodes/transform-node.d.ts +85 -0
- package/dist/flow/nodes/transform-node.d.ts.map +1 -0
- package/dist/flow/nodes/transform-node.js +107 -0
- package/dist/flow/parallel-scheduler.d.ts +175 -0
- package/dist/flow/parallel-scheduler.d.ts.map +1 -0
- package/dist/flow/parallel-scheduler.js +193 -0
- package/dist/flow/plugins/credential-provider.d.ts +47 -0
- package/dist/flow/plugins/credential-provider.d.ts.map +1 -0
- package/dist/flow/plugins/credential-provider.js +24 -0
- package/dist/flow/plugins/image-ai-plugin.d.ts +61 -0
- package/dist/flow/plugins/image-ai-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/image-ai-plugin.js +21 -0
- package/dist/flow/plugins/image-plugin.d.ts +52 -0
- package/dist/flow/plugins/image-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/image-plugin.js +22 -0
- package/dist/flow/plugins/types/describe-image-node.d.ts +16 -0
- package/dist/flow/plugins/types/describe-image-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/describe-image-node.js +9 -0
- package/dist/flow/plugins/types/index.d.ts +9 -0
- package/dist/flow/plugins/types/index.d.ts.map +1 -0
- package/dist/flow/plugins/types/index.js +8 -0
- package/dist/flow/plugins/types/optimize-node.d.ts +20 -0
- package/dist/flow/plugins/types/optimize-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/optimize-node.js +11 -0
- package/dist/flow/plugins/types/remove-background-node.d.ts +16 -0
- package/dist/flow/plugins/types/remove-background-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/remove-background-node.js +9 -0
- package/dist/flow/plugins/types/resize-node.d.ts +21 -0
- package/dist/flow/plugins/types/resize-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/resize-node.js +16 -0
- package/dist/flow/plugins/zip-plugin.d.ts +62 -0
- package/dist/flow/plugins/zip-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/zip-plugin.js +21 -0
- package/dist/flow/typed-flow.d.ts +90 -0
- package/dist/flow/typed-flow.d.ts.map +1 -0
- package/dist/flow/typed-flow.js +59 -0
- package/dist/flow/types/flow-file.d.ts +45 -0
- package/dist/flow/types/flow-file.d.ts.map +1 -0
- package/dist/flow/types/flow-file.js +27 -0
- package/dist/flow/types/flow-job.d.ts +118 -0
- package/dist/flow/types/flow-job.d.ts.map +1 -0
- package/dist/flow/types/flow-job.js +11 -0
- package/dist/flow/types/flow-types.d.ts +321 -0
- package/dist/flow/types/flow-types.d.ts.map +1 -0
- package/dist/flow/types/flow-types.js +52 -0
- package/dist/flow/types/index.d.ts +4 -0
- package/dist/flow/types/index.d.ts.map +1 -0
- package/dist/flow/types/index.js +3 -0
- package/dist/flow/types/run-args.d.ts +38 -0
- package/dist/flow/types/run-args.d.ts.map +1 -0
- package/dist/flow/types/run-args.js +30 -0
- package/dist/flow/types/type-validator.d.ts +26 -0
- package/dist/flow/types/type-validator.d.ts.map +1 -0
- package/dist/flow/types/type-validator.js +134 -0
- package/dist/flow/utils/resolve-upload-metadata.d.ts +11 -0
- package/dist/flow/utils/resolve-upload-metadata.d.ts.map +1 -0
- package/dist/flow/utils/resolve-upload-metadata.js +28 -0
- package/dist/flow-2zXnEiWL.cjs +1 -0
- package/dist/flow-CRaKy7Vj.js +2 -0
- package/dist/flow-CRaKy7Vj.js.map +1 -0
- package/dist/generate-id-Dm-Vboxq.d.ts +34 -0
- package/dist/generate-id-Dm-Vboxq.d.ts.map +1 -0
- package/dist/generate-id-LjJRLD6N.d.cts +34 -0
- package/dist/generate-id-LjJRLD6N.d.cts.map +1 -0
- package/dist/generate-id-xHp_Z7Cl.cjs +1 -0
- package/dist/generate-id-yohS1ZDk.js +2 -0
- package/dist/generate-id-yohS1ZDk.js.map +1 -0
- package/dist/index-BO8GZlbD.d.cts +1040 -0
- package/dist/index-BO8GZlbD.d.cts.map +1 -0
- package/dist/index-BoGG5KAY.d.ts +1 -0
- package/dist/index-BtBZHVmz.d.cts +1 -0
- package/dist/index-D-CoVpkZ.d.ts +1004 -0
- package/dist/index-D-CoVpkZ.d.ts.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/logger/logger.cjs +1 -0
- package/dist/logger/logger.d.cts +8 -0
- package/dist/logger/logger.d.cts.map +1 -0
- package/dist/logger/logger.d.ts +5 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +10 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/semaphore-0ZwjVpyF.js +2 -0
- package/dist/semaphore-0ZwjVpyF.js.map +1 -0
- package/dist/semaphore-BHprIjFI.d.cts +37 -0
- package/dist/semaphore-BHprIjFI.d.cts.map +1 -0
- package/dist/semaphore-DThupBkc.d.ts +37 -0
- package/dist/semaphore-DThupBkc.d.ts.map +1 -0
- package/dist/semaphore-DVrONiAV.cjs +1 -0
- package/dist/stream-limiter-CoWKv39w.js +2 -0
- package/dist/stream-limiter-CoWKv39w.js.map +1 -0
- package/dist/stream-limiter-JgOwmkMa.cjs +1 -0
- package/dist/streams/multi-stream.cjs +1 -0
- package/dist/streams/multi-stream.d.cts +91 -0
- package/dist/streams/multi-stream.d.cts.map +1 -0
- package/dist/streams/multi-stream.d.ts +86 -0
- package/dist/streams/multi-stream.d.ts.map +1 -0
- package/dist/streams/multi-stream.js +149 -0
- package/dist/streams/multi-stream.js.map +1 -0
- package/dist/streams/stream-limiter.cjs +1 -0
- package/dist/streams/stream-limiter.d.cts +36 -0
- package/dist/streams/stream-limiter.d.cts.map +1 -0
- package/dist/streams/stream-limiter.d.ts +27 -0
- package/dist/streams/stream-limiter.d.ts.map +1 -0
- package/dist/streams/stream-limiter.js +49 -0
- package/dist/streams/stream-splitter.cjs +1 -0
- package/dist/streams/stream-splitter.d.cts +68 -0
- package/dist/streams/stream-splitter.d.cts.map +1 -0
- package/dist/streams/stream-splitter.d.ts +51 -0
- package/dist/streams/stream-splitter.d.ts.map +1 -0
- package/dist/streams/stream-splitter.js +175 -0
- package/dist/streams/stream-splitter.js.map +1 -0
- package/dist/types/data-store-registry.d.ts +13 -0
- package/dist/types/data-store-registry.d.ts.map +1 -0
- package/dist/types/data-store-registry.js +4 -0
- package/dist/types/data-store.d.ts +316 -0
- package/dist/types/data-store.d.ts.map +1 -0
- package/dist/types/data-store.js +157 -0
- package/dist/types/event-broadcaster.d.ts +28 -0
- package/dist/types/event-broadcaster.d.ts.map +1 -0
- package/dist/types/event-broadcaster.js +6 -0
- package/dist/types/event-emitter.d.ts +378 -0
- package/dist/types/event-emitter.d.ts.map +1 -0
- package/dist/types/event-emitter.js +223 -0
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.d.cts +6 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +9 -0
- package/dist/types/input-file.d.ts +104 -0
- package/dist/types/input-file.d.ts.map +1 -0
- package/dist/types/input-file.js +27 -0
- package/dist/types/kv-store.d.ts +281 -0
- package/dist/types/kv-store.d.ts.map +1 -0
- package/dist/types/kv-store.js +234 -0
- package/dist/types/middleware.d.ts +17 -0
- package/dist/types/middleware.d.ts.map +1 -0
- package/dist/types/middleware.js +21 -0
- package/dist/types/upload-event.d.ts +105 -0
- package/dist/types/upload-event.d.ts.map +1 -0
- package/dist/types/upload-event.js +71 -0
- package/dist/types/upload-file.d.ts +136 -0
- package/dist/types/upload-file.d.ts.map +1 -0
- package/dist/types/upload-file.js +34 -0
- package/dist/types/websocket.d.ts +144 -0
- package/dist/types/websocket.d.ts.map +1 -0
- package/dist/types/websocket.js +40 -0
- package/dist/types-BT-cvi7T.cjs +1 -0
- package/dist/types-DhU2j-XF.js +2 -0
- package/dist/types-DhU2j-XF.js.map +1 -0
- package/dist/upload/convert-to-stream.d.ts +38 -0
- package/dist/upload/convert-to-stream.d.ts.map +1 -0
- package/dist/upload/convert-to-stream.js +43 -0
- package/dist/upload/convert-upload-to-flow-file.d.ts +14 -0
- package/dist/upload/convert-upload-to-flow-file.d.ts.map +1 -0
- package/dist/upload/convert-upload-to-flow-file.js +21 -0
- package/dist/upload/create-upload.d.ts +68 -0
- package/dist/upload/create-upload.d.ts.map +1 -0
- package/dist/upload/create-upload.js +157 -0
- package/dist/upload/index.cjs +1 -0
- package/dist/upload/index.d.cts +6 -0
- package/dist/upload/index.d.ts +4 -0
- package/dist/upload/index.d.ts.map +1 -0
- package/dist/upload/index.js +3 -0
- package/dist/upload/mime.d.ts +24 -0
- package/dist/upload/mime.d.ts.map +1 -0
- package/dist/upload/mime.js +351 -0
- package/dist/upload/upload-chunk.d.ts +58 -0
- package/dist/upload/upload-chunk.d.ts.map +1 -0
- package/dist/upload/upload-chunk.js +277 -0
- package/dist/upload/upload-server.d.ts +221 -0
- package/dist/upload/upload-server.d.ts.map +1 -0
- package/dist/upload/upload-server.js +181 -0
- package/dist/upload/upload-strategy-negotiator.d.ts +148 -0
- package/dist/upload/upload-strategy-negotiator.d.ts.map +1 -0
- package/dist/upload/upload-strategy-negotiator.js +217 -0
- package/dist/upload/upload-url.d.ts +68 -0
- package/dist/upload/upload-url.d.ts.map +1 -0
- package/dist/upload/upload-url.js +142 -0
- package/dist/upload/write-to-store.d.ts +77 -0
- package/dist/upload/write-to-store.d.ts.map +1 -0
- package/dist/upload/write-to-store.js +147 -0
- package/dist/upload-DLuICjpP.cjs +1 -0
- package/dist/upload-DaXO34dE.js +2 -0
- package/dist/upload-DaXO34dE.js.map +1 -0
- package/dist/uploadista-error-BB-Wdiz9.cjs +22 -0
- package/dist/uploadista-error-BVsVxqvz.js +23 -0
- package/dist/uploadista-error-BVsVxqvz.js.map +1 -0
- package/dist/uploadista-error-CwxYs4EB.d.ts +52 -0
- package/dist/uploadista-error-CwxYs4EB.d.ts.map +1 -0
- package/dist/uploadista-error-kKlhLRhY.d.cts +52 -0
- package/dist/uploadista-error-kKlhLRhY.d.cts.map +1 -0
- package/dist/utils/checksum.d.ts +22 -0
- package/dist/utils/checksum.d.ts.map +1 -0
- package/dist/utils/checksum.js +49 -0
- package/dist/utils/debounce.cjs +1 -0
- package/dist/utils/debounce.d.cts +38 -0
- package/dist/utils/debounce.d.cts.map +1 -0
- package/dist/utils/debounce.d.ts +36 -0
- package/dist/utils/debounce.d.ts.map +1 -0
- package/dist/utils/debounce.js +73 -0
- package/dist/utils/generate-id.cjs +1 -0
- package/dist/utils/generate-id.d.cts +2 -0
- package/dist/utils/generate-id.d.ts +32 -0
- package/dist/utils/generate-id.d.ts.map +1 -0
- package/dist/utils/generate-id.js +23 -0
- package/dist/utils/md5.cjs +1 -0
- package/dist/utils/md5.d.cts +73 -0
- package/dist/utils/md5.d.cts.map +1 -0
- package/dist/utils/md5.d.ts +71 -0
- package/dist/utils/md5.d.ts.map +1 -0
- package/dist/utils/md5.js +417 -0
- package/dist/utils/md5.js.map +1 -0
- package/dist/utils/once.cjs +1 -0
- package/dist/utils/once.d.cts +25 -0
- package/dist/utils/once.d.cts.map +1 -0
- package/dist/utils/once.d.ts +21 -0
- package/dist/utils/once.d.ts.map +1 -0
- package/dist/utils/once.js +54 -0
- package/dist/utils/once.js.map +1 -0
- package/dist/utils/semaphore.cjs +1 -0
- package/dist/utils/semaphore.d.cts +3 -0
- package/dist/utils/semaphore.d.ts +78 -0
- package/dist/utils/semaphore.d.ts.map +1 -0
- package/dist/utils/semaphore.js +134 -0
- package/dist/utils/throttle.cjs +1 -0
- package/dist/utils/throttle.d.cts +24 -0
- package/dist/utils/throttle.d.cts.map +1 -0
- package/dist/utils/throttle.d.ts +18 -0
- package/dist/utils/throttle.d.ts.map +1 -0
- package/dist/utils/throttle.js +20 -0
- package/dist/utils/throttle.js.map +1 -0
- package/docs/PARALLEL_EXECUTION.md +206 -0
- package/docs/PARALLEL_EXECUTION_QUICKSTART.md +142 -0
- package/docs/PARALLEL_EXECUTION_REFACTOR.md +184 -0
- package/package.json +80 -0
- package/src/errors/__tests__/uploadista-error.test.ts +251 -0
- package/src/errors/index.ts +2 -0
- package/src/errors/uploadista-error.ts +394 -0
- package/src/flow/README.md +352 -0
- package/src/flow/edge.test.ts +146 -0
- package/src/flow/edge.ts +60 -0
- package/src/flow/event.ts +229 -0
- package/src/flow/flow-server.ts +1089 -0
- package/src/flow/flow.ts +1050 -0
- package/src/flow/index.ts +28 -0
- package/src/flow/node.ts +249 -0
- package/src/flow/nodes/index.ts +8 -0
- package/src/flow/nodes/input-node.ts +296 -0
- package/src/flow/nodes/storage-node.ts +128 -0
- package/src/flow/nodes/transform-node.ts +154 -0
- package/src/flow/parallel-scheduler.ts +259 -0
- package/src/flow/plugins/credential-provider.ts +48 -0
- package/src/flow/plugins/image-ai-plugin.ts +66 -0
- package/src/flow/plugins/image-plugin.ts +60 -0
- package/src/flow/plugins/types/describe-image-node.ts +16 -0
- package/src/flow/plugins/types/index.ts +9 -0
- package/src/flow/plugins/types/optimize-node.ts +18 -0
- package/src/flow/plugins/types/remove-background-node.ts +18 -0
- package/src/flow/plugins/types/resize-node.ts +26 -0
- package/src/flow/plugins/zip-plugin.ts +69 -0
- package/src/flow/typed-flow.ts +279 -0
- package/src/flow/types/flow-file.ts +51 -0
- package/src/flow/types/flow-job.ts +138 -0
- package/src/flow/types/flow-types.ts +353 -0
- package/src/flow/types/index.ts +6 -0
- package/src/flow/types/run-args.ts +40 -0
- package/src/flow/types/type-validator.ts +204 -0
- package/src/flow/utils/resolve-upload-metadata.ts +48 -0
- package/src/index.ts +5 -0
- package/src/logger/logger.ts +14 -0
- package/src/streams/stream-limiter.test.ts +150 -0
- package/src/streams/stream-limiter.ts +75 -0
- package/src/types/data-store.ts +427 -0
- package/src/types/event-broadcaster.ts +39 -0
- package/src/types/event-emitter.ts +349 -0
- package/src/types/index.ts +9 -0
- package/src/types/input-file.ts +107 -0
- package/src/types/kv-store.ts +375 -0
- package/src/types/middleware.ts +54 -0
- package/src/types/upload-event.ts +75 -0
- package/src/types/upload-file.ts +139 -0
- package/src/types/websocket.ts +65 -0
- package/src/upload/convert-to-stream.ts +48 -0
- package/src/upload/create-upload.ts +214 -0
- package/src/upload/index.ts +3 -0
- package/src/upload/mime.ts +436 -0
- package/src/upload/upload-chunk.ts +364 -0
- package/src/upload/upload-server.ts +390 -0
- package/src/upload/upload-strategy-negotiator.ts +316 -0
- package/src/upload/upload-url.ts +173 -0
- package/src/upload/write-to-store.ts +211 -0
- package/src/utils/checksum.ts +61 -0
- package/src/utils/debounce.test.ts +126 -0
- package/src/utils/debounce.ts +89 -0
- package/src/utils/generate-id.ts +35 -0
- package/src/utils/md5.ts +475 -0
- package/src/utils/once.test.ts +83 -0
- package/src/utils/once.ts +63 -0
- package/src/utils/throttle.test.ts +101 -0
- package/src/utils/throttle.ts +29 -0
- package/tsconfig.json +20 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.ts +25 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# Flow Engine
|
|
2
|
+
|
|
3
|
+
A flexible and extensible flow engine for executing directed acyclic graphs (DAGs) of processing nodes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Flow Engine allows you to create complex processing pipelines by connecting nodes together. Each node represents a processing step, and edges define the data flow between nodes.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
### Core Components
|
|
12
|
+
|
|
13
|
+
- **Flow**: The main container that holds nodes and edges
|
|
14
|
+
- **Node**: Individual processing units with input/output capabilities
|
|
15
|
+
- **Edge**: Connections between nodes defining data flow
|
|
16
|
+
- **Result**: Typed results for success, error, and cancellation states
|
|
17
|
+
|
|
18
|
+
### Node Types
|
|
19
|
+
|
|
20
|
+
- **Input**: Entry point nodes that receive initial data
|
|
21
|
+
- **Process**: Processing nodes that transform data
|
|
22
|
+
- **Output**: Final nodes that produce the end result
|
|
23
|
+
- **Conditional**: Nodes that route flow based on conditions
|
|
24
|
+
- **Multiplex**: Nodes that split input into multiple parallel outputs
|
|
25
|
+
- **Merge**: Nodes that combine multiple inputs into a single output
|
|
26
|
+
|
|
27
|
+
## New Advanced Features
|
|
28
|
+
|
|
29
|
+
### 1. Zip Node
|
|
30
|
+
|
|
31
|
+
The zip node allows you to combine multiple files into a single archive:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { createZipNode } from "./nodes/zip-node";
|
|
35
|
+
|
|
36
|
+
const zipNode = createZipNode("zip-files", {
|
|
37
|
+
zipName: "archive.zip",
|
|
38
|
+
includeMetadata: true,
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Features:**
|
|
43
|
+
|
|
44
|
+
- Combines multiple input files into a single zip archive
|
|
45
|
+
- Supports both single files and file batches
|
|
46
|
+
- Optional metadata inclusion
|
|
47
|
+
- Customizable archive name
|
|
48
|
+
|
|
49
|
+
### 2. Conditional Node
|
|
50
|
+
|
|
51
|
+
The conditional node routes flow based on file properties:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { createConditionalNode } from "./nodes/conditional-node";
|
|
55
|
+
|
|
56
|
+
const conditionalNode = createConditionalNode("size-check", {
|
|
57
|
+
field: "size",
|
|
58
|
+
operator: "greaterThan",
|
|
59
|
+
value: 1024 * 1024, // 1MB
|
|
60
|
+
trueBranch: "large-file-processor",
|
|
61
|
+
falseBranch: "small-file-processor",
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Supported Conditions:**
|
|
66
|
+
|
|
67
|
+
- **Fields**: `mimeType`, `size`, `width`, `height`, `extension`
|
|
68
|
+
- **Operators**: `equals`, `notEquals`, `greaterThan`, `lessThan`, `contains`, `startsWith`
|
|
69
|
+
|
|
70
|
+
### 3. Multiplex Node
|
|
71
|
+
|
|
72
|
+
The multiplex node splits a single input into multiple parallel outputs:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { createMultiplexNode } from "./nodes/multiplex-node";
|
|
76
|
+
|
|
77
|
+
const multiplexNode = createMultiplexNode("multiplex", {
|
|
78
|
+
outputCount: 3,
|
|
79
|
+
strategy: "copy", // or "split"
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Strategies:**
|
|
84
|
+
|
|
85
|
+
- **Copy**: Creates multiple copies of the same file
|
|
86
|
+
- **Split**: Splits the file into chunks
|
|
87
|
+
|
|
88
|
+
### 4. Merge Node
|
|
89
|
+
|
|
90
|
+
The merge node combines multiple inputs into a single output:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { createMergeNode } from "./nodes/merge-node";
|
|
94
|
+
|
|
95
|
+
const mergeNode = createMergeNode("merge-files", {
|
|
96
|
+
strategy: "batch", // or "concat"
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Strategies:**
|
|
101
|
+
|
|
102
|
+
- **Batch**: Returns files as a batch
|
|
103
|
+
- **Concat**: Concatenates all files into one
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
### Basic Example
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import type { FlowNode } from "./node";
|
|
111
|
+
|
|
112
|
+
import { createFlow } from "./flow";
|
|
113
|
+
import { NodeType } from "./node";
|
|
114
|
+
import { successResult } from "./result";
|
|
115
|
+
|
|
116
|
+
// Define your data type
|
|
117
|
+
type MyData = {
|
|
118
|
+
value: number;
|
|
119
|
+
processed: boolean;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Create nodes
|
|
123
|
+
const inputNode: FlowNode<MyData, MyData> = {
|
|
124
|
+
id: "input",
|
|
125
|
+
name: "Input",
|
|
126
|
+
description: "Input node",
|
|
127
|
+
type: NodeType.input,
|
|
128
|
+
run: async ({ data }) => {
|
|
129
|
+
return successResult(data);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const processNode: FlowNode<MyData, MyData> = {
|
|
134
|
+
id: "process",
|
|
135
|
+
name: "Process",
|
|
136
|
+
description: "Process node",
|
|
137
|
+
type: NodeType.process,
|
|
138
|
+
run: async ({ data }) => {
|
|
139
|
+
return successResult({
|
|
140
|
+
...data,
|
|
141
|
+
value: data.value * 2,
|
|
142
|
+
processed: true,
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const outputNode: FlowNode<MyData, MyData> = {
|
|
148
|
+
id: "output",
|
|
149
|
+
name: "Output",
|
|
150
|
+
description: "Output node",
|
|
151
|
+
type: NodeType.output,
|
|
152
|
+
run: async ({ data }) => {
|
|
153
|
+
return successResult(data);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Create the flow
|
|
158
|
+
const flow = createFlow({
|
|
159
|
+
flowId: "simple-flow",
|
|
160
|
+
nodes: [inputNode, processNode, outputNode],
|
|
161
|
+
edges: [
|
|
162
|
+
{ source: "input", target: "process" },
|
|
163
|
+
{ source: "process", target: "output" },
|
|
164
|
+
],
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Run the flow
|
|
168
|
+
const result = await flow.run({
|
|
169
|
+
value: 5,
|
|
170
|
+
processed: false,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
if (result.type === "success") {
|
|
174
|
+
console.log("Result:", result.value);
|
|
175
|
+
// Output: { value: 10, processed: true }
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Error Handling
|
|
180
|
+
|
|
181
|
+
The flow engine provides comprehensive error handling:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const errorNode: FlowNode<MyData, MyData> = {
|
|
185
|
+
id: "error",
|
|
186
|
+
name: "Error Node",
|
|
187
|
+
type: NodeType.process,
|
|
188
|
+
run: async () => {
|
|
189
|
+
throw new Error("Something went wrong");
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const flow = createFlow({
|
|
194
|
+
nodes: [inputNode, errorNode],
|
|
195
|
+
edges: [{ source: "input", target: "error" }],
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const result = await flow.run(inputData);
|
|
199
|
+
|
|
200
|
+
if (result.type === "error") {
|
|
201
|
+
console.error("Flow failed:", result.error);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Cancellation
|
|
206
|
+
|
|
207
|
+
Flows can be cancelled during execution:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
const longRunningNode: FlowNode<MyData, MyData> = {
|
|
211
|
+
id: "long-running",
|
|
212
|
+
name: "Long Running",
|
|
213
|
+
type: NodeType.process,
|
|
214
|
+
run: async ({ runId }) => {
|
|
215
|
+
// Simulate long-running task
|
|
216
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
217
|
+
return successResult(data);
|
|
218
|
+
},
|
|
219
|
+
cancel: (runId) => {
|
|
220
|
+
// Handle cancellation
|
|
221
|
+
console.log(`Cancelling node ${runId}`);
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const flow = createFlow({
|
|
226
|
+
nodes: [inputNode, longRunningNode],
|
|
227
|
+
edges: [{ source: "input", target: "long-running" }],
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Start the flow
|
|
231
|
+
const promise = flow.run(inputData);
|
|
232
|
+
|
|
233
|
+
// Cancel after 1 second
|
|
234
|
+
setTimeout(() => {
|
|
235
|
+
flow.cancel?.(runId);
|
|
236
|
+
}, 1000);
|
|
237
|
+
|
|
238
|
+
const result = await promise;
|
|
239
|
+
if (result.type === "cancelled") {
|
|
240
|
+
console.log("Flow was cancelled");
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Features
|
|
245
|
+
|
|
246
|
+
### Topological Sorting
|
|
247
|
+
|
|
248
|
+
The engine automatically determines the correct execution order using topological sorting, ensuring nodes are executed in the right sequence based on their dependencies.
|
|
249
|
+
|
|
250
|
+
### Cycle Detection
|
|
251
|
+
|
|
252
|
+
The engine detects cycles in the flow graph and returns an error if any are found.
|
|
253
|
+
|
|
254
|
+
### Type Safety
|
|
255
|
+
|
|
256
|
+
Full TypeScript support with generic types for input and output data.
|
|
257
|
+
|
|
258
|
+
### Async Support
|
|
259
|
+
|
|
260
|
+
All nodes support asynchronous operations and proper error propagation.
|
|
261
|
+
|
|
262
|
+
### Cancellation Support
|
|
263
|
+
|
|
264
|
+
Nodes can implement cancellation logic to handle graceful shutdowns.
|
|
265
|
+
|
|
266
|
+
## Advanced Usage
|
|
267
|
+
|
|
268
|
+
### Multiple Inputs
|
|
269
|
+
|
|
270
|
+
For nodes with multiple incoming edges, you can implement custom logic to merge inputs:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
const mergeNode: FlowNode<MyData[], MyData> = {
|
|
274
|
+
id: "merge",
|
|
275
|
+
name: "Merge",
|
|
276
|
+
type: NodeType.process,
|
|
277
|
+
run: async ({ data }) => {
|
|
278
|
+
// Merge multiple inputs
|
|
279
|
+
const merged = data.reduce((acc, item) => ({
|
|
280
|
+
value: acc.value + item.value,
|
|
281
|
+
processed: acc.processed && item.processed,
|
|
282
|
+
}));
|
|
283
|
+
return successResult(merged);
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Conditional Execution
|
|
289
|
+
|
|
290
|
+
You can implement conditional logic in nodes:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const conditionalNode: FlowNode<MyData, MyData> = {
|
|
294
|
+
id: "conditional",
|
|
295
|
+
name: "Conditional",
|
|
296
|
+
type: NodeType.process,
|
|
297
|
+
run: async ({ data }) => {
|
|
298
|
+
if (data.value > 10) {
|
|
299
|
+
return successResult({ ...data, processed: true });
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
return successResult({ ...data, processed: false });
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Best Practices
|
|
309
|
+
|
|
310
|
+
1. **Use descriptive node names**: Make your nodes easy to understand and debug
|
|
311
|
+
2. **Handle errors gracefully**: Always return proper error results from nodes
|
|
312
|
+
3. **Keep nodes focused**: Each node should have a single responsibility
|
|
313
|
+
4. **Test your flows**: Create unit tests for individual nodes and integration tests for flows
|
|
314
|
+
5. **Monitor performance**: Use the runId and flowId for logging and monitoring
|
|
315
|
+
|
|
316
|
+
## API Reference
|
|
317
|
+
|
|
318
|
+
### Flow
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
type Flow<Input, Output> = {
|
|
322
|
+
nodes: FlowNode<Input, Output>[];
|
|
323
|
+
edges: FlowEdge[];
|
|
324
|
+
run: (input?: Input) => Promise<FlowResult<Output>>;
|
|
325
|
+
cancel?: (runId: string) => void;
|
|
326
|
+
};
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### FlowNode
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
type FlowNode<Input, Output> = {
|
|
333
|
+
id: string;
|
|
334
|
+
name: string;
|
|
335
|
+
type: NodeType;
|
|
336
|
+
run: (args: {
|
|
337
|
+
data: Input;
|
|
338
|
+
runId: string;
|
|
339
|
+
flowId: string;
|
|
340
|
+
}) => Promise<FlowResult<Output>>;
|
|
341
|
+
cancel?: (runId: string) => void;
|
|
342
|
+
};
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### FlowResult
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
type FlowResult<Value>
|
|
349
|
+
= | { type: "success"; value: Value }
|
|
350
|
+
| { type: "error"; error: string }
|
|
351
|
+
| { type: "cancelled" };
|
|
352
|
+
```
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createFlowEdge, type FlowEdge } from "./edge";
|
|
3
|
+
|
|
4
|
+
describe("FlowEdge", () => {
|
|
5
|
+
describe("createFlowEdge", () => {
|
|
6
|
+
it("should create a basic edge with source and target", () => {
|
|
7
|
+
const edge = createFlowEdge({
|
|
8
|
+
source: "node1",
|
|
9
|
+
target: "node2",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
expect(edge).toEqual({
|
|
13
|
+
source: "node1",
|
|
14
|
+
target: "node2",
|
|
15
|
+
sourcePort: undefined,
|
|
16
|
+
targetPort: undefined,
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should create edge with source and target ports", () => {
|
|
21
|
+
const edge = createFlowEdge({
|
|
22
|
+
source: "node1",
|
|
23
|
+
target: "node2",
|
|
24
|
+
sourcePort: "output1",
|
|
25
|
+
targetPort: "input1",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(edge).toEqual({
|
|
29
|
+
source: "node1",
|
|
30
|
+
target: "node2",
|
|
31
|
+
sourcePort: "output1",
|
|
32
|
+
targetPort: "input1",
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should create edge with only source port", () => {
|
|
37
|
+
const edge = createFlowEdge({
|
|
38
|
+
source: "node1",
|
|
39
|
+
target: "node2",
|
|
40
|
+
sourcePort: "output1",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(edge).toEqual({
|
|
44
|
+
source: "node1",
|
|
45
|
+
target: "node2",
|
|
46
|
+
sourcePort: "output1",
|
|
47
|
+
targetPort: undefined,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should create edge with only target port", () => {
|
|
52
|
+
const edge = createFlowEdge({
|
|
53
|
+
source: "node1",
|
|
54
|
+
target: "node2",
|
|
55
|
+
targetPort: "input1",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(edge).toEqual({
|
|
59
|
+
source: "node1",
|
|
60
|
+
target: "node2",
|
|
61
|
+
sourcePort: undefined,
|
|
62
|
+
targetPort: "input1",
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should handle empty string ports", () => {
|
|
67
|
+
const edge = createFlowEdge({
|
|
68
|
+
source: "node1",
|
|
69
|
+
target: "node2",
|
|
70
|
+
sourcePort: "",
|
|
71
|
+
targetPort: "",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(edge).toEqual({
|
|
75
|
+
source: "node1",
|
|
76
|
+
target: "node2",
|
|
77
|
+
sourcePort: "",
|
|
78
|
+
targetPort: "",
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should preserve all provided properties", () => {
|
|
83
|
+
const edgeData = {
|
|
84
|
+
source: "input-node",
|
|
85
|
+
target: "transform-node",
|
|
86
|
+
sourcePort: "file-output",
|
|
87
|
+
targetPort: "file-input",
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const edge = createFlowEdge(edgeData);
|
|
91
|
+
|
|
92
|
+
expect(edge.source).toBe(edgeData.source);
|
|
93
|
+
expect(edge.target).toBe(edgeData.target);
|
|
94
|
+
expect(edge.sourcePort).toBe(edgeData.sourcePort);
|
|
95
|
+
expect(edge.targetPort).toBe(edgeData.targetPort);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should create valid FlowEdge type", () => {
|
|
99
|
+
const edge: FlowEdge = createFlowEdge({
|
|
100
|
+
source: "node1",
|
|
101
|
+
target: "node2",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Type assertion test - if this compiles, the types are compatible
|
|
105
|
+
expect(edge).toHaveProperty("source");
|
|
106
|
+
expect(edge).toHaveProperty("target");
|
|
107
|
+
expect(edge).toHaveProperty("sourcePort");
|
|
108
|
+
expect(edge).toHaveProperty("targetPort");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should handle special characters in node names", () => {
|
|
112
|
+
const edge = createFlowEdge({
|
|
113
|
+
source: "node-with-dashes_and_underscores.123",
|
|
114
|
+
target: "another.node@domain.com",
|
|
115
|
+
sourcePort: "port/with/slashes",
|
|
116
|
+
targetPort: "port:with:colons",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(edge.source).toBe("node-with-dashes_and_underscores.123");
|
|
120
|
+
expect(edge.target).toBe("another.node@domain.com");
|
|
121
|
+
expect(edge.sourcePort).toBe("port/with/slashes");
|
|
122
|
+
expect(edge.targetPort).toBe("port:with:colons");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should create multiple edges with different configurations", () => {
|
|
126
|
+
const edges = [
|
|
127
|
+
createFlowEdge({ source: "a", target: "b" }),
|
|
128
|
+
createFlowEdge({ source: "b", target: "c", sourcePort: "out" }),
|
|
129
|
+
createFlowEdge({ source: "c", target: "d", targetPort: "in" }),
|
|
130
|
+
createFlowEdge({
|
|
131
|
+
source: "d",
|
|
132
|
+
target: "e",
|
|
133
|
+
sourcePort: "out",
|
|
134
|
+
targetPort: "in",
|
|
135
|
+
}),
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
expect(edges).toHaveLength(4);
|
|
139
|
+
expect(edges[0]?.sourcePort).toBeUndefined();
|
|
140
|
+
expect(edges[1]?.sourcePort).toBe("out");
|
|
141
|
+
expect(edges[2]?.targetPort).toBe("in");
|
|
142
|
+
expect(edges[3]?.sourcePort).toBe("out");
|
|
143
|
+
expect(edges[3]?.targetPort).toBe("in");
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
package/src/flow/edge.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { FlowEdge as EnhancedFlowEdge } from "./types/flow-types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a connection between two nodes in a flow, defining the data flow direction.
|
|
5
|
+
*
|
|
6
|
+
* Edges connect the output of a source node to the input of a target node,
|
|
7
|
+
* enabling data to flow through the processing pipeline in a directed acyclic graph (DAG).
|
|
8
|
+
*/
|
|
9
|
+
export type FlowEdge = EnhancedFlowEdge;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a flow edge connecting two nodes in a processing pipeline.
|
|
13
|
+
*
|
|
14
|
+
* Edges define how data flows between nodes. The data output from the source node
|
|
15
|
+
* becomes the input for the target node. For nodes with multiple inputs/outputs,
|
|
16
|
+
* ports can be specified to route data to specific connections.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Edge configuration
|
|
19
|
+
* @param config.source - ID of the source node (data originates here)
|
|
20
|
+
* @param config.target - ID of the target node (data flows to here)
|
|
21
|
+
* @param config.sourcePort - Optional port name on the source node for multi-output nodes
|
|
22
|
+
* @param config.targetPort - Optional port name on the target node for multi-input nodes
|
|
23
|
+
*
|
|
24
|
+
* @returns A FlowEdge object representing the connection
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // Simple edge connecting two nodes
|
|
29
|
+
* const edge = createFlowEdge({
|
|
30
|
+
* source: "input-1",
|
|
31
|
+
* target: "process-1"
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // Edge with ports for multi-input/output nodes
|
|
35
|
+
* const portEdge = createFlowEdge({
|
|
36
|
+
* source: "multiplex-1",
|
|
37
|
+
* target: "merge-1",
|
|
38
|
+
* sourcePort: "out-a",
|
|
39
|
+
* targetPort: "in-1"
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function createFlowEdge({
|
|
44
|
+
source,
|
|
45
|
+
target,
|
|
46
|
+
sourcePort,
|
|
47
|
+
targetPort,
|
|
48
|
+
}: {
|
|
49
|
+
source: string;
|
|
50
|
+
target: string;
|
|
51
|
+
sourcePort?: string;
|
|
52
|
+
targetPort?: string;
|
|
53
|
+
}): FlowEdge {
|
|
54
|
+
return {
|
|
55
|
+
source,
|
|
56
|
+
target,
|
|
57
|
+
sourcePort,
|
|
58
|
+
targetPort,
|
|
59
|
+
};
|
|
60
|
+
}
|