chore: update WhatsApp Web version to v2.3000.1040994085#517
Conversation
|
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 worksIf you’ve tested this PR, please comment below with: This helps us speed up the review and merge process. 📦 To test this PR locally:If you encounter any issues or have feedback, feel free to comment as well. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR updates the WhatsApp Web revision number in ChangesVersion Revision Update
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Comment |
There was a problem hiding this comment.
Pull request overview
This PR performs the daily automated bump of the WhatsApp Web client revision used by the codebase by updating the single source of truth in src/Defaults/baileys-version.json.
Changes:
- Updated the WhatsApp Web version tuple to
2.3000.1040994085. - Normalized
baileys-version.jsonformatting to the compact JSON form produced by the update script.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…bumps (#549) * fix(memory): handle ECACHEFULL on userDevicesCache.set in device-notif path (#513 review) PR #513 chatgpt-codex review (P2) caught a real gap that PR #509 introduced when it added the `maxKeys` cap to `userDevicesCache`: - PR #509 added `safeCacheSet` handling to the cache-population path in `messages-send.ts:528-548` (where USync fills the cache). - The OTHER call-site that writes to `userDevicesCache` — `messages-recv.ts:2240` in the device-notification handler ('add' / 'remove' tags) — was left unprotected. `@cacheable/node-cache`'s capacity check is `keyCount() + 1 > maxKeys` — applied BEFORE the engine checks whether the key already exists. So once the cache reaches its `maxKeys` ceiling (5,000 entries), even an UPDATE to an already-cached user throws ECACHEFULL. The guard `if (!existingCache.length) continue` at line 2210 doesn't help: it only short-circuits when the user is NOT cached. A device-list update for an already-cached user would still hit the `.set` and throw. Real impact under sustained gateway load: - Cache hits 5,000 entries (a few dozen active groups will get there). - A device-add/remove notification arrives for one of the cached users. - `userDevicesCache.set(...)` throws ECACHEFULL. - The throw propagates into the message-receive handler and lands in Baileys' outer error boundary — connection survives, but a log-level error is emitted and the affected user's device list is NOT updated in the cache. - Next message-send for that user fetches the fresh list via USync (`getUSyncDevices`), which IS guarded — so the durable behavior eventually recovers. The fix routes the device-notif write through the same `safeCacheSet` helper PR #509 used in messages-send.ts. Same swallow-ECACHEFULL semantics, same debug log, same `getUSyncDevices` fallback path. Symmetric handling across the two call-sites that update the cache. Test plan: - npm run build ✓ (3 phases pass, zero errors) - 1 line of production change in `messages-recv.ts:2240`, plus comment explaining the WHY. No test changes needed — `safeCacheSet`'s behavior is already covered by `cache-utils.test.ts`. Out of scope (intentionally NOT touched): - Carousel, lists, buttons, polls, view-once, biz quality_control, useLegacyLock, TC token custom flow, LID↔PN batched, Phase 9 multi-DB, lidDbMigrated:false, the cacheMetricsInterval memory-leak fix, schema migrations + statement cache + busy retry. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: update proto/version to v2.3000.1040989513 (#516) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1040994085 (#517) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(audit #521): 3 P2 + 2 P3 from chatgpt/copilot/coderabbit review 5 findings from the release PR #521 audit applied before promoting develop → master. The release branch itself doesn't change; this PR lands the fixes on develop and the release branch will be refreshed to include them. P2 — Thread 1 (chatgpt) — reporting-token check reads outer wrap ================================================================ `messages-send.ts:1884` gated reporting-token attachment on `reportingMessage?.messageContextInfo?.messageSecret`. For Lottie stickers post-PR #519 that secret lives INSIDE the `lottieStickerMessage` wrap — the top-level read returns undefined and the token is silently skipped. Regression vs plain sticker behaviour. Fix: lift `messageContextInfo` from both locations the same way the initial-fanout DSM read does (the lift PR #519 already shipped on line ~1198): const reportingMessageSecret = reportingMessage?.lottieStickerMessage?.message ?.messageContextInfo?.messageSecret ?? reportingMessage?.messageContextInfo?.messageSecret Required adding `reportingMessage &&` to the surrounding `if` so TypeScript doesn't lose the narrowing it previously got from the inline property chain (the narrowing was the side-effect of reading `reportingMessage.messageContextInfo` in the condition itself). P2 — Thread 5 (coderabbit Major) — retry-resend DSM drops messageContextInfo ============================================================================ `messages-send.ts:1580` rebuilds the `deviceSentMessage` envelope on the retry-resend path WITHOUT carrying `messageContextInfo` along. The initial-fanout path got the lift in PR #519 (line ~1198); the retry path was missed. Concrete impact: when a companion device receives the RETRY of a Lottie sticker via DSM, our own `unwrapDeviceSentMessage` finds: - inner = messageToSend = { lottieStickerMessage: { message: { stickerMessage, messageContextInfo } } } - inner.messageContextInfo = undefined (it's nested in the wrap) - outer.messageContextInfo = undefined (the retry envelope omitted it) → messageSecret = undefined, reporting token / encrypted-edit decryption material lost on the companion's copy. Fix: same lift inline at the retry envelope build site. P2 — Thread 2 (chatgpt) — OrphanMsmsgError stub goes to Signal retry path ========================================================================= When `decryptMsmsgBotMessage` raises `OrphanMsmsgError` (cache miss), the catch in `decode-wa-message.ts` sets `messageStubType = CIPHERTEXT` and `messageStubParameters[0] = String(err.message)`. The receive handler at `messages-recv.ts:3115` checks for known stub-param strings and falls through to the Signal retry / PDO placeholder-resend path when none match — burning retry budget asking the bot for prekeys it has no business issuing, for a problem (missing CACHE entry) that a Signal retry can never fix. Fix: add a guard for `messageStubParameters[0]?.startsWith('decryptMsmsgBotMessage:')` right after the `MISSING_KEYS_ERROR_TEXT` branch. Plain ACK (no NACK, no retry) so the server considers the message delivered. The next bot reply that arrives after the outgoing-secret cache populates will decrypt cleanly. NOT a NACK MissingMessageSecret: that would tell the server to retransmit, and the retransmission will hit the same orphan state until the outgoing-side cache is populated (deferred per PR #518). P3 — Thread 4 (copilot) — `__internal` export not consumed ========================================================== `src/Utils/meta-ai-msmsg.ts` exported an `__internal` bag of helpers (`BOT_MESSAGE_INFO`, `KEY_LENGTH`, `isMeJid`, `deriveKeyAndDecrypt`, `decodeDecryptedMsmsg`, `userOnlyJid`, `isJidGroup`) that no file in the repo actually imports. Grep confirms zero call sites. Removed — the helpers stay module-private as intended. P3 — Thread 3 (copilot) — `(err as any)?.message` in auth-utils =============================================================== `src/Utils/auth-utils.ts:714` (the trace I added in PR #515 to log `transactWith rolled back` without duplicating the stack) used a plain `(err as any)?.message` cast. Tightened to `err instanceof Error ? err.message : String(err)` — no runtime change, just removes the `any` cast and gives string fallback for non-Error throws. Validation ========== * `npm run build` clean (TS narrowing fixed via explicit `reportingMessage &&` guard). * 57/57 tests pass across the new-PR suites (dsm-context-info-preservation + meta-ai-msmsg + lottie-sticker-message + error-log-utils + process-message.protocol-guard). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(audit #521): close cubic threads 8 + 9 (Issues D, E) Two findings from the cubic re-review on PR #521 that the previous audit-fix commit (cherry-picked from closed PR #522) didn't cover. Issue D (P2) — test re-implemented production helper ==================================================== cubic thread 8: `dsm-context-info-preservation.test.ts` kept a local copy of `unwrapDeviceSentMessage` and asserted against it. Comment claimed "if rules change in decode-wa-message.ts these break first" but that was wrong — the assertions tested the LOCAL copy, not production. Reverting `decode-wa-message.ts` to the old `msg = msg.deviceSentMessage?.message || msg` would leave all 10 tests green. The tests were validating themselves. Fix: * `decode-wa-message.ts` — flipped the helper from module-private `const` to `export const unwrapDeviceSentMessage`. The function is a leaf utility; exporting it surfaces nothing operational beyond what tests need. * `dsm-context-info-preservation.test.ts` — deleted the re-derived copy, imported from `../../Utils/decode-wa-message`. Header comment updated to explain WHY we now import (production parity) instead of re-derive. Issue E (P3) — `if (!err)` too broad in compactError ==================================================== cubic thread 9: `error-log-utils.ts:33` short-circuited every falsy input (including `0`, `''`, `false`, `NaN`) to the literal string `'Unknown'`. Those are unusual but valid thrown values — code that does `throw 0` would get its actual value erased. Operational impact near zero (Signal Protocol throws `Error` instances), but the contract is wrong. Fix: * `error-log-utils.ts` — `if (!err)` → `if (err == null)`. Comment added explaining the nullish-only narrowing. * `error-log-utils.test.ts` — new test `preserves falsy primitives that are NOT null/undefined` pins the new contract: `compactError(0)` → `'0'`, `compactError(false)` → `'false'`, etc. Validation ========== * `npm run build` clean * 58/58 tests pass (5 suites: dsm-context-info + error-log-utils + meta-ai-msmsg + lottie-sticker-message + process-message). Was 57; +1 from the new falsy-primitives test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(lint): satisfy eqeqeq + remove unused isJidGroup import CI lint failed on the previous commit: - error-log-utils.ts:36 — `if (err == null)` violated the codebase's `eqeqeq` rule even though `== null` is the idiomatic nullish check. Expanded to `if (err === null || err === undefined)` for the same semantics with strict-equality compliance. - meta-ai-msmsg.ts:46 — `isJidGroup` was imported but its only consumer (the now-removed `__internal` export bag from cubic audit thread 4) is gone. Removed from the import list. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(audit #521): close cubic thread 13 — narrow OrphanMsmsg guard cubic re-review (thread 13, confidence 9) caught that the previous ACK guard was too broad: if (msg?.messageStubParameters?.[0]?.startsWith('decryptMsmsgBotMessage:')) `decryptMsmsgBotMessage` throws with a `decryptMsmsgBotMessage:` prefix for several distinct conditions, not just `OrphanMsmsgError`: - `'decryptMsmsgBotMessage: no messageSecret for ${cacheKey}'` ← OrphanMsmsgError — cache miss, ACK + wait for cache to populate - `'decryptMsmsgBotMessage: missing meta.target_id'` ← malformed stanza — deserves NACK/retry - `'decryptMsmsgBotMessage: MessageSecretMessage missing encIv/encPayload'` ← malformed proto — deserves NACK/retry - real AES-GCM auth-tag mismatch (string varies but may also start with `decryptMsmsgBotMessage:` if wrapped) ← deserves the Signal retry path The broader prefix silently ACK'd all of those, hiding real protocol failures from the server-side retry machinery. Narrow the match to the exact substring that uniquely identifies the orphan-cache case: startsWith('decryptMsmsgBotMessage: no messageSecret for ') Other `decryptMsmsgBotMessage:` failures now flow normally to the Signal retry / PDO placeholder-resend path (where they belong). Comment expanded to document why the narrow match is required. Validation: * build clean * 58/58 tests still pass Thread 12 (P3) — `String(err)` in auth-utils.ts:714 — is cosmetic and deferred per the audit recommendation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: update proto/version to v2.3000.1041008395 (#524) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1041011968 (#525) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore: update proto/version to v2.3000.1041063798 (#527) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1041103517 (#528) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore: update proto/version to v2.3000.1041168064 (#530) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1041187577 (#531) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore: update proto/version to v2.3000.1041257863 (#539) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1041271747 (#540) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore: update proto/version to v2.3000.1041336118 (#541) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1041353304 (#542) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore: update proto/version to v2.3000.1041410692 (#543) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1041420778 (#544) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(PR #546 audit): tr range BLOCKER + 5 VoIP P1s + JID-HOSTED-P2 + 4 P2/P3 polish Round-6 audit on the release branch flagged 1 blocker and 9 real findings. All applied directly on this branch so the PR merges into master clean. ## BLOCKER — `update-proto.yml` `tr` character class `tr -cd 'A-Za-z0-9:/?&=._-+~%#'` parses `_-+` as a range from `_` (0x5F) to `+` (0x2B), which GNU `tr` rejects with "reverse collating sequence order" and exits 1. The Summary step would crash on every auto-update run, breaking the entire `update-proto` pipeline that lands in master. Move the `-` to the end of the class so it's interpreted literally. ## VoIP P1s (5) bridge.ts — `#sendBatchEncryptedCall` no longer pushes the stanza when ANY destination failed to encrypt. Earlier the loop stripped `enc` from every destination on a single failure but then fell through to `sendCallStanza`, delivering a key-less offer that the peer couldn't decrypt — call setup failed silently. wasm-engine/instance.ts — three independent issues: (a) `#registerGlobalCallbacks` is no longer gated on a static flag. The map of listeners held closures over `this.#config.callbacks`, so a reconnect-after-disconnect routed events to handlers from the destroyed instance. `destroy()` now clears the static map and the init path always re-registers against the live instance. (b) `initVoipStack`'s outer catch no longer hides errors. The stack now records the failure in `#voipStackInitError`, and `waitForVoipStackReady()` re-throws it on the consumer side instead of silently resolving as "ready". (c) `#loadWasmModuleToWorker` arms a 30 s timeout that rejects the load promise. Without it, a worker that crashed before sending its `loaded` message left the engine init hanging forever. index.ts — `disconnect()` now detaches the `'CB:call'` and `'CB:receipt'` listeners it installed on `this.#sock.ws` before nulling the engine refs. Earlier the listeners outlived the engine, and an in-flight stanza would call into a torn-down `this.#engine`, throwing into the host process. ## JID-HOSTED-P2 (5 locations) bridge.ts (4) + index.ts (1) used `endsWith('@lid')` to gate LID handling, which silently rewrote `*.@hosted.lid` accounts (device 99) as PNs. Switched to `decoded.server` lookup in `bridge.ts` (the JID is already decoded right above each check) and an explicit `'@hosted.lid'` branch in `index.ts`. ## P2/P3 polish (4) lid-mapping-backend.ts (MDB-UNCACHED-P2) — `getAllLidsForPn` now uses a cached `selectAllLidsByPn` statement instead of compiling SQL per call. Same hot-path optimisation that was already in place for `deleteMapping`. env-utils.ts (ENV-TRIM-P2) — `intFromEnv` and `floatFromEnv` now `.trim()` before the empty-string check. A `KEY= ` env var with only whitespace used to slip past `=== ''` and `Number(' ')` returned 0, masquerading as a legitimate zero config. keys-with-jid-map.ts (COMMENT-BESTEFF-P3) — comment said the try/catch was "best-effort" but the catch arm always rethrows. Rewritten to match what the code actually does: the wrapper exists only to classify SQLITE_BUSY vs other errors. prometheus-metrics.ts (COMMENT-PORT-P3) — comment claimed `≥1024 unprivileged` but `intFromEnv(..., 1)` allows privileged ports too. Rewritten to acknowledge `min=1` is just "not zero / not negative" so operators running as root can bind to a privileged port if desired. ## Validation - `tsc --noEmit -p tsconfig.json` exit 0 - `eslint` on all 7 touched files: 0 errors after prettier autofix - Local jest: 2 pre-existing failures in `multi-db-backends.test.ts` and `multi-db-sqlite-auth-state.test.ts` are missing `better-sqlite3` native binding on Windows toolchain — CI Linux is the gate, those pass there. ## Customizations untouched Carousel, list, button, poll, view-once, biz quality_control, Lottie wrap, Meta AI msmsg, DSM, TC token, LID↔PN batched, Phase 9 multi-DB, useLegacyLock, schema migrations, memory leak fix — all unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: update proto/version to v2.3000.1041433777 (#547) Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> * chore: update WhatsApp Web version to v2.3000.1041437765 (#548) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(audit r6): FU-04 varint 5-byte overflow + FU-06 port upper-bound + FU-03 reverse-delete forward cleanup Round-6 audit of PR #546 surfaced 9 follow-up items. After case-by-case validation, 3 are real and acionable, 6 are intentional non-fixes — documented below. ## Applied (3) FU-04 — `libsignal.ts` varint 5-byte overflow The earlier round-5 fix rejected 6-byte varints via `shift >= 35`. This closes the remaining loophole: a 5-byte varint whose 5th byte has the top nibble set (`byte & 0xf0`) encodes a value > 2³² – 1 that `>>> 0` silently masks into a valid-looking uint32. Reject it explicitly at `shift === 28` before the bitwise-or runs. FU-06 — `prometheus-metrics.ts` port upper-bound `intFromEnv` gained an optional `max` parameter (default `Number.MAX_SAFE_INTEGER`, so existing call sites are unaffected). Prometheus port now passes `max=65535` so a `BAILEYS_PROMETHEUS_PORT=99999` falls back to the default `9092` instead of reaching `server.listen()` with an out-of-range integer. FU-03 — `keys-with-jid-map.ts` reverse-delete forward cleanup Reverse delete (`${lid}_reverse → null`) wiped the typed `jid_map` row and the inner store's `_reverse` entry but left any legacy forward entry `pnUser → lidUser` in the inner store. A subsequent `inner.get('lid-mapping', [pnUser])` would then resurrect the just-deleted LID via the fallback path. We now resolve the PN synchronously via `jidMap.getPnForLid(lidUser)` and queue its forward delete on the same pass. ## NOT applied (with reasons) FU-01 — pinning `actions/setup-node@v4` etc. to immutable SHAs The project's policy treats first-party GitHub Actions (`actions/*`) as trusted via major tag and pins only third-party actions by SHA (see `meeDamian/github-release@7ae19492...` in publish-release.yml). Changing only `setup-node` would be inconsistent. If the policy changes, this should be applied to all `actions/*` references in one pass — out of scope for this release. FU-02 / FU-05 — `audio-feeder.ts` emission loop + `disconnect()` ffmpeg Both touch the VoIP audio-capture lifecycle. The current behaviour (loop stops with ffmpeg, child process left to its natural exit) is intentional for the silence-source path and the finite-source path has a documented limitation. A proper fix needs E2E coverage of the capture state machine first — left as a tracked follow-up. FU-07 — `worker-modules.js` flatMap polyfill + WebCodecs check `worker-modules.js` is vendored verbatim from WhatsApp Web's bundle (Meta source). Patching it would create permanent divergence and break our ability to refresh the bundle on schema bumps. The `worker-bootstrap.ts` shim already polyfills `window`, so the WebCodecs throw doesn't fire in practice. FU-08 — `relay-transport.ts:327` early-packet migration Migrating buffered packets from a placeholder connection to the canonical connection after `updateRelayList()` is a multi-week redesign of the relay handshake. Edge case in early-init; deferred. FU-09 — `worker-bootstrap.ts:445` `importScripts` CWD fallback Only fires when the vendored loader.js calls `importScripts` with a relative URL — never observed in practice in the WASM bundle we ship. MAC stream verification at `final()` only — design trade-off Documented in `messages-media.ts`. Buffering the entire decrypted payload until the MAC verifies would defeat the purpose of streaming downloads. The PR moved the project from "no MAC check at all" to "MAC check at final()", which is a strict improvement. A "verify-before-emit" mode could be added later as opt-in for callers who can afford the buffering. ## Validation - `tsc --noEmit -p tsconfig.json` exit 0 - `eslint` on touched files: 0 errors - `intFromEnv` change is backward-compatible (new `max` defaults to `MAX_SAFE_INTEGER`); all existing call sites (auth, retry, batching) retain their behaviour. ## Customizations untouched Carousel, list, button, poll, view-once, biz quality_control, Lottie wrap, Meta AI msmsg, DSM, TC token, LID↔PN batched, Phase 9 multi-DB, useLegacyLock, schema migrations, memory leak fix — unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: rsalcara <rsalcara@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Automated WhatsApp Web version update.
This PR updates the WhatsApp Web client revision to the latest version fetched from
web.whatsapp.com.Version:
2.3000.1040994085Single source of truth:
src/Defaults/baileys-version.json(other files import from here)Update frequency: Daily at 09:00 UTC
Summary by cubic
Updates the WhatsApp Web client version to 2.3000.1040994085 to match web.whatsapp.com and maintain compatibility. Single source of truth updated in
src/Defaults/baileys-version.json.Written for commit c44f56a. Summary will update on new commits.
Summary by CodeRabbit