diff --git a/src/bindings/index.ts b/src/bindings/index.ts index c004b88..ba87ac4 100644 --- a/src/bindings/index.ts +++ b/src/bindings/index.ts @@ -57,6 +57,7 @@ export const generateTypeScriptBindings = ( if (primitive === "write") return ["set", `(value: ${type(requirement.valueType)}) => Promise`]; throw new Error(`State primitive ${primitive} is not supported by the TypeScript runtime binding yet`); }); + if (requirement.primitives.includes("read")) methods.push(["live", "() => Promise"]); return { type: object(methods), spec: { ...requirement, id: entry.id } }; } case "edge": { @@ -75,8 +76,13 @@ export const generateTypeScriptBindings = ( // Streaming ports need a future streaming ABI; ordinary calls are fully typed today. const operations = contract.members.flatMap((member) => member.operations.filter((operation) => operation.mode === "call") .map((operation) => ({ ...operation, name: `${member.displayName}.${operation.displayName}` }))); - return { type: object(operations.map((operation) => [operation.name, `(${params(operation.inputType)}) => Promise<${type(operation.outputType)}>`])), - spec: { kind: "interface", id: entry.id, operations: Object.fromEntries(operations.map((operation) => [operation.name, operation])) } }; + return { type: object([ + ["objectId", ref({ kind: "interface", interfaceRevisionId: requirement.interfaceRevisionId })], + ["live", object(operations.map(operation => [operation.name, `(${params(operation.inputType)}) => Promise`]))], + ...operations.map((operation): [string, string] => [operation.name, `(${params(operation.inputType)}) => Promise<${type(operation.outputType)}>`]), + ]), + spec: { kind: "interface", id: entry.id, operations: Object.fromEntries(operations.map(({name, id, inputType, outputType}) => + [name, {id, inputType, outputType}])) } }; } case "constructor": { const input = requirement.inputType; @@ -119,7 +125,7 @@ export const generateTypeScriptBindings = ( return `import { ${binding.export} as ${alias} } from ${q(binding.module)};`; }); const signatures = `${object(contexts)} ${object(handlers)}`; - const typeImports = ["BindingValue", "QxObjectRef", "QxWatchHandle", "QxHandler", "QxDerived", "QxContextLifecycle", "RelationshipCollection", "RelationshipEntry"].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures)); + const typeImports = ["BindingValue", "QxObjectRef", "QxWatchHandle", "QxHandler", "QxDerived", "QxContextLifecycle", "QxLiveValue", "RelationshipCollection", "RelationshipEntry"].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures)); return `// Generated by quixos-codegen-ts. Do not edit. Binding ABI version 1.\n` + `import { ${exports.length ? "bindQxHandler, " : ""}${[...typeImports, "QxHandlerSpec", "QxMessages"].map((name) => `type ${name}`).join(", ")} } from ${q(options.runtimeModule ?? "@quixos/camino-package-runtime")};\n` + imports.join("\n") + `\nexport const packageRevisionId = ${q(pkg.revisionId)};\n` +