librechat-analytics/server.js
DJP 31358a8b86 fix: Repair Top Agents tab after LibreChat transaction shape change
LibreChat stopped tagging agent transactions with model: agent_xxx around
2026-03; new agent transactions record the underlying LLM and link to the
message via messageId. Aggregate from messages -> transactions and union
with the legacy path so historical and current data both show.

Also create createdAt / messageId / (createdAt, model) indexes on startup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 17:08:26 -04:00

75 lines
2 KiB
JavaScript

require('dotenv').config();
const express = require('express');
const path = require('path');
const { MongoClient } = require('mongodb');
const apiRoutes = require('./routes/api');
const app = express();
const PORT = process.env.PORT || 3001;
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/LibreChat';
let db;
async function connectDB() {
const client = new MongoClient(MONGO_URI);
await client.connect();
db = client.db();
console.log('Connected to MongoDB');
await ensureIndexes(db);
return db;
}
async function ensureIndexes(db) {
try {
await Promise.all([
db.collection('transactions').createIndex({ createdAt: -1 }),
db.collection('transactions').createIndex({ messageId: 1 }),
db.collection('messages').createIndex({ createdAt: -1, model: 1 }),
]);
console.log('Indexes ensured');
} catch (e) {
console.error('Index creation failed:', e.message);
}
}
// Health check (no auth)
app.get('/health', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});
// API key auth middleware — protects both API and dashboard
function authMiddleware(req, res, next) {
const apiKey = req.headers['x-api-key'] || req.query.key;
const expected = process.env.DASHBOARD_API_KEY;
if (!expected || expected === 'changeme') {
console.warn('WARNING: DASHBOARD_API_KEY not set — dashboard is unprotected!');
return next();
}
if (apiKey !== expected) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
}
// Static files
app.use(express.static(path.join(__dirname, 'public')));
// API routes
app.use('/api', authMiddleware, (req, res, next) => {
req.db = db;
next();
}, apiRoutes);
// SPA fallback
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
connectDB().then(() => {
app.listen(PORT, () => {
console.log(`Analytics dashboard running on port ${PORT}`);
});
}).catch(err => {
console.error('Failed to connect to MongoDB:', err);
process.exit(1);
});