import type { ModulesMap } from '../agent/AgentModules' import type { MessageHandler } from '../agent/MessageHandler' import type { Constructor } from '../utils/mixins' import type { DependencyContainer } from 'tsyringe' import { container as rootContainer, InjectionToken, Lifecycle } from 'tsyringe' import { FeatureRegistry } from '../agent/FeatureRegistry' import { MessageHandlerRegistry } from '../agent/MessageHandlerRegistry' import { AriesFrameworkError } from '../error' export { InjectionToken } export class DependencyManager { public readonly container: DependencyContainer public readonly registeredModules: ModulesMap public constructor( container: DependencyContainer = rootContainer.createChildContainer(), registeredModules: ModulesMap = {} ) { this.container = container this.registeredModules = registeredModules } public registerModules(modules: ModulesMap) { const featureRegistry = this.resolve(FeatureRegistry) for (const [moduleKey, module] of Object.entries(modules)) { if (this.registeredModules[moduleKey]) { throw new AriesFrameworkError( `Module with key ${moduleKey} has already been registered. Only a single module can be registered with the same key.` ) } this.registeredModules[moduleKey] = module module.register(this, featureRegistry) } } public registerMessageHandlers(messageHandlers: MessageHandler[]) { const messageHandlerRegistry = this.resolve(MessageHandlerRegistry) for (const messageHandler of messageHandlers) { messageHandlerRegistry.registerMessageHandler(messageHandler) } } public registerSingleton(from: InjectionToken, to: InjectionToken): void public registerSingleton(token: Constructor): void // eslint-disable-next-line @typescript-eslint/no-explicit-any public registerSingleton(fromOrToken: InjectionToken | Constructor, to?: any) { this.container.registerSingleton(fromOrToken, to) } public resolve(token: InjectionToken): T { return this.container.resolve(token) } public registerInstance(token: InjectionToken, instance: T) { this.container.registerInstance(token, instance) } public isRegistered(token: InjectionToken): boolean { return this.container.isRegistered(token) } // eslint-disable-next-line @typescript-eslint/no-explicit-any public registerContextScoped(token: Constructor): void // eslint-disable-next-line @typescript-eslint/no-explicit-any public registerContextScoped(token: InjectionToken, provider: Constructor): void // eslint-disable-next-line @typescript-eslint/no-explicit-any public registerContextScoped(token: any, provider?: any) { if (provider) this.container.register(token, provider, { lifecycle: Lifecycle.ContainerScoped }) else this.container.register(token, token, { lifecycle: Lifecycle.ContainerScoped }) } /** * Dispose the dependency manager. Calls `.dispose()` on all instances that implement the `Disposable` interface and have * been constructed by the `DependencyManager`. This means all instances registered using `registerInstance` won't have the * dispose method called. */ public async dispose() { await this.container.dispose() } public createChild() { return new DependencyManager(this.container.createChildContainer(), this.registeredModules) } }