@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,275 @@
|
|
|
1
|
+
import type { FlowEvent } from "@uploadista/core/flow";
|
|
2
|
+
import type { UploadEvent } from "@uploadista/core/types";
|
|
3
|
+
import { webSocketMessageSchema } from "@uploadista/core/types";
|
|
4
|
+
import type { Logger } from "../logger";
|
|
5
|
+
import type { WebSocketLike } from "../services/websocket-service";
|
|
6
|
+
import type { UploadistaApi } from "./uploadista-api";
|
|
7
|
+
|
|
8
|
+
export type UploadistaEvent = UploadEvent | FlowEvent;
|
|
9
|
+
|
|
10
|
+
export type UploadistaWebSocketEventHandler = (event: UploadistaEvent) => void;
|
|
11
|
+
|
|
12
|
+
export type UploadistaWebSocketMessage =
|
|
13
|
+
| { type: "connection"; message: string; id: string; timestamp: string }
|
|
14
|
+
| {
|
|
15
|
+
type: "subscribed";
|
|
16
|
+
payload: { uploadId?: string; jobId?: string };
|
|
17
|
+
timestamp: string;
|
|
18
|
+
}
|
|
19
|
+
| { type: "error"; message: string; code?: string }
|
|
20
|
+
| { type: "pong"; timestamp: string }
|
|
21
|
+
| { type: "upload_event"; payload: UploadEvent }
|
|
22
|
+
| { type: "flow_event"; payload: FlowEvent };
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Unified WebSocket management for both upload and flow events
|
|
26
|
+
*/
|
|
27
|
+
export class UploadistaWebSocketManager {
|
|
28
|
+
private uploadWebsockets = new Map<string, WebSocketLike>();
|
|
29
|
+
private flowWebsockets = new Map<string, WebSocketLike>();
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
private uploadistaApi: UploadistaApi,
|
|
33
|
+
private logger: Logger,
|
|
34
|
+
private onEvent?: UploadistaWebSocketEventHandler,
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Open a WebSocket connection for upload events
|
|
39
|
+
*/
|
|
40
|
+
async openUploadWebSocket(uploadId: string): Promise<WebSocketLike> {
|
|
41
|
+
// Close existing connection if any
|
|
42
|
+
this.closeUploadWebSocket(uploadId);
|
|
43
|
+
|
|
44
|
+
const ws = await this.uploadistaApi.openUploadWebSocket(uploadId);
|
|
45
|
+
this.uploadWebsockets.set(uploadId, ws);
|
|
46
|
+
|
|
47
|
+
ws.onmessage = (event) => {
|
|
48
|
+
try {
|
|
49
|
+
const parsedEvent = webSocketMessageSchema.safeParse(
|
|
50
|
+
JSON.parse(event.data),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
if (parsedEvent.success) {
|
|
54
|
+
if (parsedEvent.data.type === "upload_event") {
|
|
55
|
+
this.onEvent?.(parsedEvent.data.payload);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
this.logger.error(
|
|
59
|
+
`Error parsing upload event: ${parsedEvent.error.message}`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
this.logger.error(`Error parsing upload event: ${error}`);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
ws.onerror = (error) => {
|
|
68
|
+
this.logger.error(`Upload WebSocket error for ${uploadId}: ${error}`);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
ws.onclose = (event) => {
|
|
72
|
+
this.logger.log(
|
|
73
|
+
`Upload WebSocket closed for ${uploadId}, \n code: ${event.code as number}, reason: ${event.reason as string}`,
|
|
74
|
+
);
|
|
75
|
+
this.uploadWebsockets.delete(uploadId);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return ws;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Open a WebSocket connection for flow/job events
|
|
83
|
+
*/
|
|
84
|
+
async openFlowWebSocket(jobId: string): Promise<WebSocketLike> {
|
|
85
|
+
// Close existing connection if any
|
|
86
|
+
this.closeFlowWebSocket(jobId);
|
|
87
|
+
|
|
88
|
+
const ws = await this.uploadistaApi.openFlowWebSocket(jobId);
|
|
89
|
+
this.flowWebsockets.set(jobId, ws);
|
|
90
|
+
|
|
91
|
+
ws.onmessage = (event) => {
|
|
92
|
+
try {
|
|
93
|
+
const message = JSON.parse(event.data) as UploadistaWebSocketMessage;
|
|
94
|
+
|
|
95
|
+
switch (message.type) {
|
|
96
|
+
case "connection":
|
|
97
|
+
this.logger.log(`Flow WebSocket connected for job: ${message.id}`);
|
|
98
|
+
break;
|
|
99
|
+
case "subscribed":
|
|
100
|
+
this.logger.log(
|
|
101
|
+
`Flow WebSocket subscribed for job: ${message.payload.jobId}`,
|
|
102
|
+
);
|
|
103
|
+
break;
|
|
104
|
+
case "error":
|
|
105
|
+
this.logger.error(
|
|
106
|
+
`Flow WebSocket error: ${message.message} for job ${jobId} with code ${message.code}`,
|
|
107
|
+
);
|
|
108
|
+
break;
|
|
109
|
+
case "pong":
|
|
110
|
+
this.logger.log(`Flow WebSocket pong received for job: ${jobId}`);
|
|
111
|
+
break;
|
|
112
|
+
case "flow_event":
|
|
113
|
+
this.onEvent?.(message.payload);
|
|
114
|
+
break;
|
|
115
|
+
default:
|
|
116
|
+
this.logger.warn(
|
|
117
|
+
`Unknown flow WebSocket message type: ${message.type}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
this.logger.error(`Error parsing flow WebSocket message:${error}`);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
ws.onerror = (error) => {
|
|
126
|
+
this.logger.error(`Flow WebSocket error for job ${jobId}: ${error}`);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
ws.onclose = (event) => {
|
|
130
|
+
this.logger.log(
|
|
131
|
+
`Flow WebSocket closed for job ${jobId}, \n code: ${event.code as number}, reason: ${event.reason as string}`,
|
|
132
|
+
);
|
|
133
|
+
this.flowWebsockets.delete(jobId);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return ws;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Open a unified WebSocket connection - automatically determines if it's for upload or flow
|
|
141
|
+
* based on the ID format (upload IDs typically start with 'upload-', job IDs start with 'job-')
|
|
142
|
+
*/
|
|
143
|
+
async openWebSocket(id: string): Promise<WebSocketLike> {
|
|
144
|
+
// Heuristic: if ID starts with 'upload-' or contains upload-related patterns, treat as upload
|
|
145
|
+
// Otherwise, treat as flow/job
|
|
146
|
+
if (id.startsWith("upload-") || id.includes("upload")) {
|
|
147
|
+
return await this.openUploadWebSocket(id);
|
|
148
|
+
}
|
|
149
|
+
return await this.openFlowWebSocket(id);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Close upload WebSocket connection
|
|
154
|
+
*/
|
|
155
|
+
closeUploadWebSocket(uploadId: string): void {
|
|
156
|
+
const ws = this.uploadWebsockets.get(uploadId);
|
|
157
|
+
if (ws) {
|
|
158
|
+
this.uploadistaApi.closeWebSocket(ws);
|
|
159
|
+
this.uploadWebsockets.delete(uploadId);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Close flow WebSocket connection
|
|
165
|
+
*/
|
|
166
|
+
closeFlowWebSocket(jobId: string): void {
|
|
167
|
+
const ws = this.flowWebsockets.get(jobId);
|
|
168
|
+
if (ws) {
|
|
169
|
+
this.uploadistaApi.closeWebSocket(ws);
|
|
170
|
+
this.flowWebsockets.delete(jobId);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Close WebSocket connection by ID (auto-detects type)
|
|
176
|
+
*/
|
|
177
|
+
closeWebSocket(id: string): void {
|
|
178
|
+
// Try both maps
|
|
179
|
+
this.closeUploadWebSocket(id);
|
|
180
|
+
this.closeFlowWebSocket(id);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Close all WebSocket connections (both upload and flow)
|
|
185
|
+
*/
|
|
186
|
+
closeAll(): void {
|
|
187
|
+
// Close all upload websockets
|
|
188
|
+
for (const [uploadId, ws] of this.uploadWebsockets.entries()) {
|
|
189
|
+
this.uploadistaApi.closeWebSocket(ws);
|
|
190
|
+
this.uploadWebsockets.delete(uploadId);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Close all flow websockets
|
|
194
|
+
for (const [jobId, ws] of this.flowWebsockets.entries()) {
|
|
195
|
+
this.uploadistaApi.closeWebSocket(ws);
|
|
196
|
+
this.flowWebsockets.delete(jobId);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Send ping to flow WebSocket
|
|
202
|
+
*/
|
|
203
|
+
sendPing(jobId: string): boolean {
|
|
204
|
+
const ws = this.flowWebsockets.get(jobId);
|
|
205
|
+
if (ws && ws.readyState === ws.OPEN) {
|
|
206
|
+
ws.send(
|
|
207
|
+
JSON.stringify({
|
|
208
|
+
type: "ping",
|
|
209
|
+
timestamp: new Date().toISOString(),
|
|
210
|
+
}),
|
|
211
|
+
);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get upload WebSocket by ID
|
|
219
|
+
*/
|
|
220
|
+
getUploadWebSocket(uploadId: string): WebSocketLike | undefined {
|
|
221
|
+
return this.uploadWebsockets.get(uploadId);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get flow WebSocket by ID
|
|
226
|
+
*/
|
|
227
|
+
getFlowWebSocket(jobId: string): WebSocketLike | undefined {
|
|
228
|
+
return this.flowWebsockets.get(jobId);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check if upload WebSocket is connected
|
|
233
|
+
*/
|
|
234
|
+
isUploadConnected(uploadId: string): boolean {
|
|
235
|
+
const ws = this.uploadWebsockets.get(uploadId);
|
|
236
|
+
return ws?.readyState === ws?.OPEN;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Check if flow WebSocket is connected
|
|
241
|
+
*/
|
|
242
|
+
isFlowConnected(jobId: string): boolean {
|
|
243
|
+
const ws = this.flowWebsockets.get(jobId);
|
|
244
|
+
return ws?.readyState === ws?.OPEN;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Check if WebSocket is connected (auto-detects type)
|
|
249
|
+
*/
|
|
250
|
+
isConnected(id: string): boolean {
|
|
251
|
+
return this.isUploadConnected(id) || this.isFlowConnected(id);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get total number of active WebSocket connections
|
|
256
|
+
*/
|
|
257
|
+
getConnectionCount(): number {
|
|
258
|
+
return this.uploadWebsockets.size + this.flowWebsockets.size;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get connection counts by type
|
|
263
|
+
*/
|
|
264
|
+
getConnectionCountByType(): {
|
|
265
|
+
upload: number;
|
|
266
|
+
flow: number;
|
|
267
|
+
total: number;
|
|
268
|
+
} {
|
|
269
|
+
return {
|
|
270
|
+
upload: this.uploadWebsockets.size,
|
|
271
|
+
flow: this.flowWebsockets.size,
|
|
272
|
+
total: this.uploadWebsockets.size + this.flowWebsockets.size,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}
|
package/src/error.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specific error types that can occur during upload and flow operations.
|
|
3
|
+
*
|
|
4
|
+
* These error names provide fine-grained categorization of failures,
|
|
5
|
+
* allowing applications to implement targeted error handling and recovery strategies.
|
|
6
|
+
*
|
|
7
|
+
* @example Error handling by type
|
|
8
|
+
* ```typescript
|
|
9
|
+
* try {
|
|
10
|
+
* await client.upload(file);
|
|
11
|
+
* } catch (error) {
|
|
12
|
+
* if (error instanceof UploadistaError) {
|
|
13
|
+
* if (error.isNetworkError()) {
|
|
14
|
+
* // Retry network-related failures
|
|
15
|
+
* console.log('Network issue, retrying...');
|
|
16
|
+
* } else if (error.name === 'UPLOAD_NOT_FOUND') {
|
|
17
|
+
* // Handle missing upload
|
|
18
|
+
* console.log('Upload not found, starting fresh');
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export type UploadistaErrorName =
|
|
25
|
+
| "UPLOAD_SIZE_NOT_SPECIFIED"
|
|
26
|
+
| "NETWORK_ERROR"
|
|
27
|
+
| "NETWORK_UNEXPECTED_RESPONSE"
|
|
28
|
+
| "UPLOAD_CHUNK_FAILED"
|
|
29
|
+
| "WRONG_UPLOAD_SIZE"
|
|
30
|
+
| "UPLOAD_LOCKED"
|
|
31
|
+
| "UPLOAD_NOT_FOUND"
|
|
32
|
+
| "CREATE_UPLOAD_FAILED"
|
|
33
|
+
| "DELETE_UPLOAD_FAILED"
|
|
34
|
+
| "PARALLEL_SEGMENT_CREATION_FAILED"
|
|
35
|
+
| "PARALLEL_SEGMENT_UPLOAD_FAILED"
|
|
36
|
+
| "FLOW_NOT_FOUND"
|
|
37
|
+
| "FLOW_INIT_FAILED"
|
|
38
|
+
| "FLOW_RUN_FAILED"
|
|
39
|
+
| "FLOW_CONTINUE_FAILED"
|
|
40
|
+
| "FLOW_UNEXPECTED_STATE"
|
|
41
|
+
| "FLOW_INCOMPATIBLE"
|
|
42
|
+
| "FLOW_NO_UPLOAD_ID"
|
|
43
|
+
| "FLOW_TIMEOUT"
|
|
44
|
+
| "FLOW_FINALIZE_FAILED"
|
|
45
|
+
| "JOB_NOT_FOUND"
|
|
46
|
+
| "WEBSOCKET_AUTH_FAILED";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Custom error class for all Uploadista client operations.
|
|
50
|
+
*
|
|
51
|
+
* Extends the standard Error class with additional context including
|
|
52
|
+
* typed error names, HTTP status codes, and underlying error causes.
|
|
53
|
+
* This allows for precise error handling and debugging.
|
|
54
|
+
*
|
|
55
|
+
* @example Basic error handling
|
|
56
|
+
* ```typescript
|
|
57
|
+
* try {
|
|
58
|
+
* await client.upload(file);
|
|
59
|
+
* } catch (error) {
|
|
60
|
+
* if (error instanceof UploadistaError) {
|
|
61
|
+
* console.log(`Error: ${error.name} - ${error.message}`);
|
|
62
|
+
* console.log(`HTTP Status: ${error.status}`);
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @example Network error detection
|
|
68
|
+
* ```typescript
|
|
69
|
+
* try {
|
|
70
|
+
* await client.upload(file);
|
|
71
|
+
* } catch (error) {
|
|
72
|
+
* if (error instanceof UploadistaError && error.isNetworkError()) {
|
|
73
|
+
* // Implement retry logic for network failures
|
|
74
|
+
* await retryWithBackoff(() => client.upload(file));
|
|
75
|
+
* }
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export class UploadistaError extends Error {
|
|
80
|
+
/**
|
|
81
|
+
* Typed error name indicating the specific type of failure
|
|
82
|
+
*/
|
|
83
|
+
name: UploadistaErrorName;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Human-readable error message describing what went wrong
|
|
87
|
+
*/
|
|
88
|
+
message: string;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The underlying error that caused this failure, if any
|
|
92
|
+
*/
|
|
93
|
+
cause: Error | undefined;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* HTTP status code from the server response, if applicable
|
|
97
|
+
*/
|
|
98
|
+
status: number | undefined;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Creates a new UploadistaError instance.
|
|
102
|
+
*
|
|
103
|
+
* @param options - Error configuration
|
|
104
|
+
* @param options.name - Typed error name for categorization
|
|
105
|
+
* @param options.message - Descriptive error message
|
|
106
|
+
* @param options.cause - Optional underlying error that caused this failure
|
|
107
|
+
* @param options.status - Optional HTTP status code from server response
|
|
108
|
+
*/
|
|
109
|
+
constructor({
|
|
110
|
+
name,
|
|
111
|
+
message,
|
|
112
|
+
cause,
|
|
113
|
+
status,
|
|
114
|
+
}: {
|
|
115
|
+
name: UploadistaErrorName;
|
|
116
|
+
message: string;
|
|
117
|
+
cause?: Error;
|
|
118
|
+
status?: number;
|
|
119
|
+
}) {
|
|
120
|
+
super();
|
|
121
|
+
this.name = name;
|
|
122
|
+
this.cause = cause;
|
|
123
|
+
this.message = message;
|
|
124
|
+
this.status = status;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Checks if this error is related to network connectivity issues.
|
|
129
|
+
*
|
|
130
|
+
* Network errors are typically transient and may succeed on retry,
|
|
131
|
+
* making them good candidates for automatic retry logic.
|
|
132
|
+
*
|
|
133
|
+
* @returns True if this is a network-related error
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* if (error.isNetworkError()) {
|
|
138
|
+
* // Safe to retry
|
|
139
|
+
* await retry(() => uploadChunk());
|
|
140
|
+
* }
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
isNetworkError(): boolean {
|
|
144
|
+
return (
|
|
145
|
+
this.name === "NETWORK_ERROR" ||
|
|
146
|
+
this.name === "NETWORK_UNEXPECTED_RESPONSE"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Service interfaces
|
|
2
|
+
|
|
3
|
+
export * from "./chunk-buffer";
|
|
4
|
+
export * from "./client";
|
|
5
|
+
export * from "./error";
|
|
6
|
+
export * from "./logger";
|
|
7
|
+
// Utilities
|
|
8
|
+
export * from "./network-monitor";
|
|
9
|
+
export * from "./services";
|
|
10
|
+
// Storage
|
|
11
|
+
export * from "./storage";
|
|
12
|
+
// Core types
|
|
13
|
+
export * from "./types";
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger interface for Uploadista client operations.
|
|
3
|
+
*
|
|
4
|
+
* Provides structured logging capabilities for debugging upload progress,
|
|
5
|
+
* flow execution, and client operations. Platform implementations should
|
|
6
|
+
* provide their own logging functions (e.g., console.log, custom loggers).
|
|
7
|
+
*
|
|
8
|
+
* @example Using with console
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const logger = createLogger(true, console.log);
|
|
11
|
+
* logger.log('Upload started');
|
|
12
|
+
* logger.warn('Retrying failed chunk');
|
|
13
|
+
* logger.error('Upload failed');
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export type Logger = {
|
|
17
|
+
/**
|
|
18
|
+
* Log informational messages (e.g., upload progress, state changes)
|
|
19
|
+
*/
|
|
20
|
+
log: (message: string) => void;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Log warning messages (e.g., retry attempts, degraded performance)
|
|
24
|
+
*/
|
|
25
|
+
warn: (message: string) => void;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Log error messages (e.g., upload failures, network errors)
|
|
29
|
+
*/
|
|
30
|
+
error: (message: string) => void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Platform-specific logging function type.
|
|
35
|
+
*
|
|
36
|
+
* Accepts a message string and outputs it to the appropriate logging destination.
|
|
37
|
+
* This abstraction allows the client to work across different platforms
|
|
38
|
+
* (browser, Node.js, React Native) with their own logging mechanisms.
|
|
39
|
+
*/
|
|
40
|
+
export type LogFunction = (message: string) => void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Default no-op logger function.
|
|
44
|
+
*
|
|
45
|
+
* Used when no custom logging function is provided.
|
|
46
|
+
* Platform implementations should provide their own (e.g., console.log).
|
|
47
|
+
*/
|
|
48
|
+
const noopLog: LogFunction = () => {
|
|
49
|
+
// No-op by default - platforms will override
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates a Logger instance with configurable output.
|
|
54
|
+
*
|
|
55
|
+
* This factory function creates a logger that can be enabled/disabled
|
|
56
|
+
* and customized with a platform-specific logging function.
|
|
57
|
+
*
|
|
58
|
+
* @param enabled - Whether logging is enabled. When false, all log calls are no-ops
|
|
59
|
+
* @param logFn - Optional custom logging function. Defaults to no-op. Pass console.log for browser/Node.js
|
|
60
|
+
* @returns A Logger instance with log, warn, and error methods
|
|
61
|
+
*
|
|
62
|
+
* @example Basic usage with console
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const logger = createLogger(true, console.log);
|
|
65
|
+
* logger.log('Upload started');
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example Disabled logger (no output)
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const logger = createLogger(false);
|
|
71
|
+
* logger.log('This will not be logged');
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example Custom logging function
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const customLog = (msg: string) => {
|
|
77
|
+
* // Send to analytics service
|
|
78
|
+
* analytics.track('upload_log', { message: msg });
|
|
79
|
+
* };
|
|
80
|
+
* const logger = createLogger(true, customLog);
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function createLogger(
|
|
84
|
+
enabled: boolean,
|
|
85
|
+
logFn: LogFunction = noopLog,
|
|
86
|
+
): Logger {
|
|
87
|
+
return {
|
|
88
|
+
log: (message: string) => {
|
|
89
|
+
if (enabled) {
|
|
90
|
+
logFn(message);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
warn: (message: string) => {
|
|
94
|
+
if (enabled) {
|
|
95
|
+
logFn(message);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
error: (message: string) => {
|
|
99
|
+
if (enabled) {
|
|
100
|
+
logFn(message);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DataStoreCapabilities,
|
|
3
|
+
UploadStrategy,
|
|
4
|
+
} from "@uploadista/core/types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Mock data store implementation for client-side capability negotiation.
|
|
8
|
+
* This doesn't perform actual data store operations but provides capability information
|
|
9
|
+
* for upload strategy decisions.
|
|
10
|
+
*/
|
|
11
|
+
export class MockClientDataStore {
|
|
12
|
+
constructor(private capabilities: DataStoreCapabilities) {}
|
|
13
|
+
|
|
14
|
+
getCapabilities(): DataStoreCapabilities {
|
|
15
|
+
return this.capabilities;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
validateUploadStrategy(strategy: UploadStrategy): boolean {
|
|
19
|
+
switch (strategy) {
|
|
20
|
+
case "parallel":
|
|
21
|
+
return this.capabilities.supportsParallelUploads;
|
|
22
|
+
case "single":
|
|
23
|
+
return true;
|
|
24
|
+
default:
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Default capabilities that assume basic parallel upload support
|
|
32
|
+
* (conservative defaults that work with most backends)
|
|
33
|
+
*/
|
|
34
|
+
export const defaultClientCapabilities: DataStoreCapabilities = {
|
|
35
|
+
supportsParallelUploads: true,
|
|
36
|
+
supportsConcatenation: true,
|
|
37
|
+
supportsDeferredLength: true,
|
|
38
|
+
supportsResumableUploads: true,
|
|
39
|
+
supportsTransactionalUploads: false,
|
|
40
|
+
maxConcurrentUploads: 6, // Browser-safe default
|
|
41
|
+
minChunkSize: 64 * 1024, // 64KB
|
|
42
|
+
maxChunkSize: 100 * 1024 * 1024, // 100MB
|
|
43
|
+
maxParts: 10000,
|
|
44
|
+
optimalChunkSize: 8 * 1024 * 1024, // 8MB
|
|
45
|
+
requiresOrderedChunks: false,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Capabilities for S3-compatible backends
|
|
50
|
+
*/
|
|
51
|
+
export const s3LikeCapabilities: DataStoreCapabilities = {
|
|
52
|
+
supportsParallelUploads: true,
|
|
53
|
+
supportsConcatenation: true,
|
|
54
|
+
supportsDeferredLength: true,
|
|
55
|
+
supportsResumableUploads: true,
|
|
56
|
+
supportsTransactionalUploads: true,
|
|
57
|
+
maxConcurrentUploads: 60,
|
|
58
|
+
minChunkSize: 5 * 1024 * 1024, // 5MiB S3 minimum
|
|
59
|
+
maxChunkSize: 5 * 1024 * 1024 * 1024, // 5GiB S3 maximum
|
|
60
|
+
maxParts: 10000,
|
|
61
|
+
optimalChunkSize: 8 * 1024 * 1024, // 8MB
|
|
62
|
+
requiresOrderedChunks: false,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Capabilities for GCS-compatible backends
|
|
67
|
+
*/
|
|
68
|
+
export const gcsLikeCapabilities: DataStoreCapabilities = {
|
|
69
|
+
supportsParallelUploads: false, // GCS doesn't have native multipart
|
|
70
|
+
supportsConcatenation: true, // Can combine files
|
|
71
|
+
supportsDeferredLength: true,
|
|
72
|
+
supportsResumableUploads: true,
|
|
73
|
+
supportsTransactionalUploads: false,
|
|
74
|
+
maxConcurrentUploads: 1,
|
|
75
|
+
minChunkSize: undefined,
|
|
76
|
+
maxChunkSize: undefined,
|
|
77
|
+
maxParts: undefined,
|
|
78
|
+
optimalChunkSize: 8 * 1024 * 1024, // 8MB
|
|
79
|
+
requiresOrderedChunks: true,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Capabilities for filesystem-based backends
|
|
84
|
+
*/
|
|
85
|
+
export const filesystemLikeCapabilities: DataStoreCapabilities = {
|
|
86
|
+
supportsParallelUploads: false, // Sequential operations
|
|
87
|
+
supportsConcatenation: false,
|
|
88
|
+
supportsDeferredLength: false,
|
|
89
|
+
supportsResumableUploads: true,
|
|
90
|
+
supportsTransactionalUploads: false,
|
|
91
|
+
maxConcurrentUploads: 1,
|
|
92
|
+
minChunkSize: undefined,
|
|
93
|
+
maxChunkSize: undefined,
|
|
94
|
+
maxParts: undefined,
|
|
95
|
+
optimalChunkSize: 1024 * 1024, // 1MB
|
|
96
|
+
requiresOrderedChunks: true,
|
|
97
|
+
};
|