discord-music-bot/deploy-commands.ts
aki 3c4dc51855 refactor: Convert project from JavaScript to TypeScript
- Converted all .js files to .ts
- Added TypeScript configuration (tsconfig.json)
- Added ESLint and Prettier configuration
- Updated package.json dependencies
- Modified Docker and application configurations
2025-04-24 13:48:10 +08:00

104 lines
4.4 KiB
TypeScript

import { REST, Routes, APIApplicationCommand } from 'discord.js';
import fs from 'node:fs';
import path from 'node:path';
import logger from './src/utils/logger'; // Use default import now
import dotenv from 'dotenv';
// --- Setup ---
dotenv.config(); // Load .env variables
// Log presence of required env vars (optional, but helpful for debugging)
// logger.info(`CLIENT_ID: ${process.env.CLIENT_ID ? 'Present' : 'MISSING!'}`);
// logger.info(`DISCORD_TOKEN: ${process.env.DISCORD_TOKEN ? 'Present' : 'MISSING!'}`);
// --- Configuration ---
const clientId = process.env.CLIENT_ID;
const token = process.env.DISCORD_TOKEN;
if (!clientId || !token) {
logger.error('Missing CLIENT_ID or DISCORD_TOKEN in .env file for command deployment!');
process.exit(1);
}
const commands: Omit<APIApplicationCommand, 'id' | 'application_id' | 'version'>[] = []; // Type the commands array more accurately
// Grab all the command files from the commands directory
const commandsPath = path.join(__dirname, 'src', 'commands');
// Read .ts files now
const commandFiles = fs.readdirSync(commandsPath).filter((file: string) => file.endsWith('.ts')); // Add string type
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
logger.info(`Started loading ${commandFiles.length} application (/) commands for deployment.`);
const loadCommandsForDeployment = async () => {
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
try {
// Use dynamic import
const commandModule = await import(filePath);
// Assuming commands export default or have a 'default' property
const command = commandModule.default || commandModule;
if (command && typeof command === 'object' && 'data' in command && typeof command.data.toJSON === 'function') {
// We push the JSON representation which matches the API structure
commands.push(command.data.toJSON());
logger.info(`Loaded command for deployment: ${command.data.name}`);
} else {
logger.warn(`[WARNING] The command at ${filePath} is missing a required "data" property with a "toJSON" method.`);
}
} catch (error: unknown) { // Type error as unknown
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Error loading command at ${filePath} for deployment: ${errorMessage}`, error);
}
}
};
// Construct and prepare an instance of the REST module
const rest = new REST({ version: '10' }).setToken(token);
// Define the deployment function
const deployCommands = async () => {
try {
await loadCommandsForDeployment(); // Wait for commands to be loaded
if (commands.length === 0) {
logger.warn('No commands loaded for deployment. Exiting.');
return;
}
logger.info(`Started refreshing ${commands.length} application (/) commands.`);
// The put method is used to fully refresh all commands
const guildId = process.env.GUILD_ID;
let data: any; // Type appropriately if possible, depends on discord.js version
if (guildId) {
// Deploying to a specific guild (faster for testing)
logger.info(`Deploying commands to guild: ${guildId}`);
data = await rest.put(
Routes.applicationGuildCommands(clientId, guildId),
{ body: commands },
);
logger.info(`Successfully reloaded ${data.length} application (/) commands in guild ${guildId}.`);
} else {
// Deploying globally (can take up to an hour)
logger.info('Deploying commands globally...');
data = await rest.put(
Routes.applicationCommands(clientId),
{ body: commands },
);
logger.info(`Successfully reloaded ${data.length} global application (/) commands.`);
}
} catch (error: unknown) { // Type error as unknown
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Failed during command deployment: ${errorMessage}`, error);
}
};
// Execute the deployment
deployCommands();
// Note: The old wipe logic is removed as PUT overwrites existing commands.
// If you specifically need to wipe commands first for some reason,
// you can add separate PUT requests with an empty body before deploying.