-
Couldn't load subscription status.
- Fork 4.6k
Add Chatwoot auth header support #2131
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
- Updated subproject reference in evolution-manager-v2. - Replaced old JavaScript and CSS asset files with new versions for improved performance and styling. - Added new CSS file for consistent font styling across the application. - Updated the evolution logo image to the latest version.
- Added features for Chatwoot enhancements, participants data handling, and LID to phone number conversion. - Updated Docker configurations to include Kafka and frontend services. - Fixed PostgreSQL migration errors and improved message handling in Baileys and Chatwoot services. - Refactored TypeScript build process and implemented exponential backoff patterns.
- Updated the release date for version 2.3.5 to 2025-10-15. - Adjusted subproject reference in evolution-manager-v2 to the latest commit.
- Integrated telemetry logging for received messages in Evolution, WhatsApp Business, and Baileys services. - Enhanced message tracking by sending the message type to the telemetry system for better observability.
- Updated subproject reference in evolution-manager-v2 to the latest commit. - Enhanced the manager_install.sh script to include npm install and build steps for the evolution-manager-v2. - Replaced old JavaScript asset file with a new version for improved performance. - Added a new CSS file for consistent styling across the application.
- Added 'submodules: recursive' option to the checkout step in multiple workflow files to ensure submodules are properly initialized during CI/CD processes.
β¦na baileys e chatwoot * corrige cache de nΓΊmeros PN, LIDs e g.us para enviar o nΓΊmero correto * atualiza para os ΓΊltimos commits da baileys * corrige envio de Γ‘udio e documentos via chatwoot no canal baileys * diversas correΓ§Γ΅es na integraΓ§Γ£o com chatwoot * corrige mensagens ignoradas no recebimento de leads
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
β¦e.ts Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
β¦e.ts Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
feat(baileys,chatwoot,on-whatsapp-cache): implementaΓ§Γ΅es e correΓ§Γ΅es na baileys e chatwoot
Evita o erro de this.isZero not is function
fix: Simplify logging of messageSent object
fix( baileys.service ): Corrige ao salvar no DB valores Uint8Array
chore: bump version to 2.3.6 and update baileys dependency to 7.0.0-rc.6
β¦oot API requests
Reviewer's GuideThis PR introduces Chatwoot auth header support while comprehensively refactoring message and attachment handling, contact resolution, cache management, logging, and CI workflows to simplify code paths and improve reliability. Sequence diagram for Chatwoot message/attachment sending with auth headersequenceDiagram
participant S as "ChatwootService"
participant C as "Chatwoot API"
participant W as "WhatsApp Channel"
S->>C: POST /conversations/:id/messages
Note right of C: Now uses 'api-access-token' header
C-->>S: Message/attachment accepted
S->>W: Send message/attachment to WhatsApp
W-->>S: Delivery status
Class diagram for OnWhatsappCache and related cache logicclassDiagram
class OnWhatsappCache {
+saveOnWhatsappCache(data)
+getAvailableNumbers(remoteJid)
}
class ISaveOnWhatsappCacheParams {
+remoteJid: string
+remoteJidAlt: string
+lid: "lid" | undefined
}
OnWhatsappCache -- ISaveOnWhatsappCacheParams
OnWhatsappCache : Logger logger
OnWhatsappCache : prismaRepository
OnWhatsappCache : configService
OnWhatsappCache : dayjs
OnWhatsappCache : getAvailableNumbers(remoteJid)
OnWhatsappCache : saveOnWhatsappCache(data)
OnWhatsappCache : Handles @lid, @g.us, and normal numbers
OnWhatsappCache : Preserves and merges jidOptions
Class diagram for ChatwootService message/attachment handlingclassDiagram
class ChatwootService {
+createConversation(instance, body)
+sendAttachment(waInstance, number, media, caption, options)
+receiveWebhook(instance, body)
+updateChatwootMessageId(message, chatwootMessageIds, instance)
-logger
-cache
-waMonitor
-prismaRepository
-provider
}
ChatwootService : Uses 'api-access-token' header for Chatwoot API
ChatwootService : Handles phone number resolution for LID and group
ChatwootService : Simplified attachment download and sending
ChatwootService : Refactored webhook and deletion logic
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:
Blocking issues:
- An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload. (link)
- An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload. (link)
- An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload. (link)
General comments:
- Thereβs a lot of repeated JID parsing and LID/Group detection logic scattered across methodsβconsider extracting that into a shared helper to reduce duplication and improve readability.
- Random delay values and hard-coded timeouts are sprinkled throughout (e.g. 500ms, 1200ms, random between 500β2000ms); centralizing these into named constants or config entries would make behavior easier to tune and reason about.
- The sequential upserts in saveOnWhatsappCache use awaits inside a loop, which may hurt performance; consider batching those writes or wrapping them in a single transaction to handle multiple records more efficiently.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Thereβs a lot of repeated JID parsing and LID/Group detection logic scattered across methodsβconsider extracting that into a shared helper to reduce duplication and improve readability.
- Random delay values and hard-coded timeouts are sprinkled throughout (e.g. 500ms, 1200ms, random between 500β2000ms); centralizing these into named constants or config entries would make behavior easier to tune and reason about.
- The sequential upserts in saveOnWhatsappCache use awaits inside a loop, which may hurt performance; consider batching those writes or wrapping them in a single transaction to handle multiple records more efficiently.
## Individual Comments
### Comment 1
<location> `src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts:1157` </location>
<code_context>
- this.logger.error(`[MEDIA DOWNLOAD] Error stack: ${downloadError.stack}`);
- this.logger.error(`[MEDIA DOWNLOAD] Full error: ${JSON.stringify(downloadError, null, 2)}`);
- throw new Error(`Failed to download media: ${downloadError.message}`);
+ mimeType = response.headers['content-type'];
}
</code_context>
<issue_to_address>
**suggestion:** Mime type assignment may be undefined if response header is missing.
If 'content-type' is missing, mimeType will be undefined. Please handle this case by setting a default value or adding a check.
```suggestion
mimeType = response.headers['content-type'] || 'application/octet-stream';
```
</issue_to_address>
### Comment 2
<location> `src/utils/onWhatsappCache.ts:121-128` </location>
<code_context>
+ `Saving: remoteJid=${remoteJid}, jidOptions=${uniqueNumbers.join(',')}, lid=${item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null}`,
+ );
+
+ if (existingRecord) {
+ await prismaRepository.isOnWhatsapp.update({
+ where: { id: existingRecord.id },
+ data: {
+ remoteJid: remoteJid,
+ jidOptions: uniqueNumbers.join(','),
+ lid: item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null,
+ },
+ });
+ } else {
+ await prismaRepository.isOnWhatsapp.create({
+ data: {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Upsert logic may overwrite existing lid value.
Preserve the existing lid value during updates if it is already set and valid, rather than always overwriting it based on the current item.
```suggestion
// Determine if we should preserve the existing lid value
const newLid = item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null;
const existingLidValid = existingRecord.lid === 'lid';
await prismaRepository.isOnWhatsapp.update({
where: { id: existingRecord.id },
data: {
remoteJid: remoteJid,
jidOptions: uniqueNumbers.join(','),
lid: existingLidValid && !newLid ? existingRecord.lid : newLid,
},
});
```
</issue_to_address>
### Comment 3
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:4452-4460` </location>
<code_context>
}
- private convertLongToNumber(obj: any): any {
+ private deserializeMessageBuffers(obj: any): any {
if (obj === null || obj === undefined) {
return obj;
}
- if (Long.isLong(obj)) {
- return obj.toNumber();
+ if (typeof obj === 'object' && !Array.isArray(obj) && !Buffer.isBuffer(obj)) {
+ const keys = Object.keys(obj);
+ const isIndexedObject = keys.every((key) => !isNaN(Number(key)));
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Deserialization may incorrectly convert objects with numeric keys.
Stricter validation is needed to ensure only intended buffer objects are converted, preventing misclassification of other objects with numeric keys.
```suggestion
if (typeof obj === 'object' && !Array.isArray(obj) && !Buffer.isBuffer(obj)) {
const keys = Object.keys(obj);
// Stricter validation: keys must be consecutive numeric strings starting from 0
const isIndexedObject =
keys.length > 0 &&
keys.every((key, idx) => key === String(idx)) &&
keys.every((key) => {
const value = obj[key];
return typeof value === 'number' && value >= 0 && value <= 255;
});
if (isIndexedObject) {
const values = keys.map((key) => obj[key]);
return new Uint8Array(values);
}
}
```
</issue_to_address>
### Comment 4
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:4498-4499` </location>
<code_context>
status: status[message.status],
- message: this.convertLongToNumber({ ...message.message }),
- contextInfo: this.convertLongToNumber(contentMsg?.contextInfo),
+ message: this.deserializeMessageBuffers({ ...message.message }),
+ contextInfo: this.deserializeMessageBuffers(contentMsg?.contextInfo),
messageType: contentType || 'unknown',
messageTimestamp: Long.isLong(message.messageTimestamp)
</code_context>
<issue_to_address>
**issue (bug_risk):** Deserialization of message and contextInfo may lose Long type information.
Verify that deserialization preserves Long values for fields like timestamps and IDs, and apply necessary conversions if not.
</issue_to_address>
### Comment 5
<location> `.github/workflows/docker-build.yml:18` </location>
<code_context>
uses: docker/setup-buildx-action@v3
</code_context>
<issue_to_address>
**security (yaml.github-actions.security.third-party-action-not-pinned-to-commit-sha):** An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload.
*Source: opengrep*
</issue_to_address>
### Comment 6
<location> `.github/workflows/docker-build.yml:21` </location>
<code_context>
uses: docker/login-action@v3
</code_context>
<issue_to_address>
**security (yaml.github-actions.security.third-party-action-not-pinned-to-commit-sha):** An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload.
*Source: opengrep*
</issue_to_address>
### Comment 7
<location> `.github/workflows/docker-build.yml:27` </location>
<code_context>
uses: docker/build-push-action@v5
</code_context>
<issue_to_address>
**security (yaml.github-actions.security.third-party-action-not-pinned-to-commit-sha):** An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload.
*Source: opengrep*
</issue_to_address>Help me be more useful! Please click π or π on each comment and I'll use the feedback to improve your reviews.
| this.logger.error(`[MEDIA DOWNLOAD] Error stack: ${downloadError.stack}`); | ||
| this.logger.error(`[MEDIA DOWNLOAD] Full error: ${JSON.stringify(downloadError, null, 2)}`); | ||
| throw new Error(`Failed to download media: ${downloadError.message}`); | ||
| mimeType = response.headers['content-type']; |
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.
suggestion: Mime type assignment may be undefined if response header is missing.
If 'content-type' is missing, mimeType will be undefined. Please handle this case by setting a default value or adding a check.
| mimeType = response.headers['content-type']; | |
| mimeType = response.headers['content-type'] || 'application/octet-stream'; |
| message: this.deserializeMessageBuffers({ ...message.message }), | ||
| contextInfo: this.deserializeMessageBuffers(contentMsg?.contextInfo), |
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.
issue (bug_risk): Deserialization of message and contextInfo may lose Long type information.
Verify that deserialization preserves Long values for fields like timestamps and IDs, and apply necessary conversions if not.
π Description
π Related Issue
Closes #(issue_number)
π§ͺ Type of Change
π§ͺ Testing
πΈ Screenshots (if applicable)
β Checklist
π Additional Notes
Summary by Sourcery
Add HTTP auth header support for Chatwoot and streamline WhatsApp integration by introducing lid mode handling, simplifying media attachment workflows, improving onWhatsApp cache logic, refining logging, and enhancing CI/build configurations.
New Features:
Bug Fixes:
Enhancements:
Build:
CI:
Documentation: