@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.
- package/.turbo/turbo-build.log +5 -0
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/auth/auth-http-client.d.ts +50 -0
- package/dist/auth/auth-http-client.d.ts.map +1 -0
- package/dist/auth/auth-http-client.js +110 -0
- package/dist/auth/direct-auth.d.ts +38 -0
- package/dist/auth/direct-auth.d.ts.map +1 -0
- package/dist/auth/direct-auth.js +95 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/no-auth.d.ts +26 -0
- package/dist/auth/no-auth.d.ts.map +1 -0
- package/dist/auth/no-auth.js +33 -0
- package/dist/auth/saas-auth.d.ts +80 -0
- package/dist/auth/saas-auth.d.ts.map +1 -0
- package/dist/auth/saas-auth.js +167 -0
- package/dist/auth/types.d.ts +101 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +8 -0
- package/dist/chunk-buffer.d.ts +209 -0
- package/dist/chunk-buffer.d.ts.map +1 -0
- package/dist/chunk-buffer.js +236 -0
- package/dist/client/create-uploadista-client.d.ts +369 -0
- package/dist/client/create-uploadista-client.d.ts.map +1 -0
- package/dist/client/create-uploadista-client.js +518 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/uploadista-api.d.ts +284 -0
- package/dist/client/uploadista-api.d.ts.map +1 -0
- package/dist/client/uploadista-api.js +444 -0
- package/dist/client/uploadista-websocket-manager.d.ts +110 -0
- package/dist/client/uploadista-websocket-manager.d.ts.map +1 -0
- package/dist/client/uploadista-websocket-manager.js +207 -0
- package/dist/error.d.ts +106 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +69 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/logger.d.ts +70 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +59 -0
- package/dist/mock-data-store.d.ts +30 -0
- package/dist/mock-data-store.d.ts.map +1 -0
- package/dist/mock-data-store.js +88 -0
- package/dist/network-monitor.d.ts +262 -0
- package/dist/network-monitor.d.ts.map +1 -0
- package/dist/network-monitor.js +291 -0
- package/dist/services/abort-controller-service.d.ts +19 -0
- package/dist/services/abort-controller-service.d.ts.map +1 -0
- package/dist/services/abort-controller-service.js +4 -0
- package/dist/services/checksum-service.d.ts +4 -0
- package/dist/services/checksum-service.d.ts.map +1 -0
- package/dist/services/checksum-service.js +1 -0
- package/dist/services/file-reader-service.d.ts +38 -0
- package/dist/services/file-reader-service.d.ts.map +1 -0
- package/dist/services/file-reader-service.js +4 -0
- package/dist/services/fingerprint-service.d.ts +4 -0
- package/dist/services/fingerprint-service.d.ts.map +1 -0
- package/dist/services/fingerprint-service.js +1 -0
- package/dist/services/http-client.d.ts +182 -0
- package/dist/services/http-client.d.ts.map +1 -0
- package/dist/services/http-client.js +1 -0
- package/dist/services/id-generation-service.d.ts +10 -0
- package/dist/services/id-generation-service.d.ts.map +1 -0
- package/dist/services/id-generation-service.js +1 -0
- package/dist/services/index.d.ts +11 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +10 -0
- package/dist/services/platform-service.d.ts +48 -0
- package/dist/services/platform-service.d.ts.map +1 -0
- package/dist/services/platform-service.js +10 -0
- package/dist/services/service-container.d.ts +25 -0
- package/dist/services/service-container.d.ts.map +1 -0
- package/dist/services/service-container.js +1 -0
- package/dist/services/storage-service.d.ts +26 -0
- package/dist/services/storage-service.d.ts.map +1 -0
- package/dist/services/storage-service.js +1 -0
- package/dist/services/websocket-service.d.ts +36 -0
- package/dist/services/websocket-service.d.ts.map +1 -0
- package/dist/services/websocket-service.js +4 -0
- package/dist/smart-chunker.d.ts +72 -0
- package/dist/smart-chunker.d.ts.map +1 -0
- package/dist/smart-chunker.js +317 -0
- package/dist/storage/client-storage.d.ts +148 -0
- package/dist/storage/client-storage.d.ts.map +1 -0
- package/dist/storage/client-storage.js +62 -0
- package/dist/storage/in-memory-storage-service.d.ts +7 -0
- package/dist/storage/in-memory-storage-service.d.ts.map +1 -0
- package/dist/storage/in-memory-storage-service.js +24 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/types/buffered-chunk.d.ts +6 -0
- package/dist/types/buffered-chunk.d.ts.map +1 -0
- package/dist/types/buffered-chunk.js +1 -0
- package/dist/types/chunk-metrics.d.ts +12 -0
- package/dist/types/chunk-metrics.d.ts.map +1 -0
- package/dist/types/chunk-metrics.js +1 -0
- package/dist/types/flow-result.d.ts +11 -0
- package/dist/types/flow-result.d.ts.map +1 -0
- package/dist/types/flow-result.js +1 -0
- package/dist/types/flow-upload-config.d.ts +54 -0
- package/dist/types/flow-upload-config.d.ts.map +1 -0
- package/dist/types/flow-upload-config.js +1 -0
- package/dist/types/flow-upload-item.d.ts +16 -0
- package/dist/types/flow-upload-item.d.ts.map +1 -0
- package/dist/types/flow-upload-item.js +1 -0
- package/dist/types/flow-upload-options.d.ts +41 -0
- package/dist/types/flow-upload-options.d.ts.map +1 -0
- package/dist/types/flow-upload-options.js +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/multi-flow-upload-options.d.ts +33 -0
- package/dist/types/multi-flow-upload-options.d.ts.map +1 -0
- package/dist/types/multi-flow-upload-options.js +1 -0
- package/dist/types/multi-flow-upload-state.d.ts +9 -0
- package/dist/types/multi-flow-upload-state.d.ts.map +1 -0
- package/dist/types/multi-flow-upload-state.js +1 -0
- package/dist/types/performance-insights.d.ts +11 -0
- package/dist/types/performance-insights.d.ts.map +1 -0
- package/dist/types/performance-insights.js +1 -0
- package/dist/types/previous-upload.d.ts +20 -0
- package/dist/types/previous-upload.d.ts.map +1 -0
- package/dist/types/previous-upload.js +9 -0
- package/dist/types/upload-options.d.ts +40 -0
- package/dist/types/upload-options.d.ts.map +1 -0
- package/dist/types/upload-options.js +1 -0
- package/dist/types/upload-response.d.ts +6 -0
- package/dist/types/upload-response.d.ts.map +1 -0
- package/dist/types/upload-response.js +1 -0
- package/dist/types/upload-result.d.ts +57 -0
- package/dist/types/upload-result.d.ts.map +1 -0
- package/dist/types/upload-result.js +1 -0
- package/dist/types/upload-session-metrics.d.ts +16 -0
- package/dist/types/upload-session-metrics.d.ts.map +1 -0
- package/dist/types/upload-session-metrics.js +1 -0
- package/dist/upload/chunk-upload.d.ts +40 -0
- package/dist/upload/chunk-upload.d.ts.map +1 -0
- package/dist/upload/chunk-upload.js +82 -0
- package/dist/upload/flow-upload.d.ts +48 -0
- package/dist/upload/flow-upload.d.ts.map +1 -0
- package/dist/upload/flow-upload.js +240 -0
- package/dist/upload/index.d.ts +3 -0
- package/dist/upload/index.d.ts.map +1 -0
- package/dist/upload/index.js +2 -0
- package/dist/upload/parallel-upload.d.ts +65 -0
- package/dist/upload/parallel-upload.d.ts.map +1 -0
- package/dist/upload/parallel-upload.js +231 -0
- package/dist/upload/single-upload.d.ts +118 -0
- package/dist/upload/single-upload.d.ts.map +1 -0
- package/dist/upload/single-upload.js +332 -0
- package/dist/upload/upload-manager.d.ts +30 -0
- package/dist/upload/upload-manager.d.ts.map +1 -0
- package/dist/upload/upload-manager.js +57 -0
- package/dist/upload/upload-metrics.d.ts +37 -0
- package/dist/upload/upload-metrics.d.ts.map +1 -0
- package/dist/upload/upload-metrics.js +236 -0
- package/dist/upload/upload-storage.d.ts +32 -0
- package/dist/upload/upload-storage.d.ts.map +1 -0
- package/dist/upload/upload-storage.js +46 -0
- package/dist/upload/upload-strategy.d.ts +66 -0
- package/dist/upload/upload-strategy.d.ts.map +1 -0
- package/dist/upload/upload-strategy.js +171 -0
- package/dist/upload/upload-utils.d.ts +26 -0
- package/dist/upload/upload-utils.d.ts.map +1 -0
- package/dist/upload/upload-utils.js +80 -0
- package/package.json +29 -0
- package/src/__tests__/smart-chunking.test.ts +399 -0
- package/src/auth/__tests__/auth-http-client.test.ts +327 -0
- package/src/auth/__tests__/direct-auth.test.ts +135 -0
- package/src/auth/__tests__/no-auth.test.ts +40 -0
- package/src/auth/__tests__/saas-auth.test.ts +337 -0
- package/src/auth/auth-http-client.ts +150 -0
- package/src/auth/direct-auth.ts +121 -0
- package/src/auth/index.ts +5 -0
- package/src/auth/no-auth.ts +39 -0
- package/src/auth/saas-auth.ts +218 -0
- package/src/auth/types.ts +105 -0
- package/src/chunk-buffer.ts +287 -0
- package/src/client/create-uploadista-client.ts +901 -0
- package/src/client/index.ts +3 -0
- package/src/client/uploadista-api.ts +857 -0
- package/src/client/uploadista-websocket-manager.ts +275 -0
- package/src/error.ts +149 -0
- package/src/index.ts +13 -0
- package/src/logger.ts +104 -0
- package/src/mock-data-store.ts +97 -0
- package/src/network-monitor.ts +445 -0
- package/src/services/abort-controller-service.ts +21 -0
- package/src/services/checksum-service.ts +3 -0
- package/src/services/file-reader-service.ts +44 -0
- package/src/services/fingerprint-service.ts +6 -0
- package/src/services/http-client.ts +229 -0
- package/src/services/id-generation-service.ts +9 -0
- package/src/services/index.ts +10 -0
- package/src/services/platform-service.ts +65 -0
- package/src/services/service-container.ts +24 -0
- package/src/services/storage-service.ts +29 -0
- package/src/services/websocket-service.ts +33 -0
- package/src/smart-chunker.ts +451 -0
- package/src/storage/client-storage.ts +186 -0
- package/src/storage/in-memory-storage-service.ts +33 -0
- package/src/storage/index.ts +2 -0
- package/src/types/buffered-chunk.ts +5 -0
- package/src/types/chunk-metrics.ts +11 -0
- package/src/types/flow-result.ts +14 -0
- package/src/types/flow-upload-config.ts +56 -0
- package/src/types/flow-upload-item.ts +16 -0
- package/src/types/flow-upload-options.ts +56 -0
- package/src/types/index.ts +13 -0
- package/src/types/multi-flow-upload-options.ts +39 -0
- package/src/types/multi-flow-upload-state.ts +9 -0
- package/src/types/performance-insights.ts +7 -0
- package/src/types/previous-upload.ts +22 -0
- package/src/types/upload-options.ts +56 -0
- package/src/types/upload-response.ts +6 -0
- package/src/types/upload-result.ts +60 -0
- package/src/types/upload-session-metrics.ts +15 -0
- package/src/upload/chunk-upload.ts +151 -0
- package/src/upload/flow-upload.ts +367 -0
- package/src/upload/index.ts +2 -0
- package/src/upload/parallel-upload.ts +387 -0
- package/src/upload/single-upload.ts +554 -0
- package/src/upload/upload-manager.ts +106 -0
- package/src/upload/upload-metrics.ts +340 -0
- package/src/upload/upload-storage.ts +87 -0
- package/src/upload/upload-strategy.ts +296 -0
- package/src/upload/upload-utils.ts +114 -0
- package/tsconfig.json +23 -0
- 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,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
|
+
}
|