import fs from 'node:fs'; import path from 'node:path'; import type { CharacterSheet, SystemDefinition } from '../shared/types.ts'; import { validateSystemDefinition } from '../shared/systemValidate.ts'; type Meta = { systems: Record; characters: Record; }; export class AppStore { private readonly rootDir: string; private readonly dbPath: string; private data: Meta = { systems: {}, characters: {} }; constructor(dbPath: string) { // dbPath historically pointed at *.sqlite — keep parent dir, use store.json this.rootDir = path.dirname(dbPath); this.dbPath = path.join(this.rootDir, 'store.json'); fs.mkdirSync(this.rootDir, { recursive: true }); this.load(); } private load(): void { try { const raw = fs.readFileSync(this.dbPath, 'utf8'); const parsed = JSON.parse(raw) as Meta; this.data = { systems: parsed.systems ?? {}, characters: parsed.characters ?? {}, }; } catch { this.data = { systems: {}, characters: {} }; this.persist(); } } private persist(): void { fs.writeFileSync(this.dbPath, JSON.stringify(this.data, null, 2), 'utf8'); } listSystems(): Array<{ id: string; name: string; revision: number; schemaVersion: number }> { return Object.values(this.data.systems) .map((s) => ({ id: s.id, name: s.name, revision: s.revision, schemaVersion: s.schemaVersion, })) .sort((a, b) => a.name.localeCompare(b.name)); } getSystem(id: string): SystemDefinition | null { return this.data.systems[id] ?? null; } upsertSystem(system: SystemDefinition): SystemDefinition { const check = validateSystemDefinition(system); if (!check.ok) { throw new Error(check.errors.map((e) => e.message).join('; ')); } const existing = this.data.systems[system.id]; const next: SystemDefinition = { ...system, revision: existing ? existing.revision + 1 : system.revision || 1, }; this.data.systems[next.id] = next; this.persist(); return next; } deleteSystem(id: string): void { delete this.data.systems[id]; for (const [cid, ch] of Object.entries(this.data.characters)) { if (ch.systemId === id) delete this.data.characters[cid]; } this.persist(); } listCharacters(systemId?: string): Array<{ id: string; name: string; systemId: string }> { return Object.values(this.data.characters) .filter((c) => (systemId ? c.systemId === systemId : true)) .map((c) => ({ id: c.id, name: c.name, systemId: c.systemId })) .sort((a, b) => a.name.localeCompare(b.name)); } getCharacter(id: string): CharacterSheet | null { return this.data.characters[id] ?? null; } upsertCharacter(character: CharacterSheet): CharacterSheet { this.data.characters[character.id] = character; this.persist(); return character; } deleteCharacter(id: string): void { delete this.data.characters[id]; this.persist(); } close(): void { this.persist(); } }