| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
|
|
|
|
|
|
|
| |
The Android app said a coinos user "isn't on White Noise yet" although
their KeyPackage was published: MDK will not invite an account whose
kind 10002 and 10050 lists it cannot find, and it looks on
relay.eu/us.whitenoise.chat and purplepag.es, where coinos never wrote.
The client now passes the account's already-signed lists along to those
relays (no signer needed, nothing rewritten), weekly and until both exist.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
| |
Tapping "Public key" now shows the npub as a QR above the text, for a
phone held up to the screen (White Noise, Amethyst, another coinos). The
bare lowercase npub, which every scanner takes.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
| |
reconnect
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
A group that misses a commit is stuck until it hears it, and a group
founded by White Noise can live on a single relay. Its subscriptions now
report a close to the chat watchdog, and one made while a relay was being
skipped as dead is rebuilt when that relay comes back.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
| |
MDK refuses relay.damus.io and relay.nostr.band outright (its retired
hosts), so a group founded here must not name them: relay.primal.net
takes damus's place. The UI test can also run against a deployed site.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Chat tab now speaks the protocol the White Noise app speaks, beside
Concord communities and NIP-17 DMs, without anyone having to pick one:
- A two-person group with no name is a direct message. It lands in the
same thread as that person's NIP-17 messages, and a reply goes back the
way their last message came. A first message goes by White Noise only
to someone whose KeyPackage another app published (a coinos wallet
reads NIP-17 on all its devices; an MLS group reaches one).
- Groups get rows of their own in the Messages list, a New group button,
an invitation card, members, add/remove/rename for admins, leave.
- Every wallet publishes a KeyPackage (kind 30443), so it can be invited.
src/mls.js is RFC 9420 for ciphersuite 0x0001 on the noble libs (no
WebAssembly), with the extensions-draft pieces Marmot needs
(app_data_dictionary, app_data_update, app_ephemeral, self_remove).
src/marmot.js is the Marmot layer: components, the account identity
proof, the 30443/444/445 event shapes and the group engine
(publish-before-apply, retained epochs, same-epoch tie-break).
State is per device, in IndexedDB (src/marmot-store.js). The whole stack
is one lazy chunk (72 KB).
Tested against the RFC 9420 vectors (tools/mls-vectors-test.js) and
against the Rust reference, MDK's wn CLI, at the protocol level
(tools/marmot-interop-test.js) and through the real UI
(tools/marmot-chat-test.js).
Not yet: attachments in these chats, push for group messages, the
app-message witness boost in fork selection.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
| |
It opened the history tab. Any open payment detail still closes with the
switch.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
| |
showSend flipped the wallet's tab to Send but left the screen where it
was; from the Spending settings page (where the co-operative exit lives
now) the form opened out of sight and the button seemed to do nothing.
Opening Send now always means the wallet screen.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
| |
It was one device-wide key, so a new account opened on whatever the last
one was reading (#gardenstr: the starter feed has the same id in every
account). Now keyed by the wallet, re-read when a wallet opens (the
feature outlives a sign-out), Popular when nothing is remembered, and the
old device-wide key is dropped. A feed opened from a link stays put.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- Pasted with the keyboard (not only the Paste button) it is complete
text: it advances at once, as a paste always did through the button.
- Typed and then left alone for 0.9s, it is checked quietly (names: our
registrar or BIP-353 DNS; zaps: the LNURL-pay endpoint answers) and the
form moves on only if something answers. A half-typed domain answers
nothing, so it just waits, with no error; finishing it moves on.
- tools/send-lnaddr-advance-test.js (live registrar/DNS, [email protected]).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
sending
- The recipient is a one-line textarea that wraps and grows (rows from
the text's length over the field's measured width), so a whole address
is in view in the field itself — no second copy in small type below.
Enter doesn't break it and pasted line breaks are dropped. Empty, it is
as tall as its hint (measured in the hint's own face), so that's whole
too.
- Past the recipient — the amount, a review, a Lightning/Ark
confirmation, a raw tx to broadcast — the history list below the send
pane is left out.
- tools/send-dest-test.js (390px and 1280px).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
new-post tint
- The new/edit feed form gets a Relays field (read this feed from these
relays only) and "Every post on these relays", which saves a firehose
feed (optionally curated) named after its relay and hides the people,
packs and topics it doesn't need. It used to take a hand-typed
/feed/all?r= link.
- The form's Back did nothing visible: opening it made no history entry,
so Back went to the page behind the feed and left the form up. The
editor (and the gear page's Spending/Savings view) are now part of the
navigation state.
- New-post tint 9% -> 16% green in light mode; dark mode unchanged.
- tools/feed-editor-relays-test.js.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
| |
It waited for half the row to sit in view for two seconds; scrolling
reset the clock and a replaced node lost it, so a tall post read in
passing or one the window remounted could stay green for good. Now the
first visible pixel starts a 3s fade (the row's background transition),
marked seen by id, whether the reader stays or scrolls on.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Measured in the live tab (screencast frames): back from a profile, the
feed's text was on screen ~200ms before its photo. The <img> was loaded
and complete on the first frame — a 3024px, 12-megapixel original that
Chrome re-decodes whenever the page is rebuilt.
- Post photos wider than the column at 2x are painted from an 1100px
WebP copy made once (fetch, createImageBitmap, OffscreenCanvas) and
kept in Cache Storage; it decodes in a few ms, decoding=sync, inside
the same frame as the text. GIFs and small pictures keep the original;
the lightbox opens the original. Profile banners use the same copies,
warmed on prefetch.
- corsFetch: primal's CDN caches its no-Origin answer without
Vary: Origin, so a CORS fetch after the <img> got that header-less copy
and failed — which had written blossom.primal.net, m.primal.net and
coinos.io off as 'no CORS', so their avatars never got local
thumbnails and painted late from the originals. A refusal is now
retried once past the cache before a host is blamed; the old list is
dropped (nocors-v2).
- DM list: the unread dot sits centred at the row's end, like the
communities' below, instead of beside the time.
- Balance card gear: the icon alone, no circle.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
| |
It was one device-wide localStorage flag, so whoever signed in next on a
till landed in the last owner's point of sale. Now it is keyed by the
wallet (still per device); the old flag is dropped since it can't say
whose it was.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- The "Accounts" pill on each balance face is now a gear. It opens that
face's settings: Spending leads with its coins (renewal, the
co-operative move to Savings, unilateral exit), then Security (lock,
change password), the recovery phrase, auto-logout; Savings adds its
public key. A wallet with no nostr identity also gets sign-in and
log-out there, since it has no profile page to hold them.
- The exit cost is no longer said under the balance; the Spending
settings state it, always, not only when coin chains run deep.
- The lone Manage link under the balance is gone (the gear is the way
in); warning notices that are about the coins link to the same page.
- The Accounts list, Add wallet and Delete all are no longer reached
from the wallet (Delete all stays behind profile > Log out > forget).
- Tests follow the gear: padlock-ask, lock-wallet and account-access
pass again; cooperative-exit-ui clicks the Spending gear.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A kind 3 is replaceable: publishing one built on a list we didn't find
wipes the real one wherever it lands. 2026-10-02, an Amethyst user with
398 follows (kept on her own relays and an archive) signed in to coinos
for the first time; the starter-follows seed asked only our relays, saw
nothing, and published Adam + coinos over her list.
- deepContactList: our relays, the profile indexes, the archives, the
person's own NIP-65 write relays, and Primal's signed copy (verified).
- Starter follows only for a key with no follow list AND no profile
anywhere ('new' meant new to coinos, not new to nostr).
- A follow, follow-many or mute made while we have never seen the list
does the deep lookup first and builds on what it finds.
- Settings > Nostr > Follow list: find older copies on history-keeping
relays and restore one as a union with the current list (nobody is
removed), for anyone already hit.
- tools/follows-overwrite-test.js: fake relay network, only an archive
holds the list; fails on the old code with the exact two-person event.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
BTCPay's NWC connector requires get_info, make_invoice, lookup_invoice
and list_transactions; we never offered lookup_invoice, so it refused the
connection string.
- ArkManager.lnLookup answers lookup_invoice from wallet state (by hash or
bolt11, either direction; pending/settled/expired/failed, preimage once
claimed). A retry's several actions on one hash defer to the furthest.
- The open app pushes a pending receive along before answering, so a
merchant polling sees it settle.
- The service worker now answers make_invoice and lookup_invoice too, and
claims a paid invoice's HTLCs during the lookup: a BTCPay sale settles
with the wallet closed. Its list_transactions reports receives as well.
- get_info and the 13194 info event list the new method.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
| |
The pill is thumb-sized now (16px, 12/24 padding) and rides above the
Post button on a phone. Drag it sideways or down and let go: it flies
off and stays away until more posts arrive than it was showing. A short
drag springs back and is not a tap.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
| |
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The server renders /nevent1 and /note1 pages with the thread inlined
(post, root, replies, kind 0s) and Open Graph tags; the client seeds its
thread cache from it and opens the thread on the first paint. Without
it, a pending frame holds the screen instead of the front door. Profile
lookups ask our relays and the profile indexes at once, streamed,
instead of one after the other behind five-second waits. A thread
opened straight from a link has no Back button.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
Arrivals used to wait behind the pill whenever the feed header was on
screen. They now go in above the first post with that post held where
it is, so the page grows upward and can be scrolled to before tapping
the pill. While the composer or another header field is in use they
still wait. The pill clears only when the reader scrolls up to the
newest post, not on the hold's own downward correction.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
| |
The form asks the ASP for a co-operative offboard quote (mining share +
service fee, minimum = fee + dust) for the address on screen, disables
Send for a balance below it and points to Lightning. A too-small amount
reads in words instead of the manager's internal error, and the
unilateral-exit note only appears when co-operation actually failed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
|
| | |
|
| | |
|
| |
|
|
|
| |
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
|
| |
|
|
|
|
|
|
|
|
| |
With no files beside it, relative punks/, locales/, nip46.js and jsqr.js
looked on the disk. From file:// they now come from v3.coinos.io (images
and scripts need no CORS; /locales/ now sends Access-Control-Allow-Origin
on the server), and standalone.html carries Public Sans inline.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The notifier now watches kind-7 reactions p-tagged at the user (opt-in
by an explicit flag, so older apps that can't word them stay quiet) and
sends zap receipts as 'zap' to apps that report the category, 'payment'
to older ones. Coinos zap receipts carry their amount into the push. The
service worker names the reactor when it knows them and stays quiet for
a muted one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
|
| |
|
|
|
|
|
|
|
|
| |
Replies (kind 1 and NIP-22 comments) are asked in their own batched #e
request beside the likes/zaps one and counted under every post of the
conversation they name; quotes ('mention') aren't replies, muted authors
aren't counted, and a sent reply counts at once.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
|
| |
|
|
|
|
|
|
|
|
| |
not its top.
It now walks history like the system Back (whose popstate restores the
scroll place); the profile page's Back does the same.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
|
| |
|
|
| |
Build the default Popular feed once on the server and let browsers verify and paint its signed events before slow media finishes. Keep custom relays, pagination, filtering, and relay fallback on their existing paths.\n\nAdd stale-while-refresh persistence, service-worker bypass, development integration, and unit/browser coverage.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
bands beside a portrait clip.
The shape comes from the post's imeta dim when it gives one (Amethyst,
Primal and others publish it), else from the clip's metadata fetched while
the row warms (3 s cap), and is remembered on the device. The box is as
wide as the column, never taller than 75vh; an unknown shape keeps 16:9.
tools/feed-video-aspect-test.js: 3:4 and 16:9 clips measured ahead, a 9:16
one shaped by imeta alone (its file served too late to probe), a broken one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WMMwWYJkPQxLgfMsY7hWcU
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
answer.
The disk cache held four feeds, so with more chips than that (or one never
opened here) a switch opened on nothing. Now:
- up to twelve feeds on disk: the four read last keep a page of 30, the
rest 5 seed posts (same 256 KB budget);
- once the feed on screen settles, every other feed with nothing on disk
has its first posts fetched ahead, one small request each, every 15 min;
- a feed with nothing on disk borrows matching posts (its people, its
topics) that open feeds already hold.
tools/feed-switch-seed-test.js: with 8 s relays, a fetched-ahead feed and a
never-opened topic feed both paint rows at once (fails on the old code).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WMMwWYJkPQxLgfMsY7hWcU
|
| |
|
|
|
| |
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WMMwWYJkPQxLgfMsY7hWcU
|
| |
|
|
|
|
|
|
|
|
|
|
| |
nostr.download, nostr.build.
A 2026-09-30 benchmark (4 MB mp4, 110 KB jpeg; upload then fetch, twice):
ditto took the mp4 in ~0.6 s and serves from ~120 ms; primal ~1.5 s;
nostr.download ~1-2 s but rejects a JPEG with data after its end marker
(motion photos); blossom.nostr.build ~5 s with ~600 ms first byte.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WMMwWYJkPQxLgfMsY7hWcU
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
then uploading; the pencil reads "New post".
ui.mediaProgress { stage, pct } (a render per whole percent) drawn as a
labelled bar under the reply and post composers, instead of only the
paperclip turning into a spinner. Upload progress comes from
XMLHttpRequest upload events (fetch() has none) in uploadPublicMedia's
new onProgress; injected fetchers (tests) keep the fetch path.
upload-progress-test: 1.2 MB at 400 KB/s climbs 0→100 in steps.
video-compress-test: the bar counts the shrink, then the upload.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
host.
No public Blossom host transcodes (nostr.build's and primal's BUD-05 /media
return the same bitrate), so a 15-20 Mbps phone clip stalled on playback.
src/video-compress.js re-encodes on the device with WebCodecs via
Mediabunny (a lazily loaded chunk, left out of the SW precache and the
standalone file): H.264, short edge 720, ~2.5 Mbps, moov first, audio
passed through, rotation baked in. Anything short of a clear win uploads
the original. A toast counts the shrinking down.
Media hosts: blossom.nostr.build first, nostr.download second (it was
unreachable for hours); a HEAD probe skips a host that doesn't answer
within 5 s instead of waiting out the whole upload timeout.
video-compress-test: 1080p 20 Mbps 5 s (landscape and rotated portrait) →
1.6 MB H.264 720p 2.49 Mbps with audio, moov first, in 2-3 s.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
up" after a handful.
#gardenstr: 5 posts across damus/primal/nos.lol/ours (they prune), 774 once
archive-keeping relays are asked too (ditto, nostr.mom, oxtr, nostrplebs,
nostr21, offchain) — topic feeds now read those. And a page whose posts
were all filtered out (replies, muted, spam) no longer ends the feed:
paging goes on from the oldest event the relays returned, up to three
asks per scroll. The quoted-note wide net gains ditto/nostrplebs/nostr21.
topic-depth-test (/feed/t/gardenstr): 9 posts then "caught up" before,
73+ and still going after.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
| |
your own feed again.
The Feed tab reopened whichever feed was last on — the session timeline —
and ‹ on it went to the chat list, so there was no way back to your own
feed. The tab now opens the last of your own feeds; ‹ on a feed opened
from somewhere (a timeline, a #tag, a pack link) steps back in history.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
article or comment, and in notifications.
Kind 1111 is the reply format for everything that isn't a kind 1 note:
uppercase E/A + K + P name the root, lowercase e/a + k + p the parent.
Threads now also ask for comments naming the root (#E, and #A for an
addressable root like an article), place each under its parent, and
draw them as posts. A reply to anything but a kind 1 note goes out as a
1111 with the root's scope and the parent's tags (copied from the
comment when the root isn't loaded); replies to kind 1 notes stay kind 1.
Comments that answer you show in Notifications.
comments-test (a real article with 4 comments; events caught at the
socket, nothing published): comments listed, reply to the article and to
a comment tagged per NIP-22.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
| |
The picture is fitted inside its box (object-fit: contain); on the phone
the box spans the column, so a tall picture (eve's 720x900) leaves bands
that used to open the lightbox. The tap is now hit-tested against where
the picture is actually drawn.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
are contenteditable.
Android keyboards (Gboard GIFs, stickers) only offer images to fields that
accept them, and Chrome says so for contenteditable, never <textarea> —
hence the greyed-out GIF key and "This app does not support images here".
<coinos-text> (src/rich-text.js) is a contenteditable that acts like a
textarea to the code around it (value, selectionStart/End, setSelection-
Range, placeholder), keeps text plain, and hands any pasted/dropped/
keyboard picture to onMedia — the paperclip's upload. The morph syncs its
value like a field's and leaves its own editing attributes alone.
composer-media-test: types like a textarea, strips pasted formatting,
a pasted GIF uploads and lands in the reply, still editable after repaint.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Back from a post keeps the feed's place.
- findNote: the reference's hints, its author's NIP-65 relays and ours,
plus a wide net of big public relays, all at once, first answer wins.
A real quote (SuiGenerisJohn → 0c5e0f08…) sat only on nostr.mom,
named by neither the nevent nor its author's relay list.
- A feed row whose quote isn't in yet shows the quote card with
"Fetching note…" / "Couldn't find that note" instead of a link;
the card replaces it once found.
- Opening a post remembers the scroll position like opening a profile
does; Back restores it instead of landing at the top of the feed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
| |
picture found later replaces it.
The quiet loading circle is capped at 1 s per face (a timer repaints when
it runs out); one miss is enough to remember someone as faceless; and a
room's warm-up adds members whose messages arrived after it first ran,
instead of reusing a warm-up that covered only the early history.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
after a reload, not a blank circle that turns into one.
Faceless answers were never persisted (they'd evict real faces from the
150-row profile blob), so every reload re-asked and showed the loading
circle until the relays said "nothing". A small pubkey->time list now
remembers them: no kind 0 on two asks running (a cold relay isn't enough),
or a kind 0 naming nothing; finding a face takes them off it.
room-faces-test --refresh: reload inside the coinos room, faces keyed by
author — 2 changed (wait→punk) before, 0 after.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Faces (profile, then the picture decoded) are warmed when the pointer is
over or presses a room's row, and while the chat list sits there; the tap
waits for them, 1.5 s at most, before the room replaces the list. A face
still loading in a room is the quiet circle, not a punk.
room-faces-test (fresh wallet, real coinos community): 57 faces flipped
punk → picture before, 0 after.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
|
| | |
|