52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
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<Config, Release, Infrastructure> = Readonly<{
|
|
config: Config;
|
|
release: Release;
|
|
infrastructure: Infrastructure;
|
|
application: ApplicationApi;
|
|
}>;
|
|
|
|
type AdapterBundle<Infrastructure> = Readonly<{
|
|
outputPorts: ApplicationOutputPorts;
|
|
infrastructure: Infrastructure;
|
|
featureInputs?: Readonly<Partial<ApplicationFeatureInputs>>;
|
|
}>;
|
|
|
|
type CompositionFactories<Config, Release, Infrastructure> = Readonly<{
|
|
loadConfig(): Promise<Config>;
|
|
loadRelease(config: Config): Promise<Release>;
|
|
createAdapters(context: Readonly<{
|
|
config: Config;
|
|
release: Release;
|
|
}>): Promise<AdapterBundle<Infrastructure>>;
|
|
}>;
|
|
|
|
/**
|
|
* 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<Config, Release, Infrastructure>(
|
|
factories: CompositionFactories<Config, Release, Infrastructure>,
|
|
): Promise<CompositionRoot<Config, Release, Infrastructure>> {
|
|
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,
|
|
});
|
|
}
|