import { Client, Events, GatewayIntentBits, PermissionFlagsBits, REST, Routes, } from "discord.js"; import { buttonCommands, ensureUnsolvedTag, slashCommands, getCtfForum } from "./commands.ts"; function requireEnv(key: string): string { let value = process.env[key]; if (!value) { throw new Error(`Missing ${key} environment variable.`); } return value; } let clientId = requireEnv("DISCORD_CLIENT_ID"); let token = requireEnv("DISCORD_TOKEN"); let activity = requireEnv("ACTIVITY"); export let celebrationMessage = requireEnv("CELEBRATION_MESSAGE"); let client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] }); let rest = new REST({ version: "10" }).setToken(token); client.once(Events.ClientReady, (c) => { console.log(`Logged in as ${c.user.tag}`); }); client.on(Events.GuildAvailable, guild => { console.log(`Available in Guild: ${guild.name}`); let role = guild.roles.botRoleFor(guild.client.user); if (!role) { console.error(`Bot has no role in ${guild.name}`); return; } for (let permission of [ PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ManageChannels, PermissionFlagsBits.ManageRoles, PermissionFlagsBits.SendMessages, PermissionFlagsBits.SendMessagesInThreads, PermissionFlagsBits.CreatePublicThreads, PermissionFlagsBits.CreatePrivateThreads, PermissionFlagsBits.ManageThreads, ]) { if (!role.permissions.has(permission)) { console.error(`Bot is missing permission ${permission} in ${guild.name}`); } } }); client.on(Events.InteractionCreate, async (interaction) => { try { if (interaction.isChatInputCommand()) { for (let command of slashCommands) { if (interaction.commandName === command.slashCommand.name) { await command.handler(interaction); break; } } } else if (interaction.isButton()) { for (let button of Object.values(buttonCommands)) { if (interaction.customId.startsWith(button.prefix)) { let id = interaction.customId.slice(button.prefix.length); await button.handler(interaction, id); break; } } } } catch (error) { if (error === "done") return; console.error("Error while handling interaction", error); if (interaction.isChatInputCommand() || interaction.isButton()) { if (interaction.deferred || interaction.replied) { await interaction.followUp({ content: "Something went wrong! :(", flags: "Ephemeral", }); } else { await interaction.reply({ content: "Something went wrong! :(", flags: "Ephemeral", }); } } } }); client.on(Events.ThreadCreate, async (thread) => { try { let forum = await getCtfForum(thread); if (thread.ownerId === client.user?.id) return; let tag = await ensureUnsolvedTag(forum); if (thread.appliedTags.includes(tag.id)) return; await thread.setAppliedTags([...thread.appliedTags, tag.id]); } catch (error) { if (error === "done") return; console.error("Failed to auto-tag thread", error); } }); await rest.put(Routes.applicationCommands(clientId), { body: slashCommands.map(command => command.slashCommand.toJSON()), }); await client.login(token); client.user?.setActivity(activity);