123456789101112131415import { capDeviceName } from "../shared/sync-limits";1617export interface PendingVouchedDevice {18 deviceId: string;19 deviceName: string;20 deviceType: string;21 longTermPublicKeyHex: string;22 signingPublicKeyHex: string;23 wsPort?: number;24 25 pairedAt: number;26 receivedAt: number;27 28 vouchedByDeviceId: string;29}3031const PENDING_KEY = "peach_pending_vouched_devices_v1";32const MAX_PENDING = 50;3334export async function listPendingVouchedDevices(): Promise<PendingVouchedDevice[]> {35 try {36 const result = await chrome.storage.local.get(PENDING_KEY);37 const value = (result as Record<string, unknown>)[PENDING_KEY];38 if (!Array.isArray(value)) return [];39 return value.filter(isPendingVouchedDevice);40 } catch {41 return [];42 }43}444546export async function addPendingVouchedDevice(47 device: PendingVouchedDevice,48): Promise<void> {49 50 51 device = { ...device, deviceName: capDeviceName(device.deviceName) };52 const pending = await listPendingVouchedDevices();53 const next = pending.filter((d) => d.deviceId !== device.deviceId);54 next.push(device);55 await chrome.storage.local.set({ [PENDING_KEY]: next.slice(-MAX_PENDING) });56}5758export async function getPendingVouchedDevice(59 deviceId: string,60): Promise<PendingVouchedDevice | null> {61 const pending = await listPendingVouchedDevices();62 return pending.find((d) => d.deviceId === deviceId) ?? null;63}6465export async function removePendingVouchedDevice(deviceId: string): Promise<void> {66 const pending = await listPendingVouchedDevices();67 await chrome.storage.local.set({68 [PENDING_KEY]: pending.filter((d) => d.deviceId !== deviceId),69 });70}7172function isPendingVouchedDevice(x: unknown): x is PendingVouchedDevice {73 if (typeof x !== "object" || x === null) return false;74 const r = x as Record<string, unknown>;75 return (76 typeof r.deviceId === "string" && !!r.deviceId &&77 typeof r.deviceName === "string" &&78 typeof r.deviceType === "string" &&79 typeof r.longTermPublicKeyHex === "string" &&80 /^[0-9a-f]{64}$/.test(r.longTermPublicKeyHex as string) &&81 typeof r.signingPublicKeyHex === "string" &&82 /^[0-9a-f]{64}$/.test(r.signingPublicKeyHex as string) &&83 typeof r.receivedAt === "number" &&84 typeof r.vouchedByDeviceId === "string"85 );86}