diff --git a/source/commands/ping.ts b/source/commands/ping.ts index 380539e..eba6243 100644 --- a/source/commands/ping.ts +++ b/source/commands/ping.ts @@ -1,14 +1,16 @@ -import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, CommandInteraction } from 'discord.js'; interface Command { - data: SlashCommandBuilder; - execute: (interaction: any) => Promise<void>; + data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">; + execute: (interaction: CommandInteraction) => Promise<void>; } -export const command: Command = { - data: new SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!'), +const command: Command = { + data: new SlashCommandBuilder() + .setName('ping') + .setDescription('Replies with Pong!'), execute: async (interaction) => { - await interaction.reply('Pong!'); + await interaction.reply(`Pong!`); }, }; diff --git a/source/commands/server.ts b/source/commands/server.ts index f650196..ce02b79 100644 --- a/source/commands/server.ts +++ b/source/commands/server.ts @@ -1,13 +1,17 @@ -import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, CommandInteraction } from 'discord.js'; interface Command { - data: SlashCommandBuilder; - execute: (interaction: any) => Promise<void>; + data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">; + execute: (interaction: CommandInteraction) => Promise<void>; } -export const command: Command = { - data: new SlashCommandBuilder().setName('server').setDescription('Provides information about the server.'), +const command: Command = { + data: new SlashCommandBuilder() + .setName('server') + .setDescription('Provides information about the server.'), execute: async (interaction) => { - await interaction.reply(`This server is ${interaction.guild.name} and has ${interaction.guild.memberCount} members.`); + await interaction.reply(`This server is ${interaction?.guild?.name} and has ${interaction?.guild?.memberCount} members.`); }, }; + +export default command; \ No newline at end of file diff --git a/source/commands/user.ts b/source/commands/user.ts index 4fa40d0..e354aa2 100644 --- a/source/commands/user.ts +++ b/source/commands/user.ts @@ -1,13 +1,21 @@ -import { SlashCommandBuilder } from 'discord.js'; +import { SlashCommandBuilder, CommandInteraction, GuildMember } from 'discord.js'; interface Command { - data: SlashCommandBuilder; - execute: (interaction: any) => Promise<void>; + data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">; + execute: (interaction: CommandInteraction) => Promise<void>; } -export const command: Command = { - data: new SlashCommandBuilder().setName('user').setDescription('Provides information about the user.'), +const command: Command = { + data: new SlashCommandBuilder() + .setName('user') + .setDescription('Provides information about the user.'), execute: async (interaction) => { - await interaction.reply(`This command was run by ${interaction.user.username}, who joined on ${interaction.member.joinedAt}.`); + if (interaction.member instanceof GuildMember) { + await interaction.reply(`This command was run by ${interaction.user.username}, who joined on ${interaction.member.joinedAt}.`); + } else { + await interaction.reply(`This command was run by ${interaction.user.username}.`); + } }, }; + +export default command; \ No newline at end of file diff --git a/source/config.example.json b/source/config.example.json index 87fb0b5..a3d2f0e 100644 --- a/source/config.example.json +++ b/source/config.example.json @@ -1,5 +1,5 @@ { "token": "DISCORD_BOT_API_KEY", - "application_client_id": "DISCORD_BOT_ID", - "guild_id": "DISCORD_SERVER_ID" + "clientId": "DISCORD_BOT_ID", + "guildId": "DISCORD_SERVER_ID" } \ No newline at end of file diff --git a/source/discord-bot.ts b/source/discord-bot.ts index 4f1f4de..8eeb68b 100644 --- a/source/discord-bot.ts +++ b/source/discord-bot.ts @@ -5,7 +5,7 @@ import { Client, Collection, Events, GatewayIntentBits } from'discord.js'; import config from './config.json' assert { type: 'json' }; import { deployCommands } from './util/deployCommand.js'; -const { token, application_client_id, guild_id } = config; +const { token } = config; // Create a new client instance const client: any = new Client({ intents: [GatewayIntentBits.Guilds] }); @@ -33,7 +33,7 @@ try { } try { - await deployCommands({token, guild_id, application_client_id}); + await deployCommands(); } catch (error: any) { console.log(`Error while registering commands: ${error}`) } diff --git a/source/util/deployCommand.ts b/source/util/deployCommand.ts index 3514cd6..47b725e 100644 --- a/source/util/deployCommand.ts +++ b/source/util/deployCommand.ts @@ -1,44 +1,45 @@ import { REST, Routes } from 'discord.js'; -import fs from 'node:fs'; -import path from 'node:path'; +import config from '../config.json' assert { type: 'json' }; +import fs from 'fs'; +import path from 'path'; -export async function deployCommands({token, guildId, clientId}: any) { - const commands = []; +const { token, clientId, guildId } = config; - const __dirname = path.resolve(); - - const commandsPath = path.join(__dirname, '/target/commands/'); - const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); +const __dirname = path.resolve(); +const commandsPath = path.join(__dirname, 'target', 'commands'); +const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); - // Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment - for (const file of commandFiles) { - const filePath = path.join('file://', commandsPath, file); - const command = await import(filePath); - if (command instanceof Object && 'data' in command && 'execute' in command) { - commands.push(command.data.toJSON()); - } else { - console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`); - } - } - - // Construct and prepare an instance of the REST module - const rest = new REST().setToken(token); - - // and deploy your commands! - (async () => { - try { - console.log(`Started refreshing ${commands.length} application (/) commands.`); - - // The put method is used to fully refresh all commands in the guild with the current set - const data: any = await rest.put( - Routes.applicationGuildCommands(clientId, guildId), - { body: commands }, - ); - - console.log(`Successfully reloaded ${data.length} application (/) commands.`); - } catch (error) { - // And of course, make sure you catch and log any errors! - console.error(error); - } - })(); -} \ No newline at end of file +const rest = new REST({ version: '9' }).setToken(token); + +export const deployCommands = async () => { + try { + console.log(`Started refreshing ${commandFiles.length} application (/) commands.`); + + // Prepare the commands array + const commands = commandFiles.map(async (file) => { + const filePath = path.join('file://', commandsPath, file); + const commandModule = await import(filePath); + const command = commandModule.default; + + if (command instanceof Object && 'data' in command) { + return command.data.toJSON(); + } else { + console.log(`[WARNING] The command at ${filePath} is missing a required "data" property.`); + return null; + } + }); + + // Filter out any null values from the commands array + const validCommands = await Promise.all(commands.filter(command => command !== null)); + + // Use the provided way of registering commands + const data: any = await rest.put( + Routes.applicationGuildCommands(clientId, guildId), + { body: validCommands }, + ); + + console.log(`Successfully reloaded ${data.length} application (/) commands.`); + } catch (error) { + console.error(error); + } +}; \ No newline at end of file