fix(ui): add timeout to service-worker readiness in push subscription flows

Wraps navigator.serviceWorker.ready with a 10s timeout so subscribe,
unsubscribe, and existing-subscription checks surface a recoverable
error instead of hanging indefinitely when SW registration fails.
This commit is contained in:
Eduardo Cruz
2026-03-13 02:38:40 -03:00
committed by Val Alexander
parent c02e527dff
commit 7881924a1b

View File

@@ -30,6 +30,22 @@ export function detectWebPushState(): WebPushState {
};
}
/** Timeout (ms) for service-worker readiness. */
const SW_READY_TIMEOUT = 10_000;
/**
* Await service-worker readiness with a timeout so callers don't hang
* indefinitely when registration fails or sw.js is unreachable.
*/
function swReady(): Promise<ServiceWorkerRegistration> {
return Promise.race([
navigator.serviceWorker.ready,
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error("Service worker not ready (timed out)")), SW_READY_TIMEOUT),
),
]);
}
/**
* URL-safe base64 string to Uint8Array (for applicationServerKey).
*/
@@ -51,7 +67,7 @@ export async function getExistingSubscription(): Promise<PushSubscription | null
if (!("serviceWorker" in navigator)) {
return null;
}
const registration = await navigator.serviceWorker.ready;
const registration = await swReady();
return await registration.pushManager.getSubscription();
}
@@ -78,7 +94,7 @@ export async function subscribeToWebPush(
}
// Subscribe via PushManager.
const registration = await navigator.serviceWorker.ready;
const registration = await swReady();
const pushSubscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(vapidPublicKey).buffer as ArrayBuffer,
@@ -105,7 +121,7 @@ export async function subscribeToWebPush(
* Unsubscribe from web push notifications.
*/
export async function unsubscribeFromWebPush(client: GatewayBrowserClient): Promise<void> {
const registration = await navigator.serviceWorker.ready;
const registration = await swReady();
const subscription = await registration.pushManager.getSubscription();
if (subscription) {