<feed xmlns='http://www.w3.org/2005/Atom'>
<title>coinosv3.git/src/nostr-login.js, branch fdroid-v1.7</title>
<subtitle>coinos v3 — bitcoin, Ark, Lightning and nostr wallet (web + Android)</subtitle>
<id>https://git.coinos.io/coinosv3.git/atom?h=fdroid-v1.7</id>
<link rel='self' href='https://git.coinos.io/coinosv3.git/atom?h=fdroid-v1.7'/>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/'/>
<updated>2026-09-15T01:00:19Z</updated>
<entry>
<title>A remote signer that drops its socket comes back by itself.</title>
<updated>2026-09-15T01:00:19Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-15T01:00:19Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=cb4e155ae6fb72282d5f186389d2ecca6db6a0f0'/>
<id>urn:sha1:cb4e155ae6fb72282d5f186389d2ecca6db6a0f0</id>
<content type='text'>
"My signer keeps disconnecting": a phone freezing the tab cut the relay
socket the bunker session talks through, every request after that hung
to its deadline, and the app declared the signer gone — a Reconnect
button, tapped over and over. Three changes: the bunker client now talks
through a pool that pings and reconnects on its own, so a dropped socket
is re-opened and the subscription re-fired without anyone noticing; a
request that does fail on a dead connection drops the session and dials
again silently, so the notice only appears if that resume fails; and
coming back from the background probes the signer with a quick question,
replacing a dead session before the next real request runs into it.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
</content>
</entry>
<entry>
<title>The Amethyst handshake survives its own launch: opening the signer app freezes the tab (relay sockets die as the approval publishes) and its callbackUrl then RELOADS the page, discarding the client key mid-handshake — so the pending connect now persists to sessionStorage, the wait races the live subscription against a stored-event poller kicked on every return to visibility, and a fresh boot resumes the handshake instead of shrugging. Proven both ways with a scripted signer: approval after reload, and approval stored while the page was gone</title>
<updated>2026-09-03T05:18:16Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-03T05:18:16Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=d28b716ae791f924d7dea901b9a9711e44bd7312'/>
<id>urn:sha1:d28b716ae791f924d7dea901b9a9711e44bd7312</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
</content>
</entry>
<entry>
<title>The DM drain wakes the signer itself: boot's single resume attempt losing to cold-start churn left the phone holding every wrap with nothing ever asking the bunker again — now a drain that finds its decryptor set incomplete calls resume (single-flight, rate-limited) before deciding anything, and the bunker resume deadline stretches to 15s</title>
<updated>2026-08-30T20:08:05Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-30T20:08:05Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=431907c9959e6d414fe13e05f76d1a1a45f7828e'/>
<id>urn:sha1:431907c9959e6d414fe13e05f76d1a1a45f7828e</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
</content>
</entry>
<entry>
<title>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</title>
<updated>2026-08-30T20:01:39Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-30T20:01:39Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=80179a2e3bdc94a83a5969d5957af9eb2f051e50'/>
<id>urn:sha1:80179a2e3bdc94a83a5969d5957af9eb2f051e50</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
</content>
</entry>
<entry>
<title>The wallet remembers it has a spending side: the relay backup carries the hint, stamped the moment spending becomes real, so a restore paints Spending from its first frame instead of reflowing when the name lookup catches up — and the sign-in toasts are gone, since a wallet appearing announces itself</title>
<updated>2026-08-28T14:57:09Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-28T14:57:09Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=274130edd7d11a0643d9b1f7469022207e5f5563'/>
<id>urn:sha1:274130edd7d11a0643d9b1f7469022207e5f5563</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
</content>
</entry>
<entry>
<title>The app arrives in movements: real ESM chunks split the bundle (entry 333KB, shared chunks alongside, 61KB of gifts/NWC/hats deferred past first paint into slots that keep their hook seniority), the lazy scripts wear IIFE coats so their names can't collide with the page's — which is what silently broke the remote-signer button — nip98 moves out of the login module so minimal builds stop hauling backup relays, and the smoke test learns the front door's new steps while the regtest stack rises from its IBD nap</title>
<updated>2026-08-26T21:16:41Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-26T21:16:41Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=e18a74b936e43aeb7f74df433d88f294f9bcc877'/>
<id>urn:sha1:e18a74b936e43aeb7f74df433d88f294f9bcc877</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
</content>
</entry>
<entry>
<title>The page arrives light and paints at once: index.html shrinks to 46KB with a static boot shell baked in — brand row, and the profile frame when the path names one — while the 789KB bundle moves to a content-addressed app-&lt;hash&gt;.js the browser keeps (a repeat visit re-downloads kilobytes, not the app); the nostr-tools barrel import goes subpath, and the NIP-46 signer client ships as its own lazy file fetched on first bunker login</title>
<updated>2026-08-26T19:06:00Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-26T19:06:00Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=0427a1b02c21fd5fa9f5df8a86e435dbb84a8451'/>
<id>urn:sha1:0427a1b02c21fd5fa9f5df8a86e435dbb84a8451</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
</content>
</entry>
<entry>
<title>Never mistake a failed backup lookup for 'no wallet yet'</title>
<updated>2026-08-04T08:06:24Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-04T08:06:24Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=971db911d47af391695a9d83a3d31c089bfee782'/>
<id>urn:sha1:971db911d47af391695a9d83a3d31c089bfee782</id>
<content type='text'>
Signing in with a key whose wallet backup exists on relays could still
land in 'create a new wallet' when the lookup failed (relays unreachable,
signer decrypt denied) — and confirming would have replaced the real
backup on any relay the new one reached. Absence is now only believed
when a relay actually answered; decrypt failures surface as errors; and
the create path takes one last look and adopts a backup that surfaces
rather than clobbering it.

Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Speak as the account you logged in with, or not at all</title>
<updated>2026-08-04T05:28:53Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-04T05:28:53Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=75ec27747ec05da8990208d67052ad11d25f3c44'/>
<id>urn:sha1:75ec27747ec05da8990208d67052ad11d25f3c44</id>
<content type='text'>
Logging in with a remote signer and reloading left the app showing your
avatar and profile while signing everything with the wallet's own key —
so chat messages arrived under a different npub with a stranger's punk
on them. identity() had a fallback: when the login signer wasn't
available it quietly used the wallet key instead. That fallback is gone.
If you logged in as a nostr account, the app speaks as that account or
it refuses and says so.

