@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,317 @@
1
+ const DEFAULT_STRATEGIES = {
2
+ conservative: {
3
+ name: "conservative",
4
+ minChunkSize: 64 * 1024, // 64 KB
5
+ maxChunkSize: 2 * 1024 * 1024, // 2 MB
6
+ initialChunkSize: 256 * 1024, // 256 KB
7
+ adaptationRate: 0.1,
8
+ },
9
+ balanced: {
10
+ name: "balanced",
11
+ minChunkSize: 128 * 1024, // 128 KB
12
+ maxChunkSize: 8 * 1024 * 1024, // 8 MB
13
+ initialChunkSize: 512 * 1024, // 512 KB
14
+ adaptationRate: 0.2,
15
+ },
16
+ aggressive: {
17
+ name: "aggressive",
18
+ minChunkSize: 256 * 1024, // 256 KB
19
+ maxChunkSize: 32 * 1024 * 1024, // 32 MB
20
+ initialChunkSize: 1024 * 1024, // 1 MB
21
+ adaptationRate: 0.3,
22
+ },
23
+ };
24
+ const S3_OPTIMIZED_STRATEGIES = {
25
+ conservative: {
26
+ name: "s3-conservative",
27
+ minChunkSize: 5 * 1024 * 1024, // 5MB - S3 minimum
28
+ maxChunkSize: 64 * 1024 * 1024, // 64MB
29
+ initialChunkSize: 8 * 1024 * 1024, // 8MB
30
+ adaptationRate: 0.1,
31
+ },
32
+ balanced: {
33
+ name: "s3-balanced",
34
+ minChunkSize: 5 * 1024 * 1024, // 5MB - S3 minimum
35
+ maxChunkSize: 128 * 1024 * 1024, // 128MB
36
+ initialChunkSize: 16 * 1024 * 1024, // 16MB
37
+ adaptationRate: 0.2,
38
+ },
39
+ aggressive: {
40
+ name: "s3-aggressive",
41
+ minChunkSize: 5 * 1024 * 1024, // 5MB - S3 minimum
42
+ maxChunkSize: 256 * 1024 * 1024, // 256MB
43
+ initialChunkSize: 32 * 1024 * 1024, // 32MB
44
+ adaptationRate: 0.3,
45
+ },
46
+ };
47
+ export class SmartChunker {
48
+ constructor(networkMonitor, config = {}) {
49
+ this.lastDecision = null;
50
+ this.consecutiveFailures = 0;
51
+ this.consecutiveSuccesses = 0;
52
+ this.connectionMetrics = null;
53
+ this.networkMonitor = networkMonitor;
54
+ this.config = {
55
+ enabled: config.enabled ?? true,
56
+ fallbackChunkSize: config.fallbackChunkSize ?? 1024 * 1024, // 1 MB
57
+ minChunkSize: config.minChunkSize ?? 64 * 1024, // 64 KB
58
+ maxChunkSize: config.maxChunkSize ?? 32 * 1024 * 1024, // 32 MB
59
+ initialChunkSize: config.initialChunkSize ?? 512 * 1024, // 512 KB
60
+ targetUtilization: config.targetUtilization ?? 0.85, // 85%
61
+ adaptationRate: config.adaptationRate ?? 0.2,
62
+ conservativeMode: config.conservativeMode ?? false,
63
+ connectionPoolingAware: config.connectionPoolingAware ?? true, // Enable by default
64
+ datastoreConstraints: config.datastoreConstraints,
65
+ };
66
+ this.currentChunkSize = this.getEffectiveInitialChunkSize();
67
+ }
68
+ getEffectiveInitialChunkSize() {
69
+ if (this.config.datastoreConstraints) {
70
+ return Math.max(this.config.initialChunkSize, this.config.datastoreConstraints.optimalChunkSize);
71
+ }
72
+ return this.config.initialChunkSize;
73
+ }
74
+ applyDatastoreConstraints(size) {
75
+ if (this.config.datastoreConstraints) {
76
+ return Math.max(this.config.datastoreConstraints.minChunkSize, Math.min(this.config.datastoreConstraints.maxChunkSize, size));
77
+ }
78
+ return size;
79
+ }
80
+ getNextChunkSize(remainingBytes) {
81
+ if (!this.config.enabled) {
82
+ return {
83
+ size: this.config.fallbackChunkSize,
84
+ strategy: "fixed",
85
+ reason: "Smart chunking disabled",
86
+ networkCondition: { type: "unknown", confidence: 0 },
87
+ };
88
+ }
89
+ const networkCondition = this.networkMonitor.getNetworkCondition();
90
+ let newSize = this.currentChunkSize;
91
+ let strategy = "adaptive";
92
+ let reason = "";
93
+ // If we don't have enough data, use initial strategy
94
+ if (networkCondition.type === "unknown") {
95
+ newSize = this.config.initialChunkSize;
96
+ strategy = "initial";
97
+ reason = "Insufficient network data";
98
+ }
99
+ else {
100
+ const chunkingStrategy = this.selectStrategy(networkCondition);
101
+ newSize = this.calculateOptimalChunkSize(networkCondition, chunkingStrategy);
102
+ strategy = chunkingStrategy.name;
103
+ reason = `Network condition: ${networkCondition.type} (confidence: ${Math.round(networkCondition.confidence * 100)}%)`;
104
+ }
105
+ // Apply remaining bytes limit
106
+ if (remainingBytes && remainingBytes < newSize) {
107
+ newSize = remainingBytes;
108
+ reason += `, limited by remaining bytes (${remainingBytes})`;
109
+ }
110
+ // Apply datastore constraints first
111
+ newSize = this.applyDatastoreConstraints(newSize);
112
+ // Ensure bounds
113
+ newSize = Math.max(this.config.minChunkSize, Math.min(this.config.maxChunkSize, newSize));
114
+ this.currentChunkSize = newSize;
115
+ this.lastDecision = {
116
+ size: newSize,
117
+ strategy,
118
+ reason,
119
+ networkCondition,
120
+ };
121
+ return this.lastDecision;
122
+ }
123
+ recordChunkResult(size, duration, success) {
124
+ // Record the result in network monitor
125
+ this.networkMonitor.recordUpload(size, duration, success);
126
+ // Update our internal state
127
+ if (success) {
128
+ this.consecutiveSuccesses++;
129
+ this.consecutiveFailures = 0;
130
+ }
131
+ else {
132
+ this.consecutiveFailures++;
133
+ this.consecutiveSuccesses = 0;
134
+ }
135
+ // Adjust chunk size based on recent performance
136
+ this.adaptChunkSize(success, duration, size);
137
+ }
138
+ getCurrentChunkSize() {
139
+ return this.currentChunkSize;
140
+ }
141
+ getLastDecision() {
142
+ return this.lastDecision;
143
+ }
144
+ reset() {
145
+ this.currentChunkSize = this.config.initialChunkSize;
146
+ this.consecutiveFailures = 0;
147
+ this.consecutiveSuccesses = 0;
148
+ this.lastDecision = null;
149
+ this.connectionMetrics = null;
150
+ }
151
+ /**
152
+ * Update connection metrics for connection pooling aware optimizations
153
+ */
154
+ updateConnectionMetrics(metrics) {
155
+ this.connectionMetrics = metrics;
156
+ }
157
+ /**
158
+ * Get insights about connection pooling impact on chunking
159
+ */
160
+ getConnectionPoolingInsights() {
161
+ if (!this.connectionMetrics || !this.config.connectionPoolingAware) {
162
+ return {
163
+ isOptimized: false,
164
+ reuseRate: 0,
165
+ recommendedMinChunkSize: this.config.minChunkSize,
166
+ connectionOverhead: 0,
167
+ };
168
+ }
169
+ const reuseRate = this.connectionMetrics.reuseRate;
170
+ const avgConnectionTime = this.connectionMetrics.averageConnectionTime;
171
+ // With good connection reuse, we can afford smaller chunks
172
+ const connectionOverhead = (1 - reuseRate) * avgConnectionTime;
173
+ const recommendedMinChunkSize = Math.max(this.config.minChunkSize, Math.floor(connectionOverhead * 10000));
174
+ return {
175
+ isOptimized: reuseRate > 0.7,
176
+ reuseRate,
177
+ recommendedMinChunkSize,
178
+ connectionOverhead,
179
+ };
180
+ }
181
+ selectStrategy(networkCondition) {
182
+ const fallbackStrategy = {
183
+ name: "fallback",
184
+ minChunkSize: 128 * 1024,
185
+ maxChunkSize: 4 * 1024 * 1024,
186
+ initialChunkSize: 512 * 1024,
187
+ adaptationRate: 0.2,
188
+ };
189
+ // Use S3-optimized strategies if datastore constraints indicate S3 (5MB minimum)
190
+ const isS3Like = this.config.datastoreConstraints?.minChunkSize === 5 * 1024 * 1024;
191
+ const strategiesSource = isS3Like
192
+ ? S3_OPTIMIZED_STRATEGIES
193
+ : DEFAULT_STRATEGIES;
194
+ if (this.config.conservativeMode) {
195
+ return strategiesSource.conservative ?? fallbackStrategy;
196
+ }
197
+ // Enhanced strategy selection with connection pooling awareness
198
+ let baseStrategy;
199
+ switch (networkCondition.type) {
200
+ case "fast":
201
+ baseStrategy =
202
+ networkCondition.confidence > 0.7
203
+ ? (strategiesSource.aggressive ?? fallbackStrategy)
204
+ : (strategiesSource.balanced ?? fallbackStrategy);
205
+ break;
206
+ case "slow":
207
+ baseStrategy = strategiesSource.conservative ?? fallbackStrategy;
208
+ break;
209
+ case "unstable":
210
+ baseStrategy = strategiesSource.conservative ?? fallbackStrategy;
211
+ break;
212
+ default:
213
+ baseStrategy = strategiesSource.balanced ?? fallbackStrategy;
214
+ }
215
+ // Apply connection pooling optimizations
216
+ if (this.config.connectionPoolingAware && this.connectionMetrics) {
217
+ return this.optimizeStrategyForConnectionPooling(baseStrategy);
218
+ }
219
+ return baseStrategy;
220
+ }
221
+ /**
222
+ * Optimize chunking strategy based on connection pooling performance
223
+ */
224
+ optimizeStrategyForConnectionPooling(strategy) {
225
+ if (!this.connectionMetrics)
226
+ return strategy;
227
+ const insights = this.getConnectionPoolingInsights();
228
+ const reuseRate = insights.reuseRate;
229
+ // High connection reuse allows for more aggressive chunking
230
+ if (reuseRate > 0.8) {
231
+ return {
232
+ ...strategy,
233
+ name: `${strategy.name}-pooled-aggressive`,
234
+ minChunkSize: Math.max(strategy.minChunkSize * 0.5, 32 * 1024), // Smaller min chunks
235
+ adaptationRate: Math.min(strategy.adaptationRate * 1.3, 0.5), // Faster adaptation
236
+ };
237
+ }
238
+ // Good connection reuse allows moderate optimization
239
+ if (reuseRate > 0.5) {
240
+ return {
241
+ ...strategy,
242
+ name: `${strategy.name}-pooled-moderate`,
243
+ minChunkSize: Math.max(strategy.minChunkSize * 0.75, 64 * 1024),
244
+ adaptationRate: Math.min(strategy.adaptationRate * 1.1, 0.4),
245
+ };
246
+ }
247
+ // Poor connection reuse requires conservative approach
248
+ return {
249
+ ...strategy,
250
+ name: `${strategy.name}-pooled-conservative`,
251
+ minChunkSize: Math.max(strategy.minChunkSize * 1.5, insights.recommendedMinChunkSize),
252
+ adaptationRate: strategy.adaptationRate * 0.8,
253
+ };
254
+ }
255
+ calculateOptimalChunkSize(networkCondition, strategy) {
256
+ let targetSize = this.currentChunkSize;
257
+ // Base calculation on current throughput
258
+ const optimalThroughput = this.networkMonitor.getOptimalThroughput();
259
+ if (optimalThroughput > 0) {
260
+ // Calculate target chunk duration (aim for 2-5 seconds per chunk)
261
+ const targetDuration = this.getTargetChunkDuration(networkCondition);
262
+ const theoreticalSize = optimalThroughput * targetDuration * this.config.targetUtilization;
263
+ // Blend current size with theoretical optimal size
264
+ const blendFactor = strategy.adaptationRate;
265
+ targetSize =
266
+ this.currentChunkSize * (1 - blendFactor) +
267
+ theoreticalSize * blendFactor;
268
+ }
269
+ // Apply strategy constraints
270
+ targetSize = Math.max(strategy.minChunkSize, Math.min(strategy.maxChunkSize, targetSize));
271
+ // Apply failure-based adjustments
272
+ if (this.consecutiveFailures > 0) {
273
+ // Reduce size on failures
274
+ const reductionFactor = Math.min(0.5, this.consecutiveFailures * 0.2);
275
+ targetSize *= 1 - reductionFactor;
276
+ }
277
+ else if (this.consecutiveSuccesses > 2) {
278
+ // Gradually increase size on consistent success
279
+ const increaseFactor = Math.min(0.3, this.consecutiveSuccesses * 0.05);
280
+ targetSize *= 1 + increaseFactor;
281
+ }
282
+ return Math.round(targetSize);
283
+ }
284
+ getTargetChunkDuration(networkCondition) {
285
+ switch (networkCondition.type) {
286
+ case "fast":
287
+ return 3; // 3 seconds for fast connections
288
+ case "slow":
289
+ return 5; // 5 seconds for slow connections to reduce overhead
290
+ case "unstable":
291
+ return 2; // 2 seconds for unstable connections for quick recovery
292
+ default:
293
+ return 3; // Default to 3 seconds
294
+ }
295
+ }
296
+ adaptChunkSize(success, duration, size) {
297
+ if (!success) {
298
+ // On failure, be more conservative
299
+ this.currentChunkSize = Math.max(this.config.minChunkSize, this.currentChunkSize * 0.8);
300
+ return;
301
+ }
302
+ // On success, check if we should adjust based on performance
303
+ const throughput = size / (duration / 1000); // bytes per second
304
+ const metrics = this.networkMonitor.getCurrentMetrics();
305
+ if (metrics.averageSpeed > 0) {
306
+ const utilizationRatio = throughput / metrics.averageSpeed;
307
+ if (utilizationRatio < this.config.targetUtilization * 0.8) {
308
+ // We're not utilizing bandwidth well, try larger chunks
309
+ this.currentChunkSize = Math.min(this.config.maxChunkSize, this.currentChunkSize * 1.1);
310
+ }
311
+ else if (utilizationRatio > this.config.targetUtilization * 1.2) {
312
+ // We might be overloading, try smaller chunks
313
+ this.currentChunkSize = Math.max(this.config.minChunkSize, this.currentChunkSize * 0.95);
314
+ }
315
+ }
316
+ }
317
+ }
@@ -0,0 +1,148 @@
1
+ import type { IdGenerationService } from "../services/id-generation-service";
2
+ import type { StorageService } from "../services/storage-service";
3
+ import { type PreviousUpload } from "../types/previous-upload";
4
+ /**
5
+ * Client-side storage interface for managing upload resumption data.
6
+ *
7
+ * Provides methods to store, retrieve, and manage previous upload information,
8
+ * enabling the client to resume interrupted uploads from where they left off.
9
+ * This is essential for implementing reliable upload resumption across sessions.
10
+ *
11
+ * Storage keys are namespaced with "uploadista::" prefix and organized by
12
+ * file fingerprint to allow quick lookup of resumable uploads.
13
+ *
14
+ * @example Finding resumable uploads
15
+ * ```typescript
16
+ * const storage = createClientStorage(localStorage);
17
+ *
18
+ * // Find all previous uploads
19
+ * const allUploads = await storage.findAllUploads();
20
+ *
21
+ * // Find uploads for a specific file
22
+ * const fingerprint = await computeFingerprint(file);
23
+ * const matches = await storage.findUploadsByFingerprint(fingerprint);
24
+ *
25
+ * if (matches.length > 0) {
26
+ * // Resume from the most recent upload
27
+ * const uploadId = matches[0].uploadId;
28
+ * await resumeUpload(uploadId);
29
+ * }
30
+ * ```
31
+ */
32
+ export type ClientStorage = {
33
+ /**
34
+ * Retrieves all stored upload records from client storage.
35
+ *
36
+ * Useful for debugging or displaying a list of resumable uploads to the user.
37
+ *
38
+ * @returns Array of all previous upload records
39
+ */
40
+ findAllUploads: () => Promise<PreviousUpload[]>;
41
+ /**
42
+ * Finds previous upload records matching a specific file fingerprint.
43
+ *
44
+ * This is the primary method for discovering resumable uploads.
45
+ * Returns uploads sorted by most recent first.
46
+ *
47
+ * @param fingerprint - The file fingerprint to search for
48
+ * @returns Array of matching upload records, or empty array if none found
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const fingerprint = await computeFingerprint(file);
53
+ * const previous = await storage.findUploadsByFingerprint(fingerprint);
54
+ *
55
+ * if (previous.length > 0) {
56
+ * console.log(`Found ${previous.length} resumable uploads`);
57
+ * console.log(`Last upload was ${previous[0].offset} bytes`);
58
+ * }
59
+ * ```
60
+ */
61
+ findUploadsByFingerprint: (fingerprint: string) => Promise<PreviousUpload[]>;
62
+ /**
63
+ * Removes an upload record from client storage.
64
+ *
65
+ * Called after an upload completes successfully or is explicitly cancelled
66
+ * to clean up storage and prevent stale resumption attempts.
67
+ *
68
+ * @param clientStorageKey - The storage key returned by addUpload
69
+ *
70
+ * @example Cleanup after successful upload
71
+ * ```typescript
72
+ * await uploadFile(file);
73
+ * await storage.removeUpload(storageKey);
74
+ * ```
75
+ */
76
+ removeUpload: (clientStorageKey: string) => Promise<void>;
77
+ /**
78
+ * Stores an upload record in client storage for future resumption.
79
+ *
80
+ * Creates a namespaced storage key that includes the file fingerprint,
81
+ * making it easy to find resumable uploads later.
82
+ *
83
+ * @param fingerprint - File fingerprint for organizing uploads
84
+ * @param upload - Upload metadata to store (uploadId, offset, etc.)
85
+ * @param options - Options object containing ID generation service
86
+ * @returns The storage key that can be used to remove this upload later, or undefined if storage failed
87
+ *
88
+ * @example Storing upload progress
89
+ * ```typescript
90
+ * const fingerprint = await computeFingerprint(file);
91
+ * const key = await storage.addUpload(
92
+ * fingerprint,
93
+ * { uploadId: 'abc123', offset: 1024000 },
94
+ * { generateId: idService }
95
+ * );
96
+ *
97
+ * // Later, remove when complete
98
+ * if (key) await storage.removeUpload(key);
99
+ * ```
100
+ */
101
+ addUpload: (fingerprint: string, upload: PreviousUpload, { generateId }: {
102
+ generateId: IdGenerationService;
103
+ }) => Promise<string | undefined>;
104
+ };
105
+ /**
106
+ * Creates a ClientStorage instance using the provided storage service.
107
+ *
108
+ * This factory function wraps a platform-specific StorageService (e.g., localStorage,
109
+ * AsyncStorage) with the ClientStorage interface, providing a consistent API
110
+ * for upload resumption across different platforms.
111
+ *
112
+ * @param storageService - Platform-specific storage implementation
113
+ * @returns ClientStorage instance for managing upload records
114
+ *
115
+ * @example Browser with localStorage
116
+ * ```typescript
117
+ * const storage = createClientStorage({
118
+ * find: async (prefix) => {
119
+ * const items: Record<string, string> = {};
120
+ * for (let i = 0; i < localStorage.length; i++) {
121
+ * const key = localStorage.key(i);
122
+ * if (key?.startsWith(prefix)) {
123
+ * items[key] = localStorage.getItem(key) || '';
124
+ * }
125
+ * }
126
+ * return items;
127
+ * },
128
+ * setItem: async (key, value) => localStorage.setItem(key, value),
129
+ * removeItem: async (key) => localStorage.removeItem(key),
130
+ * });
131
+ * ```
132
+ *
133
+ * @example React Native with AsyncStorage
134
+ * ```typescript
135
+ * const storage = createClientStorage({
136
+ * find: async (prefix) => {
137
+ * const keys = await AsyncStorage.getAllKeys();
138
+ * const matching = keys.filter(k => k.startsWith(prefix));
139
+ * const pairs = await AsyncStorage.multiGet(matching);
140
+ * return Object.fromEntries(pairs);
141
+ * },
142
+ * setItem: async (key, value) => AsyncStorage.setItem(key, value),
143
+ * removeItem: async (key) => AsyncStorage.removeItem(key),
144
+ * });
145
+ * ```
146
+ */
147
+ export declare function createClientStorage(storageService: StorageService): ClientStorage;
148
+ //# sourceMappingURL=client-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-storage.d.ts","sourceRoot":"","sources":["../../src/storage/client-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,KAAK,cAAc,EAEpB,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAEhD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,wBAAwB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAE7E;;;;;;;;;;;;;OAaG;IACH,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,SAAS,EAAE,CACT,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,EAAE,mBAAmB,CAAA;KAAE,KAChD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,cAAc,GAC7B,aAAa,CA2Bf"}
@@ -0,0 +1,62 @@
1
+ import { previousUploadSchema, } from "../types/previous-upload";
2
+ /**
3
+ * Creates a ClientStorage instance using the provided storage service.
4
+ *
5
+ * This factory function wraps a platform-specific StorageService (e.g., localStorage,
6
+ * AsyncStorage) with the ClientStorage interface, providing a consistent API
7
+ * for upload resumption across different platforms.
8
+ *
9
+ * @param storageService - Platform-specific storage implementation
10
+ * @returns ClientStorage instance for managing upload records
11
+ *
12
+ * @example Browser with localStorage
13
+ * ```typescript
14
+ * const storage = createClientStorage({
15
+ * find: async (prefix) => {
16
+ * const items: Record<string, string> = {};
17
+ * for (let i = 0; i < localStorage.length; i++) {
18
+ * const key = localStorage.key(i);
19
+ * if (key?.startsWith(prefix)) {
20
+ * items[key] = localStorage.getItem(key) || '';
21
+ * }
22
+ * }
23
+ * return items;
24
+ * },
25
+ * setItem: async (key, value) => localStorage.setItem(key, value),
26
+ * removeItem: async (key) => localStorage.removeItem(key),
27
+ * });
28
+ * ```
29
+ *
30
+ * @example React Native with AsyncStorage
31
+ * ```typescript
32
+ * const storage = createClientStorage({
33
+ * find: async (prefix) => {
34
+ * const keys = await AsyncStorage.getAllKeys();
35
+ * const matching = keys.filter(k => k.startsWith(prefix));
36
+ * const pairs = await AsyncStorage.multiGet(matching);
37
+ * return Object.fromEntries(pairs);
38
+ * },
39
+ * setItem: async (key, value) => AsyncStorage.setItem(key, value),
40
+ * removeItem: async (key) => AsyncStorage.removeItem(key),
41
+ * });
42
+ * ```
43
+ */
44
+ export function createClientStorage(storageService) {
45
+ return {
46
+ findAllUploads: async () => {
47
+ const items = await storageService.find("uploadista::");
48
+ return Object.values(items).map((item) => previousUploadSchema.parse(JSON.parse(item)));
49
+ },
50
+ findUploadsByFingerprint: async (fingerprint) => {
51
+ const items = await storageService.find(`uploadista::${fingerprint}`);
52
+ return Object.values(items).map((item) => previousUploadSchema.parse(JSON.parse(item)));
53
+ },
54
+ removeUpload: (clientStorageKey) => storageService.removeItem(clientStorageKey),
55
+ addUpload: async (fingerprint, upload, { generateId }) => {
56
+ const key = generateId.generate();
57
+ const clientStorageKey = `uploadista::${fingerprint}::${key}`;
58
+ await storageService.setItem(clientStorageKey, JSON.stringify(upload));
59
+ return clientStorageKey;
60
+ },
61
+ };
62
+ }
@@ -0,0 +1,7 @@
1
+ import type { StorageService } from "../services/storage-service";
2
+ /**
3
+ * In-memory fallback storage service for Expo
4
+ * Used when AsyncStorage is not available or for testing
5
+ */
6
+ export declare function createInMemoryStorageService(): StorageService;
7
+ //# sourceMappingURL=in-memory-storage-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-storage-service.d.ts","sourceRoot":"","sources":["../../src/storage/in-memory-storage-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,cAAc,CA0B7D"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * In-memory fallback storage service for Expo
3
+ * Used when AsyncStorage is not available or for testing
4
+ */
5
+ export function createInMemoryStorageService() {
6
+ const storage = new Map();
7
+ return {
8
+ async getItem(key) {
9
+ return storage.get(key) ?? null;
10
+ },
11
+ async setItem(key, value) {
12
+ storage.set(key, value);
13
+ },
14
+ async removeItem(key) {
15
+ storage.delete(key);
16
+ },
17
+ async findAll() {
18
+ return Object.fromEntries(storage.entries());
19
+ },
20
+ async find(prefix) {
21
+ return Object.fromEntries(Array.from(storage.entries()).filter(([key]) => key.startsWith(prefix)));
22
+ },
23
+ };
24
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./client-storage";
2
+ export * from "./in-memory-storage-service";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./client-storage";
2
+ export * from "./in-memory-storage-service";
@@ -0,0 +1,6 @@
1
+ export interface BufferedChunk {
2
+ data: Uint8Array;
3
+ size: number;
4
+ timestamp: number;
5
+ }
6
+ //# sourceMappingURL=buffered-chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffered-chunk.d.ts","sourceRoot":"","sources":["../../src/types/buffered-chunk.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ export interface ChunkMetrics {
2
+ chunkIndex: number;
3
+ size: number;
4
+ duration: number;
5
+ speed: number;
6
+ success: boolean;
7
+ retryCount: number;
8
+ timestamp: number;
9
+ networkCondition?: string;
10
+ chunkingStrategy?: string;
11
+ }
12
+ //# sourceMappingURL=chunk-metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-metrics.d.ts","sourceRoot":"","sources":["../../src/types/chunk-metrics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { UploadFile } from "@uploadista/core/types";
2
+ export type FlowResult<TOutput = UploadFile> = {
3
+ type: "success";
4
+ value: TOutput;
5
+ } | {
6
+ type: "error";
7
+ error: Error;
8
+ } | {
9
+ type: "cancelled";
10
+ };
11
+ //# sourceMappingURL=flow-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-result.d.ts","sourceRoot":"","sources":["../../src/types/flow-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,MAAM,UAAU,CAAC,OAAO,GAAG,UAAU,IACvC;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;CACd,GACD;IACE,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};