Bug fixes and ~~performance~~ typing improvements
diff --git a/src/actions/createModActionTicket.ts b/src/actions/createModActionTicket.ts
index 41f949c..0eca621 100644
--- a/src/actions/createModActionTicket.ts
+++ b/src/actions/createModActionTicket.ts
@@ -11,24 +11,11 @@
     customReason?: string
 ) {
     const config = await client.database.guilds.read(guild.id);
-    const {
-        log,
-        NucleusColors,
-        entry,
-        renderUser,
-        renderChannel,
-        renderDelta
-    } = client.logger;
+    const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
     const overwrites = [
         {
             id: member,
-            allow: [
-                "VIEW_CHANNEL",
-                "SEND_MESSAGES",
-                "ATTACH_FILES",
-                "ADD_REACTIONS",
-                "READ_MESSAGE_HISTORY"
-            ],
+            allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
             type: "member"
         }
     ] as Discord.OverwriteResolvable[];
@@ -40,13 +27,7 @@
     if (config.tickets.supportRole !== null) {
         overwrites.push({
             id: guild.roles.cache.get(config.tickets.supportRole),
-            allow: [
-                "VIEW_CHANNEL",
-                "SEND_MESSAGES",
-                "ATTACH_FILES",
-                "ADD_REACTIONS",
-                "READ_MESSAGE_HISTORY"
-            ],
+            allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
             type: "role"
         });
     }
@@ -67,16 +48,10 @@
     try {
         await c.send({
             content:
-                `<@${member.id}>` +
-                (config.tickets.supportRole !== null
-                    ? ` • <@&${config.tickets.supportRole}>`
-                    : ""),
+                `<@${member.id}>` + (config.tickets.supportRole !== null ? ` • <@&${config.tickets.supportRole}>` : ""),
             allowedMentions: {
                 users: [member.id],
-                roles:
-                    config.tickets.supportRole !== null
-                        ? [config.tickets.supportRole]
-                        : []
+                roles: config.tickets.supportRole !== null ? [config.tickets.supportRole] : []
             }
         });
         await c.send({
@@ -85,14 +60,8 @@
                     .setTitle("New Ticket")
                     .setDescription(
                         "Ticket created by a Moderator\n" +
-                            `**Support type:** ${
-                                customReason
-                                    ? customReason
-                                    : "Appeal submission"
-                            }\n` +
-                            (reason !== null
-                                ? `**Reason:**\n> ${reason}\n`
-                                : "") +
+                            `**Support type:** ${customReason ? customReason : "Appeal submission"}\n` +
+                            (reason !== null ? `**Reason:**\n> ${reason}\n` : "") +
                             `**Ticket ID:** \`${c.id}\`\n` +
                             "Type `/ticket close` to close this ticket."
                     )
@@ -121,10 +90,7 @@
             list: {
                 ticketFor: entry(member.id, renderUser(member)),
                 createdBy: entry(createdBy.id, renderUser(createdBy)),
-                created: entry(
-                    new Date().getTime(),
-                    renderDelta(new Date().getTime())
-                ),
+                created: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 ticketChannel: entry(c.id, renderChannel(c))
             },
             hidden: {
diff --git a/src/actions/roleMenu.ts b/src/actions/roleMenu.ts
index dc224e8..e7f1874 100644
--- a/src/actions/roleMenu.ts
+++ b/src/actions/roleMenu.ts
@@ -1,11 +1,22 @@
-import { MessageButton } from "discord.js";
+import { Interaction, MessageButton } from "discord.js";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
 import { MessageActionRow, MessageSelectMenu } from "discord.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
 import client from "../utils/client.js";
 import { LoadingEmbed } from "../utils/defaultEmbeds.js";
+import type { GuildConfig } from "../utils/database.js";
 
-export async function callback(interaction) {
+export interface RoleMenuSchema {
+    guild: string;
+    guildName: string;
+    guildIcon: string;
+    user: string;
+    username: string;
+    data: GuildConfig["roleMenu"]["options"];
+    interaction: Interaction;
+}
+
+export async function callback(interaction: Interaction) {
     const config = await client.database.guilds.read(interaction.guild.id);
     if (!config.roleMenu.enabled)
         return await interaction.reply({
@@ -25,9 +36,7 @@
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Roles")
-                    .setDescription(
-                        "There are no roles available. Please contact a staff member or try again later."
-                    )
+                    .setDescription("There are no roles available. Please contact a staff member or try again later.")
                     .setStatus("Danger")
                     .setEmoji("CONTROL.BLOCKCROSS")
             ],
@@ -39,8 +48,7 @@
         let code = "";
         let length = 5;
         let itt = 0;
-        const chars =
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+        const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
         let valid = false;
         while (!valid) {
             itt += 1;
@@ -66,14 +74,13 @@
             interaction: interaction
         };
         let up = true;
-        try {
-            const status = await fetch(client.config.baseUrl).then(
-                (res) => res.status
-            );
+        up = false; // FIXME: Role menu does not yet exist, so the web UI is never up
+        /*        try {
+            const status = await fetch(client.config.baseUrl).then((res) => res.status);
             if (status !== 200) up = false;
         } catch {
             up = false;
-        }
+        }*/
         m = await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
@@ -88,13 +95,8 @@
                         .setLabel("Online")
                         .setStyle("LINK")
                         .setDisabled(!up)
-                        .setURL(
-                            `${client.config.baseUrl}nucleus/rolemenu?code=${code}`
-                        ),
-                    new MessageButton()
-                        .setLabel("Manual")
-                        .setStyle("PRIMARY")
-                        .setCustomId("manual")
+                        .setURL(`${client.config.baseUrl}nucleus/rolemenu?code=${code}`),
+                    new MessageButton().setLabel("Manual").setStyle("PRIMARY").setCustomId("manual")
                 ])
             ]
         });
@@ -116,13 +118,9 @@
                     .setEmoji("GUILD.GREEN")
                     .setDescription(
                         `**${object.name}**` +
-                            (object.description
-                                ? `\n${object.description}`
-                                : "") +
+                            (object.description ? `\n${object.description}` : "") +
                             `\n\nSelect ${object.min}` +
-                            (object.min !== object.max
-                                ? ` to ${object.max}`
-                                : "") +
+                            (object.min !== object.max ? ` to ${object.max}` : "") +
                             ` role${object.max === 1 ? "" : "s"} to add.`
                     )
                     .setStatus("Success")
@@ -145,9 +143,7 @@
                                       .setLabel("Skip")
                                       .setStyle("SECONDARY")
                                       .setCustomId("skip")
-                                      .setEmoji(
-                                          getEmojiByName("CONTROL.RIGHT", "id")
-                                      )
+                                      .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
                               ]
                             : []
                     )
@@ -193,13 +189,9 @@
             });
         }
     }
