Files
aurorabot/api/src/routes/index.ts
2026-04-02 13:23:35 +02:00

106 lines
3.3 KiB
TypeScript

/**
* @fileoverview Route registration module for Aurora API.
* Aggregates all route handlers and provides a unified request handler.
*/
import type { RouteContext, RouteModule } from "./types";
import { authRoutes, isAuthenticated, getSession } from "./auth.routes";
import { healthRoutes } from "./health.routes";
import { statsRoutes } from "./stats.routes";
import { actionsRoutes } from "./actions.routes";
import { questsRoutes } from "./quests.routes";
import { settingsRoutes } from "./settings.routes";
import { guildSettingsRoutes } from "./guild-settings.routes";
import { itemsRoutes } from "./items.routes";
import { usersRoutes } from "./users.routes";
import { classesRoutes } from "./classes.routes";
import { moderationRoutes } from "./moderation.routes";
import { transactionsRoutes } from "./transactions.routes";
import { lootdropsRoutes } from "./lootdrops.routes";
import { assetsRoutes } from "./assets.routes";
import { errorResponse } from "./utils";
/** Routes that do NOT require authentication */
const publicRoutes: RouteModule[] = [
authRoutes,
healthRoutes,
];
/** Routes that require an authenticated admin session */
const protectedRoutes: RouteModule[] = [
statsRoutes,
actionsRoutes,
questsRoutes,
settingsRoutes,
guildSettingsRoutes,
itemsRoutes,
usersRoutes,
classesRoutes,
moderationRoutes,
transactionsRoutes,
lootdropsRoutes,
assetsRoutes,
];
/**
* Main request handler that routes requests to appropriate handlers.
*
* @param req - The incoming HTTP request
* @param url - Parsed URL object
* @returns Response from matching route handler, or null if no match
*
* @example
* const response = await handleRequest(req, url);
* if (response) return response;
* return new Response("Not Found", { status: 404 });
*/
export async function handleRequest(req: Request, url: URL): Promise<Response | null> {
const ctx: RouteContext = {
req,
url,
method: req.method,
pathname: url.pathname,
};
// Try public routes first (auth, health)
for (const module of publicRoutes) {
const response = await module.handler(ctx);
if (response !== null) return response;
}
// For API routes, enforce authentication
if (ctx.pathname.startsWith("/api/")) {
const session = getSession(req);
if (!session) {
return errorResponse("Unauthorized", 401);
}
// Admin-only routes: everything except stats and own user data
const playerAllowedPrefixes = ["/api/stats", "/api/health"];
const isPlayerAllowed = playerAllowedPrefixes.some(p => ctx.pathname.startsWith(p));
// Players can access their own user data
const isOwnUserRoute = ctx.pathname.match(/^\/api\/users\/\d+/) && session.role === "player";
if (session.role === "player" && !isPlayerAllowed && !isOwnUserRoute) {
return errorResponse("Admin access required", 403);
}
}
// Try protected routes
for (const module of protectedRoutes) {
const response = await module.handler(ctx);
if (response !== null) return response;
}
return null;
}
/**
* Get list of all registered route module names.
* Useful for debugging and documentation.
*/
export function getRegisteredRoutes(): string[] {
return [...publicRoutes, ...protectedRoutes].map(m => m.name);
}