Let a module's code announce the states it keeps, in Go and TypeScript (issue 1790, S10, ADR 0495 §2 §5)
process.Conn.Keeps, stdio.Keeps and the TypeScript keeps publish the announcement on the module's own subject; afterwards a state the code did not announce is refused at the call, so announcement and code cannot drift. The package goes to 0.1.15 for keeps.
This commit is contained in:
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
// A launched bundle that says what it keeps (novox/hq ADR 0495 clause 2; issue 1790): it announces its states as it is
|
||||
// imported, and a state of its own it did not announce is refused at the call.
|
||||
import { keeps, state } from "../../dist/state/index.js";
|
||||
import { registerModuleTools } from "../../dist/tools/index.js";
|
||||
import { serveRegisteredOverStdio } from "../../dist/stdio/index.js";
|
||||
|
||||
await keeps([{ name: "servers", readable: true }, { name: "own" }]);
|
||||
registerModuleTools("keeper", () => [
|
||||
{ name: "unannounced", description: "reads a state it did not announce", input: {}, run: async () => state("drafts").get("k") },
|
||||
]);
|
||||
await serveRegisteredOverStdio();
|
||||
@@ -273,3 +273,40 @@ test("topics match as the runtime's do: * one segment, # and ** any number", asy
|
||||
assert.ok(topicMatches("alpha.**", "alpha.a.b"));
|
||||
assert.ok(!topicMatches("beta.*", "alpha.happened"));
|
||||
});
|
||||
|
||||
test("a launched bundle announces what it keeps as it is imported, and binds no state it did not announce (ADR 0495, issue 1790)", async () => {
|
||||
const child = spawn(process.execPath, [fileURLToPath(new URL("./fixtures/stdio-keeps.mjs", import.meta.url))],
|
||||
{ stdio: ["pipe", "pipe", "inherit"], env: { ...process.env, MESH_SERVED_MODULE: "keeper", MESH_MODULE: "keeper", MESH_NODE: "anchor" } });
|
||||
const seen: any[] = [];
|
||||
let buffered = "";
|
||||
child.stdout.on("data", (d) => {
|
||||
buffered += d.toString();
|
||||
let at: number;
|
||||
while ((at = buffered.indexOf("\n")) >= 0) {
|
||||
seen.push(JSON.parse(buffered.slice(0, at)));
|
||||
buffered = buffered.slice(at + 1);
|
||||
}
|
||||
});
|
||||
const until = async (match: (m: any) => boolean) => {
|
||||
for (let i = 0; i < 150 && !seen.some(match); i++) await new Promise((r) => setTimeout(r, 20));
|
||||
return seen.find(match);
|
||||
};
|
||||
const send = (m: unknown) => child.stdin.write(JSON.stringify(m) + "\n");
|
||||
try {
|
||||
const asked = await until((m) => m.method === "mesh/publish");
|
||||
assert.ok(asked, "the bundle announced nothing as it was imported");
|
||||
assert.equal(asked.params.key, "states");
|
||||
assert.deepEqual(asked.params.body, {
|
||||
v: 1, module: "keeper", node: "anchor", states: [{ name: "own" }, { name: "servers", readable: true }],
|
||||
});
|
||||
send({ jsonrpc: "2.0", id: asked.id, result: {} });
|
||||
send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-03-26", capabilities: {} } });
|
||||
await until((m) => m.id === 1);
|
||||
send({ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "unannounced", arguments: {} } });
|
||||
const answered = await until((m) => m.id === 2);
|
||||
assert.match(JSON.stringify(answered), /drafts/, "a state the bundle did not announce was bound");
|
||||
assert.equal(seen.find((m) => m.method === "mesh/state.get"), undefined, "the runtime was asked for an unannounced state");
|
||||
} finally {
|
||||
child.kill();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user