-
Notifications
You must be signed in to change notification settings - Fork 5k
feat(events): add isLatest and progress to messages.set event #2260
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: main
Are you sure you want to change the base?
feat(events): add isLatest and progress to messages.set event #2260
Conversation
- 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.
Reviewer's GuideAdds support for passing arbitrary extra metadata through the event pipeline so that Baileys Sequence diagram for messages.set event with isLatest and progress propagationsequenceDiagram
participant BaileysStartupService
participant ChannelStartupService
participant EventManager
participant WebhookController
actor WebhookConsumer
BaileysStartupService->>BaileysStartupService: receive messaging_history_set(messages, isLatest, progress)
BaileysStartupService->>ChannelStartupService: sendDataWebhook(MESSAGES_SET, messagesRaw, true, undefined, {isLatest, progress})
ChannelStartupService->>ChannelStartupService: build EmitData with extra = {isLatest, progress}
ChannelStartupService->>EventManager: emit(eventData)
EventManager->>WebhookController: emit(eventData)
WebhookController->>WebhookController: build payload {
WebhookController->>WebhookController: event, instance, data, server_url, apikey, ...extra
WebhookController->>WebhookConsumer: POST messages.set payload including isLatest and progress
WebhookConsumer->>WebhookConsumer: process messages with history sync metadata
Class diagram for updated event pipeline with extra metadata supportclassDiagram
class EmitData {
+string instanceName
+string origin
+string event
+any data
+string serverUrl
+string dateTime
+string sender
+string apiKey
+boolean local
+string_array integration
+Record_string_any extra
}
class EventManager {
+emit(eventData: EmitData) Promise_void
}
class EventControllerInterface {
<<interface>>
+set(instanceName: string, data: any) Promise_any
+get(instanceName: string) Promise_any
+emit(emitData: EmitData) Promise_void
}
class EventController {
+set(instanceName: string, data: any) Promise_any
+get(instanceName: string) Promise_any
+emit(emitData: EmitData) Promise_void
}
class WebhookController {
+emit(emitData: EmitData) Promise_void
}
class RabbitmqController {
+emit(emitData: EmitData) Promise_void
}
class SqsController {
+emit(emitData: EmitData) Promise_void
}
class WebsocketController {
+emit(emitData: EmitData) Promise_void
}
class PusherController {
+emit(emitData: EmitData) Promise_void
}
class KafkaController {
+emit(emitData: EmitData) Promise_void
}
class NatsController {
+emit(emitData: EmitData) Promise_void
}
class ChannelStartupService {
+sendDataWebhook(event: Events, data: object, local: boolean, integration: string_array, extra: Record_string_any) Promise_void
}
class BaileysStartupService {
+sendDataWebhook(event: Events, data: object, local: boolean, integration: string_array, extra: Record_string_any) Promise_void
}
EventControllerInterface <|.. EventController
EventController <|-- WebhookController
EventController <|-- RabbitmqController
EventController <|-- SqsController
EventController <|-- WebsocketController
EventController <|-- PusherController
EventController <|-- KafkaController
EventController <|-- NatsController
EventManager --> WebhookController : uses
EventManager --> RabbitmqController : uses
EventManager --> SqsController : uses
EventManager --> WebsocketController : uses
EventManager --> PusherController : uses
EventManager --> KafkaController : uses
EventManager --> NatsController : uses
ChannelStartupService --> EventManager : emit events
BaileysStartupService --|> ChannelStartupService
EmitData <.. EventManager : parameter
EmitData <.. EventController : parameter
EmitData <.. WebhookController : parameter
EmitData <.. RabbitmqController : parameter
EmitData <.. SqsController : parameter
EmitData <.. WebsocketController : parameter
EmitData <.. PusherController : parameter
EmitData <.. KafkaController : parameter
EmitData <.. NatsController : parameter
note for WebhookController "In emit, builds payload with event, instance, data, and spreads extra into root"
note for KafkaController "In emit, spreads extra into Kafka message payload"
note for NatsController "In emit, spreads extra into NATS message payload"
note for RabbitmqController "In emit, spreads extra into RabbitMQ message payload"
note for SqsController "In emit, spreads extra into SQS message payload"
note for WebsocketController "In emit, spreads extra into WebSocket message payload"
note for PusherController "In emit, spreads extra into Pusher event payload"
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 there - I've reviewed your changes - here's some feedback:
- Using a generic
extra?: Record<string, any>that is spread into the root of every payload can lead to accidental key collisions with existing fields (e.g.event,instance,data); consider either namespacing (e.g.meta/context) or explicitly whitelisting allowed keys for specific events likemessages.set. - The new
extrafield is completely untyped and shared across all events; if you plan to use it beyond this case, consider tightening the typing (e.g. a discriminated union or per-event payload extension) so that fields likeisLatest/progressare discoverable and validated at compile time.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Using a generic `extra?: Record<string, any>` that is spread into the root of every payload can lead to accidental key collisions with existing fields (e.g. `event`, `instance`, `data`); consider either namespacing (e.g. `meta`/`context`) or explicitly whitelisting allowed keys for specific events like `messages.set`.
- The new `extra` field is completely untyped and shared across all events; if you plan to use it beyond this case, consider tightening the typing (e.g. a discriminated union or per-event payload extension) so that fields like `isLatest`/`progress` are discoverable and validated at compile time.
## Individual Comments
### Comment 1
<location> `src/api/integrations/event/kafka/kafka.controller.ts:265-268` </location>
<code_context>
sender,
apiKey,
integration,
+ extra,
}: EmitData): Promise<void> {
if (integration && !integration.includes('kafka')) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard object spread of optional `extra` to avoid runtime/typing issues.
`extra` is declared as optional (`extra?: Record<string, any>`), so its type is `Record<string, any> | undefined`. Spreading it directly (`...extra`) can cause TS errors (`Spread types may only be created from object types`) and may fail at runtime if `extra` is `undefined`. Please guard the spread with a fallback everywhere it’s used, for example:
```ts
const message = {
instance: instanceName,
origin,
event,
data,
server_url: serverUrl,
date_time: dateTime,
sender,
apikey: apiKey,
timestamp: Date.now(),
...(extra ?? {}),
};
```
The same guard should be applied in the other controllers (NATS, Pusher, RabbitMQ, SQS, Webhook, Websocket) for consistency.
</issue_to_address>
### Comment 2
<location> `src/api/integrations/event/webhook/webhook.controller.ts:102` </location>
<code_context>
sender,
apikey: apiKey,
timestamp: Date.now(),
+ ...extra,
};
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Consider whether `extra` should be allowed to override core event fields.
Spreading `extra` after the base properties means it can override core fields like `instance`, `origin`, `event`, `data`, `apikey`, etc. If that’s not intended, either:
- Spread `extra` first so core fields always win, or
- Nest it under a dedicated key (e.g. `extra`) instead of merging.
It would also be good to clarify this contract and apply the same pattern across all emitters (webhook, websocket, pusher, kafka, etc.).
Suggested implementation:
```typescript
// NOTE: `extra` is nested and not spread so it cannot override core event fields.
// This keeps `sender`, `server_url`, `apikey`, etc. stable while still allowing
// arbitrary additional payload data under the `extra` key.
sender,
server_url: serverUrl,
apikey: apiKey,
extra,
};
```
To fully implement the contract consistently across the codebase, you should also:
1. Apply the same “nest under `extra` instead of spreading” pattern in other emitters (websocket, Pusher, Kafka, etc.), replacing `...extra` with `extra` in their payload construction.
2. Update the `EmitData` (or equivalent) type/interface to document that arbitrary fields are carried in an `extra` object and that core event fields cannot be overridden.
3. Optionally add similar inline comments in other emitters to make the non-overriding behavior explicit for future maintainers.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- 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.
O evento
messages.setnão enviava as propriedadesisLatesteprogressdo Baileys, perdendo informações importantes sobre a sincronização do histórico.O comportamento ocorria porque o método
sendDataWebhookenviava apenas o array de mensagens:Com a sincronização de histórico do WhatsApp, é importante saber quando o sync está completo (
isLatest=true) e o progresso percentual (progress).Ajuste realizado:
ANTES:
{ "event": "messages.set", "instance": "minha-instancia", "data": [...] }DEPOIS:
{ "event": "messages.set", "instance": "minha-instancia", "isLatest": true, "progress": 85, "data": [...] }Com essa alteração, consumidores do webhook podem identificar quando a sincronização está completa e acompanhar o progresso.
📋 Description
Add support for extra fields in event payload root, specifically
isLatestandprogressfrom Baileys'messaging-history.setevent.🔗 Related Issue
N/A
🧪 Type of Change
🧪 Testing
📸 Screenshots (if applicable)
N/A
✅ Checklist
📝 Additional Notes
extra?: Record<string, any>field toEmitDatatypeEventManager.emit()to accept extra parameterssendDataWebhook()to accept and pass extra fields(extra ?? {})to handle undefined safelyevent,instance,dataextraparameter is optional