@uploadista/client-browser 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 (83) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-check.log +130 -0
  3. package/AUTO_CAPABILITIES.md +98 -0
  4. package/FRAMEWORK_INTEGRATION.md +407 -0
  5. package/LICENSE +21 -0
  6. package/README.md +795 -0
  7. package/SMART_CHUNKING.md +140 -0
  8. package/dist/client/create-uploadista-client.d.ts +182 -0
  9. package/dist/client/create-uploadista-client.d.ts.map +1 -0
  10. package/dist/client/create-uploadista-client.js +76 -0
  11. package/dist/client/index.d.ts +2 -0
  12. package/dist/client/index.d.ts.map +1 -0
  13. package/dist/client/index.js +1 -0
  14. package/dist/framework-utils.d.ts +201 -0
  15. package/dist/framework-utils.d.ts.map +1 -0
  16. package/dist/framework-utils.js +282 -0
  17. package/dist/http-client.d.ts +44 -0
  18. package/dist/http-client.d.ts.map +1 -0
  19. package/dist/http-client.js +489 -0
  20. package/dist/index.d.ts +8 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +7 -0
  23. package/dist/services/abort-controller-factory.d.ts +30 -0
  24. package/dist/services/abort-controller-factory.d.ts.map +1 -0
  25. package/dist/services/abort-controller-factory.js +98 -0
  26. package/dist/services/checksum-service.d.ts +30 -0
  27. package/dist/services/checksum-service.d.ts.map +1 -0
  28. package/dist/services/checksum-service.js +44 -0
  29. package/dist/services/create-browser-services.d.ts +36 -0
  30. package/dist/services/create-browser-services.d.ts.map +1 -0
  31. package/dist/services/create-browser-services.js +56 -0
  32. package/dist/services/file-reader.d.ts +91 -0
  33. package/dist/services/file-reader.d.ts.map +1 -0
  34. package/dist/services/file-reader.js +251 -0
  35. package/dist/services/fingerprint-service.d.ts +41 -0
  36. package/dist/services/fingerprint-service.d.ts.map +1 -0
  37. package/dist/services/fingerprint-service.js +64 -0
  38. package/dist/services/id-generation/id-generation.d.ts +40 -0
  39. package/dist/services/id-generation/id-generation.d.ts.map +1 -0
  40. package/dist/services/id-generation/id-generation.js +58 -0
  41. package/dist/services/platform-service.d.ts +38 -0
  42. package/dist/services/platform-service.d.ts.map +1 -0
  43. package/dist/services/platform-service.js +221 -0
  44. package/dist/services/storage/local-storage-service.d.ts +55 -0
  45. package/dist/services/storage/local-storage-service.d.ts.map +1 -0
  46. package/dist/services/storage/local-storage-service.js +178 -0
  47. package/dist/services/storage/session-storage-service.d.ts +55 -0
  48. package/dist/services/storage/session-storage-service.d.ts.map +1 -0
  49. package/dist/services/storage/session-storage-service.js +179 -0
  50. package/dist/services/websocket-factory.d.ts +46 -0
  51. package/dist/services/websocket-factory.d.ts.map +1 -0
  52. package/dist/services/websocket-factory.js +196 -0
  53. package/dist/types/index.d.ts +2 -0
  54. package/dist/types/index.d.ts.map +1 -0
  55. package/dist/types/index.js +1 -0
  56. package/dist/types/upload-input.d.ts +26 -0
  57. package/dist/types/upload-input.d.ts.map +1 -0
  58. package/dist/types/upload-input.js +1 -0
  59. package/dist/utils/hash-util.d.ts +60 -0
  60. package/dist/utils/hash-util.d.ts.map +1 -0
  61. package/dist/utils/hash-util.js +75 -0
  62. package/package.json +32 -0
  63. package/src/client/create-uploadista-client.ts +150 -0
  64. package/src/client/index.ts +1 -0
  65. package/src/framework-utils.ts +446 -0
  66. package/src/http-client.ts +546 -0
  67. package/src/index.ts +8 -0
  68. package/src/services/abort-controller-factory.ts +108 -0
  69. package/src/services/checksum-service.ts +46 -0
  70. package/src/services/create-browser-services.ts +81 -0
  71. package/src/services/file-reader.ts +344 -0
  72. package/src/services/fingerprint-service.ts +67 -0
  73. package/src/services/id-generation/id-generation.ts +60 -0
  74. package/src/services/platform-service.ts +231 -0
  75. package/src/services/storage/local-storage-service.ts +187 -0
  76. package/src/services/storage/session-storage-service.ts +188 -0
  77. package/src/services/websocket-factory.ts +212 -0
  78. package/src/types/index.ts +1 -0
  79. package/src/types/upload-input.ts +25 -0
  80. package/src/utils/hash-util.ts +79 -0
  81. package/tsconfig.json +22 -0
  82. package/tsconfig.tsbuildinfo +1 -0
  83. package/vitest.config.ts +15 -0
