From f3bac3066dab7d26183d8295ea3d9e3f19739f18 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Tue, 16 Jun 2026 13:04:34 -0400 Subject: [PATCH] perf(nip07): don't kill slow signers during the permission handshake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a cold login / permission cache-miss, requestEnablePermissions probes several permission-payload variants before the no-arg prompt. The specific (silent) variants were capped at 3s "to fail fast" — but real extensions REJECT an unsupported payload shape almost immediately (and a fast rejection already falls through to the next variant), so the 3s cap added no real safety. What it DID do: kill a slow-but-responsive signer mid-grant, forcing all 3 specific variants to time out (3s each) before the prompt variant finally succeeded — ~25s of dead time before signer-ready. Raise the specific-variant timeout to 20s (SPECIFIC_VARIANT_TIMEOUT_MS). The bound now only matters for a variant that genuinely HANGS; unsupported shapes still reject fast, and a slow signer can actually answer the first supported variant. Channel-sim at 16s/call: enable extension calls 4 → 1, signer-ready ~42s → ~33s, lists-sync ~58s → ~50s; healthy login unchanged (~1.6s), all lists still decrypt. Full unit suite green (pre-existing Node localStorage failures unrelated). KNOWN_BUGS #0. Co-Authored-By: Claude Opus 4.8 --- js/nostr/nip07Permissions.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/js/nostr/nip07Permissions.js b/js/nostr/nip07Permissions.js index 681fbbbf..e53eebce 100644 --- a/js/nostr/nip07Permissions.js +++ b/js/nostr/nip07Permissions.js @@ -13,6 +13,16 @@ const NIP07_PERMISSIONS_STORAGE_KEY = "bitvid:nip07:permissions"; // still allowing manual overrides via __BITVID_NIP07_ENABLE_VARIANT_TIMEOUT_MS__. const DEFAULT_ENABLE_VARIANT_TIMEOUT_MS = 45_000; +// Timeout for the SPECIFIC (silent, payload-carrying) permission variants we +// probe before the no-arg prompt. This is NOT a "fail fast" budget: real +// extensions REJECT a payload shape they don't support almost immediately, and +// a fast rejection moves us to the next variant right away. The timeout only +// bounds a variant that HANGS — so a tiny 3s cap added no real safety against +// unsupported variants but DID kill slow-but-responsive signers mid-grant, +// forcing 3 wasted attempts before the prompt variant succeeded (~25s of dead +// time on a 16s/call signer in the channel-sim). Give it real room. +const SPECIFIC_VARIANT_TIMEOUT_MS = 20_000; + export const DEFAULT_NIP07_ENCRYPTION_METHODS = Object.freeze([ // Encryption helpers — request both legacy NIP-04 and modern NIP-44 upfront "nip04.encrypt", @@ -569,11 +579,16 @@ export async function requestEnablePermissions( let lastError = null; const runPermissionMethod = async (methodName, method) => { for (const options of permissionVariants) { - // Specific permission payloads should fail fast; prompt-based no-arg calls - // get a longer timeout so users have time to confirm in extension UI. + // Specific (silent) payload variants get a generous bound so a slow signer + // can actually answer the FIRST supported one (unsupported shapes still + // reject fast and fall through immediately). The no-arg prompt variant + // gets the full window so users have time to confirm in the extension UI. const variantTimeoutOverrides = options ? { - timeoutMs: Math.min(3000, getEnableVariantTimeoutMs()), + timeoutMs: Math.min( + SPECIFIC_VARIANT_TIMEOUT_MS, + getEnableVariantTimeoutMs(), + ), retryMultiplier: 1, } : {