@wlindabla/file_uploader 1.0.0 → 2.0.1
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/README.md +54 -28
- package/dist/cjs/cache/index.d.ts +198 -0
- package/dist/cjs/cache/index.js +318 -0
- package/dist/cjs/cache/index.js.map +1 -0
- package/dist/cjs/core/index.d.ts +271 -0
- package/dist/cjs/core/index.js +762 -0
- package/dist/cjs/core/index.js.map +1 -0
- package/dist/cjs/events/chunk/index.d.ts +27 -0
- package/dist/cjs/events/chunk/index.js +70 -0
- package/dist/cjs/events/chunk/index.js.map +1 -0
- package/dist/cjs/events/complete/index.d.ts +64 -0
- package/dist/cjs/events/complete/index.js +152 -0
- package/dist/cjs/events/complete/index.js.map +1 -0
- package/dist/cjs/events/index.d.ts +95 -0
- package/dist/cjs/events/index.js +85 -0
- package/dist/cjs/events/index.js.map +1 -0
- package/dist/cjs/events/initialize/index.d.ts +45 -0
- package/dist/cjs/events/initialize/index.js +105 -0
- package/dist/cjs/events/initialize/index.js.map +1 -0
- package/dist/cjs/events/state/index.d.ts +67 -0
- package/dist/cjs/events/state/index.js +145 -0
- package/dist/cjs/events/state/index.js.map +1 -0
- package/dist/cjs/exceptions/index.d.ts +84 -0
- package/dist/{exceptions → cjs/exceptions}/index.js +38 -18
- package/dist/cjs/exceptions/index.js.map +1 -0
- package/dist/cjs/index.d.ts +14 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/subscribers/index.d.ts +34 -0
- package/dist/cjs/subscribers/index.js +187 -0
- package/dist/cjs/subscribers/index.js.map +1 -0
- package/dist/cjs/types/index.d.ts +110 -0
- package/dist/cjs/types/index.js +53 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/utils/index.d.ts +72 -0
- package/dist/cjs/utils/index.js +208 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/esm/cache/index.d.mts +198 -0
- package/dist/esm/cache/index.js +4 -0
- package/dist/{index.js.map → esm/cache/index.js.map} +1 -1
- package/dist/{events/initialize/index.js → esm/chunk-3JTTZCSQ.js} +25 -19
- package/dist/esm/chunk-3JTTZCSQ.js.map +1 -0
- package/dist/{events/state/index.js → esm/chunk-6225YMFE.js} +38 -20
- package/dist/esm/chunk-6225YMFE.js.map +1 -0
- package/dist/esm/chunk-7QVYU63E.js +6 -0
- package/dist/esm/chunk-7QVYU63E.js.map +1 -0
- package/dist/{events/complete/index.js → esm/chunk-BNMI7DW3.js} +25 -19
- package/dist/esm/chunk-BNMI7DW3.js.map +1 -0
- package/dist/{subscribers/index.js → esm/chunk-HYNJBWW5.js} +36 -34
- package/dist/esm/chunk-HYNJBWW5.js.map +1 -0
- package/dist/{events/index.js → esm/chunk-JDL3U4OX.js} +7 -37
- package/dist/esm/chunk-JDL3U4OX.js.map +1 -0
- package/dist/{events/chunk/index.js → esm/chunk-LD2DWZRJ.js} +14 -11
- package/dist/esm/chunk-LD2DWZRJ.js.map +1 -0
- package/dist/{utils/index.js → esm/chunk-MFYC4PBP.js} +15 -22
- package/dist/esm/chunk-MFYC4PBP.js.map +1 -0
- package/dist/esm/chunk-NXYS73I4.js +125 -0
- package/dist/esm/chunk-NXYS73I4.js.map +1 -0
- package/dist/{cache/index.js → esm/chunk-PFALORWQ.js} +10 -11
- package/dist/esm/chunk-PFALORWQ.js.map +1 -0
- package/dist/{core/index.js → esm/chunk-TONVXBLH.js} +239 -231
- package/dist/esm/chunk-TONVXBLH.js.map +1 -0
- package/dist/{types/index.js → esm/chunk-X757PBC5.js} +5 -7
- package/dist/esm/chunk-X757PBC5.js.map +1 -0
- package/dist/esm/core/index.d.mts +271 -0
- package/dist/esm/core/index.js +12 -0
- package/dist/esm/core/index.js.map +1 -0
- package/dist/esm/events/chunk/index.d.mts +27 -0
- package/dist/esm/events/chunk/index.js +4 -0
- package/dist/esm/events/chunk/index.js.map +1 -0
- package/dist/esm/events/complete/index.d.mts +64 -0
- package/dist/esm/events/complete/index.js +4 -0
- package/dist/esm/events/complete/index.js.map +1 -0
- package/dist/esm/events/index.d.mts +95 -0
- package/dist/esm/events/index.js +8 -0
- package/dist/esm/events/index.js.map +1 -0
- package/dist/esm/events/initialize/index.d.mts +45 -0
- package/dist/esm/events/initialize/index.js +4 -0
- package/dist/esm/events/initialize/index.js.map +1 -0
- package/dist/esm/events/state/index.d.mts +67 -0
- package/dist/esm/events/state/index.js +4 -0
- package/dist/esm/events/state/index.js.map +1 -0
- package/dist/esm/exceptions/index.d.mts +84 -0
- package/dist/esm/exceptions/index.js +4 -0
- package/dist/esm/exceptions/index.js.map +1 -0
- package/dist/esm/index.d.mts +14 -0
- package/dist/esm/index.js +14 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/subscribers/index.d.mts +34 -0
- package/dist/esm/subscribers/index.js +10 -0
- package/dist/esm/subscribers/index.js.map +1 -0
- package/dist/esm/types/index.d.mts +110 -0
- package/dist/esm/types/index.js +4 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/esm/utils/index.d.mts +72 -0
- package/dist/esm/utils/index.js +5 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/package.json +165 -14
- package/dist/cache/index.js.map +0 -1
- package/dist/core/index.js.map +0 -1
- package/dist/events/chunk/index.js.map +0 -1
- package/dist/events/complete/index.js.map +0 -1
- package/dist/events/index.js.map +0 -1
- package/dist/events/initialize/index.js.map +0 -1
- package/dist/events/state/index.js.map +0 -1
- package/dist/exceptions/index.js.map +0 -1
- package/dist/index.js +0 -49
- package/dist/subscribers/index.js.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -188,7 +188,7 @@ import {
|
|
|
188
188
|
UploadStateChangedEvent,
|
|
189
189
|
UploadProgressEvent,
|
|
190
190
|
UploadMediaCompleteEvent
|
|
191
|
-
} from '@wlindabla/file_uploader';
|
|
191
|
+
} from '@wlindabla/file_uploader/events';
|
|
192
192
|
|
|
193
193
|
import { BrowserEventDispatcher } from '@wlindabla/event_dispatcher';
|
|
194
194
|
|
|
@@ -319,8 +319,7 @@ The main class. Implements `ChunkedFileUploaderInterface`.
|
|
|
319
319
|
new ChunkedFileUploader(
|
|
320
320
|
uploadEventDispatcher: EventDispatcherInterface,
|
|
321
321
|
uploadResumeData: UploadResumeCacheInterface,
|
|
322
|
-
options: UploadOptions
|
|
323
|
-
logger?: LoggerInterface
|
|
322
|
+
options: UploadOptions
|
|
324
323
|
)
|
|
325
324
|
```
|
|
326
325
|
|
|
@@ -329,7 +328,6 @@ new ChunkedFileUploader(
|
|
|
329
328
|
| `uploadEventDispatcher` | `EventDispatcherInterface` | ✅ | Dispatcher for upload lifecycle events |
|
|
330
329
|
| `uploadResumeData` | `UploadResumeCacheInterface` | ✅ | Cache implementation for resumable uploads |
|
|
331
330
|
| `options` | `UploadOptions` | ✅ | Upload configuration options |
|
|
332
|
-
| `logger` | `LoggerInterface` | ❌ | Custom logger (default: `NoopLogger`) |
|
|
333
331
|
|
|
334
332
|
#### Methods
|
|
335
333
|
|
|
@@ -1011,7 +1009,7 @@ You are responsible for adding them to your dispatcher instance.
|
|
|
1011
1009
|
import {
|
|
1012
1010
|
InitializeUploadSubscriber,
|
|
1013
1011
|
FinalizeUploadSubscriber
|
|
1014
|
-
} from '@wlindabla/file_uploader';
|
|
1012
|
+
} from '@wlindabla/file_uploader/subscribers';
|
|
1015
1013
|
|
|
1016
1014
|
import { BrowserEventDispatcher } from '@wlindabla/event_dispatcher';
|
|
1017
1015
|
|
|
@@ -1031,7 +1029,7 @@ dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));
|
|
|
1031
1029
|
import {
|
|
1032
1030
|
InitializeUploadSubscriber,
|
|
1033
1031
|
FinalizeUploadSubscriber
|
|
1034
|
-
} from '@wlindabla/file_uploader';
|
|
1032
|
+
} from '@wlindabla/file_uploader/subscribers';
|
|
1035
1033
|
|
|
1036
1034
|
import { NodeEventDispatcher } from '@wlindabla/event_dispatcher';
|
|
1037
1035
|
|
|
@@ -1054,15 +1052,23 @@ dispatcher.addSubscriber(new FinalizeUploadSubscriber(dispatcher));
|
|
|
1054
1052
|
|
|
1055
1053
|
```typescript
|
|
1056
1054
|
import {
|
|
1057
|
-
ChunkedFileUploader,
|
|
1058
|
-
InitializeUploadSubscriber,
|
|
1059
|
-
FinalizeUploadSubscriber,
|
|
1060
1055
|
HttpFileUploaderEvents,
|
|
1061
1056
|
InitializeUploadSuccessEvent,
|
|
1062
1057
|
InitializeUploadFailureEvent,
|
|
1063
1058
|
FinalizeUploadFailureEvent,
|
|
1064
1059
|
UploadMediaCompleteEvent
|
|
1065
|
-
} from '@wlindabla/file_uploader';
|
|
1060
|
+
} from '@wlindabla/file_uploader/events';
|
|
1061
|
+
|
|
1062
|
+
import {
|
|
1063
|
+
InitializeUploadSubscriber,
|
|
1064
|
+
FinalizeUploadSubscriber
|
|
1065
|
+
} from
|
|
1066
|
+
'@wlindabla/file_uploader/subscribers'
|
|
1067
|
+
|
|
1068
|
+
import {
|
|
1069
|
+
ChunkedFileUploader
|
|
1070
|
+
} from
|
|
1071
|
+
'@wlindabla/file_uploader/core'
|
|
1066
1072
|
|
|
1067
1073
|
import { BrowserEventDispatcher } from '@wlindabla/event_dispatcher';
|
|
1068
1074
|
|
|
@@ -1122,13 +1128,23 @@ await uploader
|
|
|
1122
1128
|
|
|
1123
1129
|
```typescript
|
|
1124
1130
|
import {
|
|
1125
|
-
ChunkedFileUploader,
|
|
1126
|
-
InitializeUploadSubscriber,
|
|
1127
|
-
FinalizeUploadSubscriber,
|
|
1128
1131
|
HttpFileUploaderEvents,
|
|
1129
1132
|
InitializeUploadSuccessEvent,
|
|
1130
|
-
|
|
1131
|
-
|
|
1133
|
+
InitializeUploadFailureEvent,
|
|
1134
|
+
FinalizeUploadFailureEvent,
|
|
1135
|
+
UploadMediaCompleteEvent
|
|
1136
|
+
} from '@wlindabla/file_uploader/events';
|
|
1137
|
+
|
|
1138
|
+
import {
|
|
1139
|
+
InitializeUploadSubscriber,
|
|
1140
|
+
FinalizeUploadSubscriber
|
|
1141
|
+
} from
|
|
1142
|
+
'@wlindabla/file_uploader/subscribers'
|
|
1143
|
+
|
|
1144
|
+
import {
|
|
1145
|
+
ChunkedFileUploader
|
|
1146
|
+
} from
|
|
1147
|
+
'@wlindabla/file_uploader/core'
|
|
1132
1148
|
|
|
1133
1149
|
import { NodeEventDispatcher } from '@wlindabla/event_dispatcher';
|
|
1134
1150
|
|
|
@@ -1740,8 +1756,7 @@ class MonitoringLogger implements LoggerInterface {
|
|
|
1740
1756
|
const uploader = new ChunkedFileUploader(
|
|
1741
1757
|
dispatcher,
|
|
1742
1758
|
cache,
|
|
1743
|
-
options
|
|
1744
|
-
new MonitoringLogger()
|
|
1759
|
+
options
|
|
1745
1760
|
);
|
|
1746
1761
|
```
|
|
1747
1762
|
|
|
@@ -1762,14 +1777,17 @@ Complete browser example with progress bar and UI controls.
|
|
|
1762
1777
|
|
|
1763
1778
|
```typescript
|
|
1764
1779
|
import {
|
|
1765
|
-
ChunkedFileUploader,
|
|
1766
1780
|
HttpFileUploaderEvents,
|
|
1767
1781
|
UploadProgressEvent,
|
|
1768
1782
|
UploadStateChangedEvent,
|
|
1769
1783
|
UploadMediaCompleteEvent,
|
|
1770
1784
|
UploadCancelledEvent,
|
|
1771
|
-
|
|
1772
|
-
|
|
1785
|
+
} from '@wlindabla/file_uploader/events';
|
|
1786
|
+
|
|
1787
|
+
import {
|
|
1788
|
+
ChunkedFileUploader
|
|
1789
|
+
} from
|
|
1790
|
+
'@wlindabla/file_uploader/core'
|
|
1773
1791
|
|
|
1774
1792
|
import { BrowserEventDispatcher } from '@wlindabla/event_dispatcher';
|
|
1775
1793
|
|
|
@@ -1848,8 +1866,7 @@ const uploader = new ChunkedFileUploader(
|
|
|
1848
1866
|
maxRetries: 3,
|
|
1849
1867
|
autoSave: true,
|
|
1850
1868
|
timeout: 60000
|
|
1851
|
-
}
|
|
1852
|
-
new ConsoleLogger()
|
|
1869
|
+
}
|
|
1853
1870
|
);
|
|
1854
1871
|
|
|
1855
1872
|
// Wire up DOM
|
|
@@ -1891,8 +1908,11 @@ import {
|
|
|
1891
1908
|
HttpFileUploaderEvents,
|
|
1892
1909
|
UploadProgressEvent,
|
|
1893
1910
|
UploadMediaCompleteEvent,
|
|
1894
|
-
|
|
1895
|
-
|
|
1911
|
+
} from '@wlindabla/file_uploader/events';
|
|
1912
|
+
|
|
1913
|
+
import {
|
|
1914
|
+
ChunkedFileUploader,
|
|
1915
|
+
} from '@wlindabla/file_uploader/core';
|
|
1896
1916
|
|
|
1897
1917
|
import { NodeEventDispatcher } from '@wlindabla/event_dispatcher';
|
|
1898
1918
|
import fs from 'fs';
|
|
@@ -2056,13 +2076,19 @@ uploadFile('/path/to/large-video.mp4').catch(console.error);
|
|
|
2056
2076
|
|
|
2057
2077
|
```typescript
|
|
2058
2078
|
import {
|
|
2059
|
-
ChunkedFileUploader,
|
|
2060
|
-
HttpFileUploaderEvents,
|
|
2061
|
-
InitializeUploadFailureEvent,
|
|
2062
2079
|
FileUploadChunkError,
|
|
2063
2080
|
InitializeUploadFailureException,
|
|
2064
2081
|
UploadCancelledException
|
|
2065
|
-
} from '@wlindabla/file_uploader';
|
|
2082
|
+
} from '@wlindabla/file_uploader/exceptions';
|
|
2083
|
+
|
|
2084
|
+
import {
|
|
2085
|
+
HttpFileUploaderEvents,
|
|
2086
|
+
InitializeUploadFailureEvent
|
|
2087
|
+
} from '@wlindabla/file_uploader/events';
|
|
2088
|
+
|
|
2089
|
+
import {
|
|
2090
|
+
ChunkedFileUploader
|
|
2091
|
+
} from '@wlindabla/file_uploader/core';
|
|
2066
2092
|
|
|
2067
2093
|
// Listen to granular error events
|
|
2068
2094
|
dispatcher.addListener(
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { ResumeData } from '../types/index.js';
|
|
2
|
+
import '@wlindabla/http_client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Interface for caching upload resume data.
|
|
6
|
+
*
|
|
7
|
+
* This interface extends the base cache functionality to specifically
|
|
8
|
+
* handle resume data for file uploads, allowing uploads to be paused
|
|
9
|
+
* and resumed across browser sessions.
|
|
10
|
+
*
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const cache: UploadResumeCacheInterface = new LocalStorageUploadResumeCache();
|
|
15
|
+
*
|
|
16
|
+
* // Save progress
|
|
17
|
+
* await cache.setItem('video.mp4', {
|
|
18
|
+
* uploadedChunks: 45,
|
|
19
|
+
* totalChunks: 100,
|
|
20
|
+
* lastBytePosition: 47185920
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // Resume later
|
|
24
|
+
* const data = await cache.getItem('video.mp4');
|
|
25
|
+
* console.log(`Resume from chunk ${data.uploadedChunks}`);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
interface UploadResumeCacheInterface {
|
|
29
|
+
/**
|
|
30
|
+
* Retrieves cached resume data for a specific upload.
|
|
31
|
+
*
|
|
32
|
+
* @param key - Unique identifier for the upload (typically filename or file hash)
|
|
33
|
+
* @returns Promise resolving to the cached resume data
|
|
34
|
+
* @throws {Error} If the key doesn't exist or data is corrupted
|
|
35
|
+
*/
|
|
36
|
+
getItem(key: string): Promise<ResumeData>;
|
|
37
|
+
/**
|
|
38
|
+
* Stores resume data for an upload session.
|
|
39
|
+
*
|
|
40
|
+
* @param key - Unique identifier for the upload
|
|
41
|
+
* @param data - Resume data containing upload progress information
|
|
42
|
+
* @returns Promise that resolves when data is successfully cached
|
|
43
|
+
* @throws {Error} If storage quota is exceeded or data is invalid
|
|
44
|
+
*/
|
|
45
|
+
setItem(key: string, data: ResumeData): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Default adapter for caching resume data during file uploads.
|
|
49
|
+
*
|
|
50
|
+
* Implements an in-memory storage strategy with secure serialization,
|
|
51
|
+
* strict data validation, and comprehensive error handling.
|
|
52
|
+
*
|
|
53
|
+
* This implementation serves as a foundation for specialized adapters
|
|
54
|
+
* (localStorage, IndexedDB, sessionStorage, etc.).
|
|
55
|
+
*
|
|
56
|
+
* @implements {UploadResumeCacheInterface}
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const adapter = new DefaultUploadResumeCacheAdapter();
|
|
61
|
+
*
|
|
62
|
+
* // Save resume data
|
|
63
|
+
* await adapter.setItem('upload-123', {
|
|
64
|
+
* fileId: 'file-abc',
|
|
65
|
+
* fileName: 'document.pdf',
|
|
66
|
+
* fileSize: 5242880,
|
|
67
|
+
* uploadedChunks: 12,
|
|
68
|
+
* lastChunkIndex: 11,
|
|
69
|
+
* lastBytePosition: 1258291,
|
|
70
|
+
* chunkSize: 1048576
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* // Retrieve and resume
|
|
74
|
+
* const resumeData = await adapter.getItem('upload-123');
|
|
75
|
+
* console.log(`Resume from chunk ${resumeData.uploadedChunks}`);
|
|
76
|
+
*
|
|
77
|
+
* // Remove specific item
|
|
78
|
+
* await adapter.removeItem('upload-123');
|
|
79
|
+
*
|
|
80
|
+
* // Clear all cache
|
|
81
|
+
* await adapter.clear();
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare class DefaultUploadResumeCacheAdapter implements UploadResumeCacheInterface {
|
|
85
|
+
private cache;
|
|
86
|
+
private readonly maxCacheSize;
|
|
87
|
+
constructor();
|
|
88
|
+
/**
|
|
89
|
+
* Validates that the runtime environment is appropriate.
|
|
90
|
+
*
|
|
91
|
+
* @private
|
|
92
|
+
* @throws {UploadCacheError} If the environment is incompatible
|
|
93
|
+
*/
|
|
94
|
+
private validateEnvironment;
|
|
95
|
+
/**
|
|
96
|
+
* Validates resume data according to strict criteria.
|
|
97
|
+
*
|
|
98
|
+
* @private
|
|
99
|
+
* @param data - The data to validate
|
|
100
|
+
* @throws {UploadCacheError} If the data is invalid
|
|
101
|
+
*/
|
|
102
|
+
private validateResumeData;
|
|
103
|
+
/**
|
|
104
|
+
* Retrieves resume data for a specific upload.
|
|
105
|
+
*
|
|
106
|
+
* @param key - Unique identifier for the upload
|
|
107
|
+
* @returns Promise resolved with the resume data
|
|
108
|
+
* @throws {UploadCacheError} If the key does not exist or data is corrupted
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* try {
|
|
113
|
+
* const data = await adapter.getItem('upload-123');
|
|
114
|
+
* console.log(`${data.uploadedChunks}/${Math.ceil(data.fileSize / data.chunkSize)} chunks`);
|
|
115
|
+
* } catch (error) {
|
|
116
|
+
* console.error('Failed to retrieve data:', error.message);
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
getItem(key: string): Promise<ResumeData>;
|
|
121
|
+
/**
|
|
122
|
+
* Stores resume data for an upload session.
|
|
123
|
+
*
|
|
124
|
+
* @param key - Unique identifier for the upload
|
|
125
|
+
* @param data - Resume data containing upload progress information
|
|
126
|
+
* @returns Promise resolved when data is successfully cached
|
|
127
|
+
* @throws {UploadCacheError} If quota is exceeded or data is invalid
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* try {
|
|
132
|
+
* await adapter.setItem('upload-123', {
|
|
133
|
+
* fileId: 'file-abc',
|
|
134
|
+
* fileName: 'video.mp4',
|
|
135
|
+
* fileSize: 10737418240,
|
|
136
|
+
* uploadedChunks: 45,
|
|
137
|
+
* lastChunkIndex: 44,
|
|
138
|
+
* lastBytePosition: 47185920,
|
|
139
|
+
* chunkSize: 1048576
|
|
140
|
+
* });
|
|
141
|
+
* console.log('Data successfully saved');
|
|
142
|
+
* } catch (error) {
|
|
143
|
+
* console.error('Storage error:', error.message);
|
|
144
|
+
* }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
setItem(key: string, data: ResumeData): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Removes resume data for a specific upload.
|
|
150
|
+
*
|
|
151
|
+
* @param key - Unique identifier for the upload
|
|
152
|
+
* @returns Promise resolved after removal
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* await adapter.removeItem('upload-123');
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
removeItem(key: string): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Clears all cached resume data.
|
|
162
|
+
*
|
|
163
|
+
* @returns Promise resolved after complete cleanup
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* await adapter.clear();
|
|
168
|
+
* console.log('Cache cleared');
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
clear(): Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* Returns the number of entries currently in cache.
|
|
174
|
+
*
|
|
175
|
+
* @returns Number of cache entries
|
|
176
|
+
*/
|
|
177
|
+
get size(): number;
|
|
178
|
+
/**
|
|
179
|
+
* Returns cache usage as a percentage.
|
|
180
|
+
*
|
|
181
|
+
* @returns Usage percentage (0-100)
|
|
182
|
+
*/
|
|
183
|
+
get usage(): number;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Custom error for upload cache operations.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```typescript
|
|
190
|
+
* throw new UploadCacheError('Resume data not found', 'NOT_FOUND');
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
declare class UploadCacheError extends Error {
|
|
194
|
+
readonly code: string;
|
|
195
|
+
constructor(message: string, code: string);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export { DefaultUploadResumeCacheAdapter, UploadCacheError, type UploadResumeCacheInterface };
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var cache_exports = {};
|
|
21
|
+
__export(cache_exports, {
|
|
22
|
+
DefaultUploadResumeCacheAdapter: () => DefaultUploadResumeCacheAdapter,
|
|
23
|
+
UploadCacheError: () => UploadCacheError
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(cache_exports);
|
|
26
|
+
class DefaultUploadResumeCacheAdapter {
|
|
27
|
+
static {
|
|
28
|
+
__name(this, "DefaultUploadResumeCacheAdapter");
|
|
29
|
+
}
|
|
30
|
+
cache = /* @__PURE__ */ new Map();
|
|
31
|
+
maxCacheSize = 100;
|
|
32
|
+
constructor() {
|
|
33
|
+
this.validateEnvironment();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Validates that the runtime environment is appropriate.
|
|
37
|
+
*
|
|
38
|
+
* @private
|
|
39
|
+
* @throws {UploadCacheError} If the environment is incompatible
|
|
40
|
+
*/
|
|
41
|
+
validateEnvironment() {
|
|
42
|
+
if (typeof window === "undefined") {
|
|
43
|
+
console.warn(
|
|
44
|
+
"[UploadResumeCacheAdapter] Server-side execution detected. Consider a server-compatible adapter for persistent storage."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validates resume data according to strict criteria.
|
|
50
|
+
*
|
|
51
|
+
* @private
|
|
52
|
+
* @param data - The data to validate
|
|
53
|
+
* @throws {UploadCacheError} If the data is invalid
|
|
54
|
+
*/
|
|
55
|
+
validateResumeData(data) {
|
|
56
|
+
if (!data || typeof data !== "object") {
|
|
57
|
+
throw new UploadCacheError(
|
|
58
|
+
"Resume data must be a valid object",
|
|
59
|
+
"INVALID_DATA"
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const requiredFields = [
|
|
63
|
+
"fileId",
|
|
64
|
+
"fileName",
|
|
65
|
+
"fileSize",
|
|
66
|
+
"uploadedChunks",
|
|
67
|
+
"lastChunkIndex",
|
|
68
|
+
"lastBytePosition",
|
|
69
|
+
"chunkSize"
|
|
70
|
+
];
|
|
71
|
+
for (const field of requiredFields) {
|
|
72
|
+
if (!(field in data)) {
|
|
73
|
+
throw new UploadCacheError(
|
|
74
|
+
`Required field '${field}' is missing`,
|
|
75
|
+
"MISSING_FIELD"
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (typeof data.fileId !== "string" || !data.fileId.trim()) {
|
|
80
|
+
throw new UploadCacheError(
|
|
81
|
+
"fileId must be a non-empty string",
|
|
82
|
+
"INVALID_FILE_ID"
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (typeof data.fileName !== "string" || !data.fileName.trim()) {
|
|
86
|
+
throw new UploadCacheError(
|
|
87
|
+
"fileName must be a non-empty string",
|
|
88
|
+
"INVALID_FILE_NAME"
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (!Number.isFinite(data.fileSize) || data.fileSize <= 0) {
|
|
92
|
+
throw new UploadCacheError(
|
|
93
|
+
"fileSize must be a positive number",
|
|
94
|
+
"INVALID_FILE_SIZE"
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (!Number.isFinite(data.chunkSize) || data.chunkSize <= 0) {
|
|
98
|
+
throw new UploadCacheError(
|
|
99
|
+
"chunkSize must be a positive number",
|
|
100
|
+
"INVALID_CHUNK_SIZE"
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
if (!Number.isInteger(data.uploadedChunks) || data.uploadedChunks < 0) {
|
|
104
|
+
throw new UploadCacheError(
|
|
105
|
+
"uploadedChunks must be a non-negative integer",
|
|
106
|
+
"INVALID_UPLOADED_CHUNKS"
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (!Number.isInteger(data.lastChunkIndex) || data.lastChunkIndex < -1) {
|
|
110
|
+
throw new UploadCacheError(
|
|
111
|
+
"lastChunkIndex must be an integer >= -1",
|
|
112
|
+
"INVALID_LAST_CHUNK_INDEX"
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (!Number.isFinite(data.lastBytePosition) || data.lastBytePosition < 0) {
|
|
116
|
+
throw new UploadCacheError(
|
|
117
|
+
"lastBytePosition must be a non-negative number",
|
|
118
|
+
"INVALID_BYTE_POSITION"
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
if (data.uploadedChunks > 0 && data.lastBytePosition === 0) {
|
|
122
|
+
throw new UploadCacheError(
|
|
123
|
+
"lastBytePosition cannot be 0 if chunks have been uploaded",
|
|
124
|
+
"INCONSISTENT_DATA"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const expectedMaxChunks = Math.ceil(data.fileSize / data.chunkSize);
|
|
128
|
+
if (data.uploadedChunks > expectedMaxChunks) {
|
|
129
|
+
throw new UploadCacheError(
|
|
130
|
+
`uploadedChunks (${data.uploadedChunks}) exceeds maximum expected (${expectedMaxChunks})`,
|
|
131
|
+
"INCONSISTENT_DATA"
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Retrieves resume data for a specific upload.
|
|
137
|
+
*
|
|
138
|
+
* @param key - Unique identifier for the upload
|
|
139
|
+
* @returns Promise resolved with the resume data
|
|
140
|
+
* @throws {UploadCacheError} If the key does not exist or data is corrupted
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* try {
|
|
145
|
+
* const data = await adapter.getItem('upload-123');
|
|
146
|
+
* console.log(`${data.uploadedChunks}/${Math.ceil(data.fileSize / data.chunkSize)} chunks`);
|
|
147
|
+
* } catch (error) {
|
|
148
|
+
* console.error('Failed to retrieve data:', error.message);
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
async getItem(key) {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
try {
|
|
155
|
+
if (!key || typeof key !== "string") {
|
|
156
|
+
reject(new UploadCacheError(
|
|
157
|
+
"Key must be a non-empty string",
|
|
158
|
+
"INVALID_KEY"
|
|
159
|
+
));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const data = this.cache.get(key);
|
|
163
|
+
if (!data) {
|
|
164
|
+
reject(new UploadCacheError(
|
|
165
|
+
`Resume data for key '${key}' was not found`,
|
|
166
|
+
"NOT_FOUND"
|
|
167
|
+
));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
resolve(JSON.parse(JSON.stringify(data)));
|
|
171
|
+
} catch (error) {
|
|
172
|
+
reject(new UploadCacheError(
|
|
173
|
+
`Error retrieving data: ${error instanceof Error ? error.message : String(error)}`,
|
|
174
|
+
"RETRIEVAL_ERROR"
|
|
175
|
+
));
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Stores resume data for an upload session.
|
|
181
|
+
*
|
|
182
|
+
* @param key - Unique identifier for the upload
|
|
183
|
+
* @param data - Resume data containing upload progress information
|
|
184
|
+
* @returns Promise resolved when data is successfully cached
|
|
185
|
+
* @throws {UploadCacheError} If quota is exceeded or data is invalid
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* try {
|
|
190
|
+
* await adapter.setItem('upload-123', {
|
|
191
|
+
* fileId: 'file-abc',
|
|
192
|
+
* fileName: 'video.mp4',
|
|
193
|
+
* fileSize: 10737418240,
|
|
194
|
+
* uploadedChunks: 45,
|
|
195
|
+
* lastChunkIndex: 44,
|
|
196
|
+
* lastBytePosition: 47185920,
|
|
197
|
+
* chunkSize: 1048576
|
|
198
|
+
* });
|
|
199
|
+
* console.log('Data successfully saved');
|
|
200
|
+
* } catch (error) {
|
|
201
|
+
* console.error('Storage error:', error.message);
|
|
202
|
+
* }
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
async setItem(key, data) {
|
|
206
|
+
return new Promise((resolve, reject) => {
|
|
207
|
+
try {
|
|
208
|
+
if (!key || typeof key !== "string") {
|
|
209
|
+
reject(new UploadCacheError(
|
|
210
|
+
"Key must be a non-empty string",
|
|
211
|
+
"INVALID_KEY"
|
|
212
|
+
));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
this.validateResumeData(data);
|
|
216
|
+
if (this.cache.size >= this.maxCacheSize && !this.cache.has(key)) {
|
|
217
|
+
reject(new UploadCacheError(
|
|
218
|
+
`Cache limit (${this.maxCacheSize} entries) has been reached. Remove obsolete entries or use an adapter with persistent storage.`,
|
|
219
|
+
"CACHE_LIMIT_EXCEEDED"
|
|
220
|
+
));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
this.cache.set(key, JSON.parse(JSON.stringify(data)));
|
|
224
|
+
resolve();
|
|
225
|
+
} catch (error) {
|
|
226
|
+
if (error instanceof UploadCacheError) {
|
|
227
|
+
reject(error);
|
|
228
|
+
} else {
|
|
229
|
+
reject(new UploadCacheError(
|
|
230
|
+
`Error storing data: ${error instanceof Error ? error.message : String(error)}`,
|
|
231
|
+
"STORAGE_ERROR"
|
|
232
|
+
));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Removes resume data for a specific upload.
|
|
239
|
+
*
|
|
240
|
+
* @param key - Unique identifier for the upload
|
|
241
|
+
* @returns Promise resolved after removal
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* await adapter.removeItem('upload-123');
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
async removeItem(key) {
|
|
249
|
+
return new Promise((resolve, reject) => {
|
|
250
|
+
try {
|
|
251
|
+
if (!key || typeof key !== "string") {
|
|
252
|
+
reject(new UploadCacheError(
|
|
253
|
+
"Key must be a non-empty string",
|
|
254
|
+
"INVALID_KEY"
|
|
255
|
+
));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this.cache.delete(key);
|
|
259
|
+
resolve();
|
|
260
|
+
} catch (error) {
|
|
261
|
+
reject(new UploadCacheError(
|
|
262
|
+
`Error removing data: ${error instanceof Error ? error.message : String(error)}`,
|
|
263
|
+
"DELETION_ERROR"
|
|
264
|
+
));
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Clears all cached resume data.
|
|
270
|
+
*
|
|
271
|
+
* @returns Promise resolved after complete cleanup
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* await adapter.clear();
|
|
276
|
+
* console.log('Cache cleared');
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
async clear() {
|
|
280
|
+
return new Promise((resolve) => {
|
|
281
|
+
this.cache.clear();
|
|
282
|
+
resolve();
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Returns the number of entries currently in cache.
|
|
287
|
+
*
|
|
288
|
+
* @returns Number of cache entries
|
|
289
|
+
*/
|
|
290
|
+
get size() {
|
|
291
|
+
return this.cache.size;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Returns cache usage as a percentage.
|
|
295
|
+
*
|
|
296
|
+
* @returns Usage percentage (0-100)
|
|
297
|
+
*/
|
|
298
|
+
get usage() {
|
|
299
|
+
return this.cache.size / this.maxCacheSize * 100;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
class UploadCacheError extends Error {
|
|
303
|
+
constructor(message, code) {
|
|
304
|
+
super(message);
|
|
305
|
+
this.code = code;
|
|
306
|
+
this.name = "UploadCacheError";
|
|
307
|
+
}
|
|
308
|
+
code;
|
|
309
|
+
static {
|
|
310
|
+
__name(this, "UploadCacheError");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
314
|
+
0 && (module.exports = {
|
|
315
|
+
DefaultUploadResumeCacheAdapter,
|
|
316
|
+
UploadCacheError
|
|
317
|
+
});
|
|
318
|
+
//# sourceMappingURL=index.js.map
|