@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,444 @@
1
+ import { AuthHttpClient } from "../auth";
2
+ import { UploadistaError } from "../error";
3
+ import { defaultClientCapabilities } from "../mock-data-store";
4
+ /**
5
+ * Maps server error codes to client error names
6
+ * If no mapping exists, uses a default error name based on context
7
+ */
8
+ const mapServerErrorCodeToClientName = (serverCode, defaultName) => {
9
+ if (!serverCode)
10
+ return defaultName;
11
+ // Map common server error codes to client error names
12
+ const errorMap = {
13
+ FILE_NOT_FOUND: "UPLOAD_NOT_FOUND",
14
+ UPLOAD_ID_NOT_FOUND: "UPLOAD_NOT_FOUND",
15
+ FLOW_JOB_NOT_FOUND: "JOB_NOT_FOUND",
16
+ FLOW_NODE_ERROR: "FLOW_RUN_FAILED",
17
+ FLOW_STRUCTURE_ERROR: "FLOW_RUN_FAILED",
18
+ FLOW_CYCLE_ERROR: "FLOW_RUN_FAILED",
19
+ FLOW_INPUT_VALIDATION_ERROR: "FLOW_RUN_FAILED",
20
+ FLOW_OUTPUT_VALIDATION_ERROR: "FLOW_RUN_FAILED",
21
+ VALIDATION_ERROR: "CREATE_UPLOAD_FAILED",
22
+ DATASTORE_NOT_FOUND: "FLOW_RUN_FAILED",
23
+ };
24
+ return errorMap[serverCode] || defaultName;
25
+ };
26
+ /**
27
+ * Creates an Uploadista API instance for direct server communication.
28
+ *
29
+ * This factory creates a low-level API client that handles:
30
+ * - HTTP requests to upload and flow endpoints
31
+ * - Authentication via AuthManager (optional)
32
+ * - WebSocket connections for real-time updates
33
+ * - Error mapping from server to client error types
34
+ * - Connection pooling and metrics
35
+ *
36
+ * Most applications should use {@link createUploadistaClient} instead,
37
+ * which wraps this API with higher-level features like automatic retry,
38
+ * resumption, and smart chunking.
39
+ *
40
+ * @param baseURL - Base URL of the Uploadista server (e.g., "https://upload.example.com")
41
+ * @param uploadistBasePath - Base path for endpoints, typically "uploadista"
42
+ * @param options - Configuration object
43
+ * @param options.httpClient - HTTP client for making requests
44
+ * @param options.logger - Optional logger for debugging
45
+ * @param options.authManager - Optional authentication manager
46
+ * @param options.webSocketFactory - Factory for creating WebSocket connections
47
+ * @returns UploadistaApi instance
48
+ *
49
+ * @example Basic API instance
50
+ * ```typescript
51
+ * import { createUploadistaApi } from '@uploadista/client-core';
52
+ *
53
+ * const api = createUploadistaApi(
54
+ * 'https://upload.example.com',
55
+ * 'uploadista',
56
+ * {
57
+ * httpClient: myHttpClient,
58
+ * logger: console,
59
+ * webSocketFactory: {
60
+ * create: (url) => new WebSocket(url),
61
+ * },
62
+ * }
63
+ * );
64
+ *
65
+ * // Use the API directly
66
+ * const { upload } = await api.createUpload({
67
+ * storageId: 'my-storage',
68
+ * size: 1024,
69
+ * });
70
+ * ```
71
+ *
72
+ * @example With authentication
73
+ * ```typescript
74
+ * const authManager = new DirectAuthManager(authConfig, platformService, logger);
75
+ *
76
+ * const api = createUploadistaApi(baseUrl, 'uploadista', {
77
+ * httpClient,
78
+ * logger,
79
+ * authManager, // Automatically adds auth headers to requests
80
+ * webSocketFactory,
81
+ * });
82
+ * ```
83
+ *
84
+ * @see {@link UploadistaApi} for the API interface
85
+ * @see {@link createUploadistaClient} for the high-level client
86
+ */
87
+ export function createUploadistaApi(baseURL, uploadistBasePath, { httpClient: baseHttpClient, logger, authManager, webSocketFactory, }) {
88
+ // Create base HTTP client with connection pooling
89
+ // Wrap with auth if auth manager is provided
90
+ const httpClient = authManager
91
+ ? new AuthHttpClient(baseHttpClient, authManager)
92
+ : baseHttpClient;
93
+ // Construct endpoint URLs
94
+ const uploadEndpoint = `${baseURL}/${uploadistBasePath}/api/upload`;
95
+ const flowEndpoint = `${baseURL}/${uploadistBasePath}/api/flow`;
96
+ const jobsEndpoint = `${baseURL}/${uploadistBasePath}/api/jobs`;
97
+ // WebSocket URLs
98
+ const wsBaseURL = baseURL.replace("http", "ws");
99
+ const uploadWsURL = `${wsBaseURL}/uploadista/ws/upload`;
100
+ const flowWsURL = `${wsBaseURL}/uploadista/ws/flow`;
101
+ /**
102
+ * Helper function to extract auth token for WebSocket connection.
103
+ * Supports both DirectAuthManager (extracts from headers) and SaasAuthManager (gets cached token).
104
+ */
105
+ const getAuthTokenForWebSocket = async (manager, jobId) => {
106
+ logger?.log(`Getting auth token for WebSocket (jobId: ${jobId})`);
107
+ // Check if this is a SaasAuthManager (has attachToken method)
108
+ if ("attachToken" in manager) {
109
+ logger?.log("Detected SaasAuthManager, calling attachToken");
110
+ const headers = await manager.attachToken({}, jobId);
111
+ const authHeader = headers.Authorization;
112
+ if (authHeader?.startsWith("Bearer ")) {
113
+ logger?.log("Successfully extracted Bearer token from SaasAuthManager");
114
+ return authHeader.substring(7); // Remove "Bearer " prefix
115
+ }
116
+ logger?.log(`No valid Authorization header from SaasAuthManager: ${authHeader}`);
117
+ }
118
+ // Check if this is a DirectAuthManager (has attachCredentials method)
119
+ if ("attachCredentials" in manager) {
120
+ logger?.log("Detected DirectAuthManager, calling attachCredentials");
121
+ const headers = await manager.attachCredentials({});
122
+ const authHeader = headers.Authorization;
123
+ if (authHeader) {
124
+ logger?.log("Successfully extracted Authorization header from DirectAuthManager");
125
+ // Support both "Bearer token" and plain token formats
126
+ return authHeader.startsWith("Bearer ")
127
+ ? authHeader.substring(7)
128
+ : authHeader;
129
+ }
130
+ logger?.log(`No Authorization header from DirectAuthManager`);
131
+ }
132
+ logger?.log("No auth token could be extracted from auth manager");
133
+ return null;
134
+ };
135
+ return {
136
+ // Upload operations
137
+ getUpload: async (uploadId) => {
138
+ const res = await httpClient.request(`${uploadEndpoint}/${uploadId}`);
139
+ if (!res.ok) {
140
+ const errorData = (await res.json().catch(() => ({})));
141
+ const errorName = mapServerErrorCodeToClientName(errorData.code, "UPLOAD_NOT_FOUND");
142
+ const errorMessage = errorData.error ||
143
+ errorData.message ||
144
+ `Upload ${uploadId} not found`;
145
+ throw new UploadistaError({
146
+ name: errorName,
147
+ message: errorData.code
148
+ ? `${errorMessage} (${errorData.code})`
149
+ : errorMessage,
150
+ status: res.status,
151
+ });
152
+ }
153
+ const data = (await res.json());
154
+ return { status: res.status, upload: data };
155
+ },
156
+ deleteUpload: async (uploadId) => {
157
+ const res = await httpClient.request(`${uploadEndpoint}/${uploadId}`, {
158
+ method: "DELETE",
159
+ });
160
+ if (!res.ok) {
161
+ const errorData = (await res.json().catch(() => ({})));
162
+ const errorName = mapServerErrorCodeToClientName(errorData.code, "DELETE_UPLOAD_FAILED");
163
+ const errorMessage = errorData.error ||
164
+ errorData.message ||
165
+ `Failed to delete upload ${uploadId}`;
166
+ throw new UploadistaError({
167
+ name: errorName,
168
+ message: errorData.code
169
+ ? `${errorMessage} (${errorData.code})`
170
+ : errorMessage,
171
+ status: res.status,
172
+ });
173
+ }
174
+ return { status: res.status };
175
+ },
176
+ createUpload: async (data) => {
177
+ logger?.log(`createUpload ${JSON.stringify(data)}`);
178
+ const res = await httpClient.request(uploadEndpoint, {
179
+ method: "POST",
180
+ headers: {
181
+ "Content-Type": "application/json",
182
+ },
183
+ body: JSON.stringify(data),
184
+ });
185
+ if (!res.ok) {
186
+ const errorData = (await res.json().catch(() => ({})));
187
+ const errorName = mapServerErrorCodeToClientName(errorData.code, "CREATE_UPLOAD_FAILED");
188
+ const errorMessage = errorData.error || errorData.message || "Failed to create upload";
189
+ throw new UploadistaError({
190
+ name: errorName,
191
+ message: errorData.code
192
+ ? `${errorMessage} (${errorData.code})`
193
+ : errorMessage,
194
+ status: res.status,
195
+ });
196
+ }
197
+ const responseData = (await res.json());
198
+ logger?.log(JSON.stringify(responseData));
199
+ return { status: res.status, upload: responseData };
200
+ },
201
+ uploadChunk: async (uploadId, data, { abortController }) => {
202
+ try {
203
+ const res = await httpClient.request(`${uploadEndpoint}/${uploadId}`, {
204
+ method: "PATCH",
205
+ headers: {
206
+ "Content-Type": "application/octet-stream",
207
+ },
208
+ body: data,
209
+ signal: abortController?.signal,
210
+ });
211
+ if (!res.ok) {
212
+ const errorData = (await res
213
+ .json()
214
+ .catch(() => ({})));
215
+ throw new UploadistaError({
216
+ name: "NETWORK_ERROR",
217
+ message: errorData.error || errorData.message || "Unknown network error",
218
+ status: res.status,
219
+ });
220
+ }
221
+ const responseData = (await res.json());
222
+ return { status: res.status, upload: responseData };
223
+ }
224
+ catch (err) {
225
+ if (err instanceof UploadistaError) {
226
+ throw err;
227
+ }
228
+ throw new UploadistaError({
229
+ name: "NETWORK_ERROR",
230
+ message: "Network error",
231
+ cause: err,
232
+ });
233
+ }
234
+ },
235
+ // Flow operations
236
+ getFlow: async (flowId) => {
237
+ const res = await httpClient.request(`${flowEndpoint}/${flowId}`);
238
+ if (!res.ok) {
239
+ const errorData = (await res.json().catch(() => ({})));
240
+ const errorName = mapServerErrorCodeToClientName(errorData.code, "FLOW_NOT_FOUND");
241
+ const errorMessage = errorData.error || errorData.message || `Flow ${flowId} not found`;
242
+ throw new UploadistaError({
243
+ name: errorName,
244
+ message: errorData.code
245
+ ? `${errorMessage} (${errorData.code})`
246
+ : errorMessage,
247
+ status: res.status,
248
+ });
249
+ }
250
+ const data = (await res.json());
251
+ logger?.log(`getFlow: ${flowId}`);
252
+ return { status: res.status, flow: data };
253
+ },
254
+ runFlow: async (flowId, storageId, inputs) => {
255
+ logger?.log(`runFlow: ${flowId} with storage: ${storageId}`);
256
+ const res = await httpClient.request(`${flowEndpoint}/${flowId}/${storageId}`, {
257
+ method: "POST",
258
+ headers: {
259
+ "Content-Type": "application/json",
260
+ },
261
+ body: JSON.stringify({ inputs }),
262
+ });
263
+ if (!res.ok) {
264
+ const errorData = (await res.json().catch(() => ({})));
265
+ const errorName = mapServerErrorCodeToClientName(errorData.code, "FLOW_RUN_FAILED");
266
+ const errorMessage = errorData.error ||
267
+ errorData.message ||
268
+ `Failed to run flow ${flowId}`;
269
+ throw new UploadistaError({
270
+ name: errorName,
271
+ message: errorData.code
272
+ ? `${errorMessage} (${errorData.code})`
273
+ : errorMessage,
274
+ status: res.status,
275
+ });
276
+ }
277
+ const data = (await res.json());
278
+ logger?.log(`runFlow response: ${JSON.stringify(data)}`);
279
+ return { status: res.status, job: data };
280
+ },
281
+ continueFlow: async (jobId, nodeId, newData, options) => {
282
+ logger?.log(`continueFlow: ${jobId} at node: ${nodeId}`);
283
+ const contentType = options?.contentType || "application/json";
284
+ let body;
285
+ if (contentType === "application/octet-stream") {
286
+ // For octet-stream, newData should be a Uint8Array or similar
287
+ body = newData;
288
+ }
289
+ else {
290
+ // For JSON, wrap newData in an object
291
+ body = JSON.stringify({ newData });
292
+ }
293
+ const res = await httpClient.request(`${jobsEndpoint}/${jobId}/continue/${nodeId}`, {
294
+ method: "PATCH",
295
+ headers: {
296
+ "Content-Type": contentType,
297
+ },
298
+ body,
299
+ });
300
+ if (!res.ok) {
301
+ const errorData = (await res.json().catch(() => ({})));
302
+ const errorName = mapServerErrorCodeToClientName(errorData.code, "FLOW_CONTINUE_FAILED");
303
+ const errorMessage = errorData.error ||
304
+ errorData.message ||
305
+ `Failed to continue flow for job ${jobId}`;
306
+ throw new UploadistaError({
307
+ name: errorName,
308
+ message: errorData.code
309
+ ? `${errorMessage} (${errorData.code})`
310
+ : errorMessage,
311
+ status: res.status,
312
+ });
313
+ }
314
+ const data = (await res.json());
315
+ return data;
316
+ },
317
+ // Unified job operations
318
+ getJobStatus: async (jobId) => {
319
+ const res = await httpClient.request(`${jobsEndpoint}/${jobId}/status`);
320
+ if (!res.ok) {
321
+ const errorData = (await res.json().catch(() => ({})));
322
+ const errorName = mapServerErrorCodeToClientName(errorData.code, "JOB_NOT_FOUND");
323
+ const errorMessage = errorData.error || errorData.message || `Job ${jobId} not found`;
324
+ throw new UploadistaError({
325
+ name: errorName,
326
+ message: errorData.code
327
+ ? `${errorMessage} (${errorData.code})`
328
+ : errorMessage,
329
+ status: res.status,
330
+ });
331
+ }
332
+ const data = (await res.json());
333
+ return data;
334
+ },
335
+ // WebSocket operations
336
+ openUploadWebSocket: async (uploadId) => {
337
+ let wsUrl = `${uploadWsURL}/${uploadId}`;
338
+ // Attach auth token if auth manager is configured
339
+ // Note: For cookie-based auth (e.g., HttpOnly cookies with better-auth),
340
+ // no token is needed as cookies are automatically sent by the browser
341
+ if (authManager) {
342
+ try {
343
+ const token = await getAuthTokenForWebSocket(authManager, uploadId);
344
+ if (token) {
345
+ wsUrl += `?token=${encodeURIComponent(token)}`;
346
+ logger?.log(`WebSocket token attached for upload: ${uploadId}`);
347
+ }
348
+ else {
349
+ // No token means cookie-based auth - this is fine
350
+ logger?.log(`No token for upload WebSocket (using cookie-based auth): ${uploadId}`);
351
+ }
352
+ }
353
+ catch (error) {
354
+ const errorMessage = error instanceof Error ? error.message : String(error);
355
+ logger?.log(`Error getting auth token for upload WebSocket: ${errorMessage}`);
356
+ // Don't throw - allow cookie-based auth to proceed
357
+ logger?.log(`Proceeding with cookie-based authentication for upload WebSocket: ${uploadId}`);
358
+ }
359
+ }
360
+ const ws = webSocketFactory.create(wsUrl);
361
+ ws.onopen = () => {
362
+ logger?.log(`Upload WebSocket connection opened for: ${uploadId}`);
363
+ };
364
+ ws.onclose = () => {
365
+ logger?.log(`Upload WebSocket connection closed for: ${uploadId}`);
366
+ };
367
+ ws.onerror = (error) => {
368
+ logger?.log(`Upload WebSocket error for ${uploadId}: ${error}`);
369
+ };
370
+ return ws;
371
+ },
372
+ openFlowWebSocket: async (jobId) => {
373
+ let wsUrl = `${flowWsURL}/${jobId}`;
374
+ // Attach auth token if auth manager is configured
375
+ // Note: For cookie-based auth (e.g., HttpOnly cookies with better-auth),
376
+ // no token is needed as cookies are automatically sent by the browser
377
+ if (authManager) {
378
+ try {
379
+ const token = await getAuthTokenForWebSocket(authManager, jobId);
380
+ if (token) {
381
+ wsUrl += `?token=${encodeURIComponent(token)}`;
382
+ logger?.log(`WebSocket token attached for flow job: ${jobId}`);
383
+ }
384
+ else {
385
+ // No token means cookie-based auth - this is fine
386
+ logger?.log(`No token for flow WebSocket (using cookie-based auth): ${jobId}`);
387
+ }
388
+ }
389
+ catch (error) {
390
+ const errorMessage = error instanceof Error ? error.message : String(error);
391
+ logger?.log(`Error getting auth token for flow WebSocket: ${errorMessage}`);
392
+ // Don't throw - allow cookie-based auth to proceed
393
+ logger?.log(`Proceeding with cookie-based authentication for flow WebSocket: ${jobId}`);
394
+ }
395
+ }
396
+ const ws = webSocketFactory.create(wsUrl);
397
+ ws.onopen = () => {
398
+ logger?.log(`Flow WebSocket connection opened for job: ${jobId}`);
399
+ };
400
+ ws.onclose = () => {
401
+ logger?.log(`Flow WebSocket connection closed for job: ${jobId}`);
402
+ };
403
+ ws.onerror = (error) => {
404
+ logger?.log(`Flow WebSocket error for job ${jobId}: ${error}`);
405
+ };
406
+ return ws;
407
+ },
408
+ closeWebSocket: (ws) => {
409
+ ws.close();
410
+ },
411
+ // Connection metrics
412
+ getConnectionMetrics: () => {
413
+ return httpClient.getMetrics();
414
+ },
415
+ getDetailedConnectionMetrics: () => {
416
+ return httpClient.getDetailedMetrics();
417
+ },
418
+ warmupConnections: async (urls) => {
419
+ return httpClient.warmupConnections(urls);
420
+ },
421
+ // Capabilities
422
+ getCapabilities: async (storageId) => {
423
+ const capabilitiesUrl = `${uploadEndpoint}/capabilities?storageId=${encodeURIComponent(storageId)}`;
424
+ try {
425
+ const response = await httpClient.request(capabilitiesUrl, {
426
+ method: "GET",
427
+ headers: {
428
+ "Content-Type": "application/json",
429
+ },
430
+ });
431
+ if (!response.ok) {
432
+ logger?.log(`Failed to fetch capabilities: ${response.status} ${response.statusText}`);
433
+ return defaultClientCapabilities;
434
+ }
435
+ const data = await response.json();
436
+ return data.capabilities;
437
+ }
438
+ catch (error) {
439
+ logger?.log(`Failed to fetch server capabilities, using defaults: ${error}`);
440
+ return defaultClientCapabilities;
441
+ }
442
+ },
443
+ };
444
+ }
@@ -0,0 +1,110 @@
1
+ import type { FlowEvent } from "@uploadista/core/flow";
2
+ import type { UploadEvent } from "@uploadista/core/types";
3
+ import type { Logger } from "../logger";
4
+ import type { WebSocketLike } from "../services/websocket-service";
5
+ import type { UploadistaApi } from "./uploadista-api";
6
+ export type UploadistaEvent = UploadEvent | FlowEvent;
7
+ export type UploadistaWebSocketEventHandler = (event: UploadistaEvent) => void;
8
+ export type UploadistaWebSocketMessage = {
9
+ type: "connection";
10
+ message: string;
11
+ id: string;
12
+ timestamp: string;
13
+ } | {
14
+ type: "subscribed";
15
+ payload: {
16
+ uploadId?: string;
17
+ jobId?: string;
18
+ };
19
+ timestamp: string;
20
+ } | {
21
+ type: "error";
22
+ message: string;
23
+ code?: string;
24
+ } | {
25
+ type: "pong";
26
+ timestamp: string;
27
+ } | {
28
+ type: "upload_event";
29
+ payload: UploadEvent;
30
+ } | {
31
+ type: "flow_event";
32
+ payload: FlowEvent;
33
+ };
34
+ /**
35
+ * Unified WebSocket management for both upload and flow events
36
+ */
37
+ export declare class UploadistaWebSocketManager {
38
+ private uploadistaApi;
39
+ private logger;
40
+ private onEvent?;
41
+ private uploadWebsockets;
42
+ private flowWebsockets;
43
+ constructor(uploadistaApi: UploadistaApi, logger: Logger, onEvent?: UploadistaWebSocketEventHandler | undefined);
44
+ /**
45
+ * Open a WebSocket connection for upload events
46
+ */
47
+ openUploadWebSocket(uploadId: string): Promise<WebSocketLike>;
48
+ /**
49
+ * Open a WebSocket connection for flow/job events
50
+ */
51
+ openFlowWebSocket(jobId: string): Promise<WebSocketLike>;
52
+ /**
53
+ * Open a unified WebSocket connection - automatically determines if it's for upload or flow
54
+ * based on the ID format (upload IDs typically start with 'upload-', job IDs start with 'job-')
55
+ */
56
+ openWebSocket(id: string): Promise<WebSocketLike>;
57
+ /**
58
+ * Close upload WebSocket connection
59
+ */
60
+ closeUploadWebSocket(uploadId: string): void;
61
+ /**
62
+ * Close flow WebSocket connection
63
+ */
64
+ closeFlowWebSocket(jobId: string): void;
65
+ /**
66
+ * Close WebSocket connection by ID (auto-detects type)
67
+ */
68
+ closeWebSocket(id: string): void;
69
+ /**
70
+ * Close all WebSocket connections (both upload and flow)
71
+ */
72
+ closeAll(): void;
73
+ /**
74
+ * Send ping to flow WebSocket
75
+ */
76
+ sendPing(jobId: string): boolean;
77
+ /**
78
+ * Get upload WebSocket by ID
79
+ */
80
+ getUploadWebSocket(uploadId: string): WebSocketLike | undefined;
81
+ /**
82
+ * Get flow WebSocket by ID
83
+ */
84
+ getFlowWebSocket(jobId: string): WebSocketLike | undefined;
85
+ /**
86
+ * Check if upload WebSocket is connected
87
+ */
88
+ isUploadConnected(uploadId: string): boolean;
89
+ /**
90
+ * Check if flow WebSocket is connected
91
+ */
92
+ isFlowConnected(jobId: string): boolean;
93
+ /**
94
+ * Check if WebSocket is connected (auto-detects type)
95
+ */
96
+ isConnected(id: string): boolean;
97
+ /**
98
+ * Get total number of active WebSocket connections
99
+ */
100
+ getConnectionCount(): number;
101
+ /**
102
+ * Get connection counts by type
103
+ */
104
+ getConnectionCountByType(): {
105
+ upload: number;
106
+ flow: number;
107
+ total: number;
108
+ };
109
+ }
110
+ //# sourceMappingURL=uploadista-websocket-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploadista-websocket-manager.d.ts","sourceRoot":"","sources":["../../src/client/uploadista-websocket-manager.ts"],"names":[],"mappings":"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"}