-    let rolesToRemove = config.roleMenu.options
-        .map((o) => o.options.map((o) => o.role))
-        .flat();
+    let rolesToRemove = config.roleMenu.options.map((o) => o.options.map((o) => o.role)).flat();
     const memberRoles = interaction.member.roles.cache.map((r) => r.id);
-    rolesToRemove = rolesToRemove
-        .filter((r) => memberRoles.includes(r))
-        .filter((r) => !rolesToAdd.includes(r));
+    rolesToRemove = rolesToRemove.filter((r) => memberRoles.includes(r)).filter((r) => !rolesToAdd.includes(r));
     rolesToAdd = rolesToAdd.filter((r) => !memberRoles.includes(r));
     try {
         await interaction.member.roles.remove(rolesToRemove);
@@ -222,9 +214,7 @@
         embeds: [
             new EmojiEmbed()
                 .setTitle("Roles")
-                .setDescription(
-                    "Roles have been added. You may close this message."
-                )
+                .setDescription("Roles have been added. You may close this message.")
                 .setStatus("Success")
                 .setEmoji("GUILD.GREEN")
         ],
diff --git a/src/actions/tickets/create.ts b/src/actions/tickets/create.ts
index ca5147a..d6bf822 100644
--- a/src/actions/tickets/create.ts
+++ b/src/actions/tickets/create.ts
@@ -6,20 +6,11 @@
 
 function capitalize(s: string) {
     s = s.replace(/([A-Z])/g, " $1");
-    return s.length < 3
-        ? s.toUpperCase()
-        : s[0].toUpperCase() + s.slice(1).toLowerCase();
+    return s.length < 3 ? s.toUpperCase() : s[0].toUpperCase() + s.slice(1).toLowerCase();
 }
 
 export default async function (interaction) {
-    const {
-        log,
-        NucleusColors,
-        entry,
-        renderUser,
-        renderChannel,
-        renderDelta
-    } = client.logger;
+    const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
 
     const config = await client.database.guilds.read(interaction.guild.id);
     if (!config.tickets.enabled || !config.tickets.category) {
@@ -27,9 +18,7 @@
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Tickets are disabled")
-                    .setDescription(
-                        "Please enable tickets in the configuration to use this command."
-                    )
+                    .setDescription("Please enable tickets in the configuration to use this command.")
                     .setFooter({
                         text: interaction.member.permissions.has("MANAGE_GUILD")
                             ? "You can enable it by running /settings tickets"
@@ -41,17 +30,11 @@
             ephemeral: true
         });
     }
-    const category = interaction.guild.channels.cache.get(
-        config.tickets.category
-    ) as Discord.CategoryChannel;
+    const category = interaction.guild.channels.cache.get(config.tickets.category) as Discord.CategoryChannel;
     let count = 0;
     category.children.forEach((element) => {
         if (!(element.type === "GUILD_TEXT")) return;
-        if (
-            (element as Discord.TextChannel).topic.includes(
-                `${interaction.member.user.id}`
-            )
-        ) {
+        if ((element as Discord.TextChannel).topic.includes(`${interaction.member.user.id}`)) {
             if ((element as Discord.TextChannel).topic.endsWith("Active")) {
                 count++;
             }
@@ -76,8 +59,7 @@
     if (config.tickets.customTypes && config.tickets.useCustom) {
         ticketTypes = config.tickets.customTypes;
         custom = true;
-    } else if (config.tickets.types)
-        ticketTypes = toHexArray(config.tickets.types, tickets);
+    } else if (config.tickets.types) ticketTypes = toHexArray(config.tickets.types, tickets);
     else ticketTypes = [];
     let chosenType;
     let splitFormattedTicketTypes = [];
@@ -85,29 +67,17 @@
         let formattedTicketTypes = [];
         formattedTicketTypes = ticketTypes.map((type) => {
             if (custom) {
-                return new MessageButton()
-                    .setLabel(type)
-                    .setStyle("PRIMARY")
-                    .setCustomId(type);
+                return new MessageButton().setLabel(type).setStyle("PRIMARY").setCustomId(type);
             } else {
                 return new MessageButton()
                     .setLabel(capitalize(type))
                     .setStyle("PRIMARY")
                     .setCustomId(type)
-                    .setEmoji(
-                        getEmojiByName(
-                            "TICKETS." + type.toString().toUpperCase(),
-                            "id"
-                        )
-                    );
+                    .setEmoji(getEmojiByName("TICKETS." + type.toString().toUpperCase(), "id"));
             }
         });
         for (let i = 0; i < formattedTicketTypes.length; i += 5) {
-            splitFormattedTicketTypes.push(
-                new MessageActionRow().addComponents(
-                    formattedTicketTypes.slice(i, i + 5)
-                )
-            );
+            splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 5)));
         }
         const m = await interaction.reply({
             embeds: [
@@ -142,21 +112,12 @@
                     .setLabel(capitalize(type))
                     .setStyle(chosenType === type ? "SUCCESS" : "SECONDARY")
                     .setCustomId(type)
-                    .setEmoji(
-                        getEmojiByName(
-                            "TICKETS." + type.toString().toUpperCase(),
-                            "id"
-                        )
-                    )
+                    .setEmoji(getEmojiByName("TICKETS." + type.toString().toUpperCase(), "id"))
                     .setDisabled(true);
             }
         });
         for (let i = 0; i < formattedTicketTypes.length; i += 5) {
-            splitFormattedTicketTypes.push(
-                new MessageActionRow().addComponents(
-                    formattedTicketTypes.slice(i, i + 5)
-                )
-            );
+            splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 5)));
         }
         component.update({
             embeds: [
@@ -171,11 +132,7 @@
     } else {
         chosenType = null;
         await interaction.reply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Create Ticket")
-                    .setEmoji("GUILD.TICKET.OPEN")
-            ],
+            embeds: [new EmojiEmbed().setTitle("Create Ticket").setEmoji("GUILD.TICKET.OPEN")],
             ephemeral: true,
             components: splitFormattedTicketTypes
         });
