File size: 2,098 Bytes
65d68f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import { useState, useCallback } from "react";
import { classifyError } from "@/lib/api/errorTypes";
import { isApiError, type RateLimitScope } from "@/lib/api/client";

type RateLimitState = {
  isRateLimited: boolean;
  remainingSeconds: number;
  canRetry: boolean;
  scope: RateLimitScope | null;
};

export function useRateLimit() {
  const [rateLimitState, setRateLimitState] = useState<RateLimitState>({
    isRateLimited: false,
    remainingSeconds: 0,
    canRetry: true,
    scope: null,
  });

  const checkRateLimit = useCallback((error: unknown): boolean => {
    const errorInfo = classifyError(error);
    if (errorInfo.type === "RATE_LIMITED") {
      const scope = isApiError(error) ? error.rateLimitScope : null;
      const retryAfter = isApiError(error) && typeof error.retryAfter === "number" ? error.retryAfter : 30;
      setRateLimitState({
        isRateLimited: true,
        remainingSeconds: retryAfter,
        canRetry: false,
        scope,
      });

      // Start countdown
      let secondsLeft = retryAfter;
      const countdownInterval = setInterval(() => {
        secondsLeft -= 1;
        if (secondsLeft <= 0) {
          clearInterval(countdownInterval);
          setRateLimitState({
            isRateLimited: false,
            remainingSeconds: 0,
            canRetry: true,
            scope: null,
          });
        } else {
          setRateLimitState(prev => ({
            ...prev,
            remainingSeconds: secondsLeft,
          }));
        }
      }, 1000);

      return true;
    }
    return false;
  }, []);

  const resetRateLimit = useCallback(() => {
    setRateLimitState({
      isRateLimited: false,
      remainingSeconds: 0,
      canRetry: true,
      scope: null,
    });
  }, []);

  const getRateLimitMessage = useCallback(() => {
    if (rateLimitState.isRateLimited) {
      return `You're moving fast. I'll be ready in ${rateLimitState.remainingSeconds} seconds.`;
    }
    return "";
  }, [rateLimitState]);

  return {
    rateLimitState,
    checkRateLimit,
    resetRateLimit,
    getRateLimitMessage,
  };
}