File size: 2,540 Bytes
6fd9abb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
80
81
82
import axios from 'axios';
import { supabase } from './supabase'; 

// SHORTCUT FIX: Use environment variable for URL, fallback to localhost
const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL || 'http://localhost:8000/api',
  timeout: 120000, // Change 30000 to 120000 (2 mins) for Render cold starts
});

// Track ongoing requests to prevent duplicates
const ongoingRequests = new Map();

// Request Interceptor
api.interceptors.request.use(
  async (config) => {
    try {
      // Create a unique key for this request
      const requestKey = `${config.method}-${config.url}`;
      
      // Check if this exact request is already in progress
      if (ongoingRequests.has(requestKey)) {
        console.log("⏸️ Duplicate request blocked:", requestKey);
        return ongoingRequests.get(requestKey);
      }

      console.log("🚀 API Request:", config.method?.toUpperCase(), config.url);
      
      // Get current session with timeout
      const sessionPromise = Promise.race([
        supabase.auth.getSession(),
        new Promise((_, reject) => 
          setTimeout(() => reject(new Error('Session timeout')), 3000)
        )
      ]);
      
      const { data } = await sessionPromise;
      const token = data?.session?.access_token;
      
      if (token) {
        // console.log("✅ Token attached to request"); // Reduced log noise
        config.headers.Authorization = `Bearer ${token}`;
      }

      // Store this request
      ongoingRequests.set(requestKey, config);

      return config;
    } catch (error) {
      console.error("❌ Request interceptor error:", error.message);
      return config;
    }
  },
  (error) => {
    console.error("❌ Request setup error:", error);
    return Promise.reject(error);
  }
);

// Response Interceptor
api.interceptors.response.use(
  (response) => {
    const requestKey = `${response.config.method}-${response.config.url}`;
    ongoingRequests.delete(requestKey);
    return response;
  },
  async (error) => {
    if (error.config) {
      const requestKey = `${error.config.method}-${error.config.url}`;
      ongoingRequests.delete(requestKey);
    }
    
    // Custom Error Message for Connection Failure
    if (!error.response) {
      console.error("🌐 Network error - backend unreachable");
      error.message = "Cannot connect to server. If running locally, ensure 'python manage.py runserver' is running. If deployed, check your VITE_API_URL setting.";
    }
    
    return Promise.reject(error);
  }
);

export default api;