@massalabs/gossip-sdk 0.0.2-dev.20260211140005 → 0.0.2-dev.20260211172752

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/README.md CHANGED
@@ -47,9 +47,8 @@ await gossipSdk.openSession({
47
47
  mnemonic: 'word1 word2 word3 ... word12',
48
48
  // For existing session:
49
49
  encryptedSession: savedBlob,
50
- encryptionKey: savedKey,
50
+ encryptionKey,
51
51
  // For persistence:
52
- persistEncryptionKey: encryptionKey,
53
52
  onPersist: async (blob, key) => {
54
53
  await saveToStorage(blob, key);
55
54
  },
@@ -113,7 +112,7 @@ await gossipSdk.openSession({
113
112
  // With persistence (saves session on changes)
114
113
  await gossipSdk.openSession({
115
114
  mnemonic: 'word1 word2 word3 ... word12',
116
- persistEncryptionKey: encryptionKey,
115
+ encryptionKey,
117
116
  onPersist: async (blob, key) => {
118
117
  await db.userProfile.update(userId, { session: blob });
119
118
  },
@@ -387,25 +386,16 @@ const decoded = utils.decodeUserId(encodedString);
387
386
 
388
387
  ## Session Persistence
389
388
 
390
- For restoring sessions across app restarts:
389
+ For restoring sessions across app restarts, pass `encryptionKey` and `onPersist` when opening the session:
391
390
 
392
391
  ```typescript
393
- // Option 1: Provide persistence config in openSession
394
392
  await gossipSdk.openSession({
395
393
  mnemonic,
396
- persistEncryptionKey: key,
394
+ encryptionKey,
397
395
  onPersist: async (blob, key) => {
398
- // Save blob to your storage
399
396
  await db.userProfile.update(userId, { session: blob });
400
397
  },
401
398
  });
402
-
403
- // Option 2: Configure persistence after account creation
404
- await gossipSdk.openSession({ mnemonic });
405
- // ... create account, get encryption key ...
406
- gossipSdk.configurePersistence(encryptionKey, async (blob, key) => {
407
- await db.userProfile.update(userId, { session: blob });
408
- });
409
399
  ```
410
400
 
411
401
  ## Auto-Renewal Behavior
@@ -40,7 +40,6 @@
40
40
  */
41
41
  import { GossipDatabase, type Contact, type Discussion, type Message } from './db';
42
42
  import { type SdkConfig, type DeepPartial } from './config/sdk';
43
- import { SessionStatus, SessionConfig } from './assets/generated/wasm/gossip_wasm';
44
43
  import { EncryptionKey } from './wasm/encryption';
45
44
  import { type AnnouncementReceptionResult } from './services/announcement';
46
45
  import { discussionInitializationResult } from './services/discussion';
@@ -48,7 +47,7 @@ import { type MessageResult, type SendMessageResult } from './services/message';
48
47
  import { AuthService } from './services/auth';
49
48
  import type { DeleteContactResult, UpdateContactNameResult } from './utils/contacts';
50
49
  import { type ValidationResult } from './utils/validation';
51
- import type { UserPublicKeys } from './wasm/bindings';
50
+ import { type UserPublicKeys, SessionStatus, SessionConfig } from './wasm/bindings';
52
51
  import { SdkEventType, type SdkEventHandlers } from './core/SdkEventEmitter';
53
52
  import { AnnouncementPayload } from './utils/announcementPayload';
54
53
  import { Result } from './utils/type';
@@ -72,12 +71,10 @@ export interface OpenSessionOptions {
72
71
  mnemonic: string;
73
72
  /** Existing encrypted session blob (for restoring session) */
74
73
  encryptedSession?: Uint8Array;
75
- /** Encryption key for decrypting session */
74
+ /** Encryption key for decrypting session and storage. Will be created if not provided. */
76
75
  encryptionKey?: EncryptionKey;
77
76
  /** Callback when session state changes (for persistence) */
78
77
  onPersist?: (encryptedBlob: Uint8Array, encryptionKey: EncryptionKey) => Promise<void>;
79
- /** Encryption key for persisting session (required if onPersist is provided) */
80
- persistEncryptionKey?: EncryptionKey;
81
78
  /** Custom session configuration (optional, uses defaults if not provided) */
82
79
  sessionConfig?: SessionConfig;
83
80
  }
@@ -127,15 +124,7 @@ declare class GossipSdkImpl {
127
124
  * Get encrypted session blob for persistence.
128
125
  * Throws if no session is open.
129
126
  */
130
- getEncryptedSession(encryptionKey: EncryptionKey): Uint8Array;
131
- /**
132
- * Configure session persistence after session is opened.
133
- * Use this when you need to set up persistence after account creation.
134
- *
135
- * @param encryptionKey - Key to encrypt session blob
136
- * @param onPersist - Callback to save encrypted session blob
137
- */
138
- configurePersistence(encryptionKey: EncryptionKey, onPersist: (encryptedBlob: Uint8Array, encryptionKey: EncryptionKey) => Promise<void>): void;
127
+ getEncryptedSession(): Uint8Array;
139
128
  /** Auth service (available after init, before session) */
140
129
  get auth(): AuthService;
141
130
  /** Message service */
package/dist/gossipSdk.js CHANGED
@@ -45,6 +45,7 @@ import { defaultSdkConfig, mergeConfig, } from './config/sdk';
45
45
  import { startWasmInitialization, ensureWasmInitialized } from './wasm/loader';
46
46
  import { generateUserKeys } from './wasm/userKeys';
47
47
  import { SessionModule } from './wasm/session';
48
+ import { generateEncryptionKeyFromSeed, } from './wasm/encryption';
48
49
  import { AnnouncementService, } from './services/announcement';
49
50
  import { DiscussionService, } from './services/discussion';
50
51
  import { MessageService, } from './services/message';
@@ -54,6 +55,7 @@ import { validateUserIdFormat, validateUsernameFormat, } from './utils/validatio
54
55
  import { QueueManager } from './utils/queue';
55
56
  import { encodeUserId, decodeUserId } from './utils/userId';
56
57
  import { getContacts, getContact, addContact, updateContactName, deleteContact, } from './contacts';
58
+ import { SessionManagerWrapper, } from './wasm/bindings';
57
59
  import { SdkEventEmitter, SdkEventType, } from './core/SdkEventEmitter';
58
60
  import { SdkPolling } from './core/SdkPolling';
59
61
  export { SdkEventType };
@@ -197,29 +199,25 @@ class GossipSdkImpl {
197
199
  if (this.state.status === SdkStatus.SESSION_OPEN) {
198
200
  throw new Error('Session already open. Call closeSession() first.');
199
201
  }
200
- if (options.encryptedSession && !options.encryptionKey) {
201
- throw new Error('encryptionKey is required when encryptedSession is provided.');
202
- }
203
- if (options.onPersist && !options.persistEncryptionKey) {
204
- throw new Error('persistEncryptionKey is required when onPersist is provided.');
202
+ if (!options.encryptionKey) {
203
+ console.warn('[GossipSdk] No encryptionKey provided. Creating a new one from mnemonic.');
205
204
  }
205
+ const encryptionKey = options.encryptionKey ??
206
+ (await generateEncryptionKeyFromSeed(options.mnemonic, new Uint8Array(32).fill(0)));
206
207
  const { db, messageProtocol } = this.state;
207
- // Validate session restore options - must have both or neither
208
- if (options.encryptedSession && !options.encryptionKey) {
209
- throw new Error('encryptedSession provided without encryptionKey. Session restore requires both.');
210
- }
211
- if (options.encryptionKey && !options.encryptedSession) {
212
- console.warn('[GossipSdk] encryptionKey provided without encryptedSession - key will be ignored');
213
- }
214
- // Validate persistence options - warn if incomplete
215
- if (options.onPersist && !options.persistEncryptionKey) {
216
- console.warn('[GossipSdk] onPersist provided without persistEncryptionKey - session will not be persisted');
217
- }
218
- if (options.persistEncryptionKey && !options.onPersist) {
219
- console.warn('[GossipSdk] persistEncryptionKey provided without onPersist callback - key will be unused');
220
- }
221
- // Ensure WASM is ready
208
+ // Ensure WASM is ready before using any WASM-backed helpers
222
209
  await ensureWasmInitialized();
210
+ // Validate that encryptedSession can be decrypted with the provided key
211
+ if (options.encryptedSession) {
212
+ try {
213
+ const sessionManager = SessionManagerWrapper.from_encrypted_blob(options.encryptedSession, encryptionKey);
214
+ // We only create this wrapper for validation, free it immediately
215
+ sessionManager.free();
216
+ }
217
+ catch {
218
+ throw new Error('[GossipSdk] Failed to load encrypted session. Please provide a valid encryptedSession and encryptionKey.');
219
+ }
220
+ }
223
221
  // Generate keys from mnemonic
224
222
  const userKeys = await generateUserKeys(options.mnemonic);
225
223
  // Create session with persistence callback
@@ -228,12 +226,8 @@ class GossipSdkImpl {
228
226
  await this.handleSessionPersist();
229
227
  }, options.sessionConfig);
230
228
  // Restore existing session state if provided
231
- if (options.encryptedSession && options.encryptionKey) {
232
- // Create a minimal profile-like object for load()
233
- const profileForLoad = {
234
- session: options.encryptedSession,
235
- };
236
- session.load(profileForLoad, options.encryptionKey);
229
+ if (options.encryptedSession) {
230
+ session.load(options.encryptedSession, encryptionKey);
237
231
  }
238
232
  // Get config from initialized state
239
233
  const { config } = this.state;
@@ -255,7 +249,7 @@ class GossipSdkImpl {
255
249
  config,
256
250
  session,
257
251
  userKeys,
258
- persistEncryptionKey: options.persistEncryptionKey,
252
+ encryptionKey,
259
253
  onPersist: options.onPersist,
260
254
  };
261
255
  // Create cached service API wrappers
@@ -370,28 +364,12 @@ class GossipSdkImpl {
370
364
  * Get encrypted session blob for persistence.
371
365
  * Throws if no session is open.
372
366
  */
373
- getEncryptedSession(encryptionKey) {
367
+ getEncryptedSession() {
374
368
  const state = this.requireSession();
375
- return state.session.toEncryptedBlob(encryptionKey);
376
- }
377
- /**
378
- * Configure session persistence after session is opened.
379
- * Use this when you need to set up persistence after account creation.
380
- *
381
- * @param encryptionKey - Key to encrypt session blob
382
- * @param onPersist - Callback to save encrypted session blob
383
- */
384
- configurePersistence(encryptionKey, onPersist) {
385
- if (this.state.status !== SdkStatus.SESSION_OPEN) {
386
- throw new Error('No session open. Call openSession() first.');
369
+ if (!state.encryptionKey) {
370
+ throw new Error('No encryption key found. Call openSession() first.');
387
371
  }
388
- // Update state with persistence config
389
- this.state = {
390
- ...this.state,
391
- persistEncryptionKey: encryptionKey,
392
- onPersist,
393
- };
394
- console.log('[GossipSdk] Session persistence configured');
372
+ return state.session.toEncryptedBlob(state.encryptionKey);
395
373
  }
396
374
  // ─────────────────────────────────────────────────────────────────
397
375
  // Services (accessible only when session is open)
@@ -528,13 +506,13 @@ class GossipSdkImpl {
528
506
  async handleSessionPersist() {
529
507
  if (this.state.status !== SdkStatus.SESSION_OPEN)
530
508
  return;
531
- const { onPersist, persistEncryptionKey, session } = this.state;
532
- if (!onPersist || !persistEncryptionKey)
509
+ const { onPersist, encryptionKey, session } = this.state;
510
+ if (!onPersist || !encryptionKey)
533
511
  return;
534
512
  try {
535
- const blob = session.toEncryptedBlob(persistEncryptionKey);
513
+ const blob = session.toEncryptedBlob(encryptionKey);
536
514
  console.log(`[SessionPersist] Saving session blob (${blob.length} bytes)`);
537
- await onPersist(blob, persistEncryptionKey);
515
+ await onPersist(blob, encryptionKey);
538
516
  }
539
517
  catch (error) {
540
518
  this.eventEmitter.emit(SdkEventType.ERROR, error instanceof Error ? error : new Error(String(error)), 'session_persist');
@@ -5,7 +5,6 @@
5
5
  * using SessionManagerWrapper and related WASM classes.
6
6
  */
7
7
  import { UserPublicKeys, UserSecretKeys, ReceiveMessageOutput, SendMessageOutput, SessionStatus, EncryptionKey, SessionConfig, AnnouncementResult, UserKeys } from './bindings';
8
- import { UserProfile } from '../db';
9
8
  export declare class SessionModule {
10
9
  private sessionManager;
11
10
  private onPersist?;
@@ -33,7 +32,7 @@ export declare class SessionModule {
33
32
  /**
34
33
  * Initialize session from an encrypted blob
35
34
  */
36
- load(profile: UserProfile, encryptionKey: EncryptionKey): void;
35
+ load(encryptedSession: Uint8Array, encryptionKey: EncryptionKey): void;
37
36
  /**
38
37
  * Serialize session to an encrypted blob
39
38
  */
@@ -79,10 +79,16 @@ export class SessionModule {
79
79
  /**
80
80
  * Initialize session from an encrypted blob
81
81
  */
82
- load(profile, encryptionKey) {
82
+ load(encryptedSession, encryptionKey) {
83
83
  // Clean up existing session if any
84
84
  this.cleanup();
85
- this.sessionManager = SessionManagerWrapper.from_encrypted_blob(profile.session, encryptionKey);
85
+ try {
86
+ this.sessionManager = SessionManagerWrapper.from_encrypted_blob(encryptedSession, encryptionKey);
87
+ }
88
+ catch (error) {
89
+ const message = error instanceof Error ? error.message : JSON.stringify(error);
90
+ throw new Error(`[SessionModule] Failed to load encrypted session: ${message}`);
91
+ }
86
92
  }
87
93
  /**
88
94
  * Serialize session to an encrypted blob
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massalabs/gossip-sdk",
3
- "version": "0.0.2-dev.20260211140005",
3
+ "version": "0.0.2-dev.20260211172752",
4
4
  "description": "Gossip SDK for automation, chatbot, and integration use cases",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",