@massalabs/gossip-sdk 0.0.2-dev.20260416120049 → 0.0.2-dev.20260417075224

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.
@@ -15,12 +15,6 @@ export declare enum SdkEventType {
15
15
  SEEKERS_UPDATED = "seekersUpdated",
16
16
  SESSION_STATUS_CHANGED = "sessionStatusChanged",
17
17
  DISCUSSION_UPDATED = "discussionUpdated",
18
- WRITE_FAILED = "writeFailed",
19
- MESSAGE_OPTIMISTIC = "messageOptimistic",
20
- MESSAGE_DELETED_OPTIMISTIC = "messageDeletedOptimistic",
21
- MESSAGE_EDITED_OPTIMISTIC = "messageEditedOptimistic",
22
- MESSAGE_DELETE_FAILED = "messageDeleteFailed",
23
- MESSAGE_EDIT_FAILED = "messageEditFailed",
24
18
  MESSAGE_ACKNOWLEDGED = "messageAcknowledged",
25
19
  ERROR = "error"
26
20
  }
@@ -47,33 +41,6 @@ export type SdkEvents = {
47
41
  status: SessionStatus;
48
42
  };
49
43
  [SdkEventType.DISCUSSION_UPDATED]: string;
50
- [SdkEventType.WRITE_FAILED]: {
51
- messageId: Uint8Array | undefined;
52
- entityType: 'message' | 'discussion' | 'contact';
53
- error: Error;
54
- };
55
- [SdkEventType.MESSAGE_OPTIMISTIC]: Message;
56
- [SdkEventType.MESSAGE_DELETED_OPTIMISTIC]: {
57
- contactUserId: string;
58
- messageDbId: number;
59
- originalMsgId: Uint8Array;
60
- };
61
- [SdkEventType.MESSAGE_EDITED_OPTIMISTIC]: {
62
- contactUserId: string;
63
- messageDbId: number;
64
- newContent: string;
65
- metadata: Record<string, unknown>;
66
- };
67
- [SdkEventType.MESSAGE_DELETE_FAILED]: {
68
- contactUserId: string;
69
- messageDbId: number;
70
- original: Message;
71
- };
72
- [SdkEventType.MESSAGE_EDIT_FAILED]: {
73
- contactUserId: string;
74
- messageDbId: number;
75
- original: Message;
76
- };
77
44
  [SdkEventType.MESSAGE_ACKNOWLEDGED]: {
78
45
  contactUserId: string;
79
46
  messageDbId: number;
@@ -15,12 +15,6 @@ export var SdkEventType;
15
15
  SdkEventType["SEEKERS_UPDATED"] = "seekersUpdated";
16
16
  SdkEventType["SESSION_STATUS_CHANGED"] = "sessionStatusChanged";
17
17
  SdkEventType["DISCUSSION_UPDATED"] = "discussionUpdated";
18
- SdkEventType["WRITE_FAILED"] = "writeFailed";
19
- SdkEventType["MESSAGE_OPTIMISTIC"] = "messageOptimistic";
20
- SdkEventType["MESSAGE_DELETED_OPTIMISTIC"] = "messageDeletedOptimistic";
21
- SdkEventType["MESSAGE_EDITED_OPTIMISTIC"] = "messageEditedOptimistic";
22
- SdkEventType["MESSAGE_DELETE_FAILED"] = "messageDeleteFailed";
23
- SdkEventType["MESSAGE_EDIT_FAILED"] = "messageEditFailed";
24
18
  SdkEventType["MESSAGE_ACKNOWLEDGED"] = "messageAcknowledged";
25
19
  SdkEventType["ERROR"] = "error";
26
20
  })(SdkEventType || (SdkEventType = {}));
