diff options
| author | Adam Soltys <[email protected]> | 2026-08-30 13:01:39 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-30 13:01:39 -0700 |
| commit | 80179a2e3bdc94a83a5969d5957af9eb2f051e50 (patch) | |
| tree | 805444602fa0acb45af85312809e4e36a21727aa /src/nostr-login.js | |
| parent | d7d5484b76459c068135ebd7fb33ef19adf33bc0 (diff) | |
| download | coinosv3-80179a2e3bdc94a83a5969d5957af9eb2f051e50.tar.gz coinosv3-80179a2e3bdc94a83a5969d5957af9eb2f051e50.zip | |
The Amethyst signer stops dying every time a stranger's wrap fails to decrypt: only connection-shaped failures (with a real per-op deadline now — a backgrounded signer app used to just hang the call) drop the live bunker, the reconnect surfaces offer only the door the account actually came through (a recorded 'via', so an Amethyst-linked npub no longer stares at Google and passkey buttons), the settings card quietly reattaches from the stored session instead of waiting for a tap, and the DM retry drain eases to three full-strength passes per wrap
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
Diffstat (limited to 'src/nostr-login.js')
| -rw-r--r-- | src/nostr-login.js | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/src/nostr-login.js b/src/nostr-login.js index 514c36b..4cc1ddf 100644 --- a/src/nostr-login.js +++ b/src/nostr-login.js @@ -145,17 +145,24 @@ export async function resumeBunker(session, { onAuth, timeoutMs = 8000 } = {}) { } function bunkerAdapter(signer, pubkey, local) { + // A dead transport (relay socket gone, signer app killed in the background) + // makes a NIP-46 call hang forever, not fail — so every operation carries + // its own deadline. The distinct message lets callers tell "the signer + // never answered" (connection is dead, reconnect) from "the signer said + // no" (an answered error — the connection is fine). + const answered = (p, ms = 20_000) => Promise.race([p, + new Promise((_, rej) => setTimeout(() => rej(new Error('signer did not answer')), ms))]); return { kind: 'bunker', pubkey, label: 'remote signer', // Everything needed to rebuild this connection later. `local` is the // client key the remote signer authorised — not the user's identity key, // which never leaves the signer. session: local ? { local: hex.encode(local), bp: signer.bp } : null, - signEvent: (e) => signer.signEvent(e), - encryptSelf: (txt) => signer.nip44Encrypt(pubkey, txt), - decryptSelf: (ct) => signer.nip44Decrypt(pubkey, ct), - encryptTo: (peer, txt) => signer.nip44Encrypt(peer, txt), - decryptFrom: (peer, ct) => signer.nip44Decrypt(peer, ct), + signEvent: (e) => answered(signer.signEvent(e)), + encryptSelf: (txt) => answered(signer.nip44Encrypt(pubkey, txt)), + decryptSelf: (ct) => answered(signer.nip44Decrypt(pubkey, ct)), + encryptTo: (peer, txt) => answered(signer.nip44Encrypt(peer, txt)), + decryptFrom: (peer, ct) => answered(signer.nip44Decrypt(peer, ct)), close: () => { try { signer.close(); } catch {} }, }; } |
