/** * Rate Limit Metrics API * * Exposes rate limiting metrics for monitoring and analysis. * Requires admin/moderator authentication. */ import { createEdgeFunction } from '../_shared/edgeFunctionWrapper.ts'; import { getRecentMetrics, getMetricsStats, getFunctionMetrics, getUserMetrics, getIPMetrics, clearMetrics, } from '../_shared/rateLimitMetrics.ts'; interface QueryParams { action?: string; limit?: string; timeWindow?: string; functionName?: string; userId?: string; clientIP?: string; } const handler = async (req: Request, context: { supabase: any; user: any; span: any; requestId: string }) => { const { supabase, user } = context; // Check if user has admin or moderator role const { data: roles } = await supabase .from('user_roles') .select('role') .eq('user_id', user.id); const userRoles = roles?.map((r: any) => r.role) || []; const isAuthorized = userRoles.some((role: string) => ['admin', 'moderator', 'superuser'].includes(role) ); if (!isAuthorized) { throw new Error('Insufficient permissions'); } // Parse query parameters const url = new URL(req.url); const action = url.searchParams.get('action') || 'stats'; const limit = parseInt(url.searchParams.get('limit') || '100', 10); const timeWindow = parseInt(url.searchParams.get('timeWindow') || '60000', 10); const functionName = url.searchParams.get('functionName'); const userId = url.searchParams.get('userId'); const clientIP = url.searchParams.get('clientIP'); let responseData: any; // Route to appropriate metrics handler switch (action) { case 'recent': responseData = { metrics: getRecentMetrics(limit), count: getRecentMetrics(limit).length, }; break; case 'stats': responseData = getMetricsStats(timeWindow); break; case 'function': if (!functionName) { throw new Error('functionName parameter required for function action'); } responseData = { functionName, metrics: getFunctionMetrics(functionName, limit), count: getFunctionMetrics(functionName, limit).length, }; break; case 'user': if (!userId) { throw new Error('userId parameter required for user action'); } responseData = { userId, metrics: getUserMetrics(userId, limit), count: getUserMetrics(userId, limit).length, }; break; case 'ip': if (!clientIP) { throw new Error('clientIP parameter required for ip action'); } responseData = { clientIP, metrics: getIPMetrics(clientIP, limit), count: getIPMetrics(clientIP, limit).length, }; break; case 'clear': // Only superusers can clear metrics const isSuperuser = userRoles.includes('superuser'); if (!isSuperuser) { throw new Error('Only superusers can clear metrics'); } clearMetrics(); responseData = { success: true, message: 'Metrics cleared' }; break; default: throw new Error('Invalid action. Valid actions: recent, stats, function, user, ip, clear'); } return responseData; }; // Create edge function with automatic error handling, CORS, auth, and logging createEdgeFunction( { name: 'rate-limit-metrics', requireAuth: true, corsEnabled: true, enableTracing: false, rateLimitTier: 'lenient' }, handler );