wolfronix-sdk 1.3.1 → 2.3.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.d.ts CHANGED
@@ -3,13 +3,15 @@
3
3
  * Zero-knowledge encryption made simple
4
4
  *
5
5
  * @package @wolfronix/sdk
6
- * @version 1.3.0
6
+ * @version 2.3.0
7
7
  */
8
8
  interface WolfronixConfig {
9
9
  /** Wolfronix server base URL */
10
10
  baseUrl: string;
11
11
  /** Your enterprise client ID (optional for self-hosted) */
12
12
  clientId?: string;
13
+ /** API key for authentication (X-Wolfronix-Key header) */
14
+ wolfronixKey?: string;
13
15
  /** Request timeout in milliseconds (default: 30000) */
14
16
  timeout?: number;
15
17
  /** Retry failed requests (default: 3) */
@@ -44,6 +46,11 @@ interface DeleteResponse {
44
46
  success: boolean;
45
47
  message: string;
46
48
  }
49
+ interface KeyPartResponse {
50
+ file_id: string;
51
+ key_part_a: string;
52
+ message: string;
53
+ }
47
54
  interface MetricsResponse {
48
55
  success: boolean;
49
56
  total_encryptions: number;
@@ -56,6 +63,51 @@ interface EncryptMessagePacket {
56
63
  iv: string;
57
64
  msg: string;
58
65
  }
66
+ interface ServerEncryptResult {
67
+ /** Base64-encoded ciphertext */
68
+ encrypted_message: string;
69
+ /** Base64-encoded nonce */
70
+ nonce: string;
71
+ /** Base64-encoded client key half (Layer 4) or full key (Layer 3) */
72
+ key_part_a: string;
73
+ /** Tag for server's key_part_b lookup (Layer 4 only, empty for Layer 3) */
74
+ message_tag: string;
75
+ /** Unix timestamp */
76
+ timestamp: number;
77
+ }
78
+ interface ServerDecryptParams {
79
+ /** Base64-encoded ciphertext (from ServerEncryptResult) */
80
+ encryptedMessage: string;
81
+ /** Base64-encoded nonce */
82
+ nonce: string;
83
+ /** Base64-encoded key_part_a */
84
+ keyPartA: string;
85
+ /** Message tag for Layer 4 (omit for Layer 3) */
86
+ messageTag?: string;
87
+ }
88
+ interface ServerBatchEncryptResult {
89
+ results: Array<{
90
+ id: string;
91
+ encrypted_message: string;
92
+ nonce: string;
93
+ seq: number;
94
+ }>;
95
+ /** Shared key_part_a for the batch */
96
+ key_part_a: string;
97
+ /** Shared batch tag for key_part_b lookup (Layer 4) */
98
+ batch_tag: string;
99
+ timestamp: number;
100
+ }
101
+ interface StreamSession {
102
+ /** Client's key half (encrypt direction only) */
103
+ keyPartA?: string;
104
+ /** Stream tag for the session */
105
+ streamTag?: string;
106
+ }
107
+ interface StreamChunk {
108
+ data: string;
109
+ seq: number;
110
+ }
59
111
  declare class WolfronixError extends Error {
60
112
  readonly code: string;
61
113
  readonly statusCode?: number;
@@ -85,6 +137,8 @@ declare class Wolfronix {
85
137
  private publicKey;
86
138
  private privateKey;
87
139
  private publicKeyPEM;
140
+ /** Expose private key status for testing */
141
+ hasPrivateKey(): boolean;
88
142
  /**
89
143
  * Create a new Wolfronix client
90
144
  *
@@ -156,7 +210,14 @@ declare class Wolfronix {
156
210
  */
157
211
  encrypt(file: File | Blob | ArrayBuffer | Uint8Array, filename?: string): Promise<EncryptResponse>;
158
212
  /**
159
- * Decrypt and retrieve a file
213
+ * Decrypt and retrieve a file using zero-knowledge flow.
214
+ *
215
+ * Flow:
216
+ * 1. GET /api/v1/files/{id}/key → encrypted key_part_a
217
+ * 2. Decrypt key_part_a client-side with private key (RSA-OAEP)
218
+ * 3. POST /api/v1/files/{id}/decrypt with { decrypted_key_a } in body
219
+ *
220
+ * The private key NEVER leaves the client.
160
221
  *
161
222
  * @example
162
223
  * ```typescript
@@ -169,11 +230,18 @@ declare class Wolfronix {
169
230
  * fs.writeFileSync('decrypted.pdf', buffer);
170
231
  * ```
171
232
  */
172
- decrypt(fileId: string): Promise<Blob>;
233
+ decrypt(fileId: string, role?: string): Promise<Blob>;
173
234
  /**
174
- * Decrypt and return as ArrayBuffer
235
+ * Decrypt and return as ArrayBuffer (zero-knowledge flow)
175
236
  */
176
- decryptToBuffer(fileId: string): Promise<ArrayBuffer>;
237
+ decryptToBuffer(fileId: string, role?: string): Promise<ArrayBuffer>;
238
+ /**
239
+ * Fetch the encrypted key_part_a for a file (for client-side decryption)
240
+ *
241
+ * @param fileId The file ID to get the key for
242
+ * @returns KeyPartResponse containing the RSA-OAEP encrypted key_part_a
243
+ */
244
+ getFileKey(fileId: string): Promise<KeyPartResponse>;
177
245
  /**
178
246
  * List all encrypted files for current user
179
247
  *
@@ -196,8 +264,9 @@ declare class Wolfronix {
196
264
  /**
197
265
  * Get another user's public key (for E2E encryption)
198
266
  * @param userId The ID of the recipient
267
+ * @param clientId Optional: override the configured clientId
199
268
  */
200
- getPublicKey(userId: string): Promise<string>;
269
+ getPublicKey(userId: string, clientId?: string): Promise<string>;
201
270
  /**
202
271
  * Encrypt a short text message for a recipient (Hybrid Encryption: RSA + AES)
203
272
  * Returns a secure JSON string (packet) to send via chat
@@ -212,6 +281,105 @@ declare class Wolfronix {
212
281
  * @param packetJson The secure JSON string packet
213
282
  */
214
283
  decryptMessage(packetJson: string): Promise<string>;
284
+ /**
285
+ * Encrypt a text message via the Wolfronix server (dual-key split).
286
+ * The server generates an AES key, encrypts the message, and splits the key —
287
+ * you get key_part_a, the server holds key_part_b.
288
+ *
289
+ * Use this for server-managed message encryption (e.g., stored encrypted messages).
290
+ * For true E2E (where the server never sees plaintext), use encryptMessage() instead.
291
+ *
292
+ * @param message The plaintext message to encrypt
293
+ * @param options.layer 3 = AES only (full key returned), 4 = dual-key split (default)
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * const result = await wfx.serverEncrypt('Hello, World!');
298
+ * // Store result.encrypted_message, result.nonce, result.key_part_a, result.message_tag
299
+ * ```
300
+ */
301
+ serverEncrypt(message: string, options?: {
302
+ layer?: number;
303
+ }): Promise<ServerEncryptResult>;
304
+ /**
305
+ * Decrypt a message previously encrypted via serverEncrypt().
306
+ *
307
+ * @param params The encrypted message data (from serverEncrypt result)
308
+ * @returns The decrypted plaintext message
309
+ *
310
+ * @example
311
+ * ```typescript
312
+ * const text = await wfx.serverDecrypt({
313
+ * encryptedMessage: result.encrypted_message,
314
+ * nonce: result.nonce,
315
+ * keyPartA: result.key_part_a,
316
+ * messageTag: result.message_tag,
317
+ * });
318
+ * ```
319
+ */
320
+ serverDecrypt(params: ServerDecryptParams): Promise<string>;
321
+ /**
322
+ * Encrypt multiple messages in a single round-trip (batch).
323
+ * All messages share one AES key (different nonce per message).
324
+ * Efficient for chat history encryption or bulk operations.
325
+ *
326
+ * @param messages Array of { id, message } objects (max 100)
327
+ * @param options.layer 3 or 4 (default: 4)
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * const result = await wfx.serverEncryptBatch([
332
+ * { id: 'msg1', message: 'Hello' },
333
+ * { id: 'msg2', message: 'World' },
334
+ * ]);
335
+ * // result.results[0].encrypted_message, result.key_part_a, result.batch_tag
336
+ * ```
337
+ */
338
+ serverEncryptBatch(messages: Array<{
339
+ id: string;
340
+ message: string;
341
+ }>, options?: {
342
+ layer?: number;
343
+ }): Promise<ServerBatchEncryptResult>;
344
+ /**
345
+ * Decrypt a single message from a batch result.
346
+ * Uses the shared key_part_a and batch_tag from the batch result.
347
+ *
348
+ * @param batchResult The batch encrypt result
349
+ * @param index The index of the message to decrypt
350
+ */
351
+ serverDecryptBatchItem(batchResult: ServerBatchEncryptResult, index: number): Promise<string>;
352
+ /**
353
+ * Create a streaming encryption/decryption session over WebSocket.
354
+ * Data flows in real-time: send chunks, receive encrypted/decrypted chunks back.
355
+ *
356
+ * @param direction 'encrypt' for plaintext→ciphertext, 'decrypt' for reverse
357
+ * @param streamKey Required for decrypt — the key_part_a and stream_tag from the encrypt session
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * // Encrypt stream
362
+ * const stream = await wfx.createStream('encrypt');
363
+ * stream.onData((chunk, seq) => console.log('Encrypted chunk', seq));
364
+ * stream.send('Hello chunk 1');
365
+ * stream.send('Hello chunk 2');
366
+ * const summary = await stream.end();
367
+ * // Save stream.keyPartA and stream.streamTag for decryption
368
+ *
369
+ * // Decrypt stream
370
+ * const dStream = await wfx.createStream('decrypt', {
371
+ * keyPartA: stream.keyPartA!,
372
+ * streamTag: stream.streamTag!,
373
+ * });
374
+ * dStream.onData((chunk, seq) => console.log('Decrypted:', chunk));
375
+ * dStream.send(encryptedChunk1);
376
+ * await dStream.end();
377
+ * ```
378
+ */
379
+ createStream(direction: 'encrypt' | 'decrypt', streamKey?: {
380
+ keyPartA: string;
381
+ streamTag: string;
382
+ }): Promise<WolfronixStream>;
215
383
  /**
216
384
  * Get encryption/decryption metrics
217
385
  *
@@ -227,6 +395,77 @@ declare class Wolfronix {
227
395
  */
228
396
  healthCheck(): Promise<boolean>;
229
397
  }
398
+ type StreamDataCallback = (data: string, seq: number) => void;
399
+ type StreamErrorCallback = (error: Error) => void;
400
+ /**
401
+ * Real-time streaming encryption/decryption over WebSocket.
402
+ * Each chunk is individually encrypted with AES-256-GCM using counter-based nonces.
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * const stream = await wfx.createStream('encrypt');
407
+ * stream.onData((chunk, seq) => sendToRecipient(chunk));
408
+ * stream.onError((err) => console.error(err));
409
+ * await stream.send('audio chunk data...');
410
+ * const summary = await stream.end();
411
+ * ```
412
+ */
413
+ declare class WolfronixStream {
414
+ private readonly config;
415
+ private readonly userId;
416
+ private ws;
417
+ private dataCallbacks;
418
+ private errorCallbacks;
419
+ private pendingChunks;
420
+ private seqCounter;
421
+ /** Client's key half (available after encrypt stream init) */
422
+ keyPartA: string | null;
423
+ /** Stream tag (available after encrypt stream init) */
424
+ streamTag: string | null;
425
+ /** @internal */
426
+ constructor(config: Required<WolfronixConfig>, userId: string);
427
+ /** @internal Connect and initialize the stream session */
428
+ connect(direction: 'encrypt' | 'decrypt', streamKey?: {
429
+ keyPartA: string;
430
+ streamTag: string;
431
+ }): Promise<void>;
432
+ /**
433
+ * Send a data chunk for encryption/decryption.
434
+ * Returns a promise that resolves with the processed (encrypted/decrypted) chunk.
435
+ *
436
+ * @param data String or base64-encoded binary data
437
+ * @returns The processed chunk (base64-encoded)
438
+ */
439
+ send(data: string): Promise<string>;
440
+ /**
441
+ * Send raw binary data for encryption/decryption.
442
+ *
443
+ * @param buffer ArrayBuffer or Uint8Array
444
+ * @returns The processed chunk (base64-encoded)
445
+ */
446
+ sendBinary(buffer: ArrayBuffer | Uint8Array): Promise<string>;
447
+ /**
448
+ * Register a callback for incoming data chunks.
449
+ *
450
+ * @param callback Called with (base64Data, sequenceNumber) for each chunk
451
+ */
452
+ onData(callback: StreamDataCallback): void;
453
+ /**
454
+ * Register a callback for stream errors.
455
+ */
456
+ onError(callback: StreamErrorCallback): void;
457
+ /**
458
+ * End the stream session. Returns the total number of chunks processed.
459
+ */
460
+ end(): Promise<{
461
+ chunksProcessed: number;
462
+ }>;
463
+ /**
464
+ * Close the stream immediately without sending an end message.
465
+ */
466
+ close(): void;
467
+ private isBase64;
468
+ }
230
469
  /**
231
470
  * Create a new Wolfronix client
232
471
  *
@@ -242,4 +481,4 @@ declare class Wolfronix {
242
481
  */
243
482
  declare function createClient(config: WolfronixConfig | string): Wolfronix;
244
483
 
245
- export { type AuthResponse, AuthenticationError, type DeleteResponse, type EncryptMessagePacket, type EncryptResponse, type FileInfo, FileNotFoundError, type ListFilesResponse, type MetricsResponse, NetworkError, PermissionDeniedError, ValidationError, Wolfronix, type WolfronixConfig, WolfronixError, createClient, Wolfronix as default };
484
+ export { type AuthResponse, AuthenticationError, type DeleteResponse, type EncryptMessagePacket, type EncryptResponse, type FileInfo, FileNotFoundError, type KeyPartResponse, type ListFilesResponse, type MetricsResponse, NetworkError, PermissionDeniedError, type ServerBatchEncryptResult, type ServerDecryptParams, type ServerEncryptResult, type StreamChunk, type StreamSession, ValidationError, Wolfronix, type WolfronixConfig, WolfronixError, WolfronixStream, createClient, Wolfronix as default };