import { createApplication } from "../application/create-application.ts"; import type { ApplicationApi, ApplicationFeatureInputs, } from "../application/ports/in/application-api.ts"; import type { ApplicationOutputPorts } from "../application/ports/out/application-output-ports.ts"; export type CompositionRoot = Readonly<{ config: Config; release: Release; infrastructure: Infrastructure; application: ApplicationApi; }>; type AdapterBundle = Readonly<{ outputPorts: ApplicationOutputPorts; infrastructure: Infrastructure; featureInputs?: Readonly>; }>; type CompositionFactories = Readonly<{ loadConfig(): Promise; loadRelease(config: Config): Promise; createAdapters(context: Readonly<{ config: Config; release: Release; }>): Promise>; }>; /** * This is the only module allowed to join concrete adapters to application * ports. Boot phases are explicit so failures can stop before product mount. */ export async function createCompositionRoot( factories: CompositionFactories, ): Promise> { const config = await factories.loadConfig(); const release = await factories.loadRelease(config); const adapters = await factories.createAdapters({ config, release }); const application = createApplication( adapters.outputPorts, adapters.featureInputs, ); return Object.freeze({ config, release, infrastructure: adapters.infrastructure, application, }); }