From edd08fde5974d4a997b52444ec16a3f7328ebbaf Mon Sep 17 00:00:00 2001 From: Dorian Date: Sun, 8 Mar 2026 20:43:34 +0000 Subject: [PATCH] fix: abort dangling fetches and handle localStorage exceptions - useNostr.ts: wrap auto-restore login fetch with AbortController, abort on logout to cancel in-flight request - useWallet.ts: wrap localStorage.setItem/removeItem calls in try/catch for Safari private browsing quota exceptions Co-Authored-By: Claude Opus 4.6 --- frontend/src/composables/useNostr.ts | 3 +++ frontend/src/composables/useWallet.ts | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/frontend/src/composables/useNostr.ts b/frontend/src/composables/useNostr.ts index 878dcd0..a3dbf83 100644 --- a/frontend/src/composables/useNostr.ts +++ b/frontend/src/composables/useNostr.ts @@ -90,12 +90,14 @@ export function useNostr() { const hasExtension = computed(() => !!window.nostr) // Restore session on first load — re-verify with server (once only) + const autoRestoreController = new AbortController() if (!autoRestoreRan && pubkey.value && !bot.value) { autoRestoreRan = true fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pubkey: pubkey.value }), + signal: autoRestoreController.signal, }).then(r => r.json()).then(data => { if (data.exists) { bot.value = normalizeBotData(data.bot) @@ -368,6 +370,7 @@ export function useNostr() { } function logout() { + autoRestoreController.abort() clearAllState() // Don't clear bf_nsec on logout — user may want to log back in } diff --git a/frontend/src/composables/useWallet.ts b/frontend/src/composables/useWallet.ts index 488965e..c9856fe 100644 --- a/frontend/src/composables/useWallet.ts +++ b/frontend/src/composables/useWallet.ts @@ -16,8 +16,10 @@ function loadStored(key: string): T | null { } catch { return null } } function store(key: string, value: unknown) { - if (value == null) localStorage.removeItem(key) - else localStorage.setItem(key, JSON.stringify(value)) + try { + if (value == null) localStorage.removeItem(key) + else localStorage.setItem(key, JSON.stringify(value)) + } catch { /* Safari private browsing quota exception */ } } const isWalletConnected = ref(!!loadStored('bf_wallet_method')) @@ -73,7 +75,7 @@ export function useWallet() { } // Store NWC string locally for client-side payment sending - localStorage.setItem('bf_nwc_url', connectionString) + try { localStorage.setItem('bf_nwc_url', connectionString) } catch { /* quota */ } walletMethod.value = 'nwc' isWalletConnected.value = true store('bf_wallet_method', 'nwc') @@ -120,7 +122,7 @@ export function useWallet() { paymentStatus.value = 'idle' pendingPayment.value = null store('bf_wallet_method', null) - localStorage.removeItem('bf_nwc_url') + try { localStorage.removeItem('bf_nwc_url') } catch { /* quota */ } } async function checkWalletStatus(): Promise {