UNPKG

v0-ui-reviewer

Version:

Next-gen UI/UX reviewer with multi-model AI support (OpenAI, Claude, v0), style extraction, and live preview sandbox

70 lines (69 loc) 2.44 kB
import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; export class RateLimiter { dataPath; limits = { v0: { daily: 200, window: 24 * 60 * 60 * 1000 }, // 200/day openai: { daily: 10000, window: 60 * 1000 }, // 10k/min (simplified) anthropic: { daily: 1000, window: 60 * 1000 } // 1k/min (simplified) }; constructor() { this.dataPath = path.join(os.homedir(), '.v0-reviewer', 'rate-limits.json'); } async checkLimit(service) { const data = await this.loadData(); const now = Date.now(); const serviceData = data[service]; // Reset if window expired if (now > serviceData.resetAt) { serviceData.count = 0; serviceData.resetAt = now + this.limits[service].window; await this.saveData(data); } const limit = this.limits[service].daily; const remaining = Math.max(0, limit - serviceData.count); const allowed = remaining > 0; return { allowed, remaining, resetIn: allowed ? undefined : Math.ceil((serviceData.resetAt - now) / 1000) }; } async increment(service) { const data = await this.loadData(); data[service].count++; await this.saveData(data); } async getRemainingQuota(service) { const { remaining } = await this.checkLimit(service); return remaining; } async loadData() { try { const content = await fs.readFile(this.dataPath, 'utf-8'); return JSON.parse(content); } catch { // Initialize with empty data const now = Date.now(); return { v0: { count: 0, resetAt: now + this.limits.v0.window }, openai: { count: 0, resetAt: now + this.limits.openai.window }, anthropic: { count: 0, resetAt: now + this.limits.anthropic.window } }; } } async saveData(data) { await fs.mkdir(path.dirname(this.dataPath), { recursive: true }); await fs.writeFile(this.dataPath, JSON.stringify(data, null, 2)); } formatResetTime(seconds) { if (seconds < 60) return `${seconds}s`; if (seconds < 3600) return `${Math.ceil(seconds / 60)}m`; return `${Math.ceil(seconds / 3600)}h`; } } export default RateLimiter;