librechat-balances/routes/api.js
DJP e94cf8f503 Add low balance users view with threshold filters
Shows users below 1M/2M/3M/4M/5M tokens with filter buttons.
Sorted lowest first so admins can quickly find and top up users
running low.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:11:02 -04:00

112 lines
3.1 KiB
JavaScript

const { Router } = require('express');
const balanceService = require('../services/balance');
const router = Router();
router.get('/stats', async (req, res) => {
try {
const stats = await balanceService.getStats(req.db);
res.json(stats);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.get('/balances', async (req, res) => {
try {
const { page = 1, limit = 50 } = req.query;
const result = await balanceService.getAllBalances(req.db, parseInt(page), parseInt(limit));
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.get('/balances/low', async (req, res) => {
try {
const { threshold = 1000000 } = req.query;
const users = await balanceService.getLowBalances(req.db, parseInt(threshold));
res.json({ users });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.get('/balances/search', async (req, res) => {
try {
const { q } = req.query;
if (!q || q.length < 2) {
return res.json({ users: [] });
}
const users = await balanceService.searchUsers(req.db, q);
res.json({ users });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.get('/balances/:userId', async (req, res) => {
try {
const balance = await balanceService.getUserBalance(req.db, req.params.userId);
if (!balance) {
return res.status(404).json({ error: 'User not found' });
}
res.json(balance);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.post('/balances/:userId/set', async (req, res) => {
try {
const { amount } = req.body;
if (typeof amount !== 'number' || amount < 0) {
return res.status(400).json({ error: 'Invalid amount' });
}
const result = await balanceService.setBalance(req.db, req.params.userId, amount);
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.post('/balances/:userId/add', async (req, res) => {
try {
const { amount } = req.body;
if (typeof amount !== 'number' || amount === 0) {
return res.status(400).json({ error: 'Invalid amount' });
}
const result = await balanceService.addBalance(req.db, req.params.userId, amount);
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.post('/balances/bulk/add', async (req, res) => {
try {
const { amount } = req.body;
if (typeof amount !== 'number' || amount === 0) {
return res.status(400).json({ error: 'Invalid amount' });
}
const result = await balanceService.addToAll(req.db, amount);
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.post('/balances/bulk/set', async (req, res) => {
try {
const { amount } = req.body;
if (typeof amount !== 'number' || amount < 0) {
return res.status(400).json({ error: 'Invalid amount' });
}
const result = await balanceService.setAll(req.db, amount);
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
module.exports = router;