@massalabs/gossip-sdk 0.0.2-dev.20260128094509 → 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.
- package/dist/api/messageProtocol/index.d.ts +19 -0
- package/dist/api/messageProtocol/index.js +26 -0
- package/dist/api/messageProtocol/mock.d.ts +12 -0
- package/{src/api/messageProtocol/mock.ts → dist/api/messageProtocol/mock.js} +2 -3
- package/dist/api/messageProtocol/rest.d.ts +22 -0
- package/dist/api/messageProtocol/rest.js +161 -0
- package/dist/api/messageProtocol/types.d.ts +61 -0
- package/dist/api/messageProtocol/types.js +6 -0
- package/dist/assets/generated/wasm/README.md +281 -0
- package/dist/assets/generated/wasm/gossip_wasm.d.ts +498 -0
- package/dist/assets/generated/wasm/gossip_wasm.js +1399 -0
- package/dist/assets/generated/wasm/gossip_wasm_bg.wasm +0 -0
- package/dist/assets/generated/wasm/gossip_wasm_bg.wasm.d.ts +68 -0
- package/dist/assets/generated/wasm/package.json +15 -0
- package/dist/config/protocol.d.ts +36 -0
- package/dist/config/protocol.js +77 -0
- package/dist/config/sdk.d.ts +82 -0
- package/dist/config/sdk.js +55 -0
- package/{src/contacts.ts → dist/contacts.d.ts} +10 -94
- package/dist/contacts.js +166 -0
- package/dist/core/SdkEventEmitter.d.ts +36 -0
- package/dist/core/SdkEventEmitter.js +59 -0
- package/dist/core/SdkPolling.d.ts +35 -0
- package/dist/core/SdkPolling.js +100 -0
- package/{src/core/index.ts → dist/core/index.d.ts} +0 -2
- package/dist/core/index.js +5 -0
- package/dist/crypto/bip39.d.ts +34 -0
- package/dist/crypto/bip39.js +62 -0
- package/dist/crypto/encryption.d.ts +37 -0
- package/dist/crypto/encryption.js +46 -0
- package/dist/db.d.ts +190 -0
- package/dist/db.js +311 -0
- package/dist/gossipSdk.d.ts +274 -0
- package/dist/gossipSdk.js +690 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +77 -0
- package/dist/services/announcement.d.ts +43 -0
- package/dist/services/announcement.js +491 -0
- package/dist/services/auth.d.ts +37 -0
- package/dist/services/auth.js +76 -0
- package/dist/services/discussion.d.ts +63 -0
- package/dist/services/discussion.js +297 -0
- package/dist/services/message.d.ts +74 -0
- package/dist/services/message.js +826 -0
- package/dist/services/refresh.d.ts +41 -0
- package/dist/services/refresh.js +205 -0
- package/{src/sw.ts → dist/sw.d.ts} +1 -8
- package/dist/sw.js +10 -0
- package/dist/types/events.d.ts +80 -0
- package/dist/types/events.js +7 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.js +7 -0
- package/dist/utils/base64.d.ts +10 -0
- package/dist/utils/base64.js +30 -0
- package/dist/utils/contacts.d.ts +42 -0
- package/dist/utils/contacts.js +113 -0
- package/dist/utils/discussions.d.ts +24 -0
- package/dist/utils/discussions.js +38 -0
- package/dist/utils/logs.d.ts +19 -0
- package/dist/utils/logs.js +89 -0
- package/dist/utils/messageSerialization.d.ts +64 -0
- package/dist/utils/messageSerialization.js +184 -0
- package/dist/utils/queue.d.ts +50 -0
- package/dist/utils/queue.js +110 -0
- package/dist/utils/type.d.ts +10 -0
- package/dist/utils/type.js +4 -0
- package/dist/utils/userId.d.ts +40 -0
- package/dist/utils/userId.js +90 -0
- package/dist/utils/validation.d.ts +50 -0
- package/dist/utils/validation.js +112 -0
- package/dist/utils.d.ts +30 -0
- package/{src/utils.ts → dist/utils.js} +9 -19
- package/dist/wasm/encryption.d.ts +56 -0
- package/{src/wasm/encryption.ts → dist/wasm/encryption.js} +22 -51
- package/dist/wasm/index.d.ts +10 -0
- package/{src/wasm/index.ts → dist/wasm/index.js} +1 -8
- package/dist/wasm/loader.d.ts +21 -0
- package/dist/wasm/loader.js +103 -0
- package/dist/wasm/session.d.ts +85 -0
- package/dist/wasm/session.js +226 -0
- package/dist/wasm/userKeys.d.ts +17 -0
- package/{src/wasm/userKeys.ts → dist/wasm/userKeys.js} +6 -13
- package/package.json +5 -1
- package/src/api/messageProtocol/index.ts +0 -53
- package/src/api/messageProtocol/rest.ts +0 -209
- package/src/api/messageProtocol/types.ts +0 -70
- package/src/config/protocol.ts +0 -97
- package/src/config/sdk.ts +0 -131
- package/src/core/SdkEventEmitter.ts +0 -91
- package/src/core/SdkPolling.ts +0 -134
- package/src/crypto/bip39.ts +0 -84
- package/src/crypto/encryption.ts +0 -77
- package/src/db.ts +0 -465
- package/src/gossipSdk.ts +0 -994
- package/src/index.ts +0 -211
- package/src/services/announcement.ts +0 -653
- package/src/services/auth.ts +0 -95
- package/src/services/discussion.ts +0 -380
- package/src/services/message.ts +0 -1055
- package/src/services/refresh.ts +0 -234
- package/src/types/events.ts +0 -108
- package/src/types.ts +0 -70
- package/src/utils/base64.ts +0 -39
- package/src/utils/contacts.ts +0 -161
- package/src/utils/discussions.ts +0 -55
- package/src/utils/logs.ts +0 -86
- package/src/utils/messageSerialization.ts +0 -257
- package/src/utils/queue.ts +0 -106
- package/src/utils/type.ts +0 -7
- package/src/utils/userId.ts +0 -114
- package/src/utils/validation.ts +0 -144
- package/src/wasm/loader.ts +0 -123
- package/src/wasm/session.ts +0 -276
- package/test/config/protocol.spec.ts +0 -31
- package/test/config/sdk.spec.ts +0 -163
- package/test/db/helpers.spec.ts +0 -142
- package/test/db/operations.spec.ts +0 -128
- package/test/db/states.spec.ts +0 -535
- package/test/integration/discussion-flow.spec.ts +0 -422
- package/test/integration/messaging-flow.spec.ts +0 -708
- package/test/integration/sdk-lifecycle.spec.ts +0 -325
- package/test/mocks/index.ts +0 -9
- package/test/mocks/mockMessageProtocol.ts +0 -100
- package/test/services/auth.spec.ts +0 -311
- package/test/services/discussion.spec.ts +0 -279
- package/test/services/message-deduplication.spec.ts +0 -299
- package/test/services/message-startup.spec.ts +0 -331
- package/test/services/message.spec.ts +0 -817
- package/test/services/refresh.spec.ts +0 -199
- package/test/services/session-status.spec.ts +0 -349
- package/test/session/wasm.spec.ts +0 -227
- package/test/setup.ts +0 -52
- package/test/utils/contacts.spec.ts +0 -156
- package/test/utils/discussions.spec.ts +0 -66
- package/test/utils/queue.spec.ts +0 -52
- package/test/utils/serialization.spec.ts +0 -120
- package/test/utils/userId.spec.ts +0 -120
- package/test/utils/validation.spec.ts +0 -223
- package/test/utils.ts +0 -212
- package/tsconfig.json +0 -26
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -28
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discussion e2e-style tests
|
|
3
|
-
*
|
|
4
|
-
* Uses real WASM SessionModule with real crypto.
|
|
5
|
-
* MockMessageProtocol provides in-memory message storage (no network).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
describe,
|
|
10
|
-
it,
|
|
11
|
-
expect,
|
|
12
|
-
beforeEach,
|
|
13
|
-
afterEach,
|
|
14
|
-
vi,
|
|
15
|
-
beforeAll,
|
|
16
|
-
} from 'vitest';
|
|
17
|
-
import { AnnouncementService } from '../../src/services/announcement';
|
|
18
|
-
import { DiscussionService } from '../../src/services/discussion';
|
|
19
|
-
import { db, Contact, DiscussionStatus } from '../../src/db';
|
|
20
|
-
import { MockMessageProtocol } from '../mocks';
|
|
21
|
-
import {
|
|
22
|
-
createTestSession,
|
|
23
|
-
cleanupTestSession,
|
|
24
|
-
TestSessionData,
|
|
25
|
-
} from '../utils';
|
|
26
|
-
|
|
27
|
-
describe('Discussion Flow', () => {
|
|
28
|
-
let mockProtocol: MockMessageProtocol;
|
|
29
|
-
|
|
30
|
-
let alice: TestSessionData;
|
|
31
|
-
let aliceAnnouncementService: AnnouncementService;
|
|
32
|
-
let aliceDiscussionService: DiscussionService;
|
|
33
|
-
|
|
34
|
-
let bob: TestSessionData;
|
|
35
|
-
let bobAnnouncementService: AnnouncementService;
|
|
36
|
-
let bobDiscussionService: DiscussionService;
|
|
37
|
-
|
|
38
|
-
beforeAll(async () => {
|
|
39
|
-
mockProtocol = new MockMessageProtocol();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
beforeEach(async () => {
|
|
43
|
-
if (!db.isOpen()) {
|
|
44
|
-
await db.open();
|
|
45
|
-
}
|
|
46
|
-
await Promise.all(db.tables.map(table => table.clear()));
|
|
47
|
-
mockProtocol.clearMockData();
|
|
48
|
-
|
|
49
|
-
vi.clearAllMocks();
|
|
50
|
-
|
|
51
|
-
// Create real WASM sessions for Alice and Bob
|
|
52
|
-
alice = await createTestSession(`alice-${Date.now()}-${Math.random()}`);
|
|
53
|
-
bob = await createTestSession(`bob-${Date.now()}-${Math.random()}`);
|
|
54
|
-
|
|
55
|
-
aliceAnnouncementService = new AnnouncementService(
|
|
56
|
-
db,
|
|
57
|
-
mockProtocol,
|
|
58
|
-
alice.session
|
|
59
|
-
);
|
|
60
|
-
aliceDiscussionService = new DiscussionService(
|
|
61
|
-
db,
|
|
62
|
-
aliceAnnouncementService,
|
|
63
|
-
alice.session
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
bobAnnouncementService = new AnnouncementService(
|
|
67
|
-
db,
|
|
68
|
-
mockProtocol,
|
|
69
|
-
bob.session
|
|
70
|
-
);
|
|
71
|
-
bobDiscussionService = new DiscussionService(
|
|
72
|
-
db,
|
|
73
|
-
bobAnnouncementService,
|
|
74
|
-
bob.session
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
afterEach(async () => {
|
|
79
|
-
cleanupTestSession(alice);
|
|
80
|
-
cleanupTestSession(bob);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('Announcement Username Parsing', () => {
|
|
84
|
-
it('Bob receives announcement with username and uses it as contact name', async () => {
|
|
85
|
-
// Alice creates announcement with username in user_data
|
|
86
|
-
const jsonPayload = JSON.stringify({
|
|
87
|
-
u: 'Alice',
|
|
88
|
-
m: 'Hi, I would like to connect!',
|
|
89
|
-
});
|
|
90
|
-
const userData = new TextEncoder().encode(jsonPayload);
|
|
91
|
-
|
|
92
|
-
// Alice establishes outgoing session to Bob with user data
|
|
93
|
-
const aliceAnnouncement = await alice.session.establishOutgoingSession(
|
|
94
|
-
bob.session.ourPk,
|
|
95
|
-
userData
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// Store the announcement (simulates network)
|
|
99
|
-
await mockProtocol.sendAnnouncement(aliceAnnouncement);
|
|
100
|
-
|
|
101
|
-
// Bob fetches and processes announcements
|
|
102
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
103
|
-
|
|
104
|
-
// Bob should have Alice as a contact with the username from announcement
|
|
105
|
-
const bobContact = await db.getContactByOwnerAndUserId(
|
|
106
|
-
bob.session.userIdEncoded,
|
|
107
|
-
alice.session.userIdEncoded
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
expect(bobContact).toBeDefined();
|
|
111
|
-
expect(bobContact?.name).toBe('Alice');
|
|
112
|
-
|
|
113
|
-
const bobDiscussion = await db.getDiscussionByOwnerAndContact(
|
|
114
|
-
bob.session.userIdEncoded,
|
|
115
|
-
alice.session.userIdEncoded
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
expect(bobDiscussion).toBeDefined();
|
|
119
|
-
expect(bobDiscussion?.announcementMessage).toBe(
|
|
120
|
-
'Hi, I would like to connect!'
|
|
121
|
-
);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('Bob receives JSON announcement without username (message only)', async () => {
|
|
125
|
-
const jsonPayload = JSON.stringify({ m: 'Hello without username' });
|
|
126
|
-
const userData = new TextEncoder().encode(jsonPayload);
|
|
127
|
-
|
|
128
|
-
const aliceAnnouncement = await alice.session.establishOutgoingSession(
|
|
129
|
-
bob.session.ourPk,
|
|
130
|
-
userData
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
await mockProtocol.sendAnnouncement(aliceAnnouncement);
|
|
134
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
135
|
-
|
|
136
|
-
const bobContact = await db.getContactByOwnerAndUserId(
|
|
137
|
-
bob.session.userIdEncoded,
|
|
138
|
-
alice.session.userIdEncoded
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
expect(bobContact).toBeDefined();
|
|
142
|
-
expect(bobContact?.name).toMatch(/^New Request \d+$/);
|
|
143
|
-
|
|
144
|
-
const bobDiscussion = await db.getDiscussionByOwnerAndContact(
|
|
145
|
-
bob.session.userIdEncoded,
|
|
146
|
-
alice.session.userIdEncoded
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
expect(bobDiscussion?.announcementMessage).toBe('Hello without username');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('Bob receives announcement with username only (no message)', async () => {
|
|
153
|
-
const jsonPayload = JSON.stringify({ u: 'AliceUser' });
|
|
154
|
-
const userData = new TextEncoder().encode(jsonPayload);
|
|
155
|
-
|
|
156
|
-
const aliceAnnouncement = await alice.session.establishOutgoingSession(
|
|
157
|
-
bob.session.ourPk,
|
|
158
|
-
userData
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
await mockProtocol.sendAnnouncement(aliceAnnouncement);
|
|
162
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
163
|
-
|
|
164
|
-
const bobContact = await db.getContactByOwnerAndUserId(
|
|
165
|
-
bob.session.userIdEncoded,
|
|
166
|
-
alice.session.userIdEncoded
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
expect(bobContact).toBeDefined();
|
|
170
|
-
expect(bobContact?.name).toBe('AliceUser');
|
|
171
|
-
|
|
172
|
-
const bobDiscussion = await db.getDiscussionByOwnerAndContact(
|
|
173
|
-
bob.session.userIdEncoded,
|
|
174
|
-
alice.session.userIdEncoded
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
expect(bobDiscussion?.announcementMessage).toBeUndefined();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('Bob receives announcement without username (no colon in message)', async () => {
|
|
181
|
-
const oldFormatMessage = 'Hi, this is an old format message';
|
|
182
|
-
const userData = new TextEncoder().encode(oldFormatMessage);
|
|
183
|
-
|
|
184
|
-
const aliceAnnouncement = await alice.session.establishOutgoingSession(
|
|
185
|
-
bob.session.ourPk,
|
|
186
|
-
userData
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
await mockProtocol.sendAnnouncement(aliceAnnouncement);
|
|
190
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
191
|
-
|
|
192
|
-
const bobContact = await db.getContactByOwnerAndUserId(
|
|
193
|
-
bob.session.userIdEncoded,
|
|
194
|
-
alice.session.userIdEncoded
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
expect(bobContact).toBeDefined();
|
|
198
|
-
expect(bobContact?.name).toMatch(/^New Request \d+$/);
|
|
199
|
-
|
|
200
|
-
const bobDiscussion = await db.getDiscussionByOwnerAndContact(
|
|
201
|
-
bob.session.userIdEncoded,
|
|
202
|
-
alice.session.userIdEncoded
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
expect(bobDiscussion?.announcementMessage).toBe(oldFormatMessage);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('Bob receives JSON announcement with special characters (colons in message)', async () => {
|
|
209
|
-
const jsonPayload = JSON.stringify({
|
|
210
|
-
u: 'Alice:Smith',
|
|
211
|
-
m: 'Hello: how are you?',
|
|
212
|
-
});
|
|
213
|
-
const userData = new TextEncoder().encode(jsonPayload);
|
|
214
|
-
|
|
215
|
-
const aliceAnnouncement = await alice.session.establishOutgoingSession(
|
|
216
|
-
bob.session.ourPk,
|
|
217
|
-
userData
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
await mockProtocol.sendAnnouncement(aliceAnnouncement);
|
|
221
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
222
|
-
|
|
223
|
-
const bobContact = await db.getContactByOwnerAndUserId(
|
|
224
|
-
bob.session.userIdEncoded,
|
|
225
|
-
alice.session.userIdEncoded
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
expect(bobContact).toBeDefined();
|
|
229
|
-
expect(bobContact?.name).toBe('Alice:Smith');
|
|
230
|
-
|
|
231
|
-
const bobDiscussion = await db.getDiscussionByOwnerAndContact(
|
|
232
|
-
bob.session.userIdEncoded,
|
|
233
|
-
alice.session.userIdEncoded
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
expect(bobDiscussion?.announcementMessage).toBe('Hello: how are you?');
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('Bob receives legacy colon format (backwards compatibility)', async () => {
|
|
240
|
-
const legacyMessage = 'OldAlice:Hello from old client';
|
|
241
|
-
const userData = new TextEncoder().encode(legacyMessage);
|
|
242
|
-
|
|
243
|
-
const aliceAnnouncement = await alice.session.establishOutgoingSession(
|
|
244
|
-
bob.session.ourPk,
|
|
245
|
-
userData
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
await mockProtocol.sendAnnouncement(aliceAnnouncement);
|
|
249
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
250
|
-
|
|
251
|
-
const bobContact = await db.getContactByOwnerAndUserId(
|
|
252
|
-
bob.session.userIdEncoded,
|
|
253
|
-
alice.session.userIdEncoded
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
expect(bobContact?.name).toBe('OldAlice');
|
|
257
|
-
|
|
258
|
-
const bobDiscussion = await db.getDiscussionByOwnerAndContact(
|
|
259
|
-
bob.session.userIdEncoded,
|
|
260
|
-
alice.session.userIdEncoded
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
expect(bobDiscussion?.announcementMessage).toBe('Hello from old client');
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
describe('Discussion Initiation Happy Path', () => {
|
|
268
|
-
it('Alice sends announcement and Bob accepts', async () => {
|
|
269
|
-
// Alice adds Bob as a contact first
|
|
270
|
-
const aliceBobContact: Omit<Contact, 'id'> = {
|
|
271
|
-
ownerUserId: alice.session.userIdEncoded,
|
|
272
|
-
userId: bob.session.userIdEncoded,
|
|
273
|
-
name: 'Bob',
|
|
274
|
-
publicKeys: bob.session.ourPk.to_bytes(),
|
|
275
|
-
avatar: undefined,
|
|
276
|
-
isOnline: false,
|
|
277
|
-
lastSeen: new Date(),
|
|
278
|
-
createdAt: new Date(),
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
await db.contacts.add(aliceBobContact);
|
|
282
|
-
|
|
283
|
-
// Alice initiates discussion with Bob
|
|
284
|
-
const { discussionId: aliceDiscussionId } =
|
|
285
|
-
await aliceDiscussionService.initialize(aliceBobContact);
|
|
286
|
-
|
|
287
|
-
const aliceDiscussion = await db.discussions.get(aliceDiscussionId);
|
|
288
|
-
expect(aliceDiscussion).toBeDefined();
|
|
289
|
-
expect(aliceDiscussion?.status).toBe(DiscussionStatus.PENDING);
|
|
290
|
-
expect(aliceDiscussion?.direction).toBe('initiated');
|
|
291
|
-
expect(aliceDiscussion?.initiationAnnouncement).toBeDefined();
|
|
292
|
-
|
|
293
|
-
// Bob fetches announcements and sees Alice's request
|
|
294
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
295
|
-
|
|
296
|
-
const bobDiscussion = await db.getDiscussionByOwnerAndContact(
|
|
297
|
-
bob.session.userIdEncoded,
|
|
298
|
-
alice.session.userIdEncoded
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
expect(bobDiscussion).toBeDefined();
|
|
302
|
-
expect(bobDiscussion?.status).toBe(DiscussionStatus.PENDING);
|
|
303
|
-
expect(bobDiscussion?.direction).toBe('received');
|
|
304
|
-
|
|
305
|
-
if (!bobDiscussion) throw new Error('Bob discussion not found');
|
|
306
|
-
|
|
307
|
-
// Bob accepts the discussion
|
|
308
|
-
await bobDiscussionService.accept(bobDiscussion);
|
|
309
|
-
|
|
310
|
-
const bobDiscussionAfterAccept = await db.discussions.get(
|
|
311
|
-
bobDiscussion.id!
|
|
312
|
-
);
|
|
313
|
-
expect(bobDiscussionAfterAccept?.status).toBe(DiscussionStatus.ACTIVE);
|
|
314
|
-
expect(bobDiscussionAfterAccept?.initiationAnnouncement).toBeDefined();
|
|
315
|
-
|
|
316
|
-
// Alice fetches announcements and sees Bob's acceptance
|
|
317
|
-
await aliceAnnouncementService.fetchAndProcessAnnouncements();
|
|
318
|
-
|
|
319
|
-
const aliceDiscussionAfterAcceptance =
|
|
320
|
-
await db.discussions.get(aliceDiscussionId);
|
|
321
|
-
expect(aliceDiscussionAfterAcceptance?.status).toBe(
|
|
322
|
-
DiscussionStatus.ACTIVE
|
|
323
|
-
);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it('Both Alice and Bob send announcement at the same time', async () => {
|
|
327
|
-
// Alice adds Bob as contact
|
|
328
|
-
const aliceBobContact: Omit<Contact, 'id'> = {
|
|
329
|
-
ownerUserId: alice.session.userIdEncoded,
|
|
330
|
-
userId: bob.session.userIdEncoded,
|
|
331
|
-
name: 'Bob',
|
|
332
|
-
publicKeys: bob.session.ourPk.to_bytes(),
|
|
333
|
-
avatar: undefined,
|
|
334
|
-
isOnline: false,
|
|
335
|
-
lastSeen: new Date(),
|
|
336
|
-
createdAt: new Date(),
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
await db.contacts.add(aliceBobContact);
|
|
340
|
-
|
|
341
|
-
// Bob adds Alice as contact
|
|
342
|
-
const bobAliceContact: Omit<Contact, 'id'> = {
|
|
343
|
-
ownerUserId: bob.session.userIdEncoded,
|
|
344
|
-
userId: alice.session.userIdEncoded,
|
|
345
|
-
name: 'Alice',
|
|
346
|
-
publicKeys: alice.session.ourPk.to_bytes(),
|
|
347
|
-
avatar: undefined,
|
|
348
|
-
isOnline: false,
|
|
349
|
-
lastSeen: new Date(),
|
|
350
|
-
createdAt: new Date(),
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
await db.contacts.add(bobAliceContact);
|
|
354
|
-
|
|
355
|
-
// Both initiate at the same time
|
|
356
|
-
const { discussionId: aliceDiscussionId } =
|
|
357
|
-
await aliceDiscussionService.initialize(aliceBobContact);
|
|
358
|
-
|
|
359
|
-
const { discussionId: bobDiscussionId } =
|
|
360
|
-
await bobDiscussionService.initialize(bobAliceContact);
|
|
361
|
-
|
|
362
|
-
const aliceDiscussion = await db.discussions.get(aliceDiscussionId);
|
|
363
|
-
expect(aliceDiscussion?.status).toBe(DiscussionStatus.PENDING);
|
|
364
|
-
expect(aliceDiscussion?.direction).toBe('initiated');
|
|
365
|
-
|
|
366
|
-
const bobDiscussion = await db.discussions.get(bobDiscussionId);
|
|
367
|
-
expect(bobDiscussion?.status).toBe(DiscussionStatus.PENDING);
|
|
368
|
-
expect(bobDiscussion?.direction).toBe('initiated');
|
|
369
|
-
|
|
370
|
-
// Alice fetches and sees Bob's announcement
|
|
371
|
-
await aliceAnnouncementService.fetchAndProcessAnnouncements();
|
|
372
|
-
|
|
373
|
-
const aliceDiscussionAfterFetch =
|
|
374
|
-
await db.discussions.get(aliceDiscussionId);
|
|
375
|
-
expect(aliceDiscussionAfterFetch?.status).toBe(DiscussionStatus.ACTIVE);
|
|
376
|
-
|
|
377
|
-
// Bob fetches and sees Alice's announcement
|
|
378
|
-
await bobAnnouncementService.fetchAndProcessAnnouncements();
|
|
379
|
-
|
|
380
|
-
const bobDiscussionAfterFetch = await db.discussions.get(bobDiscussionId);
|
|
381
|
-
expect(bobDiscussionAfterFetch?.status).toBe(DiscussionStatus.ACTIVE);
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
describe('Discussion Initiation Failures', () => {
|
|
386
|
-
it('Alice signs announcement but network fails, then resend succeeds', async () => {
|
|
387
|
-
const aliceBobContact: Omit<Contact, 'id'> = {
|
|
388
|
-
ownerUserId: alice.session.userIdEncoded,
|
|
389
|
-
userId: bob.session.userIdEncoded,
|
|
390
|
-
name: 'Bob',
|
|
391
|
-
publicKeys: bob.session.ourPk.to_bytes(),
|
|
392
|
-
avatar: undefined,
|
|
393
|
-
isOnline: false,
|
|
394
|
-
lastSeen: new Date(),
|
|
395
|
-
createdAt: new Date(),
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
await db.contacts.add(aliceBobContact);
|
|
399
|
-
|
|
400
|
-
// Make network fail on first attempt
|
|
401
|
-
vi.spyOn(mockProtocol, 'sendAnnouncement')
|
|
402
|
-
.mockRejectedValueOnce(new Error('Network error'))
|
|
403
|
-
.mockResolvedValue('counter-123');
|
|
404
|
-
|
|
405
|
-
const { discussionId: aliceDiscussionId } =
|
|
406
|
-
await aliceDiscussionService.initialize(aliceBobContact);
|
|
407
|
-
|
|
408
|
-
let aliceDiscussion = await db.discussions.get(aliceDiscussionId);
|
|
409
|
-
expect(aliceDiscussion?.status).toBe(DiscussionStatus.SEND_FAILED);
|
|
410
|
-
|
|
411
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
412
|
-
|
|
413
|
-
// Resend should succeed
|
|
414
|
-
await aliceAnnouncementService.resendAnnouncements([aliceDiscussion!]);
|
|
415
|
-
|
|
416
|
-
aliceDiscussion = await db.discussions.get(aliceDiscussionId);
|
|
417
|
-
// After resend, status depends on whether Bob has responded
|
|
418
|
-
// At minimum it should not be SEND_FAILED anymore
|
|
419
|
-
expect(aliceDiscussion?.status).not.toBe(DiscussionStatus.SEND_FAILED);
|
|
420
|
-
});
|
|
421
|
-
});
|
|
422
|
-
});
|