Refusing is only reasonable if the signer usually comes back, so a login
now persists what it takes to be that identity again. A remote signer
stores its NIP-46 client key and pointer — the signer authorised that
client key, not one page load, so rebuilding from it resumes the session
without prompting. A pasted key stores the key, which is already the
seed of everything here since the wallet's mnemonic derives from it.
Resume is single-flight with a pause after failure, because identity()
is asked on every send and a signer that isn't answering must not mean a
relay connection per keystroke.

Existing remote-signer logins predate the stored session, so they need
one more sign-in to become resumable.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
</content>
</entry>
<entry>
<title>Tab carousel, login avatar fix, signer callback hint</title>
<updated>2026-08-03T06:26:38Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-03T06:26:38Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=02d60eb824cad0b8c09cb5685a6c2dbe02e16c4f'/>
<id>urn:sha1:02d60eb824cad0b8c09cb5685a6c2dbe02e16c4f</id>
<content type='text'>
Tab changes no longer flash the whole page: only the content pane below
the tab strip slides sideways with a soft cross-fade — swipe direction
when a gesture caused it, index order for taps — while the balance card
and strip stay planted. Full-page entrances remain for real page
changes (settings, chat, profile, takeovers).

After a nostr sign-in the header briefly wore the wallet key's face:
nostrLoginIdentity now reports a just-connected live signer immediately
instead of waiting for the persisted link that only lands after the
wallet opens.

The nostrconnect URI carries a callbackUrl hint (NIP-55 style) so
signer apps that honor it can bounce back to the PWA after approval —
apps that don't will still find the session signed in when the user
returns, since the handshake completes over the relay in the
background.

Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
</content>
</entry>
</feed>
