wexa-chat 0.2.6 → 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
@@ -247,6 +247,22 @@ type SearchConversationsArgs = {
247
247
  cursor?: string;
248
248
  };
249
249
 
250
+ /**
251
+ * Represents a successful chat start response
252
+ */
253
+ interface ChatStartedResponse {
254
+ object: 'ChatStarted';
255
+ chat_id: string;
256
+ message_id: string;
257
+ }
258
+ /**
259
+ * Common response type for chat API operations
260
+ */
261
+ type ChatApiResponse = ChatStartedResponse | {
262
+ error: string;
263
+ details?: unknown;
264
+ };
265
+
250
266
  interface IConversation extends Document {
251
267
  organizationId: string;
252
268
  participants: Array<{
@@ -359,6 +375,14 @@ interface MessagesService {
359
375
  populateSenders: true;
360
376
  }): Promise<PaginatedResult<MessageWithSender>>;
361
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>;
362
386
  }
363
387
  /**
364
388
  * Create messages service
@@ -582,4 +606,4 @@ interface ChatServices {
582
606
  */
583
607
  declare function initChat(mongooseInstance: typeof mongoose, options: InitOptions, server?: Server): Promise<ChatServices>;
584
608
 
585
- export { type Actor, type ChatServices, type ConversationModel, type ConversationReadEvent, type ConversationsService, type CreateConversationArgs, type EnvironmentConfig, type IConversation, type IMessage, type InitOptions, type ListMessagesArgs, type MarkReadArgs, type MessageCreatedEvent, type MessageModel, type MessageServiceHooks, type MessageWithSender, type MessagesService, type PaginatedResult, type PresenceEvent, type RedisConfig, type RuntimeConfig, type SearchConversationsArgs, type SearchMessagesArgs, type SendMessageArgs, type SocketConfig$1 as SocketConfig, type SourceType, type Transport, type TransportConfig, type TypingEvent, createConversationId, createConversationModel, createConversationsService, createCursor, createMessageId, createMessageModel, createMessagesService, createModels, createPaginatedResponse, createThreadId, createTransport, ensureIndexes, generateId, getRedisConfig, getRuntimeConfig, initChat, modelRegistry, parseCursor, searchByParticipantPair, searchConversations, searchMessages, setRuntimeConfig, sourceType, validateCreateConversationArgs, validateInitOptions, validateMarkReadArgs, validatePagination, validateSendMessageArgs };
609
+ export { type Actor, type ChatApiResponse, type ChatServices, type ChatStartedResponse, type ConversationModel, type ConversationReadEvent, type ConversationsService, type CreateConversationArgs, type EnvironmentConfig, type IConversation, type IMessage, type InitOptions, type ListMessagesArgs, type MarkReadArgs, type MessageCreatedEvent, type MessageModel, type MessageServiceHooks, type MessageWithSender, type MessagesService, type PaginatedResult, type PresenceEvent, type RedisConfig, type RuntimeConfig, type SearchConversationsArgs, type SearchMessagesArgs, type SendMessageArgs, type SocketConfig$1 as SocketConfig, type SourceType, type Transport, type TransportConfig, type TypingEvent, createConversationId, createConversationModel, createConversationsService, createCursor, createMessageId, createMessageModel, createMessagesService, createModels, createPaginatedResponse, createThreadId, createTransport, ensureIndexes, generateId, getRedisConfig, getRuntimeConfig, initChat, modelRegistry, parseCursor, searchByParticipantPair, searchConversations, searchMessages, setRuntimeConfig, sourceType, validateCreateConversationArgs, validateInitOptions, validateMarkReadArgs, validatePagination, validateSendMessageArgs };
package/dist/index.d.ts CHANGED
@@ -247,6 +247,22 @@ type SearchConversationsArgs = {
247
247
  cursor?: string;
248
248
  };
249
249
 
