Spaces:
Sleeping
Sleeping
assafvayner HF Staff
fix(app): 503 on storage failures, validated currency, lock release on shutdown, per-IP login limit, unit-only npm test
e830ad4 | 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/<namespace>/<name>'); | |
| 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 | |
| }; | |
| } | |