require('dotenv').config(); const express = require('express'); const axios = require('axios'); const cors = require('cors'); const { connect: connectDB } = require('./db'); const { authMiddleware } = require('./auth'); const { initTelegramBot } = require('./telegramBot'); // Connect to database to validate keys connectDB(); const app = express(); app.use(cors()); app.use(express.json()); // Configuration (Set these env variables on Render/Vercel) const PORT = process.env.PORT || 8080; const HUGGINGFACE_API_URL = process.env.HUGGINGFACE_API_URL || 'https://yogeshjio5770-goldscrape-api.hf.space'; // Use a single API_KEY for both validation and HF authorization const API_KEY = process.env.API_KEY || 'aurum_live_key_2026_xK9mP3vL7qR2'; if (!process.env.API_KEY) { process.env.API_KEY = API_KEY; } const CACHE_TTL_MS = (parseInt(process.env.PROXY_CACHE_SECONDS) || 5) * 1000; // default 5 seconds cache // Partitioned memory caches based on rate source const proxyCaches = { SLN: { data: null, timestamp: 0, promise: null }, IBJA: { data: null, timestamp: 0, promise: null }, BOTH: { data: null, timestamp: 0, promise: null } }; // Route: Get cached live rates (requires valid API key from Supabase) app.get('/api/rates', authMiddleware, async (req, res) => { const source = req.priceSource || 'SLN'; const cacheKey = (req.isMasterKey || source === 'BOTH') ? 'BOTH' : source; const cache = proxyCaches[cacheKey] || proxyCaches.SLN; const now = Date.now(); // If cache is fresh, serve it immediately if (cache.data && (now - cache.timestamp) < CACHE_TTL_MS) { return res.json({ ...cache.data, from_proxy_cache: true, proxy_cache_age_seconds: Math.round((now - cache.timestamp) / 1000) }); } // If already fetching from Hugging Face, reuse the active promise to avoid duplicate calls if (cache.promise) { try { const data = await cache.promise; return res.json({ ...data, from_proxy_cache: true, proxy_cache_age_seconds: Math.round((Date.now() - cache.timestamp) / 1000) }); } catch (err) { // Fallback below if promise fails } } // Fetch fresh data from Hugging Face Space passing original client api key const clientApiKey = req.headers['x-api-key'] || req.query.apikey || API_KEY; cache.promise = (async () => { const response = await axios.get(`${HUGGINGFACE_API_URL}/api/rates`, { headers: { 'x-api-key': clientApiKey }, timeout: 8000 }); // Update cache cache.data = response.data; cache.timestamp = Date.now(); cache.promise = null; return response.data; })(); try { const data = await cache.promise; res.json({ ...data, from_proxy_cache: false }); } catch (error) { cache.promise = null; // If Hugging Face is slow/down, serve stale cache as fallback if (cache.data) { console.warn('⚠️ Hugging Face API call failed. Serving stale proxy cache.'); return res.json({ ...cache.data, from_proxy_cache: true, proxy_stale_fallback: true }); } res.status(502).json({ success: false, error: 'Failed to fetch rates from Hugging Face Space backend', details: error.message }); } }); // Health check endpoint app.get('/health', (req, res) => { res.json({ status: 'UP', caches: { sln: proxyCaches.SLN.data ? 'ACTIVE' : 'EMPTY', ibja: proxyCaches.IBJA.data ? 'ACTIVE' : 'EMPTY', both: proxyCaches.BOTH.data ? 'ACTIVE' : 'EMPTY' } }); }); // Root endpoint for browser visits app.get('/', (req, res) => { res.send('
Status: Running
Use /api/rates?apikey=YOUR_KEY to fetch prices.