-
Notifications
You must be signed in to change notification settings - Fork 5.3k
fix(whatsapp): enhance contact and chat handling with improved JID ma… #2372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
fix(whatsapp): enhance contact and chat handling with improved JID ma… #2372
Conversation
…pping and debug logging
Reviewer's GuideEnhances WhatsApp Baileys history sync handling by improving contact JID derivation (especially @lid IDs), enriching chat records with both JID and LID, and adding detailed debug logs for messages, chats, and contacts during sync processing. Sequence diagram for updated WhatsApp Baileys history sync handlingsequenceDiagram
participant BaileysSocket
participant BaileysStartupService
participant PrismaRepository
participant WebhookEndpoint
BaileysSocket->>BaileysStartupService: onHistorySync(messages, chats, contacts, syncType)
BaileysStartupService->>BaileysStartupService: logger.debug("Messages abaixo")
BaileysStartupService->>BaileysStartupService: logger.debug(messages)
BaileysStartupService->>BaileysStartupService: logger.debug("Chats abaixo")
BaileysStartupService->>BaileysStartupService: logger.debug(chats)
BaileysStartupService->>BaileysStartupService: logger.debug("Contatos abaixo")
BaileysStartupService->>BaileysStartupService: logger.debug(contacts)
alt syncType is ON_DEMAND
BaileysStartupService->>BaileysStartupService: console.log(on-demand history sync)
else syncType is OTHER
BaileysStartupService->>BaileysStartupService: process normally
end
BaileysStartupService->>BaileysStartupService: contactsMap = new Map()
BaileysStartupService->>BaileysStartupService: contactsMapLidJid = new Map()
loop for each contact in contacts
alt contact.id contains @lid and contact.phoneNumber exists
BaileysStartupService->>BaileysStartupService: jid = contact.phoneNumber
else
BaileysStartupService->>BaileysStartupService: jid = contact.id
end
alt contact.id and (contact.notify or contact.name)
BaileysStartupService->>BaileysStartupService: contactsMap.set(contact.id, { name, jid })
end
BaileysStartupService->>BaileysStartupService: contactsMapLidJid.set(contact.id, { jid })
end
BaileysStartupService->>PrismaRepository: chat.findMany(where instanceId)
PrismaRepository-->>BaileysStartupService: existingChats
BaileysStartupService->>BaileysStartupService: chatsRepository = Set(existing.remoteJid)
BaileysStartupService->>BaileysStartupService: chatsRaw = []
loop for each chat in chats
alt chat.id in chatsRepository
BaileysStartupService->>BaileysStartupService: skip existing chat
else chat.id not in chatsRepository
alt chat.id contains @lid
BaileysStartupService->>BaileysStartupService: contact = contactsMapLidJid.get(chat.id)
BaileysStartupService->>BaileysStartupService: remoteLid = chat.id
alt contact and contact.jid
BaileysStartupService->>BaileysStartupService: remoteJid = contact.jid
else
BaileysStartupService->>BaileysStartupService: remoteJid = chat.id
end
else chat.id does not contain @lid
BaileysStartupService->>BaileysStartupService: remoteJid = chat.id
BaileysStartupService->>BaileysStartupService: remoteLid = null
end
BaileysStartupService->>BaileysStartupService: chatsRaw.push({ remoteJid, remoteLid, instanceId, name })
end
end
BaileysStartupService->>WebhookEndpoint: sendDataWebhook(CHATS_SET, chatsRaw)
Updated class diagram for BaileysStartupService contact and chat handlingclassDiagram
class ChannelStartupService {
}
class PrismaRepository {
+chat ChatRepository
}
class ChatRepository {
+findMany(where)
}
class BaileysStartupService {
-logger
-prismaRepository PrismaRepository
-instanceId string
+onHistorySync(messages, chats, contacts, syncType)
+sendDataWebhook(event, payload)
}
class ContactProcessingContext {
+contactsMap Map
+contactsMapLidJid Map
+buildContactsMaps(contacts)
}
class ChatProcessingContext {
+chatsRaw RemoteChat[]
+chatsRepository Set
+buildChatsRaw(chats, contactsMapLidJid, instanceId)
}
class RemoteChat {
+remoteJid string
+remoteLid string
+instanceId string
+name string
}
ChannelStartupService <|-- BaileysStartupService
BaileysStartupService --> PrismaRepository
PrismaRepository --> ChatRepository
BaileysStartupService --> ContactProcessingContext
BaileysStartupService --> ChatProcessingContext
ChatProcessingContext --> RemoteChat
Flow diagram for improved WhatsApp JID and LID mapping during history syncflowchart TD
A_start["Start history sync processing"] --> B_contacts
subgraph Contact_processing
B_contacts["Iterate contacts"] --> C_hasLid{"contact.id contains @lid and contact.phoneNumber exists"}
C_hasLid -->|yes| D_jidPhone["jid = contact.phoneNumber"]
C_hasLid -->|no| E_jidId["jid = contact.id"]
D_jidPhone --> F_checkNameNotify
E_jidId --> F_checkNameNotify["contact.id and (contact.notify or contact.name)?"]
F_checkNameNotify -->|yes| G_setContact["contactsMap.set(contact.id, { name, jid })"]
F_checkNameNotify -->|no| H_skipContact["skip name mapping"]
G_setContact --> I_setLidJid
H_skipContact --> I_setLidJid["contactsMapLidJid.set(contact.id, { jid })"]
end
I_setLidJid --> J_chats["Iterate chats"]
subgraph Chat_processing
J_chats --> K_inRepository{"chat.id in chatsRepository?"}
K_inRepository -->|yes| L_skipChat["skip chat"]
K_inRepository -->|no| M_hasLidChat{"chat.id contains @lid"}
M_hasLidChat -->|yes| N_getContact["contact = contactsMapLidJid.get(chat.id)"]
N_getContact --> O_setRemoteLid["remoteLid = chat.id"]
O_setRemoteLid --> P_hasContactJid{"contact and contact.jid?"}
P_hasContactJid -->|yes| Q_remoteJidContact["remoteJid = contact.jid"]
P_hasContactJid -->|no| R_remoteJidFallback["remoteJid = chat.id"]
M_hasLidChat -->|no| S_nonLid["remoteJid = chat.id; remoteLid = null"]
Q_remoteJidContact --> T_pushChat
R_remoteJidFallback --> T_pushChat
S_nonLid --> T_pushChat["chatsRaw.push({ remoteJid, remoteLid, instanceId, name })"]
end
L_skipChat --> U_nextChat["next chat"]
T_pushChat --> U_nextChat
U_nextChat --> V_doneChats{"more chats?"}
V_doneChats -->|yes| J_chats
V_doneChats -->|no| W_sendWebhook["sendDataWebhook(CHATS_SET, chatsRaw)"]
W_sendWebhook --> X_end["End history sync processing"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - I've found 2 issues, and left some high level feedback:
- The
@lidhandling logic for both contacts and chats is duplicated and a bit ad-hoc; consider extracting a small helper function (e.g.,normalizeLidJid(...)) to centralize this mapping and make the behavior easier to reason about and update. - In
chatsRaw,remoteLidis typed as a requiredstringbut is set tonullor left unset in some cases; either make this field optional or explicitly type it asstring | nullto better reflect actual usage. - The new debug logs dump full
messages,chats, andcontactsobjects, which may be large and sensitive; consider gating these behind a more granular debug flag or trimming the payload to key fields to keep logs manageable and safer for production.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `@lid` handling logic for both contacts and chats is duplicated and a bit ad-hoc; consider extracting a small helper function (e.g., `normalizeLidJid(...)`) to centralize this mapping and make the behavior easier to reason about and update.
- In `chatsRaw`, `remoteLid` is typed as a required `string` but is set to `null` or left unset in some cases; either make this field optional or explicitly type it as `string | null` to better reflect actual usage.
- The new debug logs dump full `messages`, `chats`, and `contacts` objects, which may be large and sensitive; consider gating these behind a more granular debug flag or trimming the payload to key fields to keep logs manageable and safer for production.
## Individual Comments
### Comment 1
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:944-948` </location>
<code_context>
}) => {
+ //These logs are crucial; when something changes in Baileys/WhatsApp, we can more easily understand what changed!
+ this.logger.debug('Messages abaixo');
+ this.logger.debug(messages);
+ this.logger.debug('Chats abaixo');
+ this.logger.debug(chats);
+ this.logger.debug('Contatos abaixo');
+ this.logger.debug(contacts);
+
try {
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Consider the volume/sensitivity of logging full message, chat and contact objects
Logging full `messages`, `chats` and `contacts` on every sync can flood logs and expose sensitive user data, especially in shared or centralized logging systems. Consider logging only identifiers/counts by default and gating full payload logs behind a feature flag, or trimming the objects to metadata before logging.
Suggested implementation:
```typescript
}) => {
const logFullPayloads = process.env.WHATSAPP_DEBUG_PAYLOADS === 'true';
// Log a safe summary by default to avoid flooding logs and leaking sensitive data
this.logger.debug('History sync payload summary', {
messagesCount: messages?.length ?? 0,
chatsCount: chats?.length ?? 0,
contactsCount: contacts?.length ?? 0,
});
// Optionally log full payloads when explicitly enabled
if (logFullPayloads) {
this.logger.debug('History sync messages payload', messages);
this.logger.debug('History sync chats payload', chats);
this.logger.debug('History sync contacts payload', contacts);
}
```
1. Consider wiring `logFullPayloads` to your existing configuration system instead of reading directly from `process.env` (e.g. inject a config service and use `this.configService.get('WHATSAPP_DEBUG_PAYLOADS')`).
2. If your logging setup prefers string messages over structured metadata, adjust the summary log to interpolate counts into the message instead of passing an object.
3. You may also want to document the `WHATSAPP_DEBUG_PAYLOADS` flag in your ops/deployment docs so that production environments keep it disabled by default.
</issue_to_address>
### Comment 2
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:1001-1004` </location>
<code_context>
}
- const chatsRaw: { remoteJid: string; instanceId: string; name?: string }[] = [];
+ const chatsRaw: { remoteJid: string; remoteLid: string; instanceId: string; name?: string }[] = [];
const chatsRepository = new Set(
(await this.prismaRepository.chat.findMany({ where: { instanceId: this.instanceId } })).map(
</code_context>
<issue_to_address>
**issue (bug_risk):** Type of `remoteLid` is declared as `string` but `null` is pushed for non-lid chats
`remoteLid` is initialized as `null` and only set when `chat.id` has `@lid`, so for normal chats you push `remoteLid: null` into an array typed as `{ remoteJid: string; remoteLid: string; ... }`. This is either a TS error or unsafely widens the type. Please align the type with the runtime value, e.g. `remoteLid?: string` with `undefined` as the default, or `remoteLid: string | null`.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
Estão resolvendo no lado do baileys também acredito que isso va direto para a master: WhiskeySockets/Baileys#2282 Então a realease 7.0.0-rc.9 ficaria com esse deficit porem com essa PR #2372 o problema seria resolvido de forma paliativa. |
…ize variable declaration
📋 Description
O evento messaging-history.set do Baileys passou a retornar o campo remoteJid como um remoteLid em alguns cenários.
Nesses casos, o remoteJid real nunca era recebido, o que tornava impossível identificar corretamente a quem o chat pertencia.
Como consequência:
Não era possível mapear o chat para um contato conhecido
O registro do chat ficava sem associação válida
A integração acabava registrando chats “órfãos”, que caíam em um limbo de dados, sem vínculo com contato ou número
Isso impactava diretamente qualquer sistema que dependesse da associação correta entre chat ↔ contato.
A correção implementa um mecanismo de resolução de identidade para o evento messaging-history.set, cobrindo os casos em que o Baileys retorna o chat.id como remoteLid e não fornece o remoteJid.
🔗 Related Issue
Closes #(issue_number)
🧪 Type of Change
🧪 Testing
📸 Screenshots (if applicable)
✅ Checklist
📝 Additional Notes