diff --git a/js/nostr/nip07Permissions.js b/js/nostr/nip07Permissions.js index b96118c3..681fbbbf 100644 --- a/js/nostr/nip07Permissions.js +++ b/js/nostr/nip07Permissions.js @@ -35,6 +35,13 @@ export const DEFAULT_NIP07_PERMISSION_METHODS = Object.freeze([ ]); export const NIP07_PRIORITY = Object.freeze({ + // CRITICAL is reserved for establishing the signer channel itself (the + // permission/enable handshake behind the readiness gate). It must outrank + // list decryption (HIGH): otherwise a flood of HIGH-priority decrypts jumps + // ahead of the gate in the queue and starves it, so the channel never gets + // warmed and every decrypt keeps timing out (the real-env ~48s "signer-ready" + // — KNOWN_BUGS #0). + CRITICAL: 20, HIGH: 10, NORMAL: 5, LOW: 1, @@ -590,6 +597,9 @@ export async function requestEnablePermissions( ...variantTimeoutOverrides, // Interactive grant — never gated by (and can heal) the breaker. bypassCircuitBreaker: true, + // Establishing the channel must outrank list decryption so the + // handshake isn't starved by a flood of HIGH-priority decrypts. + priority: NIP07_PRIORITY.CRITICAL, }, ); return true; diff --git a/js/services/hashtagPreferencesService.js b/js/services/hashtagPreferencesService.js index bdc967e7..bfbf80f2 100644 --- a/js/services/hashtagPreferencesService.js +++ b/js/services/hashtagPreferencesService.js @@ -1094,7 +1094,7 @@ class HashtagPreferencesService { // gate guarantees the extension is ready before decryption starts, so // decrypt calls should complete within 1-2s. 5s accommodates slow // extensions while still failing fast for scheme fallback. - const nip07DecryptTimeoutMs = allowPermissionPrompt ? 12000 : SHORT_TIMEOUT_MS; + const nip07DecryptTimeoutMs = allowPermissionPrompt ? 6000 : SHORT_TIMEOUT_MS; const signerDecryptOptions = { priority: NIP07_PRIORITY.NORMAL, timeoutMs: nip07DecryptTimeoutMs, diff --git a/js/subscriptions.js b/js/subscriptions.js index b04e2a05..09d8c877 100644 --- a/js/subscriptions.js +++ b/js/subscriptions.js @@ -1148,7 +1148,7 @@ class SubscriptionsManager { // decrypt calls should complete within 1-2s. 5s accommodates slow // extensions while still failing fast enough for scheme fallback. const nip07DecryptTimeoutMs = allowPermissionPrompt - ? 12000 + ? 6000 : SHORT_TIMEOUT_MS; const signerDecryptOptions = { priority: NIP07_PRIORITY.NORMAL, diff --git a/js/userBlocks.js b/js/userBlocks.js index c0f0316d..cc97e42b 100644 --- a/js/userBlocks.js +++ b/js/userBlocks.js @@ -953,11 +953,13 @@ class UserBlockListManager { : allowPermissionPrompt ? DECRYPT_TIMEOUT_MS : BACKGROUND_DECRYPT_TIMEOUT_MS; - // PERF: Previous 3s no-prompt timeout was too aggressive — extensions that - // have already granted permission still need time to decrypt. 8s gives a - // realistic window while still failing faster than the full 15s interactive - // timeout. - const nip07DecryptTimeoutMs = allowPermissionPrompt ? 15000 : 8000; + // A healthy nip04/nip44 decrypt is local crypto (~1s). The login-time value + // was 15s purely to tolerate a slow first-grant prompt — but permissions are + // pre-granted by the readiness gate, so a 15s timeout just monopolizes one of + // the two NIP-07 queue slots on a doomed call, starving the gate (real-env + // ~48s signer-ready — KNOWN_BUGS #0). 6s still tolerates a slow extension + // while freeing the slot ~2.5x faster. + const nip07DecryptTimeoutMs = allowPermissionPrompt ? 6000 : 6000; const emitStatus = (detail) => { if (!detail || typeof detail !== "object") { return;