aethex-forge/api/discord/admin-register-commands.ts
Builder.io a22b901327 completionId: cgen-2923fc81a1dc499eb4890de6f5ecff56
cgen-2923fc81a1dc499eb4890de6f5ecff56
2025-11-09 04:30:40 +00:00

169 lines
4.8 KiB
TypeScript

import type { VercelRequest, VercelResponse } from "@vercel/node";
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) {
try {
// Allow both GET and POST
if (req.method !== "POST" && req.method !== "GET") {
res.setHeader("Allow", "GET, POST");
return res.status(405).json({ error: "Method not allowed" });
}
// Basic security: Check if requester has admin token
const authHeader = req.headers.authorization;
const queryToken = req.query.token;
const adminToken = process.env.DISCORD_ADMIN_REGISTER_TOKEN;
const providedToken = authHeader
? authHeader.replace("Bearer ", "")
: queryToken;
if (!adminToken || providedToken !== adminToken) {
return res.status(401).json({ error: "Unauthorized - Invalid token" });
}
// 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,
});
}
// Import discord.js dynamically to avoid import errors
const { REST, Routes } = await import("discord.js");
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,
details: error?.stack,
});
}
}