@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,445 @@
1
+ /**
2
+ * Assessment of current network conditions based on upload performance.
3
+ *
4
+ * Used by smart chunking algorithms to adapt chunk sizes based on network quality.
5
+ */
6
+ export interface NetworkCondition {
7
+ /**
8
+ * Classification of network speed and stability:
9
+ * - "slow": Average speed below slowThreshold (default 50 KB/s)
10
+ * - "fast": Average speed above fastThreshold (default 5 MB/s)
11
+ * - "unstable": High variance in upload speeds
12
+ * - "unknown": Insufficient data to determine condition
13
+ */
14
+ type: "slow" | "fast" | "unstable" | "unknown";
15
+
16
+ /**
17
+ * Confidence level in the assessment (0-1).
18
+ * Higher values indicate more samples and more reliable assessment.
19
+ */
20
+ confidence: number;
21
+ }
22
+
23
+ /**
24
+ * Aggregated network performance metrics.
25
+ *
26
+ * Provides a comprehensive view of upload performance over time,
27
+ * useful for debugging connectivity issues and optimizing upload strategies.
28
+ */
29
+ export interface NetworkMetrics {
30
+ /** Average upload speed in bytes per second */
31
+ averageSpeed: number;
32
+
33
+ /** Average network latency in milliseconds */
34
+ latency: number;
35
+
36
+ /** Ratio of successful uploads (0-1) */
37
+ successRate: number;
38
+
39
+ /** Ratio of failed uploads (0-1) */
40
+ errorRate: number;
41
+
42
+ /** Total number of upload requests made */
43
+ totalRequests: number;
44
+
45
+ /** Total bytes uploaded successfully */
46
+ totalBytes: number;
47
+
48
+ /** Total time spent uploading in milliseconds */
49
+ totalTime: number;
50
+ }
51
+
52
+ /**
53
+ * Individual upload sample for network analysis.
54
+ *
55
+ * Each successful or failed upload is recorded as a sample,
56
+ * which is used to calculate network metrics and conditions.
57
+ */
58
+ export interface UploadSample {
59
+ /** Size of the uploaded chunk in bytes */
60
+ size: number;
61
+
62
+ /** Time taken to upload in milliseconds */
63
+ duration: number;
64
+
65
+ /** Whether the upload succeeded */
66
+ success: boolean;
67
+
68
+ /** Unix timestamp when the upload occurred */
69
+ timestamp: number;
70
+
71
+ /** Optional network latency measurement in milliseconds */
72
+ latency?: number;
73
+ }
74
+
75
+ /**
76
+ * Configuration options for NetworkMonitor.
77
+ *
78
+ * Controls how network conditions are assessed and how upload samples
79
+ * are analyzed to determine optimal chunking strategies.
80
+ */
81
+ export interface NetworkMonitorConfig {
82
+ /** Maximum number of samples to keep in memory. Defaults to 100. */
83
+ maxSamples?: number;
84
+
85
+ /** Smoothing factor for exponential moving average (0-1). Defaults to 0.1. */
86
+ smoothingFactor?: number;
87
+
88
+ /** Minimum samples required before assessing network condition. Defaults to 5. */
89
+ minSamplesForCondition?: number;
90
+
91
+ /** Upload speed threshold for "slow" classification in bytes/second. Defaults to 50 KB/s. */
92
+ slowThreshold?: number;
93
+
94
+ /** Upload speed threshold for "fast" classification in bytes/second. Defaults to 5 MB/s. */
95
+ fastThreshold?: number;
96
+
97
+ /** Coefficient of variation threshold for "unstable" classification. Defaults to 0.5. */
98
+ unstableThreshold?: number;
99
+ }
100
+
101
+ /**
102
+ * Monitors network performance during uploads to enable adaptive chunking.
103
+ *
104
+ * Tracks upload samples over time and analyzes them to determine network conditions
105
+ * (slow, fast, unstable). This information is used by smart chunking algorithms to
106
+ * dynamically adjust chunk sizes for optimal upload performance.
107
+ *
108
+ * The monitor maintains a rolling window of recent samples and calculates various
109
+ * metrics including average speed, latency, success rate, and throughput stability.
110
+ *
111
+ * @example Basic usage with smart chunking
112
+ * ```typescript
113
+ * const monitor = new NetworkMonitor({
114
+ * maxSamples: 100,
115
+ * slowThreshold: 50 * 1024, // 50 KB/s
116
+ * fastThreshold: 5 * 1024 * 1024, // 5 MB/s
117
+ * });
118
+ *
119
+ * // Record each upload
120
+ * monitor.recordUpload(
121
+ * chunkSize, // bytes
122
+ * duration, // milliseconds
123
+ * true, // success
124
+ * latency // optional latency
125
+ * );
126
+ *
127
+ * // Get current network condition
128
+ * const condition = monitor.getNetworkCondition();
129
+ * if (condition.type === 'slow') {
130
+ * // Use smaller chunks
131
+ * chunkSize = 256 * 1024;
132
+ * } else if (condition.type === 'fast') {
133
+ * // Use larger chunks
134
+ * chunkSize = 5 * 1024 * 1024;
135
+ * }
136
+ * ```
137
+ *
138
+ * @example Monitoring network metrics
139
+ * ```typescript
140
+ * const monitor = new NetworkMonitor();
141
+ *
142
+ * // After some uploads
143
+ * const metrics = monitor.getCurrentMetrics();
144
+ * console.log(`Average speed: ${metrics.averageSpeed / 1024} KB/s`);
145
+ * console.log(`Success rate: ${metrics.successRate * 100}%`);
146
+ * console.log(`Average latency: ${metrics.latency}ms`);
147
+ * ```
148
+ */
149
+ export class NetworkMonitor {
150
+ private samples: UploadSample[] = [];
151
+ private config: Required<NetworkMonitorConfig>;
152
+ private _currentMetrics: NetworkMetrics;
153
+
154
+ /**
155
+ * Creates a new NetworkMonitor instance.
156
+ *
157
+ * @param config - Optional configuration for thresholds and sample management
158
+ */
159
+ constructor(config: NetworkMonitorConfig = {}) {
160
+ this.config = {
161
+ maxSamples: config.maxSamples ?? 100,
162
+ smoothingFactor: config.smoothingFactor ?? 0.1,
163
+ minSamplesForCondition: config.minSamplesForCondition ?? 5,
164
+ slowThreshold: config.slowThreshold ?? 50 * 1024, // 50 KB/s
165
+ fastThreshold: config.fastThreshold ?? 5 * 1024 * 1024, // 5 MB/s
166
+ unstableThreshold: config.unstableThreshold ?? 0.5, // 50% coefficient of variation
167
+ };
168
+
169
+ this._currentMetrics = this.createEmptyMetrics();
170
+ }
171
+
172
+ /**
173
+ * Adds a raw upload sample to the monitor.
174
+ *
175
+ * This is called internally by recordUpload but can also be used
176
+ * to add pre-constructed samples for testing or custom tracking.
177
+ *
178
+ * @param sample - The upload sample to add
179
+ */
180
+ addSample(sample: UploadSample): void {
181
+ this.samples.push(sample);
182
+
183
+ // Keep only the most recent samples
184
+ if (this.samples.length > this.config.maxSamples) {
185
+ this.samples = this.samples.slice(-this.config.maxSamples);
186
+ }
187
+
188
+ this.updateMetrics();
189
+ }
190
+
191
+ /**
192
+ * Records an upload operation for network analysis.
193
+ *
194
+ * This is the primary method for tracking upload performance. Each chunk upload
195
+ * should be recorded to build an accurate picture of network conditions.
196
+ *
197
+ * @param size - Size of the uploaded chunk in bytes
198
+ * @param duration - Time taken to upload in milliseconds
199
+ * @param success - Whether the upload succeeded
200
+ * @param latency - Optional network latency measurement in milliseconds
201
+ *
202
+ * @example Recording successful upload
203
+ * ```typescript
204
+ * const startTime = Date.now();
205
+ * await uploadChunk(data);
206
+ * const duration = Date.now() - startTime;
207
+ * monitor.recordUpload(data.length, duration, true);
208
+ * ```
209
+ *
210
+ * @example Recording failed upload
211
+ * ```typescript
212
+ * try {
213
+ * const startTime = Date.now();
214
+ * await uploadChunk(data);
215
+ * monitor.recordUpload(data.length, Date.now() - startTime, true);
216
+ * } catch (error) {
217
+ * monitor.recordUpload(data.length, Date.now() - startTime, false);
218
+ * }
219
+ * ```
220
+ */
221
+ recordUpload(
222
+ size: number,
223
+ duration: number,
224
+ success: boolean,
225
+ latency?: number,
226
+ ): void {
227
+ this.addSample({
228
+ size,
229
+ duration,
230
+ success,
231
+ timestamp: Date.now(),
232
+ latency,
233
+ });
234
+ }
235
+
236
+ /**
237
+ * Returns the current network metrics.
238
+ *
239
+ * Provides aggregated statistics about all recorded uploads including
240
+ * average speed, latency, success rate, and totals.
241
+ *
242
+ * @returns A snapshot of current network performance metrics
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * const metrics = monitor.getCurrentMetrics();
247
+ * console.log(`Speed: ${(metrics.averageSpeed / 1024).toFixed(2)} KB/s`);
248
+ * console.log(`Success: ${(metrics.successRate * 100).toFixed(1)}%`);
249
+ * console.log(`Latency: ${metrics.latency.toFixed(0)}ms`);
250
+ * ```
251
+ */
252
+ getCurrentMetrics(): NetworkMetrics {
253
+ return { ...this._currentMetrics };
254
+ }
255
+
256
+ /**
257
+ * Analyzes recent upload samples to determine current network condition.
258
+ *
259
+ * Uses statistical analysis (coefficient of variation, average speed) to classify
260
+ * the network as slow, fast, unstable, or unknown. The confidence level indicates
261
+ * how reliable the assessment is based on the number of samples collected.
262
+ *
263
+ * @returns Current network condition with confidence level
264
+ *
265
+ * @example Adaptive chunking based on network condition
266
+ * ```typescript
267
+ * const condition = monitor.getNetworkCondition();
268
+ *
269
+ * if (condition.confidence > 0.7) {
270
+ * switch (condition.type) {
271
+ * case 'fast':
272
+ * chunkSize = 10 * 1024 * 1024; // 10MB
273
+ * break;
274
+ * case 'slow':
275
+ * chunkSize = 256 * 1024; // 256KB
276
+ * break;
277
+ * case 'unstable':
278
+ * chunkSize = 1 * 1024 * 1024; // 1MB, conservative
279
+ * break;
280
+ * }
281
+ * }
282
+ * ```
283
+ */
284
+ getNetworkCondition(): NetworkCondition {
285
+ if (this.samples.length < this.config.minSamplesForCondition) {
286
+ return { type: "unknown", confidence: 0 };
287
+ }
288
+
289
+ const recentSamples = this.getRecentSuccessfulSamples();
290
+ if (recentSamples.length < this.config.minSamplesForCondition) {
291
+ return { type: "unknown", confidence: 0.3 };
292
+ }
293
+
294
+ const speeds = recentSamples.map(
295
+ (sample) => sample.size / (sample.duration / 1000),
296
+ );
297
+ const avgSpeed =
298
+ speeds.reduce((sum, speed) => sum + speed, 0) / speeds.length;
299
+
300
+ // Calculate coefficient of variation for stability assessment
301
+ const variance =
302
+ speeds.reduce((sum, speed) => sum + (speed - avgSpeed) ** 2, 0) /
303
+ speeds.length;
304
+ const stdDev = Math.sqrt(variance);
305
+ const coefficientOfVariation = stdDev / avgSpeed;
306
+
307
+ // Determine network condition
308
+ const confidence = Math.min(
309
+ 1,
310
+ this.samples.length / (this.config.minSamplesForCondition * 2),
311
+ );
312
+
313
+ if (coefficientOfVariation > this.config.unstableThreshold) {
314
+ return { type: "unstable", confidence };
315
+ }
316
+
317
+ if (avgSpeed < this.config.slowThreshold) {
318
+ return { type: "slow", confidence };
319
+ }
320
+
321
+ if (avgSpeed > this.config.fastThreshold) {
322
+ return { type: "fast", confidence };
323
+ }
324
+
325
+ // Default to slow for conservative chunking
326
+ return { type: "slow", confidence: confidence * 0.7 };
327
+ }
328
+
329
+ /**
330
+ * Calculates the optimal upload throughput based on recent successful uploads.
331
+ *
332
+ * Uses a weighted average that gives more weight to recent samples,
333
+ * providing a responsive measure of current network capacity.
334
+ *
335
+ * @returns Optimal throughput in bytes per second, or 0 if no successful samples
336
+ *
337
+ * @example Using for chunk size calculation
338
+ * ```typescript
339
+ * const throughput = monitor.getOptimalThroughput();
340
+ * // Target 1 second per chunk
341
+ * const optimalChunkSize = Math.min(throughput, MAX_CHUNK_SIZE);
342
+ * ```
343
+ */
344
+ getOptimalThroughput(): number {
345
+ const recentSamples = this.getRecentSuccessfulSamples(10);
346
+ if (recentSamples.length === 0) return 0;
347
+
348
+ // Calculate weighted average with recent samples having higher weight
349
+ let totalWeight = 0;
350
+ let weightedSum = 0;
351
+
352
+ recentSamples.forEach((sample, index) => {
353
+ const weight = index + 1; // More recent samples get higher weight
354
+ const throughput = sample.size / (sample.duration / 1000);
355
+ weightedSum += throughput * weight;
356
+ totalWeight += weight;
357
+ });
358
+
359
+ return totalWeight > 0 ? weightedSum / totalWeight : 0;
360
+ }
361
+
362
+ /**
363
+ * Resets all samples and metrics to initial state.
364
+ *
365
+ * Useful when network conditions change significantly or when
366
+ * starting a new upload session.
367
+ *
368
+ * @example Resetting between uploads
369
+ * ```typescript
370
+ * // Complete first upload
371
+ * await uploadFile1();
372
+ *
373
+ * // Reset metrics before starting a new upload
374
+ * monitor.reset();
375
+ * await uploadFile2();
376
+ * ```
377
+ */
378
+ reset(): void {
379
+ this.samples = [];
380
+ this._currentMetrics = this.createEmptyMetrics();
381
+ }
382
+
383
+ private getRecentSuccessfulSamples(count?: number): UploadSample[] {
384
+ const successful = this.samples.filter((sample) => sample.success);
385
+ return count ? successful.slice(-count) : successful;
386
+ }
387
+
388
+ private updateMetrics(): void {
389
+ const successfulSamples = this.samples.filter((sample) => sample.success);
390
+ const totalRequests = this.samples.length;
391
+ const totalSuccessful = successfulSamples.length;
392
+
393
+ if (totalRequests === 0) {
394
+ this._currentMetrics = this.createEmptyMetrics();
395
+ return;
396
+ }
397
+
398
+ const totalBytes = successfulSamples.reduce(
399
+ (sum, sample) => sum + sample.size,
400
+ 0,
401
+ );
402
+ const totalTime = successfulSamples.reduce(
403
+ (sum, sample) => sum + sample.duration,
404
+ 0,
405
+ );
406
+
407
+ const averageSpeed = totalTime > 0 ? totalBytes / (totalTime / 1000) : 0;
408
+ const successRate = totalSuccessful / totalRequests;
409
+ const errorRate = 1 - successRate;
410
+
411
+ // Calculate average latency from samples that have latency data
412
+ const samplesWithLatency = this.samples.filter(
413
+ (sample) => sample.latency !== undefined,
414
+ );
415
+ const averageLatency =
416
+ samplesWithLatency.length > 0
417
+ ? samplesWithLatency.reduce(
418
+ (sum, sample) => sum + (sample.latency || 0),
419
+ 0,
420
+ ) / samplesWithLatency.length
421
+ : 0;
422
+
423
+ this._currentMetrics = {
424
+ averageSpeed,
425
+ latency: averageLatency,
426
+ successRate,
427
+ errorRate,
428
+ totalRequests,
429
+ totalBytes,
430
+ totalTime,
431
+ };
432
+ }
433
+
434
+ private createEmptyMetrics(): NetworkMetrics {
435
+ return {
436
+ averageSpeed: 0,
437
+ latency: 0,
438
+ successRate: 0,
439
+ errorRate: 0,
440
+ totalRequests: 0,
441
+ totalBytes: 0,
442
+ totalTime: 0,
443
+ };
444
+ }
445
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Platform-agnostic AbortController interface
3
+ */
4
+
5
+ export interface AbortControllerLike {
6
+ readonly signal: AbortSignalLike;
7
+ abort(reason?: unknown): void;
8
+ }
9
+
10
+ export interface AbortSignalLike {
11
+ readonly aborted: boolean;
12
+ addEventListener(type: "abort", listener: () => void): void;
13
+ removeEventListener(type: "abort", listener: () => void): void;
14
+ }
15
+
16
+ export interface AbortControllerFactory {
17
+ /**
18
+ * Create a new AbortController instance
19
+ */
20
+ create(): AbortControllerLike;
21
+ }
@@ -0,0 +1,3 @@
1
+ export interface ChecksumService {
2
+ computeChecksum(data: Uint8Array): Promise<string>;
3
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Platform-agnostic file reader service
3
+ */
4
+
5
+ export type SliceResult =
6
+ | {
7
+ done: true;
8
+ value: null;
9
+ size: null;
10
+ }
11
+ | {
12
+ done: boolean;
13
+ value: Uint8Array;
14
+ size: number;
15
+ };
16
+
17
+ export interface FileSource {
18
+ input: unknown;
19
+ size: number | null;
20
+ name: string | null;
21
+ type: string | null;
22
+ lastModified: number | null;
23
+ slice: (start: number, end: number) => Promise<SliceResult>;
24
+ close: () => void;
25
+ }
26
+
27
+ export interface FileReaderService<UploadInput> {
28
+ /**
29
+ * Open a file for reading
30
+ */
31
+ openFile(input: UploadInput, chunkSize: number): Promise<FileSource>;
32
+ }
33
+
34
+ export interface Base64Service {
35
+ /**
36
+ * Encode data to base64
37
+ */
38
+ toBase64(data: ArrayBuffer): string;
39
+
40
+ /**
41
+ * Decode base64 to data
42
+ */
43
+ fromBase64(data: string): ArrayBuffer;
44
+ }
@@ -0,0 +1,6 @@
1
+ export interface FingerprintService<UploadInput> {
2
+ computeFingerprint(
3
+ file: UploadInput,
4
+ endpoint: string,
5
+ ): Promise<string | null>;
6
+ }