1import type { AdoptRequest } from "../shared/vault-adopt";2import type { PairedDevice } from "../shared/sync-types";3import { storageGet, storageRemove, storageSet } from "../shared/storage";45export const PENDING_ADOPTION_HOLDER_KEY = "peach_pending_adoption_holder_v1";6export const PENDING_ADOPTION_IDENTITY_KEY = "peach_pending_adoption_identity_v2";78export type PendingAdoptionHolder = {9 request: AdoptRequest;10 createdAt: number;11};1213export type PendingAdoptionIdentity = {14 device: PairedDevice;15 createdAt: number;16};1718function isHolder(value: unknown): value is PendingAdoptionHolder {19 if (!value || typeof value !== "object") return false;20 const holder = value as Partial<PendingAdoptionHolder>;21 return typeof holder.createdAt === "number" && Number.isFinite(holder.createdAt)22 && !!holder.request && typeof holder.request === "object"23 && typeof (holder.request as Partial<AdoptRequest>).device_id === "string";24}2526export async function persistPendingAdoptionHolder(request: AdoptRequest): Promise<void> {27 await storageSet(PENDING_ADOPTION_HOLDER_KEY, JSON.stringify({ request, createdAt: Date.now() }));28}293031export async function readPendingAdoptionHolder(): Promise<PendingAdoptionHolder | null> {32 const raw = await storageGet(PENDING_ADOPTION_HOLDER_KEY);33 if (!raw) return null;34 try {35 const parsed: unknown = JSON.parse(raw);36 return isHolder(parsed) ? parsed : null;37 } catch {38 return null;39 }40}4142export async function listPendingAdoptionHolders(): Promise<Array<PendingAdoptionHolder | PendingAdoptionIdentity>> {43 const [holder, identity] = await Promise.all([44 readPendingAdoptionHolder(),45 readPendingAdoptionIdentity(),46 ]);47 return [holder, identity].filter((value): value is PendingAdoptionHolder | PendingAdoptionIdentity => value !== null);48}4950export async function removePendingAdoptionHolder(): Promise<void> {51 await Promise.all([52 storageRemove(PENDING_ADOPTION_HOLDER_KEY),53 storageRemove(PENDING_ADOPTION_IDENTITY_KEY),54 ]);55}5657export const revokePendingAdoptionHolder = removePendingAdoptionHolder;5859export async function persistPendingAdoptionIdentity(60 device: PairedDevice,61 createdAt: number,62): Promise<boolean> {63 await storageSet(PENDING_ADOPTION_IDENTITY_KEY, JSON.stringify({ device, createdAt }));64 return true;65}6667export async function readPendingAdoptionIdentity(): Promise<PendingAdoptionIdentity | null> {68 const raw = await storageGet(PENDING_ADOPTION_IDENTITY_KEY);69 if (!raw) return null;70 try {71 const value = JSON.parse(raw) as { device?: PairedDevice; createdAt?: number };72 return value.device?.deviceId && Number.isFinite(value.createdAt)73 ? { device: value.device, createdAt: value.createdAt as number }74 : null;75 } catch {76 return null;77 }78}7980export async function completePendingAdoptionIdentity(device: PairedDevice): Promise<void> {81 const pending = await readPendingAdoptionIdentity();82 if (pending?.device.deviceId === device.deviceId &&83 pending.device.longTermPublicKeyHex === device.longTermPublicKeyHex) {84 await storageRemove(PENDING_ADOPTION_IDENTITY_KEY);85 }86}