forked from syntaxbullet/aurorabot
The web/ folder contains the REST API, WebSocket server, and OAuth routes — not a web frontend. Renaming to api/ clarifies this distinction since the actual web frontend lives in panel/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
/**
|
|
* @fileoverview Statistics endpoints for Aurora API.
|
|
* Provides dashboard statistics and activity aggregation data.
|
|
*/
|
|
|
|
import type { RouteContext, RouteModule } from "./types";
|
|
import { jsonResponse, errorResponse, withErrorHandling } from "./utils";
|
|
|
|
// Cache for activity stats (heavy aggregation)
|
|
let activityPromise: Promise<import("@shared/modules/dashboard/dashboard.types").ActivityData[]> | null = null;
|
|
let lastActivityFetch: number = 0;
|
|
const ACTIVITY_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
|
|
/**
|
|
* Stats routes handler.
|
|
*
|
|
* Endpoints:
|
|
* - GET /api/stats - Full dashboard statistics
|
|
* - GET /api/stats/activity - Activity aggregation with caching
|
|
*/
|
|
async function handler(ctx: RouteContext): Promise<Response | null> {
|
|
const { pathname, method } = ctx;
|
|
|
|
/**
|
|
* @route GET /api/stats
|
|
* @description Returns comprehensive dashboard statistics including
|
|
* bot info, user counts, economy data, and leaderboards.
|
|
* @response 200 - Full dashboard stats object
|
|
* @response 500 - Error fetching statistics
|
|
*/
|
|
if (pathname === "/api/stats" && method === "GET") {
|
|
return withErrorHandling(async () => {
|
|
// Import the stats function from wherever it's defined
|
|
// This will be passed in during initialization
|
|
const { getFullDashboardStats } = await import("./stats.helper.ts");
|
|
const stats = await getFullDashboardStats();
|
|
return jsonResponse(stats);
|
|
}, "fetch dashboard stats");
|
|
}
|
|
|
|
/**
|
|
* @route GET /api/stats/activity
|
|
* @description Returns activity aggregation data with 5-minute caching.
|
|
* Heavy query, results are cached to reduce database load.
|
|
* @response 200 - Array of activity data points
|
|
* @response 500 - Error fetching activity statistics
|
|
*
|
|
* @example
|
|
* // Response
|
|
* [
|
|
* { "date": "2024-02-08", "commands": 150, "users": 25 },
|
|
* { "date": "2024-02-07", "commands": 200, "users": 30 }
|
|
* ]
|
|
*/
|
|
if (pathname === "/api/stats/activity" && method === "GET") {
|
|
return withErrorHandling(async () => {
|
|
const now = Date.now();
|
|
|
|
// If we have a valid cache, return it
|
|
if (activityPromise && (now - lastActivityFetch < ACTIVITY_CACHE_TTL)) {
|
|
const data = await activityPromise;
|
|
return jsonResponse(data);
|
|
}
|
|
|
|
// Otherwise, trigger a new fetch (deduplicated by the promise)
|
|
if (!activityPromise || (now - lastActivityFetch >= ACTIVITY_CACHE_TTL)) {
|
|
activityPromise = (async () => {
|
|
const { dashboardService } = await import("@shared/modules/dashboard/dashboard.service");
|
|
return await dashboardService.getActivityAggregation();
|
|
})();
|
|
lastActivityFetch = now;
|
|
}
|
|
|
|
const activity = await activityPromise;
|
|
return jsonResponse(activity);
|
|
}, "fetch activity stats");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export const statsRoutes: RouteModule = {
|
|
name: "stats",
|
|
handler
|
|
};
|