From fa6b5c28a6c408d95dbd3e90af5d9152d5bdfd4c Mon Sep 17 00:00:00 2001 From: Alexandre Martins Date: Wed, 26 Nov 2025 15:44:18 -0300 Subject: [PATCH 1/3] feat(events): add isLatest and progress to messages.set event - Add extra field to EmitData type for additional payload properties - Update EventManager and sendDataWebhook to support extra parameters - Update all event controllers (webhook, rabbitmq, sqs, websocket, pusher, kafka, nats) to include extra fields in payload - Pass isLatest and progress from Baileys messaging-history.set to messages.set webhook This allows consumers to know when the history sync is complete (isLatest=true) and track sync progress percentage. --- .../channel/whatsapp/whatsapp.baileys.service.ts | 5 ++++- src/api/integrations/event/event.controller.ts | 3 ++- src/api/integrations/event/event.manager.ts | 1 + src/api/integrations/event/kafka/kafka.controller.ts | 2 ++ src/api/integrations/event/nats/nats.controller.ts | 2 ++ src/api/integrations/event/pusher/pusher.controller.ts | 2 ++ src/api/integrations/event/rabbitmq/rabbitmq.controller.ts | 2 ++ src/api/integrations/event/sqs/sqs.controller.ts | 2 ++ src/api/integrations/event/webhook/webhook.controller.ts | 2 ++ src/api/integrations/event/websocket/websocket.controller.ts | 2 ++ src/api/services/channel.service.ts | 3 ++- 11 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 2636adbd..6dd89d29 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -1022,7 +1022,10 @@ export class BaileysStartupService extends ChannelStartupService { messagesRaw.push(this.prepareMessage(m)); } - this.sendDataWebhook(Events.MESSAGES_SET, [...messagesRaw]); + this.sendDataWebhook(Events.MESSAGES_SET, [...messagesRaw], true, undefined, { + isLatest, + progress, + }); if (this.configService.get('DATABASE').SAVE_DATA.HISTORIC) { await this.prismaRepository.message.createMany({ data: messagesRaw, skipDuplicates: true }); diff --git a/src/api/integrations/event/event.controller.ts b/src/api/integrations/event/event.controller.ts index 7df3de92..7b168406 100644 --- a/src/api/integrations/event/event.controller.ts +++ b/src/api/integrations/event/event.controller.ts @@ -14,12 +14,13 @@ export type EmitData = { apiKey?: string; local?: boolean; integration?: string[]; + extra?: Record; }; export interface EventControllerInterface { set(instanceName: string, data: any): Promise; get(instanceName: string): Promise; - emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local }: EmitData): Promise; + emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local, extra }: EmitData): Promise; } export class EventController { diff --git a/src/api/integrations/event/event.manager.ts b/src/api/integrations/event/event.manager.ts index 90547932..5dd3fcf2 100644 --- a/src/api/integrations/event/event.manager.ts +++ b/src/api/integrations/event/event.manager.ts @@ -123,6 +123,7 @@ export class EventManager { apiKey?: string; local?: boolean; integration?: string[]; + extra?: Record; }): Promise { await this.websocket.emit(eventData); await this.rabbitmq.emit(eventData); diff --git a/src/api/integrations/event/kafka/kafka.controller.ts b/src/api/integrations/event/kafka/kafka.controller.ts index 416bcb13..04dc8dd3 100644 --- a/src/api/integrations/event/kafka/kafka.controller.ts +++ b/src/api/integrations/event/kafka/kafka.controller.ts @@ -262,6 +262,7 @@ export class KafkaController extends EventController implements EventControllerI sender, apiKey, integration, + extra, }: EmitData): Promise { if (integration && !integration.includes('kafka')) { return; @@ -292,6 +293,7 @@ export class KafkaController extends EventController implements EventControllerI sender, apikey: apiKey, timestamp: Date.now(), + ...extra, }; const messageValue = JSON.stringify(message); diff --git a/src/api/integrations/event/nats/nats.controller.ts b/src/api/integrations/event/nats/nats.controller.ts index 09b59779..ca75f057 100644 --- a/src/api/integrations/event/nats/nats.controller.ts +++ b/src/api/integrations/event/nats/nats.controller.ts @@ -47,6 +47,7 @@ export class NatsController extends EventController implements EventControllerIn sender, apiKey, integration, + extra, }: EmitData): Promise { if (integration && !integration.includes('nats')) { return; @@ -72,6 +73,7 @@ export class NatsController extends EventController implements EventControllerIn date_time: dateTime, sender, apikey: apiKey, + ...extra, }; // Instância específica diff --git a/src/api/integrations/event/pusher/pusher.controller.ts b/src/api/integrations/event/pusher/pusher.controller.ts index eef244b2..28398df8 100644 --- a/src/api/integrations/event/pusher/pusher.controller.ts +++ b/src/api/integrations/event/pusher/pusher.controller.ts @@ -121,6 +121,7 @@ export class PusherController extends EventController implements EventController apiKey, local, integration, + extra, }: EmitData): Promise { if (integration && !integration.includes('pusher')) { return; @@ -141,6 +142,7 @@ export class PusherController extends EventController implements EventController sender, server_url: serverUrl, apikey: apiKey, + ...extra, }; if (event == 'qrcode.updated') { delete pusherData.data.qrcode.base64; diff --git a/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts index 3295b12d..7fe70479 100644 --- a/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts +++ b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts @@ -209,6 +209,7 @@ export class RabbitmqController extends EventController implements EventControll sender, apiKey, integration, + extra, }: EmitData): Promise { if (integration && !integration.includes('rabbitmq')) { return; @@ -240,6 +241,7 @@ export class RabbitmqController extends EventController implements EventControll date_time: dateTime, sender, apikey: apiKey, + ...extra, }; if (instanceRabbitmq?.enabled && this.amqpChannel) { diff --git a/src/api/integrations/event/sqs/sqs.controller.ts b/src/api/integrations/event/sqs/sqs.controller.ts index 08c89053..40ebc8d5 100644 --- a/src/api/integrations/event/sqs/sqs.controller.ts +++ b/src/api/integrations/event/sqs/sqs.controller.ts @@ -93,6 +93,7 @@ export class SqsController extends EventController implements EventControllerInt sender, apiKey, integration, + extra, }: EmitData): Promise { if (integration && !integration.includes('sqs')) { return; @@ -137,6 +138,7 @@ export class SqsController extends EventController implements EventControllerInt date_time: dateTime, sender, apikey: apiKey, + ...extra, }; const jsonStr = JSON.stringify(message); diff --git a/src/api/integrations/event/webhook/webhook.controller.ts b/src/api/integrations/event/webhook/webhook.controller.ts index bd4e5fe0..fd82f54a 100644 --- a/src/api/integrations/event/webhook/webhook.controller.ts +++ b/src/api/integrations/event/webhook/webhook.controller.ts @@ -65,6 +65,7 @@ export class WebhookController extends EventController implements EventControlle apiKey, local, integration, + extra, }: EmitData): Promise { if (integration && !integration.includes('webhook')) { return; @@ -98,6 +99,7 @@ export class WebhookController extends EventController implements EventControlle sender, server_url: serverUrl, apikey: apiKey, + ...extra, }; if (local && instance?.enabled) { diff --git a/src/api/integrations/event/websocket/websocket.controller.ts b/src/api/integrations/event/websocket/websocket.controller.ts index 72435234..a1ed613f 100644 --- a/src/api/integrations/event/websocket/websocket.controller.ts +++ b/src/api/integrations/event/websocket/websocket.controller.ts @@ -115,6 +115,7 @@ export class WebsocketController extends EventController implements EventControl sender, apiKey, integration, + extra, }: EmitData): Promise { if (integration && !integration.includes('websocket')) { return; @@ -134,6 +135,7 @@ export class WebsocketController extends EventController implements EventControl date_time: dateTime, sender, apikey: apiKey, + ...extra, }; if (configService.get('WEBSOCKET')?.GLOBAL_EVENTS) { diff --git a/src/api/services/channel.service.ts b/src/api/services/channel.service.ts index 947f9c39..06e2f565 100644 --- a/src/api/services/channel.service.ts +++ b/src/api/services/channel.service.ts @@ -431,7 +431,7 @@ export class ChannelStartupService { return data; } - public async sendDataWebhook(event: Events, data: T, local = true, integration?: string[]) { + public async sendDataWebhook(event: Events, data: T, local = true, integration?: string[], extra?: Record) { const serverUrl = this.configService.get('SERVER').URL; const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds const localISOTime = new Date(Date.now() - tzoffset).toISOString(); @@ -452,6 +452,7 @@ export class ChannelStartupService { apiKey: expose && instanceApikey ? instanceApikey : null, local, integration, + extra, }); } From 930d32df3a9c974ac0b6ceabfc3b9260e655ee42 Mon Sep 17 00:00:00 2001 From: Alexandre Martins Date: Wed, 26 Nov 2025 15:48:53 -0300 Subject: [PATCH 2/3] fix(events): guard extra spread and prevent core field override - Use (extra ?? {}) to handle undefined extra safely - Spread extra first to prevent overriding core fields like event, instance, data - Applied fix to all 7 event controllers Addresses Sourcery AI review feedback. --- .DS_Store | Bin 6148 -> 6148 bytes .../event/kafka/kafka.controller.ts | 2 +- .../event/nats/nats.controller.ts | 2 +- .../event/pusher/pusher.controller.ts | 2 +- .../event/rabbitmq/rabbitmq.controller.ts | 2 +- .../integrations/event/sqs/sqs.controller.ts | 2 +- .../event/webhook/webhook.controller.ts | 2 +- .../event/websocket/websocket.controller.ts | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.DS_Store b/.DS_Store index f4f05c71662ef24da6e8eea7dbc5916385a9163a..3ccbdbaa551a95e85817caa3724e4d477cccea4c 100644 GIT binary patch delta 27 jcmZoMXfc@J&nUSuU^g?P}DPoedc;rhBAgshE#@fhT@!b!{Frn+yVwL5HVC6*OIf2I-;vcA)ull1K9=xp!SI=zMI)O{_+C=vOy-5 diff --git a/src/api/integrations/event/kafka/kafka.controller.ts b/src/api/integrations/event/kafka/kafka.controller.ts index 04dc8dd3..543c759a 100644 --- a/src/api/integrations/event/kafka/kafka.controller.ts +++ b/src/api/integrations/event/kafka/kafka.controller.ts @@ -285,6 +285,7 @@ export class KafkaController extends EventController implements EventControllerI const logEnabled = configService.get('LOG').LEVEL.includes('WEBHOOKS'); const message = { + ...(extra ?? {}), event, instance: instanceName, data, @@ -293,7 +294,6 @@ export class KafkaController extends EventController implements EventControllerI sender, apikey: apiKey, timestamp: Date.now(), - ...extra, }; const messageValue = JSON.stringify(message); diff --git a/src/api/integrations/event/nats/nats.controller.ts b/src/api/integrations/event/nats/nats.controller.ts index ca75f057..1ff4fbae 100644 --- a/src/api/integrations/event/nats/nats.controller.ts +++ b/src/api/integrations/event/nats/nats.controller.ts @@ -66,6 +66,7 @@ export class NatsController extends EventController implements EventControllerIn const logEnabled = configService.get('LOG').LEVEL.includes('WEBHOOKS'); const message = { + ...(extra ?? {}), event, instance: instanceName, data, @@ -73,7 +74,6 @@ export class NatsController extends EventController implements EventControllerIn date_time: dateTime, sender, apikey: apiKey, - ...extra, }; // Instância específica diff --git a/src/api/integrations/event/pusher/pusher.controller.ts b/src/api/integrations/event/pusher/pusher.controller.ts index 28398df8..045f7cc4 100644 --- a/src/api/integrations/event/pusher/pusher.controller.ts +++ b/src/api/integrations/event/pusher/pusher.controller.ts @@ -134,6 +134,7 @@ export class PusherController extends EventController implements EventController const enabledLog = configService.get('LOG').LEVEL.includes('WEBHOOKS'); const eventName = event.replace(/_/g, '.').toLowerCase(); const pusherData = { + ...(extra ?? {}), event, instance: instanceName, data, @@ -142,7 +143,6 @@ export class PusherController extends EventController implements EventController sender, server_url: serverUrl, apikey: apiKey, - ...extra, }; if (event == 'qrcode.updated') { delete pusherData.data.qrcode.base64; diff --git a/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts index 7fe70479..b4625508 100644 --- a/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts +++ b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts @@ -234,6 +234,7 @@ export class RabbitmqController extends EventController implements EventControll const logEnabled = configService.get('LOG').LEVEL.includes('WEBHOOKS'); const message = { + ...(extra ?? {}), event, instance: instanceName, data, @@ -241,7 +242,6 @@ export class RabbitmqController extends EventController implements EventControll date_time: dateTime, sender, apikey: apiKey, - ...extra, }; if (instanceRabbitmq?.enabled && this.amqpChannel) { diff --git a/src/api/integrations/event/sqs/sqs.controller.ts b/src/api/integrations/event/sqs/sqs.controller.ts index 40ebc8d5..2b0398ef 100644 --- a/src/api/integrations/event/sqs/sqs.controller.ts +++ b/src/api/integrations/event/sqs/sqs.controller.ts @@ -129,6 +129,7 @@ export class SqsController extends EventController implements EventControllerInt const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`; const message = { + ...(extra ?? {}), event, instance: instanceName, dataType: 'json', @@ -138,7 +139,6 @@ export class SqsController extends EventController implements EventControllerInt date_time: dateTime, sender, apikey: apiKey, - ...extra, }; const jsonStr = JSON.stringify(message); diff --git a/src/api/integrations/event/webhook/webhook.controller.ts b/src/api/integrations/event/webhook/webhook.controller.ts index fd82f54a..7f1dd8dc 100644 --- a/src/api/integrations/event/webhook/webhook.controller.ts +++ b/src/api/integrations/event/webhook/webhook.controller.ts @@ -91,6 +91,7 @@ export class WebhookController extends EventController implements EventControlle const regex = /^(https?:\/\/)/; const webhookData = { + ...(extra ?? {}), event, instance: instanceName, data, @@ -99,7 +100,6 @@ export class WebhookController extends EventController implements EventControlle sender, server_url: serverUrl, apikey: apiKey, - ...extra, }; if (local && instance?.enabled) { diff --git a/src/api/integrations/event/websocket/websocket.controller.ts b/src/api/integrations/event/websocket/websocket.controller.ts index a1ed613f..611d5278 100644 --- a/src/api/integrations/event/websocket/websocket.controller.ts +++ b/src/api/integrations/event/websocket/websocket.controller.ts @@ -128,6 +128,7 @@ export class WebsocketController extends EventController implements EventControl const configEv = event.replace(/[.-]/gm, '_').toUpperCase(); const logEnabled = configService.get('LOG').LEVEL.includes('WEBSOCKET'); const message = { + ...(extra ?? {}), event, instance: instanceName, data, @@ -135,7 +136,6 @@ export class WebsocketController extends EventController implements EventControl date_time: dateTime, sender, apikey: apiKey, - ...extra, }; if (configService.get('WEBSOCKET')?.GLOBAL_EVENTS) { From 04ac880fcc869cb532f74eecfa892e45b5119f9f Mon Sep 17 00:00:00 2001 From: Alexandre Martins Date: Fri, 5 Dec 2025 10:58:42 -0300 Subject: [PATCH 3/3] style: fix lint formatting issues --- .../channel/whatsapp/whatsapp.baileys.service.ts | 2 +- src/api/integrations/event/event.controller.ts | 13 ++++++++++++- src/api/services/channel.service.ts | 8 +++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 6dd89d29..d2c458ec 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -82,7 +82,7 @@ import { createId as cuid } from '@paralleldrive/cuid2'; import { Instance, Message } from '@prisma/client'; import { createJid } from '@utils/createJid'; import { fetchLatestWaWebVersion } from '@utils/fetchLatestWaWebVersion'; -import {makeProxyAgent, makeProxyAgentUndici} from '@utils/makeProxyAgent'; +import { makeProxyAgent, makeProxyAgentUndici } from '@utils/makeProxyAgent'; import { getOnWhatsappCache, saveOnWhatsappCache } from '@utils/onWhatsappCache'; import { status } from '@utils/renderStatus'; import { sendTelemetry } from '@utils/sendTelemetry'; diff --git a/src/api/integrations/event/event.controller.ts b/src/api/integrations/event/event.controller.ts index 7b168406..39b52184 100644 --- a/src/api/integrations/event/event.controller.ts +++ b/src/api/integrations/event/event.controller.ts @@ -20,7 +20,18 @@ export type EmitData = { export interface EventControllerInterface { set(instanceName: string, data: any): Promise; get(instanceName: string): Promise; - emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local, extra }: EmitData): Promise; + emit({ + instanceName, + origin, + event, + data, + serverUrl, + dateTime, + sender, + apiKey, + local, + extra, + }: EmitData): Promise; } export class EventController { diff --git a/src/api/services/channel.service.ts b/src/api/services/channel.service.ts index 06e2f565..70a588ed 100644 --- a/src/api/services/channel.service.ts +++ b/src/api/services/channel.service.ts @@ -431,7 +431,13 @@ export class ChannelStartupService { return data; } - public async sendDataWebhook(event: Events, data: T, local = true, integration?: string[], extra?: Record) { + public async sendDataWebhook( + event: Events, + data: T, + local = true, + integration?: string[], + extra?: Record, + ) { const serverUrl = this.configService.get('SERVER').URL; const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds const localISOTime = new Date(Date.now() - tzoffset).toISOString();