aboutsummaryrefslogtreecommitdiffstats
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* Profile links paint whole on the first frame: the server renders /npub1…, ↵Adam Soltys2026-10-071-3/+34
| | | | | | | | | | /nprofile1… and /<name> with the kind 0, latest posts, follow counts and mentioned faces inlined (stale-while-refresh cache, 2 s budget), the app seeds its caches from it, and the big avatar never flashes punk art while a lookup runs A cold visit to a profile link showed a punk, '–' counts and no posts for 9 s. Server-side relay answers settle once events stop arriving (idle 400 ms) instead of waiting out a relay that never sends EOSE: a cold build is ~1.9 s. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* History: a Lightning payment still settling (a zap, mostly) shows at once as ↵Adam Soltys2026-10-072-6/+28
| | | | | | | | a pending Sent row with the recipient's face, and gives way to its completed row One-tap zaps now record who they went to, so their rows carry a face too. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Send suggestions: a name lookup's avatar is a quiet circle until its profile ↵Adam Soltys2026-10-071-3/+12
| | | | | | arrives — the default punk flashed in front of a new account's chosen picture Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop: the Send amount field takes the cursor as soon as it appears (once; ↵Adam Soltys2026-10-071-1/+21
| | | | | | never off another field, never on phones) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Swiping to Savings opens its Receive pane (the deposit address, no extra ↵Adam Soltys2026-10-071-6/+34
| | | | | | tap); Enter on Send picks the top suggestion, and Enter walks amount → review → confirm Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Merge branch 'worktree-agent-ad1d843e9e394974e'Adam Soltys2026-10-071-1/+3
|\
| * Feed: a picture with no column-sized copy is decoded ahead too, so its row ↵Adam Soltys2026-10-071-1/+3
| | | | | | | | | | | | | | | | | | | | | | paints it on the first frame Since column-sized copies (8249fbe), a picture small enough to keep (or a GIF) was fetched for its size but never decoded ahead: the row's <img> decoded it on sight, from the network again when the host says no-store. Decode the original ahead when there is no copy. (feed-live-test caught it.) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Merge branch 'worktree-agent-ab051145d709af327'Adam Soltys2026-10-071-4/+27
|\ \
| * | Popular: the single file opened from a disk does not ask file:///api/feedAdam Soltys2026-10-071-2/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The shared Popular snapshot is fetched from a relative /api/feed. Opened from disk (dist/standalone.html) that is file:///api/feed, a request for a file beside it that never exists (standalone-file-test: 'nothing looked for beside the file'). Only ask when served over http(s); the relay path covers the rest, as it already did for a failed fetch. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * | Feed URLs: the default feed is not opened (and fetched) a tick before the URL'sAdam Soltys2026-10-071-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A /feed?r=… (or any /feed/… link) set the feed view up synchronously but chose its feed in a setTimeout, so the first paint opened the remembered/ default feed — Popular since c89050e — and fetched the shared snapshot for it before switching. The frame now holds (header only) for that tick, the way a note link's pending frame does. public-feed-browser-test: custom relays bypass the snapshot again. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * | Communities: a room rebuilt with fresher keys folds its channels againAdam Soltys2026-10-071-1/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When our own community list came back with a channel key the local copy lacked (every community we create: its list entry carries the keys), the room was torn down to be rebuilt with them, but the wraps it had already opened stayed in seenWraps. The rebuilt room's subscription then skipped the relay replay, so its Control fold held only editions newer than the rebuild: a second channel showed up as the only one (no picker; general gone from the fold), and the guestbook lost its joins. Each room now remembers the wrap ids it opened and hands them back when it is rebuilt. chat-layout-test reaches Messages through the bottom nav. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * | Profiles: a remembered face beats a row asked for before the cache openedAdam Soltys2026-10-071-1/+7
| |/ | | | | | | | | | | | | | | | | | | | | | | Since the profile cache moved to IndexedDB, a profile asked for during boot (a restored profile page, offline or with relays failing) left a loading or miss row in memory, and the re-warm after the cache opened skipped any pk already present, so the cached name never showed (profile-draft-test: the editor reopened with an empty Display name). Placeholder rows without a name/picture (and without a real kind 0 behind them) now give way to the cached one. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Merge branch 'worktree-agent-a4c5f0908bc7757bf'Adam Soltys2026-10-071-5/+5
|\ \
| * | Emoji packs fetch again; a like paints before the author's relays are foundAdam Soltys2026-10-071-5/+5
| |/ | | | | | | | | | | | | | | | | | | | | | | | | | | Two fetchPack declarations shared messagesFeature's scope since the follow packs arrived (19ac1c4): the later one won, so adding an emoji pack from its chat link (and pulling the packs on a synced kind 10030) asked for a follow pack with undefined fields and always came back "bad pack". The emoji one is fetchEmojiPack now. reactTo awaited the author's relay list (up to 3.5 s for an author with none cached) before painting the reaction it promises "on screen before the relays answer"; the lookup now only gates the publish. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* / Profile cache: room for ~350 face thumbnails and 1500 rows now that it lives ↵Adam Soltys2026-10-071-2/+6
|/ | | | | | | | | | in IndexedDB The 320K thumbnail budget was sized for localStorage; on a phone that follows hundreds it kept ~34 faces and the rest churned (thumbnail made, evicted, original downloaded again). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Rebuildable caches move from localStorage to IndexedDB (cache-store.js)Adam Soltys2026-10-075-23/+312
| | | | | | | | | | | | | | | | | | | | localStorage is ~5M characters per site whatever the device, and a phone had filled it. Profiles, faceless list, reports, follow packs, profile pages, relay lists, the moderation baseline, community directory, link previews, video sizes/probes and search profiles (~3M on that phone) now live in IndexedDB, which shares the site's disk allowance (GBs). cacheStorage keeps localStorage's string API: reads from memory, coalesced write-behind, flushed on hide. Copies migrate on open and are removed once written. Boot waits for it (max 3s) beside the Ark store; caches read at construction re-merge on ready; an early write can't replace the stored copy. A copy an older build writes to localStorage later moves in on first ask. Wallet wipes reach it; private mode stays on localStorage. Read markers, drafts, follows, note threads and sync outboxes stay in localStorage on purpose (cross-tab consistency, early server-rendered seeding). Also asks navigator.storage.persist(). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Notifications: the face opens the sender's profile; faces of people you know ↵Adam Soltys2026-10-071-18/+28
| | | | | | | | | | | | | | | | | | stay cached; primal-hosted faces get thumbnails again - A notification's avatar now opens the actor's profile (the name and the rest of the row still open the note). - The profile cache held 150 rows evicted by fetch time, and a phone's feed churned all of them within twenty minutes, so a reload painted a punk and an npub for people you hear from daily. 300 rows now, and follows, DM peers and notification actors are evicted last (their thumbnails too). - corsFetch's "is the host reachable?" probe was answered from the HTTP cache, so any network blip blamed the host: a phone had ~100 hosts written off as no-CORS, primal, nostr.build and coinos.io among them, and those faces painted from multi-MB originals on every repaint. The probe now goes past the cache and the polluted list is reset (v5). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* DMs: file messages keep their key across reloads, tabs no longer erase each ↵Adam Soltys2026-10-071-24/+80
| | | | | | | | | | | | | | | other's cached messages, one-time re-open of the last two weeks of wraps The DM cache kept only text, so a kind-15 picture (an encrypted Blossom blob) came back after a reload as a bare link with no key. Every tab also rewrote the whole cache from its own memory, so a tab asleep since yesterday erased messages another tab had received, while the wrap log still marked them opened: those messages were never fetched again (a phone showed 2 of 4). Rows now carry kind 15's tags and merge by id with what's stored; the wrap log merges too. A one-time pass re-opens wraps from the last 14 days so damaged caches heal. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* White Noise groups reach every device of an accountAdam Soltys2026-10-062-17/+67
| | | | | | | | | | | | | | | An invitation adds all of a person's fresh KeyPackages (one per slot, at most ten) instead of one, and where our account is an admin a device that finds a sibling's KeyPackage not yet in a group adds it, so the Welcome reaches the other device through our own inbox. These are the same-account rules Marmot's multi-device direction marks as valid today; the device group and pairing it plans are not here. Verified against MDK (wn): a group with two coinos leaves of one npub plus a wn member, all three reading and writing (tools/marmot-multidevice-test.js). marmotClient takes an injectable store for tests. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Cordn group chats: MLS groups delivered through a coordinator (Amethyst 1.17 ↵Adam Soltys2026-10-066-25/+919
| | | | | | | | | | | | | | | | | | | | interop) src/contextvm.js speaks ContextVM (kind 25910 inside ephemeral gift wraps) to a coordinator; src/cordn.js is the protocol (KeyPackages with hex-text identities, the 0xC04D metadata extension, exporter-keyed ChaCha20 sealing, unsigned nostr-shaped envelopes with the sender as MLS AAD, cordn1 group refs, a record engine like marmot.js); src/cordn-client.js mirrors marmot-client.js with the same interface, so the Messages group screens drive both — New group gains a White Noise / Cordn toggle. Verified against @cordn/cli (ts-mls) on the public coordinator both ways, from the engine (tools/cordn-interop-test.js) and from the real app (tools/cordn-ui-test.js). mls.js: the OpenMLS required_capabilities rule for GroupContextExtensions now applies only to groups that carry one. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* README rewritten for today's coinos v3; build switches are COINOS_* (HAL_* ↵Adam Soltys2026-10-0517-364/+5
| | | | | | | still accepted); silent-payment leftovers removed Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* A quote inside a quote shows as a one-line preview (author + start of the ↵Adam Soltys2026-10-052-1/+24
| | | | | | | text) instead of a bare 'view note' link Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Feed: leaving via the bottom nav closes the composer (its words stay the ↵Adam Soltys2026-10-051-1/+8
| | | | | | | draft), so the Post button is back when you return Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Chat: a long attachment name truncates instead of scrolling the log sidewaysAdam Soltys2026-10-051-1/+1
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Images grid tiles are cut from the feed's own decode: scrolling All fills ↵Adam Soltys2026-10-051-16/+22
| | | | | | | the tile cache (3/30 → 22/30 tiles instant on #art) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Article cards: a dead cover falls back to the body's first picture, else no ↵Adam Soltys2026-10-051-2/+14
| | | | | | | cover (no grey box) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Profiles show their articles among the notes as cards (newest copy per ↵Adam Soltys2026-10-051-7/+26
| | | | | | | address), opened in full; the page cache keeps them as articles Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Audio links (mp3/m4a/ogg/opus/wav/flac/aac) render as a player, like AmethystAdam Soltys2026-10-052-0/+31
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Ark: say boarding is paused when the ASP asks an unmeetable minimum ↵Adam Soltys2026-10-052-0/+6
| | | | | | | (ark.coinos.io pauses boards pending an upstream captaind double-spend fix) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Feed Articles view: long-form posts (NIP-23) from the feed's ↵Adam Soltys2026-10-054-22/+133
| | | | | | | people/topics/relays as cards, own cursor + index; Popular keeps articles two others engaged with Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* nostr:naddr renders: article cards (cover, title, summary) that open to read ↵Adam Soltys2026-10-053-2/+115
| | | | | | | with headings, list/pack cards that open as feeds Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Custom feeds sync across devices: their own sync slot, newest edit wins, ↵Adam Soltys2026-10-052-5/+68
| | | | | | | deletions remembered Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Communities wear their icons: Vector's encrypted logo from the metadata, the ↵Adam Soltys2026-10-051-1/+39
| | | | | | | coinos logo for coinos Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
* Show cached communities immediately and simplify discoveryAdam Soltys2026-10-053-28/+323
|
* Show popular Concord communities on the Messages screenAdam Soltys2026-10-042-15/+33
|
* /migrate: a link that opens the coinos.io account moveAdam Soltys2026-10-041-4/+53
| | | | | | | | Fresh devices reach it through the wizard (in place of the Spending offer); an existing wallet gets the move page on its own once it can mint a payment address, and leaves it straight back to the wallet. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Feed pictures: a height-capped one's frame narrows with it (no empty bands)Adam Soltys2026-10-042-4/+5
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Feed pictures uncropped: the column's width at their own shape, height-cappedAdam Soltys2026-10-042-13/+7
| | | | | | | | | The 3:4 crop for tall pictures cut the top and bottom off comics. Now nothing is cropped; a picture is as wide as the column allows up to min(560px, 70vh) tall, and only one taller than that narrows. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Ark: a double-tapped zap no longer spends one coin twiceAdam Soltys2026-10-041-3/+29
| | | | | | | | | | | | A reconcile pass that began before the first zap took its coin handed it back as spendable (the server still said so) while the zap was in flight; the second zap picked it and the server refused: 'vtxo … already spent'. Coins whose state changed during the pass are left alone. And a payment refused for an already-spent coin now reconciles and pays once more instead of failing with the raw error. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Drop an unused timestampAdam Soltys2026-10-031-1/+0
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* CORS write-off only on a refusal corsFetch confirmed, not a body cut off ↵Adam Soltys2026-10-031-6/+6
| | | | | | | mid-download Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* CORS write-off only when the host is reachable: a dropped connection is not ↵Adam Soltys2026-10-031-2/+17
| | | | | | | a refusal Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Media grid: tiles from 360px square copies kept on disk, loaded at onceAdam Soltys2026-10-031-2/+78
| | | | | | | | | | A fast flick down the Images grid was a blank screen: every tile was a lazy <img> of the original (or the 1100px column copy) to fetch and decode. Tile copies are made once (from the column copy when there is one), kept in the Cache API and painted eagerly. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Relay panel: the hint says what changing relays does and doesn't changeAdam Soltys2026-10-031-1/+1
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Profile: tapping the avatar opens the picture full sizeAdam Soltys2026-10-031-1/+6
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Relay panel: plainer wordingAdam Soltys2026-10-031-2/+2
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Popular reads where the reactions are: ditto, nos.lol, primal, oursAdam Soltys2026-10-032-7/+24
| | | | | | | | | | | Measured: ditto held 94% of distinct reactions (and keeps a month of them); damus capped asks at ~300, pruned in a day and added nothing. Everything (raw firehose) gets its own list without damus (empty answer to a bare kind-1 ask) or ditto (~30% Mostr-bridged posts). A saved list equal to the old or current defaults follows the defaults. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Feed: a tall picture fills a 3:4 frame as wide as the column, not a skinny stripAdam Soltys2026-10-032-2/+10
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Media pager: a button opens the post itself (count of replies on it)Adam Soltys2026-10-0321-0/+26
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Media views: one empty answer is not the bottom; a crawl reads on until it ↵Adam Soltys2026-10-031-15/+27
| | | | | | | | | | | | finds a few A single empty relay answer (a timeout, a frozen socket) marked a feed's media finished for a day — 'You're all caught up' after four videos. Now it takes three in a row, old unconfirmed ends are ignored, and a crawl reads up to five pages until it has six new items of the mode. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR