-
Notifications
You must be signed in to change notification settings - Fork 5.1k
feat(channel): add support for @newsletter in sendMessage and findChannels #2296
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
Conversation
Reviewer's GuideAdds initial WhatsApp Channels (@newsletter) support by recognizing newsletter JIDs in JID creation and onWhatsApp checks, mapping outbound channel messages to a delivered status, exposing a new fetchChannels API through chat controller/router that scans stored messages for newsletter JIDs and returns a paginated list, and wiring a new /findChannels route. Sequence diagram for the new findChannels API flowsequenceDiagram
actor Client
participant ChatRouter
participant ChatController
participant WAMonitor
participant WAInstance as BaileysStartupService
participant Prisma as PrismaRepository
participant DB as Database
Client->>ChatRouter: POST /chat/findChannels
ChatRouter->>ChatRouter: dataValidate(request, contactValidateSchema)
ChatRouter->>ChatController: fetchChannels(instanceDto, query)
ChatController->>WAMonitor: resolve waInstances[instanceName]
WAMonitor-->>ChatController: WAInstance
ChatController->>WAInstance: fetchChannels(query)
WAInstance->>Prisma: message.findMany({instanceId, where, orderBy, select})
Prisma->>DB: query messages
DB-->>Prisma: messages[]
Prisma-->>WAInstance: messages[]
loop for each message
WAInstance->>WAInstance: check isJidNewsletter(remoteJid)
WAInstance->>WAInstance: update channelMap
end
WAInstance->>WAInstance: build allChannels, paginate
WAInstance-->>ChatController: {total, pages, currentPage, limit, records}
ChatController-->>ChatRouter: response
ChatRouter-->>Client: 200 OK + channel list
Class diagram for new WhatsApp channel support and fetchChannels flowclassDiagram
class BaileysStartupService {
- string instanceId
- PrismaRepository prismaRepository
+ fetchChannels(query)
+ mapMessageStatus(message)
}
class PrismaRepository {
+ message_findMany(instanceId, orderBy, where, select)
}
class ChatController {
- WAMonitor waMonitor
+ fetchChannels(instanceDto, query)
}
class WAMonitor {
- Map~string, WAInstance~ waInstances
}
class WAInstance {
+ fetchChannels(query)
}
class ChatRouter {
- ChatController chatController
+ configureRoutes()
}
class QueryContact {
+ number
+ page
+ limit
+ rows
}
class OnWhatsAppDto {
+ string jid
+ boolean isBusiness
+ string number
+ string pushName
+ string type
}
class JidUtils {
+ createJid(number)
+ isJidGroup(jid)
+ isJidNewsletter(jid)
}
%% Relationships
ChatRouter --> ChatController : uses
ChatController --> WAMonitor : uses
WAMonitor --> WAInstance : waInstances
WAInstance <|-- BaileysStartupService
BaileysStartupService --> PrismaRepository : uses
BaileysStartupService --> JidUtils : uses
BaileysStartupService --> OnWhatsAppDto : creates
ChatController --> QueryContact : parameter
File-Level Changes
Possibly linked issues
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:
- In
fetchChannels, you load all messages for an instance into memory and then paginate in application code; consider pushing the filtering and pagination into the Prisma query (e.g., filtering by newsletter JIDs and usingskip/takeorcursor) to avoid scalability issues on large histories. - Since
fetchChannelsonly usesremoteJidandmessageTimestamp, you can tighten the Prismawhereclause to pre-filter on newsletter JIDs (e.g., using a pattern or dedicated field) instead of scanning all messages and checkingisJidNewsletterin a loop.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `fetchChannels`, you load all messages for an instance into memory and then paginate in application code; consider pushing the filtering and pagination into the Prisma query (e.g., filtering by newsletter JIDs and using `skip`/`take` or `cursor`) to avoid scalability issues on large histories.
- Since `fetchChannels` only uses `remoteJid` and `messageTimestamp`, you can tighten the Prisma `where` clause to pre-filter on newsletter JIDs (e.g., using a pattern or dedicated field) instead of scanning all messages and checking `isJidNewsletter` in a loop.
## Individual Comments
### Comment 1
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:5140-5142` </location>
<code_context>
};
}
+ public async fetchChannels(query: Query<Contact>) {
+ const page = Number((query as any)?.page ?? 1);
+ const limit = Number((query as any)?.limit ?? (query as any)?.rows ?? 50);
+ const skip = (page - 1) * limit;
+
+ const messages = await this.prismaRepository.message.findMany({
</code_context>
<issue_to_address>
**issue (bug_risk):** Handle invalid/non-numeric `page` and `limit` values to avoid NaN-based pagination.
`Number(...)` can yield `NaN` for non-numeric input (e.g. `'abc'`), which then propagates into `skip`/`slice`. Please validate `page` and `limit` (e.g. with `Number.isFinite`) and default or clamp them to sane minimum values (like 1 / 50) so pagination stays predictable.
</issue_to_address>
### Comment 2
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:4716-4717` </location>
<code_context>
}
}
+ if (isJidNewsletter(message.key.remoteJid) && message.key.fromMe) {
+ messageRaw.status = status[3]; // DELIVERED MESSAGE TO NEWSLETTER CHANNEL
+ }
+
</code_context>
<issue_to_address>
**suggestion:** Avoid magic index `status[3]` by using a named constant or enum-like mapping.
Indexing into `status` with `3` obscures the meaning of this assignment and tightly couples it to the array’s ordering. Prefer a named constant or enum-like value (e.g., `Status.DELIVERED`) so the intent is clear and resilient to changes in `status`.
Suggested implementation:
```typescript
if (isJidNewsletter(message.key.remoteJid) && message.key.fromMe) {
messageRaw.status = MESSAGE_STATUS.DELIVERED_TO_NEWSLETTER;
}
```
You should also introduce an enum-like mapping for the message statuses near where `status` is defined (or imported), for example:
```ts
// Example – place this close to the `status` definition/import
const MESSAGE_STATUS = {
DELIVERED_TO_NEWSLETTER: status[3],
// optionally map other indices if they are used elsewhere, e.g.:
// PENDING: status[0],
// SENT: status[1],
// READ: status[2],
} as const;
```
If your codebase already has a status enum or constant (e.g. `Status.DELIVERED`), prefer wiring this condition to that existing type instead of introducing `MESSAGE_STATUS`. In that case, replace the usage with `Status.DELIVERED` (or the correct equivalent) and remove the new mapping.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
📋 Description
This PR introduces initial support for WhatsApp Channels (@newsletter) within EvolutionAPI.
Due to protocol limitations in the underlying WhatsApp Web / Baileys architecture, full channel support is not technically possible, but the following improvements were implemented:
✅ Added
@newsletter) using allsendMessagevariants.findChannelscontroller and endpoint, returning detected newsletter JIDs from Baileys message history.createJidandwhatsappNumberto correctly identify and handle newsletter JIDs.pushName: undefinedbecause WhatsApp Web does not provide channel metadata.These limitations come directly from the WhatsApp Web MD protocol (implemented by Baileys) and cannot be bypassed:
PENDING(server does not support revoke for@newsletter).Because of these limitations, the
findChannelsendpoint returns:remoteJidlastMessageTimestamppushName: undefinedThis ensures consistent behavior without exposing misleading or incorrect metadata.
🔗 Related Issue
Closes:
🧪 Type of Change
🧪 Testing
@newslettertested successfully📸 Screenshots (if applicable)
✅ Checklist
📝 Additional Notes
Summary by Sourcery
Add WhatsApp Channel (@newsletter) support for contact lookup, message status handling, and channel discovery endpoints.
New Features:
Enhancements: