@uploadista/flow-utility-nodes 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-check.log +5 -0
  3. package/LICENSE +21 -0
  4. package/README.md +289 -0
  5. package/dist/conditional-node.d.ts +25 -0
  6. package/dist/conditional-node.d.ts.map +1 -0
  7. package/dist/conditional-node.js +34 -0
  8. package/dist/index.d.ts +5 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +4 -0
  11. package/dist/merge-node.d.ts +12 -0
  12. package/dist/merge-node.d.ts.map +1 -0
  13. package/dist/merge-node.js +77 -0
  14. package/dist/multiplex-node.d.ts +42 -0
  15. package/dist/multiplex-node.d.ts.map +1 -0
  16. package/dist/multiplex-node.js +67 -0
  17. package/dist/nodes/conditional-node.d.ts +5 -0
  18. package/dist/nodes/conditional-node.d.ts.map +1 -0
  19. package/dist/nodes/conditional-node.js +19 -0
  20. package/dist/nodes/index.d.ts +5 -0
  21. package/dist/nodes/index.d.ts.map +1 -0
  22. package/dist/nodes/index.js +4 -0
  23. package/dist/nodes/merge-node.d.ts +7 -0
  24. package/dist/nodes/merge-node.d.ts.map +1 -0
  25. package/dist/nodes/merge-node.js +82 -0
  26. package/dist/nodes/multiplex-node.d.ts +7 -0
  27. package/dist/nodes/multiplex-node.d.ts.map +1 -0
  28. package/dist/nodes/multiplex-node.js +57 -0
  29. package/dist/nodes/zip-node.d.ts +8 -0
  30. package/dist/nodes/zip-node.d.ts.map +1 -0
  31. package/dist/nodes/zip-node.js +64 -0
  32. package/dist/types/conditional-node.d.ts +21 -0
  33. package/dist/types/conditional-node.d.ts.map +1 -0
  34. package/dist/types/conditional-node.js +13 -0
  35. package/dist/types/index.d.ts +5 -0
  36. package/dist/types/index.d.ts.map +1 -0
  37. package/dist/types/index.js +4 -0
  38. package/dist/types/merge-node.d.ts +11 -0
  39. package/dist/types/merge-node.d.ts.map +1 -0
  40. package/dist/types/merge-node.js +6 -0
  41. package/dist/types/multiplex-node.d.ts +10 -0
  42. package/dist/types/multiplex-node.d.ts.map +1 -0
  43. package/dist/types/multiplex-node.js +5 -0
  44. package/dist/types/zip-node.d.ts +8 -0
  45. package/dist/types/zip-node.d.ts.map +1 -0
  46. package/dist/types/zip-node.js +6 -0
  47. package/dist/zip-node.d.ts +9 -0
  48. package/dist/zip-node.d.ts.map +1 -0
  49. package/dist/zip-node.js +65 -0
  50. package/package.json +35 -0
  51. package/src/nodes/conditional-node.ts +28 -0
  52. package/src/nodes/index.ts +4 -0
  53. package/src/nodes/merge-node.ts +111 -0
  54. package/src/nodes/multiplex-node.ts +87 -0
  55. package/src/nodes/zip-node.ts +92 -0
  56. package/src/types/conditional-node.ts +16 -0
  57. package/src/types/index.ts +4 -0
  58. package/src/types/merge-node.ts +9 -0
  59. package/src/types/multiplex-node.ts +8 -0
  60. package/src/types/zip-node.ts +9 -0
  61. package/tsconfig.json +14 -0
  62. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @uploadista/flow-utility-nodes@0.0.2 build /Users/denislaboureyras/Documents/uploadista/dev/uploadista-workspace/uploadista-sdk/packages/flow/utility/nodes
