@chaterafrikang/sdk 0.1.0-beta.3 → 0.1.0-beta.4

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/index.cjs CHANGED
@@ -445,15 +445,19 @@ var MessageFactory = class {
445
445
  };
446
446
  }
447
447
  /**
448
- * Create a message from server payload (confirmed message)
448
+ * Create a message from server payload (confirmed message).
449
+ * Normalizes sender_id/senderId and sender_type/senderType so either snake or camelCase from server works.
449
450
  */
450
451
  static fromServerPayload(conversationId, payload) {
452
+ const senderId = payload.sender_id ?? payload.senderId;
453
+ const senderType = payload.sender_type ?? payload.senderType;
451
454
  return {
452
455
  id: payload.message_id,
453
456
  conversationId,
454
457
  content: payload.content,
455
- senderId: payload.sender_id,
456
- senderType: payload.sender_type,
458
+ senderId,
459
+ senderName: payload.sender_name,
460
+ senderType,
457
461
  messageType: payload.message_type === "system" ? "system" : "text",
458
462
  optimistic: false,
459
463
  receiptState: "sent",
@@ -461,14 +465,18 @@ var MessageFactory = class {
461
465
  };
462
466
  }
463
467
  /**
464
- * Convert an optimistic message to confirmed (reconciliation)
468
+ * Convert an optimistic message to confirmed (reconciliation).
469
+ * Normalizes sender_id/senderId and sender_type/senderType from server payload.
465
470
  */
466
471
  static confirmOptimistic(optimisticMessage, serverPayload) {
472
+ const senderId = serverPayload.sender_id ?? serverPayload.senderId;
473
+ const senderType = serverPayload.sender_type ?? serverPayload.senderType;
467
474
  return {
468
475
  ...optimisticMessage,
469
476
  optimistic: false,
470
- senderId: serverPayload.sender_id,
471
- senderType: serverPayload.sender_type,
477
+ senderId,
478
+ senderName: serverPayload.sender_name,
479
+ senderType,
472
480
  receiptState: optimisticMessage.receiptState ?? "sent",
473
481
  createdAt: serverPayload.sent_at ? new Date(serverPayload.sent_at) : optimisticMessage.createdAt
474
482
  };
@@ -619,6 +627,10 @@ var MessageManager = class extends eventemitter3.EventEmitter {
619
627
  * Map<conversationId, Map<message_id, Message>>
620
628
  */
621
629
  this.confirmedMessages = /* @__PURE__ */ new Map();
630
+ /**
631
+ * Conversations we've already warned about missing sender_id (warn once per conversation)
632
+ */
633
+ this.warnedMissingSenderId = /* @__PURE__ */ new Set();
622
634
  this.logger = new Logger(debug);
623
635
  this.receiptManager = new ReceiptManager(debug);
624
636
  this.receiptManager.on("receipt", (event) => {
@@ -659,6 +671,12 @@ var MessageManager = class extends eventemitter3.EventEmitter {
659
671
  const optimisticMessage = this.getOptimisticMessage(conversationId, messageId);
660
672
  if (optimisticMessage) {
661
673
  const reconciledMessage = this.reconcileOptimisticMessage(optimisticMessage, serverPayload);
674
+ if (reconciledMessage.senderId == null && !this.warnedMissingSenderId.has(conversationId)) {
675
+ this.warnedMissingSenderId.add(conversationId);
676
+ console.warn(
677
+ '[ChatAfrika SDK] Message payload missing sender_id (and sender_type). Clients cannot show "You" vs other participant. The realtime backend MUST include sender_id and sender_type in every type:"message" payload. See docs/REALTIME_WEBSOCKET_CONTRACT.md.'
678
+ );
679
+ }
662
680
  this.removeOptimisticMessage(conversationId, messageId);
663
681
  this.trackMessageId(conversationId, messageId);
664
682
  this.trackConfirmedMessage(conversationId, messageId, reconciledMessage);
@@ -670,6 +688,12 @@ var MessageManager = class extends eventemitter3.EventEmitter {
670
688
  }
671
689
  this.trackMessageId(conversationId, messageId);
672
690
  const message = MessageFactory.fromServerPayload(conversationId, serverPayload);
691
+ if (message.senderId == null && !this.warnedMissingSenderId.has(conversationId)) {
692
+ this.warnedMissingSenderId.add(conversationId);
693
+ console.warn(
694
+ '[ChatAfrika SDK] Message payload missing sender_id (and sender_type). Clients cannot show "You" vs other participant. The realtime backend MUST include sender_id and sender_type in every type:"message" payload. See docs/REALTIME_WEBSOCKET_CONTRACT.md.'
695
+ );
696
+ }
673
697
  this.trackConfirmedMessage(conversationId, messageId, message);
674
698
  this.emit("message", message);
675
699
  this.logger.debug("Handled incoming message:", messageId);
@@ -723,17 +747,14 @@ var MessageManager = class extends eventemitter3.EventEmitter {
723
747
  this.logger.warn("Receipt for unknown message:", event.messageId);
724
748
  }
725
749
  /**
726
- * Reconcile an optimistic message with a server confirmation
727
- *
728
- * This is called when we receive a server message with the same message_id
729
- * as an optimistic message we previously created.
730
- *
750
+ * Reconcile an optimistic message with a server confirmation.
751
+ * Does not emit again so the app receives at most one event per message_id.
752
+ *
731
753
  * @returns The reconciled (confirmed) message
732
754
  */
733
755
  reconcileOptimisticMessage(optimisticMessage, serverPayload) {
734
756
  const confirmedMessage = MessageFactory.confirmOptimistic(optimisticMessage, serverPayload);
735
- this.emit("message", confirmedMessage);
736
- this.logger.debug("Reconciled optimistic message:", optimisticMessage.id);
757
+ this.logger.debug("Reconciled optimistic message (no second emit):", optimisticMessage.id);
737
758
  return confirmedMessage;
738
759
  }
739
760
  /**
@@ -743,6 +764,15 @@ var MessageManager = class extends eventemitter3.EventEmitter {
743
764
  const seenIds = this.seenMessageIds.get(conversationId);
744
765
  return seenIds?.has(messageId) ?? false;
745
766
  }
767
+ /**
768
+ * Track message IDs from REST history so the same message is not emitted again via WebSocket.
769
+ * Call after fetchMessages() so history and real-time stay deduped.
770
+ */
771
+ trackMessageIdsFromHistory(conversationId, messageIds) {
772
+ for (const id of messageIds) {
773
+ this.trackMessageId(conversationId, id);
774
+ }
775
+ }
746
776
  /**
747
777
  * Track a message ID for a conversation (for deduplication)
748
778
  */
@@ -1037,11 +1067,16 @@ var Conversation = class extends eventemitter3.EventEmitter {
1037
1067
  "REST not configured. Set apiUrl in ChatAfrika config for fetchMessages() (token, API keys, or getRestHeaders)."
1038
1068
  );
1039
1069
  }
1040
- return this.fetchMessagesCallback({
1070
+ const result = await this.fetchMessagesCallback({
1041
1071
  externalUserId: options?.externalUserId ?? "",
1042
1072
  cursor: options?.cursor,
1043
1073
  limit: options?.limit
1044
1074
  });
1075
+ this.messageManager.trackMessageIdsFromHistory(
1076
+ this.id,
1077
+ result.messages.map((m) => m.id)
1078
+ );
1079
+ return result;
1045
1080
  }
1046
1081
  /**
1047
1082
  * Mark conversation as joined