fix: refresh Discord avatar hash on every game load (#104)

Adds fetchDiscordUserById (bot token) to the Discord service and calls it
in parallel with the DB queries on game load. When the returned hash
differs from the stored value the Player record is updated and the hash
is immediately synced into the returned game state, so the resource bar
always shows the player's current Discord avatar.

Also adds onError fallback: if the avatar URL is stale before the next
load, the resource bar component now derives the URL fresh from state on
every render rather than caching it.
This commit is contained in:
2026-03-23 14:41:21 -07:00
committed by Naomi Carrigan
parent fc222ac522
commit 830a9d2a56
4 changed files with 185 additions and 4 deletions
+35 -1
View File
@@ -106,6 +106,40 @@ const fetchDiscordUser = async(
}
};
/**
* Fetches a Discord user's profile by their Discord ID using the bot token.
* Returns null on any failure so callers are never blocked by Discord API issues.
* @param discordId - The Discord user ID to look up.
* @returns The Discord user object, or null if the fetch fails.
*/
const fetchDiscordUserById = async(
discordId: string,
): Promise<DiscordUser | null> => {
const botToken = process.env.DISCORD_BOT_TOKEN;
if (botToken === undefined || botToken === "") {
return null;
}
try {
const response = await fetch(
`https://discord.com/api/v10/users/${discordId}`,
{ headers: { Authorization: `Bot ${botToken}` } },
);
if (!response.ok) {
return null;
}
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Response JSON matches DiscordUser shape */
return await (response.json() as Promise<DiscordUser>);
} catch (error) {
void logger.error(
"discord_fetch_user_by_id",
error instanceof Error
? error
: new Error(String(error)),
);
return null;
}
};
/**
* Builds the Discord OAuth authorisation URL.
* @returns The full OAuth URL to redirect the user to.
@@ -133,4 +167,4 @@ const buildOAuthUrl = (): string => {
};
export type { DiscordTokenResponse, DiscordUser };
export { buildOAuthUrl, exchangeCode, fetchDiscordUser };
export { buildOAuthUrl, exchangeCode, fetchDiscordUser, fetchDiscordUserById };