fix(whatsapp): mensagens do celular perdidas para contatos @lid + crash P2002
continuous-integration/webhook Deploy concluido com sucesso (VPS 4)

Três correções independentes para mensagens enviadas/recebidas via celular:

1. WhatsAppConnectionManager: o listener CB:message agora captura também
   recipient_pn (InfiniteAPI v7+) além de peer_recipient_pn (Baileys oficial),
   garantindo que o PN correto do destinatário seja gravado no peerRecipientHints
   antes do messages.upsert ser emitido.

2. MessageHandler.processMessage: adicionado fast path fromMe=false via
   remoteJidAlt para contatos @lid (InfiniteAPI já resolve o PN do remetente).
   Para fromMe=true onde InfiniteAPI resolveu @lid→nosso próprio JID incorretamente,
   recupera o JID correto via peerRecipientHints antes de descartar como self-chat.

3. MessageHandler.processHistoryBatch: corrigido guard senderPn que não testava
   !msg.key.fromMe; para mensagens enviadas, senderPn é o nosso próprio JID,
   não o destinatário — o que criava self-chats corrompidos no DB.

4. whatsapp.send.routes: adicionado .catch P2002 no upsert da rota POST /send;
   race condition com eco Baileys causava unhandled rejection → exit(1) no Node 20.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Deploy Agent
2026-05-12 03:10:50 +02:00
parent ab688b7ef8
commit 9d082a17e4
3 changed files with 75 additions and 20 deletions
@@ -223,7 +223,10 @@ export function buildSendRoutes(manager: WhatsAppConnectionManager): Router {
richPayloadData = { text, footer, nativeCarousel }
}
const msg = await prisma.message.upsert({
// Race condition: o eco do Baileys pode chegar ANTES desta linha e criar o
// registro primeiro, fazendo o upsert falhar com P2002 (unique constraint).
// Nesses casos, buscamos a mensagem que já foi criada pelo eco.
let msg = await prisma.message.upsert({
where: { instanceId_messageId: { instanceId, messageId } },
create: {
tenantId,
@@ -239,6 +242,15 @@ export function buildSendRoutes(manager: WhatsAppConnectionManager): Router {
timestamp: new Date(),
},
update: {}, // já existe (eco do Baileys chegou primeiro) — não sobrescreve
}).catch(async (err: any) => {
if (err?.code === 'P2002') {
// Eco do Baileys criou o registro antes de nós — busca e retorna ele
const existing = await prisma.message.findUnique({
where: { instanceId_messageId: { instanceId, messageId } },
})
if (existing) return existing
}
throw err
})
// ── Emite eventos Socket.IO para o frontend atualizar em tempo real ───────