@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.
Files changed (83) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-check.log +130 -0
  3. package/AUTO_CAPABILITIES.md +98 -0
  4. package/FRAMEWORK_INTEGRATION.md +407 -0
  5. package/LICENSE +21 -0
  6. package/README.md +795 -0
  7. package/SMART_CHUNKING.md +140 -0
  8. package/dist/client/create-uploadista-client.d.ts +182 -0
  9. package/dist/client/create-uploadista-client.d.ts.map +1 -0
  10. package/dist/client/create-uploadista-client.js +76 -0
  11. package/dist/client/index.d.ts +2 -0
  12. package/dist/client/index.d.ts.map +1 -0
  13. package/dist/client/index.js +1 -0
  14. package/dist/framework-utils.d.ts +201 -0
  15. package/dist/framework-utils.d.ts.map +1 -0
  16. package/dist/framework-utils.js +282 -0
  17. package/dist/http-client.d.ts +44 -0
  18. package/dist/http-client.d.ts.map +1 -0
  19. package/dist/http-client.js +489 -0
  20. package/dist/index.d.ts +8 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +7 -0
  23. package/dist/services/abort-controller-factory.d.ts +30 -0
  24. package/dist/services/abort-controller-factory.d.ts.map +1 -0
  25. package/dist/services/abort-controller-factory.js +98 -0
  26. package/dist/services/checksum-service.d.ts +30 -0
  27. package/dist/services/checksum-service.d.ts.map +1 -0
  28. package/dist/services/checksum-service.js +44 -0
  29. package/dist/services/create-browser-services.d.ts +36 -0
  30. package/dist/services/create-browser-services.d.ts.map +1 -0
  31. package/dist/services/create-browser-services.js +56 -0
  32. package/dist/services/file-reader.d.ts +91 -0
  33. package/dist/services/file-reader.d.ts.map +1 -0
  34. package/dist/services/file-reader.js +251 -0
  35. package/dist/services/fingerprint-service.d.ts +41 -0
  36. package/dist/services/fingerprint-service.d.ts.map +1 -0
  37. package/dist/services/fingerprint-service.js +64 -0
  38. package/dist/services/id-generation/id-generation.d.ts +40 -0
  39. package/dist/services/id-generation/id-generation.d.ts.map +1 -0
  40. package/dist/services/id-generation/id-generation.js +58 -0
  41. package/dist/services/platform-service.d.ts +38 -0
  42. package/dist/services/platform-service.d.ts.map +1 -0
  43. package/dist/services/platform-service.js +221 -0
  44. package/dist/services/storage/local-storage-service.d.ts +55 -0
  45. package/dist/services/storage/local-storage-service.d.ts.map +1 -0
  46. package/dist/services/storage/local-storage-service.js +178 -0
  47. package/dist/services/storage/session-storage-service.d.ts +55 -0
  48. package/dist/services/storage/session-storage-service.d.ts.map +1 -0
  49. package/dist/services/storage/session-storage-service.js +179 -0
  50. package/dist/services/websocket-factory.d.ts +46 -0
  51. package/dist/services/websocket-factory.d.ts.map +1 -0
  52. package/dist/services/websocket-factory.js +196 -0
  53. package/dist/types/index.d.ts +2 -0
  54. package/dist/types/index.d.ts.map +1 -0
  55. package/dist/types/index.js +1 -0
  56. package/dist/types/upload-input.d.ts +26 -0
  57. package/dist/types/upload-input.d.ts.map +1 -0
  58. package/dist/types/upload-input.js +1 -0
  59. package/dist/utils/hash-util.d.ts +60 -0
  60. package/dist/utils/hash-util.d.ts.map +1 -0
  61. package/dist/utils/hash-util.js +75 -0
  62. package/package.json +32 -0
  63. package/src/client/create-uploadista-client.ts +150 -0
  64. package/src/client/index.ts +1 -0
  65. package/src/framework-utils.ts +446 -0
  66. package/src/http-client.ts +546 -0
  67. package/src/index.ts +8 -0
  68. package/src/services/abort-controller-factory.ts +108 -0
  69. package/src/services/checksum-service.ts +46 -0
  70. package/src/services/create-browser-services.ts +81 -0
  71. package/src/services/file-reader.ts +344 -0
  72. package/src/services/fingerprint-service.ts +67 -0
  73. package/src/services/id-generation/id-generation.ts +60 -0
  74. package/src/services/platform-service.ts +231 -0
  75. package/src/services/storage/local-storage-service.ts +187 -0
  76. package/src/services/storage/session-storage-service.ts +188 -0
  77. package/src/services/websocket-factory.ts +212 -0
  78. package/src/types/index.ts +1 -0
  79. package/src/types/upload-input.ts +25 -0
  80. package/src/utils/hash-util.ts +79 -0
  81. package/tsconfig.json +22 -0
  82. package/tsconfig.tsbuildinfo +1 -0
  83. 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"}
@@ -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
+ });