@uploadista/client-browser 0.0.3 → 0.0.4

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 (59) hide show
  1. package/dist/index.d.ts +561 -6
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -7
  4. package/dist/index.js.map +1 -0
  5. package/package.json +6 -5
  6. package/tsdown.config.ts +12 -0
  7. package/.turbo/turbo-build.log +0 -5
  8. package/.turbo/turbo-check.log +0 -130
  9. package/dist/client/create-uploadista-client.d.ts +0 -182
  10. package/dist/client/create-uploadista-client.d.ts.map +0 -1
  11. package/dist/client/create-uploadista-client.js +0 -76
  12. package/dist/client/index.d.ts +0 -2
  13. package/dist/client/index.d.ts.map +0 -1
  14. package/dist/client/index.js +0 -1
  15. package/dist/framework-utils.d.ts +0 -201
  16. package/dist/framework-utils.d.ts.map +0 -1
  17. package/dist/framework-utils.js +0 -282
  18. package/dist/http-client.d.ts +0 -44
  19. package/dist/http-client.d.ts.map +0 -1
  20. package/dist/http-client.js +0 -489
  21. package/dist/services/abort-controller-factory.d.ts +0 -30
  22. package/dist/services/abort-controller-factory.d.ts.map +0 -1
  23. package/dist/services/abort-controller-factory.js +0 -98
  24. package/dist/services/checksum-service.d.ts +0 -30
  25. package/dist/services/checksum-service.d.ts.map +0 -1
  26. package/dist/services/checksum-service.js +0 -44
  27. package/dist/services/create-browser-services.d.ts +0 -36
  28. package/dist/services/create-browser-services.d.ts.map +0 -1
  29. package/dist/services/create-browser-services.js +0 -56
  30. package/dist/services/file-reader.d.ts +0 -91
  31. package/dist/services/file-reader.d.ts.map +0 -1
  32. package/dist/services/file-reader.js +0 -251
  33. package/dist/services/fingerprint-service.d.ts +0 -41
  34. package/dist/services/fingerprint-service.d.ts.map +0 -1
  35. package/dist/services/fingerprint-service.js +0 -64
  36. package/dist/services/id-generation/id-generation.d.ts +0 -40
  37. package/dist/services/id-generation/id-generation.d.ts.map +0 -1
  38. package/dist/services/id-generation/id-generation.js +0 -58
  39. package/dist/services/platform-service.d.ts +0 -38
  40. package/dist/services/platform-service.d.ts.map +0 -1
  41. package/dist/services/platform-service.js +0 -221
  42. package/dist/services/storage/local-storage-service.d.ts +0 -55
  43. package/dist/services/storage/local-storage-service.d.ts.map +0 -1
  44. package/dist/services/storage/local-storage-service.js +0 -178
  45. package/dist/services/storage/session-storage-service.d.ts +0 -55
  46. package/dist/services/storage/session-storage-service.d.ts.map +0 -1
  47. package/dist/services/storage/session-storage-service.js +0 -179
  48. package/dist/services/websocket-factory.d.ts +0 -46
  49. package/dist/services/websocket-factory.d.ts.map +0 -1
  50. package/dist/services/websocket-factory.js +0 -196
  51. package/dist/types/index.d.ts +0 -2
  52. package/dist/types/index.d.ts.map +0 -1
  53. package/dist/types/index.js +0 -1
  54. package/dist/types/upload-input.d.ts +0 -26
  55. package/dist/types/upload-input.d.ts.map +0 -1
  56. package/dist/types/upload-input.js +0 -1
  57. package/dist/utils/hash-util.d.ts +0 -60
  58. package/dist/utils/hash-util.d.ts.map +0 -1
  59. package/dist/utils/hash-util.js +0 -75
package/dist/index.d.ts CHANGED
@@ -1,8 +1,563 @@
1
+ import * as _uploadista_client_core0 from "@uploadista/client-core";
2
+ import { ConnectionPoolConfig, FileReaderService, FlowResult, HttpClient, SliceResult, UploadResult, UploadistaClientOptions as UploadistaClientOptions$1 } from "@uploadista/client-core";
3
+ import * as _uploadista_core0 from "@uploadista/core";
4
+ import { FlowEvent } from "@uploadista/core/flow";
5
+ import { UploadEvent, UploadFile } from "@uploadista/core/types";
1
6
  export * from "@uploadista/client-core";
