#Amethyst v1.19.0: A New Login, Remote Signers on Android, Wayland, and Marketplace Cards
Highlights:
- Redesigns the **login and sign-up screens** around signers: your signer
app or a remote signer first, then the key field, on every platform.
- Adds **NIP-46 remote signer login on Android**, and makes it work with
Opal and other signers that percent-encode their bunker addresses.
- Opens **gift wraps in parallel** for remote-signer accounts: a cold start
that waited ~85s using a remote signer for DMs now takes ~20s.
- Gives the **desktop first-class key storage**: a status card in Key
Backup, a password file when there is no system keyring, and an opt-out.
- Draws **natively on Wayland** in every Linux release, with the
compositor's own title bar where it has one.
- **Compresses videos on desktop** through the system's ffmpeg, with the
same quality table as Android.
- Honors **relay rate limits**: a relay's `rate-limited:` back-off now holds
and re-sends the refused commands instead of losing them.
- Adds cards for **NIP-15 marketplaces**, NIP-85 trust assertions, Trusted
Lists, decentralized lists and NIP-29 group metadata.
## New Features
### Login and Sign-up
- Redesigns the login, sign-up and remote-signer screens on one shared frame:
the logo over a soft glow, rounded fields and buttons, Tor settings as a
chip, and a brand-and-card split on windows 840 dp and wider.
- Shows the same order everywhere: the signer app where one is installed,
the remote signer wherever it works, then "or", then the key field.
- Names and draws the installed signer app ("Login with Amber" and its
icon), or says "a signer app" when there are several.
- Lights up Login once a key is typed, and Create Account once there is a
name, and puts the terms checkbox at the top, gating every way in.
- Puts each error right under what it is about: the key field, the password
field, the signer app's button or the remote signer's button.
- Fits the logged-off screens and the remote-signer dialog on small phones,
and keeps the Add New Account bar above the form, not over it.
- Uses white and frosted cards instead of grey for the login, remote-signer,
key-storage and Key Backup surfaces.
### Remote Signers (NIP-46)
- Logs in with a NIP-46 remote signer on Android too: paste a `bunker://`
or show the `nostrconnect://` code.
- Hands the code to a signer app with Open signer, from an in-app menu when
several take it, never to Amethyst itself.
- Shows the code in a large frame ringed by the logo's colors while it
waits, with Copy, Open signer and the relays as pills.
- Lets you pick the relay your signer uses, or one of your inbox relays,
when it can't reach the defaults.
- Uses relay.nip46.com, nrs.primal.net and bucket.coracle.social, the relays
Amber and Opal default to, instead of relay.nsec.app, which stopped
answering.
- Reads percent-encoded bunker addresses, as Opal writes them, and fails
with an error instead of spinning forever.
- Accepts only an answer that carries the code's secret. Anyone who saw the
code could reply first and pose as the signer.
- Resends the same request on a retry, so a signer that queues requests for
approval (Amber) no longer asks twice.
- Waits five minutes for the signer instead of two, and introduces each
platform by its own name and icon.
- Opens gift wraps, seals and drafts up to 8 at a time ahead of the indexer.
With Amber over NIP-46, a desktop cold start opened its 118 wraps in
~20 s instead of ~85 s.
- Tries remote-signer accounts last when decrypting push notifications, so
an offline bunker no longer holds every other account's notifications.
### Desktop Key Storage
- Shows where your keys live in a status card at the top of Key Backup,
with Try again when the keychain refuses and Unlock when the key file is
locked.
- Keeps keys in a password-protected NIP-49 file (`keys.ncryptsec`) when the
computer has no system keyring, asking for the password once per launch.
- Adds "Remember my key on this device": turn it off and the key is asked
for at each launch.
- Adds Save keys to take back this run's "Don't save".
- Stops rewriting the private key to the macOS Keychain on every settings
save, which brought the Keychain password prompt back over and over.
- Fixes view-only, bunker and signer-app logins failing to load after a
restart on Windows and Linux.
- Fixes the Linux OS keyring in release builds (deb, rpm, AppImage and
Flatpak), which always fell back to the password file.
- Treats KWallet's missing item as absent, so a fresh KWallet no longer
shows "Keychain error" on every launch.
- Upgrades a read-only session when you Unlock, Try again or log in again
with the nsec.
- Reports a key the vault could not keep once per run, instead of on every
settings save.
- Keeps the `nostrconnect://` secret out of the logs.
### Desktop Video Compression
- Compresses videos through the system's ffmpeg at the quality slider's
level, with Android's resolution and bitrate table, HEVC when asked, and
H.264 otherwise.
- Strips video metadata by remuxing the original when it is the one going
up, and asks before uploading if the strip fails.
- Names the picked video and its target on the slider, such as
"High · 4K video → 2160p, 8 Mbps".
- Hides the H.265 and GIF-to-MP4 switches without ffmpeg, showing an
install hint instead.
- Tells you when an encode was discarded for not being smaller.
- Finds Homebrew and other package-manager installs of ffmpeg when the app
is launched from Finder.
### Marketplaces (NIP-15)
- Adds cards for stalls, products, marketplaces, auctions, bids and bid
confirmations, which showed as raw JSON or not at all.
- Shows a product's gallery, price, stock, stall, specs and a Message
seller button that drafts a DM with the listing.
- Shows an auction's starting bid, its start and end with the merchant's
extensions, an Upcoming/Live/Ended badge, and its highest bid and bid
count.
- Reads marketplace events leniently (prices as strings, missing ids, tag
form auctions from hash21 and mkauction), and keeps other apps' records
on the same kinds out.
### Trust and List Cards
- Adds one card for NIP-85 trusted assertions (30382-30385): what it scores,
the rank, hops, every other metric as a tile, timestamps as dates, and the
provider.
- Shows a kind 10040's designated providers, with the services each serves.
- Adds cards for Trusted Lists (30392-30395) with members best first and
their scores.
- Adds cards for decentralized list headers and items (9998/9999,
39998/39999), loading a header's items while it is on screen, with `url`,
`tel` and `email` fields as links.
- Adds a card for NIP-29 group metadata (39000) that opens the group.
- Renders hashtags, links and people in bookmark lists and sets, and quotes
pinned notes instead of printing raw `nevent` strings.
- Pages long rosters (3, then 50 per Show more) and caps chip rows with a
"+N more" chip, since event authors decide how many tags a card gets.
### Feeds and Cards
- Adds an info button to each feed filter that explains what it shows, and
on the Notifications screen, what it does to notifications.
- Loads the relay lists of people-list members you don't follow, so list
feeds, follow packs and All Follows find their notes.
- Draws live streams with their summary, start time, viewer count, and a
Watch recording button over the cover once ended.
- Shows a classified's location and a Sold badge, a zap goal's end
countdown, a calendar event's own time zone, and a long-form article's
reading time and topics.
- Renders every kind as the thread's main note the way the feed does:
RSVPs, calendars, lists, chess, live activities and more drew nothing or
plain text there.
- Resolves NIP-30 custom emoji on reaction notification cards, and draws an
untagged `:shortcode:` reaction as text instead of an empty image.
- Plays Blossom's `.mpga` audio files and Podcasting 2.0 trailers.
- Draws a kind 31337 as a music track only when it has a file to play, and
leaves the rest (ad-skip data, game state) out of the feeds.
## Performance
- Makes the outbox's delivery state mutable under its lock: a publish cost
O(relays²) in copies, ~3,400 ns per relay at 100 relays, now ~150 ns.
- Makes a screen's subscription invalidation lock-free: 1.1 ns instead of
up to 8,300 ns while an update is running.
- Returns at once when pruning frees a note that is not a zap.
## Improvements and Bug fixes
- Shows a relay that refused a post with a back-off as retrying while the
client waits it out.
- Stops one relay's hang-up during a publish retry from reconnecting the
whole relay pool.
- Fixes acks from different relays being lost, which kept an event in the
outbox and re-sent it on every reconnect.
- Fixes a forged copy of a note getting the real one dropped as its
duplicate, and deleting an addressable's old version removing the
current one.
- Downloads the Web of Trust network in ~10 s and 39 MB instead of minutes
and 380 MB: it no longer fetches every deletion the provider signed, and
learns of retracted cards over NIP-77.
- Routes the Web of Trust provider's relays like your own: clearnet by
default instead of through Tor.
- Stops a Web of Trust download on mobile data when it is not allowed,
keeps it through list updates, and checkpoints it so an interruption
loses less.
- Fixes the zoom animation for images scrolled partly out of the feed or
under the bars, and makes GIFs shrink back into their thumbnail.
- Fixes tapping a quoted reply in a chat scrolling to the wrong message.
- Stops the like icon crossfading from an empty heart on every scroll.
- Stops demoting the threads of audio rooms and video playback, which made
audio stutter under load.
- Stops an audio room's service restarting after the app was killed and
holding audio focus and a wake lock for a room that was gone.
- Stops any app from controlling picture-in-picture video playback.
- Reads timestamps written in milliseconds as seconds, which made goals
and live streams end in "54,000 years".
- Keeps the Git Repositories search's `kind:git` chip out of the Namecoin
and `.bit` lookups.
- Gives a room's name width before its label in Messages, so a Cordn group
no longer shows only its coordinator.
- Follows the testls.space ElectrumX port swap for Namecoin.
## Desktop
- Draws natively on Wayland in every Linux package, with the JetBrains
Runtime. Set `AMETHYST_X11=1` to stay on XWayland.
- Uses the compositor's title bar on KDE, sway, Hyprland, COSMIC and niri;
GNOME keeps the GTK one.
- Fixes video playback on Windows, which said "Video playback unavailable"
in 1.18.0, and on macOS release builds.
- Keeps the chart library intact in release builds, which ProGuard broke.
- Lets the `.deb` install on Ubuntu 22.04, Debian 12 and their derivatives.
- Fixes `.deb` and `.rpm` installs and removals failing on systems without
`/usr/share/desktop-directories`, and upgrades that removed the menu
entry.
- Requires the system libraries and a font in the `.rpm`, so minimal Fedora
and openSUSE installs launch.
- Renames the Flatpak app ID to `com.vitorpamplona.amethyst.Amethyst`, so it
doesn't share the Android package's listing in Nostr app stores. See
`BUILDING.md` to move your v1.18.0 data.
- Fixes the Web of Trust download, which never started on desktop, and
keeps Cordn's group state on disk.
- Drops the image viewer's URL tooltip and click-to-copy; Copy URL stays in
its menu.
- Removes the Intel macOS options from the README: only Apple Silicon is
built.
## Cli
- Fixes `amy` 1.18.0's self-contained bundles crashing on every command with
`NoClassDefFoundError: java/lang/management/ManagementFactory`.
- Lists relays `amy fetch --paginate` could not page under `unpaged_relays`,
and warns that the result may be partial.
- Adds `retry_after_ms` to `rejected_by` entries.
- Fetches all of a search such as `include:spam` on search.brainstorm.world:
`amy fetch` returned 5,000 of 35,578 events, and `amy sync` none.
## Quartz
- Implements NIP-01 rate-limit back-offs (nostr-protocol/nips#2498):
`OkMessage` and `ClosedMessage` carry `params` and `retryAfterMs`.
- Holds a relay's refused commands on its connection (`RateLimitGate`) and
re-sends them when the back-off passes, across reconnects and pool
changes, with the subscription's current filters.
- Adds `RateLimiter` and `RateLimitPolicy` for relays, with
`PolicyResult.Rejected.rateLimited`.
- Pages a NIP-50 search with no words to rank, keeps `observer:` searches on
one page, and carries the search on `fetchByIds`.
- Re-asks a page cut short inside its boundary second instead of reporting
DRAINED.
- Fixes a decoder hang on short OK, CLOSED and NEG-ERR frames, a truncated
JSON object looping, and a field like `jE` replacing an event's `id`.
- Fixes `subscribeAsFlow` and `fetchAsFlow` dropping the newest list on a
burst.
- Fixes `QuicReader` overflowing on a peer-chosen length, and a bad datagram
escaping to the crash handler.
- Reads NIP-15 marketplace events leniently, with `isWellFormed()`,
`AuctionData.endsAt()` and `AuctionBidSummary`.
- Adds `AssertionMetric` readers, Trusted List accessors and D-list
`fieldDeclarations()`, `displayHints()` and `listImage()`, with `tel` and
`email` field types.
- Adds `TimeUtils.toUnixSeconds` for millisecond timestamps.
- `EmojiUrlTag.decode` returns null unless both shortcode and url are present.
## Geode
- Adds a `[rate_limits]` section for events and REQs per client per minute,
answering with the NIP-01 back-off and 429 with `Retry-After` over NIP-FE.
Off by default.
- Counts an IPv6 client by its /64.
- Caps WebSocket frames at 1 MiB by default; one header could cost 2 GB.
## Build & Documentation
- Fails the desktop release if ProGuard strips a JNI native method, a
D-Bus transport or leaves a stale jar signature.
- Fails the `amy` build when its runtime lacks a JDK module its jars use.
- Self-tests the OS keyring on every packaged desktop build in CI.
- Speeds up `.deb` post-processing from 156 s to 51 s.
- Splits the iOS CI jobs and caches the Kotlin/Native toolchain, so they
finish under their timeout.
- Adds `tools/desktop-run` to run and screenshot the shared UI headless, and
asks agents to look at a UI change before calling it done.
- Clears the build and lint warnings across modules, and removes 125 unused
Android strings and 10 unused drawables.
- Publishes the Flatpak to Orchard.
- States that issue bounties are not a promise of payment.
## Contributors
- @Vitor Pamplona
- @⚡ Dee Kay ⚡
- @mstrofnone ⚡🥜
## Translations
- Czech, German, Swedish, and Brazilian Portuguese by @⚡ Dee Kay ⚡
- Hindi by @राज
- Hungarian by @summoner
- Polish by @Polak
Login to reply
Replies (2)
If easier to listen while multitasking — I'll turn this long one into audio for the thread once a 1,000 sats bounty is reached on this offer. Total can be from one zap or many.
can't believe how much you are constantly adding to this. awesome work. now distribute it on nostr :-D