@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,349 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import type { UploadistaError } from "../errors";
|
|
3
|
+
import type { FlowEvent } from "../flow/event";
|
|
4
|
+
import type { UploadEvent } from "./upload-event";
|
|
5
|
+
import type { WebSocketConnection } from "./websocket";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base event emitter interface for raw string message broadcasting.
|
|
9
|
+
*
|
|
10
|
+
* This is the low-level interface that event broadcasting implementations
|
|
11
|
+
* (WebSocket, Server-Sent Events, etc.) implement. It emits raw string messages
|
|
12
|
+
* without type safety or serialization.
|
|
13
|
+
*
|
|
14
|
+
* @property subscribe - Registers a WebSocket connection to receive events for a key
|
|
15
|
+
* @property unsubscribe - Removes subscription for a key
|
|
16
|
+
* @property emit - Broadcasts a string message to all subscribers of a key
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Implement BaseEventEmitter with WebSocket broadcast
|
|
21
|
+
* const websocketEmitter: BaseEventEmitter = {
|
|
22
|
+
* subscribe: (key, connection) => Effect.sync(() => {
|
|
23
|
+
* connections.set(key, [...(connections.get(key) || []), connection]);
|
|
24
|
+
* }),
|
|
25
|
+
*
|
|
26
|
+
* unsubscribe: (key) => Effect.sync(() => {
|
|
27
|
+
* connections.delete(key);
|
|
28
|
+
* }),
|
|
29
|
+
*
|
|
30
|
+
* emit: (key, event) => Effect.sync(() => {
|
|
31
|
+
* const subs = connections.get(key) || [];
|
|
32
|
+
* subs.forEach(conn => conn.send(event));
|
|
33
|
+
* })
|
|
34
|
+
* };
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export interface BaseEventEmitter {
|
|
38
|
+
readonly subscribe: (
|
|
39
|
+
key: string,
|
|
40
|
+
connection: WebSocketConnection,
|
|
41
|
+
) => Effect.Effect<void, UploadistaError>;
|
|
42
|
+
readonly unsubscribe: (key: string) => Effect.Effect<void, UploadistaError>;
|
|
43
|
+
readonly emit: (
|
|
44
|
+
key: string,
|
|
45
|
+
event: string,
|
|
46
|
+
) => Effect.Effect<void, UploadistaError>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Type-safe event emitter interface with automatic serialization.
|
|
51
|
+
*
|
|
52
|
+
* This wraps a BaseEventEmitter and handles event serialization to JSON messages,
|
|
53
|
+
* providing type safety for events and ensuring consistent message format.
|
|
54
|
+
*
|
|
55
|
+
* @template TEvent - The type of events emitted by this emitter
|
|
56
|
+
*
|
|
57
|
+
* @property subscribe - Registers a WebSocket connection to receive typed events
|
|
58
|
+
* @property unsubscribe - Removes subscription
|
|
59
|
+
* @property emit - Serializes and broadcasts a typed event
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* // Use a typed event emitter
|
|
64
|
+
* const uploadEmitter: EventEmitter<UploadEvent> = new TypedEventEmitter(
|
|
65
|
+
* baseEmitter,
|
|
66
|
+
* (event) => JSON.stringify({ type: 'upload', payload: event })
|
|
67
|
+
* );
|
|
68
|
+
*
|
|
69
|
+
* // Emit type-safe events
|
|
70
|
+
* const program = Effect.gen(function* () {
|
|
71
|
+
* const event: UploadEvent = {
|
|
72
|
+
* uploadId: "upload123",
|
|
73
|
+
* type: "progress",
|
|
74
|
+
* offset: 1024,
|
|
75
|
+
* size: 2048
|
|
76
|
+
* };
|
|
77
|
+
*
|
|
78
|
+
* // Automatic serialization
|
|
79
|
+
* yield* uploadEmitter.emit("upload123", event);
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export type EventEmitter<TEvent> = {
|
|
84
|
+
readonly subscribe: (
|
|
85
|
+
key: string,
|
|
86
|
+
connection: WebSocketConnection,
|
|
87
|
+
) => Effect.Effect<void, UploadistaError>;
|
|
88
|
+
readonly unsubscribe: (key: string) => Effect.Effect<void, UploadistaError>;
|
|
89
|
+
readonly emit: (
|
|
90
|
+
key: string,
|
|
91
|
+
event: TEvent,
|
|
92
|
+
) => Effect.Effect<void, UploadistaError>;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Typed wrapper class that adds event serialization to a BaseEventEmitter.
|
|
97
|
+
*
|
|
98
|
+
* This class implements the EventEmitter interface by wrapping a BaseEventEmitter
|
|
99
|
+
* and handling serialization for a specific event type. It converts typed events
|
|
100
|
+
* to JSON message strings before broadcasting.
|
|
101
|
+
*
|
|
102
|
+
* @template TEvent - The type of events to emit
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* // Create a typed emitter for UploadEvent
|
|
107
|
+
* const uploadEmitter = new TypedEventEmitter<UploadEvent>(
|
|
108
|
+
* baseEmitter,
|
|
109
|
+
* (event) => JSON.stringify({
|
|
110
|
+
* type: "upload_event",
|
|
111
|
+
* payload: event,
|
|
112
|
+
* timestamp: new Date().toISOString()
|
|
113
|
+
* })
|
|
114
|
+
* );
|
|
115
|
+
*
|
|
116
|
+
* // Use the emitter
|
|
117
|
+
* const effect = Effect.gen(function* () {
|
|
118
|
+
* // Subscribe a WebSocket connection
|
|
119
|
+
* yield* uploadEmitter.subscribe("upload123", websocket);
|
|
120
|
+
*
|
|
121
|
+
* // Emit an event (automatically serialized)
|
|
122
|
+
* yield* uploadEmitter.emit("upload123", {
|
|
123
|
+
* uploadId: "upload123",
|
|
124
|
+
* type: "completed",
|
|
125
|
+
* offset: 2048,
|
|
126
|
+
* size: 2048
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* // Unsubscribe when done
|
|
130
|
+
* yield* uploadEmitter.unsubscribe("upload123");
|
|
131
|
+
* });
|
|
132
|
+
*
|
|
133
|
+
* // Custom message format
|
|
134
|
+
* const customEmitter = new TypedEventEmitter<MyEvent>(
|
|
135
|
+
* baseEmitter,
|
|
136
|
+
* (event) => `EVENT:${event.type}:${JSON.stringify(event.data)}`
|
|
137
|
+
* );
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export class TypedEventEmitter<TEvent> implements EventEmitter<TEvent> {
|
|
141
|
+
constructor(
|
|
142
|
+
private baseEmitter: BaseEventEmitter,
|
|
143
|
+
private eventToMessage: (event: TEvent) => string,
|
|
144
|
+
) {}
|
|
145
|
+
|
|
146
|
+
subscribe = (
|
|
147
|
+
key: string,
|
|
148
|
+
connection: WebSocketConnection,
|
|
149
|
+
): Effect.Effect<void, UploadistaError> =>
|
|
150
|
+
this.baseEmitter.subscribe(key, connection);
|
|
151
|
+
|
|
152
|
+
unsubscribe = (key: string): Effect.Effect<void, UploadistaError> =>
|
|
153
|
+
this.baseEmitter.unsubscribe(key);
|
|
154
|
+
|
|
155
|
+
emit = (key: string, event: TEvent): Effect.Effect<void, UploadistaError> => {
|
|
156
|
+
const message = this.eventToMessage(event);
|
|
157
|
+
return this.baseEmitter.emit(key, message);
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Default event-to-message serialization helper.
|
|
163
|
+
*
|
|
164
|
+
* Creates a standardized JSON message format with type, payload, and timestamp.
|
|
165
|
+
* This is the recommended way to serialize events for WebSocket transmission.
|
|
166
|
+
*
|
|
167
|
+
* @param messageType - The message type identifier ("upload_event" or "flow_event")
|
|
168
|
+
* @returns An object with an eventToMessage function
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* // Create emitter with standard serialization
|
|
173
|
+
* const emitter = new TypedEventEmitter<UploadEvent>(
|
|
174
|
+
* baseEmitter,
|
|
175
|
+
* eventToMessageSerializer("upload_event").eventToMessage
|
|
176
|
+
* );
|
|
177
|
+
*
|
|
178
|
+
* // Messages will be formatted as:
|
|
179
|
+
* // {
|
|
180
|
+
* // "type": "upload_event",
|
|
181
|
+
* // "payload": { ...event data... },
|
|
182
|
+
* // "timestamp": "2024-01-15T10:30:00.000Z"
|
|
183
|
+
* // }
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
export const eventToMessageSerializer = (
|
|
187
|
+
messageType: "upload_event" | "flow_event",
|
|
188
|
+
) => ({
|
|
189
|
+
eventToMessage: <T>(event: T): string =>
|
|
190
|
+
JSON.stringify({
|
|
191
|
+
type: messageType,
|
|
192
|
+
payload: event,
|
|
193
|
+
timestamp: new Date().toISOString(),
|
|
194
|
+
}),
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Effect-TS context tag for the base untyped event emitter.
|
|
199
|
+
*
|
|
200
|
+
* This is the low-level emitter that broadcasting implementations provide.
|
|
201
|
+
* Most application code should use typed emitters like UploadEventEmitter instead.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* // Provide a base emitter implementation
|
|
206
|
+
* const baseEmitterLayer = Layer.succeed(BaseEventEmitterService, websocketEmitter);
|
|
207
|
+
*
|
|
208
|
+
* // Use in an Effect
|
|
209
|
+
* const effect = Effect.gen(function* () {
|
|
210
|
+
* const baseEmitter = yield* BaseEventEmitterService;
|
|
211
|
+
* yield* baseEmitter.emit("channel1", "raw message");
|
|
212
|
+
* });
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export class BaseEventEmitterService extends Context.Tag("BaseEventEmitter")<
|
|
216
|
+
BaseEventEmitterService,
|
|
217
|
+
BaseEventEmitter
|
|
218
|
+
>() {}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Effect-TS context tag for the UploadEvent typed emitter.
|
|
222
|
+
*
|
|
223
|
+
* This provides type-safe event emission for upload progress and lifecycle events.
|
|
224
|
+
* It's the primary way to broadcast upload events to connected clients.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const uploadEffect = Effect.gen(function* () {
|
|
229
|
+
* const emitter = yield* UploadEventEmitter;
|
|
230
|
+
*
|
|
231
|
+
* // Subscribe a client to upload events
|
|
232
|
+
* yield* emitter.subscribe("upload123", websocketConnection);
|
|
233
|
+
*
|
|
234
|
+
* // Emit progress event
|
|
235
|
+
* yield* emitter.emit("upload123", {
|
|
236
|
+
* uploadId: "upload123",
|
|
237
|
+
* type: "progress",
|
|
238
|
+
* offset: 512000,
|
|
239
|
+
* size: 1024000
|
|
240
|
+
* });
|
|
241
|
+
*
|
|
242
|
+
* // Emit completion event
|
|
243
|
+
* yield* emitter.emit("upload123", {
|
|
244
|
+
* uploadId: "upload123",
|
|
245
|
+
* type: "completed",
|
|
246
|
+
* offset: 1024000,
|
|
247
|
+
* size: 1024000
|
|
248
|
+
* });
|
|
249
|
+
* });
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
export class UploadEventEmitter extends Context.Tag("UploadEventEmitter")<
|
|
253
|
+
UploadEventEmitter,
|
|
254
|
+
EventEmitter<UploadEvent>
|
|
255
|
+
>() {}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Effect Layer that creates the UploadEventEmitter from a BaseEventEmitter.
|
|
259
|
+
*
|
|
260
|
+
* This layer automatically wires up JSON serialization for UploadEvent objects
|
|
261
|
+
* with the standard "upload_event" message format.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* const program = Effect.gen(function* () {
|
|
266
|
+
* const emitter = yield* UploadEventEmitter;
|
|
267
|
+
* // Use the emitter...
|
|
268
|
+
* }).pipe(
|
|
269
|
+
* Effect.provide(uploadEventEmitter),
|
|
270
|
+
* Effect.provide(baseEmitterLayer)
|
|
271
|
+
* );
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
export const uploadEventEmitter = Layer.effect(
|
|
275
|
+
UploadEventEmitter,
|
|
276
|
+
Effect.gen(function* () {
|
|
277
|
+
const baseEmitter = yield* BaseEventEmitterService;
|
|
278
|
+
return new TypedEventEmitter<UploadEvent>(
|
|
279
|
+
baseEmitter,
|
|
280
|
+
eventToMessageSerializer("upload_event").eventToMessage,
|
|
281
|
+
);
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Effect-TS context tag for the FlowEvent typed emitter.
|
|
287
|
+
*
|
|
288
|
+
* This provides type-safe event emission for flow processing lifecycle events.
|
|
289
|
+
* It's used to broadcast flow execution progress, node completion, and errors.
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```typescript
|
|
293
|
+
* const flowEffect = Effect.gen(function* () {
|
|
294
|
+
* const emitter = yield* FlowEventEmitter;
|
|
295
|
+
*
|
|
296
|
+
* // Subscribe a client to flow job events
|
|
297
|
+
* yield* emitter.subscribe("job123", websocketConnection);
|
|
298
|
+
*
|
|
299
|
+
* // Emit node start event
|
|
300
|
+
* yield* emitter.emit("job123", {
|
|
301
|
+
* jobId: "job123",
|
|
302
|
+
* eventType: "NodeStart",
|
|
303
|
+
* flowId: "flow_resize",
|
|
304
|
+
* nodeId: "resize_1"
|
|
305
|
+
* });
|
|
306
|
+
*
|
|
307
|
+
* // Emit node completion event
|
|
308
|
+
* yield* emitter.emit("job123", {
|
|
309
|
+
* jobId: "job123",
|
|
310
|
+
* eventType: "NodeEnd",
|
|
311
|
+
* flowId: "flow_resize",
|
|
312
|
+
* nodeId: "resize_1",
|
|
313
|
+
* result: { width: 800, height: 600 }
|
|
314
|
+
* });
|
|
315
|
+
* });
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
export class FlowEventEmitter extends Context.Tag("FlowEventEmitter")<
|
|
319
|
+
FlowEventEmitter,
|
|
320
|
+
EventEmitter<FlowEvent>
|
|
321
|
+
>() {}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Effect Layer that creates the FlowEventEmitter from a BaseEventEmitter.
|
|
325
|
+
*
|
|
326
|
+
* This layer automatically wires up JSON serialization for FlowEvent objects
|
|
327
|
+
* with the standard "flow_event" message format.
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```typescript
|
|
331
|
+
* const program = Effect.gen(function* () {
|
|
332
|
+
* const emitter = yield* FlowEventEmitter;
|
|
333
|
+
* // Use the emitter...
|
|
334
|
+
* }).pipe(
|
|
335
|
+
* Effect.provide(flowEventEmitter),
|
|
336
|
+
* Effect.provide(baseEmitterLayer)
|
|
337
|
+
* );
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
export const flowEventEmitter = Layer.effect(
|
|
341
|
+
FlowEventEmitter,
|
|
342
|
+
Effect.gen(function* () {
|
|
343
|
+
const baseEmitter = yield* BaseEventEmitterService;
|
|
344
|
+
return new TypedEventEmitter<FlowEvent>(
|
|
345
|
+
baseEmitter,
|
|
346
|
+
eventToMessageSerializer("flow_event").eventToMessage,
|
|
347
|
+
);
|
|
348
|
+
}),
|
|
349
|
+
);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./data-store";
|
|
2
|
+
export * from "./event-broadcaster";
|
|
3
|
+
export * from "./event-emitter";
|
|
4
|
+
export * from "./input-file";
|
|
5
|
+
export * from "./kv-store";
|
|
6
|
+
export * from "./middleware";
|
|
7
|
+
export * from "./upload-event";
|
|
8
|
+
export * from "./upload-file";
|
|
9
|
+
export * from "./websocket";
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zod schema for validating InputFile objects.
|
|
5
|
+
*
|
|
6
|
+
* This schema defines the structure and validation rules for file upload requests.
|
|
7
|
+
* Use this schema to parse and validate input data when creating new uploads.
|
|
8
|
+
*
|
|
9
|
+
* @see {@link InputFile} for the TypeScript type
|
|
10
|
+
*/
|
|
11
|
+
export const inputFileSchema = z.object({
|
|
12
|
+
uploadLengthDeferred: z.boolean().optional(),
|
|
13
|
+
storageId: z.string(),
|
|
14
|
+
size: z.number(),
|
|
15
|
+
type: z.string(),
|
|
16
|
+
fileName: z.string().optional(),
|
|
17
|
+
lastModified: z.number().optional(),
|
|
18
|
+
metadata: z.string().optional(),
|
|
19
|
+
checksum: z.string().optional(),
|
|
20
|
+
checksumAlgorithm: z.string().optional(),
|
|
21
|
+
flow: z
|
|
22
|
+
.object({
|
|
23
|
+
flowId: z.string(),
|
|
24
|
+
nodeId: z.string(),
|
|
25
|
+
jobId: z.string(),
|
|
26
|
+
})
|
|
27
|
+
.optional(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Represents the input data for creating a new file upload.
|
|
32
|
+
*
|
|
33
|
+
* This type defines the information required to initiate an upload.
|
|
34
|
+
* It's used by clients to provide upload metadata before sending file data.
|
|
35
|
+
*
|
|
36
|
+
* @property storageId - Target storage backend identifier (e.g., "s3-production", "azure-blob")
|
|
37
|
+
* @property size - File size in bytes
|
|
38
|
+
* @property type - MIME type of the file (e.g., "image/jpeg", "application/pdf")
|
|
39
|
+
* @property uploadLengthDeferred - If true, file size is not known upfront (streaming upload)
|
|
40
|
+
* @property fileName - Original filename from the client
|
|
41
|
+
* @property lastModified - File's last modified timestamp in milliseconds since epoch
|
|
42
|
+
* @property metadata - Base64-encoded metadata string (as per tus protocol)
|
|
43
|
+
* @property checksum - Expected file checksum for validation
|
|
44
|
+
* @property checksumAlgorithm - Algorithm used for checksum (e.g., "md5", "sha256")
|
|
45
|
+
* @property flow - Optional flow processing configuration
|
|
46
|
+
* @property flow.flowId - ID of the flow to execute on this file
|
|
47
|
+
* @property flow.nodeId - Starting node ID in the flow
|
|
48
|
+
* @property flow.jobId - Flow job execution ID
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* // Basic file upload
|
|
53
|
+
* const inputFile: InputFile = {
|
|
54
|
+
* storageId: "s3-production",
|
|
55
|
+
* size: 1024000,
|
|
56
|
+
* type: "image/jpeg",
|
|
57
|
+
* fileName: "photo.jpg",
|
|
58
|
+
* lastModified: Date.now()
|
|
59
|
+
* };
|
|
60
|
+
*
|
|
61
|
+
* // Upload with metadata (base64 encoded as per tus protocol)
|
|
62
|
+
* const metadata = btoa(JSON.stringify({
|
|
63
|
+
* userId: "user_123",
|
|
64
|
+
* albumId: "album_456"
|
|
65
|
+
* }));
|
|
66
|
+
* const inputWithMetadata: InputFile = {
|
|
67
|
+
* storageId: "s3-production",
|
|
68
|
+
* size: 2048000,
|
|
69
|
+
* type: "image/png",
|
|
70
|
+
* fileName: "screenshot.png",
|
|
71
|
+
* metadata
|
|
72
|
+
* };
|
|
73
|
+
*
|
|
74
|
+
* // Upload with checksum validation
|
|
75
|
+
* const inputWithChecksum: InputFile = {
|
|
76
|
+
* storageId: "s3-production",
|
|
77
|
+
* size: 512000,
|
|
78
|
+
* type: "application/pdf",
|
|
79
|
+
* fileName: "document.pdf",
|
|
80
|
+
* checksum: "5d41402abc4b2a76b9719d911017c592",
|
|
81
|
+
* checksumAlgorithm: "md5"
|
|
82
|
+
* };
|
|
83
|
+
*
|
|
84
|
+
* // Upload that triggers a flow
|
|
85
|
+
* const inputWithFlow: InputFile = {
|
|
86
|
+
* storageId: "s3-temp",
|
|
87
|
+
* size: 4096000,
|
|
88
|
+
* type: "image/jpeg",
|
|
89
|
+
* fileName: "large-image.jpg",
|
|
90
|
+
* flow: {
|
|
91
|
+
* flowId: "resize-and-optimize",
|
|
92
|
+
* nodeId: "input_1",
|
|
93
|
+
* jobId: "job_789"
|
|
94
|
+
* }
|
|
95
|
+
* };
|
|
96
|
+
*
|
|
97
|
+
* // Streaming upload (size unknown)
|
|
98
|
+
* const streamingInput: InputFile = {
|
|
99
|
+
* storageId: "s3-production",
|
|
100
|
+
* size: 0, // Will be updated as data arrives
|
|
101
|
+
* type: "video/mp4",
|
|
102
|
+
* uploadLengthDeferred: true,
|
|
103
|
+
* fileName: "live-stream.mp4"
|
|
104
|
+
* };
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export type InputFile = z.infer<typeof inputFileSchema>;
|