fix: resolve @lid (LID) to phone number in messages handlers and fix …#2450
fix: resolve @lid (LID) to phone number in messages handlers and fix …#2450jeandgardany wants to merge 15 commits into
Conversation
…QR code loop - messages.upsert: mutate received.key.remoteJid to remoteJidAlt when @lid is detected, ensuring prepareMessage, chatbot emit, contact upsert and all downstream uses receive the correct @s.whatsapp.net JID instead of the LID identifier - messages.update: after finding the stored message by key.id, resolve @lid using remoteJidAlt (fork field) or findMessage.key.remoteJid as fallback; applies to DB status update, webhook to N8N, messageUpdate record and chat unread counter - connectionUpdate: guard against infinite QR code regeneration loop when connection closes before QR is scanned (no wuid, no statusCode) - Dockerfile: use tsup directly instead of npm run build to bypass pre-existing tsc type error on terminateCall; add openssl/libc6-compat to Alpine final stage for Prisma compatibility - docker-compose.yaml: switch from remote image to local build so fixes persist across container recreations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reviewer's GuideUpdates WhatsApp Baileys service to normalize @lid JIDs to standard phone-number JIDs across message handlers, adds a connection guard to prevent infinite QR regeneration loops, and adjusts Docker/Docker Compose setup to build locally with tsup and additional Alpine dependencies for Prisma. Sequence diagram for resolving @lid JID on messages.upsertsequenceDiagram
actor WhatsAppServer
participant BaileysStartupService
participant MessagePreparer
participant Chatbot
participant ContactStore
WhatsAppServer->>BaileysStartupService: messages.upsert(received)
BaileysStartupService->>BaileysStartupService: normalize messageTimestamp
alt received.key.remoteJid contains @lid and received.key.remoteJidAlt exists
BaileysStartupService->>BaileysStartupService: set received.key.remoteJid = received.key.remoteJidAlt
end
BaileysStartupService->>BaileysStartupService: check settings.groupsIgnore and @g.us
alt not ignored
BaileysStartupService->>MessagePreparer: prepareMessage(received)
MessagePreparer-->>BaileysStartupService: preparedMessage
BaileysStartupService->>Chatbot: emit message event with normalized remoteJid
BaileysStartupService->>ContactStore: upsert contact with normalized remoteJid
end
Sequence diagram for resolving @lid JID on messages.updatesequenceDiagram
actor WhatsAppServer
participant BaileysStartupService
participant MessageStore
participant Webhook
participant ChatUnreadCounter
WhatsAppServer->>BaileysStartupService: messages.update([{ key, update }])
BaileysStartupService->>MessageStore: findMessageByKeyId(key.id)
MessageStore-->>BaileysStartupService: findMessage
alt key.remoteJid contains @lid
BaileysStartupService->>BaileysStartupService: resolvedRemoteJid = key.remoteJidAlt or findMessage.key.remoteJid or key.remoteJid
else
BaileysStartupService->>BaileysStartupService: resolvedRemoteJid = key.remoteJid
end
alt update.message is null and update.status is undefined
BaileysStartupService->>Webhook: sendDataWebhook(MESSAGES_DELETE, message with resolvedRemoteJid)
else update.status is defined and changed
alt not key.fromMe and resolvedRemoteJid exists
BaileysStartupService->>ChatUnreadCounter: mark chat read for resolvedRemoteJid
alt status is READ
BaileysStartupService->>BaileysStartupService: updateMessagesReadedByTimestamp(resolvedRemoteJid, findMessage.messageTimestamp)
end
end
BaileysStartupService->>Webhook: sendDataWebhook(MESSAGES_UPDATE, message with resolvedRemoteJid)
end
Updated class diagram for BaileysStartupService JID normalization and connection guardclassDiagram
class ChannelStartupService {
}
class BaileysStartupService {
- instance
- instanceId
- logger
+ connectionUpdate(connection, lastDisconnect)
+ onMessagesUpsert(received)
+ onMessagesUpdate(key, update)
+ sendDataWebhook(event, payload)
+ updateMessagesReadedByTimestamp(remoteJid, messageTimestamp)
}
ChannelStartupService <|-- BaileysStartupService
class ConnectionUpdateLogic {
+ shouldReconnect(instance, statusCode) bool
}
class JidNormalizer {
+ normalizeRemoteJidOnUpsert(received) string
+ resolveRemoteJidOnUpdate(key, findMessage) string
}
BaileysStartupService ..> ConnectionUpdateLogic : uses
BaileysStartupService ..> JidNormalizer : uses
Flow diagram for connectionUpdate QR loop guardflowchart TD
A[connectionUpdate receives connection close] --> B[Read lastDisconnect error statusCode]
B --> C{instance.wuid exists?}
C -->|yes| D[Proceed to reconnect evaluation]
C -->|no| E{statusCode exists?}
E -->|no| F[Log and return without reconnect to prevent QR loop]
E -->|yes| D
D --> G[Check codesToNotReconnect]
G --> H{shouldReconnect?}
H -->|yes| I[Reconnect to WhatsApp]
H -->|no| J[Do not reconnect]
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.
Hey - I've found 1 issue, and left some high level feedback:
- The hard-coded
POSTGRES_PASSWORD=090271jdindocker-compose.yamlexposes a real-looking credential; consider reverting to a placeholder or environment-driven secret so sensitive values are not committed. - Switching the Docker build step from
npm run buildto runningtsupdirectly to bypass an existingtscerror may hide real type issues; it would be more robust to fix the underlyingterminateCalltype problem and keep a type-checking step in the build/CI pipeline. - The new
remoteJidAlthandling relies on multiple(key as any)casts; defining a proper type/interface for the message key structure would make this logic safer and easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The hard-coded `POSTGRES_PASSWORD=090271jd` in `docker-compose.yaml` exposes a real-looking credential; consider reverting to a placeholder or environment-driven secret so sensitive values are not committed.
- Switching the Docker build step from `npm run build` to running `tsup` directly to bypass an existing `tsc` error may hide real type issues; it would be more robust to fix the underlying `terminateCall` type problem and keep a type-checking step in the build/CI pipeline.
- The new `remoteJidAlt` handling relies on multiple `(key as any)` casts; defining a proper type/interface for the message key structure would make this logic safer and easier to maintain.
## Individual Comments
### Comment 1
<location path="docker-compose.yaml" line_range="45" />
<code_context>
- 5432:5432
environment:
- - POSTGRES_PASSWORD=PASSWORD
+ - POSTGRES_PASSWORD=090271jd
volumes:
- postgres_data:/var/lib/postgresql/data
</code_context>
<issue_to_address>
**🚨 issue (security):** Hardcoding the Postgres password in docker-compose is a security risk.
Commiting a concrete password in `docker-compose.yaml` increases the risk of secret leakage and complicates rotation. Use an env var, Docker secret, or `.env` file instead (e.g., `POSTGRES_PASSWORD=${POSTGRES_PASSWORD}`) and manage the actual value outside version control.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- Add IMessageRaw interface to properly type prepareMessage() return - Replace unsafe 'key as any' casts with ExtendedIMessageKey - Add MessageBodyWithExtendedKey interface for chatwoot service - Improve code readability with descriptive variable names (pollKey, receivedKey) Addresses Sourcery code review feedback regarding type safety in remoteJidAlt handling. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace literal password with \${POSTGRES_PASSWORD} env var reference.
Password must be set in .env file (already gitignored).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dlers - message-receipt.update: resolve @lid to @s.whatsapp.net before updating read status, ensuring receipts match messages stored with resolved JIDs - contacts.upsert: use lidJidAlt when contact.id contains @lid, so contacts are saved with the correct @s.whatsapp.net JID - contacts.update: same LID resolution for contact updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… LidContact) Addresses Sourcery AI review feedback: introduces LidMessageKey and LidContact interfaces extending Baileys proto types with the LID-specific fields (remoteJidAlt, lidJidAlt), and adds resolveLidJid/resolveLidContact helpers to eliminate all `as any` casts for LID resolution across the codebase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b66926f to
b3b2d24
Compare
…qrcode-loop # Conflicts: # Dockerfile # docker-compose.yaml # src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts # src/api/types/wa.types.ts
…psert
- Add missing `import { createJid }` from @utils/createJid and replace
all `this.createJid()` calls with the imported function (was causing
"this.createJid is not a function" runtime error)
- Fix inverted chat existence check: update existing chat name instead
of trying to create a duplicate (was causing Prisma P2002 unique
constraint errors that blocked webhook delivery to n8n)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
why change the docker compose and docker file? |
|
Hi! As part of our PR triage, we noticed the Check Code Quality workflow has not run on this PR (it requires maintainer approval for first-time external contributors, which we've now enabled). To trigger CI:
Once CI runs and is green I'll re-review for merge. Thanks! |
|
Obrigado pelo trabalho de tipar o tratamento de
Pontos adicionais:
Reabrir depois do rebase e da divisão em 3 PRs focados. |
Transition the codebase from a passive fork of EvolutionAPI/evolution-api (unmaintained since Dec 2025, now closed-source paid product) to a self-maintained internal application. - Add Dependabot config: weekly npm updates (Baileys excluded from auto-bump), monthly GitHub Actions and Docker updates, grouped minor/patch PRs - Add npm audit step to CI with --audit-level=critical (production scope only); high/moderate surface in logs but do not block builds until next Baileys upgrade clears the libsignal-chained backlog - Pin Node 20 LTS via .nvmrc (matches CI) - Update package.json metadata: repository, bugs, homepage, author point to jeandgardany/evolution-api; original author preserved in contributors per Apache-2.0 attribution - Add overrides.protobufjs ^7.6.0 to resolve critical CVEs that come via libsignal-node and have no upstream fix in Baileys yet - npm audit fix applied to lockfile (non-breaking): 74 vulnerabilities to 11, 2 critical to 0 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…support
Several Baileys API changes since the upstream codebase shipped require
adaptation, plus the LID predicate functions need to flow through to read
receipts and outgoing message keys. Also resolves type and lint issues
surfaced by the lockfile refresh from the security baseline.
- fetchStatus now returns an array — index into [0]?.status (2 call sites)
- offerCall / terminateCall lost typed declarations — cast through `any`
- speechToText no longer accepts updateMediaMessage as the 3rd argument
- group-participants.update payload widened with optional `author` and
string[] | any[] participants to accept LID-mode events
- replace isJidUser with isPnUser || isLidUser for participant detection in
outgoing message keys and read-receipt filtering
- relocate ExtendedIMessageKey from whatsapp.baileys.service.ts to
wa.types.ts — types belong in the types module
- add wa namespace fields: ownerJid, wavoipToken; optional
ConfigSessionPhone.VERSION for pinning WA Web version
- cast response.headers['content-type'] to string (3 sites) — axios v1
AxiosHeaderValue is a union; Content-Type is always textual
- convert 9 unused `catch (error)` blocks to ES2019 `catch {}` syntax
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the upstream-oriented CLAUDE.md with a maintenance briefing tailored to the DGGirl deployment: documents the directory layout, message flow, known bugs (QR loop / LID), N8N integration patterns, and the operational checklist for running this codebase as an internally-owned application post-EvolutionAPI's December 2025 sunset. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Olá @jeandgardany, obrigado pela contribuição. O fix de Bloqueantes críticos
Como prosseguirPor favor abra uma nova PR focada contendo apenas: ✅ ❌ Sem Dockerfile, sem docker-compose, sem CLAUDE.md, sem package-lock.json regen Vou fechar esta PR quando você abrir a substituta focada. Obrigado pela contribuição — o trabalho de tipagem de LID é genuinamente útil. |
Telemetry now requires TELEMETRY_URL to be set explicitly. Removes the silent fallback to https://log.evolution-api.com/telemetry so this fork no longer leaks route hits to the abandoned upstream endpoint.
These workflows pushed to evoapicloud/evolution-api on Docker Hub — a registry owned by the original upstream. This fork has no credentials for that org, so the workflows ran red on every release. Local builds via 'docker compose build api' continue to work and remain the only release path until a fork-owned registry is set up.
- index.router root endpoint: 'documentation' field now points to the fork README instead of doc.evolution-api.com (offline). - chatwoot bot contact defaults: generic 'WhatsApp Bot' org name and empty logo URL (Chatwoot falls back to its own placeholder) instead of the EvolutionAPI brand assets.
- README badges, support links, donations and premium support sections removed (all pointed to channels owned by the abandoned upstream). Replaced with a Fork Notice and Support section pointing to the fork's issue tracker and maintainer email. - SECURITY.md and AGENTS.md: contact email switched to the fork maintainer. - Issue templates: removed Discord/WhatsApp support links and updated the prior-issues search to the fork's issue tracker. - package.json: kept Davidson Gomes as historical contributor but removed the upstream email and repo URL (both broken).
The previous Node 20 + 'npm install -f' combination was the residue of a merge-conflict resolution in 9e1e7be that dropped upstream commit 5512585 (Node 20→24 upgrade) and reverted 'npm ci --silent' back to 'npm install -f'. The original justification — masking a tsc error in terminateCall — is no longer relevant: that callsite is already cast to 'any' (whatsapp.baileys.service.ts:1897) and 'tsc --noEmit' now passes clean. Restored: - node:24-alpine (both builder and final stages) - npm ci --silent --ignore-scripts (deterministic install from lockfile; --ignore-scripts skips the husky 'prepare' hook that has no place in a container build) - COPY ./package-lock.json into the builder stage so 'npm ci' can find it Updated image labels to reflect fork ownership (Jean Lima, github.com/jeandgardany, jeandgardany@hotmail.com) and bumped the hard-coded version label from 2.2.0 to match package.json's 2.3.7.
…QR code loop
messages.upsert: mutate received.key.remoteJid to remoteJidAlt when @lid is detected, ensuring prepareMessage, chatbot emit, contact upsert and all downstream uses receive the correct @s.whatsapp.net JID instead of the LID identifier
messages.update: after finding the stored message by key.id, resolve @lid using remoteJidAlt (fork field) or findMessage.key.remoteJid as fallback; applies to DB status update, webhook to N8N, messageUpdate record and chat unread counter
connectionUpdate: guard against infinite QR code regeneration loop when connection closes before QR is scanned (no wuid, no statusCode)
Dockerfile: use tsup directly instead of npm run build to bypass pre-existing tsc type error on terminateCall; add openssl/libc6-compat to Alpine final stage for Prisma compatibility
docker-compose.yaml: switch from remote image to local build so fixes persist across container recreations
📋 Description
🔗 Related Issue
Closes #(issue_number)
🧪 Type of Change
🧪 Testing
📸 Screenshots (if applicable)
✅ Checklist
📝 Additional Notes
Summary by Sourcery
Handle WhatsApp @lid JIDs consistently in message handlers and prevent QR reconnect loops, while updating container build configuration for local builds and Prisma compatibility.
Bug Fixes:
Build:
Deployment:
Chores: