Expose confirmed server projections through the typed replica client

This commit is contained in:
Timothy J. Aveni
2026-09-21 00:27:39 -07:00
parent 08e322e59f
commit b4ac9700c6
5 changed files with 77 additions and 10 deletions
+1
View File
@@ -82,4 +82,5 @@ revision "package:reader-runtime@1" {
query HighlightWindowList id "reader:highlight-window-list" root workspace HighlightData document "queries/highlight-list.graphql" operation "HighlightList" { view Comment as CommentData; local from HighlightWindow; max rows 200; watch; }
query HighlightEditorInputs id "reader:editor-inputs" root HighlightData document "queries/editor-inputs.graphql" operation "HighlightEditorInputs" { view Comment as CommentData; replica; max rows 1; }
query HighlightEditorView id "reader:editor-view" root HighlightData document "queries/editor-view.graphql" operation "HighlightEditorView" { view Comment as CommentData; local from HighlightEditorInputs; max rows 1; watch; }
query ConfirmedColor id "reader:confirmed-color" root HighlightData document "queries/confirmed-color.graphql" operation "ConfirmedColor" { view Comment as CommentData; max rows 1; watch; }
}
@@ -0,0 +1,3 @@
query ConfirmedColor {
root { color }
}
+1 -1
View File
@@ -8,7 +8,7 @@ test("complete reader contracts compose factories, portable selectors, CRDT edit
assert.equal(workspace.constructors.length, 0);
assert.equal(workspace.atoms.length, 3);
const linked = linkQueries(workspace);
assert.equal(linked.length, 8);
assert.equal(linked.length, 9);
assert.equal(linked.filter((q) => q.checked.declaration.placement?.kind === "local").length, 4);
const screen = linked.find((q) => q.checked.declaration.displayName === "ReaderScreen")!;
assert.ok(screen.fields.some((f) => f.memberId === "highlight:excerpt" && f.binding.kind === "package"));
+24
View File
@@ -79,3 +79,27 @@ test("a portable subset of a mixed interface excludes remote dependencies", asyn
selected.operations!.push(operation.id);
assert.throws(generate, /select a portable subset/);
});
test("server projection descriptors are distinct from canonical inputs and have result decoders", async () => {
const { generatePortableClientBindings } = await import("../src/bindings/portable-client.js");
const plan = compileExecutionPlan(await loadReaderWorkspace());
const source = generatePortableClientBindings(plan, { target: "browser" });
const projections = source.slice(
source.indexOf("export const serverProjections"),
source.indexOf("export const results"),
);
assert.match(projections, /ConfirmedColor/);
assert.match(projections, /satisfies ServerProjection/);
assert.match(source.slice(source.indexOf("export const results")), /ConfirmedColor/);
const live = compileExecutionPlan(
await loadReaderWorkspace((name, text) =>
name === "queries/confirmed-color.graphql" ? text.replace("color", "color @live") : text,
),
);
const rejected = generatePortableClientBindings(live, { target: "browser" });
assert.doesNotMatch(
rejected.slice(rejected.indexOf("export const serverProjections"), rejected.indexOf("export const results")),
/ConfirmedColor/,
);
assert.match(rejected, /QUERY_NOT_SNAPSHOT_PROJECTION/);
});