Skip to content

Conversation

@JefersonRamos
Copy link
Contributor

@JefersonRamos JefersonRamos commented Jan 20, 2026

📋 Description

O evento messaging-history.set do Baileys passou a retornar o campo remoteJid como um remoteLid em alguns cenários.
Nesses casos, o remoteJid real nunca era recebido, o que tornava impossível identificar corretamente a quem o chat pertencia.

Como consequência:

Não era possível mapear o chat para um contato conhecido
O registro do chat ficava sem associação válida
A integração acabava registrando chats “órfãos”, que caíam em um limbo de dados, sem vínculo com contato ou número
Isso impactava diretamente qualquer sistema que dependesse da associação correta entre chat ↔ contato.

A correção implementa um mecanismo de resolução de identidade para o evento messaging-history.set, cobrindo os casos em que o Baileys retorna o chat.id como remoteLid e não fornece o remoteJid.

🔗 Related Issue

Closes #(issue_number)

🧪 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

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 20, 2026

Reviewer's Guide

Enhances WhatsApp Baileys history sync handling by improving contact JID derivation (especially @lid IDs), enriching chat records with both JID and LID, and adding detailed debug logs for messages, chats, and contacts during sync processing.

Sequence diagram for updated WhatsApp Baileys history sync handling

sequenceDiagram
  participant BaileysSocket
  participant BaileysStartupService
  participant PrismaRepository
  participant WebhookEndpoint

  BaileysSocket->>BaileysStartupService: onHistorySync(messages, chats, contacts, syncType)
  BaileysStartupService->>BaileysStartupService: logger.debug("Messages abaixo")
  BaileysStartupService->>BaileysStartupService: logger.debug(messages)
  BaileysStartupService->>BaileysStartupService: logger.debug("Chats abaixo")
  BaileysStartupService->>BaileysStartupService: logger.debug(chats)
  BaileysStartupService->>BaileysStartupService: logger.debug("Contatos abaixo")
  BaileysStartupService->>BaileysStartupService: logger.debug(contacts)

  alt syncType is ON_DEMAND
    BaileysStartupService->>BaileysStartupService: console.log(on-demand history sync)
  else syncType is OTHER
    BaileysStartupService->>BaileysStartupService: process normally
  end

  BaileysStartupService->>BaileysStartupService: contactsMap = new Map()
  BaileysStartupService->>BaileysStartupService: contactsMapLidJid = new Map()

  loop for each contact in contacts
    alt contact.id contains @lid and contact.phoneNumber exists
      BaileysStartupService->>BaileysStartupService: jid = contact.phoneNumber
    else
      BaileysStartupService->>BaileysStartupService: jid = contact.id
    end

    alt contact.id and (contact.notify or contact.name)
      BaileysStartupService->>BaileysStartupService: contactsMap.set(contact.id, { name, jid })
    end
    BaileysStartupService->>BaileysStartupService: contactsMapLidJid.set(contact.id, { jid })
  end

  BaileysStartupService->>PrismaRepository: chat.findMany(where instanceId)
  PrismaRepository-->>BaileysStartupService: existingChats
  BaileysStartupService->>BaileysStartupService: chatsRepository = Set(existing.remoteJid)

  BaileysStartupService->>BaileysStartupService: chatsRaw = []
  loop for each chat in chats
    alt chat.id in chatsRepository
      BaileysStartupService->>BaileysStartupService: skip existing chat
    else chat.id not in chatsRepository
      alt chat.id contains @lid
        BaileysStartupService->>BaileysStartupService: contact = contactsMapLidJid.get(chat.id)
        BaileysStartupService->>BaileysStartupService: remoteLid = chat.id
        alt contact and contact.jid
          BaileysStartupService->>BaileysStartupService: remoteJid = contact.jid
        else
          BaileysStartupService->>BaileysStartupService: remoteJid = chat.id
        end
      else chat.id does not contain @lid
        BaileysStartupService->>BaileysStartupService: remoteJid = chat.id
        BaileysStartupService->>BaileysStartupService: remoteLid = null
      end
      BaileysStartupService->>BaileysStartupService: chatsRaw.push({ remoteJid, remoteLid, instanceId, name })
    end
  end

  BaileysStartupService->>WebhookEndpoint: sendDataWebhook(CHATS_SET, chatsRaw)
Loading

Updated class diagram for BaileysStartupService contact and chat handling

