@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.
- package/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-check.log +130 -0
- package/AUTO_CAPABILITIES.md +98 -0
- package/FRAMEWORK_INTEGRATION.md +407 -0
- package/LICENSE +21 -0
- package/README.md +795 -0
- package/SMART_CHUNKING.md +140 -0
- package/dist/client/create-uploadista-client.d.ts +182 -0
- package/dist/client/create-uploadista-client.d.ts.map +1 -0
- package/dist/client/create-uploadista-client.js +76 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +1 -0
- package/dist/framework-utils.d.ts +201 -0
- package/dist/framework-utils.d.ts.map +1 -0
- package/dist/framework-utils.js +282 -0
- package/dist/http-client.d.ts +44 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +489 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/services/abort-controller-factory.d.ts +30 -0
- package/dist/services/abort-controller-factory.d.ts.map +1 -0
- package/dist/services/abort-controller-factory.js +98 -0
- package/dist/services/checksum-service.d.ts +30 -0
- package/dist/services/checksum-service.d.ts.map +1 -0
- package/dist/services/checksum-service.js +44 -0
- package/dist/services/create-browser-services.d.ts +36 -0
- package/dist/services/create-browser-services.d.ts.map +1 -0
- package/dist/services/create-browser-services.js +56 -0
- package/dist/services/file-reader.d.ts +91 -0
- package/dist/services/file-reader.d.ts.map +1 -0
- package/dist/services/file-reader.js +251 -0
- package/dist/services/fingerprint-service.d.ts +41 -0
- package/dist/services/fingerprint-service.d.ts.map +1 -0
- package/dist/services/fingerprint-service.js +64 -0
- package/dist/services/id-generation/id-generation.d.ts +40 -0
- package/dist/services/id-generation/id-generation.d.ts.map +1 -0
- package/dist/services/id-generation/id-generation.js +58 -0
- package/dist/services/platform-service.d.ts +38 -0
- package/dist/services/platform-service.d.ts.map +1 -0
- package/dist/services/platform-service.js +221 -0
- package/dist/services/storage/local-storage-service.d.ts +55 -0
- package/dist/services/storage/local-storage-service.d.ts.map +1 -0
- package/dist/services/storage/local-storage-service.js +178 -0
- package/dist/services/storage/session-storage-service.d.ts +55 -0
- package/dist/services/storage/session-storage-service.d.ts.map +1 -0
- package/dist/services/storage/session-storage-service.js +179 -0
- package/dist/services/websocket-factory.d.ts +46 -0
- package/dist/services/websocket-factory.d.ts.map +1 -0
- package/dist/services/websocket-factory.js +196 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/upload-input.d.ts +26 -0
- package/dist/types/upload-input.d.ts.map +1 -0
- package/dist/types/upload-input.js +1 -0
- package/dist/utils/hash-util.d.ts +60 -0
- package/dist/utils/hash-util.d.ts.map +1 -0
- package/dist/utils/hash-util.js +75 -0
- package/package.json +32 -0
- package/src/client/create-uploadista-client.ts +150 -0
- package/src/client/index.ts +1 -0
- package/src/framework-utils.ts +446 -0
- package/src/http-client.ts +546 -0
- package/src/index.ts +8 -0
- package/src/services/abort-controller-factory.ts +108 -0
- package/src/services/checksum-service.ts +46 -0
- package/src/services/create-browser-services.ts +81 -0
- package/src/services/file-reader.ts +344 -0
- package/src/services/fingerprint-service.ts +67 -0
- package/src/services/id-generation/id-generation.ts +60 -0
- package/src/services/platform-service.ts +231 -0
- package/src/services/storage/local-storage-service.ts +187 -0
- package/src/services/storage/session-storage-service.ts +188 -0
- package/src/services/websocket-factory.ts +212 -0
- package/src/types/index.ts +1 -0
- package/src/types/upload-input.ts +25 -0
- package/src/utils/hash-util.ts +79 -0
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import type { PlatformService, Timeout } from "@uploadista/client-core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a browser-specific platform service that provides environment capabilities.
|
|
5
|
+
*
|
|
6
|
+
* This service abstracts platform-specific functionality and provides a consistent
|
|
7
|
+
* interface for the Uploadista client to interact with browser APIs. It handles:
|
|
8
|
+
* - Timer management (setTimeout/clearTimeout)
|
|
9
|
+
* - Environment detection (browser vs. Node.js)
|
|
10
|
+
* - Network connectivity status
|
|
11
|
+
* - File object detection and metadata extraction
|
|
12
|
+
*
|
|
13
|
+
* This abstraction allows the core upload logic to remain platform-agnostic while
|
|
14
|
+
* still accessing browser-specific features when needed.
|
|
15
|
+
*
|
|
16
|
+
* @returns A PlatformService configured for browser environments
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { createBrowserPlatformService } from '@uploadista/client-browser';
|
|
21
|
+
*
|
|
22
|
+
* const platform = createBrowserPlatformService();
|
|
23
|
+
*
|
|
24
|
+
* // Check if running in browser
|
|
25
|
+
* console.log('Is browser:', platform.isBrowser()); // true
|
|
26
|
+
*
|
|
27
|
+
* // Check network status
|
|
28
|
+
* console.log('Is online:', platform.isOnline()); // true or false
|
|
29
|
+
*
|
|
30
|
+
* // Extract file metadata
|
|
31
|
+
* const fileInput = document.querySelector('input[type="file"]');
|
|
32
|
+
* const file = fileInput.files[0];
|
|
33
|
+
* console.log('File name:', platform.getFileName(file));
|
|
34
|
+
* console.log('File type:', platform.getFileType(file));
|
|
35
|
+
* console.log('File size:', platform.getFileSize(file));
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function createBrowserPlatformService(): PlatformService {
|
|
39
|
+
return {
|
|
40
|
+
/**
|
|
41
|
+
* Schedules a function to be executed after a specified delay.
|
|
42
|
+
*
|
|
43
|
+
* Wraps the browser's native `setTimeout` function.
|
|
44
|
+
*
|
|
45
|
+
* @param callback - Function to execute after the delay
|
|
46
|
+
* @param ms - Delay in milliseconds before executing the callback
|
|
47
|
+
* @returns A timeout ID that can be passed to clearTimeout
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const timeoutId = platform.setTimeout(() => {
|
|
52
|
+
* console.log('Executed after 1 second');
|
|
53
|
+
* }, 1000);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
setTimeout: (callback: () => void, ms: number | undefined) => {
|
|
57
|
+
return globalThis.setTimeout(callback, ms);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Cancels a timeout previously scheduled with setTimeout.
|
|
62
|
+
*
|
|
63
|
+
* Wraps the browser's native `clearTimeout` function.
|
|
64
|
+
*
|
|
65
|
+
* @param id - The timeout ID returned by setTimeout
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const timeoutId = platform.setTimeout(() => { }, 1000);
|
|
70
|
+
* platform.clearTimeout(timeoutId); // Cancel the timeout
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
clearTimeout: (id: Timeout) => {
|
|
74
|
+
globalThis.clearTimeout(id as number);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Checks if the code is running in a browser environment.
|
|
79
|
+
*
|
|
80
|
+
* Detects browser by checking for the existence of the `window` object.
|
|
81
|
+
* This is useful for conditional logic that should only run in browsers.
|
|
82
|
+
*
|
|
83
|
+
* @returns `true` if running in a browser, `false` otherwise
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* if (platform.isBrowser()) {
|
|
88
|
+
* // Browser-specific code
|
|
89
|
+
* console.log('Running in browser');
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
isBrowser: () => {
|
|
94
|
+
return typeof window !== "undefined";
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Checks if the browser is currently online.
|
|
99
|
+
*
|
|
100
|
+
* Uses the Navigator Online Status API (`navigator.onLine`) to determine
|
|
101
|
+
* network connectivity. Note that this only indicates if the device has
|
|
102
|
+
* a network connection, not if it can reach the internet.
|
|
103
|
+
*
|
|
104
|
+
* @returns `true` if online, `false` if offline, defaults to `true` if not in browser
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* if (platform.isOnline()) {
|
|
109
|
+
* // Proceed with upload
|
|
110
|
+
* await client.upload(file);
|
|
111
|
+
* } else {
|
|
112
|
+
* console.log('Waiting for network connection...');
|
|
113
|
+
* }
|
|
114
|
+
*
|
|
115
|
+
* // Listen for online/offline events
|
|
116
|
+
* window.addEventListener('online', () => {
|
|
117
|
+
* console.log('Back online, resuming upload');
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
isOnline: () => {
|
|
122
|
+
if (typeof navigator !== "undefined") {
|
|
123
|
+
return navigator.onLine;
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Checks if a value is a File object.
|
|
130
|
+
*
|
|
131
|
+
* Type guard to determine if an unknown value is a browser File object.
|
|
132
|
+
* Useful for validating upload inputs and conditional file handling.
|
|
133
|
+
*
|
|
134
|
+
* @param value - The value to check
|
|
135
|
+
* @returns `true` if the value is a File instance, `false` otherwise
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const input = getUploadInput(); // unknown type
|
|
140
|
+
*
|
|
141
|
+
* if (platform.isFileLike(input)) {
|
|
142
|
+
* // TypeScript knows input is a File here
|
|
143
|
+
* console.log('Uploading file:', input.name);
|
|
144
|
+
* }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
isFileLike: (value: unknown) => {
|
|
148
|
+
return value instanceof File;
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Extracts the file name from a File object.
|
|
153
|
+
*
|
|
154
|
+
* @param file - The file to extract the name from
|
|
155
|
+
* @returns The file name string, or `undefined` if not a File
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* const file = new File(['content'], 'document.pdf');
|
|
160
|
+
* const name = platform.getFileName(file);
|
|
161
|
+
* console.log(name); // "document.pdf"
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
getFileName: (file: unknown) => {
|
|
165
|
+
if (file instanceof File) {
|
|
166
|
+
return file.name;
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Extracts the MIME type from a File object.
|
|
173
|
+
*
|
|
174
|
+
* @param file - The file to extract the type from
|
|
175
|
+
* @returns The MIME type string, or `undefined` if not a File
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const file = new File(['content'], 'image.png', { type: 'image/png' });
|
|
180
|
+
* const type = platform.getFileType(file);
|
|
181
|
+
* console.log(type); // "image/png"
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
getFileType: (file: unknown) => {
|
|
185
|
+
if (file instanceof File) {
|
|
186
|
+
return file.type;
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Extracts the file size in bytes from a File object.
|
|
193
|
+
*
|
|
194
|
+
* @param file - The file to extract the size from
|
|
195
|
+
* @returns The file size in bytes, or `undefined` if not a File
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* const file = new File(['Hello'], 'greeting.txt');
|
|
200
|
+
* const size = platform.getFileSize(file);
|
|
201
|
+
* console.log(size); // 5 (bytes)
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
getFileSize: (file: unknown) => {
|
|
205
|
+
if (file instanceof File) {
|
|
206
|
+
return file.size;
|
|
207
|
+
}
|
|
208
|
+
return undefined;
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Extracts the last modified timestamp from a File object.
|
|
213
|
+
*
|
|
214
|
+
* @param file - The file to extract the timestamp from
|
|
215
|
+
* @returns The last modified timestamp in milliseconds since epoch, or `undefined` if not a File
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* const file = new File(['content'], 'data.txt');
|
|
220
|
+
* const lastModified = platform.getFileLastModified(file);
|
|
221
|
+
* console.log(new Date(lastModified)); // Date object of when file was last modified
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
getFileLastModified: (file: unknown) => {
|
|
225
|
+
if (file instanceof File) {
|
|
226
|
+
return file.lastModified;
|
|
227
|
+
}
|
|
228
|
+
return undefined;
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { StorageService } from "@uploadista/client-core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a browser storage service using localStorage for persistent data storage.
|
|
5
|
+
*
|
|
6
|
+
* This service provides a key-value storage interface backed by the browser's
|
|
7
|
+
* localStorage API. Data stored with this service persists across browser sessions
|
|
8
|
+
* and page reloads until explicitly deleted or cleared by the user.
|
|
9
|
+
*
|
|
10
|
+
* Use cases include:
|
|
11
|
+
* - Persisting upload state for resumable uploads
|
|
12
|
+
* - Caching file metadata and fingerprints
|
|
13
|
+
* - Storing user preferences and settings
|
|
14
|
+
* - Maintaining upload history
|
|
15
|
+
*
|
|
16
|
+
* **Important notes:**
|
|
17
|
+
* - localStorage has a typical limit of 5-10MB per origin
|
|
18
|
+
* - Data is stored as strings (objects are JSON-serialized)
|
|
19
|
+
* - localStorage is synchronous but this service wraps it in Promises for consistency
|
|
20
|
+
* - Data is scoped to the origin (protocol + domain + port)
|
|
21
|
+
* - Users can clear localStorage through browser settings
|
|
22
|
+
*
|
|
23
|
+
* @returns A StorageService backed by browser localStorage
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { createLocalStorageService } from '@uploadista/client-browser';
|
|
28
|
+
*
|
|
29
|
+
* const storage = createLocalStorageService();
|
|
30
|
+
*
|
|
31
|
+
* // Store upload state
|
|
32
|
+
* await storage.setItem('upload:123', JSON.stringify({
|
|
33
|
+
* fileId: '123',
|
|
34
|
+
* progress: 75,
|
|
35
|
+
* uploadedChunks: [0, 1, 2]
|
|
36
|
+
* }));
|
|
37
|
+
*
|
|
38
|
+
* // Retrieve upload state
|
|
39
|
+
* const data = await storage.getItem('upload:123');
|
|
40
|
+
* if (data) {
|
|
41
|
+
* const state = JSON.parse(data);
|
|
42
|
+
* console.log('Resuming upload at', state.progress, '%');
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* // Find all uploads
|
|
46
|
+
* const uploads = await storage.find('upload:');
|
|
47
|
+
* console.log('Found', Object.keys(uploads).length, 'uploads');
|
|
48
|
+
*
|
|
49
|
+
* // Clean up completed upload
|
|
50
|
+
* await storage.removeItem('upload:123');
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @see {@link createSessionStorageService} for session-only storage
|
|
54
|
+
*/
|
|
55
|
+
export function createLocalStorageService(): StorageService {
|
|
56
|
+
/**
|
|
57
|
+
* Internal helper to find entries matching a prefix.
|
|
58
|
+
*
|
|
59
|
+
* Iterates through all localStorage keys and returns those that start
|
|
60
|
+
* with the specified prefix along with their values.
|
|
61
|
+
*
|
|
62
|
+
* @param prefix - Key prefix to filter by
|
|
63
|
+
* @returns Object mapping matching keys to their values
|
|
64
|
+
* @private
|
|
65
|
+
*/
|
|
66
|
+
const findEntries = (prefix: string): Record<string, string> => {
|
|
67
|
+
const results: Record<string, string> = {};
|
|
68
|
+
|
|
69
|
+
for (const key in localStorage) {
|
|
70
|
+
if (key.startsWith(prefix)) {
|
|
71
|
+
const item = localStorage.getItem(key);
|
|
72
|
+
if (item) {
|
|
73
|
+
results[key] = item;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return results;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
/**
|
|
83
|
+
* Retrieves a value from localStorage by key.
|
|
84
|
+
*
|
|
85
|
+
* @param key - The key to retrieve
|
|
86
|
+
* @returns Promise resolving to the value, or null if the key doesn't exist
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const value = await storage.getItem('user:preferences');
|
|
91
|
+
* if (value) {
|
|
92
|
+
* const prefs = JSON.parse(value);
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
async getItem(key: string): Promise<string | null> {
|
|
97
|
+
return localStorage.getItem(key);
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Stores a value in localStorage.
|
|
102
|
+
*
|
|
103
|
+
* If the key already exists, its value will be overwritten.
|
|
104
|
+
* Values must be strings; use JSON.stringify() for objects.
|
|
105
|
+
*
|
|
106
|
+
* @param key - The key to store under
|
|
107
|
+
* @param value - The string value to store
|
|
108
|
+
*
|
|
109
|
+
* @throws {QuotaExceededError} If localStorage quota is exceeded
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* // Store string
|
|
114
|
+
* await storage.setItem('upload:status', 'completed');
|
|
115
|
+
*
|
|
116
|
+
* // Store object
|
|
117
|
+
* await storage.setItem('upload:metadata', JSON.stringify({
|
|
118
|
+
* name: 'file.txt',
|
|
119
|
+
* size: 1024
|
|
120
|
+
* }));
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
async setItem(key: string, value: string): Promise<void> {
|
|
124
|
+
localStorage.setItem(key, value);
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Removes a value from localStorage by key.
|
|
129
|
+
*
|
|
130
|
+
* If the key doesn't exist, this is a no-op (no error is thrown).
|
|
131
|
+
*
|
|
132
|
+
* @param key - The key to remove
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* // Clean up completed upload
|
|
137
|
+
* await storage.removeItem('upload:123');
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
async removeItem(key: string): Promise<void> {
|
|
141
|
+
localStorage.removeItem(key);
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Retrieves all entries from localStorage.
|
|
146
|
+
*
|
|
147
|
+
* Returns an object mapping every key in localStorage to its value.
|
|
148
|
+
* Use with caution as this can return a large amount of data.
|
|
149
|
+
*
|
|
150
|
+
* @returns Promise resolving to object with all key-value pairs
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const all = await storage.findAll();
|
|
155
|
+
* console.log('Total items in storage:', Object.keys(all).length);
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
async findAll(): Promise<Record<string, string>> {
|
|
159
|
+
return findEntries("");
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Finds all entries with keys starting with a given prefix.
|
|
164
|
+
*
|
|
165
|
+
* Useful for querying related data or implementing namespacing.
|
|
166
|
+
* For example, use "upload:" prefix to find all upload-related entries.
|
|
167
|
+
*
|
|
168
|
+
* @param prefix - The key prefix to search for
|
|
169
|
+
* @returns Promise resolving to object with matching key-value pairs
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* // Find all uploads
|
|
174
|
+
* const uploads = await storage.find('upload:');
|
|
175
|
+
* for (const [key, value] of Object.entries(uploads)) {
|
|
176
|
+
* console.log('Upload:', key, JSON.parse(value));
|
|
177
|
+
* }
|
|
178
|
+
*
|
|
179
|
+
* // Find user preferences
|
|
180
|
+
* const prefs = await storage.find('pref:');
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
async find(prefix: string): Promise<Record<string, string>> {
|
|
184
|
+
return findEntries(prefix);
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type { StorageService } from "@uploadista/client-core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a browser storage service using sessionStorage for temporary data storage.
|
|
5
|
+
*
|
|
6
|
+
* This service provides a key-value storage interface backed by the browser's
|
|
7
|
+
* sessionStorage API. Unlike localStorage, data stored with sessionStorage is
|
|
8
|
+
* only available for the duration of the page session and is cleared when the
|
|
9
|
+
* browser tab or window is closed.
|
|
10
|
+
*
|
|
11
|
+
* Use cases include:
|
|
12
|
+
* - Temporary upload state during a session
|
|
13
|
+
* - One-time authentication tokens
|
|
14
|
+
* - Transient UI state
|
|
15
|
+
* - Session-specific preferences
|
|
16
|
+
*
|
|
17
|
+
* **Key differences from localStorage:**
|
|
18
|
+
* - Data persists only for the current browser tab/window session
|
|
19
|
+
* - Each tab has its own isolated sessionStorage
|
|
20
|
+
* - Data is cleared when the tab/window is closed
|
|
21
|
+
* - Page reloads preserve sessionStorage (unlike in-memory storage)
|
|
22
|
+
* - Same storage quota limits as localStorage (5-10MB)
|
|
23
|
+
*
|
|
24
|
+
* @returns A StorageService backed by browser sessionStorage
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { createSessionStorageService } from '@uploadista/client-browser';
|
|
29
|
+
*
|
|
30
|
+
* const storage = createSessionStorageService();
|
|
31
|
+
*
|
|
32
|
+
* // Store temporary upload state
|
|
33
|
+
* await storage.setItem('temp-upload:abc', JSON.stringify({
|
|
34
|
+
* fileId: 'abc',
|
|
35
|
+
* started: Date.now()
|
|
36
|
+
* }));
|
|
37
|
+
*
|
|
38
|
+
* // Retrieve within same session
|
|
39
|
+
* const data = await storage.getItem('temp-upload:abc');
|
|
40
|
+
* if (data) {
|
|
41
|
+
* const state = JSON.parse(data);
|
|
42
|
+
* console.log('Upload started at', new Date(state.started));
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* // Find all temporary uploads
|
|
46
|
+
* const tempUploads = await storage.find('temp-upload:');
|
|
47
|
+
*
|
|
48
|
+
* // Clean up
|
|
49
|
+
* await storage.removeItem('temp-upload:abc');
|
|
50
|
+
* // OR: Close tab/window to clear all sessionStorage
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @see {@link createLocalStorageService} for persistent storage
|
|
54
|
+
*/
|
|
55
|
+
export function createSessionStorageService(): StorageService {
|
|
56
|
+
/**
|
|
57
|
+
* Internal helper to find entries matching a prefix.
|
|
58
|
+
*
|
|
59
|
+
* Iterates through all sessionStorage keys and returns those that start
|
|
60
|
+
* with the specified prefix along with their values.
|
|
61
|
+
*
|
|
62
|
+
* @param prefix - Key prefix to filter by
|
|
63
|
+
* @returns Object mapping matching keys to their values
|
|
64
|
+
* @private
|
|
65
|
+
*/
|
|
66
|
+
const findEntries = (prefix: string): Record<string, string> => {
|
|
67
|
+
const results: Record<string, string> = {};
|
|
68
|
+
|
|
69
|
+
for (const key in sessionStorage) {
|
|
70
|
+
if (key.startsWith(prefix)) {
|
|
71
|
+
const item = sessionStorage.getItem(key);
|
|
72
|
+
if (item) {
|
|
73
|
+
results[key] = item;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return results;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
/**
|
|
83
|
+
* Retrieves a value from sessionStorage by key.
|
|
84
|
+
*
|
|
85
|
+
* @param key - The key to retrieve
|
|
86
|
+
* @returns Promise resolving to the value, or null if the key doesn't exist
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const token = await storage.getItem('session:auth-token');
|
|
91
|
+
* if (token) {
|
|
92
|
+
* // Use token for requests
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
async getItem(key: string): Promise<string | null> {
|
|
97
|
+
return sessionStorage.getItem(key);
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Stores a value in sessionStorage.
|
|
102
|
+
*
|
|
103
|
+
* If the key already exists, its value will be overwritten.
|
|
104
|
+
* Values must be strings; use JSON.stringify() for objects.
|
|
105
|
+
* Data will be cleared when the browser tab/window is closed.
|
|
106
|
+
*
|
|
107
|
+
* @param key - The key to store under
|
|
108
|
+
* @param value - The string value to store
|
|
109
|
+
*
|
|
110
|
+
* @throws {QuotaExceededError} If sessionStorage quota is exceeded
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Store temporary state
|
|
115
|
+
* await storage.setItem('wizard:step', '2');
|
|
116
|
+
*
|
|
117
|
+
* // Store temporary object
|
|
118
|
+
* await storage.setItem('temp:upload', JSON.stringify({
|
|
119
|
+
* progress: 50,
|
|
120
|
+
* paused: false
|
|
121
|
+
* }));
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
async setItem(key: string, value: string): Promise<void> {
|
|
125
|
+
sessionStorage.setItem(key, value);
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Removes a value from sessionStorage by key.
|
|
130
|
+
*
|
|
131
|
+
* If the key doesn't exist, this is a no-op (no error is thrown).
|
|
132
|
+
*
|
|
133
|
+
* @param key - The key to remove
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* // Clean up temporary data
|
|
138
|
+
* await storage.removeItem('temp:upload:123');
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
async removeItem(key: string): Promise<void> {
|
|
142
|
+
sessionStorage.removeItem(key);
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Retrieves all entries from sessionStorage.
|
|
147
|
+
*
|
|
148
|
+
* Returns an object mapping every key in sessionStorage to its value.
|
|
149
|
+
* This only includes data for the current tab/window.
|
|
150
|
+
*
|
|
151
|
+
* @returns Promise resolving to object with all key-value pairs
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const all = await storage.findAll();
|
|
156
|
+
* console.log('Session items:', Object.keys(all).length);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
async findAll(): Promise<Record<string, string>> {
|
|
160
|
+
return findEntries("");
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Finds all entries with keys starting with a given prefix.
|
|
165
|
+
*
|
|
166
|
+
* Useful for querying related session data. For example, use "temp:"
|
|
167
|
+
* prefix to find all temporary entries.
|
|
168
|
+
*
|
|
169
|
+
* @param prefix - The key prefix to search for
|
|
170
|
+
* @returns Promise resolving to object with matching key-value pairs
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* // Find all temporary uploads in this session
|
|
175
|
+
* const tempUploads = await storage.find('temp-upload:');
|
|
176
|
+
* for (const [key, value] of Object.entries(tempUploads)) {
|
|
177
|
+
* console.log('Temp upload:', key, JSON.parse(value));
|
|
178
|
+
* }
|
|
179
|
+
*
|
|
180
|
+
* // Find wizard state
|
|
181
|
+
* const wizardState = await storage.find('wizard:');
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
async find(prefix: string): Promise<Record<string, string>> {
|
|
185
|
+
return findEntries(prefix);
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|