169 lines
4.8 KiB
TypeScript
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,
|
|
});
|
|
}
|
|
}
|