Create admin endpoint to register Discord commands from web UI

cgen-313ec6ce04ef4104b5e86da3c2e89329
This commit is contained in:
Builder.io 2025-11-08 20:56:03 +00:00
parent 53bb0c8eb0
commit 332f7c2803

View file

@ -0,0 +1,166 @@
import type { VercelRequest, VercelResponse } from "@vercel/node";
import { REST, Routes } from "discord.js";
interface CommandData {
name: string;
description: string;
options?: any[];
}
// Define all commands that should be registered
const COMMANDS: CommandData[] = [
{
name: "verify",
description: "Link your Discord account to AeThex",
},
{
name: "set-realm",
description: "Choose your primary arm/realm (Labs, GameForge, Corp, etc.)",
options: [
{
name: "realm",
type: 3,
description: "Your primary realm",
required: true,
choices: [
{ name: "Labs", value: "labs" },
{ name: "GameForge", value: "gameforge" },
{ name: "Corp", value: "corp" },
{ name: "Foundation", value: "foundation" },
{ name: "Dev-Link", value: "devlink" },
],
},
],
},
{
name: "profile",
description: "View your linked AeThex profile",
},
{
name: "unlink",
description: "Disconnect your Discord account from AeThex",
},
{
name: "verify-role",
description: "Check your assigned Discord roles",
},
];
export default async function handler(
req: VercelRequest,
res: VercelResponse
) {
// Verify this is a POST request
if (req.method !== "POST") {
res.setHeader("Allow", "POST");
return res.status(405).json({ error: "Method not allowed" });
}
// Basic security: Check if requester has admin token
const authHeader = req.headers.authorization;
const adminToken = process.env.DISCORD_ADMIN_REGISTER_TOKEN;
if (!adminToken || authHeader !== `Bearer ${adminToken}`) {
return res.status(401).json({ error: "Unauthorized" });
}
// Validate environment variables
const requiredVars = ["DISCORD_BOT_TOKEN", "DISCORD_CLIENT_ID"];
const missingVars = requiredVars.filter((v) => !process.env[v]);
if (missingVars.length > 0) {
return res.status(500).json({
error: "Missing environment variables",
missing: missingVars,
});
}
try {
const rest = new REST({ version: "10" }).setToken(
process.env.DISCORD_BOT_TOKEN!
);
console.log(
`📝 Registering ${COMMANDS.length} Discord slash commands...`
);
try {
// Try bulk update first
const data = await rest.put(
Routes.applicationCommands(process.env.DISCORD_CLIENT_ID!),
{ body: COMMANDS }
);
console.log(`✅ Successfully registered ${data.length} slash commands`);
return res.status(200).json({
success: true,
message: `Registered ${data.length} slash commands`,
commands: (data as any[]).map((cmd: any) => cmd.name),
});
} catch (bulkError: any) {
// Handle Error 50240 (Entry Point conflict)
if (bulkError.code === 50240) {
console.warn(
"⚠️ Error 50240: Entry Point detected. Registering individually..."
);
const results = [];
let successCount = 0;
let skipCount = 0;
for (const command of COMMANDS) {
try {
// Try to post individual command
const posted = await rest.post(
Routes.applicationCommands(process.env.DISCORD_CLIENT_ID!),
{ body: command }
);
results.push({
name: command.name,
status: "registered",
id: (posted as any).id,
});
successCount++;
} catch (postError: any) {
// If command already exists (50045), skip it
if (postError.code === 50045) {
results.push({
name: command.name,
status: "already_exists",
});
skipCount++;
} else {
results.push({
name: command.name,
status: "error",
error: postError.message,
});
}
}
}
console.log(
`✅ Registration complete: ${successCount} new, ${skipCount} already existed`
);
return res.status(200).json({
success: true,
message: `Registered ${successCount} new commands (${skipCount} already existed)`,
results,
note: "Entry Point command is managed by Discord (Activities enabled)",
});
}
throw bulkError;
}
} catch (error: any) {
console.error("❌ Failed to register commands:", error);
return res.status(500).json({
success: false,
error: error?.message || "Failed to register commands",
code: error?.code,
});
}
}