@uploadista/core 0.0.10 → 0.0.12
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/dist/flow/index.cjs +1 -1
- package/dist/flow/index.d.cts +2 -2
- package/dist/flow/index.d.mts +2 -2
- package/dist/flow/index.mjs +1 -1
- package/dist/{flow-DEohelFR.mjs → flow-CpDQ8dgf.mjs} +2 -2
- package/dist/flow-CpDQ8dgf.mjs.map +1 -0
- package/dist/{flow-C_doYlGf.cjs → flow-wZzF8vml.cjs} +1 -1
- package/dist/{index-Bg1HsPC1.d.cts → index-DHOYyzYt.d.cts} +760 -104
- package/dist/index-DHOYyzYt.d.cts.map +1 -0
- package/dist/{index-BQ8Ns-NS.d.mts → index-DdT18SQi.d.mts} +760 -104
- package/dist/index-DdT18SQi.d.mts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.mts +1 -1
- package/dist/upload/index.d.cts +1 -1
- package/dist/upload/index.d.mts +1 -1
- package/package.json +3 -3
- package/src/flow/index.ts +2 -0
- package/src/flow/plugins/credential-provider.ts +7 -1
- package/src/flow/plugins/image-ai-plugin.ts +5 -3
- package/src/flow/plugins/image-plugin.ts +46 -4
- package/src/flow/plugins/plugins.ts +19 -0
- package/src/flow/plugins/types/index.ts +1 -0
- package/src/flow/plugins/types/transform-image-node.ts +283 -0
- package/src/flow/plugins/zip-plugin.ts +4 -2
- package/src/flow/typed-flow.ts +199 -60
- package/src/flow/types/index.ts +3 -0
- package/src/flow/types/type-utils.ts +166 -0
- package/type-tests/type-utils.test-d.ts +235 -0
- package/dist/flow-DEohelFR.mjs.map +0 -1
- package/dist/index-BQ8Ns-NS.d.mts.map +0 -1
- package/dist/index-Bg1HsPC1.d.cts.map +0 -1
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type of transformation to apply to an image.
|
|
5
|
+
*/
|
|
6
|
+
export type TransformationType =
|
|
7
|
+
| "resize"
|
|
8
|
+
| "blur"
|
|
9
|
+
| "rotate"
|
|
10
|
+
| "flip"
|
|
11
|
+
| "grayscale"
|
|
12
|
+
| "sepia"
|
|
13
|
+
| "brightness"
|
|
14
|
+
| "contrast"
|
|
15
|
+
| "sharpen"
|
|
16
|
+
| "watermark"
|
|
17
|
+
| "logo"
|
|
18
|
+
| "text";
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Basic Transformations
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resize transformation parameters.
|
|
26
|
+
* Resizes the image to the specified dimensions with the given fit mode.
|
|
27
|
+
*/
|
|
28
|
+
export const resizeTransformSchema = z.object({
|
|
29
|
+
type: z.literal("resize"),
|
|
30
|
+
/** Target width in pixels (optional) */
|
|
31
|
+
width: z.number().positive().optional(),
|
|
32
|
+
/** Target height in pixels (optional) */
|
|
33
|
+
height: z.number().positive().optional(),
|
|
34
|
+
/** How the image should fit within the specified dimensions */
|
|
35
|
+
fit: z.enum(["contain", "cover", "fill"]),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export type ResizeTransform = z.infer<typeof resizeTransformSchema>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Blur transformation parameters.
|
|
42
|
+
* Applies Gaussian blur to the image.
|
|
43
|
+
*/
|
|
44
|
+
export const blurTransformSchema = z.object({
|
|
45
|
+
type: z.literal("blur"),
|
|
46
|
+
/** Blur strength (sigma). Range: 0.3 to 1000 */
|
|
47
|
+
sigma: z.number().min(0.3).max(1000),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export type BlurTransform = z.infer<typeof blurTransformSchema>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Rotate transformation parameters.
|
|
54
|
+
* Rotates the image by the specified angle.
|
|
55
|
+
*/
|
|
56
|
+
export const rotateTransformSchema = z.object({
|
|
57
|
+
type: z.literal("rotate"),
|
|
58
|
+
/** Rotation angle in degrees. Positive values rotate clockwise. */
|
|
59
|
+
angle: z.number(),
|
|
60
|
+
/** Background color for exposed areas (optional, defaults to transparent) */
|
|
61
|
+
background: z.string().optional(),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export type RotateTransform = z.infer<typeof rotateTransformSchema>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Flip transformation parameters.
|
|
68
|
+
* Flips the image horizontally or vertically.
|
|
69
|
+
*/
|
|
70
|
+
export const flipTransformSchema = z.object({
|
|
71
|
+
type: z.literal("flip"),
|
|
72
|
+
/** Direction to flip the image */
|
|
73
|
+
direction: z.enum(["horizontal", "vertical"]),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export type FlipTransform = z.infer<typeof flipTransformSchema>;
|
|
77
|
+
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// Filter Transformations
|
|
80
|
+
// ============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Grayscale transformation parameters.
|
|
84
|
+
* Converts the image to grayscale.
|
|
85
|
+
*/
|
|
86
|
+
export const grayscaleTransformSchema = z.object({
|
|
87
|
+
type: z.literal("grayscale"),
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export type GrayscaleTransform = z.infer<typeof grayscaleTransformSchema>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Sepia transformation parameters.
|
|
94
|
+
* Applies a sepia tone effect to the image.
|
|
95
|
+
*/
|
|
96
|
+
export const sepiaTransformSchema = z.object({
|
|
97
|
+
type: z.literal("sepia"),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
export type SepiaTransform = z.infer<typeof sepiaTransformSchema>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Brightness transformation parameters.
|
|
104
|
+
* Adjusts the brightness of the image.
|
|
105
|
+
*/
|
|
106
|
+
export const brightnessTransformSchema = z.object({
|
|
107
|
+
type: z.literal("brightness"),
|
|
108
|
+
/** Brightness adjustment value. Range: -100 to +100. 0 = no change. */
|
|
109
|
+
value: z.number().min(-100).max(100),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
export type BrightnessTransform = z.infer<typeof brightnessTransformSchema>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Contrast transformation parameters.
|
|
116
|
+
* Adjusts the contrast of the image.
|
|
117
|
+
*/
|
|
118
|
+
export const contrastTransformSchema = z.object({
|
|
119
|
+
type: z.literal("contrast"),
|
|
120
|
+
/** Contrast adjustment value. Range: -100 to +100. 0 = no change. */
|
|
121
|
+
value: z.number().min(-100).max(100),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export type ContrastTransform = z.infer<typeof contrastTransformSchema>;
|
|
125
|
+
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Effect Transformations
|
|
128
|
+
// ============================================================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Sharpen transformation parameters.
|
|
132
|
+
* Applies sharpening to the image.
|
|
133
|
+
*/
|
|
134
|
+
export const sharpenTransformSchema = z.object({
|
|
135
|
+
type: z.literal("sharpen"),
|
|
136
|
+
/** Sharpening strength (sigma). Optional, uses default if not specified. */
|
|
137
|
+
sigma: z.number().positive().optional(),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
export type SharpenTransform = z.infer<typeof sharpenTransformSchema>;
|
|
141
|
+
|
|
142
|
+
// ============================================================================
|
|
143
|
+
// Advanced Transformations
|
|
144
|
+
// ============================================================================
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Position for overlays (watermarks, logos, text).
|
|
148
|
+
*/
|
|
149
|
+
export type OverlayPosition =
|
|
150
|
+
| "top-left"
|
|
151
|
+
| "top-right"
|
|
152
|
+
| "bottom-left"
|
|
153
|
+
| "bottom-right"
|
|
154
|
+
| "center";
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Watermark transformation parameters.
|
|
158
|
+
* Overlays a watermark image on the main image.
|
|
159
|
+
*/
|
|
160
|
+
export const watermarkTransformSchema = z.object({
|
|
161
|
+
type: z.literal("watermark"),
|
|
162
|
+
/** URL to the watermark image file (e.g., https://example.com/watermark.png) */
|
|
163
|
+
imagePath: z.string().min(1).url(),
|
|
164
|
+
/** Position of the watermark on the image */
|
|
165
|
+
position: z.enum([
|
|
166
|
+
"top-left",
|
|
167
|
+
"top-right",
|
|
168
|
+
"bottom-left",
|
|
169
|
+
"bottom-right",
|
|
170
|
+
"center",
|
|
171
|
+
]),
|
|
172
|
+
/** Opacity of the watermark. Range: 0 (transparent) to 1 (opaque) */
|
|
173
|
+
opacity: z.number().min(0).max(1),
|
|
174
|
+
/** Horizontal offset in pixels from the position anchor (optional) */
|
|
175
|
+
offsetX: z.number().optional(),
|
|
176
|
+
/** Vertical offset in pixels from the position anchor (optional) */
|
|
177
|
+
offsetY: z.number().optional(),
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
export type WatermarkTransform = z.infer<typeof watermarkTransformSchema>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Logo transformation parameters.
|
|
184
|
+
* Overlays a logo image on the main image with scaling.
|
|
185
|
+
*/
|
|
186
|
+
export const logoTransformSchema = z.object({
|
|
187
|
+
type: z.literal("logo"),
|
|
188
|
+
/** URL to the logo image file (e.g., https://example.com/logo.png) */
|
|
189
|
+
imagePath: z.string().min(1).url(),
|
|
190
|
+
/** Position of the logo on the image */
|
|
191
|
+
position: z.enum([
|
|
192
|
+
"top-left",
|
|
193
|
+
"top-right",
|
|
194
|
+
"bottom-left",
|
|
195
|
+
"bottom-right",
|
|
196
|
+
"center",
|
|
197
|
+
]),
|
|
198
|
+
/** Scale factor for the logo. Range: 0.1 to 2.0 */
|
|
199
|
+
scale: z.number().min(0.1).max(2.0),
|
|
200
|
+
/** Horizontal offset in pixels from the position anchor (optional) */
|
|
201
|
+
offsetX: z.number().optional(),
|
|
202
|
+
/** Vertical offset in pixels from the position anchor (optional) */
|
|
203
|
+
offsetY: z.number().optional(),
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
export type LogoTransform = z.infer<typeof logoTransformSchema>;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Text transformation parameters.
|
|
210
|
+
* Overlays text on the image.
|
|
211
|
+
*/
|
|
212
|
+
export const textTransformSchema = z.object({
|
|
213
|
+
type: z.literal("text"),
|
|
214
|
+
/** Text content to overlay */
|
|
215
|
+
text: z.string().min(1),
|
|
216
|
+
/** Position of the text on the image */
|
|
217
|
+
position: z.enum([
|
|
218
|
+
"top-left",
|
|
219
|
+
"top-right",
|
|
220
|
+
"bottom-left",
|
|
221
|
+
"bottom-right",
|
|
222
|
+
"center",
|
|
223
|
+
]),
|
|
224
|
+
/** Font size in pixels */
|
|
225
|
+
fontSize: z.number().positive(),
|
|
226
|
+
/** Text color (hex code or named color) */
|
|
227
|
+
color: z.string().min(1),
|
|
228
|
+
/** Font family name (optional) */
|
|
229
|
+
fontFamily: z.string().optional(),
|
|
230
|
+
/** Horizontal offset in pixels from the position anchor (optional) */
|
|
231
|
+
offsetX: z.number().optional(),
|
|
232
|
+
/** Vertical offset in pixels from the position anchor (optional) */
|
|
233
|
+
offsetY: z.number().optional(),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
export type TextTransform = z.infer<typeof textTransformSchema>;
|
|
237
|
+
|
|
238
|
+
// ============================================================================
|
|
239
|
+
// Discriminated Union
|
|
240
|
+
// ============================================================================
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Schema for validating any transformation type.
|
|
244
|
+
* This is a discriminated union of all transformation schemas.
|
|
245
|
+
*/
|
|
246
|
+
export const transformationSchema = z.discriminatedUnion("type", [
|
|
247
|
+
resizeTransformSchema,
|
|
248
|
+
blurTransformSchema,
|
|
249
|
+
rotateTransformSchema,
|
|
250
|
+
flipTransformSchema,
|
|
251
|
+
grayscaleTransformSchema,
|
|
252
|
+
sepiaTransformSchema,
|
|
253
|
+
brightnessTransformSchema,
|
|
254
|
+
contrastTransformSchema,
|
|
255
|
+
sharpenTransformSchema,
|
|
256
|
+
watermarkTransformSchema,
|
|
257
|
+
logoTransformSchema,
|
|
258
|
+
textTransformSchema,
|
|
259
|
+
]);
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* A single image transformation operation.
|
|
263
|
+
* This is a discriminated union type that can represent any transformation.
|
|
264
|
+
*/
|
|
265
|
+
export type Transformation = z.infer<typeof transformationSchema>;
|
|
266
|
+
|
|
267
|
+
// ============================================================================
|
|
268
|
+
// Transform Image Node Parameters
|
|
269
|
+
// ============================================================================
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Parameters for the transform image node.
|
|
273
|
+
* Contains an ordered array of transformations to apply sequentially.
|
|
274
|
+
*/
|
|
275
|
+
export const transformImageParamsSchema = z.object({
|
|
276
|
+
/** Ordered array of transformations to apply. Applied sequentially. */
|
|
277
|
+
transformations: z.array(transformationSchema).min(1),
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Parameters for the transform image node.
|
|
282
|
+
*/
|
|
283
|
+
export type TransformImageParams = z.infer<typeof transformImageParamsSchema>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UploadistaError } from "@uploadista/core/errors";
|
|
2
|
-
import { Context, type Effect } from "effect";
|
|
2
|
+
import { Context, type Effect, type Layer } from "effect";
|
|
3
3
|
import type { UploadFile } from "@/types";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -40,7 +40,7 @@ export type ZipPluginShape = {
|
|
|
40
40
|
*/
|
|
41
41
|
zip: (
|
|
42
42
|
inputs: ZipInput[],
|
|
43
|
-
options: ZipParams
|
|
43
|
+
options: ZipParams,
|
|
44
44
|
) => Effect.Effect<Uint8Array, UploadistaError>;
|
|
45
45
|
// unzip: (input: ZipInput) => Effect.Effect<Uint8Array, UploadistaError>;
|
|
46
46
|
};
|
|
@@ -67,3 +67,5 @@ export class ZipPlugin extends Context.Tag("ZipPlugin")<
|
|
|
67
67
|
ZipPlugin,
|
|
68
68
|
ZipPluginShape
|
|
69
69
|
>() {}
|
|
70
|
+
|
|
71
|
+
export type ZipPluginLayer = Layer.Layer<ZipPlugin, never, never>;
|
package/src/flow/typed-flow.ts
CHANGED
|
@@ -11,58 +11,163 @@ import type { Flow, FlowExecutionResult } from "./flow";
|
|
|
11
11
|
import { createFlowWithSchema } from "./flow";
|
|
12
12
|
import { NodeType } from "./node";
|
|
13
13
|
import type {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
FlowEdge,
|
|
15
|
+
FlowNode,
|
|
16
|
+
TypeCompatibilityChecker,
|
|
17
17
|
} from "./types/flow-types";
|
|
18
|
+
import type { ExtractEffectRequirements, ResolveEffect } from "./types";
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Defines a node that can be used in a typed flow.
|
|
22
|
+
*
|
|
23
|
+
* A node definition can be either:
|
|
24
|
+
* - A plain FlowNode object
|
|
25
|
+
* - An Effect that resolves to a FlowNode (for nodes requiring dependencies)
|
|
26
|
+
*
|
|
27
|
+
* @template TNodeError - The error types that the node can produce
|
|
28
|
+
* @template TNodeRequirements - The services/dependencies the node requires
|
|
29
|
+
*/
|
|
19
30
|
export type NodeDefinition<TNodeError = never, TNodeRequirements = never> =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
| FlowNode<any, any, CoreUploadistaError>
|
|
32
|
+
| Effect.Effect<
|
|
33
|
+
FlowNode<any, any, CoreUploadistaError>,
|
|
34
|
+
TNodeError,
|
|
35
|
+
TNodeRequirements
|
|
36
|
+
>;
|
|
26
37
|
|
|
38
|
+
/**
|
|
39
|
+
* A record mapping node IDs to their definitions.
|
|
40
|
+
*
|
|
41
|
+
* This is the primary type used for defining the nodes in a typed flow,
|
|
42
|
+
* allowing TypeScript to infer input/output schemas and requirements.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const nodes = {
|
|
47
|
+
* input: fileInputNode,
|
|
48
|
+
* resize: Effect.succeed(imageResizeNode),
|
|
49
|
+
* output: s3OutputNode
|
|
50
|
+
* } satisfies NodeDefinitionsRecord;
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
27
53
|
export type NodeDefinitionsRecord = Record<string, NodeDefinition<any, any>>;
|
|
28
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Extracts the error type from a NodeDefinition.
|
|
57
|
+
*
|
|
58
|
+
* If the node is an Effect, extracts its error type.
|
|
59
|
+
* If the node is a plain FlowNode, returns never (no errors).
|
|
60
|
+
*/
|
|
29
61
|
type NodeDefinitionError<T> = T extends Effect.Effect<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
62
|
+
FlowNode<any, any, CoreUploadistaError>,
|
|
63
|
+
infer TError,
|
|
64
|
+
any
|
|
33
65
|
>
|
|
34
|
-
|
|
35
|
-
|
|
66
|
+
? TError
|
|
67
|
+
: never;
|
|
36
68
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
: never;
|
|
69
|
+
/**
|
|
70
|
+
* Extracts the requirements (dependencies) from a NodeDefinition.
|
|
71
|
+
*
|
|
72
|
+
* Uses the shared ExtractEffectRequirements utility for consistency.
|
|
73
|
+
*/
|
|
74
|
+
type NodeDefinitionRequirements<T> = ExtractEffectRequirements<T>;
|
|
44
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Extracts all possible errors from all nodes in a flow as a union.
|
|
78
|
+
*
|
|
79
|
+
* This iterates through all nodes in the record and combines their
|
|
80
|
+
* error types into a single union type.
|
|
81
|
+
*/
|
|
45
82
|
type NodesErrorUnion<TNodes extends NodeDefinitionsRecord> = {
|
|
46
|
-
|
|
83
|
+
[K in keyof TNodes]: NodeDefinitionError<TNodes[K]>;
|
|
47
84
|
}[keyof TNodes];
|
|
48
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Extracts all service requirements from all nodes in a flow as a union.
|
|
88
|
+
*
|
|
89
|
+
* This iterates through all nodes in the record and combines their
|
|
90
|
+
* requirement types into a single union type representing all services
|
|
91
|
+
* needed by the flow.
|
|
92
|
+
*
|
|
93
|
+
* @template TNodes - The record of node definitions
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* const nodes = {
|
|
98
|
+
* resize: imageResizeNode, // requires ImagePlugin
|
|
99
|
+
* zip: zipNode, // requires ZipPlugin
|
|
100
|
+
* };
|
|
101
|
+
* type Requirements = NodesRequirementsUnion<typeof nodes>;
|
|
102
|
+
* // Requirements = ImagePlugin | ZipPlugin
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
49
105
|
type NodesRequirementsUnion<TNodes extends NodeDefinitionsRecord> = {
|
|
50
|
-
|
|
106
|
+
[K in keyof TNodes]: NodeDefinitionRequirements<TNodes[K]>;
|
|
51
107
|
}[keyof TNodes];
|
|
52
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Extracts all service requirements from a flow's nodes.
|
|
111
|
+
*
|
|
112
|
+
* This includes all services required by any node in the flow,
|
|
113
|
+
* including UploadServer (which is provided by the runtime).
|
|
114
|
+
*
|
|
115
|
+
* @template TNodes - The record of node definitions
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const myFlow = createFlow({
|
|
120
|
+
* nodes: {
|
|
121
|
+
* input: fileInputNode,
|
|
122
|
+
* process: imageProcessNode, // requires ImagePlugin
|
|
123
|
+
* },
|
|
124
|
+
* edges: [...]
|
|
125
|
+
* });
|
|
126
|
+
* type AllRequirements = FlowRequirements<typeof myFlow.nodes>;
|
|
127
|
+
* // AllRequirements = ImagePlugin | UploadServer
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
53
130
|
export type FlowRequirements<TNodes extends NodeDefinitionsRecord> =
|
|
54
|
-
|
|
131
|
+
NodesRequirementsUnion<TNodes>;
|
|
55
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Extracts plugin service requirements from a flow, excluding UploadServer.
|
|
135
|
+
*
|
|
136
|
+
* This type is useful for determining which plugin layers need to be
|
|
137
|
+
* provided when creating a server, as UploadServer is automatically
|
|
138
|
+
* provided by the runtime.
|
|
139
|
+
*
|
|
140
|
+
* @template TNodes - The record of node definitions
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const myFlow = createFlow({
|
|
145
|
+
* nodes: {
|
|
146
|
+
* resize: imageResizeNode, // requires ImagePlugin
|
|
147
|
+
* upload: s3OutputNode, // requires UploadServer
|
|
148
|
+
* },
|
|
149
|
+
* edges: [...]
|
|
150
|
+
* });
|
|
151
|
+
* type PluginRequirements = FlowPluginRequirements<typeof myFlow.nodes>;
|
|
152
|
+
* // PluginRequirements = ImagePlugin (UploadServer excluded)
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
56
155
|
export type FlowPluginRequirements<TNodes extends NodeDefinitionsRecord> =
|
|
57
|
-
|
|
156
|
+
Exclude<FlowRequirements<TNodes>, UploadServer>;
|
|
58
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Infers the concrete FlowNode type from a NodeDefinition.
|
|
160
|
+
*
|
|
161
|
+
* If the definition is already a FlowNode, returns it as-is.
|
|
162
|
+
* If the definition is an Effect, extracts the FlowNode from the Effect's success type.
|
|
163
|
+
*
|
|
164
|
+
* Uses the shared ResolveEffect utility for consistency.
|
|
165
|
+
*/
|
|
59
166
|
type InferNode<T> = T extends FlowNode<any, any, CoreUploadistaError>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
: never
|
|
65
|
-
: never;
|
|
167
|
+
? T
|
|
168
|
+
: ResolveEffect<T> extends FlowNode<any, any, CoreUploadistaError>
|
|
169
|
+
? ResolveEffect<T>
|
|
170
|
+
: never;
|
|
66
171
|
|
|
67
172
|
type ResolvedNodesRecord<TNodes extends NodeDefinitionsRecord> = {
|
|
68
173
|
[K in keyof TNodes]: InferNode<TNodes[K]>;
|
|
@@ -138,37 +243,71 @@ declare const typedFlowInputsSymbol: unique symbol;
|
|
|
138
243
|
declare const typedFlowOutputsSymbol: unique symbol;
|
|
139
244
|
declare const typedFlowPluginsSymbol: unique symbol;
|
|
140
245
|
|
|
246
|
+
/**
|
|
247
|
+
* A type-safe Flow that infers input/output types and requirements from its nodes.
|
|
248
|
+
*
|
|
249
|
+
* TypedFlow extends the base Flow type with additional type information that
|
|
250
|
+
* allows TypeScript to verify inputs, outputs, and plugin requirements at compile time.
|
|
251
|
+
*
|
|
252
|
+
* The phantom type properties (using unique symbols) enable type-level metadata
|
|
253
|
+
* without affecting runtime behavior, allowing other type utilities to extract
|
|
254
|
+
* this information for validation purposes.
|
|
255
|
+
*
|
|
256
|
+
* @template TNodes - Record of node definitions used in the flow
|
|
257
|
+
* @template TInputSchema - Zod schema for flow inputs (inferred from input nodes)
|
|
258
|
+
* @template TOutputSchema - Zod schema for flow outputs (inferred from output nodes)
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* const myFlow = createFlow({
|
|
263
|
+
* nodes: {
|
|
264
|
+
* input: fileInputNode,
|
|
265
|
+
* resize: imageResizeNode,
|
|
266
|
+
* output: s3OutputNode
|
|
267
|
+
* },
|
|
268
|
+
* edges: [
|
|
269
|
+
* { source: 'input', target: 'resize' },
|
|
270
|
+
* { source: 'resize', target: 'output' }
|
|
271
|
+
* ]
|
|
272
|
+
* });
|
|
273
|
+
*
|
|
274
|
+
* // TypeScript infers:
|
|
275
|
+
* // - Input types from fileInputNode.inputSchema
|
|
276
|
+
* // - Output types from s3OutputNode.outputSchema
|
|
277
|
+
* // - Requirements: ImagePlugin (from resize node)
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
141
280
|
export type TypedFlow<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
281
|
+
TNodes extends NodeDefinitionsRecord,
|
|
282
|
+
TInputSchema extends z.ZodTypeAny,
|
|
283
|
+
TOutputSchema extends z.ZodTypeAny,
|
|
145
284
|
> = Flow<TInputSchema, TOutputSchema, FlowRequirements<TNodes>> & {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
285
|
+
run: (args: {
|
|
286
|
+
inputs?: Partial<FlowInputMap<TNodes>>;
|
|
287
|
+
storageId: string;
|
|
288
|
+
jobId: string;
|
|
289
|
+
}) => Effect.Effect<
|
|
290
|
+
FlowExecutionResult<FlowOutputMap<TNodes>>,
|
|
291
|
+
CoreUploadistaError,
|
|
292
|
+
FlowRequirements<TNodes>
|
|
293
|
+
>;
|
|
294
|
+
resume: (args: {
|
|
295
|
+
jobId: string;
|
|
296
|
+
storageId: string;
|
|
297
|
+
nodeResults: Record<string, unknown>;
|
|
298
|
+
executionState: {
|
|
299
|
+
executionOrder: string[];
|
|
300
|
+
currentIndex: number;
|
|
301
|
+
inputs: Partial<FlowInputMap<TNodes>>;
|
|
302
|
+
};
|
|
303
|
+
}) => Effect.Effect<
|
|
304
|
+
FlowExecutionResult<FlowOutputMap<TNodes>>,
|
|
305
|
+
CoreUploadistaError,
|
|
306
|
+
FlowRequirements<TNodes>
|
|
307
|
+
>;
|
|
308
|
+
readonly [typedFlowInputsSymbol]?: FlowInputMap<TNodes>;
|
|
309
|
+
readonly [typedFlowOutputsSymbol]?: FlowOutputMap<TNodes>;
|
|
310
|
+
readonly [typedFlowPluginsSymbol]?: FlowPluginRequirements<TNodes>;
|
|
172
311
|
};
|
|
173
312
|
|
|
174
313
|
const buildUnionSchema = (
|