123456789101112131415export interface PendingVouchedDevice {16 deviceId: string;17 deviceName: string;18 deviceType: string;19 longTermPublicKeyHex: string;20 signingPublicKeyHex: string;21 wsPort?: number;22 23 pairedAt: number;24 receivedAt: number;25 26 vouchedByDeviceId: string;27}2829const PENDING_KEY = "peach_pending_vouched_devices_v1";30const MAX_PENDING = 50;3132export async function listPendingVouchedDevices(): Promise<PendingVouchedDevice[]> {33 try {34 const result = await chrome.storage.local.get(PENDING_KEY);35 const value = (result as Record<string, unknown>)[PENDING_KEY];36 if (!Array.isArray(value)) return [];37 return value.filter(isPendingVouchedDevice);38 } catch {39 return [];40 }41}424344export async function addPendingVouchedDevice(45 device: PendingVouchedDevice,46): Promise<void> {47 const pending = await listPendingVouchedDevices();48 const next = pending.filter((d) => d.deviceId !== device.deviceId);49 next.push(device);50 await chrome.storage.local.set({ [PENDING_KEY]: next.slice(-MAX_PENDING) });51}5253export async function getPendingVouchedDevice(54 deviceId: string,55): Promise<PendingVouchedDevice | null> {56 const pending = await listPendingVouchedDevices();57 return pending.find((d) => d.deviceId === deviceId) ?? null;58}5960export async function removePendingVouchedDevice(deviceId: string): Promise<void> {61 const pending = await listPendingVouchedDevices();62 await chrome.storage.local.set({63 [PENDING_KEY]: pending.filter((d) => d.deviceId !== deviceId),64 });65}6667function isPendingVouchedDevice(x: unknown): x is PendingVouchedDevice {68 if (typeof x !== "object" || x === null) return false;69 const r = x as Record<string, unknown>;70 return (71 typeof r.deviceId === "string" && !!r.deviceId &&72 typeof r.deviceName === "string" &&73 typeof r.deviceType === "string" &&74 typeof r.longTermPublicKeyHex === "string" &&75 /^[0-9a-f]{64}$/.test(r.longTermPublicKeyHex as string) &&76 typeof r.signingPublicKeyHex === "string" &&77 /^[0-9a-f]{64}$/.test(r.signingPublicKeyHex as string) &&78 typeof r.receivedAt === "number" &&79 typeof r.vouchedByDeviceId === "string"80 );81}