import type { Store } from '@/store/store' import { CACHE_COMPAT, getCache } from '@/store/manager' // How long a host stays "known compatible" before difyctl re-probes /_version. export const COMPAT_TTL_MS = 60 * 60 * 1000 // Only *positive* (compatible) verdicts are cached — never "too old". A host that // was too old is re-probed every time, so a just-upgraded server clears a previous // block immediately instead of staying locked out for the whole TTL. const COMPATIBLE_KEY = { key: 'compatible', default: {} as Record } as const export type CompatStore = { readonly isFreshCompatible: (host: string, now?: Date) => boolean readonly markCompatible: (host: string, now?: Date) => Promise } export type CompatStoreOptions = { readonly store?: Store readonly now?: () => Date readonly ttlMs?: number } export async function loadCompatStore(opts: CompatStoreOptions = {}): Promise { const store = opts.store ?? getCache(CACHE_COMPAT) const ttlMs = opts.ttlMs ?? COMPAT_TTL_MS const clock = opts.now ?? (() => new Date()) const memory = await readCompatible(store) return { isFreshCompatible: (host, now) => { const last = memory.get(host) if (last === undefined) return false const elapsed = Math.max(0, (now ?? clock()).getTime() - last) return elapsed < ttlMs }, markCompatible: async (host, now) => { const stamp = (now ?? clock()).getTime() memory.set(host, stamp) // Re-read disk inside the write cycle so concurrent processes touching // different hosts don't clobber each other's stamps. const onDisk = await readCompatible(store) onDisk.set(host, stamp) await writeCompatible(store, onDisk) }, } } async function readCompatible(store: Store): Promise> { const out = new Map() let raw: Record try { raw = await store.get(COMPATIBLE_KEY) } catch { return out } for (const [host, iso] of Object.entries(raw)) { const t = Date.parse(iso) if (!Number.isNaN(t)) out.set(host, t) } return out } async function writeCompatible(store: Store, state: Map): Promise { const compatible: Record = {} for (const [host, t] of state) compatible[host] = new Date(t).toISOString() await store.set(COMPATIBLE_KEY, compatible) }