fix: flush creds queue before reconnect socket open (#67464) (thanks @neeravmakwana)

* WhatsApp: flush creds queue before reconnect socket open

* fix: flush creds queue before reconnect socket open (#67464) (thanks @neeravmakwana)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
Neerav Makwana
2026-04-16 00:46:00 -04:00
committed by GitHub
parent 78df859e15
commit 405c63fb32
3 changed files with 39 additions and 7 deletions

View File

@@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai
- Dashboard: constrain exec approval modal overflow on desktop so long command content no longer pushes action buttons out of view. (#67082) Thanks @Ziy1-Tan.
- Agents/CLI transcripts: persist successful CLI-backed turns into the OpenClaw session transcript so google-gemini-cli replies appear in session history and the Control UI again. (#67490) Thanks @obviyus.
- Discord/tool-call text: strip standalone Gemma-style `<function>...</function>` tool-call payloads from visible assistant text without truncating prose examples or trailing replies. (#67318) Thanks @joelnishanth.
- WhatsApp/web-session: drain the pending per-auth creds save queue before reopening sockets so reconnect-time auth bootstrap no longer races in-flight `creds.json` writes and falsely restores from backup. (#67464) Thanks @neeravmakwana.
## 2026.4.15-beta.1

View File

@@ -1,20 +1,35 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { getRegisteredWhatsAppConnectionController } from "./connection-controller-registry.js";
import { WhatsAppConnectionController } from "./connection-controller.js";
import { createWaSocket, waitForWaConnection } from "./session.js";
import {
createWaSocket,
waitForCredsSaveQueueWithTimeout,
waitForWaConnection,
} from "./session.js";
vi.mock("./session.js", async () => {
const actual = await vi.importActual<typeof import("./session.js")>("./session.js");
return {
...actual,
createWaSocket: vi.fn(),
waitForCredsSaveQueueWithTimeout: vi.fn(async () => {}),
waitForWaConnection: vi.fn(),
};
});
const createWaSocketMock = vi.mocked(createWaSocket);
const waitForCredsSaveQueueWithTimeoutMock = vi.mocked(waitForCredsSaveQueueWithTimeout);
const waitForWaConnectionMock = vi.mocked(waitForWaConnection);
function createListenerStub(messageId = "ok") {
return {
sendMessage: vi.fn(async () => ({ messageId })),
sendPoll: vi.fn(async () => ({ messageId })),
sendReaction: vi.fn(async () => {}),
sendComposingTo: vi.fn(async () => {}),
};
}
describe("WhatsAppConnectionController", () => {
let controller: WhatsAppConnectionController;
@@ -66,6 +81,26 @@ describe("WhatsAppConnectionController", () => {
expect(controller.getActiveListener()).toBeNull();
});
it("flushes pending creds saves before opening a socket", async () => {
const callOrder: string[] = [];
waitForCredsSaveQueueWithTimeoutMock.mockImplementationOnce(async () => {
callOrder.push("wait");
});
createWaSocketMock.mockImplementationOnce(async () => {
callOrder.push("create");
return { ws: { close: vi.fn() } } as never;
});
waitForWaConnectionMock.mockResolvedValueOnce(undefined);
await controller.openConnection({
connectionId: "conn-flush-first",
createListener: async () => createListenerStub() as never,
});
expect(waitForCredsSaveQueueWithTimeoutMock).toHaveBeenCalledWith("/tmp/wa-auth");
expect(callOrder).toEqual(["wait", "create"]);
});
it("keeps the previous registered controller until a replacement listener is ready", async () => {
const liveController = new WhatsAppConnectionController({
accountId: "work",
@@ -83,12 +118,7 @@ describe("WhatsAppConnectionController", () => {
maxAttempts: 5,
},
});
const liveListener = {
sendMessage: vi.fn(async () => ({ messageId: "live-msg" })),
sendPoll: vi.fn(async () => ({ messageId: "live-poll" })),
sendReaction: vi.fn(async () => {}),
sendComposingTo: vi.fn(async () => {}),
};
const liveListener = createListenerStub("live");
createWaSocketMock.mockResolvedValueOnce({ ws: { close: vi.fn() } } as never);
waitForWaConnectionMock.mockResolvedValueOnce(undefined);
await liveController.openConnection({

View File

@@ -347,6 +347,7 @@ export class WhatsAppConnectionController {
let sock: WaSocket | null = null;
let connection: WhatsAppLiveConnection | null = null;
try {
await waitForCredsSaveQueueWithTimeout(this.authDir);
sock = await createWaSocket(false, this.verbose, {
authDir: this.authDir,
});