1import { REST, Routes, SlashCommandBuilder } from 'discord.js'
2import { readdirSync } from 'node:fs'
3import { join } from 'node:path'
4import { config } from 'dotenv'
5import Logger from '@/classes/logger'
6
7interface EnvVars {
8 DISCORD_BOT_TOKEN: string
9 DISCORD_CLIENT_ID: string
10 DISCORD_GUILD_ID: string
11}
12
13export const deployCommands = async () => {
14 config()
15 const commands = []
16
17 // Validate environment variables
18 const requiredEnvVars: (keyof EnvVars)[] = [
19 'DISCORD_BOT_TOKEN',
20 'DISCORD_CLIENT_ID',
21 'DISCORD_GUILD_ID',
22 ]
23
24 const missingVars = requiredEnvVars.filter((key) => !process.env[key])
25 if (missingVars.length > 0) {
26 Logger.log(
27 'error',
28 `Missing environment variables: ${missingVars.join(', ')}`,
29 'Commands',
30 )
31 process.exit(1)
32 }
33
34 const {
35 DISCORD_BOT_TOKEN: token,
36 DISCORD_CLIENT_ID: clientId,
37 DISCORD_GUILD_ID: guildId,
38 } = process.env as unknown as EnvVars
39
40 try {
41 // Load commands
42 const folderPath = join(__dirname, '..', 'commands')
43 const commandFolders = readdirSync(folderPath)
44
45 for (const folder of commandFolders) {
46 const commandFiles = readdirSync(join(folderPath, folder)).filter(
47 (file) =>
48 file.endsWith(process.env.NODE_ENV === 'production' ? '.js' : '.ts'),
49 )
50
51 for (const file of commandFiles) {
52 const command = require(join(folderPath, folder, file)).default
53 if (!command?.data?.name) {
54 Logger.log(
55 'warn',
56 `Command ${file} is missing required properties`,
57 'Commands',
58 )
59 continue
60 }
61 commands.push(
62 command.data instanceof SlashCommandBuilder ?
63 command.data.toJSON()
64 : command.data,
65 )
66 }
67 }
68
69 // Deploy commands
70 const rest = new REST({ version: '10' }).setToken(token)
71 Logger.log(
72 'info',
73 `Deploying ${commands.length} application (/) commands...`,
74 'Commands',
75 )
76
77 await rest.put(Routes.applicationGuildCommands(clientId, guildId), {
78 body: commands,
79 })
80
81 Logger.log(
82 'info',
83 'Successfully deployed application (/) commands.',
84 'Commands',
85 )
86 } catch (error) {
87 Logger.log('error', `Failed to deploy commands: ${error}`, 'Commands')
88 process.exit(1)
89 }
90}
91
92// Self-executing function when run directly
93if (require.main === module) {
94 deployCommands().catch(console.error)
95}
96