import { describe, expect, test } from "vitest"; import { encodeTid, nextTid } from "../app/lib/utils/tid.ts"; /** Regex from the AT Protocol TID syntax: 13 base32-sortable chars, top bit clear. */ const TID_RE = /^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/; const S32 = "234567abcdefghijklmnopqrstuvwxyz"; function decode(tid: string): { micros: bigint; clockId: bigint } { let n = 0n; for (const c of tid) n = n * 32n + BigInt(S32.indexOf(c)); return { micros: n >> 10n, clockId: n & 1023n }; } describe("encodeTid", () => { test("matches rkeys the PDS actually minted", () => { // Real rkeys pulled from prod, with their decoded write times. If our // encoding drifts from the PDS's these stop matching. expect(encodeTid(1786983086755000n, 363n)).toBe("3mtc3q3q57sff"); expect(encodeTid(1786983092839000n, 363n)).toBe("3mtc3qbjsmsff"); expect(encodeTid(1786983128892000n, 363n)).toBe("3mtc3rdw2n2ff"); }); test("round-trips", () => { const { micros, clockId } = decode(encodeTid(1786983086755000n, 363n)); expect(micros).toBe(1786983086755000n); expect(clockId).toBe(363n); }); test("sorts lexicographically by time", () => { const early = encodeTid(1786983086755000n, 1023n); const late = encodeTid(1786983092839000n, 0n); expect(early < late).toBe(true); }); }); describe("nextTid", () => { test("emits valid TIDs", () => { expect(nextTid()).toMatch(TID_RE); }); test("is strictly increasing within a single millisecond tick", () => { // A 10-photo gallery mints ~31 rkeys back to back; none may collide. const tids = Array.from({ length: 31 }, () => nextTid()); expect(new Set(tids).size).toBe(31); expect([...tids].sort()).toEqual(tids); for (const tid of tids) expect(tid).toMatch(TID_RE); }); test("encodes a timestamp close to now", () => { const before = BigInt(Date.now()) * 1000n; const { micros } = decode(nextTid()); const after = BigInt(Date.now()) * 1000n; expect(micros >= before).toBe(true); // Allow for the manual +1us stepping done by earlier tests in this file. expect(micros - after < 1_000_000n).toBe(true); }); });