import { Log } from "@/util/log" export namespace State { interface Entry { state: any dispose?: (state: any) => Promise } const log = Log.create({ service: "state" }) const recordsByKey = new Map>() export function create(root: () => string, init: () => S, dispose?: (state: Awaited) => Promise) { return () => { const key = root() let entries = recordsByKey.get(key) if (!entries) { entries = new Map() recordsByKey.set(key, entries) } const exists = entries.get(init) if (exists) return exists.state as S const state = init() entries.set(init, { state, dispose, }) return state } } export async function dispose(key: string) { const entries = recordsByKey.get(key) if (!entries) return log.info("waiting for state disposal to complete", { key }) let disposalFinished = false setTimeout(() => { if (!disposalFinished) { log.warn( "state disposal is taking an unusually long time - if it does not complete in a reasonable time, please report this as a bug", { key }, ) } }, 10000).unref() const tasks: Promise[] = [] for (const entry of entries.values()) { if (!entry.dispose) continue const task = Promise.resolve(entry.state) .then((state) => entry.dispose!(state)) .catch((error) => { log.error("Error while disposing state:", { error, key }) }) tasks.push(task) } entries.clear() recordsByKey.delete(key) await Promise.all(tasks) disposalFinished = true log.info("state disposal completed", { key }) } }