@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,367 @@
1
+ import type { UploadFile } from "@uploadista/core/types";
2
+ import type { UploadistaApi } from "../client/uploadista-api";
3
+ import { UploadistaError } from "../error";
4
+ import type { Logger } from "../logger";
5
+ import type { AbortControllerLike } from "../services";
6
+ import type { FileSource } from "../services/file-reader-service";
7
+ import type { PlatformService, Timeout } from "../services/platform-service";
8
+ import type { SmartChunker, SmartChunkerConfig } from "../smart-chunker";
9
+ import type { FlowUploadConfig } from "../types/flow-upload-config";
10
+
11
+ import { shouldRetry } from "./chunk-upload";
12
+ import type { Callbacks } from "./single-upload";
13
+ import type { UploadMetrics } from "./upload-metrics";
14
+ import { inStatusCategory } from "./upload-utils";
15
+
16
+ /**
17
+ * Start a flow-based upload by initializing the streaming input node
18
+ */
19
+ export async function startFlowUpload({
20
+ source,
21
+ flowConfig,
22
+ uploadistaApi,
23
+ logger,
24
+ platformService,
25
+ openWebSocket,
26
+ closeWebSocket,
27
+ ...callbacks
28
+ }: {
29
+ source: FileSource;
30
+ flowConfig: FlowUploadConfig;
31
+ uploadistaApi: UploadistaApi;
32
+ logger: Logger;
33
+ platformService: PlatformService;
34
+ openWebSocket: (jobId: string) => void;
35
+ closeWebSocket: (jobId: string) => void;
36
+ } & Callbacks): Promise<
37
+ { jobId: string; uploadFile: UploadFile; inputNodeId: string } | undefined
38
+ > {
39
+ const { flowId, storageId } = flowConfig;
40
+
41
+ // Get the flow to find the streaming input node
42
+ const { flow } = await uploadistaApi.getFlow(flowId);
43
+
44
+ // Find the streaming-input-node in the flow
45
+ const inputNode = flow.nodes.find((node) => node.type === "input");
46
+
47
+ if (!inputNode) {
48
+ const error = new UploadistaError({
49
+ name: "FLOW_INCOMPATIBLE",
50
+ message: `Flow ${flowId} does not have a streaming input node. The flow must contain a node with type "input" to support flow uploads.`,
51
+ });
52
+ callbacks.onError?.(error);
53
+ throw error;
54
+ }
55
+
56
+ const inputNodeId = inputNode.id;
57
+
58
+ // Step 1: Initialize the flow with init operation
59
+ const metadata = {
60
+ originalName: source.name ?? "unknown",
61
+ mimeType: source.type ?? "application/octet-stream",
62
+ size: source.size ?? 0,
63
+ ...flowConfig.metadata,
64
+ };
65
+
66
+ logger.log(`Starting flow upload for flow ${flowId}, node ${inputNodeId}`);
67
+
68
+ const { status, job } = await uploadistaApi.runFlow(flowId, storageId, {
69
+ [inputNodeId]: {
70
+ operation: "init",
71
+ storageId,
72
+ metadata,
73
+ },
74
+ });
75
+
76
+ const jobId = job.id;
77
+
78
+ if (!inStatusCategory(status, 200) || !jobId) {
79
+ const error = new UploadistaError({
80
+ name: "FLOW_INIT_FAILED",
81
+ message: "Failed to initialize flow upload",
82
+ });
83
+ callbacks.onError?.(error);
84
+ throw error;
85
+ }
86
+
87
+ callbacks.onJobStart?.(jobId);
88
+
89
+ logger.log(`Flow job ${jobId} created, opening WebSocket`);
90
+
91
+ // Open WebSocket to listen for flow events
92
+ // Events are buffered in the Durable Object until connection is established
93
+ openWebSocket(jobId);
94
+
95
+ logger.log(`Waiting for upload ID from node`);
96
+
97
+ // Step 2: Wait for the streaming-input-node to pause and return the upload file
98
+ // Poll job status until paused (with timeout)
99
+ const maxAttempts = 60; // 30 seconds total
100
+ const pollInterval = 500; // 0.5 second
101
+ let attempts = 0;
102
+ let jobStatus = await uploadistaApi.getJobStatus(jobId);
103
+
104
+ while (jobStatus.status !== "paused" && attempts < maxAttempts) {
105
+ await new Promise<void>((resolve) =>
106
+ platformService.setTimeout(resolve, pollInterval),
107
+ );
108
+ jobStatus = await uploadistaApi.getJobStatus(jobId);
109
+ attempts++;
110
+ }
111
+
112
+ if (jobStatus.status !== "paused") {
113
+ const error = new UploadistaError({
114
+ name: "FLOW_TIMEOUT",
115
+ message: `Flow did not pause after init (status: ${jobStatus.status})`,
116
+ });
117
+ callbacks.onError?.(error);
118
+ throw error;
119
+ }
120
+
121
+ // Get the upload file from streaming input node task result
122
+ const streamingInputTask = jobStatus.tasks.find(
123
+ (task) => task.nodeId === inputNodeId,
124
+ );
125
+ const uploadFile = streamingInputTask?.result as UploadFile;
126
+
127
+ if (!uploadFile?.id) {
128
+ const error = new UploadistaError({
129
+ name: "FLOW_NO_UPLOAD_ID",
130
+ message: "Flow did not return upload ID after init",
131
+ });
132
+ callbacks.onError?.(error);
133
+ throw error;
134
+ }
135
+
136
+ logger.log(`Upload ID received: ${uploadFile.id}`);
137
+
138
+ callbacks.onStart?.({
139
+ uploadId: uploadFile.id,
140
+ size: source.size ?? null,
141
+ });
142
+
143
+ return { jobId, uploadFile, inputNodeId };
144
+ }
145
+
146
+ /**
147
+ * Upload chunks directly to the upload API (not through continueFlow)
148
+ * This is more efficient and reuses the existing upload infrastructure
149
+ */
150
+ export async function performFlowUpload({
151
+ jobId,
152
+ uploadFile,
153
+ inputNodeId,
154
+ offset,
155
+ source,
156
+ retryAttempt = 0,
157
+ abortController,
158
+ retryDelays,
159
+ smartChunker,
160
+ uploadistaApi,
161
+ logger,
162
+ smartChunking,
163
+ metrics,
164
+ platformService,
165
+ onRetry,
166
+ ...callbacks
167
+ }: {
168
+ jobId: string;
169
+ uploadFile: UploadFile;
170
+ inputNodeId: string;
171
+ offset: number;
172
+ retryAttempt?: number;
173
+ source: FileSource;
174
+ abortController: AbortControllerLike;
175
+ retryDelays: number[] | undefined;
176
+ smartChunker: SmartChunker;
177
+ uploadistaApi: UploadistaApi;
178
+ logger: Logger;
179
+ smartChunking?: SmartChunkerConfig;
180
+ metrics: UploadMetrics;
181
+ platformService: PlatformService;
182
+ onRetry?: (timeout: Timeout) => void;
183
+ } & Callbacks): Promise<void> {
184
+ let offsetBeforeRetry = offset;
185
+ let currentOffset = offset;
186
+
187
+ try {
188
+ // Get optimal chunk size
189
+ const remainingBytes = source.size ? source.size - offset : undefined;
190
+ const chunkSizeDecision = smartChunker.getNextChunkSize(remainingBytes);
191
+ const chunkSize = chunkSizeDecision.size;
192
+ const endByte = Math.min(offset + chunkSize, source.size ?? 0);
193
+ const sliceResult = await source.slice(offset, endByte);
194
+
195
+ if (!sliceResult || !sliceResult.value) {
196
+ throw new UploadistaError({
197
+ name: "NETWORK_ERROR",
198
+ message: "Failed to read chunk from file",
199
+ });
200
+ }
201
+
202
+ const chunkData = sliceResult.value;
203
+
204
+ // Upload chunk directly to upload API (bypassing flow)
205
+ const startTime = Date.now();
206
+
207
+ const res = await uploadistaApi.uploadChunk(uploadFile.id, chunkData, {
208
+ abortController,
209
+ });
210
+
211
+ const duration = Date.now() - startTime;
212
+
213
+ if (!res.upload) {
214
+ throw new UploadistaError({
215
+ name: "UPLOAD_CHUNK_FAILED",
216
+ message: "Upload chunk response missing upload data",
217
+ });
218
+ }
219
+
220
+ currentOffset = res.upload.offset;
221
+
222
+ callbacks.onProgress?.(uploadFile.id, currentOffset, source.size ?? 0);
223
+ callbacks.onChunkComplete?.(
224
+ currentOffset - offset,
225
+ offset,
226
+ source.size ?? 0,
227
+ );
228
+
229
+ // Record detailed chunk metrics
230
+ if (smartChunking?.enabled !== false) {
231
+ const chunkIndex = Math.floor(offset / chunkSize);
232
+
233
+ metrics.recordChunk({
234
+ chunkIndex,
235
+ size: chunkSize,
236
+ duration,
237
+ speed: chunkSize / (duration / 1000),
238
+ success: true,
239
+ retryCount: retryAttempt,
240
+ networkCondition:
241
+ smartChunker.getLastDecision()?.networkCondition?.type,
242
+ chunkingStrategy: smartChunker.getLastDecision()?.strategy,
243
+ });
244
+
245
+ // Update smart chunker with connection metrics
246
+ const connectionMetrics = uploadistaApi.getConnectionMetrics();
247
+ smartChunker.updateConnectionMetrics(connectionMetrics);
248
+ }
249
+
250
+ // Check if upload is complete after uploading the chunk
251
+ if (currentOffset >= (source.size ?? 0)) {
252
+ if (source) source.close();
253
+
254
+ // Complete metrics session
255
+ if (smartChunking?.enabled !== false) {
256
+ const sessionMetrics = metrics.endSession();
257
+ if (sessionMetrics) {
258
+ logger.log(
259
+ `Flow upload completed: ${sessionMetrics.totalSize} bytes in ${sessionMetrics.totalDuration}ms, avg speed: ${Math.round(sessionMetrics.averageSpeed / 1024)}KB/s`,
260
+ );
261
+ }
262
+ }
263
+
264
+ // Upload is complete - finalize the flow
265
+ logger.log(`Finalizing flow upload for job ${jobId}`);
266
+
267
+ try {
268
+ await uploadistaApi.continueFlow(
269
+ jobId,
270
+ inputNodeId,
271
+ {
272
+ operation: "finalize",
273
+ uploadId: uploadFile.id,
274
+ },
275
+ { contentType: "application/json" },
276
+ );
277
+ } catch (err) {
278
+ // Finalization errors should not trigger chunk retry logic
279
+ const error = new UploadistaError({
280
+ name: "FLOW_FINALIZE_FAILED",
281
+ message: `Failed to finalize flow upload for job ${jobId}`,
282
+ cause: err as Error,
283
+ });
284
+ callbacks.onError?.(error);
285
+ throw error;
286
+ }
287
+ return;
288
+ }
289
+
290
+ // Continue uploading next chunk
291
+ await performFlowUpload({
292
+ jobId,
293
+ uploadFile,
294
+ inputNodeId,
295
+ offset: currentOffset,
296
+ source,
297
+ platformService,
298
+ retryDelays,
299
+ smartChunker,
300
+ uploadistaApi,
301
+ logger,
302
+ smartChunking,
303
+ metrics,
304
+ onRetry,
305
+ abortController,
306
+ ...callbacks,
307
+ });
308
+ } catch (err) {
309
+ // Retry logic similar to single-upload
310
+ if (retryDelays != null) {
311
+ const shouldResetDelays =
312
+ offset != null && currentOffset > offsetBeforeRetry;
313
+ if (shouldResetDelays) {
314
+ retryAttempt = 0;
315
+ }
316
+
317
+ const castedErr = !(err instanceof UploadistaError)
318
+ ? new UploadistaError({
319
+ name: "NETWORK_ERROR",
320
+ message: "Network error during flow upload",
321
+ cause: err as Error,
322
+ })
323
+ : err;
324
+
325
+ if (
326
+ shouldRetry(
327
+ platformService,
328
+ castedErr,
329
+ retryAttempt,
330
+ retryDelays,
331
+ callbacks.onShouldRetry,
332
+ )
333
+ ) {
334
+ const delay = retryDelays[retryAttempt];
335
+ offsetBeforeRetry = offset;
336
+
337
+ const timeout = platformService.setTimeout(async () => {
338
+ await performFlowUpload({
339
+ jobId,
340
+ uploadFile,
341
+ inputNodeId,
342
+ offset,
343
+ source,
344
+ retryAttempt: retryAttempt + 1,
345
+ retryDelays,
346
+ smartChunker,
347
+ uploadistaApi,
348
+ logger,
349
+ smartChunking,
350
+ metrics,
351
+ platformService,
352
+ onRetry,
353
+ abortController,
354
+ ...callbacks,
355
+ });
356
+ }, delay);
357
+ onRetry?.(timeout);
358
+ } else {
359
+ throw new UploadistaError({
360
+ name: "UPLOAD_CHUNK_FAILED",
361
+ message: `Failed to upload chunk for job ${jobId} at offset ${offset}`,
362
+ cause: err as Error,
363
+ });
364
+ }
365
+ }
366
+ }
367
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./upload-metrics";
2
+ export * from "./upload-utils";