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 <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-01-28 00:50:00 +00:00
1 parent 63e5c9f415
commit 33a5f64c9f
1 file changed
+8 -20
+8 -20
View File
@@ -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,
});