import assert from "node:assert/strict"; import test from "node:test"; import { bindQxHandler, decodeQxValue, encodeQxValue, jsToProtoValue, liveValue, protoValueToJs } from "../dist/index.js"; const scalar = (name) => ({ kind: "scalar", name }); const unit = { kind: "builtin", name: "unit" }; test("binding codecs round trip nested bytes, 64-bit integers, nulls, and references", () => { const values = [[scalar("int64"), -(2n ** 63n)], [scalar("uint64"), 2n ** 64n - 1n], [scalar("bytes"), new Uint8Array([0, 255])], [{ kind: "list", value: { kind: "optional", value: scalar("int64") } }, [null, 2n ** 60n]], [{ kind: "object-ref", expectation: { kind: "atom", atomId: "thing" } }, "obj:thing"]]; for (const [type, value] of values) assert.deepEqual(decodeQxValue(type, encodeQxValue(type, value, {}), {}), value); }); test("typed state and interface ports preserve declared values and exact operation IDs", async () => { const spec = { inputType: scalar("int64"), outputType: scalar("bytes"), ports: { data: { kind: "state", id: "state-id", valueType: scalar("int64"), primitives: ["read", "write"] }, reader: { kind: "interface", id: "interface-id", operations: { "payload.get": { id: "get-id", inputType: unit, outputType: scalar("bytes") } } }, } }; let written; const handler = bindQxHandler(spec, async ({ input, ports }) => { assert.equal(input, 2n ** 60n); assert.equal(await ports.data.get(), 9n); await ports.data.set(input); return ports.reader["payload.get"](); }, {}); const result = await handler({ inputProto: { value: jsToProtoValue(2n ** 60n) }, objectId: "obj", state: (id) => { assert.equal(id, "state-id"); return { live: async () => liveValue(jsToProtoValue(9n)), set: async (value) => { written = value; }, }; }, interface: (id) => { assert.equal(id, "interface-id"); return { live: async (operation, input) => { assert.equal(operation, "get-id"); assert.deepEqual(input, {}); return liveValue(jsToProtoValue(new Uint8Array([7]))); } }; }, }); assert.equal(written.$quixosValue.kind.value, String(2n ** 60n)); assert.deepEqual(result.$quixosValue.kind.value, new Uint8Array([7])); }); test("external message bindings and derived event types are used at the boundary", async () => { const message = { kind: "message", descriptorId: "Payload" }; const messages = { Payload: { encode: jsToProtoValue, decode: protoValueToJs } }; const handler = bindQxHandler({ inputType: message, outputType: { kind: "builtin", name: "watch-handle" }, eventType: message, ports: {} }, { kind: "derived", get: ({ input }) => ({ value: input.title }) }, messages); assert.equal(handler.kind, "derived"); const result = await handler.get({ objectId: "obj", inputProto: { title: jsToProtoValue("hello") } }); assert.deepEqual(protoValueToJs(result.$quixosValue), { value: "hello" }); assert.throws(() => encodeQxValue(message, {}, {}), /Missing message binding/); });