From 5a274b87922316594f8faa114138ec7864cdc580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 12 Nov 2026 14:09:36 +0100 Subject: [PATCH] fix(push): give the subscription removal a five-second limit Sign-out removes the push row first, through the raw fetch helper, which has no default timeout. On a connection that is up but carries nothing, the sign-out waited for the browser's own timeout before the logout request even started. The removal now gives up after five seconds. --- src/hooks/__tests__/use-logout.test.ts | 2 ++ src/lib/notifications/web-push-subscription.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/hooks/__tests__/use-logout.test.ts b/src/hooks/__tests__/use-logout.test.ts index b6d0483b9..49e14c26b 100644 --- a/src/hooks/__tests__/use-logout.test.ts +++ b/src/hooks/__tests__/use-logout.test.ts @@ -137,6 +137,8 @@ describe("useLogout", () => { expect(JSON.parse(String(deleteCall[1]?.body))).toEqual({ endpoint: subscription.endpoint, }); + // A connection that carries nothing must not hold the sign-out. + expect(deleteCall[1]?.signal).toBeInstanceOf(AbortSignal); expect(replace).toHaveBeenCalledWith("/auth/login"); }); diff --git a/src/lib/notifications/web-push-subscription.ts b/src/lib/notifications/web-push-subscription.ts index ace66218e..654075eeb 100644 --- a/src/lib/notifications/web-push-subscription.ts +++ b/src/lib/notifications/web-push-subscription.ts @@ -9,11 +9,16 @@ async function browserSubscription(): Promise { return (await registration?.pushManager.getSubscription()) ?? null; } +/** + * Bounded: on a connection that is up but carries nothing, sign-out would + * otherwise wait out the browser's own timeout before it even starts. + */ function deleteServerRow(subscription: PushSubscription): Promise { return apiFetchRaw("/api/notifications/web-push", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ endpoint: subscription.endpoint }), + signal: AbortSignal.timeout(5_000), }); }