UNPKG

@sphereon/ssi-types

Version:

SSI Common Types

211 lines (182 loc) • 5.97 kB
import { EventEmitter } from 'events' import { Loggers, LogLevel, LogMethod } from '../logging' export enum System { GENERAL = 'general', KMS = 'kms', IDENTITY = 'identity', OID4VCI = 'oid4vci', OID4VP = 'oid4vp', SIOPv2 = 'siopv2', PE = 'PE', CREDENTIALS = 'credentials', WEB3 = 'web3', PROFILE = 'profile', CONTACT = 'contact', } export enum SubSystem { KEY = 'key', DID_PROVIDER = 'did_provider', DID_RESOLVER = 'did_resolver', OID4VP_OP = 'oid4vp_op', OID4VCI_CLIENT = 'oid4vci_client', SIOPv2_OP = 'siopv2_op', CONTACT_MANAGER = 'contact_manager', VC_ISSUER = 'vc_issuer', VC_VERIFIER = 'vc_verifier', VC_PERSISTENCE = 'vc_persistence', TRANSPORT = 'transport', PROFILE = 'profile', API = 'api', } export enum ActionType { CREATE = 'create', READ = 'read', UPDATE = 'update', DELETE = 'delete', EXECUTE = 'execute', } export enum DefaultActionSubType { KEY_GENERATION = 'Key generation', KEY_IMPORT = 'Key import', KEY_PERSISTENCE = 'Key persistence', KEY_REMOVAL = 'Key removal', DID_CREATION = 'DID creation', DID_RESOLUTION = 'DID resolution', DID_SERVICE_UPDATE = 'DID service update', VC_ISSUE = 'VC issue', VC_VERIFY = 'VC verify', VC_SHARE = 'VC share', VC_DELETE = 'VC delete', VC_ISSUE_DECLINE = 'VC issue decline', VC_SHARE_DECLINE = 'VC share decline', } export type ActionSubType = DefaultActionSubType | string export enum InitiatorType { USER = 'user', SYSTEM = 'system', EXTERNAL = 'external', } export enum SystemCorrelationIdType { DID = 'did', URL = 'url', EMAIL = 'email', HOSTNAME = 'hostname', PHONE = 'phone', USER = 'user', } export type EventData = { system: string subSystemType: string } export interface BasicEvent<SourceType, PayloadType extends EventData> { id: string correlationId?: string eventName: string initiator?: string initiatorType: InitiatorType system: System subsystem: SubSystem data: PayloadType } type EmitterInstance = { enabled: boolean emitter: EventEmitter } export class EventManager { private static readonly INSTANCE = new EventManager() private _emitters = new Map<string, EmitterInstance>() private constructor() {} public static instance(): EventManager { return EventManager.INSTANCE } register(name: string, emitter: EventEmitter, opts?: { disabled: boolean }): EventEmitter { this._emitters.set(name, { emitter, enabled: opts?.disabled !== true }) return emitter } get(name: string, opts?: { onlyEnabled?: boolean }): EventEmitter { const { emitter, enabled } = this._emitters.get(name) ?? {} if (!emitter) { throw Error(`No emitter registered with name ${name}`) } else if (opts?.onlyEnabled && !enabled) { throw Error(`Emitter with name ${name} is not enabled`) } return emitter } getOrCreate(name: string, opts?: { onlyEnabled?: boolean }): EventEmitter { if (this.has(name)) { return this.get(name, opts) } return this.register(name, new BasicEventEmitter()) } has(name: string): boolean { return this._emitters.has(name) } emitters(filter?: { eventName?: string | symbol; onlyEnabled?: boolean }): Array<EventEmitter> { const all = Array.from(new Set(this._emitters.values())) return this.emittersImpl(all, filter).map((e) => e.emitter) } hasEventName(eventName: string | symbol) { return this.eventNames().includes(eventName) } eventNames(): Array<string | symbol> { return Array.from(new Set(this.emitters().flatMap((emitter) => emitter.eventNames()))) } emitBasic(event: BasicEvent<any, any>, ...args: any[]) { return this.emit(event.eventName, event, args) } emit(eventName: string | symbol, event: Omit<BasicEvent<any, any>, 'eventName'> | any, ...args: any[]): void { if ('id' in event && 'system' in event && !event.eventName) { event.eventName = eventName } Loggers.DEFAULT.options('sphereon:events', { methods: [LogMethod.CONSOLE], defaultLogLevel: LogLevel.INFO, }) .get('sphereon:events') .log(`Emitting '${eventName.toString()}' event`, event) const emitters = this.emitters({ eventName }) emitters.flatMap((emitter) => emitter.emit(eventName, event, args)) } listenerCount(eventName: string | symbol) { const emitters = this.emitters({ eventName }) return emitters.map((emitter) => emitter.listenerCount(eventName)).reduce((previous, current) => current + previous) } listeners(filter: { emitterName?: string; eventName: string; onlyEnabled?: boolean }): Array<Function> { const emitters = filter?.emitterName ? [this.get(filter.emitterName, filter)] : this.emitters(filter) return Array.from( new Set( this.emittersImpl( emitters.map((emitter) => { return { emitter, enabled: true } }), filter, ).flatMap((emitter) => emitter.emitter.listeners(filter.eventName)), ), ) } private emittersImpl( all: { emitter: EventEmitter; enabled: boolean }[], filter?: { eventName?: string | symbol onlyEnabled?: boolean }, ): Array<EmitterInstance> { const { eventName } = filter ?? {} if (!eventName) { return all } const filtered = all.filter((emitter) => emitter.emitter.eventNames().includes(eventName) && (emitter.enabled || filter?.onlyEnabled !== true)) return Array.from(new Set(filtered)) } } export class BasicEventEmitter extends EventEmitter { addListener(eventName: string | symbol, listener: (event: BasicEvent<any, any>, ...args: any[]) => void): this { return super.addListener(eventName, listener) } once(eventName: string | symbol, listener: (event: BasicEvent<any, any>, ...args: any[]) => void): this { return super.once(eventName, listener) } emit(eventName: string, event: BasicEvent<any, any>, ...args: any[]): boolean { return super.emit(eventName, ...args) } }