@@ -183,13 +140,7 @@
     const overwrites = [
         {
             id: interaction.member,
-            allow: [
-                "VIEW_CHANNEL",
-                "SEND_MESSAGES",
-                "ATTACH_FILES",
-                "ADD_REACTIONS",
-                "READ_MESSAGE_HISTORY"
-            ],
+            allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
             type: "member"
         }
     ] as Discord.OverwriteResolvable[];
@@ -201,31 +152,21 @@
     if (config.tickets.supportRole !== null) {
         overwrites.push({
             id: interaction.guild.roles.cache.get(config.tickets.supportRole),
-            allow: [
-                "VIEW_CHANNEL",
-                "SEND_MESSAGES",
-                "ATTACH_FILES",
-                "ADD_REACTIONS",
-                "READ_MESSAGE_HISTORY"
-            ],
+            allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
             type: "role"
         });
     }
 
     let c;
     try {
-        c = await interaction.guild.channels.create(
-            interaction.member.user.username,
-            {
-                type: "GUILD_TEXT",
-                topic: `${interaction.member.user.id} Active`,
-                parent: config.tickets.category,
-                nsfw: false,
-                permissionOverwrites:
-                    overwrites as Discord.OverwriteResolvable[],
-                reason: "Creating ticket"
-            }
-        );
+        c = await interaction.guild.channels.create(interaction.member.user.username, {
+            type: "GUILD_TEXT",
+            topic: `${interaction.member.user.id} Active`,
+            parent: config.tickets.category,
+            nsfw: false,
+            permissionOverwrites: overwrites as Discord.OverwriteResolvable[],
+            reason: "Creating ticket"
+        });
     } catch (e) {
         return await interaction.editReply({
             embeds: [
@@ -241,24 +182,15 @@
         await c.send({
             content:
                 `<@${interaction.member.user.id}>` +
-                (config.tickets.supportRole !== null
-                    ? ` • <@&${config.tickets.supportRole}>`
-                    : ""),
+                (config.tickets.supportRole !== null ? ` • <@&${config.tickets.supportRole}>` : ""),
             allowedMentions: {
                 users: [(interaction.member as Discord.GuildMember).id],
-                roles:
-                    config.tickets.supportRole !== null
-                        ? [config.tickets.supportRole]
-                        : []
+                roles: config.tickets.supportRole !== null ? [config.tickets.supportRole] : []
             }
         });
-        let content = interaction.options
-            ? interaction.options.getString("message") || ""
-            : "";
+        let content = interaction.options ? interaction.options.getString("message") || "" : "";
         if (content) content = `**Message:**\n> ${content}\n`;
-        const emoji = custom
-            ? ""
-            : getEmojiByName("TICKETS." + chosenType.toUpperCase());
+        const emoji = custom ? "" : getEmojiByName("TICKETS." + chosenType.toUpperCase());
         await c.send({
             embeds: [
                 new EmojiEmbed()
@@ -266,9 +198,7 @@
                     .setDescription(
                         `Ticket created by <@${interaction.member.user.id}>\n` +
                             `**Support type:** ${
-                                chosenType !== null
-                                    ? emoji + " " + capitalize(chosenType)
-                                    : "General"
+                                chosenType !== null ? emoji + " " + capitalize(chosenType) : "General"
                             }\n` +
                             `**Ticket ID:** \`${c.id}\`\n${content}\n` +
                             "Type `/ticket close` to close this ticket."
@@ -296,14 +226,8 @@
                 timestamp: new Date().getTime()
             },
             list: {
-                ticketFor: entry(
-                    interaction.member.user.id,
-                    renderUser(interaction.member.user)
-                ),
-                created: entry(
-                    new Date().getTime(),
-                    renderDelta(new Date().getTime())
-                ),
+                ticketFor: entry(interaction.member.user.id, renderUser(interaction.member.user)),
+                created: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 ticketChannel: entry(c.id, renderChannel(c))
             },
             hidden: {
@@ -318,9 +242,7 @@
         embeds: [
             new EmojiEmbed()
                 .setTitle("Create Ticket")
-                .setDescription(
-                    `Ticket created. You can view it here: <#${c.id}>`
-                )
+                .setDescription(`Ticket created. You can view it here: <#${c.id}>`)
                 .setStatus("Success")
                 .setEmoji("GUILD.TICKET.OPEN")
         ],
diff --git a/src/actions/tickets/delete.ts b/src/actions/tickets/delete.ts
index 6509c03..d692a1e 100644
--- a/src/actions/tickets/delete.ts
+++ b/src/actions/tickets/delete.ts
@@ -4,14 +4,7 @@
 import getEmojiByName from "../../utils/getEmojiByName.js";
 
 export default async function (interaction) {
-    const {
-        log,
-        NucleusColors,
-        entry,
-        renderUser,
-        renderChannel,
-        renderDelta
-    } = client.logger;
+    const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
 
     const config = await client.database.guilds.read(interaction.guild.id);
     let thread = false;
@@ -21,9 +14,7 @@
     if (
         !channel.parent ||
         config.tickets.category !== channel.parent.id ||
-        (thread
-            ? threadChannel.parent.parent.id !== config.tickets.category
-            : false)
+        (thread ? threadChannel.parent.parent.id !== config.tickets.category : false)
     ) {
         return interaction.reply({
             embeds: [
@@ -61,22 +52,10 @@
             list: {
                 ticketFor: entry(
                     channel.topic.split(" ")[0],
-                    renderUser(
-                        (
-                            await interaction.guild.members.fetch(
-                                channel.topic.split(" ")[0]
-                            )
-                        ).user
-                    )
+                    renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)
                 ),
-                deletedBy: entry(
-                    interaction.member.user.id,
-                    renderUser(interaction.member.user)
-                ),
-                deleted: entry(
-                    new Date().getTime(),
-                    renderDelta(new Date().getTime())
-                )
+                deletedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
+                deleted: entry(new Date().getTime(), renderDelta(new Date().getTime()))
             },
             hidden: {
                 guild: interaction.guild.id
@@ -109,16 +88,8 @@
         ] as Discord.OverwriteResolvable[];
         if (config.tickets.supportRole !== null) {
             overwrites.push({
-                id: interaction.guild.roles.cache.get(
-                    config.tickets.supportRole
-                ),
-                allow: [
-                    "VIEW_CHANNEL",
-                    "SEND_MESSAGES",
-                    "ATTACH_FILES",
-                    "ADD_REACTIONS",
-                    "READ_MESSAGE_HISTORY"
-                ],
+                id: interaction.guild.roles.cache.get(config.tickets.supportRole),
+                allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
                 type: "role"
             });
         }
@@ -136,22 +107,10 @@
             list: {
                 ticketFor: entry(
                     channel.topic.split(" ")[0],
-                    renderUser(
-                        (
-                            await interaction.guild.members.fetch(
-                                channel.topic.split(" ")[0]
-                            )
-                        ).user
-                    )
+                    renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)
                 ),
-                closedBy: entry(
-                    interaction.member.user.id,
-                    renderUser(interaction.member.user)
-                ),
-                closed: entry(
-                    new Date().getTime(),
-                    renderDelta(new Date().getTime())
-                ),
+                closedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
+                closed: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 ticketChannel: entry(channel.id, renderChannel(channel))
             },
             hidden: {
@@ -184,12 +143,7 @@
                                       .setLabel("Create Transcript and Delete")
                                       .setStyle("PRIMARY")
                                       .setCustomId("createtranscript")
-                                      .setEmoji(
-                                          getEmojiByName(
-                                              "CONTROL.DOWNLOAD",
-                                              "id"
-                                          )
-                                      )
+                                      .setEmoji(getEmojiByName("CONTROL.DOWNLOAD", "id"))
                               ]
                             : []
                     )
@@ -219,8 +173,7 @@
         }
     });
     if (deleted) {
-        const { log, NucleusColors, entry, renderUser, renderDelta } =
-            member.client.logger;
+        const { log, NucleusColors, entry, renderUser, renderDelta } = member.client.logger;
         const data = {
             meta: {
                 type: "ticketPurge",
@@ -233,10 +186,7 @@
             list: {
                 ticketFor: entry(member, renderUser(member)),
                 deletedBy: entry(null, "Member left server"),
-                deleted: entry(
-                    new Date().getTime(),
-                    renderDelta(new Date().getTime())
-                ),
+                deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 ticketsDeleted: deleted
             },
             hidden: {