feat: Implement a new API routing system by adding dedicated route files for users, transactions, assets, items, quests, and other game entities, and integrating them into the server.
All checks were successful
Deploy to Production / test (push) Successful in 44s

This commit is contained in:
syntaxbullet
2026-02-08 18:57:42 +01:00
parent 073348fa55
commit 553b9b4952
19 changed files with 2713 additions and 1336 deletions

View File

@@ -0,0 +1,158 @@
/**
* @fileoverview Bot settings endpoints for Aurora API.
* Provides endpoints for reading and updating bot configuration,
* as well as fetching Discord metadata.
*/
import type { RouteContext, RouteModule } from "./types";
import { jsonResponse, errorResponse, withErrorHandling } from "./utils";
/**
* JSON replacer for BigInt serialization.
*/
function jsonReplacer(_key: string, value: unknown): unknown {
return typeof value === "bigint" ? value.toString() : value;
}
/**
* Settings routes handler.
*
* Endpoints:
* - GET /api/settings - Get current bot configuration
* - POST /api/settings - Update bot configuration (partial merge)
* - GET /api/settings/meta - Get Discord metadata (roles, channels, commands)
*/
async function handler(ctx: RouteContext): Promise<Response | null> {
const { pathname, method, req } = ctx;
// Only handle requests to /api/settings*
if (!pathname.startsWith("/api/settings")) {
return null;
}
/**
* @route GET /api/settings
* @description Returns the current bot configuration.
* Configuration includes economy settings, leveling settings,
* command toggles, and other system settings.
* @response 200 - Full configuration object
* @response 500 - Error fetching settings
*
* @example
* // Response
* {
* "economy": { "dailyReward": 100, "streakBonus": 10 },
* "leveling": { "xpPerMessage": 15, "levelUpChannel": "123456789" },
* "commands": { "disabled": [], "channelLocks": {} }
* }
*/
if (pathname === "/api/settings" && method === "GET") {
return withErrorHandling(async () => {
const { config } = await import("@shared/lib/config");
return new Response(JSON.stringify(config, jsonReplacer), {
headers: { "Content-Type": "application/json" }
});
}, "fetch settings");
}
/**
* @route POST /api/settings
* @description Updates bot configuration with partial merge.
* Only the provided fields will be updated; other settings remain unchanged.
* After updating, commands are automatically reloaded.
*
* @body Partial configuration object
* @response 200 - `{ success: true }`
* @response 400 - Validation error
* @response 500 - Error saving settings
*
* @example
* // Request - Only update economy daily reward
* POST /api/settings
* { "economy": { "dailyReward": 150 } }
*/
if (pathname === "/api/settings" && method === "POST") {
try {
const partialConfig = await req.json();
const { saveConfig, config: currentConfig } = await import("@shared/lib/config");
const { deepMerge } = await import("@shared/lib/utils");
// Merge partial update into current config
const mergedConfig = deepMerge(currentConfig, partialConfig);
// saveConfig throws if validation fails
saveConfig(mergedConfig);
const { systemEvents, EVENTS } = await import("@shared/lib/events");
systemEvents.emit(EVENTS.ACTIONS.RELOAD_COMMANDS);
return jsonResponse({ success: true });
} catch (error) {
// Return 400 for validation errors
const message = error instanceof Error ? error.message : String(error);
return errorResponse("Failed to save settings", 400, message);
}
}
/**
* @route GET /api/settings/meta
* @description Returns Discord server metadata for settings UI.
* Provides lists of roles, channels, and registered commands.
*
* @response 200 - `{ roles: Role[], channels: Channel[], commands: Command[] }`
* @response 500 - Error fetching metadata
*
* @example
* // Response
* {
* "roles": [
* { "id": "123456789", "name": "Admin", "color": "#FF0000" }
* ],
* "channels": [
* { "id": "987654321", "name": "general", "type": 0 }
* ],
* "commands": [
* { "name": "daily", "category": "economy" }
* ]
* }
*/
if (pathname === "/api/settings/meta" && method === "GET") {
return withErrorHandling(async () => {
const { AuroraClient } = await import("../../../bot/lib/BotClient");
const { env } = await import("@shared/lib/env");
if (!env.DISCORD_GUILD_ID) {
return jsonResponse({ roles: [], channels: [], commands: [] });
}
const guild = AuroraClient.guilds.cache.get(env.DISCORD_GUILD_ID);
if (!guild) {
return jsonResponse({ roles: [], channels: [], commands: [] });
}
// Map roles and channels to a simplified format
const roles = guild.roles.cache
.sort((a, b) => b.position - a.position)
.map(r => ({ id: r.id, name: r.name, color: r.hexColor }));
const channels = guild.channels.cache
.map(c => ({ id: c.id, name: c.name, type: c.type }));
const commands = Array.from(AuroraClient.knownCommands.entries())
.map(([name, category]) => ({ name, category }))
.sort((a, b) => {
if (a.category !== b.category) return a.category.localeCompare(b.category);
return a.name.localeCompare(b.name);
});
return jsonResponse({ roles, channels, commands });
}, "fetch settings meta");
}
return null;
}
export const settingsRoutes: RouteModule = {
name: "settings",
handler
};