import { Mutex as AsyncMutex } from 'async-mutex' export const makeMutex = () => { const mutex = new AsyncMutex() return { mutex(code: () => Promise | T): Promise { return mutex.runExclusive(code) } } } export type Mutex = ReturnType export const makeKeyedMutex = () => { const map = new Map() return { async mutex(key: string, task: () => Promise | T): Promise { let entry = map.get(key) if (!entry) { entry = { mutex: new AsyncMutex(), refCount: 0 } map.set(key, entry) } entry.refCount++ try { return await entry.mutex.runExclusive(task) } finally { entry.refCount-- // only delete it if this is still the current entry if (entry.refCount === 0 && map.get(key) === entry) { map.delete(key) } } } } } export type KeyedMutex = ReturnType