import type { PlayerCharacter } from "@initiative/domain"; import { playerCharacterId, VALID_PLAYER_COLORS, VALID_PLAYER_ICONS, } from "@initiative/domain"; const STORAGE_KEY = "initiative:player-characters"; export function savePlayerCharacters(characters: PlayerCharacter[]): void { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(characters)); } catch { // Silently swallow errors (quota exceeded, storage unavailable) } } function rehydrateCharacter(raw: unknown): PlayerCharacter | null { if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null; const entry = raw as Record; if (typeof entry.id !== "string" || entry.id.length === 0) return null; if (typeof entry.name !== "string" || entry.name.trim().length === 0) return null; if ( typeof entry.ac !== "number" || !Number.isInteger(entry.ac) || entry.ac < 0 ) return null; if ( typeof entry.maxHp !== "number" || !Number.isInteger(entry.maxHp) || entry.maxHp < 1 ) return null; if (typeof entry.color !== "string" || !VALID_PLAYER_COLORS.has(entry.color)) return null; if (typeof entry.icon !== "string" || !VALID_PLAYER_ICONS.has(entry.icon)) return null; return { id: playerCharacterId(entry.id), name: entry.name, ac: entry.ac, maxHp: entry.maxHp, color: entry.color as PlayerCharacter["color"], icon: entry.icon as PlayerCharacter["icon"], }; } export function loadPlayerCharacters(): PlayerCharacter[] { try { const raw = localStorage.getItem(STORAGE_KEY); if (raw === null) return []; const parsed: unknown = JSON.parse(raw); if (!Array.isArray(parsed)) return []; const characters: PlayerCharacter[] = []; for (const item of parsed) { const pc = rehydrateCharacter(item); if (pc !== null) { characters.push(pc); } } return characters; } catch { return []; } }