2026-09-21 11:23:26 -07:00
|
|
|
import assert from "node:assert/strict";
|
|
|
|
|
import { test } from "node:test";
|
|
|
|
|
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/index.js";
|
|
|
|
|
import {
|
|
|
|
|
compileExecutionPlan,
|
|
|
|
|
generateInterfaceClientBindings,
|
|
|
|
|
publicOperationContract,
|
|
|
|
|
linkInterfaceOperation,
|
|
|
|
|
publicQueryContract,
|
|
|
|
|
linkPackageQuery,
|
|
|
|
|
} from "../src/execution-world/index.js";
|
|
|
|
|
import { compileQuery } from "../src/query/compile.js";
|
|
|
|
|
import { parseControllerCatalog, validateControllers } from "../src/capability-model/controllers.js";
|
|
|
|
|
const source = { repository: "https://example.test/contracts.git", commit: "a".repeat(40) };
|
|
|
|
|
const parsed = compileCapabilityResourceSource(
|
|
|
|
|
`interface Data id "data" revision "data@1" {
|
2026-09-28 20:29:21 -07:00
|
|
|
queryable portable value label id "label" : string { get id "label:get" execution snapshot; }
|
2026-09-21 11:23:26 -07:00
|
|
|
operation publish id "publish" : string -> unit { call id "publish:call"; }
|
|
|
|
|
}`,
|
|
|
|
|
{ source },
|
|
|
|
|
);
|
|
|
|
|
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] };
|
2026-09-28 10:28:49 -07:00
|
|
|
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 {
|
2026-09-28 20:29:21 -07:00
|
|
|
get id "position:get" execution snapshot;
|
|
|
|
|
set id "position:set" execution transaction;
|
2026-09-28 10:28:49 -07:00
|
|
|
}
|
|
|
|
|
field remote id "remote" : string {
|
|
|
|
|
get id "remote:get";
|
|
|
|
|
set id "remote:set";
|
|
|
|
|
}
|
|
|
|
|
value arbitrary id "arbitrary" : string {
|
2026-09-28 20:29:21 -07:00
|
|
|
get id "arbitrary:get" execution snapshot;
|
|
|
|
|
set id "arbitrary:set" execution transaction;
|
2026-09-28 10:28:49 -07:00
|
|
|
}
|
|
|
|
|
value text id "text" : string {
|
|
|
|
|
get id "text:get";
|
2026-09-28 20:29:21 -07:00
|
|
|
edit id "text:edit" execution transaction;
|
2026-09-28 10:28:49 -07:00
|
|
|
}
|
|
|
|
|
}`,
|
|
|
|
|
{ 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(
|
2026-09-28 20:29:21 -07:00
|
|
|
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
|
|
|
|
package Setter id "setter" revision "setter@1" {
|
|
|
|
|
operation replaceValue id "write" : string -> unit mode call execution transaction targets [JavaScript,server] receiver any;
|
2026-09-28 10:28:49 -07:00
|
|
|
}`,
|
|
|
|
|
{ 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),
|
|
|
|
|
);
|
|
|
|
|
});
|
2026-09-21 11:23:26 -07:00
|
|
|
const compile = async () => {
|
|
|
|
|
const pkg = compileCapabilityResourceSource(
|
|
|
|
|
`import interface Data; package Views id "views" revision "views@1" {
|
|
|
|
|
query Labels id "labels" root workspace Data document "labels.graphql" operation "Labels" { replica; }
|
|
|
|
|
operation publish id "export:publish" : string -> unit mode call receiver any;
|
|
|
|
|
}`,
|
|
|
|
|
{ source, environment },
|
|
|
|
|
);
|
|
|
|
|
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
|
|
|
|
|
const revision = pkg.resource.revision;
|
|
|
|
|
revision.checkedQueries = [
|
|
|
|
|
await compileQuery(
|
|
|
|
|
revision.queries![0]!,
|
|
|
|
|
[iface],
|
|
|
|
|
async () => "query Labels { root { objects(first: 10) { entries { node { label } } } } }",
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
const result = compileCapabilitySource(
|
|
|
|
|
`workspace Test id "test" revision "test@1" commit "${source.commit}" {
|
|
|
|
|
import interface Data; import package Views;
|
|
|
|
|
atom One id "one"; atom Two id "two";
|
|
|
|
|
${["One", "Two"]
|
|
|
|
|
.map(
|
|
|
|
|
(atom) => `conform ${atom} as Data id "${atom}:data" {
|
|
|
|
|
private state ${atom}Label id "${atom}:label" on ${atom} : string policy register default "";
|
|
|
|
|
bind label.get to state ${atom}Label.read;
|
|
|
|
|
bind publish.call to package Views.publish;
|
|
|
|
|
}`,
|
|
|
|
|
)
|
|
|
|
|
.join("\n")}
|
|
|
|
|
}`,
|
|
|
|
|
"workspace.qx",
|
|
|
|
|
{ ...environment, packages: new Map([["Views", revision]]) },
|
|
|
|
|
);
|
|
|
|
|
assert.ok(result.ok, JSON.stringify(result.diagnostics));
|
|
|
|
|
return compileExecutionPlan(result.workspace);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
test("one imported operation contract links to two atom implementations without containing either", async () => {
|
|
|
|
|
const plan = await compile();
|
|
|
|
|
const contract = publicOperationContract(iface, iface.members[0]!.operations[0]!);
|
|
|
|
|
assert.equal(linkInterfaceOperation(plan, "one", contract).atomId, "one");
|
|
|
|
|
assert.equal(linkInterfaceOperation(plan, "two", contract).atomId, "two");
|
|
|
|
|
const generated = generateInterfaceClientBindings({ Data: iface });
|
2026-09-21 14:03:14 -07:00
|
|
|
assert.ok(generated.includes("defineInterfaceOperation<null, string,"));
|
2026-09-21 11:23:26 -07:00
|
|
|
for (const privateValue of [plan.digest, "One:label", '"atomId"', '"binding"'])
|
|
|
|
|
assert.equal(generated.includes(privateValue), false);
|
|
|
|
|
assert.throws(() => linkInterfaceOperation(plan, "absent", contract), /UNINSTALLED_OPERATION/);
|
|
|
|
|
for (const change of [{ scope: "class" }, { input: { kind: "string" } }, { execution: { kind: "remote" } }])
|
|
|
|
|
assert.throws(
|
|
|
|
|
() => linkInterfaceOperation(plan, "one", { ...contract, ...change } as typeof contract),
|
|
|
|
|
/CLIENT_CONTRACT_MISMATCH/,
|
|
|
|
|
);
|
|
|
|
|
assert.throws(() => linkInterfaceOperation({ ...plan, digest: "bad" }, "one", contract), /INVALID_PLAN/);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("package query handles bind the checked definition, placement and codecs", async () => {
|
|
|
|
|
const plan = await compile();
|
|
|
|
|
const contract = publicQueryContract(plan.definition.workspace.packageImports[0]!, "labels");
|
|
|
|
|
assert.equal(linkPackageQuery(plan, contract).query.checked.declaration.id, "labels");
|
|
|
|
|
for (const change of [{ placement: "local" }, { definitionDigest: "bad" }, { output: null }])
|
|
|
|
|
assert.throws(() => linkPackageQuery(plan, { ...contract, ...change } as typeof contract), /CLIENT_QUERY_MISMATCH/);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("controller templates check object capability effects and exact input mapping", () => {
|
|
|
|
|
const catalog = {
|
|
|
|
|
schemaVersion: 1,
|
|
|
|
|
controllers: [
|
|
|
|
|
{ id: "publish-label", subject: "data@1", snapshot: "label:get", remote: "publish:call", input: "value" },
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
assert.equal(parseControllerCatalog(JSON.stringify(catalog), [iface]).length, 1);
|
|
|
|
|
for (const change of [
|
|
|
|
|
{ input: "unit" },
|
|
|
|
|
{ input: "callback" },
|
|
|
|
|
{ subject: "missing" },
|
|
|
|
|
{ snapshot: "publish:call" },
|
|
|
|
|
{ remote: "label:get" },
|
|
|
|
|
{ url: "https://example.test" },
|
|
|
|
|
]) {
|
|
|
|
|
const invalid = { ...catalog, controllers: [{ ...catalog.controllers[0], ...change }] };
|
|
|
|
|
assert.throws(() => parseControllerCatalog(JSON.stringify(invalid), [iface]), /Controller|controller/);
|
|
|
|
|
}
|
|
|
|
|
assert.throws(
|
|
|
|
|
() =>
|
|
|
|
|
parseControllerCatalog(
|
|
|
|
|
JSON.stringify({ ...catalog, controllers: [...catalog.controllers, ...catalog.controllers] }),
|
|
|
|
|
[iface],
|
|
|
|
|
),
|
|
|
|
|
/unique/,
|
|
|
|
|
);
|
|
|
|
|
const classIface = structuredClone(iface);
|
|
|
|
|
classIface.members[1]!.operations[0]!.scope = "class";
|
|
|
|
|
assert.ok(
|
|
|
|
|
validateControllers(parseControllerCatalog(JSON.stringify(catalog), [iface]), [classIface], "controllers").length,
|
|
|
|
|
);
|
|
|
|
|
});
|