2026-03-22 03:30:21 +00:00
< script setup lang = "ts" >
import { computed , ref , nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '@/stores/app'
import ControllerIndicator from '@/components/ControllerIndicator.vue'
import { rpcClient } from '@/api/rpc-client'
const { t } = useI18n ( )
const store = useAppStore ( )
// Server name
const serverName = computed ( ( ) => store . serverName )
const editingServerName = ref ( false )
const serverNameDraft = ref ( '' )
const serverNameInput = ref < HTMLInputElement | null > ( null )
function startEditServerName ( ) {
serverNameDraft . value = serverName . value
editingServerName . value = true
nextTick ( ( ) => serverNameInput . value ? . select ( ) )
}
async function saveServerName ( ) {
const name = serverNameDraft . value . trim ( )
if ( ! name || name === serverName . value ) {
editingServerName . value = false
return
}
try {
await rpcClient . call ( { method : 'server.set-name' , params : { name } } )
store . updateServerName ( name )
} catch ( e ) {
if ( import . meta . env . DEV ) console . error ( 'Failed to rename server:' , e )
}
editingServerName . value = false
}
// Version & release notes
const version = computed ( ( ) => store . serverInfo ? . version || '0.0.0' )
const showReleaseNotes = ref ( false )
// Identity
const serverTorAddressFromStore = computed ( ( ) => store . serverInfo ? . [ 'tor-address' ] || null )
const torAddressFromRpc = ref < string | null > ( null )
const serverTorAddress = computed ( ( ) => serverTorAddressFromStore . value || torAddressFromRpc . value )
const userDid = computed ( ( ) => {
try {
return localStorage . getItem ( 'neode_did' ) || null
} catch {
return null
}
} )
const copiedOnion = ref ( false )
const copiedDid = ref ( false )
let copiedTimer : ReturnType < typeof setTimeout > | null = null
async function copyOnionAddress ( ) {
const addr = serverTorAddress . value
if ( ! addr ) return
try {
await navigator . clipboard . writeText ( addr )
} catch {
const ta = document . createElement ( 'textarea' )
ta . value = addr
ta . style . position = 'fixed'
ta . style . opacity = '0'
document . body . appendChild ( ta )
ta . select ( )
document . execCommand ( 'copy' )
document . body . removeChild ( ta )
}
copiedOnion . value = true
if ( copiedTimer ) clearTimeout ( copiedTimer )
copiedTimer = setTimeout ( ( ) => { copiedOnion . value = false } , 2000 )
}
async function copyDid ( ) {
if ( ! userDid . value ) return
try {
await navigator . clipboard . writeText ( userDid . value )
} catch {
const ta = document . createElement ( 'textarea' )
ta . value = userDid . value
ta . style . position = 'fixed'
ta . style . opacity = '0'
document . body . appendChild ( ta )
ta . select ( )
document . execCommand ( 'copy' )
document . body . removeChild ( ta )
}
copiedDid . value = true
setTimeout ( ( ) => { copiedDid . value = false } , 2000 )
}
// Load Tor address on mount if not in store
async function init ( ) {
if ( ! serverTorAddressFromStore . value ) {
try {
const res = await rpcClient . getTorAddress ( )
torAddressFromRpc . value = res . tor _address ? ? null
} catch ( e ) {
if ( import . meta . env . DEV ) console . warn ( 'Tor address may not be available yet' , e )
}
}
}
init ( )
< / script >
< template >
<!-- Controller indicator - Mobile only -- >
< div class = "md:hidden mb-4" >
< ControllerIndicator / >
< / div >
<!-- Info Grid -- >
2026-03-31 01:41:24 +01:00
< div class = "grid grid-cols-1 md:grid-cols-2 gap-4 mb-6" >
<!-- Server Name Card ( editable ) — container : Enter to edit , Enter to save , Escape to exit -- >
< div data -controller -container tabindex = "0" class = "bg-black/20 rounded-xl px-5 py-4 border border-white/10 transition-all hover:-translate-y-1" >
2026-03-22 03:30:21 +00:00
< div class = "flex items-center gap-3 mb-2" >
< svg class = "w-5 h-5 text-white/70" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" / >
< / svg >
< p class = "text-xs font-semibold text-white/60 uppercase tracking-wide" > { { t ( 'settings.serverName' ) } } < / p >
< / div >
< div v-if = "editingServerName" class="flex items-center gap-2" >
< input
ref = "serverNameInput"
v - model = "serverNameDraft"
type = "text"
maxlength = "64"
class = "flex-1 px-3 py-1.5 bg-white/10 border border-white/20 rounded-lg text-white text-lg font-semibold focus:outline-none focus:border-white/40 transition-colors"
@ keydown . enter = "saveServerName"
@ keydown . escape = "editingServerName = false"
/ >
< button
class = "px-3 py-1.5 bg-white/10 border border-white/20 rounded-lg text-white/70 hover:text-white hover:bg-white/15 transition-colors text-sm"
@ click = "saveServerName"
> Save < / button >
< button
class = "px-3 py-1.5 text-white/50 hover:text-white/70 transition-colors text-sm"
@ click = "editingServerName = false"
> Cancel < / button >
< / div >
< div v -else class = "flex items-center gap-2 group cursor-pointer" @click ="startEditServerName" >
< p class = "text-lg font-semibold text-white/95" > { { serverName } } < / p >
< svg class = "w-4 h-4 text-white/30 group-hover:text-white/60 transition-colors" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" / >
< / svg >
< / div >
< / div >
<!-- Version Card -- >
< div class = "bg-black/20 rounded-xl px-5 py-4 border border-white/10" >
< div class = "flex items-center gap-3 mb-2" >
< svg class = "w-5 h-5 text-white/70" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" / >
< / svg >
< p class = "text-xs font-semibold text-white/60 uppercase tracking-wide" > { { t ( 'common.version' ) } } < / p >
< / div >
< div class = "flex items-center justify-between" >
< p class = "text-lg font-semibold text-white/95" > { { version } } < / p >
< button
@ click = "showReleaseNotes = true"
class = "glass-button px-3 py-1.5 text-xs"
> What ' s New < / button >
< / div >
< / div >
<!-- Release Notes Modal -- >
< Teleport to = "body" >
< Transition name = "modal" >
< div v-if = "showReleaseNotes" class="fixed inset-0 z-[3000] flex items-center justify-center p-4" @click="showReleaseNotes = false" >
< div class = "absolute inset-0 bg-black/60 backdrop-blur-sm" > < / div >
< div @ click.stop class = "glass-card p-6 max-w-lg w-full relative z-10 flex flex-col" style = "max-height: 85vh" >
< div class = "flex items-start justify-between gap-4 mb-5 shrink-0" >
< h3 class = "text-xl font-semibold text-white" > What ' s New < / h3 >
< button @ click = "showReleaseNotes = false" class = "p-2 rounded-lg hover:bg-white/10 text-white/70 hover:text-white transition-colors" aria -label = " Close " >
< svg class = "w-5 h-5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M6 18L18 6M6 6l12 12" / > < / svg >
< / button >
< / div >
< div class = "overflow-y-auto flex-1 min-h-0 space-y-6 pr-1" >
2026-04-20 20:20:36 -04:00
<!-- v1 .7 .18 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .18 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Nodes discovered through a trusted peer now land as Trusted instead of Observer . When your federated peer shares its own peer list with you , those nodes get the same trust level as a direct invite — the link they came through is already one you vetted , so you no longer need to promote them by hand before they can be used normally . < / p >
< p > The update flow now writes clearer logs at every step . Start of download , cancel , and apply each emit a one - line entry to the system journal with the staging path and the affected files , so if a download misbehaves on your node it ' s easy to see exactly where it got to . < / p >
< / div >
< / div >
2026-04-20 19:10:34 -04:00
<!-- v1 .7 .17 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .17 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > When a download gets stuck , you can now cancel it . A new Cancel Download button sits next to the progress bar — it stops the transfer , clears the partial file , and returns you to a clean state so you can retry . No more staring at a frozen bar with no way to recover . < / p >
< p > Downloads that stall for 30 seconds or more now say so . The progress bar turns amber and shows 'Download appears stuck — try Cancel and start again' instead of just sitting silently at whatever percent it reached . < / p >
< p > Canceling is fast . It no longer has to wait out the retry timer — the download bails within half a second , so you ' re not stuck watching a stuck screen while you wait to unstick it . < / p >
< / div >
< / div >
2026-04-20 18:12:02 -04:00
<!-- v1 .7 .16 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .16 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Federation is now bidirectional and instant . When someone joins using your invite code , their node appears on your Federation page automatically — no need for the inviter to click Sync or wait for the next poll . Names and node details populate within seconds of the handshake finishing . < / p >
< p > New nodes can no longer federate with themselves . Accepting an invite that points back at the local node ( by DID , public key , or onion address ) is rejected up front , so self - peering no longer clutters the node list with a duplicate card . < / p >
< p > Transitive discovery : if nodes A and B are already federated and node C joins A , all three nodes now learn about each other . The new peer is pulled in as an Observer entry on existing federation members , so you can promote to Trusted with one click instead of trading a second invite code . < / p >
< p > The Federation page auto - refreshes every five seconds while it ' s open . Status changes , new peers , and incoming join requests surface on their own — clicking Sync remains available for an on - demand pull . < / p >
< / div >
< / div >
<!-- v1 .7 .15 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .15 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Updates survive network hiccups . Downloads now resume from exactly where a dropped connection left off , and retry up to 6 times with increasing gaps between attempts , instead of restarting from byte zero or giving up . < / p >
< p > The download progress bar now shows real progress . Instead of a fake number that creeps to 95 % and freezes , you see the actual bytes arriving , and it continues to update correctly even if you navigate away and come back . < / p >
< p > Update check itself retries on slow responses . If git . tx1138 . com is momentarily overloaded , the node tries three times with a five - second wait between attempts before concluding you ' re up to date . < / p >
< / div >
< / div >
<!-- v1 .7 .14 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .14 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Installing an update now shows a full - screen progress overlay with the Archipelago logo , a status message , and an animated bar . The page reloads itself automatically once the new version is up — no manual refresh . If something stalls , a 'Reload now' button appears after a few minutes . < / p >
< p > Download progress no longer looks frozen near the end . The bar pauses at 95 % with a 'Finishing download — verifying checksum…' message and spinner while the last bytes arrive and are hashed . < / p >
< p > FIPS Reconnect now genuinely tries to fix the anchor . It runs a proper recovery sequence ( stop → start → wait for the bootstrap window → check peers ) and tells you the likely reason it 's still unreachable — corrupt identity key, seed not unlocked, network blocking UDP, or the anchor server being down — instead of a generic ' try again ' . < / p >
< p > Healed a latent FIPS identity bug : the public - key file was being written in text form ( an 'npub1…' string ) on some nodes , which the daemon couldn 't parse and silently authenticated with a garbage key. The Reconnect button now rewrites the file in the correct binary format and re-installs the config before restarting — nodes stuck with no peers for ' no reason ' should come back online . < / p >
< p > AIUI ( Claude sidebar ) is back . The installer now ships AIUI in the frontend bundle and preserves it across future updates — it was being wiped on every OTA because it lived outside the Vue build . < / p >
< p > Installing a big app ( IndeedHub , Bitcoin , Penpot ) no longer gives up early and shows 'didn' t work ' while the download is still running in the background . The client waits up to 45 minutes for the install pipeline to finish . < / p >
< p > 'Rollback to Previous' is now labelled 'Rollback Available' — clearer that it 's a choice you have, not a status you' re stuck with . < / p >
< / div >
< / div >
<!-- v1 .7 .13 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .13 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > App catalog now loads reliably . Before , the Marketplace / Discover page couldn 't fetch the catalog of apps because the upstream host wasn' t sending the right CORS headers and the node 's security policy didn' t allow the fallback URL either . The node now fetches the catalog server - side and serves it same - origin to the browser — no more blank app lists . < / p >
< / div >
< / div >
<!-- v1 .7 .12 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .12 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Nothing new — version bump so freshly - installed nodes ( from the 1.7 .11 ISO ) have something to OTA down , confirming the end - to - end update pipeline out of the box . < / p >
< / div >
< / div >
<!-- v1 .7 .11 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .11 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > OTA proof release — first version where Install Update should run clean from the UI with no manual steps . Click it and watch the sidebar flip to 1.7 .11 - alpha on its own . < / p >
< / div >
< / div >
<!-- v1 .7 .10 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .10 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Install Update actually applies now . The installer had to write into system folders that the backend service was sandboxed out of — every earlier 'Failed to apply update' was a layer of that onion . Fixed by running the file swaps in a separate system context . < / p >
< p > FIPS status on the Home and Server pages now reflects whether the public anchor is reachable . You 'll see ' Active · N peers ' (green) when healthy or ' No anchor ' ( orange ) when the network is blocking the bootstrap — same signal as the full FIPS card . < / p >
< p > Pasting an https : //… URL into the profile picture or banner now previews correctly. Before, if the URL failed to load, the UI would silently blank out instead of showing your initial as a placeholder.</p>
< p > Uploaded profile pictures under 64 KB are now embedded directly in your Nostr profile ( as a data URL ) , so any Nostr client can see them — not just ones routing over Tor . Larger uploads keep the onion URL for now , with a hint to paste a public URL for wider visibility . < / p >
< / div >
< / div >
<!-- v1 .7 .9 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .9 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > OTA verification release — nothing new to see . Click Install Update , grab a coffee , and watch the sidebar flip to 1.7 .9 - alpha on its own . If this one works end to end , the pipeline is solid and future updates will flow the same way . < / p >
< / div >
< / div >
<!-- v1 .7 .8 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .8 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Install Update finally works end - to - end over the air . The installer was trying to overwrite the running backend binary with a tool that fails on in - use files ( ETXTBSY ) — swapped it for an atomic rename , which the kernel allows on a live executable . Every previous 'Failed to apply update' attempt was this one root cause . < / p >
< / div >
< / div >
<!-- v1 .7 .7 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .7 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Over - the - air update test — no feature changes , just a version bump so your node can walk through the whole update flow end - to - end using the new robust installer . Safe to apply ; nothing to do afterwards . < / p >
< / div >
< / div >
<!-- v1 .7 .6 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .6 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Install Update is now more robust . Each install gets its own uniquely - named staging folder and then moves files into place — the previous version had a small cleanup step that could hit a transient filesystem hiccup and bail out halfway . You ' ll also still see a rollback folder after a successful install . < / p >
< p > Dev - box OTA : nodes that build archipelago from source can now opt into the standard Download → Install flow instead of Pull & amp ; Rebuild , by setting ARCHIPELAGO _UPDATE _URL in the service environment . Useful when the dev machine has a checked - out repo but you want to test the regular update path . < / p >
< / div >
< / div >
<!-- v1 .7 .5 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .5 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Over - the - air update test — no feature changes , just a fresh version number so your node can walk through the whole update flow end - to - end : check , download , install , auto - restart . Safe to apply ; nothing to do afterwards . < / p >
< / div >
< / div >
<!-- v1 .7 .4 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .4 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Install Update actually installs now . Before , the final step extracted the new UI into the wrong folder and bailed with 'Failed to apply update' — your node ended up backing up cleanly but never swapping in the new files . Fixed . < / p >
< p > Download progress no longer overshoots 100 % . You ' ll see the bar climb smoothly to 95 % and then jump to 100 % when the download actually finishes . < / p >
< / div >
< / div >
<!-- v1 .7 .3 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .3 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > The version number in the sidebar now always matches the actual running version — no more lying to you about being on an older release after an update . < / p >
< p > FIPS Mesh card on the server page : cleaner layout on desktop ( no more awkward gaps ) , and a one - click Reconnect button when the public anchor is unreachable — it restarts the FIPS daemon so it can re - bootstrap from the anchor . < / p >
< p > Profile pictures now show correctly in the identity list and editor . Before , uploaded images silently failed to render because the URL was only reachable over Tor ; the UI now rewrites them to a local path while keeping the external URL for other Nostr clients . < / p >
< p > Identity rows now show your Display Name first ( from your Nostr profile ) with the internal identity name beside it in parentheses , so you see the name other people will see — not just the one you picked when creating it . < / p >
< / div >
< / div >
<!-- v1 .7 .2 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .2 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Install Update now actually installs . Before , the button would back up your current version then fail with 'Failed to apply update' because the installer couldn ' t write into system folders . < / p >
< p > The button 's also been renamed to ' Install Update ' (previously ' Apply Update ' ) and the node restarts itself a moment after you click it — no more manual restart step . < / p >
< p > Your existing identities now show the generated avatar instead of just their initials — same look as freshly created ones . < / p >
< p > Everything from 1.7 .0 - alpha and 1.7 .1 - alpha carries over ( default avatars on creation , one - click Save publishes to Nostr relays , public blob URLs for profile pictures , 30 - minute download window , VPN peer restore on reboot , reconciler - only - repairs , filebrowser fix ) . < / p >
< / div >
< / div >
<!-- v1 .7 .1 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .1 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Over - the - air update test — same features as 1.7 .0 , just a fresh version number so your node can try the new download - and - apply flow end - to - end . Safe to apply ; nothing to do afterwards . < / p >
< / div >
< / div >
<!-- v1 .7 .0 - alpha -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .7 .0 - alpha < / span >
< span class = "text-xs text-white/40" > Apr 20 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Every identity now gets a personal avatar the moment it ' s created . Your main node identity gets a distinctive hexagonal - network icon ; other identities get a colourful generated pattern unique to each one . < / p >
< p > Profile editor : upload a profile picture and a banner , then tap Save — your Nostr profile now goes out to the relays in one step . No more 'Save' vs 'Save & Publish' confusion . < / p >
< p > Profile pictures and banners you upload are now reachable by other Nostr clients across the network — not just your own browser . Anyone who sees your profile on a relay can load the image . < / p >
< p > Update downloads on slow connections no longer cut out right at the end . The client waits up to 30 minutes for each component instead of giving up after 15 seconds . < / p >
< p > When you move a node to a new version without going through Check for Updates ( for example via a reinstall or manual copy ) , it now reports the new version correctly instead of endlessly saying 'update available' . < / p >
< p > Your VPN peers come back automatically after a reboot . No more rescanning QR codes on your phone or laptop . < / p >
< p > Fresh installs stay lean — only File Browser is included out of the box . Other apps wait in the Marketplace until you pick them . < / p >
< p > File Browser stops rebooting itself every few hours — the housekeeper now leaves it alone once it ' s healthy . < / p >
< p > One - click 'Pull & Rebuild' button works for nodes that update from source ( the development path ) , not just the standard download path . < / p >
< p > The download progress number is now clean ( like 45.23 % ) instead of 45.270894 % . < / p >
< / div >
< / div >
2026-04-11 09:38:45 -04:00
<!-- v1 .3 .5 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .3 .5 < / span >
< span class = "text-xs text-white/40" > Apr 11 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< p > Migrated container registry to git . tx1138 . com < / p >
< / div >
< / div >
2026-04-07 15:05:56 +01:00
<!-- v1 .3 .4 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .3 .4 < / span >
< span class = "text-xs text-white/40" > Apr 7 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > NostrVPN — Built - in Mesh VPN < / h4 >
< p > NostrVPN is now a native system service . Peer discovery via Nostr relays , WireGuard tunnels . Auto - configured with your node ' s identity during onboarding — no setup required . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > New Marketplace Apps < / h4 >
< p > FIPS ( encrypted mesh network ) and Routstr ( decentralized AI inference with Cashu payments ) available as installable apps . Status UIs included for headless apps . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > ISO Boot Fix < / h4 >
< p > Fixed backend service crash on fresh ISO installs caused by overly restrictive systemd security settings . Fresh installs now boot cleanly . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > Bootstrap from Trusted Node < / h4 >
< p > New installs auto - connect to a trusted Bitcoin node via Tor during initial sync . ElectrumX , LND , and BTCPay work immediately while your local chain catches up . < / p >
< / div >
< / div >
< / div >
2026-03-22 03:30:21 +00:00
<!-- v1 .3 .0 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300" > v1 .3 .0 < / span >
< span class = "text-xs text-white/40" > Mar 19 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > Full Security Audit < / h4 >
< p > 33 security findings from a comprehensive penetration test — all fixed . Backend now only accessible through nginx . Path traversal , SSRF , and XSS vulnerabilities eliminated . Federation requires cryptographic signatures . Session tokens rotate after 2 FA . Destructive operations now require password confirmation . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > Container Reliability < / h4 >
< p > Memory limits on every container prevent one app from crashing the whole system . Crashed apps now show a red "crashed" badge with a restart button instead of disappearing . Smart health status shows "starting up" , "healthy" , or "unhealthy" in real time . Apps you stop stay stopped — no more auto - restart fighting . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > Wallet on Home < / h4 >
< p > The Home dashboard now shows your Bitcoin wallet with on - chain , Lightning , and ecash balances . Send , receive , and view transaction history right from the home screen . New Transactions modal shows your full history with confirmations . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > LND Connect Fixed < / h4 >
< p > Connect Your Wallet ( Zeus , Zap , BlueWallet ) now works over both local network and Tor . QR codes generate correctly with REST API access . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > UI Polish < / h4 >
< p > Mesh view redesigned . New glass button styles throughout . Restart button on running apps . Improved app status badges . Cleaner navigation on the Apps page . < / p >
< / div >
< / div >
< / div >
<!-- alpha .9 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60" > v1 .2 .0 - alpha .9 < / span >
< span class = "text-xs text-white/40" > Mar 18 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > Security Hardening Complete < / h4 >
< p > All 12 pentest findings fixed . CSRF tokens now survive restarts . Password hashing upgraded to Argon2id . Bitcoin RPC gets a unique random password on every install . Federation messages require ed25519 signatures . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > 7 Bugs Squashed < / h4 >
< p > Random logouts fixed ( P0 ) . Uninstall dialog is now a proper full - screen modal with an "Uninstalling..." overlay . App cards no longer flicker between Start / Launch during container scans . ElectrumX index estimate corrected . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > Bitcoin Sync on Dashboard < / h4 >
< p > Homepage System card now shows Bitcoin Core sync progress , block height , and green / orange status indicator when Bitcoin is running . < / p >
< / div >
< / div >
< / div >
<!-- alpha .8 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60" > v1 .2 .0 - alpha .8 < / span >
< span class = "text-xs text-white/40" > Mar 18 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > Pentest Remediation ( 9 / 12 ) < / h4 >
< p > Fixed 9 of 12 security findings : session auth on LND connect info , DEV _MODE removed from production , ed25519 signature verification on node messages , path traversal protection , NIP - 07 origin validation , AIUI session checks , strict onion validation . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > UI Polish Batch < / h4 >
< p > Fedimint renamed to "Fedimint Guardian" . Tab - launch icons . Marketplace sorts installed apps to end . Mesh mobile layout fixed . On - Chain first in receive modals . Federation shows names instead of DIDs . Cleaner iframe error screens . < / p >
< / div >
< / div >
< / div >
<!-- alpha .7 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60" > v1 .2 .0 - alpha .7 < / span >
< span class = "text-xs text-white/40" > Mar 18 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > Marketplace & Credentials < / h4 >
< p > 29 containers running rootless . Marketplace app aliases working . Credential injection for inter - container authentication . < / p >
< / div >
< / div >
< / div >
<!-- alpha .4 - 6 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60" > v1 .2 .0 - alpha .4 - 6 < / span >
< span class = "text-xs text-white/40" > Mar 18 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > Rootless Podman Migration < / h4 >
< p > Migrated all containers from root to rootless Podman . UID namespace mapping , volume ownership fixes , sysctl tuning . Bitcoin RPC verified , all web services confirmed healthy . 29 containers up and running . < / p >
< / div >
< / div >
< / div >
<!-- alpha .2 - 3 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60" > v1 .2 .0 - alpha .2 - 3 < / span >
< span class = "text-xs text-white/40" > Mar 18 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > Systemd Hardening Restored < / h4 >
< p > Full systemd security sandbox restored now that containers run rootless . NoNewPrivileges , restricted namespaces , and system call filtering re - enabled . Session persistence and boot sequence fixes . < / p >
< / div >
< / div >
< / div >
<!-- alpha .1 -- >
< div >
< div class = "flex items-center gap-2 mb-3" >
< span class = "text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60" > v1 .2 .0 - alpha .1 < / span >
< span class = "text-xs text-white/40" > Mar 18 , 2026 < / span >
< / div >
< div class = "space-y-3 text-sm text-white/80 pl-3 border-l border-white/10" >
< div >
< h4 class = "text-white font-medium mb-1" > Mesh Radio & Container Stability < / h4 >
< p > LoRa mesh radio auto - detects USB port changes with a new Connect button . Fixed container crash loops — all apps start cleanly and stay stable . Apps starting up show progress instead of re - appearing in the store . Tor routing enabled by default for Bitcoin and Lightning . < / p >
< / div >
< div >
< h4 class = "text-white font-medium mb-1" > Off - Grid Bitcoin < / h4 >
< p > Receive Bitcoin block headers over mesh radio . Dead man ' s switch broadcasts location to trusted contacts if you go silent . GPS sharing is opt - in only . < / p >
< / div >
< / div >
< / div >
< / div >
< button @ click = "showReleaseNotes = false" class = "glass-button w-full mt-4 py-2 text-sm shrink-0" > Close < / button >
< / div >
< / div >
< / Transition >
< / Teleport >
<!-- Session Card -- >
< div class = "bg-black/20 rounded-xl px-5 py-4 border border-white/10 md:col-span-2" >
< div class = "flex items-center gap-3 mb-2" >
< svg class = "w-5 h-5 text-green-400" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" / >
< / svg >
< p class = "text-xs font-semibold text-white/60 uppercase tracking-wide" > { { t ( 'settings.sessionStatus' ) } } < / p >
< / div >
< p class = "text-base font-medium text-white/90" > { { t ( 'settings.loggedIn' ) } } < / p >
< / div >
<!-- Identity Card : DID + Tor Address -- >
< div v-if = "userDid || serverTorAddress" class="bg-black/20 rounded-xl px-5 py-4 border border-white/10 md:col-span-2 space-y-4" >
< div v-if = "userDid" >
< div class = "flex items-center justify-between gap-2 mb-2" >
< div class = "flex items-center gap-3 min-w-0" >
< svg class = "w-5 h-5 text-amber-400 shrink-0" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" / >
< / svg >
< p class = "text-xs font-semibold text-white/60 uppercase tracking-wide" > { { t ( 'settings.yourDid' ) } } < / p >
< / div >
< button
@ click = "copyDid"
class = "shrink-0 px-3 py-1.5 rounded-lg glass-button glass-button-sm text-xs font-medium text-white/90 hover:text-white transition-colors flex items-center gap-1.5"
>
< svg v-if = "!copiedDid" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" / >
< / svg >
< span v -else class = "text-green-400 text-xs" > { { t ( 'common.copied' ) } } < / span >
< span v-if = "!copiedDid" > {{ t ( ' common.copy ' ) }} < / span >
< / button >
< / div >
< p class = "text-sm font-mono text-white/90 break-all" :title = "userDid" > { { userDid } } < / p >
< p class = "text-xs text-white/50 mt-1" > { { t ( 'settings.didHelper' ) } } < / p >
< / div >
< div v-if = "serverTorAddress" :class="userDid ? 'pt-4 border-t border-white/10' : ''" >
< div class = "flex items-center gap-3 mb-2" >
< svg class = "w-5 h-5 text-amber-400 shrink-0" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" / >
< / svg >
< p class = "text-xs font-semibold text-white/60 uppercase tracking-wide" > { { t ( 'settings.onionAddress' ) } } < / p >
< / div >
< p class = "text-sm font-mono text-amber-400/90 break-all mb-1" :title = "serverTorAddress" > { { serverTorAddress } } < / p >
< p class = "text-xs text-white/50 mb-3" > { { t ( 'settings.onionHelper' ) } } < / p >
< button
@ click = "copyOnionAddress"
class = "w-full min-h-[44px] rounded-lg glass-button text-sm font-medium text-white/90 hover:text-white transition-colors flex items-center justify-center gap-2"
>
< svg v-if = "!copiedOnion" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" / >
< / svg >
< span v-if = "!copiedOnion" > {{ t ( ' common.copy ' ) }} < / span >
< span v -else class = "text-green-400" > { { t ( 'common.copied' ) } } < / span >
< / button >
< / div >
< / div >
< / div >
< / template >