import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync, copyFileSync } from 'fs'; import { resolve } from 'path'; import type { UnitsData } from '$lib/types'; // Path is relative to project root (where the server runs from) const DATA_DIR = resolve('data'); const DEFAULTS_DIR = resolve('defaults'); const UNITS_PATH = resolve(DATA_DIR, 'units.json'); const CONFIG_PATH = resolve(DATA_DIR, 'config.json'); const DEFAULT_UNITS_PATH = resolve(DEFAULTS_DIR, 'units.json'); const DEFAULT_CONFIG_PATH = resolve(DEFAULTS_DIR, 'config.json'); export interface AppConfig { adminPath: string; /** Label shown next to the YOLO mode toggle. Defaults to "YOLO mode". */ yoloLabel?: string; /** Description shown inline after the label. Defaults to "(cross-group conversions)". */ yoloDescription?: string; /** * Controls when the YOLO mode toggle is visible to users. * 'auto' — show only when more than one group is present (default) * 'never' — always hidden */ yoloVisibility?: 'auto' | 'never'; } /** Ensure data/ directory exists and seed missing files from defaults/. */ function ensureDataDir(): void { mkdirSync(DATA_DIR, { recursive: true }); if (!existsSync(UNITS_PATH) && existsSync(DEFAULT_UNITS_PATH)) { copyFileSync(DEFAULT_UNITS_PATH, UNITS_PATH); console.log('[humor-units] First run: seeded data/units.json from defaults/units.json'); } if (!existsSync(CONFIG_PATH) && existsSync(DEFAULT_CONFIG_PATH)) { copyFileSync(DEFAULT_CONFIG_PATH, CONFIG_PATH); console.log('[humor-units] First run: seeded data/config.json from defaults/config.json'); } } /** Read units.json synchronously. Seeds from defaults on first run. */ export function loadData(): UnitsData { ensureDataDir(); if (!existsSync(UNITS_PATH)) { throw new Error(`[humor-units] units.json not found at ${UNITS_PATH} and no default available.`); } const raw = readFileSync(UNITS_PATH, 'utf8'); return JSON.parse(raw) as UnitsData; } /** Write full UnitsData atomically (write to temp, rename). */ export function saveData(data: UnitsData): void { const tmp = UNITS_PATH + '.tmp'; writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf8'); renameSync(tmp, UNITS_PATH); } /** Read config.json synchronously. Seeds from defaults on first run. */ export function loadConfig(): AppConfig { ensureDataDir(); if (!existsSync(CONFIG_PATH)) { throw new Error(`[humor-units] config.json not found at ${CONFIG_PATH} and no default available.`); } const raw = readFileSync(CONFIG_PATH, 'utf8'); return JSON.parse(raw) as AppConfig; } /** Write config.json atomically. */ export function saveConfig(config: AppConfig): void { const tmp = CONFIG_PATH + '.tmp'; writeFileSync(tmp, JSON.stringify(config, null, 2) + '\n', 'utf8'); renameSync(tmp, CONFIG_PATH); }