Implement shared live fields and checked query hydration

Add native register acknowledgments and idempotent mutation replay, shared optimistic field controllers, overlapping custom setters, non-suspending hooks and explicit Suspense. Carry checked @live provenance through batched queries and hydrate shared browser fields with coverage leases. Update tracker/scaffolds/guides and verify compiler, PostgreSQL, browser and immutable workspace paths.
This commit is contained in:
Timothy J. Aveni
2026-09-18 01:10:48 -07:00
parent a05f58f7fe
commit 2dffdbcd9f
17 changed files with 527 additions and 148 deletions
+44
View File
@@ -4,6 +4,8 @@ import { compileCapabilityResourceSource } from "../src/capability-language/inde
import { compileQuery } from "../src/query/compile.js";
import { QueryCompileError } from "../src/query/types.js";
import { checkQueryTemplate } from "../src/query/templates.js";
import { queryPresentation } from "../src/query/presentation.js";
import { querySelectionToWire } from "../src/query/proto.js";
import type { InterfaceRevision } from "../src/capability-model/types.js";
const source = { repository: "https://example.test/queries.git", commit: "a".repeat(40) };
@@ -125,6 +127,48 @@ const document = `query Upcoming($first: Int!, $before: Int64!) {
const compile = (query = document, row = "fragment Row on TaskFacts { title due }", clauses = "") =>
compileQuery(fixture(clauses), [collection, facts], async (name) => (name.endsWith("row.graphql") ? row : query));
test("live selections preserve aliases, nullable values, fragment conditions and wire identity", async () => {
const checked = await compile(
`query Upcoming($show: Boolean!) {root {items(first: 3) {entries {node {plain: title ...Row @include(if: $show)}}}}}`,
`fragment Row on TaskFacts {label: title @live due @live}`,
);
const fields = queryPresentation(checked, [collection, facts]);
assert.deepEqual(
fields.map((f) => f.path),
[
["root", "items", "entries", "*", "node", "label"],
["root", "items", "entries", "*", "node", "due"],
],
);
assert.equal(fields[0]!.getOperationId, "title:get");
assert.equal(fields[0]!.setOperationId, undefined);
assert.equal(fields[1]!.valueType.kind, "optional");
assert.equal(fields[0]!.conditions.length, 1);
assert.ok(JSON.stringify(checked.selection.map(querySelectionToWire)).includes(fields[0]!.selectionId));
const defaults = await compile(
`query Upcoming($show: Boolean! = true) {root {items(first: 3) {entries {node {...Row @include(if: $show)}}}}}`,
"fragment Row on TaskFacts {title @live}",
);
assert.equal(queryPresentation(defaults, [collection, facts])[0]!.conditions[0]!.defaultValue, true);
});
test("live selections reject RPC getters, synthetic selections and conflicting presentations", async () => {
for (const [selected, code] of [
["score @live", "QUERY_LIVE_UNSUPPORTED"],
["_qx @live {ref}", "QUERY_LIVE_UNSUPPORTED"],
["title @live title", "QUERY_LIVE_CONFLICT"],
["title @live(unchecked: true)", "QUERY_VALIDATION"],
])
await assert.rejects(
compile(
`query Upcoming {root {items(first: 3) {entries {node {...Row}}}}}`,
`fragment Row on TaskFacts {${selected}}`,
'allow TaskFacts.score select "bounded";',
),
(error: unknown) => error instanceof QueryCompileError && error.code === code,
);
});
test("query dependency ports resolve exact exports without declaration ordering constraints", () => {
const result = compileCapabilityResourceSource(
`import interface Tasks;