From 1e3173424a9c474caa99146a81d2b7e4efa671f4 Mon Sep 17 00:00:00 2001 From: yiekheng Date: Sat, 9 May 2026 16:28:01 +0800 Subject: [PATCH] fix(bot): pin Baileys to latest WA Web version + handle smart quotes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two pairing-flow fixes after live test: - Connection Failure during pairing: Baileys announced a stale WhatsApp Web version that the server rejected before the QR was emitted. Pull the current version via fetchLatestBaileysVersion() at session start. - Telegram mobile auto-converts straight quotes to curly quotes, so labels like /pair "test 1" arrived as “test 1” and the curly quotes were never stripped. Extend the quote-stripping regex on /pair, /unpair, /groups. --- apps/bot/src/telegram/commands/groups.ts | 5 ++++- apps/bot/src/telegram/commands/pair.ts | 5 ++++- apps/bot/src/telegram/commands/unpair.ts | 5 ++++- apps/bot/src/whatsapp/session.ts | 8 +++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/bot/src/telegram/commands/groups.ts b/apps/bot/src/telegram/commands/groups.ts index 72d406a..cd43fda 100644 --- a/apps/bot/src/telegram/commands/groups.ts +++ b/apps/bot/src/telegram/commands/groups.ts @@ -3,7 +3,10 @@ import { db } from "../../db.js"; export async function handleGroups(ctx: Context): Promise { const text = ctx.message?.text ?? ""; - const label = text.replace(/^\/groups\s*/, "").trim().replace(/^["']|["']$/g, ""); + const label = text + .replace(/^\/groups\s*/, "") + .trim() + .replace(/^["'“”‘’]|["'“”‘’]$/g, ""); if (!label) { await ctx.reply('Usage: /groups "Account Label"'); return; diff --git a/apps/bot/src/telegram/commands/pair.ts b/apps/bot/src/telegram/commands/pair.ts index 66f88d7..029b009 100644 --- a/apps/bot/src/telegram/commands/pair.ts +++ b/apps/bot/src/telegram/commands/pair.ts @@ -12,7 +12,10 @@ const qrMessageIdByAccount = new Map(); export async function handlePair(ctx: Context): Promise { const text = ctx.message?.text ?? ""; - const label = text.replace(/^\/pair\s*/, "").trim().replace(/^["']|["']$/g, ""); + const label = text + .replace(/^\/pair\s*/, "") + .trim() + .replace(/^["'“”‘’]|["'“”‘’]$/g, ""); if (!label) { await ctx.reply('Usage: /pair "Account Label"'); return; diff --git a/apps/bot/src/telegram/commands/unpair.ts b/apps/bot/src/telegram/commands/unpair.ts index a3079a6..d3b2c8c 100644 --- a/apps/bot/src/telegram/commands/unpair.ts +++ b/apps/bot/src/telegram/commands/unpair.ts @@ -10,7 +10,10 @@ import { writeAuditLog } from "../../audit.js"; export async function handleUnpair(ctx: Context): Promise { const text = ctx.message?.text ?? ""; - const label = text.replace(/^\/unpair\s*/, "").trim().replace(/^["']|["']$/g, ""); + const label = text + .replace(/^\/unpair\s*/, "") + .trim() + .replace(/^["'“”‘’]|["'“”‘’]$/g, ""); if (!label) { await ctx.reply('Usage: /unpair "Account Label"'); return; diff --git a/apps/bot/src/whatsapp/session.ts b/apps/bot/src/whatsapp/session.ts index c0e7940..52f7314 100644 --- a/apps/bot/src/whatsapp/session.ts +++ b/apps/bot/src/whatsapp/session.ts @@ -3,6 +3,7 @@ import { join } from "node:path"; import { makeWASocket, useMultiFileAuthState, + fetchLatestBaileysVersion, type WASocket, type ConnectionState, DisconnectReason, @@ -34,9 +35,14 @@ export async function startSession(params: { const { state, saveCreds } = await useMultiFileAuthState(sessionDir); + // Fetch the WhatsApp Web version Baileys should announce. Without this, + // the noise handshake fails because WA's server-side rejects stale versions. + const { version, isLatest } = await fetchLatestBaileysVersion(); + logger.info({ accountId, version, isLatest }, "session: using WA Web version"); + const socket = makeWASocket({ + version, auth: state, - printQRInTerminal: false, browser: Browsers.macOS("Safari"), syncFullHistory: false, logger: logger.child({ accountId, component: "baileys" }) as never,