From b9f4355df251f89a241e24ab4fefef0c53d3c005 Mon Sep 17 00:00:00 2001 From: Berg Pinheiro Date: Tue, 28 Jul 2026 22:18:20 -0300 Subject: [PATCH] fix(NOWEB): resolve WhatsApp Web version instead of using the stale bundled default The version baked into the pinned Baileys fork goes stale whenever WhatsApp bumps the version it accepts server-side, breaking every NOWEB session at once (STARTING -> FAILED). Resolve it in priority order: WAHA_NOWEB_WA_VERSION env var, then Baileys' own fetchLatestBaileysVersion() (cached per process, falls back to the bundled default on failure). --- src/core/engines/noweb/session.noweb.core.ts | 12 +++- src/core/engines/noweb/utils.ts | 68 +++++++++++++++++++- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/core/engines/noweb/session.noweb.core.ts b/src/core/engines/noweb/session.noweb.core.ts index f61ca6125..06c0c5f85 100644 --- a/src/core/engines/noweb/session.noweb.core.ts +++ b/src/core/engines/noweb/session.noweb.core.ts @@ -62,6 +62,7 @@ import { } from '@waha/core/engines/noweb/noweb.newsletter'; import { NowebAuthFactoryCore } from '@waha/core/engines/noweb/NowebAuthFactoryCore'; import { NowebInMemoryStore } from '@waha/core/engines/noweb/store/NowebInMemoryStore'; +import { resolveWaVersion } from '@waha/core/engines/noweb/utils'; import { NotImplementedByEngineError } from '@waha/core/exceptions'; import { toVcardV3 } from '@waha/core/vcard'; import { createAgentProxy } from '@waha/core/helpers.proxy'; @@ -355,7 +356,10 @@ export class WhatsappSessionNoWebCore extends WhatsappSession { await this.sock?.logout(); } - getSocketConfig(agents: Agents | undefined, state): Partial { + async getSocketConfig( + agents: Agents | undefined, + state, + ): Promise> { // Detect browser let browser = ['Ubuntu', 'Chrome', '22.04.4'] as WABrowserDescription; let deviceName = @@ -391,6 +395,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession { if (markOnlineOnConnect == undefined) { markOnlineOnConnect = true; } + const version = await resolveWaVersion(this.engineLogger); return { agent: agents?.socket, // Baileys media upload uses Node https.request in Node runtime. @@ -407,6 +412,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession { msgRetryCounterCache: this.msgRetryCounterCache, placeholderResendCache: this.placeholderResendCache, markOnlineOnConnect: markOnlineOnConnect, + ...(version ? { version } : {}), }; } @@ -425,10 +431,10 @@ export class WhatsappSessionNoWebCore extends WhatsappSession { } const { state, saveCreds } = this.authNOWEBStore; const agents = this.makeProxyAgents(); - const socketConfig: SocketConfig = this.getSocketConfig( + const socketConfig: SocketConfig = (await this.getSocketConfig( agents, state, - ) as SocketConfig; + )) as SocketConfig; const sock = makeWASocket(socketConfig); sock.ev.on('creds.update', saveCreds); return sock; diff --git a/src/core/engines/noweb/utils.ts b/src/core/engines/noweb/utils.ts index 3ee74a9f2..78c2ced8a 100644 --- a/src/core/engines/noweb/utils.ts +++ b/src/core/engines/noweb/utils.ts @@ -1,6 +1,72 @@ -import type { proto } from '@adiwajshing/baileys'; +import type { proto, WAVersion } from '@adiwajshing/baileys'; +import { fetchLatestBaileysVersion } from '@adiwajshing/baileys'; +import type { ILogger } from '@adiwajshing/baileys/lib/Utils/logger'; import esm from '@waha/vendor/esm'; +/** + * The WhatsApp Web version baked into the bundled Baileys fork can go stale + * whenever WhatsApp bumps the version its servers accept, breaking every + * NOWEB session at once (connections stuck in STARTING -> FAILED). Resolve + * it in priority order so operators aren't stuck waiting for a WAHA release: + * 1. WAHA_NOWEB_WA_VERSION env var, e.g. "2,3000,1037641644" + * 2. Auto-detected latest version (cached per process; Baileys itself + * falls back to its bundled default if the fetch fails) + */ +const AUTO_VERSION_TTL_MS = 60 * 60 * 1000; // 1h +let cachedAutoVersion: { version: WAVersion; fetchedAt: number } | null = + null; + +export async function resolveWaVersion( + logger: ILogger, +): Promise { + const envVersion = process.env.WAHA_NOWEB_WA_VERSION; + if (envVersion) { + const parsed = envVersion.split(',').map((part) => Number(part.trim())); + if (parsed.length === 3 && parsed.every((n) => Number.isFinite(n))) { + logger.info( + { version: parsed }, + 'Using WhatsApp Web version from WAHA_NOWEB_WA_VERSION', + ); + return parsed as WAVersion; + } + logger.warn( + `Ignoring WAHA_NOWEB_WA_VERSION="${envVersion}" - expected "major,minor,patch", e.g. "2,3000,1037641644"`, + ); + } + + const now = Date.now(); + if ( + cachedAutoVersion && + now - cachedAutoVersion.fetchedAt < AUTO_VERSION_TTL_MS + ) { + logger.debug( + { version: cachedAutoVersion.version }, + 'Using cached auto-detected WhatsApp Web version', + ); + return cachedAutoVersion.version; + } + + try { + const { version, isLatest } = await fetchLatestBaileysVersion(); + cachedAutoVersion = { version, fetchedAt: now }; + if (isLatest) { + logger.info({ version }, 'Auto-detected latest WhatsApp Web version'); + } else { + logger.warn( + { version }, + 'Could not auto-detect the latest WhatsApp Web version, using the bundled default - set WAHA_NOWEB_WA_VERSION to pin one explicitly', + ); + } + return version; + } catch (err) { + logger.warn( + { err }, + 'Failed to resolve WhatsApp Web version, falling back to the Baileys default', + ); + return undefined; + } +} + export function extractMediaContent( content: any | proto.IMessage | null | undefined, ) {