fix(api): resolve route path mismatches

- Add /usage alias for /cliproxy/stats (frontend compatibility)
- Create account-routes.ts to fix /accounts/accounts double path
- Update index.ts to mount accountRoutes at /accounts
- Remove account code from profile-routes.ts
- Clean up unused imports in profile-routes.ts
This commit is contained in:
kaitranntt
2025-12-21 18:03:15 -05:00
parent e84df00740
commit 557926ffe3
4 changed files with 99 additions and 66 deletions
+68
View File
@@ -0,0 +1,68 @@
/**
* Account Routes - CRUD operations for Claude accounts (profiles.json)
*
* Separated from profile-routes.ts to avoid dual-mounting conflicts.
*/
import { Router, Request, Response } from 'express';
import * as fs from 'fs';
import * as path from 'path';
import { getCcsDir } from '../../utils/config-manager';
const router = Router();
/**
* GET /api/accounts - List accounts from profiles.json
*/
router.get('/', (_req: Request, res: Response): void => {
try {
const profilesPath = path.join(getCcsDir(), 'profiles.json');
if (!fs.existsSync(profilesPath)) {
res.json({ accounts: [], default: null });
return;
}
const data = JSON.parse(fs.readFileSync(profilesPath, 'utf8'));
const accounts = Object.entries(data.profiles || {}).map(([name, meta]) => {
const metadata = meta as Record<string, unknown>;
return {
name,
...metadata,
};
});
res.json({ accounts, default: data.default || null });
} catch (error) {
res.status(500).json({ error: (error as Error).message });
}
});
/**
* POST /api/accounts/default - Set default account
*/
router.post('/default', (req: Request, res: Response): void => {
try {
const { name } = req.body;
if (!name) {
res.status(400).json({ error: 'Missing required field: name' });
return;
}
const profilesPath = path.join(getCcsDir(), 'profiles.json');
const data = fs.existsSync(profilesPath)
? JSON.parse(fs.readFileSync(profilesPath, 'utf8'))
: { profiles: {} };
data.default = name;
fs.writeFileSync(profilesPath, JSON.stringify(data, null, 2) + '\n');
res.json({ default: name });
} catch (error) {
res.status(500).json({ error: (error as Error).message });
}
});
export default router;
+14 -4
View File
@@ -19,10 +19,9 @@ import { checkCliproxyUpdate } from '../../cliproxy/binary-manager';
const router = Router();
/**
* GET /api/cliproxy/stats - Get CLIProxyAPI usage statistics
* Returns: CliproxyStats or error if proxy not running
* Shared handler for stats/usage endpoint
*/
router.get('/stats', async (_req: Request, res: Response): Promise<void> => {
const handleStatsRequest = async (_req: Request, res: Response): Promise<void> => {
try {
// Check if proxy is running first
const running = await isCliproxyRunning();
@@ -48,7 +47,18 @@ router.get('/stats', async (_req: Request, res: Response): Promise<void> => {
} catch (error) {
res.status(500).json({ error: (error as Error).message });
}
});
};
/**
* GET /api/cliproxy/stats - Get CLIProxyAPI usage statistics
* Returns: CliproxyStats or error if proxy not running
*/
router.get('/stats', handleStatsRequest);
/**
* GET /api/cliproxy/usage - Alias for /stats (frontend compatibility)
*/
router.get('/usage', handleStatsRequest);
/**
* GET /api/cliproxy/status - Check CLIProxyAPI running status
+2 -1
View File
@@ -9,6 +9,7 @@ import { Router } from 'express';
// Import domain routers
import profileRoutes from './profile-routes';
import accountRoutes from './account-routes';
import configRoutes from './config-routes';
import healthRoutes from './health-routes';
import providerRoutes from './provider-routes';
@@ -28,7 +29,7 @@ export const apiRoutes = Router();
// Profile CRUD, settings management, presets, accounts
apiRoutes.use('/profiles', profileRoutes);
apiRoutes.use('/settings', settingsRoutes);
apiRoutes.use('/accounts', profileRoutes);
apiRoutes.use('/accounts', accountRoutes);
// ==================== Unified Config ====================
// Config format, migration
+15 -61
View File
@@ -1,13 +1,11 @@
/**
* Profile Routes - CRUD operations for user profiles and accounts
* Profile Routes - CRUD operations for user profiles
*
* Uses unified config (config.yaml) when available, falls back to legacy (config.json).
* Note: Account routes have been moved to account-routes.ts
*/
import { Router, Request, Response } from 'express';
import * as fs from 'fs';
import * as path from 'path';
import { getCcsDir } from '../../utils/config-manager';
import { isReservedName, RESERVED_PROFILE_NAMES } from '../../config/reserved-names';
import { createApiProfile, removeApiProfile } from '../../api/services/profile-writer';
import { apiProfileExists, listApiProfiles } from '../../api/services/profile-reader';
@@ -20,15 +18,19 @@ const router = Router();
/**
* GET /api/profiles - List all profiles
*/
router.get('/', (_req: Request, res: Response) => {
const result = listApiProfiles();
// Map isConfigured -> configured for UI compatibility
const profiles = result.profiles.map((p) => ({
name: p.name,
settingsPath: p.settingsPath,
configured: p.isConfigured,
}));
res.json({ profiles });
router.get('/', (_req: Request, res: Response): void => {
try {
const result = listApiProfiles();
// Map isConfigured -> configured for UI compatibility
const profiles = result.profiles.map((p) => ({
name: p.name,
settingsPath: p.settingsPath,
configured: p.isConfigured,
}));
res.json({ profiles });
} catch (error) {
res.status(500).json({ error: (error as Error).message });
}
});
/**
@@ -117,52 +119,4 @@ router.delete('/:name', (req: Request, res: Response): void => {
res.json({ name, deleted: true });
});
// ==================== Accounts ====================
/**
* GET /api/accounts - List accounts from profiles.json
*/
router.get('/accounts', (_req: Request, res: Response): void => {
const profilesPath = path.join(getCcsDir(), 'profiles.json');
if (!fs.existsSync(profilesPath)) {
res.json({ accounts: [], default: null });
return;
}
const data = JSON.parse(fs.readFileSync(profilesPath, 'utf8'));
const accounts = Object.entries(data.profiles || {}).map(([name, meta]) => {
const metadata = meta as Record<string, unknown>;
return {
name,
...metadata,
};
});
res.json({ accounts, default: data.default || null });
});
/**
* POST /api/accounts/default - Set default account
*/
router.post('/accounts/default', (req: Request, res: Response): void => {
const { name } = req.body;
if (!name) {
res.status(400).json({ error: 'Missing required field: name' });
return;
}
const profilesPath = path.join(getCcsDir(), 'profiles.json');
const data = fs.existsSync(profilesPath)
? JSON.parse(fs.readFileSync(profilesPath, 'utf8'))
: { profiles: {} };
data.default = name;
fs.writeFileSync(profilesPath, JSON.stringify(data, null, 2) + '\n');
res.json({ default: name });
});
export default router;