wolfronix-sdk 1.0.0

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/dist/index.js ADDED
@@ -0,0 +1,505 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthenticationError: () => AuthenticationError,
24
+ FileNotFoundError: () => FileNotFoundError,
25
+ NetworkError: () => NetworkError,
26
+ PermissionDeniedError: () => PermissionDeniedError,
27
+ ValidationError: () => ValidationError,
28
+ Wolfronix: () => Wolfronix,
29
+ WolfronixError: () => WolfronixError,
30
+ createClient: () => createClient,
31
+ default: () => index_default
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+ var WolfronixError = class extends Error {
35
+ constructor(message, code, statusCode, details) {
36
+ super(message);
37
+ this.name = "WolfronixError";
38
+ this.code = code;
39
+ this.statusCode = statusCode;
40
+ this.details = details;
41
+ }
42
+ };
43
+ var AuthenticationError = class extends WolfronixError {
44
+ constructor(message = "Authentication failed") {
45
+ super(message, "AUTH_ERROR", 401);
46
+ this.name = "AuthenticationError";
47
+ }
48
+ };
49
+ var FileNotFoundError = class extends WolfronixError {
50
+ constructor(fileId) {
51
+ super(`File not found: ${fileId}`, "FILE_NOT_FOUND", 404);
52
+ this.name = "FileNotFoundError";
53
+ }
54
+ };
55
+ var PermissionDeniedError = class extends WolfronixError {
56
+ constructor(message = "Permission denied") {
57
+ super(message, "PERMISSION_DENIED", 403);
58
+ this.name = "PermissionDeniedError";
59
+ }
60
+ };
61
+ var NetworkError = class extends WolfronixError {
62
+ constructor(message = "Network request failed") {
63
+ super(message, "NETWORK_ERROR");
64
+ this.name = "NetworkError";
65
+ }
66
+ };
67
+ var ValidationError = class extends WolfronixError {
68
+ constructor(message) {
69
+ super(message, "VALIDATION_ERROR", 400);
70
+ this.name = "ValidationError";
71
+ }
72
+ };
73
+ var Wolfronix = class {
74
+ /**
75
+ * Create a new Wolfronix client
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const wfx = new Wolfronix({
80
+ * baseUrl: 'https://wolfronix-server:5002',
81
+ * clientId: 'your-client-id'
82
+ * });
83
+ * ```
84
+ */
85
+ constructor(config) {
86
+ this.token = null;
87
+ this.userId = null;
88
+ this.tokenExpiry = null;
89
+ if (typeof config === "string") {
90
+ this.config = {
91
+ baseUrl: config,
92
+ clientId: "",
93
+ timeout: 3e4,
94
+ retries: 3,
95
+ insecure: false
96
+ };
97
+ } else {
98
+ this.config = {
99
+ baseUrl: config.baseUrl,
100
+ clientId: config.clientId || "",
101
+ timeout: config.timeout || 3e4,
102
+ retries: config.retries || 3,
103
+ insecure: config.insecure || false
104
+ };
105
+ }
106
+ this.config.baseUrl = this.config.baseUrl.replace(/\/$/, "");
107
+ }
108
+ // ==========================================================================
109
+ // Private Helpers
110
+ // ==========================================================================
111
+ getHeaders(includeAuth = true) {
112
+ const headers = {
113
+ "Accept": "application/json"
114
+ };
115
+ if (this.config.clientId) {
116
+ headers["X-Client-ID"] = this.config.clientId;
117
+ }
118
+ if (includeAuth && this.token) {
119
+ headers["Authorization"] = `Bearer ${this.token}`;
120
+ }
121
+ return headers;
122
+ }
123
+ async request(method, endpoint, options = {}) {
124
+ const { body, formData, includeAuth = true, responseType = "json" } = options;
125
+ const url = `${this.config.baseUrl}${endpoint}`;
126
+ const headers = this.getHeaders(includeAuth);
127
+ if (body && !formData) {
128
+ headers["Content-Type"] = "application/json";
129
+ }
130
+ let lastError = null;
131
+ for (let attempt = 1; attempt <= this.config.retries; attempt++) {
132
+ try {
133
+ const controller = new AbortController();
134
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
135
+ const fetchOptions = {
136
+ method,
137
+ headers,
138
+ signal: controller.signal
139
+ };
140
+ if (formData) {
141
+ fetchOptions.body = formData;
142
+ } else if (body) {
143
+ fetchOptions.body = JSON.stringify(body);
144
+ }
145
+ const response = await fetch(url, fetchOptions);
146
+ clearTimeout(timeoutId);
147
+ if (!response.ok) {
148
+ const errorBody = await response.json().catch(() => ({}));
149
+ if (response.status === 401) {
150
+ throw new AuthenticationError(errorBody.error || "Authentication failed");
151
+ }
152
+ if (response.status === 403) {
153
+ throw new PermissionDeniedError(errorBody.error || "Permission denied");
154
+ }
155
+ if (response.status === 404) {
156
+ throw new FileNotFoundError(endpoint);
157
+ }
158
+ throw new WolfronixError(
159
+ errorBody.error || `Request failed with status ${response.status}`,
160
+ "REQUEST_ERROR",
161
+ response.status,
162
+ errorBody
163
+ );
164
+ }
165
+ if (responseType === "blob") {
166
+ return await response.blob();
167
+ }
168
+ if (responseType === "arraybuffer") {
169
+ return await response.arrayBuffer();
170
+ }
171
+ return await response.json();
172
+ } catch (error) {
173
+ lastError = error;
174
+ if (error instanceof AuthenticationError || error instanceof PermissionDeniedError || error instanceof FileNotFoundError) {
175
+ throw error;
176
+ }
177
+ if (attempt < this.config.retries) {
178
+ await this.sleep(Math.pow(2, attempt) * 100);
179
+ continue;
180
+ }
181
+ }
182
+ }
183
+ throw lastError || new NetworkError("Request failed after retries");
184
+ }
185
+ sleep(ms) {
186
+ return new Promise((resolve) => setTimeout(resolve, ms));
187
+ }
188
+ ensureAuthenticated() {
189
+ if (!this.token) {
190
+ throw new AuthenticationError("Not authenticated. Call login() or register() first.");
191
+ }
192
+ }
193
+ // ==========================================================================
194
+ // Authentication Methods
195
+ // ==========================================================================
196
+ /**
197
+ * Register a new user
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * const { user_id, token } = await wfx.register('user@example.com', 'password123');
202
+ * ```
203
+ */
204
+ async register(email, password) {
205
+ if (!email || !password) {
206
+ throw new ValidationError("Email and password are required");
207
+ }
208
+ const response = await this.request("POST", "/api/v1/register", {
209
+ body: { email, password },
210
+ includeAuth: false
211
+ });
212
+ if (response.success) {
213
+ this.token = response.token;
214
+ this.userId = response.user_id;
215
+ this.tokenExpiry = new Date(Date.now() + 24 * 60 * 60 * 1e3);
216
+ }
217
+ return response;
218
+ }
219
+ /**
220
+ * Login with existing credentials
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * await wfx.login('user@example.com', 'password123');
225
+ * ```
226
+ */
227
+ async login(email, password) {
228
+ if (!email || !password) {
229
+ throw new ValidationError("Email and password are required");
230
+ }
231
+ const response = await this.request("POST", "/api/v1/login", {
232
+ body: { email, password },
233
+ includeAuth: false
234
+ });
235
+ if (response.success) {
236
+ this.token = response.token;
237
+ this.userId = response.user_id;
238
+ this.tokenExpiry = new Date(Date.now() + 24 * 60 * 60 * 1e3);
239
+ }
240
+ return response;
241
+ }
242
+ /**
243
+ * Set authentication token directly (useful for server-side apps)
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * wfx.setToken('jwt-token-here', 'user-id-here');
248
+ * ```
249
+ */
250
+ setToken(token, userId) {
251
+ this.token = token;
252
+ this.userId = userId || null;
253
+ this.tokenExpiry = new Date(Date.now() + 24 * 60 * 60 * 1e3);
254
+ }
255
+ /**
256
+ * Clear authentication state (logout)
257
+ */
258
+ logout() {
259
+ this.token = null;
260
+ this.userId = null;
261
+ this.tokenExpiry = null;
262
+ }
263
+ /**
264
+ * Check if client is authenticated
265
+ */
266
+ isAuthenticated() {
267
+ return !!this.token && (!this.tokenExpiry || this.tokenExpiry > /* @__PURE__ */ new Date());
268
+ }
269
+ /**
270
+ * Get current user ID
271
+ */
272
+ getUserId() {
273
+ return this.userId;
274
+ }
275
+ // ==========================================================================
276
+ // File Operations
277
+ // ==========================================================================
278
+ /**
279
+ * Encrypt and store a file
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * // Browser
284
+ * const fileInput = document.querySelector('input[type="file"]');
285
+ * const result = await wfx.encrypt(fileInput.files[0]);
286
+ *
287
+ * // Node.js
288
+ * const buffer = fs.readFileSync('document.pdf');
289
+ * const result = await wfx.encrypt(buffer, 'document.pdf');
290
+ * ```
291
+ */
292
+ async encrypt(file, filename) {
293
+ this.ensureAuthenticated();
294
+ const formData = new FormData();
295
+ if (file instanceof File) {
296
+ formData.append("file", file);
297
+ } else if (file instanceof Blob) {
298
+ formData.append("file", file, filename || "file");
299
+ } else if (file instanceof ArrayBuffer) {
300
+ const blob = new Blob([new Uint8Array(file)]);
301
+ formData.append("file", blob, filename || "file");
302
+ } else if (file instanceof Uint8Array) {
303
+ const arrayBuffer = file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength);
304
+ const blob = new Blob([arrayBuffer]);
305
+ formData.append("file", blob, filename || "file");
306
+ } else {
307
+ throw new ValidationError("Invalid file type. Expected File, Blob, Buffer, or ArrayBuffer");
308
+ }
309
+ formData.append("user_id", this.userId || "");
310
+ return this.request("POST", "/api/v1/encrypt", {
311
+ formData
312
+ });
313
+ }
314
+ /**
315
+ * Encrypt a file using streaming (for large files)
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * const result = await wfx.encryptStream(largeFile, (progress) => {
320
+ * console.log(`Progress: ${progress}%`);
321
+ * });
322
+ * ```
323
+ */
324
+ async encryptStream(file, onProgress) {
325
+ this.ensureAuthenticated();
326
+ const tokenResponse = await this.request("POST", "/api/v1/stream/token", {
327
+ body: {
328
+ user_id: this.userId,
329
+ client_id: this.config.clientId
330
+ }
331
+ });
332
+ const formData = new FormData();
333
+ formData.append("file", file);
334
+ formData.append("user_id", this.userId || "");
335
+ formData.append("stream_token", tokenResponse.token);
336
+ if (onProgress && typeof XMLHttpRequest !== "undefined") {
337
+ return new Promise((resolve, reject) => {
338
+ const xhr = new XMLHttpRequest();
339
+ xhr.upload.onprogress = (event) => {
340
+ if (event.lengthComputable) {
341
+ onProgress(Math.round(event.loaded / event.total * 100));
342
+ }
343
+ };
344
+ xhr.onload = () => {
345
+ if (xhr.status >= 200 && xhr.status < 300) {
346
+ resolve(JSON.parse(xhr.responseText));
347
+ } else {
348
+ reject(new WolfronixError("Upload failed", "UPLOAD_ERROR", xhr.status));
349
+ }
350
+ };
351
+ xhr.onerror = () => reject(new NetworkError("Upload failed"));
352
+ xhr.open("POST", `${this.config.baseUrl}/api/v1/stream/encrypt`);
353
+ const headers = this.getHeaders();
354
+ Object.entries(headers).forEach(([key, value]) => {
355
+ xhr.setRequestHeader(key, value);
356
+ });
357
+ xhr.send(formData);
358
+ });
359
+ }
360
+ return this.request("POST", "/api/v1/stream/encrypt", {
361
+ formData
362
+ });
363
+ }
364
+ /**
365
+ * Decrypt and retrieve a file
366
+ *
367
+ * @example
368
+ * ```typescript
369
+ * // Get as Blob (browser)
370
+ * const blob = await wfx.decrypt('file-id');
371
+ * const url = URL.createObjectURL(blob);
372
+ *
373
+ * // Get as Buffer (Node.js)
374
+ * const buffer = await wfx.decryptToBuffer('file-id');
375
+ * fs.writeFileSync('decrypted.pdf', buffer);
376
+ * ```
377
+ */
378
+ async decrypt(fileId) {
379
+ this.ensureAuthenticated();
380
+ if (!fileId) {
381
+ throw new ValidationError("File ID is required");
382
+ }
383
+ return this.request("GET", `/api/v1/decrypt/${fileId}`, {
384
+ responseType: "blob"
385
+ });
386
+ }
387
+ /**
388
+ * Decrypt and return as ArrayBuffer
389
+ */
390
+ async decryptToBuffer(fileId) {
391
+ this.ensureAuthenticated();
392
+ if (!fileId) {
393
+ throw new ValidationError("File ID is required");
394
+ }
395
+ return this.request("GET", `/api/v1/decrypt/${fileId}`, {
396
+ responseType: "arraybuffer"
397
+ });
398
+ }
399
+ /**
400
+ * Decrypt using streaming (for large files)
401
+ */
402
+ async decryptStream(fileId, onProgress) {
403
+ this.ensureAuthenticated();
404
+ if (onProgress && typeof XMLHttpRequest !== "undefined") {
405
+ return new Promise((resolve, reject) => {
406
+ const xhr = new XMLHttpRequest();
407
+ xhr.responseType = "blob";
408
+ xhr.onprogress = (event) => {
409
+ if (event.lengthComputable) {
410
+ onProgress(Math.round(event.loaded / event.total * 100));
411
+ }
412
+ };
413
+ xhr.onload = () => {
414
+ if (xhr.status >= 200 && xhr.status < 300) {
415
+ resolve(xhr.response);
416
+ } else {
417
+ reject(new WolfronixError("Download failed", "DOWNLOAD_ERROR", xhr.status));
418
+ }
419
+ };
420
+ xhr.onerror = () => reject(new NetworkError("Download failed"));
421
+ xhr.open("GET", `${this.config.baseUrl}/api/v1/stream/decrypt/${fileId}`);
422
+ const headers = this.getHeaders();
423
+ Object.entries(headers).forEach(([key, value]) => {
424
+ xhr.setRequestHeader(key, value);
425
+ });
426
+ xhr.send();
427
+ });
428
+ }
429
+ return this.request("GET", `/api/v1/stream/decrypt/${fileId}`, {
430
+ responseType: "blob"
431
+ });
432
+ }
433
+ /**
434
+ * List all encrypted files for current user
435
+ *
436
+ * @example
437
+ * ```typescript
438
+ * const { files } = await wfx.listFiles();
439
+ * files.forEach(f => console.log(f.original_name, f.file_id));
440
+ * ```
441
+ */
442
+ async listFiles() {
443
+ this.ensureAuthenticated();
444
+ return this.request("GET", "/api/v1/files");
445
+ }
446
+ /**
447
+ * Delete an encrypted file
448
+ *
449
+ * @example
450
+ * ```typescript
451
+ * await wfx.deleteFile('file-id');
452
+ * ```
453
+ */
454
+ async deleteFile(fileId) {
455
+ this.ensureAuthenticated();
456
+ if (!fileId) {
457
+ throw new ValidationError("File ID is required");
458
+ }
459
+ return this.request("DELETE", `/api/v1/files/${fileId}`);
460
+ }
461
+ // ==========================================================================
462
+ // Metrics & Status
463
+ // ==========================================================================
464
+ /**
465
+ * Get encryption/decryption metrics
466
+ *
467
+ * @example
468
+ * ```typescript
469
+ * const metrics = await wfx.getMetrics();
470
+ * console.log(`Total encryptions: ${metrics.total_encryptions}`);
471
+ * ```
472
+ */
473
+ async getMetrics() {
474
+ this.ensureAuthenticated();
475
+ return this.request("GET", "/api/v1/metrics");
476
+ }
477
+ /**
478
+ * Check if server is healthy
479
+ */
480
+ async healthCheck() {
481
+ try {
482
+ await this.request("GET", "/health", {
483
+ includeAuth: false
484
+ });
485
+ return true;
486
+ } catch {
487
+ return false;
488
+ }
489
+ }
490
+ };
491
+ function createClient(config) {
492
+ return new Wolfronix(config);
493
+ }
494
+ var index_default = Wolfronix;
495
+ // Annotate the CommonJS export names for ESM import in node:
496
+ 0 && (module.exports = {
497
+ AuthenticationError,
498
+ FileNotFoundError,
499
+ NetworkError,
500
+ PermissionDeniedError,
501
+ ValidationError,
502
+ Wolfronix,
503
+ WolfronixError,
504
+ createClient
505
+ });