import assert from "node:assert/strict"; import { test } from "node:test"; import { did, load, now } from "../../../rust/src/harness.mjs"; const { module, run, handle } = await load(new URL("../../../target/wasm32-unknown-unknown/release/statusphere.wasm", import.meta.url), new URL("./module.json", import.meta.url)); const ENTRIES = ["set_status", "clear_status"]; const start = (fields) => ({ did, now, ...fields, state: null, event: { type: "start" } }); // respond(call) answers each call and records it. const recorded = (answer) => { const calls = []; return { calls, respond: (call) => (calls.push(call), answer(call)) }; }; test("module has no imports and exports the ABI", () => { assert.equal(WebAssembly.Module.imports(module).length, 0); const names = WebAssembly.Module.exports(module).map((e) => e.name); for (const name of ["memory", "alloc", ...ENTRIES]) assert.ok(names.includes(name), name); }); test("set_status reads the latest status, writes, then reports the new uri", async () => { const { calls, respond } = recorded((call) => call.nsid === "com.atproto.repo.listRecords" ? { ok: true, output: { records: [{ uri: `at://${did}/xyz.statusphere.status/old`, value: { status: "🙂" } }] } } : { ok: true, output: { uri: `at://${did}/xyz.statusphere.status/new`, cid: "bafy" } }, ); const ran = await handle("set_status", { status: "🦋" }, { respond }); assert.deepEqual(calls.map((call) => call.nsid), ["com.atproto.repo.listRecords", "com.atproto.repo.createRecord"]); assert.deepEqual(calls[0].params, { repo: did, collection: "xyz.statusphere.status", limit: "1" }); assert.deepEqual(calls[1].input, { repo: did, collection: "xyz.statusphere.status", record: { $type: "xyz.statusphere.status", status: "🦋", createdAt: now }, }); assert.deepEqual(ran.result, { status: "🦋", unchanged: false, uri: `at://${did}/xyz.statusphere.status/new` }); }); test("set_status skips the write when the latest status already matches", async () => { const uri = `at://${did}/xyz.statusphere.status/same`; const ran = await handle("set_status", { status: "🦋" }, { respond: () => ({ ok: true, output: { records: [{ uri, value: { status: "🦋" } }] } }) }); assert.equal(ran.calls.length, 1); assert.deepEqual(ran.result, { status: "🦋", unchanged: true, uri }); }); test("set_status normalizes now to UTC milliseconds", () => { const out = run("set_status", { did, now: "2026-11-06T04:00:00-08:00", state: { status: "🙂" }, event: { type: "result", id: "list", nsid: "com.atproto.repo.listRecords", ok: true, output: { records: [] } }, }); assert.equal(out.calls[0].input.record.createdAt, "2026-11-06T12:00:00.000Z"); }); test("set_status rejects an empty status and an invalid now", () => { assert.match(run("set_status", start({ status: "" })).error, /status/); assert.match(run("set_status", start({ status: "🦋", now: "yesterday" })).error, /now/); }); test("a failed call surfaces as the module error", async () => { const ran = await handle("set_status", { status: "🦋" }, { respond: () => ({ ok: false, error: "listRecords failed with 500" }) }); assert.equal(ran.error, "listRecords failed with 500"); }); test("clear_status deletes every listed status", async () => { const records = ["a", "b", "c"].map((rkey) => ({ uri: `at://${did}/xyz.statusphere.status/${rkey}`, value: { status: "🦋" } })); const { calls, respond } = recorded((call) => call.nsid === "com.atproto.repo.listRecords" ? { ok: true, output: { records } } : { ok: call.input.rkey !== "c", output: {} }, ); // The harness host has no anyRecords, so deletes of records it did not create need runModule with module.json's. const { runModule } = await import("../../../javascript/src/run-module/index.js"); const ctx = { wasm: { run: async ({ entry, input }) => run(entry, { ...input, now }) } }; const call = async (nsid, request) => { const answer = respond({ nsid, ...request }); if (!answer.ok) throw new Error("delete failed"); return answer.output; }; const ran = await runModule(ctx, { module, anyRecords: ["xyz.statusphere.status"] }, "clear_status", { did }, call); assert.deepEqual( calls.slice(1).map((call) => [call.nsid, call.input.rkey]), [ ["com.atproto.repo.deleteRecord", "a"], ["com.atproto.repo.deleteRecord", "b"], ["com.atproto.repo.deleteRecord", "c"], ], ); assert.deepEqual(ran.result, { deleted: 2, failed: 1 }); }); test("clear_status with nothing to delete makes no delete calls", async () => { const ran = await handle("clear_status", {}, { respond: () => ({ ok: true, output: { records: [] } }) }); assert.equal(ran.calls.length, 1); assert.deepEqual(ran.result, { deleted: 0 }); }); // module.json anyRecords lets clear_status delete statuses other clients (or another host) created. test("runModule lets clear_status delete statuses it did not create only via anyRecords", async () => { const { runModule } = await import("../../../javascript/src/run-module/index.js"); const spec = JSON.parse(await (await import("node:fs/promises")).readFile(new URL("./module.json", import.meta.url), "utf8")); const ctx = { wasm: { run: async ({ entry, input }) => run(entry, input) } }; const records = [{ uri: `at://${did}/xyz.statusphere.status/a`, value: { status: "🦋" } }]; const call = async (nsid) => (nsid === "com.atproto.repo.listRecords" ? { records } : {}); const clear = (anyRecords) => runModule(ctx, { module, calls: spec.calls, anyRecords }, "clear_status", { did }, call); assert.deepEqual((await clear(spec.anyRecords)).result, { deleted: 1, failed: 0 }); const refused = await clear(undefined); assert.deepEqual(refused.result, { deleted: 0, failed: 1 }); assert.match(refused.calls[1].error, /not created by this module/); });