import { env } from '$env/dynamic/private'; import { dev } from '$app/environment'; export interface Config { storage: 'local' | 'hf'; hfToken: string; hfBucket: `buckets/${string}`; /** Directory inside the bucket that this deployment owns; '' means the bucket root. */ hfPrefix: string; localDataDir: string; sessionSecret: string; currency: string; compactionIntervalMs: number; } function required(name: string, value: string | undefined): string { if (!value) throw new Error(`Missing required environment variable ${name}`); return value; } export function loadConfig(): Config { const storage = (env.STORAGE ?? (dev ? 'local' : 'hf')) as Config['storage']; if (storage !== 'local' && storage !== 'hf') throw new Error(`STORAGE must be 'local' or 'hf', got '${storage}'`); const sessionSecret = env.SESSION_SECRET ?? (dev ? 'dev-only-session-secret-do-not-use-in-prod' : undefined); const hfBucket = storage === 'hf' ? required('HF_BUCKET', env.HF_BUCKET) : ''; if (storage === 'hf' && !hfBucket.startsWith('buckets/')) throw new Error('HF_BUCKET must look like buckets//'); const secret = required('SESSION_SECRET', sessionSecret); if (!dev && secret.length < 32) throw new Error('SESSION_SECRET must be at least 32 characters in production'); const compactionIntervalMs = Number(env.COMPACTION_INTERVAL_MS ?? 3_600_000); if (!Number.isFinite(compactionIntervalMs) || compactionIntervalMs < 60_000) throw new Error('COMPACTION_INTERVAL_MS must be a number of milliseconds ≥ 60000'); const currency = env.CURRENCY ?? 'USD'; if (!/^[A-Z]{3}$/.test(currency)) throw new Error('CURRENCY must be a 3-letter uppercase ISO 4217 code'); return { storage, hfToken: storage === 'hf' ? required('HF_TOKEN', env.HF_TOKEN) : '', hfBucket: hfBucket as `buckets/${string}`, hfPrefix: (env.HF_PREFIX ?? '').replace(/^\/+|\/+$/g, ''), localDataDir: env.LOCAL_DATA_DIR ?? '.data', sessionSecret: secret, currency, compactionIntervalMs }; }