import type { ApplicationFeatureInputs } from "../application/ports/in/application-api.ts"; import { createReferenceFeatureInstalledInput } from "./reference-feature/adapters/create-reference-feature-input.ts"; import { REFERENCE_FEATURE_ID } from "./reference-feature/contracts/reference-feature-contract.ts"; import { createTechLogFeatureInstalledInput } from "./tech-log/adapters/create-tech-log-feature-input.ts"; import type { CsrfTokenProvider } from "./tech-log/adapters/http/studio-session-csrf.ts"; import { TECH_LOG_FEATURE_ID } from "./tech-log/application/tech-log-feature-input.ts"; import { INSTALLED_PRODUCT_FEATURE_IDS } from "./installed-product-manifest.ts"; /** * §3.5. Partial on purpose: a feature the manifest did not select supplies no * driving input, so consumers have to narrow before calling one. A total type * here would let feature code compile against an input that is not there. */ type InstalledFeatureInputs = Readonly< // Template merge. The reference feature is optional — the manifest may // narrow it out — so its input stays `Partial`. TechLog is this product's // own UI and is always installed, so its input is total. Partial> & Pick >; export function createInstalledFeatureInputs( context: Parameters[0] & Readonly<{ studioSource: "MOCK" | "HTTP"; apiBaseUrl: string; requestTimeoutMs: number; csrf: CsrfTokenProvider; }>, ): InstalledFeatureInputs { const techLogFeature = createTechLogFeatureInstalledInput(context); if (!INSTALLED_PRODUCT_FEATURE_IDS.includes(REFERENCE_FEATURE_ID)) { // A build that narrowed the reference feature out still ships TechLog. return Object.freeze({ [techLogFeature.featureId]: techLogFeature.input, }) as InstalledFeatureInputs; } const referenceFeature = createReferenceFeatureInstalledInput(context); return Object.freeze({ [referenceFeature.featureId]: referenceFeature.input, [techLogFeature.featureId]: techLogFeature.input, }) as InstalledFeatureInputs; }