aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
Commit message (Collapse)AuthorAgeFilesLines
* The chat window fits the screen, and the header stops asking questionsAdam Soltys2026-08-031-16/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The message log had a fixed 62vh height, so the card was head + panels + log + composer tall and the input fell off the bottom of the screen. The card is now sized to the viewport and the log is the only part that flexes: opening the invite or member panel shrinks the scroll area instead of pushing the composer out of reach. Three header changes, all the same idea — don't show a control for a choice nobody is making: '+' becomes 'Add person', because a plus sign doesn't say what it adds. A lone channel isn't named at all. '#general' next to a composer that says 'Message #general' points at a choice of one; several channels become a select, which is what a choice looks like. The new-channel field hides behind a 'New channel' button. Sitting open right after you create a community, it reads as something you're supposed to fill in. tools/chat-layout-test.js holds the line at three viewport sizes with both panels open, and covers the header behaviour through actually adding a second channel. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Drop the 'signer reconnected' toastAdam Soltys2026-08-031-2/+2
| | | | | | | | | | A dark pill floating at the bottom of the screen reads as a stray button under the footer, and it was saying something the page already showed: the badge flips to connected and the reconnect controls disappear. Failures still surface — those go in the card, where the problem is. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Give the nostr settings page a way to reconnectAdam Soltys2026-08-031-2/+2
| | | | | | | | | | | | | | | | | | | | | The app could tell you your signer wasn't connected and then send you somewhere with nothing to click: once an account was linked, the nostr card showed only an npub. It now shows connected/not connected, says what's missing, and offers the same signer options as signing in — refusing a different account rather than quietly swapping identities, since this is a reconnect and not a login. Pasted keys go back to not being persisted at all. Storing one would have survived a reload, but the UI promises a pasted key is used once and never kept, and that promise is worth more than saving a paste; those logins reconnect from this card like any other. The chat banner now tracks the live signer alone. The flag that suppressed it after a reconnect would also have hidden a later genuine disconnect. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Offer the signer back where you'd notice it's missingAdam Soltys2026-08-031-1/+25
| | | | | | | | | | | | | A remote signer dropped by a reload now says so above the composer, with a button that reconnects in place — rather than letting someone write a message and only then be told it can't be sent as them. Failing that it opens the nostr settings, where logging in again is the fallback. Every remote-signer login made before sessions were persisted lands in exactly this state once. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Speak as the account you logged in with, or not at allAdam Soltys2026-08-031-1/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | 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 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Only people you know get to buzz your phoneAdam Soltys2026-08-031-0/+36
| | | | | | | | | | | | | | | | | | | | | | | | | | | | A NIP-17 wrap is signed by a throwaway key with the sender sealed under two layers of nip44, so no server can filter DMs by who sent them. The notifier now ships the wrap inside the push payload and the service worker opens it locally: a message from someone you follow arrives with their name on it, a stranger's is dropped, and your own sent-copy — every DM is wrapped to the sender too — no longer notifies you about what you just typed. That needs the nostr identity key in the worker's IndexedDB, which dm-inbox.js states plainly: for a seed-derived identity it is a second copy of a key localStorage's seed already yields, and it exists only to keep strangers out. A remote signer never hands its key over, so those wallets store no secret and keep getting unfiltered notifications rather than silence. Silence is always the riskier failure here, so the rule leans the other way whenever it isn't sure: a wrap we can't open notifies, an account with no contact list published notifies (otherwise a new user's welcome message would vanish), and anyone you already have a thread with counts as known whether or not you follow them. The server-side DM cooldown drops to a second — with the device discarding pushes, a throttle there would let a discarded one swallow the message behind it. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Messages in the header, and a room you can tell is aliveAdam Soltys2026-08-031-7/+239
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The header carries a message button again, left of the wallet selector, with a red dot when a conversation is waiting. Unread is a per-thread watermark on the newest message from someone else, kept in the rumor's own created_at so it means the same thing on every device it syncs to. Rooms subscribe at startup now, or the dot could not speak for a community nobody was listening to. Communities no longer buzz a phone by default: push registration only carries the stream keys of communities you have opted in, per community, from a bell in the room header. DMs and payments are unchanged. Presence and typing ride the channel stream as 21059 wraps, so who is around stays inside the community's encryption rather than becoming a public status. Measured against relay.coinos.io and nos.lol, neither actually drops NIP-01 ephemeral kinds, so beats carry a NIP-40 expiration and relay.coinos.io sweeps kind 21059 hourly — and presence is dated by the beat, never by arrival, or a replayed beat would light up the whole member list. The member list follows Telegram: online, then last seen in minutes and hours, then a vague 'recently' rather than advertising how long someone has been gone. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Profile: no editable lightning addressAdam Soltys2026-08-031-3/+8
| | | | | | | | | | | Editing it here reads like renaming your coinos account, and for someone using an address from elsewhere it invites breaking their own zaps. The field is gone; an existing address is preserved untouched, and one is filled in from the coinos payment address only when the profile has none, so other clients can still zap them. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Pay screens: bigger recipient chip, no loading-screen flashesAdam Soltys2026-08-031-3/+5
| | | | | | | | | | | | Resolving a recipient (ark advert → BIP-353 → lightning) no longer takes over the screen twice on the way: both steps keep the send form in place and report progress as one inline line, so picking someone goes straight to something actionable. The recipient chip on the zap card gets a large variant — a 30px avatar and full-size name, since it's who the money is going to. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Profile page: hide machine-noise fields, real Back buttonAdam Soltys2026-08-031-5/+14
| | | | | | | | | | | | An npub-shaped lightning address (npub1…@npub.cash) duplicated the npub box below it and overflowed the card — it's hidden now, as is a lud16 identical to the nip05. A one-character "about" (fiatjaf's is literally "~") is noise rather than a bio, so it's skipped. Both remaining identity lines wrap. The inline ‹ chevron becomes a full-width Back button under the actions, matching every other page. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* First-run onboarding: a five-step wizard and a coach-mark tourAdam Soltys2026-08-021-0/+22
| | | | | | | | | | | | | | | | | | | Fresh devices land in a full-screen flow instead of the unlock screen: welcome → "do you have a nostr account?" (sign in brings wallet, name, and profile along; No mints a wallet on the spot) → claim a username (the background npub-default only surfaces a Keep button; a custom claim — or a restored login's recovered name — advances by itself) → pick a punk or upload a photo (nostr.build), published as the kind-0 name+picture → confetti. "Enter coinos" drops into a three-stop tour: the avatar menu, the Spending/Savings toggle, and the tabs with the swipe tip — each highlighted by a measured gold ring over a dimmed page. One time only (localStorage flag), with an "I already have a wallet" escape to the classic screen. New seams: names.namesClaimForm, messages.publishProfile. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Push notifications for payments and messages; offline Spending noticeAdam Soltys2026-08-021-0/+67
| | | | | | | | | | | | | | | | | | | | | | | The nwcpush notifier grows a second registration kind alongside NWC: a notify watch of what it can see without keys — kind-1059 wraps p-tagged at the user (DMs, direct invites), zap receipts (9735/9737), and wraps authored by the user's community channel keys (chat). It pushes a typed nudge, throttled per device (chat bursts collapse); the service worker shows a generic notification unless a window is visible, and tapping opens the app. The names registrar reports settled lightning-address receives server-to-server (token-gated /notify), so the common payment path notifies even with no nostr event in sight. The app registers silently whenever permission is already granted and keeps the watch current as communities change; a dismissible card on the chat home offers to enable it otherwise. Ark zap receipts (9737) join the relay whitelist so the payment watch can see them. Also: the offline Spending receive pane now says you're offline and offers a one-tap switch to Savings instead of spinning forever. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Avatars: no punk flash while profiles loadAdam Soltys2026-08-021-8/+36
| | | | | | | | | | | The punk is a statement about having no picture, not a loading state — in-flight profiles show a quiet empty circle instead. Known profiles persist (capped at 150, daily background refresh) so your own avatar and regular correspondents paint correctly on the first frame of the next session. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Header: wallet + avatar only; the avatar opens an identity menuAdam Soltys2026-08-021-17/+3
| | | | | | | | | | | The chat button leaves the header — the avatar's popup menu carries Edit profile, Settings, Messages, and Logout (lock()). The menu is available inside the chat takeover too, which now keeps the full header. Messages provides just the avatar node via the headerAvatar seam; the app owns the menu. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Profile: copy icon inside the npub box instead of a "Copy key" buttonAdam Soltys2026-08-021-3/+8
| | | | | | | | An npub isn't a key — no button, no label; just a small copy glyph right-aligned in the box. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Identity polish: 12-char npub default names, no ellipsis, copyable npubAdam Soltys2026-08-021-2/+3
| | | | | | | | | The registrar's auto-claimed username and every npub-fallback display name use the npub's first 12 characters, shown whole (no truncation dots), and the profile page's npub gets a copy button. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Own profile opens straight into the editor; avatar rightmost in headerAdam Soltys2026-08-021-36/+39
| | | | | | | | | | The Edit profile button is gone — your profile page renders the prefilled kind-0 form as soon as the published profile loads, with one Save. The header order becomes chat · wallet selector · avatar, via a dedicated headerAvatar seam so the avatar sits rightmost. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Punk default avatars, header profile button, owner channel creationAdam Soltys2026-08-021-15/+48
| | | | | | | | | | | | | | | | Everyone gets a face: profiles without a picture fall back to a coinos punk, picked deterministically by the pubkey's last byte — the same 64 webps and formula the coinos app uses (initials show through if the image can't load). Your own avatar moves from the chat home to the app header next to the wallet selector, opening your editable profile from anywhere. Community owners can add channels from the room's + panel: one owner-signed ChannelMetadata edition (CORD-03), and every member's channel switcher grows when the fold lands. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Profiles: view pages, editable own kind 0, zap recipients in historyAdam Soltys2026-08-021-9/+149
| | | | | | | | | | | | | | | | | | | Tapping any avatar or author name (chat rooms, DM threads, the chat home) opens a profile page: avatar, name, nip05, lightning address, about, npub, with Message and Pay actions (Pay runs the npub payment cascade). Your own profile — reachable from your avatar on the chat home — gets an editor for name, about, picture, and lightning address (prefilled with your coinos address); saving merges over the newest published kind 0 so fields we don't understand survive the round trip. Zaps now remember who they went to: the ark feature keys the recipient by what the movement already records (destination address or invoice) and history rows wear a clickable avatar chip that opens the profile. The messages feature exposes showProfile/profileChip seams so any feature can do the same. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Recipient search: usernames and npubs, in chat and the Send formAdam Soltys2026-08-021-18/+46
| | | | | | | | | | | | | | | | | | | | A shared engine (src/recipient-search.js) merges three ranked sources: an exact npub/hex paste, coinos usernames from the registrar's new /search prefix endpoint, and NIP-50 kind-0 full-text search on relay.nostr.band — the approach the major web clients take, since ordinary relays don't index profiles. Results dedupe by pubkey, fill avatars in one batched kind-0 fetch, and cache per query so narrowing never re-hits the network. Input is debounced 300ms and gated by a searchable() heuristic so addresses, invoices, and keys never trigger a search. Chat's New message panel narrows as you type and opens the thread on pick; the Send form shows the same candidates under the destination input and picking one runs the normal paste path (payment address → BIP-353, npub → zap). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat home: New message / Join / Create as real buttonsAdam Soltys2026-08-021-3/+3
| | | | | | | | They rendered as linklike text, indistinguishable from the section headings beside them; btn-sm gives them borders and weight. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat behind a header button, full-screen; move-panel polishAdam Soltys2026-08-021-6/+21
| | | | | | | | | | | | | | | Chat leaves the tab bar (which returns to its four evenly spaced tabs) for an icon button in the header next to the wallet selector. It now takes over the whole screen — no balance card, no tabs — with a back button on the chat home view, and the logo still leads back to the wallet. The generic tabs/tabContent seams this reverts to unused are removed again. Move panel: the direction toggle stretches across the card, and the "X sats in Spending" line is gone — the balance sits right above it. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat: device sync via Community List (13302) and Invite List (13303)Adam Soltys2026-08-021-4/+181
| | | | | | | | | | | | | | | Memberships and minted invite-link keys now follow the user across devices: both lists are NIP-44 self-encrypted replaceables (CORD-02 §8, CORD-05 §4), published under the wallet key (the cross-device constant) and the login npub when a signer is live. Merging validates the self-certifying community_id before adopting keys, keeps tombstones permanent, and lets the newest of added_at/removed_at win, so a stale device can never resurrect a community you left. Leaving is a two-tap control in the room's invite panel (the built-in coinos community is exempt) and publishes a guestbook Leave alongside the tombstone. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat v2: DMs, invites, and multi-community — coinos is the default, not ↵Adam Soltys2026-08-021-223/+709
| | | | | | | | | | | | | | | | | | | | | | | the only - NIP-17 private DMs (src/dm.js): kind-14 rumors in sender-signed seals under ephemeral wraps; interops with other nostr DM clients. Login signers gained encryptTo/decryptFrom so extensions and bunkers can seal to a peer; the inbox listens for both the login npub and the wallet key and publishes a kind-10050 DM-relay list for the wallet key when none exists. - Concord invites (CORD-05): mint shareable links (33301 bundle on relays, keys only in the URL fragment), join by pasting a link or opening v3.coinos.io/invite/…, and direct invites giftwrapped to an npub with the k-tag index hint. Bundles self-certify the founder before anything joins. - Multi-community: home view lists DM threads and communities; found your own community in-app (owner-signed genesis). coinos stays baked in as default. - Welcome DM: the names registrar DMs every first-time registrant from Adam's npub on claim (config: welcome{sk,message}; deduped in registrar state). Every new wallet auto-claims a payment address, so every new user gets one. - relay.coinos.io write policy now allows 33301/13302/13303. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Rebrand: hal → coinos v3Adam Soltys2026-08-021-3/+3
| | | | | | | | | | | | The app already presents as Coinos; this finishes the job in the repo: package name, README, GitHub link, code comments, and the stale locale lines that still explained the old "Hal Wallet" name (they fall back to the English tribute line). Kept: the hal-nwc-pouch IndexedDB name (an upgrade-compat identifier), the halwallet.app domain in the BIP-353 names feature (live infrastructure), and the Hal Finney tribute itself. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat: Concord encrypted community messaging, with a default coinos roomAdam Soltys2026-08-021-0/+415
Implements the Concord protocol (CORD-01..04) — private streams, the control-plane fold, guestbook membership, owner-rooted authority — and ships a built-in "coinos" community founded by Adam's npub (owner/admin). Messages sign with the nostr login identity when a signer is live, else the wallet's NIP-06 key; all encryption rides derived stream keys so remote signers only ever sign seals. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi