@uploadista/core 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-check.log +231 -0
- package/.turbo/turbo-format.log +5 -0
- package/LICENSE +21 -0
- package/README.md +1120 -0
- package/dist/chunk-CUT6urMc.cjs +1 -0
- package/dist/debounce-C2SeqcxD.js +2 -0
- package/dist/debounce-C2SeqcxD.js.map +1 -0
- package/dist/debounce-LZK7yS7Z.cjs +1 -0
- package/dist/errors/index.cjs +1 -0
- package/dist/errors/index.d.cts +3 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/uploadista-error.d.ts +209 -0
- package/dist/errors/uploadista-error.d.ts.map +1 -0
- package/dist/errors/uploadista-error.js +322 -0
- package/dist/errors-8i_aMxOE.js +1 -0
- package/dist/errors-CRm1FHHT.cjs +0 -0
- package/dist/flow/edge.d.ts +47 -0
- package/dist/flow/edge.d.ts.map +1 -0
- package/dist/flow/edge.js +40 -0
- package/dist/flow/event.d.ts +206 -0
- package/dist/flow/event.d.ts.map +1 -0
- package/dist/flow/event.js +53 -0
- package/dist/flow/flow-server.d.ts +223 -0
- package/dist/flow/flow-server.d.ts.map +1 -0
- package/dist/flow/flow-server.js +614 -0
- package/dist/flow/flow.d.ts +238 -0
- package/dist/flow/flow.d.ts.map +1 -0
- package/dist/flow/flow.js +629 -0
- package/dist/flow/index.cjs +1 -0
- package/dist/flow/index.d.cts +6 -0
- package/dist/flow/index.d.ts +24 -0
- package/dist/flow/index.d.ts.map +1 -0
- package/dist/flow/index.js +24 -0
- package/dist/flow/node.d.ts +136 -0
- package/dist/flow/node.d.ts.map +1 -0
- package/dist/flow/node.js +153 -0
- package/dist/flow/nodes/index.d.ts +8 -0
- package/dist/flow/nodes/index.d.ts.map +1 -0
- package/dist/flow/nodes/index.js +7 -0
- package/dist/flow/nodes/input-node.d.ts +78 -0
- package/dist/flow/nodes/input-node.d.ts.map +1 -0
- package/dist/flow/nodes/input-node.js +233 -0
- package/dist/flow/nodes/storage-node.d.ts +67 -0
- package/dist/flow/nodes/storage-node.d.ts.map +1 -0
- package/dist/flow/nodes/storage-node.js +94 -0
- package/dist/flow/nodes/streaming-input-node.d.ts +69 -0
- package/dist/flow/nodes/streaming-input-node.d.ts.map +1 -0
- package/dist/flow/nodes/streaming-input-node.js +156 -0
- package/dist/flow/nodes/transform-node.d.ts +85 -0
- package/dist/flow/nodes/transform-node.d.ts.map +1 -0
- package/dist/flow/nodes/transform-node.js +107 -0
- package/dist/flow/parallel-scheduler.d.ts +175 -0
- package/dist/flow/parallel-scheduler.d.ts.map +1 -0
- package/dist/flow/parallel-scheduler.js +193 -0
- package/dist/flow/plugins/credential-provider.d.ts +47 -0
- package/dist/flow/plugins/credential-provider.d.ts.map +1 -0
- package/dist/flow/plugins/credential-provider.js +24 -0
- package/dist/flow/plugins/image-ai-plugin.d.ts +61 -0
- package/dist/flow/plugins/image-ai-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/image-ai-plugin.js +21 -0
- package/dist/flow/plugins/image-plugin.d.ts +52 -0
- package/dist/flow/plugins/image-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/image-plugin.js +22 -0
- package/dist/flow/plugins/types/describe-image-node.d.ts +16 -0
- package/dist/flow/plugins/types/describe-image-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/describe-image-node.js +9 -0
- package/dist/flow/plugins/types/index.d.ts +9 -0
- package/dist/flow/plugins/types/index.d.ts.map +1 -0
- package/dist/flow/plugins/types/index.js +8 -0
- package/dist/flow/plugins/types/optimize-node.d.ts +20 -0
- package/dist/flow/plugins/types/optimize-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/optimize-node.js +11 -0
- package/dist/flow/plugins/types/remove-background-node.d.ts +16 -0
- package/dist/flow/plugins/types/remove-background-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/remove-background-node.js +9 -0
- package/dist/flow/plugins/types/resize-node.d.ts +21 -0
- package/dist/flow/plugins/types/resize-node.d.ts.map +1 -0
- package/dist/flow/plugins/types/resize-node.js +16 -0
- package/dist/flow/plugins/zip-plugin.d.ts +62 -0
- package/dist/flow/plugins/zip-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/zip-plugin.js +21 -0
- package/dist/flow/typed-flow.d.ts +90 -0
- package/dist/flow/typed-flow.d.ts.map +1 -0
- package/dist/flow/typed-flow.js +59 -0
- package/dist/flow/types/flow-file.d.ts +45 -0
- package/dist/flow/types/flow-file.d.ts.map +1 -0
- package/dist/flow/types/flow-file.js +27 -0
- package/dist/flow/types/flow-job.d.ts +118 -0
- package/dist/flow/types/flow-job.d.ts.map +1 -0
- package/dist/flow/types/flow-job.js +11 -0
- package/dist/flow/types/flow-types.d.ts +321 -0
- package/dist/flow/types/flow-types.d.ts.map +1 -0
- package/dist/flow/types/flow-types.js +52 -0
- package/dist/flow/types/index.d.ts +4 -0
- package/dist/flow/types/index.d.ts.map +1 -0
- package/dist/flow/types/index.js +3 -0
- package/dist/flow/types/run-args.d.ts +38 -0
- package/dist/flow/types/run-args.d.ts.map +1 -0
- package/dist/flow/types/run-args.js +30 -0
- package/dist/flow/types/type-validator.d.ts +26 -0
- package/dist/flow/types/type-validator.d.ts.map +1 -0
- package/dist/flow/types/type-validator.js +134 -0
- package/dist/flow/utils/resolve-upload-metadata.d.ts +11 -0
- package/dist/flow/utils/resolve-upload-metadata.d.ts.map +1 -0
- package/dist/flow/utils/resolve-upload-metadata.js +28 -0
- package/dist/flow-2zXnEiWL.cjs +1 -0
- package/dist/flow-CRaKy7Vj.js +2 -0
- package/dist/flow-CRaKy7Vj.js.map +1 -0
- package/dist/generate-id-Dm-Vboxq.d.ts +34 -0
- package/dist/generate-id-Dm-Vboxq.d.ts.map +1 -0
- package/dist/generate-id-LjJRLD6N.d.cts +34 -0
- package/dist/generate-id-LjJRLD6N.d.cts.map +1 -0
- package/dist/generate-id-xHp_Z7Cl.cjs +1 -0
- package/dist/generate-id-yohS1ZDk.js +2 -0
- package/dist/generate-id-yohS1ZDk.js.map +1 -0
- package/dist/index-BO8GZlbD.d.cts +1040 -0
- package/dist/index-BO8GZlbD.d.cts.map +1 -0
- package/dist/index-BoGG5KAY.d.ts +1 -0
- package/dist/index-BtBZHVmz.d.cts +1 -0
- package/dist/index-D-CoVpkZ.d.ts +1004 -0
- package/dist/index-D-CoVpkZ.d.ts.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/logger/logger.cjs +1 -0
- package/dist/logger/logger.d.cts +8 -0
- package/dist/logger/logger.d.cts.map +1 -0
- package/dist/logger/logger.d.ts +5 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +10 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/semaphore-0ZwjVpyF.js +2 -0
- package/dist/semaphore-0ZwjVpyF.js.map +1 -0
- package/dist/semaphore-BHprIjFI.d.cts +37 -0
- package/dist/semaphore-BHprIjFI.d.cts.map +1 -0
- package/dist/semaphore-DThupBkc.d.ts +37 -0
- package/dist/semaphore-DThupBkc.d.ts.map +1 -0
- package/dist/semaphore-DVrONiAV.cjs +1 -0
- package/dist/stream-limiter-CoWKv39w.js +2 -0
- package/dist/stream-limiter-CoWKv39w.js.map +1 -0
- package/dist/stream-limiter-JgOwmkMa.cjs +1 -0
- package/dist/streams/multi-stream.cjs +1 -0
- package/dist/streams/multi-stream.d.cts +91 -0
- package/dist/streams/multi-stream.d.cts.map +1 -0
- package/dist/streams/multi-stream.d.ts +86 -0
- package/dist/streams/multi-stream.d.ts.map +1 -0
- package/dist/streams/multi-stream.js +149 -0
- package/dist/streams/multi-stream.js.map +1 -0
- package/dist/streams/stream-limiter.cjs +1 -0
- package/dist/streams/stream-limiter.d.cts +36 -0
- package/dist/streams/stream-limiter.d.cts.map +1 -0
- package/dist/streams/stream-limiter.d.ts +27 -0
- package/dist/streams/stream-limiter.d.ts.map +1 -0
- package/dist/streams/stream-limiter.js +49 -0
- package/dist/streams/stream-splitter.cjs +1 -0
- package/dist/streams/stream-splitter.d.cts +68 -0
- package/dist/streams/stream-splitter.d.cts.map +1 -0
- package/dist/streams/stream-splitter.d.ts +51 -0
- package/dist/streams/stream-splitter.d.ts.map +1 -0
- package/dist/streams/stream-splitter.js +175 -0
- package/dist/streams/stream-splitter.js.map +1 -0
- package/dist/types/data-store-registry.d.ts +13 -0
- package/dist/types/data-store-registry.d.ts.map +1 -0
- package/dist/types/data-store-registry.js +4 -0
- package/dist/types/data-store.d.ts +316 -0
- package/dist/types/data-store.d.ts.map +1 -0
- package/dist/types/data-store.js +157 -0
- package/dist/types/event-broadcaster.d.ts +28 -0
- package/dist/types/event-broadcaster.d.ts.map +1 -0
- package/dist/types/event-broadcaster.js +6 -0
- package/dist/types/event-emitter.d.ts +378 -0
- package/dist/types/event-emitter.d.ts.map +1 -0
- package/dist/types/event-emitter.js +223 -0
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.d.cts +6 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +9 -0
- package/dist/types/input-file.d.ts +104 -0
- package/dist/types/input-file.d.ts.map +1 -0
- package/dist/types/input-file.js +27 -0
- package/dist/types/kv-store.d.ts +281 -0
- package/dist/types/kv-store.d.ts.map +1 -0
- package/dist/types/kv-store.js +234 -0
- package/dist/types/middleware.d.ts +17 -0
- package/dist/types/middleware.d.ts.map +1 -0
- package/dist/types/middleware.js +21 -0
- package/dist/types/upload-event.d.ts +105 -0
- package/dist/types/upload-event.d.ts.map +1 -0
- package/dist/types/upload-event.js +71 -0
- package/dist/types/upload-file.d.ts +136 -0
- package/dist/types/upload-file.d.ts.map +1 -0
- package/dist/types/upload-file.js +34 -0
- package/dist/types/websocket.d.ts +144 -0
- package/dist/types/websocket.d.ts.map +1 -0
- package/dist/types/websocket.js +40 -0
- package/dist/types-BT-cvi7T.cjs +1 -0
- package/dist/types-DhU2j-XF.js +2 -0
- package/dist/types-DhU2j-XF.js.map +1 -0
- package/dist/upload/convert-to-stream.d.ts +38 -0
- package/dist/upload/convert-to-stream.d.ts.map +1 -0
- package/dist/upload/convert-to-stream.js +43 -0
- package/dist/upload/convert-upload-to-flow-file.d.ts +14 -0
- package/dist/upload/convert-upload-to-flow-file.d.ts.map +1 -0
- package/dist/upload/convert-upload-to-flow-file.js +21 -0
- package/dist/upload/create-upload.d.ts +68 -0
- package/dist/upload/create-upload.d.ts.map +1 -0
- package/dist/upload/create-upload.js +157 -0
- package/dist/upload/index.cjs +1 -0
- package/dist/upload/index.d.cts +6 -0
- package/dist/upload/index.d.ts +4 -0
- package/dist/upload/index.d.ts.map +1 -0
- package/dist/upload/index.js +3 -0
- package/dist/upload/mime.d.ts +24 -0
- package/dist/upload/mime.d.ts.map +1 -0
- package/dist/upload/mime.js +351 -0
- package/dist/upload/upload-chunk.d.ts +58 -0
- package/dist/upload/upload-chunk.d.ts.map +1 -0
- package/dist/upload/upload-chunk.js +277 -0
- package/dist/upload/upload-server.d.ts +221 -0
- package/dist/upload/upload-server.d.ts.map +1 -0
- package/dist/upload/upload-server.js +181 -0
- package/dist/upload/upload-strategy-negotiator.d.ts +148 -0
- package/dist/upload/upload-strategy-negotiator.d.ts.map +1 -0
- package/dist/upload/upload-strategy-negotiator.js +217 -0
- package/dist/upload/upload-url.d.ts +68 -0
- package/dist/upload/upload-url.d.ts.map +1 -0
- package/dist/upload/upload-url.js +142 -0
- package/dist/upload/write-to-store.d.ts +77 -0
- package/dist/upload/write-to-store.d.ts.map +1 -0
- package/dist/upload/write-to-store.js +147 -0
- package/dist/upload-DLuICjpP.cjs +1 -0
- package/dist/upload-DaXO34dE.js +2 -0
- package/dist/upload-DaXO34dE.js.map +1 -0
- package/dist/uploadista-error-BB-Wdiz9.cjs +22 -0
- package/dist/uploadista-error-BVsVxqvz.js +23 -0
- package/dist/uploadista-error-BVsVxqvz.js.map +1 -0
- package/dist/uploadista-error-CwxYs4EB.d.ts +52 -0
- package/dist/uploadista-error-CwxYs4EB.d.ts.map +1 -0
- package/dist/uploadista-error-kKlhLRhY.d.cts +52 -0
- package/dist/uploadista-error-kKlhLRhY.d.cts.map +1 -0
- package/dist/utils/checksum.d.ts +22 -0
- package/dist/utils/checksum.d.ts.map +1 -0
- package/dist/utils/checksum.js +49 -0
- package/dist/utils/debounce.cjs +1 -0
- package/dist/utils/debounce.d.cts +38 -0
- package/dist/utils/debounce.d.cts.map +1 -0
- package/dist/utils/debounce.d.ts +36 -0
- package/dist/utils/debounce.d.ts.map +1 -0
- package/dist/utils/debounce.js +73 -0
- package/dist/utils/generate-id.cjs +1 -0
- package/dist/utils/generate-id.d.cts +2 -0
- package/dist/utils/generate-id.d.ts +32 -0
- package/dist/utils/generate-id.d.ts.map +1 -0
- package/dist/utils/generate-id.js +23 -0
- package/dist/utils/md5.cjs +1 -0
- package/dist/utils/md5.d.cts +73 -0
- package/dist/utils/md5.d.cts.map +1 -0
- package/dist/utils/md5.d.ts +71 -0
- package/dist/utils/md5.d.ts.map +1 -0
- package/dist/utils/md5.js +417 -0
- package/dist/utils/md5.js.map +1 -0
- package/dist/utils/once.cjs +1 -0
- package/dist/utils/once.d.cts +25 -0
- package/dist/utils/once.d.cts.map +1 -0
- package/dist/utils/once.d.ts +21 -0
- package/dist/utils/once.d.ts.map +1 -0
- package/dist/utils/once.js +54 -0
- package/dist/utils/once.js.map +1 -0
- package/dist/utils/semaphore.cjs +1 -0
- package/dist/utils/semaphore.d.cts +3 -0
- package/dist/utils/semaphore.d.ts +78 -0
- package/dist/utils/semaphore.d.ts.map +1 -0
- package/dist/utils/semaphore.js +134 -0
- package/dist/utils/throttle.cjs +1 -0
- package/dist/utils/throttle.d.cts +24 -0
- package/dist/utils/throttle.d.cts.map +1 -0
- package/dist/utils/throttle.d.ts +18 -0
- package/dist/utils/throttle.d.ts.map +1 -0
- package/dist/utils/throttle.js +20 -0
- package/dist/utils/throttle.js.map +1 -0
- package/docs/PARALLEL_EXECUTION.md +206 -0
- package/docs/PARALLEL_EXECUTION_QUICKSTART.md +142 -0
- package/docs/PARALLEL_EXECUTION_REFACTOR.md +184 -0
- package/package.json +80 -0
- package/src/errors/__tests__/uploadista-error.test.ts +251 -0
- package/src/errors/index.ts +2 -0
- package/src/errors/uploadista-error.ts +394 -0
- package/src/flow/README.md +352 -0
- package/src/flow/edge.test.ts +146 -0
- package/src/flow/edge.ts +60 -0
- package/src/flow/event.ts +229 -0
- package/src/flow/flow-server.ts +1089 -0
- package/src/flow/flow.ts +1050 -0
- package/src/flow/index.ts +28 -0
- package/src/flow/node.ts +249 -0
- package/src/flow/nodes/index.ts +8 -0
- package/src/flow/nodes/input-node.ts +296 -0
- package/src/flow/nodes/storage-node.ts +128 -0
- package/src/flow/nodes/transform-node.ts +154 -0
- package/src/flow/parallel-scheduler.ts +259 -0
- package/src/flow/plugins/credential-provider.ts +48 -0
- package/src/flow/plugins/image-ai-plugin.ts +66 -0
- package/src/flow/plugins/image-plugin.ts +60 -0
- package/src/flow/plugins/types/describe-image-node.ts +16 -0
- package/src/flow/plugins/types/index.ts +9 -0
- package/src/flow/plugins/types/optimize-node.ts +18 -0
- package/src/flow/plugins/types/remove-background-node.ts +18 -0
- package/src/flow/plugins/types/resize-node.ts +26 -0
- package/src/flow/plugins/zip-plugin.ts +69 -0
- package/src/flow/typed-flow.ts +279 -0
- package/src/flow/types/flow-file.ts +51 -0
- package/src/flow/types/flow-job.ts +138 -0
- package/src/flow/types/flow-types.ts +353 -0
- package/src/flow/types/index.ts +6 -0
- package/src/flow/types/run-args.ts +40 -0
- package/src/flow/types/type-validator.ts +204 -0
- package/src/flow/utils/resolve-upload-metadata.ts +48 -0
- package/src/index.ts +5 -0
- package/src/logger/logger.ts +14 -0
- package/src/streams/stream-limiter.test.ts +150 -0
- package/src/streams/stream-limiter.ts +75 -0
- package/src/types/data-store.ts +427 -0
- package/src/types/event-broadcaster.ts +39 -0
- package/src/types/event-emitter.ts +349 -0
- package/src/types/index.ts +9 -0
- package/src/types/input-file.ts +107 -0
- package/src/types/kv-store.ts +375 -0
- package/src/types/middleware.ts +54 -0
- package/src/types/upload-event.ts +75 -0
- package/src/types/upload-file.ts +139 -0
- package/src/types/websocket.ts +65 -0
- package/src/upload/convert-to-stream.ts +48 -0
- package/src/upload/create-upload.ts +214 -0
- package/src/upload/index.ts +3 -0
- package/src/upload/mime.ts +436 -0
- package/src/upload/upload-chunk.ts +364 -0
- package/src/upload/upload-server.ts +390 -0
- package/src/upload/upload-strategy-negotiator.ts +316 -0
- package/src/upload/upload-url.ts +173 -0
- package/src/upload/write-to-store.ts +211 -0
- package/src/utils/checksum.ts +61 -0
- package/src/utils/debounce.test.ts +126 -0
- package/src/utils/debounce.ts +89 -0
- package/src/utils/generate-id.ts +35 -0
- package/src/utils/md5.ts +475 -0
- package/src/utils/once.test.ts +83 -0
- package/src/utils/once.ts +63 -0
- package/src/utils/throttle.test.ts +101 -0
- package/src/utils/throttle.ts +29 -0
- package/tsconfig.json +20 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.ts +25 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { UploadistaError } from "../../errors";
|
|
4
|
+
import { type UploadFile, uploadFileSchema } from "../../types";
|
|
5
|
+
import { UploadServer } from "../../upload";
|
|
6
|
+
import { createFlowNode, NodeType } from "../node";
|
|
7
|
+
import { completeNodeExecution } from "../types";
|
|
8
|
+
import { resolveUploadMetadata } from "../utils/resolve-upload-metadata";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Schema for storage node parameters.
|
|
12
|
+
* Currently empty but can be extended for storage-specific configuration.
|
|
13
|
+
*/
|
|
14
|
+
export const storageParamsSchema = z.object({});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Parameters for the storage node.
|
|
18
|
+
* Currently no parameters are required, but the schema is available for future extensions.
|
|
19
|
+
*/
|
|
20
|
+
export type StorageParams = z.infer<typeof storageParamsSchema>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Creates a storage node for storing files in the specified storage.
|
|
24
|
+
*
|
|
25
|
+
* The storage node handles the process of:
|
|
26
|
+
* 1. Reading the input file from the upload server
|
|
27
|
+
* 2. Checking if the file is already in the target storage
|
|
28
|
+
* 3. If not, transferring the file to the target storage
|
|
29
|
+
* 4. Applying optional post-processing
|
|
30
|
+
* 5. Returning the final stored file
|
|
31
|
+
*
|
|
32
|
+
* @param id - Unique identifier for the node
|
|
33
|
+
* @param postProcessFile - Optional function to process the file after storage
|
|
34
|
+
* @returns An Effect that creates a flow node configured for file storage
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Create basic storage node
|
|
39
|
+
* const storageNode = yield* createStorageNode("store-file");
|
|
40
|
+
*
|
|
41
|
+
* // Create storage node with post-processing
|
|
42
|
+
* const storageWithProcessing = yield* createStorageNode("store-and-process", (file) => {
|
|
43
|
+
* return Effect.succeed({
|
|
44
|
+
* ...file,
|
|
45
|
+
* metadata: { ...file.metadata, processed: true }
|
|
46
|
+
* });
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function createStorageNode(
|
|
51
|
+
id: string,
|
|
52
|
+
postProcessFile: (file: UploadFile) => Effect.Effect<UploadFile> = (file) =>
|
|
53
|
+
Effect.succeed(file)
|
|
54
|
+
) {
|
|
55
|
+
return Effect.gen(function* () {
|
|
56
|
+
const uploadServer = yield* UploadServer;
|
|
57
|
+
return yield* createFlowNode({
|
|
58
|
+
id,
|
|
59
|
+
name: "Storage",
|
|
60
|
+
description: "Stores a file in the storage",
|
|
61
|
+
type: NodeType.output,
|
|
62
|
+
inputSchema: uploadFileSchema,
|
|
63
|
+
outputSchema: uploadFileSchema,
|
|
64
|
+
run: ({ data: file, storageId, flowId, jobId, clientId }) => {
|
|
65
|
+
return Effect.gen(function* () {
|
|
66
|
+
const { type, fileName, metadata, metadataJson } =
|
|
67
|
+
resolveUploadMetadata(file.metadata);
|
|
68
|
+
const flow = {
|
|
69
|
+
flowId,
|
|
70
|
+
nodeId: id,
|
|
71
|
+
jobId,
|
|
72
|
+
};
|
|
73
|
+
const normalizedFile = metadata ? { ...file, metadata } : file;
|
|
74
|
+
|
|
75
|
+
const upload = yield* uploadServer.getUpload(file.id);
|
|
76
|
+
if (!upload.id) {
|
|
77
|
+
return yield* Effect.fail(
|
|
78
|
+
UploadistaError.fromCode(
|
|
79
|
+
"FILE_READ_ERROR",
|
|
80
|
+
new Error("Upload Key is undefined")
|
|
81
|
+
)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
// If the upload is already in the correct storage, return the file, just update the flow
|
|
85
|
+
if (upload.storage.id === storageId) {
|
|
86
|
+
return completeNodeExecution(
|
|
87
|
+
yield* postProcessFile({ ...normalizedFile, flow })
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const inputBytes = yield* uploadServer.read(file.id, clientId);
|
|
92
|
+
const stream = new ReadableStream({
|
|
93
|
+
start(controller) {
|
|
94
|
+
controller.enqueue(inputBytes);
|
|
95
|
+
controller.close();
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const uploadResult = yield* uploadServer.upload(
|
|
100
|
+
{
|
|
101
|
+
storageId,
|
|
102
|
+
size: inputBytes.byteLength,
|
|
103
|
+
type,
|
|
104
|
+
fileName,
|
|
105
|
+
lastModified: 0,
|
|
106
|
+
metadata: metadataJson,
|
|
107
|
+
flow,
|
|
108
|
+
},
|
|
109
|
+
clientId,
|
|
110
|
+
stream
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const resolvedUploadResult = resolveUploadMetadata(
|
|
114
|
+
uploadResult.metadata
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const postProcessed = yield* postProcessFile(
|
|
118
|
+
resolvedUploadResult.metadata
|
|
119
|
+
? { ...uploadResult, metadata: resolvedUploadResult.metadata }
|
|
120
|
+
: uploadResult
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
return completeNodeExecution(postProcessed);
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { UploadistaError } from "../../errors";
|
|
3
|
+
import type { UploadFile } from "../../types";
|
|
4
|
+
import { uploadFileSchema } from "../../types";
|
|
5
|
+
import { UploadServer } from "../../upload";
|
|
6
|
+
import { createFlowNode, NodeType } from "../node";
|
|
7
|
+
import { completeNodeExecution } from "../types";
|
|
8
|
+
import { resolveUploadMetadata } from "../utils/resolve-upload-metadata";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Configuration object for creating a transform node.
|
|
12
|
+
*/
|
|
13
|
+
export interface TransformNodeConfig {
|
|
14
|
+
/** Unique identifier for the node */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Human-readable name for the node */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Description of what the node does */
|
|
19
|
+
description: string;
|
|
20
|
+
/** Function that transforms file bytes */
|
|
21
|
+
transform: (
|
|
22
|
+
bytes: Uint8Array,
|
|
23
|
+
file: UploadFile
|
|
24
|
+
) => Effect.Effect<
|
|
25
|
+
Uint8Array | { bytes: Uint8Array; type?: string; fileName?: string },
|
|
26
|
+
UploadistaError
|
|
27
|
+
>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a transform node that handles the common pattern of:
|
|
32
|
+
* 1. Reading bytes from an UploadFile
|
|
33
|
+
* 2. Transforming the bytes
|
|
34
|
+
* 3. Uploading the result as a new UploadFile
|
|
35
|
+
*
|
|
36
|
+
* This simplifies nodes that just need to transform file bytes without
|
|
37
|
+
* worrying about upload server interactions.
|
|
38
|
+
*
|
|
39
|
+
* @param config - Configuration object for the transform node
|
|
40
|
+
* @returns An Effect that creates a flow node configured for file transformation
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // Create an image resize transform node
|
|
45
|
+
* const resizeNode = yield* createTransformNode({
|
|
46
|
+
* id: "resize-image",
|
|
47
|
+
* name: "Resize Image",
|
|
48
|
+
* description: "Resizes images to specified dimensions",
|
|
49
|
+
* transform: (bytes, file) => {
|
|
50
|
+
* // Your transformation logic here
|
|
51
|
+
* return Effect.succeed(transformedBytes);
|
|
52
|
+
* }
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Create a transform node that changes file metadata
|
|
56
|
+
* const metadataTransformNode = yield* createTransformNode({
|
|
57
|
+
* id: "add-metadata",
|
|
58
|
+
* name: "Add Metadata",
|
|
59
|
+
* description: "Adds custom metadata to files",
|
|
60
|
+
* transform: (bytes, file) => {
|
|
61
|
+
* return Effect.succeed({
|
|
62
|
+
* bytes,
|
|
63
|
+
* type: "application/custom",
|
|
64
|
+
* fileName: `processed-${file.fileName}`
|
|
65
|
+
* });
|
|
66
|
+
* }
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function createTransformNode({
|
|
71
|
+
id,
|
|
72
|
+
name,
|
|
73
|
+
description,
|
|
74
|
+
transform,
|
|
75
|
+
}: TransformNodeConfig) {
|
|
76
|
+
return Effect.gen(function* () {
|
|
77
|
+
const uploadServer = yield* UploadServer;
|
|
78
|
+
|
|
79
|
+
return yield* createFlowNode({
|
|
80
|
+
id,
|
|
81
|
+
name,
|
|
82
|
+
description,
|
|
83
|
+
type: NodeType.process,
|
|
84
|
+
inputSchema: uploadFileSchema,
|
|
85
|
+
outputSchema: uploadFileSchema,
|
|
86
|
+
run: ({ data: file, storageId, flowId, jobId, clientId }) => {
|
|
87
|
+
return Effect.gen(function* () {
|
|
88
|
+
const flow = {
|
|
89
|
+
flowId,
|
|
90
|
+
nodeId: id,
|
|
91
|
+
jobId,
|
|
92
|
+
};
|
|
93
|
+
// Read input bytes from upload server
|
|
94
|
+
const inputBytes = yield* uploadServer.read(file.id, clientId);
|
|
95
|
+
|
|
96
|
+
// Transform the bytes using the provided function
|
|
97
|
+
const transformResult = yield* transform(inputBytes, file);
|
|
98
|
+
|
|
99
|
+
// Handle both simple Uint8Array and object with metadata
|
|
100
|
+
const outputBytes =
|
|
101
|
+
transformResult instanceof Uint8Array
|
|
102
|
+
? transformResult
|
|
103
|
+
: transformResult.bytes;
|
|
104
|
+
|
|
105
|
+
const outputType =
|
|
106
|
+
transformResult instanceof Uint8Array
|
|
107
|
+
? undefined
|
|
108
|
+
: transformResult.type;
|
|
109
|
+
|
|
110
|
+
const outputFileName =
|
|
111
|
+
transformResult instanceof Uint8Array
|
|
112
|
+
? undefined
|
|
113
|
+
: transformResult.fileName;
|
|
114
|
+
|
|
115
|
+
// Create a stream from the output bytes
|
|
116
|
+
const stream = new ReadableStream({
|
|
117
|
+
start(controller) {
|
|
118
|
+
controller.enqueue(outputBytes);
|
|
119
|
+
controller.close();
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const { type, fileName, metadata, metadataJson } =
|
|
124
|
+
resolveUploadMetadata(file.metadata);
|
|
125
|
+
|
|
126
|
+
// Upload the transformed bytes back to the upload server
|
|
127
|
+
// Use output metadata if provided, otherwise fall back to original
|
|
128
|
+
const result = yield* uploadServer.upload(
|
|
129
|
+
{
|
|
130
|
+
storageId,
|
|
131
|
+
size: outputBytes.byteLength,
|
|
132
|
+
type: outputType ?? type,
|
|
133
|
+
fileName: outputFileName ?? fileName,
|
|
134
|
+
lastModified: 0,
|
|
135
|
+
metadata: metadataJson,
|
|
136
|
+
flow,
|
|
137
|
+
},
|
|
138
|
+
clientId,
|
|
139
|
+
stream
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
return completeNodeExecution(
|
|
143
|
+
metadata
|
|
144
|
+
? {
|
|
145
|
+
...result,
|
|
146
|
+
metadata,
|
|
147
|
+
}
|
|
148
|
+
: result
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parallel execution scheduler for flow nodes.
|
|
3
|
+
*
|
|
4
|
+
* The ParallelScheduler analyzes flow dependencies and groups nodes into execution
|
|
5
|
+
* levels where nodes at the same level can run in parallel. It manages concurrency
|
|
6
|
+
* using Effect's built-in concurrency control to prevent resource exhaustion.
|
|
7
|
+
*
|
|
8
|
+
* @module flow/parallel-scheduler
|
|
9
|
+
* @see {@link ParallelScheduler} for the main scheduler class
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* This scheduler groups nodes by execution level (respecting dependencies) and executes
|
|
13
|
+
* each level in parallel with controlled concurrency. Levels are executed sequentially
|
|
14
|
+
* to ensure dependencies are satisfied before dependent nodes execute.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const scheduler = new ParallelScheduler({ maxConcurrency: 4 });
|
|
19
|
+
*
|
|
20
|
+
* // Group nodes by execution level
|
|
21
|
+
* const levels = scheduler.groupNodesByExecutionLevel(nodes, edges);
|
|
22
|
+
*
|
|
23
|
+
* // Execute nodes in a level with Effect
|
|
24
|
+
* const results = yield* scheduler.executeNodesInParallel([
|
|
25
|
+
* () => executeNode("node1"),
|
|
26
|
+
* () => executeNode("node2"),
|
|
27
|
+
* () => executeNode("node3")
|
|
28
|
+
* ]);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { Effect } from "effect";
|
|
33
|
+
import type { FlowNode } from "./types/flow-types";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Represents a level in the execution hierarchy where all nodes can run in parallel.
|
|
37
|
+
*
|
|
38
|
+
* @property level - The execution level (0 = first to execute, higher = later)
|
|
39
|
+
* @property nodes - Array of node IDs that can execute in parallel at this level
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```
|
|
43
|
+
* Level 0: [input_node] (no dependencies)
|
|
44
|
+
* Level 1: [resize, optimize] (all depend on level 0)
|
|
45
|
+
* Level 2: [storage] (depends on level 1)
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export interface ExecutionLevel {
|
|
49
|
+
level: number;
|
|
50
|
+
nodes: string[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Configuration options for the ParallelScheduler.
|
|
55
|
+
*
|
|
56
|
+
* @property maxConcurrency - Maximum number of nodes to execute in parallel (default: 4)
|
|
57
|
+
* Controls how many nodes run simultaneously within a level
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const scheduler = new ParallelScheduler({ maxConcurrency: 8 });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export interface ParallelSchedulerConfig {
|
|
65
|
+
maxConcurrency?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Scheduler for executing flow nodes in parallel while respecting dependencies.
|
|
70
|
+
*
|
|
71
|
+
* The scheduler performs topological sorting to identify nodes that can run
|
|
72
|
+
* concurrently, groups them into execution levels, and provides methods to
|
|
73
|
+
* execute them with controlled concurrency using Effect.
|
|
74
|
+
*
|
|
75
|
+
* Key responsibilities:
|
|
76
|
+
* - Analyze flow dependencies and detect cycles
|
|
77
|
+
* - Group nodes into parallel execution levels
|
|
78
|
+
* - Execute levels in parallel with concurrency limits
|
|
79
|
+
* - Provide utilities to check parallel execution feasibility
|
|
80
|
+
*/
|
|
81
|
+
export class ParallelScheduler {
|
|
82
|
+
private maxConcurrency: number;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Creates a new ParallelScheduler instance.
|
|
86
|
+
*
|
|
87
|
+
* @param config - Configuration for the scheduler
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const scheduler = new ParallelScheduler({ maxConcurrency: 4 });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
constructor(config: ParallelSchedulerConfig = {}) {
|
|
94
|
+
this.maxConcurrency = config.maxConcurrency ?? 4;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Groups nodes into execution levels where nodes in the same level can run in parallel.
|
|
99
|
+
*
|
|
100
|
+
* Uses Kahn's algorithm to perform topological sorting with level identification.
|
|
101
|
+
* Nodes are grouped by their distance from source nodes (input nodes with no dependencies).
|
|
102
|
+
*
|
|
103
|
+
* @param nodes - Array of flow nodes to analyze
|
|
104
|
+
* @param edges - Array of edges defining dependencies between nodes
|
|
105
|
+
* @returns Array of execution levels, ordered from 0 (no dependencies) onwards
|
|
106
|
+
* @throws Error if a cycle is detected in the flow graph
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const levels = scheduler.groupNodesByExecutionLevel(nodes, edges);
|
|
111
|
+
* // levels = [
|
|
112
|
+
* // { level: 0, nodes: ['input_1'] },
|
|
113
|
+
* // { level: 1, nodes: ['resize_1', 'optimize_1'] },
|
|
114
|
+
* // { level: 2, nodes: ['output_1'] }
|
|
115
|
+
* // ]
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
groupNodesByExecutionLevel(
|
|
119
|
+
nodes: FlowNode<unknown, unknown>[],
|
|
120
|
+
edges: Array<{ source: string; target: string }>,
|
|
121
|
+
): ExecutionLevel[] {
|
|
122
|
+
// Build dependency graph
|
|
123
|
+
const graph: Record<string, string[]> = {};
|
|
124
|
+
const inDegree: Record<string, number> = {};
|
|
125
|
+
|
|
126
|
+
// Initialize graph structure
|
|
127
|
+
nodes.forEach((node) => {
|
|
128
|
+
graph[node.id] = [];
|
|
129
|
+
inDegree[node.id] = 0;
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Build edges and calculate in-degrees
|
|
133
|
+
edges.forEach((edge) => {
|
|
134
|
+
graph[edge.source]?.push(edge.target);
|
|
135
|
+
inDegree[edge.target] = (inDegree[edge.target] || 0) + 1;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const levels: ExecutionLevel[] = [];
|
|
139
|
+
const processedNodes = new Set<string>();
|
|
140
|
+
let levelIndex = 0;
|
|
141
|
+
|
|
142
|
+
// Use Kahn's algorithm to group nodes by level
|
|
143
|
+
while (processedNodes.size < nodes.length) {
|
|
144
|
+
// Find all nodes with zero in-degree that haven't been processed
|
|
145
|
+
const currentLevelNodes = Object.keys(inDegree).filter(
|
|
146
|
+
(nodeId) => inDegree[nodeId] === 0 && !processedNodes.has(nodeId),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (currentLevelNodes.length === 0) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
"Cycle detected in flow graph - cannot execute in parallel",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
levels.push({
|
|
156
|
+
level: levelIndex++,
|
|
157
|
+
nodes: currentLevelNodes,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Remove current level nodes and update in-degrees for dependent nodes
|
|
161
|
+
currentLevelNodes.forEach((nodeId) => {
|
|
162
|
+
processedNodes.add(nodeId);
|
|
163
|
+
delete inDegree[nodeId];
|
|
164
|
+
|
|
165
|
+
// Decrease in-degree for all nodes that depend on this node
|
|
166
|
+
graph[nodeId]?.forEach((dependentId) => {
|
|
167
|
+
if (inDegree[dependentId] !== undefined) {
|
|
168
|
+
inDegree[dependentId]--;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return levels;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Executes a batch of Effect-based node executors in parallel with concurrency control.
|
|
179
|
+
*
|
|
180
|
+
* All executors are run in parallel, but the number of concurrent executions is limited
|
|
181
|
+
* by maxConcurrency. This prevents resource exhaustion while maximizing parallelism.
|
|
182
|
+
*
|
|
183
|
+
* @template T - The return type of each executor
|
|
184
|
+
* @template E - The error type of the Effects
|
|
185
|
+
* @template R - The requirements type of the Effects
|
|
186
|
+
*
|
|
187
|
+
* @param nodeExecutors - Array of Effect-returning functions to execute in parallel
|
|
188
|
+
* @returns Effect that resolves to array of results in the same order as input
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* const results = yield* scheduler.executeNodesInParallel([
|
|
193
|
+
* () => executeNode("node1"),
|
|
194
|
+
* () => executeNode("node2"),
|
|
195
|
+
* () => executeNode("node3")
|
|
196
|
+
* ]);
|
|
197
|
+
* // results will be in order: [result1, result2, result3]
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
executeNodesInParallel<T, E, R>(
|
|
201
|
+
nodeExecutors: Array<() => Effect.Effect<T, E, R>>,
|
|
202
|
+
): Effect.Effect<T[], E, R> {
|
|
203
|
+
return Effect.all(
|
|
204
|
+
nodeExecutors.map((executor) => executor()),
|
|
205
|
+
{
|
|
206
|
+
concurrency: this.maxConcurrency,
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Determines if a set of nodes can be safely executed in parallel.
|
|
213
|
+
*
|
|
214
|
+
* Nodes can execute in parallel if all their dependencies have been completed.
|
|
215
|
+
* This is typically called to verify that nodes in an execution level are ready
|
|
216
|
+
* to run given the current node results.
|
|
217
|
+
*
|
|
218
|
+
* @param nodeIds - Array of node IDs to check
|
|
219
|
+
* @param nodeResults - Map of completed node IDs to their results
|
|
220
|
+
* @param reverseGraph - Dependency graph mapping node IDs to their incoming dependencies
|
|
221
|
+
* @returns true if all dependencies for all nodes are in nodeResults, false otherwise
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const canRun = scheduler.canExecuteInParallel(
|
|
226
|
+
* ['resize_1', 'optimize_1'],
|
|
227
|
+
* nodeResults,
|
|
228
|
+
* reverseGraph
|
|
229
|
+
* );
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
canExecuteInParallel(
|
|
233
|
+
nodeIds: string[],
|
|
234
|
+
nodeResults: Map<string, unknown>,
|
|
235
|
+
reverseGraph: Record<string, string[]>,
|
|
236
|
+
): boolean {
|
|
237
|
+
return nodeIds.every((nodeId) => {
|
|
238
|
+
const dependencies = reverseGraph[nodeId] || [];
|
|
239
|
+
return dependencies.every((depId) => nodeResults.has(depId));
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Gets execution statistics for monitoring and debugging.
|
|
245
|
+
*
|
|
246
|
+
* @returns Object containing current scheduler configuration
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* const stats = scheduler.getStats();
|
|
251
|
+
* console.log(`Max concurrency: ${stats.maxConcurrency}`);
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
getStats() {
|
|
255
|
+
return {
|
|
256
|
+
maxConcurrency: this.maxConcurrency,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Context, type Effect } from "effect";
|
|
2
|
+
import type { UploadistaError } from "@/errors";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shape definition for the Credential Provider interface.
|
|
6
|
+
* Defines the contract for retrieving credentials for various services.
|
|
7
|
+
*/
|
|
8
|
+
export interface CredentialProviderShape {
|
|
9
|
+
/**
|
|
10
|
+
* Retrieves credentials for a specific service and client.
|
|
11
|
+
*
|
|
12
|
+
* @param params - Parameters for credential retrieval
|
|
13
|
+
* @param params.clientId - Unique identifier for the client, or null if not available
|
|
14
|
+
* @param params.serviceType - Optional service type to get specific credentials for
|
|
15
|
+
* @returns An Effect that resolves to a record of credential key-value pairs
|
|
16
|
+
* @throws {UploadistaError} When credential retrieval fails
|
|
17
|
+
*/
|
|
18
|
+
getCredential: (params: {
|
|
19
|
+
clientId: string | null;
|
|
20
|
+
serviceType?: string;
|
|
21
|
+
}) => Effect.Effect<Record<string, unknown>, UploadistaError>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Context tag for the Credential Provider.
|
|
26
|
+
*
|
|
27
|
+
* This tag provides a type-safe way to access credential functionality
|
|
28
|
+
* throughout the application using Effect's dependency injection system.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { CredentialProvider } from "@uploadista/core/flow/plugins";
|
|
33
|
+
*
|
|
34
|
+
* // In your flow node
|
|
35
|
+
* const program = Effect.gen(function* () {
|
|
36
|
+
* const credentialProvider = yield* CredentialProvider;
|
|
37
|
+
* const credentials = yield* credentialProvider.getCredential({
|
|
38
|
+
* clientId: "user123",
|
|
39
|
+
* serviceType: "replicate"
|
|
40
|
+
* });
|
|
41
|
+
* return credentials;
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class CredentialProvider extends Context.Tag("CredentialProvider")<
|
|
46
|
+
CredentialProvider,
|
|
47
|
+
CredentialProviderShape
|
|
48
|
+
>() {}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { UploadistaError } from "@uploadista/core/errors";
|
|
2
|
+
import { Context, type Effect } from "effect";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Context information for AI image processing operations.
|
|
6
|
+
* Contains client identification for tracking and billing purposes.
|
|
7
|
+
*/
|
|
8
|
+
export type ImageAiContext = {
|
|
9
|
+
/** Unique identifier for the client making the request, or null if not available */
|
|
10
|
+
clientId: string | null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Shape definition for the Image AI Plugin interface.
|
|
15
|
+
* Defines the contract that all image AI implementations must follow.
|
|
16
|
+
*/
|
|
17
|
+
export type ImageAiPluginShape = {
|
|
18
|
+
/**
|
|
19
|
+
* Removes the background from an image using AI processing.
|
|
20
|
+
*
|
|
21
|
+
* @param inputUrl - The URL of the input image to process
|
|
22
|
+
* @param context - Context information including client ID for tracking
|
|
23
|
+
* @returns An Effect that resolves to an object containing the output image URL
|
|
24
|
+
* @throws {UploadistaError} When the background removal fails
|
|
25
|
+
*/
|
|
26
|
+
removeBackground: (
|
|
27
|
+
inputUrl: string,
|
|
28
|
+
context: ImageAiContext
|
|
29
|
+
) => Effect.Effect<{ outputUrl: string }, UploadistaError>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generates a textual description of an image using AI analysis.
|
|
33
|
+
*
|
|
34
|
+
* @param inputUrl - The URL of the input image to analyze
|
|
35
|
+
* @param context - Context information including client ID for tracking
|
|
36
|
+
* @returns An Effect that resolves to an object containing the image description
|
|
37
|
+
* @throws {UploadistaError} When the image analysis fails
|
|
38
|
+
*/
|
|
39
|
+
describeImage: (
|
|
40
|
+
inputUrl: string,
|
|
41
|
+
context: ImageAiContext
|
|
42
|
+
) => Effect.Effect<{ description: string }, UploadistaError>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Context tag for the Image AI Plugin.
|
|
47
|
+
*
|
|
48
|
+
* This tag provides a type-safe way to access image AI functionality
|
|
49
|
+
* throughout the application using Effect's dependency injection system.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { ImageAiPlugin } from "@uploadista/core/flow/plugins";
|
|
54
|
+
*
|
|
55
|
+
* // In your flow node
|
|
56
|
+
* const program = Effect.gen(function* () {
|
|
57
|
+
* const imageAi = yield* ImageAiPlugin;
|
|
58
|
+
* const result = yield* imageAi.removeBackground(imageUrl, { clientId: "user123" });
|
|
59
|
+
* return result.outputUrl;
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export class ImageAiPlugin extends Context.Tag("ImageAiPlugin")<
|
|
64
|
+
ImageAiPlugin,
|
|
65
|
+
ImageAiPluginShape
|
|
66
|
+
>() {}
|