File size: 1,796 Bytes
3786a3f
 
 
 
 
 
 
f14eb69
3786a3f
 
f14eb69
3786a3f
 
 
 
 
 
 
 
 
 
f14eb69
3786a3f
 
 
 
f14eb69
 
 
 
 
 
 
 
 
 
 
3786a3f
 
 
 
 
 
 
 
 
f14eb69
3786a3f
 
 
 
 
 
 
 
f14eb69
3786a3f
 
 
 
 
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
import axios, { AxiosError } from 'axios';
import { API_BASE_URL } from './constants';
import { useAuthStore } from '@/store/auth';

const api = axios.create({
  baseURL: API_BASE_URL,
  headers: { 'Content-Type': 'application/json' },
  timeout: 90000, // 90s — LLM calls can be slow
});

// Attach Bearer token to every request
api.interceptors.request.use((config) => {
  if (typeof window !== 'undefined') {
    const token = useAuthStore.getState().accessToken;
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
  }
  return config;
});

// Handle 401 (auto-refresh) and 429 (rate limit)
api.interceptors.response.use(
  (response) => response,
  async (error: AxiosError) => {
    const original = error.config as any;

    // 429 – surface a clear, user-friendly rate limit message
    if (error.response?.status === 429) {
      const err: any = new Error(
        'LLM rate limit reached (429). Please wait 30 seconds and try again.'
      );
      err.response = { data: { error: err.message }, status: 429 };
      return Promise.reject(err);
    }

    // 401 – try to refresh the token once
    if (
      error.response?.status === 401 &&
      !original._retry &&
      typeof window !== 'undefined'
    ) {
      original._retry = true;
      const refresh = useAuthStore.getState().refreshToken;
      if (refresh) {
        try {
          const { data } = await axios.post(`${API_BASE_URL}/auth/token/refresh/`, { refresh });
          useAuthStore.getState().setTokens(data.access, refresh);
          original.headers.Authorization = `Bearer ${data.access}`;
          return api(original);
        } catch {
          useAuthStore.getState().logout();
        }
      }
    }

    return Promise.reject(error);
  }
);

export default api;