diff --git a/src/util/support/global.ts b/src/util/support/global.ts index 323eb33..8b91dfb 100644 --- a/src/util/support/global.ts +++ b/src/util/support/global.ts @@ -1,18 +1,30 @@ import {Collection} from '../collection/Collection' import {uuid4} from './data' +import {AsyncLocalStorage} from 'async_hooks' /** * Type structure for a single item in the global registry. */ export type GlobalRegistrant = { key: string | symbol, value: any } +export class AccessGlobalRegistryOutsideAsyncLifecycleError extends Error { + constructor() { + super('Attempted to access global registry outside of an async context.') + } +} + /** * A convenient class to manage global variables. */ -export class GlobalRegistry extends Collection { - constructor() { - super() - this.setGlobal('registry_uuid', uuid4()) +export class GlobalRegistry { + protected readonly storage: AsyncLocalStorage> = new AsyncLocalStorage>() + + /** Run a closure with a global registry. */ + public run(closure: () => T): T { + return this.storage.run(new Collection(), (): T => { + this.setGlobal('registry_uuid', uuid4()) + return closure() + }) } /** @@ -21,11 +33,11 @@ export class GlobalRegistry extends Collection { * @param value */ public setGlobal(key: string | symbol, value: unknown): this { - const existing = this.firstWhere('key', '=', key) + const existing = this.getCollection().firstWhere('key', '=', key) if ( existing ) { existing.value = value } else { - this.push({ + this.getCollection().push({ key, value, }) @@ -39,7 +51,17 @@ export class GlobalRegistry extends Collection { * @param key */ public getGlobal(key: string | symbol): any { - return this.firstWhere('key', '=', key)?.value + return this.getCollection().firstWhere('key', '=', key)?.value + } + + /** Get the globals collection or throw an error if outside async context. */ + protected getCollection(): Collection { + const coll = this.storage.getStore() + if ( !coll ) { + throw new AccessGlobalRegistryOutsideAsyncLifecycleError() + } + + return coll } }