fix(gateway): stop stale device token reconnect loops

This commit is contained in:
Peter Steinberger
2026-04-28 11:37:10 +01:00
parent 205d8d4994
commit 885806d5ca
5 changed files with 90 additions and 1 deletions

View File

@@ -515,6 +515,36 @@ describe("GatewayBrowserClient", () => {
vi.useRealTimers();
});
it("clears stale stored device tokens and does not reconnect on AUTH_DEVICE_TOKEN_MISMATCH", async () => {
vi.useFakeTimers();
const client = new GatewayBrowserClient({
url: "ws://127.0.0.1:18789",
});
const { ws, connectFrame } = await startConnect(client);
expect(connectFrame.params?.auth?.token).toBe("stored-device-token");
ws.emitMessage({
type: "res",
id: connectFrame.id,
ok: false,
error: {
code: "INVALID_REQUEST",
message: "unauthorized",
details: { code: "AUTH_DEVICE_TOKEN_MISMATCH" },
},
});
await expectSocketClosed(ws);
ws.emitClose(4008, "connect failed");
expect(loadDeviceAuthToken({ deviceId: "device-1", role: "operator" })).toBeNull();
await vi.advanceTimersByTimeAsync(30_000);
expect(wsInstances).toHaveLength(1);
vi.useRealTimers();
});
});
describe("shouldRetryWithDeviceToken", () => {

View File

@@ -86,6 +86,7 @@ export function isNonRecoverableAuthError(error: GatewayErrorInfo | undefined):
code === ConnectErrorDetailCodes.AUTH_PASSWORD_MISSING ||
code === ConnectErrorDetailCodes.AUTH_PASSWORD_MISMATCH ||
code === ConnectErrorDetailCodes.AUTH_RATE_LIMITED ||
code === ConnectErrorDetailCodes.AUTH_DEVICE_TOKEN_MISMATCH ||
code === ConnectErrorDetailCodes.PAIRING_REQUIRED ||
code === ConnectErrorDetailCodes.CONTROL_UI_DEVICE_IDENTITY_REQUIRED ||
code === ConnectErrorDetailCodes.DEVICE_IDENTITY_REQUIRED
@@ -519,8 +520,12 @@ export class GatewayBrowserClient {
} else {
this.pendingConnectError = undefined;
}
const usedStoredDeviceToken =
Boolean(plan.selectedAuth.storedToken) &&
(plan.selectedAuth.resolvedDeviceToken === plan.selectedAuth.storedToken ||
plan.selectedAuth.authDeviceToken === plan.selectedAuth.storedToken);
if (
plan.selectedAuth.canFallbackToShared &&
usedStoredDeviceToken &&
plan.deviceIdentity &&
connectErrorCode === ConnectErrorDetailCodes.AUTH_DEVICE_TOKEN_MISMATCH
) {