export interface TrustedNetwork { ssid?: string; bssid?: string; isTailscale: boolean; addedAt: number; } export interface PairedDevice { deviceId: string; displayName: string; x25519PublicKey: string; pairedAt: number; lastSeenAt?: number; lastSyncAt?: number; lastKnownIp?: string; } // A stripped-down device record propagated in SYNC_VAULT_SEND so every peer // learns the full mesh without re-pairing. No IP — IPs are ephemeral and // discovered fresh via subnet scan. export interface SyncableDevice { publicKeyHex: string; deviceName: string; pairedAt: number; } export type SyncMessage = | { type: 'SYNC_HELLO' } | { type: 'SYNC_VAULT_SEND'; blob: string; timestamp: number; license?: string; devices: SyncableDevice[] } | { type: 'SYNC_VAULT_ACK'; applied: boolean } | { type: 'SYNC_DONE' } | { type: 'SYNC_ERROR'; error: string }; export type SyncStatus = "synced" | "syncing" | "no_peers" | "not_trusted" | "offline"; /** * Pairing request received from a peer that needs user confirmation. * * The banner expires after 60 seconds (`expiresAt - receivedAt = 60_000`); * after that the popup hides the banner and the background drops the * request. The publicKeyHex is the peer's static X25519 identity — it * gets written to trusted devices on accept and discarded on reject. */ export interface IncomingPairingRequest { deviceName: string; publicKeyHex: string; receivedAt: number; expiresAt: number; /** * Connection id of the still-open pairing-only socket. The background's * RESPOND_INCOMING_PAIRING handler sends PAIR_ACCEPT or PAIR_REJECT over * this connection then disconnects. May be absent for synthetic test * injections that do not have a real connection behind them. */ connectionId?: string; }