/** * @fileoverview Class management endpoints for Aurora API. * Provides CRUD operations for player classes/guilds. */ import type { RouteContext, RouteModule } from "./types"; import { jsonResponse, errorResponse, parseBody, parseStringIdFromPath, withErrorHandling } from "./utils"; import { CreateClassSchema, UpdateClassSchema } from "./schemas"; /** * Classes routes handler. * * Endpoints: * - GET /api/classes - List all classes * - POST /api/classes - Create a new class * - PUT /api/classes/:id - Update a class * - DELETE /api/classes/:id - Delete a class */ async function handler(ctx: RouteContext): Promise { const { pathname, method, req } = ctx; // Only handle requests to /api/classes* if (!pathname.startsWith("/api/classes")) { return null; } const { classService } = await import("@shared/modules/class/class.service"); /** * @route GET /api/classes * @description Returns all classes/guilds in the system. * * @response 200 - `{ classes: Class[] }` * @response 500 - Error fetching classes * * @example * // Response * { * "classes": [ * { "id": "1", "name": "Warrior", "balance": "5000", "roleId": "123456789" } * ] * } */ if (pathname === "/api/classes" && method === "GET") { return withErrorHandling(async () => { const classes = await classService.getAllClasses(); return jsonResponse({ classes }); }, "fetch classes"); } /** * @route POST /api/classes * @description Creates a new class/guild. * * @body { * id: string | number (required) - Unique class identifier, * name: string (required) - Class display name, * balance?: string | number - Initial class balance (default: 0), * roleId?: string - Associated Discord role ID * } * @response 201 - `{ success: true, class: Class }` * @response 400 - Missing required fields * @response 500 - Error creating class * * @example * // Request * POST /api/classes * { "id": "2", "name": "Mage", "balance": "0", "roleId": "987654321" } */ if (pathname === "/api/classes" && method === "POST") { return withErrorHandling(async () => { const data = await req.json() as Record; if (!data.id || !data.name || typeof data.name !== 'string') { return errorResponse("Missing required fields: id and name are required", 400); } const newClass = await classService.createClass({ id: BigInt(data.id), name: data.name, balance: data.balance ? BigInt(data.balance) : 0n, roleId: data.roleId || null, }); return jsonResponse({ success: true, class: newClass }, 201); }, "create class"); } /** * @route PUT /api/classes/:id * @description Updates an existing class. * * @param id - Class ID * @body { * name?: string - Updated class name, * balance?: string | number - Updated balance, * roleId?: string - Updated Discord role ID * } * @response 200 - `{ success: true, class: Class }` * @response 404 - Class not found * @response 500 - Error updating class */ if (pathname.match(/^\/api\/classes\/\d+$/) && method === "PUT") { const id = parseStringIdFromPath(pathname); if (!id) return null; return withErrorHandling(async () => { const data = await req.json() as Record; const updateData: any = {}; if (data.name !== undefined) updateData.name = data.name; if (data.balance !== undefined) updateData.balance = BigInt(data.balance); if (data.roleId !== undefined) updateData.roleId = data.roleId; const updatedClass = await classService.updateClass(BigInt(id), updateData); if (!updatedClass) { return errorResponse("Class not found", 404); } return jsonResponse({ success: true, class: updatedClass }); }, "update class"); } /** * @route DELETE /api/classes/:id * @description Deletes a class. Users assigned to this class will need to be reassigned. * * @param id - Class ID * @response 204 - Class deleted (no content) * @response 500 - Error deleting class */ if (pathname.match(/^\/api\/classes\/\d+$/) && method === "DELETE") { const id = parseStringIdFromPath(pathname); if (!id) return null; return withErrorHandling(async () => { await classService.deleteClass(BigInt(id)); return new Response(null, { status: 204 }); }, "delete class"); } return null; } export const classesRoutes: RouteModule = { name: "classes", handler };