import { describe, expect, it } from "vitest"; import type { PairedDevice } from "../shared/sync-types"; import { isRouteCapableMeshPeer, nextMeshWaiterRetryDelay, selectDialTargets, weDialMeshPeer, } from "../shared/mesh-peer-role"; function peer( id: string, key: string, overrides: Partial = {}, ): PairedDevice { return { deviceId: id, deviceName: id, deviceType: "extension", longTermPublicKeyHex: key, signingPublicKeyHex: "cc".repeat(32), rendezvousSecretHex: "dd".repeat(32), relayUrl: "wss://relay.peachpasswords.com", trustSource: "vouched", pairedAt: 1, ...overrides, }; } describe("mesh relay roles", () => { it("assigns exactly one dialer for every device-type combination", () => { const low = "11".repeat(32); const high = "ee".repeat(32); for (const deviceType of ["extension", "android", "ios"] as const) { expect(weDialMeshPeer(low, high)).toBe(true); expect(weDialMeshPeer(high, low)).toBe(false); expect( selectDialTargets( [peer(deviceType, high, { deviceType })], low, ).map((device) => device.deviceId), ).toEqual([deviceType]); } }); it("admits direct and vouched routes but rejects incomplete or unknown rows", () => { const key = "ee".repeat(32); expect(isRouteCapableMeshPeer(peer("direct", key, { trustSource: "direct" }))).toBe(true); expect(isRouteCapableMeshPeer(peer("vouched", key))).toBe(true); // PB-26-213: the public registry carries no reusable secrets, so their // absence no longer affects route capability — the secret resolves from // the encrypted pair-secret record (or trusted session) at dial time. expect(isRouteCapableMeshPeer(peer("missing-secret", key, { rendezvousSecretHex: undefined, }))).toBe(true); expect(isRouteCapableMeshPeer(peer("printer", key, { deviceType: "printer" as PairedDevice["deviceType"], }))).toBe(false); // PB-26-006: absent or unknown trustSource fails closed. expect(isRouteCapableMeshPeer(peer("no-trust", key, { trustSource: undefined, }))).toBe(false); expect(isRouteCapableMeshPeer(peer("unknown-trust", key, { trustSource: "mystery" as PairedDevice["trustSource"], }))).toBe(false); }); it("backs off failed waiter reconnects and resets after a completed round", () => { expect(nextMeshWaiterRetryDelay(2_000, false)).toBe(4_000); expect(nextMeshWaiterRetryDelay(20_000, false)).toBe(30_000); expect(nextMeshWaiterRetryDelay(30_000, true)).toBe(2_000); }); });