import type { ArchivePlatesResponse, LibraryFilePlatesResponse } from '../types/plates'; const API_BASE = '/api/v1'; export class ApiError extends Error { status: number; constructor(message: string, status: number) { super(message); this.name = 'ApiError'; this.status = status; } } // Auth token storage // By default tokens are stored in sessionStorage (tab-scoped, cleared on close). // When the token originates from the ?token= URL param (kiosk bootstrap), it is // additionally persisted in localStorage so the kiosk survives page reloads. // 'persistent' also writes to localStorage so the token survives tab close // (used by Remember Me and the ?token= kiosk bootstrap). let authToken: string | null = sessionStorage.getItem('auth_token') ?? localStorage.getItem('auth_token'); export type TokenPersistence = 'session' | 'persistent'; export function setAuthToken(token: string | null, persistence: TokenPersistence = 'session') { authToken = token; try { if (token) { sessionStorage.setItem('auth_token', token); } else { sessionStorage.removeItem('auth_token'); } } catch (err) { // Storage unavailable (quota exceeded, private mode): in-memory token still works for this tab. console.warn('setAuthToken: sessionStorage unavailable, token kept in-memory only', err); } try { if (!token) { localStorage.removeItem('auth_token'); } else if (persistence === 'persistent') { localStorage.setItem('auth_token', token); } } catch (err) { console.warn('setAuthToken: localStorage operation failed', err); } } export function getAuthToken(): string | null { return authToken; } // Stream token for image/video URLs loaded via /