classDiagram
  class ChannelStartupService {
  }

  class PrismaRepository {
    +chat ChatRepository
  }

  class ChatRepository {
    +findMany(where)
  }

  class BaileysStartupService {
    -logger
    -prismaRepository PrismaRepository
    -instanceId string
    +onHistorySync(messages, chats, contacts, syncType)
    +sendDataWebhook(event, payload)
  }

  class ContactProcessingContext {
    +contactsMap Map
    +contactsMapLidJid Map
    +buildContactsMaps(contacts)
  }

  class ChatProcessingContext {
    +chatsRaw RemoteChat[]
    +chatsRepository Set
    +buildChatsRaw(chats, contactsMapLidJid, instanceId)
  }

  class RemoteChat {
    +remoteJid string
    +remoteLid string
    +instanceId string
    +name string
  }

  ChannelStartupService <|-- BaileysStartupService
  BaileysStartupService --> PrismaRepository
  PrismaRepository --> ChatRepository

  BaileysStartupService --> ContactProcessingContext
  BaileysStartupService --> ChatProcessingContext

  ChatProcessingContext --> RemoteChat
Loading

Flow diagram for improved WhatsApp JID and LID mapping during history sync

flowchart TD
  A_start["Start history sync processing"] --> B_contacts

  subgraph Contact_processing
    B_contacts["Iterate contacts"] --> C_hasLid{"contact.id contains @lid and contact.phoneNumber exists"}
    C_hasLid -->|yes| D_jidPhone["jid = contact.phoneNumber"]
    C_hasLid -->|no| E_jidId["jid = contact.id"]

    D_jidPhone --> F_checkNameNotify
    E_jidId --> F_checkNameNotify["contact.id and (contact.notify or contact.name)?"]

    F_checkNameNotify -->|yes| G_setContact["contactsMap.set(contact.id, { name, jid })"]
    F_checkNameNotify -->|no| H_skipContact["skip name mapping"]

    G_setContact --> I_setLidJid
    H_skipContact --> I_setLidJid["contactsMapLidJid.set(contact.id, { jid })"]
  end

  I_setLidJid --> J_chats["Iterate chats"]

  subgraph Chat_processing
    J_chats --> K_inRepository{"chat.id in chatsRepository?"}
    K_inRepository -->|yes| L_skipChat["skip chat"]
    K_inRepository -->|no| M_hasLidChat{"chat.id contains @lid"}

    M_hasLidChat -->|yes| N_getContact["contact = contactsMapLidJid.get(chat.id)"]
    N_getContact --> O_setRemoteLid["remoteLid = chat.id"]
    O_setRemoteLid --> P_hasContactJid{"contact and contact.jid?"}
    P_hasContactJid -->|yes| Q_remoteJidContact["remoteJid = contact.jid"]
    P_hasContactJid -->|no| R_remoteJidFallback["remoteJid = chat.id"]

    M_hasLidChat -->|no| S_nonLid["remoteJid = chat.id; remoteLid = null"]

    Q_remoteJidContact --> T_pushChat
    R_remoteJidFallback --> T_pushChat
    S_nonLid --> T_pushChat["chatsRaw.push({ remoteJid, remoteLid, instanceId, name })"]
  end

  L_skipChat --> U_nextChat["next chat"]
  T_pushChat --> U_nextChat
  U_nextChat --> V_doneChats{"more chats?"}
  V_doneChats -->|yes| J_chats
  V_doneChats -->|no| W_sendWebhook["sendDataWebhook(CHATS_SET, chatsRaw)"]

  W_sendWebhook --> X_end["End history sync processing"]
Loading

File-Level Changes

Change Details Files
Add detailed debug logging for history sync payloads (messages, chats, contacts) to aid diagnosing Baileys/WhatsApp changes.
  • Log a marker string and the full messages array at debug level when processing history sync.
  • Log a marker string and the full chats array at debug level when processing history sync.
  • Log a marker string and the full contacts array at debug level when processing history sync.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Improve contact JID mapping, including support for @lid contacts with fallback to phone numbers.
  • Introduce a contactsMapLidJid map to store JID information keyed by contact.id (potentially @lid).
  • Derive a contact JID from phoneNumber when contact.id contains '@lid', falling back to contact.id if no phone number is present.
  • Store contacts in contactsMap using the derived JID while retaining the display name from contact.name or contact.notify.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Extend chat handling to track both remote JID and remote LID and to resolve JIDs for @lid-based chats via the contacts map.
  • Extend chatsRaw elements to include a remoteLid field alongside remoteJid and instanceId.
  • For chats whose id contains '@lid', look up the corresponding contact in contactsMapLidJid and map chat.id to remoteLid while resolving remoteJid from the contact’s JID when available.
  • Fallback to using chat.id as remoteJid when no contact-based JID mapping is available.
  • Send the enriched chatsRaw array (with JID/LID separation) via the CHATS_SET webhook event.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

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 - I've found 2 issues, and left some high level feedback:

  • The @lid handling logic for both contacts and chats is duplicated and a bit ad-hoc; consider extracting a small helper function (e.g., normalizeLidJid(...)) to centralize this mapping and make the behavior easier to reason about and update.
  • In chatsRaw, remoteLid is typed as a required string but is set to null or left unset in some cases; either make this field optional or explicitly type it as string | null to better reflect actual usage.
  • The new debug logs dump full messages, chats, and contacts objects, which may be large and sensitive; consider gating these behind a more granular debug flag or trimming the payload to key fields to keep logs manageable and safer for production.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `@lid` handling logic for both contacts and chats is duplicated and a bit ad-hoc; consider extracting a small helper function (e.g., `normalizeLidJid(...)`) to centralize this mapping and make the behavior easier to reason about and update.
