@massalabs/gossip-sdk 0.0.2-dev.20260428020111 → 0.0.2-dev.20260428143717

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.
@@ -3,8 +3,20 @@
3
3
  *
4
4
  * This file contains the real WASM implementation of the SessionModule
5
5
  * using SessionManagerWrapper and related WASM classes.
6
+ *
7
+ * All Uint8Array values returned from WASM are funneled through `copyOut` /
8
+ * `copyOutMany` so callers always get JS-owned buffers. Without this, a
9
+ * subsequent WASM allocation that grows linear memory detaches the original
10
+ * `wasm.memory.buffer` and any Uint8Array view sitting on top of it — leading
11
+ * to "detached ArrayBuffer" failures on the next read.
6
12
  */
7
- import { UserPublicKeys, UserSecretKeys, ReceiveMessageOutput, SendMessageOutput, SessionStatus, EncryptionKey, SessionConfig, AnnouncementResult, UserKeys } from './bindings.js';
13
+ import { UserPublicKeys, UserSecretKeys, SendMessageOutput, SessionStatus, EncryptionKey, SessionConfig, AnnouncementResult, UserKeys } from './bindings.js';
14
+ export interface ReceivedMessage {
15
+ message: Uint8Array;
16
+ user_id: Uint8Array;
17
+ timestamp: number;
18
+ acknowledged_seekers: Uint8Array[];
19
+ }
8
20
  export declare class SessionModule {
9
21
  private sessionManager;
10
22
  private onPersist?;
@@ -57,7 +69,7 @@ export declare class SessionModule {
57
69
  /**
58
70
  * Process an incoming ciphertext from the message board
59
71
  */
60
- feedIncomingMessageBoardRead(seeker: Uint8Array, ciphertext: Uint8Array): Promise<ReceiveMessageOutput | undefined>;
72
+ feedIncomingMessageBoardRead(seeker: Uint8Array, ciphertext: Uint8Array): Promise<ReceivedMessage | undefined>;
61
73
  /**
62
74
  * Send a message to a peer.
63
75
  * IMPORTANT: This persists session state before returning.
@@ -3,9 +3,17 @@
3
3
  *
4
4
  * This file contains the real WASM implementation of the SessionModule
5
5
  * using SessionManagerWrapper and related WASM classes.
6
+ *
7
+ * All Uint8Array values returned from WASM are funneled through `copyOut` /
8
+ * `copyOutMany` so callers always get JS-owned buffers. Without this, a
9
+ * subsequent WASM allocation that grows linear memory detaches the original
10
+ * `wasm.memory.buffer` and any Uint8Array view sitting on top of it — leading
11
+ * to "detached ArrayBuffer" failures on the next read.
6
12
  */
7
13
  import { SessionManagerWrapper, SessionStatus, SessionConfig, } from './bindings.js';
8
14
  import { encodeUserId } from '../utils/userId.js';
15
+ const copyOut = (a) => new Uint8Array(a);
16
+ const copyOutMany = (xs) => xs.map(copyOut);
9
17
  export class SessionModule {
10
18
  constructor(userKeys, onPersist, config) {
11
19
  Object.defineProperty(this, "sessionManager", {
@@ -46,7 +54,7 @@ export class SessionModule {
46
54
  });
47
55
  this.ourPk = userKeys.public_keys();
48
56
  this.ourSk = userKeys.secret_keys();
49
- this.userId = this.ourPk.derive_id();
57
+ this.userId = copyOut(this.ourPk.derive_id());
50
58
  this.userIdEncoded = encodeUserId(this.userId);
51
59
  const sessionConfig = config ?? SessionConfig.new_default();
52
60
  this.sessionManager = new SessionManagerWrapper(sessionConfig);
@@ -97,7 +105,7 @@ export class SessionModule {
97
105
  if (!this.sessionManager) {
98
106
  throw new Error('Session manager is not initialized');
99
107
  }
100
- return this.sessionManager.to_encrypted_blob(key);
108
+ return copyOut(this.sessionManager.to_encrypted_blob(key));
101
109
  }
102
110
  cleanup() {
103
111
  this.sessionManager?.free();
@@ -114,7 +122,7 @@ export class SessionModule {
114
122
  throw new Error('Session manager is not initialized');
115
123
  }
116
124
  const userDataBytes = userData ?? new Uint8Array(0);
117
- const result = this.sessionManager.establish_outgoing_session(peerPk, this.ourPk, this.ourSk, userDataBytes);
125
+ const result = copyOut(this.sessionManager.establish_outgoing_session(peerPk, this.ourPk, this.ourSk, userDataBytes));
118
126
  if (result.length === 0) {
119
127
  throw new Error('Failed to establish outgoing session. Session manager returned empty announcement bytes.');
120
128
  }
@@ -142,7 +150,7 @@ export class SessionModule {
142
150
  if (!this.sessionManager) {
143
151
  throw new Error('Session manager is not initialized');
144
152
  }
145
- return this.sessionManager.get_message_board_read_keys();
153
+ return copyOutMany(this.sessionManager.get_message_board_read_keys());
146
154
  }
147
155
  /**
148
156
  * Process an incoming ciphertext from the message board
@@ -152,8 +160,20 @@ export class SessionModule {
152
160
  throw new Error('Session manager is not initialized');
153
161
  }
154
162
  const result = this.sessionManager.feed_incoming_message_board_read(seeker, ciphertext, this.ourSk);
163
+ if (!result) {
164
+ return undefined;
165
+ }
166
+ // Snapshot before any further WASM activity (persistIfNeeded / scheduler
167
+ // yields) can grow linear memory and detach views.
168
+ const snapshot = {
169
+ message: copyOut(result.message),
170
+ user_id: copyOut(result.user_id),
171
+ timestamp: result.timestamp,
172
+ acknowledged_seekers: copyOutMany(result.acknowledged_seekers),
173
+ };
174
+ result.free();
155
175
  await this.persistIfNeeded();
156
- return result;
176
+ return snapshot;
157
177
  }
158
178
  /**
159
179
  * Send a message to a peer.
@@ -177,7 +197,7 @@ export class SessionModule {
177
197
  if (!this.sessionManager) {
178
198
  throw new Error('Session manager is not initialized');
179
199
  }
180
- return this.sessionManager.peer_list();
200
+ return copyOutMany(this.sessionManager.peer_list());
181
201
  }
182
202
  /**
183
203
  * Get the session status for a peer
@@ -205,7 +225,7 @@ export class SessionModule {
205
225
  if (!this.sessionManager) {
206
226
  throw new Error('Session manager is not initialized');
207
227
  }
208
- const result = this.sessionManager.refresh();
228
+ const result = copyOutMany(this.sessionManager.refresh());
209
229
  await this.persistIfNeeded();
210
230
  return result;
211
231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massalabs/gossip-sdk",
3
- "version": "0.0.2-dev.20260428020111",
3
+ "version": "0.0.2-dev.20260428143717",
4
4
  "description": "Gossip SDK for automation, chatbot, and integration use cases",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",