Implement query execution, scoped RPC enrichment, live collections, and scaffold integration
This commit is contained in:
+43
-3
@@ -144,6 +144,33 @@ export const generateTypeScriptBindings = (
|
||||
const port = (entry: DependencyPort): { type: string; spec: unknown } => {
|
||||
const requirement = entry.requirement;
|
||||
switch (requirement.kind) {
|
||||
case "query": {
|
||||
const query = schema.packages
|
||||
.find((candidate) => candidate.revisionId === requirement.packageRevisionId)
|
||||
?.checkedQueries?.find((query) => query.declaration.id === requirement.queryId);
|
||||
if (!query) throw new Error(`Missing checked query ${requirement.packageRevisionId}:${requirement.queryId}`);
|
||||
return {
|
||||
type: object([
|
||||
["execute", `(variables: ${type(query.variables)}) => Promise<${type(query.output)}>`],
|
||||
...(query.declaration.watch
|
||||
? ([
|
||||
[
|
||||
"watch",
|
||||
`(variables: ${type(query.variables)}, signal: AbortSignal) => AsyncIterable<QxQuerySnapshot<${type(query.output)}>>`,
|
||||
],
|
||||
] as [string, string][])
|
||||
: []),
|
||||
]),
|
||||
spec: {
|
||||
kind: "query",
|
||||
id: entry.id,
|
||||
definitionDigest: query.definitionDigest,
|
||||
variables: query.variables,
|
||||
output: query.output,
|
||||
watch: query.declaration.watch,
|
||||
},
|
||||
};
|
||||
}
|
||||
case "state": {
|
||||
const methods = requirement.primitives.map((primitive): [string, string] => {
|
||||
if (primitive === "read") return ["get", `() => Promise<${type(requirement.valueType)}>`];
|
||||
@@ -282,7 +309,12 @@ export const generateTypeScriptBindings = (
|
||||
for (const definition of pkg.genericExports ?? []) {
|
||||
handlers.push([
|
||||
definition.displayName,
|
||||
genericImplementationType(definition, [...schema.interfaces, ...(schema.interfaceTemplates ?? [])], type),
|
||||
genericImplementationType(
|
||||
definition,
|
||||
[...schema.interfaces, ...(schema.interfaceTemplates ?? [])],
|
||||
type,
|
||||
(requirement) => port({ id: capabilityId.dependencyPort("query"), displayName: "query", requirement }).type,
|
||||
),
|
||||
]);
|
||||
}
|
||||
// Unused imported interfaces must not introduce new message-codec obligations.
|
||||
@@ -326,7 +358,13 @@ export const generateTypeScriptBindings = (
|
||||
const queryResults = object(
|
||||
(pkg.checkedQueries ?? []).map((query) => [query.declaration.displayName, type(query.output)]),
|
||||
);
|
||||
const signatures = `${object(contexts)} ${object(handlers)} ${object(results)} ${queryVariables} ${queryResults} ${contracts.map((entry) => entry.type).join(" ")}`;
|
||||
const queryDescriptors = object(
|
||||
(pkg.checkedQueries ?? []).map((query) => [
|
||||
query.declaration.displayName,
|
||||
`QxQueryDescriptor<QueryVariables[${q(query.declaration.displayName)}], QueryResults[${q(query.declaration.displayName)}], ${q(query.declaration.root)}>`,
|
||||
]),
|
||||
);
|
||||
const signatures = `${object(contexts)} ${object(handlers)} ${object(results)} ${queryVariables} ${queryResults} ${queryDescriptors} ${contracts.map((entry) => entry.type).join(" ")}`;
|
||||
const typeImports = [
|
||||
"BindingValue",
|
||||
"QxObjectRef",
|
||||
@@ -339,6 +377,8 @@ export const generateTypeScriptBindings = (
|
||||
"QxLiveValue",
|
||||
"RelationshipCollection",
|
||||
"RelationshipEntry",
|
||||
"QxQuerySnapshot",
|
||||
"QxQueryDescriptor",
|
||||
].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures));
|
||||
return (
|
||||
`// Generated by quixos-codegen-ts. Do not edit. Binding ABI version 1.\n` +
|
||||
@@ -348,7 +388,7 @@ export const generateTypeScriptBindings = (
|
||||
`declare const appliedType: unique symbol;\ntype QxApplied<Definition extends string, Arguments extends readonly unknown[]> = string & {readonly [appliedType]: (value: [Definition, Arguments]) => [Definition, Arguments]};\n` +
|
||||
`export type Contexts = ${object(contexts)};\nexport type Results = ${object(results)};\nexport type Implementation = ${object(handlers)};\n` +
|
||||
`export type QueryVariables = ${queryVariables};\nexport type QueryResults = ${queryResults};\n` +
|
||||
`export const queries = ${JSON.stringify(Object.fromEntries((pkg.checkedQueries ?? []).map((query) => [query.declaration.displayName, { id: `${pkg.revisionId}:${query.declaration.id}`, definitionDigest: query.definitionDigest, rootInterfaceRevisionId: query.declaration.root, variables: query.variables, output: query.output, watch: query.declaration.watch }])), null, 2)} as const;\n` +
|
||||
`export const queries: ${queryDescriptors} = ${JSON.stringify(Object.fromEntries((pkg.checkedQueries ?? []).map((query) => [query.declaration.displayName, { id: `${pkg.revisionId}:${query.declaration.id}`, definitionDigest: query.definitionDigest, rootInterfaceRevisionId: query.declaration.root, variables: query.variables, output: query.output, watch: query.declaration.watch }])), null, 2)} as const;\n` +
|
||||
`export const contracts = {${contracts.map((entry) => `${q(entry.iface.revisionId)}: ${entry.code}`).join(",\n")}};\n` +
|
||||
`export const interfaces = {${contracts
|
||||
.filter((entry) => contracts.filter((other) => other.iface.displayName === entry.iface.displayName).length === 1)
|
||||
|
||||
Reference in New Issue
Block a user