Refactor architecture: improve env loading and command workflow

This commit is contained in:
syntaxbullet
2025-12-05 12:06:29 +01:00
parent f4b72b93e4
commit 48995204a5
16 changed files with 362 additions and 30 deletions

View File

@@ -1,7 +1,8 @@
import { Client as DiscordClient, Collection, GatewayIntentBits, REST, Routes, SlashCommandBuilder } from "discord.js";
import { Client as DiscordClient, Collection, GatewayIntentBits, REST, Routes } from "discord.js";
import { readdir } from "node:fs/promises";
import { join } from "node:path";
import type { Command } from "@lib/types";
import { env } from "@lib/env";
class Client extends DiscordClient {
@@ -34,15 +35,21 @@ class Client extends DiscordClient {
try {
const commandModule = await import(filePath);
const commands = Object.values(commandModule);
if (commands.length === 0) {
console.warn(`⚠️ No commands found in ${file.name}`);
continue;
}
for (const command of commands) {
if (this.isValidCommand(command)) {
this.commands.set(command.data.name, command);
console.log(`Loaded command: ${command.data.name}`);
console.log(`Loaded command: ${command.data.name}`);
} else {
console.warn(`⚠️ Skipping invalid command in ${file.name}`);
}
}
} catch (error) {
console.error(`Failed to load command from ${filePath}:`, error);
console.error(`Failed to load command from ${filePath}:`, error);
}
}
} catch (error) {
@@ -55,9 +62,22 @@ class Client extends DiscordClient {
}
async deployCommands() {
const rest = new REST().setToken(this.token!);
// We use env.DISCORD_BOT_TOKEN directly so this can run without client.login()
const token = env.DISCORD_BOT_TOKEN;
if (!token) {
console.error("❌ DISCORD_BOT_TOKEN is not set.");
return;
}
const rest = new REST().setToken(token);
const commandsData = this.commands.map(c => c.data.toJSON());
const guildId = process.env.DISCORD_GUILD_ID;
const guildId = env.DISCORD_GUILD_ID;
const clientId = env.DISCORD_CLIENT_ID;
if (!clientId) {
console.error("❌ DISCORD_CLIENT_ID is not set.");
return;
}
try {
console.log(`Started refreshing ${commandsData.length} application (/) commands.`);
@@ -66,22 +86,27 @@ class Client extends DiscordClient {
if (guildId) {
console.log(`Registering commands to guild: ${guildId}`);
data = await rest.put(
Routes.applicationGuildCommands(this.user!.id, guildId),
Routes.applicationGuildCommands(clientId, guildId),
{ body: commandsData },
);
// Clear global commands to avoid duplicates
await rest.put(Routes.applicationCommands(this.user!.id), { body: [] });
await rest.put(Routes.applicationCommands(clientId), { body: [] });
} else {
console.log('Registering commands globally');
data = await rest.put(
Routes.applicationCommands(this.user!.id),
Routes.applicationCommands(clientId),
{ body: commandsData },
);
}
console.log(`Successfully reloaded ${(data as any).length} application (/) commands.`);
} catch (error) {
console.error(error);
console.log(`Successfully reloaded ${(data as any).length} application (/) commands.`);
} catch (error: any) {
if (error.code === 50001) {
console.warn("⚠️ Missing Access: The bot is not in the guild or lacks 'applications.commands' scope.");
console.warn(" If you are testing locally, make sure you invited the bot with scope 'bot applications.commands'.");
} else {
console.error(error);
}
}
}
}