@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,56 @@
1
+ /**
2
+ * Configuration for uploading a file through a flow pipeline.
3
+ *
4
+ * Flows enable processing uploaded files through a sequence of transformation
5
+ * nodes (e.g., image resize, format conversion, validation) before final storage.
6
+ *
7
+ * @example Basic flow upload
8
+ * ```typescript
9
+ * const config: FlowUploadConfig = {
10
+ * flowId: 'image-optimization',
11
+ * storageId: 'processed-images',
12
+ * };
13
+ *
14
+ * await client.uploadWithFlow(file, config, {
15
+ * onProgress: (progress) => console.log(`${progress}%`),
16
+ * onSuccess: (result) => console.log('Processed:', result),
17
+ * });
18
+ * ```
19
+ *
20
+ * @example With specific output node
21
+ * ```typescript
22
+ * const config: FlowUploadConfig = {
23
+ * flowId: 'multi-format-conversion',
24
+ * storageId: 'images',
25
+ * outputNodeId: 'webp-output', // Get WebP version instead of first output
26
+ * metadata: {
27
+ * userId: '123',
28
+ * album: 'vacation-2024',
29
+ * },
30
+ * };
31
+ * ```
32
+ */
33
+ export type FlowUploadConfig = {
34
+ /** Unique identifier of the flow to execute */
35
+ flowId: string;
36
+
37
+ /** Storage backend where flow outputs will be saved */
38
+ storageId: string;
39
+
40
+ /**
41
+ * Specify which output node to use for single-value callbacks like onSuccess.
42
+ *
43
+ * For flows with multiple output nodes, this determines which output
44
+ * is passed to the onSuccess callback. If not specified, uses the first
45
+ * output node. The onFlowComplete callback receives all outputs regardless.
46
+ */
47
+ outputNodeId?: string;
48
+
49
+ /**
50
+ * Additional metadata to attach to the upload and flow execution.
51
+ *
52
+ * This metadata is stored with the upload and can be used for tracking,
53
+ * filtering, or providing context to flow nodes.
54
+ */
55
+ metadata?: Record<string, string>;
56
+ };
@@ -0,0 +1,16 @@
1
+ import type { UploadFile } from "@uploadista/core";
2
+
3
+ /**
4
+ * Flow upload item for multi-flow-upload tracking
5
+ */
6
+ export interface FlowUploadItem<UploadInput> {
7
+ id: string;
8
+ file: UploadInput;
9
+ status: "pending" | "uploading" | "success" | "error" | "aborted";
10
+ progress: number;
11
+ bytesUploaded: number;
12
+ totalBytes: number;
13
+ error: Error | null;
14
+ result: UploadFile | null;
15
+ jobId: string | null;
16
+ }
@@ -0,0 +1,56 @@
1
+ import type { UploadFile } from "@uploadista/core/types";
2
+ import type { FlowUploadConfig } from "./flow-upload-config";
3
+
4
+ export interface FlowUploadOptions<TOutput = UploadFile> {
5
+ /**
6
+ * Flow configuration
7
+ */
8
+ flowConfig: FlowUploadConfig;
9
+
10
+ /**
11
+ * Called when upload progress updates
12
+ */
13
+ onProgress?: (
14
+ progress: number,
15
+ bytesUploaded: number,
16
+ totalBytes: number | null,
17
+ ) => void;
18
+
19
+ /**
20
+ * Called when a chunk completes
21
+ */
22
+ onChunkComplete?: (
23
+ chunkSize: number,
24
+ bytesAccepted: number,
25
+ bytesTotal: number | null,
26
+ ) => void;
27
+
28
+ /**
29
+ * Called when the flow completes successfully (receives full flow outputs)
30
+ * This is the recommended callback for multi-output flows
31
+ * Format: { [outputNodeId]: result, ... }
32
+ */
33
+ onFlowComplete?: (outputs: Record<string, unknown>) => void;
34
+
35
+ /**
36
+ * Called when upload succeeds (legacy, single-output flows)
37
+ * For single-output flows, receives the value from the specified outputNodeId
38
+ * or the first output node if outputNodeId is not specified
39
+ */
40
+ onSuccess?: (result: TOutput) => void;
41
+
42
+ /**
43
+ * Called when upload fails
44
+ */
45
+ onError?: (error: Error) => void;
46
+
47
+ /**
48
+ * Called when upload is aborted
49
+ */
50
+ onAbort?: () => void;
51
+
52
+ /**
53
+ * Custom retry logic
54
+ */
55
+ onShouldRetry?: (error: Error, retryAttempt: number) => boolean;
56
+ }
@@ -0,0 +1,13 @@
1
+ export * from "./chunk-metrics";
2
+ export * from "./flow-result";
3
+ export * from "./flow-upload-config";
4
+ export * from "./flow-upload-item";
5
+ export * from "./flow-upload-options";
6
+ export * from "./multi-flow-upload-options";
7
+ export * from "./multi-flow-upload-state";
8
+ export * from "./performance-insights";
9
+ export * from "./previous-upload";
10
+ export * from "./upload-options";
11
+ export * from "./upload-response";
12
+ export * from "./upload-result";
13
+ export * from "./upload-session-metrics";
@@ -0,0 +1,39 @@
1
+ import type { FlowUploadConfig } from "./flow-upload-config";
2
+ import type { FlowUploadItem } from "./flow-upload-item";
3
+
4
+ export interface MultiFlowUploadOptions<UploadInput> {
5
+ /**
6
+ * Flow configuration
7
+ */
8
+ flowConfig: FlowUploadConfig;
9
+
10
+ /**
11
+ * Maximum number of concurrent uploads (default: 3)
12
+ */
13
+ maxConcurrent?: number;
14
+
15
+ /**
16
+ * Called when an individual upload progresses
17
+ */
18
+ onItemProgress?: (item: FlowUploadItem<UploadInput>) => void;
19
+
20
+ /**
21
+ * Called when an individual upload succeeds
22
+ */
23
+ onItemSuccess?: (item: FlowUploadItem<UploadInput>) => void;
24
+
25
+ /**
26
+ * Called when an individual upload fails
27
+ */
28
+ onItemError?: (item: FlowUploadItem<UploadInput>, error: Error) => void;
29
+
30
+ /**
31
+ * Called when all uploads complete
32
+ */
33
+ onComplete?: (items: FlowUploadItem<UploadInput>[]) => void;
34
+
35
+ /**
36
+ * Custom retry logic
37
+ */
38
+ onShouldRetry?: (error: Error, retryAttempt: number) => boolean;
39
+ }
@@ -0,0 +1,9 @@
1
+ import type { FlowUploadItem } from "./flow-upload-item";
2
+
3
+ export interface MultiFlowUploadState<UploadInput> {
4
+ items: FlowUploadItem<UploadInput>[];
5
+ totalProgress: number;
6
+ activeUploads: number;
7
+ completedUploads: number;
8
+ failedUploads: number;
9
+ }
@@ -0,0 +1,7 @@
1
+ export interface PerformanceInsights {
2
+ overallEfficiency: number; // 0-1 score
3
+ chunkingEffectiveness: number; // 0-1 score
4
+ networkStability: number; // 0-1 score
5
+ recommendations: string[];
6
+ optimalChunkSizeRange: { min: number; max: number };
7
+ }
@@ -0,0 +1,22 @@
1
+ import z from "zod";
2
+
3
+ export type PreviousUpload = {
4
+ size: number | null;
5
+ metadata: { [key: string]: string | number | boolean };
6
+ creationTime: string;
7
+ uploadId?: string;
8
+ parallelUploadUrls?: string[];
9
+ clientStorageKey: string;
10
+ };
11
+
12
+ export const previousUploadSchema = z.object({
13
+ size: z.number().nullable(),
14
+ metadata: z.record(
15
+ z.string(),
16
+ z.union([z.string(), z.number(), z.boolean()]),
17
+ ),
18
+ creationTime: z.string(),
19
+ uploadId: z.string().optional(),
20
+ parallelUploadUrls: z.array(z.string()).optional(),
21
+ clientStorageKey: z.string(),
22
+ });
@@ -0,0 +1,56 @@
1
+ import type { UploadFile } from "@uploadista/core";
2
+
3
+ export interface UploadOptions {
4
+ /**
5
+ * Upload metadata to attach to the file
6
+ */
7
+ metadata?: Record<string, string>;
8
+
9
+ /**
10
+ * Whether to defer the upload size calculation
11
+ */
12
+ uploadLengthDeferred?: boolean;
13
+
14
+ /**
15
+ * Manual upload size override
16
+ */
17
+ uploadSize?: number;
18
+
19
+ /**
20
+ * Called when upload progress updates
21
+ */
22
+ onProgress?: (
23
+ progress: number,
24
+ bytesUploaded: number,
25
+ totalBytes: number | null,
26
+ ) => void;
27
+
28
+ /**
29
+ * Called when a chunk completes
30
+ */
31
+ onChunkComplete?: (
32
+ chunkSize: number,
33
+ bytesAccepted: number,
34
+ bytesTotal: number | null,
35
+ ) => void;
36
+
37
+ /**
38
+ * Called when upload succeeds
39
+ */
40
+ onSuccess?: (result: UploadFile) => void;
41
+
42
+ /**
43
+ * Called when upload fails
44
+ */
45
+ onError?: (error: Error) => void;
46
+
47
+ /**
48
+ * Called when upload is aborted
49
+ */
50
+ onAbort?: () => void;
51
+
52
+ /**
53
+ * Custom retry logic
54
+ */
55
+ onShouldRetry?: (error: Error, retryAttempt: number) => boolean;
56
+ }
@@ -0,0 +1,6 @@
1
+ import type { UploadFile } from "@uploadista/core";
2
+
3
+ export type UploadResponse = {
4
+ upload?: UploadFile;
5
+ status: number;
6
+ };
@@ -0,0 +1,60 @@
1
+ import type { UploadFile } from "@uploadista/core";
2
+
3
+ /**
4
+ * Discriminated union representing the result of an upload operation.
5
+ *
6
+ * Provides a type-safe way to handle the three possible outcomes of an upload:
7
+ * success, error, or cancellation. This pattern enables exhaustive checking
8
+ * of all cases at compile time.
9
+ *
10
+ * @template TOutput - The type of the successful result value. Defaults to UploadFile
11
+ *
12
+ * @example Handling upload results
13
+ * ```typescript
14
+ * function handleUploadResult(result: UploadResult) {
15
+ * switch (result.type) {
16
+ * case 'success':
17
+ * console.log('Upload complete:', result.value.id);
18
+ * break;
19
+ * case 'error':
20
+ * console.error('Upload failed:', result.error.message);
21
+ * break;
22
+ * case 'cancelled':
23
+ * console.log('Upload was cancelled by user');
24
+ * break;
25
+ * }
26
+ * }
27
+ * ```
28
+ *
29
+ * @example With custom output type
30
+ * ```typescript
31
+ * interface ProcessedImage {
32
+ * url: string;
33
+ * width: number;
34
+ * height: number;
35
+ * }
36
+ *
37
+ * const result: UploadResult<ProcessedImage> = await uploadAndProcess(file);
38
+ *
39
+ * if (result.type === 'success') {
40
+ * console.log(`Image processed: ${result.value.width}x${result.value.height}`);
41
+ * }
42
+ * ```
43
+ */
44
+ export type UploadResult<TOutput = UploadFile> =
45
+ | {
46
+ /** Indicates the upload completed successfully */
47
+ type: "success";
48
+ /** The successful result value (e.g., upload metadata or processed output) */
49
+ value: TOutput;
50
+ }
51
+ | {
52
+ /** Indicates the upload failed with an error */
53
+ type: "error";
54
+ /** The error that caused the upload to fail */
55
+ error: Error;
56
+ }
57
+ | {
58
+ /** Indicates the upload was cancelled by the user or application */
59
+ type: "cancelled";
60
+ };
@@ -0,0 +1,15 @@
1
+ export interface UploadSessionMetrics {
2
+ uploadId: string;
3
+ totalSize: number;
4
+ totalDuration: number;
5
+ chunksCompleted: number;
6
+ chunksTotal: number;
7
+ averageSpeed: number;
8
+ peakSpeed: number;
9
+ minSpeed: number;
10
+ totalRetries: number;
11
+ successRate: number;
12
+ adaptiveChunkingEnabled: boolean;
13
+ startTime: number;
14
+ endTime?: number;
15
+ }
@@ -0,0 +1,151 @@
1
+ import type { UploadistaApi } from "../client/uploadista-api";
2
+ import { UploadistaError } from "../error";
3
+ import type { Logger } from "../logger";
4
+ import type { AbortControllerLike } from "../services";
5
+ import type { FileSource } from "../services/file-reader-service";
6
+ import type { PlatformService } from "../services/platform-service";
7
+ import type { SmartChunker } from "../smart-chunker";
8
+ import type { UploadResponse } from "../types/upload-response";
9
+ import { inStatusCategory } from "./upload-utils";
10
+
11
+ export type OnProgress = (
12
+ uploadId: string,
13
+ bytesSent: number,
14
+ bytesTotal: number | null,
15
+ ) => void;
16
+
17
+ export type OnShouldRetry = (
18
+ error: UploadistaError,
19
+ retryAttempt: number,
20
+ ) => boolean;
21
+
22
+ /**
23
+ * uploadChunk reads a chunk from the source and sends it using the
24
+ * supplied request object. It will not handle the response.
25
+ */
26
+ export async function uploadChunk({
27
+ uploadId,
28
+ source,
29
+ offset,
30
+ uploadLengthDeferred,
31
+ abortController,
32
+ onProgress,
33
+ smartChunker,
34
+ uploadistaApi,
35
+ logger,
36
+ }: {
37
+ uploadId: string;
38
+ source: FileSource;
39
+ offset: number;
40
+ uploadLengthDeferred: boolean | undefined;
41
+ abortController: AbortControllerLike;
42
+ onProgress?: OnProgress;
43
+ smartChunker: SmartChunker;
44
+ uploadistaApi: UploadistaApi;
45
+ logger: Logger;
46
+ }): Promise<UploadResponse> {
47
+ const start = offset ?? 0;
48
+ const remainingBytes = source.size ? source.size - start : undefined;
49
+ const chunkSizeDecision = smartChunker.getNextChunkSize(remainingBytes);
50
+ const currentChunkSize = chunkSizeDecision.size;
51
+ let end = start + currentChunkSize;
52
+
53
+ // The specified chunkSize may be Infinity or the calcluated end position
54
+ // may exceed the file's size. In both cases, we limit the end position to
55
+ // the input's total size for simpler calculations and correctness.
56
+ if (
57
+ source.size &&
58
+ (end === Number.POSITIVE_INFINITY || end > source.size) &&
59
+ !uploadLengthDeferred
60
+ ) {
61
+ end = source.size;
62
+ }
63
+
64
+ const { value, size, done } = await source.slice(start, end);
65
+ const sizeOfValue = size ?? 0;
66
+ const chunkStartTime = Date.now();
67
+
68
+ // If the upload length is deferred, the upload size was not specified during
69
+ // upload creation. So, if the file reader is done reading, we know the total
70
+ // upload size and can tell the tus server.
71
+ if (uploadLengthDeferred && done) {
72
+ source.size = offset + sizeOfValue;
73
+ }
74
+
75
+ // The specified uploadSize might not match the actual amount of data that a source
76
+ // provides. In these cases, we cannot successfully complete the upload, so we
77
+ // rather error out and let the user know. If not, tus-js-client will be stuck
78
+ // in a loop of repeating empty PATCH requests.
79
+ // See https://community.transloadit.com/t/how-to-abort-hanging-companion-uploads/16488/13
80
+ const newSize = offset + sizeOfValue;
81
+ if (!uploadLengthDeferred && done && newSize !== source.size) {
82
+ throw new UploadistaError({
83
+ name: "WRONG_UPLOAD_SIZE",
84
+ message: `upload was configured with a size of ${size} bytes, but the source is done after ${newSize} bytes`,
85
+ });
86
+ }
87
+
88
+ const result = await uploadistaApi.uploadChunk(uploadId, value, {
89
+ onProgress: (bytes, total) => {
90
+ onProgress?.(uploadId, bytes, total);
91
+ },
92
+ abortController,
93
+ });
94
+
95
+ // Record performance metrics
96
+ const chunkDuration = Date.now() - chunkStartTime;
97
+ const success = result.status >= 200 && result.status < 300;
98
+
99
+ smartChunker.recordChunkResult(sizeOfValue, chunkDuration, success);
100
+
101
+ logger.log(
102
+ `Chunk upload ${success ? "succeeded" : "failed"}: ${sizeOfValue} bytes in ${chunkDuration}ms (${chunkSizeDecision.strategy} strategy)`,
103
+ );
104
+
105
+ return result;
106
+ }
107
+
108
+ /**
109
+ * Checks whether or not it is ok to retry a request.
110
+ * @param {UploadistaError} err the error returned from the last request
111
+ * @param {number} retryAttempt the number of times the request has already been retried
112
+ * @param {number[]} retryDelays configured retry delays
113
+ * @param {OnShouldRetry} onShouldRetry optional custom retry logic
114
+ */
115
+ export function shouldRetry(
116
+ platformService: PlatformService,
117
+ err: UploadistaError,
118
+ retryAttempt: number,
119
+ retryDelays?: number[],
120
+ onShouldRetry?: OnShouldRetry,
121
+ ): boolean {
122
+ if (
123
+ retryDelays == null ||
124
+ retryAttempt >= retryDelays.length ||
125
+ !err.isNetworkError()
126
+ ) {
127
+ return false;
128
+ }
129
+
130
+ if (onShouldRetry) {
131
+ return onShouldRetry(err, retryAttempt);
132
+ }
133
+
134
+ return defaultOnShouldRetry(platformService, err);
135
+ }
136
+
137
+ /**
138
+ * determines if the request should be retried. Will only retry if not a status 4xx except a 409 or 423
139
+ * @param {UploadistaError} err
140
+ * @returns {boolean}
141
+ */
142
+ export function defaultOnShouldRetry(
143
+ platformService: PlatformService,
144
+ err: UploadistaError,
145
+ ): boolean {
146
+ const status = err.status ?? 0;
147
+ return (
148
+ (!inStatusCategory(status, 400) || status === 409 || status === 423) &&
149
+ platformService.isOnline()
150
+ );
151
+ }