type LogEntry = { id: number; message: string; kind: 'info' | 'warn' | 'error'; at: number; }; type AppState = { /** * Which top-level screen is showing. 'searching' auto-retries in the * background; 'permission' is the one-off WebUSB grant, which the browser * will not let us trigger without a click. */ view: 'status' | 'searching' | 'permission' | 'ready'; /** Shown while `view` is 'status'. */ message?: string; config?: import('web-gphoto2').Config; supportedOps?: import('web-gphoto2').SupportedOps; prefs: import('./settings.js').Prefs; seq: import('./intervalometer.js').SequenceState; log: LogEntry[]; settingsOpen: boolean; singleShotStatus: 'idle' | 'busy'; /** Whether the preview pane is currently filling the screen. */ fullscreen?: boolean; };