@uploadista/flow-images-nodes 0.0.18 → 0.0.20-beta.1

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/index.d.mts CHANGED
@@ -1,10 +1,8 @@
1
- import * as _uploadista_core_errors0 from "@uploadista/core/errors";
2
1
  import { UploadistaError } from "@uploadista/core/errors";
3
- import * as _uploadista_core_flow0 from "@uploadista/core/flow";
4
- import { FileNamingConfig, ImageAiPlugin, ImagePlugin, NodeType, OptimizeParams, ResizeParams, TransformImageParams } from "@uploadista/core/flow";
5
- import * as _uploadista_core_types0 from "@uploadista/core/types";
2
+ import { FileNamingConfig, ImageAiPlugin, ImagePlugin, NodeType, OptimizeParams, ResizeParams, StreamingConfig, TransformImageParams, TransformMode } from "@uploadista/core/flow";
6
3
  import { Effect } from "effect";
7
- import * as _uploadista_core_upload0 from "@uploadista/core/upload";
4
+ import * as _uploadista_core0 from "@uploadista/core";
5
+ import { UploadistaError as UploadistaError$1 } from "@uploadista/core";
8
6
  import { UploadServer } from "@uploadista/core/upload";
9
7
  import * as zod_v4_core0 from "zod/v4/core";
10
8
  import * as zod0 from "zod";
