wexa-chat 0.2.0 → 0.2.2

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
@@ -121,7 +121,7 @@ export type InitOptions = {
121
121
  - `searchByParticipantPair({ organizationId, a, b })`
122
122
 
123
123
  - Messages
124
- - `sendMessage({ organizationId, conversationId, senderModel, senderId, text, source, kind?, parentMessageId?, rootThreadId? })`
124
+ - `sendMessage({ organizationId, conversationId, senderModel, senderId, text, source, kind?, parentMessageId?, rootThreadId?, connectorIds? })`
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 })`
@@ -209,9 +209,9 @@ The method returns messages sorted by creation time (newest first), making it id
209
209
 
210
210
  The type `MessageWithSender` is exported from the package for proper TypeScript support.
211
211
 
212
- ### Message Source
212
+ ### Sending messages and connectors
213
213
 
214
- Messages now include a required `source` field (array) to indicate one or more origins for a message. The model enforces `source` values via an enum of strings:
214
+ Messages include a required `source` field (array) to indicate one or more origins for a message. Valid values are enforced by an enum of strings:
215
215
 
216
216
  ```ts
217
217
  export const sourceType = {
@@ -224,8 +224,35 @@ export const sourceType = {
224
224
  export type SourceType = (typeof sourceType)[keyof typeof sourceType];
225
225
  ```
226
226
 
227
- When sending a message via `sendMessage`, you must provide `source: SourceType[]`.
228
- For internal server-generated messages, use `[sourceType.CORE]`.
227
+ When sending a message via `sendMessage`, you must provide `source: SourceType[]`. For internal server‑generated messages, use `[sourceType.CORE]`.
228
+
229
+ If you include external connectors in the `source` (e.g., `linkedin`, `whatsapp`), you can optionally pass `connectorIds` to perform the external send and to persist identifiers for quick follow‑ups:
230
+
231
+ ```ts
232
+ await chat.services.messages.sendMessage({
233
+ organizationId: 'org-123',
234
+ conversationId: 'conv-456',
235
+ senderModel: 'User',
236
+ senderId: 'user-1',
237
+ text: 'Hello from Wexa',
238
+ source: [sourceType.CORE, sourceType.LINKEDIN, sourceType.WHATSAPP],
239
+ connectorIds: {
240
+ linkedin: { connectorId: 'ln-connector-1', contactId: 'https://linkedin.com/in/someone' },
241
+ whatsapp: { connectorId: 'wa-connector-1', contactId: '+1 234 567 8901' },
242
+ },
243
+ });
244
+ ```
245
+
246
+ Under the hood (`src/services/messages.service.ts`):
247
+
248
+ - LinkedIn: posts to the LinkedIn connector with `{ linkedin_url, text }`.
249
+ - WhatsApp: posts to the WhatsApp connector with `{ phone_numbers, text }` (phone is sanitized to remove spaces and a leading `+`).
250
+ - Each external task runs concurrently. A successful task's `source` remains in the stored message. Failures are collected into a `failed_source` array attached to the returned message instance at runtime: `message.failed_source: Array<{ source: string; message: string }>`.
251
+ - The conversation document is updated with last message metadata and, when applicable, with connector identifiers:
252
+ - `lastLinkedInId: string` — set from `connectorIds.linkedin.contactId` when `source` includes `linkedin`.
253
+ - `lastWhatsAppId: string` — set from a sanitized `connectorIds.whatsapp.contactId` when `source` includes `whatsapp`.
254
+
255
+ This allows subsequent UI actions to prefill the last known contact handles for LinkedIn and WhatsApp.
229
256
 
230
257
  ## Models
231
258
 
package/dist/index.d.cts CHANGED
@@ -147,7 +147,7 @@ interface IMessage extends Document {
147
147
  /**
148
148
  * Create (or retrieve) Message model safely
149
149
  */
150
- declare function createMessageModel(options: InitOptions, conn?: Connection): Model<IMessage>;
150
+ declare function createMessageModel(options: InitOptions, conn: Connection): Model<IMessage>;
151
151
 
152
152
  declare const modelRegistry: Map<string, mongoose.Model<any, {}, {}, {}, any, any>>;
153
153
  /**
@@ -259,6 +259,8 @@ interface IConversation extends Document {
259
259
  lastMessagePreview?: string;
260
260
  lastMessageSenderId?: string;
261
261
  lastMessageSenderModel?: string;
262
+ lastLinkedInId?: string;
263
+ lastWhatsAppId?: string;
262
264
  metadata?: Record<string, any>;
263
265
  createdAt: Date;
264
266
  updatedAt: Date;
@@ -266,7 +268,7 @@ interface IConversation extends Document {
266
268
  /**
267
269
  * Create (or retrieve) Conversation model safely
268
270
  */
269
- declare function createConversationModel(options: InitOptions, conn?: Connection): Model<IConversation>;
271
+ declare function createConversationModel(options: InitOptions, conn: Connection): Model<IConversation>;
270
272
 
271
273
  /**
272
274
  * Pagination result interface
package/dist/index.d.ts CHANGED
@@ -147,7 +147,7 @@ interface IMessage extends Document {
147
147
  /**
148
148
  * Create (or retrieve) Message model safely
149
149
  */
150
- declare function createMessageModel(options: InitOptions, conn?: Connection): Model<IMessage>;
150
+ declare function createMessageModel(options: InitOptions, conn: Connection): Model<IMessage>;
151
151
 
152
152
  declare const modelRegistry: Map<string, mongoose.Model<any, {}, {}, {}, any, any>>;
153
153
  /**
@@ -259,6 +259,8 @@ interface IConversation extends Document {
259
259
  lastMessagePreview?: string;
260
260
  lastMessageSenderId?: string;
261
261
  lastMessageSenderModel?: string;
262
+ lastLinkedInId?: string;
263
+ lastWhatsAppId?: string;
262
264
  metadata?: Record<string, any>;
263
265
  createdAt: Date;
264
266
  updatedAt: Date;
@@ -266,7 +268,7 @@ interface IConversation extends Document {
266
268
  /**
267
269
  * Create (or retrieve) Conversation model safely
268
270
  */
269
- declare function createConversationModel(options: InitOptions, conn?: Connection): Model<IConversation>;
271
+ declare function createConversationModel(options: InitOptions, conn: Connection): Model<IConversation>;
270
272
 
271
273
  /**
272
274
  * Pagination result interface
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- var mongoose = require('mongoose');
4
3
  var axios = require('axios');
5
4
  var Redis = require('ioredis');
6
5
  var ws = require('ws');
@@ -8,13 +7,12 @@ var url = require('url');
8
7
 
9
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
9
 
11
- var mongoose__default = /*#__PURE__*/_interopDefault(mongoose);
12
10
  var axios__default = /*#__PURE__*/_interopDefault(axios);
13
11
  var Redis__default = /*#__PURE__*/_interopDefault(Redis);
14
12
  var url__default = /*#__PURE__*/_interopDefault(url);
15
13
 
16
14
  // src/models/Conversation.model.ts
17
- function createConversationModel(options, conn = mongoose__default.default.connection) {
15
+ function createConversationModel(options, conn) {
18
16
  const connectionId = conn.id || conn.name || "default";
19
17
  const registryKey = `${connectionId}:Conversation`;
20
18
  if (modelRegistry.has(registryKey)) {
@@ -26,7 +24,8 @@ function createConversationModel(options, conn = mongoose__default.default.conne
26
24
  modelRegistry.set(registryKey, existingModel);
27
25
  return existingModel;
28
26
  }
29
- const ParticipantSchema = new mongoose.Schema(
27
+ const Schema = conn.base.Schema;
28
+ const ParticipantSchema = new Schema(
30
29
  {
31
30
  entityModel: {
32
31
  type: String,
@@ -45,7 +44,7 @@ function createConversationModel(options, conn = mongoose__default.default.conne
45
44
  },
46
45
  { _id: false }
47
46
  );
48
- const ConversationSchema = new mongoose.Schema(
47
+ const ConversationSchema = new Schema(
49
48
  {
50
49
  organizationId: {
51
50
  type: String,
@@ -71,7 +70,9 @@ function createConversationModel(options, conn = mongoose__default.default.conne
71
70
  lastMessagePreview: String,
72
71
  lastMessageSenderId: String,
73
72
  lastMessageSenderModel: String,
74
- metadata: mongoose.Schema.Types.Mixed
73
+ lastLinkedInId: String,
74
+ lastWhatsAppId: String,
75
+ metadata: Schema.Types.Mixed
75
76
  },
76
77
  { timestamps: true }
77
78
  );
@@ -79,13 +80,15 @@ function createConversationModel(options, conn = mongoose__default.default.conne
79
80
  modelRegistry.set(registryKey, model);
80
81
  return model;
81
82
  }
83
+
84
+ // src/models/Message.model.ts
82
85
  var sourceType = {
83
86
  LINKEDIN: "linkedin",
84
87
  WHATSAPP: "whatsapp",
85
88
  EMAIL: "email",
86
89
  CORE: "core"
87
90
  };
88
- function createMessageModel(options, conn = mongoose__default.default.connection) {
91
+ function createMessageModel(options, conn) {
89
92
  const connectionId = conn.id || conn.name || "default";
90
93
  const registryKey = `${connectionId}:Message`;
91
94
  if (modelRegistry.has(registryKey)) {
@@ -97,7 +100,8 @@ function createMessageModel(options, conn = mongoose__default.default.connection
97
100
  modelRegistry.set(registryKey, existingModel);
98
101
  return existingModel;
99
102
  }
100
- const MessageSchema = new mongoose.Schema(
103
+ const Schema = conn.base.Schema;
104
+ const MessageSchema = new Schema(
101
105
  {
102
106
  organizationId: {
103
107
  type: String,
@@ -305,13 +309,23 @@ function createConversationsService(models) {
305
309
  * Create a new conversation or find existing one between participants
306
310
  */
307
311
  async createOrFindConversation(args) {
312
+ console.log("Creating or finding conversation for users:", {
313
+ args
314
+ });
308
315
  const { organizationId, a, b } = args;
316
+ console.log("Creating or finding conversation for users:", {
317
+ organizationId,
318
+ a,
319
+ b
320
+ });
309
321
  try {
322
+ console.log("asdfa");
310
323
  const existingConversation = await searchByParticipantPair(Conversation, {
311
324
  organizationId,
312
325
  a,
313
326
  b
314
327
  });
328
+ console.log("Existing conversation:", existingConversation);
315
329
  if (existingConversation) {
316
330
  return existingConversation;
317
331
  }
@@ -334,7 +348,9 @@ function createConversationsService(models) {
334
348
  lastMessageAt: /* @__PURE__ */ new Date()
335
349
  // Set initial lastMessageAt
336
350
  });
351
+ console.log("New conversation:", newConversation);
337
352
  await newConversation.save();
353
+ console.log("Saved conversation:", newConversation);
338
354
  return newConversation;
339
355
  } catch (error) {
340
356
  console.error("Error in createOrFindConversation:", error);
@@ -535,8 +551,11 @@ function createMessagesService(models, hooks = {}) {
535
551
  const success_source = ["core"];
536
552
  const failed_source = [];
537
553
  const tasks = [];
554
+ let lastLinkedInId;
555
+ let lastWhatsAppId;
538
556
  if (Array.isArray(source) && source.includes("linkedin")) {
539
557
  const LinkedinConnector = connectorIds && connectorIds.linkedin;
558
+ lastLinkedInId = LinkedinConnector == null ? void 0 : LinkedinConnector.connectorId;
540
559
  if (LinkedinConnector) {
541
560
  tasks.push({
542
561
  name: "linkedin",
@@ -554,6 +573,7 @@ function createMessagesService(models, hooks = {}) {
554
573
  }
555
574
  if (Array.isArray(source) && source.includes("whatsapp")) {
556
575
  const whatsappConnector = connectorIds && connectorIds.whatsapp;
576
+ lastWhatsAppId = whatsappConnector == null ? void 0 : whatsappConnector.connectorId;
557
577
  if (whatsappConnector) {
558
578
  tasks.push({
559
579
  name: "whatsapp",
@@ -599,13 +619,16 @@ function createMessagesService(models, hooks = {}) {
599
619
  rootThreadId: rootThreadId || parentMessageId
600
620
  });
601
621
  await message.save();
622
+ const conversationUpdate = {
623
+ lastMessageAt: message.createdAt,
624
+ lastMessagePreview: text.substring(0, 100),
625
+ lastMessageSenderId: senderId,
626
+ lastMessageSenderModel: senderModel
627
+ };
628
+ if (lastLinkedInId) conversationUpdate.lastLinkedInId = lastLinkedInId;
629
+ if (lastWhatsAppId) conversationUpdate.lastWhatsAppId = lastWhatsAppId;
602
630
  await Conversation.findByIdAndUpdate(conversationId, {
603
- $set: {
604
- lastMessageAt: message.createdAt,
605
- lastMessagePreview: text.substring(0, 100),
606
- lastMessageSenderId: senderId,
607
- lastMessageSenderModel: senderModel
608
- }
631
+ $set: conversationUpdate
609
632
  });
610
633
  if (onMessageCreated) {
611
634
  onMessageCreated(message);
@@ -687,18 +710,18 @@ function createMessagesService(models, hooks = {}) {
687
710
  }
688
711
  sendersByModel[senderModel].add(senderId);
689
712
  });
690
- const mongoose3 = Message.base;
713
+ const mongoose = Message.base;
691
714
  const senders = {};
692
715
  await Promise.all(
693
716
  Object.entries(sendersByModel).map(async ([senderModel, senderIdsSet]) => {
694
717
  const modelName = modelMapping[senderModel] || senderModel;
695
718
  const senderIds = Array.from(senderIdsSet);
696
- if (!mongoose3.modelNames().includes(modelName)) {
719
+ if (!mongoose.modelNames().includes(modelName)) {
697
720
  console.warn(`Model ${modelName} not found for sender population`);
698
721
  return;
699
722
  }
700
723
  try {
701
- const SenderModel = mongoose3.model(modelName);
724
+ const SenderModel = mongoose.model(modelName);
702
725
  const modelSenders = await SenderModel.find({ _id: { $in: senderIds } }).select(fields).lean().exec();
703
726
  senders[senderModel] = {};
704
727
  modelSenders.forEach((sender) => {