4
+ > tsc -b
5
+
@@ -0,0 +1,5 @@
1
+
2
+ > @uploadista/flow-utility-nodes@ check /Users/denislaboureyras/Documents/uploadista/dev/uploadista/packages/uploadista/flow/utility-nodes
3
+ > biome check --write ./src
4
+
5
+ Checked 10 files in 48ms. No fixes applied.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 uploadista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,289 @@
1
+ # @uploadista/flow-utility-nodes
2
+
3
+ Flow utility nodes for Uploadista. Provides conditional routing, merging, multiplexing, and data transformation operations in upload pipelines.
4
+
5
+ ## Overview
6
+
7
+ Utility nodes enable complex flow logic without custom code:
8
+
9
+ - **Conditional Node**: Route uploads based on file properties
10
+ - **Merge Node**: Combine multiple inputs into one
11
+ - **Multiplex Node**: Split single input across multiple outputs
12
+ - **Zip Node**: Archive multiple files together
13
+
14
+ Perfect for building sophisticated upload workflows.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @uploadista/flow-utility-nodes
20
+ # or
21
+ pnpm add @uploadista/flow-utility-nodes
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { conditionalNode, mergeNode, multiplexNode, zipNode } from "@uploadista/flow-utility-nodes";
28
+ import { Effect } from "effect";
29
+
30
+ // Route based on file properties
31
+ const flow = {
32
+ nodes: [
33
+ { id: "input", type: "input" },
34
+ {
35
+ id: "router",
36
+ type: "conditional",
37
+ params: {
38
+ field: "mimeType",
39
+ operator: "contains",
40
+ value: "image",
41
+ },
42
+ },
43
+ { id: "output", type: "output" },
44
+ ],
45
+ edges: [
46
+ { from: "input", to: "router" },
47
+ { from: "router", to: "output" },
48
+ ],
49
+ };
50
+ ```
51
+
52
+ ## Features
53
+
54
+ - ✅ **Conditional Routing**: Route based on file properties
55
+ - ✅ **Data Merging**: Combine multiple streams
56
+ - ✅ **Multiplexing**: Split to multiple outputs
57
+ - ✅ **Type Safe**: Full TypeScript support
58
+ - ✅ **No Custom Code**: Visual flow building
59
+
60
+ ## Node Types
61
+
62
+ ### Conditional Node
63
+
64
+ Route inputs based on file properties.
65
+
66
+ **Parameters**:
67
+ ```typescript
68
+ {
69
+ field: "mimeType" | "size" | "width" | "height" | "extension",
70
+ operator: "equals" | "notEquals" | "greaterThan" | "lessThan" | "contains" | "startsWith",
71
+ value: string | number
72
+ }
73
+ ```
74
+
75
+ **Example**: Route images to resize, documents to compress
76
+ ```typescript
77
+ {
78
+ type: "conditional",
79
+ params: {
80
+ field: "mimeType",
81
+ operator: "contains",
82
+ value: "image",
83
+ },
84
+ }
85
+ ```
86
+
87
+ ### Merge Node
88
+
89
+ Combine multiple inputs into batch.
90
+
91
+ **Parameters**:
92
+ ```typescript
93
+ {
94
+ strategy: "concat" | "batch",
95
+ separator?: string,
96
+ inputCount: 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
97
+ }
98
+ ```
99
+
100
+ **Example**: Batch 5 uploads before processing
101
+ ```typescript
102
+ {
103
+ type: "merge",
104
+ params: {
105
+ strategy: "batch",
106
+ inputCount: 5,
107
+ },
108
+ }
109
+ ```
110
+
111
+ ### Multiplex Node
112
+
113
+ Split input to multiple independent paths.
114
+
115
+ **Parameters**:
116
+ ```typescript
117
+ {
118
+ outputCount: 2 | 3 | 4 | 5
119
+ }
120
+ ```
121
+
122
+ **Example**: Send to S3 and archive simultaneously
123
+ ```typescript
124
+ {
125
+ type: "multiplex",
126
+ params: {
127
+ outputCount: 2,
128
+ },
129
+ }
130
+ ```
131
+
132
+ ### Zip Node
133
+
134
+ Archive multiple files (see `@uploadista/flow-utility-zipjs`).
135
+
136
+ ## Use Cases
137
+
138
+ ### Case 1: Smart Routing
139
+
140
+ ```
141
+ Input → Conditional
142
+ ├─ Image → Resize
143
+ ├─ PDF → Compress
144
+ └─ Document → Archive
145
+ → Output
146
+ ```
147
+
148
+ ### Case 2: Batch Processing
149
+
150
+ ```
151
+ Input 1 ┐
152
+ Input 2 ├─ Merge (batch 3) → Process → Output
153
+ Input 3 ┘
154
+ ```
155
+
156
+ ### Case 3: Multi-Destination
157
+
158
+ ```
159
+ Input → Multiplex ├─ Store to S3
160
+ ├─ Archive to GCS
161
+ └─ Notify Webhook
162
+ ```
163
+
164
+ ## API Reference
165
+
166
+ All nodes exported from main entry point.
167
+
168
+ ```typescript
169
+ import {
170
+ conditionalNode,
171
+ mergeNode,
172
+ multiplexNode,
173
+ zipNode,
174
+ } from "@uploadista/flow-utility-nodes";
175
+ ```
176
+
177
+ ## Examples
178
+
179
+ ### Example 1: Image/Document Routing
180
+
181
+ ```typescript
182
+ const flow = {
183
+ nodes: [
184
+ { id: "input", type: "input" },
185
+ {
186
+ id: "router",
187
+ type: "conditional",
188
+ params: {
189
+ field: "mimeType",
190
+ operator: "contains",
191
+ value: "image",
192
+ },
193
+ },
194
+ { id: "resize", type: "resize", params: { width: 800 } },
195
+ { id: "s3", type: "s3", params: { bucket: "images" } },
196
+ { id: "pdf-store", type: "s3", params: { bucket: "documents" } },
197
+ { id: "output", type: "output" },
198
+ ],
199
+ edges: [
200
+ { from: "input", to: "router" },
201
+ { from: "router", true: "resize", false: "pdf-store" },
202
+ { from: "resize", to: "s3" },
203
+ { from: "s3", to: "output" },
204
+ { from: "pdf-store", to: "output" },
205
+ ],
206
+ };
207
+ ```
208
+
209
+ ### Example 2: Batch Processing
210
+
211
+ ```typescript
212
+ const batchFlow = {
213
+ nodes: [
214
+ { id: "input1", type: "input" },
215
+ { id: "input2", type: "input" },
216
+ { id: "input3", type: "input" },
217
+ {
218
+ id: "merge",
219
+ type: "merge",
220
+ params: { strategy: "batch", inputCount: 3 },
221
+ },
222
+ { id: "process", type: "custom", params: {} },
223
+ { id: "output", type: "output" },
224
+ ],
225
+ edges: [
226
+ { from: "input1", to: "merge" },
227
+ { from: "input2", to: "merge" },
228
+ { from: "input3", to: "merge" },
229
+ { from: "merge", to: "process" },
230
+ { from: "process", to: "output" },
231
+ ],
232
+ };
233
+ ```
234
+
235
+ ### Example 3: Multi-Path Distribution
236
+
237
+ ```typescript
238
+ const multiPath = {
239
+ nodes: [
240
+ { id: "input", type: "input" },
241
+ { id: "split", type: "multiplex", params: { outputCount: 3 } },
242
+ { id: "s3", type: "s3", params: { bucket: "primary" } },
243
+ { id: "gcs", type: "gcs", params: { bucket: "backup" } },
244
+ { id: "archive", type: "zip", params: {} },
245
+ { id: "output", type: "output" },
246
+ ],
247
+ edges: [
248
+ { from: "input", to: "split" },
249
+ { from: "split", index: 0, to: "s3" },
250
+ { from: "split", index: 1, to: "gcs" },
251
+ { from: "split", index: 2, to: "archive" },
252
+ { from: "s3", to: "output" },
253
+ { from: "gcs", to: "output" },
254
+ { from: "archive", to: "output" },
255
+ ],
256
+ };
257
+ ```
258
+
259
+ ## Configuration
260
+
261
+ Nodes configured via `params` object in flow definition:
262
+
263
+ ```typescript
264
+ {
265
+ id: "node-id",
266
+ type: "conditional",
267
+ params: {
268
+ field: "mimeType",
269
+ operator: "contains",
270
+ value: "image",
271
+ },
272
+ }
273
+ ```
274
+
275
+ ## Related Packages
276
+
277
+ - [@uploadista/core](../../core) - Core flow types
278
+ - [@uploadista/flow-utility-zipjs](../zipjs) - Archive node
279
+ - [@uploadista/flow-images-nodes](../images/nodes) - Image utilities
280
+ - [@uploadista/server](../../servers/server) - Upload server
281
+
282
+ ## License
283
+
284
+ See [LICENSE](../../../LICENSE) in the main repository.
285
+
286
+ ## See Also
287
+
288
+ - [FLOW_NODES.md](../FLOW_NODES.md) - Complete node gallery
289
+ - [Server Setup Guide](../../../SERVER_SETUP.md) - Flow integration
@@ -0,0 +1,25 @@
1
+ import { type FlowFile } from "@uploadista/flow-core";
2
+ import { z } from "zod";
3
+ export declare const conditionalParamsSchema: z.ZodObject<{
4
+ field: z.ZodEnum<{
5
+ mimeType: "mimeType";
6
+ size: "size";
7
+ width: "width";
8
+ height: "height";
9
+ extension: "extension";
10
+ }>;
11
+ operator: z.ZodEnum<{
12
+ equals: "equals";
13
+ notEquals: "notEquals";
14
+ greaterThan: "greaterThan";
15
+ lessThan: "lessThan";
16
+ contains: "contains";
17
+ startsWith: "startsWith";
18
+ }>;
19
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
20
+ trueBranch: z.ZodString;
21
+ falseBranch: z.ZodOptional<z.ZodString>;
22
+ }, z.core.$strip>;
23
+ export type ConditionalParams = z.infer<typeof conditionalParamsSchema>;
24
+ export declare function createConditionalNode(id: string, { field, operator, value, trueBranch, falseBranch }: ConditionalParams): import("@uploadista/flow-core").FlowNode<FlowFile, FlowFile>;
25
+ //# sourceMappingURL=conditional-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditional-node.d.ts","sourceRoot":"","sources":["../src/conditional-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAGd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;iBAalC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,MAAM,EACV,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,iBAAiB,gEAmBvE"}
@@ -0,0 +1,34 @@
1
+ import { createFlowNode, flowFileSchema, NodeType, } from "@uploadista/flow-core";
2
+ import { z } from "zod";
3
+ export const conditionalParamsSchema = z.object({
4
+ field: z.enum(["mimeType", "size", "width", "height", "extension"]),
5
+ operator: z.enum([
6
+ "equals",
7
+ "notEquals",
8
+ "greaterThan",
9
+ "lessThan",
10
+ "contains",
11
+ "startsWith",
12
+ ]),
13
+ value: z.union([z.string(), z.number()]),
14
+ trueBranch: z.string(),
15
+ falseBranch: z.string().optional(),
16
+ });
17
+ // Define schemas for input and output
18
+ export function createConditionalNode(id, { field, operator, value, trueBranch, falseBranch }) {
19
+ return createFlowNode({
20
+ id,
21
+ name: "Conditional Router",
22
+ description: `Routes flow based on ${field} ${operator} ${value}`,
23
+ type: NodeType.conditional,
24
+ inputSchema: flowFileSchema,
25
+ outputSchema: flowFileSchema,
26
+ condition: { field, operator, value },
27
+ branches: [trueBranch, falseBranch].filter((branch) => branch !== undefined),
28
+ run: async ({ data }) => {
29
+ // The actual routing logic is handled by the flow engine
30
+ // This node just passes through the data
31
+ return data;
32
+ },
33
+ });
34
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./conditional-node";
2
+ export * from "./merge-node";
3
+ export * from "./multiplex-node";
4
+ export * from "./zip-node";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./nodes/conditional-node";
2
+ export * from "./nodes/merge-node";
3
+ export * from "./nodes/multiplex-node";
4
+ export * from "./nodes/zip-node";
@@ -0,0 +1,12 @@
1
+ import { type FlowFile, type FlowFileBatch } from "@uploadista/flow-core";
2
+ import { z } from "zod";
3
+ export declare const mergeParamsSchema: z.ZodObject<{
4
+ strategy: z.ZodDefault<z.ZodEnum<{
5
+ concat: "concat";
6
+ batch: "batch";
7
+ }>>;
8
+ separator: z.ZodOptional<z.ZodDefault<z.ZodString>>;
9
+ }, z.core.$strip>;
10
+ export type MergeParams = z.infer<typeof mergeParamsSchema>;
11
+ export declare function createMergeNode(id: string, { strategy, separator: _separator }: MergeParams): import("@uploadista/flow-core").FlowNode<Record<string, FlowFile | FlowFileBatch>, FlowFile | FlowFileBatch>;
12
+ //# sourceMappingURL=merge-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-node.d.ts","sourceRoot":"","sources":["../src/merge-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,aAAa,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,iBAAiB;;;;;;iBAG5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAO5D,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,WAAW,gHAwEjD"}
@@ -0,0 +1,77 @@
1
+ import { createFlowNode, flowDataSchema, isFlowFile, NodeType, } from "@uploadista/flow-core";
2
+ import { z } from "zod";
3
+ export const mergeParamsSchema = z.object({
4
+ strategy: z.enum(["concat", "batch"]).default("batch"),
5
+ separator: z.string().default("\n").optional(),
6
+ });
7
+ // Define schemas for input and output
8
+ const inputSchema = z.record(z.string(), flowDataSchema);
9
+ const outputSchema = flowDataSchema;
10
+ export function createMergeNode(id, { strategy, separator: _separator }) {
11
+ return createFlowNode({
12
+ id,
13
+ name: "Merge Files",
14
+ description: `Merges multiple files using ${strategy} strategy`,
15
+ type: NodeType.merge,
16
+ inputSchema,
17
+ outputSchema,
18
+ multiInput: true,
19
+ run: async ({ data: inputs }) => {
20
+ if (!inputs) {
21
+ throw new Error("No inputs provided to merge node");
22
+ }
23
+ const inputFiles = [];
24
+ // Collect all input files
25
+ for (const [_sourceId, input] of Object.entries(inputs)) {
26
+ if (isFlowFile(input)) {
27
+ // Handle single FlowFile
28
+ inputFiles.push(input);
29
+ }
30
+ else {
31
+ // Handle FlowFileBatch
32
+ inputFiles.push(...input.files);
33
+ }
34
+ }
35
+ if (inputFiles.length === 0) {
36
+ throw new Error("No files to merge");
37
+ }
38
+ if (strategy === "batch") {
39
+ // Return as a batch
40
+ return {
41
+ files: inputFiles,
42
+ metadata: {
43
+ batchId: crypto.randomUUID(),
44
+ totalSize: inputFiles.reduce((sum, file) => sum + file.metadata.size, 0),
45
+ fileCount: inputFiles.length,
46
+ },
47
+ };
48
+ }
49
+ else if (strategy === "concat") {
50
+ // Concatenate all files into one
51
+ const inputBytesArray = [];
52
+ let totalSize = 0;
53
+ for (const file of inputFiles) {
54
+ inputBytesArray.push(file.inputBytes);
55
+ totalSize += file.inputBytes.length;
56
+ }
57
+ const mergedInputBytes = new Uint8Array(totalSize);
58
+ let offset = 0;
59
+ for (const inputBytes of inputBytesArray) {
60
+ mergedInputBytes.set(inputBytes, offset);
61
+ offset += inputBytes.length;
62
+ }
63
+ return {
64
+ path: `merged_${crypto.randomUUID()}`,
65
+ inputBytes: mergedInputBytes,
66
+ metadata: {
67
+ mimeType: "application/octet-stream",
68
+ size: totalSize,
69
+ originalName: `merged_${inputFiles.length}_files`,
70
+ extension: "bin",
71
+ },
72
+ };
73
+ }
74
+ throw new Error(`Unknown merge strategy: ${strategy}`);
75
+ },
76
+ });
77
+ }
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ export declare const multiplexParamsSchema: z.ZodObject<{
3
+ outputCount: z.ZodNumber;
4
+ strategy: z.ZodDefault<z.ZodEnum<{
5
+ split: "split";
6
+ copy: "copy";
7
+ }>>;
8
+ }, z.core.$strip>;
9
+ export type MultiplexParams = z.infer<typeof multiplexParamsSchema>;
10
+ export declare function createMultiplexNode(id: string, { outputCount, strategy }: MultiplexParams): import("@uploadista/flow-core").FlowNode<{
11
+ path: string;
12
+ inputBytes: Uint8Array<ArrayBufferLike>;
13
+ metadata: {
14
+ mimeType: string;
15
+ size: number;
16
+ width?: number | undefined;
17
+ height?: number | undefined;
18
+ format?: string | undefined;
19
+ originalName?: string | undefined;
20
+ extension?: string | undefined;
21
+ };
22
+ }, {
23
+ files: {
24
+ path: string;
25
+ inputBytes: Uint8Array<ArrayBufferLike>;
26
+ metadata: {
27
+ mimeType: string;
28
+ size: number;
29
+ width?: number | undefined;
30
+ height?: number | undefined;
31
+ format?: string | undefined;
32
+ originalName?: string | undefined;
33
+ extension?: string | undefined;
34
+ };
35
+ }[];
36
+ metadata?: {
37
+ batchId: string;
38
+ totalSize: number;
39
+ fileCount: number;
40
+ } | undefined;
41
+ }>;
42
+ //# sourceMappingURL=multiplex-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiplex-node.d.ts","sourceRoot":"","sources":["../src/multiplex-node.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qBAAqB;;;;;;iBAGhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,MAAM,EACV,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoE3C"}
@@ -0,0 +1,67 @@
1
+ import { createFlowNode, flowFileBatchSchema, flowFileSchema, NodeType, } from "@uploadista/flow-core";
2
+ import { z } from "zod";
3
+ export const multiplexParamsSchema = z.object({
4
+ outputCount: z.number().min(1).max(10),
5
+ strategy: z.enum(["copy", "split"]).default("copy"),
6
+ });
7
+ // Define schemas for input and output
8
+ export function createMultiplexNode(id, { outputCount, strategy }) {
9
+ return createFlowNode({
10
+ id,
11
+ name: "Multiplex",
12
+ description: `Splits input into ${outputCount} parallel outputs using ${strategy} strategy`,
13
+ type: NodeType.multiplex,
14
+ inputSchema: flowFileSchema,
15
+ outputSchema: flowFileBatchSchema,
16
+ multiOutput: true,
17
+ run: async ({ data }) => {
18
+ if (strategy === "copy") {
19
+ // Copy the same file to multiple outputs
20
+ const files = Array.from({ length: outputCount }, (_, index) => ({
21
+ path: `${data.path}_copy_${index}`,
22
+ inputBytes: data.inputBytes,
23
+ metadata: {
24
+ ...data.metadata,
25
+ originalName: `${data.metadata.originalName || data.path}_copy_${index}`,
26
+ },
27
+ }));
28
+ return {
29
+ files,
30
+ metadata: {
31
+ batchId: crypto.randomUUID(),
32
+ totalSize: files.length * data.metadata.size,
33
+ fileCount: files.length,
34
+ },
35
+ };
36
+ }
37
+ else if (strategy === "split") {
38
+ // Split the file into chunks
39
+ const chunkSize = Math.ceil(data.inputBytes.length / outputCount);
40
+ const files = [];
41
+ for (let i = 0; i < outputCount; i++) {
42
+ const start = i * chunkSize;
43
+ const end = Math.min(start + chunkSize, data.inputBytes.length);
44
+ const chunk = data.inputBytes.subarray(start, end);
45
+ files.push({
46
+ path: `${data.path}_part_${i}`,
47
+ inputBytes: chunk,
48
+ metadata: {
49
+ ...data.metadata,
50
+ size: chunk.length,
51
+ originalName: `${data.metadata.originalName || data.path}_part_${i}`,
52
+ },
53
+ });
54
+ }
55
+ return {
56
+ files,
57
+ metadata: {
58
+ batchId: crypto.randomUUID(),
59
+ totalSize: data.inputBytes.length,
60
+ fileCount: files.length,
61
+ },
62
+ };
63
+ }
64
+ throw new Error(`Unknown multiplex strategy: ${strategy}`);
65
+ },
66
+ });
67
+ }
@@ -0,0 +1,5 @@
1
+ import { type UploadFile } from "@uploadista/core/types";
2
+ import { Effect } from "effect";
3
+ import type { ConditionalParams } from "@/types/conditional-node";
4
+ export declare function createConditionalNode(id: string, { field, operator, value }: ConditionalParams): Effect.Effect<import("@uploadista/core").FlowNode<UploadFile, UploadFile, import("@uploadista/core").UploadistaError>, never, never>;
5
+ //# sourceMappingURL=conditional-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditional-node.d.ts","sourceRoot":"","sources":["../../src/nodes/conditional-node.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,MAAM,EACV,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,wIAgB9C"}
@@ -0,0 +1,19 @@
1
+ import { completeNodeExecution, createFlowNode, NodeType, } from "@uploadista/core/flow";
2
+ import { uploadFileSchema } from "@uploadista/core/types";
3
+ import { Effect } from "effect";
4
+ export function createConditionalNode(id, { field, operator, value }) {
5
+ return createFlowNode({
6
+ id,
7
+ name: "Conditional Router",
8
+ description: `Routes flow based on ${field} ${operator} ${value}`,
9
+ type: NodeType.conditional,
10
+ inputSchema: uploadFileSchema,
11
+ outputSchema: uploadFileSchema,
12
+ condition: { field, operator, value },
13
+ run: ({ data }) => {
14
+ // The actual routing logic is handled by the flow engine
15
+ // This node just passes through the data
16
+ return Effect.succeed(completeNodeExecution(data));
17
+ },
18
+ });
19
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./conditional-node";
2
+ export * from "./merge-node";
3
+ export * from "./multiplex-node";
4
+ export * from "./zip-node";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nodes/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./conditional-node";
2
+ export * from "./merge-node";
3
+ export * from "./multiplex-node";
4
+ export * from "./zip-node";
@@ -0,0 +1,7 @@
1
+ import { UploadistaError } from "@uploadista/core/errors";
2
+ import { type UploadFile } from "@uploadista/core/types";
3
+ import { UploadServer } from "@uploadista/core/upload";
4
+ import { Effect } from "effect";
5
+ import type { MergeParams } from "@/types/merge-node";
6
+ export declare function createMergeNode(id: string, { strategy, separator: _separator }: MergeParams): Effect.Effect<import("@uploadista/core").FlowNode<Record<string, UploadFile>, UploadFile, UploadistaError>, never, UploadServer>;
7
+ //# sourceMappingURL=merge-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-node.d.ts","sourceRoot":"","sources":["../../src/nodes/merge-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAM1D,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,WAAW,oIA6FjD"}