package/README.md ADDED
@@ -0,0 +1,795 @@
1
+ # @uploadista/client-browser
2
+
3
+ Browser-optimized upload client for Uploadista with native Web APIs.
4
+
5
+ ## Overview
6
+
7
+ `@uploadista/client-browser` is the browser-specific implementation of the Uploadista upload client. It provides a complete file upload solution optimized for modern web browsers, leveraging native browser APIs for optimal performance and compatibility.
8
+
9
+ This package extends `@uploadista/client-core` with browser-specific implementations:
10
+ - **Fetch API** for HTTP requests with connection pooling
11
+ - **File API** for reading File and Blob objects
12
+ - **Web Crypto API** for checksums and fingerprints
13
+ - **WebSocket API** for real-time progress updates
14
+ - **LocalStorage API** for upload state persistence
15
+
16
+ The client supports resumable uploads, parallel chunk uploads, progress tracking, and automatic retry with exponential backoff. It's designed to handle files of any size by reading and uploading them in configurable chunks, keeping memory usage low even for multi-gigabyte files.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @uploadista/client-browser
22
+ # or
23
+ pnpm add @uploadista/client-browser
24
+ # or
25
+ yarn add @uploadista/client-browser
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```typescript
31
+ import { createUploadistaClient } from '@uploadista/client-browser';
32
+
33
+ // Create the client
34
+ const client = createUploadistaClient({
35
+ endpoint: 'https://api.uploadista.com/upload'
36
+ });
37
+
38
+ // Get file from input
39
+ const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');
40
+ const file = fileInput.files[0];
41
+
42
+ // Upload with progress tracking
43
+ const upload = await client.upload(file, {
44
+ onProgress: (event) => {
45
+ console.log(`Progress: ${event.progress}%`);
46
+ console.log(`Speed: ${event.bytesPerSecond / 1024} KB/s`);
47
+ }
48
+ });
49
+
50
+ console.log('Upload complete:', upload.id);
51
+ console.log('File URL:', upload.url);
52
+ ```
53
+
54
+ ## Features
55
+
56
+ - **Browser-Native APIs** - Uses Fetch, File API, WebSocket, and Web Crypto for optimal performance
57
+ - **Resumable Uploads** - Automatically resume interrupted uploads using fingerprinting
58
+ - **Chunked Uploads** - Upload files in configurable chunks to handle large files efficiently
59
+ - **Connection Pooling** - Optimized HTTP/2 connection reuse with keep-alive
60
+ - **Progress Tracking** - Real-time progress updates with upload speed and ETA
61
+ - **WebSocket Support** - Real-time events for upload and flow processing updates
62
+ - **Automatic Retry** - Configurable retry logic with exponential backoff
63
+ - **LocalStorage Persistence** - Save upload state for resumption across page reloads
64
+ - **TypeScript Support** - Full type safety with TypeScript definitions
65
+ - **Framework Utilities** - Helper types and utilities for React, Vue, and other frameworks
66
+
67
+ ## API Reference
68
+
69
+ ### createUploadistaClient()
70
+
71
+ Creates a browser-optimized Uploadista client with automatic service configuration.
72
+
73
+ ```typescript
74
+ function createUploadistaClient(
75
+ options: UploadistaClientOptions
76
+ ): UploadistaClient<File | Blob>
77
+ ```
78
+
79
+ **Options:**
80
+
81
+ - `endpoint` (string, required) - Upload endpoint URL
82
+ - `chunkSize` (number) - Chunk size in bytes (default: 5MB)
83
+ - `retryDelays` (number[]) - Retry delays in milliseconds (default: [0, 1000, 3000, 5000])
84
+ - `connectionPooling` (ConnectionPoolConfig) - HTTP connection pooling configuration
85
+ - `storeFingerprintForResuming` (boolean) - Enable resumable uploads (default: true)
86
+ - `allowedMetaFields` (string[]) - Allowed metadata field names
87
+
88
+ **Returns:** UploadistaClient configured for browser use
89
+
90
+ **Example:**
91
+
92
+ ```typescript
93
+ const client = createUploadistaClient({
94
+ endpoint: 'https://api.uploadista.com/upload',
95
+ chunkSize: 10 * 1024 * 1024, // 10MB chunks
96
+ retryDelays: [1000, 3000, 5000, 10000],
97
+ connectionPooling: {
98
+ maxConnectionsPerHost: 6,
99
+ enableHttp2: true,
100
+ keepAliveTimeout: 60000
101
+ },
102
+ storeFingerprintForResuming: true,
103
+ allowedMetaFields: ['userId', 'projectId', 'tags']
104
+ });
105
+ ```
106
+
107
+ ### createHttpClient()
108
+
109
+ Creates a Fetch-based HTTP client with connection pooling and metrics tracking.
110
+
111
+ ```typescript
112
+ function createHttpClient(
113
+ config?: ConnectionPoolConfig
114
+ ): HttpClient
115
+ ```
116
+
117
+ **Config Options:**
118
+
119
+ - `maxConnectionsPerHost` (number) - Maximum concurrent connections per host (default: 6)
120
+ - `connectionTimeout` (number) - Connection timeout in milliseconds (default: 30000)
121
+ - `keepAliveTimeout` (number) - Keep-alive timeout in milliseconds (default: 60000)
122
+ - `enableHttp2` (boolean) - Enable HTTP/2 multiplexing (default: true)
123
+ - `retryOnConnectionError` (boolean) - Retry on connection errors (default: true)
124
+
125
+ **Returns:** HttpClient with connection pooling and health monitoring
126
+
127
+ **Example:**
128
+
129
+ ```typescript
130
+ import { createHttpClient } from '@uploadista/client-browser';
131
+
132
+ const httpClient = createHttpClient({
133
+ maxConnectionsPerHost: 10,
134
+ connectionTimeout: 60000,
135
+ keepAliveTimeout: 120000,
136
+ enableHttp2: true
137
+ });
138
+
139
+ // Make requests
140
+ const response = await httpClient.request('https://api.example.com/data', {
141
+ method: 'POST',
142
+ headers: { 'Content-Type': 'application/json' },
143
+ body: JSON.stringify({ key: 'value' })
144
+ });
145
+
146
+ // Check connection health
147
+ const metrics = httpClient.getDetailedMetrics();
148
+ console.log('Connection health:', metrics.health.status);
149
+ console.log('Reuse rate:', Math.round(metrics.reuseRate * 100) + '%');
150
+ ```
151
+
152
+ ### createBrowserFileReaderService()
153
+
154
+ Creates a file reader service for opening and reading File/Blob objects in chunks.
155
+
156
+ ```typescript
157
+ function createBrowserFileReaderService(): FileReaderService<BrowserUploadInput>
158
+ ```
159
+
160
+ **Returns:** FileReaderService configured for browser File/Blob objects
161
+
162
+ **Example:**
163
+
164
+ ```typescript
165
+ import { createBrowserFileReaderService } from '@uploadista/client-browser';
166
+
167
+ const fileReader = createBrowserFileReaderService();
168
+
169
+ // Open a file from input
170
+ const input = document.querySelector<HTMLInputElement>('input[type="file"]');
171
+ const file = input.files[0];
172
+ const source = await fileReader.openFile(file, 5 * 1024 * 1024); // 5MB chunks
173
+
174
+ console.log('File name:', source.name);
175
+ console.log('File size:', source.size);
176
+ console.log('File type:', source.type);
177
+
178
+ // Read first chunk
179
+ const chunk = await source.slice(0, 5 * 1024 * 1024);
180
+ console.log('Read', chunk.size, 'bytes');
181
+
182
+ // Close when done
183
+ source.close();
184
+ ```
185
+
186
+ ### BrowserUploadInput
187
+
188
+ Type representing browser file inputs that can be uploaded.
189
+
190
+ ```typescript
191
+ type BrowserUploadInput = File | Blob
192
+ ```
193
+
194
+ **File** - From file input elements, drag-and-drop, or File constructor
195
+ **Blob** - From programmatic creation or API responses
196
+
197
+ **Example:**
198
+
199
+ ```typescript
200
+ // From file input
201
+ const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');
202
+ const file: BrowserUploadInput = fileInput.files[0];
203
+
204
+ // From drag and drop
205
+ element.addEventListener('drop', (e) => {
206
+ e.preventDefault();
207
+ const file: BrowserUploadInput = e.dataTransfer.files[0];
208
+ client.upload(file);
209
+ });
210
+
211
+ // From Blob
212
+ const blob: BrowserUploadInput = new Blob(
213
+ ['Hello, world!'],
214
+ { type: 'text/plain' }
215
+ );
216
+ client.upload(blob);
217
+
218
+ // From canvas
219
+ const canvas = document.querySelector('canvas');
220
+ canvas.toBlob((blob) => {
221
+ if (blob) {
222
+ client.upload(blob);
223
+ }
224
+ });
225
+ ```
226
+
227
+ ## Configuration
228
+
229
+ ### Connection Pooling
230
+
231
+ Optimize HTTP connection reuse for better upload performance:
232
+
233
+ ```typescript
234
+ const client = createUploadistaClient({
235
+ endpoint: 'https://api.uploadista.com/upload',
236
+ connectionPooling: {
237
+ maxConnectionsPerHost: 6, // Browser default for HTTP/1.1
238
+ connectionTimeout: 30000, // 30 seconds
239
+ keepAliveTimeout: 60000, // 1 minute
240
+ enableHttp2: true, // Enable HTTP/2 multiplexing
241
+ retryOnConnectionError: true // Retry on connection failures
242
+ }
243
+ });
244
+ ```
245
+
246
+ ### Chunk Size
247
+
248
+ Balance memory usage and upload efficiency:
249
+
250
+ ```typescript
251
+ const client = createUploadistaClient({
252
+ endpoint: 'https://api.uploadista.com/upload',
253
+ chunkSize: 5 * 1024 * 1024 // 5MB chunks (default)
254
+
255
+ // For slow connections
256
+ // chunkSize: 1 * 1024 * 1024 // 1MB chunks
257
+
258
+ // For fast connections
259
+ // chunkSize: 10 * 1024 * 1024 // 10MB chunks
260
+ });
261
+ ```
262
+
263
+ ### Resumable Uploads
264
+
265
+ Enable automatic upload resumption after interruptions:
266
+
267
+ ```typescript
268
+ const client = createUploadistaClient({
269
+ endpoint: 'https://api.uploadista.com/upload',
270
+ storeFingerprintForResuming: true, // Enable resumable uploads
271
+
272
+ // Upload will be fingerprinted and stored in localStorage
273
+ // If interrupted, it will automatically resume from the last chunk
274
+ });
275
+ ```
276
+
277
+ ### Retry Configuration
278
+
279
+ Configure automatic retry with exponential backoff:
280
+
281
+ ```typescript
282
+ const client = createUploadistaClient({
283
+ endpoint: 'https://api.uploadista.com/upload',
284
+ retryDelays: [0, 1000, 3000, 5000], // Retry after 0s, 1s, 3s, 5s
285
+
286
+ // First attempt: immediate
287
+ // Second attempt: 1 second delay
288
+ // Third attempt: 3 second delay
289
+ // Fourth attempt: 5 second delay
290
+ // After 4 retries, upload fails
291
+ });
292
+ ```
293
+
294
+ ## Examples
295
+
296
+ ### Example 1: Basic File Upload
297
+
298
+ Simple file upload from a file input element:
299
+
300
+ ```typescript
301
+ import { createUploadistaClient } from '@uploadista/client-browser';
302
+
303
+ const client = createUploadistaClient({
304
+ endpoint: 'https://api.uploadista.com/upload'
305
+ });
306
+
307
+ const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');
308
+ fileInput.addEventListener('change', async (e) => {
309
+ const file = e.target.files?.[0];
310
+ if (!file) return;
311
+
312
+ try {
313
+ const upload = await client.upload(file);
314
+ console.log('Upload successful!');
315
+ console.log('File ID:', upload.id);
316
+ console.log('File URL:', upload.url);
317
+ } catch (error) {
318
+ console.error('Upload failed:', error);
319
+ }
320
+ });
321
+ ```
322
+
323
+ ### Example 2: Upload with Progress Tracking
324
+
325
+ Track upload progress with real-time updates:
326
+
327
+ ```typescript
328
+ import { createUploadistaClient } from '@uploadista/client-browser';
329
+
330
+ const client = createUploadistaClient({
331
+ endpoint: 'https://api.uploadista.com/upload'
332
+ });
333
+
334
+ const progressBar = document.querySelector<HTMLProgressElement>('.progress-bar');
335
+ const speedDisplay = document.querySelector<HTMLSpanElement>('.speed');
336
+ const etaDisplay = document.querySelector<HTMLSpanElement>('.eta');
337
+
338
+ const upload = await client.upload(file, {
339
+ onProgress: (event) => {
340
+ // Update progress bar
341
+ progressBar.value = event.progress;
342
+
343
+ // Display upload speed
344
+ const speedMBps = (event.bytesPerSecond / 1024 / 1024).toFixed(2);
345
+ speedDisplay.textContent = `${speedMBps} MB/s`;
346
+
347
+ // Calculate and display ETA
348
+ const remainingBytes = event.totalBytes - event.bytesUploaded;
349
+ const etaSeconds = Math.round(remainingBytes / event.bytesPerSecond);
350
+ etaDisplay.textContent = `${etaSeconds}s remaining`;
351
+ }
352
+ });
353
+ ```
354
+
355
+ ### Example 3: Upload with WebSocket for Real-Time Updates
356
+
357
+ Use WebSocket for real-time upload events and flow processing updates:
358
+
359
+ ```typescript
360
+ import { createUploadistaClient } from '@uploadista/client-browser';
361
+
362
+ const client = createUploadistaClient({
363
+ endpoint: 'https://api.uploadista.com/upload'
364
+ });
365
+
366
+ // Upload file and get WebSocket connection
367
+ const upload = await client.upload(file);
368
+
369
+ // Connect to WebSocket for real-time events
370
+ const ws = new WebSocket(`wss://api.uploadista.com/ws/${upload.id}`);
371
+
372
+ ws.addEventListener('message', (event) => {
373
+ const message = JSON.parse(event.data);
374
+
375
+ switch (message.type) {
376
+ case 'upload_progress':
377
+ console.log('Progress:', message.payload.progress + '%');
378
+ break;
379
+
380
+ case 'upload_complete':
381
+ console.log('Upload complete:', message.payload);
382
+ break;
383
+
384
+ case 'flow_start':
385
+ console.log('Flow processing started');
386
+ break;
387
+
388
+ case 'flow_progress':
389
+ console.log('Flow progress:', message.payload.nodeId);
390
+ break;
391
+
392
+ case 'flow_complete':
393
+ console.log('Flow complete:', message.payload.result);
394
+ break;
395
+
396
+ case 'error':
397
+ console.error('Error:', message.message);
398
+ break;
399
+ }
400
+ });
401
+
402
+ ws.addEventListener('open', () => {
403
+ console.log('WebSocket connected');
404
+ });
405
+
406
+ ws.addEventListener('error', (error) => {
407
+ console.error('WebSocket error:', error);
408
+ });
409
+
410
+ ws.addEventListener('close', () => {
411
+ console.log('WebSocket disconnected');
412
+ });
413
+ ```
414
+
415
+ ### Example 4: Multi-File Upload
416
+
417
+ Upload multiple files with progress tracking for each file:
418
+
419
+ ```typescript
420
+ import { createUploadistaClient } from '@uploadista/client-browser';
421
+
422
+ const client = createUploadistaClient({
423
+ endpoint: 'https://api.uploadista.com/upload'
424
+ });
425
+
426
+ const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');
427
+ fileInput.multiple = true;
428
+
429
+ fileInput.addEventListener('change', async (e) => {
430
+ const files = Array.from(e.target.files || []);
431
+
432
+ const uploadPromises = files.map(file =>
433
+ client.upload(file, {
434
+ onProgress: (event) => {
435
+ console.log(`${file.name}: ${event.progress}%`);
436
+ }
437
+ })
438
+ );
439
+
440
+ try {
441
+ const results = await Promise.all(uploadPromises);
442
+ console.log('All uploads complete:', results);
443
+ } catch (error) {
444
+ console.error('One or more uploads failed:', error);
445
+ }
446
+ });
447
+ ```
448
+
449
+ ### Example 5: Drag and Drop Upload
450
+
451
+ Handle drag-and-drop file uploads:
452
+
453
+ ```typescript
454
+ import { createUploadistaClient } from '@uploadista/client-browser';
455
+
456
+ const client = createUploadistaClient({
457
+ endpoint: 'https://api.uploadista.com/upload'
458
+ });
459
+
460
+ const dropZone = document.querySelector<HTMLDivElement>('.drop-zone');
461
+
462
+ dropZone.addEventListener('dragover', (e) => {
463
+ e.preventDefault();
464
+ dropZone.classList.add('drag-over');
465
+ });
466
+
467
+ dropZone.addEventListener('dragleave', () => {
468
+ dropZone.classList.remove('drag-over');
469
+ });
470
+
471
+ dropZone.addEventListener('drop', async (e) => {
472
+ e.preventDefault();
473
+ dropZone.classList.remove('drag-over');
474
+
475
+ const files = Array.from(e.dataTransfer.files);
476
+
477
+ for (const file of files) {
478
+ try {
479
+ const upload = await client.upload(file, {
480
+ onProgress: (event) => {
481
+ console.log(`${file.name}: ${event.progress}%`);
482
+ }
483
+ });
484
+ console.log(`${file.name} uploaded:`, upload.id);
485
+ } catch (error) {
486
+ console.error(`${file.name} failed:`, error);
487
+ }
488
+ }
489
+ });
490
+ ```
491
+
492
+ ### Example 6: Upload with Metadata
493
+
494
+ Include custom metadata with your uploads:
495
+
496
+ ```typescript
497
+ import { createUploadistaClient } from '@uploadista/client-browser';
498
+
499
+ const client = createUploadistaClient({
500
+ endpoint: 'https://api.uploadista.com/upload',
501
+ allowedMetaFields: ['userId', 'projectId', 'tags', 'description']
502
+ });
503
+
504
+ const upload = await client.upload(file, {
505
+ metadata: {
506
+ userId: 'user-123',
507
+ projectId: 'project-456',
508
+ tags: 'profile-photo, avatar',
509
+ description: 'User profile photo'
510
+ }
511
+ });
512
+
513
+ console.log('Upload with metadata:', upload);
514
+ ```
515
+
516
+ ### Example 7: Resumable Upload with Fingerprinting
517
+
518
+ Automatically resume interrupted uploads:
519
+
520
+ ```typescript
521
+ import { createUploadistaClient } from '@uploadista/client-browser';
522
+
523
+ const client = createUploadistaClient({
524
+ endpoint: 'https://api.uploadista.com/upload',
525
+ storeFingerprintForResuming: true // Enable resumable uploads
526
+ });
527
+
528
+ // First upload attempt
529
+ const upload = await client.upload(file, {
530
+ onProgress: (event) => {
531
+ console.log('Progress:', event.progress + '%');
532
+
533
+ // Simulate interruption at 50%
534
+ if (event.progress >= 50) {
535
+ window.location.reload(); // Page reload
536
+ }
537
+ }
538
+ });
539
+
540
+ // After page reload, same file will automatically resume from 50%
541
+ // The client fingerprints the file and stores progress in localStorage
542
+ ```
543
+
544
+ ### Example 8: Connection Health Monitoring
545
+
546
+ Monitor HTTP connection health and performance:
547
+
548
+ ```typescript
549
+ import { createHttpClient } from '@uploadista/client-browser';
550
+
551
+ const httpClient = createHttpClient({
552
+ maxConnectionsPerHost: 6,
553
+ keepAliveTimeout: 60000,
554
+ enableHttp2: true
555
+ });
556
+
557
+ // Monitor connection health periodically
558
+ setInterval(() => {
559
+ const metrics = httpClient.getDetailedMetrics();
560
+
561
+ console.log('Connection Health:', metrics.health.status);
562
+ console.log('Health Score:', metrics.health.score);
563
+ console.log('Connection Reuse Rate:', Math.round(metrics.reuseRate * 100) + '%');
564
+ console.log('Average Connection Time:', Math.round(metrics.averageConnectionTime) + 'ms');
565
+ console.log('Requests/sec:', metrics.requestsPerSecond.toFixed(2));
566
+ console.log('Error Rate:', (metrics.errorRate * 100).toFixed(1) + '%');
567
+
568
+ if (metrics.health.status === 'degraded' || metrics.health.status === 'poor') {
569
+ console.warn('Connection Issues:', metrics.health.issues);
570
+ console.log('Recommendations:', metrics.health.recommendations);
571
+ }
572
+ }, 30000); // Check every 30 seconds
573
+ ```
574
+
575
+ ### Example 9: Flow Execution with File Upload
576
+
577
+ Upload a file and execute a processing flow:
578
+
579
+ ```typescript
580
+ import { createUploadistaClient } from '@uploadista/client-browser';
581
+
582
+ const client = createUploadistaClient({
583
+ endpoint: 'https://api.uploadista.com/upload'
584
+ });
585
+
586
+ // Upload image file
587
+ const imageFile = document.querySelector<HTMLInputElement>('input[type="file"]').files[0];
588
+ const upload = await client.upload(imageFile);
589
+
590
+ // Execute image processing flow
591
+ const flowResult = await client.executeFlow({
592
+ flowId: 'image-resize-optimize',
593
+ inputs: {
594
+ 'input-1': upload.id // Reference uploaded file
595
+ },
596
+ storageId: 'storage-1'
597
+ });
598
+
599
+ console.log('Flow execution complete:', flowResult);
600
+ console.log('Processed images:', flowResult.outputs);
601
+ ```
602
+
603
+ ## Browser Compatibility
604
+
605
+ `@uploadista/client-browser` is compatible with modern browsers that support:
606
+
607
+ - **Fetch API** - Chrome 42+, Firefox 39+, Safari 10.1+, Edge 14+
608
+ - **File API** - Chrome 13+, Firefox 3.6+, Safari 6+, Edge 12+
609
+ - **Web Crypto API** - Chrome 37+, Firefox 34+, Safari 11+, Edge 79+
610
+ - **WebSocket** - Chrome 16+, Firefox 11+, Safari 7+, Edge 12+
611
+ - **LocalStorage** - Chrome 4+, Firefox 3.5+, Safari 4+, Edge 12+
612
+
613
+ ### Minimum Browser Versions
614
+
615
+ - Chrome/Edge: 79+
616
+ - Firefox: 67+
617
+ - Safari: 11+
618
+ - Opera: 66+
619
+
620
+ ### Features by Browser
621
+
622
+ | Feature | Chrome | Firefox | Safari | Edge |
623
+ |---------|--------|---------|--------|------|
624
+ | Chunked Upload | 42+ | 39+ | 10.1+ | 14+ |
625
+ | Resumable Upload | 37+ | 34+ | 11+ | 79+ |
626
+ | WebSocket Events | 16+ | 11+ | 7+ | 12+ |
627
+ | HTTP/2 Multiplexing | 49+ | 52+ | 10.1+ | 79+ |
628
+ | Connection Pooling | 42+ | 39+ | 10.1+ | 14+ |
629
+
630
+ ### Polyfills
631
+
632
+ For older browser support, consider using polyfills:
633
+
634
+ - `whatwg-fetch` - Fetch API polyfill
635
+ - `abortcontroller-polyfill` - AbortController polyfill
636
+ - `webcrypto-shim` - Web Crypto API polyfill
637
+
638
+ ```bash
639
+ npm install whatwg-fetch abortcontroller-polyfill webcrypto-shim
640
+ ```
641
+
642
+ ```typescript
643
+ import 'whatwg-fetch';
644
+ import 'abortcontroller-polyfill/dist/polyfill-patch-fetch';
645
+ import 'webcrypto-shim';
646
+
647
+ import { createUploadistaClient } from '@uploadista/client-browser';
648
+ ```
649
+
650
+ ## Related Packages
651
+
652
+ ### Core Packages
653
+ - [@uploadista/core](../../../core/README.md) - Core flow engine and upload system
654
+ - [@uploadista/client-core](../core/README.md) - Platform-agnostic client logic
655
+
656
+ ### Other Client Packages
657
+ - [@uploadista/react](../react/README.md) - React hooks and components for Uploadista
658
+
659
+ ### Server Packages
660
+ - [@uploadista/server](../../server/README.md) - Server-side upload handling
661
+
662
+ ## Troubleshooting
663
+
664
+ ### Issue: Upload fails with CORS error
665
+
666
+ **Solution:** Ensure your server is configured to accept requests from your domain:
667
+
668
+ ```javascript
669
+ // Server-side (example)
670
+ app.use((req, res, next) => {
671
+ res.setHeader('Access-Control-Allow-Origin', 'https://your-domain.com');
672
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
673
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
674
+ next();
675
+ });
676
+ ```
677
+
678
+ ### Issue: Upload fails on mobile Safari
679
+
680
+ **Solution:** Mobile Safari has stricter memory limits. Use smaller chunk sizes:
681
+
682
+ ```typescript
683
+ const client = createUploadistaClient({
684
+ endpoint: 'https://api.uploadista.com/upload',
685
+ chunkSize: 1 * 1024 * 1024 // 1MB chunks for mobile
686
+ });
687
+ ```
688
+
689
+ ### Issue: Resumable uploads not working
690
+
691
+ **Solution:** Verify that:
692
+ 1. `storeFingerprintForResuming` is enabled
693
+ 2. LocalStorage is not disabled or full
694
+ 3. The file hasn't been modified (fingerprint would change)
695
+ 4. The server supports resumable uploads
696
+
697
+ ```typescript
698
+ // Check if localStorage is available
699
+ if (typeof localStorage !== 'undefined') {
700
+ const client = createUploadistaClient({
701
+ endpoint: 'https://api.uploadista.com/upload',
702
+ storeFingerprintForResuming: true
703
+ });
704
+ }
705
+ ```
706
+
707
+ ### Issue: Slow upload speeds
708
+
709
+ **Solution:**
710
+ 1. Check connection health metrics
711
+ 2. Increase chunk size for fast connections
712
+ 3. Enable HTTP/2 multiplexing
713
+ 4. Warm up connections before uploading
714
+
715
+ ```typescript
716
+ const httpClient = createHttpClient({
717
+ maxConnectionsPerHost: 10,
718
+ enableHttp2: true,
719
+ keepAliveTimeout: 120000
720
+ });
721
+
722
+ // Warm up connections
723
+ await httpClient.warmupConnections(['https://api.uploadista.com']);
724
+
725
+ const client = createUploadistaClient({
726
+ endpoint: 'https://api.uploadista.com/upload',
727
+ chunkSize: 10 * 1024 * 1024, // 10MB chunks for fast connections
728
+ connectionPooling: {
729
+ maxConnectionsPerHost: 10,
730
+ enableHttp2: true
731
+ }
732
+ });
733
+ ```
734
+
735
+ ### Issue: Memory usage too high
736
+
737
+ **Solution:** Reduce chunk size to decrease memory usage:
738
+
739
+ ```typescript
740
+ const client = createUploadistaClient({
741
+ endpoint: 'https://api.uploadista.com/upload',
742
+ chunkSize: 1 * 1024 * 1024 // 1MB chunks
743
+ });
744
+ ```
745
+
746
+ ### Issue: WebSocket connection fails
747
+
748
+ **Solution:**
749
+ 1. Verify WebSocket URL is correct (wss:// for HTTPS)
750
+ 2. Check firewall/proxy settings
751
+ 3. Ensure server supports WebSocket upgrades
752
+ 4. Implement reconnection logic
753
+
754
+ ```typescript
755
+ let ws: WebSocket;
756
+ let reconnectAttempts = 0;
757
+ const maxReconnectAttempts = 5;
758
+
759
+ function connectWebSocket(uploadId: string) {
760
+ ws = new WebSocket(`wss://api.uploadista.com/ws/${uploadId}`);
761
+
762
+ ws.addEventListener('open', () => {
763
+ console.log('Connected');
764
+ reconnectAttempts = 0;
765
+ });
766
+
767
+ ws.addEventListener('close', () => {
768
+ if (reconnectAttempts < maxReconnectAttempts) {
769
+ reconnectAttempts++;
770
+ const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
771
+ setTimeout(() => connectWebSocket(uploadId), delay);
772
+ }
773
+ });
774
+ }
775
+ ```
776
+
777
+ ### Issue: File upload fails with large files
778
+
779
+ **Solution:**
780
+ 1. Use chunked uploads (enabled by default)
781
+ 2. Increase chunk size for better performance
782
+ 3. Enable resumable uploads for reliability
783
+
784
+ ```typescript
785
+ const client = createUploadistaClient({
786
+ endpoint: 'https://api.uploadista.com/upload',
787
+ chunkSize: 5 * 1024 * 1024, // 5MB chunks
788
+ storeFingerprintForResuming: true, // Enable resumable uploads
789
+ retryDelays: [1000, 3000, 5000, 10000] // Retry on failure
790
+ });
791
+ ```
792
+
793
+ ## License
794
+
795
+ MIT