Skip to content

fix: route pn sends to mapped lid#2692

Open
frndchagas wants to merge 2 commits into
WhiskeySockets:masterfrom
frndchagas:fix/route-pn-send-to-mapped-lid
Open

fix: route pn sends to mapped lid#2692
frndchagas wants to merge 2 commits into
WhiskeySockets:masterfrom
frndchagas:fix/route-pn-send-to-mapped-lid

Conversation

@frndchagas

@frndchagas frndchagas commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Route 1:1 PN sends to a locally mapped LID when the mapping is already stored.
  • Preserve the original PN as alternate addressing metadata on the local message key and outgoing stanza.
  • Add a local-only LID lookup so sendMessage does not trigger implicit USync for unmapped PN contacts.

Protocol / behavior context

For warm contacts with an existing PN -> LID mapping, Baileys already resolves LID sessions during assertSessions, but the final 1:1 message stanza could still be addressed to the PN. That can produce server-side ERROR 463 for contacts that should be LID-addressed.

This keeps the scope narrow: it only routes sends when a local mapping already exists. Cold/unmapped PN sends keep the existing behavior.

WA Web captured JS sanity

Ran:

./tools/wa-web-sanity.sh 'addressing_mode|recipient_pn|remoteJidAlt|participant_pn|sender_pn|peer_recipient_pn'

Relevant matches from the captured WA Web bundle:

  • WAWeb/Send/MsgCreateFanoutStanza.js
  • WAWeb/Send/MsgCreateDeviceStanza.js
  • WAWeb/Handle/MsgParser.js
  • WAWeb/Send/MsgCommonApi.js

Relevant excerpt:

recipient_pn: ...,
addressing_mode: ...

WA Web emits alternate PN attrs alongside LID addressing, and parses those attrs back on receive.

Live validation note

I attempted a live repro with the contribution test session. The external target checked during validation had no PN -> LID mapping locally or after a deliberate USync lookup, so it did not exercise the reported mapped-LID case. A self-send confirmed local PN -> LID mapping mechanics but did not reproduce ERROR 463, because the old PN path received SERVER_ACK.

So this PR is validated by deterministic tests and WA Web send/parser sanity, not by a confirmed live 463 repro.

Tests

  • yarn lint - 0 errors; existing no-explicit-any warnings remain
  • yarn test - 29 suites / 415 tests passed

Related to #2683
Related to #2688

Drafted with Codex, reviewed and tested by me.


Summary by cubic

Route PN-addressed 1:1 sends to the locally mapped LID when available, and include the PN as alternate addressing metadata. This prevents server 463 failures for warm contacts and avoids implicit USync on send, with added validation and cached-miss handling.

  • Bug Fixes
    • Added local-only lookup getStoredLIDForPN and resolveMessageSendJid to switch PN → LID without USync when a mapping exists.
    • Preserved PN as remoteJidAlt and added stanza attrs addressing_mode: 'lid' and recipient_pn; keep device IDs and hosted vs standard domains.
    • Hardened resolution: validate stored LID users, cache local misses to avoid repeated store reads, and fall back to PN on errors or non-LID values; extended tests for mapped/unmapped, hosted, device-specific, and non-PN sends.

Written for commit 93e8ac6. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Outbound messages to PN and hosted-PN recipients now automatically resolve to the appropriate stored LID destination (when available), including LID addressing metadata.
    • Device-specific LID addressing is applied consistently when deriving LID destinations.
  • Bug Fixes
    • Improved reuse of stored PN→LID lookup results and reduced repeated “missing mapping” checks; misses are cleared when mappings are later stored.
  • Tests
    • Expanded LID-mapping coverage with an in-memory key store and new getStoredLIDForPN scenarios.
    • Added unit tests for resolveMessageSendJid covering success, fallback, and non-PN/LID cases.

@whiskeysockets-bot

Copy link
Copy Markdown
Contributor

Thanks for opening this pull request and contributing to the project!

The next step is for the maintainers to review your changes. If everything looks good, it will be approved and merged into the main branch.

In the meantime, anyone in the community is encouraged to test this pull request and provide feedback.

✅ How to confirm it works

If you’ve tested this PR, please comment below with:

