sync-storage.ts

4.6 KB · raw

1import type { TrustedNetwork, PairedDevice, IncomingPairingRequest } from '../shared/sync-types';23const TRUSTED_NETWORKS_KEY = 'peach_trusted_networks';4const PAIRED_DEVICES_KEY = 'peach_paired_devices';5const INCOMING_PAIR_KEY = 'peach_incoming_pair';6const PEACH_HAS_PAIRED_KEY = 'peach_has_paired';78// ---------------------------------------------------------------------------9// Has-paired flag10//11// Set once on first successful pairing. Never cleared — controls whether the12// sync info sheet is shown.13// ---------------------------------------------------------------------------1415export async function getHasPaired(): Promise<boolean> {16  try {17    const result = await chrome.storage.local.get(PEACH_HAS_PAIRED_KEY);18    return (result as Record<string, unknown>)[PEACH_HAS_PAIRED_KEY] === true;19  } catch {20    return false;21  }22}2324export async function setHasPaired(): Promise<void> {25  await chrome.storage.local.set({ [PEACH_HAS_PAIRED_KEY]: true });26}2728// ---------------------------------------------------------------------------29// Trusted Networks30// ---------------------------------------------------------------------------3132export async function getTrustedNetworks(): Promise<TrustedNetwork[]> {33  try {34    const result = await chrome.storage.local.get(TRUSTED_NETWORKS_KEY);35    return (result as { peach_trusted_networks?: TrustedNetwork[] })[TRUSTED_NETWORKS_KEY] ?? [];36  } catch {37    return [];38  }39}4041export async function addTrustedNetwork(network: TrustedNetwork): Promise<void> {42  try {43    const networks = await getTrustedNetworks();44    networks.push(network);45    await chrome.storage.local.set({ [TRUSTED_NETWORKS_KEY]: networks });46  } catch (err) {47    throw new Error(`Failed to add trusted network: ${err}`);48  }49}5051export async function removeTrustedNetwork(addedAt: number): Promise<void> {52  try {53    const networks = await getTrustedNetworks();54    const filtered = networks.filter((n) => n.addedAt !== addedAt);55    await chrome.storage.local.set({ [TRUSTED_NETWORKS_KEY]: filtered });56  } catch (err) {57    throw new Error(`Failed to remove trusted network: ${err}`);58  }59}6061// ---------------------------------------------------------------------------62// Paired Devices63// ---------------------------------------------------------------------------6465export async function getPairedDevices(): Promise<PairedDevice[]> {66  try {67    const result = await chrome.storage.local.get(PAIRED_DEVICES_KEY);68    return (result as { peach_paired_devices?: PairedDevice[] })[PAIRED_DEVICES_KEY] ?? [];69  } catch {70    return [];71  }72}7374export async function addPairedDevice(device: PairedDevice): Promise<void> {75  try {76    const devices = await getPairedDevices();77    const exists = devices.some((d) => d.deviceId === device.deviceId);78    if (exists) throw new Error(`Device ${device.deviceId} is already paired`);79    devices.push(device);80    await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: devices });81  } catch (err) {82    throw new Error(`Failed to add paired device: ${err}`);83  }84}8586export async function removePairedDevice(deviceId: string): Promise<void> {87  try {88    const devices = await getPairedDevices();89    const filtered = devices.filter((d) => d.deviceId !== deviceId);90    await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: filtered });91  } catch (err) {92    throw new Error(`Failed to remove paired device: ${err}`);93  }94}9596// ---------------------------------------------------------------------------97// Incoming Pairing Request98//99// Stored in session storage so the request disappears when the browser closes100// and never lands on disk. The 60-second expiry is enforced by the consumer101// (`getIncomingPairingRequest` returns null past expiry and clears storage).102// ---------------------------------------------------------------------------103104export async function setIncomingPairingRequest(105  request: IncomingPairingRequest106): Promise<void> {107  await chrome.storage.session.set({ [INCOMING_PAIR_KEY]: request });108}109110export async function getIncomingPairingRequest(): Promise<IncomingPairingRequest | null> {111  try {112    const result = await chrome.storage.session.get(INCOMING_PAIR_KEY);113    const request = (result as { peach_incoming_pair?: IncomingPairingRequest })[INCOMING_PAIR_KEY];114    if (!request) return null;115    if (Date.now() >= request.expiresAt) {116      await clearIncomingPairingRequest();117      return null;118    }119    return request;120  } catch {121    return null;122  }123}124125export async function clearIncomingPairingRequest(): Promise<void> {126  try {127    await chrome.storage.session.remove(INCOMING_PAIR_KEY);128  } catch {129    // session storage may be unavailable in some contexts; safe to ignore.130  }131}