@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.
Files changed (235) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +100 -0
  4. package/dist/auth/auth-http-client.d.ts +50 -0
  5. package/dist/auth/auth-http-client.d.ts.map +1 -0
  6. package/dist/auth/auth-http-client.js +110 -0
  7. package/dist/auth/direct-auth.d.ts +38 -0
  8. package/dist/auth/direct-auth.d.ts.map +1 -0
  9. package/dist/auth/direct-auth.js +95 -0
  10. package/dist/auth/index.d.ts +6 -0
  11. package/dist/auth/index.d.ts.map +1 -0
  12. package/dist/auth/index.js +5 -0
  13. package/dist/auth/no-auth.d.ts +26 -0
  14. package/dist/auth/no-auth.d.ts.map +1 -0
  15. package/dist/auth/no-auth.js +33 -0
  16. package/dist/auth/saas-auth.d.ts +80 -0
  17. package/dist/auth/saas-auth.d.ts.map +1 -0
  18. package/dist/auth/saas-auth.js +167 -0
  19. package/dist/auth/types.d.ts +101 -0
  20. package/dist/auth/types.d.ts.map +1 -0
  21. package/dist/auth/types.js +8 -0
  22. package/dist/chunk-buffer.d.ts +209 -0
  23. package/dist/chunk-buffer.d.ts.map +1 -0
  24. package/dist/chunk-buffer.js +236 -0
  25. package/dist/client/create-uploadista-client.d.ts +369 -0
  26. package/dist/client/create-uploadista-client.d.ts.map +1 -0
  27. package/dist/client/create-uploadista-client.js +518 -0
  28. package/dist/client/index.d.ts +4 -0
  29. package/dist/client/index.d.ts.map +1 -0
  30. package/dist/client/index.js +3 -0
  31. package/dist/client/uploadista-api.d.ts +284 -0
  32. package/dist/client/uploadista-api.d.ts.map +1 -0
  33. package/dist/client/uploadista-api.js +444 -0
  34. package/dist/client/uploadista-websocket-manager.d.ts +110 -0
  35. package/dist/client/uploadista-websocket-manager.d.ts.map +1 -0
  36. package/dist/client/uploadista-websocket-manager.js +207 -0
  37. package/dist/error.d.ts +106 -0
  38. package/dist/error.d.ts.map +1 -0
  39. package/dist/error.js +69 -0
  40. package/dist/index.d.ts +9 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +12 -0
  43. package/dist/logger.d.ts +70 -0
  44. package/dist/logger.d.ts.map +1 -0
  45. package/dist/logger.js +59 -0
  46. package/dist/mock-data-store.d.ts +30 -0
  47. package/dist/mock-data-store.d.ts.map +1 -0
  48. package/dist/mock-data-store.js +88 -0
  49. package/dist/network-monitor.d.ts +262 -0
  50. package/dist/network-monitor.d.ts.map +1 -0
  51. package/dist/network-monitor.js +291 -0
  52. package/dist/services/abort-controller-service.d.ts +19 -0
  53. package/dist/services/abort-controller-service.d.ts.map +1 -0
  54. package/dist/services/abort-controller-service.js +4 -0
  55. package/dist/services/checksum-service.d.ts +4 -0
  56. package/dist/services/checksum-service.d.ts.map +1 -0
  57. package/dist/services/checksum-service.js +1 -0
  58. package/dist/services/file-reader-service.d.ts +38 -0
  59. package/dist/services/file-reader-service.d.ts.map +1 -0
  60. package/dist/services/file-reader-service.js +4 -0
  61. package/dist/services/fingerprint-service.d.ts +4 -0
  62. package/dist/services/fingerprint-service.d.ts.map +1 -0
  63. package/dist/services/fingerprint-service.js +1 -0
  64. package/dist/services/http-client.d.ts +182 -0
  65. package/dist/services/http-client.d.ts.map +1 -0
  66. package/dist/services/http-client.js +1 -0
  67. package/dist/services/id-generation-service.d.ts +10 -0
  68. package/dist/services/id-generation-service.d.ts.map +1 -0
  69. package/dist/services/id-generation-service.js +1 -0
  70. package/dist/services/index.d.ts +11 -0
  71. package/dist/services/index.d.ts.map +1 -0
  72. package/dist/services/index.js +10 -0
  73. package/dist/services/platform-service.d.ts +48 -0
  74. package/dist/services/platform-service.d.ts.map +1 -0
  75. package/dist/services/platform-service.js +10 -0
  76. package/dist/services/service-container.d.ts +25 -0
  77. package/dist/services/service-container.d.ts.map +1 -0
  78. package/dist/services/service-container.js +1 -0
  79. package/dist/services/storage-service.d.ts +26 -0
  80. package/dist/services/storage-service.d.ts.map +1 -0
  81. package/dist/services/storage-service.js +1 -0
  82. package/dist/services/websocket-service.d.ts +36 -0
  83. package/dist/services/websocket-service.d.ts.map +1 -0
  84. package/dist/services/websocket-service.js +4 -0
  85. package/dist/smart-chunker.d.ts +72 -0
  86. package/dist/smart-chunker.d.ts.map +1 -0
  87. package/dist/smart-chunker.js +317 -0
  88. package/dist/storage/client-storage.d.ts +148 -0
  89. package/dist/storage/client-storage.d.ts.map +1 -0
  90. package/dist/storage/client-storage.js +62 -0
  91. package/dist/storage/in-memory-storage-service.d.ts +7 -0
  92. package/dist/storage/in-memory-storage-service.d.ts.map +1 -0
  93. package/dist/storage/in-memory-storage-service.js +24 -0
  94. package/dist/storage/index.d.ts +3 -0
  95. package/dist/storage/index.d.ts.map +1 -0
  96. package/dist/storage/index.js +2 -0
  97. package/dist/types/buffered-chunk.d.ts +6 -0
  98. package/dist/types/buffered-chunk.d.ts.map +1 -0
  99. package/dist/types/buffered-chunk.js +1 -0
  100. package/dist/types/chunk-metrics.d.ts +12 -0
  101. package/dist/types/chunk-metrics.d.ts.map +1 -0
  102. package/dist/types/chunk-metrics.js +1 -0
  103. package/dist/types/flow-result.d.ts +11 -0
  104. package/dist/types/flow-result.d.ts.map +1 -0
  105. package/dist/types/flow-result.js +1 -0
  106. package/dist/types/flow-upload-config.d.ts +54 -0
  107. package/dist/types/flow-upload-config.d.ts.map +1 -0
  108. package/dist/types/flow-upload-config.js +1 -0
  109. package/dist/types/flow-upload-item.d.ts +16 -0
  110. package/dist/types/flow-upload-item.d.ts.map +1 -0
  111. package/dist/types/flow-upload-item.js +1 -0
  112. package/dist/types/flow-upload-options.d.ts +41 -0
  113. package/dist/types/flow-upload-options.d.ts.map +1 -0
  114. package/dist/types/flow-upload-options.js +1 -0
  115. package/dist/types/index.d.ts +14 -0
  116. package/dist/types/index.d.ts.map +1 -0
  117. package/dist/types/index.js +13 -0
  118. package/dist/types/multi-flow-upload-options.d.ts +33 -0
  119. package/dist/types/multi-flow-upload-options.d.ts.map +1 -0
  120. package/dist/types/multi-flow-upload-options.js +1 -0
  121. package/dist/types/multi-flow-upload-state.d.ts +9 -0
  122. package/dist/types/multi-flow-upload-state.d.ts.map +1 -0
  123. package/dist/types/multi-flow-upload-state.js +1 -0
  124. package/dist/types/performance-insights.d.ts +11 -0
  125. package/dist/types/performance-insights.d.ts.map +1 -0
  126. package/dist/types/performance-insights.js +1 -0
  127. package/dist/types/previous-upload.d.ts +20 -0
  128. package/dist/types/previous-upload.d.ts.map +1 -0
  129. package/dist/types/previous-upload.js +9 -0
  130. package/dist/types/upload-options.d.ts +40 -0
  131. package/dist/types/upload-options.d.ts.map +1 -0
  132. package/dist/types/upload-options.js +1 -0
  133. package/dist/types/upload-response.d.ts +6 -0
  134. package/dist/types/upload-response.d.ts.map +1 -0
  135. package/dist/types/upload-response.js +1 -0
  136. package/dist/types/upload-result.d.ts +57 -0
  137. package/dist/types/upload-result.d.ts.map +1 -0
  138. package/dist/types/upload-result.js +1 -0
  139. package/dist/types/upload-session-metrics.d.ts +16 -0
  140. package/dist/types/upload-session-metrics.d.ts.map +1 -0
  141. package/dist/types/upload-session-metrics.js +1 -0
  142. package/dist/upload/chunk-upload.d.ts +40 -0
  143. package/dist/upload/chunk-upload.d.ts.map +1 -0
  144. package/dist/upload/chunk-upload.js +82 -0
  145. package/dist/upload/flow-upload.d.ts +48 -0
  146. package/dist/upload/flow-upload.d.ts.map +1 -0
  147. package/dist/upload/flow-upload.js +240 -0
  148. package/dist/upload/index.d.ts +3 -0
  149. package/dist/upload/index.d.ts.map +1 -0
  150. package/dist/upload/index.js +2 -0
  151. package/dist/upload/parallel-upload.d.ts +65 -0
  152. package/dist/upload/parallel-upload.d.ts.map +1 -0
  153. package/dist/upload/parallel-upload.js +231 -0
  154. package/dist/upload/single-upload.d.ts +118 -0
  155. package/dist/upload/single-upload.d.ts.map +1 -0
  156. package/dist/upload/single-upload.js +332 -0
  157. package/dist/upload/upload-manager.d.ts +30 -0
  158. package/dist/upload/upload-manager.d.ts.map +1 -0
  159. package/dist/upload/upload-manager.js +57 -0
  160. package/dist/upload/upload-metrics.d.ts +37 -0
  161. package/dist/upload/upload-metrics.d.ts.map +1 -0
  162. package/dist/upload/upload-metrics.js +236 -0
  163. package/dist/upload/upload-storage.d.ts +32 -0
  164. package/dist/upload/upload-storage.d.ts.map +1 -0
  165. package/dist/upload/upload-storage.js +46 -0
  166. package/dist/upload/upload-strategy.d.ts +66 -0
  167. package/dist/upload/upload-strategy.d.ts.map +1 -0
  168. package/dist/upload/upload-strategy.js +171 -0
  169. package/dist/upload/upload-utils.d.ts +26 -0
  170. package/dist/upload/upload-utils.d.ts.map +1 -0
  171. package/dist/upload/upload-utils.js +80 -0
  172. package/package.json +29 -0
  173. package/src/__tests__/smart-chunking.test.ts +399 -0
  174. package/src/auth/__tests__/auth-http-client.test.ts +327 -0
  175. package/src/auth/__tests__/direct-auth.test.ts +135 -0
  176. package/src/auth/__tests__/no-auth.test.ts +40 -0
  177. package/src/auth/__tests__/saas-auth.test.ts +337 -0
  178. package/src/auth/auth-http-client.ts +150 -0
  179. package/src/auth/direct-auth.ts +121 -0
  180. package/src/auth/index.ts +5 -0
  181. package/src/auth/no-auth.ts +39 -0
  182. package/src/auth/saas-auth.ts +218 -0
  183. package/src/auth/types.ts +105 -0
  184. package/src/chunk-buffer.ts +287 -0
  185. package/src/client/create-uploadista-client.ts +901 -0
  186. package/src/client/index.ts +3 -0
  187. package/src/client/uploadista-api.ts +857 -0
  188. package/src/client/uploadista-websocket-manager.ts +275 -0
  189. package/src/error.ts +149 -0
  190. package/src/index.ts +13 -0
  191. package/src/logger.ts +104 -0
  192. package/src/mock-data-store.ts +97 -0
  193. package/src/network-monitor.ts +445 -0
  194. package/src/services/abort-controller-service.ts +21 -0
  195. package/src/services/checksum-service.ts +3 -0
  196. package/src/services/file-reader-service.ts +44 -0
  197. package/src/services/fingerprint-service.ts +6 -0
  198. package/src/services/http-client.ts +229 -0
  199. package/src/services/id-generation-service.ts +9 -0
  200. package/src/services/index.ts +10 -0
  201. package/src/services/platform-service.ts +65 -0
  202. package/src/services/service-container.ts +24 -0
  203. package/src/services/storage-service.ts +29 -0
  204. package/src/services/websocket-service.ts +33 -0
  205. package/src/smart-chunker.ts +451 -0
  206. package/src/storage/client-storage.ts +186 -0
  207. package/src/storage/in-memory-storage-service.ts +33 -0
  208. package/src/storage/index.ts +2 -0
  209. package/src/types/buffered-chunk.ts +5 -0
  210. package/src/types/chunk-metrics.ts +11 -0
  211. package/src/types/flow-result.ts +14 -0
  212. package/src/types/flow-upload-config.ts +56 -0
  213. package/src/types/flow-upload-item.ts +16 -0
  214. package/src/types/flow-upload-options.ts +56 -0
  215. package/src/types/index.ts +13 -0
  216. package/src/types/multi-flow-upload-options.ts +39 -0
  217. package/src/types/multi-flow-upload-state.ts +9 -0
  218. package/src/types/performance-insights.ts +7 -0
  219. package/src/types/previous-upload.ts +22 -0
  220. package/src/types/upload-options.ts +56 -0
  221. package/src/types/upload-response.ts +6 -0
  222. package/src/types/upload-result.ts +60 -0
  223. package/src/types/upload-session-metrics.ts +15 -0
  224. package/src/upload/chunk-upload.ts +151 -0
  225. package/src/upload/flow-upload.ts +367 -0
  226. package/src/upload/index.ts +2 -0
  227. package/src/upload/parallel-upload.ts +387 -0
  228. package/src/upload/single-upload.ts +554 -0
  229. package/src/upload/upload-manager.ts +106 -0
  230. package/src/upload/upload-metrics.ts +340 -0
  231. package/src/upload/upload-storage.ts +87 -0
  232. package/src/upload/upload-strategy.ts +296 -0
  233. package/src/upload/upload-utils.ts +114 -0
  234. package/tsconfig.json +23 -0
  235. 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
+ };