aboutsummaryrefslogtreecommitdiffstats
path: root/src/i18n.js
Commit message (Collapse)AuthorAgeFilesLines
* The wallet's push notifications are worded so Chrome's spam model lets them ↵HEADmasterAdam Soltys7 hours1-1/+4
| | | | | | | through. "Any way to stop classifying v3 notifications as spam? I've seen this a few times now" (Adam, 2026-11-03, phone: "Possible spam — Chrome detected possible spam from v3.coinos.io", Unsubscribe / Show notification): Chrome on Android scores every web notification's title and body with an on-device model before showing it, hides it behind that warning above 90 of 100, and — nine warnings in a week on a phone whose engagement with the site is under 50 — revokes the site's notification permission outright (Chromium kAutoRevokeSuspiciousNotification, enabled by default). The model is a text classifier trained on Gemini-made examples of scam notifications, and our lines were their very shape: "Payment received" 95, "Incoming payment / Someone is trying to send you money…" 99, "Payment request / An app is asking your wallet to pay…" 99, "alice is calling / Voice call. Tap to answer." 99, "New message / You have a new private message." 92, "alice / sent you a message." 95, "New reply to your post / <text>" 98, "alice reacted ❤️ / to your post…" 97. Desktop Chrome runs the same model (without the warning) and reports each score to chrome://histograms, so the lines were measured rather than guessed — ~200 candidates on Chrome 156's model: "sats" reads as money without reading as a payment scam, "payment" doesn't; a sender's name in the body of a message or reaction line tips it over, "New chat" / "<name>" doesn't; any "reply" title is 96–99; a reply's own text is out of our hands (an @name or a link in it scores 97+), so it no longer rides along; "Calling" / "<name>" is 11–29 where every "<name> is calling" is 80–99. src/notify-text.js holds every line, with the measurements; the worker, the background responder and the renewal warning draw from it. The new lines score 8–46 (the shortcode reaction 67). tools/notif-spam-score.js re-measures them in a throwaway Chrome (SystemNotifications off, so nothing reaches the desktop) and fails at 90 — run it before changing any of them. On the phone that already warned, "Show notification" then "Always allow" marks the site trusted and stops both the warning and the revocation count Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6TFgisGKUDhdStLUvs
* The front page has a door for a wallet made elsewhere: "Restore from twelve ↵Adam Soltys34 hours1-0/+2
| | | | | | | words", straight to the phrase field. "Signing in on another device … it was hard to find how until I realised you click to make a new wallet, where then you get the option to use the seed phrase for an existing wallet" (user feedback, 2026-11-02): the import used to hide as a line under the freshly minted words behind "Create a new wallet". It sits below the sign-in buttons with the migrate door, and the step it opens is titled "Restore your wallet" rather than "Set up your wallet". tools/onboard-backup-test.js checks the door, that it opens on the phrase field with no minted words, and that a typed phrase opens the wallet Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6TFgisGKUDhdStLUvs
* Comments scoped to a web address show with the page they are on. DaddyTube ↵Adam Soltys40 hours1-0/+1
| | | | | | | posts NIP-22 comments (kind 1111) on a film's IMDb page: an I tag naming the address, no e or E tag. Adam's own ("Charming and wholesome", 2026-11-02, on relay.primal.net) showed on neither his profile's Replies tab — the profile page never asked for kind 1111 at all — nor in the Conversations view, whose warm-up pass asked for posts and reposts rather than the view's own kinds, and the refresh that asks properly is skipped for half a minute after it. The profile asks for comments now, the warm-up pass asks for what the view shows, and a comment with no post to show above it carries the page it is on where "Replying to" would go — "Comment on imdb.com/title/tt32565993", linked, or the comment's own alt tag when it has one ("Comment on Sheep Detectives (2025) in DaddyTube") — in place of the bare "reply" tag. Also, a report naming a post as 'other' with the author's bare p tag beside it counted as a report of the PERSON (an 'other' e tag didn't count as naming a post), and two such from follows folded everything the author wrote; every post named now counts. tools/web-comment-test.js plays all of it against a fake relay Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6TFgisGKUDhdStLUvs
* A clip whose file its host no longer has says so where the player stood, ↵Adam Soltys2 days1-0/+1
| | | | | | | with the file's link, instead of sitting as a dead player under "Tap to play". A post's video "won't play" (Adam, 2026-11-01): the mp4 had been deleted from Primal's blossom, which answers a 404 with no CORS headers, so the probe couldn't read the status and the box waited for a tap that loaded nothing — no client renders it (the reply under the post says as much) and no other blossom host has the hash. The player is the first to know: its original failing now tries the server's copy once (a file the browser can't decode fails the same way, and the copy plays that one), and the copy failing too marks the clip gone for a day — the line and the link in the box, its cover, play button and controls off, a short box; the next paint of the post says it at once with no request, the media warm-up and the in-view hook leave it alone, and the videos grid leaves it out as it did a 404 the probe could read. Outside the feed the box used to be hidden on an error before anything was said; it gets the line too. tools/video-gone-test.js serves the clips from a second origin without CORS, one of them a 404, and checks the line, the untouched live clip and the silent repaint Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6TFgisGKUDhdStLUvs
* A profile (kind 0) is never written over one we failed to find. 2026-10-30, ↵Adam Soltys4 days1-0/+11
| | | | | | a long-time nostr user signed in with his key for the first time; our relays had never seen his kind 0 (it lived on ditto, snort and oxtr), the 3 s lookup came back empty, and the payment-address publish went out as {lud16, nip05} alone: name, picture and banner gone from every relay (nicstazzema, shown as npub1yk2lkr7). An empty quick lookup now widens to the same search the follow list got after its own overwrite (indexes, archives, the key's own write relays, Primal's signed copy) before anything is written, once per key per session so a brand-new key's first publish waits once. For anyone already hit, the profile editor offers "Look for older copies": a kind 0 from a history-keeping relay fills only the fields still empty in the editor, and Save publishes it. tools/kind0-overwrite-test.js plays the incident against a fake relay network where only an archive holds the profile Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Signer wording no longer names Amber: the Android login reads "Sign in with ↵Adam Soltys6 days1-5/+5
| | | | | | | a signer app", Messages offers "Connect signer", and the login hint says it works with remote signer apps, since Amethyst and others can sign too Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6TUeqTyZB8eXLGymUY
* Scheduled posts: the composer's clock button opens a "Post at" time (an hour ↵Adam Soltys6 days1-0/+7
| | | | | | | ahead, on the quarter hour) and turns Post into Schedule. The note is signed now with that created_at, so a remote signer asks while you're there, and handed to the notifier, which publishes it at that time; nothing reaches a relay before then. What's waiting shows as "Scheduled (n)" under the composer and on your profile, each with Cancel (a kind 5 to the notifier, so it never goes out); one cancelled on another device leaves the list at the next status check Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6TUeqTyZB8eXLGymUY
* A gift link names its sender: the link carries the sender's nostr key, ↵Adam Soltys7 days1-0/+3
| | | | | | signed over the gift's code (#f=…, beside the note), so the claim screen shows "From <name>" and claiming follows them. A signature that doesn't match the code names nobody, so a link can't be passed on as someone else's gift. "Show it's from me" is ticked by default when making a gift, and unticking it is remembered; the gift's record keeps the sender, so View and Copy link again keep it too Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Payment address and Change username are one card: the name sits in an ↵Adam Soltys9 days1-0/+1
| | | | | | | editable field beside @domain with Copy address and Release; typing a different name swaps those for the "old address stops working" line, Cancel and "Change to <name>" Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QjVvE4YAcK3AGwV7kZXeN4
* An Ark gift's claim button just says "Claim it now" (no "(instant, no ↵Adam Soltys9 days1-0/+1
| | | | | | | fee)"); an on-chain gift still shows its network fee Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QjVvE4YAcK3AGwV7kZXeN4
* Gifts carry a note: an optional "Add a note" when making one, quoted above ↵Adam Soltys9 days1-0/+1
| | | | | | | the amount for whoever opens it. It rides the link after the # (#m=…), so no server sees it; the gift's record keeps it, so Copy link again and View include it; with a note the QR is byte mode Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QjVvE4YAcK3AGwV7kZXeN4
* A gift opened into a new wallet goes on, once its seed is written down, to ↵Adam Soltys10 days1-0/+2
| | | | | | | the first-run steps: pick a username, then a picture and a cover ("Not now" lands in the account the gift arrived in). Also fixes Verify backup on the gift screen, which crashed (pickConfirm wasn't passed to the gifts feature) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QjVvE4YAcK3AGwV7kZXeN4
* Feed clips with a mouse: a big play/pause in the middle on hover that plays ↵Adam Soltys10 days1-0/+2
| | | | | | | or pauses in place, a click on a playing clip pauses it (a paused one still opens the pager), and a tall clip is held to three quarters of a computer screen with its box narrowed to the clip's shape Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QjVvE4YAcK3AGwV7kZXeN4
* A closed wallet finishes the Lightning sends an earlier wake left in flight, ↵Adam Soltys11 days1-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | instead of calling the invoice "already paid" with no preimage and locking its coin until the app opens PullCap's night of 2026-10-23 (hourly 1-sat NWC requests to a closed iPhone PWA): three of fifteen hours went wrong the same way. The push woke the worker, it reserved the coin and wrote the ln-pay action to the mirror, and the phone stopped it before the ASP was ever asked (no cosign in captaind's log for those minutes). The client's retry ten minutes later hit the manager's duplicate check, "this invoice was already paid or is being paid", published as an INTERNAL error that the client read as paid — hours before the money moved. And since the stuck action held the wallet's only coin, the next hour's request (a different invoice) found nothing spendable and fell to "Open Coinos to approve". Everything settled at once when the app opened at 07:12 and resumed the actions. - nwc-respond.js: pay_invoice first looks for a send already on the books for this invoice — finishing one in flight and answering with its preimage, repeating the preimage of one already done (nothing new on the spend log) — and before paying a new invoice drives any other stuck send to completion so its coin comes back. tendLnPays() does the same on every wake, lookups included, and hands back "Payment sent" lines for what settled. rec.pendingPays remembers which connection a send belongs to (the action is the manager's); the app's mirror rewrite carries it. - manager.js: the duplicate check says "already paid" only for a settled send, "already in progress" for one on its way. - features/nwc.js: the open app answers a repeated invoice from the local action (preimage when settled, an honest "still in progress" otherwise) before asking the ASP about a sibling device. - sw-nwc.js: one push at a time over the shared mirror (Web Lock), so a client's lookup + retry seconds apart can't double-drive one send. A diary of what the worker did — each push, each ln-pay step as the mirror saves it, every notification shown or refused, the fallback taken — is appended line by line to IndexedDB (nwc-bg.js appendBgLog), so a worker the phone stops mid-push leaves its last step behind. Settings → Notifications → "Background activity log" copies it. - tests: nwc-sw-test covers the four resumed-send cases; sw-push-quota mocks the new seams and its "suspended app" case now expects the stand-in-first order shipped in 91dbee4 (it had been failing since). Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Amber sign-in on Android works past the first request, and a migrated ↵Adam Soltys11 days1-0/+2
| | | | | | | | | | | | | | profile no longer keeps its released placeholder address Jarryd (DM, 2026-10-24): on Android he could not sign in with Amber and had to paste his nsec, and his profile page showed the temporary name he had picked while the editor showed his real one. Amber: Chrome lets a page open another app only on the heels of a tap. The Sign-in tap carried the get_public_key request, but the request the login fires once the key is back (decrypt the backup, sign the relay list…) had no tap behind it, so Chrome dropped the nostrsigner: navigation with a console warning the page never sees ("Navigation is blocked") and the card spun forever. Reproduced on Adam's Pixel 9 with Amber 6.6.9 (Amber 4.1.3 did not even parse the web request). Now a request without a user activation behind it waits for one: the card says the signer has another request and offers an "Open signer app" button that launches it from the tap; a launch that leaves the page in front (never hidden) is treated as blocked too and gets the same button. The clipboard is still read on return (that part worked). Profile: the migration released the placeholder name and repointed lud16/nip05 to the new one, while the legacy-avatar import ran at the same moment, read the same old kind 0, and republished it nine seconds later with the placeholder address back ([email protected], dead on both coinos.io and v3). Kind-0 publishes now go one at a time, merge over the newest copy this session sent, and are stamped strictly later than it (relays keep the lower id of two with the same second). The profile page shows the claimed address instead of a same-domain name that is no longer ours, and once the domain confirms the old name is dead it repoints the kind 0 in the background (healStaleAddress), so zaps to the published lightning address reach the wallet again. tools/profile-publish-race-test.js plays the migration's two publishes at once against an in-memory relay. tools/amber-login-test.js and identity-test pass; name-migration-test and avatar-profile-test fail the same way on the previous commit. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Deep coins are renewed under every tier, free of the base fee, before the ↵Adam Soltys12 days1-1/+1
| | | | | | | | | | | | | | | | | | | server's depth cap strands them A coin's exit depth grows by one per off-chain hop; the server refuses to cosign a spend of a coin at max_vtxo_exit_depth (100), so a wallet paying hourly from one change chain has an unspendable coin within days. Survey of the ASP's 2,279 unspent coins: median depth 7, 154 coins past 40 holding 7.7k sats, five already stuck at the cap. The server now waives the refresh base fee when every input is at its deep_waiver_depth (60; ArkInfo.fees.refresh carries it). The client mirrors that in refreshFee, never selects a capped coin as an input (the shortfall message says why), and flattens deep coins whatever the custody tier: the open app in a round of their own, the worker with a standing order two blocks out per coin. The default tier's copy names the one exception. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* iPhone: a push shows its line first and the outcome replaces it; a crash ↵Adam Soltys12 days1-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | loop on open lands in safe mode; a closed-app payment is one history row PullCap's night of 2026-10-22 on an iPhone: four hourly payments made while closed, no notification for the fourth, then no more wake-ups until the app was opened — WebKit's silent-push quota. APNs accepted every push (no 410); the device had stopped listening. The stand-in line went up at the END of the push handler, after a payment that can take most of the budget, and a worker stopped before its last line showed nothing. On an Apple endpoint the line now goes up first and the outcome ("Payment sent") replaces it. The same phone then crashed on every open ("A problem repeatedly occurred"). An inline guard counts page starts before the app runs; the app clears the count after eight seconds alive or a clean leave, and notes the boot phase it reaches. A third start in a row opens in safe mode: no automatic Ark connection, a notice naming the last phase, "Open normally" and "Copy report". Every payment the worker made showed twice once the app opened: the worker's own ln-send row (merged from the mirror) and the "while closed" note the app adds from its spend log. The note now stamps the existing row, and lnFoldedIds hides a twin that still forms. The balance was never counted twice — it comes from the coins. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Automatic renewals only when worth it (fee under a tenth of what renews); ↵Adam Soltys12 days1-1/+1
| | | | | | | | | | orphan HTLC coins are settled by the server's answer Adam's wallet renewed a 1,000-sat coin past its expiry plus four bits of change for 301 sats — the expiry trigger had no floor, only the depth trigger did. Now every automatic renewal, under either renewing strategy, is skipped when the fee would exceed a tenth of the coins it renews; they stay spendable, the server honors them, and the strategy card says so. Reconcile: five 22-sat HTLC-send coins sat 'pending' for days — their Lightning payments' actions had been pruned, and an unheld pending coin was only asked about when it was a plain pubkey coin. HTLC orphans are asked about now too: spent is spent; one the server still holds open stays pending (an HTLC coin is never this wallet's to spend). tools/ark-htlc-orphan.test.js. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Manage page: the card is "Custody strategy"Adam Soltys12 days1-1/+1
| | | | Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Manage page: Renew, Withdraw and Exit sit under the coin table and act on ↵Adam Soltys12 days1-2/+4
| | | | | | | | the ticked coins; a unilateral exit can be partial; the explainers moved to the confirmations Adam, 2026-10-23: the three buttons belong right below the table so it is clear they act on the selection, "co-operative exit" is Withdraw and "unilateral exit" is Exit, Exit names the ticked total and takes just those coins, and the explainer cards were a wall — they now appear where the action is decided: the renewal text and fee schedule on the Renew confirmation, the withdraw note on the form it opens, the exit cost comparison on the Exit confirmation. The page is the coins, their three buttons, and the custody strategy. The buttons stay (disabled) while every coin is in a round. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Spending settings: the coins first, then the custody strategy as a drop-down ↵Adam Soltys12 days1-1/+1
| | | | | | | | that describes only the chosen one Adam, 2026-10-23: three descriptions at once were a wall of text. The card now sits between the coins table and Renewal, is a select of the three strategies with their prices, and shows one paragraph — the chosen strategy's. The intro is two sentences shorter. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Custody card: drop "Coinos holds it for you"Adam Soltys12 days1-1/+1
| | | | Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Custody card: a full stop where the colon wasAdam Soltys12 days1-1/+1
| | | | Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Custody card: "paying still works" (paying and withdrawing are one thing; ↵Adam Soltys12 days1-1/+1
| | | | | | receiving goes without saying) Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Co-operative exit takes the ticked coins: a subset on the Manage page goes ↵Adam Soltys12 days1-0/+4
| | | | | | | | on-chain as exactly those coins Adam, 2026-10-23: the checkboxes only fed Renew; the exit button always prefilled the whole balance. The manager's offboard always took a coin list, and the fee quote prices each coin by its own expiry, so the page now passes the selection through: the card says which coins will move and prices their total, the exit form shows "N selected coins · amount" instead of an amount field, the quote is for those coins, and no fresh coin is split off first. Nothing ticked (or everything) still means the whole balance, with the editable amount as before. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Custody card: plain words — "Allow coins to expire", "Minimize renewal ↵Adam Soltys12 days1-10/+10
| | | | | | | | cost", "Minimize exit cost"; no timelocks, rounds or "the old Coinos" Adam, 2026-10-23. Coins "expire"; the exit is "yours until then"; what a renewal buys is said without naming the mechanism. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Custody card copy: "coin", not "Spending coin"; Coinos capitalized; the ↵Adam Soltys12 days1-7/+7
| | | | | | | | default tier says the exit stays until a coin's timelock runs out Adam, 2026-10-23: "Coinos holds my coins" read as if the holder never had a unilateral exit. They do, until the timelock runs out; only then does Coinos hold the coin. The option is now "Coinos holds my coins once they expire", its description says so, and the intro says what the timelock buys and what renewing keeps. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* The third custody tier keeps exits cheap by depth, not by date: "Keep my ↵Adam Soltys12 days1-3/+3
| | | | | | | | | | exit cheap" renews a coin once its history is four hops deep Why: a unilateral exit publishes one on-chain transaction per off-chain hop, so depth — not age — is what makes an exit expensive, and a renewal a week before expiry flattens exactly the same history a renewal in the last hours does. The week-ahead "early" tier only guarded against the server being unreachable at the very end, which is not the case worth selling. (Adam, 2026-10-23.) exit = self (last-hours renewal, free bracket + base, the same grid-snapped backstop) plus: any coin whose genesis chain is 4+ hops deep is renewed in the next round the app runs, paying the top bracket + base — but only when that fee is under a tenth of the coin (flattening a 21-sat coin for 300 sats helps nobody; its exit is uneconomic anyway). Deep coins ride along with an expiry renewal when one is due, or get a round of their own. The server-side backstop stays near-expiry only: depth changes only while the wallet transacts, i.e. while the app is open. A stored 'early' reads as 'exit'. Card copy says what the hop count means and what the two prices are for. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Custody is a choice, and coinos holding the coins is the default: nothing ↵Adam Soltys12 days1-0/+16
| | | | | | | | | | | | | | | | | | | | renews on its own and no renewal fee is paid unless the user opts in Why: renewal fees were "money passively draining" to people who thought they had a custodial wallet (Stacker News, 2026-10-22). Measured over Sep–Oct: 84% of what users paid came from the client's own consolidation round at 20 coins (0.2% + 300 on every fresh coin), the rest from 300-sat rounds that each cohort of Lightning-received coins (30-day pool lifetime) triggered on its own schedule. The ASP itself honors a coin past its timelock — rounds and offboards never checked expiry, and captaind's allow_expired_arkoor (now on at ark.coinos.io) lets arkoor spends through too — so expiry only ever meant "the exit is gone", which most people coming from v2 never had. Settings → Spending gets a Custody card with three tiers: - coinos holds my coins (default): no renewals, no fees; a coin past its timelock shows as "held by coinos", stays spendable and receivable, and is left out of a unilateral exit (there is nothing on-chain for it to take). - Keep my own exit: renew in the last hours (free bracket + base), the server backstop registered 36 blocks out and snapped to a 48-block grid so every wallet's orders share one round. - Renew a week early: 1008 blocks out on a 144-block grid (0.1% + base). renewPolicy() in ark/manager.js is the one table; the app, the service worker (the mirror carries the tier) and the Manage page all read it. Only shown on servers that honor expired coins (presets carry honorsExpired); elsewhere renewal stays automatic. Manager: honorsExpired makes a past-timelock coin ordinary money (balance, selection, receive validation via acceptExpired) while a server refusal (expiryRejected) still excludes it; such coins spend LAST so an older build on the receiving side almost never meets one. A once-per-wallet rescan re-reads the mailbox and adopts coins older builds refused as expired, un-forgets expired dust, and clears stale refusals. The refresh gate that retired a renewal of expired inputs is gone (the server accepts them; the Manage page's Renew of exactly those coins was failing silently). Automatic consolidation is gone; the send cap goes 24 → 48 coins; small change (<1,000 sats) folds into a renewal that happens anyway. Server (cs:~/ark/captaind-main.toml, restarted): allow_expired_arkoor = true; pool vtxo_lifetime 4320 → 8640 so Lightning-received coins live as long as the rest. Tests: tools/ark/custody-test.js (policies, honoring, ordering, grid snap, validator), tools/ark/custody-ui-test.js (the card, held coins, exit count, switching), nwc-sw-test updated for the tier the worker reads. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Timed reactions sit on the seek bar at their moment, and the usual buttons ↵Adam Soltys2026-10-201-1/+1
| | | | | | | | | carry the time The "at this time" reply/like/zap buttons are gone, and with them the panel they made over the pager. A reply, like or zap made from a post's own buttons (the feed's, or the pager's ♥ ⚡ and post) while its clip has played is about that moment; the reply box says so and its × makes it about the whole post. What was said, reacted or zapped at a moment sits over the bar at that moment (a custom :emoji: as its picture, from the reaction's own tag; it was showing as :cb-rofl: text), a tap goes there and says who and what, and in the pager it floats up off the bar as the clip plays past. Your reaction no longer turns the count red, only the heart. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Posts: a relay named in a post (wss://…) is a link to what's on it — the ↵Adam Soltys2026-10-191-0/+1
| | | | | | | raw firehose of that relay alone (/feed/all?r=…). Trailing punctuation stays outside the link. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Profiles: past streams move off the top into a Streams tab (beside Posts and ↵Adam Soltys2026-10-191-0/+1
| | | | | | | Replies, shown once they've streamed), as the Live chip's grid of tiles. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Add timestamp comments, reactions and zaps with audio waveform seekingAdam Soltys2026-10-191-0/+3
|
* Streams: Delete recording, and Past streams that scroll on.Adam Soltys2026-10-191-0/+4
| | | | | | | | | - **Delete recording:** your own ended stream's page has the button. The live server lets the recording go, and the stream is announced again without it, so other apps drop the link too. A deleted one leaves Past streams and says the streamer deleted it. - **Admin:** the Take down button no longer shows on the admin's own streams. - **Past streams** scroll on: 24 at a time as the grid's foot comes near, then older ones from the relays (before the oldest held), until a page brings nothing. They're no longer cut off at a month. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Screen sharing. In a call: Share screen in the call's bar (where the browser ↵Adam Soltys2026-10-191-0/+3
| | | | | | | can — desktops) puts your screen in your camera's place, or into the call if your camera's off; Stop sharing, or the browser's own, brings the camera back or stops the picture, and the other side's view follows (a picture that stops coming is hidden). Live: Share screen / Back to camera on the broadcast bar switches without stopping the stream; the browser's Stop sharing goes back to the camera instead of ending it, and a cancelled screen picker leaves the camera going. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A voice call can turn video: Turn on camera in the call's bar puts your ↵Adam Soltys2026-10-181-0/+1
| | | | | | | camera in (a renegotiation, NIP-AC's kind 25055); the other side sees you at once and gets the same button for theirs. The call's sound carries on throughout. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams on coinos's server: a ⚑ Report button (what's wrong, a note) for ↵Adam Soltys2026-10-181-0/+20
| | | | | | | anyone signed in, and Take down for the admin (asks whether to bar the account too); a taken-down stream says so and plays nothing. Go live asks the server first: a name claimed less than a day ago is told when it can, and a barred account that it can't, Start off. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams: one our live server has ended reads ended, whatever its last ↵Adam Soltys2026-10-181-0/+3
| | | | | | | announcement says (an app closed mid-stream never says so, and it read live for an hour with no way to stop it); its host gets End — on the stream and on their profile — which publishes the ended announcement with the recording. Each announcement is now newer than the last to the second (an ended stamped the same second as the live before it lost to it). A recording that is a web page (zap.stream's Rumble links) gets a Watch the recording link instead of a player that can't play it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Sign media uploads with the user's Nostr login identityAdam Soltys2026-10-181-0/+1
|
* Past streams: under the Live chip, the feed's streams of the last month that ↵Adam Soltys2026-10-181-0/+2
| | | | | | | left a recording (newest first, when each ended); a profile lists its person's too. A tap plays the recording. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A Lightning invoice from Receive says to keep coinos open until it's paid ↵Adam Soltys2026-10-181-0/+2
| | | | | | | — paid while coinos is closed, the money goes back to the sender — and that it lasts an hour (ark.coinos.io's invoices now expire in 1 h, not 48); when the hour is up the QR gives way to "expired" and a New invoice button. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Settings → Wallet → Transaction history: Export CSV — every payment in ↵Adam Soltys2026-10-181-0/+3
| | | | | | | Spending and Savings as a line of a CSV file, oldest first: date (UTC), account, type, rail (Lightning, Ark, on-chain), what was paid, its fee, the change to the balance and its worth in your currency at the time, status, the transaction or payment hash, who it went to, the invoice. A failed payment is left out; a renewal is its fee. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live streams have their own chip, after Videos: a grid of the feed's streams ↵Adam Soltys2026-10-181-0/+2
| | | | | | | on now, a red dot on the chip while someone in the feed is streaming — no longer a strip above every feed's posts. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A call from someone you don't follow and haven't written to no longer ↵Adam Soltys2026-10-181-0/+2
| | | | | | | vanishes: it doesn't ring, but it's a missed call in your conversation with them, saying it didn't ring and why, a tap away from calling back (with the app shut, the worker notes it for the app, without a notification). A muted person's still leaves nothing. A logged call no longer counts as having written to someone. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Call history: each call is a row in its conversation — Outgoing / Incoming ↵Adam Soltys2026-10-181-0/+11
| | | | | | | video call · 4:12, Missed, Declined, No answer, Cancelled, Busy — a tap calls back. Kept like a message and sent to our own inbox (kind 1405, gift-wrapped to us alone) so our other devices list it; a call logged by two of our devices shows once, by its call-id. A call that rang while the app was shut and went unanswered is a missed call when it next opens. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Calls ring a closed app: the notifier wakes the phone for a call offer, the ↵Adam Soltys2026-10-181-0/+1
| | | | | | | service worker fetches the offer's wrap, opens it with your key and rings — "Alice is calling", until answered or missed — for someone you follow or talk to; the tap opens coinos ringing with the offer it kept. A call answered from a push still connects: the caller sends its candidates again once answered. Settings → Notifications → Calls. Also: the worker's DM key mirror retries when the wallet's keys aren't there yet (it waited five minutes). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Allow custom Blossom servers for attachments and post mediaAdam Soltys2026-10-181-0/+6
|
* Voice and video calls in DMs (NIP-AC, as Amethyst, nospeak and Noscall speak ↵Adam Soltys2026-10-181-0/+26
| | | | | | | it): 📞 and 🎥 in a conversation's header; a call from someone you follow or have written to rings over any page (tone, buzz, a notification when the app is out of sight) with Answer and Decline; mute, camera off, switch camera, minimize to a bar, hang up. WebRTC device to device (DTLS-SRTP), set up by signed messages in ephemeral gift wraps to the DM inboxes; TURN from coinos's live server (Cloudflare) for the connections that can't go direct. A remote signer puts the candidates inside the offer and answer instead of signing one each. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live rings and going live. A face whose person is streaming wears a red ring ↵Adam Soltys2026-10-181-0/+21
| | | | | | | (LIVE under the bigger ones) and opens the stream. Go live (the composer's red dot, or your profile) sends your camera or screen to coinos's live server (coinosv3-server live/: the recording over a WebSocket, HLS out), announces it as your kind 30311 once three segments exist (Chrome's own player won't start a live playlist with fewer), refreshes it each minute with how many watch, reconnects to the same stream if the link drops, and ends it with its recording. Needs a coinos name. Also: the service worker leaves /live/ and /vmedia/hls alone (it froze a live playlist at its first copy). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live streams (NIP-53), to watch: a row of what's on above a feed (Following: ↵Adam Soltys2026-10-181-0/+18
| | | | | | | your follows' streams; Everything and Popular: all), a stream's own page at /naddr1… (the HLS stream playing — hls.js where the browser has no HLS — its chat and zaps as they come, a chat line sent as kind 1311, ⚡ to the host), a card for a post linking a stream, and a LIVE line on a streamer's profile. A stream quiet for an hour is over; one that drops is retried; zaps on a stream carry its a tag. Also: the single-file build's video stub gains streamVideo (its uploads threw since the HLS uploads). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg