feat(02-05): cache the six Mesh tab-entry fetch groups without serializing them

- Mesh.vue: six useCachedResource entries wrap mesh.refreshAll(),
  transport.fetchStatus(), refreshFederationNodes(), refreshSelfOnion(),
  refreshSelfDid() and refreshContacts(), each with an explicit TTL
  (10s reachability/transport, 30s federation/contacts, 300s self
  DID/onion) and persist decision (T-02-01: every group carrying peer
  or self identity data is persist:false; only aggregate transport
  status may persist)
- armMeshLive's Promise.all fan-out becomes a single Promise.allSettled
  over refreshMeshGroupIfStale() per group, so a revisit inside TTL
  issues zero RPC, a stale revisit revalidates concurrently (not a
  serial chain, T-02-16), and one rejected group never blocks the rest
- RefreshIndicator wired into the Mesh header, driven by whether any of
  the six groups is refreshing — visible while peer reachability
  revalidates on re-entry so a resumed tab never shows a frozen
  reachability state as current (T-02-13)
- dedup: true added to every underlying rpc-client.ts/mesh.ts/
  transport.ts fetcher call backing the six groups
- useCachedResource() calls live in Mesh.vue rather than inside
  stores/mesh.ts or stores/transport.ts: Pinia's defineStore(id, setup)
  runs in a bare effectScope, not a component instance, so the
  composable's internal onActivated() would silently no-op there; the
  fetchers still wrap the stores' own actions unchanged, so those
  actions' other callers (clearAllMesh, setMeshOnly, the pre-send
  balance check) keep their guaranteed-fresh, uncached reads

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-30 16:14:32 -04:00
co-authored by Claude Fable 5
parent e582124259
commit 31389bcc3c
6 changed files with 507 additions and 9 deletions
+5 -2
View File
@@ -318,7 +318,7 @@ export const useMeshStore = defineStore('mesh', () => {
async function fetchStatus() {
try {
loading.value = true
const res = await rpcClient.call<MeshStatus>({ method: 'mesh.status' })
const res = await rpcClient.call<MeshStatus>({ method: 'mesh.status', dedup: true })
status.value = res
trackDetectedDevices(res)
} catch (err: unknown) {
@@ -462,6 +462,7 @@ export const useMeshStore = defineStore('mesh', () => {
try {
const res = await rpcClient.call<{ peers: MeshPeer[]; count: number }>({
method: 'mesh.peers',
dedup: true,
})
peers.value = res.peers
updateNodePositionsFromPeers(res.peers)
@@ -475,6 +476,7 @@ export const useMeshStore = defineStore('mesh', () => {
const res = await rpcClient.call<{ messages: MeshMessage[]; count: number }>({
method: 'mesh.messages',
params: limit ? { limit } : {},
dedup: true,
})
if (seedLastSeenFromHistory && res.messages.length > 0) {
for (const m of res.messages) {
@@ -1019,7 +1021,7 @@ export const useMeshStore = defineStore('mesh', () => {
async function fetchDeadmanStatus() {
try {
deadmanStatus.value = await rpcClient.call<AlertStatus>({ method: 'mesh.deadman-status' })
deadmanStatus.value = await rpcClient.call<AlertStatus>({ method: 'mesh.deadman-status', dedup: true })
} catch {
// Dead man switch not available
}
@@ -1052,6 +1054,7 @@ export const useMeshStore = defineStore('mesh', () => {
const res = await rpcClient.call<{ headers: BlockHeader[]; latest_height: number; count: number }>({
method: 'mesh.block-headers',
params: { count },
dedup: true,
})
blockHeaders.value = res.headers
latestBlockHeight.value = res.latest_height
+2 -1
View File
@@ -45,7 +45,7 @@ export const useTransportStore = defineStore('transport', () => {
try {
loading.value = true
error.value = null
const res = await rpcClient.call<TransportStatus>({ method: 'transport.status' })
const res = await rpcClient.call<TransportStatus>({ method: 'transport.status', dedup: true })
status.value = res
} catch (err: unknown) {
error.value = err instanceof Error ? err.message : 'Failed to fetch transport status'
@@ -58,6 +58,7 @@ export const useTransportStore = defineStore('transport', () => {
try {
const res = await rpcClient.call<{ peers: TransportPeer[] }>({
method: 'transport.peers',
dedup: true,
})
peers.value = res.peers
} catch (err: unknown) {