diff --git a/src/lib/infrastructure/ioc/container-config.ts b/src/lib/infrastructure/ioc/container-config.ts index 095f57e8..4307f035 100644 --- a/src/lib/infrastructure/ioc/container-config.ts +++ b/src/lib/infrastructure/ioc/container-config.ts @@ -37,7 +37,9 @@ import SwitchAccountInputPort from "@/lib/core/port/primary/switch-account-input import SwitchAccountUseCase from "@/lib/core/use-case/switch-account-usecase"; import SwitchAccountController, { ISwitchAccountController } from "../controller/switch-account-controller"; import SwitchAccountPresenter from "../presenter/switch-account-presenter"; -import { loadFeatures } from "@/lib/sdk/ioc-helpers"; +import { loadFeatures, loadFeaturesSync } from "@/lib/sdk/ioc-helpers"; +import ListDidsFeature from "./features/list-dids-feature"; +import LoginConfigFeature from "./features/logic-config-feature"; /** @@ -50,7 +52,10 @@ appContainer.bind(GATEWAYS.DID).to(RucioDIDGateway); appContainer.bind(GATEWAYS.ENV_CONFIG).to(EnvConfigGateway); appContainer.bind(GATEWAYS.STREAM).to(StreamingGateway).inRequestScope(); -loadFeatures(appContainer) +loadFeaturesSync(appContainer, [ + new ListDidsFeature(appContainer), + new LoginConfigFeature(appContainer) +]) appContainer.bind(INPUT_PORT.USERPASS_LOGIN).to(UserPassLoginUseCase).inRequestScope(); appContainer.bind(CONTROLLERS.USERPASS_LOGIN).to(UserPassLoginController); diff --git a/src/lib/infrastructure/ioc/features/list-dids-feature.ts b/src/lib/infrastructure/ioc/features/list-dids-feature.ts index bf71ff7e..e95f7fb3 100644 --- a/src/lib/infrastructure/ioc/features/list-dids-feature.ts +++ b/src/lib/infrastructure/ioc/features/list-dids-feature.ts @@ -1,42 +1,47 @@ -import DIDGatewayOutputPort from "@/lib/core/port/secondary/did-gateway-output-port"; -import { ListDIDsError, ListDIDsRequest, ListDIDsResponse } from "@/lib/core/usecase-models/list-dids-usecase-models"; -import { ListDIDsControllerParameters } from "@/lib/infrastructure/controller/list-dids-controller"; -import { ListDIDsViewModel } from "@/lib/infrastructure/data/view-model/list-did"; -import { BaseStreamableFeature, IOCSymbols } from "@/lib/sdk/ioc-helpers"; -import GATEWAYS from "@/lib/infrastructure/ioc/ioc-symbols-gateway"; -import CONTROLLERS from "@/lib/infrastructure/ioc/ioc-symbols-controllers"; -import INPUT_PORT from "@/lib/infrastructure/ioc/ioc-symbols-input-port"; -import USECASE_FACTORY from "@/lib/infrastructure/ioc/ioc-symbols-usecase-factory"; -import { Container } from "inversify"; -import ListDIDsController from "@/lib/infrastructure/controller/list-dids-controller"; -import ListDIDsUseCase from "@/lib/core/use-case/list-dids-usecase"; -import ListDIDsPresenter from "../../presenter/list-dids-presenter"; - +import DIDGatewayOutputPort from '@/lib/core/port/secondary/did-gateway-output-port' +import { + ListDIDsError, + ListDIDsRequest, + ListDIDsResponse, +} from '@/lib/core/usecase-models/list-dids-usecase-models' +import { ListDIDsControllerParameters } from '@/lib/infrastructure/controller/list-dids-controller' +import { ListDIDsViewModel } from '@/lib/infrastructure/data/view-model/list-did' +import { + BaseStreamableFeature, + IFeature, + IOCSymbols, +} from '@/lib/sdk/ioc-helpers' +import GATEWAYS from '@/lib/infrastructure/ioc/ioc-symbols-gateway' +import CONTROLLERS from '@/lib/infrastructure/ioc/ioc-symbols-controllers' +import INPUT_PORT from '@/lib/infrastructure/ioc/ioc-symbols-input-port' +import USECASE_FACTORY from '@/lib/infrastructure/ioc/ioc-symbols-usecase-factory' +import { Container } from 'inversify' +import ListDIDsController from '@/lib/infrastructure/controller/list-dids-controller' +import ListDIDsUseCase from '@/lib/core/use-case/list-dids-usecase' +import ListDIDsPresenter from '../../presenter/list-dids-presenter' export default class ListDidsFeature extends BaseStreamableFeature< ListDIDsControllerParameters, ListDIDsRequest, ListDIDsResponse, ListDIDsError, - ListDIDsViewModel> { - constructor( appContainer: Container ) { - const didGateway = appContainer.get(GATEWAYS.DID) - const symbols: IOCSymbols = { - CONTROLLER: CONTROLLERS.LIST_DIDS, - USECASE_FACTORY: USECASE_FACTORY.LIST_DIDS, - INPUT_PORT: INPUT_PORT.LIST_DIDS, - } + ListDIDsViewModel +> { + constructor(appContainer: Container) { + const didGateway = appContainer.get(GATEWAYS.DID) + const symbols: IOCSymbols = { + CONTROLLER: CONTROLLERS.LIST_DIDS, + USECASE_FACTORY: USECASE_FACTORY.LIST_DIDS, + INPUT_PORT: INPUT_PORT.LIST_DIDS, + } super( - appContainer, + 'ListDIDs', ListDIDsController, ListDIDsUseCase, - [ - didGateway, - ], + [didGateway], ListDIDsPresenter, false, - symbols + symbols, ) } - - } \ No newline at end of file +} diff --git a/src/lib/infrastructure/ioc/features/logic-config-feature.ts b/src/lib/infrastructure/ioc/features/logic-config-feature.ts index 40a57306..906b80fe 100644 --- a/src/lib/infrastructure/ioc/features/logic-config-feature.ts +++ b/src/lib/infrastructure/ioc/features/logic-config-feature.ts @@ -19,10 +19,7 @@ export default class LoginConfigFeature extends BaseFeature< LoginConfigError, LoginViewModel > { - constructor( - appContainer: Container, - - ) { + constructor(appContainer: Container) { const envGateway: EnvConfigGateway = appContainer.get(GATEWAYS.ENV_CONFIG) const symbols: IOCSymbols = { CONTROLLER: CONTROLLERS.LOGIN_CONFIG, @@ -30,7 +27,7 @@ export default class LoginConfigFeature extends BaseFeature< INPUT_PORT: INPUT_PORT.LOGIN_CONFIG, } super( - appContainer, + "LoginConfig", LoginConfigController, LoginConfigUseCase, [ diff --git a/src/lib/sdk/ioc-helpers.ts b/src/lib/sdk/ioc-helpers.ts index 823eee45..5773a928 100644 --- a/src/lib/sdk/ioc-helpers.ts +++ b/src/lib/sdk/ioc-helpers.ts @@ -20,6 +20,20 @@ export type IOCSymbols = { INPUT_PORT: symbol, // A symbol for the input port dependency. } + +/** + * A base interface for loadable features in the web application. + */ +export interface IFeature{ + name: string + /** + * Load the feature into the IoC container. + * @param appContainer The IoC container for the application. + */ + load(appContainer: Container): void; +} + + /** * A base class for features in a web application. The IOC bindings for the clean architecture components * of the feature are generated automatically. @@ -36,7 +50,7 @@ TControllerParams extends TParameters, TErrorModel, TViewModel, > -{ +implements IFeature { /** * Creates a new instance of the `BaseFeature` class. * @template TControllerParams The type of the parameters for the controller. @@ -53,22 +67,28 @@ TControllerParams extends TParameters, * @param symbols An object that contains symbols for the different types of dependencies in the IoC container. */ public constructor( - appContainer: Container, - Controller: new (useCaseFactory: TUseCaseFactory) => BaseController, - UseCase: new (presenter: BaseOutputPort, ...args: any[]) => TUseCase, - useCaseContructorArgs: any[] = [], - Presenter: new (response: NextApiResponse, session?: IronSession) => BasePresenter, - passSessionToPresenter: boolean = false, - symbols: IOCSymbols, - ) { + public name: string, + private Controller: new (useCaseFactory: TUseCaseFactory) => BaseController, + private UseCase: new (presenter: BaseOutputPort, ...args: any[]) => TUseCase, + private useCaseContructorArgs: any[] = [], + private Presenter: new (response: NextApiResponse, session?: IronSession) => BasePresenter, + private passSessionToPresenter: boolean = false, + private symbols: IOCSymbols, + ) {} + + /** + * Load this feature into the IoC container. + * @param appContainer The IoC container for the application. + */ + load(appContainer: Container): void { this.createIOCBindings( appContainer, - Controller, - UseCase, - useCaseContructorArgs, - Presenter, - passSessionToPresenter, - symbols, + this.Controller, + this.UseCase, + this.useCaseContructorArgs, + this.Presenter, + this.passSessionToPresenter, + this.symbols, ) } @@ -141,7 +161,7 @@ export class BaseStreamableFeature< TResponseModel extends BaseResponseModel, TErrorModel, TViewModel extends BaseViewModel, -> { +> implements IFeature{ /** * Creates a new instance of the `BaseStreamableFeature` class. * @param appContainer The IoC container for the application. @@ -153,22 +173,28 @@ export class BaseStreamableFeature< * @param symbols An object that contains symbols for the different types of dependencies in the IoC container. */ constructor( - appContainer: Container, - Controller: new (useCaseFactory: TUseCaseFactory) => BaseController, - UseCase: new (presenter: BaseStreamingOutputPort, ...args: any[]) => TUseCase, - useCaseContructorArgs: any[] = [], - Presenter: new (response: NextApiResponse, session?: IronSession) => BaseStreamingPresenter, - passSessionToPresenter: boolean = false, - symbols: IOCSymbols, - ) { + public name: string, + private Controller: new (useCaseFactory: TUseCaseFactory) => BaseController, + private UseCase: new (presenter: BaseStreamingOutputPort, ...args: any[]) => TUseCase, + private useCaseContructorArgs: any[] = [], + private Presenter: new (response: NextApiResponse, session?: IronSession) => BaseStreamingPresenter, + private passSessionToPresenter: boolean = false, + private symbols: IOCSymbols, + ) {} + + /** + * Load this feature into the IoC container. + * @param appContainer The IoC container for the application. + */ + public load(appContainer: Container): void { this.createIOCBindings( appContainer, - Controller, - UseCase, - useCaseContructorArgs, - Presenter, - passSessionToPresenter, - symbols, + this.Controller, + this.UseCase, + this.useCaseContructorArgs, + this.Presenter, + this.passSessionToPresenter, + this.symbols, ) } @@ -225,6 +251,9 @@ export class BaseStreamableFeature< * Loads features from the features directory into the IoC Container. * @param appContainer The IoC container for the application. * @param featuresDir The directory to load features from. Defaults to `src/lib/infrastructure/ioc/features`. + * @deprecated NextJS Compiler does not support server side dynamic imports. + * The modules cannot be found at runtime as .next directory contains its own dynnamic file structure. + * Use loadFeaturesSync instead. */ export async function loadFeatures(appContainer: Container, featuresDir?: string) { const FEATURES_PATH = featuresDir || path.join(process.cwd(), 'src', 'lib', 'infrastructure', 'ioc', 'features'); @@ -257,4 +286,17 @@ export async function loadFeatures(appContainer: Container, featuresDir?: string throw error; } } -} \ No newline at end of file +} + +export function loadFeaturesSync(appContainer: Container, features: IFeature[]) { + console.log(`Loading ${features.length} features`) + for ( const feature of features ) { + try { + console.log(`Loading feature ${feature.name}`) + feature.load(appContainer); + } catch (error) { + console.error(`Error loading feature ${feature.name}: ${error}`) + throw error; + } + } +}