@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 +4 -14
- package/dist/gossipSdk.d.ts +3 -14
- package/dist/gossipSdk.js +29 -51
- package/dist/wasm/session.d.ts +1 -2
- package/dist/wasm/session.js +8 -2
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/gossipSdk.d.ts
CHANGED
|
@@ -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
|
|
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(
|
|
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 (
|
|
201
|
-
|
|
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
|
-
//
|
|
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
|
|
232
|
-
|
|
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
|
-
|
|
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(
|
|
367
|
+
getEncryptedSession() {
|
|
374
368
|
const state = this.requireSession();
|
|
375
|
-
|
|
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
|
-
|
|
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,
|
|
532
|
-
if (!onPersist || !
|
|
509
|
+
const { onPersist, encryptionKey, session } = this.state;
|
|
510
|
+
if (!onPersist || !encryptionKey)
|
|
533
511
|
return;
|
|
534
512
|
try {
|
|
535
|
-
const blob = session.toEncryptedBlob(
|
|
513
|
+
const blob = session.toEncryptedBlob(encryptionKey);
|
|
536
514
|
console.log(`[SessionPersist] Saving session blob (${blob.length} bytes)`);
|
|
537
|
-
await onPersist(blob,
|
|
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');
|
package/dist/wasm/session.d.ts
CHANGED
|
@@ -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(
|
|
35
|
+
load(encryptedSession: Uint8Array, encryptionKey: EncryptionKey): void;
|
|
37
36
|
/**
|
|
38
37
|
* Serialize session to an encrypted blob
|
|
39
38
|
*/
|
package/dist/wasm/session.js
CHANGED
|
@@ -79,10 +79,16 @@ export class SessionModule {
|
|
|
79
79
|
/**
|
|
80
80
|
* Initialize session from an encrypted blob
|
|
81
81
|
*/
|
|
82
|
-
load(
|
|
82
|
+
load(encryptedSession, encryptionKey) {
|
|
83
83
|
// Clean up existing session if any
|
|
84
84
|
this.cleanup();
|
|
85
|
-
|
|
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