Centralize rate limiting config

Create shared rateLimitConfig.ts with tiers (strict, moderate, lenient, generous, per-user variants) and update edge functions to import centralized rate limiters. Replace inline rate limiter usage with new config, preserving backward compatibility. Add documentation guide for rate limiting usage.
This commit is contained in:
gpt-engineer-app[bot]
2025-11-10 21:33:08 +00:00
parent bf3da6414a
commit ed6ddbd04b
5 changed files with 495 additions and 38 deletions

View File

@@ -129,50 +129,56 @@ class RateLimiter {
}
}
// Export factory function for different rate limit tiers
// Import centralized rate limit configurations
import {
RATE_LIMIT_STRICT,
RATE_LIMIT_MODERATE,
RATE_LIMIT_STANDARD,
RATE_LIMIT_LENIENT,
RATE_LIMIT_GENEROUS,
RATE_LIMIT_PER_USER_STRICT,
RATE_LIMIT_PER_USER_MODERATE,
RATE_LIMIT_PER_USER_STANDARD,
RATE_LIMIT_PER_USER_LENIENT,
} from './rateLimitConfig.ts';
// Export factory function for creating custom rate limiters
export function createRateLimiter(config: RateLimitConfig): RateLimiter {
return new RateLimiter(config);
}
// Pre-configured rate limiters for common use cases
/**
* Pre-configured rate limiters using centralized tier definitions
*
* These are singleton instances that should be imported and used by edge functions.
* See rateLimitConfig.ts for detailed documentation on when to use each tier.
*/
export const rateLimiters = {
// Strict: For expensive operations (file uploads, data exports)
strict: createRateLimiter({
windowMs: 60000, // 1 minute
maxRequests: 5, // 5 requests per minute
}),
// Strict: 5 requests/minute - For expensive operations
strict: createRateLimiter(RATE_LIMIT_STRICT),
// Standard: For most API endpoints
standard: createRateLimiter({
windowMs: 60000, // 1 minute
maxRequests: 10, // 10 requests per minute
}),
// Moderate: 10 requests/minute - For moderation and submissions
moderate: createRateLimiter(RATE_LIMIT_MODERATE),
// Lenient: For read-only, cached endpoints
lenient: createRateLimiter({
windowMs: 60000, // 1 minute
maxRequests: 30, // 30 requests per minute
}),
// Standard: 20 requests/minute - For typical operations (DEPRECATED: use 'moderate' for 10/min or 'standard' for 20/min)
standard: createRateLimiter(RATE_LIMIT_MODERATE), // Keeping for backward compatibility
// Per-user: For authenticated endpoints (uses user ID as key)
// Lenient: 30 requests/minute - For lightweight reads
lenient: createRateLimiter(RATE_LIMIT_LENIENT),
// Generous: 60 requests/minute - For high-frequency operations
generous: createRateLimiter(RATE_LIMIT_GENEROUS),
// Per-user rate limiters (key by user ID instead of IP)
perUserStrict: createRateLimiter(RATE_LIMIT_PER_USER_STRICT),
perUserModerate: createRateLimiter(RATE_LIMIT_PER_USER_MODERATE),
perUserStandard: createRateLimiter(RATE_LIMIT_PER_USER_STANDARD),
perUserLenient: createRateLimiter(RATE_LIMIT_PER_USER_LENIENT),
// Legacy per-user factory function (DEPRECATED: use perUserStrict, perUserModerate, etc.)
perUser: (maxRequests: number = 20) => createRateLimiter({
windowMs: 60000,
...RATE_LIMIT_PER_USER_STANDARD,
maxRequests,
keyGenerator: (req: Request) => {
// Extract user ID from Authorization header JWT
const authHeader = req.headers.get('Authorization');
if (authHeader) {
try {
const token = authHeader.replace('Bearer ', '');
const payload = JSON.parse(atob(token.split('.')[1]));
return `user:${payload.sub}`;
} catch {
// Fall back to IP if JWT parsing fails
return req.headers.get('x-forwarded-for')?.split(',')[0] || '0.0.0.0';
}
}
return req.headers.get('x-forwarded-for')?.split(',')[0] || '0.0.0.0';
}
}),
};