deployDiscordCommands.ts

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