Skip to content

Conversation

@KokeroO
Copy link
Contributor

@KokeroO KokeroO commented Oct 12, 2025

📋 Description

🔗 Related Issue

Closes #2071, #2065, #2063, #2007, #2003, #1834, #1811

🧪 Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧹 Code cleanup
  • 🔒 Security fix

🧪 Testing

  • Manual testing completed
  • Functionality verified in development environment
  • No breaking changes introduced
  • Tested with different connection types (if applicable)

📸 Screenshots (if applicable)

✅ Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have manually tested my changes thoroughly
  • I have verified the changes work with different scenarios
  • Any dependent changes have been merged and published

📝 Additional Notes

Changes commented on in file change notes.

Summary by Sourcery

Refactor and correct core messaging services to improve connection reuse, cache handling, and event processing, while cleaning up deprecated code and updating tooling configurations.

New Features:

  • Use Readable streams for sending attachments instead of raw buffers
  • Add support for new document extensions (.dxf, .dwg)
  • Introduce custom addressing mode for lid messages via remoteJidAlt

Bug Fixes:

  • Reuse a single Postgres client in ChatwootService instead of creating new connections
  • Correct remoteJid and contact identifier updates for lid addressing
  • Fix stale conversation races by rechecking cache/locks and adding TTL on cached conversation IDs
  • Handle message deletion and update events by removing Chatwoot messages and database records accordingly
  • Load i18n translation files from the proper __dirname path
  • Replace ExtendedMessageKey with WAMessageKey for consistent message key handling

Enhancements:

  • Simplify createMessage and sendData flows by removing inline closures and stale error retries
  • Streamline BaileysStartupService by eliminating redundant remoteJid transformations and stale methods
  • Improve logging for conversation lookup, new message events, and duplicate updates
  • Clean up unused parameters and remove deprecated helper methods in ChatwootService

Build:

  • Update pre-commit hook to run TypeScript compile check (tsc --noEmit)
  • Add @swc/core and @swc/helpers to devDependencies

Chores:

  • Refactor chatwoot-import-helper to handle group contacts without phone numbers
  • Remove obsolete methods findOpenConversation and handleStaleConversationError

- Changed the build command in package.json to use TypeScript compiler (tsc) with noEmit option.
- Added @swc/core and @swc/helpers as development dependencies for improved performance.

refactor: clean up WhatsApp Baileys service

- Removed unused properties and interfaces related to message keys.
- Simplified message handling logic by removing redundant checks and conditions.
- Updated message timestamp handling for consistency.
- Improved readability and maintainability by restructuring code and removing commented-out sections.

refactor: optimize Chatwoot service

- Streamlined database queries by reusing PostgreSQL client connection.
- Enhanced conversation creation logic with better cache handling.
- Removed unnecessary methods and improved existing ones for clarity.
- Updated message sending logic to handle file streams instead of buffers.

fix: improve translation loading mechanism

- Simplified translation file loading by removing environment variable checks.
- Ensured translations are loaded from a consistent path within the project structure.
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 12, 2025

Reviewer's Guide

This PR refactors database client usage, overhauls conversation and messaging flows in ChatwootService, simplifies message send and streaming logic, cleans up legacy mapping in the Baileys service, streamlines i18n loading, enhances import helper phone binding for groups, and updates build tooling and dependencies.

Sequence diagram for the updated Chatwoot conversation creation flow

sequenceDiagram
  participant User
  participant ChatwootService
  participant CacheService
  participant ChatwootClient
  participant Database

  User->>ChatwootService: createConversation(instance, body)
  ChatwootService->>CacheService: has(cacheKey)?
  alt Conversation exists in cache
    ChatwootService->>CacheService: get(cacheKey)
    ChatwootService->>ChatwootClient: get(conversationId)
    alt Conversation exists in Chatwoot
      ChatwootService-->>User: return conversationId
    else Conversation missing in Chatwoot
      ChatwootService->>CacheService: delete(cacheKey)
      ChatwootService->>ChatwootService: createConversation(instance, body) (retry)
    end
  else Conversation not in cache
    ChatwootService->>CacheService: has(lockKey)?
    alt Lock exists
      ChatwootService->>CacheService: wait for release or timeout
    end
    ChatwootService->>CacheService: set(lockKey)
    ChatwootService->>ChatwootClient: get contactConversations
    alt Open conversation found
      ChatwootService->>CacheService: set(cacheKey, conversationId)
      ChatwootService-->>User: return conversationId
    else No open conversation
      ChatwootService->>ChatwootClient: create new conversation
      ChatwootService->>CacheService: set(cacheKey, newConversationId)
      ChatwootService-->>User: return newConversationId
    end
    ChatwootService->>CacheService: delete(lockKey)
  end
Loading

File-Level Changes

Change Details Files
Database client initialization refactor
  • Removed async getPgClient() and replaced with pgClient property
  • Initialized postgres connection once in constructor
  • Updated all SQL queries to use this.pgClient directly
