@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,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a browser storage service using sessionStorage for temporary data storage.
|
|
3
|
+
*
|
|
4
|
+
* This service provides a key-value storage interface backed by the browser's
|
|
5
|
+
* sessionStorage API. Unlike localStorage, data stored with sessionStorage is
|
|
6
|
+
* only available for the duration of the page session and is cleared when the
|
|
7
|
+
* browser tab or window is closed.
|
|
8
|
+
*
|
|
9
|
+
* Use cases include:
|
|
10
|
+
* - Temporary upload state during a session
|
|
11
|
+
* - One-time authentication tokens
|
|
12
|
+
* - Transient UI state
|
|
13
|
+
* - Session-specific preferences
|
|
14
|
+
*
|
|
15
|
+
* **Key differences from localStorage:**
|
|
16
|
+
* - Data persists only for the current browser tab/window session
|
|
17
|
+
* - Each tab has its own isolated sessionStorage
|
|
18
|
+
* - Data is cleared when the tab/window is closed
|
|
19
|
+
* - Page reloads preserve sessionStorage (unlike in-memory storage)
|
|
20
|
+
* - Same storage quota limits as localStorage (5-10MB)
|
|
21
|
+
*
|
|
22
|
+
* @returns A StorageService backed by browser sessionStorage
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { createSessionStorageService } from '@uploadista/client-browser';
|
|
27
|
+
*
|
|
28
|
+
* const storage = createSessionStorageService();
|
|
29
|
+
*
|
|
30
|
+
* // Store temporary upload state
|
|
31
|
+
* await storage.setItem('temp-upload:abc', JSON.stringify({
|
|
32
|
+
* fileId: 'abc',
|
|
33
|
+
* started: Date.now()
|
|
34
|
+
* }));
|
|
35
|
+
*
|
|
36
|
+
* // Retrieve within same session
|
|
37
|
+
* const data = await storage.getItem('temp-upload:abc');
|
|
38
|
+
* if (data) {
|
|
39
|
+
* const state = JSON.parse(data);
|
|
40
|
+
* console.log('Upload started at', new Date(state.started));
|
|
41
|
+
* }
|
|
42
|
+
*
|
|
43
|
+
* // Find all temporary uploads
|
|
44
|
+
* const tempUploads = await storage.find('temp-upload:');
|
|
45
|
+
*
|
|
46
|
+
* // Clean up
|
|
47
|
+
* await storage.removeItem('temp-upload:abc');
|
|
48
|
+
* // OR: Close tab/window to clear all sessionStorage
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @see {@link createLocalStorageService} for persistent storage
|
|
52
|
+
*/
|
|
53
|
+
export function createSessionStorageService() {
|
|
54
|
+
/**
|
|
55
|
+
* Internal helper to find entries matching a prefix.
|
|
56
|
+
*
|
|
57
|
+
* Iterates through all sessionStorage keys and returns those that start
|
|
58
|
+
* with the specified prefix along with their values.
|
|
59
|
+
*
|
|
60
|
+
* @param prefix - Key prefix to filter by
|
|
61
|
+
* @returns Object mapping matching keys to their values
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
const findEntries = (prefix) => {
|
|
65
|
+
const results = {};
|
|
66
|
+
for (const key in sessionStorage) {
|
|
67
|
+
if (key.startsWith(prefix)) {
|
|
68
|
+
const item = sessionStorage.getItem(key);
|
|
69
|
+
if (item) {
|
|
70
|
+
results[key] = item;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return results;
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
/**
|
|
78
|
+
* Retrieves a value from sessionStorage by key.
|
|
79
|
+
*
|
|
80
|
+
* @param key - The key to retrieve
|
|
81
|
+
* @returns Promise resolving to the value, or null if the key doesn't exist
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const token = await storage.getItem('session:auth-token');
|
|
86
|
+
* if (token) {
|
|
87
|
+
* // Use token for requests
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
async getItem(key) {
|
|
92
|
+
return sessionStorage.getItem(key);
|
|
93
|
+
},
|
|
94
|
+
/**
|
|
95
|
+
* Stores a value in sessionStorage.
|
|
96
|
+
*
|
|
97
|
+
* If the key already exists, its value will be overwritten.
|
|
98
|
+
* Values must be strings; use JSON.stringify() for objects.
|
|
99
|
+
* Data will be cleared when the browser tab/window is closed.
|
|
100
|
+
*
|
|
101
|
+
* @param key - The key to store under
|
|
102
|
+
* @param value - The string value to store
|
|
103
|
+
*
|
|
104
|
+
* @throws {QuotaExceededError} If sessionStorage quota is exceeded
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* // Store temporary state
|
|
109
|
+
* await storage.setItem('wizard:step', '2');
|
|
110
|
+
*
|
|
111
|
+
* // Store temporary object
|
|
112
|
+
* await storage.setItem('temp:upload', JSON.stringify({
|
|
113
|
+
* progress: 50,
|
|
114
|
+
* paused: false
|
|
115
|
+
* }));
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
async setItem(key, value) {
|
|
119
|
+
sessionStorage.setItem(key, value);
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Removes a value from sessionStorage by key.
|
|
123
|
+
*
|
|
124
|
+
* If the key doesn't exist, this is a no-op (no error is thrown).
|
|
125
|
+
*
|
|
126
|
+
* @param key - The key to remove
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* // Clean up temporary data
|
|
131
|
+
* await storage.removeItem('temp:upload:123');
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
async removeItem(key) {
|
|
135
|
+
sessionStorage.removeItem(key);
|
|
136
|
+
},
|
|
137
|
+
/**
|
|
138
|
+
* Retrieves all entries from sessionStorage.
|
|
139
|
+
*
|
|
140
|
+
* Returns an object mapping every key in sessionStorage to its value.
|
|
141
|
+
* This only includes data for the current tab/window.
|
|
142
|
+
*
|
|
143
|
+
* @returns Promise resolving to object with all key-value pairs
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const all = await storage.findAll();
|
|
148
|
+
* console.log('Session items:', Object.keys(all).length);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
async findAll() {
|
|
152
|
+
return findEntries("");
|
|
153
|
+
},
|
|
154
|
+
/**
|
|
155
|
+
* Finds all entries with keys starting with a given prefix.
|
|
156
|
+
*
|
|
157
|
+
* Useful for querying related session data. For example, use "temp:"
|
|
158
|
+
* prefix to find all temporary entries.
|
|
159
|
+
*
|
|
160
|
+
* @param prefix - The key prefix to search for
|
|
161
|
+
* @returns Promise resolving to object with matching key-value pairs
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* // Find all temporary uploads in this session
|
|
166
|
+
* const tempUploads = await storage.find('temp-upload:');
|
|
167
|
+
* for (const [key, value] of Object.entries(tempUploads)) {
|
|
168
|
+
* console.log('Temp upload:', key, JSON.parse(value));
|
|
169
|
+
* }
|
|
170
|
+
*
|
|
171
|
+
* // Find wizard state
|
|
172
|
+
* const wizardState = await storage.find('wizard:');
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
async find(prefix) {
|
|
176
|
+
return findEntries(prefix);
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { WebSocketFactory } from "@uploadista/client-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a factory for browser WebSocket connections.
|
|
4
|
+
*
|
|
5
|
+
* This factory is used by the Uploadista client to create WebSocket connections
|
|
6
|
+
* for real-time features. It wraps the browser's native WebSocket API and provides
|
|
7
|
+
* a consistent interface for the client.
|
|
8
|
+
*
|
|
9
|
+
* The factory creates WebSockets that support:
|
|
10
|
+
* - Real-time upload progress updates
|
|
11
|
+
* - Flow execution status streaming
|
|
12
|
+
* - Live error and event notifications
|
|
13
|
+
* - Bidirectional client-server communication
|
|
14
|
+
*
|
|
15
|
+
* @returns A WebSocketFactory that creates browser-compatible WebSocket connections
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { createBrowserWebSocketFactory } from '@uploadista/client-browser';
|
|
20
|
+
*
|
|
21
|
+
* const factory = createBrowserWebSocketFactory();
|
|
22
|
+
*
|
|
23
|
+
* // Create a WebSocket connection
|
|
24
|
+
* const ws = factory.create('wss://api.example.com/ws/upload/123');
|
|
25
|
+
*
|
|
26
|
+
* // Set up event handlers
|
|
27
|
+
* ws.onmessage = (event) => {
|
|
28
|
+
* const data = JSON.parse(event.data);
|
|
29
|
+
* if (data.type === 'progress') {
|
|
30
|
+
* console.log('Upload progress:', data.progress);
|
|
31
|
+
* }
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* ws.onopen = () => {
|
|
35
|
+
* console.log('WebSocket connected');
|
|
36
|
+
* };
|
|
37
|
+
*
|
|
38
|
+
* ws.onclose = (event) => {
|
|
39
|
+
* console.log('WebSocket closed:', event.code, event.reason);
|
|
40
|
+
* };
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @see {@link BrowserWebSocket} for the WebSocket implementation details
|
|
44
|
+
*/
|
|
45
|
+
export declare const createBrowserWebSocketFactory: () => WebSocketFactory;
|
|
46
|
+
//# sourceMappingURL=websocket-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-factory.d.ts","sourceRoot":"","sources":["../../src/services/websocket-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,yBAAyB,CAAC;AAsK/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,eAAO,MAAM,6BAA6B,QAAO,gBAE/C,CAAC"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser implementation of WebSocket that wraps the native WebSocket API.
|
|
3
|
+
*
|
|
4
|
+
* This class provides a minimal wrapper around the browser's native WebSocket
|
|
5
|
+
* to ensure compatibility with the Uploadista client's WebSocketLike interface.
|
|
6
|
+
* It's used for real-time communication features like:
|
|
7
|
+
* - Upload progress streaming
|
|
8
|
+
* - Flow execution status updates
|
|
9
|
+
* - Real-time error notifications
|
|
10
|
+
* - Live event feeds
|
|
11
|
+
*
|
|
12
|
+
* The wrapper preserves all WebSocket states and properly proxies all events
|
|
13
|
+
* while maintaining the standard WebSocket lifecycle.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const ws = new BrowserWebSocket('wss://api.example.com/ws');
|
|
18
|
+
*
|
|
19
|
+
* ws.onopen = () => {
|
|
20
|
+
* console.log('Connected');
|
|
21
|
+
* ws.send('Hello server');
|
|
22
|
+
* };
|
|
23
|
+
*
|
|
24
|
+
* ws.onmessage = (event) => {
|
|
25
|
+
* console.log('Message:', event.data);
|
|
26
|
+
* };
|
|
27
|
+
*
|
|
28
|
+
* ws.onerror = (event) => {
|
|
29
|
+
* console.error('Error:', event.message);
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* ws.onclose = (event) => {
|
|
33
|
+
* console.log('Closed:', event.code, event.reason);
|
|
34
|
+
* };
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
class BrowserWebSocket {
|
|
38
|
+
/** WebSocket is currently connecting (readyState = 0) */
|
|
39
|
+
CONNECTING = 0;
|
|
40
|
+
/** WebSocket connection is open and ready (readyState = 1) */
|
|
41
|
+
OPEN = 1;
|
|
42
|
+
/** WebSocket is closing (readyState = 2) */
|
|
43
|
+
CLOSING = 2;
|
|
44
|
+
/** WebSocket connection is closed (readyState = 3) */
|
|
45
|
+
CLOSED = 3;
|
|
46
|
+
/**
|
|
47
|
+
* Current state of the WebSocket connection.
|
|
48
|
+
*
|
|
49
|
+
* Possible values:
|
|
50
|
+
* - 0 (CONNECTING): Connection is being established
|
|
51
|
+
* - 1 (OPEN): Connection is open and ready for communication
|
|
52
|
+
* - 2 (CLOSING): Connection is closing
|
|
53
|
+
* - 3 (CLOSED): Connection is closed or couldn't be opened
|
|
54
|
+
*/
|
|
55
|
+
readyState;
|
|
56
|
+
/** Event handler called when the connection is established */
|
|
57
|
+
onopen = null;
|
|
58
|
+
/** Event handler called when the connection is closed */
|
|
59
|
+
onclose = null;
|
|
60
|
+
/** Event handler called when an error occurs */
|
|
61
|
+
onerror = null;
|
|
62
|
+
/** Event handler called when a message is received */
|
|
63
|
+
onmessage = null;
|
|
64
|
+
native;
|
|
65
|
+
/**
|
|
66
|
+
* Creates a new BrowserWebSocket instance.
|
|
67
|
+
*
|
|
68
|
+
* Initializes a native WebSocket connection to the specified URL and sets up
|
|
69
|
+
* event handler proxying to convert native events to the WebSocketLike format.
|
|
70
|
+
*
|
|
71
|
+
* @param url - WebSocket URL to connect to (must use ws:// or wss:// protocol)
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const ws = new BrowserWebSocket('wss://api.example.com/upload/progress');
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
constructor(url) {
|
|
79
|
+
this.native = new WebSocket(url);
|
|
80
|
+
this.readyState = this.native.readyState;
|
|
81
|
+
// Proxy event handlers to convert native events to WebSocketLike format
|
|
82
|
+
this.native.onopen = () => {
|
|
83
|
+
this.readyState = this.native.readyState;
|
|
84
|
+
this.onopen?.();
|
|
85
|
+
};
|
|
86
|
+
this.native.onclose = (event) => {
|
|
87
|
+
this.readyState = this.native.readyState;
|
|
88
|
+
const closeEvent = event;
|
|
89
|
+
this.onclose?.({ code: closeEvent.code, reason: closeEvent.reason });
|
|
90
|
+
};
|
|
91
|
+
this.native.onerror = (_event) => {
|
|
92
|
+
this.onerror?.({ message: "WebSocket error" });
|
|
93
|
+
};
|
|
94
|
+
this.native.onmessage = (event) => {
|
|
95
|
+
const messageEvent = event;
|
|
96
|
+
this.onmessage?.({ data: messageEvent.data });
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Sends data through the WebSocket connection.
|
|
101
|
+
*
|
|
102
|
+
* The data can be either a string (text message) or a Uint8Array (binary message).
|
|
103
|
+
* The connection must be in the OPEN state before sending data.
|
|
104
|
+
*
|
|
105
|
+
* @param data - String or binary data to send
|
|
106
|
+
*
|
|
107
|
+
* @throws {Error} If the connection is not open
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* // Send text message
|
|
112
|
+
* ws.send('{"type": "subscribe", "channel": "uploads"}');
|
|
113
|
+
*
|
|
114
|
+
* // Send binary data
|
|
115
|
+
* const buffer = new Uint8Array([1, 2, 3, 4]);
|
|
116
|
+
* ws.send(buffer);
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
send(data) {
|
|
120
|
+
this.native.send(data);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Closes the WebSocket connection.
|
|
124
|
+
*
|
|
125
|
+
* Optionally accepts a close code and reason that will be sent to the server.
|
|
126
|
+
* Standard close codes include:
|
|
127
|
+
* - 1000: Normal closure
|
|
128
|
+
* - 1001: Going away (e.g., page navigation)
|
|
129
|
+
* - 1002: Protocol error
|
|
130
|
+
* - 1003: Unsupported data
|
|
131
|
+
*
|
|
132
|
+
* @param code - Optional close code (default: 1000 for normal closure)
|
|
133
|
+
* @param reason - Optional human-readable reason for closing
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* // Normal close
|
|
138
|
+
* ws.close();
|
|
139
|
+
*
|
|
140
|
+
* // Close with reason
|
|
141
|
+
* ws.close(1000, 'Upload completed');
|
|
142
|
+
*
|
|
143
|
+
* // Close due to error
|
|
144
|
+
* ws.close(1011, 'Internal error during upload');
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
close(code, reason) {
|
|
148
|
+
this.native.close(code, reason);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Creates a factory for browser WebSocket connections.
|
|
153
|
+
*
|
|
154
|
+
* This factory is used by the Uploadista client to create WebSocket connections
|
|
155
|
+
* for real-time features. It wraps the browser's native WebSocket API and provides
|
|
156
|
+
* a consistent interface for the client.
|
|
157
|
+
*
|
|
158
|
+
* The factory creates WebSockets that support:
|
|
159
|
+
* - Real-time upload progress updates
|
|
160
|
+
* - Flow execution status streaming
|
|
161
|
+
* - Live error and event notifications
|
|
162
|
+
* - Bidirectional client-server communication
|
|
163
|
+
*
|
|
164
|
+
* @returns A WebSocketFactory that creates browser-compatible WebSocket connections
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* import { createBrowserWebSocketFactory } from '@uploadista/client-browser';
|
|
169
|
+
*
|
|
170
|
+
* const factory = createBrowserWebSocketFactory();
|
|
171
|
+
*
|
|
172
|
+
* // Create a WebSocket connection
|
|
173
|
+
* const ws = factory.create('wss://api.example.com/ws/upload/123');
|
|
174
|
+
*
|
|
175
|
+
* // Set up event handlers
|
|
176
|
+
* ws.onmessage = (event) => {
|
|
177
|
+
* const data = JSON.parse(event.data);
|
|
178
|
+
* if (data.type === 'progress') {
|
|
179
|
+
* console.log('Upload progress:', data.progress);
|
|
180
|
+
* }
|
|
181
|
+
* };
|
|
182
|
+
*
|
|
183
|
+
* ws.onopen = () => {
|
|
184
|
+
* console.log('WebSocket connected');
|
|
185
|
+
* };
|
|
186
|
+
*
|
|
187
|
+
* ws.onclose = (event) => {
|
|
188
|
+
* console.log('WebSocket closed:', event.code, event.reason);
|
|
189
|
+
* };
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @see {@link BrowserWebSocket} for the WebSocket implementation details
|
|
193
|
+
*/
|
|
194
|
+
export const createBrowserWebSocketFactory = () => ({
|
|
195
|
+
create: (url) => new BrowserWebSocket(url),
|
|
196
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./upload-input";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-specific upload input types that can be used with the Uploadista client.
|
|
3
|
+
*
|
|
4
|
+
* In the browser environment, files can be provided as either:
|
|
5
|
+
* - `File` objects from file input elements or drag-and-drop
|
|
6
|
+
* - `Blob` objects created programmatically or from other sources
|
|
7
|
+
*
|
|
8
|
+
* Both types use the browser's File API and can be chunked for upload.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // From file input
|
|
13
|
+
* const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');
|
|
14
|
+
* const file: BrowserUploadInput = fileInput.files[0];
|
|
15
|
+
*
|
|
16
|
+
* // From drag and drop
|
|
17
|
+
* element.addEventListener('drop', (e) => {
|
|
18
|
+
* const file: BrowserUploadInput = e.dataTransfer.files[0];
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // From Blob
|
|
22
|
+
* const blob: BrowserUploadInput = new Blob(['content'], { type: 'text/plain' });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export type BrowserUploadInput = Blob | File;
|
|
26
|
+
//# sourceMappingURL=upload-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-input.d.ts","sourceRoot":"","sources":["../../src/types/upload-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes the SHA-256 checksum of a Blob using the Web Crypto API.
|
|
3
|
+
*
|
|
4
|
+
* This utility function provides a browser-native way to compute cryptographic
|
|
5
|
+
* hashes of file data. It uses the SubtleCrypto API (part of Web Crypto) which
|
|
6
|
+
* provides hardware-accelerated cryptographic operations when available.
|
|
7
|
+
*
|
|
8
|
+
* The SHA-256 algorithm produces a 256-bit (32-byte) hash value, typically
|
|
9
|
+
* rendered as a 64-character hexadecimal string. SHA-256 is widely used for:
|
|
10
|
+
* - File integrity verification
|
|
11
|
+
* - Content deduplication
|
|
12
|
+
* - File fingerprinting
|
|
13
|
+
* - Checksum validation
|
|
14
|
+
*
|
|
15
|
+
* **Performance note:** For large files (>100MB), this function loads the entire
|
|
16
|
+
* file into memory before hashing. For extremely large files, consider chunked
|
|
17
|
+
* hashing approaches if memory is a concern.
|
|
18
|
+
*
|
|
19
|
+
* @param blob - The Blob or File to hash
|
|
20
|
+
* @returns Promise resolving to the hex-encoded SHA-256 hash
|
|
21
|
+
*
|
|
22
|
+
* @throws {Error} When the hash computation fails (e.g., out of memory, crypto API unavailable)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { computeblobSha256 } from '@uploadista/client-browser';
|
|
27
|
+
*
|
|
28
|
+
* // Hash a File from input
|
|
29
|
+
* const fileInput = document.querySelector('input[type="file"]');
|
|
30
|
+
* const file = fileInput.files[0];
|
|
31
|
+
* const hash = await computeblobSha256(file);
|
|
32
|
+
* console.log('File SHA-256:', hash);
|
|
33
|
+
* // Output: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
34
|
+
*
|
|
35
|
+
* // Hash a Blob
|
|
36
|
+
* const blob = new Blob(['Hello, World!'], { type: 'text/plain' });
|
|
37
|
+
* const hash = await computeblobSha256(blob);
|
|
38
|
+
* console.log('Blob SHA-256:', hash);
|
|
39
|
+
*
|
|
40
|
+
* // Verify file integrity
|
|
41
|
+
* const expectedHash = 'abc123...';
|
|
42
|
+
* const actualHash = await computeblobSha256(file);
|
|
43
|
+
* if (actualHash === expectedHash) {
|
|
44
|
+
* console.log('File integrity verified');
|
|
45
|
+
* } else {
|
|
46
|
+
* console.error('File has been modified or corrupted');
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* // Check for duplicate files
|
|
50
|
+
* const file1Hash = await computeblobSha256(file1);
|
|
51
|
+
* const file2Hash = await computeblobSha256(file2);
|
|
52
|
+
* if (file1Hash === file2Hash) {
|
|
53
|
+
* console.log('Files are identical (same content)');
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest} for SubtleCrypto.digest API
|
|
58
|
+
*/
|
|
59
|
+
export declare function computeblobSha256(blob: Blob): Promise<string>;
|
|
60
|
+
//# sourceMappingURL=hash-util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-util.d.ts","sourceRoot":"","sources":["../../src/utils/hash-util.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBnE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes the SHA-256 checksum of a Blob using the Web Crypto API.
|
|
3
|
+
*
|
|
4
|
+
* This utility function provides a browser-native way to compute cryptographic
|
|
5
|
+
* hashes of file data. It uses the SubtleCrypto API (part of Web Crypto) which
|
|
6
|
+
* provides hardware-accelerated cryptographic operations when available.
|
|
7
|
+
*
|
|
8
|
+
* The SHA-256 algorithm produces a 256-bit (32-byte) hash value, typically
|
|
9
|
+
* rendered as a 64-character hexadecimal string. SHA-256 is widely used for:
|
|
10
|
+
* - File integrity verification
|
|
11
|
+
* - Content deduplication
|
|
12
|
+
* - File fingerprinting
|
|
13
|
+
* - Checksum validation
|
|
14
|
+
*
|
|
15
|
+
* **Performance note:** For large files (>100MB), this function loads the entire
|
|
16
|
+
* file into memory before hashing. For extremely large files, consider chunked
|
|
17
|
+
* hashing approaches if memory is a concern.
|
|
18
|
+
*
|
|
19
|
+
* @param blob - The Blob or File to hash
|
|
20
|
+
* @returns Promise resolving to the hex-encoded SHA-256 hash
|
|
21
|
+
*
|
|
22
|
+
* @throws {Error} When the hash computation fails (e.g., out of memory, crypto API unavailable)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { computeblobSha256 } from '@uploadista/client-browser';
|
|
27
|
+
*
|
|
28
|
+
* // Hash a File from input
|
|
29
|
+
* const fileInput = document.querySelector('input[type="file"]');
|
|
30
|
+
* const file = fileInput.files[0];
|
|
31
|
+
* const hash = await computeblobSha256(file);
|
|
32
|
+
* console.log('File SHA-256:', hash);
|
|
33
|
+
* // Output: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
34
|
+
*
|
|
35
|
+
* // Hash a Blob
|
|
36
|
+
* const blob = new Blob(['Hello, World!'], { type: 'text/plain' });
|
|
37
|
+
* const hash = await computeblobSha256(blob);
|
|
38
|
+
* console.log('Blob SHA-256:', hash);
|
|
39
|
+
*
|
|
40
|
+
* // Verify file integrity
|
|
41
|
+
* const expectedHash = 'abc123...';
|
|
42
|
+
* const actualHash = await computeblobSha256(file);
|
|
43
|
+
* if (actualHash === expectedHash) {
|
|
44
|
+
* console.log('File integrity verified');
|
|
45
|
+
* } else {
|
|
46
|
+
* console.error('File has been modified or corrupted');
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* // Check for duplicate files
|
|
50
|
+
* const file1Hash = await computeblobSha256(file1);
|
|
51
|
+
* const file2Hash = await computeblobSha256(file2);
|
|
52
|
+
* if (file1Hash === file2Hash) {
|
|
53
|
+
* console.log('Files are identical (same content)');
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest} for SubtleCrypto.digest API
|
|
58
|
+
*/
|
|
59
|
+
export async function computeblobSha256(blob) {
|
|
60
|
+
try {
|
|
61
|
+
// Read blob as ArrayBuffer
|
|
62
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
63
|
+
// Compute SHA-256 hash using Web Crypto API
|
|
64
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", arrayBuffer);
|
|
65
|
+
// Convert hash to hex string
|
|
66
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
67
|
+
const hashHex = hashArray
|
|
68
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
69
|
+
.join("");
|
|
70
|
+
return hashHex;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw new Error(`Failed to compute file checksum: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uploadista/client-browser",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.3",
|
|
5
|
+
"description": "Browser client for Uploadista",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Uploadista",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.ts",
|
|
10
|
+
"./flow": "./src/flow/index.ts",
|
|
11
|
+
"./upload": "./src/upload/index.ts",
|
|
12
|
+
"./framework-utils": "./src/framework-utils.ts"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"js-base64": "3.7.8",
|
|
16
|
+
"@uploadista/core": "0.0.3",
|
|
17
|
+
"@uploadista/client-core": "0.0.3"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"vitest": "3.2.4",
|
|
21
|
+
"@uploadista/typescript-config": "0.0.3"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -b",
|
|
25
|
+
"format": "biome format --write ./src",
|
|
26
|
+
"lint": "biome lint --write ./src",
|
|
27
|
+
"check": "biome check --write ./src ",
|
|
28
|
+
"test": "vitest",
|
|
29
|
+
"test:run": "vitest run",
|
|
30
|
+
"test:watch": "vitest --watch"
|
|
31
|
+
}
|
|
32
|
+
}
|