From 33a5f64c9fa28b4fd8d0045eb9c1e8e1c6de19a0 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 00:50:00 +0000 Subject: [PATCH] fix(nostr): ensure NIP-07 operations are retried on timeout Previously, `runNip07WithRetry` cached the initial promise of a NIP-07 operation. If a request timed out (e.g., due to a dropped extension popup), the retry logic would re-await the same stale promise, causing the application to hang indefinitely instead of sending a new request. This commit modifies `runNip07WithRetry` to invoke the operation factory function on every attempt, ensuring that retries generate fresh requests to the extension. Fixes slow/stalled list syncing (hashtags, subscriptions) for users with NIP-07 extensions. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- js/nostr/nip07Permissions.js | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/js/nostr/nip07Permissions.js b/js/nostr/nip07Permissions.js index 18d719f7..60bb0cdb 100644 --- a/js/nostr/nip07Permissions.js +++ b/js/nostr/nip07Permissions.js @@ -192,26 +192,13 @@ export async function runNip07WithRetry( retryMultiplier = 2, } = {}, ) { - let hasStarted = false; - let cachedPromise = null; - - const getOrStartOperation = () => { - if (!hasStarted) { - hasStarted = true; - try { - cachedPromise = Promise.resolve(operation()); - } catch (error) { - hasStarted = false; - cachedPromise = null; - throw error; - } - } - - return cachedPromise; - }; + // We wrap the operation invocation to ensure it returns a fresh promise each time + // we attempt it. This is critical for retries: if the first attempt stalls (dropped + // by extension), re-awaiting the same promise would just keep waiting on the dead request. + const invokeOperation = () => Promise.resolve(operation()); try { - return await withNip07Timeout(getOrStartOperation, { + return await withNip07Timeout(invokeOperation, { timeoutMs, message: NIP07_LOGIN_TIMEOUT_ERROR_MESSAGE, }); @@ -230,10 +217,11 @@ export async function runNip07WithRetry( ); devLogger.warn( - `[nostr] ${label} taking longer than ${timeoutMs}ms. Waiting up to ${extendedTimeout}ms for extension response.`, + `[nostr] ${label} taking longer than ${timeoutMs}ms. Retrying with ${extendedTimeout}ms timeout.`, ); - return withNip07Timeout(getOrStartOperation, { + // On retry, we invoke operation() again to send a fresh request to the extension. + return withNip07Timeout(invokeOperation, { timeoutMs: extendedTimeout, message: NIP07_LOGIN_TIMEOUT_ERROR_MESSAGE, });