- In `chatsRaw`, `remoteLid` is typed as a required `string` but is set to `null` or left unset in some cases; either make this field optional or explicitly type it as `string | null` to better reflect actual usage.
- The new debug logs dump full `messages`, `chats`, and `contacts` objects, which may be large and sensitive; consider gating these behind a more granular debug flag or trimming the payload to key fields to keep logs manageable and safer for production.

## Individual Comments

### Comment 1
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:944-948` </location>
<code_context>
     }) => {
+      //These logs are crucial; when something changes in Baileys/WhatsApp, we can more easily understand what changed!
+      this.logger.debug('Messages abaixo');
+      this.logger.debug(messages);
+      this.logger.debug('Chats abaixo');
+      this.logger.debug(chats);
+      this.logger.debug('Contatos abaixo');
+      this.logger.debug(contacts);
+
       try {
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Consider the volume/sensitivity of logging full message, chat and contact objects

Logging full `messages`, `chats` and `contacts` on every sync can flood logs and expose sensitive user data, especially in shared or centralized logging systems. Consider logging only identifiers/counts by default and gating full payload logs behind a feature flag, or trimming the objects to metadata before logging.

Suggested implementation:

```typescript
    }) => {
      const logFullPayloads = process.env.WHATSAPP_DEBUG_PAYLOADS === 'true';

      // Log a safe summary by default to avoid flooding logs and leaking sensitive data
      this.logger.debug('History sync payload summary', {
        messagesCount: messages?.length ?? 0,
        chatsCount: chats?.length ?? 0,
        contactsCount: contacts?.length ?? 0,
      });

      // Optionally log full payloads when explicitly enabled
      if (logFullPayloads) {
        this.logger.debug('History sync messages payload', messages);
        this.logger.debug('History sync chats payload', chats);
        this.logger.debug('History sync contacts payload', contacts);
      }

```

1. Consider wiring `logFullPayloads` to your existing configuration system instead of reading directly from `process.env` (e.g. inject a config service and use `this.configService.get('WHATSAPP_DEBUG_PAYLOADS')`).
2. If your logging setup prefers string messages over structured metadata, adjust the summary log to interpolate counts into the message instead of passing an object.
3. You may also want to document the `WHATSAPP_DEBUG_PAYLOADS` flag in your ops/deployment docs so that production environments keep it disabled by default.
</issue_to_address>

### Comment 2
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:1001-1004` </location>
<code_context>
         }

-        const chatsRaw: { remoteJid: string; instanceId: string; name?: string }[] = [];
+        const chatsRaw: { remoteJid: string; remoteLid: string; instanceId: string; name?: string }[] = [];
         const chatsRepository = new Set(
           (await this.prismaRepository.chat.findMany({ where: { instanceId: this.instanceId } })).map(
</code_context>

<issue_to_address>
**issue (bug_risk):** Type of `remoteLid` is declared as `string` but `null` is pushed for non-lid chats

`remoteLid` is initialized as `null` and only set when `chat.id` has `@lid`, so for normal chats you push `remoteLid: null` into an array typed as `{ remoteJid: string; remoteLid: string; ... }`. This is either a TS error or unsafely widens the type. Please align the type with the runtime value, e.g. `remoteLid?: string` with `undefined` as the default, or `remoteLid: string | null`.
</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.

@Jeferson-Ramos-Einov
Copy link
Contributor

Estão resolvendo no lado do baileys também acredito que isso va direto para a master: WhiskeySockets/Baileys#2282

Então a realease 7.0.0-rc.9 ficaria com esse deficit porem com essa PR #2372 o problema seria resolvido de forma paliativa.

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