fix(discord): add token-based fallback for application ID resolution

When the Discord API call to /oauth2/applications/@me fails (timeout,
network error), the bot fails to start with "Failed to resolve Discord
application id". Add a fallback that extracts the application ID by
base64-decoding the first segment of the bot token, keeping it as a
string to avoid precision loss for snowflake IDs exceeding
Number.MAX_SAFE_INTEGER (2^53 - 1).

Fixes #29608

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dhananjai1729
2026-02-28 15:21:34 +05:30
committed by Peter Steinberger
parent 7f4d1b7531
commit 4b2e35ab95

View File

@@ -165,11 +165,44 @@ export async function probeDiscord(
}
}
/**
* Extract the application (bot user) ID from a Discord bot token by
* base64-decoding the first segment. Discord tokens have the format:
* base64(user_id) . timestamp . hmac
* The decoded first segment is the numeric snowflake ID as a plain string,
* so we keep it as a string to avoid precision loss for IDs that exceed
* Number.MAX_SAFE_INTEGER.
*/
export function parseApplicationIdFromToken(token: string): string | undefined {
const normalized = normalizeDiscordToken(token);
if (!normalized) {
return undefined;
}
const firstDot = normalized.indexOf(".");
if (firstDot <= 0) {
return undefined;
}
try {
const decoded = Buffer.from(normalized.slice(0, firstDot), "base64").toString("utf-8");
if (/^\d+$/.test(decoded)) {
return decoded;
}
return undefined;
} catch {
return undefined;
}
}
export async function fetchDiscordApplicationId(
token: string,
timeoutMs: number,
fetcher: typeof fetch = fetch,
): Promise<string | undefined> {
const json = await fetchDiscordApplicationMe(token, timeoutMs, fetcher);
return json?.id ?? undefined;
if (json?.id) {
return json.id;
}
// Fallback: extract the application ID directly from the token to handle
// cases where the API call fails (timeout, network error, etc.).
return parseApplicationIdFromToken(token);
}