src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts
createConversation logic overhaul
  • Reworked isLid detection using remoteJidAlt
  • Early exit if clientCw() returns null
  • Enhanced cache & lock handling with API conversation existence check
  • Removed redundant findOpen/findAndReopen methods and simplified reopen logic
src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts
Message creation and sendData streamlining
  • Removed doCreateMessage/doSendData closures and retry handlers
  • Unified direct client.messages.create and axios.request calls
  • Replaced Buffer usage with Readable streams for attachments
src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts
Baileys service cleanup and caching adjustments
  • Dropped ExtendedMessageKey and legacy @lid mapping
  • Adjusted update cache TTL and duplicate detection logic
  • Unified participant mapping and removed unused code paths
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
i18n path configuration simplification
  • Removed dynamic baseDir logic and env var support
  • Hardcoded translationsPath via __dirname
  • Always load JSON translations by language
src/utils/i18n.ts
Chatwoot import helper enhancements
  • Detect groups to prepend name with “(GROUP)”
  • Bind phone number conditionally, using NULL for groups
src/api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper.ts
Build tooling and dependency updates
  • Replaced pre-commit build step with tsc --noEmit
  • Added @swc/core and @swc/helpers to devDependencies
package.json

Assessment against linked issues

Issue Objective Addressed Explanation
#2071 Ensure that when a client replies to a message, the response appears in the same conversation/ticket, not as a new conversation with a random number.
#2071 Prevent duplication of client contacts with random numbers and emails when they respond to messages.

Possibly linked issues

  • #Webhook not working, PrismaClientValidationError in whatsapp.baileys.service.ts: PR modifies remoteJid and participant handling in whatsapp.baileys.service.ts, fixing a PrismaClientValidationError by ensuring correct string types for key paths, resolving webhook failures.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a 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:

  • Detected that function argument language has entered the fs module. An attacker could potentially control the location of this file, to include going backwards in the directory with '../'. To address this, ensure that user-controlled variables in file paths are validated. (link)

General comments:

  • Replacing getPgClient() with a single pgClient property could lead to connection reuse issues if it isn’t a pool—please verify that it supports concurrent queries and reconnections or revert to per‐query acquisition.
  • The recursive retry in createConversation when a cached conversation is missing risks unbounded recursion—consider refactoring it into a loop with a max retry count to avoid potential stack overflows.
  • The stale‐conversation retry logic was removed from sendData, so 404 errors on sending may go unhandled; it’d be safer to reintroduce error handling that recreates the conversation before retrying the send.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Replacing `getPgClient()` with a single `pgClient` property could lead to connection reuse issues if it isn’t a pool—please verify that it supports concurrent queries and reconnections or revert to per‐query acquisition.
- The recursive retry in `createConversation` when a cached conversation is missing risks unbounded recursion—consider refactoring it into a loop with a max retry count to avoid potential stack overflows.
- The stale‐conversation retry logic was removed from `sendData`, so 404 errors on sending may go unhandled; it’d be safer to reintroduce error handling that recreates the conversation before retrying the send.

## Individual Comments

### Comment 1
<location> `src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts:627-636` </location>
<code_context>
-
-        const client = await this.clientCw(instance);
-        if (!client) return null;
+        if (await this.cache.has(cacheKey)) {
+          return (await this.cache.get(cacheKey)) as number;
+        }

         const isGroup = remoteJid.includes('@g.us');
         const chatId = isGroup ? remoteJid : remoteJid.split('@')[0];
@@ -760,39 +779,34 @@ export class ChatwootService {
           return null;
         }

-        let inboxConversation = null;
-
-        if (this.provider.reopenConversation) {
-          inboxConversation = this.findOpenConversation(contactConversations.payload, filterInbox.id);
-
-          if (inboxConversation) {
-            this.logger.verbose(
-              `Found open conversation in reopenConversation mode: ${JSON.stringify(inboxConversation)}`,
-            );
+        let inboxConversation = contactConversations.payload.find(
+          (conversation) => conversation.inbox_id == filterInbox.id,
+        );
</code_context>

<issue_to_address>
**issue (bug_risk):** Recursive call to createConversation if conversation does not exist may lead to stack overflow in rare cases.

If a conversationId in the cache is consistently missing from Chatwoot, this recursion could become infinite. Please add a retry limit or guard to prevent stack overflow.
</issue_to_address>

### Comment 2
<location> `src/utils/i18n.ts:15` </location>
<code_context>
    const translationContent = fs.readFileSync(languagePath, 'utf8');
</code_context>

<issue_to_address>
**security (javascript.lang.security.audit.detect-non-literal-fs-filename):** Detected that function argument `language` has entered the fs module. An attacker could potentially control the location of this file, to include going backwards in the directory with '../'. To address this, ensure that user-controlled variables in file paths are validated.

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@DavidsonGomes DavidsonGomes merged commit 20eef33 into EvolutionAPI:develop Oct 13, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants