import type {InterfaceRevision, ValueType} from "../capability-model/types.js"; /** Host clients have no package receiver, but must use the same checked * interface signatures and argument framing as generated package ports. */ export const generateClientContracts = (interfaces: InterfaceRevision[], messages: Record) => { const type = (value: ValueType): string => { switch (value.kind) { case "builtin": return value.name === "unit" ? "undefined" : "string"; case "scalar": return ({bool: "boolean", string: "string", bytes: "Uint8Array", int32: "number", uint32: "number", double: "number", int64: "bigint", uint64: "bigint"})[value.name]; case "object-ref": return `{readonly $quixosRef: string}`; case "optional": return `(${type(value.value)} | null)`; case "list": return `Array<${type(value.value)}>`; case "record": return `{${Object.entries(value.fields).map(([name, field]) => `${JSON.stringify(name)}${field.kind === "optional" ? "?" : ""}: ${type(field)}`).join("; ")}}`; case "message": { const binding = messages[value.descriptorId]; if (!binding) throw new Error(`Missing host message type ${value.descriptorId}`); return binding; } } }; const operations = interfaces.flatMap(iface => iface.members.flatMap(member => member.operations .filter(operation => operation.mode === "call").map(operation => ({...operation, interfaceRevisionId: iface.revisionId})))); return `// Generated from checked QX interfaces. Regenerate with scripts/generate-platform-contracts.mjs.\n` + `export type PlatformInputs = {\n${operations.map(operation => ` ${JSON.stringify(operation.id)}: ${type(operation.inputType)};`).join("\n")}\n};\n` + `export const platformOperations = ${JSON.stringify(Object.fromEntries(operations.map(operation => [operation.id, { interfaceRevisionId: operation.interfaceRevisionId, input: operation.inputType.kind === "builtin" && operation.inputType.name === "unit" ? "unit" : ["record", "message"].includes(operation.inputType.kind) ? "fields" : "value", }])), null, 2)} as const;\n`; };