export function cacher(thunk: () => Promise, ttlSeconds = 60) { const noCache: unique symbol = Symbol("cache"); let cache: Promise | symbol = noCache; return function execThunk(): Promise { if (typeof cache !== "symbol") { return cache; } cache = thunk(); setTimeout(() => { cache = noCache; }, 1000 * ttlSeconds); return cache; }; } // This cache repo is really just a map of cache keys to cachers // callback is the function to cache, props are the call arguments export function cacheRepo( callback: (this: This, props: Props) => Promise, ttlSeconds = 60 ) { const repo = new Map Promise>(); return function execCallback(this: This, props: Props): Promise { const cacheKey = JSON.stringify(props); let myCacher = repo.get(cacheKey); if (myCacher) { return myCacher(); } const myThunk = () => callback.call(this, props); myCacher = cacher(myThunk, ttlSeconds); repo.set(cacheKey, myCacher); setTimeout(() => { // Note: this critical delete step helps minimize the cache mem size, avoid mem leaks repo.delete(cacheKey); }, 1000 * ttlSeconds); return myCacher(); }; }