@@ -117,13 +117,6 @@ export declare class MessageService {
117
117
  getReactions(contactUserId: string): Promise<Message[]>;
118
118
  /** Send a message and await the full DB write + queue pipeline. */
119
119
  send(message: Omit<Message, 'id'>): Promise<SendMessageResult>;
120
- /**
121
- * Optimistic send: generates messageId, emits MESSAGE_OPTIMISTIC immediately,
122
- * and persists in the background. Returns synchronously.
123
- */
124
- send(message: Omit<Message, 'id'>, options: {
125
- optimistic: true;
126
- }): SendMessageResult;
127
120
  /**
128
121
  * Send a text message (simplified).
129
122
  * Builds the Message internally, sends it via queue, and triggers state update.
@@ -1307,50 +1307,12 @@ export class MessageService {
1307
1307
  const rows = await this.queries.messages.getReactionsByOwnerAndContact(this.session.userIdEncoded, contactUserId);
1308
1308
  return rows.map(rowToMessage);
1309
1309
  }
1310
- send(message, options) {
1311
- if (!options?.optimistic) {
1312
- if (this.queueManager) {
1313
- return this.queueManager.enqueue(message.contactUserId, () => this.sendMessage(message));
1314
- }
1315
- return this.sendMessage(message);
1316
- }
1317
- const log = logger.forMethod('send:optimistic');
1318
- const peerId = decodeUserId(message.contactUserId);
1319
- if (peerId.length !== 32) {
1320
- return {
1321
- success: false,
1322
- error: 'Invalid contact userId (must be 32 bytes)',
1323
- };
1310
+ /** Send a message and await the full DB write + queue pipeline. */
1311
+ async send(message) {
1312
+ if (this.queueManager) {
1313
+ return this.queueManager.enqueue(message.contactUserId, () => this.sendMessage(message));
1324
1314
  }
1325
- const messageId = message.type !== MessageType.KEEP_ALIVE &&
1326
- message.type !== MessageType.RETENTION_POLICY
1327
- ? crypto.getRandomValues(new Uint8Array(MESSAGE_ID_SIZE))
1328
- : undefined;
1329
- const optimisticMessage = {
1330
- ...message,
1331
- messageId,
1332
- status: MessageStatus.WAITING_SESSION,
1333
- };
1334
- this.eventEmitter.emit(SdkEventType.MESSAGE_OPTIMISTIC, optimisticMessage);
1335
- log.info('optimistic send', { messageType: message.type });
1336
- // Persist in background (non-optimistic path)
1337
- this.send({ ...message, messageId }).then(result => {
1338
- if (!result.success) {
1339
- this.eventEmitter.emit(SdkEventType.WRITE_FAILED, {
1340
- messageId,
1341
- entityType: 'message',
1342
- error: new Error(result.error ?? 'Unknown error'),
1343
- });
1344
- }
1345
- }, error => {
1346
- log.error('optimistic send failed', { error });
1347
- this.eventEmitter.emit(SdkEventType.WRITE_FAILED, {
1348
- messageId,
1349
- entityType: 'message',
1350
- error: error instanceof Error ? error : new Error(String(error)),
1351
- });
1352
- });
1353
- return { success: true, message: optimisticMessage };
1315
+ return this.sendMessage(message);
1354
1316
  }
1355
1317
  /**
1356
1318
  * Send a text message (simplified).
@@ -1389,57 +1351,30 @@ export class MessageService {
1389
1351
  return false;
1390
1352
  if (!row.messageId)
1391
1353
  throw new Error('Cannot delete a message that has no messageId');
1392
- const original = rowToMessage(row);
1393
1354
  const ownerUserId = this.session.userIdEncoded;
1394
- // Emit optimistic event so UI updates immediately (skip for reactions —
1395
- // the store handles reaction removal separately).
1396
- if (row.type !== MessageType.REACTION) {
1397
- this.eventEmitter.emit(SdkEventType.MESSAGE_DELETED_OPTIMISTIC, {
1398
- contactUserId: row.contactUserId,
1399
- messageDbId: id,
1400
- originalMsgId: row.messageId,
1401
- });
1402
- }
1403
- try {
1404
- const messageId = row.messageId;
1405
- await this.queries.conn.withTransaction(async () => {
1406
- await this.queries.messages.updateById(id, {
1407
- content: '[Message deleted]',
1408
- type: MessageType.DELETED,
1409
- });
1410
- await this.queries.messages.deleteReactionsForMessage(ownerUserId, row.contactUserId, encodeToBase64(messageId));
1411
- });
1412
- const controlMessage = {
1413
- ownerUserId,
1414
- contactUserId: row.contactUserId,
1415
- content: '',
1355
+ const messageId = row.messageId;
1356
+ await this.queries.conn.withTransaction(async () => {
1357
+ await this.queries.messages.updateById(id, {
1358
+ content: '[Message deleted]',
1416
1359
  type: MessageType.DELETED,
1417
- direction: MessageDirection.OUTGOING,
1418
- status: MessageStatus.WAITING_SESSION,
1419
- timestamp: new Date(),
1420
- deleteOf: { originalMsgId: row.messageId },
1421
- };
1422
- const result = await this.send(controlMessage);
1423
- if (!result.success)
1424
- throw new Error(result.error ?? 'Failed to enqueue delete message');
1425
- await this.refreshService?.stateUpdate();
1426
- return true;
1427
- }
1428
- catch (error) {
1429
- // Rollback: emit failure so store can restore original
1430
- if (row.type !== MessageType.REACTION) {
1431
- this.eventEmitter.emit(SdkEventType.MESSAGE_DELETE_FAILED, {
1432
- contactUserId: row.contactUserId,
1433
- messageDbId: id,
1434
- original,
1435
- });
1436
- }
1437
- // Best-effort DB rollback
1438
- await this.queries.messages
1439
- .updateById(id, { content: original.content, type: original.type })
1440
- .catch(() => { });
1441
- throw error;
1442
- }
1360
+ });
1361
+ await this.queries.messages.deleteReactionsForMessage(ownerUserId, row.contactUserId, encodeToBase64(messageId));
1362
+ });
1363
+ const controlMessage = {
1364
+ ownerUserId,
1365
+ contactUserId: row.contactUserId,
1366
+ content: '',
1367
+ type: MessageType.DELETED,
1368
+ direction: MessageDirection.OUTGOING,
1369
+ status: MessageStatus.WAITING_SESSION,
1370
+ timestamp: new Date(),
1371
+ deleteOf: { originalMsgId: row.messageId },
1372
+ };
1373
+ const result = await this.send(controlMessage);
1374
+ if (!result.success)
1375
+ throw new Error(result.error ?? 'Failed to enqueue delete message');
1376
+ await this.refreshService?.stateUpdate();
1377
+ return true;
1443
1378
  }
1444
1379
  async sendReaction(contactUserId, emoji, originalMsgId) {
1445
1380
  const message = {
@@ -1469,53 +1404,29 @@ export class MessageService {
1469
1404
  return false;
1470
1405
  if (!row.messageId || row.messageId.length !== MESSAGE_ID_SIZE)
1471
1406
  throw new Error('Cannot edit a message that has no valid messageId');
1472
- const original = rowToMessage(row);
1473
1407
  const ownerUserId = this.session.userIdEncoded;
1474
1408
  const existingMetadata = deserializeMetadata(row.metadata) ?? {};
1475
1409
  const mergedMetadata = { ...existingMetadata, edited: true };
1476
- // Emit optimistic event so UI updates immediately
1477
- this.eventEmitter.emit(SdkEventType.MESSAGE_EDITED_OPTIMISTIC, {
1478
- contactUserId: row.contactUserId,
1479
- messageDbId: id,
1480
- newContent,
1481
- metadata: mergedMetadata,
1410
+ await this.queries.messages.updateById(id, {
1411
+ content: newContent,
1412
+ metadata: serializeMetadata(mergedMetadata),
1482
1413
  });
1483
- try {
1484
- await this.queries.messages.updateById(id, {
1485
- content: newContent,
1486
- metadata: serializeMetadata(mergedMetadata),
1487
- });
1488
- const controlMessage = {
1489
- ownerUserId,
1490
- contactUserId: row.contactUserId,
1491
- content: newContent,
1492
- type: MessageType.TEXT,
1493
- direction: MessageDirection.OUTGOING,
1494
- status: MessageStatus.WAITING_SESSION,
1495
- timestamp: new Date(),
1496
- editOf: { originalMsgId: row.messageId },
1497
- metadata: { control: 'edit' },
1498
- };
1499
- const result = await this.send(controlMessage);
1500
- if (!result.success)
1501
- throw new Error(result.error ?? 'Failed to enqueue edit message');
1502
- await this.refreshService?.stateUpdate();
1503
- return true;
1504
- }
1505
- catch (error) {
1506
- this.eventEmitter.emit(SdkEventType.MESSAGE_EDIT_FAILED, {
1507
- contactUserId: row.contactUserId,
1508
- messageDbId: id,
1509
- original,
1510
- });
1511
- await this.queries.messages
1512
- .updateById(id, {
1513
- content: original.content,
1514
- metadata: row.metadata ?? undefined,
1515
- })
1516
- .catch(() => { });
1517
- throw error;
1518
- }
1414
+ const controlMessage = {
1415
+ ownerUserId,
1416
+ contactUserId: row.contactUserId,
1417
+ content: newContent,
1418
+ type: MessageType.TEXT,
1419
+ direction: MessageDirection.OUTGOING,
1420
+ status: MessageStatus.WAITING_SESSION,
1421
+ timestamp: new Date(),
1422
+ editOf: { originalMsgId: row.messageId },
1423
+ metadata: { control: 'edit' },
1424
+ };
1425
+ const result = await this.send(controlMessage);
1426
+ if (!result.success)
1427
+ throw new Error(result.error ?? 'Failed to enqueue edit message');
1428
+ await this.refreshService?.stateUpdate();
1429
+ return true;
1519
1430
  }
1520
1431
  /**
1521
1432
  * Hard-delete messages that have exceeded their discussion retention duration.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massalabs/gossip-sdk",
3
- "version": "0.0.2-dev.20260416120049",
3
+ "version": "0.0.2-dev.20260417075224",
4
4
  "description": "Gossip SDK for automation, chatbot, and integration use cases",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",