import { compileInspectionTemplates, type InspectionTemplate } from "./inspection.js"; import path from "node:path"; import { loadCheckedArtifactWorld } from "./receipts.js"; import { contentArtifactUrl, loadArtifactWorld, type LoadedArtifactWorld } from "./files.js"; import { selectArtifactImplementation, type ArtifactImplementation, type ComponentArtifact } from "./artifacts.js"; import { ExecutionPlanError, hexDigest, type ExecutionPlan } from "./plan.js"; import { publicOperationContract, publicQueryContract, type PublicOperationContract, type PublicQueryContract, } from "./client-contracts.js"; import { resultInterfaces } from "./projections.js"; /** Activation is assigned by graph authority, never by a package artifact. */ export interface ActiveExecutionIdentity { readonly workspace: string; readonly world: string; readonly plan: string; readonly epoch: string; } /** Host-owned execution selection. The lifecycle manager fills its checked inputs. */ export interface ExecutionGroupIdentity { readonly logicalId: string; readonly executionDigest: string; } export interface ClientContractCatalog { readonly inspections: readonly InspectionTemplate[]; readonly resultInterfaces: Readonly>; readonly operations: readonly PublicOperationContract[]; readonly queries: readonly PublicQueryContract[]; readonly components: readonly InstalledComponent[]; readonly presentations: readonly { id: string; subject: string; packageRevision: string; component: string }[]; readonly moduleBindings: readonly { atom: string; interface: string; member: string; packageRevision: string; id: string; }[]; } /** Explicit projection prevents accidental spreading of filesystem roots or private bindings. */ export function clientContractCatalog( plan: ExecutionPlan, installation: ExecutionInstallation, requestedPackages: readonly string[], ): ClientContractCatalog { if (installation.plan !== plan.digest || hexDigest(plan.definition) !== plan.digest) throw new ExecutionPlanError( "CATALOG_PLAN_MISMATCH", plan.digest, "Installation and public catalog must use the same checked plan", ); const packages = requestedPackages.map((revision) => { const pkg = plan.definition.workspace.packageImports.find((p) => p.revisionId === revision); if (!pkg) throw new ExecutionPlanError("UNINSTALLED_PACKAGE", revision, "Requested catalog package is not installed"); return pkg; }); // Interface metadata contains no authority or private implementation configuration. // A later admission optimization can narrow this set without changing operation identities. const operations = plan.definition.workspace.interfaceImports .filter((i) => !i.template) .flatMap((iface) => iface.members.flatMap((member) => member.operations .filter((o) => o.mode === "call") .map((operation) => publicOperationContract(iface, operation)), ), ); const inspection = compileInspectionTemplates(plan); return { inspections: inspection.templates, resultInterfaces: Object.fromEntries( plan.definition.operations.map((operation) => [operation.key, resultInterfaces(plan, operation.key)]), ), operations, queries: [ ...inspection.contracts, ...packages.flatMap((pkg) => (pkg.checkedQueries ?? []).map((q) => publicQueryContract(pkg, q.declaration.id))), ], components: installation.components.filter((c) => requestedPackages.includes(c.packageRevision)), moduleBindings: plan.definition.workspace.conformances.flatMap((c) => (c.moduleBindings ?? []) .filter((b) => requestedPackages.includes(b.packageRevisionId)) .map((b) => ({ atom: c.atomId, interface: c.interfaceRevisionId, member: b.memberId, packageRevision: b.packageRevisionId, id: b.moduleId, })), ), presentations: (plan.definition.presentations ?? []) .filter((p) => requestedPackages.includes(p.packageRevisionId)) .map((p) => ({ id: p.id, subject: p.subject, packageRevision: p.packageRevisionId, component: p.componentId })), }; } export interface PackageInstallationSelection { readonly browser?: { readonly id?: string }; readonly service?: { readonly id?: string }; /** Including a module is optional; executing it still requires host trust policy. */ readonly module?: { readonly id?: string }; } export interface ExecutionInstallation { readonly codec: "camino-execution-installation-v1"; readonly plan: string; readonly world: string; readonly packages: readonly { readonly revision: string; readonly root: string; readonly service?: ArtifactImplementation; readonly module?: ArtifactImplementation; readonly browserImplementation?: ArtifactImplementation; readonly browserURL?: string; readonly browserRegistry?: string; }[]; readonly routes: Readonly>; readonly coreURL?: string; readonly engineURL?: string; readonly components: readonly InstalledComponent[]; } /** Safe to expose in a presentation catalog: no source paths, state slots, or host configuration. */ export interface InstalledComponent { readonly role: { readonly interface: string; readonly member: string; readonly subject: string; readonly contract: string; readonly typeArguments?: readonly unknown[]; readonly requiredInterfaces?: readonly string[]; }; readonly packageRevision: string; readonly id: string; readonly subject: string; readonly url: string; readonly exportName: string; readonly styles: readonly string[]; readonly compatibility: ComponentArtifact["compatibility"]; /** Owned and interpreted by the React artifact consumer. */ readonly preparation?: unknown; readonly sharedModules: Readonly>; } /** Build-time validation uses the compiler selected by the Nix derivation. */ export async function checkExecutionInstallation( plan: ExecutionPlan, roots: Readonly>, generator: string, selections: Readonly> = {}, ): Promise { const loaded = await loadCheckedArtifactWorld(plan, roots, generator); return assembleExecutionInstallation(plan, roots, loaded, selections); } /** Load immutable artifacts without regenerating bindings with the host compiler. * Format, coverage, content and runtime ABI checks still apply. This grants no * authority to activate a world or run optional modules in process. */ export async function loadExecutionInstallation( plan: ExecutionPlan, roots: Readonly>, selections: Readonly> = {}, ): Promise { return assembleExecutionInstallation(plan, roots, await loadArtifactWorld(plan, roots), selections); } function assembleExecutionInstallation( plan: ExecutionPlan, roots: Readonly>, loaded: LoadedArtifactWorld, selections: Readonly>, ): ExecutionInstallation { const fail = (where: string, message: string): never => { throw new ExecutionPlanError("INSTALLATION_INVALID", where, message); }; for (const revision of Object.keys(selections)) if (!loaded.manifests.some((manifest) => manifest.packageRevisionId === revision)) fail(revision, "Selection names a package outside this checked world"); const routes: Record = Object.create(null); const packages: ExecutionInstallation["packages"][number][] = []; const components: InstalledComponent[] = []; const sharedComponentModules = new Map(); let coreURL: string | undefined, engineURL: string | undefined; for (const manifest of loaded.manifests) { const revision = manifest.packageRevisionId; const root = roots[revision]!; const selection = selections[revision] ?? {}; const exports = plan.definition.packages.find((pkg) => pkg.revision === revision)!.exports; const service = exports.length || selection.service ? selectArtifactImplementation(manifest, { ...selection.service, target: "server", compatibility: "quixos-service-v1", exports: exports.map((entry) => entry.id), }) : undefined; for (const component of manifest.components ?? []) { const sharedModules = Object.fromEntries( Object.entries(component.sharedModules).map(([name, filePath]) => { const file = component.files.find((file) => file.path === filePath)!; const url = contentArtifactUrl(file), previous = sharedComponentModules.get(name); if (previous && previous !== url) fail(component.id, `Components disagree on shared module ${name}`); sharedComponentModules.set(name, url); return [name, url]; }), ) as InstalledComponent["sharedModules"]; for (const file of component.files) { const url = contentArtifactUrl(file); if (routes[url] && routes[url].mediaType !== file.mediaType) fail(url, "Conflicting artifact media types"); routes[url] ??= { path: path.join(root, file.path), mediaType: file.mediaType }; } components.push({ ...(() => { const pkg = plan.definition.workspace.packageImports.find((entry) => entry.revisionId === revision); const artifact = pkg?.buildArtifacts?.["org.quixos.react.preparation/1"] as | { modules: { module: string }[] } | undefined; const preparation = artifact?.modules.find((entry) => entry.module === component.id); return preparation ? { preparation } : {}; })(), role: (() => { const module = plan.definition.packages .find((p) => p.revision === revision)! .modules!.find((m) => m.id === component.id)!; return { interface: module.interfaceRevisionId, member: module.memberId, subject: component.subject, contract: module.contract, ...(module.typeArguments ? { typeArguments: module.typeArguments } : {}), ...(module.requiredInterfaces ? { requiredInterfaces: module.requiredInterfaces } : {}), }; })(), packageRevision: revision, id: component.id, subject: component.subject, compatibility: component.compatibility, exportName: component.exportName, styles: component.files.filter((file) => file.mediaType === "text/css").map(contentArtifactUrl), sharedModules, url: contentArtifactUrl(component.files.find((file) => file.path === component.path)!), }); } const module = selection.module ? selectArtifactImplementation(manifest, { ...selection.module, target: "server", compatibility: "quixos-js-module-v1", exports: exports.map((entry) => entry.id), }) : undefined; const browserExports = exports.filter( (entry) => entry.execution.kind !== "remote" && entry.execution.targets.includes("target:org.quixos.execution.javascript@1"), ); if (!browserExports.length) { if (selection.browser) fail(revision, "Package has no browser exports to select"); packages.push({ revision, root, ...(service ? { service } : {}), ...(module ? { module } : {}) }); continue; } const browser = selectArtifactImplementation(manifest, { ...selection.browser, target: "target:org.quixos.execution.javascript@1", compatibility: "quixos-js-module-v1", exports: browserExports.map((entry) => entry.id), }); const entry = browser.files.find((file) => file.path === browser.path)!; const shared = (name: string) => { const files = browser.files.filter((file) => file.path.endsWith("/" + name)); if (files.length !== 1) fail(revision, "Expected one shared " + name); return contentArtifactUrl(files[0]!); }; const core = shared("core.mjs"), engine = shared("engine.mjs"); if ((coreURL && coreURL !== core) || (engineURL && engineURL !== engine)) fail(revision, "Browser packages disagree on the shared runtime identity"); coreURL = core; engineURL = engine; for (const file of browser.files) { const url = contentArtifactUrl(file); if (routes[url] && routes[url].mediaType !== file.mediaType) fail(url, "Conflicting artifact media types"); routes[url] ??= { path: path.join(root, file.path), mediaType: file.mediaType }; } packages.push({ revision, root, ...(service ? { service } : {}), ...(module ? { module } : {}), browserImplementation: browser, browserURL: contentArtifactUrl(entry), browserRegistry: browser.registryExport, }); } return { codec: "camino-execution-installation-v1", plan: plan.digest, world: loaded.digest, packages, components, routes, ...(coreURL ? { coreURL, engineURL } : {}), }; }