@uploadista/client-core 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +5 -0
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/auth/auth-http-client.d.ts +50 -0
- package/dist/auth/auth-http-client.d.ts.map +1 -0
- package/dist/auth/auth-http-client.js +110 -0
- package/dist/auth/direct-auth.d.ts +38 -0
- package/dist/auth/direct-auth.d.ts.map +1 -0
- package/dist/auth/direct-auth.js +95 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/no-auth.d.ts +26 -0
- package/dist/auth/no-auth.d.ts.map +1 -0
- package/dist/auth/no-auth.js +33 -0
- package/dist/auth/saas-auth.d.ts +80 -0
- package/dist/auth/saas-auth.d.ts.map +1 -0
- package/dist/auth/saas-auth.js +167 -0
- package/dist/auth/types.d.ts +101 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +8 -0
- package/dist/chunk-buffer.d.ts +209 -0
- package/dist/chunk-buffer.d.ts.map +1 -0
- package/dist/chunk-buffer.js +236 -0
- package/dist/client/create-uploadista-client.d.ts +369 -0
- package/dist/client/create-uploadista-client.d.ts.map +1 -0
- package/dist/client/create-uploadista-client.js +518 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/uploadista-api.d.ts +284 -0
- package/dist/client/uploadista-api.d.ts.map +1 -0
- package/dist/client/uploadista-api.js +444 -0
- package/dist/client/uploadista-websocket-manager.d.ts +110 -0
- package/dist/client/uploadista-websocket-manager.d.ts.map +1 -0
- package/dist/client/uploadista-websocket-manager.js +207 -0
- package/dist/error.d.ts +106 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +69 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/logger.d.ts +70 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +59 -0
- package/dist/mock-data-store.d.ts +30 -0
- package/dist/mock-data-store.d.ts.map +1 -0
- package/dist/mock-data-store.js +88 -0
- package/dist/network-monitor.d.ts +262 -0
- package/dist/network-monitor.d.ts.map +1 -0
- package/dist/network-monitor.js +291 -0
- package/dist/services/abort-controller-service.d.ts +19 -0
- package/dist/services/abort-controller-service.d.ts.map +1 -0
- package/dist/services/abort-controller-service.js +4 -0
- package/dist/services/checksum-service.d.ts +4 -0
- package/dist/services/checksum-service.d.ts.map +1 -0
- package/dist/services/checksum-service.js +1 -0
- package/dist/services/file-reader-service.d.ts +38 -0
- package/dist/services/file-reader-service.d.ts.map +1 -0
- package/dist/services/file-reader-service.js +4 -0
- package/dist/services/fingerprint-service.d.ts +4 -0
- package/dist/services/fingerprint-service.d.ts.map +1 -0
- package/dist/services/fingerprint-service.js +1 -0
- package/dist/services/http-client.d.ts +182 -0
- package/dist/services/http-client.d.ts.map +1 -0
- package/dist/services/http-client.js +1 -0
- package/dist/services/id-generation-service.d.ts +10 -0
- package/dist/services/id-generation-service.d.ts.map +1 -0
- package/dist/services/id-generation-service.js +1 -0
- package/dist/services/index.d.ts +11 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +10 -0
- package/dist/services/platform-service.d.ts +48 -0
- package/dist/services/platform-service.d.ts.map +1 -0
- package/dist/services/platform-service.js +10 -0
- package/dist/services/service-container.d.ts +25 -0
- package/dist/services/service-container.d.ts.map +1 -0
- package/dist/services/service-container.js +1 -0
- package/dist/services/storage-service.d.ts +26 -0
- package/dist/services/storage-service.d.ts.map +1 -0
- package/dist/services/storage-service.js +1 -0
- package/dist/services/websocket-service.d.ts +36 -0
- package/dist/services/websocket-service.d.ts.map +1 -0
- package/dist/services/websocket-service.js +4 -0
- package/dist/smart-chunker.d.ts +72 -0
- package/dist/smart-chunker.d.ts.map +1 -0
- package/dist/smart-chunker.js +317 -0
- package/dist/storage/client-storage.d.ts +148 -0
- package/dist/storage/client-storage.d.ts.map +1 -0
- package/dist/storage/client-storage.js +62 -0
- package/dist/storage/in-memory-storage-service.d.ts +7 -0
- package/dist/storage/in-memory-storage-service.d.ts.map +1 -0
- package/dist/storage/in-memory-storage-service.js +24 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/types/buffered-chunk.d.ts +6 -0
- package/dist/types/buffered-chunk.d.ts.map +1 -0
- package/dist/types/buffered-chunk.js +1 -0
- package/dist/types/chunk-metrics.d.ts +12 -0
- package/dist/types/chunk-metrics.d.ts.map +1 -0
- package/dist/types/chunk-metrics.js +1 -0
- package/dist/types/flow-result.d.ts +11 -0
- package/dist/types/flow-result.d.ts.map +1 -0
- package/dist/types/flow-result.js +1 -0
- package/dist/types/flow-upload-config.d.ts +54 -0
- package/dist/types/flow-upload-config.d.ts.map +1 -0
- package/dist/types/flow-upload-config.js +1 -0
- package/dist/types/flow-upload-item.d.ts +16 -0
- package/dist/types/flow-upload-item.d.ts.map +1 -0
- package/dist/types/flow-upload-item.js +1 -0
- package/dist/types/flow-upload-options.d.ts +41 -0
- package/dist/types/flow-upload-options.d.ts.map +1 -0
- package/dist/types/flow-upload-options.js +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/multi-flow-upload-options.d.ts +33 -0
- package/dist/types/multi-flow-upload-options.d.ts.map +1 -0
- package/dist/types/multi-flow-upload-options.js +1 -0
- package/dist/types/multi-flow-upload-state.d.ts +9 -0
- package/dist/types/multi-flow-upload-state.d.ts.map +1 -0
- package/dist/types/multi-flow-upload-state.js +1 -0
- package/dist/types/performance-insights.d.ts +11 -0
- package/dist/types/performance-insights.d.ts.map +1 -0
- package/dist/types/performance-insights.js +1 -0
- package/dist/types/previous-upload.d.ts +20 -0
- package/dist/types/previous-upload.d.ts.map +1 -0
- package/dist/types/previous-upload.js +9 -0
- package/dist/types/upload-options.d.ts +40 -0
- package/dist/types/upload-options.d.ts.map +1 -0
- package/dist/types/upload-options.js +1 -0
- package/dist/types/upload-response.d.ts +6 -0
- package/dist/types/upload-response.d.ts.map +1 -0
- package/dist/types/upload-response.js +1 -0
- package/dist/types/upload-result.d.ts +57 -0
- package/dist/types/upload-result.d.ts.map +1 -0
- package/dist/types/upload-result.js +1 -0
- package/dist/types/upload-session-metrics.d.ts +16 -0
- package/dist/types/upload-session-metrics.d.ts.map +1 -0
- package/dist/types/upload-session-metrics.js +1 -0
- package/dist/upload/chunk-upload.d.ts +40 -0
- package/dist/upload/chunk-upload.d.ts.map +1 -0
- package/dist/upload/chunk-upload.js +82 -0
- package/dist/upload/flow-upload.d.ts +48 -0
- package/dist/upload/flow-upload.d.ts.map +1 -0
- package/dist/upload/flow-upload.js +240 -0
- package/dist/upload/index.d.ts +3 -0
- package/dist/upload/index.d.ts.map +1 -0
- package/dist/upload/index.js +2 -0
- package/dist/upload/parallel-upload.d.ts +65 -0
- package/dist/upload/parallel-upload.d.ts.map +1 -0
- package/dist/upload/parallel-upload.js +231 -0
- package/dist/upload/single-upload.d.ts +118 -0
- package/dist/upload/single-upload.d.ts.map +1 -0
- package/dist/upload/single-upload.js +332 -0
- package/dist/upload/upload-manager.d.ts +30 -0
- package/dist/upload/upload-manager.d.ts.map +1 -0
- package/dist/upload/upload-manager.js +57 -0
- package/dist/upload/upload-metrics.d.ts +37 -0
- package/dist/upload/upload-metrics.d.ts.map +1 -0
- package/dist/upload/upload-metrics.js +236 -0
- package/dist/upload/upload-storage.d.ts +32 -0
- package/dist/upload/upload-storage.d.ts.map +1 -0
- package/dist/upload/upload-storage.js +46 -0
- package/dist/upload/upload-strategy.d.ts +66 -0
- package/dist/upload/upload-strategy.d.ts.map +1 -0
- package/dist/upload/upload-strategy.js +171 -0
- package/dist/upload/upload-utils.d.ts +26 -0
- package/dist/upload/upload-utils.d.ts.map +1 -0
- package/dist/upload/upload-utils.js +80 -0
- package/package.json +29 -0
- package/src/__tests__/smart-chunking.test.ts +399 -0
- package/src/auth/__tests__/auth-http-client.test.ts +327 -0
- package/src/auth/__tests__/direct-auth.test.ts +135 -0
- package/src/auth/__tests__/no-auth.test.ts +40 -0
- package/src/auth/__tests__/saas-auth.test.ts +337 -0
- package/src/auth/auth-http-client.ts +150 -0
- package/src/auth/direct-auth.ts +121 -0
- package/src/auth/index.ts +5 -0
- package/src/auth/no-auth.ts +39 -0
- package/src/auth/saas-auth.ts +218 -0
- package/src/auth/types.ts +105 -0
- package/src/chunk-buffer.ts +287 -0
- package/src/client/create-uploadista-client.ts +901 -0
- package/src/client/index.ts +3 -0
- package/src/client/uploadista-api.ts +857 -0
- package/src/client/uploadista-websocket-manager.ts +275 -0
- package/src/error.ts +149 -0
- package/src/index.ts +13 -0
- package/src/logger.ts +104 -0
- package/src/mock-data-store.ts +97 -0
- package/src/network-monitor.ts +445 -0
- package/src/services/abort-controller-service.ts +21 -0
- package/src/services/checksum-service.ts +3 -0
- package/src/services/file-reader-service.ts +44 -0
- package/src/services/fingerprint-service.ts +6 -0
- package/src/services/http-client.ts +229 -0
- package/src/services/id-generation-service.ts +9 -0
- package/src/services/index.ts +10 -0
- package/src/services/platform-service.ts +65 -0
- package/src/services/service-container.ts +24 -0
- package/src/services/storage-service.ts +29 -0
- package/src/services/websocket-service.ts +33 -0
- package/src/smart-chunker.ts +451 -0
- package/src/storage/client-storage.ts +186 -0
- package/src/storage/in-memory-storage-service.ts +33 -0
- package/src/storage/index.ts +2 -0
- package/src/types/buffered-chunk.ts +5 -0
- package/src/types/chunk-metrics.ts +11 -0
- package/src/types/flow-result.ts +14 -0
- package/src/types/flow-upload-config.ts +56 -0
- package/src/types/flow-upload-item.ts +16 -0
- package/src/types/flow-upload-options.ts +56 -0
- package/src/types/index.ts +13 -0
- package/src/types/multi-flow-upload-options.ts +39 -0
- package/src/types/multi-flow-upload-state.ts +9 -0
- package/src/types/performance-insights.ts +7 -0
- package/src/types/previous-upload.ts +22 -0
- package/src/types/upload-options.ts +56 -0
- package/src/types/upload-response.ts +6 -0
- package/src/types/upload-result.ts +60 -0
- package/src/types/upload-session-metrics.ts +15 -0
- package/src/upload/chunk-upload.ts +151 -0
- package/src/upload/flow-upload.ts +367 -0
- package/src/upload/index.ts +2 -0
- package/src/upload/parallel-upload.ts +387 -0
- package/src/upload/single-upload.ts +554 -0
- package/src/upload/upload-manager.ts +106 -0
- package/src/upload/upload-metrics.ts +340 -0
- package/src/upload/upload-storage.ts +87 -0
- package/src/upload/upload-strategy.ts +296 -0
- package/src/upload/upload-utils.ts +114 -0
- package/tsconfig.json +23 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,901 @@
|
|
|
1
|
+
import type { DataStoreCapabilities } from "@uploadista/core/types";
|
|
2
|
+
import type { AuthConfig, AuthManager } from "../auth";
|
|
3
|
+
import { DirectAuthManager, NoAuthManager, SaasAuthManager } from "../auth";
|
|
4
|
+
import type { Logger } from "../logger";
|
|
5
|
+
import { createLogger } from "../logger";
|
|
6
|
+
import { defaultClientCapabilities } from "../mock-data-store";
|
|
7
|
+
import { NetworkMonitor, type NetworkMonitorConfig } from "../network-monitor";
|
|
8
|
+
import type { AbortControllerFactory } from "../services/abort-controller-service";
|
|
9
|
+
import type { ChecksumService } from "../services/checksum-service";
|
|
10
|
+
import type { FileReaderService } from "../services/file-reader-service";
|
|
11
|
+
import type { FingerprintService } from "../services/fingerprint-service";
|
|
12
|
+
import type { ConnectionPoolConfig, HttpClient } from "../services/http-client";
|
|
13
|
+
import type { IdGenerationService } from "../services/id-generation-service";
|
|
14
|
+
import type { PlatformService, Timeout } from "../services/platform-service";
|
|
15
|
+
import type {
|
|
16
|
+
WebSocketFactory,
|
|
17
|
+
WebSocketLike,
|
|
18
|
+
} from "../services/websocket-service";
|
|
19
|
+
import { SmartChunker, type SmartChunkerConfig } from "../smart-chunker";
|
|
20
|
+
import type { ClientStorage } from "../storage/client-storage";
|
|
21
|
+
import type { FlowUploadConfig } from "../types/flow-upload-config";
|
|
22
|
+
|
|
23
|
+
import { performFlowUpload, startFlowUpload } from "../upload/flow-upload";
|
|
24
|
+
import { startParallelUpload } from "../upload/parallel-upload";
|
|
25
|
+
import {
|
|
26
|
+
type Callbacks,
|
|
27
|
+
performUpload,
|
|
28
|
+
startSingleUpload,
|
|
29
|
+
} from "../upload/single-upload";
|
|
30
|
+
import { abort, terminate } from "../upload/upload-manager";
|
|
31
|
+
import {
|
|
32
|
+
UploadMetrics,
|
|
33
|
+
type UploadMetricsConfig,
|
|
34
|
+
} from "../upload/upload-metrics";
|
|
35
|
+
import {
|
|
36
|
+
findPreviousUploads,
|
|
37
|
+
resumeFromPreviousUpload,
|
|
38
|
+
} from "../upload/upload-storage";
|
|
39
|
+
import {
|
|
40
|
+
negotiateUploadStrategy,
|
|
41
|
+
type UploadStrategyConfig,
|
|
42
|
+
validateAndThrow,
|
|
43
|
+
validateConfiguration,
|
|
44
|
+
} from "../upload/upload-strategy";
|
|
45
|
+
import { calculateFileSize } from "../upload/upload-utils";
|
|
46
|
+
import { createUploadistaApi } from "./uploadista-api";
|
|
47
|
+
import {
|
|
48
|
+
type UploadistaWebSocketEventHandler,
|
|
49
|
+
UploadistaWebSocketManager,
|
|
50
|
+
} from "./uploadista-websocket-manager";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Options for individual upload operations.
|
|
54
|
+
*
|
|
55
|
+
* Extends the base upload callbacks with configuration for deferred length,
|
|
56
|
+
* size overrides, metadata, and checksum computation.
|
|
57
|
+
*/
|
|
58
|
+
export type UploadistaUploadOptions = {
|
|
59
|
+
/**
|
|
60
|
+
* Whether to defer specifying the upload size until later.
|
|
61
|
+
* Useful for streaming uploads where size isn't known upfront.
|
|
62
|
+
* Defaults to false.
|
|
63
|
+
*/
|
|
64
|
+
uploadLengthDeferred?: boolean;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Manual override for upload size in bytes.
|
|
68
|
+
* If not provided, size is determined from the file/blob.
|
|
69
|
+
*/
|
|
70
|
+
uploadSize?: number;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Custom metadata to attach to the upload.
|
|
74
|
+
* Stored as key-value pairs on the server.
|
|
75
|
+
*/
|
|
76
|
+
metadata?: Record<string, string>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Whether to compute checksums for uploaded chunks.
|
|
80
|
+
* Enables integrity verification but adds computational overhead.
|
|
81
|
+
* Defaults to false.
|
|
82
|
+
*/
|
|
83
|
+
computeChecksum?: boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Checksum algorithm to use (e.g., "sha256", "md5").
|
|
87
|
+
* Only relevant if computeChecksum is true.
|
|
88
|
+
*/
|
|
89
|
+
checksumAlgorithm?: string;
|
|
90
|
+
} & Callbacks;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Configuration options for creating an Uploadista client.
|
|
94
|
+
*
|
|
95
|
+
* This comprehensive configuration object allows customization of all aspects
|
|
96
|
+
* of upload behavior including chunking, retries, authentication, storage,
|
|
97
|
+
* network monitoring, and platform-specific services.
|
|
98
|
+
*
|
|
99
|
+
* @template UploadInput - The platform-specific file/blob type (e.g., File, Blob, Buffer)
|
|
100
|
+
*/
|
|
101
|
+
export type UploadistaClientOptions<UploadInput> = {
|
|
102
|
+
/** Base URL of the Uploadista server (e.g., "https://upload.example.com") */
|
|
103
|
+
baseUrl: string;
|
|
104
|
+
|
|
105
|
+
/** Base path for Uploadista endpoints. Defaults to "uploadista" */
|
|
106
|
+
uploadistaBasePath?: string;
|
|
107
|
+
|
|
108
|
+
/** Storage backend identifier configured on the server */
|
|
109
|
+
storageId: string;
|
|
110
|
+
|
|
111
|
+
/** Retry delay intervals in milliseconds. Defaults to [1000, 3000, 5000] */
|
|
112
|
+
retryDelays?: number[];
|
|
113
|
+
|
|
114
|
+
/** Default chunk size in bytes for uploads */
|
|
115
|
+
chunkSize: number;
|
|
116
|
+
|
|
117
|
+
/** Number of parallel upload streams. Defaults to 1 (sequential) */
|
|
118
|
+
parallelUploads?: number;
|
|
119
|
+
|
|
120
|
+
/** Chunk size for parallel uploads. Required if parallelUploads > 1 */
|
|
121
|
+
parallelChunkSize?: number;
|
|
122
|
+
|
|
123
|
+
/** Service for computing checksums of uploaded chunks */
|
|
124
|
+
checksumService: ChecksumService;
|
|
125
|
+
|
|
126
|
+
/** Strategy configuration for determining upload approach (single/parallel/chunked) */
|
|
127
|
+
uploadStrategy?: UploadStrategyConfig;
|
|
128
|
+
|
|
129
|
+
/** Smart chunking configuration for adaptive chunk sizes based on network conditions */
|
|
130
|
+
smartChunking?: SmartChunkerConfig;
|
|
131
|
+
|
|
132
|
+
/** Network monitoring configuration for tracking upload performance */
|
|
133
|
+
networkMonitoring?: NetworkMonitorConfig;
|
|
134
|
+
|
|
135
|
+
/** Upload metrics configuration for performance insights */
|
|
136
|
+
uploadMetrics?: UploadMetricsConfig;
|
|
137
|
+
|
|
138
|
+
/** HTTP client with connection pooling support */
|
|
139
|
+
httpClient: HttpClient;
|
|
140
|
+
|
|
141
|
+
/** Service for generating unique IDs */
|
|
142
|
+
generateId: IdGenerationService;
|
|
143
|
+
|
|
144
|
+
/** Client-side storage for upload resumption data */
|
|
145
|
+
clientStorage: ClientStorage;
|
|
146
|
+
|
|
147
|
+
/** Platform-specific file reading service */
|
|
148
|
+
fileReader: FileReaderService<UploadInput>;
|
|
149
|
+
|
|
150
|
+
/** Logger for debugging and monitoring */
|
|
151
|
+
logger: Logger;
|
|
152
|
+
|
|
153
|
+
/** Service for computing file fingerprints for resumption */
|
|
154
|
+
fingerprintService: FingerprintService<UploadInput>;
|
|
155
|
+
|
|
156
|
+
/** Whether to store fingerprints for upload resumption. Defaults to true */
|
|
157
|
+
storeFingerprintForResuming: boolean;
|
|
158
|
+
|
|
159
|
+
/** Factory for creating WebSocket connections */
|
|
160
|
+
webSocketFactory: WebSocketFactory;
|
|
161
|
+
|
|
162
|
+
/** Factory for creating abort controllers */
|
|
163
|
+
abortControllerFactory: AbortControllerFactory;
|
|
164
|
+
|
|
165
|
+
/** Platform-specific service for timers and async operations */
|
|
166
|
+
platformService: PlatformService;
|
|
167
|
+
|
|
168
|
+
/** Global error handler for all upload operations */
|
|
169
|
+
onError?: (error: Error) => void;
|
|
170
|
+
|
|
171
|
+
/** WebSocket event handler for real-time upload/flow events */
|
|
172
|
+
onEvent?: UploadistaWebSocketEventHandler;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Optional authentication configuration.
|
|
176
|
+
* Supports two modes:
|
|
177
|
+
* - Direct: Bring your own auth (headers, cookies, custom tokens)
|
|
178
|
+
* - SaaS: Standard JWT token exchange with auth server
|
|
179
|
+
*
|
|
180
|
+
* If omitted, client operates in no-auth mode (backward compatible).
|
|
181
|
+
*
|
|
182
|
+
* @example Direct mode with Bearer token
|
|
183
|
+
* ```typescript
|
|
184
|
+
* auth: {
|
|
185
|
+
* mode: 'direct',
|
|
186
|
+
* getCredentials: () => ({
|
|
187
|
+
* headers: { 'Authorization': 'Bearer token123' }
|
|
188
|
+
* })
|
|
189
|
+
* }
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @example SaaS mode with auth server
|
|
193
|
+
* ```typescript
|
|
194
|
+
* auth: {
|
|
195
|
+
* mode: 'saas',
|
|
196
|
+
* authServerUrl: 'https://auth.myapp.com/token',
|
|
197
|
+
* getCredentials: () => ({ username: 'user', password: 'pass' })
|
|
198
|
+
* }
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
auth?: AuthConfig;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Default connection pooling configuration with health monitoring.
|
|
206
|
+
*
|
|
207
|
+
* Optimized for typical upload scenarios with support for HTTP/2 multiplexing,
|
|
208
|
+
* connection reuse, and automatic retry on connection errors.
|
|
209
|
+
*/
|
|
210
|
+
export const defaultConnectionPoolingConfig: ConnectionPoolConfig = {
|
|
211
|
+
/** Maximum concurrent connections per host */
|
|
212
|
+
maxConnectionsPerHost: 8,
|
|
213
|
+
/** Timeout for establishing new connections in milliseconds */
|
|
214
|
+
connectionTimeout: 20000,
|
|
215
|
+
/** Keep-alive timeout for idle connections in milliseconds */
|
|
216
|
+
keepAliveTimeout: 90000,
|
|
217
|
+
/** Enable HTTP/2 for connection multiplexing */
|
|
218
|
+
enableHttp2: true,
|
|
219
|
+
/** Automatically retry requests on connection errors */
|
|
220
|
+
retryOnConnectionError: true,
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Creates a unified Uploadista client for file uploads and flow processing.
|
|
225
|
+
*
|
|
226
|
+
* This is the primary factory function for creating an Uploadista client instance.
|
|
227
|
+
* It configures all upload capabilities including:
|
|
228
|
+
* - Resumable chunked uploads with automatic retry
|
|
229
|
+
* - Parallel upload streams for large files
|
|
230
|
+
* - Smart chunking based on network conditions
|
|
231
|
+
* - Flow-based file processing pipelines
|
|
232
|
+
* - WebSocket support for real-time progress
|
|
233
|
+
* - Authentication (direct, SaaS, or no-auth modes)
|
|
234
|
+
*
|
|
235
|
+
* The client automatically:
|
|
236
|
+
* - Fetches server capabilities and adapts upload strategy
|
|
237
|
+
* - Monitors network performance for optimal chunking
|
|
238
|
+
* - Stores upload state for resumption across sessions
|
|
239
|
+
* - Manages WebSocket connections for progress tracking
|
|
240
|
+
*
|
|
241
|
+
* @template UploadInput - Platform-specific file type (File, Blob, Buffer, etc.)
|
|
242
|
+
* @param options - Comprehensive client configuration
|
|
243
|
+
* @returns Uploadista client instance with upload and flow methods
|
|
244
|
+
*
|
|
245
|
+
* @example Basic browser setup
|
|
246
|
+
* ```typescript
|
|
247
|
+
* import { createUploadistaClient } from '@uploadista/client-core';
|
|
248
|
+
* import { browserServices } from '@uploadista/client-browser';
|
|
249
|
+
*
|
|
250
|
+
* const client = createUploadistaClient({
|
|
251
|
+
* baseUrl: 'https://upload.example.com',
|
|
252
|
+
* storageId: 'my-storage',
|
|
253
|
+
* chunkSize: 5 * 1024 * 1024, // 5MB chunks
|
|
254
|
+
* ...browserServices,
|
|
255
|
+
* });
|
|
256
|
+
*
|
|
257
|
+
* // Upload a file
|
|
258
|
+
* const { abort } = await client.upload(file, {
|
|
259
|
+
* onProgress: (progress) => console.log(`${progress}% complete`),
|
|
260
|
+
* onSuccess: (result) => console.log('Upload complete:', result),
|
|
261
|
+
* });
|
|
262
|
+
* ```
|
|
263
|
+
*
|
|
264
|
+
* @example Upload with flow processing
|
|
265
|
+
* ```typescript
|
|
266
|
+
* const client = createUploadistaClient(config);
|
|
267
|
+
*
|
|
268
|
+
* // Upload and process through a flow
|
|
269
|
+
* const { abort, jobId } = await client.uploadWithFlow(file, {
|
|
270
|
+
* flowId: 'image-optimization-flow',
|
|
271
|
+
* storageId: 'images',
|
|
272
|
+
* outputNodeId: 'optimized-output',
|
|
273
|
+
* }, {
|
|
274
|
+
* onProgress: (progress) => console.log(`${progress}%`),
|
|
275
|
+
* onSuccess: (result) => console.log('Processed:', result),
|
|
276
|
+
* });
|
|
277
|
+
*
|
|
278
|
+
* // Monitor job status
|
|
279
|
+
* const status = await client.getJobStatus(jobId);
|
|
280
|
+
* ```
|
|
281
|
+
*
|
|
282
|
+
* @example Parallel uploads for large files
|
|
283
|
+
* ```typescript
|
|
284
|
+
* const client = createUploadistaClient({
|
|
285
|
+
* baseUrl: 'https://upload.example.com',
|
|
286
|
+
* storageId: 'large-files',
|
|
287
|
+
* chunkSize: 10 * 1024 * 1024, // 10MB
|
|
288
|
+
* parallelUploads: 4, // 4 concurrent streams
|
|
289
|
+
* parallelChunkSize: 5 * 1024 * 1024, // 5MB per stream
|
|
290
|
+
* ...browserServices,
|
|
291
|
+
* });
|
|
292
|
+
*
|
|
293
|
+
* await client.upload(largeFile);
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* @example With authentication
|
|
297
|
+
* ```typescript
|
|
298
|
+
* const client = createUploadistaClient({
|
|
299
|
+
* baseUrl: 'https://upload.example.com',
|
|
300
|
+
* storageId: 'protected',
|
|
301
|
+
* chunkSize: 5 * 1024 * 1024,
|
|
302
|
+
* auth: {
|
|
303
|
+
* mode: 'direct',
|
|
304
|
+
* getCredentials: async () => ({
|
|
305
|
+
* headers: {
|
|
306
|
+
* 'Authorization': `Bearer ${await getToken()}`,
|
|
307
|
+
* },
|
|
308
|
+
* }),
|
|
309
|
+
* },
|
|
310
|
+
* ...browserServices,
|
|
311
|
+
* });
|
|
312
|
+
* ```
|
|
313
|
+
*
|
|
314
|
+
* @example Smart chunking with network monitoring
|
|
315
|
+
* ```typescript
|
|
316
|
+
* const client = createUploadistaClient({
|
|
317
|
+
* baseUrl: 'https://upload.example.com',
|
|
318
|
+
* storageId: 'adaptive',
|
|
319
|
+
* chunkSize: 1 * 1024 * 1024, // Fallback: 1MB
|
|
320
|
+
* smartChunking: {
|
|
321
|
+
* enabled: true,
|
|
322
|
+
* minChunkSize: 256 * 1024, // 256KB min
|
|
323
|
+
* maxChunkSize: 10 * 1024 * 1024, // 10MB max
|
|
324
|
+
* },
|
|
325
|
+
* networkMonitoring: {
|
|
326
|
+
* slowThreshold: 50 * 1024, // 50 KB/s
|
|
327
|
+
* fastThreshold: 5 * 1024 * 1024, // 5 MB/s
|
|
328
|
+
* },
|
|
329
|
+
* ...browserServices,
|
|
330
|
+
* });
|
|
331
|
+
*
|
|
332
|
+
* // Monitor network conditions
|
|
333
|
+
* const condition = client.getNetworkCondition();
|
|
334
|
+
* console.log(`Network: ${condition.type} (confidence: ${condition.confidence})`);
|
|
335
|
+
* ```
|
|
336
|
+
*
|
|
337
|
+
* @see {@link UploadistaClientOptions} for full configuration options
|
|
338
|
+
* @see {@link UploadistaUploadOptions} for per-upload options
|
|
339
|
+
*/
|
|
340
|
+
export function createUploadistaClient<UploadInput>({
|
|
341
|
+
baseUrl: _baseUrl,
|
|
342
|
+
uploadistaBasePath = "uploadista",
|
|
343
|
+
storageId,
|
|
344
|
+
retryDelays = [1000, 3000, 5000],
|
|
345
|
+
chunkSize,
|
|
346
|
+
parallelUploads = 1,
|
|
347
|
+
parallelChunkSize,
|
|
348
|
+
uploadStrategy,
|
|
349
|
+
smartChunking,
|
|
350
|
+
networkMonitoring,
|
|
351
|
+
uploadMetrics,
|
|
352
|
+
checksumService,
|
|
353
|
+
onEvent,
|
|
354
|
+
generateId,
|
|
355
|
+
httpClient,
|
|
356
|
+
logger = createLogger(true),
|
|
357
|
+
fileReader,
|
|
358
|
+
fingerprintService,
|
|
359
|
+
clientStorage,
|
|
360
|
+
storeFingerprintForResuming = true,
|
|
361
|
+
webSocketFactory,
|
|
362
|
+
abortControllerFactory,
|
|
363
|
+
platformService,
|
|
364
|
+
auth,
|
|
365
|
+
}: UploadistaClientOptions<UploadInput>) {
|
|
366
|
+
const baseUrl = _baseUrl.replace(/\/$/, "");
|
|
367
|
+
|
|
368
|
+
// Create auth manager based on configuration
|
|
369
|
+
const authManager: AuthManager = auth
|
|
370
|
+
? auth.mode === "direct"
|
|
371
|
+
? new DirectAuthManager(auth, platformService, logger)
|
|
372
|
+
: new SaasAuthManager(auth, httpClient)
|
|
373
|
+
: new NoAuthManager();
|
|
374
|
+
|
|
375
|
+
// Log auth mode for debugging (without exposing credentials)
|
|
376
|
+
if (auth) {
|
|
377
|
+
logger.log(
|
|
378
|
+
`Authentication enabled in ${auth.mode} mode${auth.mode === "saas" ? ` (server: ${auth.authServerUrl})` : ""}`,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Create the unified API with auth support
|
|
383
|
+
const uploadistaApi = createUploadistaApi(baseUrl, uploadistaBasePath, {
|
|
384
|
+
logger,
|
|
385
|
+
httpClient,
|
|
386
|
+
authManager,
|
|
387
|
+
webSocketFactory,
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Initialize smart chunking components
|
|
391
|
+
const networkMonitor = new NetworkMonitor(networkMonitoring);
|
|
392
|
+
const metrics = new UploadMetrics(uploadMetrics);
|
|
393
|
+
|
|
394
|
+
// Cache for server capabilities
|
|
395
|
+
let cachedCapabilities: DataStoreCapabilities | null = null;
|
|
396
|
+
|
|
397
|
+
const getCapabilities = async (): Promise<DataStoreCapabilities> => {
|
|
398
|
+
if (cachedCapabilities) {
|
|
399
|
+
return cachedCapabilities;
|
|
400
|
+
}
|
|
401
|
+
cachedCapabilities = await uploadistaApi.getCapabilities(storageId);
|
|
402
|
+
return cachedCapabilities;
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// Initialize smart chunker with datastore constraints from server capabilities
|
|
406
|
+
let smartChunker: SmartChunker;
|
|
407
|
+
const initializeSmartChunker = async () => {
|
|
408
|
+
if (smartChunker) return smartChunker;
|
|
409
|
+
|
|
410
|
+
const capabilities = await getCapabilities();
|
|
411
|
+
|
|
412
|
+
const datastoreConstraints =
|
|
413
|
+
capabilities.minChunkSize &&
|
|
414
|
+
capabilities.maxChunkSize &&
|
|
415
|
+
capabilities.optimalChunkSize
|
|
416
|
+
? {
|
|
417
|
+
minChunkSize: capabilities.minChunkSize,
|
|
418
|
+
maxChunkSize: capabilities.maxChunkSize,
|
|
419
|
+
optimalChunkSize: capabilities.optimalChunkSize,
|
|
420
|
+
requiresOrderedChunks: capabilities.requiresOrderedChunks,
|
|
421
|
+
}
|
|
422
|
+
: undefined;
|
|
423
|
+
|
|
424
|
+
smartChunker = new SmartChunker(networkMonitor, {
|
|
425
|
+
enabled: true,
|
|
426
|
+
...smartChunking,
|
|
427
|
+
fallbackChunkSize: chunkSize,
|
|
428
|
+
datastoreConstraints,
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
logger.log(
|
|
432
|
+
`Smart chunker initialized with datastore constraints: ${JSON.stringify(datastoreConstraints)}`,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
return smartChunker;
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// WebSocket management (uses uploadistaApi for both upload and flow websockets)
|
|
439
|
+
const wsManager = new UploadistaWebSocketManager(
|
|
440
|
+
uploadistaApi,
|
|
441
|
+
logger,
|
|
442
|
+
onEvent,
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Upload a file
|
|
447
|
+
*/
|
|
448
|
+
const upload = async (
|
|
449
|
+
file: UploadInput,
|
|
450
|
+
{
|
|
451
|
+
uploadLengthDeferred = false,
|
|
452
|
+
uploadSize,
|
|
453
|
+
onProgress,
|
|
454
|
+
onChunkComplete,
|
|
455
|
+
onSuccess,
|
|
456
|
+
onShouldRetry,
|
|
457
|
+
onError,
|
|
458
|
+
}: UploadistaUploadOptions = {},
|
|
459
|
+
): Promise<{ abort: () => void }> => {
|
|
460
|
+
let uploadId: string | null = null;
|
|
461
|
+
let uploadIdStorageKey: string | null = null;
|
|
462
|
+
|
|
463
|
+
const fingerprint = await fingerprintService.computeFingerprint(
|
|
464
|
+
file,
|
|
465
|
+
`${baseUrl}/${uploadistaBasePath}/api/upload`,
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
logger.log(`fingerprint: ${fingerprint}`);
|
|
469
|
+
if (!fingerprint) {
|
|
470
|
+
throw new Error("unable calculate fingerprint for this input file");
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const previousUploads = await findPreviousUploads(
|
|
474
|
+
clientStorage,
|
|
475
|
+
fingerprint,
|
|
476
|
+
);
|
|
477
|
+
if (previousUploads.length > 0 && previousUploads[0] != null) {
|
|
478
|
+
const previousUpload = resumeFromPreviousUpload(previousUploads[0]);
|
|
479
|
+
uploadIdStorageKey = previousUpload.clientStorageKey;
|
|
480
|
+
uploadId = previousUpload.uploadId;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const source = await fileReader.openFile(file, chunkSize);
|
|
484
|
+
|
|
485
|
+
const size = calculateFileSize(source.size, {
|
|
486
|
+
uploadLengthDeferred,
|
|
487
|
+
uploadSize,
|
|
488
|
+
});
|
|
489
|
+
source.size = size;
|
|
490
|
+
|
|
491
|
+
const initializedSmartChunker = await initializeSmartChunker();
|
|
492
|
+
|
|
493
|
+
const isSmartChunkingEnabled = smartChunking?.enabled !== false;
|
|
494
|
+
if (isSmartChunkingEnabled) {
|
|
495
|
+
metrics.startSession(fingerprint, size || 0, true);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const capabilities = await getCapabilities();
|
|
499
|
+
|
|
500
|
+
const negotiatedStrategy = negotiateUploadStrategy({
|
|
501
|
+
capabilities,
|
|
502
|
+
fileSize: size,
|
|
503
|
+
chunkSize,
|
|
504
|
+
parallelUploads,
|
|
505
|
+
uploadLengthDeferred,
|
|
506
|
+
strategyConfig: uploadStrategy,
|
|
507
|
+
logger,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
if (negotiatedStrategy.strategy === "parallel") {
|
|
511
|
+
logger.log(
|
|
512
|
+
`Using parallel upload with ${negotiatedStrategy.parallelUploads} streams`,
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
const parallelResult = await startParallelUpload({
|
|
516
|
+
checksumService,
|
|
517
|
+
source,
|
|
518
|
+
storageId,
|
|
519
|
+
fingerprint,
|
|
520
|
+
uploadLengthDeferred,
|
|
521
|
+
parallelUploads: negotiatedStrategy.parallelUploads,
|
|
522
|
+
parallelChunkSize,
|
|
523
|
+
retryDelays,
|
|
524
|
+
smartChunker: initializedSmartChunker,
|
|
525
|
+
uploadistaApi,
|
|
526
|
+
logger,
|
|
527
|
+
smartChunking,
|
|
528
|
+
metrics,
|
|
529
|
+
clientStorage,
|
|
530
|
+
generateId,
|
|
531
|
+
storeFingerprintForResuming,
|
|
532
|
+
abortControllerFactory,
|
|
533
|
+
platformService,
|
|
534
|
+
openWebSocket: (id) => {
|
|
535
|
+
wsManager.openUploadWebSocket(id);
|
|
536
|
+
// Note: WebSocket opening is now async due to auth, but this callback is sync
|
|
537
|
+
// The WebSocket will be opened in the background
|
|
538
|
+
return null as unknown as WebSocketLike;
|
|
539
|
+
},
|
|
540
|
+
closeWebSocket: (id) => wsManager.closeUploadWebSocket(id),
|
|
541
|
+
terminate: (id) =>
|
|
542
|
+
terminate(id, uploadistaApi, platformService, retryDelays),
|
|
543
|
+
onProgress,
|
|
544
|
+
onChunkComplete,
|
|
545
|
+
onSuccess,
|
|
546
|
+
onError,
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
if (parallelResult) {
|
|
550
|
+
return {
|
|
551
|
+
abort: async () => {
|
|
552
|
+
await parallelResult.abort();
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
logger.log("Parallel upload failed, falling back to single upload");
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Single upload path
|
|
561
|
+
const result = await startSingleUpload({
|
|
562
|
+
source,
|
|
563
|
+
storageId,
|
|
564
|
+
uploadId,
|
|
565
|
+
platformService,
|
|
566
|
+
uploadIdStorageKey,
|
|
567
|
+
checksumService,
|
|
568
|
+
fingerprint,
|
|
569
|
+
uploadLengthDeferred,
|
|
570
|
+
uploadistaApi,
|
|
571
|
+
logger,
|
|
572
|
+
clientStorage,
|
|
573
|
+
generateId,
|
|
574
|
+
storeFingerprintForResuming,
|
|
575
|
+
openWebSocket: (id) => {
|
|
576
|
+
wsManager.openUploadWebSocket(id);
|
|
577
|
+
// Note: WebSocket opening is now async due to auth, but this callback is sync
|
|
578
|
+
// The WebSocket will be opened in the background
|
|
579
|
+
return null as unknown as WebSocketLike;
|
|
580
|
+
},
|
|
581
|
+
closeWebSocket: (id) => wsManager.closeUploadWebSocket(id),
|
|
582
|
+
onProgress,
|
|
583
|
+
onChunkComplete,
|
|
584
|
+
onSuccess,
|
|
585
|
+
onError,
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
if (result) {
|
|
589
|
+
const abortController = abortControllerFactory.create();
|
|
590
|
+
const { uploadId, uploadIdStorageKey, offset } = result;
|
|
591
|
+
|
|
592
|
+
let timeoutId: Timeout | null = null;
|
|
593
|
+
|
|
594
|
+
performUpload({
|
|
595
|
+
platformService,
|
|
596
|
+
uploadId,
|
|
597
|
+
offset,
|
|
598
|
+
source,
|
|
599
|
+
uploadLengthDeferred,
|
|
600
|
+
retryDelays,
|
|
601
|
+
smartChunker: initializedSmartChunker,
|
|
602
|
+
uploadistaApi,
|
|
603
|
+
logger,
|
|
604
|
+
smartChunking,
|
|
605
|
+
metrics,
|
|
606
|
+
abortController,
|
|
607
|
+
onProgress,
|
|
608
|
+
onChunkComplete,
|
|
609
|
+
onSuccess,
|
|
610
|
+
onShouldRetry,
|
|
611
|
+
onRetry: (timeout) => {
|
|
612
|
+
timeoutId = timeout;
|
|
613
|
+
},
|
|
614
|
+
onError,
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
return {
|
|
618
|
+
abort: () => {
|
|
619
|
+
abort({
|
|
620
|
+
platformService,
|
|
621
|
+
uploadId,
|
|
622
|
+
uploadIdStorageKey,
|
|
623
|
+
retryTimeout: timeoutId,
|
|
624
|
+
shouldTerminate: true,
|
|
625
|
+
abortController,
|
|
626
|
+
uploadistaApi,
|
|
627
|
+
retryDelays,
|
|
628
|
+
clientStorage,
|
|
629
|
+
});
|
|
630
|
+
},
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return {
|
|
635
|
+
abort: () => {},
|
|
636
|
+
};
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// Run validation on client creation
|
|
640
|
+
validateAndThrow(
|
|
641
|
+
{
|
|
642
|
+
baseUrl,
|
|
643
|
+
storageId,
|
|
644
|
+
chunkSize,
|
|
645
|
+
parallelUploads,
|
|
646
|
+
parallelChunkSize,
|
|
647
|
+
uploadStrategy,
|
|
648
|
+
},
|
|
649
|
+
logger,
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Upload a file through a flow (using streaming-input-node)
|
|
654
|
+
*/
|
|
655
|
+
const uploadWithFlow = async (
|
|
656
|
+
file: UploadInput,
|
|
657
|
+
flowConfig: FlowUploadConfig,
|
|
658
|
+
{
|
|
659
|
+
onProgress,
|
|
660
|
+
onChunkComplete,
|
|
661
|
+
onSuccess,
|
|
662
|
+
onShouldRetry,
|
|
663
|
+
onJobStart,
|
|
664
|
+
onError,
|
|
665
|
+
}: Omit<
|
|
666
|
+
UploadistaUploadOptions,
|
|
667
|
+
"uploadLengthDeferred" | "uploadSize" | "metadata"
|
|
668
|
+
> = {},
|
|
669
|
+
): Promise<{ abort: () => void; jobId: string }> => {
|
|
670
|
+
const source = await fileReader.openFile(file, chunkSize);
|
|
671
|
+
|
|
672
|
+
const initializedSmartChunker = await initializeSmartChunker();
|
|
673
|
+
|
|
674
|
+
const isSmartChunkingEnabled = smartChunking?.enabled !== false;
|
|
675
|
+
if (isSmartChunkingEnabled) {
|
|
676
|
+
const fingerprint = await fingerprintService.computeFingerprint(
|
|
677
|
+
file,
|
|
678
|
+
`${baseUrl}/${uploadistaBasePath}/api/flow`,
|
|
679
|
+
);
|
|
680
|
+
metrics.startSession(fingerprint || "unknown", source.size || 0, true);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const result = await startFlowUpload({
|
|
684
|
+
source,
|
|
685
|
+
flowConfig,
|
|
686
|
+
uploadistaApi,
|
|
687
|
+
logger,
|
|
688
|
+
platformService,
|
|
689
|
+
openWebSocket: (id) => wsManager.openFlowWebSocket(id),
|
|
690
|
+
closeWebSocket: (id) => wsManager.closeWebSocket(id),
|
|
691
|
+
onProgress,
|
|
692
|
+
onChunkComplete,
|
|
693
|
+
onSuccess,
|
|
694
|
+
onJobStart,
|
|
695
|
+
onError,
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
if (!result) {
|
|
699
|
+
return {
|
|
700
|
+
abort: () => {},
|
|
701
|
+
jobId: "",
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const { jobId, uploadFile, inputNodeId } = result;
|
|
706
|
+
const abortController = abortControllerFactory.create();
|
|
707
|
+
|
|
708
|
+
// Open upload WebSocket to receive upload progress events
|
|
709
|
+
await wsManager.openUploadWebSocket(uploadFile.id);
|
|
710
|
+
|
|
711
|
+
let timeoutId: Timeout | null = null;
|
|
712
|
+
|
|
713
|
+
performFlowUpload({
|
|
714
|
+
jobId,
|
|
715
|
+
uploadFile,
|
|
716
|
+
inputNodeId,
|
|
717
|
+
offset: uploadFile.offset,
|
|
718
|
+
source,
|
|
719
|
+
retryDelays,
|
|
720
|
+
smartChunker: initializedSmartChunker,
|
|
721
|
+
uploadistaApi,
|
|
722
|
+
logger,
|
|
723
|
+
smartChunking,
|
|
724
|
+
metrics,
|
|
725
|
+
platformService,
|
|
726
|
+
abortController,
|
|
727
|
+
onProgress,
|
|
728
|
+
onChunkComplete,
|
|
729
|
+
onSuccess,
|
|
730
|
+
onShouldRetry,
|
|
731
|
+
onRetry: (timeout) => {
|
|
732
|
+
timeoutId = timeout;
|
|
733
|
+
},
|
|
734
|
+
onError,
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
return {
|
|
738
|
+
abort: () => {
|
|
739
|
+
abortController.abort();
|
|
740
|
+
if (timeoutId) {
|
|
741
|
+
platformService.clearTimeout(timeoutId);
|
|
742
|
+
}
|
|
743
|
+
// Close both flow and upload WebSockets
|
|
744
|
+
wsManager.closeWebSocket(jobId);
|
|
745
|
+
wsManager.closeUploadWebSocket(uploadFile.id);
|
|
746
|
+
},
|
|
747
|
+
jobId,
|
|
748
|
+
};
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
return {
|
|
752
|
+
// Upload operations
|
|
753
|
+
upload,
|
|
754
|
+
uploadWithFlow,
|
|
755
|
+
abort: (params: Parameters<typeof abort>[0]) => abort(params),
|
|
756
|
+
|
|
757
|
+
// Flow operations
|
|
758
|
+
getFlow: async (flowId: string) => {
|
|
759
|
+
const { status, flow } = await uploadistaApi.getFlow(flowId);
|
|
760
|
+
return { status, flow };
|
|
761
|
+
},
|
|
762
|
+
|
|
763
|
+
runFlow: async ({
|
|
764
|
+
flowId,
|
|
765
|
+
inputs,
|
|
766
|
+
storageId: flowStorageId,
|
|
767
|
+
}: {
|
|
768
|
+
flowId: string;
|
|
769
|
+
inputs: Record<string, unknown>;
|
|
770
|
+
storageId?: string;
|
|
771
|
+
}) => {
|
|
772
|
+
const { status, job } = await uploadistaApi.runFlow(
|
|
773
|
+
flowId,
|
|
774
|
+
flowStorageId || storageId,
|
|
775
|
+
inputs,
|
|
776
|
+
);
|
|
777
|
+
return { status, job };
|
|
778
|
+
},
|
|
779
|
+
|
|
780
|
+
continueFlow: async ({
|
|
781
|
+
jobId,
|
|
782
|
+
nodeId,
|
|
783
|
+
newData,
|
|
784
|
+
contentType,
|
|
785
|
+
}: {
|
|
786
|
+
jobId: string;
|
|
787
|
+
nodeId: string;
|
|
788
|
+
newData: unknown;
|
|
789
|
+
contentType?: "application/json" | "application/octet-stream";
|
|
790
|
+
}) => {
|
|
791
|
+
return uploadistaApi.continueFlow(jobId, nodeId, newData, {
|
|
792
|
+
contentType,
|
|
793
|
+
});
|
|
794
|
+
},
|
|
795
|
+
|
|
796
|
+
// Job operations (unified for both uploads and flows)
|
|
797
|
+
getJobStatus: async (jobId: string) => {
|
|
798
|
+
return uploadistaApi.getJobStatus(jobId);
|
|
799
|
+
},
|
|
800
|
+
|
|
801
|
+
// WebSocket management methods
|
|
802
|
+
openUploadWebSocket: (uploadId: string) =>
|
|
803
|
+
wsManager.openUploadWebSocket(uploadId),
|
|
804
|
+
openFlowWebSocket: (jobId: string) => wsManager.openFlowWebSocket(jobId),
|
|
805
|
+
openWebSocket: (id: string) => wsManager.openWebSocket(id),
|
|
806
|
+
closeWebSocket: (id: string) => wsManager.closeWebSocket(id),
|
|
807
|
+
closeAllWebSockets: () => wsManager.closeAll(),
|
|
808
|
+
sendPing: (jobId: string) => wsManager.sendPing(jobId),
|
|
809
|
+
isWebSocketConnected: (id: string) => wsManager.isConnected(id),
|
|
810
|
+
getWebSocketConnectionCount: () => wsManager.getConnectionCount(),
|
|
811
|
+
getWebSocketConnectionCountByType: () =>
|
|
812
|
+
wsManager.getConnectionCountByType(),
|
|
813
|
+
|
|
814
|
+
// Smart chunking utilities
|
|
815
|
+
getNetworkMetrics: () => networkMonitor.getCurrentMetrics(),
|
|
816
|
+
getNetworkCondition: () => networkMonitor.getNetworkCondition(),
|
|
817
|
+
getChunkingInsights: () => metrics.getPerformanceInsights(),
|
|
818
|
+
exportMetrics: () => metrics.exportMetrics(),
|
|
819
|
+
|
|
820
|
+
// Connection pooling utilities
|
|
821
|
+
getConnectionMetrics: () => uploadistaApi.getConnectionMetrics(),
|
|
822
|
+
getDetailedConnectionMetrics: () =>
|
|
823
|
+
uploadistaApi.getDetailedConnectionMetrics(),
|
|
824
|
+
warmupConnections: (urls: string[]) =>
|
|
825
|
+
uploadistaApi.warmupConnections(urls),
|
|
826
|
+
|
|
827
|
+
// Smart chunking insights
|
|
828
|
+
getConnectionPoolingInsights: async () => {
|
|
829
|
+
const chunker = await initializeSmartChunker();
|
|
830
|
+
return chunker.getConnectionPoolingInsights();
|
|
831
|
+
},
|
|
832
|
+
|
|
833
|
+
resetMetrics: async () => {
|
|
834
|
+
networkMonitor.reset();
|
|
835
|
+
const chunker = await initializeSmartChunker();
|
|
836
|
+
chunker.reset();
|
|
837
|
+
metrics.reset();
|
|
838
|
+
},
|
|
839
|
+
|
|
840
|
+
// Configuration validation
|
|
841
|
+
validateConfiguration: (options: UploadistaClientOptions<UploadInput>) => {
|
|
842
|
+
return validateConfiguration(options, defaultClientCapabilities, logger);
|
|
843
|
+
},
|
|
844
|
+
|
|
845
|
+
validateConfigurationAsync: async (
|
|
846
|
+
options: UploadistaClientOptions<UploadInput>,
|
|
847
|
+
) => {
|
|
848
|
+
const errors: string[] = [];
|
|
849
|
+
const warnings: string[] = [];
|
|
850
|
+
|
|
851
|
+
// Fetch capabilities using the authenticated HTTP client
|
|
852
|
+
const capabilities = await uploadistaApi.getCapabilities(
|
|
853
|
+
options.storageId,
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
const validation = validateConfiguration(options, capabilities, logger);
|
|
857
|
+
errors.push(...validation.errors);
|
|
858
|
+
warnings.push(...validation.warnings);
|
|
859
|
+
|
|
860
|
+
return {
|
|
861
|
+
valid: errors.length === 0,
|
|
862
|
+
errors,
|
|
863
|
+
warnings,
|
|
864
|
+
capabilities,
|
|
865
|
+
};
|
|
866
|
+
},
|
|
867
|
+
|
|
868
|
+
getCapabilities,
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Uploadista client instance type.
|
|
874
|
+
*
|
|
875
|
+
* The client provides methods for:
|
|
876
|
+
* - **Upload operations**: upload(), uploadWithFlow()
|
|
877
|
+
* - **Flow operations**: getFlow(), runFlow(), continueFlow()
|
|
878
|
+
* - **Job management**: getJobStatus()
|
|
879
|
+
* - **WebSocket management**: openUploadWebSocket(), openFlowWebSocket(), closeWebSocket()
|
|
880
|
+
* - **Metrics and diagnostics**: getNetworkMetrics(), getChunkingInsights(), exportMetrics()
|
|
881
|
+
* - **Connection pooling**: getConnectionMetrics(), warmupConnections()
|
|
882
|
+
* - **Configuration validation**: validateConfiguration(), validateConfigurationAsync()
|
|
883
|
+
*
|
|
884
|
+
* @example Basic usage
|
|
885
|
+
* ```typescript
|
|
886
|
+
* const client = createUploadistaClient(config);
|
|
887
|
+
*
|
|
888
|
+
* // Upload a file
|
|
889
|
+
* await client.upload(file, {
|
|
890
|
+
* onProgress: (progress) => console.log(`${progress}%`),
|
|
891
|
+
* onSuccess: (result) => console.log('Done:', result.id),
|
|
892
|
+
* });
|
|
893
|
+
*
|
|
894
|
+
* // Get network metrics
|
|
895
|
+
* const metrics = client.getNetworkMetrics();
|
|
896
|
+
* console.log(`Speed: ${metrics.averageSpeed / 1024} KB/s`);
|
|
897
|
+
* ```
|
|
898
|
+
*
|
|
899
|
+
* @see {@link createUploadistaClient} for creating an instance
|
|
900
|
+
*/
|
|
901
|
+
export type UploadistaClient = ReturnType<typeof createUploadistaClient>;
|