/** * mizan cache — TypeScript adapter. * * Same protocol as Python's mizan.cache. Cross-language conformance * verified by pin tests. */ export { MemoryCache } from './backend' export type { CacheBackend } from './backend' export { deriveCacheKey, buildIndexKeys } from './keys' import type { CacheBackend } from './backend' import { deriveCacheKey, buildIndexKeys } from './keys' let _cacheInstance: CacheBackend | null = null export function getCache(): CacheBackend | null { return _cacheInstance } export function setCache(backend: CacheBackend | null): void { _cacheInstance = backend } export function resetCache(): void { _cacheInstance = null } export function cacheGet( secret: string, backend: CacheBackend, context: string, params: Record, userId?: string, rev: number = 0, ): string | null { const key = deriveCacheKey(secret, context, params, userId, rev) return backend.get(key) } export function cachePut( secret: string, backend: CacheBackend, context: string, params: Record, value: string, userId?: string, rev: number = 0, ): void { const key = deriveCacheKey(secret, context, params, userId, rev) const indexes = buildIndexKeys(context, params) backend.put(key, value, indexes) } export function cachePurge( backend: CacheBackend, context: string, params?: Record | null, ): number { if (params) { // Scoped purge — AND semantics (intersection) const setsPerParam: Set[] = [] const paramIndexKeys: string[] = [] for (const [k, v] of Object.entries(params).sort(([a], [b]) => a.localeCompare(b))) { const indexKey = `mizan:idx:${context}:${k}=${String(v)}` paramIndexKeys.push(indexKey) setsPerParam.push(backend.getIndex(indexKey)) } let keysToDelete: Set if (setsPerParam.length > 0) { keysToDelete = setsPerParam[0] for (let i = 1; i < setsPerParam.length; i++) { keysToDelete = new Set([...keysToDelete].filter(k => setsPerParam[i].has(k))) } } else { keysToDelete = new Set() } if (keysToDelete.size > 0) { for (const idxKey of paramIndexKeys) { backend.removeFromIndex(idxKey, keysToDelete) } backend.removeFromIndex(`mizan:idx:${context}`, keysToDelete) return backend.deleteMany([...keysToDelete]) } return 0 } else { // Broad purge const indexKey = `mizan:idx:${context}` const keysToDelete = backend.getIndex(indexKey) backend.deleteIndex(indexKey) backend.deleteIndexesByPrefix(`mizan:idx:${context}:`) if (keysToDelete.size > 0) { return backend.deleteMany([...keysToDelete]) } return 0 } }