From ac0c1c26b1848f526b05252384cf6c8d1b894d5a Mon Sep 17 00:00:00 2001 From: Nimrod Gutman Date: Fri, 20 Feb 2026 14:28:31 +0200 Subject: [PATCH] fix: preserve ios bg refresh plist key and handle web login retry failures --- apps/ios/project.yml | 2 ++ src/web/login.coverage.test.ts | 16 ++++++++++++++++ src/web/login.ts | 6 ++++++ 3 files changed, 24 insertions(+) diff --git a/apps/ios/project.yml b/apps/ios/project.yml index 45c5b11048a..9b43db118ef 100644 --- a/apps/ios/project.yml +++ b/apps/ios/project.yml @@ -100,6 +100,8 @@ targets: UIBackgroundModes: - audio - remote-notification + BGTaskSchedulerPermittedIdentifiers: + - ai.openclaw.ios.bgrefresh NSLocalNetworkUsageDescription: OpenClaw discovers and connects to your OpenClaw gateway on the local network. NSAppTransportSecurity: NSAllowsArbitraryLoadsInWebContent: true diff --git a/src/web/login.coverage.test.ts b/src/web/login.coverage.test.ts index 8b3673006eb..3c92cf942c1 100644 --- a/src/web/login.coverage.test.ts +++ b/src/web/login.coverage.test.ts @@ -80,6 +80,22 @@ describe("loginWeb coverage", () => { expect(secondSock.ws.close).toHaveBeenCalled(); }); + it("formats retry failure when restart login also closes", async () => { + formatErrorMock.mockReturnValueOnce("status=408 Request Time-out QR refs attempts ended"); + waitForWaConnectionMock + .mockRejectedValueOnce({ output: { statusCode: 515 } }) + .mockRejectedValueOnce({ + output: { + statusCode: 408, + payload: { error: "Request Time-out", message: "QR refs attempts ended" }, + }, + }); + + await expect(loginWeb(false, waitForWaConnectionMock as never)).rejects.toThrow( + /status=408 Request Time-out QR refs attempts ended/i, + ); + }); + it("clears creds and throws when logged out", async () => { waitForWaConnectionMock.mockRejectedValueOnce({ output: { statusCode: DisconnectReason.loggedOut }, diff --git a/src/web/login.ts b/src/web/login.ts index b336f8ebe4f..edecaba3328 100644 --- a/src/web/login.ts +++ b/src/web/login.ts @@ -45,6 +45,12 @@ export async function loginWeb( await wait(retry); console.log(success("✅ Linked after restart; web session ready.")); return; + } catch (retryErr) { + const formatted = formatError(retryErr); + console.error( + danger(`WhatsApp Web connection ended after restart before fully opening. ${formatted}`), + ); + throw new Error(formatted, { cause: retryErr }); } finally { setTimeout(() => retry.ws?.close(), 500); }