From 3b44a93ea91aaf90a2e55c63ace01ded1545e577 Mon Sep 17 00:00:00 2001 From: LucasRobs Date: Tue, 10 Feb 2026 22:50:14 -0300 Subject: [PATCH 1/5] bug fix menssage echoes --- .../channel/meta/whatsapp.business.service.ts | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/api/integrations/channel/meta/whatsapp.business.service.ts b/src/api/integrations/channel/meta/whatsapp.business.service.ts index 1e4808c156..4e297b7e83 100644 --- a/src/api/integrations/channel/meta/whatsapp.business.service.ts +++ b/src/api/integrations/channel/meta/whatsapp.business.service.ts @@ -133,7 +133,18 @@ export class BusinessStartupService extends ChannelStartupService { this.eventHandler(content); - this.phoneNumber = createJid(content.messages ? content.messages[0].from : content.statuses[0]?.recipient_id); + // Determinar o phoneNumber baseado no tipo de conteúdo recebido + if (content.messages && content.messages.length > 0) { + this.phoneNumber = createJid(content.messages[0].from); + } else if (content.message_echoes && content.message_echoes.length > 0) { + // message_echoes são ecos das mensagens enviadas pelo próprio número + this.phoneNumber = createJid(content.message_echoes[0].to); + } else if (content.statuses && content.statuses.length > 0) { + this.phoneNumber = createJid(content.statuses[0].recipient_id); + } else { + this.logger.warn('Nenhuma mensagem, status ou echo encontrado no conteúdo recebido'); + return; + } } catch (error) { this.logger.error(error); throw new InternalServerErrorException(error?.toString()); @@ -392,10 +403,16 @@ export class BusinessStartupService extends ChannelStartupService { if (received.messages) { const message = received.messages[0]; // Añadir esta línea para definir message + // Determinar fromMe: true se é um echo ou se from == phone_number_id ou display_phone_number + const isFromMe = + received.isEcho === true || + message.from === received.metadata?.phone_number_id || + message.from === received.metadata?.display_phone_number; + const key = { id: message.id, remoteJid: this.phoneNumber, - fromMe: message.from === received.metadata.phone_number_id, + fromMe: isFromMe, }; if (message.type === 'sticker') { @@ -926,11 +943,34 @@ export class BusinessStartupService extends ChannelStartupService { } else { this.logger.warn(`Tipo de mensaje no reconocido: ${message.type}`); } - } else if (content.statuses) { + } else if (content.message_echoes && content.message_echoes.length > 0) { + // message_echoes são ecos das mensagens enviadas pelo próprio número + // Converter message_echoes para o formato de messages para processamento + const echoMessage = content.message_echoes[0]; + this.logger.log(`Processando message_echo do tipo: ${echoMessage.type}`); + + // Criar estrutura compatível com o formato esperado + // Adicionar flag isEcho para que messageHandle saiba que fromMe = true + const convertedContent = { + ...content, + isEcho: true, // Flag para indicar que é um echo (mensagem enviada pelo próprio número) + messages: content.message_echoes.map((echo: any) => ({ + ...echo, + from: echo.from, + id: echo.id, + timestamp: echo.timestamp, + type: echo.type, + text: echo.text, + })), + }; + + // Processar como mensagem enviada (fromMe = true) + this.messageHandle(convertedContent, database, settings); + } else if (content.statuses && content.statuses.length > 0) { // Procesar actualizaciones de estado this.messageHandle(content, database, settings); } else { - this.logger.warn('No se encontraron mensajes ni estados en el contenido recibido'); + this.logger.warn('No se encontraron mensajes, message_echoes ni estados en el contenido recibido'); } } catch (error) { this.logger.error('Error en eventHandler:'); From d21d8b9417f64719221f2d5e42432ef00d0d00ff Mon Sep 17 00:00:00 2001 From: LucasRobs Date: Thu, 11 Jun 2026 12:40:03 -0300 Subject: [PATCH 2/5] fix(meta): handle message echoes without contact profile --- .../channel/meta/whatsapp.business.service.ts | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/api/integrations/channel/meta/whatsapp.business.service.ts b/src/api/integrations/channel/meta/whatsapp.business.service.ts index 4e297b7e83..059b149638 100644 --- a/src/api/integrations/channel/meta/whatsapp.business.service.ts +++ b/src/api/integrations/channel/meta/whatsapp.business.service.ts @@ -396,9 +396,20 @@ export class BusinessStartupService extends ChannelStartupService { protected async messageHandle(received: any, database: Database, settings: any) { try { let messageRaw: any; - let pushName: any; - - if (received.contacts) pushName = received.contacts[0].profile.name; + const firstMessage = received.messages?.[0]; + const firstContact = received.contacts?.[0]; + const contactPhone = + firstContact?.profile?.phone ?? firstContact?.wa_id ?? firstContact?.phone ?? firstContact?.input; + const messageRemoteJid = received.isEcho ? firstMessage?.to : firstMessage?.from; + const remoteJidSource = messageRemoteJid || contactPhone; + const remoteJid = remoteJidSource ? createJid(remoteJidSource) : this.phoneNumber; + const pushName = + firstContact?.profile?.name ?? firstContact?.name ?? firstContact?.formatted_name ?? firstContact?.pushName; + + if (!remoteJid && received.messages) { + this.logger.warn('Unable to identify remoteJid for received message'); + return; + } if (received.messages) { const message = received.messages[0]; // Añadir esta línea para definir message @@ -411,7 +422,7 @@ export class BusinessStartupService extends ChannelStartupService { const key = { id: message.id, - remoteJid: this.phoneNumber, + remoteJid, fromMe: isFromMe, }; @@ -714,29 +725,21 @@ export class BusinessStartupService extends ChannelStartupService { }); } - const contact = await this.prismaRepository.contact.findFirst({ - where: { instanceId: this.instanceId, remoteJid: key.remoteJid }, - }); - const contactRaw: any = { - remoteJid: received.contacts[0].profile.phone, - pushName, - // profilePicUrl: '', + remoteJid: key.remoteJid, instanceId: this.instanceId, }; + if (pushName) contactRaw.pushName = pushName; if (contactRaw.remoteJid === 'status@broadcast') { return; } - if (contact) { - const contactRaw: any = { - remoteJid: received.contacts[0].profile.phone, - pushName, - // profilePicUrl: '', - instanceId: this.instanceId, - }; + const contact = await this.prismaRepository.contact.findFirst({ + where: { instanceId: this.instanceId, remoteJid: contactRaw.remoteJid }, + }); + if (contact) { this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw); if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { From 5985a34be9157ba6fc8a647963e03f717415b97d Mon Sep 17 00:00:00 2001 From: LucasRobs Date: Thu, 11 Jun 2026 12:47:37 -0300 Subject: [PATCH 3/5] fix(meta): set webhook phone number before handling --- .../integrations/channel/meta/whatsapp.business.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/integrations/channel/meta/whatsapp.business.service.ts b/src/api/integrations/channel/meta/whatsapp.business.service.ts index 059b149638..5b0bef907f 100644 --- a/src/api/integrations/channel/meta/whatsapp.business.service.ts +++ b/src/api/integrations/channel/meta/whatsapp.business.service.ts @@ -131,8 +131,6 @@ export class BusinessStartupService extends ChannelStartupService { try { this.loadChatwoot(); - this.eventHandler(content); - // Determinar o phoneNumber baseado no tipo de conteúdo recebido if (content.messages && content.messages.length > 0) { this.phoneNumber = createJid(content.messages[0].from); @@ -145,6 +143,8 @@ export class BusinessStartupService extends ChannelStartupService { this.logger.warn('Nenhuma mensagem, status ou echo encontrado no conteúdo recebido'); return; } + + this.eventHandler(content); } catch (error) { this.logger.error(error); throw new InternalServerErrorException(error?.toString()); From 65395a3374199ae1515dc30d9f366945778990be Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 13 Jul 2026 21:52:28 -0300 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20adiciona=20middleware=20de=20log=20?= =?UTF-8?q?para=20todas=20as=20requisi=C3=A7=C3=B5es=20HTTP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loga método, URL, status, tempo de resposta e IP de origem de cada requisição que chega na API, usando o Logger padrão do projeto. --- src/api/middleware/requestLogger.middleware.ts | 16 ++++++++++++++++ src/main.ts | 3 +++ 2 files changed, 19 insertions(+) create mode 100644 src/api/middleware/requestLogger.middleware.ts diff --git a/src/api/middleware/requestLogger.middleware.ts b/src/api/middleware/requestLogger.middleware.ts new file mode 100644 index 0000000000..4b7ea1f32a --- /dev/null +++ b/src/api/middleware/requestLogger.middleware.ts @@ -0,0 +1,16 @@ +import { Logger } from '@config/logger.config'; +import { NextFunction, Request, Response } from 'express'; + +const logger = new Logger('HTTP'); + +export function requestLogger(req: Request, res: Response, next: NextFunction): void { + const start = Date.now(); + const ip = req.ip || req.socket?.remoteAddress || '-'; + + res.on('finish', () => { + const duration = Date.now() - start; + logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms - ip: ${ip}`); + }); + + next(); +} diff --git a/src/main.ts b/src/main.ts index f1f00ba9ae..bed7ae45b5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,6 +2,7 @@ import '@utils/instrumentSentry'; // Now import other modules +import { requestLogger } from '@api/middleware/requestLogger.middleware'; import { ProviderFiles } from '@api/provider/sessions'; import { PrismaRepository } from '@api/repository/repository.service'; import { HttpStatus, router } from '@api/routes/index.router'; @@ -44,6 +45,8 @@ async function bootstrap() { const prismaRepository = new PrismaRepository(configService); await prismaRepository.onModuleInit(); + app.use(requestLogger); + app.use( cors({ origin(requestOrigin, callback) { From 899336409df3d6e5b7124e59fa774ec7e33f3a87 Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 13 Jul 2026 23:00:09 -0300 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20loga=20body=20das=20requisi=C3=A7?= =?UTF-8?q?=C3=B5es=20do=20webhook=20meta=20em=20cor=20destacada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/middleware/requestLogger.middleware.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/middleware/requestLogger.middleware.ts b/src/api/middleware/requestLogger.middleware.ts index 4b7ea1f32a..095f3fc56c 100644 --- a/src/api/middleware/requestLogger.middleware.ts +++ b/src/api/middleware/requestLogger.middleware.ts @@ -10,6 +10,10 @@ export function requestLogger(req: Request, res: Response, next: NextFunction): res.on('finish', () => { const duration = Date.now() - start; logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms - ip: ${ip}`); + + if (req.originalUrl.startsWith('/webhook/meta') && req.body && Object.keys(req.body).length > 0) { + logger.warn(`[body] ${req.method} ${req.originalUrl}: ${JSON.stringify(req.body)}`); + } }); next();