2
- export { createUploadistaClient, type UploadistaClientOptions } from "./client";
3
- export * from "./framework-utils";
4
- export { createHttpClient } from "./http-client";
5
- export type { FileReader } from "./services/file-reader";
6
- export { createBrowserFileReaderService } from "./services/file-reader";
7
- export * from "./types";
7
+
8
+ //#region src/types/upload-input.d.ts
9
+
10
+ /**
11
+ * Browser-specific upload input types that can be used with the Uploadista client.
12
+ *
13
+ * In the browser environment, files can be provided as either:
14
+ * - `File` objects from file input elements or drag-and-drop
15
+ * - `Blob` objects created programmatically or from other sources
16
+ *
17
+ * Both types use the browser's File API and can be chunked for upload.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // From file input
22
+ * const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');
23
+ * const file: BrowserUploadInput = fileInput.files[0];
24
+ *
25
+ * // From drag and drop
26
+ * element.addEventListener('drop', (e) => {
27
+ * const file: BrowserUploadInput = e.dataTransfer.files[0];
28
+ * });
29
+ *
30
+ * // From Blob
31
+ * const blob: BrowserUploadInput = new Blob(['content'], { type: 'text/plain' });
32
+ * ```
33
+ */
34
+ type BrowserUploadInput = Blob | File;
35
+ //#endregion
36
+ //#region src/client/create-uploadista-client.d.ts
37
+ /**
38
+ * Configuration options for creating a browser-specific Uploadista client.
39
+ *
40
+ * This interface extends the core client options but omits browser-specific
41
+ * services that are automatically provided by the browser environment.
42
+ * These services include WebSocket factory, AbortController, ID generation,
43
+ * storage, logging, platform detection, fingerprinting, HTTP client, file reader,
44
+ * and checksum calculation.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * import { createUploadistaClient } from '@uploadista/client-browser';
49
+ *
50
+ * const client = createUploadistaClient({
51
+ * endpoint: 'https://api.uploadista.com/upload',
52
+ * connectionPooling: {
53
+ * maxConnectionsPerHost: 6,
54
+ * enableHttp2: true
55
+ * }
56
+ * });
57
+ * ```
58
+ */
59
+ interface UploadistaClientOptions extends Omit<UploadistaClientOptions$1<BrowserUploadInput>, "webSocketFactory" | "abortControllerFactory" | "generateId" | "clientStorage" | "logger" | "platformService" | "fingerprintService" | "httpClient" | "fileReader" | "checksumService"> {
60
+ /**
61
+ * Connection pooling configuration for the HTTP client.
62
+ *
63
+ * Controls how the browser manages HTTP connections for optimal performance.
64
+ * The browser's native fetch API with keep-alive headers is used under the hood.
65
+ *
66
+ * @default
67
+ * ```typescript
68
+ * {
69
+ * maxConnectionsPerHost: 6,
70
+ * connectionTimeout: 30000,
71
+ * keepAliveTimeout: 60000,
72
+ * enableHttp2: true,
73
+ * retryOnConnectionError: true
74
+ * }
75
+ * ```
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * connectionPooling: {
80
+ * maxConnectionsPerHost: 10,
81
+ * enableHttp2: true,
82
+ * keepAliveTimeout: 120000
83
+ * }
84
+ * ```
85
+ */
86
+ connectionPooling?: ConnectionPoolConfig;
87
+ }
88
+ /**
89
+ * Creates a browser-optimized Uploadista client for file uploads and flow processing.
90
+ *
91
+ * This factory function automatically configures all browser-specific services including:
92
+ * - Fetch-based HTTP client with connection pooling
93
+ * - Native WebSocket support for real-time progress
94
+ * - localStorage for upload state persistence
95
+ * - Web Crypto API for checksums and fingerprints
96
+ * - File API for reading and chunking files
97
+ * - Browser platform detection and capabilities
98
+ *
99
+ * The created client can handle File and Blob objects from file inputs, drag-and-drop,
100
+ * or programmatically created content. It supports resumable uploads, progress tracking,
101
+ * and flow-based file processing.
102
+ *
103
+ * @param options - Configuration options for the browser client
104
+ * @returns A fully configured Uploadista client ready for browser use
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * import { createUploadistaClient } from '@uploadista/client-browser';
109
+ *
110
+ * // Basic usage
111
+ * const client = createUploadistaClient({
112
+ * endpoint: 'https://api.uploadista.com/upload'
113
+ * });
114
+ *
115
+ * // With custom configuration
116
+ * const client = createUploadistaClient({
117
+ * endpoint: 'https://api.uploadista.com/upload',
118
+ * connectionPooling: {
119
+ * maxConnectionsPerHost: 6,
120
+ * enableHttp2: true,
121
+ * keepAliveTimeout: 60000
122
+ * },
123
+ * chunkSize: 5 * 1024 * 1024, // 5MB chunks
124
+ * retryDelays: [1000, 3000, 5000],
125
+ * allowedMetaFields: ['userId', 'projectId']
126
+ * });
127
+ *
128
+ * // Upload a file
129
+ * const fileInput = document.querySelector('input[type="file"]');
130
+ * const file = fileInput.files[0];
131
+ *
132
+ * const upload = await client.upload(file, {
133
+ * onProgress: (event) => {
134
+ * console.log(`Progress: ${event.progress}%`);
135
+ * }
136
+ * });
137
+ *
138
+ * console.log('Upload complete:', upload.id);
139
+ * ```
140
+ *
141
+ * @see {@link UploadistaClientOptions} for available configuration options
142
+ * @see {@link BrowserUploadInput} for supported file input types
143
+ */
144
+ declare function createUploadistaClient(options: UploadistaClientOptions): {
145
+ upload: (file: BrowserUploadInput, {
146
+ uploadLengthDeferred,
147
+ uploadSize,
148
+ onProgress,
149
+ onChunkComplete,
150
+ onSuccess,
151
+ onShouldRetry,
152
+ onError
153
+ }?: _uploadista_client_core0.UploadistaUploadOptions) => Promise<{
154
+ abort: () => void;
155
+ }>;
156
+ uploadWithFlow: (file: BrowserUploadInput, flowConfig: _uploadista_client_core0.FlowUploadConfig, {
157
+ onProgress,
158
+ onChunkComplete,
159
+ onSuccess,
160
+ onShouldRetry,
161
+ onJobStart,
162
+ onError
163
+ }?: Omit<_uploadista_client_core0.UploadistaUploadOptions, "uploadLengthDeferred" | "uploadSize" | "metadata">) => Promise<{
164
+ abort: () => void;
165
+ jobId: string;
166
+ }>;
167
+ abort: (params: Parameters<typeof void 0>[0]) => Promise<void>;
168
+ getFlow: (flowId: string) => Promise<{
169
+ status: number;
170
+ flow: _uploadista_core0.FlowData;
171
+ }>;
172
+ runFlow: ({
173
+ flowId,
174
+ inputs,
175
+ storageId: flowStorageId
176
+ }: {
177
+ flowId: string;
178
+ inputs: Record<string, unknown>;
179
+ storageId?: string;
180
+ }) => Promise<{
181
+ status: number;
182
+ job: _uploadista_core0.FlowJob;
183
+ }>;
184
+ continueFlow: ({
185
+ jobId,
186
+ nodeId,
187
+ newData,
188
+ contentType
189
+ }: {
190
+ jobId: string;
191
+ nodeId: string;
192
+ newData: unknown;
193
+ contentType?: "application/json" | "application/octet-stream";
194
+ }) => Promise<_uploadista_core0.FlowJob>;
195
+ getJobStatus: (jobId: string) => Promise<_uploadista_core0.FlowJob>;
196
+ openUploadWebSocket: (uploadId: string) => Promise<_uploadista_client_core0.WebSocketLike>;
197
+ openFlowWebSocket: (jobId: string) => Promise<_uploadista_client_core0.WebSocketLike>;
198
+ openWebSocket: (id: string) => Promise<_uploadista_client_core0.WebSocketLike>;
199
+ closeWebSocket: (id: string) => void;
200
+ closeAllWebSockets: () => void;
201
+ sendPing: (jobId: string) => boolean;
202
+ isWebSocketConnected: (id: string) => boolean;
203
+ getWebSocketConnectionCount: () => number;
204
+ getWebSocketConnectionCountByType: () => {
205
+ upload: number;
206
+ flow: number;
207
+ total: number;
208
+ };
209
+ getNetworkMetrics: () => _uploadista_client_core0.NetworkMetrics;
210
+ getNetworkCondition: () => _uploadista_client_core0.NetworkCondition;
211
+ getChunkingInsights: () => _uploadista_client_core0.PerformanceInsights;
212
+ exportMetrics: () => {
213
+ session: Partial<_uploadista_client_core0.UploadSessionMetrics>;
214
+ chunks: _uploadista_client_core0.ChunkMetrics[];
215
+ insights: _uploadista_client_core0.PerformanceInsights;
216
+ };
217
+ getConnectionMetrics: () => _uploadista_client_core0.ConnectionMetrics;
218
+ getDetailedConnectionMetrics: () => _uploadista_client_core0.DetailedConnectionMetrics;
219
+ warmupConnections: (urls: string[]) => Promise<void>;
220
+ getConnectionPoolingInsights: () => Promise<{
221
+ isOptimized: boolean;
222
+ reuseRate: number;
223
+ recommendedMinChunkSize: number;
224
+ connectionOverhead: number;
225
+ }>;
226
+ resetMetrics: () => Promise<void>;
227
+ validateConfiguration: (options: UploadistaClientOptions$1<BrowserUploadInput>) => {
228
+ valid: boolean;
229
+ errors: string[];
230
+ warnings: string[];
231
+ };
232
+ validateConfigurationAsync: (options: UploadistaClientOptions$1<BrowserUploadInput>) => Promise<{
233
+ valid: boolean;
234
+ errors: string[];
235
+ warnings: string[];
236
+ capabilities: _uploadista_core0.DataStoreCapabilities;
237
+ }>;
238
+ getCapabilities: () => Promise<_uploadista_core0.DataStoreCapabilities>;
239
+ };
240
+ //#endregion
241
+ //#region src/framework-utils.d.ts
242
+ /**
243
+ * Base upload state that framework wrappers should implement
244
+ */
245
+ interface BaseUploadState {
246
+ status: "idle" | "uploading" | "success" | "error" | "aborted";
247
+ progress: number;
248
+ bytesUploaded: number;
249
+ totalBytes: number;
250
+ error?: Error;
251
+ result?: UploadResult<UploadFile>;
252
+ }
253
+ /**
254
+ * Base flow upload state
255
+ */
256
+ interface BaseFlowUploadState extends BaseUploadState {
257
+ jobId?: string;
258
+ flowStatus?: "pending" | "processing" | "completed" | "failed";
259
+ flowResult?: FlowResult<unknown>;
260
+ }
261
+ /**
262
+ * Progress callback signature
263
+ */
264
+ type ProgressCallback = (uploadId: string, bytesUploaded: number, totalBytes: number) => void;
265
+ /**
266
+ * Complete callback signature
267
+ */
268
+ type CompleteCallback = (uploadId: string, result: UploadResult) => void;
269
+ /**
270
+ * Error callback signature
271
+ */
272
+ type ErrorCallback = (uploadId: string, error: Error) => void;
273
+ /**
274
+ * Abort callback signature
275
+ */
276
+ type AbortCallback = (uploadId: string) => void;
277
+ /**
278
+ * Event handler signature for framework wrappers
279
+ */
280
+ type EventHandler<T = unknown> = (event: T) => void;
281
+ /**
282
+ * WebSocket event handler signature
283
+ */
284
+ type WebSocketEventHandler = (event: UploadEvent | FlowEvent) => void;
285
+ /**
286
+ * Framework state updater function signature
287
+ * @template T - The state type
288
+ */
289
+ type StateUpdater<T> = (updater: (prevState: T) => T) => void;
290
+ /**
291
+ * Cleanup function returned by setup functions
292
+ */
293
+ type CleanupFunction = () => void;
294
+ /**
295
+ * Upload item for multi-upload tracking
296
+ */
297
+ interface UploadItem {
298
+ id: string;
299
+ file: File;
300
+ status: BaseUploadState["status"];
301
+ progress: number;
302
+ bytesUploaded: number;
303
+ totalBytes: number;
304
+ error?: Error;
305
+ result?: UploadResult;
306
+ }
307
+ /**
308
+ * Multi-upload aggregate statistics
309
+ */
310
+ interface MultiUploadStats {
311
+ totalFiles: number;
312
+ completedFiles: number;
313
+ failedFiles: number;
314
+ totalBytes: number;
315
+ uploadedBytes: number;
316
+ totalProgress: number;
317
+ allComplete: boolean;
318
+ hasErrors: boolean;
319
+ }
320
+ /**
321
+ * Drag and drop state
322
+ */
323
+ interface DragDropState {
324
+ isDragging: boolean;
325
+ isOver: boolean;
326
+ files: File[];
327
+ }
328
+ /**
329
+ * File validation result
330
+ */
331
+ interface FileValidationResult {
332
+ valid: boolean;
333
+ error?: string;
334
+ }
335
+ /**
336
+ * File validation function signature
337
+ */
338
+ type FileValidator = (file: File) => FileValidationResult;
339
+ /**
340
+ * Utility: Calculate aggregate upload statistics
341
+ */
342
+ declare function calculateMultiUploadStats(uploads: UploadItem[]): MultiUploadStats;
343
+ /**
344
+ * Utility: Format file size for display
345
+ */
346
+ declare function formatFileSize(bytes: number): string;
347
+ /**
348
+ * Utility: Format progress percentage
349
+ */
350
+ declare function formatProgress(progress: number): string;
351
+ /**
352
+ * Utility: Get file extension
353
+ */
354
+ declare function getFileExtension(filename: string): string;
355
+ /**
356
+ * Utility: Check if file is an image
357
+ */
358
+ declare function isImageFile(file: File): boolean;
359
+ /**
360
+ * Utility: Check if file is a video
361
+ */
362
+ declare function isVideoFile(file: File): boolean;
363
+ /**
364
+ * Utility: Create file size validator
365
+ */
366
+ declare function createFileSizeValidator(maxSizeBytes: number): FileValidator;
367
+ /**
368
+ * Utility: Create file type validator
369
+ */
370
+ declare function createFileTypeValidator(allowedTypes: string[]): FileValidator;
371
+ /**
372
+ * Utility: Compose multiple validators
373
+ */
374
+ declare function composeValidators(...validators: FileValidator[]): FileValidator;
375
+ /**
376
+ * Utility: Generate unique upload ID
377
+ */
378
+ declare function generateUploadId(): string;
379
+ /**
380
+ * Utility: Create delay promise for retry logic
381
+ */
382
+ declare function delay(ms: number): Promise<void>;
383
+ /**
384
+ * Utility: Calculate exponential backoff delay
385
+ */
386
+ declare function calculateBackoff(attempt: number, baseDelay?: number, maxDelay?: number): number;
387
+ /**
388
+ * Utility: Create retry wrapper for upload function
389
+ */
390
+ declare function createRetryWrapper<T>(fn: () => Promise<T>, maxAttempts?: number, shouldRetry?: (error: unknown) => boolean): () => Promise<T>;
391
+ /**
392
+ * Type guard: Check if error is network-related (should retry)
393
+ */
394
+ declare function isNetworkError(error: unknown): boolean;
395
+ /**
396
+ * Type guard: Check if error is abort-related (should not retry)
397
+ */
398
+ declare function isAbortError(error: unknown): boolean;
399
+ /**
400
+ * Format upload speed in human-readable format
401
+ */
402
+ declare function formatSpeed(bytesPerSecond: number): string;
403
+ /**
404
+ * Format duration in human-readable format
405
+ */
406
+ declare function formatDuration(milliseconds: number): string;
407
+ /**
408
+ * Validate file type against accepted types
409
+ */
410
+ declare function validateFileType(file: File, accept: string[]): boolean;
411
+ /**
412
+ * Check if a file is an audio file
413
+ */
414
+ declare function isAudioFile(file: File): boolean;
415
+ /**
416
+ * Check if a file is a document
417
+ */
418
+ declare function isDocumentFile(file: File): boolean;
419
+ /**
420
+ * Create a preview URL for a file (if supported)
421
+ */
422
+ declare function createFilePreview(file: File): string | null;
423
+ /**
424
+ * Clean up a preview URL created with createFilePreview
425
+ */
426
+ declare function revokeFilePreview(previewUrl: string): void;
427
+ /**
428
+ * Calculate progress percentage
429
+ */
430
+ declare function calculateProgress(current: number, total: number): number;
431
+ //#endregion
432
+ //#region src/http-client.d.ts
433
+ /**
434
+ * Creates a browser-optimized HTTP client using the Fetch API.
435
+ *
436
+ * This factory function returns an HttpClient implementation that uses the browser's
437
+ * native fetch() API with connection keep-alive headers for optimal performance.
438
+ * The client automatically manages connection pooling, tracks metrics, and provides
439
+ * connection health monitoring.
440
+ *
441
+ * @param config - Optional connection pooling configuration
442
+ * @returns A configured HTTP client ready for making requests
443
+ *
444
+ * @example
445
+ * ```typescript
446
+ * import { createHttpClient } from '@uploadista/client-browser';
447
+ *
448
+ * // Basic usage with defaults
449
+ * const client = createHttpClient();
450
+ *
451
+ * // With custom configuration
452
+ * const client = createHttpClient({
453
+ * maxConnectionsPerHost: 10,
454
+ * connectionTimeout: 60000,
455
+ * keepAliveTimeout: 120000,
456
+ * enableHttp2: true,
457
+ * retryOnConnectionError: true
458
+ * });
459
+ *
460
+ * // Make a request
461
+ * const response = await client.request('https://api.example.com/data', {
462
+ * method: 'POST',
463
+ * headers: { 'Content-Type': 'application/json' },
464
+ * body: JSON.stringify({ key: 'value' })
465
+ * });
466
+ *
467
+ * // Check connection health
468
+ * const metrics = client.getDetailedMetrics();
469
+ * console.log('Connection health:', metrics.health.status);
470
+ * ```
471
+ *
472
+ * @see {@link BrowserHttpClient} for implementation details
473
+ */
474
+ declare function createHttpClient(config?: ConnectionPoolConfig): HttpClient;
475
+ //#endregion
476
+ //#region src/services/file-reader.d.ts
477
+ /**
478
+ * Browser-specific file reader interface for opening and reading file data.
479
+ *
480
+ * Provides methods to open File/Blob objects and create FileSource instances
481
+ * that support chunked reading for upload operations.
482
+ */
483
+ type FileReader = {
484
+ /**
485
+ * Opens a file and prepares it for chunked reading.
486
+ *
487
+ * @param input - The File or Blob to open
488
+ * @param chunkSize - Size of chunks to read (in bytes)
489
+ * @returns Promise resolving to a FileSource for reading the file
490
+ */
491
+ openFile: (input: BrowserUploadInput, chunkSize: number) => Promise<FileSource>;
492
+ };
493
+ /**
494
+ * Represents an opened file that can be read in chunks.
495
+ *
496
+ * This interface provides the core functionality for reading file data
497
+ * in a streaming fashion, which is essential for uploading large files
498
+ * without loading them entirely into memory.
499
+ */
500
+ type FileSource = {
501
+ /** The original input File or Blob */
502
+ input: BrowserUploadInput;
503
+ /** Total size of the file in bytes, or null if unknown */
504
+ size: number | null;
505
+ /**
506
+ * Reads a slice of data from the file.
507
+ *
508
+ * @param start - Starting byte offset
509
+ * @param end - Ending byte offset (exclusive)
510
+ * @returns Promise resolving to the slice result with data and metadata
511
+ */
512
+ slice: (start: number, end: number) => Promise<SliceResult>;
513
+ /**
514
+ * Closes the file and releases any resources.
515
+ *
516
+ * For browser File/Blob objects, this is typically a no-op as there are
517
+ * no resources to release, but is included for interface compatibility.
518
+ */
519
+ close: () => void;
520
+ };
521
+ /**
522
+ * Creates a browser-specific file reader service for the Uploadista client.
523
+ *
524
+ * This service provides the ability to open and read File/Blob objects from
525
+ * the browser's File API. It converts browser-native file objects into a
526
+ * format that can be chunked and uploaded efficiently.
527
+ *
528
+ * The service currently supports:
529
+ * - File objects from `<input type="file">` elements
530
+ * - File objects from drag-and-drop events
531
+ * - Blob objects created programmatically
532
+ *
533
+ * Future support may include:
534
+ * - ReadableStream for streaming data
535
+ *
536
+ * @returns A FileReaderService configured for browser environments
537
+ *
538
+ * @example
539
+ * ```typescript
540
+ * import { createBrowserFileReaderService } from '@uploadista/client-browser';
541
+ *
542
+ * const fileReader = createBrowserFileReaderService();
543
+ *
544
+ * // Open a file from input element
545
+ * const input = document.querySelector('input[type="file"]');
546
+ * const file = input.files[0];
547
+ * const source = await fileReader.openFile(file, 5 * 1024 * 1024); // 5MB chunks
548
+ *
549
+ * console.log('File name:', source.name);
550
+ * console.log('File size:', source.size);
551
+ * console.log('File type:', source.type);
552
+ *
553
+ * // Read first chunk
554
+ * const chunk = await source.slice(0, 5 * 1024 * 1024);
555
+ * console.log('Read', chunk.size, 'bytes');
556
+ * ```
557
+ *
558
+ * @throws {Error} When the input is not a File or Blob
559
+ */
560
+ declare function createBrowserFileReaderService(): FileReaderService<BrowserUploadInput>;
561
+ //#endregion
562
+ export { AbortCallback, BaseFlowUploadState, BaseUploadState, BrowserUploadInput, CleanupFunction, CompleteCallback, DragDropState, ErrorCallback, EventHandler, type FileReader, FileValidationResult, FileValidator, MultiUploadStats, ProgressCallback, StateUpdater, UploadItem, type UploadistaClientOptions, WebSocketEventHandler, calculateBackoff, calculateMultiUploadStats, calculateProgress, composeValidators, createBrowserFileReaderService, createFilePreview, createFileSizeValidator, createFileTypeValidator, createHttpClient, createRetryWrapper, createUploadistaClient, delay, formatDuration, formatFileSize, formatProgress, formatSpeed, generateUploadId, getFileExtension, isAbortError, isAudioFile, isDocumentFile, isImageFile, isNetworkError, isVideoFile, revokeFilePreview, validateFileType };
8
563
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAChF,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/upload-input.ts","../src/client/create-uploadista-client.ts","../src/framework-utils.ts","../src/http-client.ts","../src/services/file-reader.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,7 +1,2 @@
1
- // Re-export everything from client-core
2
- export * from "@uploadista/client-core";
3
- export { createUploadistaClient } from "./client";
4
- export * from "./framework-utils";
5
- export { createHttpClient } from "./http-client";
6
- export { createBrowserFileReaderService } from "./services/file-reader";
7
- export * from "./types";
1
+ import{createClientStorage as e,createLogger as t,createUploadistaClient as n}from"@uploadista/client-core";export*from"@uploadista/client-core";function r(e){return new i(e)}var i=class{config;metrics;connectionTimes=[];requestCount=0;connectionCount=0;errorCount=0;timeoutCount=0;retryCount=0;startTime=Date.now();http2Info;constructor(e={}){this.config={maxConnectionsPerHost:e.maxConnectionsPerHost??6,connectionTimeout:e.connectionTimeout??3e4,keepAliveTimeout:e.keepAliveTimeout??6e4,enableHttp2:e.enableHttp2??!0,retryOnConnectionError:e.retryOnConnectionError??!0},this.metrics={activeConnections:0,totalConnections:0,reuseRate:0,averageConnectionTime:0},this.http2Info=this.detectHttp2Support()}detectHttp2Support(){let e=`serviceWorker`in navigator&&`fetch`in window,t=`ReadableStream`in window&&`WritableStream`in window&&`TransformStream`in window;return{supported:e,detected:!1,version:t?`h2`:`h1.1`,multiplexingActive:t&&this.config.enableHttp2}}async request(e,t={}){this.requestCount++;let n={method:t.method||`GET`,headers:{Connection:`keep-alive`,"Keep-Alive":`timeout=${this.config.keepAliveTimeout/1e3}`,...t.headers},body:t.body,credentials:t.credentials||`include`,signal:t.signal};if(t.timeout){let r=new AbortController,i=setTimeout(()=>r.abort(),t.timeout);t.signal&&t.signal.addEventListener(`abort`,()=>r.abort()),n.signal=r.signal;try{let t=await this.makeRequest(e,n);return clearTimeout(i),t}catch(e){throw clearTimeout(i),e}}return this.makeRequest(e,n)}async makeRequest(e,t){let n=Date.now();try{let r=await fetch(e,t),i=Date.now()-n;return this.recordConnectionMetrics(i),{status:r.status,statusText:r.statusText,headers:r.headers,ok:r.ok,json:()=>r.json(),text:()=>r.text(),arrayBuffer:()=>r.arrayBuffer()}}catch(e){throw this.connectionCount++,e}}recordConnectionMetrics(e){this.connectionTimes.push(e),this.connectionCount++,this.connectionTimes.length>100&&this.connectionTimes.shift(),this.metrics.totalConnections=this.connectionCount,this.metrics.averageConnectionTime=this.connectionTimes.reduce((e,t)=>e+t,0)/this.connectionTimes.length;let t=this.connectionTimes.filter(e=>e<100).length;this.metrics.reuseRate=t/this.connectionTimes.length}getMetrics(){return{...this.metrics}}getDetailedMetrics(){let e=this.calculateConnectionHealth(),t=(Date.now()-this.startTime)/1e3,n=t>0?this.requestCount/t:0,r=this.requestCount>0?this.errorCount/this.requestCount:0,i=this.connectionTimes.filter(e=>e<100).length,a=this.connectionTimes.length-i;return{...this.metrics,health:e,requestsPerSecond:n,errorRate:r,timeouts:this.timeoutCount,retries:this.retryCount,fastConnections:i,slowConnections:a,http2Info:this.http2Info}}calculateConnectionHealth(){let e=[],t=[],n=100;this.metrics.reuseRate<.3?(e.push(`Low connection reuse rate`),t.push(`Check if keep-alive headers are working`),n-=30):this.metrics.reuseRate<.7&&(e.push(`Moderate connection reuse rate`),t.push(`Consider adjusting keep-alive timeout`),n-=15);let r=this.requestCount>0?this.errorCount/this.requestCount:0;r>.1?(e.push(`High error rate`),t.push(`Check network stability and server configuration`),n-=25):r>.05&&(e.push(`Moderate error rate`),t.push(`Monitor network conditions`),n-=10),this.metrics.averageConnectionTime>1e3?(e.push(`Slow connection establishment`),t.push(`Check network latency and DNS resolution`),n-=20):this.metrics.averageConnectionTime>500&&(e.push(`Moderate connection latency`),t.push(`Consider connection warming`),n-=10);let i;return i=n>=80?`healthy`:n>=60?`degraded`:`poor`,{status:i,score:Math.max(0,n),issues:e,recommendations:t}}async warmupConnections(e){if(e.length===0)return;console.log(`Warming up connections to ${e.length} hosts...`);let t=e.map(async e=>{try{await this.request(e,{method:`HEAD`,timeout:5e3})}catch(t){console.warn(`Connection warmup failed for ${e}:`,t)}});await Promise.allSettled(t),console.log(`Connection warmup completed`)}reset(){this.connectionTimes=[],this.requestCount=0,this.connectionCount=0,this.errorCount=0,this.timeoutCount=0,this.retryCount=0,this.startTime=Date.now(),this.metrics={activeConnections:0,totalConnections:0,reuseRate:0,averageConnectionTime:0},this.http2Info=this.detectHttp2Support()}async close(){console.log(`Gracefully shutting down HTTP client...`),await new Promise(e=>setTimeout(e,100));let e=this.getDetailedMetrics();console.log(`Final connection metrics:`,{totalRequests:this.requestCount,connectionReuse:`${Math.round(e.reuseRate*100)}%`,averageConnectionTime:`${Math.round(e.averageConnectionTime)}ms`,health:e.health.status}),this.reset(),console.log(`HTTP client shutdown complete`)}},a=class{native;constructor(){this.native=new AbortController}get signal(){return this.native.signal}abort(e){this.native.abort(e)}};const o=()=>({create:()=>new a});async function s(e){try{let t=await e.arrayBuffer(),n=await crypto.subtle.digest(`SHA-256`,t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,`0`)).join(``)}catch(e){throw Error(`Failed to compute file checksum: ${e instanceof Error?e.message:`Unknown error`}`)}}function c(){return{computeChecksum:async e=>s(new Blob([e]))}}function l(e){return{input:e,size:e.size,slice:async(t,n)=>{let r=e.slice(t,n),i=r.size,a=n>=e.size;return{value:new Uint8Array(await r.arrayBuffer()),size:i,done:a}},close:()=>{}}}function u(){return{openFile:async(e,t)=>{if(e instanceof Blob){let t=l(e);return{input:t.input,size:t.size,slice:t.slice,close:t.close,name:t.input instanceof File?t.input.name:null,type:t.input instanceof File?t.input.type:null,lastModified:t.input instanceof File?t.input.lastModified:null}}throw Error(`source object may only be an instance of File, Blob in this environment`)}}}function d(){return{computeFingerprint:async(e,t)=>s(e)}}function f(){return{generate:()=>crypto.randomUUID()}}function p(){return{setTimeout:(e,t)=>globalThis.setTimeout(e,t),clearTimeout:e=>{globalThis.clearTimeout(e)},isBrowser:()=>typeof window<`u`,isOnline:()=>typeof navigator<`u`?navigator.onLine:!0,isFileLike:e=>e instanceof File,getFileName:e=>{if(e instanceof File)return e.name},getFileType:e=>{if(e instanceof File)return e.type},getFileSize:e=>{if(e instanceof File)return e.size},getFileLastModified:e=>{if(e instanceof File)return e.lastModified}}}function m(){let e=e=>{let t={};for(let n in localStorage)if(n.startsWith(e)){let e=localStorage.getItem(n);e&&(t[n]=e)}return t};return{async getItem(e){return localStorage.getItem(e)},async setItem(e,t){localStorage.setItem(e,t)},async removeItem(e){localStorage.removeItem(e)},async findAll(){return e(``)},async find(t){return e(t)}}}var h=class{CONNECTING=0;OPEN=1;CLOSING=2;CLOSED=3;readyState;onopen=null;onclose=null;onerror=null;onmessage=null;native;constructor(e){this.native=new WebSocket(e),this.readyState=this.native.readyState,this.native.onopen=()=>{this.readyState=this.native.readyState,this.onopen?.()},this.native.onclose=e=>{this.readyState=this.native.readyState;let t=e;this.onclose?.({code:t.code,reason:t.reason})},this.native.onerror=e=>{this.onerror?.({message:`WebSocket error`})},this.native.onmessage=e=>{let t=e;this.onmessage?.({data:t.data})}}send(e){this.native.send(e)}close(e,t){this.native.close(e,t)}};const g=()=>({create:e=>new h(e)});function _(e={}){let{connectionPooling:t,useLocalStorage:n=!0}=e,i=m(),a=f(),s=r(t),l=u(),h=g(),_=o(),v=c(),y=d();return{platform:p(),storage:i,idGeneration:a,httpClient:s,fileReader:l,websocket:h,abortController:_,checksumService:v,fingerprintService:y}}function v(r){let i=_({connectionPooling:r.connectionPooling});return n({...r,webSocketFactory:i.websocket,abortControllerFactory:i.abortController,platformService:i.platform,httpClient:i.httpClient,fileReader:i.fileReader,generateId:i.idGeneration,fingerprintService:i.fingerprintService,checksumService:i.checksumService,logger:t(!1,()=>{}),clientStorage:e(i.storage)})}function y(e){let t=e.length,n=e.filter(e=>e.status===`success`).length,r=e.filter(e=>e.status===`error`).length,i=e.reduce((e,t)=>e+t.totalBytes,0),a=e.reduce((e,t)=>e+t.bytesUploaded,0);return{totalFiles:t,completedFiles:n,failedFiles:r,totalBytes:i,uploadedBytes:a,totalProgress:i>0?a/i*100:0,allComplete:e.every(e=>e.status===`success`),hasErrors:e.some(e=>e.status===`error`)}}function b(e){if(e===0)return`0 Bytes`;let t=1024,n=[`Bytes`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Number.parseFloat((e/t**r).toFixed(2))} ${n[r]}`}function x(e){return`${Math.round(e)}%`}function S(e){let t=e.lastIndexOf(`.`);return t===-1?``:e.slice(t+1).toLowerCase()}function C(e){return e.type.startsWith(`image/`)}function w(e){return e.type.startsWith(`video/`)}function T(e){return t=>t.size>e?{valid:!1,error:`File size exceeds maximum of ${b(e)}`}:{valid:!0}}function E(e){return t=>{let n=t.type.toLowerCase(),r=S(t.name);return e.some(e=>{if(e.startsWith(`.`))return e.slice(1)===r;if(e.includes(`*`)){let t=e.replace(`*`,``);return n.startsWith(t)}return n===e})?{valid:!0}:{valid:!1,error:`File type not allowed. Allowed types: ${e.join(`, `)}`}}}function D(...e){return t=>{for(let n of e){let e=n(t);if(!e.valid)return e}return{valid:!0}}}function O(){return`upload-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}function k(e){return new Promise(t=>setTimeout(t,e))}function A(e,t=1e3,n=3e4){return Math.min(t*2**e,n)+Math.random()*1e3}function j(e,t=3,n=()=>!0){return async()=>{let r;for(let i=0;i<t;i++)try{return await e()}catch(e){if(r=e,i<t-1&&n(e)){await k(A(i));continue}break}throw r}}function M(e){return e instanceof Error?e.message.includes(`network`)||e.message.includes(`timeout`)||e.message.includes(`connection`)||e.message.includes(`ECONNREFUSED`)||e.message.includes(`ETIMEDOUT`):!1}function N(e){return e instanceof Error?e.name===`AbortError`||e.message.includes(`abort`):!1}function P(e){if(e===0)return`0 B/s`;let t=1024,n=[`B/s`,`KB/s`,`MB/s`,`GB/s`],r=Math.floor(Math.log(e)/Math.log(t));return`${parseFloat((e/t**r).toFixed(1))} ${n[r]}`}function F(e){if(e<1e3)return`${Math.round(e)}ms`;if(e<6e4)return`${Math.round(e/1e3)}s`;if(e<36e5){let t=Math.floor(e/6e4),n=Math.round(e%6e4/1e3);return n>0?`${t}m ${n}s`:`${t}m`}let t=Math.floor(e/36e5),n=Math.round(e%36e5/6e4);return n>0?`${t}h ${n}m`:`${t}h`}function I(e,t){return!t||t.length===0?!0:t.some(t=>{if(t.startsWith(`.`))return e.name.toLowerCase().endsWith(t.toLowerCase());if(t.endsWith(`/*`)){let n=t.slice(0,-2);return e.type.startsWith(n)}return e.type===t})}function L(e){return e.type.startsWith(`audio/`)}function R(e){return[`application/pdf`,`application/msword`,`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,`application/vnd.ms-excel`,`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,`application/vnd.ms-powerpoint`,`application/vnd.openxmlformats-officedocument.presentationml.presentation`,`text/plain`,`text/csv`,`application/rtf`].includes(e.type)}function z(e){return C(e)||w(e)||L(e)?URL.createObjectURL(e):null}function B(e){URL.revokeObjectURL(e)}function V(e,t){return t===0?0:Math.min(100,Math.max(0,Math.round(e/t*100)))}export{A as calculateBackoff,y as calculateMultiUploadStats,V as calculateProgress,D as composeValidators,u as createBrowserFileReaderService,z as createFilePreview,T as createFileSizeValidator,E as createFileTypeValidator,r as createHttpClient,j as createRetryWrapper,v as createUploadistaClient,k as delay,F as formatDuration,b as formatFileSize,x as formatProgress,P as formatSpeed,O as generateUploadId,S as getFileExtension,N as isAbortError,L as isAudioFile,R as isDocumentFile,C as isImageFile,M as isNetworkError,w as isVideoFile,B as revokeFilePreview,I as validateFileType};
2
+ //# sourceMappingURL=index.js.map