/** Non-secret facts about the registered virtual device, in package storage. */ import { packageStorage } from 'kody:runtime' import { ARCHIVE_SIGNING_KEY, DEVICE_KEY } from './config.ts' export type DeviceRecord = { locale: string withUsername: boolean serial: string deviceType: string customerId?: string deviceName?: string connectedAt: string /** Unix seconds when the current access token expires. */ accessTokenExpiresAt: number /** Saved package id that owns the token secrets; builds host-approval links. */ packageId?: string /** First time an Audible call succeeded, which proves the hosts are approved. */ verifiedAt?: string } /** ADP signing material. Stored only while archive is enabled. */ export type ArchiveSigning = { adpToken: string devicePrivateKey: string } export class NotConnectedError extends Error { constructor() { super('Audible is not connected. Open the Connect tab in the Audible app.') this.name = 'NotConnectedError' } } function parse(raw: unknown): T | null { if (raw == null) return null if (typeof raw === 'string') { try { return JSON.parse(raw) as T } catch { return null } } return raw as T } export async function loadDevice(): Promise { const device = parse(await packageStorage().get(DEVICE_KEY)) return device?.serial && device.locale ? device : null } export async function requireDevice(): Promise { const device = await loadDevice() if (!device) throw new NotConnectedError() return device } export async function saveDevice(device: DeviceRecord): Promise { await packageStorage().set(DEVICE_KEY, device) } export async function clearDevice(): Promise { await packageStorage().delete(DEVICE_KEY) } export async function loadArchiveSigning(): Promise { const signing = parse(await packageStorage().get(ARCHIVE_SIGNING_KEY)) return signing?.adpToken && signing.devicePrivateKey ? signing : null } export async function saveArchiveSigning(signing: ArchiveSigning): Promise { await packageStorage().set(ARCHIVE_SIGNING_KEY, signing) } export async function clearArchiveSigning(): Promise { await packageStorage().delete(ARCHIVE_SIGNING_KEY) }