/** * Rate Limit Analytics Endpoint * GET /api/analytics/rate-limits * * View Drift RPC rate limit occurrences for monitoring and optimization */ import { NextResponse } from 'next/server' import { getPrismaClient } from '@/lib/database/trades' export async function GET() { try { const prisma = getPrismaClient() // Get rate limit events from last 7 days const sevenDaysAgo = new Date() sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7) const rateLimitEvents = await prisma.systemEvent.findMany({ where: { eventType: { in: ['rate_limit_hit', 'rate_limit_recovered', 'rate_limit_exhausted'] }, createdAt: { gte: sevenDaysAgo } }, orderBy: { createdAt: 'desc' }, take: 100 }) // Calculate statistics const stats = { total_hits: rateLimitEvents.filter(e => e.eventType === 'rate_limit_hit').length, total_recovered: rateLimitEvents.filter(e => e.eventType === 'rate_limit_recovered').length, total_exhausted: rateLimitEvents.filter(e => e.eventType === 'rate_limit_exhausted').length, // Group by hour to see patterns by_hour: {} as Record, // Average recovery time avg_recovery_time_ms: 0, max_recovery_time_ms: 0, } // Process recovery times const recoveredEvents = rateLimitEvents.filter(e => e.eventType === 'rate_limit_recovered') if (recoveredEvents.length > 0) { const recoveryTimes = recoveredEvents .map(e => (e.details as any)?.totalTimeMs) .filter(t => typeof t === 'number') if (recoveryTimes.length > 0) { stats.avg_recovery_time_ms = recoveryTimes.reduce((a, b) => a + b, 0) / recoveryTimes.length stats.max_recovery_time_ms = Math.max(...recoveryTimes) } } // Group by hour rateLimitEvents.forEach(event => { const hour = event.createdAt.getHours() stats.by_hour[hour] = (stats.by_hour[hour] || 0) + 1 }) return NextResponse.json({ success: true, stats, recent_events: rateLimitEvents.slice(0, 20).map(e => ({ type: e.eventType, message: e.message, details: e.details, timestamp: e.createdAt.toISOString(), })), analysis: { recovery_rate: stats.total_hits > 0 ? `${((stats.total_recovered / stats.total_hits) * 100).toFixed(1)}%` : 'N/A', failure_rate: stats.total_hits > 0 ? `${((stats.total_exhausted / stats.total_hits) * 100).toFixed(1)}%` : 'N/A', avg_recovery_time: stats.avg_recovery_time_ms > 0 ? `${(stats.avg_recovery_time_ms / 1000).toFixed(1)}s` : 'N/A', max_recovery_time: stats.max_recovery_time_ms > 0 ? `${(stats.max_recovery_time_ms / 1000).toFixed(1)}s` : 'N/A', } }) } catch (error) { console.error('❌ Rate limit analytics error:', error) return NextResponse.json({ success: false, error: error instanceof Error ? error.message : 'Unknown error' }, { status: 500 }) } }