import fs from 'fs/promises'; import path from 'path'; const DATA_DIR = '/data'; const STORE_FILE = path.join(DATA_DIR, 'web-search-usage.json'); const APP_TIMEZONE = process.env.APP_TIMEZONE || 'America/New_York'; let state = { days: {} }; let loaded = false; let saveChain = Promise.resolve(); function todayKey() { return new Intl.DateTimeFormat('en-CA', { timeZone: APP_TIMEZONE, year: 'numeric', month: '2-digit', day: '2-digit', }).format(new Date()); } function pruneDays() { const keepKey = todayKey(); state.days = Object.fromEntries( Object.entries(state.days || {}).filter(([key]) => key === keepKey) ); } async function ensureLoaded() { if (loaded) return; loaded = true; try { await fs.mkdir(DATA_DIR, { recursive: true }); const raw = await fs.readFile(STORE_FILE, 'utf8'); const parsed = JSON.parse(raw); if (parsed && typeof parsed === 'object') state = parsed; } catch {} pruneDays(); } function saveState() { saveChain = saveChain.then(async () => { pruneDays(); await fs.mkdir(DATA_DIR, { recursive: true }); await fs.writeFile(STORE_FILE, JSON.stringify(state, null, 2), 'utf8'); }).catch((err) => { console.error('Failed to persist web search usage:', err); }); return saveChain; } function getCounterRecord(key) { const day = todayKey(); if (!state.days[day]) state.days[day] = {}; if (!state.days[day][key]) state.days[day][key] = 0; return { day, used: state.days[day][key], set(nextValue) { state.days[day][key] = nextValue; }, }; } export async function getWebSearchUsage(key, limit = 15) { await ensureLoaded(); const record = getCounterRecord(key); return { limit, used: record.used, remaining: Math.max(0, limit - record.used), window: record.day, period: 'daily', }; } export async function consumeWebSearchUsage(key, limit = 15) { await ensureLoaded(); const record = getCounterRecord(key); if (record.used >= limit) { return { allowed: false, ...(await getWebSearchUsage(key, limit)), }; } record.set(record.used + 1); await saveState(); return { allowed: true, ...(await getWebSearchUsage(key, limit)), }; }