Follow-up to 1fb71b4b on the same v1.7.0-alpha line.
Identity avatars
• New module `avatar.rs` generates two deterministic SVG styles keyed
off the pubkey: a 5×5 mirrored identicon for sub-identities and a
hexagonal-network motif for the master (seed index 0) identity.
Both returned as base64 data URLs, so a fresh identity has a
recognisable picture before the user uploads anything.
• `IdentityManager::create()` and `create_from_seed()` populate
`profile.picture` on creation. Index 0 gets the node SVG; all
other seed-derived + ad-hoc identities get the identicon.
Blob store — public flag for profile assets
• `BlobMeta.public` (default false) added; `BlobStore::put()` takes
a `public: bool`. Missing in legacy meta files = false.
• `POST /api/blob` now stores uploads with public=true and returns
`public_url` alongside `self_test_url`. public_url is
`http://<node-onion>/blob/<cid>` (no cap) if Tor has published the
archipelago hidden service, else falls back to the local path.
• `GET /blob/<cid>` bypasses the HMAC capability check when the
requested blob is flagged public — external Nostr clients fetching
a kind-0 `picture` URL can't hold a cap.
• Mesh callers (content_ref attachments, dispatch rehydration) pin
public=false explicitly so nothing leaks out of the mesh path.
Profile editor UX
• Collapsed Save + Save & Publish into one button — the Save action
now persists locally AND publishes the kind-0 metadata event in
one step. Uploads store `public_url` into `profile.picture` /
`profile.banner` so the published URL is reachable by external
clients.
Update client — the 15-second cliff
• Frontend `rpcClient.call` for `update.download` now has an
explicit 30-minute timeout (was falling back to the default 15 s).
`update.apply` gets 5 min, `update.git-apply` gets 15 min. Matches
what the backend is actually willing to wait for.
• Backend `load_state()` reconciles `state.current_version` with
`CARGO_PKG_VERSION` on every start. Sideloaded or reflashed nodes
were stuck advertising the old version even with a new binary in
place, which kept re-offering the same release as an update.
Manifest changelog rewritten for fleet readers per the saved feedback
(no function names, no file paths). Artefacts refreshed:
binary 12f838c5…5ba82d 40381864
frontend dc3b63af…e9a8370 76984288
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously the profile editor only accepted external URLs for
picture/banner — typing in a URL works, but anyone without their
own image host couldn't use an avatar at all. Now there's an
"Upload" button next to each field that pushes the selected file
to /api/blob and pastes the returned capability-signed local URL
(`/blob/<cid>?cap=…&exp=…&peer=…`) straight into the form field.
- Two new refs: avatarUploading / bannerUploading so each button
shows "Uploading…" independently.
- uploadAsset(ev, 'picture' | 'banner') wraps the POST, validates
HTTP 200 + presence of self_test_url, surfaces failures in the
existing profileError banner.
- File input is re-cleared on completion so the user can pick the
same file again without refreshing.
- Live preview in the <img> at the top of the editor updates
immediately because profileForm[field] is reactive.
Image persists through Save & Publish via the existing
identity.update-profile + identity.publish-profile (both now
multi-relay). The image URL is still local-only — external nostr
clients won't resolve it until we integrate a public image host
(noted in task #29).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pairs with the backend change that broadcasts kind:0 to every
enabled relay. Web5Identities.vue's publishProfile() now reads the
richer response ({accepted, rejected, relays_attempted, published})
and shows one of three states:
- all relays accepted → "Published to all N relays (event_id…)"
- partial → "Published to X/N relays" plus a warning with the first
relay's rejection reason
- zero → "Published to 0/N relays — check Manage Relays" (error)
User can now tell at a glance whether their profile actually made
it to the wider nostr network or only the local relay.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Onboarding:
- Persist current step in localStorage — page refresh resumes where user was
- Router afterEach saves step; guard redirects to saved step, not always intro
- Show npub alongside DID on restore success screen
UI fixes:
- Clipboard polyfill for HTTP contexts (fixes Copy DID crash on non-HTTPS)
- AppCard installing overlay shows for pkg.state=installing (survives refresh)
- Hide uninstall button during installation
- Frontend version bumped to 1.3.2
App store:
- OnlyOffice fully removed from marketplace, curated apps, app config
- Replaced with CryptPad references throughout
- Remove OnlyOffice from ISO capture patterns
Container stability:
- UI containers (bitcoin-ui, lnd-ui, electrs-ui) pull from registry first
- Added --cap-add FOWNER for rootless Podman compatibility
- electrs-ui now included in first-boot loop alongside bitcoin-ui and lnd-ui
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>