1import { describe, expect, it } from "vitest";2import type { PairedDevice } from "../shared/sync-types";3import {4 isRouteCapableMeshPeer,5 nextMeshWaiterRetryDelay,6 selectDialTargets,7 weDialMeshPeer,8} from "../shared/mesh-peer-role";910function peer(11 id: string,12 key: string,13 overrides: Partial<PairedDevice> = {},14): PairedDevice {15 return {16 deviceId: id,17 deviceName: id,18 deviceType: "extension",19 longTermPublicKeyHex: key,20 signingPublicKeyHex: "cc".repeat(32),21 rendezvousSecretHex: "dd".repeat(32),22 relayUrl: "wss://relay.peachpasswords.com",23 trustSource: "vouched",24 pairedAt: 1,25 ...overrides,26 };27}2829describe("mesh relay roles", () => {30 it("assigns exactly one dialer for every device-type combination", () => {31 const low = "11".repeat(32);32 const high = "ee".repeat(32);33 for (const deviceType of ["extension", "android", "ios"] as const) {34 expect(weDialMeshPeer(low, high)).toBe(true);35 expect(weDialMeshPeer(high, low)).toBe(false);36 expect(37 selectDialTargets(38 [peer(deviceType, high, { deviceType })],39 low,40 ).map((device) => device.deviceId),41 ).toEqual([deviceType]);42 }43 });4445 it("admits direct and vouched routes but rejects incomplete or unknown rows", () => {46 const key = "ee".repeat(32);47 expect(isRouteCapableMeshPeer(peer("direct", key, { trustSource: "direct" }))).toBe(true);48 expect(isRouteCapableMeshPeer(peer("vouched", key))).toBe(true);49 50 51 52 expect(isRouteCapableMeshPeer(peer("missing-secret", key, {53 rendezvousSecretHex: undefined,54 }))).toBe(true);55 expect(isRouteCapableMeshPeer(peer("printer", key, {56 deviceType: "printer" as PairedDevice["deviceType"],57 }))).toBe(false);58 59 expect(isRouteCapableMeshPeer(peer("no-trust", key, {60 trustSource: undefined,61 }))).toBe(false);62 expect(isRouteCapableMeshPeer(peer("unknown-trust", key, {63 trustSource: "mystery" as PairedDevice["trustSource"],64 }))).toBe(false);65 });6667 it("backs off failed waiter reconnects and resets after a completed round", () => {68 expect(nextMeshWaiterRetryDelay(2_000, false)).toBe(4_000);69 expect(nextMeshWaiterRetryDelay(20_000, false)).toBe(30_000);70 expect(nextMeshWaiterRetryDelay(30_000, true)).toBe(2_000);71 });72});