atproto user agency toolkit for individuals and groups
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 250 lines 6.5 kB view raw
1import { describe, it, expect, beforeAll } from "vitest"; 2import { 3 loadP2pdsLexicons, 4 getLexicon, 5 validateP2pdsRecord, 6} from "./lexicons.js"; 7 8describe("lexicons", () => { 9 beforeAll(() => { 10 loadP2pdsLexicons(); 11 }); 12 13 describe("loadP2pdsLexicons", () => { 14 it("loads peer and offer lexicons", () => { 15 const peer = getLexicon("org.p2pds.peer"); 16 const offer = getLexicon("org.p2pds.replication.offer"); 17 18 expect(peer).toBeDefined(); 19 expect(peer!.id).toBe("org.p2pds.peer"); 20 expect(peer!.lexicon).toBe(1); 21 expect(peer!.defs.main.type).toBe("record"); 22 23 expect(offer).toBeDefined(); 24 expect(offer!.id).toBe("org.p2pds.replication.offer"); 25 expect(offer!.defs.main.type).toBe("record"); 26 }); 27 28 it("peer lexicon has correct schema", () => { 29 const peer = getLexicon("org.p2pds.peer")!; 30 const props = peer.defs.main.record.properties; 31 const required = peer.defs.main.record.required; 32 33 expect(required).toContain("peerId"); 34 expect(required).toContain("multiaddrs"); 35 expect(required).toContain("createdAt"); 36 37 expect(props.peerId.type).toBe("string"); 38 expect(props.multiaddrs.type).toBe("array"); 39 expect(props.createdAt.type).toBe("string"); 40 expect(props.createdAt.format).toBe("datetime"); 41 }); 42 43 it("offer lexicon has correct schema", () => { 44 const offer = getLexicon("org.p2pds.replication.offer")!; 45 const props = offer.defs.main.record.properties; 46 const required = offer.defs.main.record.required; 47 48 expect(required).toContain("subject"); 49 expect(required).toContain("minCopies"); 50 expect(required).toContain("intervalSec"); 51 expect(required).toContain("priority"); 52 expect(required).toContain("createdAt"); 53 54 expect(props.subject.type).toBe("string"); 55 expect(props.subject.format).toBe("did"); 56 expect(props.minCopies.type).toBe("integer"); 57 expect(props.priority.maximum).toBe(100); 58 }); 59 }); 60 61 describe("validateP2pdsRecord — org.p2pds.peer", () => { 62 const validPeer = { 63 $type: "org.p2pds.peer", 64 peerId: "12D3KooWNvSZnPi3RrhrTwEY4LuuBeB6K6facKUCJcyWG1aoDd2p", 65 multiaddrs: ["/ip4/127.0.0.1/tcp/4001"], 66 createdAt: "2026-01-15T10:30:00.000Z", 67 }; 68 69 it("accepts a valid peer record", () => { 70 expect(() => 71 validateP2pdsRecord("org.p2pds.peer", validPeer), 72 ).not.toThrow(); 73 }); 74 75 it("rejects missing peerId", () => { 76 const { peerId: _, ...bad } = validPeer; 77 expect(() => 78 validateP2pdsRecord("org.p2pds.peer", bad), 79 ).toThrow("Missing required field: peerId"); 80 }); 81 82 it("rejects missing multiaddrs", () => { 83 const { multiaddrs: _, ...bad } = validPeer; 84 expect(() => 85 validateP2pdsRecord("org.p2pds.peer", bad), 86 ).toThrow("Missing required field: multiaddrs"); 87 }); 88 89 it("rejects missing createdAt", () => { 90 const { createdAt: _, ...bad } = validPeer; 91 expect(() => 92 validateP2pdsRecord("org.p2pds.peer", bad), 93 ).toThrow("Missing required field: createdAt"); 94 }); 95 96 it("rejects non-string peerId", () => { 97 expect(() => 98 validateP2pdsRecord("org.p2pds.peer", { 99 ...validPeer, 100 peerId: 123, 101 }), 102 ).toThrow("must be a string"); 103 }); 104 105 it("rejects non-array multiaddrs", () => { 106 expect(() => 107 validateP2pdsRecord("org.p2pds.peer", { 108 ...validPeer, 109 multiaddrs: "not-an-array", 110 }), 111 ).toThrow("must be an array"); 112 }); 113 114 it("rejects invalid datetime", () => { 115 expect(() => 116 validateP2pdsRecord("org.p2pds.peer", { 117 ...validPeer, 118 createdAt: "not-a-date", 119 }), 120 ).toThrow("valid datetime"); 121 }); 122 123 it("accepts empty multiaddrs array", () => { 124 expect(() => 125 validateP2pdsRecord("org.p2pds.peer", { 126 ...validPeer, 127 multiaddrs: [], 128 }), 129 ).not.toThrow(); 130 }); 131 132 it("rejects non-string items in multiaddrs", () => { 133 expect(() => 134 validateP2pdsRecord("org.p2pds.peer", { 135 ...validPeer, 136 multiaddrs: [123], 137 }), 138 ).toThrow("must be a string"); 139 }); 140 }); 141 142 describe("validateP2pdsRecord — org.p2pds.replication.offer", () => { 143 const validOffer = { 144 $type: "org.p2pds.replication.offer", 145 subject: "did:plc:abc123", 146 minCopies: 2, 147 intervalSec: 600, 148 priority: 50, 149 createdAt: "2026-01-15T10:30:00.000Z", 150 }; 151 152 it("accepts a valid offer record", () => { 153 expect(() => 154 validateP2pdsRecord("org.p2pds.replication.offer", validOffer), 155 ).not.toThrow(); 156 }); 157 158 it("rejects missing subject", () => { 159 const { subject: _, ...bad } = validOffer; 160 expect(() => 161 validateP2pdsRecord("org.p2pds.replication.offer", bad), 162 ).toThrow("Missing required field: subject"); 163 }); 164 165 it("rejects non-DID subject", () => { 166 expect(() => 167 validateP2pdsRecord("org.p2pds.replication.offer", { 168 ...validOffer, 169 subject: "not-a-did", 170 }), 171 ).toThrow("must be a valid DID"); 172 }); 173 174 it("rejects non-integer minCopies", () => { 175 expect(() => 176 validateP2pdsRecord("org.p2pds.replication.offer", { 177 ...validOffer, 178 minCopies: 1.5, 179 }), 180 ).toThrow("must be an integer"); 181 }); 182 183 it("rejects minCopies below minimum", () => { 184 expect(() => 185 validateP2pdsRecord("org.p2pds.replication.offer", { 186 ...validOffer, 187 minCopies: 0, 188 }), 189 ).toThrow(">= 1"); 190 }); 191 192 it("rejects priority above maximum", () => { 193 expect(() => 194 validateP2pdsRecord("org.p2pds.replication.offer", { 195 ...validOffer, 196 priority: 101, 197 }), 198 ).toThrow("<= 100"); 199 }); 200 201 it("rejects priority below minimum", () => { 202 expect(() => 203 validateP2pdsRecord("org.p2pds.replication.offer", { 204 ...validOffer, 205 priority: -1, 206 }), 207 ).toThrow(">= 0"); 208 }); 209 210 it("accepts boundary values", () => { 211 expect(() => 212 validateP2pdsRecord("org.p2pds.replication.offer", { 213 ...validOffer, 214 minCopies: 1, 215 priority: 0, 216 intervalSec: 1, 217 }), 218 ).not.toThrow(); 219 220 expect(() => 221 validateP2pdsRecord("org.p2pds.replication.offer", { 222 ...validOffer, 223 priority: 100, 224 }), 225 ).not.toThrow(); 226 }); 227 }); 228 229 describe("validateP2pdsRecord — unknown NSID", () => { 230 it("throws for unknown NSID", () => { 231 expect(() => 232 validateP2pdsRecord("org.p2pds.unknown", {}), 233 ).toThrow("No lexicon loaded for NSID"); 234 }); 235 }); 236 237 describe("validateP2pdsRecord — non-object", () => { 238 it("rejects null", () => { 239 expect(() => 240 validateP2pdsRecord("org.p2pds.peer", null), 241 ).toThrow("must be an object"); 242 }); 243 244 it("rejects string", () => { 245 expect(() => 246 validateP2pdsRecord("org.p2pds.peer", "string"), 247 ).toThrow("must be an object"); 248 }); 249 }); 250});