@@ -16,7 +14,7 @@ declare function createDescribeImageNode(id: string, {
16
14
  }?: {
17
15
  credentialId?: string;
18
16
  keepOutput?: boolean;
19
- }): Effect.Effect<_uploadista_core_flow0.FlowNodeData & {
17
+ }): Effect.Effect<_uploadista_core0.FlowNodeData & {
20
18
  inputSchema: zod0.ZodType<{
21
19
  id: string;
22
20
  offset: number;
@@ -130,7 +128,7 @@ declare function createDescribeImageNode(id: string, {
130
128
  flowId: string;
131
129
  inputs?: Record<string, unknown>;
132
130
  clientId: string | null;
133
- }) => Effect.Effect<_uploadista_core_flow0.NodeExecutionResult<{
131
+ }) => Effect.Effect<_uploadista_core0.NodeExecutionResult<{
134
132
  description: string;
135
133
  confidence?: number | undefined;
136
134
  metadata?: Record<string, unknown> | undefined;
@@ -148,7 +146,7 @@ declare function createDescribeImageNode(id: string, {
148
146
  retryDelay?: number;
149
147
  exponentialBackoff?: boolean;
150
148
  };
151
- circuitBreaker?: _uploadista_core_flow0.FlowCircuitBreakerConfig;
149
+ circuitBreaker?: _uploadista_core0.FlowCircuitBreakerConfig;
152
150
  } & {
153
151
  type: NodeType.process;
154
152
  }, UploadistaError, ImageAiPlugin>;
@@ -157,18 +155,37 @@ declare function createDescribeImageNode(id: string, {
157
155
  /**
158
156
  * Creates an optimize node that optimizes images for web delivery.
159
157
  *
158
+ * Supports both buffered and streaming modes for memory-efficient processing
159
+ * of large images. In streaming mode, the image is read and processed
160
+ * incrementally, reducing peak memory usage.
161
+ *
160
162
  * @param id - Unique node identifier
161
163
  * @param params - Optimize parameters (quality, format)
162
164
  * @param options - Optional configuration
163
165
  * @param options.keepOutput - Whether to keep output in flow results
164
166
  * @param options.naming - File naming configuration (auto suffix: `${format}`)
167
+ * @param options.mode - Transform mode: "buffered" (default), "streaming", or "auto"
168
+ * @param options.streamingConfig - Streaming configuration (file size threshold, chunk size)
165
169
  *
166
170
  * @example
167
171
  * ```typescript
168
- * // With auto-naming: "photo.jpg" -> "photo-webp.webp"
172
+ * // Buffered mode (default) - "photo.jpg" -> "photo-webp.webp"
169
173
  * const optimize = yield* createOptimizeNode("opt-1", { quality: 80, format: "webp" }, {
170
174
  * naming: { mode: "auto" }
171
175
  * });
176
+ *
177
+ * // Streaming mode for large files
178
+ * const optimizeStreaming = yield* createOptimizeNode("opt-2", { quality: 80, format: "webp" }, {
179
+ * mode: "streaming",
180
+ * naming: { mode: "auto" }
181
+ * });
182
+ *
183
+ * // Auto mode - uses streaming for files > 1MB
184
+ * const optimizeAuto = yield* createOptimizeNode("opt-3", { quality: 80, format: "webp" }, {
185
+ * mode: "auto",
186
+ * streamingConfig: { fileSizeThreshold: 1_048_576 },
187
+ * naming: { mode: "auto" }
188
+ * });
172
189
  * ```
173
190
  */
174
191
  declare function createOptimizeNode(id: string, {
@@ -177,17 +194,19 @@ declare function createOptimizeNode(id: string, {
177
194
  }: OptimizeParams, options?: {
178
195
  keepOutput?: boolean;
179
196
  naming?: FileNamingConfig;
180
- }): Effect.Effect<_uploadista_core_flow0.FlowNodeData & {
181
- inputSchema: zod0.ZodType<_uploadista_core_types0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core_types0.UploadFile, unknown>>;
182
- outputSchema: zod0.ZodType<_uploadista_core_types0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core_types0.UploadFile, unknown>>;
197
+ mode?: TransformMode;
198
+ streamingConfig?: StreamingConfig;
199
+ }): Effect.Effect<_uploadista_core0.FlowNodeData & {
200
+ inputSchema: zod0.ZodType<_uploadista_core0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core0.UploadFile, unknown>>;
201
+ outputSchema: zod0.ZodType<_uploadista_core0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core0.UploadFile, unknown>>;
183
202
  run: (args: {
184
- data: _uploadista_core_types0.UploadFile;
203
+ data: _uploadista_core0.UploadFile;
185
204
  jobId: string;
186
205
  storageId: string;
187
206
  flowId: string;
188
207
  inputs?: Record<string, unknown>;
189
208
  clientId: string | null;
190
- }) => Effect.Effect<_uploadista_core_flow0.NodeExecutionResult<_uploadista_core_types0.UploadFile>, _uploadista_core_errors0.UploadistaError, never>;
209
+ }) => Effect.Effect<_uploadista_core0.NodeExecutionResult<_uploadista_core0.UploadFile>, UploadistaError$1, never>;
191
210
  condition?: {
192
211
  field: string;
193
212
  operator: string;
@@ -201,10 +220,10 @@ declare function createOptimizeNode(id: string, {
201
220
  retryDelay?: number;
202
221
  exponentialBackoff?: boolean;
203
222
  };
204
- circuitBreaker?: _uploadista_core_flow0.FlowCircuitBreakerConfig;
223
+ circuitBreaker?: _uploadista_core0.FlowCircuitBreakerConfig;
205
224
  } & {
206
- type: _uploadista_core_flow0.NodeType;
207
- }, _uploadista_core_errors0.UploadistaError, ImagePlugin | _uploadista_core_upload0.UploadServer>;
225
+ type: _uploadista_core0.NodeType;
226
+ }, UploadistaError$1, ImagePlugin | _uploadista_core0.UploadServer>;
208
227
  //#endregion
209
228
  //#region src/remove-background-node.d.ts
210
229
  /**
@@ -232,7 +251,7 @@ declare function createRemoveBackgroundNode(id: string, {
232
251
  credentialId?: string;
233
252
  keepOutput?: boolean;
234
253
  naming?: FileNamingConfig;
235
- }): Effect.Effect<_uploadista_core_flow0.FlowNodeData & {
254
+ }): Effect.Effect<_uploadista_core0.FlowNodeData & {
236
255
  inputSchema: zod0.ZodType<{
237
256
  id: string;
238
257
  offset: number;
@@ -298,7 +317,7 @@ declare function createRemoveBackgroundNode(id: string, {
298
317
  traceFlags: number;
299
318
  } | undefined;
300
319
  }, unknown>>;
301
- outputSchema: zod0.ZodType<_uploadista_core_types0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core_types0.UploadFile, unknown>>;
320
+ outputSchema: zod0.ZodType<_uploadista_core0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core0.UploadFile, unknown>>;
302
321
  run: (args: {
303
322
  data: {
304
323
  id: string;
@@ -338,7 +357,7 @@ declare function createRemoveBackgroundNode(id: string, {
338
357
  flowId: string;
339
358
  inputs?: Record<string, unknown>;
340
359
  clientId: string | null;
341
- }) => Effect.Effect<_uploadista_core_flow0.NodeExecutionResult<_uploadista_core_types0.UploadFile>, UploadistaError, never>;
360
+ }) => Effect.Effect<_uploadista_core0.NodeExecutionResult<_uploadista_core0.UploadFile>, UploadistaError, never>;
342
361
  condition?: {
343
362
  field: string;
344
363
  operator: string;
@@ -352,7 +371,7 @@ declare function createRemoveBackgroundNode(id: string, {
352
371
  retryDelay?: number;
353
372
  exponentialBackoff?: boolean;
354
373
  };
355
- circuitBreaker?: _uploadista_core_flow0.FlowCircuitBreakerConfig;
374
+ circuitBreaker?: _uploadista_core0.FlowCircuitBreakerConfig;
356
375
  } & {
357
376
  type: NodeType.process;
358
377
  }, UploadistaError, ImageAiPlugin | UploadServer>;
@@ -361,18 +380,36 @@ declare function createRemoveBackgroundNode(id: string, {
361
380
  /**
362
381
  * Creates a resize node that resizes images to specified dimensions.
363
382
  *
383
+ * Supports both buffered and streaming modes for memory-efficient processing
384
+ * of large images. In streaming mode, the image is read and processed
385
+ * incrementally, reducing peak memory usage.
386
+ *
364
387
  * @param id - Unique node identifier
365
388
  * @param params - Resize parameters (width, height, fit)
366
389
  * @param options - Optional configuration
367
390
  * @param options.keepOutput - Whether to keep output in flow results
368
391
  * @param options.naming - File naming configuration (auto suffix: `${width}x${height}`)
392
+ * @param options.mode - Transform mode: "buffered", "streaming", or "auto" (default)
393
+ * @param options.streamingConfig - Streaming configuration (file size threshold, chunk size)
369
394
  *
370
395
  * @example
371
396
  * ```typescript
372
- * // With auto-naming: "photo.jpg" -> "photo-800x600.jpg"
397
+ * // Auto mode (default) - uses streaming for files > 1MB, otherwise buffered
373
398
  * const resize = yield* createResizeNode("resize-1", { width: 800, height: 600 }, {
374
399
  * naming: { mode: "auto" }
375
400
  * });
401
+ *
402
+ * // Force buffered mode for small files
403
+ * const resizeBuffered = yield* createResizeNode("resize-2", { width: 800, height: 600 }, {
404
+ * mode: "buffered",
405
+ * naming: { mode: "auto" }
406
+ * });
407
+ *
408
+ * // Force streaming mode for memory efficiency
409
+ * const resizeStreaming = yield* createResizeNode("resize-3", { width: 800, height: 600 }, {
410
+ * mode: "streaming",
411
+ * naming: { mode: "auto" }
412
+ * });
376
413
  * ```
377
414
  */
378
415
  declare function createResizeNode(id: string, {
@@ -382,17 +419,19 @@ declare function createResizeNode(id: string, {
382
419
  }: ResizeParams, options?: {
383
420
  keepOutput?: boolean;
384
421
  naming?: FileNamingConfig;
385
- }): Effect.Effect<_uploadista_core_flow0.FlowNodeData & {
386
- inputSchema: zod0.ZodType<_uploadista_core_types0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core_types0.UploadFile, unknown>>;
387
- outputSchema: zod0.ZodType<_uploadista_core_types0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core_types0.UploadFile, unknown>>;
422
+ mode?: TransformMode;
423
+ streamingConfig?: StreamingConfig;
424
+ }): Effect.Effect<_uploadista_core0.FlowNodeData & {
425
+ inputSchema: zod0.ZodType<_uploadista_core0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core0.UploadFile, unknown>>;
426
+ outputSchema: zod0.ZodType<_uploadista_core0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core0.UploadFile, unknown>>;
388
427
  run: (args: {
389
- data: _uploadista_core_types0.UploadFile;
428
+ data: _uploadista_core0.UploadFile;
390
429
  jobId: string;
391
430
  storageId: string;
392
431
  flowId: string;
393
432
  inputs?: Record<string, unknown>;
394
433
  clientId: string | null;
395
- }) => Effect.Effect<_uploadista_core_flow0.NodeExecutionResult<_uploadista_core_types0.UploadFile>, _uploadista_core_errors0.UploadistaError, never>;
434
+ }) => Effect.Effect<_uploadista_core0.NodeExecutionResult<_uploadista_core0.UploadFile>, _uploadista_core0.UploadistaError, never>;
396
435
  condition?: {
397
436
  field: string;
398
437
  operator: string;
@@ -406,10 +445,10 @@ declare function createResizeNode(id: string, {
406
445
  retryDelay?: number;
407
446
  exponentialBackoff?: boolean;
408
447
  };
409
- circuitBreaker?: _uploadista_core_flow0.FlowCircuitBreakerConfig;
448
+ circuitBreaker?: _uploadista_core0.FlowCircuitBreakerConfig;
410
449
  } & {
411
- type: _uploadista_core_flow0.NodeType;
412
- }, _uploadista_core_errors0.UploadistaError, ImagePlugin | _uploadista_core_upload0.UploadServer>;
450
+ type: _uploadista_core0.NodeType;
451
+ }, _uploadista_core0.UploadistaError, ImagePlugin | _uploadista_core0.UploadServer>;
413
452
  //#endregion
414
453
  //#region src/transform-image-node.d.ts
415
454
  /**
@@ -419,24 +458,32 @@ declare function createResizeNode(id: string, {
419
458
  * together. Each transformation is applied to the output of the previous transformation,
420
459
  * allowing for powerful image manipulation pipelines.
421
460
  *
461
+ * Supports both buffered and streaming modes for memory-efficient processing
462
+ * of large images. In streaming mode, each transformation is applied in sequence
463
+ * using streaming where supported.
464
+ *
422
465
  * Supported transformations include:
423
466
  * - Basic: resize, blur, rotate, flip
424
467
  * - Filters: grayscale, sepia, brightness, contrast
425
468
  * - Effects: sharpen
426
- * - Advanced: watermark, logo, text
469
+ * - Advanced: watermark, logo, text (streaming not supported for these)
427
470
  *
428
471
  * Note: Watermark and logo transformations require imagePath to be a valid URL.
429
472
  * Images will be fetched from the provided URL during transformation.
473
+ * Streaming mode is not supported for watermark, logo, and text transformations;
474
+ * these will cause fallback to buffered mode.
430
475
  *
431
476
  * @param id - Unique identifier for this node
432
477
  * @param params - Parameters including the transformations array
433
478
  * @param options - Optional configuration
434
479
  * @param options.keepOutput - Whether to keep output in flow results
435
480
  * @param options.naming - File naming configuration (auto suffix: `transformed`)
481
+ * @param options.mode - Transform mode: "buffered", "streaming", or "auto" (default)
482
+ * @param options.streamingConfig - Streaming configuration (file size threshold, chunk size)
436
483
  *
437
484
  * @example
438
485
  * ```typescript
439
- * // With auto-naming: "photo.jpg" -> "photo-transformed.jpg"
486
+ * // Auto mode (default) - uses streaming for files > 1MB, otherwise buffered
440
487
  * const node = yield* createTransformImageNode("transform-1", {
441
488
  * transformations: [
442
489
  * { type: 'resize', width: 800, height: 600, fit: 'cover' },
@@ -445,6 +492,25 @@ declare function createResizeNode(id: string, {
445
492
  * }, {
446
493
  * naming: { mode: "auto" }
447
494
  * });
495
+ *
496
+ * // Force buffered mode for small files
497
+ * const nodeBuffered = yield* createTransformImageNode("transform-2", {
498
+ * transformations: [
499
+ * { type: 'resize', width: 800, height: 600, fit: 'cover' },
500
+ * { type: 'blur', sigma: 5 }
501
+ * ]
502
+ * }, {
503
+ * mode: "buffered",
504
+ * naming: { mode: "auto" }
505
+ * });
506
+ *
507
+ * // Force streaming mode for memory efficiency
508
+ * const nodeStreaming = yield* createTransformImageNode("transform-3", {
509
+ * transformations: [{ type: 'grayscale' }]
510
+ * }, {
511
+ * mode: "streaming",
512
+ * naming: { mode: "auto" }
513
+ * });
448
514
  * ```
449
515
  */
450
516
  declare function createTransformImageNode(id: string, {
@@ -452,17 +518,19 @@ declare function createTransformImageNode(id: string, {
452
518
  }: TransformImageParams, options?: {
453
519
  keepOutput?: boolean;
454
520
  naming?: FileNamingConfig;
455
- }): Effect.Effect<_uploadista_core_flow0.FlowNodeData & {
456
- inputSchema: zod0.ZodType<_uploadista_core_types0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core_types0.UploadFile, unknown>>;
457
- outputSchema: zod0.ZodType<_uploadista_core_types0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core_types0.UploadFile, unknown>>;
521
+ mode?: TransformMode;
522
+ streamingConfig?: StreamingConfig;
523
+ }): Effect.Effect<_uploadista_core0.FlowNodeData & {
524
+ inputSchema: zod0.ZodType<_uploadista_core0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core0.UploadFile, unknown>>;
525
+ outputSchema: zod0.ZodType<_uploadista_core0.UploadFile, unknown, zod_v4_core0.$ZodTypeInternals<_uploadista_core0.UploadFile, unknown>>;
458
526
  run: (args: {
459
- data: _uploadista_core_types0.UploadFile;
527
+ data: _uploadista_core0.UploadFile;
460
528
  jobId: string;
461
529
  storageId: string;
462
530
  flowId: string;
463
531
  inputs?: Record<string, unknown>;
464
532
  clientId: string | null;
465
- }) => Effect.Effect<_uploadista_core_flow0.NodeExecutionResult<_uploadista_core_types0.UploadFile>, _uploadista_core_errors0.UploadistaError, never>;
533
+ }) => Effect.Effect<_uploadista_core0.NodeExecutionResult<_uploadista_core0.UploadFile>, UploadistaError, never>;
466
534
  condition?: {
467
535
  field: string;
468
536
  operator: string;
@@ -476,10 +544,10 @@ declare function createTransformImageNode(id: string, {
476
544
  retryDelay?: number;
477
545
  exponentialBackoff?: boolean;
478
546
  };
479
- circuitBreaker?: _uploadista_core_flow0.FlowCircuitBreakerConfig;
547
+ circuitBreaker?: _uploadista_core0.FlowCircuitBreakerConfig;
480
548
  } & {
481
- type: _uploadista_core_flow0.NodeType;
482
- }, _uploadista_core_errors0.UploadistaError, ImagePlugin | _uploadista_core_upload0.UploadServer>;
549
+ type: _uploadista_core0.NodeType;
550
+ }, UploadistaError, ImagePlugin | _uploadista_core0.UploadServer>;
483
551
  //#endregion
484
552
  //#region src/wait-for-url.d.ts
485
553
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/describe-image-node.ts","../src/optimize-node.ts","../src/remove-background-node.ts","../src/resize-node.ts","../src/transform-image-node.ts","../src/wait-for-url.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/describe-image-node.ts","../src/optimize-node.ts","../src/remove-background-node.ts","../src/resize-node.ts","../src/transform-image-node.ts","../src/wait-for-url.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{UploadistaError as e}from"@uploadista/core/errors";import{IMAGE_DESCRIPTION_OUTPUT_TYPE_ID as t,ImageAiPlugin as n,ImagePlugin as r,NodeType as i,STORAGE_OUTPUT_TYPE_ID as a,applyFileNaming as o,buildNamingContext as s,completeNodeExecution as c,createFlowNode as l,createTransformNode as u,getBaseName as d,imageDescriptionOutputSchema as f,resolveUploadMetadata as p}from"@uploadista/core/flow";import{uploadFileSchema as m}from"@uploadista/core/types";import{Effect as h}from"effect";import{UploadServer as g}from"@uploadista/core/upload";function _(t,n={}){let{maxWaitTime:r=1e4,retryDelay:i=500}=n;return h.gen(function*(){let n=Date.now();for(;Date.now()-n<r;){let e=yield*h.tryPromise(()=>fetch(t,{method:`HEAD`})).pipe(h.catchAll(()=>h.succeed(null)));if(e?.ok){yield*h.logInfo(`URL ${t} is now available`);return}e?yield*h.logDebug(`URL not ready yet (${e.status}), retrying...`):yield*h.logDebug(`URL check failed, retrying...`),yield*h.sleep(i)}return yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:`URL ${t} not available after ${r}ms`}).toEffect()})}function v(r,{credentialId:a,keepOutput:o}={}){return h.gen(function*(){let s=yield*n;return yield*l({id:r,name:`Describe Image`,description:`Describes the image using AI`,type:i.process,nodeTypeId:`describe-image`,outputTypeId:t,keepOutput:o,inputSchema:m,outputSchema:f,circuitBreaker:{enabled:!0,failureThreshold:5,resetTimeout:6e4,fallback:{type:`skip`,passThrough:!0}},run:({data:t,flowId:n,jobId:i,clientId:o})=>h.gen(function*(){let l={flowId:n,nodeId:r,jobId:i},u=t.url;if(!u)return yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:`URL is required for describe image operation`}).toEffect();yield*h.logInfo(`Describing image for file ${t.id} at URL: ${u}`),yield*_(u);let d={clientId:o,credentialId:a},f=yield*s.describeImage(u,d).pipe(h.catchAll(t=>h.gen(function*(){return yield*h.logError(`Failed to describe image`,t),yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:t instanceof Error?t.message:`Failed to describe image`}).toEffect()})));return yield*h.logInfo(`Successfully described image for file ${t.id}`),c({description:f.description,flow:l})})})})}const y={jpeg:`image/jpeg`,webp:`image/webp`,png:`image/png`,avif:`image/avif`},b={jpeg:`jpg`,webp:`webp`,png:`png`,avif:`avif`};function x(e,{quality:t,format:n},i){return h.gen(function*(){let c=yield*r;return yield*u({id:e,name:`Optimize`,description:`Optimizes an image for web delivery`,nodeTypeId:`optimize-image`,outputTypeId:a,keepOutput:i?.keepOutput,nodeType:`optimize`,namingVars:{format:n,quality:t},transform:(r,a)=>h.map(c.optimize(r,{quality:t,format:n}),r=>{let c=y[n],l=b[n],u=a.metadata?.fileName,f;if(u&&typeof u==`string`)if(i?.naming){let r={...i.naming,autoSuffix:i.naming.autoSuffix??(e=>e.format??n)};f=`${d(o(a,s(a,{flowId:a.flow?.flowId??``,jobId:a.flow?.jobId??``,nodeId:e,nodeType:`optimize`},{format:n,quality:t}),r))}.${l}`}else f=u.replace(/\.[^.]+$/,`.${l}`);return{bytes:r,type:c,fileName:f}})})})}function S(t,{credentialId:r,keepOutput:u,naming:d}={}){return h.gen(function*(){let f=yield*n,v=yield*g;return yield*l({id:t,name:`Remove Background`,description:`Removes the background from an image`,type:i.process,nodeTypeId:`remove-background`,outputTypeId:a,keepOutput:u,inputSchema:m,outputSchema:m,circuitBreaker:{enabled:!0,failureThreshold:5,resetTimeout:6e4,fallback:{type:`skip`,passThrough:!0}},run:({data:n,flowId:i,jobId:a,storageId:l,clientId:u})=>h.gen(function*(){let m={flowId:i,nodeId:t,jobId:a},g=n.url;if(!g)return yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:`URL is required for remove background operation`}).toEffect();yield*h.logInfo(`Removing background for file ${n.id} at URL: ${n.url}`),yield*_(g);let y={clientId:u,credentialId:r},{outputUrl:b}=yield*f.removeBackground(g,y).pipe(h.catchAll(t=>h.gen(function*(){return yield*h.logError(`Failed to remove background`,t),yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:t instanceof Error?t.message:`Failed to remove background from image`}).toEffect()}))),{type:x,fileName:S,metadata:C,metadataJson:w}=p(n.metadata),T=S;if(d){let e={...d,autoSuffix:d.autoSuffix??(()=>`nobg`)};T=o(n,s(n,{flowId:i,jobId:a,nodeId:t,nodeType:`remove-background`}),e)}yield*h.logInfo(`Uploading processed file to storage`);let E=yield*v.uploadFromUrl({storageId:l,size:0,type:x,fileName:T,lastModified:0,metadata:w,flow:m},u,b).pipe(h.catchAll(t=>h.gen(function*(){return yield*h.logError(`Failed to upload processed file`,t),yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:t instanceof Error?t.message:`Failed to upload processed file`}).toEffect()})));yield*h.logInfo(`Successfully removed background for file ${n.id}`);let D=C?{...C,...T!==S&&{fileName:T,originalName:T,name:T,extension:T.split(`.`).pop()||C.extension}}:E.metadata;return c(D?{...E,metadata:D}:E)})})})}function C(e,{width:t,height:n,fit:i},o){return h.gen(function*(){let s=yield*r,c=o?.naming?{...o.naming,autoSuffix:o.naming.autoSuffix??(e=>`${e.width??t}x${e.height??n}`)}:void 0;return yield*u({id:e,name:`Resize`,description:`Resizes an image to the specified dimensions`,nodeTypeId:`resize-image`,outputTypeId:a,keepOutput:o?.keepOutput,naming:c,nodeType:`resize`,namingVars:{width:t,height:n},transform:e=>s.resize(e,{height:n,width:t,fit:i})})})}function w(e,t,n){return h.reduce(n,t,(t,n)=>e.transform(t,n))}function T(e,{transformations:t},n){return h.gen(function*(){let i=yield*r,o=n?.naming?{...n.naming,autoSuffix:n.naming.autoSuffix??(()=>`transformed`)}:void 0;return yield*u({id:e,name:`Transform Image`,description:`Apply ${t.length} transformation${t.length===1?``:`s`} to the image`,nodeTypeId:`transform-image`,outputTypeId:a,keepOutput:n?.keepOutput,naming:o,nodeType:`transform-image`,transform:e=>w(i,e,t)})})}export{v as createDescribeImageNode,x as createOptimizeNode,S as createRemoveBackgroundNode,C as createResizeNode,T as createTransformImageNode,_ as waitForUrlAvailability};
1
+ import{UploadistaError as e}from"@uploadista/core/errors";import{IMAGE_DESCRIPTION_OUTPUT_TYPE_ID as t,ImageAiPlugin as n,ImagePlugin as r,NodeType as i,STORAGE_OUTPUT_TYPE_ID as a,applyFileNaming as o,buildNamingContext as s,completeNodeExecution as c,createFlowNode as l,createTransformNode as u,getBaseName as d,imageDescriptionOutputSchema as f,resolveUploadMetadata as p}from"@uploadista/core/flow";import{uploadFileSchema as m}from"@uploadista/core/types";import{Effect as h,Stream as g}from"effect";import{UploadistaError as _}from"@uploadista/core";import{UploadServer as v}from"@uploadista/core/upload";function y(t,n={}){let{maxWaitTime:r=1e4,retryDelay:i=500}=n;return h.gen(function*(){let n=Date.now();for(;Date.now()-n<r;){let e=yield*h.tryPromise(()=>fetch(t,{method:`HEAD`})).pipe(h.catchAll(()=>h.succeed(null)));if(e?.ok){yield*h.logInfo(`URL ${t} is now available`);return}e?yield*h.logDebug(`URL not ready yet (${e.status}), retrying...`):yield*h.logDebug(`URL check failed, retrying...`),yield*h.sleep(i)}return yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:`URL ${t} not available after ${r}ms`}).toEffect()})}function b(r,{credentialId:a,keepOutput:o}={}){return h.gen(function*(){let s=yield*n;return yield*l({id:r,name:`Describe Image`,description:`Describes the image using AI`,type:i.process,nodeTypeId:`describe-image`,outputTypeId:t,keepOutput:o,inputSchema:m,outputSchema:f,circuitBreaker:{enabled:!0,failureThreshold:5,resetTimeout:6e4,fallback:{type:`skip`,passThrough:!0}},run:({data:t,flowId:n,jobId:i,clientId:o})=>h.gen(function*(){let l={flowId:n,nodeId:r,jobId:i},u=t.url;if(!u)return yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:`URL is required for describe image operation`}).toEffect();yield*h.logInfo(`Describing image for file ${t.id} at URL: ${u}`),yield*y(u);let d={clientId:o,credentialId:a},f=yield*s.describeImage(u,d).pipe(h.catchAll(t=>h.gen(function*(){return yield*h.logError(`Failed to describe image`,t),yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:t instanceof Error?t.message:`Failed to describe image`}).toEffect()})));return yield*h.logInfo(`Successfully described image for file ${t.id}`),c({description:f.description,flow:l})})})})}const x={jpeg:`image/jpeg`,webp:`image/webp`,png:`image/png`,avif:`image/avif`},S={jpeg:`jpg`,webp:`webp`,png:`png`,avif:`avif`};function C(e,{quality:t,format:n},i){return h.gen(function*(){let c=yield*r,l=c.supportsStreaming??!1,f=i?.mode??`buffered`,p=f===`buffered`?`buffered`:l?f:`buffered`,m=r=>{let a=x[n],c=S[n],l=r.metadata?.fileName,u;if(l&&typeof l==`string`)if(i?.naming){let a={...i.naming,autoSuffix:i.naming.autoSuffix??(e=>e.format??n)};u=`${d(o(r,s(r,{flowId:r.flow?.flowId??``,jobId:r.flow?.jobId??``,nodeId:e,nodeType:`optimize`},{format:n,quality:t}),a))}.${c}`}else u=l.replace(/\.[^.]+$/,`.${c}`);return{newType:a,newFileName:u}};return yield*u({id:e,name:`Optimize`,description:`Optimizes an image for web delivery`,nodeTypeId:`optimize-image`,outputTypeId:a,keepOutput:i?.keepOutput,nodeType:`optimize`,namingVars:{format:n,quality:t},mode:p,streamingConfig:i?.streamingConfig,transform:(e,r)=>h.map(c.optimize(e,{quality:t,format:n}),e=>{let{newType:t,newFileName:n}=m(r);return{bytes:e,type:t,fileName:n}}),streamingTransform:c.optimizeStream?(e,r)=>{let i=c.optimizeStream;if(!i)throw _.fromCode(`UNKNOWN_ERROR`);return h.gen(function*(){let a=yield*i(e,{quality:t,format:n}),{newType:o,newFileName:s}=m(r);return{stream:a,type:o,fileName:s}})}:void 0})})}function w(t,{credentialId:r,keepOutput:u,naming:d}={}){return h.gen(function*(){let f=yield*n,g=yield*v;return yield*l({id:t,name:`Remove Background`,description:`Removes the background from an image`,type:i.process,nodeTypeId:`remove-background`,outputTypeId:a,keepOutput:u,inputSchema:m,outputSchema:m,circuitBreaker:{enabled:!0,failureThreshold:5,resetTimeout:6e4,fallback:{type:`skip`,passThrough:!0}},run:({data:n,flowId:i,jobId:a,storageId:l,clientId:u})=>h.gen(function*(){let m={flowId:i,nodeId:t,jobId:a},_=n.url;if(!_)return yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:`URL is required for remove background operation`}).toEffect();yield*h.logInfo(`Removing background for file ${n.id} at URL: ${n.url}`),yield*y(_);let v={clientId:u,credentialId:r},{outputUrl:b}=yield*f.removeBackground(_,v).pipe(h.catchAll(t=>h.gen(function*(){return yield*h.logError(`Failed to remove background`,t),yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:t instanceof Error?t.message:`Failed to remove background from image`}).toEffect()}))),{type:x,fileName:S,metadata:C,metadataJson:w}=p(n.metadata),T=S;if(d){let e={...d,autoSuffix:d.autoSuffix??(()=>`nobg`)};T=o(n,s(n,{flowId:i,jobId:a,nodeId:t,nodeType:`remove-background`}),e)}yield*h.logInfo(`Uploading processed file to storage`);let E=yield*g.uploadFromUrl({storageId:l,size:0,type:x,fileName:T,lastModified:0,metadata:w,flow:m},u,b).pipe(h.catchAll(t=>h.gen(function*(){return yield*h.logError(`Failed to upload processed file`,t),yield*e.fromCode(`FLOW_NODE_ERROR`,{cause:t instanceof Error?t.message:`Failed to upload processed file`}).toEffect()})));yield*h.logInfo(`Successfully removed background for file ${n.id}`);let D=C?{...C,...T!==S&&{fileName:T,originalName:T,name:T,extension:T.split(`.`).pop()||C.extension}}:E.metadata;return c(D?{...E,metadata:D}:E)})})})}function T(e,{width:t,height:n,fit:i},o){return h.gen(function*(){let s=yield*r,c=s.supportsStreaming??!1,l=o?.mode??`auto`,d=l===`buffered`?`buffered`:c?l:`buffered`,f=o?.naming?{...o.naming,autoSuffix:o.naming.autoSuffix??(e=>`${e.width??t}x${e.height??n}`)}:void 0;return yield*u({id:e,name:`Resize`,description:`Resizes an image to the specified dimensions`,nodeTypeId:`resize-image`,outputTypeId:a,keepOutput:o?.keepOutput,naming:f,nodeType:`resize`,namingVars:{width:t,height:n},mode:d,streamingConfig:o?.streamingConfig,transform:e=>s.resize(e,{height:n,width:t,fit:i}),streamingTransform:s.resizeStream?e=>h.gen(function*(){let r=s.resizeStream;if(!r)throw Error(`resizeStream not available`);return{stream:yield*r(e,{width:t,height:n,fit:i})}}):void 0})})}function E(e,t,n){return h.reduce(n,t,(t,n)=>e.transform(t,n))}function D(e,t,n){let r=e.transformStream;return r?h.reduce(n,t,(e,t)=>h.flatMap(r(e,t),e=>h.succeed(e))):h.gen(function*(){let r=[];yield*g.runForEach(t,e=>h.sync(()=>{r.push(e)}));let i=r.reduce((e,t)=>e+t.byteLength,0),a=new Uint8Array(i),o=0;for(let e of r)a.set(e,o),o+=e.byteLength;let s=yield*E(e,a,n);return g.make(s)})}function O(e,{transformations:t},n){return h.gen(function*(){let i=yield*r,o=i.supportsStreaming??!1,s=n?.mode??`auto`,c=t.some(e=>e.type===`watermark`||e.type===`logo`||e.type===`text`),l=s===`buffered`?`buffered`:o&&!c?s:`buffered`,d=n?.naming?{...n.naming,autoSuffix:n.naming.autoSuffix??(()=>`transformed`)}:void 0;return yield*u({id:e,name:`Transform Image`,description:`Apply ${t.length} transformation${t.length===1?``:`s`} to the image`,nodeTypeId:`transform-image`,outputTypeId:a,keepOutput:n?.keepOutput,naming:d,nodeType:`transform-image`,mode:l,streamingConfig:n?.streamingConfig,transform:e=>E(i,e,t),streamingTransform:o&&!c?e=>h.gen(function*(){return{stream:yield*D(i,e,t)}}):void 0})})}export{b as createDescribeImageNode,C as createOptimizeNode,w as createRemoveBackgroundNode,T as createResizeNode,O as createTransformImageNode,y as waitForUrlAvailability};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["formatToMimeType: Record<OptimizeParams[\"format\"], string>","formatToExtension: Record<OptimizeParams[\"format\"], string>","newFileName: string | undefined","namingConfig: FileNamingConfig","namingConfig: FileNamingConfig","namingConfig: FileNamingConfig | undefined","namingConfig: FileNamingConfig | undefined"],"sources":["../src/wait-for-url.ts","../src/describe-image-node.ts","../src/optimize-node.ts","../src/remove-background-node.ts","../src/resize-node.ts","../src/transform-image-node.ts"],"sourcesContent":["import { UploadistaError } from \"@uploadista/core/errors\";\nimport { Effect } from \"effect\";\n\n/**\n * Waits for a URL to become available by periodically checking its accessibility.\n * This is useful when a file has just been uploaded and may not be immediately\n * accessible due to CDN propagation or storage consistency delays.\n *\n * @param url - The URL to check for availability\n * @param options - Configuration options\n * @param options.maxWaitTime - Maximum time to wait in milliseconds (default: 10000)\n * @param options.retryDelay - Delay between retries in milliseconds (default: 500)\n * @returns Effect that succeeds when URL is available or fails with UploadistaError\n */\nexport function waitForUrlAvailability(\n url: string,\n options: {\n maxWaitTime?: number;\n retryDelay?: number;\n } = {},\n): Effect.Effect<void, UploadistaError> {\n const { maxWaitTime = 10000, retryDelay = 500 } = options;\n\n return Effect.gen(function* () {\n const startTime = Date.now();\n\n while (Date.now() - startTime < maxWaitTime) {\n const response = yield* Effect.tryPromise(() =>\n fetch(url, { method: \"HEAD\" }),\n ).pipe(Effect.catchAll(() => Effect.succeed(null)));\n\n if (response?.ok) {\n yield* Effect.logInfo(`URL ${url} is now available`);\n return;\n }\n\n if (response) {\n yield* Effect.logDebug(\n `URL not ready yet (${response.status}), retrying...`,\n );\n } else {\n yield* Effect.logDebug(`URL check failed, retrying...`);\n }\n\n yield* Effect.sleep(retryDelay);\n }\n\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause: `URL ${url} not available after ${maxWaitTime}ms`,\n }).toEffect();\n });\n}\n","import { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n completeNodeExecution,\n createFlowNode,\n IMAGE_DESCRIPTION_OUTPUT_TYPE_ID,\n ImageAiPlugin,\n imageDescriptionOutputSchema,\n NodeType,\n} from \"@uploadista/core/flow\";\nimport { uploadFileSchema } from \"@uploadista/core/types\";\n\nimport { Effect } from \"effect\";\nimport { waitForUrlAvailability } from \"./wait-for-url\";\n\nexport function createDescribeImageNode(\n id: string,\n { credentialId, keepOutput }: { credentialId?: string; keepOutput?: boolean } = {},\n) {\n return Effect.gen(function* () {\n const imageAiService = yield* ImageAiPlugin;\n\n return yield* createFlowNode({\n id,\n name: \"Describe Image\",\n description: \"Describes the image using AI\",\n type: NodeType.process,\n nodeTypeId: \"describe-image\",\n outputTypeId: IMAGE_DESCRIPTION_OUTPUT_TYPE_ID,\n keepOutput,\n inputSchema: uploadFileSchema,\n outputSchema: imageDescriptionOutputSchema,\n // AI service - enable circuit breaker with skip fallback\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n resetTimeout: 60000,\n fallback: { type: \"skip\", passThrough: true },\n },\n run: ({ data: file, flowId, jobId, clientId }) => {\n return Effect.gen(function* () {\n const flow = {\n flowId,\n nodeId: id,\n jobId,\n };\n\n const fileUrl = file.url;\n\n // Validate input\n if (!fileUrl) {\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause: \"URL is required for describe image operation\",\n }).toEffect();\n }\n\n yield* Effect.logInfo(\n `Describing image for file ${file.id} at URL: ${fileUrl}`,\n );\n\n // Wait for URL to be available with retry mechanism\n yield* waitForUrlAvailability(fileUrl);\n\n // Build context for ImageAI plugin\n const context = {\n clientId,\n credentialId,\n };\n\n // Describe image with error handling\n const result = yield* imageAiService\n .describeImage(fileUrl, context)\n .pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logError(\"Failed to describe image\", error);\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause:\n error instanceof Error\n ? error.message\n : \"Failed to describe image\",\n }).toEffect();\n }),\n ),\n );\n\n yield* Effect.logInfo(\n `Successfully described image for file ${file.id}`,\n );\n\n // Return structured image description output (not UploadFile)\n return completeNodeExecution({\n description: result.description,\n flow,\n });\n });\n },\n });\n });\n}\n","import {\n applyFileNaming,\n buildNamingContext,\n createTransformNode,\n type FileNamingConfig,\n getBaseName,\n ImagePlugin,\n type OptimizeParams,\n STORAGE_OUTPUT_TYPE_ID,\n} from \"@uploadista/core/flow\";\nimport { Effect } from \"effect\";\n\n// Map image format to MIME type\nconst formatToMimeType: Record<OptimizeParams[\"format\"], string> = {\n jpeg: \"image/jpeg\",\n webp: \"image/webp\",\n png: \"image/png\",\n avif: \"image/avif\",\n};\n\n// Map image format to file extension\nconst formatToExtension: Record<OptimizeParams[\"format\"], string> = {\n jpeg: \"jpg\",\n webp: \"webp\",\n png: \"png\",\n avif: \"avif\",\n};\n\n/**\n * Creates an optimize node that optimizes images for web delivery.\n *\n * @param id - Unique node identifier\n * @param params - Optimize parameters (quality, format)\n * @param options - Optional configuration\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `${format}`)\n *\n * @example\n * ```typescript\n * // With auto-naming: \"photo.jpg\" -> \"photo-webp.webp\"\n * const optimize = yield* createOptimizeNode(\"opt-1\", { quality: 80, format: \"webp\" }, {\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createOptimizeNode(\n id: string,\n { quality, format }: OptimizeParams,\n options?: { keepOutput?: boolean; naming?: FileNamingConfig },\n) {\n return Effect.gen(function* () {\n const imageService = yield* ImagePlugin;\n\n return yield* createTransformNode({\n id,\n name: \"Optimize\",\n description: \"Optimizes an image for web delivery\",\n nodeTypeId: \"optimize-image\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput: options?.keepOutput,\n // Note: naming is handled in transform since format changes extension\n nodeType: \"optimize\",\n namingVars: { format, quality },\n transform: (inputBytes, file) =>\n Effect.map(\n imageService.optimize(inputBytes, { quality, format }),\n (optimizedBytes) => {\n // Return bytes with updated metadata if format changes\n const newType = formatToMimeType[format];\n const newExtension = formatToExtension[format];\n\n // Get original fileName\n const fileName = file.metadata?.fileName;\n let newFileName: string | undefined;\n\n if (fileName && typeof fileName === \"string\") {\n // Apply naming if configured\n if (options?.naming) {\n const namingConfig: FileNamingConfig = {\n ...options.naming,\n autoSuffix:\n options.naming.autoSuffix ?? ((ctx) => ctx.format ?? format),\n };\n const namingContext = buildNamingContext(\n file,\n {\n flowId: file.flow?.flowId ?? \"\",\n jobId: file.flow?.jobId ?? \"\",\n nodeId: id,\n nodeType: \"optimize\",\n },\n { format, quality },\n );\n // Apply naming to get base name with suffix\n const namedFile = applyFileNaming(file, namingContext, namingConfig);\n // Replace extension with new format extension\n newFileName = `${getBaseName(namedFile)}.${newExtension}`;\n } else {\n // No naming config, just update extension\n newFileName = fileName.replace(/\\.[^.]+$/, `.${newExtension}`);\n }\n }\n\n return {\n bytes: optimizedBytes,\n type: newType,\n fileName: newFileName,\n } as\n | Uint8Array\n | { bytes: Uint8Array; type: string; fileName?: string };\n },\n ),\n });\n });\n}\n","import { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n applyFileNaming,\n buildNamingContext,\n completeNodeExecution,\n createFlowNode,\n type FileNamingConfig,\n ImageAiPlugin,\n NodeType,\n resolveUploadMetadata,\n STORAGE_OUTPUT_TYPE_ID,\n} from \"@uploadista/core/flow\";\nimport { uploadFileSchema } from \"@uploadista/core/types\";\nimport { UploadServer } from \"@uploadista/core/upload\";\nimport { Effect } from \"effect\";\nimport { waitForUrlAvailability } from \"./wait-for-url\";\n\n/**\n * Creates a remove-background node that removes backgrounds from images using AI.\n *\n * @param id - Unique node identifier\n * @param options - Optional configuration\n * @param options.credentialId - Optional credential ID for AI service\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `nobg`)\n *\n * @example\n * ```typescript\n * // With auto-naming: \"photo.jpg\" -> \"photo-nobg.jpg\"\n * const node = yield* createRemoveBackgroundNode(\"remove-bg-1\", {\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createRemoveBackgroundNode(\n id: string,\n { credentialId, keepOutput, naming }: { credentialId?: string; keepOutput?: boolean; naming?: FileNamingConfig } = {},\n) {\n return Effect.gen(function* () {\n const imageAiService = yield* ImageAiPlugin;\n const uploadServer = yield* UploadServer;\n\n return yield* createFlowNode({\n id,\n name: \"Remove Background\",\n description: \"Removes the background from an image\",\n type: NodeType.process,\n nodeTypeId: \"remove-background\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput,\n inputSchema: uploadFileSchema,\n outputSchema: uploadFileSchema,\n // AI service - enable circuit breaker with skip fallback\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n resetTimeout: 60000,\n fallback: { type: \"skip\", passThrough: true },\n },\n run: ({ data: file, flowId, jobId, storageId, clientId }) => {\n return Effect.gen(function* () {\n const flow = {\n flowId,\n nodeId: id,\n jobId,\n };\n\n const fileUrl = file.url;\n\n // Validate input\n if (!fileUrl) {\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause: \"URL is required for remove background operation\",\n }).toEffect();\n }\n\n yield* Effect.logInfo(\n `Removing background for file ${file.id} at URL: ${file.url}`,\n );\n\n // Wait for URL to be available with retry mechanism\n yield* waitForUrlAvailability(fileUrl);\n\n // Build context for ImageAI plugin\n const context = {\n clientId,\n credentialId,\n };\n\n // Remove background with error handling\n const backgroundRemovalResult = yield* imageAiService\n .removeBackground(fileUrl, context)\n .pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logError(\"Failed to remove background\", error);\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause:\n error instanceof Error\n ? error.message\n : \"Failed to remove background from image\",\n }).toEffect();\n }),\n ),\n );\n\n const { outputUrl } = backgroundRemovalResult;\n const { type, fileName, metadata, metadataJson } =\n resolveUploadMetadata(file.metadata);\n\n // Apply file naming if configured\n let outputFileName = fileName;\n if (naming) {\n const namingConfig: FileNamingConfig = {\n ...naming,\n autoSuffix: naming.autoSuffix ?? (() => \"nobg\"),\n };\n const namingContext = buildNamingContext(\n file,\n {\n flowId,\n jobId,\n nodeId: id,\n nodeType: \"remove-background\",\n },\n );\n outputFileName = applyFileNaming(file, namingContext, namingConfig);\n }\n\n yield* Effect.logInfo(`Uploading processed file to storage`);\n\n // Upload the transformed bytes back to the upload server with error handling\n const result = yield* uploadServer\n .uploadFromUrl(\n {\n storageId,\n size: 0,\n type,\n fileName: outputFileName,\n lastModified: 0,\n metadata: metadataJson,\n flow,\n },\n clientId,\n outputUrl,\n )\n .pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logError(\n \"Failed to upload processed file\",\n error,\n );\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause:\n error instanceof Error\n ? error.message\n : \"Failed to upload processed file\",\n }).toEffect();\n }),\n ),\n );\n\n yield* Effect.logInfo(\n `Successfully removed background for file ${file.id}`,\n );\n\n // Update metadata with new filename if naming was applied\n const updatedMetadata = metadata\n ? {\n ...metadata,\n ...(outputFileName !== fileName && {\n fileName: outputFileName,\n originalName: outputFileName,\n name: outputFileName,\n extension: outputFileName.split(\".\").pop() || metadata.extension,\n }),\n }\n : result.metadata;\n\n return completeNodeExecution(\n updatedMetadata\n ? {\n ...result,\n metadata: updatedMetadata,\n }\n : result,\n );\n });\n },\n });\n });\n}\n","import {\n createTransformNode,\n type FileNamingConfig,\n ImagePlugin,\n type ResizeParams,\n STORAGE_OUTPUT_TYPE_ID,\n} from \"@uploadista/core/flow\";\nimport { Effect } from \"effect\";\n\n/**\n * Creates a resize node that resizes images to specified dimensions.\n *\n * @param id - Unique node identifier\n * @param params - Resize parameters (width, height, fit)\n * @param options - Optional configuration\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `${width}x${height}`)\n *\n * @example\n * ```typescript\n * // With auto-naming: \"photo.jpg\" -> \"photo-800x600.jpg\"\n * const resize = yield* createResizeNode(\"resize-1\", { width: 800, height: 600 }, {\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createResizeNode(\n id: string,\n { width, height, fit }: ResizeParams,\n options?: { keepOutput?: boolean; naming?: FileNamingConfig },\n) {\n return Effect.gen(function* () {\n const imageService = yield* ImagePlugin;\n\n // Build naming config with auto suffix for resize\n const namingConfig: FileNamingConfig | undefined = options?.naming\n ? {\n ...options.naming,\n // Provide default auto suffix generator for resize nodes\n autoSuffix:\n options.naming.autoSuffix ??\n ((ctx) => `${ctx.width ?? width}x${ctx.height ?? height}`),\n }\n : undefined;\n\n return yield* createTransformNode({\n id,\n name: \"Resize\",\n description: \"Resizes an image to the specified dimensions\",\n nodeTypeId: \"resize-image\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput: options?.keepOutput,\n naming: namingConfig,\n nodeType: \"resize\",\n namingVars: { width, height },\n transform: (inputBytes) =>\n imageService.resize(inputBytes, { height, width, fit }),\n });\n });\n}\n","import {\n createTransformNode,\n type FileNamingConfig,\n ImagePlugin,\n STORAGE_OUTPUT_TYPE_ID,\n type TransformImageParams,\n} from \"@uploadista/core/flow\";\nimport { Effect } from \"effect\";\n\n/**\n * Apply a chain of transformations to an image by reducing over the transformations array.\n * Each transformation receives the output of the previous transformation as input.\n *\n * @param imageService - The image plugin service to use for transformations\n * @param inputBytes - The input image bytes\n * @param transformations - Array of transformations to apply in sequence\n * @returns Effect that resolves to the final transformed image bytes\n */\nfunction applyTransformationChain(\n imageService: ReturnType<typeof ImagePlugin.of>,\n inputBytes: Uint8Array,\n transformations: TransformImageParams[\"transformations\"],\n) {\n return Effect.reduce(transformations, inputBytes, (bytes, transformation) =>\n imageService.transform(bytes, transformation),\n );\n}\n\n/**\n * Creates a transform image node that applies multiple transformations sequentially.\n *\n * This node enables complex image processing workflows by chaining multiple transformations\n * together. Each transformation is applied to the output of the previous transformation,\n * allowing for powerful image manipulation pipelines.\n *\n * Supported transformations include:\n * - Basic: resize, blur, rotate, flip\n * - Filters: grayscale, sepia, brightness, contrast\n * - Effects: sharpen\n * - Advanced: watermark, logo, text\n *\n * Note: Watermark and logo transformations require imagePath to be a valid URL.\n * Images will be fetched from the provided URL during transformation.\n *\n * @param id - Unique identifier for this node\n * @param params - Parameters including the transformations array\n * @param options - Optional configuration\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `transformed`)\n *\n * @example\n * ```typescript\n * // With auto-naming: \"photo.jpg\" -> \"photo-transformed.jpg\"\n * const node = yield* createTransformImageNode(\"transform-1\", {\n * transformations: [\n * { type: 'resize', width: 800, height: 600, fit: 'cover' },\n * { type: 'brightness', value: 20 }\n * ]\n * }, {\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createTransformImageNode(\n id: string,\n { transformations }: TransformImageParams,\n options?: { keepOutput?: boolean; naming?: FileNamingConfig },\n) {\n return Effect.gen(function* () {\n const imageService = yield* ImagePlugin;\n\n // Build naming config with auto suffix for transform-image\n const namingConfig: FileNamingConfig | undefined = options?.naming\n ? {\n ...options.naming,\n autoSuffix: options.naming.autoSuffix ?? (() => \"transformed\"),\n }\n : undefined;\n\n return yield* createTransformNode({\n id,\n name: \"Transform Image\",\n description: `Apply ${transformations.length} transformation${transformations.length === 1 ? \"\" : \"s\"} to the image`,\n nodeTypeId: \"transform-image\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput: options?.keepOutput,\n naming: namingConfig,\n nodeType: \"transform-image\",\n transform: (inputBytes) =>\n applyTransformationChain(imageService, inputBytes, transformations),\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["formatToMimeType: Record<OptimizeParams[\"format\"], string>","formatToExtension: Record<OptimizeParams[\"format\"], string>","effectiveMode: TransformMode","newFileName: string | undefined","namingConfig: FileNamingConfig","UploadistaError","namingConfig: FileNamingConfig","effectiveMode: TransformMode","namingConfig: FileNamingConfig | undefined","chunks: Uint8Array[]","effectiveMode: TransformMode","namingConfig: FileNamingConfig | undefined"],"sources":["../src/wait-for-url.ts","../src/describe-image-node.ts","../src/optimize-node.ts","../src/remove-background-node.ts","../src/resize-node.ts","../src/transform-image-node.ts"],"sourcesContent":["import { UploadistaError } from \"@uploadista/core/errors\";\nimport { Effect } from \"effect\";\n\n/**\n * Waits for a URL to become available by periodically checking its accessibility.\n * This is useful when a file has just been uploaded and may not be immediately\n * accessible due to CDN propagation or storage consistency delays.\n *\n * @param url - The URL to check for availability\n * @param options - Configuration options\n * @param options.maxWaitTime - Maximum time to wait in milliseconds (default: 10000)\n * @param options.retryDelay - Delay between retries in milliseconds (default: 500)\n * @returns Effect that succeeds when URL is available or fails with UploadistaError\n */\nexport function waitForUrlAvailability(\n url: string,\n options: {\n maxWaitTime?: number;\n retryDelay?: number;\n } = {},\n): Effect.Effect<void, UploadistaError> {\n const { maxWaitTime = 10000, retryDelay = 500 } = options;\n\n return Effect.gen(function* () {\n const startTime = Date.now();\n\n while (Date.now() - startTime < maxWaitTime) {\n const response = yield* Effect.tryPromise(() =>\n fetch(url, { method: \"HEAD\" }),\n ).pipe(Effect.catchAll(() => Effect.succeed(null)));\n\n if (response?.ok) {\n yield* Effect.logInfo(`URL ${url} is now available`);\n return;\n }\n\n if (response) {\n yield* Effect.logDebug(\n `URL not ready yet (${response.status}), retrying...`,\n );\n } else {\n yield* Effect.logDebug(`URL check failed, retrying...`);\n }\n\n yield* Effect.sleep(retryDelay);\n }\n\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause: `URL ${url} not available after ${maxWaitTime}ms`,\n }).toEffect();\n });\n}\n","import { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n completeNodeExecution,\n createFlowNode,\n IMAGE_DESCRIPTION_OUTPUT_TYPE_ID,\n ImageAiPlugin,\n imageDescriptionOutputSchema,\n NodeType,\n} from \"@uploadista/core/flow\";\nimport { uploadFileSchema } from \"@uploadista/core/types\";\n\nimport { Effect } from \"effect\";\nimport { waitForUrlAvailability } from \"./wait-for-url\";\n\nexport function createDescribeImageNode(\n id: string,\n { credentialId, keepOutput }: { credentialId?: string; keepOutput?: boolean } = {},\n) {\n return Effect.gen(function* () {\n const imageAiService = yield* ImageAiPlugin;\n\n return yield* createFlowNode({\n id,\n name: \"Describe Image\",\n description: \"Describes the image using AI\",\n type: NodeType.process,\n nodeTypeId: \"describe-image\",\n outputTypeId: IMAGE_DESCRIPTION_OUTPUT_TYPE_ID,\n keepOutput,\n inputSchema: uploadFileSchema,\n outputSchema: imageDescriptionOutputSchema,\n // AI service - enable circuit breaker with skip fallback\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n resetTimeout: 60000,\n fallback: { type: \"skip\", passThrough: true },\n },\n run: ({ data: file, flowId, jobId, clientId }) => {\n return Effect.gen(function* () {\n const flow = {\n flowId,\n nodeId: id,\n jobId,\n };\n\n const fileUrl = file.url;\n\n // Validate input\n if (!fileUrl) {\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause: \"URL is required for describe image operation\",\n }).toEffect();\n }\n\n yield* Effect.logInfo(\n `Describing image for file ${file.id} at URL: ${fileUrl}`,\n );\n\n // Wait for URL to be available with retry mechanism\n yield* waitForUrlAvailability(fileUrl);\n\n // Build context for ImageAI plugin\n const context = {\n clientId,\n credentialId,\n };\n\n // Describe image with error handling\n const result = yield* imageAiService\n .describeImage(fileUrl, context)\n .pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logError(\"Failed to describe image\", error);\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause:\n error instanceof Error\n ? error.message\n : \"Failed to describe image\",\n }).toEffect();\n }),\n ),\n );\n\n yield* Effect.logInfo(\n `Successfully described image for file ${file.id}`,\n );\n\n // Return structured image description output (not UploadFile)\n return completeNodeExecution({\n description: result.description,\n flow,\n });\n });\n },\n });\n });\n}\n","import { UploadistaError } from \"@uploadista/core\";\nimport {\n applyFileNaming,\n buildNamingContext,\n createTransformNode,\n type FileNamingConfig,\n getBaseName,\n ImagePlugin,\n type OptimizeParams,\n STORAGE_OUTPUT_TYPE_ID,\n type StreamingConfig,\n type TransformMode,\n} from \"@uploadista/core/flow\";\nimport { Effect } from \"effect\";\n\n// Map image format to MIME type\nconst formatToMimeType: Record<OptimizeParams[\"format\"], string> = {\n jpeg: \"image/jpeg\",\n webp: \"image/webp\",\n png: \"image/png\",\n avif: \"image/avif\",\n};\n\n// Map image format to file extension\nconst formatToExtension: Record<OptimizeParams[\"format\"], string> = {\n jpeg: \"jpg\",\n webp: \"webp\",\n png: \"png\",\n avif: \"avif\",\n};\n\n/**\n * Creates an optimize node that optimizes images for web delivery.\n *\n * Supports both buffered and streaming modes for memory-efficient processing\n * of large images. In streaming mode, the image is read and processed\n * incrementally, reducing peak memory usage.\n *\n * @param id - Unique node identifier\n * @param params - Optimize parameters (quality, format)\n * @param options - Optional configuration\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `${format}`)\n * @param options.mode - Transform mode: \"buffered\" (default), \"streaming\", or \"auto\"\n * @param options.streamingConfig - Streaming configuration (file size threshold, chunk size)\n *\n * @example\n * ```typescript\n * // Buffered mode (default) - \"photo.jpg\" -> \"photo-webp.webp\"\n * const optimize = yield* createOptimizeNode(\"opt-1\", { quality: 80, format: \"webp\" }, {\n * naming: { mode: \"auto\" }\n * });\n *\n * // Streaming mode for large files\n * const optimizeStreaming = yield* createOptimizeNode(\"opt-2\", { quality: 80, format: \"webp\" }, {\n * mode: \"streaming\",\n * naming: { mode: \"auto\" }\n * });\n *\n * // Auto mode - uses streaming for files > 1MB\n * const optimizeAuto = yield* createOptimizeNode(\"opt-3\", { quality: 80, format: \"webp\" }, {\n * mode: \"auto\",\n * streamingConfig: { fileSizeThreshold: 1_048_576 },\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createOptimizeNode(\n id: string,\n { quality, format }: OptimizeParams,\n options?: {\n keepOutput?: boolean;\n naming?: FileNamingConfig;\n mode?: TransformMode;\n streamingConfig?: StreamingConfig;\n },\n) {\n return Effect.gen(function* () {\n const imageService = yield* ImagePlugin;\n\n // Determine if streaming is available and requested\n const supportsStreaming = imageService.supportsStreaming ?? false;\n const requestedMode = options?.mode ?? \"buffered\";\n\n // If streaming requested but not supported, fall back to buffered\n const effectiveMode: TransformMode =\n requestedMode === \"buffered\"\n ? \"buffered\"\n : supportsStreaming\n ? requestedMode\n : \"buffered\";\n\n // Helper to build output metadata from optimized result\n const buildOutputMetadata = (file: {\n metadata?: Record<string, unknown>;\n flow?: { flowId?: string; jobId?: string };\n }) => {\n const newType = formatToMimeType[format];\n const newExtension = formatToExtension[format];\n\n // Get original fileName\n const fileName = file.metadata?.fileName;\n let newFileName: string | undefined;\n\n if (fileName && typeof fileName === \"string\") {\n // Apply naming if configured\n if (options?.naming) {\n const namingConfig: FileNamingConfig = {\n ...options.naming,\n autoSuffix:\n options.naming.autoSuffix ?? ((ctx) => ctx.format ?? format),\n };\n const namingContext = buildNamingContext(\n file as Parameters<typeof buildNamingContext>[0],\n {\n flowId: file.flow?.flowId ?? \"\",\n jobId: file.flow?.jobId ?? \"\",\n nodeId: id,\n nodeType: \"optimize\",\n },\n { format, quality },\n );\n // Apply naming to get base name with suffix\n const namedFile = applyFileNaming(\n file as Parameters<typeof applyFileNaming>[0],\n namingContext,\n namingConfig,\n );\n // Replace extension with new format extension\n newFileName = `${getBaseName(namedFile)}.${newExtension}`;\n } else {\n // No naming config, just update extension\n newFileName = fileName.replace(/\\.[^.]+$/, `.${newExtension}`);\n }\n }\n\n return { newType, newFileName };\n };\n\n return yield* createTransformNode({\n id,\n name: \"Optimize\",\n description: \"Optimizes an image for web delivery\",\n nodeTypeId: \"optimize-image\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput: options?.keepOutput,\n // Note: naming is handled in transform since format changes extension\n nodeType: \"optimize\",\n namingVars: { format, quality },\n mode: effectiveMode,\n streamingConfig: options?.streamingConfig,\n // Buffered transform (used when mode is \"buffered\" or \"auto\" selects buffered)\n transform: (inputBytes, file) =>\n Effect.map(\n imageService.optimize(inputBytes, { quality, format }),\n (optimizedBytes) => {\n const { newType, newFileName } = buildOutputMetadata(file);\n return {\n bytes: optimizedBytes,\n type: newType,\n fileName: newFileName,\n } as\n | Uint8Array\n | { bytes: Uint8Array; type: string; fileName?: string };\n },\n ),\n // Streaming transform (used when mode is \"streaming\" or \"auto\" selects streaming)\n streamingTransform: imageService.optimizeStream\n ? (inputStream, file) => {\n const optimizeStreamFn = imageService.optimizeStream;\n if (!optimizeStreamFn) {\n throw UploadistaError.fromCode(\"UNKNOWN_ERROR\");\n }\n return Effect.gen(function* () {\n // Use the streaming optimization\n const outputStream = yield* optimizeStreamFn(inputStream, {\n quality,\n format,\n });\n\n const { newType, newFileName } = buildOutputMetadata(file);\n\n return {\n stream: outputStream,\n type: newType,\n fileName: newFileName,\n };\n });\n }\n : undefined,\n });\n });\n}\n","import { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n applyFileNaming,\n buildNamingContext,\n completeNodeExecution,\n createFlowNode,\n type FileNamingConfig,\n ImageAiPlugin,\n NodeType,\n resolveUploadMetadata,\n STORAGE_OUTPUT_TYPE_ID,\n} from \"@uploadista/core/flow\";\nimport { uploadFileSchema } from \"@uploadista/core/types\";\nimport { UploadServer } from \"@uploadista/core/upload\";\nimport { Effect } from \"effect\";\nimport { waitForUrlAvailability } from \"./wait-for-url\";\n\n/**\n * Creates a remove-background node that removes backgrounds from images using AI.\n *\n * @param id - Unique node identifier\n * @param options - Optional configuration\n * @param options.credentialId - Optional credential ID for AI service\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `nobg`)\n *\n * @example\n * ```typescript\n * // With auto-naming: \"photo.jpg\" -> \"photo-nobg.jpg\"\n * const node = yield* createRemoveBackgroundNode(\"remove-bg-1\", {\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createRemoveBackgroundNode(\n id: string,\n { credentialId, keepOutput, naming }: { credentialId?: string; keepOutput?: boolean; naming?: FileNamingConfig } = {},\n) {\n return Effect.gen(function* () {\n const imageAiService = yield* ImageAiPlugin;\n const uploadServer = yield* UploadServer;\n\n return yield* createFlowNode({\n id,\n name: \"Remove Background\",\n description: \"Removes the background from an image\",\n type: NodeType.process,\n nodeTypeId: \"remove-background\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput,\n inputSchema: uploadFileSchema,\n outputSchema: uploadFileSchema,\n // AI service - enable circuit breaker with skip fallback\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n resetTimeout: 60000,\n fallback: { type: \"skip\", passThrough: true },\n },\n run: ({ data: file, flowId, jobId, storageId, clientId }) => {\n return Effect.gen(function* () {\n const flow = {\n flowId,\n nodeId: id,\n jobId,\n };\n\n const fileUrl = file.url;\n\n // Validate input\n if (!fileUrl) {\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause: \"URL is required for remove background operation\",\n }).toEffect();\n }\n\n yield* Effect.logInfo(\n `Removing background for file ${file.id} at URL: ${file.url}`,\n );\n\n // Wait for URL to be available with retry mechanism\n yield* waitForUrlAvailability(fileUrl);\n\n // Build context for ImageAI plugin\n const context = {\n clientId,\n credentialId,\n };\n\n // Remove background with error handling\n const backgroundRemovalResult = yield* imageAiService\n .removeBackground(fileUrl, context)\n .pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logError(\"Failed to remove background\", error);\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause:\n error instanceof Error\n ? error.message\n : \"Failed to remove background from image\",\n }).toEffect();\n }),\n ),\n );\n\n const { outputUrl } = backgroundRemovalResult;\n const { type, fileName, metadata, metadataJson } =\n resolveUploadMetadata(file.metadata);\n\n // Apply file naming if configured\n let outputFileName = fileName;\n if (naming) {\n const namingConfig: FileNamingConfig = {\n ...naming,\n autoSuffix: naming.autoSuffix ?? (() => \"nobg\"),\n };\n const namingContext = buildNamingContext(\n file,\n {\n flowId,\n jobId,\n nodeId: id,\n nodeType: \"remove-background\",\n },\n );\n outputFileName = applyFileNaming(file, namingContext, namingConfig);\n }\n\n yield* Effect.logInfo(`Uploading processed file to storage`);\n\n // Upload the transformed bytes back to the upload server with error handling\n const result = yield* uploadServer\n .uploadFromUrl(\n {\n storageId,\n size: 0,\n type,\n fileName: outputFileName,\n lastModified: 0,\n metadata: metadataJson,\n flow,\n },\n clientId,\n outputUrl,\n )\n .pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logError(\n \"Failed to upload processed file\",\n error,\n );\n return yield* UploadistaError.fromCode(\"FLOW_NODE_ERROR\", {\n cause:\n error instanceof Error\n ? error.message\n : \"Failed to upload processed file\",\n }).toEffect();\n }),\n ),\n );\n\n yield* Effect.logInfo(\n `Successfully removed background for file ${file.id}`,\n );\n\n // Update metadata with new filename if naming was applied\n const updatedMetadata = metadata\n ? {\n ...metadata,\n ...(outputFileName !== fileName && {\n fileName: outputFileName,\n originalName: outputFileName,\n name: outputFileName,\n extension: outputFileName.split(\".\").pop() || metadata.extension,\n }),\n }\n : result.metadata;\n\n return completeNodeExecution(\n updatedMetadata\n ? {\n ...result,\n metadata: updatedMetadata,\n }\n : result,\n );\n });\n },\n });\n });\n}\n","import {\n createTransformNode,\n type FileNamingConfig,\n ImagePlugin,\n type ResizeParams,\n STORAGE_OUTPUT_TYPE_ID,\n type StreamingConfig,\n type TransformMode,\n} from \"@uploadista/core/flow\";\nimport { Effect } from \"effect\";\n\n/**\n * Creates a resize node that resizes images to specified dimensions.\n *\n * Supports both buffered and streaming modes for memory-efficient processing\n * of large images. In streaming mode, the image is read and processed\n * incrementally, reducing peak memory usage.\n *\n * @param id - Unique node identifier\n * @param params - Resize parameters (width, height, fit)\n * @param options - Optional configuration\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `${width}x${height}`)\n * @param options.mode - Transform mode: \"buffered\", \"streaming\", or \"auto\" (default)\n * @param options.streamingConfig - Streaming configuration (file size threshold, chunk size)\n *\n * @example\n * ```typescript\n * // Auto mode (default) - uses streaming for files > 1MB, otherwise buffered\n * const resize = yield* createResizeNode(\"resize-1\", { width: 800, height: 600 }, {\n * naming: { mode: \"auto\" }\n * });\n *\n * // Force buffered mode for small files\n * const resizeBuffered = yield* createResizeNode(\"resize-2\", { width: 800, height: 600 }, {\n * mode: \"buffered\",\n * naming: { mode: \"auto\" }\n * });\n *\n * // Force streaming mode for memory efficiency\n * const resizeStreaming = yield* createResizeNode(\"resize-3\", { width: 800, height: 600 }, {\n * mode: \"streaming\",\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createResizeNode(\n id: string,\n { width, height, fit }: ResizeParams,\n options?: {\n keepOutput?: boolean;\n naming?: FileNamingConfig;\n mode?: TransformMode;\n streamingConfig?: StreamingConfig;\n },\n) {\n return Effect.gen(function* () {\n const imageService = yield* ImagePlugin;\n\n // Determine if streaming is available and requested\n const supportsStreaming = imageService.supportsStreaming ?? false;\n const requestedMode = options?.mode ?? \"auto\";\n\n // If streaming requested but not supported, fall back to buffered\n const effectiveMode: TransformMode =\n requestedMode === \"buffered\"\n ? \"buffered\"\n : supportsStreaming\n ? requestedMode\n : \"buffered\";\n\n // Build naming config with auto suffix for resize\n const namingConfig: FileNamingConfig | undefined = options?.naming\n ? {\n ...options.naming,\n // Provide default auto suffix generator for resize nodes\n autoSuffix:\n options.naming.autoSuffix ??\n ((ctx) => `${ctx.width ?? width}x${ctx.height ?? height}`),\n }\n : undefined;\n\n return yield* createTransformNode({\n id,\n name: \"Resize\",\n description: \"Resizes an image to the specified dimensions\",\n nodeTypeId: \"resize-image\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput: options?.keepOutput,\n naming: namingConfig,\n nodeType: \"resize\",\n namingVars: { width, height },\n mode: effectiveMode,\n streamingConfig: options?.streamingConfig,\n // Buffered transform (used when mode is \"buffered\" or \"auto\" selects buffered)\n transform: (inputBytes) =>\n imageService.resize(inputBytes, { height, width, fit }),\n // Streaming transform (used when mode is \"streaming\" or \"auto\" selects streaming)\n streamingTransform: imageService.resizeStream\n ? (inputStream) =>\n Effect.gen(function* () {\n const resizeStreamFn = imageService.resizeStream;\n if (!resizeStreamFn) {\n throw new Error(\"resizeStream not available\");\n }\n const outputStream = yield* resizeStreamFn(inputStream, {\n width,\n height,\n fit,\n });\n return { stream: outputStream };\n })\n : undefined,\n });\n });\n}\n","import {\n createTransformNode,\n type FileNamingConfig,\n ImagePlugin,\n STORAGE_OUTPUT_TYPE_ID,\n type StreamingConfig,\n type TransformImageParams,\n type TransformMode,\n} from \"@uploadista/core/flow\";\nimport type { UploadistaError } from \"@uploadista/core/errors\";\nimport { Effect, Stream } from \"effect\";\n\n/**\n * Apply a chain of transformations to an image by reducing over the transformations array.\n * Each transformation receives the output of the previous transformation as input.\n *\n * @param imageService - The image plugin service to use for transformations\n * @param inputBytes - The input image bytes\n * @param transformations - Array of transformations to apply in sequence\n * @returns Effect that resolves to the final transformed image bytes\n */\nfunction applyTransformationChain(\n imageService: ReturnType<typeof ImagePlugin.of>,\n inputBytes: Uint8Array,\n transformations: TransformImageParams[\"transformations\"],\n) {\n return Effect.reduce(transformations, inputBytes, (bytes, transformation) =>\n imageService.transform(bytes, transformation),\n );\n}\n\n/**\n * Apply a chain of transformations using streaming where possible.\n * Falls back to buffered processing for transformations that don't support streaming.\n *\n * @param imageService - The image plugin service to use for transformations\n * @param inputStream - The input image as a stream\n * @param transformations - Array of transformations to apply in sequence\n * @returns Effect that resolves to the final transformed image stream\n */\nfunction applyStreamingTransformationChain(\n imageService: ReturnType<typeof ImagePlugin.of>,\n inputStream: Stream.Stream<Uint8Array, UploadistaError>,\n transformations: TransformImageParams[\"transformations\"],\n): Effect.Effect<Stream.Stream<Uint8Array, UploadistaError>, UploadistaError> {\n const transformStreamFn = imageService.transformStream;\n\n if (!transformStreamFn) {\n // If streaming not supported, collect to buffer and use buffered chain\n return Effect.gen(function* () {\n // Collect stream to buffer\n const chunks: Uint8Array[] = [];\n yield* Stream.runForEach(inputStream, (chunk) =>\n Effect.sync(() => {\n chunks.push(chunk);\n }),\n );\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const inputBuffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n inputBuffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n // Apply transformations\n const result = yield* applyTransformationChain(\n imageService,\n inputBuffer,\n transformations,\n );\n return Stream.make(result);\n });\n }\n\n // Apply each transformation in sequence using streaming\n return Effect.reduce(\n transformations,\n inputStream,\n (currentStream, transformation) =>\n Effect.flatMap(\n transformStreamFn(currentStream, transformation),\n (outputStream) => Effect.succeed(outputStream),\n ),\n );\n}\n\n/**\n * Creates a transform image node that applies multiple transformations sequentially.\n *\n * This node enables complex image processing workflows by chaining multiple transformations\n * together. Each transformation is applied to the output of the previous transformation,\n * allowing for powerful image manipulation pipelines.\n *\n * Supports both buffered and streaming modes for memory-efficient processing\n * of large images. In streaming mode, each transformation is applied in sequence\n * using streaming where supported.\n *\n * Supported transformations include:\n * - Basic: resize, blur, rotate, flip\n * - Filters: grayscale, sepia, brightness, contrast\n * - Effects: sharpen\n * - Advanced: watermark, logo, text (streaming not supported for these)\n *\n * Note: Watermark and logo transformations require imagePath to be a valid URL.\n * Images will be fetched from the provided URL during transformation.\n * Streaming mode is not supported for watermark, logo, and text transformations;\n * these will cause fallback to buffered mode.\n *\n * @param id - Unique identifier for this node\n * @param params - Parameters including the transformations array\n * @param options - Optional configuration\n * @param options.keepOutput - Whether to keep output in flow results\n * @param options.naming - File naming configuration (auto suffix: `transformed`)\n * @param options.mode - Transform mode: \"buffered\", \"streaming\", or \"auto\" (default)\n * @param options.streamingConfig - Streaming configuration (file size threshold, chunk size)\n *\n * @example\n * ```typescript\n * // Auto mode (default) - uses streaming for files > 1MB, otherwise buffered\n * const node = yield* createTransformImageNode(\"transform-1\", {\n * transformations: [\n * { type: 'resize', width: 800, height: 600, fit: 'cover' },\n * { type: 'brightness', value: 20 }\n * ]\n * }, {\n * naming: { mode: \"auto\" }\n * });\n *\n * // Force buffered mode for small files\n * const nodeBuffered = yield* createTransformImageNode(\"transform-2\", {\n * transformations: [\n * { type: 'resize', width: 800, height: 600, fit: 'cover' },\n * { type: 'blur', sigma: 5 }\n * ]\n * }, {\n * mode: \"buffered\",\n * naming: { mode: \"auto\" }\n * });\n *\n * // Force streaming mode for memory efficiency\n * const nodeStreaming = yield* createTransformImageNode(\"transform-3\", {\n * transformations: [{ type: 'grayscale' }]\n * }, {\n * mode: \"streaming\",\n * naming: { mode: \"auto\" }\n * });\n * ```\n */\nexport function createTransformImageNode(\n id: string,\n { transformations }: TransformImageParams,\n options?: {\n keepOutput?: boolean;\n naming?: FileNamingConfig;\n mode?: TransformMode;\n streamingConfig?: StreamingConfig;\n },\n) {\n return Effect.gen(function* () {\n const imageService = yield* ImagePlugin;\n\n // Determine if streaming is available and requested\n const supportsStreaming = imageService.supportsStreaming ?? false;\n const requestedMode = options?.mode ?? \"auto\";\n\n // Check if any transformations don't support streaming\n const hasUnsupportedTransformations = transformations.some(\n (t) => t.type === \"watermark\" || t.type === \"logo\" || t.type === \"text\",\n );\n\n // If streaming requested but not supported or unsupported transformations, fall back to buffered\n const effectiveMode: TransformMode =\n requestedMode === \"buffered\"\n ? \"buffered\"\n : supportsStreaming && !hasUnsupportedTransformations\n ? requestedMode\n : \"buffered\";\n\n // Build naming config with auto suffix for transform-image\n const namingConfig: FileNamingConfig | undefined = options?.naming\n ? {\n ...options.naming,\n autoSuffix: options.naming.autoSuffix ?? (() => \"transformed\"),\n }\n : undefined;\n\n return yield* createTransformNode({\n id,\n name: \"Transform Image\",\n description: `Apply ${transformations.length} transformation${transformations.length === 1 ? \"\" : \"s\"} to the image`,\n nodeTypeId: \"transform-image\",\n outputTypeId: STORAGE_OUTPUT_TYPE_ID,\n keepOutput: options?.keepOutput,\n naming: namingConfig,\n nodeType: \"transform-image\",\n mode: effectiveMode,\n streamingConfig: options?.streamingConfig,\n // Buffered transform (used when mode is \"buffered\" or \"auto\" selects buffered)\n transform: (inputBytes) =>\n applyTransformationChain(imageService, inputBytes, transformations),\n // Streaming transform (used when mode is \"streaming\" or \"auto\" selects streaming)\n streamingTransform:\n supportsStreaming && !hasUnsupportedTransformations\n ? (inputStream) =>\n Effect.gen(function* () {\n const outputStream =\n yield* applyStreamingTransformationChain(\n imageService,\n inputStream,\n transformations,\n );\n return { stream: outputStream };\n })\n : undefined,\n });\n });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uploadista/flow-images-nodes",
3
3
  "type": "module",
4
- "version": "0.0.18",
4
+ "version": "0.0.20-beta.1",
5
5
  "description": "Image processing nodes for Uploadista Flow",
6
6
  "license": "MIT",
7
7
  "author": "Uploadista",
@@ -14,7 +14,7 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "@uploadista/core": "0.0.18"
17
+ "@uploadista/core": "0.0.20-beta.1"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "effect": "^3.0.0",
@@ -24,10 +24,10 @@
24
24
  "@effect/vitest": "0.27.0",
25
25
  "@types/node": "24.10.1",
26
26
  "effect": "3.19.8",
27
- "tsdown": "0.16.8",
27
+ "tsdown": "0.17.0",
28
28
  "vitest": "4.0.15",
29
29
  "zod": "4.1.13",
30
- "@uploadista/typescript-config": "0.0.18"
30
+ "@uploadista/typescript-config": "0.0.20-beta.1"
31
31
  },
32
32
  "scripts": {
33
33
  "build": "tsdown",