rate-limit.ts 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import { Ratelimit } from "@upstash/ratelimit";
  2. import { Redis } from "@upstash/redis";
  3. // Lazy initialization to avoid errors when Redis env vars are not configured
  4. let _minuteRateLimit: Ratelimit | null = null;
  5. let _dailyRateLimit: Ratelimit | null = null;
  6. function getRedis(): Redis | null {
  7. const url = process.env.KV_REST_API_URL;
  8. const token = process.env.KV_REST_API_TOKEN;
  9. if (!url || !token) {
  10. return null;
  11. }
  12. return new Redis({ url, token });
  13. }
  14. // No-op rate limiter for when Redis is not configured
  15. const noopRateLimiter = {
  16. limit: async () => ({ success: true, limit: 0, remaining: 0, reset: 0 }),
  17. };
  18. // 10 requests per minute (sliding window)
  19. export const minuteRateLimit = {
  20. limit: async (identifier: string) => {
  21. if (!_minuteRateLimit) {
  22. const redis = getRedis();
  23. if (!redis) return noopRateLimiter.limit();
  24. _minuteRateLimit = new Ratelimit({
  25. redis,
  26. limiter: Ratelimit.slidingWindow(10, "1 m"),
  27. prefix: "ratelimit:minute",
  28. });
  29. }
  30. return _minuteRateLimit.limit(identifier);
  31. },
  32. };
  33. // 100 requests per day (fixed window)
  34. export const dailyRateLimit = {
  35. limit: async (identifier: string) => {
  36. if (!_dailyRateLimit) {
  37. const redis = getRedis();
  38. if (!redis) return noopRateLimiter.limit();
  39. _dailyRateLimit = new Ratelimit({
  40. redis,
  41. limiter: Ratelimit.fixedWindow(100, "1 d"),
  42. prefix: "ratelimit:daily",
  43. });
  44. }
  45. return _dailyRateLimit.limit(identifier);
  46. },
  47. };