@massalabs/gossip-sdk 0.0.1 → 0.0.2-dev.20260128111120

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.
Files changed (142) hide show
  1. package/dist/api/messageProtocol/index.d.ts +19 -0
  2. package/dist/api/messageProtocol/index.js +26 -0
  3. package/dist/api/messageProtocol/mock.d.ts +12 -0
  4. package/{src/api/messageProtocol/mock.ts → dist/api/messageProtocol/mock.js} +2 -3
  5. package/dist/api/messageProtocol/rest.d.ts +22 -0
  6. package/dist/api/messageProtocol/rest.js +161 -0
  7. package/dist/api/messageProtocol/types.d.ts +61 -0
  8. package/dist/api/messageProtocol/types.js +6 -0
  9. package/dist/assets/generated/wasm/README.md +281 -0
  10. package/dist/assets/generated/wasm/gossip_wasm.d.ts +498 -0
  11. package/dist/assets/generated/wasm/gossip_wasm.js +1399 -0
  12. package/dist/assets/generated/wasm/gossip_wasm_bg.wasm +0 -0
  13. package/dist/assets/generated/wasm/gossip_wasm_bg.wasm.d.ts +68 -0
  14. package/dist/assets/generated/wasm/package.json +15 -0
  15. package/dist/config/protocol.d.ts +36 -0
  16. package/dist/config/protocol.js +77 -0
  17. package/dist/config/sdk.d.ts +82 -0
  18. package/dist/config/sdk.js +55 -0
  19. package/{src/contacts.ts → dist/contacts.d.ts} +10 -94
  20. package/dist/contacts.js +166 -0
  21. package/dist/core/SdkEventEmitter.d.ts +36 -0
  22. package/dist/core/SdkEventEmitter.js +59 -0
  23. package/dist/core/SdkPolling.d.ts +35 -0
  24. package/dist/core/SdkPolling.js +100 -0
  25. package/{src/core/index.ts → dist/core/index.d.ts} +0 -2
  26. package/dist/core/index.js +5 -0
  27. package/dist/crypto/bip39.d.ts +34 -0
  28. package/dist/crypto/bip39.js +62 -0
  29. package/dist/crypto/encryption.d.ts +37 -0
  30. package/dist/crypto/encryption.js +46 -0
  31. package/dist/db.d.ts +190 -0
  32. package/dist/db.js +311 -0
  33. package/dist/gossipSdk.d.ts +274 -0
  34. package/dist/gossipSdk.js +690 -0
  35. package/dist/index.d.ts +73 -0
  36. package/dist/index.js +77 -0
  37. package/dist/services/announcement.d.ts +43 -0
  38. package/dist/services/announcement.js +491 -0
  39. package/dist/services/auth.d.ts +37 -0
  40. package/dist/services/auth.js +76 -0
  41. package/dist/services/discussion.d.ts +63 -0
  42. package/dist/services/discussion.js +297 -0
  43. package/dist/services/message.d.ts +74 -0
  44. package/dist/services/message.js +826 -0
  45. package/dist/services/refresh.d.ts +41 -0
  46. package/dist/services/refresh.js +205 -0
  47. package/{src/sw.ts → dist/sw.d.ts} +1 -8
  48. package/dist/sw.js +10 -0
  49. package/dist/types/events.d.ts +80 -0
  50. package/dist/types/events.js +7 -0
  51. package/dist/types.d.ts +32 -0
  52. package/dist/types.js +7 -0
  53. package/dist/utils/base64.d.ts +10 -0
  54. package/dist/utils/base64.js +30 -0
  55. package/dist/utils/contacts.d.ts +42 -0
  56. package/dist/utils/contacts.js +113 -0
  57. package/dist/utils/discussions.d.ts +24 -0
  58. package/dist/utils/discussions.js +38 -0
  59. package/dist/utils/logs.d.ts +19 -0
  60. package/dist/utils/logs.js +89 -0
  61. package/dist/utils/messageSerialization.d.ts +64 -0
  62. package/dist/utils/messageSerialization.js +184 -0
  63. package/dist/utils/queue.d.ts +50 -0
  64. package/dist/utils/queue.js +110 -0
  65. package/dist/utils/type.d.ts +10 -0
  66. package/dist/utils/type.js +4 -0
  67. package/dist/utils/userId.d.ts +40 -0
  68. package/dist/utils/userId.js +90 -0
  69. package/dist/utils/validation.d.ts +50 -0
  70. package/dist/utils/validation.js +112 -0
  71. package/dist/utils.d.ts +30 -0
  72. package/{src/utils.ts → dist/utils.js} +9 -19
  73. package/dist/wasm/encryption.d.ts +56 -0
  74. package/{src/wasm/encryption.ts → dist/wasm/encryption.js} +22 -51
  75. package/dist/wasm/index.d.ts +10 -0
  76. package/{src/wasm/index.ts → dist/wasm/index.js} +1 -8
  77. package/dist/wasm/loader.d.ts +21 -0
  78. package/dist/wasm/loader.js +103 -0
  79. package/dist/wasm/session.d.ts +85 -0
  80. package/dist/wasm/session.js +226 -0
  81. package/dist/wasm/userKeys.d.ts +17 -0
  82. package/{src/wasm/userKeys.ts → dist/wasm/userKeys.js} +6 -13
  83. package/package.json +5 -1
  84. package/src/api/messageProtocol/index.ts +0 -53
  85. package/src/api/messageProtocol/rest.ts +0 -209
  86. package/src/api/messageProtocol/types.ts +0 -70
  87. package/src/config/protocol.ts +0 -97
  88. package/src/config/sdk.ts +0 -131
  89. package/src/core/SdkEventEmitter.ts +0 -91
  90. package/src/core/SdkPolling.ts +0 -134
  91. package/src/crypto/bip39.ts +0 -84
  92. package/src/crypto/encryption.ts +0 -77
  93. package/src/db.ts +0 -465
  94. package/src/gossipSdk.ts +0 -994
  95. package/src/index.ts +0 -211
  96. package/src/services/announcement.ts +0 -653
  97. package/src/services/auth.ts +0 -95
  98. package/src/services/discussion.ts +0 -380
  99. package/src/services/message.ts +0 -1055
  100. package/src/services/refresh.ts +0 -234
  101. package/src/types/events.ts +0 -108
  102. package/src/types.ts +0 -70
  103. package/src/utils/base64.ts +0 -39
  104. package/src/utils/contacts.ts +0 -161
  105. package/src/utils/discussions.ts +0 -55
  106. package/src/utils/logs.ts +0 -86
  107. package/src/utils/messageSerialization.ts +0 -257
  108. package/src/utils/queue.ts +0 -106
  109. package/src/utils/type.ts +0 -7
  110. package/src/utils/userId.ts +0 -114
  111. package/src/utils/validation.ts +0 -144
  112. package/src/wasm/loader.ts +0 -123
  113. package/src/wasm/session.ts +0 -276
  114. package/test/config/protocol.spec.ts +0 -31
  115. package/test/config/sdk.spec.ts +0 -163
  116. package/test/db/helpers.spec.ts +0 -142
  117. package/test/db/operations.spec.ts +0 -128
  118. package/test/db/states.spec.ts +0 -535
  119. package/test/integration/discussion-flow.spec.ts +0 -422
  120. package/test/integration/messaging-flow.spec.ts +0 -708
  121. package/test/integration/sdk-lifecycle.spec.ts +0 -325
  122. package/test/mocks/index.ts +0 -9
  123. package/test/mocks/mockMessageProtocol.ts +0 -100
  124. package/test/services/auth.spec.ts +0 -311
  125. package/test/services/discussion.spec.ts +0 -279
  126. package/test/services/message-deduplication.spec.ts +0 -299
  127. package/test/services/message-startup.spec.ts +0 -331
  128. package/test/services/message.spec.ts +0 -817
  129. package/test/services/refresh.spec.ts +0 -199
  130. package/test/services/session-status.spec.ts +0 -349
  131. package/test/session/wasm.spec.ts +0 -227
  132. package/test/setup.ts +0 -52
  133. package/test/utils/contacts.spec.ts +0 -156
  134. package/test/utils/discussions.spec.ts +0 -66
  135. package/test/utils/queue.spec.ts +0 -52
  136. package/test/utils/serialization.spec.ts +0 -120
  137. package/test/utils/userId.spec.ts +0 -120
  138. package/test/utils/validation.spec.ts +0 -223
  139. package/test/utils.ts +0 -212
  140. package/tsconfig.json +0 -26
  141. package/tsconfig.tsbuildinfo +0 -1
  142. package/vitest.config.ts +0 -28
