export interface RobotHotspotAdapterCandidate { ssid: string; signalPercent: number; connected: boolean; open: boolean; nativeKey: unknown; } export interface RobotHotspotAdapter { scan(signal: AbortSignal): Promise; connect(candidate: RobotHotspotAdapterCandidate, signal: AbortSignal): Promise; currentSsid(signal: AbortSignal): Promise; clear(): void; } export class RobotHotspotAdapterError extends Error { constructor(public readonly reason: 'unsupported' | 'permission_denied' | 'scan_failed' | 'connect_failed') { super(reason); this.name = 'RobotHotspotAdapterError'; } } export function throwIfAborted(signal: AbortSignal): void { if (signal.aborted) throw signal.reason; } export function abortableDelay(milliseconds: number, signal: AbortSignal): Promise { if (signal.aborted) return Promise.reject(signal.reason); return new Promise((resolve, reject) => { const timer = setTimeout(resolve, milliseconds); signal.addEventListener('abort', () => { clearTimeout(timer); reject(signal.reason); }, { once: true }); }); }