Tested and working ✅

This helps us speed up the review and merge process.

📦 To test this PR locally:

# NPM
npm install @whiskeysockets/baileys@frndchagas/Baileys#fix/route-pn-send-to-mapped-lid

# Yarn (v2+)
yarn add @whiskeysockets/baileys@frndchagas/Baileys#fix/route-pn-send-to-mapped-lid

# PNPM
pnpm add @whiskeysockets/baileys@frndchagas/Baileys#fix/route-pn-send-to-mapped-lid

If you encounter any issues or have feedback, feel free to comment as well.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds cached PN-to-LID lookup helpers in the signal mapping store and uses them to rewrite outbound PN/hosted-PN sends to LID addressing, with tests covering store lookup behavior and message send resolution.

Changes

PN to LID Resolution

Layer / File(s) Summary
LID mapping store helpers and refactor
src/Signal/lid-mapping.ts
Introduces cached PN-miss tracking, device-specific LID construction, and refactors PN lookup and batch resolution to use the new helpers.
LID mapping store tests
src/__tests__/Signal/lid-mapping.test.ts
Expands the store test harness and adds coverage for local lookup, device preservation, hosted LID formatting, malformed values, and cached misses.
resolveMessageSendJid and sendMessage wiring
src/Socket/messages-send.ts
Introduces resolveMessageSendJid and wires sendMessage to use the resolved JID for generation, metadata, and relay.
resolveMessageSendJid tests
src/__tests__/Socket/messages-send.test.ts
Adds tests for mapped, unmapped, hosted, non-PN, and non-LID outcomes of resolveMessageSendJid.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Poem

A PN hops in, unsure of its name,
The burrow maps LIDs just the same.
Cached or found, the path is clear,
Hosted or plain, the send draws near.
🐰📨 Off it goes, addressed just right,
Through LID lanes into the night.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: routing PN sends to a mapped LID.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/__tests__/Signal/lid-mapping.test.ts (1)

25-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a hosted-PN stored lookup case.

The source helper has a new decoded.server === 'hosted' branch, but these tests only cover @s.whatsapp.net. Add one assertion for 12345@hosted -> 98765@hosted.lid so the local-only hosted path is locked down.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/Signal/lid-mapping.test.ts` around lines 25 - 56, The
getStoredLIDForPN tests in lid-mapping.test.ts only cover `@s.whatsapp.net`
inputs, so add a case for the new hosted-PN branch in
lidMappingStore.getStoredLIDForPN. Create an assertion for a stored mapping like
12345@hosted returning 98765@hosted.lid, and verify it still uses the local
lid-mapping lookup path without calling mockPnToLIDFunc.
src/__tests__/Socket/messages-send.test.ts (1)

1-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Solid unit coverage for resolveMessageSendJid; wiring into sendMessage remains untested.

All five branches (mapped PN, unmapped PN, hosted PN→hosted LID, non-PN passthrough, stored-value-not-a-LID) are covered and match the implementation. However, the actual wiring in sendMessage (setting fullMsg.key.remoteJidAlt/addressingMode, calling generateWAMessage/relayMessage with the resolved LID) has no integration test mocking binary nodes/relayMessage. As per path instructions, "New protocol paths or stanza handlers should have integration tests mocking binary nodes, not e2e tests," and this PR changes the outbound stanza addressing path.

Want me to draft an integration test stubbing signalRepository.lidMapping.getStoredLIDForPN and asserting the relayed JID/attrs for a mapped-PN send?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/Socket/messages-send.test.ts` around lines 1 - 65, The unit
tests for resolveMessageSendJid are fine, but the outbound sendMessage wiring
that uses its result is still untested. Add an integration-style test around
sendMessage that mocks generateWAMessage and relayMessage plus
signalRepository.lidMapping.getStoredLIDForPN, then assert the resolved LID is
used for the relayed stanza and that fullMsg.key.remoteJidAlt/addressingMode and
the addressing attributes are set correctly for a mapped PN send.

Source: Path instructions

src/Socket/messages-send.ts (1)

80-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing logger on an async, non-obvious protocol resolution path.

