-
Notifications
You must be signed in to change notification settings - Fork 5.2k
feat: add generateMessageID method and support for messageId in sendM… #2361
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?
feat: add generateMessageID method and support for messageId in sendM… #2361
Conversation
Reviewer's GuideAdds support for externally generated WhatsApp/Baileys message IDs, including a new internal API endpoint to pre-generate Baileys-compatible message IDs and wiring the optional messageId through DTOs, controllers, services, and the send pipeline so it overrides default ID generation when provided. Sequence diagram for the new generateMessageID API flowsequenceDiagram
actor Integrator
participant HTTP_API as HTTP_API
participant BaileysRouter as BaileysRouter
participant BaileysController as BaileysController
participant BaileysStartupService as BaileysStartupService
participant BaileysSock as BaileysSock
Integrator->>HTTP_API: GET /baileys/generateMessageID/{instance}
HTTP_API->>BaileysRouter: routeRequest
BaileysRouter->>BaileysController: generateMessageID(instanceDto)
BaileysController->>BaileysStartupService: generateMessageID()
BaileysStartupService->>BaileysSock: generateMessageIDV2(userId)
BaileysSock-->>BaileysStartupService: messageId
BaileysStartupService-->>BaileysController: { id: messageId }
BaileysController-->>BaileysRouter: { id: messageId }
BaileysRouter-->>HTTP_API: HTTP 200 { id: messageId }
HTTP_API-->>Integrator: returns preGenerated messageId
Sequence diagram for sending messages with optional external messageIdsequenceDiagram
actor Integrator
participant EvolutionAPI as EvolutionAPI
participant EvolutionStartupService as EvolutionStartupService
participant BaileysStartupService as BaileysStartupService
participant BaileysSock as BaileysSock
participant WhatsAppServer as WhatsAppServer
Integrator->>EvolutionAPI: POST /sendMessage with options.messageId?
EvolutionAPI->>EvolutionStartupService: sendMessage(sender, message, options)
EvolutionStartupService->>EvolutionStartupService: messageId = options.messageId || v4()
EvolutionStartupService->>BaileysStartupService: sendMessage(sender, message, optionsWithMessageId)
BaileysStartupService->>BaileysStartupService: use options.messageId when calling sock.sendMessage
BaileysStartupService->>BaileysSock: sendMessage(jid, content, options.messageId)
BaileysSock->>WhatsAppServer: sendMessage with provided messageId
WhatsAppServer-->>BaileysSock: ack using same messageId
BaileysSock-->>BaileysStartupService: send result
BaileysStartupService-->>EvolutionStartupService: send result
EvolutionStartupService-->>Integrator: HTTP 200 with tracking using messageId
Updated class diagram for Baileys and Evolution messaging structuresclassDiagram
class BaileysStartupService {
- client
+ sendMessage(sender, message, options, isIntegration)
- generateMessageID() Promise
}
class EvolutionStartupService {
+ sendMessage(sender, message, options, file, isIntegration)
- createAudioMessage(sender, options)
}
class BaileysController {
- waMonitor
+ baileysOnWhatsapp(jid)
+ generateMessageID(instanceDto)
+ profilePictureUrl(instanceDto, body)
}
class Options {
+ delay: number
+ presence: string
+ linkPreview: boolean
+ mentionsEveryOne: boolean
+ mentioned: string[]
+ webhookUrl: string
+ messageId: string
}
class Metadata {
+ delay: number
+ presence: string
+ linkPreview: boolean
+ mentionsEveryOne: boolean
+ mentioned: string[]
+ encoding: boolean
+ notConvertSticker: boolean
+ messageId: string
}
class SendTextDto {
}
class InstanceDto {
+ instanceName: string
}
class WaMonitor {
+ waInstances: Map
}
class BaileysSock {
+ user: any
+ generateMessageIDV2(userId)
+ sendMessage(jid, content, messageId)
}
Metadata <|-- SendTextDto
Options o-- EvolutionStartupService
Options o-- BaileysStartupService
BaileysController o-- WaMonitor
WaMonitor o-- BaileysStartupService
BaileysStartupService o-- BaileysSock
BaileysController ..> InstanceDto
EvolutionStartupService ..> Options
BaileysStartupService ..> Options
Metadata ..> Options
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 3 issues, and left some high level feedback:
- In
sendMessage, the change fromnulltooptions.messageIdassumesoptionsis always defined; consider usingoptions?.messageId(or a default) to avoid runtime errors whenoptionsis undefined. - The new
generateMessageIDmethod is declaredprivateinBaileysStartupServicebut is invoked fromBaileysControllerviainstance.generateMessageID(); either make it public or expose it via a dedicated public wrapper to avoid TypeScript access violations and clarify its intended usage. - In
generateMessageID, you’re callinggenerateMessageIDV2(this.client.user?.id)without checking thatthis.client.user?.idexists; adding a guard or clear error when the instance is not connected would make the behavior more predictable.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `sendMessage`, the change from `null` to `options.messageId` assumes `options` is always defined; consider using `options?.messageId` (or a default) to avoid runtime errors when `options` is undefined.
- The new `generateMessageID` method is declared `private` in `BaileysStartupService` but is invoked from `BaileysController` via `instance.generateMessageID()`; either make it public or expose it via a dedicated public wrapper to avoid TypeScript access violations and clarify its intended usage.
- In `generateMessageID`, you’re calling `generateMessageIDV2(this.client.user?.id)` without checking that `this.client.user?.id` exists; adding a guard or clear error when the instance is not connected would make the behavior more predictable.
## Individual Comments
### Comment 1
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:1983-1988` </location>
<code_context>
}
}
+ private async generateMessageID() {
+
+ return {
+ id: generateMessageIDV2(this.client.user?.id)
+ };
+ }
</code_context>
<issue_to_address>
**suggestion:** Consider making `generateMessageID` synchronous and/or public if it's part of the controller surface.
This method doesn’t `await` anything, so it can be made synchronous to avoid unnecessary promise wrapping. Since it’s called externally via `instance.generateMessageID(...)`, treating it as `public` would also better reflect its actual usage and improve typings and maintainability.
```suggestion
public generateMessageID() {
return {
id: generateMessageIDV2(this.client.user?.id)
};
}
```
</issue_to_address>
### Comment 2
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:2253` </location>
<code_context>
linkPreview,
quoted,
- null,
+ options.messageId,
group?.ephemeralDuration,
// group?.participants,
</code_context>
<issue_to_address>
**issue (bug_risk):** Passing `undefined` instead of `null` for `messageId` may subtly change behavior; consider preserving the old null semantics.
To keep the old behavior while allowing explicit IDs, you can pass `options?.messageId ?? null` here (and in the other similar call).
</issue_to_address>
### Comment 3
<location> `src/api/integrations/channel/evolution/evolution.channel.service.ts:321` </location>
<code_context>
let audioFile;
- const messageId = v4();
+ const messageId = options?.messageId || v4();
let messageRaw: any;
</code_context>
<issue_to_address>
**suggestion:** Prefer nullish coalescing over `||` when choosing between provided and generated message IDs.
`options?.messageId || v4()` will replace any falsy `messageId` (like an empty string) with a new ID. If the intent is to only fall back when `messageId` is `null` or `undefined`, use `const messageId = options?.messageId ?? v4();` to preserve valid-but-falsy IDs.
```suggestion
const messageId = options?.messageId ?? v4();
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Outdated
Show resolved
Hide resolved
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Outdated
Show resolved
Hide resolved
src/api/integrations/channel/evolution/evolution.channel.service.ts
Outdated
Show resolved
Hide resolved
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
…ce.ts Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
…essage DTO
📋 Description
Em cenários de alto volume de envio de mensagens via Evolution API, chamadas HTTP síncronas podem sofrer timeout, fazendo com que o backend do integrador perca a referência do msg.key.id, apesar da mensagem já ter sido gerada/enviada pelo Baileys.
Como o messageId é gerado localmente pelo Baileys antes do envio, adotei uma abordagem que permite pré-gerar esse identificador no mesmo contexto da sessão, eliminando a dependência da resposta HTTP para rastreamento.
Criada uma nova API interna:
POST /baileys/generateMessageID/{instance}Essa API:
Ajustado o fluxo de envio para:
Benefícios:
Observações importantes:
🔗 Related Issue
Closes #(issue_number)
🧪 Type of Change
🧪 Testing
📸 Screenshots (if applicable)
✅ Checklist
📝 Additional Notes
Summary by Sourcery
Add support for externally supplied WhatsApp message IDs and expose an internal API to pre-generate protocol-compatible message IDs per instance.
New Features:
Enhancements: