rate-limit.ts 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import { Ratelimit } from "@upstash/ratelimit";
  2. import { Redis } from "@upstash/redis";
  3. let _minuteRateLimit: Ratelimit | null = null;
  4. let _dailyRateLimit: Ratelimit | null = null;
  5. function getRedis(): Redis | null {
  6. const url = process.env.KV_REST_API_URL;
  7. const token = process.env.KV_REST_API_TOKEN;
  8. if (!url || !token) {
  9. return null;
  10. }
  11. return new Redis({ url, token });
  12. }
  13. const noopRateLimiter = {
  14. limit: async () => ({ success: true, limit: 0, remaining: 0, reset: 0 }),
  15. };
  16. const MINUTE_LIMIT = Number(process.env.RATE_LIMIT_PER_MINUTE) || 10;
  17. const DAILY_LIMIT = Number(process.env.RATE_LIMIT_PER_DAY) || 100;
  18. export const minuteRateLimit = {
  19. limit: async (identifier: string) => {
  20. if (!_minuteRateLimit) {
  21. const redis = getRedis();
  22. if (!redis) return noopRateLimiter.limit();
  23. _minuteRateLimit = new Ratelimit({
  24. redis,
  25. limiter: Ratelimit.slidingWindow(MINUTE_LIMIT, "1 m"),
  26. prefix: "ratelimit:game-engine:minute",
  27. });
  28. }
  29. return _minuteRateLimit.limit(identifier);
  30. },
  31. };
  32. export const dailyRateLimit = {
  33. limit: async (identifier: string) => {
  34. if (!_dailyRateLimit) {
  35. const redis = getRedis();
  36. if (!redis) return noopRateLimiter.limit();
  37. _dailyRateLimit = new Ratelimit({
  38. redis,
  39. limiter: Ratelimit.fixedWindow(DAILY_LIMIT, "1 d"),
  40. prefix: "ratelimit:game-engine:daily",
  41. });
  42. }
  43. return _dailyRateLimit.limit(identifier);
  44. },
  45. };