diff options
Diffstat (limited to 'src/features/messages.js')
| -rw-r--r-- | src/features/messages.js | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index 06371cf..597cb23 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -2898,11 +2898,28 @@ export function messagesFeature(ctx) { // "nothing to wait for": counting those passes gave every wrap sealed to // the login npub up after ~40 s with only the wallet key tried, and the // wrap log then hid it from every later session (a phone kept 9 of 186 - // messages). An interactive signer (Amber) is live from the moment it - // resumes and never decrypts here, so it counts as complete. + // messages). An interactive signer (Amber by intent) never decrypts here + // either, so it is incomplete too: counted as complete, every wrap sealed + // to the login npub was given up on the wallet key and logged as opened + // — an Amber user's threads held only what that device had sent. function decryptorsComplete() { const login = hook('nostrLoginIdentity'); - return !login || !!(login.signer && (login.signer.interactive || login.signer.decryptFrom)); + return !login || !!(login.signer && !login.signer.interactive && login.signer.decryptFrom); + } + const interactiveLogin = () => { const l = hook('nostrLoginIdentity'); return !!(l && l.signer && l.signer.interactive); }; + // Wraps logged while an interactive signer stood in for the login npub + // may be messages no key here ever tried. Once a signer that can decrypt + // takes over (Amber reconnected over NIP-46), the heal pass re-opens + // every wrap the relays still hold. + function noteSignerGap() { + const s = st(); + if (interactiveLogin()) { if (!s.dmSignerGap) { s.dmSignerGap = true; save(s); } return; } + if (!s.dmSignerGap || !decryptorsComplete()) return; + delete s.dmSignerGap; + s.dmHeal = 0; + save(s); + wrapLog = null; healed.clear(); seenWraps.clear(); + if (dmStarted) resubscribeStreams(); } // Raw-key unwraps (seed-derived / pasted nsec — the common case) run in @@ -3055,6 +3072,7 @@ export function messagesFeature(ctx) { const pks = dmSubKeys(); if (!pks.length) return; dmStarted = true; + if (interactiveLogin()) noteSignerGap(); loadSeenWraps(); // warm threads from the local cache. A self-thread of our own messages is // the residue of the old sent-copy misthreading (each welcome DM landed @@ -12140,6 +12158,17 @@ export function messagesFeature(ctx) { }, ui.msgReconnecting ? h('span', { class: 'spinner sm' }) : t('msgReconnect'))); } + // Amber by intent signs, but each decrypt would be a trip through the app, + // so nothing sent TO the login npub is opened here — a thread shows only + // what this device sent. Amber also speaks NIP-46; connected that way it + // decrypts quietly, and the messages held back open. + function amberDmNotice() { + if (wallet.watchOnly || !interactiveLogin()) return null; + return h('div', { class: 'row gap6 chat-signer-off', style: 'align-items:center' }, + h('span', { class: 'small muted grow' }, t('msgAmberDms')), + h('button', { class: 'btn-sm', onClick: () => hook('nostrSignerUpgrade') }, t('msgAmberConnect'))); + } + // Enter sends; Shift+Enter (the textarea's native edit) and Ctrl+J insert // a newline. Height follows the text as it's typed — imperatively, since // typing doesn't re-render — with rows as the re-render fallback. @@ -12402,6 +12431,8 @@ export function messagesFeature(ctx) { // that quietly won't open are listed. const lockedRow = signerNotice(); if (lockedRow && wallet.watchOnly) kids.push(lockedRow); + const amberRow = amberDmNotice(); + if (amberRow) kids.push(amberRow); if (pendingLink && pendingLink.where !== 'communities') kids.push(linkInviteCard()); for (const [rid, inv] of pendingDirect) kids.push(directInviteCard(rid, inv)); @@ -13319,6 +13350,7 @@ export function messagesFeature(ctx) { h('div', { class: 'chat-time' }, timeLabel(m.rumor.created_at * 1000))))) : [h('div', { class: 'muted small', style: 'text-align:center;padding:24px 0' }, t('msgNoDmsYet'))])), dmReplyBar(), + amberDmNotice(), composer(t('msgDmPlaceholder'), () => sendDM(peer), null, 'dm:' + peer, (f) => sendDMFile(peer, f)), ui.msgSheet ? dmSheet(peer) : null, choice && ui.msgRoutePick ? routeSheet(peer, choice) : null); @@ -13796,7 +13828,7 @@ export function messagesFeature(ctx) { }, // nostr-login just connected or resumed a signer: wraps the backfill // couldn't open a moment ago can be opened now — drain right away. - nostrSignerLive() { scheduleDrain(0); }, + nostrSignerLive() { noteSignerGap(); scheduleDrain(0); }, // Anyone (ark's history, other features) can open a profile or render a // small clickable identity chip. showProfile(pk) { openProfile(pk); return true; }, |
