feat(ui): B5 — /ws/db pushes revalidate cached resources
Some checks failed
Demo images / Build & push demo images (push) Failing after 2m5s
Some checks failed
Demo images / Build & push demo images (push) Failing after 2m5s
Bridge WebSocket patches into the resource layer: a /peer-health/<onion> patch invalidates that peer's cloud.peer-browse entry and the federation node list; /package-data patches invalidate the tor-services list. invalidate() debounces 800ms and refetches only keys with mounted subscribers, so patch storms cost one revalidation per key; the 30s staleness reconciliation remains the backstop for unmapped data. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8907cc47d9
commit
73228114b9
@ -2,9 +2,38 @@
|
||||
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import type { DataModel } from '../types/api'
|
||||
import type { DataModel, PatchOperation } from '../types/api'
|
||||
import { wsClient, applyDataPatch } from '../api/websocket'
|
||||
import { rpcClient } from '../api/rpc-client'
|
||||
import { useResourcesStore } from './resources'
|
||||
|
||||
/** Unescape one JSON-pointer segment (RFC 6901: ~1 → '/', ~0 → '~'). */
|
||||
function pointerSegment(path: string, prefix: string): string {
|
||||
const seg = path.slice(prefix.length).split('/')[0] ?? ''
|
||||
return seg.replace(/~1/g, '/').replace(/~0/g, '~')
|
||||
}
|
||||
|
||||
/** B5: bridge /ws/db pushes into the cached-resource layer. Each patch op
|
||||
* maps to the resource keys whose backing data it changes; invalidate()
|
||||
* debounces (800ms) and only refetches keys with mounted subscribers, so a
|
||||
* patch storm costs one revalidation per key. The 30s staleness
|
||||
* reconciliation stays as the backstop for anything unmapped. */
|
||||
function invalidateResourcesForPatch(patch: PatchOperation[]): void {
|
||||
const resources = useResourcesStore()
|
||||
for (const op of patch) {
|
||||
const path = op.path ?? ''
|
||||
if (path.startsWith('/peer-health/')) {
|
||||
// A peer flipping reachability changes both its browse result and the
|
||||
// federation node list's online state.
|
||||
const onion = pointerSegment(path, '/peer-health/')
|
||||
if (onion) resources.invalidate(`cloud.peer-browse:${onion}`)
|
||||
resources.invalidate('federation.nodes')
|
||||
} else if (path.startsWith('/package-data/')) {
|
||||
// App installs/uninstalls add or remove their tor services.
|
||||
resources.invalidate('server.tor-services')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useSyncStore = defineStore('sync', () => {
|
||||
// State
|
||||
@ -108,6 +137,7 @@ export const useSyncStore = defineStore('sync', () => {
|
||||
try {
|
||||
if (import.meta.env.DEV) console.log('[Store] Applying patch at revision', update.rev || 'unknown')
|
||||
data.value = applyDataPatch(data.value, update.patch)
|
||||
invalidateResourcesForPatch(update.patch)
|
||||
// Mark as connected once we receive any valid patch
|
||||
if (!isConnected.value) {
|
||||
isConnected.value = true
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user