feat(platform): add Discord onboarding and Velocity gate

This commit is contained in:
dmg
2026-08-01 13:45:18 -04:00
parent 9d305e5dc9
commit c5de0a1810
80 changed files with 4840 additions and 1572 deletions
+65
View File
@@ -0,0 +1,65 @@
const MINECRAFT_USERNAME = /^[A-Za-z0-9_]{3,16}$/;
const MINECRAFT_UUID = /^[0-9a-f]{32}$/i;
const DISCORD_NICKNAME_LIMIT = 32;
export interface JavaProfile {
uuid: string;
username: string;
}
export async function lookupJavaProfile(
username: string,
request: typeof fetch = fetch,
): Promise<JavaProfile | null> {
const candidate = username.trim();
if (!MINECRAFT_USERNAME.test(candidate)) return null;
const response = await request(
`https://api.mojang.com/users/profiles/minecraft/${encodeURIComponent(candidate)}`,
{ headers: { accept: "application/json" }, cache: "no-store" },
);
if (response.status === 204 || response.status === 404) return null;
if (!response.ok) throw new Error(`Mojang profile lookup failed (${response.status})`);
const profile: unknown = await response.json();
if (!profile || typeof profile !== "object") return null;
const { id, name } = profile as { id?: unknown; name?: unknown };
if (typeof id !== "string" || !MINECRAFT_UUID.test(id)) return null;
if (typeof name !== "string" || !MINECRAFT_USERNAME.test(name)) return null;
return { uuid: id.toLowerCase(), username: name };
}
export function formatDiscordNickname(firstName: string, minecraftUsername: string) {
const suffix = ` (${minecraftUsername})`;
const availableCharacters = DISCORD_NICKNAME_LIMIT - [...suffix].length;
const shortenedName = [...firstName.trim()].slice(0, Math.max(1, availableCharacters)).join("").trimEnd();
return `${shortenedName}${suffix}`;
}
export async function updateGuildNickname(
input: {
guildId: string;
discordUserId: string;
nickname: string;
botToken: string;
},
request: typeof fetch = fetch,
) {
const response = await request(
`https://discord.com/api/v10/guilds/${input.guildId}/members/${input.discordUserId}`,
{
method: "PATCH",
headers: {
authorization: `Bot ${input.botToken}`,
"content-type": "application/json",
},
body: JSON.stringify({ nick: input.nickname }),
},
);
if (!response.ok) {
throw new Error(`Discord nickname update failed (${response.status})`);
}
}