diff options
Diffstat (limited to 'src/features/nostrlogin.js')
| -rw-r--r-- | src/features/nostrlogin.js | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/src/features/nostrlogin.js b/src/features/nostrlogin.js index f39f9c3..83144cd 100644 --- a/src/features/nostrlogin.js +++ b/src/features/nostrlogin.js @@ -69,7 +69,7 @@ export function nostrLoginFeature(ctx) { // decrypt that" is a healthy connection doing its job — the DM inbox probes // it with wraps that turn out to be someone else's, and treating each // refusal as a dead signer disconnected Amethyst users over and over. - const SIGNER_DEAD = /did not answer|timed? ?out|connect|closed|socket|relay|network/i; + const SIGNER_DEAD = /did not answer|timed? ?out|connect|closed|not open|socket|relay|network/i; const selfHealing = (signer) => { if (!signer || signer.kind !== 'bunker') return signer; const guard = (fn) => async (...args) => { @@ -611,12 +611,18 @@ export function nostrLoginFeature(ctx) { // time, and a pause after a failure: identity() asks on every send, and a // signer that isn't answering shouldn't mean a new relay connection per // keystroke. - async function resumeLogin() { + const tabHidden = () => typeof document !== 'undefined' && document.visibilityState === 'hidden'; + async function resumeLogin({ force = false } = {}) { if (liveSigner()) return live; const st = load(); if (!st.pubkey) return null; if (resuming) return resuming; - if (Date.now() - resumeFailedAt < 20_000) return null; + if (!force && Date.now() - resumeFailedAt < 20_000) return null; + // A phone freezes a hidden tab: a remote signer asked from there can't be + // heard, and that silence isn't the session failing — don't count it. + let wasHidden = tabHidden(); + const onVis = () => { if (tabHidden()) wasHidden = true; }; + if (typeof document !== 'undefined') document.addEventListener('visibilitychange', onVis); resuming = (async () => { // a stored passkey-derived key reattaches instantly — no network, no // dialog; see sessionOf for why this key (alone among keys) is kept @@ -645,10 +651,13 @@ export function nostrLoginFeature(ctx) { })(); try { const s = await resuming; - if (!s) resumeFailedAt = Date.now(); - else announceLive(); + if (!s && !wasHidden) resumeFailedAt = Date.now(); + else if (s) announceLive(); return s; - } finally { resuming = null; } + } finally { + resuming = null; + if (typeof document !== 'undefined') document.removeEventListener('visibilitychange', onVis); + } } // Which door this account came through, for the reconnect surfaces. State @@ -708,8 +717,31 @@ export function nostrLoginFeature(ctx) { // reattach silently). Same guarded buttons as the settings card — an // extension, the signer-app deeplink/QR, or a pasted key — and the run // refuses a different account. + // While the reconnect screen is up, keep trying the stored session: the + // remote signer authorised this client key long ago and nearly always still + // answers — it just wasn't heard the moment the screen opened (tab frozen, + // relay socket cut, the signer app asleep until opened). One try and then + // nothing meant a brand-new connection every time. + let retryT = 0; + const retryStored = () => { + clearTimeout(retryT); retryT = 0; + if (ui.nostrReconnect !== true || liveSigner()) return; + const st = load(); + if (!st.session || st.session.amber) return; + if (!tabHidden()) { + resumeLogin({ force: true }).then((sg) => { + if (sg && ui.nostrReconnect === true) { stopNostrConnect(); ui.nostrReconnect = null; ui.nostrConnectOpen = false; render(); } + }).catch(() => {}); + } + retryT = setTimeout(retryStored, 10_000); + }; + if (typeof document !== 'undefined') { + document.addEventListener('visibilitychange', () => { if (!tabHidden() && ui.nostrReconnect === true) retryStored(); }); + } + function reconnectScreen() { const st = load(); + if (ui.nostrReconnect === true && !retryT && st.session && !st.session.amber) retryT = setTimeout(retryStored, 0); // 'upgrade': Amber by intent is live but can't read messages — offer // only its NIP-46 door (nostrconnect), same account enforced const upgrade = ui.nostrReconnect === 'upgrade'; @@ -756,7 +788,7 @@ export function nostrLoginFeature(ctx) { if (!st.pubkey || liveSigner()) return false; ui.nostrReconnect = true; ui.nostrLoginError = ''; - this.nostrLoginResume().then((sg) => { + resumeLogin({ force: true }).then((sg) => { if (sg && ui.nostrReconnect) { ui.nostrReconnect = null; render(); } }).catch(() => {}); render(); |
