Make local graph execution optional across composed packages
This commit is contained in:
@@ -2,12 +2,13 @@ import assert from "node:assert/strict";
|
||||
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
|
||||
const contract = `interface Limit id "limit" revision "limit@1" {
|
||||
operation change id "change" : int32 -> unit {
|
||||
call id "change:call" execution transaction targets [browser, server];
|
||||
call id "change:call" execution transaction;
|
||||
}
|
||||
}`;
|
||||
export const runtime = `external atom Item id "item";
|
||||
export const runtime = `symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom Item id "item";
|
||||
package Runtime id "runtime" revision "runtime@1" {
|
||||
operation change id "runtime:change" : int32 -> unit mode call execution transaction targets [browser, server]
|
||||
operation change id "runtime:change" : int32 -> unit mode call execution transaction targets [JavaScript, server]
|
||||
receiver atom Item requires { state level id "write:value" : int32 [write]; } accept using check;
|
||||
operation check id "runtime:check" : int32 -> unit mode call execution snapshot targets [server]
|
||||
receiver atom Item requires {
|
||||
|
||||
@@ -28,9 +28,9 @@ test("acceptance syntax retains separate final-state ports through formatting, p
|
||||
]);
|
||||
assert.equal(kernel.packages[0]!.exports.find((e) => e.id === "runtime:change")!.acceptance, "runtime:check");
|
||||
assert.ok(
|
||||
!generatePortableTypeScriptBindings(plan.definition.bindingSchema, "runtime@1", { target: "browser" }).includes(
|
||||
'"runtime:check"',
|
||||
),
|
||||
!generatePortableTypeScriptBindings(plan.definition.bindingSchema, "runtime@1", {
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
}).includes('"runtime:check"'),
|
||||
);
|
||||
assert.ok(
|
||||
generatePortableTypeScriptBindings(plan.definition.bindingSchema, "runtime@1", { target: "server" }).includes(
|
||||
@@ -43,7 +43,7 @@ test("acceptance syntax retains separate final-state ports through formatting, p
|
||||
test("acceptance declarations reject wrong effects/signatures and missing or mutable ports", () => {
|
||||
for (const [pkg, ws] of [
|
||||
[runtime.replace("snapshot targets [server]", "transaction targets [server]"), workspace],
|
||||
[runtime.replace("snapshot targets [server]", "snapshot targets [browser, server]"), workspace],
|
||||
[runtime.replace("snapshot targets [server]", "snapshot targets [JavaScript, server]"), workspace],
|
||||
[
|
||||
runtime.replace('check id "runtime:check" : int32 -> unit', 'check id "runtime:check" : string -> unit'),
|
||||
workspace,
|
||||
|
||||
@@ -46,7 +46,9 @@ test("gateway serves only declared browser assets with correct Wasm MIME and con
|
||||
const plan = compileExecutionPlan(await loadReaderWorkspace()),
|
||||
fixture = buildArtifactFixture(plan);
|
||||
const wasm = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0]);
|
||||
const browser = fixture.manifest.implementations.find((i) => i.target === "browser")!;
|
||||
const browser = fixture.manifest.implementations.find(
|
||||
(i) => i.target === "target:org.quixos.execution.javascript@1",
|
||||
)!;
|
||||
browser.files.push({
|
||||
path: "portable/browser/assets/café.wasm",
|
||||
bytes: wasm.length,
|
||||
|
||||
@@ -13,7 +13,7 @@ export const buildArtifactFixture = (plan: ExecutionPlan, revision = plan.defini
|
||||
target: string,
|
||||
compatibility: ArtifactImplementation["compatibility"],
|
||||
): ArtifactImplementation => {
|
||||
const path = compatibility === "quixos-service-v1" ? "bin/service" : `portable/${target}/module.mjs`;
|
||||
const path = compatibility === "quixos-service-v1" ? "bin/service" : `portable/${id}/module.mjs`;
|
||||
const value = {
|
||||
id,
|
||||
target,
|
||||
@@ -44,7 +44,7 @@ export const buildArtifactFixture = (plan: ExecutionPlan, revision = plan.defini
|
||||
implementations: [
|
||||
implementation("service", "server", "quixos-service-v1"),
|
||||
implementation("server", "server", "quixos-js-module-v1"),
|
||||
implementation("browser", "browser", "quixos-js-module-v1"),
|
||||
implementation("browser", "target:org.quixos.execution.javascript@1", "quixos-js-module-v1"),
|
||||
],
|
||||
};
|
||||
return { manifest, bytes, read: async () => bytes };
|
||||
|
||||
@@ -229,7 +229,7 @@ test("resource-owned fragment imports compile through the locked package closure
|
||||
await writeFile(path.join(dirs.item!, "quixos.lock"), lock());
|
||||
await writeFile(
|
||||
path.join(dirs.item!, "interface.qx"),
|
||||
`interface Item id "item" revision "item@1" {queryable value title id "title" : string {get id "title:get" execution snapshot targets [browser,server];}}`,
|
||||
`interface Item id "item" revision "item@1" {queryable value title id "title" : string {get id "title:get" execution snapshot;}}`,
|
||||
);
|
||||
await writeFile(path.join(dirs.rows!, "quixos.lock"), lock(dependency("interface", "Item")));
|
||||
await writeFile(
|
||||
|
||||
@@ -14,7 +14,7 @@ import { parseControllerCatalog, validateControllers } from "../src/capability-m
|
||||
const source = { repository: "https://example.test/contracts.git", commit: "a".repeat(40) };
|
||||
const parsed = compileCapabilityResourceSource(
|
||||
`interface Data id "data" revision "data@1" {
|
||||
queryable portable value label id "label" : string { get id "label:get" execution snapshot targets [browser, server]; }
|
||||
queryable portable value label id "label" : string { get id "label:get" execution snapshot; }
|
||||
operation publish id "publish" : string -> unit { call id "publish:call"; }
|
||||
}`,
|
||||
{ source },
|
||||
@@ -26,20 +26,20 @@ test("native fields certify one storage slot; only browser writes get live descr
|
||||
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];
|
||||
get id "position:get" execution snapshot;
|
||||
set id "position:set" execution transaction;
|
||||
}
|
||||
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];
|
||||
get id "arbitrary:get" execution snapshot;
|
||||
set id "arbitrary:set" execution transaction;
|
||||
}
|
||||
value text id "text" : string {
|
||||
get id "text:get";
|
||||
edit id "text:edit" execution transaction targets [browser, server];
|
||||
edit id "text:edit" execution transaction;
|
||||
}
|
||||
}`,
|
||||
{ source },
|
||||
@@ -92,8 +92,9 @@ test("native fields certify one storage slot; only browser writes get live descr
|
||||
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;
|
||||
`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;
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
|
||||
@@ -52,7 +52,7 @@ test("checked component scaffolding composes with execution handlers without rep
|
||||
await apply("function", {
|
||||
name: "echo",
|
||||
id: "echo",
|
||||
declaration: 'function echo id "echo" : string -> string execution snapshot targets [browser,server];',
|
||||
declaration: 'function echo id "echo" : string -> string execution snapshot targets [JavaScript,server];',
|
||||
});
|
||||
await apply("component", {
|
||||
name: "Details",
|
||||
|
||||
@@ -24,7 +24,7 @@ test("compound captured changes survive planning, transport lowering and typed e
|
||||
]);
|
||||
assert.deepEqual(paths.find((op) => op.operation === "compound:content:edit")!.inputChanges, [[]]);
|
||||
const code = generatePortableTypeScriptBindings(plan.definition.bindingSchema, "compound:runtime@1", {
|
||||
target: "browser",
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
});
|
||||
assert.ok(code.includes("PreparedChange<"));
|
||||
assert.ok(code.includes('"edit"'));
|
||||
@@ -33,8 +33,9 @@ test("compound captured changes survive planning, transport lowering and typed e
|
||||
test("prepared changes require one storable materialized type", () => {
|
||||
for (const shape of ["change<string, bool>", "change<atom N>", "change<atom-ref<N>>", "change<change<string>>"]) {
|
||||
const result = compileCapabilityResourceSource(
|
||||
`external atom N id "n"; package P id "p" revision "p@1" {
|
||||
function f id "f" : ${shape} -> unit execution transaction targets [browser, server];
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom N id "n"; package P id "p" revision "p@1" {
|
||||
function f id "f" : ${shape} -> unit execution transaction targets [JavaScript, server];
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
|
||||
@@ -192,9 +192,9 @@ test("rule private edges substitute Self and captured endpoints with stable proj
|
||||
|
||||
test("rule creation ports close captured atom parameters and retain initialization checking", () => {
|
||||
const compile = fixture([
|
||||
'interface Factory<object T> id "factory" revision "factory@1" {operation create id "create" : unit -> ref<T> {call id "call" execution transaction targets [browser,server];}}',
|
||||
'interface Factory<object T> id "factory" revision "factory@1" {operation create id "create" : unit -> ref<T> {call id "call" execution transaction;}}',
|
||||
'interface Creates<object T> id "creates" revision "creates@1" {}',
|
||||
'package Runtime id "runtime" revision "runtime@1" {operation create<object T> id "create" : unit -> ref<T> mode call execution transaction targets [browser,server] receiver any requires {creation result id "result" : T input unit;};}',
|
||||
'symbol JavaScript id "target:org.quixos.execution.javascript@1";\npackage Runtime id "runtime" revision "runtime@1" {operation create<object T> id "create" : unit -> ref<T> mode call execution transaction targets [JavaScript,server] receiver any requires {creation result id "result" : T input unit;};}',
|
||||
]);
|
||||
const rule = `conform<object T> Creates<T> as Factory<T> id "factory-rule" {
|
||||
bind create.call to package Runtime.create<T> with {result to creation T with {};};
|
||||
@@ -324,7 +324,7 @@ test("rule inverse reads retain the concrete conformance ownership checks", () =
|
||||
const compile = fixture([
|
||||
'interface Parent id "parent" revision "parent@1" {}',
|
||||
'interface Child id "child" revision "child@1" {}',
|
||||
'import interface Parent; interface Owned id "owned" revision "owned@1" {queryable relation parent id "parent-ref" : optional-one interface Parent {resolve id "parent-read" execution snapshot targets [browser,server];}}',
|
||||
'import interface Parent; interface Owned id "owned" revision "owned@1" {queryable relation parent id "parent-ref" : optional-one interface Parent {resolve id "parent-read" execution snapshot;}}',
|
||||
]);
|
||||
const source = `
|
||||
atom P id "p"; atom C id "c";
|
||||
|
||||
@@ -6,8 +6,8 @@ const content = "record { text:string; tags:list<string>; }";
|
||||
const iface = compileCapabilityResourceSource(
|
||||
`interface Comment id "comment" revision "comment@1" {
|
||||
value content id "content" : ${content} {
|
||||
get id "content:get" execution snapshot targets [browser, server];
|
||||
edit id "content:edit" execution transaction targets [browser, server];
|
||||
get id "content:get" execution snapshot;
|
||||
edit id "content:edit" execution transaction;
|
||||
}
|
||||
}`,
|
||||
{ source },
|
||||
@@ -68,7 +68,7 @@ test("authored prepared changes retain their materialized type as transport valu
|
||||
test("generic edit retains its materialized type through specialization", () => {
|
||||
const generic = compileCapabilityResourceSource(
|
||||
`interface Cell<value T : storable> id "cell" revision "cell@1" {
|
||||
value content id "content" : T { get id "get"; edit id "edit" execution transaction targets [browser, server]; }
|
||||
value content id "content" : T { get id "get"; edit id "edit" execution transaction; }
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
|
||||
@@ -14,23 +14,24 @@ const iface = (text: string): InterfaceRevision => {
|
||||
return result.resource.revision;
|
||||
};
|
||||
const data = iface(`interface Data id "data" revision "data@1" {
|
||||
value title id "title" : string { get id "title:get" execution snapshot targets [browser, server]; }
|
||||
value title id "title" : string { get id "title:get" execution snapshot; }
|
||||
}`);
|
||||
const tagged = iface(`interface Tagged id "tagged" revision "tagged@1" {
|
||||
value tags id "tags" : list<string> { get id "tags:get" execution snapshot targets [browser, server]; }
|
||||
value tags id "tags" : list<string> { get id "tags:get" execution snapshot; }
|
||||
}`);
|
||||
const factory = iface(`external atom Note id "note";
|
||||
interface Factory id "factory" revision "factory@1" {
|
||||
static operation create id "create" : ${seed} -> atom-ref<Note> { call id "create:call" execution transaction targets [browser, server]; }
|
||||
static operation importNote id "import" : ${seed} -> atom-ref<Note> { call id "import:call" execution transaction targets [browser, server]; }
|
||||
static operation create id "create" : ${seed} -> atom-ref<Note> { call id "create:call" execution transaction; }
|
||||
static operation importNote id "import" : ${seed} -> atom-ref<Note> { call id "import:call" execution transaction; }
|
||||
}`);
|
||||
const runtime = compileCapabilityResourceSource(
|
||||
`external atom Note id "note";
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom Note id "note";
|
||||
package Runtime id "runtime" revision "runtime@1" {
|
||||
function createNote id "create-note" : ${seed} -> atom-ref<Note> execution transaction targets [browser, server] requires {
|
||||
function createNote id "create-note" : ${seed} -> atom-ref<Note> execution transaction targets [JavaScript, server] requires {
|
||||
creation note id "new-note" : Note input ${seed};
|
||||
};
|
||||
function importNote id "import-note" : ${seed} -> atom-ref<Note> execution transaction targets [browser, server] requires {
|
||||
function importNote id "import-note" : ${seed} -> atom-ref<Note> execution transaction targets [JavaScript, server] requires {
|
||||
creation note id "new-note" : Note input ${seed};
|
||||
};
|
||||
}`,
|
||||
@@ -137,9 +138,10 @@ test("defaults supply unmapped state and seeds cannot invoke an undeclared owner
|
||||
|
||||
test("creation ports cannot be used in snapshot execution", () => {
|
||||
const result = compileCapabilityResourceSource(
|
||||
`external atom Note id "note";
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom Note id "note";
|
||||
package P id "p" revision "p@1" {
|
||||
function createNote id "create" : unit -> atom-ref<Note> execution snapshot targets [browser, server] requires {
|
||||
function createNote id "create" : unit -> atom-ref<Note> execution snapshot targets [JavaScript, server] requires {
|
||||
creation note id "note" : Note input record { title:string; };
|
||||
};
|
||||
}`,
|
||||
|
||||
+16
-14
@@ -15,7 +15,7 @@ const factory = compileCapabilityResourceSource(
|
||||
`external atom Entry id "atom:entry";
|
||||
interface EntryFactory id "interface:entry-factory" revision "interface:entry-factory@1" {
|
||||
static operation create id "entry:create" : unit -> atom-ref<Entry> {
|
||||
call id "entry:create:call" execution transaction targets [server];
|
||||
call id "entry:create:call" execution transaction;
|
||||
}
|
||||
}`,
|
||||
{ source },
|
||||
@@ -23,12 +23,12 @@ interface EntryFactory id "interface:entry-factory" revision "interface:entry-fa
|
||||
assert.ok(factory.ok && factory.resource.kind === "interface", JSON.stringify(factory.diagnostics));
|
||||
const data = compileCapabilityResourceSource(
|
||||
`interface Data id "interface:data" revision "interface:data@1" {
|
||||
queryable value body id "body" : string { get id "body:get" execution snapshot targets [browser, server]; edit id "body:edit" execution transaction targets [browser, server]; }
|
||||
queryable value notes id "notes" : string { get id "notes:get" execution snapshot targets [browser, server]; edit id "notes:edit" execution transaction targets [browser, server]; }
|
||||
operation revise id "revise" : record {body:change<string>; notes:change<string>; reject:bool;} -> unit {call id "revise:call" execution transaction targets [browser, server];}
|
||||
queryable value body id "body" : string { get id "body:get" execution snapshot; edit id "body:edit" execution transaction; }
|
||||
queryable value notes id "notes" : string { get id "notes:get" execution snapshot; edit id "notes:edit" execution transaction; }
|
||||
operation revise id "revise" : record {body:change<string>; notes:change<string>; reject:bool;} -> unit {call id "revise:call" execution transaction;}
|
||||
queryable value label id "label" : string {
|
||||
get id "label:get" execution snapshot targets [browser, server];
|
||||
set id "label:set" execution transaction targets [browser, server];
|
||||
get id "label:get" execution snapshot;
|
||||
set id "label:set" execution transaction;
|
||||
}
|
||||
}`,
|
||||
{ source },
|
||||
@@ -36,8 +36,8 @@ const data = compileCapabilityResourceSource(
|
||||
const constructors = compileCapabilityResourceSource(
|
||||
`external atom Entry id "atom:entry"; external atom Independent id "atom:independent";
|
||||
interface Factories id "interface:factories" revision "interface:factories@1" {
|
||||
static operation createOne id "create-one" : string -> atom-ref<Entry> { call id "create-one:call" execution transaction targets [browser, server]; }
|
||||
static operation createTwo id "create-two" : unit -> atom-ref<Independent> { call id "create-two:call" execution transaction targets [browser, server]; }
|
||||
static operation createOne id "create-one" : string -> atom-ref<Entry> { call id "create-one:call" execution transaction; }
|
||||
static operation createTwo id "create-two" : unit -> atom-ref<Independent> { call id "create-two:call" execution transaction; }
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
@@ -70,7 +70,8 @@ for (const variant of ["base", "added", "gateway", "gateway-next", "session"]) {
|
||||
gateway = session || variant.startsWith("gateway"),
|
||||
commit = { base: "a", added: "b", gateway: "c", "gateway-next": "d", session: "e" }[variant]!.repeat(40);
|
||||
const pkg = compileCapabilityResourceSource(
|
||||
`${gateway ? 'external atom Entry id "atom:entry";' : ""}
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
${gateway ? 'external atom Entry id "atom:entry";' : ""}
|
||||
${session ? 'external atom Independent id "atom:independent"; import interface Data; import interface View;' : ""}
|
||||
package Owner id "package:owner" revision "package:owner@1" {
|
||||
function identity id "identity" : int32 -> record { pid: int32; child: int32; } execution remote;
|
||||
@@ -78,9 +79,9 @@ package Owner id "package:owner" revision "package:owner@1" {
|
||||
${
|
||||
session
|
||||
? `module Editor id "component:owner-editor" implements View.render;
|
||||
function createOne id "create-one" : string -> atom-ref<Entry> execution transaction targets [browser, server] requires { creation entry id "one:birth" : Entry input unit; };
|
||||
function createTwo id "create-two" : unit -> atom-ref<Independent> execution transaction targets [browser, server] requires { creation entry id "two:birth" : Independent input unit; };
|
||||
operation revise id "revise" : record {body:change<string>; notes:change<string>; reject:bool;} -> unit mode call execution transaction targets [browser, server] receiver any requires {
|
||||
function createOne id "create-one" : string -> atom-ref<Entry> execution transaction targets [JavaScript, server] requires { creation entry id "one:birth" : Entry input unit; };
|
||||
function createTwo id "create-two" : unit -> atom-ref<Independent> execution transaction targets [JavaScript, server] requires { creation entry id "two:birth" : Independent input unit; };
|
||||
operation revise id "revise" : record {body:change<string>; notes:change<string>; reject:bool;} -> unit mode call execution transaction targets [JavaScript, server] receiver any requires {
|
||||
state body id "revise:body" : string [edit]; state notes id "revise:notes" : string [edit];
|
||||
};
|
||||
query Inputs id "inputs" root workspace Data document "inputs.graphql" operation "Inputs" { replica; }
|
||||
@@ -202,9 +203,10 @@ await import("./emit-controllers.js");
|
||||
// Standalone public builder roots must work without opting into the other modes.
|
||||
for (const kind of ["portable", "service"]) {
|
||||
const pkg = compileCapabilityResourceSource(
|
||||
`package Owner id "package:owner" revision "package:owner@1" {
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
package Owner id "package:owner" revision "package:owner@1" {
|
||||
function identity id "identity" : int32 -> record {pid:int32;child:int32;}
|
||||
execution ${kind === "portable" ? "snapshot targets [browser,server]" : "remote"};
|
||||
execution ${kind === "portable" ? "snapshot targets [JavaScript,server]" : "remote"};
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
|
||||
@@ -7,17 +7,21 @@ import { compileExecutionPlan } from "../src/execution-world/plan.js";
|
||||
import { generatePortableTypeScriptBindings } from "../src/bindings/portable.js";
|
||||
import { generatePortableClientBindings } from "../src/bindings/portable-client.js";
|
||||
import { loadCompositeWorkspace } from "./composite-fixture.js";
|
||||
import { javascriptTarget } from "../src/execution-world/native-backends.js";
|
||||
const executionTarget = (lane: string) => (lane === "browser" ? javascriptTarget : lane);
|
||||
const plan = compileExecutionPlan(await loadReaderWorkspace());
|
||||
await mkdir("dist/portable-reader", { recursive: true });
|
||||
for (const target of ["browser", "server"])
|
||||
await writeFile(
|
||||
`dist/portable-reader/${target}.ts`,
|
||||
generatePortableTypeScriptBindings(plan.definition.bindingSchema, "package:reader-runtime@1", { target }),
|
||||
generatePortableTypeScriptBindings(plan.definition.bindingSchema, "package:reader-runtime@1", {
|
||||
target: executionTarget(target),
|
||||
}),
|
||||
);
|
||||
await writeFile("dist/portable-reader/plan.json", JSON.stringify(plan));
|
||||
await writeFile("dist/portable-reader/kernel.json", JSON.stringify(compileKernelProgram(plan)));
|
||||
await writeFile("dist/portable-reader/queries.json", JSON.stringify(compileQueryProgram(plan)));
|
||||
await writeFile("dist/portable-reader/client.ts", generatePortableClientBindings(plan, { target: "browser" }));
|
||||
await writeFile("dist/portable-reader/client.ts", generatePortableClientBindings(plan, { target: javascriptTarget }));
|
||||
const serviceWorkspace = structuredClone(plan.definition.workspace);
|
||||
serviceWorkspace.atoms = [];
|
||||
serviceWorkspace.conformances = [];
|
||||
@@ -49,7 +53,9 @@ for (const target of ["browser", "server"])
|
||||
] as const)
|
||||
await writeFile(
|
||||
`dist/portable-reader/composite/${name}-${target}.ts`,
|
||||
generatePortableTypeScriptBindings(composite.definition.bindingSchema, revision, { target }),
|
||||
generatePortableTypeScriptBindings(composite.definition.bindingSchema, revision, {
|
||||
target: executionTarget(target),
|
||||
}),
|
||||
);
|
||||
|
||||
const { portableGenericPlan } = await import("./portable-generic-fixture.js");
|
||||
@@ -59,7 +65,9 @@ await mkdir("dist/portable-reader/generic", { recursive: true });
|
||||
for (const target of ["browser", "server"]) {
|
||||
await writeFile(
|
||||
`dist/portable-reader/generic/${target}.ts`,
|
||||
generatePortableTypeScriptBindings(generic.definition.bindingSchema, genericPackage.revisionId, { target }),
|
||||
generatePortableTypeScriptBindings(generic.definition.bindingSchema, genericPackage.revisionId, {
|
||||
target: executionTarget(target),
|
||||
}),
|
||||
);
|
||||
}
|
||||
const stringEntry = genericPackage.exports.find((e) => e.inputType.kind === "scalar")!;
|
||||
@@ -141,7 +149,7 @@ await writeFile(
|
||||
await writeFile(
|
||||
"dist/portable-reader/presentation-mount/browser.ts",
|
||||
generatePortableTypeScriptBindings(presentationMount.definition.bindingSchema, "presentation-runtime@1", {
|
||||
target: "browser",
|
||||
target: javascriptTarget,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { test } from "node:test";
|
||||
import { compileCapabilityResourceSource } from "../src/capability-language/index.js";
|
||||
|
||||
const source = { repository: "https://example.test/execution.git", commit: "a".repeat(40) };
|
||||
const data = (execution = "snapshot targets [browser, server]") =>
|
||||
const data = (execution = "snapshot") =>
|
||||
compileCapabilityResourceSource(
|
||||
`
|
||||
interface Data id "interface:data" revision "interface:data@1" {
|
||||
@@ -14,13 +14,14 @@ interface Data id "interface:data" revision "interface:data@1" {
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
const program = (selection: string, execution = "snapshot targets [browser, server]") => {
|
||||
const program = (selection: string, execution = "snapshot targets [JavaScript, server]") => {
|
||||
const contract = data();
|
||||
assert.ok(contract.ok, JSON.stringify(contract.diagnostics));
|
||||
assert.equal(contract.resource.kind, "interface");
|
||||
if (contract.resource.kind !== "interface") throw new Error("Expected interface");
|
||||
return compileCapabilityResourceSource(
|
||||
`
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
|
||||
import interface Data;
|
||||
package Reader id "package:reader" revision "package:reader@1" {
|
||||
function label id "export:label" : unit -> string execution ${execution} requires {
|
||||
@@ -43,7 +44,10 @@ test("portable contracts preserve exact selected operations and targets", () =>
|
||||
assert.equal(result.resource.kind, "package");
|
||||
if (result.resource.kind !== "package") return;
|
||||
const entry = result.resource.revision.exports[0]!;
|
||||
assert.deepEqual(entry.execution, { kind: "snapshot", targets: ["browser", "server"] });
|
||||
assert.deepEqual(entry.execution, {
|
||||
kind: "snapshot",
|
||||
targets: ["target:org.quixos.execution.javascript@1", "server"],
|
||||
});
|
||||
assert.deepEqual(entry.dependencyPorts[0]!.requirement, {
|
||||
kind: "interface",
|
||||
interfaceRevisionId: "interface:data@1",
|
||||
@@ -53,10 +57,10 @@ test("portable contracts preserve exact selected operations and targets", () =>
|
||||
|
||||
test("portable dependency diagnostics reject remote defaults and broad acquisition", () => {
|
||||
for (const [selection, execution, message] of [
|
||||
["using [refresh.call]", "snapshot targets [browser]", "remote-only"],
|
||||
["", "snapshot targets [browser]", "select"],
|
||||
["using [label.get, label.get]", "snapshot targets [browser]", "duplicates"],
|
||||
["using [label.set]", "snapshot targets [browser]", "Unknown"],
|
||||
["using [refresh.call]", "snapshot targets [JavaScript, server]", "remote-only"],
|
||||
["", "snapshot targets [JavaScript, server]", "select"],
|
||||
["using [label.get, label.get]", "snapshot targets [JavaScript, server]", "duplicates"],
|
||||
["using [label.set]", "snapshot targets [JavaScript, server]", "Unknown"],
|
||||
]) {
|
||||
const result = program(selection!, execution);
|
||||
assert.equal(result.ok, false);
|
||||
@@ -64,11 +68,26 @@ test("portable dependency diagnostics reject remote defaults and broad acquisiti
|
||||
}
|
||||
});
|
||||
|
||||
test("package code targets may exceed a dependency's public minimum", () => {
|
||||
test("execution targets must resolve nominal declarations", () => {
|
||||
const result = program("using [label.get]", "snapshot targets [arduino]");
|
||||
assert.ok(result.ok, JSON.stringify(result.diagnostics));
|
||||
// A workspace still has to provide the full installed closure before an
|
||||
// operation can promise this target; package code alone is insufficient.
|
||||
assert.equal(result.ok, false);
|
||||
assert.match(JSON.stringify(result.diagnostics), /Unknown nominal execution target arduino/);
|
||||
});
|
||||
|
||||
test("nominal targets are identified by symbols rather than platform spellings or interfaces", () => {
|
||||
const compile = (alias: string, identity: string) =>
|
||||
compileCapabilityResourceSource(
|
||||
`symbol ${alias} id "${identity}"; package P id "p" revision "p@1" { function f id "f" : unit -> unit execution transaction targets [${alias},server]; }`,
|
||||
{ source },
|
||||
);
|
||||
const device = compile("ESP32", "target:example.device@1");
|
||||
const renamed = compile("MyController", "target:example.device@1");
|
||||
assert.ok(device.ok && device.resource.kind === "package");
|
||||
assert.ok(renamed.ok && renamed.resource.kind === "package");
|
||||
assert.deepEqual(device.resource.revision.exports[0]!.execution, renamed.resource.revision.exports[0]!.execution);
|
||||
assert.deepEqual(device.resource.externalInterfaces, [], "A target identity has no interface definition dependency");
|
||||
assert.equal(compile("server", "target:example.device@1").ok, false);
|
||||
assert.equal(compile("Alias", "server").ok, false);
|
||||
});
|
||||
|
||||
test("portable query getters and target declarations are checked", () => {
|
||||
@@ -80,9 +99,10 @@ test("portable query getters and target declarations are checked", () => {
|
||||
test("snapshot exports reject mutable state ports but transactions admit them", () => {
|
||||
const compile = (effect: string) =>
|
||||
compileCapabilityResourceSource(
|
||||
`
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
|
||||
package Reader id "package:reader" revision "package:reader@1" {
|
||||
function update id "export:update" : string -> unit execution ${effect} targets [browser, server] requires {
|
||||
function update id "export:update" : string -> unit execution ${effect} targets [JavaScript, server] requires {
|
||||
state storage id "port:value" : string [read, write];
|
||||
};
|
||||
}`,
|
||||
@@ -137,7 +157,7 @@ package Reader id "package:reader" revision "package:reader@1" {
|
||||
delete remote.members[0]!.operations[0]!.execution;
|
||||
await assert.rejects(
|
||||
compileQuery(local, [remote], async () => document("Presentation", "availableObjects")),
|
||||
/browser snapshot getter/,
|
||||
/graph snapshot getter/,
|
||||
);
|
||||
const { capabilityId } = await import("../src/capability-model/index.js");
|
||||
const linked = linkQueries({
|
||||
@@ -200,15 +220,16 @@ test("generic selected ports preserve operation identities and execution through
|
||||
const { specializePackageExport, capabilityId } = await import("../src/capability-model/index.js");
|
||||
const iface = compileCapabilityResourceSource(
|
||||
`interface Cell<value T> id "cell" revision "cell@1" {
|
||||
value content id "content" : T { get id "content:get" execution snapshot targets [browser, server]; }
|
||||
value content id "content" : T { get id "content:get" execution snapshot; }
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
assert.ok(iface.ok && iface.resource.kind === "interface", JSON.stringify(iface.diagnostics));
|
||||
const pkg = compileCapabilityResourceSource(
|
||||
`import interface Cell;
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
import interface Cell;
|
||||
package P id "p" revision "p@1" {
|
||||
function load<value T> id "read" : unit -> T execution snapshot targets [browser, server] requires {
|
||||
function load<value T> id "read" : unit -> T execution snapshot targets [JavaScript, server] requires {
|
||||
interface cell id "cell" : Cell<T> using [content.get];
|
||||
};
|
||||
}`,
|
||||
@@ -236,7 +257,10 @@ test("generic selected ports preserve operation identities and execution through
|
||||
implementsInterface: () => false,
|
||||
},
|
||||
);
|
||||
assert.deepEqual(specialized.execution, { kind: "snapshot", targets: ["browser", "server"] });
|
||||
assert.deepEqual(specialized.execution, {
|
||||
kind: "snapshot",
|
||||
targets: ["target:org.quixos.execution.javascript@1", "server"],
|
||||
});
|
||||
assert.deepEqual(specialized.dependencyPorts[0]!.requirement.kind, "interface");
|
||||
const requirement = specialized.dependencyPorts[0]!.requirement;
|
||||
if (requirement.kind === "interface")
|
||||
|
||||
@@ -88,7 +88,7 @@ test("outbound provider changes invalidate consumers while caller changes preser
|
||||
mode: "call",
|
||||
inputType: { kind: "builtin", name: "unit" },
|
||||
outputType: { kind: "scalar", name: "string" },
|
||||
execution: { kind: "snapshot", targets: ["browser", "server"] },
|
||||
execution: { kind: "snapshot", targets: ["target:org.quixos.execution.javascript@1", "server"] },
|
||||
receiverRequirement: { kind: "exact-atom", atomId: id.atom("atom:reader:document") },
|
||||
dependencyPorts: [
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function emitExecutionScaffold(root: string) {
|
||||
tools: { quixos: source, protocol: source, helpers: source, sdk: source },
|
||||
});
|
||||
for (const [name, execution] of [
|
||||
["echo", "snapshot targets [browser, server]"],
|
||||
["echo", "snapshot targets [JavaScript, server]"],
|
||||
["serverEcho", "snapshot targets [server]"],
|
||||
["remoteEcho", "remote"],
|
||||
]) {
|
||||
|
||||
@@ -17,23 +17,63 @@ import {
|
||||
|
||||
import { buildArtifactFixture as buildFixture } from "./artifact-fixture.js";
|
||||
import { compileKernelProgram } from "../src/execution-world/kernel.js";
|
||||
import { loadCompositeWorkspace } from "./composite-fixture.js";
|
||||
import { standardNativeBackends } from "../src/execution-world/native-backends.js";
|
||||
|
||||
test("optional targets close over calls into another package", async () => {
|
||||
const workspace = await loadCompositeWorkspace();
|
||||
const before = compileExecutionPlan(workspace).definition.operations.find(
|
||||
(op) => op.operationId === "document:annotate:call",
|
||||
)!;
|
||||
assert.ok(before, "fixture exposes the composed add-highlight operation");
|
||||
assert.equal(before.availableTargets.length, 2);
|
||||
workspace.packageImports.find((pkg) => pkg.revisionId === "package:comment-runtime@1")!.exports[0]!.execution = {
|
||||
kind: "transaction",
|
||||
targets: ["server"],
|
||||
};
|
||||
const after = compileExecutionPlan(workspace).definition.operations.find((op) => op.key === before.key)!;
|
||||
assert.deepEqual(after.availableTargets, ["server"]);
|
||||
assert.deepEqual(after.execution, before.execution);
|
||||
});
|
||||
|
||||
test("native support can be supplied for a nominal device target without platform syntax", async () => {
|
||||
const workspace = await loadReaderWorkspace();
|
||||
const target = "interface:example.esp32@1";
|
||||
for (const pkg of workspace.packageImports)
|
||||
for (const entry of pkg.exports) {
|
||||
if (entry.execution && entry.execution.kind !== "remote") entry.execution.targets.push(target);
|
||||
}
|
||||
const plan = compileExecutionPlan(workspace, [
|
||||
...standardNativeBackends,
|
||||
{ target, supports: (binding) => binding.kind === "state" || binding.kind === "edge" },
|
||||
]);
|
||||
assert.ok(
|
||||
plan.definition.operations
|
||||
.filter((op) => op.binding.kind === "state")
|
||||
.every((op) => op.availableTargets.includes(target)),
|
||||
);
|
||||
assert.ok(
|
||||
plan.definition.operations.some((op) => op.binding.kind === "package" && op.availableTargets.includes(target)),
|
||||
);
|
||||
});
|
||||
const resign = (implementation: ArtifactImplementation) => {
|
||||
const { contentDigest, ...body } = implementation;
|
||||
implementation.contentDigest = implementationDigest(body);
|
||||
};
|
||||
|
||||
test("installed targets can exceed the public requirement without changing that contract", async () => {
|
||||
const workspace = await loadReaderWorkspace((name, text) =>
|
||||
name === "DocumentFactory.qx" ? text.replaceAll("targets [browser, server]", "targets [server]") : text,
|
||||
);
|
||||
test("installed targets are implementation properties; authoritative fallback preserves the interface", async () => {
|
||||
const workspace = await loadReaderWorkspace();
|
||||
const plan = compileExecutionPlan(workspace);
|
||||
const factory = plan.definition.operations.find(
|
||||
(op) => op.binding.kind === "package" && op.binding.exportId === "reader:create-document",
|
||||
)!;
|
||||
assert.deepEqual(factory.execution, { kind: "transaction", targets: ["server"] });
|
||||
assert.deepEqual(factory.availableTargets, ["browser", "server"]);
|
||||
assert.deepEqual(factory.availableTargets, ["server", "target:org.quixos.execution.javascript@1"]);
|
||||
const kernel = compileKernelProgram(plan) as { operations: { key: string; targets: string[] }[] };
|
||||
assert.deepEqual(kernel.operations.find((op) => op.key === factory.key)!.targets, ["browser", "server"]);
|
||||
assert.deepEqual(kernel.operations.find((op) => op.key === factory.key)!.targets, [
|
||||
"server",
|
||||
"target:org.quixos.execution.javascript@1",
|
||||
]);
|
||||
|
||||
const provider = workspace.packageImports
|
||||
.flatMap((pkg) => pkg.exports)
|
||||
@@ -102,8 +142,8 @@ test("artifact closure checks bytes, exact source/schema, ABI, exports and targe
|
||||
(m.versions as unknown as Record<string, string>).value = "v2";
|
||||
}, /Incompatible runtime codecs/);
|
||||
await negative((m) => {
|
||||
m.implementations = m.implementations.filter((i) => i.target !== "browser");
|
||||
}, /Missing browser implementation/);
|
||||
m.implementations = m.implementations.filter((i) => i.target !== "target:org.quixos.execution.javascript@1");
|
||||
}, /Missing target:org.quixos.execution.javascript@1 implementation/);
|
||||
await negative((m) => {
|
||||
m.implementations = m.implementations.filter((i) => i.compatibility !== "quixos-service-v1");
|
||||
}, /Missing service fallback/);
|
||||
@@ -211,7 +251,7 @@ test("closed generic applications retain distinct identities and codec shapes",
|
||||
const source = { repository: "https://example.test/generic.git", commit: "a".repeat(40) };
|
||||
const definition = compileCapabilityResourceSource(
|
||||
`interface Cell<value V : storable> id "cell" revision "cell@1" {
|
||||
value content id "value" : V { get id "get" execution snapshot targets [browser, server]; }
|
||||
value content id "value" : V { get id "get" execution snapshot; }
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
@@ -269,11 +309,10 @@ test("query dependencies propagate target requirements through selected getters"
|
||||
binding: { kind: "query", packageRevisionId: pkg.revisionId, queryId: query.id, scope: "workspace" },
|
||||
});
|
||||
compileExecutionPlan(workspace);
|
||||
const field = workspace.interfaceImports
|
||||
.find((i) => i.displayName === "HighlightData")!
|
||||
.members.find((m) => m.displayName === "color")!;
|
||||
field.operations.find((o) => o.displayName === "get")!.execution = { kind: "snapshot", targets: ["browser"] };
|
||||
assert.throws(() => compileExecutionPlan(workspace), /MISSING_EXECUTION_TARGET.*test:selector-query.*server/);
|
||||
// Package artifact support is checked over the composed graph; an interface
|
||||
// declaration cannot manufacture an authoritative implementation.
|
||||
entry.execution = { kind: "snapshot", targets: ["target:org.quixos.execution.javascript@1"] };
|
||||
assert.throws(() => compileExecutionPlan(workspace), /MISSING_SERVER_IMPLEMENTATION/);
|
||||
});
|
||||
|
||||
test("implementation selection is explicit, target checked and independent of manifest order", async () => {
|
||||
@@ -281,7 +320,7 @@ test("implementation selection is explicit, target checked and independent of ma
|
||||
const plan = compileExecutionPlan(await loadReaderWorkspace());
|
||||
const { manifest, read } = buildFixture(plan);
|
||||
const selection = {
|
||||
target: "browser",
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
compatibility: "quixos-js-module-v1" as const,
|
||||
exports: [manifest.implementations[0]!.exports[0]!],
|
||||
};
|
||||
|
||||
+6
-6
@@ -1,17 +1,17 @@
|
||||
type Summary = record { text: string; basedOn: string; };
|
||||
interface DocumentData id "async:document-data" revision "async:document-data@1" {
|
||||
queryable value content id "async:content" : string {
|
||||
get id "async:content:get" execution snapshot targets [browser, server];
|
||||
get id "async:content:get" execution snapshot;
|
||||
}
|
||||
queryable value summary id "async:summary" : Summary {
|
||||
get id "async:summary:get" execution snapshot targets [browser, server];
|
||||
set id "async:summary:set" execution transaction targets [browser, server];
|
||||
get id "async:summary:get" execution snapshot;
|
||||
set id "async:summary:set" execution transaction;
|
||||
}
|
||||
queryable value pendingJob id "async:pending-job" : optional<record { operationId: string; }> {
|
||||
get id "async:pending-job:get" execution snapshot targets [server];
|
||||
set id "async:pending-job:set" execution transaction targets [server];
|
||||
get id "async:pending-job:get" execution snapshot;
|
||||
set id "async:pending-job:set" execution transaction;
|
||||
}
|
||||
operation recordSummary id "async:record-summary" : record { operationId: string; summary: Summary; } -> unit {
|
||||
call id "async:record-summary:call" execution transaction targets [server];
|
||||
call id "async:record-summary:call" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -6,7 +6,7 @@ type Entry = variant id "canvas:entry@1" {
|
||||
};
|
||||
interface CanvasContent id "canvas" revision "canvas@1" {
|
||||
queryable value entries id "entries" : list<Entry> {
|
||||
get id "entries:get" execution snapshot targets [browser,server];
|
||||
edit id "entries:edit" execution transaction targets [browser,server];
|
||||
get id "entries:get" execution snapshot;
|
||||
edit id "entries:edit" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,17 +1,18 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
type Replacement = record { expected: list<string>; targets: list<atom-ref<Node>>; };
|
||||
type Seed = record { label: string; };
|
||||
external atom Node id "collection:node";
|
||||
package CollectionRuntime id "collection:runtime" revision "collection:runtime@1" {
|
||||
operation version id "collection:runtime:version" : unit -> list<string>
|
||||
mode call execution snapshot targets [browser, server] receiver atom Node requires {
|
||||
mode call execution snapshot targets [JavaScript, server] receiver atom Node requires {
|
||||
edge items id "collection:version:items" : many atom Node [resolve];
|
||||
};
|
||||
operation replace id "collection:runtime:replace" : Replacement -> unit
|
||||
mode call execution transaction targets [browser, server] receiver atom Node requires {
|
||||
mode call execution transaction targets [JavaScript, server] receiver atom Node requires {
|
||||
edge items id "collection:replace:items" : many atom Node [resolve, connect, disconnect];
|
||||
};
|
||||
operation ensure id "collection:runtime:ensure" : unit -> atom-ref<Node>
|
||||
mode call execution transaction targets [browser, server] receiver atom Node requires {
|
||||
mode call execution transaction targets [JavaScript, server] receiver atom Node requires {
|
||||
edge detail id "collection:ensure:detail" : optional-one atom Node [resolve, connect];
|
||||
creation node id "collection:ensure:node" : Node input Seed;
|
||||
};
|
||||
|
||||
+8
-8
@@ -2,25 +2,25 @@ type Replacement = record { expected: list<string>; targets: list<atom-ref<Node>
|
||||
external atom Node id "collection:node";
|
||||
interface NodeData id "collection:data" revision "collection:data@1" {
|
||||
queryable portable value version id "collection:version" : list<string> {
|
||||
get id "collection:version:get" execution snapshot targets [browser, server];
|
||||
get id "collection:version:get" execution snapshot;
|
||||
}
|
||||
operation replace id "collection:replace" : Replacement -> unit {
|
||||
call id "collection:replace:call" execution transaction targets [browser, server];
|
||||
call id "collection:replace:call" execution transaction;
|
||||
}
|
||||
operation ensure id "collection:ensure" : unit -> atom-ref<Node> {
|
||||
call id "collection:ensure:call" execution transaction targets [browser, server];
|
||||
call id "collection:ensure:call" execution transaction;
|
||||
}
|
||||
queryable value label id "collection:label" : string {
|
||||
get id "collection:label:get" execution snapshot targets [browser, server];
|
||||
set id "collection:label:set" execution transaction targets [browser, server];
|
||||
get id "collection:label:get" execution snapshot;
|
||||
set id "collection:label:set" execution transaction;
|
||||
}
|
||||
queryable relation items id "collection:items" : many atom Node {
|
||||
resolve id "collection:items:resolve" execution snapshot targets [browser, server];
|
||||
resolve id "collection:items:resolve" execution snapshot;
|
||||
}
|
||||
queryable relation containers id "collection:containers" : many atom Node {
|
||||
resolve id "collection:containers:resolve" execution snapshot targets [browser, server];
|
||||
resolve id "collection:containers:resolve" execution snapshot;
|
||||
}
|
||||
queryable relation detail id "collection:detail" : optional-one atom Node {
|
||||
resolve id "collection:detail:resolve" execution snapshot targets [browser, server];
|
||||
resolve id "collection:detail:resolve" execution snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,9 +1,10 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom Note id "compound:note";
|
||||
type Content = record { text: string; tags: list<string>; };
|
||||
type Edit = record { change: change<Content>; resolved: bool; };
|
||||
package EditRuntime id "compound:runtime" revision "compound:runtime@1" {
|
||||
operation batch id "compound:runtime:batch" : record { edits: list<Edit>; } -> unit
|
||||
mode call execution transaction targets [browser, server] receiver atom Note requires {
|
||||
mode call execution transaction targets [JavaScript, server] receiver atom Note requires {
|
||||
state content id "compound:batch:content" : Content [edit];
|
||||
state resolved id "compound:batch:resolved" : bool [write];
|
||||
} accept using checkBatch;
|
||||
@@ -12,7 +13,7 @@ package EditRuntime id "compound:runtime" revision "compound:runtime@1" {
|
||||
state allowed id "compound:batch:allowed" : bool [read];
|
||||
};
|
||||
operation update id "compound:runtime:update" : Edit -> unit
|
||||
mode call execution transaction targets [browser, server] receiver atom Note requires {
|
||||
mode call execution transaction targets [JavaScript, server] receiver atom Note requires {
|
||||
state content id "compound:edit:content" : Content [edit];
|
||||
state resolved id "compound:edit:resolved" : bool [write];
|
||||
} accept using check;
|
||||
|
||||
+7
-7
@@ -2,20 +2,20 @@ type Content = record { text: string; tags: list<string>; };
|
||||
type Edit = record { change: change<Content>; resolved: bool; };
|
||||
interface NoteData id "compound:data" revision "compound:data@1" {
|
||||
operation batch id "compound:batch" : record { edits: list<Edit>; } -> unit {
|
||||
call id "compound:batch:call" execution transaction targets [browser, server];
|
||||
call id "compound:batch:call" execution transaction;
|
||||
}
|
||||
operation update id "compound:update" : Edit -> unit {
|
||||
call id "compound:update:call" execution transaction targets [browser, server];
|
||||
call id "compound:update:call" execution transaction;
|
||||
}
|
||||
queryable value content id "compound:content" : Content {
|
||||
get id "compound:content:get" execution snapshot targets [browser, server];
|
||||
edit id "compound:content:edit" execution transaction targets [browser, server];
|
||||
get id "compound:content:get" execution snapshot;
|
||||
edit id "compound:content:edit" execution transaction;
|
||||
}
|
||||
queryable value resolved id "compound:resolved" : bool {
|
||||
get id "compound:resolved:get" execution snapshot targets [browser, server];
|
||||
get id "compound:resolved:get" execution snapshot;
|
||||
}
|
||||
queryable value title id "compound:title" : string {
|
||||
get id "compound:title:get" execution snapshot targets [browser, server];
|
||||
set id "compound:title:set" execution transaction targets [browser, server];
|
||||
get id "compound:title:get" execution snapshot;
|
||||
set id "compound:title:set" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,11 +1,11 @@
|
||||
external atom Display id "device:display";
|
||||
type Request=record {url:string;text:string;version:int32;};
|
||||
interface Device id "device" revision "device@1" {
|
||||
static operation create id "device:create" : string -> atom-ref<Display> {call id "device:create:call" execution transaction targets [browser,server];}
|
||||
queryable value enabled id "device:enabled" : bool {get id "device:enabled:get" execution snapshot targets [browser,server];set id "device:enabled:set" execution transaction targets [browser,server];}
|
||||
queryable value requested id "device:requested" : Request {get id "device:requested:get" execution snapshot targets [browser,server];}
|
||||
queryable value observed id "device:observed" : optional<Request> {get id "device:observed:get" execution snapshot targets [browser,server];}
|
||||
operation requestText id "device:request" : string -> unit {call id "device:request:call" execution transaction targets [browser,server];}
|
||||
operation recordObservation id "device:record" : Request -> unit {call id "device:record:call" execution transaction targets [server];}
|
||||
operation remove id "device:remove" : unit -> unit {call id "device:remove:call" execution transaction targets [server];}
|
||||
static operation create id "device:create" : string -> atom-ref<Display> {call id "device:create:call" execution transaction;}
|
||||
queryable value enabled id "device:enabled" : bool {get id "device:enabled:get" execution snapshot;set id "device:enabled:set" execution transaction;}
|
||||
queryable value requested id "device:requested" : Request {get id "device:requested:get" execution snapshot;}
|
||||
queryable value observed id "device:observed" : optional<Request> {get id "device:observed:get" execution snapshot;}
|
||||
operation requestText id "device:request" : string -> unit {call id "device:request:call" execution transaction;}
|
||||
operation recordObservation id "device:record" : Request -> unit {call id "device:record:call" execution transaction;}
|
||||
operation remove id "device:remove" : unit -> unit {call id "device:remove:call" execution transaction;}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
type Request=record {url:string;text:string;version:int32;};
|
||||
interface DeviceController id "device-controller" revision "device-controller@1" {
|
||||
queryable portable value enabled id "controller:enabled" : bool {get id "controller:enabled:get" execution snapshot targets [server];}
|
||||
operation snapshot id "device:snapshot" : unit -> optional<Request> {call id "device:snapshot:call" execution snapshot targets [server];}
|
||||
queryable portable value enabled id "controller:enabled" : bool {get id "controller:enabled:get" execution snapshot;}
|
||||
operation snapshot id "device:snapshot" : unit -> optional<Request> {call id "device:snapshot:call" execution snapshot;}
|
||||
operation apply id "device:apply" : optional<Request> -> unit {call id "device:apply:call" execution remote;}
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
import interface Device;
|
||||
import interface DeviceController;
|
||||
external atom Display id "device:display";
|
||||
type Request=record {url:string;text:string;version:int32;};
|
||||
package Driver id "driver" revision "driver@1" {
|
||||
function create id "driver:create" : string -> atom-ref<Display> execution transaction targets [browser,server] requires {creation device id "device" : Display input record {enabled:bool;requested:Request;observed:optional<Request>;};};
|
||||
operation request id "driver:request" : string -> unit mode call execution transaction targets [browser,server] receiver any requires {state requested id "requested" : Request [read,write];};
|
||||
function create id "driver:create" : string -> atom-ref<Display> execution transaction targets [JavaScript,server] requires {creation device id "device" : Display input record {enabled:bool;requested:Request;observed:optional<Request>;};};
|
||||
operation request id "driver:request" : string -> unit mode call execution transaction targets [JavaScript,server] receiver any requires {state requested id "requested" : Request [read,write];};
|
||||
operation snapshot id "driver:snapshot" : unit -> optional<Request> mode call execution snapshot targets [server] receiver any requires {interface data id "data" : Device using [enabled.get,requested.get,observed.get];};
|
||||
operation recordObservation id "driver:record" : Request -> unit mode call execution transaction targets [server] receiver any requires {state requested id "requested" : Request [read];state observed id "observed" : optional<Request> [write];};
|
||||
operation apply id "driver:apply" : optional<Request> -> unit mode call execution remote receiver any requires {interface device id "device" : Device using [recordObservation.call];};
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
interface EventHandler<value Payload,value Parameters> id "interface:org.quixos.events:handler" revision "interface:org.quixos.events:handler@1" {
|
||||
operation handle id "events:handle" : record {event:Payload;parameters:Parameters;} -> unit {
|
||||
call id "events:handle:call" execution transaction targets [server];
|
||||
call id "events:handle:call" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -1,13 +1,13 @@
|
||||
// Required server support; a checked installed implementation may additionally predict locally.
|
||||
interface EventStream<value Payload> id "interface:org.quixos.events:stream" revision "interface:org.quixos.events:stream@1" {
|
||||
operation publish id "events:publish" : Payload -> record {publication:string;} {
|
||||
call id "events:publish:call" execution transaction targets [server];
|
||||
call id "events:publish:call" execution transaction;
|
||||
}
|
||||
queryable value head id "events:head" : optional<uint64> {
|
||||
get id "events:head:get" execution snapshot targets [server];
|
||||
get id "events:head:get" execution snapshot;
|
||||
}
|
||||
operation readPage id "events:read-page" : record {after:optional<string>;limit:uint32;}
|
||||
-> record {entries:list<record {publication:string;position:uint64;payload:Payload;}>;next:optional<string>;asOfHead:optional<uint64>;} {
|
||||
call id "events:read-page:call" execution snapshot targets [server];
|
||||
call id "events:read-page:call" execution snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -7,12 +7,12 @@ type StartPosition = variant id "org.quixos.events:start@1" {
|
||||
};
|
||||
interface EventSubscription<value Payload,value Parameters> id "interface:org.quixos.events:subscription" revision "interface:org.quixos.events:subscription@1" {
|
||||
operation attach id "events:attach" : record {source:interface-ref<EventStream<Payload>>;handler:interface-ref<EventHandler<Payload,Parameters>>;parameters:Parameters;start:StartPosition;} -> unit {
|
||||
call id "events:attach:call" execution transaction targets [server];
|
||||
call id "events:attach:call" execution transaction;
|
||||
}
|
||||
queryable value status id "events:status" : record {status:string;generation:uint64;cursor:uint64;failure:optional<record {publication:string;code:string;message:string;}>;} {
|
||||
get id "events:status:get" execution snapshot targets [server];
|
||||
get id "events:status:get" execution snapshot;
|
||||
}
|
||||
operation pause id "events:pause" : unit -> unit {call id "events:pause:call" execution transaction targets [server];}
|
||||
operation resume id "events:resume" : unit -> unit {call id "events:resume:call" execution transaction targets [server];}
|
||||
operation retire id "events:retire" : unit -> unit {call id "events:retire:call" execution transaction targets [server];}
|
||||
operation pause id "events:pause" : unit -> unit {call id "events:pause:call" execution transaction;}
|
||||
operation resume id "events:resume" : unit -> unit {call id "events:resume:call" execution transaction;}
|
||||
operation retire id "events:retire" : unit -> unit {call id "events:retire:call" execution transaction;}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@ external atom Comment id "atom:reader:comment";
|
||||
interface CommentFactory id "interface:reader:comment-factory"
|
||||
revision "interface:reader:comment-factory@1" {
|
||||
operation prepareComment id "document:prepare-comment" : bool -> atom-ref<Comment> {
|
||||
call id "document:prepare-comment:call" execution transaction targets [browser, server];
|
||||
call id "document:prepare-comment:call" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom Document id "atom:reader:document";
|
||||
external atom Comment id "atom:reader:comment";
|
||||
import interface CommentData;
|
||||
type CommentSeed = record { content: record { text: string; tags: list<string>; }; };
|
||||
package CommentRuntime id "package:comment-runtime" revision "package:comment-runtime@1" {
|
||||
operation prepareComment id "comment:prepare"
|
||||
: bool -> atom-ref<Comment> mode call execution transaction targets [browser, server]
|
||||
: bool -> atom-ref<Comment> mode call execution transaction targets [JavaScript, server]
|
||||
receiver atom Document requires {
|
||||
creation comment id "comment:prepare:comment" : Comment input CommentSeed;
|
||||
};
|
||||
|
||||
+1
-1
@@ -20,6 +20,6 @@ interface DocumentFactory id "interface:reader:document-factory"
|
||||
revision "interface:reader:document-factory@1" {
|
||||
static operation create id "document:create" : DocumentSeed -> atom-ref<Document> {
|
||||
call id "document:create:call"
|
||||
execution transaction targets [browser, server];
|
||||
execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
interface DocumentLabel id "interface:reader:document-label"
|
||||
revision "interface:reader:document-label@1" {
|
||||
queryable value title id "document:view-title" : string {
|
||||
get id "document:view-title:get" execution snapshot targets [browser, server];
|
||||
get id "document:view-title:get" execution snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
interface DocumentMetadata id "interface:reader:document-metadata"
|
||||
revision "interface:reader:document-metadata@1" {
|
||||
queryable value label id "document:label" : string {
|
||||
get id "document:label:get" execution snapshot targets [browser, server];
|
||||
get id "document:label:get" execution snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -1,3 +1,4 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
// Shared record definitions, repeated explicitly in independently locked resources.
|
||||
external atom Document id "atom:reader:document";
|
||||
external atom Highlight id "atom:reader:highlight";
|
||||
@@ -30,7 +31,7 @@ package ReaderRuntime id "package:reader-runtime"
|
||||
revision "package:reader-runtime@1" {
|
||||
operation addHighlight id "reader:add-highlight"
|
||||
: SourceRange -> atom-ref<Highlight>
|
||||
mode call execution transaction targets [browser, server]
|
||||
mode call execution transaction targets [JavaScript, server]
|
||||
receiver atom Document requires {
|
||||
interface document id "reader:add:document" : DocumentData
|
||||
using [sourceRevision.get, content.get, highlights.connect];
|
||||
@@ -39,7 +40,7 @@ revision "package:reader-runtime@1" {
|
||||
};
|
||||
|
||||
operation excerpt id "reader:excerpt" : unit -> string
|
||||
mode call execution snapshot targets [browser, server]
|
||||
mode call execution snapshot targets [JavaScript, server]
|
||||
receiver atom Highlight requires {
|
||||
state range id "reader:excerpt:range" : SourceRange [read];
|
||||
interface document id "reader:excerpt:document" : DocumentData
|
||||
@@ -49,11 +50,11 @@ revision "package:reader-runtime@1" {
|
||||
// A receiverless function needs no synthetic service object.
|
||||
function validateRange id "reader:validate-range"
|
||||
: record { range: SourceRange; content: string; } -> bool
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot targets [JavaScript, server];
|
||||
|
||||
function createDocument id "reader:create-document"
|
||||
: DocumentSeed -> atom-ref<Document>
|
||||
execution transaction targets [browser, server] requires {
|
||||
execution transaction targets [JavaScript, server] requires {
|
||||
creation document id "reader:create:document" : Document input DocumentSeed;
|
||||
};
|
||||
query ReplicaInputs id "reader:replica-inputs" root DocumentData
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ interface CommentData id "interface:reader:comment-data"
|
||||
revision "interface:reader:comment-data@1" {
|
||||
queryable value content id "comment:content" : CommentContent {
|
||||
get id "comment:content:get"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
edit id "comment:content:edit"
|
||||
execution transaction targets [browser, server];
|
||||
execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,6 +20,6 @@ interface DocumentActions id "interface:reader:document-actions"
|
||||
revision "interface:reader:document-actions@1" {
|
||||
operation annotate id "document:annotate" : SourceRange -> atom-ref<Highlight> {
|
||||
call id "document:annotate:call"
|
||||
execution transaction targets [browser, server];
|
||||
execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -20,17 +20,17 @@ interface DocumentData id "interface:reader:document-data"
|
||||
revision "interface:reader:document-data@1" {
|
||||
queryable value sourceRevision id "document:source-revision" : string {
|
||||
get id "document:source-revision:get"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
}
|
||||
queryable value content id "document:content" : string {
|
||||
get id "document:content:get"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
}
|
||||
queryable relation highlights id "document:highlights"
|
||||
: many-unique atom Highlight {
|
||||
resolve id "document:highlights:resolve"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
connect id "document:highlights:connect"
|
||||
execution transaction targets [browser, server];
|
||||
execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,6 +20,6 @@ interface DocumentFactory id "interface:reader:document-factory"
|
||||
revision "interface:reader:document-factory@1" {
|
||||
static operation create id "document:create" : DocumentSeed -> atom-ref<Document> {
|
||||
call id "document:create:call"
|
||||
execution transaction targets [browser, server];
|
||||
execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -20,20 +20,20 @@ interface HighlightData id "interface:reader:highlight-data"
|
||||
revision "interface:reader:highlight-data@1" {
|
||||
queryable value range id "highlight:range" : SourceRange {
|
||||
get id "highlight:range:get"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
}
|
||||
queryable value color id "highlight:color" : string {
|
||||
get id "highlight:color:get"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
set id "highlight:color:set"
|
||||
execution transaction targets [browser, server];
|
||||
execution transaction;
|
||||
}
|
||||
queryable portable value excerpt id "highlight:excerpt" : string {
|
||||
get id "highlight:excerpt:get"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
}
|
||||
queryable relation comments id "highlight:comments" : many-unique atom Comment {
|
||||
resolve id "highlight:comments:resolve"
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -1,3 +1,4 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
// Shared record definitions, repeated explicitly in independently locked resources.
|
||||
external atom Document id "atom:reader:document";
|
||||
external atom Highlight id "atom:reader:highlight";
|
||||
@@ -29,7 +30,7 @@ package ReaderRuntime id "package:reader-runtime"
|
||||
revision "package:reader-runtime@1" {
|
||||
operation addHighlight id "reader:add-highlight"
|
||||
: SourceRange -> atom-ref<Highlight>
|
||||
mode call execution transaction targets [browser, server]
|
||||
mode call execution transaction targets [JavaScript, server]
|
||||
receiver atom Document requires {
|
||||
interface document id "reader:add:document" : DocumentData
|
||||
using [sourceRevision.get, content.get, highlights.connect];
|
||||
@@ -38,7 +39,7 @@ revision "package:reader-runtime@1" {
|
||||
};
|
||||
|
||||
operation excerpt id "reader:excerpt" : unit -> string
|
||||
mode call execution snapshot targets [browser, server]
|
||||
mode call execution snapshot targets [JavaScript, server]
|
||||
receiver atom Highlight requires {
|
||||
state range id "reader:excerpt:range" : SourceRange [read];
|
||||
interface document id "reader:excerpt:document" : DocumentData
|
||||
@@ -48,11 +49,11 @@ revision "package:reader-runtime@1" {
|
||||
// A receiverless function needs no synthetic service object.
|
||||
function validateRange id "reader:validate-range"
|
||||
: record { range: SourceRange; content: string; } -> bool
|
||||
execution snapshot targets [browser, server];
|
||||
execution snapshot targets [JavaScript, server];
|
||||
|
||||
function createDocument id "reader:create-document"
|
||||
: DocumentSeed -> atom-ref<Document>
|
||||
execution transaction targets [browser, server] requires {
|
||||
execution transaction targets [JavaScript, server] requires {
|
||||
creation document id "reader:create:document" : Document input DocumentSeed;
|
||||
};
|
||||
query ReplicaInputs id "reader:replica-inputs" root DocumentData
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import interface PresentationState;
|
||||
interface DocumentNavigation id "document-navigation" revision "document-navigation@1" requires PresentationState {
|
||||
queryable value compact id "document-navigation:compact" : bool {
|
||||
get id "document-navigation:compact:get" execution snapshot targets [browser,server];
|
||||
set id "document-navigation:compact:set" execution transaction targets [browser,server];
|
||||
get id "document-navigation:compact:get" execution snapshot;
|
||||
set id "document-navigation:compact:set" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,15 +1,15 @@
|
||||
import interface PresentationState;
|
||||
interface PresentationMount id "presentation-mount" revision "presentation-mount@1" {
|
||||
static operation create id "presentation-mount:create" : unit -> interface-ref<PresentationMount> {
|
||||
call id "presentation-mount:create:call" execution transaction targets [browser,server];
|
||||
call id "presentation-mount:create:call" execution transaction;
|
||||
}
|
||||
queryable relation members id "presentation-mount:members" : many-unique interface PresentationState {
|
||||
resolve id "presentation-mount:members:resolve" execution snapshot targets [browser,server];
|
||||
resolve id "presentation-mount:members:resolve" execution snapshot;
|
||||
}
|
||||
queryable relation root id "presentation-mount:root" : optional-one interface PresentationState {
|
||||
resolve id "presentation-mount:root:resolve" execution snapshot targets [browser,server];
|
||||
resolve id "presentation-mount:root:resolve" execution snapshot;
|
||||
}
|
||||
operation attach id "presentation-mount:attach" : interface-ref<PresentationState> -> unit {
|
||||
call id "presentation-mount:attach:call" execution transaction targets [browser,server];
|
||||
call id "presentation-mount:attach:call" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,3 +1,4 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
import interface PresentationStates;
|
||||
import interface ReaderNavigation;
|
||||
external atom ReaderNavigationRecord id "reader-navigation-record";
|
||||
@@ -6,24 +7,24 @@ import interface PresentationMount;
|
||||
import interface StateFactory;
|
||||
external atom PresentationMountRecord id "presentation-mount-record";
|
||||
package PresentationRuntime id "presentation-runtime" revision "presentation-runtime@1" {
|
||||
function createReaderState id "presentation-runtime:create-reader-state" : record {occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> interface-ref<ReaderNavigation> execution transaction targets [browser,server] requires {
|
||||
function createReaderState id "presentation-runtime:create-reader-state" : record {occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> interface-ref<ReaderNavigation> execution transaction targets [JavaScript,server] requires {
|
||||
creation navigation id "navigation" : ReaderNavigationRecord input record {occurrence:string;parent:optional<interface-ref<PresentationState>>;};
|
||||
};
|
||||
function createPresentationMount id "presentation-runtime:create" : unit -> interface-ref<PresentationMount> execution transaction targets [browser,server] requires {
|
||||
function createPresentationMount id "presentation-runtime:create" : unit -> interface-ref<PresentationMount> execution transaction targets [JavaScript,server] requires {
|
||||
creation presentationMount id "presentationMount" : PresentationMountRecord input unit;
|
||||
};
|
||||
operation attach id "presentation-runtime:attach" : interface-ref<PresentationState> -> unit mode call execution transaction targets [browser,server] receiver any requires {
|
||||
operation attach id "presentation-runtime:attach" : interface-ref<PresentationState> -> unit mode call execution transaction targets [JavaScript,server] receiver any requires {
|
||||
edge members id "members" : many-unique interface PresentationState [resolve,connect];
|
||||
edge root id "root" : optional-one interface PresentationState [resolve,connect];
|
||||
interface metadata id "state" : PresentationState using [presentationMount.resolve,parent.resolve] from input;
|
||||
};
|
||||
operation ensure<object Navigation implements PresentationState> id "presentation-runtime:ensure" : record {presentationMount:interface-ref<PresentationMount>;occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> ref<Navigation> mode call execution transaction targets [browser,server] receiver any requires {
|
||||
operation ensure<object Navigation implements PresentationState> id "presentation-runtime:ensure" : record {presentationMount:interface-ref<PresentationMount>;occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> ref<Navigation> mode call execution transaction targets [JavaScript,server] receiver any requires {
|
||||
edge states id "states" : many-unique object Navigation keyed "string" [resolve,connect];
|
||||
interface metadata id "state" : PresentationState using [occurrence.get,presentationMount.resolve,parent.resolve] from input;
|
||||
interface presentationMount id "presentationMount" : PresentationMount using [attach.call] from input;
|
||||
interface factory id "factory" : StateFactory<Navigation> using [create.call];
|
||||
};
|
||||
function createState<object Navigation> id "presentation-runtime:create-state" : record {occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> ref<Navigation> execution transaction targets [browser,server] requires {
|
||||
function createState<object Navigation> id "presentation-runtime:create-state" : record {occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> ref<Navigation> execution transaction targets [JavaScript,server] requires {
|
||||
creation navigation id "navigation" : Navigation input record {occurrence:string;parent:optional<interface-ref<PresentationState>>;};
|
||||
};
|
||||
query ReaderStateInputs id "reader-state:inputs" root PresentationStates<atom ReaderNavigationRecord> document "queries/reader-inputs.graphql" operation "ReaderState" { replica; view ReaderNavigationRecord as ReaderNavigation; max rows 100; }
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
external interface PresentationMount revision "presentation-mount@1";
|
||||
interface PresentationState id "presentation-state" revision "presentation-state@1" {
|
||||
queryable value occurrence id "state:occurrence" : string {
|
||||
get id "state:occurrence:get" execution snapshot targets [browser,server];
|
||||
get id "state:occurrence:get" execution snapshot;
|
||||
}
|
||||
queryable relation presentationMount id "state:presentation-mount" : optional-one interface PresentationMount {
|
||||
resolve id "state:presentation-mount:resolve" execution snapshot targets [browser,server];
|
||||
resolve id "state:presentation-mount:resolve" execution snapshot;
|
||||
}
|
||||
queryable relation parent id "state:parent" : optional-one interface PresentationState {
|
||||
resolve id "state:parent:resolve" execution snapshot targets [browser,server];
|
||||
resolve id "state:parent:resolve" execution snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@ import interface PresentationState;
|
||||
import interface PresentationMount;
|
||||
interface PresentationStates<object Navigation implements PresentationState> id "presentation-states" revision "presentation-states@1" {
|
||||
queryable relation states id "presentation-states:states" : many-unique object Navigation keyed "string" {
|
||||
resolve id "presentation-states:states:resolve" execution snapshot targets [browser,server];
|
||||
resolve id "presentation-states:states:resolve" execution snapshot;
|
||||
}
|
||||
operation ensure id "presentation-states:ensure" : record {presentationMount:interface-ref<PresentationMount>;occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> ref<Navigation> {
|
||||
call id "presentation-states:ensure:call" execution transaction targets [browser,server];
|
||||
call id "presentation-states:ensure:call" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import interface PresentationState;
|
||||
interface ReaderNavigation id "reader-navigation" revision "reader-navigation@1" requires PresentationState {
|
||||
queryable value page id "reader-navigation:mode" : string {
|
||||
get id "reader-navigation:mode:get" execution snapshot targets [browser,server];
|
||||
set id "reader-navigation:mode:set" execution transaction targets [browser,server];
|
||||
get id "reader-navigation:mode:get" execution snapshot;
|
||||
set id "reader-navigation:mode:set" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import interface PresentationState;
|
||||
interface StateFactory<object Navigation implements PresentationState> id "state-factory" revision "state-factory@1" {
|
||||
static operation create id "state-factory:create" : record {occurrence:string;parent:optional<interface-ref<PresentationState>>;} -> ref<Navigation> {
|
||||
call id "state-factory:create:call" execution transaction targets [browser,server];
|
||||
call id "state-factory:create:call" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+5
-5
@@ -1,15 +1,15 @@
|
||||
interface Task id "recurring:task-data" revision "recurring:task-data@1" {
|
||||
queryable value occurrence id "recurring:occurrence" : uint64 {
|
||||
get id "recurring:occurrence:get" execution snapshot targets [browser, server];
|
||||
get id "recurring:occurrence:get" execution snapshot;
|
||||
}
|
||||
queryable value due id "recurring:due" : int64 {
|
||||
get id "recurring:due:get" execution snapshot targets [browser, server];
|
||||
get id "recurring:due:get" execution snapshot;
|
||||
}
|
||||
queryable value title id "recurring:title" : string {
|
||||
get id "recurring:title:get" execution snapshot targets [browser, server];
|
||||
set id "recurring:title:set" execution transaction targets [browser, server];
|
||||
get id "recurring:title:get" execution snapshot;
|
||||
set id "recurring:title:set" execution transaction;
|
||||
}
|
||||
operation complete id "recurring:complete" : uint64 -> unit {
|
||||
call id "recurring:complete:call" execution transaction targets [browser, server];
|
||||
call id "recurring:complete:call" execution transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom TaskObject id "recurring:task";
|
||||
package TaskRuntime id "recurring:runtime" revision "recurring:runtime@1" {
|
||||
operation complete id "recurring:runtime:complete" : uint64 -> unit
|
||||
mode call execution transaction targets [browser, server] receiver atom TaskObject requires {
|
||||
mode call execution transaction targets [JavaScript, server] receiver atom TaskObject requires {
|
||||
state occurrence id "recurring:port:occurrence" : uint64 [read, write];
|
||||
state due id "recurring:port:due" : int64 [read, write];
|
||||
};
|
||||
|
||||
Vendored
+3
-3
@@ -1,11 +1,11 @@
|
||||
interface TreeData id "tree:data" revision "tree:data@1" {
|
||||
operation reparent id "tree:reparent" : optional<interface-ref<TreeData>> -> unit {
|
||||
call id "tree:reparent:call" execution transaction targets [browser, server];
|
||||
call id "tree:reparent:call" execution transaction;
|
||||
}
|
||||
queryable relation parent id "tree:parent" : optional-one interface TreeData {
|
||||
resolve id "tree:parent:resolve" execution snapshot targets [browser, server];
|
||||
resolve id "tree:parent:resolve" execution snapshot;
|
||||
}
|
||||
queryable relation children id "tree:children" : many interface TreeData {
|
||||
resolve id "tree:children:resolve" execution snapshot targets [browser, server];
|
||||
resolve id "tree:children:resolve" execution snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-1
@@ -1,8 +1,9 @@
|
||||
symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom Node id "tree:node";
|
||||
import interface TreeData;
|
||||
package TreeRuntime id "tree:runtime" revision "tree:runtime@1" {
|
||||
operation reparent id "tree:runtime:reparent" : optional<interface-ref<TreeData>> -> unit
|
||||
mode call execution transaction targets [browser, server] receiver atom Node requires {
|
||||
mode call execution transaction targets [JavaScript, server] receiver atom Node requires {
|
||||
edge parent id "tree:move:parent" : optional-one interface TreeData [resolve, connect, disconnect];
|
||||
} accept using check;
|
||||
operation check id "tree:runtime:check" : optional<interface-ref<TreeData>> -> unit
|
||||
|
||||
@@ -609,7 +609,7 @@ test("edge read targets honor declared interface prerequisites without inferring
|
||||
for (const text of [
|
||||
'interface Base id "base" revision "base@1" {}',
|
||||
'import interface Base; interface Detailed id "detailed" revision "detailed@1" requires Base {}',
|
||||
'import interface Base; interface Holder id "holder" revision "holder@1" {queryable relation item id "item" : optional-one interface Base {resolve id "item:resolve" execution snapshot targets [browser,server];}}',
|
||||
'import interface Base; interface Holder id "holder" revision "holder@1" {queryable relation item id "item" : optional-one interface Base {resolve id "item:resolve" execution snapshot;}}',
|
||||
]) {
|
||||
const parsed = compileCapabilityResourceSource(text, { source, environment: { interfaces } });
|
||||
assert.ok(parsed.ok, JSON.stringify(parsed.diagnostics));
|
||||
|
||||
@@ -58,12 +58,12 @@ const contract = `external atom Document id "document";
|
||||
type Event = record { document: atom-ref<Document>; title: string; };
|
||||
interface Stream id "stream" revision "stream@1" {
|
||||
operation publish id "publish" : Event -> record { publication: string; } {
|
||||
call id "publish:call" execution transaction targets [server];
|
||||
call id "publish:call" execution transaction;
|
||||
}
|
||||
queryable value head id "head" : optional<uint64> { get id "head:get" execution snapshot targets [server]; }
|
||||
queryable value head id "head" : optional<uint64> { get id "head:get" execution snapshot; }
|
||||
operation readPage id "page" : record { after: optional<string>; limit: uint32; }
|
||||
-> record { entries: list<record { publication: string; position: uint64; payload: Event; }>; next: optional<string>; asOfHead: optional<uint64>; } {
|
||||
call id "page:call" execution snapshot targets [server];
|
||||
call id "page:call" execution snapshot;
|
||||
}
|
||||
}`;
|
||||
const assembly = `workspace Journals id "journals" revision "journals@1" commit "${source.commit}" {
|
||||
@@ -127,7 +127,7 @@ test("subscription storage infers its typed handler and retains configuration re
|
||||
`external atom Document id "document";
|
||||
interface Receiver id "receiver" revision "receiver@1" {
|
||||
operation receive id "receive" : record { event: record { document: atom-ref<Document>; title: string; }; parameters: string; } -> unit {
|
||||
call id "receive:call" execution transaction targets [server];
|
||||
call id "receive:call" execution transaction;
|
||||
}
|
||||
}`,
|
||||
);
|
||||
@@ -139,12 +139,12 @@ import interface Receiver;
|
||||
type Start = variant id "start" { future id "future" : unit; retained id "retained" : unit; afterCursor id "after" : string; };
|
||||
interface Subscription id "subscription" revision "subscription@1" {
|
||||
operation attach id "attach" : record { source: interface-ref<Stream>; handler: interface-ref<Receiver>; parameters: string; start: Start; } -> unit {
|
||||
call id "attach:call" execution transaction targets [server];
|
||||
call id "attach:call" execution transaction;
|
||||
}
|
||||
queryable value status id "status" : record { status: string; generation: uint64; cursor: uint64; failure: optional<record { publication: string; code: string; message: string; }>; } {
|
||||
get id "status:get" execution snapshot targets [server];
|
||||
get id "status:get" execution snapshot;
|
||||
}
|
||||
operation retire id "retire" : unit -> unit { call id "retire:call" execution transaction targets [server]; }
|
||||
operation retire id "retire" : unit -> unit { call id "retire:call" execution transaction; }
|
||||
}`,
|
||||
);
|
||||
const ws = assembly
|
||||
|
||||
@@ -12,19 +12,20 @@ const source = { repository: "https://example.test/keyed.git", commit: "a".repea
|
||||
const iface = compileCapabilityResourceSource(
|
||||
`interface Index<object Item> id "index" revision "index@1" {
|
||||
queryable relation entries id "entries" : many object Item keyed "string" {
|
||||
resolve id "resolve" execution snapshot targets [browser,server];
|
||||
connect id "connect" execution transaction targets [browser,server];
|
||||
resolve id "resolve" execution snapshot;
|
||||
connect id "connect" execution transaction;
|
||||
}
|
||||
operation add id "add" : record {mapKey:string;target:ref<Item>;} -> unit {
|
||||
call id "add-call" execution transaction targets [browser,server];
|
||||
call id "add-call" execution transaction;
|
||||
}
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
assert.ok(iface.ok && iface.resource.kind === "interface", JSON.stringify(iface.diagnostics));
|
||||
const pkg = compileCapabilityResourceSource(
|
||||
`package Runtime id "runtime" revision "runtime@1" {
|
||||
operation add<object Item> id "add" : record {mapKey:string;target:ref<Item>;} -> unit mode call execution transaction targets [browser,server] receiver any requires {
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
package Runtime id "runtime" revision "runtime@1" {
|
||||
operation add<object Item> id "add" : record {mapKey:string;target:ref<Item>;} -> unit mode call execution transaction targets [JavaScript,server] receiver any requires {
|
||||
edge entries id "entries" : many object Item keyed "string" [resolve,connect];
|
||||
};
|
||||
}`,
|
||||
@@ -61,7 +62,7 @@ test("generic keyed relationships and portable ports have matching checked shape
|
||||
const plan = compileExecutionPlan(result.workspace);
|
||||
assert.doesNotThrow(() => compileKernelProgram(plan));
|
||||
const bindings = generatePortableTypeScriptBindings(plan.definition.bindingSchema, "runtime@1", {
|
||||
target: "browser",
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
});
|
||||
assert.match(bindings, /readonly "mapKey": string/);
|
||||
assert.match(bindings, /readonly "connect": \(input: \{ readonly "mapKey": string;/);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { formatQx } from "../src/capability-language/source.js";
|
||||
import { compileExecutionPlan, compileKernelProgram } from "../src/execution-world/index.js";
|
||||
const contract = `interface Item id "item" revision "item@1" {
|
||||
operation remove id "remove" : unit -> unit {
|
||||
call id "remove:call" execution transaction targets [server];
|
||||
call id "remove:call" execution transaction;
|
||||
}
|
||||
}`;
|
||||
const workspace = `workspace Lifecycle id "workspace:lifecycle" revision "workspace:lifecycle@1" commit "${"a".repeat(40)}" {
|
||||
@@ -45,10 +45,9 @@ test("lifecycle binding and endpoint policies survive formatting and kernel comp
|
||||
});
|
||||
test("deletion rejects browser, snapshot, remote, class, payload and unknown primitive promises", () => {
|
||||
for (const [iface, ws] of [
|
||||
[contract.replace("targets [server]", "targets [browser, server]"), workspace],
|
||||
[contract.replace("transaction targets", "snapshot targets"), workspace],
|
||||
[contract.replace("execution transaction targets [server]", "execution remote"), workspace],
|
||||
[contract.replace("execution transaction targets [server]", ""), workspace],
|
||||
[contract.replace("execution transaction", "execution snapshot"), workspace],
|
||||
[contract.replace("execution transaction", "execution remote"), workspace],
|
||||
[contract.replace("execution transaction", ""), workspace],
|
||||
[contract.replace("operation remove", "static operation remove"), workspace],
|
||||
[contract.replace("unit -> unit", "string -> unit"), workspace],
|
||||
[contract.replace("unit -> unit", "unit -> string"), workspace],
|
||||
|
||||
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { compileQuery } from "../src/query/compile.js";
|
||||
import { linkQueries } from "../src/query/link.js";
|
||||
import { compileExecutionPlan } from "../src/execution-world/plan.js";
|
||||
import { loadReaderWorkspace as load, readReaderFixture as read } from "./reader-fixture.js";
|
||||
test("complete reader contracts compose factories, portable selectors, CRDT edits, and bounded query scopes", async () => {
|
||||
const workspace = await load();
|
||||
@@ -23,15 +24,19 @@ test("complete reader contracts compose factories, portable selectors, CRDT edit
|
||||
);
|
||||
});
|
||||
|
||||
test("reader composition reports the dependency that weakens a portable promise", async () => {
|
||||
await assert.rejects(
|
||||
load((name, text) =>
|
||||
name === "ReaderRuntime.qx"
|
||||
? text.replace(/(operation excerpt[\s\S]*?targets )\[browser, server\]/, "$1[server]")
|
||||
: text,
|
||||
),
|
||||
/does not provide execution target browser/,
|
||||
test("ordinary operations allow server fallback; explicitly local projections require local code", async () => {
|
||||
const serverExcerpt = await load((name, text) =>
|
||||
name === "ReaderRuntime.qx"
|
||||
? text.replace(/(operation excerpt[\s\S]*?targets )\[JavaScript, server\]/, "$1[server]")
|
||||
: text,
|
||||
);
|
||||
assert.throws(() => compileExecutionPlan(serverExcerpt), /NONPORTABLE_QUERY_FIELD/);
|
||||
for (const pkg of serverExcerpt.packageImports)
|
||||
pkg.queries = pkg.queries?.filter((q) => q.placement?.kind !== "local");
|
||||
const fallback = compileExecutionPlan(serverExcerpt).definition.operations.find(
|
||||
(op) => op.operationId === "highlight:excerpt:get",
|
||||
)!;
|
||||
assert.deepEqual(fallback.availableTargets, ["server"]);
|
||||
await assert.rejects(
|
||||
load((name, text) =>
|
||||
name === "ReaderRuntime.qx"
|
||||
@@ -56,6 +61,6 @@ test("a field can remain server-queryable while failing local query placement",
|
||||
await compileQuery(admission, workspace.interfaceImports, read);
|
||||
await assert.rejects(
|
||||
compileQuery(local, workspace.interfaceImports, read),
|
||||
/browser snapshot getter for HighlightData.color/,
|
||||
/graph snapshot getter for HighlightData.color/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -22,7 +22,9 @@ test("service bindings depend on their consumed contract, not workspace or sourc
|
||||
|
||||
test("reader portable bindings have selected facets, creation inputs and stable keyed calls", async () => {
|
||||
const schema = compileExecutionPlan(await loadReaderWorkspace()).definition.bindingSchema;
|
||||
const source = generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", { target: "browser" });
|
||||
const source = generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", {
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
});
|
||||
assert.match(source, /readonly "sourceRevision.get": \(\) => Promise<string>/);
|
||||
assert.match(
|
||||
source,
|
||||
@@ -32,22 +34,30 @@ test("reader portable bindings have selected facets, creation inputs and stable
|
||||
assert.match(source, /readonly "create":/);
|
||||
assert.match(source, /readonly "comments": ReadonlyArray/);
|
||||
assert.doesNotMatch(source, /"highlights.resolve"|context\.conform|objectId|"live"/);
|
||||
assert.equal(source, generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", { target: "browser" }));
|
||||
assert.equal(
|
||||
source,
|
||||
generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", {
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
}),
|
||||
);
|
||||
const server = generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", { target: "server" });
|
||||
assert.equal(source.replace('target = "browser"', 'target = "server"'), server);
|
||||
assert.equal(source.replace('target = "target:org.quixos.execution.javascript@1"', 'target = "server"'), server);
|
||||
});
|
||||
|
||||
test("generation rejects remote dependencies, wrong effects and unsupported shapes explicitly", async () => {
|
||||
const schema = compileExecutionPlan(await loadReaderWorkspace()).definition.bindingSchema;
|
||||
const generate = () => generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", { target: "browser" });
|
||||
const generate = () =>
|
||||
generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", {
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
});
|
||||
const entry = schema.packages[0]!.exports.find((e) => e.displayName === "addHighlight")!;
|
||||
entry.execution = { kind: "snapshot", targets: ["browser"] };
|
||||
entry.execution = { kind: "snapshot", targets: ["target:org.quixos.execution.javascript@1"] };
|
||||
assert.throws(generate, /Snapshot context cannot expose mutation ports/);
|
||||
entry.execution = { kind: "transaction", targets: ["browser"] };
|
||||
entry.execution = { kind: "transaction", targets: ["target:org.quixos.execution.javascript@1"] };
|
||||
const iface = schema.interfaces.find((i) => i.revisionId === "interface:reader:document-data@1")!;
|
||||
const getter = iface.members[0]!.operations[0]!;
|
||||
getter.execution = { kind: "remote" };
|
||||
assert.throws(generate, /not an object call available in portable target browser/);
|
||||
assert.throws(generate, /not an object call available in portable target target:org.quixos.execution.javascript@1/);
|
||||
getter.execution = { kind: "snapshot", targets: ["browser", "server"] };
|
||||
entry.dependencyPorts[0]!.requirement = { kind: "reflection", selectors: ["active"] };
|
||||
assert.throws(generate, /Only checked presentation metadata is portable/);
|
||||
@@ -59,7 +69,9 @@ test("closed generic portable handlers have distinct concrete codecs and no univ
|
||||
const schema = plan.definition.bindingSchema;
|
||||
const pkg = schema.packages[0]!;
|
||||
assert.equal(pkg.exports.length, 2);
|
||||
const generated = generatePortableTypeScriptBindings(schema, pkg.revisionId, { target: "browser" });
|
||||
const generated = generatePortableTypeScriptBindings(schema, pkg.revisionId, {
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
});
|
||||
assert.match(generated, /readonly input: string/);
|
||||
assert.match(generated, /readonly input: ReadonlyArray<bigint>/);
|
||||
for (const entry of pkg.exports) {
|
||||
@@ -69,7 +81,7 @@ test("closed generic portable handlers have distinct concrete codecs and no univ
|
||||
}
|
||||
assert.notEqual(pkg.exports[0]!.displayName, pkg.exports[1]!.displayName);
|
||||
assert.equal(
|
||||
generated.replace('target = "browser"', 'target = "server"'),
|
||||
generated.replace('target = "target:org.quixos.execution.javascript@1"', 'target = "server"'),
|
||||
generatePortableTypeScriptBindings(schema, pkg.revisionId, { target: "server" }),
|
||||
);
|
||||
});
|
||||
@@ -90,7 +102,10 @@ test("a portable subset of a mixed interface excludes remote dependencies", asyn
|
||||
displayName: "remote",
|
||||
operations: [operation],
|
||||
});
|
||||
const generate = () => generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", { target: "browser" });
|
||||
const generate = () =>
|
||||
generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", {
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
});
|
||||
assert.doesNotMatch(generate(), /readonly "remote.get"/);
|
||||
selected.operations!.push(operation.id);
|
||||
assert.throws(generate, /select a portable subset/);
|
||||
@@ -99,7 +114,7 @@ test("a portable subset of a mixed interface excludes remote dependencies", asyn
|
||||
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 source = generatePortableClientBindings(plan, { target: "target:org.quixos.execution.javascript@1" });
|
||||
const projections = source.slice(
|
||||
source.indexOf("export const serverProjections"),
|
||||
source.indexOf("export const results"),
|
||||
@@ -127,7 +142,9 @@ test("static interface ports keep unit arguments explicit for generic factory co
|
||||
op.inputType = { kind: "builtin", name: "unit" };
|
||||
port.requirement.operations = [op.id];
|
||||
delete port.requirement.receiver;
|
||||
const generated = generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", { target: "browser" });
|
||||
const generated = generatePortableTypeScriptBindings(schema, "package:reader-runtime@1", {
|
||||
target: "target:org.quixos.execution.javascript@1",
|
||||
});
|
||||
assert.match(generated, /"explicitInput": true/);
|
||||
assert.match(generated, /input: null/);
|
||||
});
|
||||
|
||||
@@ -9,17 +9,18 @@ export function portableGenericPlan() {
|
||||
`
|
||||
interface Echo<value T> id "echo-interface" revision "echo-interface@2" {
|
||||
operation echo id "echo-member" : T -> T {
|
||||
call id "echo-call" execution snapshot targets [browser, server];
|
||||
call id "echo-call" execution snapshot;
|
||||
}
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
assert.ok(iface.ok && iface.resource.kind === "interface", JSON.stringify(iface.diagnostics));
|
||||
const pkg = compileCapabilityResourceSource(
|
||||
`
|
||||
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
|
||||
package Generic id "generic" revision "generic@3" {
|
||||
operation echo<value T> id "echo" : T -> T mode call
|
||||
execution snapshot targets [browser, server] receiver any;
|
||||
execution snapshot targets [JavaScript, server] receiver any;
|
||||
}`,
|
||||
{ source: { ...source, commit: "b".repeat(40) } },
|
||||
);
|
||||
|
||||
@@ -24,8 +24,8 @@ async function fixture(replacement = "First", change?: (artifact: ReactPreparati
|
||||
return result.resource;
|
||||
};
|
||||
for (const text of [
|
||||
'interface Row id "row" revision "row@1" { queryable value title id "title" : string {get id "title:get" execution snapshot targets [browser, server];} queryable value detail id "detail" : string {get id "detail:get" execution snapshot targets [browser, server];} }',
|
||||
'import interface Row; interface Library id "library" revision "library@1" { queryable relation selected id "selected" : optional-one interface Row {resolve id "selected:get" execution snapshot targets [browser, server];} }',
|
||||
'interface Row id "row" revision "row@1" { queryable value title id "title" : string {get id "title:get" execution snapshot;} queryable value detail id "detail" : string {get id "detail:get" execution snapshot;} }',
|
||||
'import interface Row; interface Library id "library" revision "library@1" { queryable relation selected id "selected" : optional-one interface Row {resolve id "selected:get" execution snapshot;} }',
|
||||
'import interface Row; interface RowRole id "row-role" revision "row-role@1" { module render id "row-render" contract "org.quixos.react.subject-only/1" subject interface Row; }',
|
||||
'import interface Library; interface LibraryRole id "library-role" revision "library-role@1" { module render id "library-render" contract "org.quixos.react.subject-only/1" subject interface Library; }',
|
||||
]) {
|
||||
|
||||
@@ -437,17 +437,17 @@ test("React tooling generates checked owner queries from imported closed navigat
|
||||
const state = iface(
|
||||
`import interface PresentationMount; import interface Subject;
|
||||
interface PresentationState id "state" revision "state@1" {
|
||||
queryable value occurrence id "occurrence" : string {get id "occurrence:get" execution snapshot targets [browser,server];}
|
||||
queryable relation presentationMount id "mount" : optional-one interface PresentationMount {resolve id "mount:resolve" execution snapshot targets [browser,server];}
|
||||
queryable relation parent id "parent" : optional-one interface PresentationState {resolve id "parent:resolve" execution snapshot targets [browser,server];}
|
||||
queryable relation source id "source" : exactly-one interface Subject {resolve id "source:resolve" execution snapshot targets [browser,server];}
|
||||
queryable value occurrence id "occurrence" : string {get id "occurrence:get" execution snapshot;}
|
||||
queryable relation presentationMount id "mount" : optional-one interface PresentationMount {resolve id "mount:resolve" execution snapshot;}
|
||||
queryable relation parent id "parent" : optional-one interface PresentationState {resolve id "parent:resolve" execution snapshot;}
|
||||
queryable relation source id "source" : exactly-one interface Subject {resolve id "source:resolve" execution snapshot;}
|
||||
}`,
|
||||
[mount, subject],
|
||||
);
|
||||
const navigation = iface(
|
||||
`import interface PresentationState;
|
||||
interface Navigation<value T> id "navigation" revision "navigation@1" requires PresentationState {
|
||||
queryable value custom id "custom" : T {get id "custom:get" execution snapshot targets [browser,server];}
|
||||
queryable value custom id "custom" : T {get id "custom:get" execution snapshot;}
|
||||
}`,
|
||||
[mount, subject, state],
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { PackageRevision } from "../src/capability-model/types.js";
|
||||
const source = { repository: "https://example.test/fragments", commit: "a".repeat(40) };
|
||||
const compiled = compileCapabilityResourceSource(
|
||||
`interface Item id "item" revision "item@1" {
|
||||
queryable value title id "title" : string {get id "title:get" execution snapshot targets [browser,server];}
|
||||
queryable value title id "title" : string {get id "title:get" execution snapshot;}
|
||||
queryable rpc value remote id "remote" : string {get id "remote:get";}
|
||||
}`,
|
||||
{ source },
|
||||
|
||||
@@ -7,8 +7,8 @@ import { defaultQueryBudgets, type QueryDeclaration } from "../src/query/types.j
|
||||
const source = { repository: "https://example.test/structured.git", commit: "a".repeat(40) };
|
||||
const result = compileCapabilityResourceSource(
|
||||
`interface Highlight id "highlight" revision "highlight@1" {
|
||||
queryable value range id "range" : record { sourceRevision:string; start:int32; end:int32; } { get id "range:get" execution snapshot targets [browser, server]; }
|
||||
queryable value content id "content" : record { text:string; tags:list<string>; metadata:optional<record { score:int32; }>; } { get id "content:get" execution snapshot targets [browser, server]; }
|
||||
queryable value range id "range" : record { sourceRevision:string; start:int32; end:int32; } { get id "range:get" execution snapshot; }
|
||||
queryable value content id "content" : record { text:string; tags:list<string>; metadata:optional<record { score:int32; }>; } { get id "content:get" execution snapshot; }
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
|
||||
@@ -6,10 +6,11 @@ import { generatePortableTypeScriptBindings } from "../src/bindings/portable.js"
|
||||
import { formatQx } from "../src/capability-language/source.js";
|
||||
const source = { repository: "https://example.test/reference.git", commit: "a".repeat(40) };
|
||||
const iface = `interface Data id "data" revision "data@1" {
|
||||
value content id "content" : string { get id "content:get" execution snapshot targets [server]; }
|
||||
operation peek id "peek" : interface-ref<Data> -> string { call id "peek:call" execution snapshot targets [server]; }
|
||||
value content id "content" : string { get id "content:get" execution snapshot; }
|
||||
operation peek id "peek" : interface-ref<Data> -> string { call id "peek:call" execution snapshot; }
|
||||
}`;
|
||||
const pkg = `external atom Item id "item";
|
||||
const pkg = `symbol JavaScript id "target:org.quixos.execution.javascript@1";
|
||||
external atom Item id "item";
|
||||
import interface Data;
|
||||
package Runtime id "runtime" revision "runtime@1" {
|
||||
operation peek id "runtime:peek" : interface-ref<Data> -> string mode call execution snapshot targets [server]
|
||||
@@ -83,15 +84,15 @@ test("closed generic specialization preserves reference-selected interface ports
|
||||
});
|
||||
|
||||
test("portable input-selected reads use installed support beyond the public minimum", () => {
|
||||
const portable = pkg.replaceAll("targets [server]", "targets [browser, server]");
|
||||
const portable = pkg.replaceAll("targets [server]", "targets [JavaScript, server]");
|
||||
const optional = compile(portable);
|
||||
assert.ok(optional.ok, JSON.stringify(optional.diagnostics));
|
||||
const plan = compileExecutionPlan(optional.workspace);
|
||||
assert.deepEqual(plan.definition.operations.find((op) => op.operationId === "peek:call")!.availableTargets, [
|
||||
"browser",
|
||||
"server",
|
||||
"target:org.quixos.execution.javascript@1",
|
||||
]);
|
||||
const result = compile(portable, workspace, iface.replaceAll("targets [server]", "targets [browser, server]"));
|
||||
const result = compile(portable, workspace, iface);
|
||||
assert.ok(result.ok, JSON.stringify(result.diagnostics));
|
||||
});
|
||||
|
||||
@@ -102,8 +103,8 @@ test("input-selected transactions compose only within a compatible transaction c
|
||||
const txPackage = pkg.replace("execution snapshot targets [server]", "execution transaction targets [server]");
|
||||
// Use an operation for the selected write; value getters themselves must remain snapshots.
|
||||
const contract = txInterface.replace(
|
||||
'value content id "content" : string { get id "content:get" execution transaction targets [server]; }',
|
||||
'operation update id "content" : unit -> string { call id "content:get" execution transaction targets [server]; }',
|
||||
'value content id "content" : string { get id "content:get" execution transaction; }',
|
||||
'operation update id "content" : unit -> string { call id "content:get" execution transaction; }',
|
||||
);
|
||||
const implementation = txPackage.replace("using [content.get]", "using [update.call]");
|
||||
const model = workspace.replace(
|
||||
|
||||
@@ -35,7 +35,7 @@ test("execution scaffolds route typed handlers by declared effect and target wit
|
||||
id: "export:" + name,
|
||||
declaration: `function ${name} id "export:${name}" : unit -> unit execution ${execution};`,
|
||||
});
|
||||
await add("both", "transaction targets [browser, server]");
|
||||
await add("both", "transaction targets [JavaScript, server]");
|
||||
await add("serverOnly", "snapshot targets [server]");
|
||||
await add("asyncWork", "remote");
|
||||
const read = (file: string) => fs.readFile(path.join(root, file), "utf8");
|
||||
@@ -48,8 +48,8 @@ test("execution scaffolds route typed handlers by declared effect and target wit
|
||||
assert.match(await read("src/impl/both.ts"), /PortableImplementation/);
|
||||
assert.match(await read("flake.nix"), /checkedArtifacts/);
|
||||
assert.match(await read("flake.nix"), /entries.browser/);
|
||||
await assert.rejects(add("both", "transaction targets [browser, server]"), /unique/);
|
||||
await assert.rejects(add("invalid", "snapshot targets [remote]"), /browser\/server/);
|
||||
await assert.rejects(add("both", "transaction targets [JavaScript, server]"), /unique/);
|
||||
await assert.rejects(add("invalid", "snapshot targets [remote]"), /TypeScript scaffold supports/);
|
||||
await assert.rejects(apply("function", { name: "missing", id: "export:missing" }), /explicit execution/);
|
||||
await assert.rejects(apply("migration", { name: "migration", id: "export:migration" }), /retired/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user