File size: 2,160 Bytes
0c3fbdd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const fs = require('fs');
const path = require('path');

const app = express();
const proxyCache = {}; // Memory cache for active proxies

// Load Endpoints
let endpoints = {};
try {
    endpoints = JSON.parse(fs.readFileSync(path.join(__dirname, 'endpoints.json'), 'utf8'));
    console.log("✔ Loaded:", Object.keys(endpoints).join(', '));
} catch (e) {
    console.error("✘ Error: endpoints.json missing or invalid.");
}

// 1. Static Frontend
app.use(express.static(path.join(__dirname, 'public')));

// 2. Info Route
app.get('/api/endpoints', (req, res) => res.json(endpoints));

// 3. The "Smart Proxy" Router
app.use('/:nick', (req, res, next) => {
    const { nick } = req.params;

    // Ignore internal or invalid requests
    if (nick === 'api' || !endpoints[nick]) return next();

    // Create the proxy if it doesn't exist in cache
    if (!proxyCache[nick]) {
        const target = endpoints[nick].url;
        console.log(`[Setup] Routing /${nick} -> ${target}`);

        proxyCache[nick] = createProxyMiddleware({
            target: target,
            changeOrigin: true,
            pathRewrite: { [`^/${nick}`]: '' }, // Strips /gpt4 or /nim from the URL
            onProxyReq: (proxyReq) => {
                proxyReq.setHeader('host', new URL(target).host);
            },
            onProxyRes: (proxyRes, req, res) => {
                // Global CORS fix for SillyTavern/Bots
                res.setHeader('Access-Control-Allow-Origin', '*');
                res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
                res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
            },
            onError: (err, req, res) => {
                console.error(`[Error: ${nick}]`, err.message);
                res.status(502).json({ error: "Provider Offline. Is your G4F Space paused?" });
            }
        });
    }

    return proxyCache[nick](req, res, next);
});

const PORT = 7860;
app.listen(PORT, '0.0.0.0', () => console.log(`🚀 Hub active on port ${PORT}`));