UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

71 lines (66 loc) 1.91 kB
import QuickLRU from 'quick-lru' import {concat, defer, EMPTY, map, type Observable, of, type OperatorFunction} from 'rxjs' import {tap} from 'rxjs/operators' /** * The interface that any caching layer must implement * @internal */ interface SWRCache<T> { /** * Note: This will throw if key does not exist. Always check for existence with `has` before calling */ get(key: string): T has(key: string): boolean set(key: string, value: T): void delete(key: string): void } const createSWRCache = createLRUCache /** * * Create an SWR (Stale While Revalidate) rxjs operator that will store the latest value in a cache and emit the last know value upon observable subscription * @param options - Options * @internal */ export function createSWR<T>(options: {maxSize: number}) { const cache = createSWRCache<T>(options) return function rxSwr(key: string): OperatorFunction<T, {fromCache: boolean; value: T}> { return (input$: Observable<T>) => { return concat( defer(() => (cache.has(key) ? of({fromCache: true, value: cache.get(key)}) : EMPTY)), input$.pipe( tap((result) => cache.set(key, result)), map((value) => ({ fromCache: false, value: value, })), ), ) } } } /** * For now, the only cache layer implemented is an in-memory LRU. * @param options - LRU options * @internal */ function createLRUCache<T>(options: {maxSize: number}): SWRCache<T> { const lru = new QuickLRU<string, {value: T}>(options) return { get(key: string) { const entry = lru.get(key) if (!entry) { throw new Error(`Key not found in LRU cache: ${key}`) } return entry.value }, set(key: string, value: T) { lru.set(key, {value}) }, delete(key: string) { lru.delete(key) }, has(key: string) { return lru.has(key) }, } }