resolveMessageSendJid crosses an async boundary and makes a protocol-relevant decision (rewriting outbound addressing PN→LID), but takes no logger, unlike similar resolution helpers referenced in this same file (e.g. the logger.debug(...) calls around LID/PN identity selection at lines 852-857). Adding a debug log when a PN send is rewritten to LID (and why) would aid diagnosing addressing issues without needing production repro. As per coding guidelines, "Every code path that crosses an async boundary should accept a logger: ILogger (pino-compatible)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Socket/messages-send.ts` around lines 80 - 104, resolveMessageSendJid
currently rewrites PN to LID across an async boundary without any logging, which
makes this protocol decision hard to trace. Update resolveMessageSendJid to
accept a logger: ILogger argument like the other helpers in messages-send.ts,
and add a debug log when a PN/hosted PN JID is resolved to a LID (including the
original jid and the reason it was rewritten or left unchanged). Keep the
logging consistent with the logger.debug usage elsewhere in the file and thread
the logger through any call sites.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/Signal/lid-mapping.test.ts`:
- Around line 27-29: Remove the local TypeScript suppressions in the
`lid-mapping.test.ts` mocks and type the returned values as a keyed record
instead of casting to `SignalDataTypeMap['lid-mapping']`, since that type is
just `string`. Update the `mockKeys.get.mockResolvedValue(...)` call near the
top of the test and apply the same cleanup to the matching `mockKeys.get` mocks
below so the test data matches the actual shape without `@ts-ignore`.

In `@src/Signal/lid-mapping.ts`:
- Around line 35-44: The LID JID builder in lid-mapping should validate the
stored lidUser value more strictly before returning a JID, since
lidUser.toString() only guards against empty strings and can still emit
malformed values. Update the validation in the method that constructs the JID so
it rejects invalid cached/stored user values before composing the final string,
and keep the warning in structured logging form with the object first and
message last in the this.logger.warn call.

---

Nitpick comments:
In `@src/__tests__/Signal/lid-mapping.test.ts`:
- Around line 25-56: The getStoredLIDForPN tests in lid-mapping.test.ts only
cover `@s.whatsapp.net` inputs, so add a case for the new hosted-PN branch in
lidMappingStore.getStoredLIDForPN. Create an assertion for a stored mapping like
12345@hosted returning 98765@hosted.lid, and verify it still uses the local
lid-mapping lookup path without calling mockPnToLIDFunc.

In `@src/__tests__/Socket/messages-send.test.ts`:
- Around line 1-65: The unit tests for resolveMessageSendJid are fine, but the
outbound sendMessage wiring that uses its result is still untested. Add an
integration-style test around sendMessage that mocks generateWAMessage and
relayMessage plus signalRepository.lidMapping.getStoredLIDForPN, then assert the
resolved LID is used for the relayed stanza and that
fullMsg.key.remoteJidAlt/addressingMode and the addressing attributes are set
correctly for a mapped PN send.

In `@src/Socket/messages-send.ts`:
- Around line 80-104: resolveMessageSendJid currently rewrites PN to LID across
an async boundary without any logging, which makes this protocol decision hard
to trace. Update resolveMessageSendJid to accept a logger: ILogger argument like
the other helpers in messages-send.ts, and add a debug log when a PN/hosted PN
JID is resolved to a LID (including the original jid and the reason it was
rewritten or left unchanged). Keep the logging consistent with the logger.debug
usage elsewhere in the file and thread the logger through any call sites.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 025bb378-278e-44f6-b2c1-87c1c385b6bf

📥 Commits

Reviewing files that changed from the base of the PR and between 731cd6b and 7f12e85.

📒 Files selected for processing (4)
  • src/Signal/lid-mapping.ts
  • src/Socket/messages-send.ts
  • src/__tests__/Signal/lid-mapping.test.ts
  • src/__tests__/Socket/messages-send.test.ts

Comment thread src/__tests__/Signal/lid-mapping.test.ts Outdated
Comment thread src/Signal/lid-mapping.ts Outdated
Comment thread src/Socket/messages-send.ts
@frndchagas frndchagas marked this pull request as ready for review July 4, 2026 16:48

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/Signal/lid-mapping.ts
@freefugga

Copy link
Copy Markdown

Tested and working ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

3 participants