Generalize live field bindings and use them for Studio canvas gestures

This commit is contained in:
Timothy J. Aveni
2026-09-28 11:12:11 -07:00
parent 696023b4ba
commit 0ace71eae6
13 changed files with 1766 additions and 1586 deletions
+89
View File
@@ -22,6 +22,95 @@ const parsed = compileCapabilityResourceSource(
assert.ok(parsed.ok && parsed.resource.kind === "interface", JSON.stringify(parsed.diagnostics));
const iface = parsed.resource.revision;
const environment = { interfaces: new Map([["Data", iface]]), interfaceClosure: [iface] };
test("native fields certify one storage slot; only browser writes get live descriptors", () => {
const parsed = compileCapabilityResourceSource(
`interface Fields id "fields" revision "fields@1" {
queryable field position id "position" : string {
get id "position:get" execution snapshot targets [browser, server];
set id "position:set" execution transaction targets [browser, server];
}
field remote id "remote" : string {
get id "remote:get";
set id "remote:set";
}
value arbitrary id "arbitrary" : string {
get id "arbitrary:get" execution snapshot targets [browser,server];
set id "arbitrary:set" execution transaction targets [browser, server];
}
value text id "text" : string {
get id "text:get";
edit id "text:edit" execution transaction targets [browser, server];
}
}`,
{ source },
);
assert.ok(parsed.ok && parsed.resource.kind === "interface", JSON.stringify(parsed.diagnostics));
const revision = parsed.resource.revision;
const generated = generateInterfaceClientBindings({ Fields: revision });
assert.match(generated, /defineFieldOperation<string, "register",/);
assert.match(generated, /defineFieldOperation<string, "crdt",/);
for (const member of revision.members) {
const operation = member.operations.at(-1)!;
assert.equal(
publicOperationContract(revision, operation).fieldPolicy,
member.displayName === "position" ? "register" : member.displayName === "text" ? "crdt" : undefined,
);
}
const workspace = `workspace W id "w" revision "w@1" commit "${source.commit}" {
import interface Fields; atom A id "a";
conform A as Fields id "a:fields" {
private state First id "first" on A : string policy register default "";
private state Second id "second" on A : string policy register default "";
private state Text id "text" on A : string policy crdt(string);
initialize { text to state Text; };
bind position.get to state First.read;
bind position.set to state First.write;
bind remote.get to state Second.read;
bind remote.set to state Second.write;
bind arbitrary.get to state Second.read;
bind arbitrary.set to state Second.write;
bind text.get to state Text.read;
bind text.edit to state Text.edit;
}
}`;
const env = { interfaces: new Map([["Fields", revision]]) };
const good = compileCapabilitySource(workspace, "workspace.qx", env);
assert.ok(good.ok, JSON.stringify(good.diagnostics));
const bad = compileCapabilitySource(
workspace.replace("bind position.set to state First.write", "bind position.set to state Second.write"),
"workspace.qx",
env,
);
assert.equal(bad.ok, false);
assert.ok(
bad.diagnostics.some((d) => d.message.includes("same native state slot")),
JSON.stringify(bad.diagnostics),
);
const forwarded = workspace
.replace("bind position.get to state First.read", "bind position.get to interface Fields.arbitrary.get")
.replace("bind position.set to state First.write", "bind position.set to interface Fields.arbitrary.set");
const goodForward = compileCapabilitySource(forwarded, "workspace.qx", env);
assert.ok(goodForward.ok, JSON.stringify(goodForward.diagnostics));
const pkg = compileCapabilityResourceSource(
`package Setter id "setter" revision "setter@1" {
operation replaceValue id "write" : string -> unit mode call execution transaction targets [browser,server] receiver any;
}`,
{ source },
);
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
const badForward = compileCapabilitySource(
forwarded
.replace("import interface Fields;", "import interface Fields; import package Setter;")
.replace("bind arbitrary.set to state Second.write", "bind arbitrary.set to package Setter.replaceValue"),
"workspace.qx",
{ ...env, packages: new Map([["Setter", pkg.resource.revision]]) },
);
assert.equal(badForward.ok, false);
assert.ok(
badForward.diagnostics.some((d) => d.message.includes("same native state slot")),
JSON.stringify(badForward.diagnostics),
);
});
const compile = async () => {
const pkg = compileCapabilityResourceSource(
`import interface Data; package Views id "views" revision "views@1" {