Nadoora / server /src /app.ts
aiqknow's picture
Upload 404 files
0872c3e verified
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import path from 'path';
import { fileURLToPath } from 'url';
import { keysRouter } from './routes/keys.js';
import { modelsRouter } from './routes/models.js';
import { proxyRouter, isRetryableError } from './routes/proxy.js';
import { fallbackRouter } from './routes/fallback.js';
import { analyticsRouter } from './routes/analytics.js';
import { healthRouter } from './routes/health.js';
import { settingsRouter } from './routes/settings.js';
import { errorHandler } from './middleware/errorHandler.js';
import { routeRequest, recordRateLimitHit, recordSuccess } from './services/router.js';
import { recordRequest, recordTokens, setCooldown } from './services/ratelimit.js';
import { getUnifiedApiKey } from './db/index.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export function createApp() {
const app = express();
app.use(helmet({ contentSecurityPolicy: false, hsts: false }));
app.use(cors());
app.use(express.json({ limit: '1mb' }));
// Admin Dashboard Authentication (Bearer Token)
const adminPassword = process.env.ADMIN_PASSWORD;
if (adminPassword) {
// Login endpoint
app.post('/api/login', (req, res) => {
const { password } = req.body;
if (password === adminPassword) {
res.json({ token: adminPassword }); // Using password as token for simplicity
} else {
res.status(401).json({ error: 'Invalid password' });
}
});
app.use((req, res, next) => {
// Allow proxy endpoints, health check, and login
if (req.path.startsWith('/v1/')) return next();
if (req.path === '/api' && req.method === 'POST') return next();
if (req.path === '/api/ping') return next();
if (req.path === '/api/login') return next();
// Only protect /api/* management routes
if (req.path.startsWith('/api/')) {
const authHeader = req.headers.authorization || '';
const token = authHeader.replace(/^Bearer\s+/i, '');
if (token === adminPassword) {
return next();
}
return res.status(401).json({ error: 'Authentication required' });
}
// Allow static file serving (UI routing will handle redirects)
return next();
});
}
// API routes
app.use('/api/keys', keysRouter);
app.use('/api/models', modelsRouter);
app.use('/api/fallback', fallbackRouter);
app.use('/api/analytics', analyticsRouter);
app.use('/api/health', healthRouter);
app.use('/api/settings', settingsRouter);
// Custom simple API for standard apps
app.post('/api', async (req, res) => {
const { prompt } = req.body;
if (!prompt || typeof prompt !== 'string') {
return res.status(400).json({ status: 'error', message: 'Missing prompt' });
}
// Auth check
const authHeader = req.headers.authorization;
const isLocal = req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1';
if (authHeader && !isLocal) {
const token = authHeader.replace(/^Bearer\s+/i, '');
const unifiedKey = getUnifiedApiKey();
if (token !== unifiedKey) {
return res.status(401).json({ status: 'error', message: 'Invalid API key' });
}
}
const messages = [{ role: 'user' as const, content: prompt }];
const estimatedTokens = Math.ceil(prompt.length / 4) + 1000;
const skipKeys = new Set<string>();
let lastError: any = null;
for (let attempt = 0; attempt < 20; attempt++) {
try {
const route = routeRequest(estimatedTokens, skipKeys.size > 0 ? skipKeys : undefined);
recordRequest(route.platform, route.modelId, route.keyId);
const result = await route.provider.chatCompletion(
route.apiKey, messages, route.modelId,
{ temperature: 0.7 }
);
const totalTokens = result.usage?.total_tokens ?? 0;
recordTokens(route.platform, route.modelId, route.keyId, totalTokens);
recordSuccess(route.modelDbId);
return res.json({
status: 'success',
text: result.choices[0]?.message?.content || ''
});
} catch (err: any) {
lastError = err;
if (isRetryableError(err)) {
// If we have a route, put it on cooldown
try {
const route = routeRequest(estimatedTokens, skipKeys.size > 0 ? skipKeys : undefined);
const skipId = `${route.platform}:${route.modelId}:${route.keyId}`;
skipKeys.add(skipId);
setCooldown(route.platform, route.modelId, route.keyId, 120_000);
recordRateLimitHit(route.modelDbId);
} catch {
// No more routes available
}
console.log(`[CustomAPI] ${err.message.slice(0, 60)}, falling back (attempt ${attempt + 1}/20)`);
continue;
}
// Non-retryable error
return res.status(500).json({ status: 'error', message: err.message });
}
}
res.status(429).json({ status: 'error', message: `All models failed after retries. Last: ${lastError?.message}` });
});
// OpenAI-compatible proxy
app.use('/v1', proxyRouter);
// Health check
app.get('/api/ping', (_req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// Error handler (for API routes)
app.use(errorHandler);
// Serve client static files (after API error handler)
const clientDist = path.resolve(__dirname, '../../client/dist');
app.use(express.static(clientDist));
// SPA fallback — serve index.html for non-API routes
app.use((req, res, next) => {
if (req.path === '/api' || req.path.startsWith('/api/') || req.path.startsWith('/v1/')) {
next();
return;
}
res.sendFile(path.join(clientDist, 'index.html'));
});
return app;
}