wexa-chat 0.3.0 → 0.3.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 +67 -0
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -312,6 +312,73 @@ await chat.services.messages.sendMessage({
|
|
|
312
312
|
});
|
|
313
313
|
```
|
|
314
314
|
|
|
315
|
+
##### Email Threading Explained
|
|
316
|
+
|
|
317
|
+
Email threading works by maintaining a stable `thread_id` across all messages in the same conversation:
|
|
318
|
+
|
|
319
|
+
**How it works:**
|
|
320
|
+
|
|
321
|
+
1. **First Email (New Thread)**
|
|
322
|
+
- Recruiter sends first email → Unipile returns `provider_id: "A"`
|
|
323
|
+
- Conversation stores `emailChatId = "A"` (the thread identifier)
|
|
324
|
+
- Message stores `metadata.email.providerId = "A"`
|
|
325
|
+
|
|
326
|
+
2. **Candidate Replies**
|
|
327
|
+
- Webhook arrives with `thread_id: "A"` and new `provider_id: "B"`
|
|
328
|
+
- System finds conversation by `emailChatId = "A"`
|
|
329
|
+
- Message stores `metadata.email.providerId = "B"`
|
|
330
|
+
|
|
331
|
+
3. **Recruiter Replies (Threading)**
|
|
332
|
+
- To continue the thread, pass `replyTo: "B"` (candidate's provider_id)
|
|
333
|
+
- Unipile returns new `provider_id: "C"`
|
|
334
|
+
- `emailChatId` remains `"A"` (NOT updated for replies)
|
|
335
|
+
- Message stores `metadata.email.providerId = "C"`
|
|
336
|
+
|
|
337
|
+
**Key Points:**
|
|
338
|
+
- `emailChatId` = Set ONCE on first email, used to find conversation
|
|
339
|
+
- `replyTo` = Previous message's `provider_id`, maintains email thread
|
|
340
|
+
- `providerId` = Current message's ID, stored for future replies
|
|
341
|
+
|
|
342
|
+
**Example: Reply to candidate's email**
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
// 1. Get the last message from candidate
|
|
346
|
+
const messages = await chat.services.messages.listMessages({
|
|
347
|
+
organizationId: 'org-123',
|
|
348
|
+
conversationId: 'conv-456',
|
|
349
|
+
limit: 10,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const lastCandidateMsg = messages.items
|
|
353
|
+
.find(m => m.senderModel === 'Application');
|
|
354
|
+
|
|
355
|
+
// 2. Extract their providerId for threading
|
|
356
|
+
const replyToId = lastCandidateMsg?.metadata?.email?.providerId;
|
|
357
|
+
|
|
358
|
+
// 3. Send reply with replyTo
|
|
359
|
+
await chat.services.messages.sendMessage({
|
|
360
|
+
organizationId: 'org-123',
|
|
361
|
+
conversationId: 'conv-456',
|
|
362
|
+
senderModel: 'User',
|
|
363
|
+
senderId: 'user-1',
|
|
364
|
+
text: 'Great to hear from you! Let me provide more details...',
|
|
365
|
+
source: [sourceType.EMAIL],
|
|
366
|
+
connectorIds: {
|
|
367
|
+
email: { connectorId: 'em-connector-1', contactId: 'john@candidate.com' },
|
|
368
|
+
},
|
|
369
|
+
metadata: {
|
|
370
|
+
email: {
|
|
371
|
+
subject: 'Re: Job Opportunity',
|
|
372
|
+
recipientName: 'John Doe',
|
|
373
|
+
replyTo: replyToId, // ← This keeps emails in the same thread
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**Without `replyTo`:** Each email creates a new thread (separate email chains)
|
|
380
|
+
**With `replyTo`:** All emails stay in one thread (Gmail conversation view)
|
|
381
|
+
|
|
315
382
|
#### Multi-Platform Messages
|
|
316
383
|
|
|
317
384
|
```ts
|
package/dist/index.js
CHANGED
|
@@ -566,6 +566,7 @@ function createMessagesService(models, hooks = {}) {
|
|
|
566
566
|
* @returns The created message
|
|
567
567
|
*/
|
|
568
568
|
async sendMessage(args) {
|
|
569
|
+
var _a, _b;
|
|
569
570
|
const {
|
|
570
571
|
organizationId,
|
|
571
572
|
conversationId,
|
|
@@ -659,7 +660,7 @@ function createMessagesService(models, hooks = {}) {
|
|
|
659
660
|
tasks.push({
|
|
660
661
|
name: "email",
|
|
661
662
|
run: async () => {
|
|
662
|
-
var
|
|
663
|
+
var _a2;
|
|
663
664
|
const path = paths.email.sendEmail(String(emailConnector.connectorId));
|
|
664
665
|
const primaryRecipient = {
|
|
665
666
|
display_name: (emailMeta == null ? void 0 : emailMeta.recipientName) || "Recipient",
|
|
@@ -712,7 +713,7 @@ function createMessagesService(models, hooks = {}) {
|
|
|
712
713
|
const res = await getAxios().post(path, payload);
|
|
713
714
|
console.log("Email response:", res.data);
|
|
714
715
|
const data = res.data;
|
|
715
|
-
if ((
|
|
716
|
+
if ((_a2 = data.mail_sent_data) == null ? void 0 : _a2.provider_id) {
|
|
716
717
|
emailChatId = data.mail_sent_data.provider_id;
|
|
717
718
|
console.log("Email provider_id extracted:", emailChatId);
|
|
718
719
|
} else {
|
|
@@ -731,12 +732,12 @@ function createMessagesService(models, hooks = {}) {
|
|
|
731
732
|
if (tasks.length > 0) {
|
|
732
733
|
const results = await Promise.allSettled(tasks.map((t) => t.run()));
|
|
733
734
|
results.forEach((result, idx) => {
|
|
734
|
-
var
|
|
735
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
735
736
|
const name = tasks[idx].name;
|
|
736
737
|
if (result.status === "fulfilled") {
|
|
737
738
|
success_source.push(name);
|
|
738
739
|
} else {
|
|
739
|
-
const error = ((_c = (
|
|
740
|
+
const error = ((_c = (_b2 = (_a2 = result.reason) == null ? void 0 : _a2.response) == null ? void 0 : _b2.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";
|
|
740
741
|
failed_source.push({
|
|
741
742
|
source: name,
|
|
742
743
|
message: typeof error === "string" ? error : JSON.stringify(error)
|
|
@@ -779,7 +780,9 @@ function createMessagesService(models, hooks = {}) {
|
|
|
779
780
|
if (lastEmailId) conversationUpdate.lastEmailId = lastEmailId;
|
|
780
781
|
if (linkedinChatId) conversationUpdate.linkedinChatId = linkedinChatId;
|
|
781
782
|
if (whatsappChatId) conversationUpdate.whatsappChatId = whatsappChatId;
|
|
782
|
-
if (emailChatId)
|
|
783
|
+
if (emailChatId && !((_b = (_a = args.metadata) == null ? void 0 : _a.email) == null ? void 0 : _b.replyTo)) {
|
|
784
|
+
conversationUpdate.emailChatId = emailChatId;
|
|
785
|
+
}
|
|
783
786
|
await Conversation.findByIdAndUpdate(conversationId, {
|
|
784
787
|
$set: conversationUpdate
|
|
785
788
|
});
|
|
@@ -852,7 +855,7 @@ function createMessagesService(models, hooks = {}) {
|
|
|
852
855
|
*/
|
|
853
856
|
async receiveLinkedinMessage(args) {
|
|
854
857
|
const { linkedinChatId, message, messageId, senderName, senderProfileUrl } = args;
|
|
855
|
-
const conversation = await Conversation.findOne({ linkedinChatId }).lean();
|
|
858
|
+
const conversation = await Conversation.findOne({ linkedinChatId }).sort({ lastMessageAt: -1 }).lean();
|
|
856
859
|
if (!conversation) {
|
|
857
860
|
throw new Error("Conversation not found for given linkedinChatId");
|
|
858
861
|
}
|