chore: release v1.7.86-alpha
This commit is contained in:
@@ -324,14 +324,49 @@ const messageToast = useMessageToast()
|
||||
const web5Badge = useWeb5BadgeStore()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const CONNECTED_NODES_CACHE_KEY = 'archipelago.web5.connected-nodes.v1'
|
||||
type ConnectedNodesCache = {
|
||||
peers: Peer[]
|
||||
observers: Peer[]
|
||||
peerReachable: Record<string, boolean>
|
||||
connectionRequests: ConnectionRequest[]
|
||||
}
|
||||
|
||||
function readConnectedNodesCache(): Partial<ConnectedNodesCache> {
|
||||
if (typeof window === 'undefined') return {}
|
||||
try {
|
||||
const raw = window.sessionStorage.getItem(CONNECTED_NODES_CACHE_KEY)
|
||||
if (!raw) return {}
|
||||
const parsed = JSON.parse(raw) as Partial<ConnectedNodesCache>
|
||||
return {
|
||||
peers: Array.isArray(parsed.peers) ? parsed.peers : [],
|
||||
observers: Array.isArray(parsed.observers) ? parsed.observers : [],
|
||||
peerReachable: parsed.peerReachable && typeof parsed.peerReachable === 'object' ? parsed.peerReachable : {},
|
||||
connectionRequests: Array.isArray(parsed.connectionRequests) ? parsed.connectionRequests : [],
|
||||
}
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function writeConnectedNodesCache(state: ConnectedNodesCache) {
|
||||
if (typeof window === 'undefined') return
|
||||
try {
|
||||
window.sessionStorage.setItem(CONNECTED_NODES_CACHE_KEY, JSON.stringify(state))
|
||||
} catch {
|
||||
// Cache is best-effort.
|
||||
}
|
||||
}
|
||||
|
||||
const nodesContainerRef = ref<HTMLElement | null>(null)
|
||||
const nodesContainerTab = ref<'trusted' | 'observers' | 'messages' | 'requests'>('trusted')
|
||||
const { receivedMessages, loadingMessages, unreadCount, loadReceivedMessages, markAsRead } = messageToast
|
||||
|
||||
const peers = ref<Peer[]>([])
|
||||
const observers = ref<Peer[]>([])
|
||||
const cached = readConnectedNodesCache()
|
||||
const peers = ref<Peer[]>(cached.peers ?? [])
|
||||
const observers = ref<Peer[]>(cached.observers ?? [])
|
||||
const loadingPeers = ref(false)
|
||||
const peerReachableLocal = ref<Record<string, boolean>>({})
|
||||
const peerReachableLocal = ref<Record<string, boolean>>(cached.peerReachable ?? {})
|
||||
const peerReachable = computed(() => ({ ...appStore.peerHealth, ...peerReachableLocal.value }))
|
||||
const discovering = ref(false)
|
||||
|
||||
@@ -351,7 +386,7 @@ const sendMessageError = ref('')
|
||||
const sendMessageSuccess = ref('')
|
||||
|
||||
// Connection requests
|
||||
const connectionRequests = ref<ConnectionRequest[]>([])
|
||||
const connectionRequests = ref<ConnectionRequest[]>(cached.connectionRequests ?? [])
|
||||
const loadingRequests = ref(false)
|
||||
const processingRequestId = ref<string | null>(null)
|
||||
|
||||
@@ -388,6 +423,7 @@ function switchToRequestsTab() {
|
||||
}
|
||||
|
||||
async function loadPeers() {
|
||||
const hadPeers = peers.value.length > 0 || observers.value.length > 0
|
||||
loadingPeers.value = true
|
||||
try {
|
||||
const res = await rpcClient.listPeers()
|
||||
@@ -427,8 +463,18 @@ async function loadPeers() {
|
||||
peerReachableLocal.value[p.onion] = false
|
||||
}
|
||||
}
|
||||
writeConnectedNodesCache({
|
||||
peers: peers.value,
|
||||
observers: observers.value,
|
||||
peerReachable: peerReachableLocal.value,
|
||||
connectionRequests: connectionRequests.value,
|
||||
})
|
||||
} catch (e) {
|
||||
if (import.meta.env.DEV) console.error('Failed to load peers:', e)
|
||||
if (!hadPeers) {
|
||||
peers.value = []
|
||||
observers.value = []
|
||||
}
|
||||
} finally {
|
||||
loadingPeers.value = false
|
||||
}
|
||||
@@ -483,6 +529,12 @@ async function loadConnectionRequests() {
|
||||
const res = await rpcClient.call<{ requests: ConnectionRequest[] }>({ method: 'network.list-requests' })
|
||||
connectionRequests.value = res.requests || []
|
||||
web5Badge.pendingRequestCount = connectionRequests.value.length
|
||||
writeConnectedNodesCache({
|
||||
peers: peers.value,
|
||||
observers: observers.value,
|
||||
peerReachable: peerReachableLocal.value,
|
||||
connectionRequests: connectionRequests.value,
|
||||
})
|
||||
} catch {
|
||||
if (!hadRequests) connectionRequests.value = []
|
||||
} finally {
|
||||
@@ -496,6 +548,12 @@ async function acceptRequest(requestId: string) {
|
||||
await rpcClient.call({ method: 'network.accept-request', params: { request_id: requestId } })
|
||||
connectionRequests.value = connectionRequests.value.filter(r => r.id !== requestId)
|
||||
web5Badge.pendingRequestCount = connectionRequests.value.length
|
||||
writeConnectedNodesCache({
|
||||
peers: peers.value,
|
||||
observers: observers.value,
|
||||
peerReachable: peerReachableLocal.value,
|
||||
connectionRequests: connectionRequests.value,
|
||||
})
|
||||
await loadPeers()
|
||||
emit('toast', t('web5.connectionAccepted'))
|
||||
} catch {
|
||||
@@ -511,6 +569,12 @@ async function rejectRequest(requestId: string) {
|
||||
await rpcClient.call({ method: 'network.reject-request', params: { request_id: requestId } })
|
||||
connectionRequests.value = connectionRequests.value.filter(r => r.id !== requestId)
|
||||
web5Badge.pendingRequestCount = connectionRequests.value.length
|
||||
writeConnectedNodesCache({
|
||||
peers: peers.value,
|
||||
observers: observers.value,
|
||||
peerReachable: peerReachableLocal.value,
|
||||
connectionRequests: connectionRequests.value,
|
||||
})
|
||||
emit('toast', t('web5.requestRejected'))
|
||||
} catch {
|
||||
emit('toast', t('web5.failedToRejectRequest'))
|
||||
|
||||
@@ -389,6 +389,29 @@ import type { ManagedIdentity, IdentityProfile } from './types'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const IDENTITIES_CACHE_KEY = 'archipelago.web5.identities.v1'
|
||||
|
||||
function readIdentitiesCache(): ManagedIdentity[] {
|
||||
if (typeof window === 'undefined') return []
|
||||
try {
|
||||
const raw = window.sessionStorage.getItem(IDENTITIES_CACHE_KEY)
|
||||
if (!raw) return []
|
||||
const parsed = JSON.parse(raw) as ManagedIdentity[]
|
||||
return Array.isArray(parsed) ? parsed : []
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function writeIdentitiesCache(identities: ManagedIdentity[]) {
|
||||
if (typeof window === 'undefined') return
|
||||
try {
|
||||
window.sessionStorage.setItem(IDENTITIES_CACHE_KEY, JSON.stringify(identities))
|
||||
} catch {
|
||||
// Cache is opportunistic only.
|
||||
}
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
showStagger: boolean
|
||||
}>()
|
||||
@@ -397,7 +420,7 @@ const emit = defineEmits<{
|
||||
toast: [text: string]
|
||||
}>()
|
||||
|
||||
const managedIdentities = ref<ManagedIdentity[]>([])
|
||||
const managedIdentities = ref<ManagedIdentity[]>(readIdentitiesCache())
|
||||
const identitiesLoading = ref(false)
|
||||
const showCreateIdentityModal = ref(false)
|
||||
const newIdentityName = ref('Personal')
|
||||
@@ -508,6 +531,7 @@ async function loadIdentities() {
|
||||
try {
|
||||
const res = await rpcClient.call<{ identities: ManagedIdentity[] }>({ method: 'identity.list' })
|
||||
managedIdentities.value = res.identities || []
|
||||
writeIdentitiesCache(managedIdentities.value)
|
||||
} catch {
|
||||
if (!hadIdentities) managedIdentities.value = []
|
||||
} finally {
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="userDid" class="flex gap-2 mt-auto">
|
||||
<button
|
||||
@click="$emit('copyDid')"
|
||||
class="flex-1 px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors"
|
||||
>
|
||||
{{ didCopied ? t('common.copiedBang') : t('web5.copyDid') }}
|
||||
</button>
|
||||
<button
|
||||
@click="$emit('copyDid')"
|
||||
class="flex-1 px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors"
|
||||
>
|
||||
{{ didCopied ? t('common.copiedBang') : t('web5.copyDid') }}
|
||||
</button>
|
||||
<button
|
||||
@click="$emit('showDidDocument')"
|
||||
class="flex-1 px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors"
|
||||
@@ -69,19 +69,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="dhtDid" class="flex gap-2 mt-auto">
|
||||
<button
|
||||
@click="$emit('copyDhtDid')"
|
||||
class="flex-1 px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors"
|
||||
>
|
||||
{{ dhtDidCopied ? 'Copied!' : 'Copy' }}
|
||||
</button>
|
||||
<button
|
||||
@click="$emit('refreshDhtDid')"
|
||||
:disabled="publishingDht"
|
||||
class="flex-1 px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors disabled:opacity-50"
|
||||
>
|
||||
{{ publishingDht ? 'Refreshing...' : 'Refresh DHT' }}
|
||||
</button>
|
||||
<button
|
||||
@click="$emit('copyDhtDid')"
|
||||
class="flex-1 px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors"
|
||||
>
|
||||
{{ dhtDidCopied ? 'Copied!' : 'Copy' }}
|
||||
</button>
|
||||
<button
|
||||
@click="$emit('refreshDhtDid')"
|
||||
:disabled="publishingDht"
|
||||
class="flex-1 px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors disabled:opacity-50"
|
||||
>
|
||||
{{ publishingDht ? 'Refreshing...' : 'Refresh DHT' }}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
v-else-if="userDid"
|
||||
|
||||
Reference in New Issue
Block a user