From 9c1a87296d2c9b2c3f637608343343a3fb23057d Mon Sep 17 00:00:00 2001 From: emallson Date: Wed, 7 Jan 2026 11:05:39 -0500 Subject: [PATCH 1/2] add "players in fight" api endpoint to fix classic issue --- src/route/wcl.ts | 2 + src/route/wcl/fight-players.ts | 112 +++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/route/wcl/fight-players.ts diff --git a/src/route/wcl.ts b/src/route/wcl.ts index 91927ba..c5d28bf 100644 --- a/src/route/wcl.ts +++ b/src/route/wcl.ts @@ -7,9 +7,11 @@ import parses from "./wcl/character-parses"; import encounterRankings from "./wcl/encounter-rankings"; import { cacheControl } from "../common/cache-control"; import guildReports from "./wcl/guild-reports"; +import fightPlayers from "./wcl/fight-players"; const wcl: FastifyPluginAsync = async (app) => { app.register(cacheControl); + fightPlayers(app); fights(app); events(app); eventsByType(app); diff --git a/src/route/wcl/fight-players.ts b/src/route/wcl/fight-players.ts new file mode 100644 index 0000000..1294370 --- /dev/null +++ b/src/route/wcl/fight-players.ts @@ -0,0 +1,112 @@ +import { ReportParams, wrapEndpoint } from "./common"; +import * as api from "../../wcl/api"; +import { gql } from "graphql-request"; + +type PlayerDetailsResponse = { + reportData: { + report: { + playerDetails: { + data: { + playerDetails: { + tanks?: PlayerDetailsPlayer[]; + dps?: PlayerDetailsPlayer[]; + healers?: PlayerDetailsPlayer[]; + }; + }; + }; + }; + }; +}; + +type PlayerDetailsPlayer = { + name: string; + id: number; + guid: number; + type: string; + server: string; + region: string; + icon: string; + minItemLevel: number; + maxItemLevel: number; + specs: Array<{ spec: string; count: number }>; + combatantInfo?: { + specIDs: number[]; + }; +}; + +type PlayerDetails = { + id: number; + name: string; + server: string; + region: string; + ilvl: number; + className: string; + specName?: string; + specID?: number; + role: "tank" | "dps" | "healer"; + guid: number; +}; + +function extractPlayerDetails( + player: PlayerDetailsPlayer, + role: "dps" | "tanks" | "healers", +): PlayerDetails { + return { + id: player.id, + name: player.name, + server: player.server, + region: player.region, + // since we are only querying a single fight, min = max + ilvl: player.minItemLevel, + className: player.type, + specName: player.specs[0]?.spec, + specID: player.combatantInfo?.specIDs[0], + role: (role === "dps" ? "dps" : role.slice(0, -1)) as PlayerDetails["role"], + guid: player.guid, + }; +} + +const playerDetailsQuery = gql` + query getPlayerDetails($code: String, $fight: Int) { + reportData { + report(code: $code) { + playerDetails(fightIDs: [$fight], includeCombatantInfo: true) + } + } + } +`; + +const fightPlayers = wrapEndpoint<{}, ReportParams & { fight: string }>( + "/i/v2/report/:code/fight/:fight/players", + "wcl-fight-players", + async (req) => { + const rawData = await api.query< + PlayerDetailsResponse, + { code: string; fight: number } + >( + playerDetailsQuery, + { + code: req.params.code, + fight: parseInt(req.params.fight), + }, + { + refreshToken: req.user?.data.wcl?.refreshToken, + }, + ); + + const details = rawData.reportData.report.playerDetails.data.playerDetails; + + const result = []; + for (const key of Object.keys(details) as (keyof typeof details)[]) { + for (const player of details[key] ?? []) { + result.push(extractPlayerDetails(player, key)); + } + } + + return { + players: result, + }; + }, +); + +export default fightPlayers; From 12a2578d1e6e2ce72aef057258338ffb5c70be17 Mon Sep 17 00:00:00 2001 From: emallson Date: Thu, 8 Jan 2026 09:53:34 -0500 Subject: [PATCH 2/2] ilvl can be undefined --- src/route/wcl/fight-players.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/route/wcl/fight-players.ts b/src/route/wcl/fight-players.ts index 1294370..114b5a6 100644 --- a/src/route/wcl/fight-players.ts +++ b/src/route/wcl/fight-players.ts @@ -26,8 +26,8 @@ type PlayerDetailsPlayer = { server: string; region: string; icon: string; - minItemLevel: number; - maxItemLevel: number; + minItemLevel?: number; + maxItemLevel?: number; specs: Array<{ spec: string; count: number }>; combatantInfo?: { specIDs: number[]; @@ -39,7 +39,7 @@ type PlayerDetails = { name: string; server: string; region: string; - ilvl: number; + ilvl?: number; className: string; specName?: string; specID?: number;