Standardize Camino query references and retire live field sidecars

This commit is contained in:
Timothy J. Aveni
2026-09-22 15:41:27 -07:00
parent 152f58a3c6
commit eba85ba158
28 changed files with 88 additions and 217 deletions
+11 -29
View File
@@ -87,6 +87,16 @@ export async function compileQuery(
definitions.push(...document.definitions);
}
const document: DocumentNode = { kind: "Document" as DocumentNode["kind"], definitions };
visit(document, {
Directive(node) {
if (node.name.value === "live")
fail(
"QUERY_RETIRED_DIRECTIVE",
"@live is retired. Observations watch ordinary query values; use checked operations for mutations.",
node,
);
},
});
const generated = querySchema(declaration, interfaces, document);
const operations = definitions.filter((entry) => entry.kind === "OperationDefinition");
if (
@@ -201,16 +211,7 @@ export async function compileQuery(
Field(node) {
const parent = info.getParentType();
const contract = parent && generated.byName.get(parent.name);
if (node.directives?.some((directive) => directive.name.value === "live")) {
const member = contract?.members.find((entry) => entry.displayName === node.name.value);
if (!member || member.kind !== "value" || member.queryRead?.execution !== "native")
fail(
"QUERY_LIVE_UNSUPPORTED",
"@live requires a direct native-queryable value field, not RPC enrichment or a synthetic result",
node,
);
}
if (!contract || node.name.value === "_qx") return;
if (!contract || node.name.value === "_camino") return;
mark(contract.revisionId, node.name.value, "select", node);
const member = contract.members.find((entry) => entry.displayName === node.name.value)!;
if (member.kind !== "relationship" || (member.cardinality !== "many" && member.cardinality !== "many-unique"))
@@ -425,13 +426,6 @@ export async function compileQuery(
{
name: node.name.value,
key: node.alias?.value ?? node.name.value,
...(node.directives?.some((directive) => directive.name.value === "live")
? {
liveSelectionId: createHash("sha256")
.update(JSON.stringify([node.loc?.source.name, node.loc?.start, contract?.revisionId, member?.id]))
.digest("hex"),
}
: {}),
...(member && contract ? { interfaceRevisionId: contract.revisionId, memberId: member.id } : {}),
...(member?.kind === "relationship" ? { targetInterfaceRevisionId: generated.target(member) } : {}),
conditions: [...inherited, ...conditions(node.directives)],
@@ -447,18 +441,6 @@ export async function compileQuery(
const normalized = print(document),
schema = printSchema(generated.schema);
const selections = selection(operations[0]!.selectionSet, generated.schema.getQueryType()!);
const checkPresentation = (entries: QuerySelection[]) => {
for (const key of new Set(entries.map((entry) => entry.key))) {
const siblings = entries.filter((entry) => entry.key === key);
if (siblings.some((entry) => entry.liveSelectionId) && siblings.some((entry) => !entry.liveSelectionId))
throw new QueryCompileError(
"QUERY_LIVE_CONFLICT",
`${key} mixes live and plain selections; use separate aliases`,
);
checkPresentation(siblings.flatMap((entry) => entry.selection));
}
};
checkPresentation(selections);
const definitionDigest = createHash("sha256")
.update(
canonicalJson({