Speed up Nostr login and fix list sync, storage unlock, and feed registration

- Remove redundant double signer readiness gate evaluation that added 5-10s
  to the login path (authSessionCoordinator)
- Reduce decryption timeouts (10s→6s per scheme, 3s→1.5s retry delay,
  8s→5s NIP-07 no-prompt, 45s→25s overall ensureLoaded) for faster scheme
  fallback during list sync
- Fix storage tab unlock: remove overly strict capabilities check that
  blocked lazy-injecting NIP-07 extensions, and add auto-unlock attempt
  when profile modal opens with an active signer
- Fix subscription/hashtag decryption: always resolve signer for background
  refreshes (was previously gated behind allowPermissionPrompt), and always
  check window.nostr as fallback decryptor regardless of prompt mode
- Fix capabilities check in subscription decryption: use method existence
  instead of dynamic capabilities getter that returns false during lazy
  extension injection
- Wrap Promise.any decryptor calls in Promise.resolve().then() to catch
  synchronous throws from NIP-07 adapter methods when extension modules
  haven't loaded yet
- Make watch-history feed registration race-safe with pre-check and
  try/catch for concurrent registration attempts
- Improve NIP-07 extension detection with DOMContentLoaded listener for
  faster detection of extensions that inject during page load

https://claude.ai/code/session_0174XTB5ADJ9cMBSucqL9Wer
This commit is contained in:
Claude committed 2026-02-09 00:18:43 +00:00
1 parent dc196b8e43
commit 29215d9b5e
6 files changed
+173 -93

No files matched your search

+24 -8
View File
@@ -9982,7 +9982,23 @@ export class ProfileModalController {
return;
}
const isUnlocked = storageService && storageService.masterKeys.has(pubkey);
let isUnlocked = storageService && storageService.masterKeys.has(pubkey);
// Auto-unlock: If not already unlocked and a signer is available, attempt
// a silent unlock in the background. This eliminates the manual "Unlock"
// click for users whose extension has already granted permissions.
if (!isUnlocked && storageService && !this.storageUnlockFailure) {
const signer = getActiveSigner();
if (signer && (typeof signer.nip44Decrypt === "function" || typeof signer.nip04Decrypt === "function")) {
try {
await storageService.unlock(pubkey, { signer });
isUnlocked = storageService.masterKeys.has(pubkey);
} catch (autoUnlockError) {
// Silent failure — user can still manually unlock.
devLogger.log("[ProfileModal] Auto-unlock storage skipped:", autoUnlockError?.message || autoUnlockError);
}
}
}
if (this.storageStatusText) {
if (isUnlocked) {
@@ -10238,14 +10254,14 @@ export class ProfileModalController {
}
}
const caps = signer?.capabilities && typeof signer.capabilities === "object"
? signer.capabilities
: null;
const hasNip44Decrypt =
caps?.nip44 !== false && typeof signer?.nip44Decrypt === "function";
// FIX: Check for method existence only, not capabilities. NIP-07 adapters
// always expose nip04Decrypt/nip44Decrypt methods that perform their own
// existence checks at call time. The capabilities getter dynamically queries
// the extension which may not have injected its NIP-44/04 modules yet
// (lazy injection), causing a false-negative that blocks the unlock flow.
const hasNip44Decrypt = typeof signer?.nip44Decrypt === "function";
const hasNip04Decrypt =
caps?.nip04 !== false &&
(typeof signer?.nip04Decrypt === "function" || typeof signer?.decrypt === "function");
typeof signer?.nip04Decrypt === "function" || typeof signer?.decrypt === "function";
if (!hasNip44Decrypt && !hasNip04Decrypt) {
const missingDecryptError = new Error(