@@ -1,325 +0,0 @@
1
- /**
2
- * GossipSdk lifecycle and event wiring tests
3
- */
4
-
5
- import { beforeEach, describe, expect, it, vi } from 'vitest';
6
- import { GossipDatabase } from '../../src/db';
7
- import type { EncryptionKey } from '../../src/wasm/encryption';
8
-
9
- const protocolMock = vi.hoisted(() => ({
10
- createMessageProtocolMock: vi.fn(),
11
- }));
12
-
13
- const eventState = vi.hoisted(() => ({
14
- lastEvents: null as {
15
- onMessageReceived?: (message: unknown) => void;
16
- onDiscussionRequest?: (...args: unknown[]) => void;
17
- onError?: (...args: unknown[]) => void;
18
- } | null,
19
- }));
20
-
21
- const sessionMock = vi.hoisted(() => {
22
- const userIdBytes = new Uint8Array(32).fill(9);
23
- const userIdEncoded = 'gossip1testsessionuserid';
24
- const state = { lastSessionInstance: null as MockSession | null };
25
-
26
- class MockSession {
27
- userId = userIdBytes;
28
- userIdEncoded = userIdEncoded;
29
- ourPk = { key: 'pk' };
30
- load = vi.fn();
31
- cleanup = vi.fn();
32
- toEncryptedBlob = vi.fn().mockReturnValue(new Uint8Array([9]));
33
- private onPersist?: () => void;
34
-
35
- constructor(_keys: unknown, onPersist?: () => void) {
36
- this.onPersist = onPersist;
37
- state.lastSessionInstance = this;
38
- }
39
-
40
- emitPersist() {
41
- this.onPersist?.();
42
- }
43
- }
44
-
45
- return { MockSession, state, userIdBytes, userIdEncoded };
46
- });
47
-
48
- vi.mock('../../src/api/messageProtocol', () => ({
49
- createMessageProtocol: () => protocolMock.createMessageProtocolMock(),
50
- }));
51
-
52
- vi.mock('../../src/wasm/loader', () => ({
53
- startWasmInitialization: vi.fn(),
54
- ensureWasmInitialized: vi.fn().mockResolvedValue(undefined),
55
- }));
56
-
57
- vi.mock('../../src/wasm/userKeys', () => ({
58
- generateUserKeys: vi.fn().mockResolvedValue({}),
59
- }));
60
-
61
- vi.mock('../../src/wasm/session', async () => {
62
- return {
63
- SessionModule: sessionMock.MockSession,
64
- };
65
- });
66
-
67
- vi.mock('../../src/services/auth', () => ({
68
- AuthService: class {
69
- constructor() {}
70
- },
71
- }));
72
-
73
- vi.mock('../../src/services/announcement', () => ({
74
- AnnouncementService: class {
75
- constructor(
76
- _db: unknown,
77
- _protocol: unknown,
78
- _session: unknown,
79
- events: typeof eventState.lastEvents
80
- ) {
81
- eventState.lastEvents = events ?? null;
82
- }
83
- },
84
- }));
85
-
86
- vi.mock('../../src/services/message', () => ({
87
- MessageService: class {
88
- sendMessage = vi.fn();
89
- fetchMessages = vi.fn();
90
- resendMessages = vi.fn();
91
- findMessageBySeeker = vi.fn();
92
-
93
- constructor(
94
- _db: unknown,
95
- _protocol: unknown,
96
- _session: unknown,
97
- events: typeof eventState.lastEvents
98
- ) {
99
- eventState.lastEvents = events ?? null;
100
- }
101
- },
102
- }));
103
-
104
- vi.mock('../../src/services/discussion', () => ({
105
- DiscussionService: class {
106
- initialize = vi.fn();
107
- accept = vi.fn();
108
- renew = vi.fn();
109
- isStableState = vi.fn();
110
- constructor(
111
- _db: unknown,
112
- _announcement: unknown,
113
- _session: unknown,
114
- events: typeof eventState.lastEvents
115
- ) {
116
- eventState.lastEvents = events ?? null;
117
- }
118
- },
119
- }));
120
-
121
- vi.mock('../../src/services/refresh', () => ({
122
- RefreshService: class {
123
- handleSessionRefresh = vi.fn();
124
- constructor(
125
- _db: unknown,
126
- _message: unknown,
127
- _session: unknown,
128
- events: typeof eventState.lastEvents
129
- ) {
130
- eventState.lastEvents = events ?? null;
131
- }
132
- },
133
- }));
134
-
135
- describe('GossipSdkImpl lifecycle', () => {
136
- beforeEach(() => {
137
- vi.clearAllMocks();
138
- protocolMock.createMessageProtocolMock.mockReturnValue({
139
- fetchMessages: vi.fn(),
140
- sendMessage: vi.fn(),
141
- sendAnnouncement: vi.fn(),
142
- fetchAnnouncements: vi.fn(),
143
- fetchPublicKeyByUserId: vi.fn(),
144
- postPublicKey: vi.fn(),
145
- changeNode: vi.fn(),
146
- });
147
- sessionMock.state.lastSessionInstance = null;
148
- eventState.lastEvents = null;
149
- });
150
-
151
- it('initializes once and exposes auth service', async () => {
152
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
153
- const sdk = new GossipSdkImpl();
154
-
155
- await sdk.init({ db: new GossipDatabase() });
156
- expect(sdk.isInitialized).toBe(true);
157
- expect(() => sdk.auth).not.toThrow();
158
-
159
- const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
160
- await sdk.init({ db: new GossipDatabase() });
161
- expect(warnSpy).toHaveBeenCalled();
162
- });
163
-
164
- it('throws on openSession before init', async () => {
165
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
166
- const sdk = new GossipSdkImpl();
167
-
168
- await expect(sdk.openSession({ mnemonic: 'test words' })).rejects.toThrow(
169
- 'SDK not initialized'
170
- );
171
- });
172
-
173
- it('opens and closes session with getters wired', async () => {
174
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
175
- const sdk = new GossipSdkImpl();
176
-
177
- await sdk.init({ db: new GossipDatabase() });
178
- await sdk.openSession({ mnemonic: 'test words' });
179
-
180
- expect(sdk.isSessionOpen).toBe(true);
181
- expect(sdk.userIdBytes).toBeInstanceOf(Uint8Array);
182
- expect(sdk.userIdBytes.length).toBe(32);
183
- expect(sdk.publicKeys).toBeDefined();
184
-
185
- await sdk.closeSession();
186
- expect(sdk.isSessionOpen).toBe(false);
187
- expect(sessionMock.state.lastSessionInstance?.cleanup).toHaveBeenCalled();
188
- expect(() => sdk.messages).toThrow('No session open');
189
- });
190
-
191
- it('restores encrypted session when provided', async () => {
192
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
193
- const sdk = new GossipSdkImpl();
194
- const encryptedSession = new Uint8Array([1, 2, 3]);
195
- const encryptionKey = {} as EncryptionKey;
196
-
197
- await sdk.init({ db: new GossipDatabase() });
198
- await sdk.openSession({
199
- mnemonic: 'test words',
200
- encryptedSession,
201
- encryptionKey,
202
- });
203
-
204
- expect(sessionMock.state.lastSessionInstance?.load).toHaveBeenCalled();
205
- });
206
-
207
- it('persists session via onPersist callback', async () => {
208
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
209
- const sdk = new GossipSdkImpl();
210
- const onPersist = vi.fn().mockResolvedValue(undefined);
211
- const persistEncryptionKey = {} as EncryptionKey;
212
-
213
- await sdk.init({ db: new GossipDatabase() });
214
- await sdk.openSession({
215
- mnemonic: 'test words',
216
- onPersist,
217
- persistEncryptionKey,
218
- });
219
-
220
- sessionMock.state.lastSessionInstance?.emitPersist();
221
- expect(onPersist).toHaveBeenCalledWith(
222
- new Uint8Array([9]),
223
- persistEncryptionKey
224
- );
225
- });
226
-
227
- it('bridges message events to sdk.on handlers', async () => {
228
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
229
- const sdk = new GossipSdkImpl();
230
- const handler = vi.fn();
231
-
232
- await sdk.init({ db: new GossipDatabase() });
233
- sdk.on('message', handler);
234
- await sdk.openSession({ mnemonic: 'test words' });
235
-
236
- eventState.lastEvents?.onMessageReceived?.({ id: 1 });
237
- expect(handler).toHaveBeenCalledWith({ id: 1 });
238
- });
239
- });
240
-
241
- describe('GossipSdkImpl.configurePersistence', () => {
242
- beforeEach(() => {
243
- vi.clearAllMocks();
244
- protocolMock.createMessageProtocolMock.mockReturnValue({
245
- fetchMessages: vi.fn(),
246
- sendMessage: vi.fn(),
247
- sendAnnouncement: vi.fn(),
248
- fetchAnnouncements: vi.fn(),
249
- fetchPublicKeyByUserId: vi.fn(),
250
- postPublicKey: vi.fn(),
251
- changeNode: vi.fn(),
252
- });
253
- sessionMock.state.lastSessionInstance = null;
254
- eventState.lastEvents = null;
255
- });
256
-
257
- it('throws if called before session is opened', async () => {
258
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
259
- const sdk = new GossipSdkImpl();
260
- const onPersist = vi.fn();
261
- const encryptionKey = {} as EncryptionKey;
262
-
263
- await sdk.init({ db: new GossipDatabase() });
264
-
265
- expect(() => sdk.configurePersistence(encryptionKey, onPersist)).toThrow(
266
- 'No session open'
267
- );
268
- });
269
-
270
- it('configures persistence after session is opened without initial onPersist', async () => {
271
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
272
- const sdk = new GossipSdkImpl();
273
- const onPersist = vi.fn().mockResolvedValue(undefined);
274
- const encryptionKey = {} as EncryptionKey;
275
-
276
- await sdk.init({ db: new GossipDatabase() });
277
-
278
- await sdk.openSession({ mnemonic: 'test words' });
279
-
280
- sdk.configurePersistence(encryptionKey, onPersist);
281
-
282
- sessionMock.state.lastSessionInstance?.emitPersist();
283
-
284
- expect(onPersist).toHaveBeenCalledWith(new Uint8Array([9]), encryptionKey);
285
- });
286
-
287
- it('replaces existing onPersist callback when reconfigured', async () => {
288
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
289
- const sdk = new GossipSdkImpl();
290
- const originalOnPersist = vi.fn().mockResolvedValue(undefined);
291
- const newOnPersist = vi.fn().mockResolvedValue(undefined);
292
- const originalKey = { original: true } as unknown as EncryptionKey;
293
- const newKey = { new: true } as unknown as EncryptionKey;
294
-
295
- await sdk.init({ db: new GossipDatabase() });
296
-
297
- await sdk.openSession({
298
- mnemonic: 'test words',
299
- onPersist: originalOnPersist,
300
- persistEncryptionKey: originalKey,
301
- });
302
-
303
- sdk.configurePersistence(newKey, newOnPersist);
304
-
305
- sessionMock.state.lastSessionInstance?.emitPersist();
306
-
307
- expect(originalOnPersist).not.toHaveBeenCalled();
308
- expect(newOnPersist).toHaveBeenCalledWith(new Uint8Array([9]), newKey);
309
- });
310
-
311
- it('ensures persistence is called with correct encryption key', async () => {
312
- const { GossipSdkImpl } = await import('../../src/gossipSdk');
313
- const sdk = new GossipSdkImpl();
314
- const onPersist = vi.fn().mockResolvedValue(undefined);
315
- const specificKey = { keyId: 'test-key-123' } as unknown as EncryptionKey;
316
-
317
- await sdk.init({ db: new GossipDatabase() });
318
- await sdk.openSession({ mnemonic: 'test words' });
319
-
320
- sdk.configurePersistence(specificKey, onPersist);
321
- sessionMock.state.lastSessionInstance?.emitPersist();
322
-
323
- expect(onPersist).toHaveBeenCalledWith(expect.any(Uint8Array), specificKey);
324
- });
325
- });
@@ -1,9 +0,0 @@
1
- /**
2
- * Test Mocks
3
- *
4
- * Only MockMessageProtocol is needed - it provides an in-memory
5
- * implementation to avoid network calls during tests.
6
- *
7
- * SessionModule uses real WASM - no mock needed since WASM works in Node.
8
- */
9
- export { MockMessageProtocol } from './mockMessageProtocol';
@@ -1,100 +0,0 @@
1
- /**
2
- * In-Memory Mock Message Protocol for Testing
3
- *
4
- * This mock stores messages and announcements in memory,
5
- * allowing tests to verify messaging flows without network calls.
6
- */
7
-
8
- import type { IMessageProtocol } from '../../src/api/messageProtocol/types';
9
- import type {
10
- EncryptedMessage,
11
- BulletinItem,
12
- } from '../../src/api/messageProtocol/types';
13
-
14
- export class MockMessageProtocol implements IMessageProtocol {
15
- private messages: Map<string, Uint8Array> = new Map();
16
- private announcements: BulletinItem[] = [];
17
- private announcementCounter = 0;
18
-
19
- constructor(
20
- public baseUrl: string = 'mock://test',
21
- public timeout: number = 10000,
22
- public retryAttempts: number = 3
23
- ) {}
24
-
25
- async fetchMessages(seekers: Uint8Array[]): Promise<EncryptedMessage[]> {
26
- const results: EncryptedMessage[] = [];
27
- for (const seeker of seekers) {
28
- const key = this.uint8ArrayToKey(seeker);
29
- const ciphertext = this.messages.get(key);
30
- if (ciphertext) {
31
- results.push({ seeker, ciphertext });
32
- }
33
- }
34
- return results;
35
- }
36
-
37
- async sendMessage(message: EncryptedMessage): Promise<void> {
38
- const key = this.uint8ArrayToKey(message.seeker);
39
- this.messages.set(key, message.ciphertext);
40
- }
41
-
42
- async sendAnnouncement(announcement: Uint8Array): Promise<string> {
43
- const counter = String(++this.announcementCounter);
44
- this.announcements.push({ counter, data: announcement });
45
- return counter;
46
- }
47
-
48
- async fetchAnnouncements(
49
- limit?: number,
50
- cursor?: string
51
- ): Promise<BulletinItem[]> {
52
- let results = [...this.announcements];
53
-
54
- // Filter by cursor (return only announcements after this counter)
55
- if (cursor) {
56
- const cursorNum = parseInt(cursor, 10);
57
- results = results.filter(a => parseInt(a.counter, 10) > cursorNum);
58
- }
59
-
60
- // Apply limit
61
- if (limit && limit > 0) {
62
- results = results.slice(0, limit);
63
- }
64
-
65
- return results;
66
- }
67
-
68
- async fetchPublicKeyByUserId(_userId: Uint8Array): Promise<string> {
69
- // Return empty string - tests should handle this
70
- return '';
71
- }
72
-
73
- async postPublicKey(_publicKey: string): Promise<string> {
74
- return 'mock-counter';
75
- }
76
-
77
- async changeNode(newBaseUrl: string): Promise<{ success: boolean }> {
78
- this.baseUrl = newBaseUrl;
79
- return { success: true };
80
- }
81
-
82
- // Test helper methods
83
- clearMockData(): void {
84
- this.messages.clear();
85
- this.announcements = [];
86
- this.announcementCounter = 0;
87
- }
88
-
89
- getStoredMessages(): Map<string, Uint8Array> {
90
- return new Map(this.messages);
91
- }
92
-
93
- getStoredAnnouncements(): BulletinItem[] {
94
- return [...this.announcements];
95
- }
96
-
97
- private uint8ArrayToKey(arr: Uint8Array): string {
98
- return Array.from(arr).join(',');
99
- }
100
- }