1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// node --test web/marque/marque-cubit.test.mjs (after `cargo wasm`)
// The cubit with the real marque module, runModule and the Node wasm runner; only OAuth, the PLC
// directory and the PDS are stubbed.
import assert from "node:assert/strict";
import { mkdtemp } from "node:fs/promises";
import { registerHooks } from "node:module";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { test } from "node:test";
// The page resolves atlibs/ through its import map; Node gets the same mapping here.
registerHooks({
resolve(specifier, context, next) {
const lib = specifier.startsWith("atlibs/") && new URL(`../../../atlibs/javascript/src/${specifier.slice("atlibs/".length)}`, import.meta.url).href;
return next(lib || specifier, context);
},
});
const { MarqueCubit } = await import("./marque-cubit.js");
const { localModule } = await import("../../../atlibs/javascript/src/run-module/index.js");
const { createNodeContext, fileFetch } = await import("../../../atlibs/javascript/src/server/index.js");
const did = "did:plc:lpfuqerea3deuoyrn7ojser4";
const modules = new URL("./modules/", import.meta.url);
const domainUri = `at://${did}/at.marque.domain/example.com`;
// One PDS: a domain and its zone. Public reads come through fetch, the session's writes through fetchHandler.
function world() {
const domain = { uri: domainUri, cid: "bafyd", value: { $type: "at.marque.domain", domain: "example.com", status: "active", expiresAt: "2027-09-24T00:00:00Z" } };
const zone = { uri: `at://${did}/at.marque.dns/example.com`, cid: "bafyz1", value: { $type: "at.marque.dns", domain: "example.com", subject: { uri: domainUri, cid: "bafyd" }, records: [{ name: "@", recordType: "A", value: "192.0.2.1", ttl: 60 }], createdAt: "2026-01-01T00:00:00Z" } };
const writes = [];
const read = (url) => {
const q = new URL(url).searchParams;
if (url.includes("com.atproto.repo.listRecords")) return Response.json({ records: [domain] });
if (q.get("collection") === "at.marque.domain") return Response.json(domain);
return Response.json(zone);
};
async function fetch(url) {
if (url === `https://plc.directory/${did}`) return Response.json({ service: [{ id: "#atproto_pds", serviceEndpoint: "https://pds.example" }] });
if (url.startsWith("https://pds.example/xrpc/com.atproto.repo.")) return read(url);
return new Response("not found", { status: 404 });
}
const session = {
did,
async fetchHandler(path, init) {
if (path === "/xrpc/com.atproto.repo.putRecord") {
const body = JSON.parse(init.body);
writes.push(body);
if (body.swapRecord !== zone.cid) return Response.json({ error: "InvalidSwap" }, { status: 400 });
Object.assign(zone, { cid: `bafyz${writes.length + 1}`, value: body.record });
return Response.json({ uri: zone.uri, cid: zone.cid });
}
return Response.json({ error: "InvalidRequest" }, { status: 400 });
},
};
return { fetch, session, writes, zone };
}
async function cubitWith(signedIn, fetch) {
const ctx = createNodeContext({ id: "marque-test", stateDir: await mkdtemp(join(tmpdir(), "marque-")), fetch });
const client = Promise.resolve({ init: async () => signedIn && { session: signedIn }, signIn: async () => {}, revoke: async () => {} });
const marque = localModule(new URL("marque.wasm", modules), new URL("marque.json", modules), fileFetch);
const cubit = new MarqueCubit({ ctx, client, marque });
await cubit.init();
return cubit;
}
test("signed out: any account's domains and zone are public reads", async () => {
const { fetch } = world();
const cubit = await cubitWith(undefined, fetch);
assert.equal(cubit.state.session, "signed-out");
await cubit.domains(did);
assert.deepEqual(cubit.state.domains.result.domains.map((d) => d.domain), ["example.com"]);
await cubit.open("example.com");
assert.equal(cubit.state.zone.result.records[0].value, "192.0.2.1");
await cubit.change("create_record", { name: "www", type: "A", value: "192.0.2.2" });
assert.match(cubit.state.change.error, /may not call com.atproto.repo.putRecord|needs a session/);
});
test("signed in: lists on init, then adds, changes and removes records through the session", async () => {
const { fetch, session, writes, zone } = world();
const cubit = await cubitWith(session, fetch);
assert.equal(cubit.state.did, did);
assert.deepEqual(cubit.state.domains.result.domains.map((d) => d.domain), ["example.com"]);
await cubit.open("example.com");
await cubit.change("create_record", { name: "_atproto", type: "TXT", value: `did=${did}`, ttl: "", priority: "" });
assert.equal(cubit.state.change.status, "done", cubit.state.change.error ?? JSON.stringify(cubit.state));
assert.deepEqual(cubit.state.zone.result.records.map((r) => r.name), ["@", "_atproto"], "the zone is reloaded after a change");
await cubit.change("update_record", { name: "@", type: "A", value: "192.0.2.1", newName: "", newValue: "192.0.2.9", ttl: "300", priority: "" });
assert.equal(cubit.state.change.status, "done", cubit.state.change.error ?? JSON.stringify(cubit.state));
await cubit.change("delete_record", { name: "_atproto", type: "TXT", value: `did=${did}` });
assert.deepEqual(zone.value.records, [{ name: "@", recordType: "A", value: "192.0.2.9", ttl: 300 }]);
assert.deepEqual(writes.map((w) => [w.collection, w.rkey, w.swapRecord]), [
["at.marque.dns", "example.com", "bafyz1"],
["at.marque.dns", "example.com", "bafyz2"],
["at.marque.dns", "example.com", "bafyz3"],
]);
await cubit.change("create_record", { name: "x", type: "MX", value: "mail.example.com" });
assert.match(cubit.state.change.error, /priority/);
assert.equal(writes.length, 3);
});