Implement typed module contracts and conformance bindings
This commit is contained in:
@@ -10,6 +10,7 @@ import type {
|
||||
OperationId,
|
||||
} from "../capability-model/types.js";
|
||||
import { validateWorkspaceRevision } from "../capability-model/validation.js";
|
||||
import { moduleContract } from "../capability-model/modules.js";
|
||||
import { canonicalJson, contentDigest } from "../capability-model/evolution.js";
|
||||
import { resolveForwardedBinding } from "../capability-model/forwarding.js";
|
||||
import { linkQueries, type LinkedQuery } from "../query/link.js";
|
||||
@@ -58,14 +59,41 @@ export interface PlannedQuery {
|
||||
admittedOperations: string[];
|
||||
}
|
||||
export interface PlanPackage {
|
||||
modules?: (NonNullable<WorkspaceRevision["packageImports"][number]["modules"]>[number] & {
|
||||
contract: string;
|
||||
subject?: import("../capability-model/types.js").ObjectExpectation;
|
||||
})[];
|
||||
controllers?: NonNullable<WorkspaceRevision["packageImports"][number]["controllers"]>;
|
||||
components?: NonNullable<WorkspaceRevision["packageImports"][number]["components"]>;
|
||||
components?: { id: string; displayName: string; subject: InterfaceRevisionId; runtime: "react" }[];
|
||||
revision: string;
|
||||
source: WorkspaceRevision["packageImports"][number]["source"];
|
||||
sourceDigest: string;
|
||||
bindingDigest: string;
|
||||
exports: { id: string; execution: ExecutionContract }[];
|
||||
}
|
||||
|
||||
/** React consumes these module contracts; other contracts remain metadata until
|
||||
* an artifact consumer exists. This does not make modules callable operations. */
|
||||
function componentDeclarations(workspace: WorkspaceRevision, pkg: WorkspaceRevision["packageImports"][number]) {
|
||||
return [
|
||||
...(pkg.modules ?? []).flatMap((module) => {
|
||||
const contract = moduleContract(workspace.interfaceImports, module)!;
|
||||
if (
|
||||
!["org.quixos.react.component/1", "org.quixos.react.subject-only/1"].includes(contract.contract) ||
|
||||
contract.subject?.kind !== "interface"
|
||||
)
|
||||
return [];
|
||||
return [
|
||||
{
|
||||
id: module.id,
|
||||
displayName: module.displayName,
|
||||
subject: contract.subject.interfaceRevisionId,
|
||||
runtime: "react" as const,
|
||||
},
|
||||
];
|
||||
}),
|
||||
];
|
||||
}
|
||||
export interface ExecutionPlanDefinition {
|
||||
presentations?: NonNullable<WorkspaceRevision["presentations"]>;
|
||||
codec: "camino-execution-plan-v1";
|
||||
@@ -430,8 +458,22 @@ export function compileExecutionPlan(input: WorkspaceRevision): ExecutionPlan {
|
||||
source: p.source,
|
||||
sourceDigest: hexDigest({ revision: p.revisionId, source: p.source }),
|
||||
bindingDigest: hexDigest(normalizedSchema),
|
||||
...(p.modules?.length
|
||||
? {
|
||||
modules: sorted(p.modules, (module) => module.id).map((module) => {
|
||||
const contract = moduleContract(workspace.interfaceImports, module)!;
|
||||
return {
|
||||
...module,
|
||||
contract: contract.contract,
|
||||
...(contract.subject ? { subject: contract.subject } : {}),
|
||||
};
|
||||
}),
|
||||
}
|
||||
: {}),
|
||||
...(p.controllers?.length ? { controllers: sorted(p.controllers, (controller) => controller.id) } : {}),
|
||||
...(p.components?.length ? { components: sorted(p.components, (component) => component.id) } : {}),
|
||||
...(componentDeclarations(workspace, p).length
|
||||
? { components: sorted(componentDeclarations(workspace, p), (component) => component.id) }
|
||||
: {}),
|
||||
exports: sorted(p.exports, (e) => e.id).map((e) => ({ id: e.id, execution: e.execution ?? { kind: "remote" } })),
|
||||
})),
|
||||
owners: sorted(workspace.conformances, (c) => c.id ?? "").map((c) => {
|
||||
|
||||
Reference in New Issue
Block a user