250
+ /**
251
+ * Represents a successful chat start response
252
+ */
253
+ interface ChatStartedResponse {
254
+ object: 'ChatStarted';
255
+ chat_id: string;
256
+ message_id: string;
257
+ }
258
+ /**
259
+ * Common response type for chat API operations
260
+ */
261
+ type ChatApiResponse = ChatStartedResponse | {
262
+ error: string;
263
+ details?: unknown;
264
+ };
265
+
250
266
  interface IConversation extends Document {
251
267
  organizationId: string;
252
268
  participants: Array<{
@@ -359,6 +375,14 @@ interface MessagesService {
359
375
  populateSenders: true;
360
376
  }): Promise<PaginatedResult<MessageWithSender>>;
361
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>;
362
386
  }
363
387
  /**
364
388
  * Create messages service
@@ -582,4 +606,4 @@ interface ChatServices {
582
606
  */
583
607
  declare function initChat(mongooseInstance: typeof mongoose, options: InitOptions, server?: Server): Promise<ChatServices>;
584
608
 
585
- export { type Actor, type ChatServices, type ConversationModel, type ConversationReadEvent, type ConversationsService, type CreateConversationArgs, type EnvironmentConfig, type IConversation, type IMessage, type InitOptions, type ListMessagesArgs, type MarkReadArgs, type MessageCreatedEvent, type MessageModel, type MessageServiceHooks, type MessageWithSender, type MessagesService, type PaginatedResult, type PresenceEvent, type RedisConfig, type RuntimeConfig, type SearchConversationsArgs, type SearchMessagesArgs, type SendMessageArgs, type SocketConfig$1 as SocketConfig, type SourceType, type Transport, type TransportConfig, type TypingEvent, createConversationId, createConversationModel, createConversationsService, createCursor, createMessageId, createMessageModel, createMessagesService, createModels, createPaginatedResponse, createThreadId, createTransport, ensureIndexes, generateId, getRedisConfig, getRuntimeConfig, initChat, modelRegistry, parseCursor, searchByParticipantPair, searchConversations, searchMessages, setRuntimeConfig, sourceType, validateCreateConversationArgs, validateInitOptions, validateMarkReadArgs, validatePagination, validateSendMessageArgs };
609
+ export { type Actor, type ChatApiResponse, type ChatServices, type ChatStartedResponse, type ConversationModel, type ConversationReadEvent, type ConversationsService, type CreateConversationArgs, type EnvironmentConfig, type IConversation, type IMessage, type InitOptions, type ListMessagesArgs, type MarkReadArgs, type MessageCreatedEvent, type MessageModel, type MessageServiceHooks, type MessageWithSender, type MessagesService, type PaginatedResult, type PresenceEvent, type RedisConfig, type RuntimeConfig, type SearchConversationsArgs, type SearchMessagesArgs, type SendMessageArgs, type SocketConfig$1 as SocketConfig, type SourceType, type Transport, type TransportConfig, type TypingEvent, createConversationId, createConversationModel, createConversationsService, createCursor, createMessageId, createMessageModel, createMessagesService, createModels, createPaginatedResponse, createThreadId, createTransport, ensureIndexes, generateId, getRedisConfig, getRuntimeConfig, initChat, modelRegistry, parseCursor, searchByParticipantPair, searchConversations, searchMessages, setRuntimeConfig, sourceType, validateCreateConversationArgs, validateInitOptions, validateMarkReadArgs, validatePagination, validateSendMessageArgs };
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;
@@ -555,6 +557,8 @@ function createMessagesService(models, hooks = {}) {
555
557
  const tasks = [];
556
558
  let lastLinkedInId;
557
559
  let lastWhatsAppId;
560
+ let linkedinChatId;
561
+ let whatsappChatId;
558
562
  if (Array.isArray(source) && source.includes("linkedin")) {
559
563
  const LinkedinConnector = connectorIds && connectorIds.linkedin;
560
564
  lastLinkedInId = LinkedinConnector == null ? void 0 : LinkedinConnector.connectorId;
@@ -563,10 +567,18 @@ function createMessagesService(models, hooks = {}) {
563
567
  name: "linkedin",
564
568
  run: async () => {
565
569
  const path = paths.linkedin.startChat(String(LinkedinConnector.connectorId));
566
- await getAxios().post(path, {
567
- linkedin_url: LinkedinConnector.contactId,
568
- text
569
- });
570
+ try {
571
+ const res = await getAxios().post(path, {
572
+ linkedin_url: LinkedinConnector.contactId,
573
+ text
574
+ });
575
+ const data = res.data;
576
+ console.log("linkedinChatId", data);
577
+ linkedinChatId = data.chat_data.chat_id;
578
+ return { status: "fulfilled", value: data };
579
+ } catch (error) {
580
+ return { status: "rejected", reason: error };
581
+ }
570
582
  }
571
583
  });
572
584
  } else {
@@ -587,7 +599,14 @@ function createMessagesService(models, hooks = {}) {
587
599
  phone_numbers: sanitize(raw),
588
600
  text
589
601
  };
590
- await getAxios().post(path, body);
602
+ try {
603
+ const res = await getAxios().post(path, body);
604
+ const data = res.data;
605
+ whatsappChatId = data.chat_id;
606
+ return { status: "fulfilled", value: data };
607
+ } catch (error) {
608
+ return { status: "rejected", reason: error };
609
+ }
591
610
  }
