export type ReactiveCacheListener = (value: T) => void; export interface ReactiveCacheRef { value: T; } export interface ReactiveCache { cache: Map>; subscribers: Map>>; } export function createReactiveCache(): ReactiveCache { return { cache: new Map(), subscribers: new Map(), }; } export function createReactiveCacheRef( cache: ReactiveCache, key: string, value: T, ): ReactiveCacheRef { const currentRef = cache.cache.get(key); if (currentRef) { return currentRef; } const newRef: ReactiveCacheRef = { value, }; cache.cache.set(key, newRef); return newRef; } export function subscribeReactiveCache( cache: ReactiveCache, key: string, listener: ReactiveCacheListener, ): () => void { let subscribers = cache.subscribers.get(key); if (!subscribers) { subscribers = new Set(); cache.subscribers.set(key, subscribers); } subscribers.add(listener); return () => { if (subscribers) { subscribers.delete(listener); } }; } export function setReactiveCacheValue( cache: ReactiveCache, key: string, value: T, notify = true, ): void { const currentRef = createReactiveCacheRef(cache, key, value); currentRef.value = value; if (notify) { let subscribers = cache.subscribers.get(key); if (!subscribers) { subscribers = new Set(); cache.subscribers.set(key, subscribers); } for (const listener of subscribers.keys()) { listener(value); } } } export function getReactiveCacheListenerSize( cache: ReactiveCache, key: string, ): number { const result = cache.subscribers.get(key); if (result) { return result.size; } return 0; }