diff --git a/demo/src/BaseAgent.ts b/demo/src/BaseAgent.ts index 3332af9ec4..efc4260103 100644 --- a/demo/src/BaseAgent.ts +++ b/demo/src/BaseAgent.ts @@ -42,7 +42,7 @@ export class BaseAgent { this.config = config - this.agent = new Agent(config, agentDependencies) + this.agent = new Agent({ config, dependencies: agentDependencies }) this.agent.registerInboundTransport(new HttpInboundTransport({ port })) this.agent.registerOutboundTransport(new HttpOutboundTransport()) } diff --git a/packages/core/src/agent/Agent.ts b/packages/core/src/agent/Agent.ts index 50e00f6610..c1bdc5e009 100644 --- a/packages/core/src/agent/Agent.ts +++ b/packages/core/src/agent/Agent.ts @@ -2,6 +2,7 @@ import type { InboundTransport } from '../transport/InboundTransport' import type { OutboundTransport } from '../transport/OutboundTransport' import type { InitConfig } from '../types' import type { AgentDependencies } from './AgentDependencies' +import type { AgentModulesInput, ModulesMap } from './AgentModules' import type { AgentMessageReceivedEvent } from './Events' import type { Subscription } from 'rxjs' @@ -12,27 +13,14 @@ import { CacheRepository } from '../cache' import { InjectionSymbols } from '../constants' import { JwsService } from '../crypto/JwsService' import { AriesFrameworkError } from '../error' -import { BasicMessagesModule } from '../modules/basic-messages' -import { ConnectionsModule } from '../modules/connections' -import { CredentialsModule } from '../modules/credentials' -import { DidsModule } from '../modules/dids' -import { DiscoverFeaturesModule } from '../modules/discover-features' -import { GenericRecordsModule } from '../modules/generic-records' -import { IndyModule } from '../modules/indy' -import { LedgerModule } from '../modules/ledger' -import { OutOfBandModule } from '../modules/oob' -import { ProofsModule } from '../modules/proofs' -import { QuestionAnswerModule } from '../modules/question-answer' -import { MediatorModule, RecipientModule } from '../modules/routing' -import { W3cVcModule } from '../modules/vc' import { DependencyManager } from '../plugins' import { DidCommMessageRepository, StorageUpdateService, StorageVersionRepository } from '../storage' import { InMemoryMessageRepository } from '../storage/InMemoryMessageRepository' import { IndyStorageService } from '../storage/IndyStorageService' -import { WalletModule } from '../wallet' import { IndyWallet } from '../wallet/IndyWallet' import { AgentConfig } from './AgentConfig' +import { extendModulesWithDefaultModules } from './AgentModules' import { BaseAgent } from './BaseAgent' import { Dispatcher } from './Dispatcher' import { EnvelopeService } from './EnvelopeService' @@ -44,17 +32,71 @@ import { MessageSender } from './MessageSender' import { TransportService } from './TransportService' import { AgentContext, DefaultAgentContextProvider } from './context' -export class Agent extends BaseAgent { +interface AgentOptions { + config: InitConfig + modules?: AgentModules + dependencies: AgentDependencies +} + +export class Agent extends BaseAgent { public messageSubscription: Subscription - public constructor( - initialConfig: InitConfig, - dependencies: AgentDependencies, - dependencyManager?: DependencyManager - ) { - // NOTE: we can't create variables before calling super as TS will complain that the super call must be the - // the first statement in the constructor. - super(new AgentConfig(initialConfig, dependencies), dependencyManager ?? new DependencyManager()) + public constructor(options: AgentOptions, dependencyManager = new DependencyManager()) { + const agentConfig = new AgentConfig(options.config, options.dependencies) + const modulesWithDefaultModules = extendModulesWithDefaultModules(agentConfig, options.modules) + + // Register internal dependencies + dependencyManager.registerSingleton(EventEmitter) + dependencyManager.registerSingleton(MessageSender) + dependencyManager.registerSingleton(MessageReceiver) + dependencyManager.registerSingleton(TransportService) + dependencyManager.registerSingleton(Dispatcher) + dependencyManager.registerSingleton(EnvelopeService) + dependencyManager.registerSingleton(FeatureRegistry) + dependencyManager.registerSingleton(JwsService) + dependencyManager.registerSingleton(CacheRepository) + dependencyManager.registerSingleton(DidCommMessageRepository) + dependencyManager.registerSingleton(StorageVersionRepository) + dependencyManager.registerSingleton(StorageUpdateService) + + dependencyManager.registerInstance(AgentConfig, agentConfig) + dependencyManager.registerInstance(InjectionSymbols.AgentDependencies, agentConfig.agentDependencies) + dependencyManager.registerInstance(InjectionSymbols.Stop$, new Subject()) + dependencyManager.registerInstance(InjectionSymbols.FileSystem, new agentConfig.agentDependencies.FileSystem()) + + // Register possibly already defined services + if (!dependencyManager.isRegistered(InjectionSymbols.Wallet)) { + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndyWallet) + } + if (!dependencyManager.isRegistered(InjectionSymbols.Logger)) { + dependencyManager.registerInstance(InjectionSymbols.Logger, agentConfig.logger) + } + if (!dependencyManager.isRegistered(InjectionSymbols.StorageService)) { + dependencyManager.registerSingleton(InjectionSymbols.StorageService, IndyStorageService) + } + if (!dependencyManager.isRegistered(InjectionSymbols.MessageRepository)) { + dependencyManager.registerSingleton(InjectionSymbols.MessageRepository, InMemoryMessageRepository) + } + + // Register all modules. This will also include the default modules + dependencyManager.registerModules(modulesWithDefaultModules) + + // TODO: contextCorrelationId for base wallet + // Bind the default agent context to the container for use in modules etc. + dependencyManager.registerInstance( + AgentContext, + new AgentContext({ + dependencyManager, + contextCorrelationId: 'default', + }) + ) + + // If no agent context provider has been registered we use the default agent context provider. + if (!dependencyManager.isRegistered(InjectionSymbols.AgentContextProvider)) { + dependencyManager.registerSingleton(InjectionSymbols.AgentContextProvider, DefaultAgentContextProvider) + } + + super(agentConfig, dependencyManager) const stop$ = this.dependencyManager.resolve>(InjectionSymbols.Stop$) @@ -156,91 +198,6 @@ export class Agent extends BaseAgent { this._isInitialized = false } - protected registerDependencies(dependencyManager: DependencyManager) { - // Register internal dependencies - dependencyManager.registerSingleton(EventEmitter) - dependencyManager.registerSingleton(MessageSender) - dependencyManager.registerSingleton(MessageReceiver) - dependencyManager.registerSingleton(TransportService) - dependencyManager.registerSingleton(Dispatcher) - dependencyManager.registerSingleton(EnvelopeService) - dependencyManager.registerSingleton(FeatureRegistry) - dependencyManager.registerSingleton(JwsService) - dependencyManager.registerSingleton(CacheRepository) - dependencyManager.registerSingleton(DidCommMessageRepository) - dependencyManager.registerSingleton(StorageVersionRepository) - dependencyManager.registerSingleton(StorageUpdateService) - - dependencyManager.registerInstance(AgentConfig, this.agentConfig) - dependencyManager.registerInstance(InjectionSymbols.AgentDependencies, this.agentConfig.agentDependencies) - dependencyManager.registerInstance(InjectionSymbols.Stop$, new Subject()) - dependencyManager.registerInstance(InjectionSymbols.FileSystem, new this.agentConfig.agentDependencies.FileSystem()) - - // Register possibly already defined services - if (!dependencyManager.isRegistered(InjectionSymbols.Wallet)) { - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndyWallet) - } - if (!dependencyManager.isRegistered(InjectionSymbols.Logger)) { - dependencyManager.registerInstance(InjectionSymbols.Logger, this.logger) - } - if (!dependencyManager.isRegistered(InjectionSymbols.StorageService)) { - dependencyManager.registerSingleton(InjectionSymbols.StorageService, IndyStorageService) - } - if (!dependencyManager.isRegistered(InjectionSymbols.MessageRepository)) { - dependencyManager.registerSingleton(InjectionSymbols.MessageRepository, InMemoryMessageRepository) - } - - // Register all modules - dependencyManager.registerModules( - new ConnectionsModule({ - autoAcceptConnections: this.agentConfig.autoAcceptConnections, - }), - new CredentialsModule({ - autoAcceptCredentials: this.agentConfig.autoAcceptCredentials, - }), - new ProofsModule({ - autoAcceptProofs: this.agentConfig.autoAcceptProofs, - }), - new MediatorModule({ - autoAcceptMediationRequests: this.agentConfig.autoAcceptMediationRequests, - }), - new RecipientModule({ - maximumMessagePickup: this.agentConfig.maximumMessagePickup, - mediatorInvitationUrl: this.agentConfig.mediatorConnectionsInvite, - mediatorPickupStrategy: this.agentConfig.mediatorPickupStrategy, - mediatorPollingInterval: this.agentConfig.mediatorPollingInterval, - }), - new BasicMessagesModule(), - new QuestionAnswerModule(), - new GenericRecordsModule(), - new LedgerModule({ - connectToIndyLedgersOnStartup: this.agentConfig.connectToIndyLedgersOnStartup, - indyLedgers: this.agentConfig.indyLedgers, - }), - new DiscoverFeaturesModule(), - new DidsModule(), - new WalletModule(), - new OutOfBandModule(), - new IndyModule(), - new W3cVcModule() - ) - - // TODO: contextCorrelationId for base wallet - // Bind the default agent context to the container for use in modules etc. - dependencyManager.registerInstance( - AgentContext, - new AgentContext({ - dependencyManager, - contextCorrelationId: 'default', - }) - ) - - // If no agent context provider has been registered we use the default agent context provider. - if (!this.dependencyManager.isRegistered(InjectionSymbols.AgentContextProvider)) { - this.dependencyManager.registerSingleton(InjectionSymbols.AgentContextProvider, DefaultAgentContextProvider) - } - } - protected async getMediationConnection(mediatorInvitationUrl: string) { const outOfBandInvitation = this.oob.parseInvitation(mediatorInvitationUrl) const outOfBandRecord = await this.oob.findByInvitationId(outOfBandInvitation.id) diff --git a/packages/core/src/agent/AgentModules.ts b/packages/core/src/agent/AgentModules.ts new file mode 100644 index 0000000000..958a90f47e --- /dev/null +++ b/packages/core/src/agent/AgentModules.ts @@ -0,0 +1,212 @@ +import type { Module, DependencyManager } from '../plugins' +import type { Constructor } from '../utils/mixins' +import type { AgentConfig } from './AgentConfig' + +import { BasicMessagesModule } from '../modules/basic-messages' +import { ConnectionsModule } from '../modules/connections' +import { CredentialsModule } from '../modules/credentials' +import { DidsModule } from '../modules/dids' +import { DiscoverFeaturesModule } from '../modules/discover-features' +import { GenericRecordsModule } from '../modules/generic-records' +import { IndyModule } from '../modules/indy' +import { LedgerModule } from '../modules/ledger' +import { OutOfBandModule } from '../modules/oob' +import { ProofsModule } from '../modules/proofs' +import { QuestionAnswerModule } from '../modules/question-answer' +import { MediatorModule, RecipientModule } from '../modules/routing' +import { W3cVcModule } from '../modules/vc' +import { WalletModule } from '../wallet' + +/** + * Simple utility type that represent a map of modules. This is used to map from moduleKey (api key) to the api in the framework. + */ +export type ModulesMap = { [key: string]: Module } + +// eslint-disable-next-line @typescript-eslint/ban-types +export type EmptyModuleMap = {} + +/** + * Default modules can be optionally defined to provide custom configuration. This type makes it so that it is not + * possible to use a different key for the default modules + */ +export type AgentModulesInput = Partial & ModulesMap + +/** + * Type that represents the default agent modules. This is the {@link ModulesMap} variant for the default modules in the framework. + * It uses the return type of the {@link getDefaultAgentModules} method to automatically infer which modules are always available on + * the agent and in the agent. namespace. + */ +export type DefaultAgentModules = { + [moduleKey in keyof ReturnType]: ReturnType< + ReturnType[moduleKey] + > +} + +export type WithoutDefaultModules = { + [moduleKey in Exclude]: Modules[moduleKey] +} + +/** + * Type that represents the api object of the agent (`agent.xxx`). It will extract all keys of the modules and map this to the + * registered {@link Module.api} class instance. If the module does not have an api class registered, the property will be removed + * and won't be available on the api object. + * + * @example + * If the following AgentModules type was passed: + * ```ts + * { + * connections: ConnectionsModule + * indy: IndyModule + * } + * ``` + * + * And we use the `AgentApi` type like this: + * ```ts + * type MyAgentApi = AgentApi<{ + * connections: ConnectionsModule + * indy: IndyModule + * }> + * ``` + * + * the resulting agent api will look like: + * + * ```ts + * { + * connections: ConnectionsApi + * } + * ``` + * + * The `indy` module has been ignored because it doesn't define an api class. + */ +export type AgentApi = { + [moduleKey in keyof Modules as Modules[moduleKey]['api'] extends Constructor + ? moduleKey + : never]: Modules[moduleKey]['api'] extends Constructor ? InstanceType : never +} + +/** + * Method to get the default agent modules to be registered on any agent instance. + * + * @note This implementation is quite ugly and is meant to be temporary. It extracts the module specific config from the agent config + * and will only construct the module if the method is called. This prevents the modules from being initialized if they are already configured by the end + * user using the `module` property in the agent constructor. + */ +function getDefaultAgentModules(agentConfig: AgentConfig) { + return { + connections: () => + new ConnectionsModule({ + autoAcceptConnections: agentConfig.autoAcceptConnections, + }), + credentials: () => + new CredentialsModule({ + autoAcceptCredentials: agentConfig.autoAcceptCredentials, + }), + proofs: () => + new ProofsModule({ + autoAcceptProofs: agentConfig.autoAcceptProofs, + }), + mediator: () => + new MediatorModule({ + autoAcceptMediationRequests: agentConfig.autoAcceptMediationRequests, + }), + mediationRecipient: () => + new RecipientModule({ + maximumMessagePickup: agentConfig.maximumMessagePickup, + mediatorInvitationUrl: agentConfig.mediatorConnectionsInvite, + mediatorPickupStrategy: agentConfig.mediatorPickupStrategy, + mediatorPollingInterval: agentConfig.mediatorPollingInterval, + }), + basicMessages: () => new BasicMessagesModule(), + questionAnswer: () => new QuestionAnswerModule(), + genericRecords: () => new GenericRecordsModule(), + ledger: () => + new LedgerModule({ + connectToIndyLedgersOnStartup: agentConfig.connectToIndyLedgersOnStartup, + indyLedgers: agentConfig.indyLedgers, + }), + discovery: () => new DiscoverFeaturesModule(), + dids: () => new DidsModule(), + wallet: () => new WalletModule(), + oob: () => new OutOfBandModule(), + indy: () => new IndyModule(), + w3cVc: () => new W3cVcModule(), + } as const +} + +/** + * Extend the provided modules object with the default agent modules. If the modules property already contains a module with the same + * name as a default module, the module won't be added to the extended module object. This allows users of the framework to override + * the modules with custom configuration. The agent constructor type ensures you can't provide a different module for a key that registered + * on the default agent. + */ +export function extendModulesWithDefaultModules( + agentConfig: AgentConfig, + modules?: AgentModules +): AgentModules & DefaultAgentModules { + const extendedModules: Record = { ...modules } + const defaultAgentModules = getDefaultAgentModules(agentConfig) + + // Register all default modules, if not registered yet + for (const [moduleKey, getConfiguredModule] of Object.entries(defaultAgentModules)) { + // Do not register if the module is already registered. + if (modules && modules[moduleKey]) continue + + extendedModules[moduleKey] = getConfiguredModule() + } + + return extendedModules as AgentModules & DefaultAgentModules +} + +/** + * Get the agent api object based on the modules registered in the dependency manager. For each registered module on the + * dependency manager, the method will extract the api class from the module, resolve it and assign it to the module key + * as provided in the agent constructor (or the {@link getDefaultAgentModules} method). + * + * Modules that don't have an api class defined ({@link Module.api} is undefined) will be ignored and won't be added to the + * api object. + * + * If the api of a module is passed in the `excluded` array, the api will not be added to the resulting api object. + * + * @example + * If the dependency manager has the following modules configured: + * ```ts + * { + * connections: ConnectionsModule + * indy: IndyModule + * } + * ``` + * + * And we call the `getAgentApi` method like this: + * ```ts + * const api = getAgentApi(dependencyManager) + * ``` + * + * the resulting agent api will look like: + * + * ```ts + * { + * connections: ConnectionsApi + * } + * ``` + * + * The `indy` module has been ignored because it doesn't define an api class. + */ +export function getAgentApi( + dependencyManager: DependencyManager, + excludedApis: unknown[] = [] +): AgentApi { + // Create the api object based on the `api` properties on the modules. If no `api` exists + // on the module it will be ignored. + const api = Object.entries(dependencyManager.registeredModules).reduce((api, [moduleKey, module]) => { + // Module has no api + if (!module.api) return api + + const apiInstance = dependencyManager.resolve(module.api) + + // Api is excluded + if (excludedApis.includes(apiInstance)) return api + return { ...api, [moduleKey]: apiInstance } + }, {}) as AgentApi + + return api +} diff --git a/packages/core/src/agent/BaseAgent.ts b/packages/core/src/agent/BaseAgent.ts index ed407c881d..1f33036f2c 100644 --- a/packages/core/src/agent/BaseAgent.ts +++ b/packages/core/src/agent/BaseAgent.ts @@ -1,27 +1,28 @@ import type { Logger } from '../logger' import type { DependencyManager } from '../plugins' import type { AgentConfig } from './AgentConfig' +import type { AgentApi, EmptyModuleMap, ModulesMap, WithoutDefaultModules } from './AgentModules' import type { TransportSession } from './TransportService' import { AriesFrameworkError } from '../error' -import { BasicMessagesApi } from '../modules/basic-messages/BasicMessagesApi' -import { ConnectionsApi } from '../modules/connections/ConnectionsApi' -import { CredentialsApi } from '../modules/credentials/CredentialsApi' -import { DidsApi } from '../modules/dids/DidsApi' +import { BasicMessagesApi } from '../modules/basic-messages' +import { ConnectionsApi } from '../modules/connections' +import { CredentialsApi } from '../modules/credentials' +import { DidsApi } from '../modules/dids' import { DiscoverFeaturesApi } from '../modules/discover-features' -import { GenericRecordsApi } from '../modules/generic-records/GenericRecordsApi' -import { LedgerApi } from '../modules/ledger/LedgerApi' -import { OutOfBandApi } from '../modules/oob/OutOfBandApi' +import { GenericRecordsApi } from '../modules/generic-records' +import { LedgerApi } from '../modules/ledger' +import { OutOfBandApi } from '../modules/oob' import { ProofsApi } from '../modules/proofs/ProofsApi' -import { QuestionAnswerApi } from '../modules/question-answer/QuestionAnswerApi' -import { MediatorApi } from '../modules/routing/MediatorApi' -import { RecipientApi } from '../modules/routing/RecipientApi' +import { QuestionAnswerApi } from '../modules/question-answer' +import { MediatorApi, RecipientApi } from '../modules/routing' import { StorageUpdateService } from '../storage' import { UpdateAssistant } from '../storage/migration/UpdateAssistant' import { DEFAULT_UPDATE_CONFIG } from '../storage/migration/updates' -import { WalletApi } from '../wallet/WalletApi' +import { WalletApi } from '../wallet' import { WalletError } from '../wallet/error' +import { getAgentApi } from './AgentModules' import { EventEmitter } from './EventEmitter' import { FeatureRegistry } from './FeatureRegistry' import { MessageReceiver } from './MessageReceiver' @@ -29,7 +30,7 @@ import { MessageSender } from './MessageSender' import { TransportService } from './TransportService' import { AgentContext } from './context' -export abstract class BaseAgent { +export abstract class BaseAgent { protected agentConfig: AgentConfig protected logger: Logger public readonly dependencyManager: DependencyManager @@ -42,19 +43,21 @@ export abstract class BaseAgent { protected agentContext: AgentContext public readonly connections: ConnectionsApi + public readonly credentials: CredentialsApi public readonly proofs: ProofsApi + public readonly mediator: MediatorApi + public readonly mediationRecipient: RecipientApi public readonly basicMessages: BasicMessagesApi + public readonly questionAnswer: QuestionAnswerApi public readonly genericRecords: GenericRecordsApi public readonly ledger: LedgerApi - public readonly questionAnswer!: QuestionAnswerApi - public readonly credentials: CredentialsApi - public readonly mediationRecipient: RecipientApi - public readonly mediator: MediatorApi public readonly discovery: DiscoverFeaturesApi public readonly dids: DidsApi public readonly wallet: WalletApi public readonly oob: OutOfBandApi + public readonly modules: AgentApi> + public constructor(agentConfig: AgentConfig, dependencyManager: DependencyManager) { this.dependencyManager = dependencyManager @@ -73,8 +76,6 @@ export abstract class BaseAgent { ) } - this.registerDependencies(this.dependencyManager) - // Resolve instances after everything is registered this.eventEmitter = this.dependencyManager.resolve(EventEmitter) this.featureRegistry = this.dependencyManager.resolve(FeatureRegistry) @@ -83,10 +84,9 @@ export abstract class BaseAgent { this.transportService = this.dependencyManager.resolve(TransportService) this.agentContext = this.dependencyManager.resolve(AgentContext) - // We set the modules in the constructor because that allows to set them as read-only this.connections = this.dependencyManager.resolve(ConnectionsApi) this.credentials = this.dependencyManager.resolve(CredentialsApi) as CredentialsApi - this.proofs = this.dependencyManager.resolve(ProofsApi) as ProofsApi + this.proofs = this.dependencyManager.resolve(ProofsApi) this.mediator = this.dependencyManager.resolve(MediatorApi) this.mediationRecipient = this.dependencyManager.resolve(RecipientApi) this.basicMessages = this.dependencyManager.resolve(BasicMessagesApi) @@ -97,6 +97,25 @@ export abstract class BaseAgent { this.dids = this.dependencyManager.resolve(DidsApi) this.wallet = this.dependencyManager.resolve(WalletApi) this.oob = this.dependencyManager.resolve(OutOfBandApi) + + const defaultApis = [ + this.connections, + this.credentials, + this.proofs, + this.mediator, + this.mediationRecipient, + this.basicMessages, + this.questionAnswer, + this.genericRecords, + this.ledger, + this.discovery, + this.dids, + this.wallet, + this.oob, + ] + + // Set the api of the registered modules on the agent, excluding the default apis + this.modules = getAgentApi(this.dependencyManager, defaultApis) } public get isInitialized() { @@ -180,6 +199,4 @@ export abstract class BaseAgent { public get context() { return this.agentContext } - - protected abstract registerDependencies(dependencyManager: DependencyManager): void } diff --git a/packages/core/src/agent/__tests__/Agent.test.ts b/packages/core/src/agent/__tests__/Agent.test.ts index 8e33e303ff..0a091e51d9 100644 --- a/packages/core/src/agent/__tests__/Agent.test.ts +++ b/packages/core/src/agent/__tests__/Agent.test.ts @@ -1,4 +1,8 @@ -import { getBaseConfig } from '../../../tests/helpers' +import type { DependencyManager, Module } from '../../plugins' + +import { injectable } from 'tsyringe' + +import { getAgentOptions } from '../../../tests/helpers' import { InjectionSymbols } from '../../constants' import { BasicMessageRepository, BasicMessageService } from '../../modules/basic-messages' import { BasicMessagesApi } from '../../modules/basic-messages/BasicMessagesApi' @@ -15,11 +19,12 @@ import { ProofsApi } from '../../modules/proofs/ProofsApi' import { V1ProofService } from '../../modules/proofs/protocol/v1' import { V2ProofService } from '../../modules/proofs/protocol/v2' import { - MediatorApi, - RecipientApi, + MediationRecipientService, MediationRepository, + MediatorApi, MediatorService, - MediationRecipientService, + RecipientApi, + RecipientModule, } from '../../modules/routing' import { InMemoryMessageRepository } from '../../storage/InMemoryMessageRepository' import { IndyStorageService } from '../../storage/IndyStorageService' @@ -31,9 +36,62 @@ import { FeatureRegistry } from '../FeatureRegistry' import { MessageReceiver } from '../MessageReceiver' import { MessageSender } from '../MessageSender' -const { config, agentDependencies: dependencies } = getBaseConfig('Agent Class Test') +const agentOptions = getAgentOptions('Agent Class Test') + +const myModuleMethod = jest.fn() +@injectable() +class MyApi { + public myModuleMethod = myModuleMethod +} + +class MyModule implements Module { + public api = MyApi + public register(dependencyManager: DependencyManager) { + dependencyManager.registerContextScoped(MyApi) + } +} describe('Agent', () => { + describe('Module registration', () => { + test('does not return default modules on modules key if no modules were provided', () => { + const agent = new Agent(agentOptions) + + expect(agent.modules).toEqual({}) + }) + + test('registers custom and default modules if custom modules are provided', () => { + const agent = new Agent({ + ...agentOptions, + modules: { + myModule: new MyModule(), + }, + }) + + expect(agent.modules.myModule.myModuleMethod).toBe(myModuleMethod) + expect(agent.modules).toEqual({ + myModule: expect.any(MyApi), + }) + }) + + test('override default module configuration', () => { + const agent = new Agent({ + ...agentOptions, + modules: { + myModule: new MyModule(), + mediationRecipient: new RecipientModule({ + maximumMessagePickup: 42, + }), + }, + }) + + // Should be custom module config property, not the default value + expect(agent.mediationRecipient.config.maximumMessagePickup).toBe(42) + expect(agent.modules).toEqual({ + myModule: expect.any(MyApi), + }) + }) + }) + describe('Initialization', () => { let agent: Agent @@ -48,7 +106,7 @@ describe('Agent', () => { it('isInitialized should only return true after initialization', async () => { expect.assertions(2) - agent = new Agent(config, dependencies) + agent = new Agent(agentOptions) expect(agent.isInitialized).toBe(false) await agent.initialize() @@ -58,7 +116,7 @@ describe('Agent', () => { it('wallet isInitialized should return true after agent initialization if wallet config is set in agent constructor', async () => { expect.assertions(4) - agent = new Agent(config, dependencies) + agent = new Agent(agentOptions) const wallet = agent.context.wallet expect(agent.isInitialized).toBe(false) @@ -71,8 +129,8 @@ describe('Agent', () => { it('wallet must be initialized if wallet config is not set before agent can be initialized', async () => { expect.assertions(9) - const { walletConfig, ...withoutWalletConfig } = config - agent = new Agent(withoutWalletConfig, dependencies) + const { walletConfig, ...withoutWalletConfig } = agentOptions.config + agent = new Agent({ ...agentOptions, config: withoutWalletConfig }) expect(agent.isInitialized).toBe(false) expect(agent.wallet.isInitialized).toBe(false) @@ -92,24 +150,9 @@ describe('Agent', () => { }) }) - describe('Change label', () => { - let agent: Agent - - it('should return new label after setter is called', async () => { - expect.assertions(2) - const newLabel = 'Agent: Agent Class Test 2' - - agent = new Agent(config, dependencies) - expect(agent.config.label).toBe(config.label) - - agent.config.label = newLabel - expect(agent.config.label).toBe(newLabel) - }) - }) - describe('Dependency Injection', () => { it('should be able to resolve registered instances', () => { - const agent = new Agent(config, dependencies) + const agent = new Agent(agentOptions) const container = agent.dependencyManager // Modules @@ -140,7 +183,7 @@ describe('Agent', () => { expect(container.resolve(IndyLedgerService)).toBeInstanceOf(IndyLedgerService) // Symbols, interface based - expect(container.resolve(InjectionSymbols.Logger)).toBe(config.logger) + expect(container.resolve(InjectionSymbols.Logger)).toBe(agentOptions.config.logger) expect(container.resolve(InjectionSymbols.MessageRepository)).toBeInstanceOf(InMemoryMessageRepository) expect(container.resolve(InjectionSymbols.StorageService)).toBeInstanceOf(IndyStorageService) @@ -152,7 +195,7 @@ describe('Agent', () => { }) it('should return the same instance for consequent resolves', () => { - const agent = new Agent(config, dependencies) + const agent = new Agent(agentOptions) const container = agent.dependencyManager // Modules @@ -201,7 +244,7 @@ describe('Agent', () => { }) it('all core features are properly registered', () => { - const agent = new Agent(config, dependencies) + const agent = new Agent(agentOptions) const registry = agent.dependencyManager.resolve(FeatureRegistry) const protocols = registry.query({ featureType: 'protocol', match: '*' }).map((p) => p.id) diff --git a/packages/core/src/agent/__tests__/AgentConfig.test.ts b/packages/core/src/agent/__tests__/AgentConfig.test.ts index dc4708ebc8..559a9880a3 100644 --- a/packages/core/src/agent/__tests__/AgentConfig.test.ts +++ b/packages/core/src/agent/__tests__/AgentConfig.test.ts @@ -20,6 +20,21 @@ describe('AgentConfig', () => { }) }) + describe('label', () => { + it('should return new label after setter is called', async () => { + expect.assertions(2) + const newLabel = 'Agent: Agent Class Test 2' + + const agentConfig = getAgentConfig('AgentConfig Test', { + label: 'Test', + }) + expect(agentConfig.label).toBe('Test') + + agentConfig.label = newLabel + expect(agentConfig.label).toBe(newLabel) + }) + }) + describe('extend()', () => { it('extends the existing AgentConfig', () => { const agentConfig = new AgentConfig( diff --git a/packages/core/src/agent/__tests__/AgentModules.test.ts b/packages/core/src/agent/__tests__/AgentModules.test.ts new file mode 100644 index 0000000000..2dc6eca2ae --- /dev/null +++ b/packages/core/src/agent/__tests__/AgentModules.test.ts @@ -0,0 +1,137 @@ +import type { Module } from '../../plugins' + +import { + ConnectionsModule, + CredentialsModule, + ProofsModule, + MediatorModule, + RecipientModule, + BasicMessagesModule, + QuestionAnswerModule, + LedgerModule, + DidsModule, + OutOfBandModule, +} from '../..' +import { getAgentConfig } from '../../../tests/helpers' +import { DiscoverFeaturesModule } from '../../modules/discover-features' +import { GenericRecordsModule } from '../../modules/generic-records' +import { IndyModule } from '../../modules/indy' +import { W3cVcModule } from '../../modules/vc' +import { DependencyManager, injectable } from '../../plugins' +import { WalletModule } from '../../wallet' +import { extendModulesWithDefaultModules, getAgentApi } from '../AgentModules' + +const agentConfig = getAgentConfig('AgentModules Test') + +@injectable() +class MyApi {} + +class MyModuleWithApi implements Module { + public api = MyApi + public register(dependencyManager: DependencyManager) { + dependencyManager.registerContextScoped(MyApi) + } +} + +class MyModuleWithoutApi implements Module { + public register() { + // nothing to register + } +} + +describe('AgentModules', () => { + describe('getAgentApi', () => { + test('returns object with all api instances for modules with public api in dependency manager', () => { + const dependencyManager = new DependencyManager() + + dependencyManager.registerModules({ + withApi: new MyModuleWithApi(), + withoutApi: new MyModuleWithoutApi(), + }) + + const api = getAgentApi(dependencyManager) + + expect(api).toEqual({ + withApi: expect.any(MyApi), + }) + }) + }) + + describe('extendModulesWithDefaultModules', () => { + test('returns default modules if no modules were provided', () => { + const extendedModules = extendModulesWithDefaultModules(agentConfig) + + expect(extendedModules).toEqual({ + connections: expect.any(ConnectionsModule), + credentials: expect.any(CredentialsModule), + proofs: expect.any(ProofsModule), + mediator: expect.any(MediatorModule), + mediationRecipient: expect.any(RecipientModule), + basicMessages: expect.any(BasicMessagesModule), + questionAnswer: expect.any(QuestionAnswerModule), + genericRecords: expect.any(GenericRecordsModule), + ledger: expect.any(LedgerModule), + discovery: expect.any(DiscoverFeaturesModule), + dids: expect.any(DidsModule), + wallet: expect.any(WalletModule), + oob: expect.any(OutOfBandModule), + indy: expect.any(IndyModule), + w3cVc: expect.any(W3cVcModule), + }) + }) + + test('returns custom and default modules if custom modules are provided', () => { + const myModule = new MyModuleWithApi() + const extendedModules = extendModulesWithDefaultModules(agentConfig, { + myModule, + }) + + expect(extendedModules).toEqual({ + connections: expect.any(ConnectionsModule), + credentials: expect.any(CredentialsModule), + proofs: expect.any(ProofsModule), + mediator: expect.any(MediatorModule), + mediationRecipient: expect.any(RecipientModule), + basicMessages: expect.any(BasicMessagesModule), + questionAnswer: expect.any(QuestionAnswerModule), + genericRecords: expect.any(GenericRecordsModule), + ledger: expect.any(LedgerModule), + discovery: expect.any(DiscoverFeaturesModule), + dids: expect.any(DidsModule), + wallet: expect.any(WalletModule), + oob: expect.any(OutOfBandModule), + indy: expect.any(IndyModule), + w3cVc: expect.any(W3cVcModule), + myModule, + }) + }) + + test('does not override default module if provided as custom module', () => { + const myModule = new MyModuleWithApi() + const connections = new ConnectionsModule() + const extendedModules = extendModulesWithDefaultModules(agentConfig, { + myModule, + connections, + }) + + expect(extendedModules).toEqual({ + connections: connections, + credentials: expect.any(CredentialsModule), + proofs: expect.any(ProofsModule), + mediator: expect.any(MediatorModule), + mediationRecipient: expect.any(RecipientModule), + basicMessages: expect.any(BasicMessagesModule), + questionAnswer: expect.any(QuestionAnswerModule), + genericRecords: expect.any(GenericRecordsModule), + ledger: expect.any(LedgerModule), + discovery: expect.any(DiscoverFeaturesModule), + dids: expect.any(DidsModule), + wallet: expect.any(WalletModule), + oob: expect.any(OutOfBandModule), + indy: expect.any(IndyModule), + w3cVc: expect.any(W3cVcModule), + myModule, + }) + }) + }) +}) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ef2d804359..89e06c665f 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -5,6 +5,7 @@ export { MessageReceiver } from './agent/MessageReceiver' export { Agent } from './agent/Agent' export { BaseAgent } from './agent/BaseAgent' export * from './agent' +export type { ModulesMap, DefaultAgentModules, EmptyModuleMap } from './agent/AgentModules' export { EventEmitter } from './agent/EventEmitter' export { FeatureRegistry } from './agent/FeatureRegistry' export { Handler, HandlerInboundMessage } from './agent/Handler' @@ -52,6 +53,7 @@ export * from './error' export * from './wallet/error' export { Key, KeyType } from './crypto' export { parseMessageType, IsValidMessageType } from './utils/messageType' +export type { Constructor } from './utils/mixins' export * from './agent/Events' diff --git a/packages/core/src/modules/basic-messages/BasicMessagesModule.ts b/packages/core/src/modules/basic-messages/BasicMessagesModule.ts index 169e3afc48..fd1fd77f6c 100644 --- a/packages/core/src/modules/basic-messages/BasicMessagesModule.ts +++ b/packages/core/src/modules/basic-messages/BasicMessagesModule.ts @@ -9,6 +9,8 @@ import { BasicMessageRepository } from './repository' import { BasicMessageService } from './services' export class BasicMessagesModule implements Module { + public readonly api = BasicMessagesApi + /** * Registers the dependencies of the basic message module on the dependency manager. */ diff --git a/packages/core/src/modules/connections/ConnectionsModule.ts b/packages/core/src/modules/connections/ConnectionsModule.ts index a76d95ee71..b589f202ce 100644 --- a/packages/core/src/modules/connections/ConnectionsModule.ts +++ b/packages/core/src/modules/connections/ConnectionsModule.ts @@ -13,6 +13,7 @@ import { ConnectionService, TrustPingService } from './services' export class ConnectionsModule implements Module { public readonly config: ConnectionsModuleConfig + public readonly api = ConnectionsApi public constructor(config?: ConnectionsModuleConfigOptions) { this.config = new ConnectionsModuleConfig(config) diff --git a/packages/core/src/modules/credentials/CredentialsModule.ts b/packages/core/src/modules/credentials/CredentialsModule.ts index 475224b0f8..a54a20b1a7 100644 --- a/packages/core/src/modules/credentials/CredentialsModule.ts +++ b/packages/core/src/modules/credentials/CredentialsModule.ts @@ -14,6 +14,7 @@ import { CredentialRepository } from './repository' export class CredentialsModule implements Module { public readonly config: CredentialsModuleConfig + public readonly api = CredentialsApi public constructor(config?: CredentialsModuleConfigOptions) { this.config = new CredentialsModuleConfig(config) diff --git a/packages/core/src/modules/credentials/protocol/v1/__tests__/v1-connectionless-credentials.e2e.test.ts b/packages/core/src/modules/credentials/protocol/v1/__tests__/v1-connectionless-credentials.e2e.test.ts index 3f8c508400..085142c8ea 100644 --- a/packages/core/src/modules/credentials/protocol/v1/__tests__/v1-connectionless-credentials.e2e.test.ts +++ b/packages/core/src/modules/credentials/protocol/v1/__tests__/v1-connectionless-credentials.e2e.test.ts @@ -6,7 +6,7 @@ import { ReplaySubject, Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../../../tests/transport/SubjectOutboundTransport' -import { prepareForIssuance, waitForCredentialRecordSubject, getBaseConfig } from '../../../../../../tests/helpers' +import { prepareForIssuance, waitForCredentialRecordSubject, getAgentOptions } from '../../../../../../tests/helpers' import testLogger from '../../../../../../tests/logger' import { Agent } from '../../../../../agent/Agent' import { CredentialEventTypes } from '../../../CredentialEvents' @@ -15,11 +15,11 @@ import { CredentialState } from '../../../models/CredentialState' import { CredentialExchangeRecord } from '../../../repository/CredentialExchangeRecord' import { V1CredentialPreview } from '../messages/V1CredentialPreview' -const faberConfig = getBaseConfig('Faber connection-less Credentials V1', { +const faberAgentOptions = getAgentOptions('Faber connection-less Credentials V1', { endpoints: ['rxjs:faber'], }) -const aliceConfig = getBaseConfig('Alice connection-less Credentials V1', { +const aliceAgentOptions = getAgentOptions('Alice connection-less Credentials V1', { endpoints: ['rxjs:alice'], }) @@ -43,12 +43,12 @@ describe('V1 Connectionless Credentials', () => { 'rxjs:faber': faberMessages, 'rxjs:alice': aliceMessages, } - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts index ced9f4f195..0382f05f1c 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts @@ -6,7 +6,7 @@ import { ReplaySubject, Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../../../tests/transport/SubjectOutboundTransport' -import { prepareForIssuance, waitForCredentialRecordSubject, getBaseConfig } from '../../../../../../tests/helpers' +import { prepareForIssuance, waitForCredentialRecordSubject, getAgentOptions } from '../../../../../../tests/helpers' import testLogger from '../../../../../../tests/logger' import { Agent } from '../../../../../agent/Agent' import { CredentialEventTypes } from '../../../CredentialEvents' @@ -15,11 +15,11 @@ import { CredentialState } from '../../../models/CredentialState' import { CredentialExchangeRecord } from '../../../repository/CredentialExchangeRecord' import { V2CredentialPreview } from '../messages' -const faberConfig = getBaseConfig('Faber connection-less Credentials V2', { +const faberAgentOptions = getAgentOptions('Faber connection-less Credentials V2', { endpoints: ['rxjs:faber'], }) -const aliceConfig = getBaseConfig('Alice connection-less Credentials V2', { +const aliceAgentOptions = getAgentOptions('Alice connection-less Credentials V2', { endpoints: ['rxjs:alice'], }) @@ -43,12 +43,12 @@ describe('V2 Connectionless Credentials', () => { 'rxjs:faber': faberMessages, 'rxjs:alice': aliceMessages, } - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials.e2e.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials.e2e.test.ts index afc83def5a..c3b73fd6ef 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials.e2e.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials.e2e.test.ts @@ -365,6 +365,7 @@ describe('v2 credentials', () => { state: CredentialState.CredentialReceived, }) + // testLogger.test('Alice sends credential ack to Faber') await aliceAgent.credentials.acceptCredential({ credentialRecordId: aliceCredentialRecord.id }) testLogger.test('Faber waits for credential ack from Alice') @@ -427,7 +428,6 @@ describe('v2 credentials', () => { threadId: faberCredentialRecord.threadId, state: CredentialState.OfferReceived, }) - faberCredentialRecord = await faberAgent.credentials.negotiateProposal({ credentialRecordId: faberCredentialRecord.id, credentialFormats: { diff --git a/packages/core/src/modules/dids/DidsModule.ts b/packages/core/src/modules/dids/DidsModule.ts index 0a43f0a154..dbf46d7cad 100644 --- a/packages/core/src/modules/dids/DidsModule.ts +++ b/packages/core/src/modules/dids/DidsModule.ts @@ -14,6 +14,8 @@ export class DidsModule implements Module { this.config = new DidsModuleConfig(config) } + public readonly api = DidsApi + /** * Registers the dependencies of the dids module module on the dependency manager. */ diff --git a/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts b/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts index 264dffe6f9..a7cb1d869e 100644 --- a/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts +++ b/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts @@ -5,7 +5,7 @@ import type { Wallet } from '@aries-framework/core' import { convertPublicKeyToX25519, generateKeyPairFromSeed } from '@stablelib/ed25519' -import { genesisPath, getBaseConfig } from '../../../../tests/helpers' +import { genesisPath, getAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { KeyType } from '../../../crypto' import { TypedArrayEncoder } from '../../../utils' @@ -14,7 +14,7 @@ import { PeerDidNumAlgo } from '../methods/peer/didPeer' import { InjectionSymbols, JsonTransformer } from '@aries-framework/core' -const { config, agentDependencies } = getBaseConfig('Faber Dids Registrar', { +const agentOptions = getAgentOptions('Faber Dids Registrar', { indyLedgers: [ { id: `localhost`, @@ -29,7 +29,7 @@ describe('dids', () => { let agent: Agent beforeAll(async () => { - agent = new Agent(config, agentDependencies) + agent = new Agent(agentOptions) await agent.initialize() }) diff --git a/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts b/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts index 39e3710c19..861d7f0d1a 100644 --- a/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts +++ b/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts @@ -2,18 +2,16 @@ import type { Wallet } from '../../../wallet' import { convertPublicKeyToX25519 } from '@stablelib/ed25519' -import { getBaseConfig } from '../../../../tests/helpers' +import { getAgentOptions } from '../../../../tests/helpers' import { sleep } from '../../../utils/sleep' import { InjectionSymbols, Key, KeyType, JsonTransformer, Agent } from '@aries-framework/core' -const { config, agentDependencies } = getBaseConfig('Faber Dids Resolver', {}) - describe('dids', () => { let agent: Agent beforeAll(async () => { - agent = new Agent(config, agentDependencies) + agent = new Agent(getAgentOptions('Faber Dids')) await agent.initialize() }) diff --git a/packages/core/src/modules/discover-features/DiscoverFeaturesModule.ts b/packages/core/src/modules/discover-features/DiscoverFeaturesModule.ts index d7be4b3732..79caa885f9 100644 --- a/packages/core/src/modules/discover-features/DiscoverFeaturesModule.ts +++ b/packages/core/src/modules/discover-features/DiscoverFeaturesModule.ts @@ -10,6 +10,7 @@ import { V1DiscoverFeaturesService } from './protocol/v1' import { V2DiscoverFeaturesService } from './protocol/v2' export class DiscoverFeaturesModule implements Module { + public readonly api = DiscoverFeaturesApi public readonly config: DiscoverFeaturesModuleConfig public constructor(config?: DiscoverFeaturesModuleConfigOptions) { diff --git a/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts b/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts index 258eb4f543..19e48cd386 100644 --- a/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts +++ b/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts @@ -9,7 +9,7 @@ import { ReplaySubject, Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getBaseConfig, makeConnection } from '../../../../tests/helpers' +import { getAgentOptions, makeConnection } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { DiscoverFeaturesEventTypes } from '../DiscoverFeaturesEvents' @@ -27,19 +27,19 @@ describe('v1 discover features', () => { 'rxjs:faber': faberMessages, 'rxjs:alice': aliceMessages, } - const faberConfig = getBaseConfig('Faber Discover Features V1 E2E', { + const faberAgentOptions = getAgentOptions('Faber Discover Features V1 E2E', { endpoints: ['rxjs:faber'], }) - const aliceConfig = getBaseConfig('Alice Discover Features V1 E2E', { + const aliceAgentOptions = getAgentOptions('Alice Discover Features V1 E2E', { endpoints: ['rxjs:alice'], }) - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() diff --git a/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts b/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts index f014f5b6a6..20e2d72e2b 100644 --- a/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts +++ b/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts @@ -9,7 +9,7 @@ import { ReplaySubject, Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getBaseConfig, makeConnection } from '../../../../tests/helpers' +import { getAgentOptions, makeConnection } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { GoalCode, Feature } from '../../../agent/models' import { DiscoverFeaturesEventTypes } from '../DiscoverFeaturesEvents' @@ -29,19 +29,19 @@ describe('v2 discover features', () => { 'rxjs:faber': faberMessages, 'rxjs:alice': aliceMessages, } - const faberConfig = getBaseConfig('Faber Discover Features V2 E2E', { + const faberAgentOptions = getAgentOptions('Faber Discover Features V2 E2E', { endpoints: ['rxjs:faber'], }) - const aliceConfig = getBaseConfig('Alice Discover Features V2 E2E', { + const aliceAgentOptions = getAgentOptions('Alice Discover Features V2 E2E', { endpoints: ['rxjs:alice'], }) - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() diff --git a/packages/core/src/modules/generic-records/GenericRecordsModule.ts b/packages/core/src/modules/generic-records/GenericRecordsModule.ts index 0171374197..a302933083 100644 --- a/packages/core/src/modules/generic-records/GenericRecordsModule.ts +++ b/packages/core/src/modules/generic-records/GenericRecordsModule.ts @@ -5,6 +5,8 @@ import { GenericRecordsRepository } from './repository/GenericRecordsRepository' import { GenericRecordService } from './services/GenericRecordService' export class GenericRecordsModule implements Module { + public readonly api = GenericRecordsApi + /** * Registers the dependencies of the generic records module on the dependency manager. */ diff --git a/packages/core/src/modules/ledger/LedgerModule.ts b/packages/core/src/modules/ledger/LedgerModule.ts index eb501dac91..8bb9a3de82 100644 --- a/packages/core/src/modules/ledger/LedgerModule.ts +++ b/packages/core/src/modules/ledger/LedgerModule.ts @@ -10,6 +10,7 @@ import { IndyLedgerService, IndyPoolService } from './services' export class LedgerModule implements Module { public readonly config: LedgerModuleConfig + public readonly api = LedgerApi public constructor(config?: LedgerModuleConfigOptions) { this.config = new LedgerModuleConfig(config) diff --git a/packages/core/src/modules/oob/OutOfBandApi.ts b/packages/core/src/modules/oob/OutOfBandApi.ts index 7408417bd7..e1561edfe2 100644 --- a/packages/core/src/modules/oob/OutOfBandApi.ts +++ b/packages/core/src/modules/oob/OutOfBandApi.ts @@ -15,7 +15,6 @@ import { filterContextCorrelationId, AgentEventTypes } from '../../agent/Events' import { FeatureRegistry } from '../../agent/FeatureRegistry' import { MessageSender } from '../../agent/MessageSender' import { createOutboundMessage } from '../../agent/helpers' -import { FeatureQuery } from '../../agent/models' import { InjectionSymbols } from '../../constants' import { ServiceDecorator } from '../../decorators/service/ServiceDecorator' import { AriesFrameworkError } from '../../error' diff --git a/packages/core/src/modules/oob/OutOfBandModule.ts b/packages/core/src/modules/oob/OutOfBandModule.ts index 6cf1cebdd0..e79ab11ac8 100644 --- a/packages/core/src/modules/oob/OutOfBandModule.ts +++ b/packages/core/src/modules/oob/OutOfBandModule.ts @@ -8,6 +8,8 @@ import { OutOfBandService } from './OutOfBandService' import { OutOfBandRepository } from './repository' export class OutOfBandModule implements Module { + public readonly api = OutOfBandApi + /** * Registers the dependencies of the ot of band module on the dependency manager. */ diff --git a/packages/core/src/modules/proofs/ProofsModule.ts b/packages/core/src/modules/proofs/ProofsModule.ts index 81fe915fd8..05136c95a0 100644 --- a/packages/core/src/modules/proofs/ProofsModule.ts +++ b/packages/core/src/modules/proofs/ProofsModule.ts @@ -13,6 +13,7 @@ import { ProofRepository } from './repository' export class ProofsModule implements Module { public readonly config: ProofsModuleConfig + public readonly api = ProofsApi public constructor(config?: ProofsModuleConfigOptions) { this.config = new ProofsModuleConfig(config) diff --git a/packages/core/src/modules/question-answer/QuestionAnswerModule.ts b/packages/core/src/modules/question-answer/QuestionAnswerModule.ts index 0a353a4f1d..3525d5b9ad 100644 --- a/packages/core/src/modules/question-answer/QuestionAnswerModule.ts +++ b/packages/core/src/modules/question-answer/QuestionAnswerModule.ts @@ -9,6 +9,8 @@ import { QuestionAnswerRepository } from './repository' import { QuestionAnswerService } from './services' export class QuestionAnswerModule implements Module { + public readonly api = QuestionAnswerApi + /** * Registers the dependencies of the question answer module on the dependency manager. */ diff --git a/packages/core/src/modules/routing/MediatorModule.ts b/packages/core/src/modules/routing/MediatorModule.ts index 348e23aca4..db81da0f1a 100644 --- a/packages/core/src/modules/routing/MediatorModule.ts +++ b/packages/core/src/modules/routing/MediatorModule.ts @@ -13,6 +13,7 @@ import { MediatorService } from './services' export class MediatorModule implements Module { public readonly config: MediatorModuleConfig + public readonly api = MediatorApi public constructor(config?: MediatorModuleConfigOptions) { this.config = new MediatorModuleConfig(config) diff --git a/packages/core/src/modules/routing/RecipientModule.ts b/packages/core/src/modules/routing/RecipientModule.ts index 068f1f43af..7f160cdb4a 100644 --- a/packages/core/src/modules/routing/RecipientModule.ts +++ b/packages/core/src/modules/routing/RecipientModule.ts @@ -12,6 +12,7 @@ import { MediationRecipientService, RoutingService } from './services' export class RecipientModule implements Module { public readonly config: RecipientModuleConfig + public readonly api = RecipientApi public constructor(config?: RecipientModuleConfigOptions) { this.config = new RecipientModuleConfig(config) diff --git a/packages/core/src/modules/routing/__tests__/mediation.test.ts b/packages/core/src/modules/routing/__tests__/mediation.test.ts index c616bdd522..d3814e54b3 100644 --- a/packages/core/src/modules/routing/__tests__/mediation.test.ts +++ b/packages/core/src/modules/routing/__tests__/mediation.test.ts @@ -5,7 +5,7 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getBaseConfig, waitForBasicMessage } from '../../../../tests/helpers' +import { getAgentOptions, waitForBasicMessage } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { InjectionSymbols } from '../../../constants' import { sleep } from '../../../utils/sleep' @@ -13,16 +13,16 @@ import { ConnectionRecord, HandshakeProtocol } from '../../connections' import { MediatorPickupStrategy } from '../MediatorPickupStrategy' import { MediationState } from '../models/MediationState' -const recipientConfig = getBaseConfig('Mediation: Recipient', { +const recipientAgentOptions = getAgentOptions('Mediation: Recipient', { indyLedgers: [], }) -const mediatorConfig = getBaseConfig('Mediation: Mediator', { +const mediatorAgentOptions = getAgentOptions('Mediation: Mediator', { autoAcceptMediationRequests: true, endpoints: ['rxjs:mediator'], indyLedgers: [], }) -const senderConfig = getBaseConfig('Mediation: Sender', { +const senderAgentOptions = getAgentOptions('Mediation: Sender', { endpoints: ['rxjs:sender'], indyLedgers: [], }) @@ -66,7 +66,7 @@ describe('mediator establishment', () => { } // Initialize mediatorReceived message - mediatorAgent = new Agent(mediatorConfig.config, recipientConfig.agentDependencies) + mediatorAgent = new Agent(mediatorAgentOptions) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) await mediatorAgent.initialize() @@ -79,16 +79,16 @@ describe('mediator establishment', () => { }) // Initialize recipient with mediation connections invitation - recipientAgent = new Agent( - { - ...recipientConfig.config, + recipientAgent = new Agent({ + ...recipientAgentOptions, + config: { + ...recipientAgentOptions.config, mediatorConnectionsInvite: mediatorOutOfBandRecord.outOfBandInvitation.toUrl({ domain: 'https://example.com/ssi', }), mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }, - recipientConfig.agentDependencies - ) + }) recipientAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) recipientAgent.registerInboundTransport(new SubjectInboundTransport(recipientMessages)) await recipientAgent.initialize() @@ -111,7 +111,7 @@ describe('mediator establishment', () => { expect(recipientMediator?.state).toBe(MediationState.Granted) // Initialize sender agent - senderAgent = new Agent(senderConfig.config, senderConfig.agentDependencies) + senderAgent = new Agent(senderAgentOptions) senderAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) senderAgent.registerInboundTransport(new SubjectInboundTransport(senderMessages)) await senderAgent.initialize() @@ -158,7 +158,7 @@ describe('mediator establishment', () => { } // Initialize mediator - mediatorAgent = new Agent(mediatorConfig.config, recipientConfig.agentDependencies) + mediatorAgent = new Agent(mediatorAgentOptions) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) await mediatorAgent.initialize() @@ -171,16 +171,16 @@ describe('mediator establishment', () => { }) // Initialize recipient with mediation connections invitation - recipientAgent = new Agent( - { - ...recipientConfig.config, + recipientAgent = new Agent({ + ...recipientAgentOptions, + config: { + ...recipientAgentOptions.config, mediatorConnectionsInvite: mediatorOutOfBandRecord.outOfBandInvitation.toUrl({ domain: 'https://example.com/ssi', }), mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }, - recipientConfig.agentDependencies - ) + }) recipientAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) recipientAgent.registerInboundTransport(new SubjectInboundTransport(recipientMessages)) await recipientAgent.initialize() @@ -202,22 +202,22 @@ describe('mediator establishment', () => { // Restart recipient agent await recipientAgent.shutdown() - recipientAgent = new Agent( - { - ...recipientConfig.config, + recipientAgent = new Agent({ + ...recipientAgentOptions, + config: { + ...recipientAgentOptions.config, mediatorConnectionsInvite: mediatorOutOfBandRecord.outOfBandInvitation.toUrl({ domain: 'https://example.com/ssi', }), mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }, - recipientConfig.agentDependencies - ) + }) recipientAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) recipientAgent.registerInboundTransport(new SubjectInboundTransport(recipientMessages)) await recipientAgent.initialize() // Initialize sender agent - senderAgent = new Agent(senderConfig.config, senderConfig.agentDependencies) + senderAgent = new Agent(senderAgentOptions) senderAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) senderAgent.registerInboundTransport(new SubjectInboundTransport(senderMessages)) await senderAgent.initialize() diff --git a/packages/core/src/modules/routing/__tests__/pickup.test.ts b/packages/core/src/modules/routing/__tests__/pickup.test.ts index 9320ea85da..69d43e8c46 100644 --- a/packages/core/src/modules/routing/__tests__/pickup.test.ts +++ b/packages/core/src/modules/routing/__tests__/pickup.test.ts @@ -5,16 +5,16 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getBaseConfig, waitForBasicMessage } from '../../../../tests/helpers' +import { getAgentOptions, waitForBasicMessage } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { HandshakeProtocol } from '../../connections' import { MediatorPickupStrategy } from '../MediatorPickupStrategy' -const recipientConfig = getBaseConfig('Mediation: Recipient Pickup', { +const recipientOptions = getAgentOptions('Mediation: Recipient Pickup', { autoAcceptConnections: true, indyLedgers: [], }) -const mediatorConfig = getBaseConfig('Mediation: Mediator Pickup', { +const mediatorOptions = getAgentOptions('Mediation: Mediator Pickup', { autoAcceptConnections: true, endpoints: ['rxjs:mediator'], indyLedgers: [], @@ -39,7 +39,7 @@ describe('E2E Pick Up protocol', () => { } // Initialize mediatorReceived message - mediatorAgent = new Agent(mediatorConfig.config, recipientConfig.agentDependencies) + mediatorAgent = new Agent(mediatorOptions) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) await mediatorAgent.initialize() @@ -52,7 +52,7 @@ describe('E2E Pick Up protocol', () => { }) // Initialize recipient - recipientAgent = new Agent(recipientConfig.config, recipientConfig.agentDependencies) + recipientAgent = new Agent(recipientOptions) recipientAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await recipientAgent.initialize() @@ -91,7 +91,7 @@ describe('E2E Pick Up protocol', () => { } // Initialize mediatorReceived message - mediatorAgent = new Agent(mediatorConfig.config, recipientConfig.agentDependencies) + mediatorAgent = new Agent(mediatorOptions) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) await mediatorAgent.initialize() @@ -104,7 +104,7 @@ describe('E2E Pick Up protocol', () => { }) // Initialize recipient - recipientAgent = new Agent(recipientConfig.config, recipientConfig.agentDependencies) + recipientAgent = new Agent(recipientOptions) recipientAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await recipientAgent.initialize() diff --git a/packages/core/src/plugins/DependencyManager.ts b/packages/core/src/plugins/DependencyManager.ts index fe662670fc..734a43ce81 100644 --- a/packages/core/src/plugins/DependencyManager.ts +++ b/packages/core/src/plugins/DependencyManager.ts @@ -1,23 +1,39 @@ +import type { ModulesMap } from '../agent/AgentModules' import type { Constructor } from '../utils/mixins' -import type { Module } from './Module' import type { DependencyContainer } from 'tsyringe' import { container as rootContainer, InjectionToken, Lifecycle } from 'tsyringe' import { FeatureRegistry } from '../agent/FeatureRegistry' +import { AriesFrameworkError } from '../error' export { InjectionToken } export class DependencyManager { public readonly container: DependencyContainer + public readonly registeredModules: ModulesMap - public constructor(container: DependencyContainer = rootContainer.createChildContainer()) { + public constructor( + container: DependencyContainer = rootContainer.createChildContainer(), + registeredModules: ModulesMap = {} + ) { this.container = container + this.registeredModules = registeredModules } - public registerModules(...modules: Module[]) { + public registerModules(modules: ModulesMap) { const featureRegistry = this.resolve(FeatureRegistry) - modules.forEach((module) => module.register(this, 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 registerSingleton(from: InjectionToken, to: InjectionToken): void @@ -60,6 +76,6 @@ export class DependencyManager { } public createChild() { - return new DependencyManager(this.container.createChildContainer()) + return new DependencyManager(this.container.createChildContainer(), this.registeredModules) } } diff --git a/packages/core/src/plugins/Module.ts b/packages/core/src/plugins/Module.ts index 68fa680855..f76b5329d1 100644 --- a/packages/core/src/plugins/Module.ts +++ b/packages/core/src/plugins/Module.ts @@ -3,6 +3,7 @@ import type { Constructor } from '../utils/mixins' import type { DependencyManager } from './DependencyManager' export interface Module { + api?: Constructor register(dependencyManager: DependencyManager, featureRegistry: FeatureRegistry): void } diff --git a/packages/core/src/plugins/__tests__/DependencyManager.test.ts b/packages/core/src/plugins/__tests__/DependencyManager.test.ts index f576ad4811..780bbaba67 100644 --- a/packages/core/src/plugins/__tests__/DependencyManager.test.ts +++ b/packages/core/src/plugins/__tests__/DependencyManager.test.ts @@ -1,4 +1,5 @@ import type { Module } from '../Module' +import type { DependencyContainer } from 'tsyringe' import { container as rootContainer, injectable, Lifecycle } from 'tsyringe' @@ -10,11 +11,15 @@ class Instance { } const instance = new Instance() -const container = rootContainer.createChildContainer() -const dependencyManager = new DependencyManager(container) -const featureRegistry = container.resolve(FeatureRegistry) - describe('DependencyManager', () => { + let container: DependencyContainer + let dependencyManager: DependencyManager + + beforeEach(() => { + container = rootContainer.createChildContainer() + dependencyManager = new DependencyManager(container) + }) + afterEach(() => { jest.resetAllMocks() container.reset() @@ -35,12 +40,19 @@ describe('DependencyManager', () => { const module1 = new Module1() const module2 = new Module2() - dependencyManager.registerModules(module1, module2) + const featureRegistry = container.resolve(FeatureRegistry) + + dependencyManager.registerModules({ module1, module2 }) expect(module1.register).toHaveBeenCalledTimes(1) expect(module1.register).toHaveBeenLastCalledWith(dependencyManager, featureRegistry) expect(module2.register).toHaveBeenCalledTimes(1) expect(module2.register).toHaveBeenLastCalledWith(dependencyManager, featureRegistry) + + expect(dependencyManager.registeredModules).toMatchObject({ + module1, + module2, + }) }) }) @@ -121,5 +133,22 @@ describe('DependencyManager', () => { expect(createChildSpy).toHaveBeenCalledTimes(1) expect(childDependencyManager.container).toBe(createChildSpy.mock.results[0].value) }) + + it('inherits the registeredModules from the parent dependency manager', () => { + const module = { + register: jest.fn(), + } + + dependencyManager.registerModules({ + module1: module, + module2: module, + }) + + const childDependencyManager = dependencyManager.createChild() + expect(childDependencyManager.registeredModules).toMatchObject({ + module1: module, + module2: module, + }) + }) }) }) diff --git a/packages/core/src/storage/migration/__tests__/0.1.test.ts b/packages/core/src/storage/migration/__tests__/0.1.test.ts index ecfca2ed69..fc2b3fb047 100644 --- a/packages/core/src/storage/migration/__tests__/0.1.test.ts +++ b/packages/core/src/storage/migration/__tests__/0.1.test.ts @@ -7,7 +7,7 @@ import path from 'path' import { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' import { Agent } from '../../../../src' -import { agentDependencies } from '../../../../tests/helpers' +import { agentDependencies as dependencies } from '../../../../tests/helpers' import { InjectionSymbols } from '../../../constants' import { DependencyManager } from '../../../plugins' import * as uuid from '../../../utils/uuid' @@ -57,10 +57,9 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const agent = new Agent( { - label: 'Test Agent', - walletConfig, + config: { label: 'Test Agent', walletConfig }, + dependencies, }, - agentDependencies, dependencyManager ) @@ -117,10 +116,9 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const agent = new Agent( { - label: 'Test Agent', - walletConfig, + config: { label: 'Test Agent', walletConfig }, + dependencies, }, - agentDependencies, dependencyManager ) @@ -179,11 +177,9 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const agent = new Agent( { - label: 'Test Agent', - walletConfig, - autoUpdateStorageOnStartup: true, + config: { label: 'Test Agent', walletConfig, autoUpdateStorageOnStartup: true }, + dependencies, }, - agentDependencies, dependencyManager ) @@ -229,11 +225,13 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const agent = new Agent( { - label: 'Test Agent', - walletConfig, - autoUpdateStorageOnStartup: true, + config: { + label: 'Test Agent', + walletConfig, + autoUpdateStorageOnStartup: true, + }, + dependencies, }, - agentDependencies, dependencyManager ) diff --git a/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts b/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts index 4cc59315e2..ec4545d05e 100644 --- a/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts +++ b/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts @@ -1,13 +1,13 @@ import type { BaseRecord } from '../../BaseRecord' import { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' -import { getBaseConfig } from '../../../../tests/helpers' +import { getAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { InjectionSymbols } from '../../../constants' import { DependencyManager } from '../../../plugins' import { UpdateAssistant } from '../UpdateAssistant' -const { agentDependencies, config } = getBaseConfig('UpdateAssistant') +const agentOptions = getAgentOptions('UpdateAssistant') describe('UpdateAssistant', () => { let updateAssistant: UpdateAssistant @@ -19,7 +19,7 @@ describe('UpdateAssistant', () => { storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - agent = new Agent(config, agentDependencies, dependencyManager) + agent = new Agent(agentOptions, dependencyManager) updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { diff --git a/packages/core/src/storage/migration/__tests__/backup.test.ts b/packages/core/src/storage/migration/__tests__/backup.test.ts index 557e521549..5bcf588afb 100644 --- a/packages/core/src/storage/migration/__tests__/backup.test.ts +++ b/packages/core/src/storage/migration/__tests__/backup.test.ts @@ -4,7 +4,7 @@ import type { StorageUpdateError } from '../error/StorageUpdateError' import { readFileSync, unlinkSync } from 'fs' import path from 'path' -import { getBaseConfig } from '../../../../tests/helpers' +import { getAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { InjectionSymbols } from '../../../constants' import { AriesFrameworkError } from '../../../error' @@ -13,7 +13,7 @@ import { JsonTransformer } from '../../../utils' import { StorageUpdateService } from '../StorageUpdateService' import { UpdateAssistant } from '../UpdateAssistant' -const { agentDependencies, config } = getBaseConfig('UpdateAssistant | Backup') +const agentOptions = getAgentOptions('UpdateAssistant | Backup') const aliceCredentialRecordsString = readFileSync( path.join(__dirname, '__fixtures__/alice-4-credentials-0.1.json'), @@ -30,7 +30,7 @@ describe('UpdateAssistant | Backup', () => { let backupPath: string beforeEach(async () => { - agent = new Agent(config, agentDependencies) + agent = new Agent(agentOptions) const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` diff --git a/packages/core/src/wallet/WalletModule.ts b/packages/core/src/wallet/WalletModule.ts index 002dda6b2f..608285cd55 100644 --- a/packages/core/src/wallet/WalletModule.ts +++ b/packages/core/src/wallet/WalletModule.ts @@ -6,6 +6,8 @@ import { WalletApi } from './WalletApi' // TODO: this should be moved into the modules directory export class WalletModule implements Module { + public readonly api = WalletApi + /** * Registers the dependencies of the wallet module on the injection dependencyManager. */ diff --git a/packages/core/tests/agents.test.ts b/packages/core/tests/agents.test.ts index 484d98aa4c..47393e371b 100644 --- a/packages/core/tests/agents.test.ts +++ b/packages/core/tests/agents.test.ts @@ -9,12 +9,12 @@ import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutbou import { Agent } from '../src/agent/Agent' import { HandshakeProtocol } from '../src/modules/connections' -import { waitForBasicMessage, getBaseConfig } from './helpers' +import { waitForBasicMessage, getAgentOptions } from './helpers' -const aliceConfig = getBaseConfig('Agents Alice', { +const aliceAgentOptions = getAgentOptions('Agents Alice', { endpoints: ['rxjs:alice'], }) -const bobConfig = getBaseConfig('Agents Bob', { +const bobAgentOptions = getAgentOptions('Agents Bob', { endpoints: ['rxjs:bob'], }) @@ -40,12 +40,12 @@ describe('agents', () => { 'rxjs:bob': bobMessages, } - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() - bobAgent = new Agent(bobConfig.config, bobConfig.agentDependencies) + bobAgent = new Agent(bobAgentOptions) bobAgent.registerInboundTransport(new SubjectInboundTransport(bobMessages)) bobAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await bobAgent.initialize() diff --git a/packages/core/tests/connections.test.ts b/packages/core/tests/connections.test.ts index e9cbe9906d..01461162e2 100644 --- a/packages/core/tests/connections.test.ts +++ b/packages/core/tests/connections.test.ts @@ -9,7 +9,7 @@ import { DidExchangeState, HandshakeProtocol } from '../src' import { Agent } from '../src/agent/Agent' import { OutOfBandState } from '../src/modules/oob/domain/OutOfBandState' -import { getBaseConfig } from './helpers' +import { getAgentOptions } from './helpers' describe('connections', () => { let faberAgent: Agent @@ -26,13 +26,13 @@ describe('connections', () => { }) it('one should be able to make multiple connections using a multi use invite', async () => { - const faberConfig = getBaseConfig('Faber Agent Connections', { + const faberAgentOptions = getAgentOptions('Faber Agent Connections', { endpoints: ['rxjs:faber'], }) - const aliceConfig = getBaseConfig('Alice Agent Connections', { + const aliceAgentOptions = getAgentOptions('Alice Agent Connections', { endpoints: ['rxjs:alice'], }) - const acmeConfig = getBaseConfig('Acme Agent Connections', { + const acmeAgentOptions = getAgentOptions('Acme Agent Connections', { endpoints: ['rxjs:acme'], }) @@ -45,17 +45,17 @@ describe('connections', () => { 'rxjs:acme': acmeMessages, } - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() - acmeAgent = new Agent(acmeConfig.config, acmeConfig.agentDependencies) + acmeAgent = new Agent(acmeAgentOptions) acmeAgent.registerInboundTransport(new SubjectInboundTransport(acmeMessages)) acmeAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await acmeAgent.initialize() @@ -100,19 +100,19 @@ describe('connections', () => { 'rxjs:faber': faberMessages, } - const faberConfig = getBaseConfig('Faber Agent Connections 2', { + const faberAgentOptions = getAgentOptions('Faber Agent Connections 2', { endpoints: ['rxjs:faber'], }) - const aliceConfig = getBaseConfig('Alice Agent Connections 2') + const aliceAgentOptions = getAgentOptions('Alice Agent Connections 2') // Faber defines both inbound and outbound transports - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() // Alice only has outbound transport - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() diff --git a/packages/core/tests/generic-records.test.ts b/packages/core/tests/generic-records.test.ts index a206a5e71c..efe7455e2f 100644 --- a/packages/core/tests/generic-records.test.ts +++ b/packages/core/tests/generic-records.test.ts @@ -3,9 +3,9 @@ import type { GenericRecord } from '../src/modules/generic-records/repository/Ge import { Agent } from '../src/agent/Agent' import { RecordNotFoundError } from '../src/error' -import { getBaseConfig } from './helpers' +import { getAgentOptions } from './helpers' -const aliceConfig = getBaseConfig('Generic Records Alice', { +const aliceAgentOptions = getAgentOptions('Generic Records Alice', { endpoints: ['rxjs:alice'], }) @@ -24,7 +24,7 @@ describe('genericRecords', () => { }) test('store generic-record record', async () => { - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) await aliceAgent.initialize() // Save genericRecord message (Minimal) diff --git a/packages/core/tests/helpers.ts b/packages/core/tests/helpers.ts index d98a2160d2..f23e24dbc5 100644 --- a/packages/core/tests/helpers.ts +++ b/packages/core/tests/helpers.ts @@ -21,7 +21,7 @@ import type { Observable } from 'rxjs' import path from 'path' import { firstValueFrom, ReplaySubject, Subject } from 'rxjs' -import { catchError, filter, map, tap, timeout } from 'rxjs/operators' +import { catchError, filter, map, timeout } from 'rxjs/operators' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' @@ -47,7 +47,8 @@ import { Key, KeyType } from '../src/crypto' import { Attachment, AttachmentData } from '../src/decorators/attachment/Attachment' import { AutoAcceptCredential } from '../src/modules/credentials/models/CredentialAutoAcceptType' import { V1CredentialPreview } from '../src/modules/credentials/protocol/v1/messages/V1CredentialPreview' -import { DidCommV1Service, DidKey } from '../src/modules/dids' +import { DidCommV1Service } from '../src/modules/dids' +import { DidKey } from '../src/modules/dids/methods/key' import { OutOfBandRole } from '../src/modules/oob/domain/OutOfBandRole' import { OutOfBandState } from '../src/modules/oob/domain/OutOfBandState' import { OutOfBandInvitation } from '../src/modules/oob/messages' @@ -72,7 +73,7 @@ export const genesisPath = process.env.GENESIS_TXN_PATH export const publicDidSeed = process.env.TEST_AGENT_PUBLIC_DID_SEED ?? '000000000000000000000000Trustee9' export { agentDependencies } -export function getBaseConfig(name: string, extraConfig: Partial = {}) { +export function getAgentOptions(name: string, extraConfig: Partial = {}) { const config: InitConfig = { label: `Agent: ${name}`, walletConfig: { @@ -96,10 +97,10 @@ export function getBaseConfig(name: string, extraConfig: Partial = { ...extraConfig, } - return { config, agentDependencies } as const + return { config, dependencies: agentDependencies } as const } -export function getBasePostgresConfig(name: string, extraConfig: Partial = {}) { +export function getPostgresAgentOptions(name: string, extraConfig: Partial = {}) { const config: InitConfig = { label: `Agent: ${name}`, walletConfig: { @@ -133,12 +134,12 @@ export function getBasePostgresConfig(name: string, extraConfig: Partial = {}) { - const { config, agentDependencies } = getBaseConfig(name, extraConfig) - return new AgentConfig(config, agentDependencies) + const { config, dependencies } = getAgentOptions(name, extraConfig) + return new AgentConfig(config, dependencies) } export function getAgentContext({ @@ -659,21 +660,21 @@ export async function setupCredentialTests( 'rxjs:faber': faberMessages, 'rxjs:alice': aliceMessages, } - const faberConfig = getBaseConfig(faberName, { + const faberAgentOptions = getAgentOptions(faberName, { endpoints: ['rxjs:faber'], autoAcceptCredentials, }) - const aliceConfig = getBaseConfig(aliceName, { + const aliceAgentOptions = getAgentOptions(aliceName, { endpoints: ['rxjs:alice'], autoAcceptCredentials, }) - const faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + const faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - const aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + const aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() @@ -706,12 +707,12 @@ export async function setupProofsTest(faberName: string, aliceName: string, auto const unique = uuid().substring(0, 4) - const faberConfig = getBaseConfig(`${faberName}-${unique}`, { + const faberAgentOptions = getAgentOptions(`${faberName}-${unique}`, { autoAcceptProofs, endpoints: ['rxjs:faber'], }) - const aliceConfig = getBaseConfig(`${aliceName}-${unique}`, { + const aliceAgentOptions = getAgentOptions(`${aliceName}-${unique}`, { autoAcceptProofs, endpoints: ['rxjs:alice'], }) @@ -723,12 +724,12 @@ export async function setupProofsTest(faberName: string, aliceName: string, auto 'rxjs:faber': faberMessages, 'rxjs:alice': aliceMessages, } - const faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + const faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - const aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + const aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() diff --git a/packages/core/tests/ledger.test.ts b/packages/core/tests/ledger.test.ts index ce0802353d..969bd32c0c 100644 --- a/packages/core/tests/ledger.test.ts +++ b/packages/core/tests/ledger.test.ts @@ -5,17 +5,15 @@ import { Agent } from '../src/agent/Agent' import { DID_IDENTIFIER_REGEX, isAbbreviatedVerkey, isFullVerkey, VERKEY_REGEX } from '../src/utils/did' import { sleep } from '../src/utils/sleep' -import { genesisPath, getBaseConfig } from './helpers' +import { genesisPath, getAgentOptions } from './helpers' import testLogger from './logger' -const { config: faberConfig, agentDependencies: faberDependencies } = getBaseConfig('Faber Ledger') - describe('ledger', () => { let faberAgent: Agent let schemaId: indy.SchemaId beforeAll(async () => { - faberAgent = new Agent(faberConfig, faberDependencies) + faberAgent = new Agent(getAgentOptions('Faber Ledger')) await faberAgent.initialize() }) @@ -141,7 +139,7 @@ describe('ledger', () => { it('should correctly store the genesis file if genesis transactions is passed', async () => { const genesisTransactions = await promises.readFile(genesisPath, { encoding: 'utf-8' }) - const { config, agentDependencies: dependencies } = getBaseConfig('Faber Ledger Genesis Transactions', { + const agentOptions = getAgentOptions('Faber Ledger Genesis Transactions', { indyLedgers: [ { id: 'pool-Faber Ledger Genesis Transactions', @@ -150,7 +148,7 @@ describe('ledger', () => { }, ], }) - const agent = new Agent(config, dependencies) + const agent = new Agent(agentOptions) await agent.initialize() if (!faberAgent.publicDid?.did) { diff --git a/packages/core/tests/migration.test.ts b/packages/core/tests/migration.test.ts index ef1590e69e..0dbf6b02dc 100644 --- a/packages/core/tests/migration.test.ts +++ b/packages/core/tests/migration.test.ts @@ -3,13 +3,13 @@ import type { VersionString } from '../src/utils/version' import { Agent } from '../src/agent/Agent' import { UpdateAssistant } from '../src/storage/migration/UpdateAssistant' -import { getBaseConfig } from './helpers' +import { getAgentOptions } from './helpers' -const { config, agentDependencies } = getBaseConfig('Migration', { publicDidSeed: undefined, indyLedgers: [] }) +const agentOptions = getAgentOptions('Migration', { publicDidSeed: undefined, indyLedgers: [] }) describe('migration', () => { test('manually initiating the update assistant to perform an update', async () => { - const agent = new Agent(config, agentDependencies) + const agent = new Agent(agentOptions) const updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { mediationRoleUpdateStrategy: 'allMediator' }, @@ -30,7 +30,7 @@ describe('migration', () => { // The storage version will normally be stored in e.g. persistent storage on a mobile device let currentStorageVersion: VersionString = '0.1' - const agent = new Agent(config, agentDependencies) + const agent = new Agent(agentOptions) if (currentStorageVersion !== UpdateAssistant.frameworkStorageVersion) { const updateAssistant = new UpdateAssistant(agent, { @@ -51,7 +51,7 @@ describe('migration', () => { }) test('Automatic update on agent startup', async () => { - const agent = new Agent({ ...config, autoUpdateStorageOnStartup: true }, agentDependencies) + const agent = new Agent({ ...agentOptions, config: { ...agentOptions.config, autoUpdateStorageOnStartup: true } }) await agent.initialize() await agent.shutdown() diff --git a/packages/core/tests/multi-protocol-version.test.ts b/packages/core/tests/multi-protocol-version.test.ts index 0a2f86aa93..83dc39986a 100644 --- a/packages/core/tests/multi-protocol-version.test.ts +++ b/packages/core/tests/multi-protocol-version.test.ts @@ -10,12 +10,12 @@ import { Agent } from '../src/agent/Agent' import { AgentEventTypes } from '../src/agent/Events' import { createOutboundMessage } from '../src/agent/helpers' -import { getBaseConfig } from './helpers' +import { getAgentOptions } from './helpers' -const aliceConfig = getBaseConfig('Multi Protocol Versions - Alice', { +const aliceAgentOptions = getAgentOptions('Multi Protocol Versions - Alice', { endpoints: ['rxjs:alice'], }) -const bobConfig = getBaseConfig('Multi Protocol Versions - Bob', { +const bobAgentOptions = getAgentOptions('Multi Protocol Versions - Bob', { endpoints: ['rxjs:bob'], }) @@ -41,7 +41,7 @@ describe('multi version protocols', () => { const mockHandle = jest.fn() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) @@ -51,7 +51,7 @@ describe('multi version protocols', () => { await aliceAgent.initialize() - bobAgent = new Agent(bobConfig.config, bobConfig.agentDependencies) + bobAgent = new Agent(bobAgentOptions) bobAgent.registerInboundTransport(new SubjectInboundTransport(bobMessages)) bobAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await bobAgent.initialize() diff --git a/packages/core/tests/oob-mediation-provision.test.ts b/packages/core/tests/oob-mediation-provision.test.ts index 448b68e3bb..3a95ee0c85 100644 --- a/packages/core/tests/oob-mediation-provision.test.ts +++ b/packages/core/tests/oob-mediation-provision.test.ts @@ -10,16 +10,16 @@ import { Agent } from '../src/agent/Agent' import { DidExchangeState, HandshakeProtocol } from '../src/modules/connections' import { MediationState, MediatorPickupStrategy } from '../src/modules/routing' -import { getBaseConfig, waitForBasicMessage } from './helpers' +import { getAgentOptions, waitForBasicMessage } from './helpers' -const faberConfig = getBaseConfig('OOB mediation provision - Faber Agent', { +const faberAgentOptions = getAgentOptions('OOB mediation provision - Faber Agent', { endpoints: ['rxjs:faber'], }) -const aliceConfig = getBaseConfig('OOB mediation provision - Alice Recipient Agent', { +const aliceAgentOptions = getAgentOptions('OOB mediation provision - Alice Recipient Agent', { endpoints: ['rxjs:alice'], mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) -const mediatorConfig = getBaseConfig('OOB mediation provision - Mediator Agent', { +const mediatorAgentOptions = getAgentOptions('OOB mediation provision - Mediator Agent', { endpoints: ['rxjs:mediator'], autoAcceptMediationRequests: true, }) @@ -49,17 +49,17 @@ describe('out of band with mediation set up with provision method', () => { 'rxjs:mediator': mediatorMessages, } - mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) + mediatorAgent = new Agent(mediatorAgentOptions) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await mediatorAgent.initialize() - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) const mediationOutOfBandRecord = await mediatorAgent.oob.createInvitation(makeConnectionConfig) diff --git a/packages/core/tests/oob-mediation.test.ts b/packages/core/tests/oob-mediation.test.ts index 34ff80b35d..091c62b1ed 100644 --- a/packages/core/tests/oob-mediation.test.ts +++ b/packages/core/tests/oob-mediation.test.ts @@ -9,18 +9,18 @@ import { Agent } from '../src/agent/Agent' import { DidExchangeState, HandshakeProtocol } from '../src/modules/connections' import { MediationState, MediatorPickupStrategy } from '../src/modules/routing' -import { getBaseConfig, waitForBasicMessage } from './helpers' +import { getAgentOptions, waitForBasicMessage } from './helpers' -const faberConfig = getBaseConfig('OOB mediation - Faber Agent', { +const faberAgentOptions = getAgentOptions('OOB mediation - Faber Agent', { endpoints: ['rxjs:faber'], }) -const aliceConfig = getBaseConfig('OOB mediation - Alice Recipient Agent', { +const aliceAgentOptions = getAgentOptions('OOB mediation - Alice Recipient Agent', { endpoints: ['rxjs:alice'], // FIXME: discover features returns that we support this protocol, but we don't support all roles // we should return that we only support the mediator role so we don't have to explicitly declare this mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) -const mediatorConfig = getBaseConfig('OOB mediation - Mediator Agent', { +const mediatorAgentOptions = getAgentOptions('OOB mediation - Mediator Agent', { endpoints: ['rxjs:mediator'], autoAcceptMediationRequests: true, }) @@ -48,17 +48,17 @@ describe('out of band with mediation', () => { 'rxjs:mediator': mediatorMessages, } - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() - mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) + mediatorAgent = new Agent(mediatorAgentOptions) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await mediatorAgent.initialize() diff --git a/packages/core/tests/oob.test.ts b/packages/core/tests/oob.test.ts index 416522376a..9172496c09 100644 --- a/packages/core/tests/oob.test.ts +++ b/packages/core/tests/oob.test.ts @@ -20,7 +20,7 @@ import { DidCommMessageRepository, DidCommMessageRole } from '../src/storage' import { JsonEncoder } from '../src/utils' import { TestMessage } from './TestMessage' -import { getBaseConfig, prepareForIssuance, waitForCredentialRecord } from './helpers' +import { getAgentOptions, prepareForIssuance, waitForCredentialRecord } from './helpers' import { AgentEventTypes, @@ -30,10 +30,10 @@ import { V1CredentialPreview, } from '@aries-framework/core' -const faberConfig = getBaseConfig('Faber Agent OOB', { +const faberAgentOptions = getAgentOptions('Faber Agent OOB', { endpoints: ['rxjs:faber'], }) -const aliceConfig = getBaseConfig('Alice Agent OOB', { +const aliceAgentOptions = getAgentOptions('Alice Agent OOB', { endpoints: ['rxjs:alice'], }) @@ -67,12 +67,12 @@ describe('out of band', () => { 'rxjs:alice': aliceMessages, } - faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent = new Agent(faberAgentOptions) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await faberAgent.initialize() - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() diff --git a/packages/core/tests/postgres.e2e.test.ts b/packages/core/tests/postgres.e2e.test.ts index 3a92c8ef46..eedffe43b5 100644 --- a/packages/core/tests/postgres.e2e.test.ts +++ b/packages/core/tests/postgres.e2e.test.ts @@ -11,12 +11,12 @@ import { loadPostgresPlugin, WalletScheme } from '../../node/src' import { Agent } from '../src/agent/Agent' import { HandshakeProtocol } from '../src/modules/connections' -import { waitForBasicMessage, getBasePostgresConfig } from './helpers' +import { waitForBasicMessage, getPostgresAgentOptions } from './helpers' -const alicePostgresConfig = getBasePostgresConfig('AgentsAlice', { +const alicePostgresAgentOptions = getPostgresAgentOptions('AgentsAlice', { endpoints: ['rxjs:alice'], }) -const bobPostgresConfig = getBasePostgresConfig('AgentsBob', { +const bobPostgresAgentOptions = getPostgresAgentOptions('AgentsBob', { endpoints: ['rxjs:bob'], }) @@ -59,12 +59,12 @@ describe('postgres agents', () => { // loading the postgres wallet plugin loadPostgresPlugin(storageConfig.config, storageConfig.credentials) - aliceAgent = new Agent(alicePostgresConfig.config, alicePostgresConfig.agentDependencies) + aliceAgent = new Agent(alicePostgresAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await aliceAgent.initialize() - bobAgent = new Agent(bobPostgresConfig.config, bobPostgresConfig.agentDependencies) + bobAgent = new Agent(bobPostgresAgentOptions) bobAgent.registerInboundTransport(new SubjectInboundTransport(bobMessages)) bobAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await bobAgent.initialize() diff --git a/packages/core/tests/v1-connectionless-proofs.test.ts b/packages/core/tests/v1-connectionless-proofs.test.ts index 68b4a4c5ac..684584a97a 100644 --- a/packages/core/tests/v1-connectionless-proofs.test.ts +++ b/packages/core/tests/v1-connectionless-proofs.test.ts @@ -29,7 +29,7 @@ import { sleep } from '../src/utils/sleep' import { uuid } from '../src/utils/uuid' import { - getBaseConfig, + getAgentOptions, issueCredential, makeConnection, prepareForIssuance, @@ -221,7 +221,7 @@ describe('Present Proof', () => { const unique = uuid().substring(0, 4) - const mediatorConfig = getBaseConfig(`Connectionless proofs with mediator Mediator-${unique}`, { + const mediatorAgentOptions = getAgentOptions(`Connectionless proofs with mediator Mediator-${unique}`, { autoAcceptMediationRequests: true, endpoints: ['rxjs:mediator'], }) @@ -235,7 +235,7 @@ describe('Present Proof', () => { } // Initialize mediator - const mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) + const mediatorAgent = new Agent(mediatorAgentOptions) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) await mediatorAgent.initialize() @@ -250,7 +250,7 @@ describe('Present Proof', () => { handshakeProtocols: [HandshakeProtocol.Connections], }) - const faberConfig = getBaseConfig(`Connectionless proofs with mediator Faber-${unique}`, { + const faberAgentOptions = getAgentOptions(`Connectionless proofs with mediator Faber-${unique}`, { autoAcceptProofs: AutoAcceptProof.Always, mediatorConnectionsInvite: faberMediationOutOfBandRecord.outOfBandInvitation.toUrl({ domain: 'https://example.com', @@ -258,7 +258,7 @@ describe('Present Proof', () => { mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) - const aliceConfig = getBaseConfig(`Connectionless proofs with mediator Alice-${unique}`, { + const aliceAgentOptions = getAgentOptions(`Connectionless proofs with mediator Alice-${unique}`, { autoAcceptProofs: AutoAcceptProof.Always, mediatorConnectionsInvite: aliceMediationOutOfBandRecord.outOfBandInvitation.toUrl({ domain: 'https://example.com', @@ -266,12 +266,12 @@ describe('Present Proof', () => { mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) - const faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + const faberAgent = new Agent(faberAgentOptions) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) await faberAgent.initialize() - const aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + const aliceAgent = new Agent(aliceAgentOptions) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) await aliceAgent.initialize() diff --git a/packages/core/tests/v2-connectionless-proofs.test.ts b/packages/core/tests/v2-connectionless-proofs.test.ts index b426713e3e..0acb20850f 100644 --- a/packages/core/tests/v2-connectionless-proofs.test.ts +++ b/packages/core/tests/v2-connectionless-proofs.test.ts @@ -27,7 +27,7 @@ import { LinkedAttachment } from '../src/utils/LinkedAttachment' import { uuid } from '../src/utils/uuid' import { - getBaseConfig, + getAgentOptions, issueCredential, makeConnection, prepareForIssuance, @@ -220,7 +220,7 @@ describe('Present Proof', () => { const unique = uuid().substring(0, 4) - const mediatorConfig = getBaseConfig(`Connectionless proofs with mediator Mediator-${unique}`, { + const mediatorOptions = getAgentOptions(`Connectionless proofs with mediator Mediator-${unique}`, { autoAcceptMediationRequests: true, endpoints: ['rxjs:mediator'], }) @@ -234,7 +234,7 @@ describe('Present Proof', () => { } // Initialize mediator - const mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) + const mediatorAgent = new Agent(mediatorOptions) mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) await mediatorAgent.initialize() @@ -249,7 +249,7 @@ describe('Present Proof', () => { handshakeProtocols: [HandshakeProtocol.Connections], }) - const faberConfig = getBaseConfig(`Connectionless proofs with mediator Faber-${unique}`, { + const faberOptions = getAgentOptions(`Connectionless proofs with mediator Faber-${unique}`, { autoAcceptProofs: AutoAcceptProof.Always, mediatorConnectionsInvite: faberMediationOutOfBandRecord.outOfBandInvitation.toUrl({ domain: 'https://example.com', @@ -257,7 +257,7 @@ describe('Present Proof', () => { mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) - const aliceConfig = getBaseConfig(`Connectionless proofs with mediator Alice-${unique}`, { + const aliceOptions = getAgentOptions(`Connectionless proofs with mediator Alice-${unique}`, { autoAcceptProofs: AutoAcceptProof.Always, // logger: new TestLogger(LogLevel.test), mediatorConnectionsInvite: aliceMediationOutOfBandRecord.outOfBandInvitation.toUrl({ @@ -266,12 +266,12 @@ describe('Present Proof', () => { mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) - const faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + const faberAgent = new Agent(faberOptions) faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) await faberAgent.initialize() - const aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + const aliceAgent = new Agent(aliceOptions) aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) await aliceAgent.initialize() diff --git a/packages/core/tests/wallet.test.ts b/packages/core/tests/wallet.test.ts index 2d6d718d0c..3362741146 100644 --- a/packages/core/tests/wallet.test.ts +++ b/packages/core/tests/wallet.test.ts @@ -9,18 +9,18 @@ import { WalletInvalidKeyError } from '../src/wallet/error' import { WalletDuplicateError } from '../src/wallet/error/WalletDuplicateError' import { WalletNotFoundError } from '../src/wallet/error/WalletNotFoundError' -import { getBaseConfig } from './helpers' +import { getAgentOptions } from './helpers' -const aliceConfig = getBaseConfig('wallet-tests-Alice') -const bobConfig = getBaseConfig('wallet-tests-Bob') +const aliceAgentOptions = getAgentOptions('wallet-tests-Alice') +const bobAgentOptions = getAgentOptions('wallet-tests-Bob') describe('wallet', () => { let aliceAgent: Agent let bobAgent: Agent beforeEach(async () => { - aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) - bobAgent = new Agent(bobConfig.config, bobConfig.agentDependencies) + aliceAgent = new Agent(aliceAgentOptions) + bobAgent = new Agent(bobAgentOptions) }) afterEach(async () => { @@ -141,7 +141,7 @@ describe('wallet', () => { // Initialize the wallet again and assert record does not exist // This should create a new wallet // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await bobAgent.wallet.initialize(bobConfig.config.walletConfig!) + await bobAgent.wallet.initialize(bobAgentOptions.config.walletConfig!) expect(await bobBasicMessageRepository.findById(bobAgent.context, basicMessageRecord.id)).toBeNull() await bobAgent.wallet.delete() diff --git a/packages/module-tenants/src/TenantAgent.ts b/packages/module-tenants/src/TenantAgent.ts index 20d0e61eb7..cf0deb7931 100644 --- a/packages/module-tenants/src/TenantAgent.ts +++ b/packages/module-tenants/src/TenantAgent.ts @@ -1,8 +1,8 @@ -import type { AgentContext } from '@aries-framework/core' +import type { AgentContext, DefaultAgentModules, ModulesMap } from '@aries-framework/core' import { AriesFrameworkError, BaseAgent } from '@aries-framework/core' -export class TenantAgent extends BaseAgent { +export class TenantAgent extends BaseAgent { private sessionHasEnded = false public constructor(agentContext: AgentContext) { @@ -26,8 +26,4 @@ export class TenantAgent extends BaseAgent { this._isInitialized = false this.sessionHasEnded = true } - - protected registerDependencies() { - // Nothing to do here - } } diff --git a/packages/module-tenants/src/TenantsApi.ts b/packages/module-tenants/src/TenantsApi.ts index 901c21e35f..430bd2634f 100644 --- a/packages/module-tenants/src/TenantsApi.ts +++ b/packages/module-tenants/src/TenantsApi.ts @@ -1,4 +1,5 @@ import type { CreateTenantOptions, GetTenantAgentOptions, WithTenantAgentCallback } from './TenantsApiOptions' +import type { EmptyModuleMap, ModulesMap } from '@aries-framework/core' import { AgentContext, inject, InjectionSymbols, AgentContextProvider, injectable, Logger } from '@aries-framework/core' @@ -6,7 +7,7 @@ import { TenantAgent } from './TenantAgent' import { TenantRecordService } from './services' @injectable() -export class TenantsApi { +export class TenantsApi { private agentContext: AgentContext private tenantRecordService: TenantRecordService private agentContextProvider: AgentContextProvider @@ -24,12 +25,12 @@ export class TenantsApi { this.logger = logger } - public async getTenantAgent({ tenantId }: GetTenantAgentOptions): Promise { + public async getTenantAgent({ tenantId }: GetTenantAgentOptions): Promise> { this.logger.debug(`Getting tenant agent for tenant '${tenantId}'`) const tenantContext = await this.agentContextProvider.getAgentContextForContextCorrelationId(tenantId) this.logger.trace(`Got tenant context for tenant '${tenantId}'`) - const tenantAgent = new TenantAgent(tenantContext) + const tenantAgent = new TenantAgent(tenantContext) await tenantAgent.initialize() this.logger.trace(`Initializing tenant agent for tenant '${tenantId}'`) @@ -38,7 +39,7 @@ export class TenantsApi { public async withTenantAgent( options: GetTenantAgentOptions, - withTenantAgentCallback: WithTenantAgentCallback + withTenantAgentCallback: WithTenantAgentCallback ): Promise { this.logger.debug(`Getting tenant agent for tenant '${options.tenantId}' in with tenant agent callback`) const tenantAgent = await this.getTenantAgent(options) diff --git a/packages/module-tenants/src/TenantsApiOptions.ts b/packages/module-tenants/src/TenantsApiOptions.ts index 12b01a16b8..def445b627 100644 --- a/packages/module-tenants/src/TenantsApiOptions.ts +++ b/packages/module-tenants/src/TenantsApiOptions.ts @@ -1,11 +1,14 @@ import type { TenantAgent } from './TenantAgent' import type { TenantConfig } from './models/TenantConfig' +import type { ModulesMap } from '@aries-framework/core' export interface GetTenantAgentOptions { tenantId: string } -export type WithTenantAgentCallback = (tenantAgent: TenantAgent) => Promise +export type WithTenantAgentCallback = ( + tenantAgent: TenantAgent +) => Promise export interface CreateTenantOptions { config: Omit diff --git a/packages/module-tenants/src/TenantsModule.ts b/packages/module-tenants/src/TenantsModule.ts index 190f165c3e..0d4880d61a 100644 --- a/packages/module-tenants/src/TenantsModule.ts +++ b/packages/module-tenants/src/TenantsModule.ts @@ -1,5 +1,6 @@ import type { TenantsModuleConfigOptions } from './TenantsModuleConfig' -import type { DependencyManager, Module } from '@aries-framework/core' +import type { ModulesMap, DependencyManager, Module, EmptyModuleMap } from '@aries-framework/core' +import type { Constructor } from '@aries-framework/core' import { InjectionSymbols } from '@aries-framework/core' @@ -10,9 +11,11 @@ import { TenantSessionCoordinator } from './context/TenantSessionCoordinator' import { TenantRepository, TenantRoutingRepository } from './repository' import { TenantRecordService } from './services' -export class TenantsModule implements Module { +export class TenantsModule implements Module { public readonly config: TenantsModuleConfig + public readonly api: Constructor> = TenantsApi + public constructor(config?: TenantsModuleConfigOptions) { this.config = new TenantsModuleConfig(config) } diff --git a/packages/module-tenants/src/__tests__/TenantAgent.test.ts b/packages/module-tenants/src/__tests__/TenantAgent.test.ts index 901afd77a0..ce599ef4bf 100644 --- a/packages/module-tenants/src/__tests__/TenantAgent.test.ts +++ b/packages/module-tenants/src/__tests__/TenantAgent.test.ts @@ -5,16 +5,16 @@ import { TenantAgent } from '../TenantAgent' describe('TenantAgent', () => { test('possible to construct a TenantAgent instance', () => { - const agent = new Agent( - { + const agent = new Agent({ + config: { label: 'test', walletConfig: { id: 'Wallet: TenantAgentRoot', key: 'Wallet: TenantAgentRoot', }, }, - agentDependencies - ) + dependencies: agentDependencies, + }) const tenantDependencyManager = agent.dependencyManager.createChild() diff --git a/packages/module-tenants/src/__tests__/TenantsApi.test.ts b/packages/module-tenants/src/__tests__/TenantsApi.test.ts index 3650c64509..e2c5c28fed 100644 --- a/packages/module-tenants/src/__tests__/TenantsApi.test.ts +++ b/packages/module-tenants/src/__tests__/TenantsApi.test.ts @@ -1,6 +1,6 @@ import { Agent, AgentContext, InjectionSymbols } from '@aries-framework/core' -import { agentDependencies, getAgentConfig, getAgentContext, mockFunction } from '../../../core/tests/helpers' +import { getAgentContext, getAgentOptions, mockFunction } from '../../../core/tests/helpers' import { TenantAgent } from '../TenantAgent' import { TenantsApi } from '../TenantsApi' import { TenantAgentContextProvider } from '../context/TenantAgentContextProvider' @@ -15,11 +15,11 @@ const AgentContextProviderMock = TenantAgentContextProvider as jest.Mock { describe('getTenantAgent', () => { @@ -28,7 +28,7 @@ describe('TenantsApi', () => { const tenantAgentContext = getAgentContext({ contextCorrelationId: 'tenant-id', dependencyManager: tenantDependencyManager, - agentConfig: agentConfig.extend({ + agentConfig: rootAgent.config.extend({ label: 'tenant-agent', walletConfig: { id: 'Wallet: TenantsApi: tenant-id', @@ -65,7 +65,7 @@ describe('TenantsApi', () => { const tenantAgentContext = getAgentContext({ contextCorrelationId: 'tenant-id', dependencyManager: tenantDependencyManager, - agentConfig: agentConfig.extend({ + agentConfig: rootAgent.config.extend({ label: 'tenant-agent', walletConfig: { id: 'Wallet: TenantsApi: tenant-id', @@ -103,7 +103,7 @@ describe('TenantsApi', () => { const tenantAgentContext = getAgentContext({ contextCorrelationId: 'tenant-id', dependencyManager: tenantDependencyManager, - agentConfig: agentConfig.extend({ + agentConfig: rootAgent.config.extend({ label: 'tenant-agent', walletConfig: { id: 'Wallet: TenantsApi: tenant-id', diff --git a/packages/module-tenants/tests/tenant-sessions.e2e.test.ts b/packages/module-tenants/tests/tenant-sessions.e2e.test.ts index 9043a5a5e4..61da36bd79 100644 --- a/packages/module-tenants/tests/tenant-sessions.e2e.test.ts +++ b/packages/module-tenants/tests/tenant-sessions.e2e.test.ts @@ -1,10 +1,11 @@ import type { InitConfig } from '@aries-framework/core' -import { Agent, DependencyManager } from '@aries-framework/core' +import { Agent } from '@aries-framework/core' import { agentDependencies } from '@aries-framework/node' import testLogger from '../../core/tests/logger' -import { TenantsApi, TenantsModule } from '../src' + +import { TenantsModule } from '@aries-framework/module-tenants' jest.setTimeout(2000000) @@ -19,15 +20,14 @@ const agentConfig: InitConfig = { autoAcceptConnections: true, } -// Register tenant module. For now we need to create a custom dependency manager -// and register all plugins before initializing the agent. Later, we can add the module registration -// to the agent constructor. -const dependencyManager = new DependencyManager() -dependencyManager.registerModules(new TenantsModule()) - // Create multi-tenant agent -const agent = new Agent(agentConfig, agentDependencies, dependencyManager) -const agentTenantsApi = agent.dependencyManager.resolve(TenantsApi) +const agent = new Agent({ + config: agentConfig, + dependencies: agentDependencies, + modules: { + tenants: new TenantsModule(), + }, +}) describe('Tenants Sessions E2E', () => { beforeAll(async () => { @@ -42,7 +42,7 @@ describe('Tenants Sessions E2E', () => { test('create 100 sessions in parallel for the same tenant and close them', async () => { const numberOfSessions = 100 - const tenantRecord = await agentTenantsApi.createTenant({ + const tenantRecord = await agent.modules.tenants.createTenant({ config: { label: 'Agent 1 Tenant 1', }, @@ -51,7 +51,7 @@ describe('Tenants Sessions E2E', () => { const tenantAgentPromises = [] for (let session = 0; session < numberOfSessions; session++) { - tenantAgentPromises.push(agentTenantsApi.getTenantAgent({ tenantId: tenantRecord.id })) + tenantAgentPromises.push(agent.modules.tenants.getTenantAgent({ tenantId: tenantRecord.id })) } const tenantAgents = await Promise.all(tenantAgentPromises) @@ -65,7 +65,7 @@ describe('Tenants Sessions E2E', () => { const tenantRecordPromises = [] for (let tenantNo = 0; tenantNo < numberOfTenants; tenantNo++) { - const tenantRecord = agentTenantsApi.createTenant({ + const tenantRecord = agent.modules.tenants.createTenant({ config: { label: 'Agent 1 Tenant 1', }, @@ -79,7 +79,7 @@ describe('Tenants Sessions E2E', () => { const tenantAgentPromises = [] for (const tenantRecord of tenantRecords) { for (let session = 0; session < numberOfSessions; session++) { - tenantAgentPromises.push(agentTenantsApi.getTenantAgent({ tenantId: tenantRecord.id })) + tenantAgentPromises.push(agent.modules.tenants.getTenantAgent({ tenantId: tenantRecord.id })) } } diff --git a/packages/module-tenants/tests/tenants.e2e.test.ts b/packages/module-tenants/tests/tenants.e2e.test.ts index a8b24a88f1..5c2a616e57 100644 --- a/packages/module-tenants/tests/tenants.e2e.test.ts +++ b/packages/module-tenants/tests/tenants.e2e.test.ts @@ -1,12 +1,13 @@ import type { InitConfig } from '@aries-framework/core' -import { OutOfBandRecord, Agent, DependencyManager } from '@aries-framework/core' +import { OutOfBandRecord, Agent } from '@aries-framework/core' import { agentDependencies } from '@aries-framework/node' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' import testLogger from '../../core/tests/logger' -import { TenantsApi, TenantsModule } from '../src' + +import { TenantsModule } from '@aries-framework/module-tenants' jest.setTimeout(2000000) @@ -32,18 +33,22 @@ const agent2Config: InitConfig = { autoAcceptConnections: true, } -// Register tenant module. For now we need to create a custom dependency manager -// and register all plugins before initializing the agent. Later, we can add the module registration -// to the agent constructor. -const agent1DependencyManager = new DependencyManager() -agent1DependencyManager.registerModules(new TenantsModule()) - -const agent2DependencyManager = new DependencyManager() -agent2DependencyManager.registerModules(new TenantsModule()) - // Create multi-tenant agents -const agent1 = new Agent(agent1Config, agentDependencies, agent1DependencyManager) -const agent2 = new Agent(agent2Config, agentDependencies, agent2DependencyManager) +const agent1 = new Agent({ + config: agent1Config, + modules: { + tenants: new TenantsModule(), + }, + dependencies: agentDependencies, +}) + +const agent2 = new Agent({ + config: agent2Config, + modules: { + tenants: new TenantsModule(), + }, + dependencies: agentDependencies, +}) // Register inbound and outbound transports (so we can communicate with ourselves) const agent1InboundTransport = new SubjectInboundTransport() @@ -65,9 +70,6 @@ agent2.registerOutboundTransport( }) ) -const agent1TenantsApi = agent1.dependencyManager.resolve(TenantsApi) -const agent2TenantsApi = agent2.dependencyManager.resolve(TenantsApi) - describe('Tenants E2E', () => { beforeAll(async () => { await agent1.initialize() @@ -83,47 +85,48 @@ describe('Tenants E2E', () => { test('create get and delete a tenant', async () => { // Create tenant - let tenantRecord1 = await agent1TenantsApi.createTenant({ + let tenantRecord1 = await agent1.modules.tenants.createTenant({ config: { label: 'Tenant 1', }, }) // Retrieve tenant record from storage - tenantRecord1 = await agent1TenantsApi.getTenantById(tenantRecord1.id) + tenantRecord1 = await agent1.modules.tenants.getTenantById(tenantRecord1.id) // Get tenant agent - const tenantAgent = await agent1TenantsApi.getTenantAgent({ + const tenantAgent = await agent1.modules.tenants.getTenantAgent({ tenantId: tenantRecord1.id, }) await tenantAgent.endSession() // Delete tenant agent - await agent1TenantsApi.deleteTenantById(tenantRecord1.id) + await agent1.modules.tenants.deleteTenantById(tenantRecord1.id) // Can not get tenant agent again - await expect(agent1TenantsApi.getTenantAgent({ tenantId: tenantRecord1.id })).rejects.toThrow( + await expect(agent1.modules.tenants.getTenantAgent({ tenantId: tenantRecord1.id })).rejects.toThrow( `TenantRecord: record with id ${tenantRecord1.id} not found.` ) }) test('create a connection between two tenants within the same agent', async () => { // Create tenants - const tenantRecord1 = await agent1TenantsApi.createTenant({ + const tenantRecord1 = await agent1.modules.tenants.createTenant({ config: { label: 'Tenant 1', }, }) - const tenantRecord2 = await agent1TenantsApi.createTenant({ + const tenantRecord2 = await agent1.modules.tenants.createTenant({ config: { label: 'Tenant 2', }, }) - const tenantAgent1 = await agent1TenantsApi.getTenantAgent({ + const tenantAgent1 = await agent1.modules.tenants.getTenantAgent({ tenantId: tenantRecord1.id, }) - const tenantAgent2 = await agent1TenantsApi.getTenantAgent({ + + const tenantAgent2 = await agent1.modules.tenants.getTenantAgent({ tenantId: tenantRecord2.id, }) @@ -154,27 +157,27 @@ describe('Tenants E2E', () => { await tenantAgent2.endSession() // Delete tenants (will also delete wallets) - await agent1TenantsApi.deleteTenantById(tenantAgent1.context.contextCorrelationId) - await agent1TenantsApi.deleteTenantById(tenantAgent2.context.contextCorrelationId) + await agent1.modules.tenants.deleteTenantById(tenantAgent1.context.contextCorrelationId) + await agent1.modules.tenants.deleteTenantById(tenantAgent2.context.contextCorrelationId) }) test('create a connection between two tenants within different agents', async () => { // Create tenants - const tenantRecord1 = await agent1TenantsApi.createTenant({ + const tenantRecord1 = await agent1.modules.tenants.createTenant({ config: { label: 'Agent 1 Tenant 1', }, }) - const tenantAgent1 = await agent1TenantsApi.getTenantAgent({ + const tenantAgent1 = await agent1.modules.tenants.getTenantAgent({ tenantId: tenantRecord1.id, }) - const tenantRecord2 = await agent2TenantsApi.createTenant({ + const tenantRecord2 = await agent2.modules.tenants.createTenant({ config: { label: 'Agent 2 Tenant 1', }, }) - const tenantAgent2 = await agent2TenantsApi.getTenantAgent({ + const tenantAgent2 = await agent2.modules.tenants.getTenantAgent({ tenantId: tenantRecord2.id, }) @@ -195,18 +198,18 @@ describe('Tenants E2E', () => { await tenantAgent2.endSession() // Delete tenants (will also delete wallets) - await agent1TenantsApi.deleteTenantById(tenantRecord1.id) - await agent2TenantsApi.deleteTenantById(tenantRecord2.id) + await agent1.modules.tenants.deleteTenantById(tenantRecord1.id) + await agent2.modules.tenants.deleteTenantById(tenantRecord2.id) }) test('perform actions within the callback of withTenantAgent', async () => { - const tenantRecord = await agent1TenantsApi.createTenant({ + const tenantRecord = await agent1.modules.tenants.createTenant({ config: { label: 'Agent 1 Tenant 1', }, }) - await agent1TenantsApi.withTenantAgent({ tenantId: tenantRecord.id }, async (tenantAgent) => { + await agent1.modules.tenants.withTenantAgent({ tenantId: tenantRecord.id }, async (tenantAgent) => { const outOfBandRecord = await tenantAgent.oob.createInvitation() expect(outOfBandRecord).toBeInstanceOf(OutOfBandRecord) @@ -214,6 +217,6 @@ describe('Tenants E2E', () => { expect(tenantAgent.config.label).toBe('Agent 1 Tenant 1') }) - await agent1TenantsApi.deleteTenantById(tenantRecord.id) + await agent1.modules.tenants.deleteTenantById(tenantRecord.id) }) }) diff --git a/samples/extension-module/dummy/DummyModule.ts b/samples/extension-module/dummy/DummyModule.ts index 44374596ba..7aab0695c1 100644 --- a/samples/extension-module/dummy/DummyModule.ts +++ b/samples/extension-module/dummy/DummyModule.ts @@ -2,13 +2,16 @@ import type { DependencyManager, FeatureRegistry, Module } from '@aries-framewor import { Protocol } from '@aries-framework/core' +import { DummyApi } from './DummyApi' import { DummyRepository } from './repository' import { DummyService } from './services' export class DummyModule implements Module { + public api = DummyApi + public register(dependencyManager: DependencyManager, featureRegistry: FeatureRegistry) { // Api - dependencyManager.registerContextScoped(DummyModule) + dependencyManager.registerContextScoped(DummyApi) dependencyManager.registerSingleton(DummyRepository) dependencyManager.registerSingleton(DummyService) diff --git a/samples/extension-module/requester.ts b/samples/extension-module/requester.ts index 4eaf2c9e7b..3a4a7726f3 100644 --- a/samples/extension-module/requester.ts +++ b/samples/extension-module/requester.ts @@ -4,7 +4,7 @@ import { Agent, AriesFrameworkError, ConsoleLogger, LogLevel, WsOutboundTranspor import { agentDependencies } from '@aries-framework/node' import { filter, first, firstValueFrom, map, ReplaySubject, timeout } from 'rxjs' -import { DummyEventTypes, DummyApi, DummyState, DummyModule } from './dummy' +import { DummyEventTypes, DummyState, DummyModule } from './dummy' const run = async () => { // Create transports @@ -12,8 +12,8 @@ const run = async () => { const wsOutboundTransport = new WsOutboundTransport() // Setup the agent - const agent = new Agent( - { + const agent = new Agent({ + config: { label: 'Dummy-powered agent - requester', walletConfig: { id: 'requester', @@ -22,18 +22,15 @@ const run = async () => { logger: new ConsoleLogger(LogLevel.test), autoAcceptConnections: true, }, - agentDependencies - ) - - // Register the DummyModule - agent.dependencyManager.registerModules(new DummyModule()) + modules: { + dummy: new DummyModule(), + }, + dependencies: agentDependencies, + }) // Register transports agent.registerOutboundTransport(wsOutboundTransport) - // Inject DummyApi - const dummyApi = agent.dependencyManager.resolve(DummyApi) - // Now agent will handle messages and events from Dummy protocol //Initialize the agent @@ -61,7 +58,7 @@ const run = async () => { .subscribe(subject) // Send a dummy request and wait for response - const record = await dummyApi.request(connectionRecord.id) + const record = await agent.modules.dummy.request(connectionRecord.id) agent.config.logger.info(`Request received for Dummy Record: ${record.id}`) const dummyRecord = await firstValueFrom(subject) diff --git a/samples/extension-module/responder.ts b/samples/extension-module/responder.ts index 8d09540a3e..9235db89c7 100644 --- a/samples/extension-module/responder.ts +++ b/samples/extension-module/responder.ts @@ -6,7 +6,7 @@ import { agentDependencies, HttpInboundTransport, WsInboundTransport } from '@ar import express from 'express' import { Server } from 'ws' -import { DummyModule, DummyEventTypes, DummyApi, DummyState } from './dummy' +import { DummyModule, DummyEventTypes, DummyState } from './dummy' const run = async () => { // Create transports @@ -19,8 +19,8 @@ const run = async () => { const wsOutboundTransport = new WsOutboundTransport() // Setup the agent - const agent = new Agent( - { + const agent = new Agent({ + config: { label: 'Dummy-powered agent - responder', endpoints: [`ws://localhost:${port}`], walletConfig: { @@ -30,11 +30,11 @@ const run = async () => { logger: new ConsoleLogger(LogLevel.test), autoAcceptConnections: true, }, - agentDependencies - ) - - // Register the DummyModule - agent.dependencyManager.registerModules(new DummyModule()) + modules: { + dummy: new DummyModule(), + }, + dependencies: agentDependencies, + }) // Register transports agent.registerInboundTransport(httpInboundTransport) @@ -47,9 +47,6 @@ const run = async () => { res.send(outOfBandInvitation.toUrl({ domain: `http://localhost:${port}/invitation` })) }) - // Inject DummyApi - const dummyApi = agent.dependencyManager.resolve(DummyApi) - // Now agent will handle messages and events from Dummy protocol //Initialize the agent @@ -64,7 +61,7 @@ const run = async () => { // Subscribe to dummy record events agent.events.on(DummyEventTypes.StateChanged, async (event: DummyStateChangedEvent) => { if (event.payload.dummyRecord.state === DummyState.RequestReceived) { - await dummyApi.respond(event.payload.dummyRecord.id) + await agent.modules.dummy.respond(event.payload.dummyRecord.id) } }) diff --git a/samples/mediator.ts b/samples/mediator.ts index da4dd15293..f62d1d00b8 100644 --- a/samples/mediator.ts +++ b/samples/mediator.ts @@ -53,7 +53,7 @@ const agentConfig: InitConfig = { } // Set up agent -const agent = new Agent(agentConfig, agentDependencies) +const agent = new Agent({ config: agentConfig, dependencies: agentDependencies }) const config = agent.config // Create all transports diff --git a/tests/e2e-http.test.ts b/tests/e2e-http.test.ts index fa140f4220..4bd2396d41 100644 --- a/tests/e2e-http.test.ts +++ b/tests/e2e-http.test.ts @@ -1,23 +1,23 @@ -import { getBaseConfig } from '../packages/core/tests/helpers' +import { getAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' import { HttpOutboundTransport, Agent, AutoAcceptCredential, MediatorPickupStrategy } from '@aries-framework/core' import { HttpInboundTransport } from '@aries-framework/node' -const recipientConfig = getBaseConfig('E2E HTTP Recipient', { +const recipientAgentOptions = getAgentOptions('E2E HTTP Recipient', { autoAcceptCredentials: AutoAcceptCredential.ContentApproved, mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) const mediatorPort = 3000 -const mediatorConfig = getBaseConfig('E2E HTTP Mediator', { +const mediatorAgentOptions = getAgentOptions('E2E HTTP Mediator', { endpoints: [`http://localhost:${mediatorPort}`], autoAcceptMediationRequests: true, }) const senderPort = 3001 -const senderConfig = getBaseConfig('E2E HTTP Sender', { +const senderAgentOptions = getAgentOptions('E2E HTTP Sender', { endpoints: [`http://localhost:${senderPort}`], mediatorPollingInterval: 1000, autoAcceptCredentials: AutoAcceptCredential.ContentApproved, @@ -30,9 +30,9 @@ describe('E2E HTTP tests', () => { let senderAgent: Agent beforeEach(async () => { - recipientAgent = new Agent(recipientConfig.config, recipientConfig.agentDependencies) - mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) - senderAgent = new Agent(senderConfig.config, senderConfig.agentDependencies) + recipientAgent = new Agent(recipientAgentOptions) + mediatorAgent = new Agent(mediatorAgentOptions) + senderAgent = new Agent(senderAgentOptions) }) afterEach(async () => { diff --git a/tests/e2e-subject.test.ts b/tests/e2e-subject.test.ts index 51945cf1ed..1b6cdb09cc 100644 --- a/tests/e2e-subject.test.ts +++ b/tests/e2e-subject.test.ts @@ -2,7 +2,7 @@ import type { SubjectMessage } from './transport/SubjectInboundTransport' import { Subject } from 'rxjs' -import { getBaseConfig } from '../packages/core/tests/helpers' +import { getAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' import { SubjectInboundTransport } from './transport/SubjectInboundTransport' @@ -10,15 +10,15 @@ import { SubjectOutboundTransport } from './transport/SubjectOutboundTransport' import { Agent, AutoAcceptCredential, MediatorPickupStrategy } from '@aries-framework/core' -const recipientConfig = getBaseConfig('E2E Subject Recipient', { +const recipientAgentOptions = getAgentOptions('E2E Subject Recipient', { autoAcceptCredentials: AutoAcceptCredential.ContentApproved, mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) -const mediatorConfig = getBaseConfig('E2E Subject Mediator', { +const mediatorAgentOptions = getAgentOptions('E2E Subject Mediator', { endpoints: ['rxjs:mediator'], autoAcceptMediationRequests: true, }) -const senderConfig = getBaseConfig('E2E Subject Sender', { +const senderAgentOptions = getAgentOptions('E2E Subject Sender', { endpoints: ['rxjs:sender'], mediatorPollingInterval: 1000, autoAcceptCredentials: AutoAcceptCredential.ContentApproved, @@ -31,9 +31,9 @@ describe('E2E Subject tests', () => { let senderAgent: Agent beforeEach(async () => { - recipientAgent = new Agent(recipientConfig.config, recipientConfig.agentDependencies) - mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) - senderAgent = new Agent(senderConfig.config, senderConfig.agentDependencies) + recipientAgent = new Agent(recipientAgentOptions) + mediatorAgent = new Agent(mediatorAgentOptions) + senderAgent = new Agent(senderAgentOptions) }) afterEach(async () => { diff --git a/tests/e2e-ws-pickup-v2.test.ts b/tests/e2e-ws-pickup-v2.test.ts index 8acb7bb96b..45c641c7d7 100644 --- a/tests/e2e-ws-pickup-v2.test.ts +++ b/tests/e2e-ws-pickup-v2.test.ts @@ -1,24 +1,24 @@ -import { getBaseConfig } from '../packages/core/tests/helpers' +import { getAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' import { Agent, WsOutboundTransport, AutoAcceptCredential, MediatorPickupStrategy } from '@aries-framework/core' import { WsInboundTransport } from '@aries-framework/node' -const recipientConfig = getBaseConfig('E2E WS Pickup V2 Recipient ', { +const recipientOptions = getAgentOptions('E2E WS Pickup V2 Recipient ', { autoAcceptCredentials: AutoAcceptCredential.ContentApproved, mediatorPickupStrategy: MediatorPickupStrategy.PickUpV2, }) // FIXME: port numbers should not depend on availability from other test suites that use web sockets const mediatorPort = 4100 -const mediatorConfig = getBaseConfig('E2E WS Pickup V2 Mediator', { +const mediatorOptions = getAgentOptions('E2E WS Pickup V2 Mediator', { endpoints: [`ws://localhost:${mediatorPort}`], autoAcceptMediationRequests: true, }) const senderPort = 4101 -const senderConfig = getBaseConfig('E2E WS Pickup V2 Sender', { +const senderOptions = getAgentOptions('E2E WS Pickup V2 Sender', { endpoints: [`ws://localhost:${senderPort}`], mediatorPollingInterval: 1000, autoAcceptCredentials: AutoAcceptCredential.ContentApproved, @@ -31,9 +31,9 @@ describe('E2E WS Pickup V2 tests', () => { let senderAgent: Agent beforeEach(async () => { - recipientAgent = new Agent(recipientConfig.config, recipientConfig.agentDependencies) - mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) - senderAgent = new Agent(senderConfig.config, senderConfig.agentDependencies) + recipientAgent = new Agent(recipientOptions) + mediatorAgent = new Agent(mediatorOptions) + senderAgent = new Agent(senderOptions) }) afterEach(async () => { diff --git a/tests/e2e-ws.test.ts b/tests/e2e-ws.test.ts index f8452eb484..e0bd5f27ab 100644 --- a/tests/e2e-ws.test.ts +++ b/tests/e2e-ws.test.ts @@ -1,23 +1,23 @@ -import { getBaseConfig } from '../packages/core/tests/helpers' +import { getAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' import { Agent, WsOutboundTransport, AutoAcceptCredential, MediatorPickupStrategy } from '@aries-framework/core' import { WsInboundTransport } from '@aries-framework/node' -const recipientConfig = getBaseConfig('E2E WS Recipient ', { +const recipientAgentOptions = getAgentOptions('E2E WS Recipient ', { autoAcceptCredentials: AutoAcceptCredential.ContentApproved, mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }) const mediatorPort = 4000 -const mediatorConfig = getBaseConfig('E2E WS Mediator', { +const mediatorAgentOptions = getAgentOptions('E2E WS Mediator', { endpoints: [`ws://localhost:${mediatorPort}`], autoAcceptMediationRequests: true, }) const senderPort = 4001 -const senderConfig = getBaseConfig('E2E WS Sender', { +const senderAgentOptions = getAgentOptions('E2E WS Sender', { endpoints: [`ws://localhost:${senderPort}`], mediatorPollingInterval: 1000, autoAcceptCredentials: AutoAcceptCredential.ContentApproved, @@ -30,9 +30,9 @@ describe('E2E WS tests', () => { let senderAgent: Agent beforeEach(async () => { - recipientAgent = new Agent(recipientConfig.config, recipientConfig.agentDependencies) - mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) - senderAgent = new Agent(senderConfig.config, senderConfig.agentDependencies) + recipientAgent = new Agent(recipientAgentOptions) + mediatorAgent = new Agent(mediatorAgentOptions) + senderAgent = new Agent(senderAgentOptions) }) afterEach(async () => { diff --git a/yarn.lock b/yarn.lock index dd7f0e014b..1fdd754f6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8791,7 +8791,7 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-path@^4.0.4: +parse-path@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.4.tgz#4bf424e6b743fb080831f03b536af9fc43f0ffea" integrity sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==