592
611
  });
593
612
  } else {
@@ -596,22 +615,21 @@ function createMessagesService(models, hooks = {}) {
596
615
  }
597
616
  if (tasks.length > 0) {
598
617
  const results = await Promise.allSettled(tasks.map((t) => t.run()));
599
- results.forEach((res, idx) => {
618
+ results.forEach((result, idx) => {
619
+ var _a, _b, _c, _d, _e, _f;
600
620
  const name = tasks[idx].name;
601
- if (res.status === "fulfilled") {
621
+ if (result.status === "fulfilled") {
602
622
  success_source.push(name);
603
623
  } else {
604
- const err = success_source;
605
- res.reason.response.data.detail || res.reason.response.data || "Unknown error";
624
+ const error = ((_c = (_b = (_a = result.reason) == null ? void 0 : _a.response) == null ? void 0 : _b.data) == null ? void 0 : _c.detail) || ((_e = (_d = result.reason) == null ? void 0 : _d.response) == null ? void 0 : _e.data) || ((_f = result.reason) == null ? void 0 : _f.message) || "Unknown error";
606
625
  failed_source.push({
607
626
  source: name,
608
- message: typeof err === "string" ? err : JSON.stringify(err)
627
+ message: typeof error === "string" ? error : JSON.stringify(error)
609
628
  });
629
+ console.error(`${name} failed:`, error);
610
630
  }
611
631
  });
612
- console.log("results", results);
613
632
  }
614
- console.log("success_source", success_source);
615
633
  const message = new Message({
616
634
  organizationId,
617
635
  conversationId,
@@ -632,6 +650,8 @@ function createMessagesService(models, hooks = {}) {
632
650
  };
633
651
  if (lastLinkedInId) conversationUpdate.lastLinkedInId = lastLinkedInId;
634
652
  if (lastWhatsAppId) conversationUpdate.lastWhatsAppId = lastWhatsAppId;
653
+ if (linkedinChatId) conversationUpdate.linkedinChatId = linkedinChatId;
654
+ if (whatsappChatId) conversationUpdate.whatsappChatId = whatsappChatId;
635
655
  await Conversation.findByIdAndUpdate(conversationId, {
636
656
  $set: conversationUpdate
637
657
  });
@@ -641,6 +661,86 @@ function createMessagesService(models, hooks = {}) {
641
661
  message.failed_source = failed_source;
642
662
  return message;
643
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
+ },
644
744
  /**
645
745
  * List messages for a conversation with pagination
646
746
  * @param args Message listing arguments