┌─ TS ───────────────────────────────────────────────────────────────────────┐
│ // leaderboard command handler │
│ │
│ import type { │
│ DiscordInteraction, │
│ InteractionResponseData, │
│ LeaderboardCommandOptions, │
│ } from "../types.js"; │
│ import type { │
│ LeaderboardData, │
│ PlayerLeaderboardData, │
│ ChallengeRun, │
│ Player, │
│ } from "../../lib/types.js"; │
│ import { │
│ fetchGlobalLeaderboard, │
│ fetchRegionalLeaderboard, │
│ fetchRealmLeaderboard, │
│ fetchPlayerLeaderboard, │
│ } from "../../lib/api.js"; │
│ import { API_BASE_URL, DEFAULT_SEASON_ID } from "../constants.js"; │
│ import { │
│ createDungeonLeaderboardEmbed, │
│ createPlayerLeaderboardEmbed, │
│ createDungeonLeaderboardRefreshButton, │
│ createPlayerLeaderboardRefreshButton, │
│ type LeaderboardRun, │
│ type PlayerRanking, │
│ } from "../embeds/leaderboard.js"; │
│ import { │
│ createAPIErrorEmbed, │
│ createInvalidInputEmbed, │
│ } from "../embeds/error.js"; │
│ import { getDungeons } from "../indexes/cache.js"; │
│ │
│ /** │
│ * handles the /leaderboard command │
│ * routes to dungeon or players subcommand │
│ */ │
│ export async function handleLeaderboardCommand( │
│ interaction: DiscordInteraction, │
│ ): Promise<InteractionResponseData> { │
│ const subcommand = interaction.data?.options?.[0]; │
│ │
│ if (!subcommand) { │
│ return { │
│ embeds: [createInvalidInputEmbed("subcommand", "missing")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ if (subcommand.name === "dungeon") { │
│ return handleDungeonLeaderboard(subcommand.options || []); │
│ } else if (subcommand.name === "players") { │
│ return handlePlayersLeaderboard(subcommand.options || []); │
│ } │
│ │
│ return { │
│ embeds: [createInvalidInputEmbed("subcommand", subcommand.name)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ /** │
│ * handles /leaderboard dungeon subcommand │
│ */ │
│ async function handleDungeonLeaderboard( │
│ options: Array<{ name: string; value?: string | number | boolean }>, │
│ ): Promise<InteractionResponseData> { │
│ const dungeon = getOptionValue(options, "dungeon") as string; │
│ const scope = getOptionValue(options, "scope") as string; │
│ const region = getOptionValue(options, "region") as string | undefined; │
│ const realm = getOptionValue(options, "realm") as string | undefined; │
│ const limit = (getOptionValue(options, "limit") as number) || 10; │
│ const season = │
│ (getOptionValue(options, "season") as string) || DEFAULT_SEASON_ID; │
│ const page = 1; │
│ │
│ // validate required options │
│ if (!dungeon || !scope) { │
│ return { │
│ embeds: [ │
│ createInvalidInputEmbed("options", "dungeon and scope are required"), │
│ ], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate scope │
│ if (!["global", "region", "realm"].includes(scope)) { │
│ return { │
│ embeds: [createInvalidInputEmbed("scope", scope)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate region if scope is region or realm │
│ if ((scope === "region" || scope === "realm") && !region) { │
│ return { │
│ embeds: [createInvalidInputEmbed("region", "required for this scope")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate realm if scope is realm │
│ if (scope === "realm" && !realm) { │
│ return { │
│ embeds: [createInvalidInputEmbed("realm", "required for realm scope")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ try { │
│ // get dungeon name from cache │
│ const dungeons = await getDungeons(); │
│ const dungeonInfo = dungeons.find((d) => d.slug === dungeon); │
│ if (!dungeonInfo) { │
│ return { │
│ embeds: [createInvalidInputEmbed("dungeon", dungeon)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // fetch leaderboard based on scope │
│ let data: LeaderboardData | null = null; │
│ const seasonNum = Number(season); │
│ if (scope === "global") { │
│ data = await fetchGlobalLeaderboard( │
│ dungeonInfo.id, │
│ page, │
│ undefined, │
│ API_BASE_URL, │
│ seasonNum, │
│ ); │
│ } else if (scope === "region") { │
│ data = await fetchRegionalLeaderboard( │
│ region!, │
│ dungeonInfo.id, │
│ page, │
│ undefined, │
│ API_BASE_URL, │
│ seasonNum, │
│ ); │
│ } else if (scope === "realm") { │
│ data = await fetchRealmLeaderboard( │
│ region!, │
│ realm!, │
│ dungeonInfo.id, │
│ page, │
│ undefined, │
│ API_BASE_URL, │
│ seasonNum, │
│ ); │
│ } │
│ │
│ if (!data || !data.leading_groups) { │
│ return { │
│ embeds: [createAPIErrorEmbed("No leaderboard data found")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // map runs to our interface (timestamp is already in ms) │
│ const runs: LeaderboardRun[] = data.leading_groups.map((run) => ({ │
│ rank: 0, // not used, calculated from index in embed │
│ duration: run.duration, │
│ timestamp: new Date(run.completed_timestamp).toISOString(), │
│ members: run.members, │
│ })); │
│ │
│ // create embed │
│ const embed = createDungeonLeaderboardEmbed( │
│ dungeonInfo.name, │
│ dungeon, │
│ scope, │
│ region, │
│ realm, │
│ runs, │
│ limit, │
│ season, │
│ ); │
│ │
│ // create refresh button │
│ const components = createDungeonLeaderboardRefreshButton( │
│ dungeon, │
│ scope, │
│ region, │
│ realm, │
│ limit, │
│ season, │
│ ); │
│ │
│ return { │
│ embeds: [embed], │
│ components, │
│ }; │
│ } catch (error) { │
│ console.error("Error fetching dungeon leaderboard:", error); │
│ return { │
│ embeds: [createAPIErrorEmbed()], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ } │
│ │
│ // handles /leaderboard players subcommand │
│ async function handlePlayersLeaderboard( │
│ options: Array<{ name: string; value?: string | number | boolean }>, │
│ ): Promise<InteractionResponseData> { │
│ const scopeValue = getOptionValue(options, "scope") as string; │
│ const region = getOptionValue(options, "region") as string | undefined; │
│ const realm = getOptionValue(options, "realm") as string | undefined; │
│ const className = getOptionValue(options, "class") as string | undefined; │
│ const limit = (getOptionValue(options, "limit") as number) || 25; │
│ const season = │
│ (getOptionValue(options, "season") as string) || DEFAULT_SEASON_ID; │
│ const page = 1; │
│ │
│ // validate required options │
│ if (!scopeValue) { │
│ return { │
│ embeds: [createInvalidInputEmbed("scope", "required")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate scope │
│ if (!["global", "region", "realm"].includes(scopeValue)) { │
│ return { │
│ embeds: [createInvalidInputEmbed("scope", scopeValue)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // map scope value to API format ("region" -> "regional") │
│ const scope: "global" | "regional" | "realm" = │
│ scopeValue === "region" ? "regional" : (scopeValue as "global" | "realm"); │
│ │
│ try { │
│ // build API options │
│ const opts: { classKey?: string; realmSlug?: string; seasonId?: number } = │
│ {}; │
│ if (className) opts.classKey = className; │
│ if (realm && scope === "realm") opts.realmSlug = realm; │
│ if (season) opts.seasonId = Number(season); │
│ │
│ // fetch player leaderboard │
│ const data: PlayerLeaderboardData | null = await fetchPlayerLeaderboard( │
│ scope, │
│ region, │
│ page, │
│ 10, │
│ opts, │
│ API_BASE_URL, │
│ ); │
│ │
│ if (!data || !data.leaderboard) { │
│ return { │
│ embeds: [createAPIErrorEmbed("No player leaderboard data found")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // map players to our interface │
│ const players: PlayerRanking[] = data.leaderboard.map((player, index) => ({ │
│ rank: player.global_ranking || index + 1, // use index+1 as fallback │
│ name: player.name, │
│ realm_name: player.realm_name, │
│ region: player.region, │
│ class_name: player.class_name, │
│ active_spec_name: player.active_spec_name, │
│ best_avg_time: player.combined_best_time, │
│ completed_dungeons: player.dungeons_completed || 0, │
│ global_ranking_bracket: player.global_ranking_bracket, │
│ })); │
│ │
│ // create embed │
│ const embed = createPlayerLeaderboardEmbed( │
│ scope, │
│ region, │
│ realm, │
│ className, │
│ players, │
│ limit, │
│ season, │
│ ); │
│ │
│ // create refresh button │
│ const components = createPlayerLeaderboardRefreshButton( │
│ scope, │
│ region, │
│ realm, │
│ className, │
│ limit, │
│ season, │
│ ); │
│ │
│ return { │
│ embeds: [embed], │
│ components, │
│ }; │
│ } catch (error) { │
│ console.error("Error fetching player leaderboard:", error); │
│ return { │
│ embeds: [createAPIErrorEmbed()], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ } │
│ │
│ // helper to get option value by name │
│ function getOptionValue( │
│ options: Array<{ name: string; value?: string | number | boolean }>, │
│ name: string, │
│ ): string | number | boolean | undefined { │
│ return options.find((opt) => opt.name === name)?.value; │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ TS ─────────────────────────────────┐
│ // leaderboard command handler │
│ │
│ import type { │
│ DiscordInteraction, │
│ InteractionResponseData, │
│ LeaderboardCommandOptions, │
│ } from "../types.js"; │
│ import type { │
│ LeaderboardData, │
│ PlayerLeaderboardData, │
│ ChallengeRun, │
│ Player, │
│ } from "../../lib/types.js"; │
│ import { │
│ fetchGlobalLeaderboard, │
│ fetchRegionalLeaderboard, │
│ fetchRealmLeaderboard, │
│ fetchPlayerLeaderboard, │
│ } from "../../lib/api.js"; │
│ import { API_BASE_URL, DEFAULT_SEASON_ID } f │
│ rom "../constants.js"; │
│ import { │
│ createDungeonLeaderboardEmbed, │
│ createPlayerLeaderboardEmbed, │
│ createDungeonLeaderboardRefreshButton, │
│ createPlayerLeaderboardRefreshButton, │
│ type LeaderboardRun, │
│ type PlayerRanking, │
│ } from "../embeds/leaderboard.js"; │
│ import { │
│ createAPIErrorEmbed, │
│ createInvalidInputEmbed, │
│ } from "../embeds/error.js"; │
│ import { getDungeons } from "../indexes/cach │
│ e.js"; │
│ │
│ /** │
│ * handles the /leaderboard command │
│ * routes to dungeon or players subcommand │
│ */ │
│ export async function handleLeaderboardComma │
│ nd( │
│ interaction: DiscordInteraction, │
│ ): Promise<InteractionResponseData> { │
│ const subcommand = interaction.data?.optio │
│ ns?.[0]; │
│ │
│ if (!subcommand) { │
│ return { │
│ embeds: [createInvalidInputEmbed("subc │
│ ommand", "missing")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ if (subcommand.name === "dungeon") { │
│ return handleDungeonLeaderboard(subcomma │
│ nd.options || []); │
│ } else if (subcommand.name === "players") │
│ { │
│ return handlePlayersLeaderboard(subcomma │
│ nd.options || []); │
│ } │
│ │
│ return { │
│ embeds: [createInvalidInputEmbed("subcom │
│ mand", subcommand.name)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ /** │
│ * handles /leaderboard dungeon subcommand │
│ */ │
│ async function handleDungeonLeaderboard( │
│ options: Array<{ name: string; value?: str │
│ ing | number | boolean }>, │
│ ): Promise<InteractionResponseData> { │
│ const dungeon = getOptionValue(options, "d │
│ ungeon") as string; │
│ const scope = getOptionValue(options, "sco │
│ pe") as string; │
│ const region = getOptionValue(options, "re │
│ gion") as string | undefined; │
│ const realm = getOptionValue(options, "rea │
│ lm") as string | undefined; │
│ const limit = (getOptionValue(options, "li │
│ mit") as number) || 10; │
│ const season = │
│ (getOptionValue(options, "season") as st │
│ ring) || DEFAULT_SEASON_ID; │
│ const page = 1; │
│ │
│ // validate required options │
│ if (!dungeon || !scope) { │
│ return { │
│ embeds: [ │
│ createInvalidInputEmbed("options", " │
│ dungeon and scope are required"), │
│ ], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate scope │
│ if (!["global", "region", "realm"].include │
│ s(scope)) { │
│ return { │
│ embeds: [createInvalidInputEmbed("scop │
│ e", scope)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate region if scope is region or r │
│ ealm │
│ if ((scope === "region" || scope === "real │
│ m") && !region) { │
│ return { │
│ embeds: [createInvalidInputEmbed("regi │
│ on", "required for this scope")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate realm if scope is realm │
│ if (scope === "realm" && !realm) { │
│ return { │
│ embeds: [createInvalidInputEmbed("real │
│ m", "required for realm scope")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ try { │
│ // get dungeon name from cache │
│ const dungeons = await getDungeons(); │
│ const dungeonInfo = dungeons.find((d) => │
│ d.slug === dungeon); │
│ if (!dungeonInfo) { │
│ return { │
│ embeds: [createInvalidInputEmbed("du │
│ ngeon", dungeon)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // fetch leaderboard based on scope │
│ let data: LeaderboardData | null = null; │
│ const seasonNum = Number(season); │
│ if (scope === "global") { │
│ data = await fetchGlobalLeaderboard( │
│ dungeonInfo.id, │
│ page, │
│ undefined, │
│ API_BASE_URL, │
│ seasonNum, │
│ ); │
│ } else if (scope === "region") { │
│ data = await fetchRegionalLeaderboard( │
│ region!, │
│ dungeonInfo.id, │
│ page, │
│ undefined, │
│ API_BASE_URL, │
│ seasonNum, │
│ ); │
│ } else if (scope === "realm") { │
│ data = await fetchRealmLeaderboard( │
│ region!, │
│ realm!, │
│ dungeonInfo.id, │
│ page, │
│ undefined, │
│ API_BASE_URL, │
│ seasonNum, │
│ ); │
│ } │
│ │
│ if (!data || !data.leading_groups) { │
│ return { │
│ embeds: [createAPIErrorEmbed("No lea │
│ derboard data found")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // map runs to our interface (timestamp │
│ is already in ms) │
│ const runs: LeaderboardRun[] = data.lead │
│ ing_groups.map((run) => ({ │
│ rank: 0, // not used, calculated from │
│ index in embed │
│ duration: run.duration, │
│ timestamp: new Date(run.completed_time │
│ stamp).toISOString(), │
│ members: run.members, │
│ })); │
│ │
│ // create embed │
│ const embed = createDungeonLeaderboardEm │
│ bed( │
│ dungeonInfo.name, │
│ dungeon, │
│ scope, │
│ region, │
│ realm, │
│ runs, │
│ limit, │
│ season, │
│ ); │
│ │
│ // create refresh button │
│ const components = createDungeonLeaderbo │
│ ardRefreshButton( │
│ dungeon, │
│ scope, │
│ region, │
│ realm, │
│ limit, │
│ season, │
│ ); │
│ │
│ return { │
│ embeds: [embed], │
│ components, │
│ }; │
│ } catch (error) { │
│ console.error("Error fetching dungeon le │
│ aderboard:", error); │
│ return { │
│ embeds: [createAPIErrorEmbed()], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ } │
│ │
│ // handles /leaderboard players subcommand │
│ async function handlePlayersLeaderboard( │
│ options: Array<{ name: string; value?: str │
│ ing | number | boolean }>, │
│ ): Promise<InteractionResponseData> { │
│ const scopeValue = getOptionValue(options, │
│ "scope") as string; │
│ const region = getOptionValue(options, "re │
│ gion") as string | undefined; │
│ const realm = getOptionValue(options, "rea │
│ lm") as string | undefined; │
│ const className = getOptionValue(options, │
│ "class") as string | undefined; │
│ const limit = (getOptionValue(options, "li │
│ mit") as number) || 25; │
│ const season = │
│ (getOptionValue(options, "season") as st │
│ ring) || DEFAULT_SEASON_ID; │
│ const page = 1; │
│ │
│ // validate required options │
│ if (!scopeValue) { │
│ return { │
│ embeds: [createInvalidInputEmbed("scop │
│ e", "required")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // validate scope │
│ if (!["global", "region", "realm"].include │
│ s(scopeValue)) { │
│ return { │
│ embeds: [createInvalidInputEmbed("scop │
│ e", scopeValue)], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // map scope value to API format ("region" │
│ -> "regional") │
│ const scope: "global" | "regional" | "real │
│ m" = │
│ scopeValue === "region" ? "regional" : ( │
│ scopeValue as "global" | "realm"); │
│ │
│ try { │
│ // build API options │
│ const opts: { classKey?: string; realmSl │
│ ug?: string; seasonId?: number } = │
│ {}; │
│ if (className) opts.classKey = className │
│ ; │
│ if (realm && scope === "realm") opts.rea │
│ lmSlug = realm; │
│ if (season) opts.seasonId = Number(seaso │
│ n); │
│ │
│ // fetch player leaderboard │
│ const data: PlayerLeaderboardData | null │
│ = await fetchPlayerLeaderboard( │
│ scope, │
│ region, │
│ page, │
│ 10, │
│ opts, │
│ API_BASE_URL, │
│ ); │
│ │
│ if (!data || !data.leaderboard) { │
│ return { │
│ embeds: [createAPIErrorEmbed("No pla │
│ yer leaderboard data found")], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ │
│ // map players to our interface │
│ const players: PlayerRanking[] = data.le │
│ aderboard.map((player, index) => ({ │
│ rank: player.global_ranking || index + │
│ 1, // use index+1 as fallback │
│ name: player.name, │
│ realm_name: player.realm_name, │
│ region: player.region, │
│ class_name: player.class_name, │
│ active_spec_name: player.active_spec_n │
│ ame, │
│ best_avg_time: player.combined_best_ti │
│ me, │
│ completed_dungeons: player.dungeons_co │
│ mpleted || 0, │
│ global_ranking_bracket: player.global_ │
│ ranking_bracket, │
│ })); │
│ │
│ // create embed │
│ const embed = createPlayerLeaderboardEmb │
│ ed( │
│ scope, │
│ region, │
│ realm, │
│ className, │
│ players, │
│ limit, │
│ season, │
│ ); │
│ │
│ // create refresh button │
│ const components = createPlayerLeaderboa │
│ rdRefreshButton( │
│ scope, │
│ region, │
│ realm, │
│ className, │
│ limit, │
│ season, │
│ ); │
│ │
│ return { │
│ embeds: [embed], │
│ components, │
│ }; │
│ } catch (error) { │
│ console.error("Error fetching player lea │
│ derboard:", error); │
│ return { │
│ embeds: [createAPIErrorEmbed()], │
│ flags: 64, // EPHEMERAL │
│ }; │
│ } │
│ } │
│ │
│ // helper to get option value by name │
│ function getOptionValue( │
│ options: Array<{ name: string; value?: str │
│ ing | number | boolean }>, │
│ name: string, │
│ ): string | number | boolean | undefined { │
│ return options.find((opt) => opt.name === │
│ name)?.value; │
│ } │
└──────────────────────────────────────────────┘