fix(bot): pin Baileys to latest WA Web version + handle smart quotes

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.
This commit is contained in:
yiekheng 2026-05-09 16:28:01 +08:00
parent 33e1fcd2c4
commit 1e3173424a
4 changed files with 19 additions and 4 deletions

View File

@ -3,7 +3,10 @@ import { db } from "../../db.js";
export async function handleGroups(ctx: Context): Promise<void> { export async function handleGroups(ctx: Context): Promise<void> {
const text = ctx.message?.text ?? ""; 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) { if (!label) {
await ctx.reply('Usage: /groups "Account Label"'); await ctx.reply('Usage: /groups "Account Label"');
return; return;

View File

@ -12,7 +12,10 @@ const qrMessageIdByAccount = new Map<string, number>();
export async function handlePair(ctx: Context): Promise<void> { export async function handlePair(ctx: Context): Promise<void> {
const text = ctx.message?.text ?? ""; 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) { if (!label) {
await ctx.reply('Usage: /pair "Account Label"'); await ctx.reply('Usage: /pair "Account Label"');
return; return;

View File

@ -10,7 +10,10 @@ import { writeAuditLog } from "../../audit.js";
export async function handleUnpair(ctx: Context): Promise<void> { export async function handleUnpair(ctx: Context): Promise<void> {
const text = ctx.message?.text ?? ""; 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) { if (!label) {
await ctx.reply('Usage: /unpair "Account Label"'); await ctx.reply('Usage: /unpair "Account Label"');
return; return;

View File

@ -3,6 +3,7 @@ import { join } from "node:path";
import { import {
makeWASocket, makeWASocket,
useMultiFileAuthState, useMultiFileAuthState,
fetchLatestBaileysVersion,
type WASocket, type WASocket,
type ConnectionState, type ConnectionState,
DisconnectReason, DisconnectReason,
@ -34,9 +35,14 @@ export async function startSession(params: {
const { state, saveCreds } = await useMultiFileAuthState(sessionDir); 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({ const socket = makeWASocket({
version,
auth: state, auth: state,
printQRInTerminal: false,
browser: Browsers.macOS("Safari"), browser: Browsers.macOS("Safari"),
syncFullHistory: false, syncFullHistory: false,
logger: logger.child({ accountId, component: "baileys" }) as never, logger: logger.child({ accountId, component: "baileys" }) as never,