wexa-chat 0.2.9 → 0.2.10

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/README.md CHANGED
@@ -125,6 +125,8 @@ export type InitOptions = {
125
125
  - `listMessages({ organizationId, conversationId, limit?, cursor? })`
126
126
  - `listMessagesWithSenders({ organizationId, conversationId, limit?, cursor?, populateSenders: true, populateOptions? })`
127
127
  - `markRead({ organizationId, conversationId, participantModel, participantId, messageId })`
128
+ - `receiveWhatsappMessage({ whatsappChatId, message })`
129
+ - `receiveLinkedinMessage({ linkedinChatId, message })`
128
130
 
129
131
  DTO types live in `src/types/dto.ts`.
130
132
 
@@ -254,6 +256,29 @@ Under the hood (`src/services/messages.service.ts`):
254
256
 
255
257
  This allows subsequent UI actions to prefill the last known contact handles for LinkedIn and WhatsApp.
256
258
 
259
+ ### Receiving inbound connector messages
260
+
261
+ When an external connector delivers a new inbound message, you can persist it directly using the chat ID stored on the conversation:
262
+
263
+ ```ts
264
+ await chat.services.messages.receiveWhatsappMessage({
265
+ whatsappChatId: 'wa-chat-123',
266
+ message: 'Hello from WhatsApp',
267
+ });
268
+
269
+ await chat.services.messages.receiveLinkedinMessage({
270
+ linkedinChatId: 'li-chat-456',
271
+ message: 'Hello from LinkedIn',
272
+ });
273
+ ```
274
+
275
+ Both helpers will:
276
+
277
+ 1. Locate the conversation by the given chat ID.
278
+ 2. Use the `Application` participant from the conversation as the sender.
279
+ 3. Create a new message with `kind: 'text'` and `source` set to the respective connector.
280
+ 4. Update the conversation summary fields (`lastMessageAt`, `lastMessagePreview`, `lastMessageSenderId`, `lastMessageSenderModel`).
281
+
257
282
  ## Models
258
283
 
259
284
  The package exports the following model types which can be imported directly:
package/dist/index.d.cts CHANGED
@@ -375,6 +375,14 @@ interface MessagesService {
375
375
  populateSenders: true;
376
376
  }): Promise<PaginatedResult<MessageWithSender>>;
377
377
  markRead(args: MarkReadArgs): Promise<void>;
378
+ receiveWhatsappMessage(args: {
379
+ whatsappChatId: string;
380
+ message: string;
381
+ }): Promise<IMessage>;
382
+ receiveLinkedinMessage(args: {
383
+ linkedinChatId: string;
384
+ message: string;
385
+ }): Promise<IMessage>;
378
386
  }
379
387
  /**
380
388
  * Create messages service
package/dist/index.d.ts CHANGED
@@ -375,6 +375,14 @@ interface MessagesService {
375
375
  populateSenders: true;
376
376
  }): Promise<PaginatedResult<MessageWithSender>>;
377
377
  markRead(args: MarkReadArgs): Promise<void>;
378
+ receiveWhatsappMessage(args: {
379
+ whatsappChatId: string;
380
+ message: string;
381
+ }): Promise<IMessage>;
382
+ receiveLinkedinMessage(args: {
383
+ linkedinChatId: string;
384
+ message: string;
385
+ }): Promise<IMessage>;
378
386
  }
379
387
  /**
380
388
  * Create messages service
package/dist/index.js CHANGED
@@ -78,6 +78,8 @@ function createConversationModel(options, conn) {
78
78
  },
79
79
  { timestamps: true }
80
80
  );
81
+ ConversationSchema.index({ linkedinChatId: 1 }, { unique: false, sparse: true });
82
+ ConversationSchema.index({ whatsappChatId: 1 }, { unique: false, sparse: true });
81
83
  const model = conn.model(name, ConversationSchema);
82
84
  modelRegistry.set(registryKey, model);
83
85
  return model;
@@ -659,6 +661,86 @@ function createMessagesService(models, hooks = {}) {
659
661
  message.failed_source = failed_source;
660
662
  return message;
661
663
  },
664
+ /**
665
+ * Receive a new message by whatsappChatId
666
+ */
667
+ async receiveWhatsappMessage({ whatsappChatId, message }) {
668
+ const conversation = await Conversation.findOne({ whatsappChatId }).lean();
669
+ if (!conversation) {
670
+ throw new Error("Conversation not found for given whatsappChatId");
671
+ }
672
+ const applicationParticipant = conversation.participants.find(
673
+ (p) => p.entityModel === "Application"
674
+ );
675
+ if (!applicationParticipant) {
676
+ throw new Error("Application participant not found in conversation");
677
+ }
678
+ const orgId = conversation.organizationId;
679
+ const senderModel = "Application";
680
+ const senderId = applicationParticipant.entityId;
681
+ const msgDoc = new Message({
682
+ organizationId: orgId,
683
+ conversationId: String(conversation._id),
684
+ senderModel,
685
+ senderId,
686
+ text: message,
687
+ kind: "text",
688
+ source: ["whatsapp"],
689
+ parentMessageId: void 0,
690
+ rootThreadId: void 0
691
+ });
692
+ await msgDoc.save();
693
+ await Conversation.findByIdAndUpdate(conversation._id, {
694
+ $set: {
695
+ lastMessageAt: msgDoc.createdAt,
696
+ lastMessagePreview: message.substring(0, 100),
697
+ lastMessageSenderId: senderId,
698
+ lastMessageSenderModel: senderModel
699
+ }
700
+ });
701
+ if (onMessageCreated) onMessageCreated(msgDoc);
702
+ return msgDoc;
703
+ },
704
+ /**
705
+ * Receive a new message by linkedinChatId
706
+ */
707
+ async receiveLinkedinMessage({ linkedinChatId, message }) {
708
+ const conversation = await Conversation.findOne({ linkedinChatId }).lean();
709
+ if (!conversation) {
710
+ throw new Error("Conversation not found for given linkedinChatId");
711
+ }
712
+ const applicationParticipant = conversation.participants.find(
713
+ (p) => p.entityModel === "Application"
714
+ );
715
+ if (!applicationParticipant) {
716
+ throw new Error("Application participant not found in conversation");
717
+ }
718
+ const orgId = conversation.organizationId;
719
+ const senderModel = "Application";
720
+ const senderId = applicationParticipant.entityId;
721
+ const msgDoc = new Message({
722
+ organizationId: orgId,
723
+ conversationId: String(conversation._id),
724
+ senderModel,
725
+ senderId,
726
+ text: message,
727
+ kind: "text",
728
+ source: ["linkedin"],
729
+ parentMessageId: void 0,
730
+ rootThreadId: void 0
731
+ });
732
+ await msgDoc.save();
733
+ await Conversation.findByIdAndUpdate(conversation._id, {
734
+ $set: {
735
+ lastMessageAt: msgDoc.createdAt,
736
+ lastMessagePreview: message.substring(0, 100),
737
+ lastMessageSenderId: senderId,
738
+ lastMessageSenderModel: senderModel
739
+ }
740
+ });
741
+ if (onMessageCreated) onMessageCreated(msgDoc);
742
+ return msgDoc;
743
+ },
662
744
  /**
663
745
  * List messages for a conversation with pagination
664
746
  * @param args Message listing arguments