@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,212 @@
|
|
|
1
|
+
import type { WebSocketFactory, WebSocketLike } from "@uploadista/client-core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Browser implementation of WebSocket that wraps the native WebSocket API.
|
|
5
|
+
*
|
|
6
|
+
* This class provides a minimal wrapper around the browser's native WebSocket
|
|
7
|
+
* to ensure compatibility with the Uploadista client's WebSocketLike interface.
|
|
8
|
+
* It's used for real-time communication features like:
|
|
9
|
+
* - Upload progress streaming
|
|
10
|
+
* - Flow execution status updates
|
|
11
|
+
* - Real-time error notifications
|
|
12
|
+
* - Live event feeds
|
|
13
|
+
*
|
|
14
|
+
* The wrapper preserves all WebSocket states and properly proxies all events
|
|
15
|
+
* while maintaining the standard WebSocket lifecycle.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const ws = new BrowserWebSocket('wss://api.example.com/ws');
|
|
20
|
+
*
|
|
21
|
+
* ws.onopen = () => {
|
|
22
|
+
* console.log('Connected');
|
|
23
|
+
* ws.send('Hello server');
|
|
24
|
+
* };
|
|
25
|
+
*
|
|
26
|
+
* ws.onmessage = (event) => {
|
|
27
|
+
* console.log('Message:', event.data);
|
|
28
|
+
* };
|
|
29
|
+
*
|
|
30
|
+
* ws.onerror = (event) => {
|
|
31
|
+
* console.error('Error:', event.message);
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* ws.onclose = (event) => {
|
|
35
|
+
* console.log('Closed:', event.code, event.reason);
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
class BrowserWebSocket implements WebSocketLike {
|
|
40
|
+
/** WebSocket is currently connecting (readyState = 0) */
|
|
41
|
+
readonly CONNECTING = 0;
|
|
42
|
+
/** WebSocket connection is open and ready (readyState = 1) */
|
|
43
|
+
readonly OPEN = 1;
|
|
44
|
+
/** WebSocket is closing (readyState = 2) */
|
|
45
|
+
readonly CLOSING = 2;
|
|
46
|
+
/** WebSocket connection is closed (readyState = 3) */
|
|
47
|
+
readonly CLOSED = 3;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Current state of the WebSocket connection.
|
|
51
|
+
*
|
|
52
|
+
* Possible values:
|
|
53
|
+
* - 0 (CONNECTING): Connection is being established
|
|
54
|
+
* - 1 (OPEN): Connection is open and ready for communication
|
|
55
|
+
* - 2 (CLOSING): Connection is closing
|
|
56
|
+
* - 3 (CLOSED): Connection is closed or couldn't be opened
|
|
57
|
+
*/
|
|
58
|
+
readyState: number;
|
|
59
|
+
|
|
60
|
+
/** Event handler called when the connection is established */
|
|
61
|
+
onopen: (() => void) | null = null;
|
|
62
|
+
|
|
63
|
+
/** Event handler called when the connection is closed */
|
|
64
|
+
onclose: ((event: { code: number; reason: string }) => void) | null = null;
|
|
65
|
+
|
|
66
|
+
/** Event handler called when an error occurs */
|
|
67
|
+
onerror: ((event: { message: string }) => void) | null = null;
|
|
68
|
+
|
|
69
|
+
/** Event handler called when a message is received */
|
|
70
|
+
onmessage: ((event: { data: string }) => void) | null = null;
|
|
71
|
+
|
|
72
|
+
private native: WebSocket;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates a new BrowserWebSocket instance.
|
|
76
|
+
*
|
|
77
|
+
* Initializes a native WebSocket connection to the specified URL and sets up
|
|
78
|
+
* event handler proxying to convert native events to the WebSocketLike format.
|
|
79
|
+
*
|
|
80
|
+
* @param url - WebSocket URL to connect to (must use ws:// or wss:// protocol)
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const ws = new BrowserWebSocket('wss://api.example.com/upload/progress');
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
constructor(url: string) {
|
|
88
|
+
this.native = new WebSocket(url);
|
|
89
|
+
this.readyState = this.native.readyState;
|
|
90
|
+
|
|
91
|
+
// Proxy event handlers to convert native events to WebSocketLike format
|
|
92
|
+
this.native.onopen = () => {
|
|
93
|
+
this.readyState = this.native.readyState;
|
|
94
|
+
this.onopen?.();
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
this.native.onclose = (event) => {
|
|
98
|
+
this.readyState = this.native.readyState;
|
|
99
|
+
const closeEvent = event as CloseEvent;
|
|
100
|
+
this.onclose?.({ code: closeEvent.code, reason: closeEvent.reason });
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
this.native.onerror = (_event) => {
|
|
104
|
+
this.onerror?.({ message: "WebSocket error" });
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
this.native.onmessage = (event) => {
|
|
108
|
+
const messageEvent = event as MessageEvent;
|
|
109
|
+
this.onmessage?.({ data: messageEvent.data });
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Sends data through the WebSocket connection.
|
|
115
|
+
*
|
|
116
|
+
* The data can be either a string (text message) or a Uint8Array (binary message).
|
|
117
|
+
* The connection must be in the OPEN state before sending data.
|
|
118
|
+
*
|
|
119
|
+
* @param data - String or binary data to send
|
|
120
|
+
*
|
|
121
|
+
* @throws {Error} If the connection is not open
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* // Send text message
|
|
126
|
+
* ws.send('{"type": "subscribe", "channel": "uploads"}');
|
|
127
|
+
*
|
|
128
|
+
* // Send binary data
|
|
129
|
+
* const buffer = new Uint8Array([1, 2, 3, 4]);
|
|
130
|
+
* ws.send(buffer);
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
send(data: string | Uint8Array): void {
|
|
134
|
+
this.native.send(data);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Closes the WebSocket connection.
|
|
139
|
+
*
|
|
140
|
+
* Optionally accepts a close code and reason that will be sent to the server.
|
|
141
|
+
* Standard close codes include:
|
|
142
|
+
* - 1000: Normal closure
|
|
143
|
+
* - 1001: Going away (e.g., page navigation)
|
|
144
|
+
* - 1002: Protocol error
|
|
145
|
+
* - 1003: Unsupported data
|
|
146
|
+
*
|
|
147
|
+
* @param code - Optional close code (default: 1000 for normal closure)
|
|
148
|
+
* @param reason - Optional human-readable reason for closing
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* // Normal close
|
|
153
|
+
* ws.close();
|
|
154
|
+
*
|
|
155
|
+
* // Close with reason
|
|
156
|
+
* ws.close(1000, 'Upload completed');
|
|
157
|
+
*
|
|
158
|
+
* // Close due to error
|
|
159
|
+
* ws.close(1011, 'Internal error during upload');
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
close(code?: number, reason?: string): void {
|
|
163
|
+
this.native.close(code, reason);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Creates a factory for browser WebSocket connections.
|
|
169
|
+
*
|
|
170
|
+
* This factory is used by the Uploadista client to create WebSocket connections
|
|
171
|
+
* for real-time features. It wraps the browser's native WebSocket API and provides
|
|
172
|
+
* a consistent interface for the client.
|
|
173
|
+
*
|
|
174
|
+
* The factory creates WebSockets that support:
|
|
175
|
+
* - Real-time upload progress updates
|
|
176
|
+
* - Flow execution status streaming
|
|
177
|
+
* - Live error and event notifications
|
|
178
|
+
* - Bidirectional client-server communication
|
|
179
|
+
*
|
|
180
|
+
* @returns A WebSocketFactory that creates browser-compatible WebSocket connections
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* import { createBrowserWebSocketFactory } from '@uploadista/client-browser';
|
|
185
|
+
*
|
|
186
|
+
* const factory = createBrowserWebSocketFactory();
|
|
187
|
+
*
|
|
188
|
+
* // Create a WebSocket connection
|
|
189
|
+
* const ws = factory.create('wss://api.example.com/ws/upload/123');
|
|
190
|
+
*
|
|
191
|
+
* // Set up event handlers
|
|
192
|
+
* ws.onmessage = (event) => {
|
|
193
|
+
* const data = JSON.parse(event.data);
|
|
194
|
+
* if (data.type === 'progress') {
|
|
195
|
+
* console.log('Upload progress:', data.progress);
|
|
196
|
+
* }
|
|
197
|
+
* };
|
|
198
|
+
*
|
|
199
|
+
* ws.onopen = () => {
|
|
200
|
+
* console.log('WebSocket connected');
|
|
201
|
+
* };
|
|
202
|
+
*
|
|
203
|
+
* ws.onclose = (event) => {
|
|
204
|
+
* console.log('WebSocket closed:', event.code, event.reason);
|
|
205
|
+
* };
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @see {@link BrowserWebSocket} for the WebSocket implementation details
|
|
209
|
+
*/
|
|
210
|
+
export const createBrowserWebSocketFactory = (): WebSocketFactory => ({
|
|
211
|
+
create: (url: string): WebSocketLike => new BrowserWebSocket(url),
|
|
212
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./upload-input";
|
|
@@ -0,0 +1,25 @@
|
|
|
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;
|
|
@@ -0,0 +1,79 @@
|
|
|
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: Blob): Promise<string> {
|
|
60
|
+
try {
|
|
61
|
+
// Read blob as ArrayBuffer
|
|
62
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
63
|
+
|
|
64
|
+
// Compute SHA-256 hash using Web Crypto API
|
|
65
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", arrayBuffer);
|
|
66
|
+
|
|
67
|
+
// Convert hash to hex string
|
|
68
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
69
|
+
const hashHex = hashArray
|
|
70
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
71
|
+
.join("");
|
|
72
|
+
|
|
73
|
+
return hashHex;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Failed to compute file checksum: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@uploadista/typescript-config/base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"lib": ["ES2020", "DOM"],
|
|
5
|
+
"baseUrl": "./",
|
|
6
|
+
"paths": {
|
|
7
|
+
"@/*": ["./src/*"]
|
|
8
|
+
},
|
|
9
|
+
"typeRoots": ["../../node_modules/@types"],
|
|
10
|
+
"types": [],
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"rootDir": "./src"
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts"],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"node_modules",
|
|
17
|
+
"dist",
|
|
18
|
+
"**/__tests__/**",
|
|
19
|
+
"**/*.test.ts",
|
|
20
|
+
"**/*.spec.ts"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/framework-utils.ts","./src/http-client.ts","./src/index.ts","./src/client/create-uploadista-client.ts","./src/client/index.ts","./src/services/abort-controller-factory.ts","./src/services/checksum-service.ts","./src/services/create-browser-services.ts","./src/services/file-reader.ts","./src/services/fingerprint-service.ts","./src/services/platform-service.ts","./src/services/websocket-factory.ts","./src/services/id-generation/id-generation.ts","./src/services/storage/local-storage-service.ts","./src/services/storage/session-storage-service.ts","./src/types/index.ts","./src/types/upload-input.ts","./src/utils/hash-util.ts"],"version":"5.9.3"}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
8
|
+
exclude: ['node_modules', 'dist'],
|
|
9
|
+
coverage: {
|
|
10
|
+
provider: 'v8',
|
|
11
|
+
reporter: ['text', 'json', 'html'],
|
|
12
|
+
exclude: ['node_modules/', 'dist/', '**/*.d.ts', '**/*.test.ts', '**/*.spec.ts']
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
});
|