From e4450c8417624b71d779cb4f41692538f9165e10 Mon Sep 17 00:00:00 2001
From: sowgro <tpoke.ferrari@gmail.com>
Date: Sat, 2 Sep 2023 19:12:47 -0400
Subject: first commit

---
 .../discord.js/src/structures/ActionRow.js         |   46 +
 .../discord.js/src/structures/ActionRowBuilder.js  |   35 +
 .../discord.js/src/structures/AnonymousGuild.js    |   97 ++
 .../src/structures/ApplicationCommand.js           |  606 +++++++++
 .../ApplicationRoleConnectionMetadata.js           |   46 +
 .../discord.js/src/structures/Attachment.js        |  151 +++
 .../discord.js/src/structures/AttachmentBuilder.js |  116 ++
 .../structures/AutoModerationActionExecution.js    |  116 ++
 .../src/structures/AutoModerationRule.js           |  284 ++++
 .../src/structures/AutocompleteInteraction.js      |  102 ++
 node_modules/discord.js/src/structures/Base.js     |   43 +
 .../discord.js/src/structures/BaseChannel.js       |  155 +++
 .../discord.js/src/structures/BaseGuild.js         |  119 ++
 .../discord.js/src/structures/BaseGuildEmoji.js    |   56 +
 .../src/structures/BaseGuildTextChannel.js         |  186 +++
 .../src/structures/BaseGuildVoiceChannel.js        |  234 ++++
 .../discord.js/src/structures/BaseInteraction.js   |  344 +++++
 .../src/structures/BaseSelectMenuComponent.js      |   56 +
 .../discord.js/src/structures/ButtonBuilder.js     |   44 +
 .../discord.js/src/structures/ButtonComponent.js   |   65 +
 .../discord.js/src/structures/ButtonInteraction.js |   11 +
 .../discord.js/src/structures/CategoryChannel.js   |   45 +
 .../src/structures/ChannelSelectMenuBuilder.js     |   31 +
 .../src/structures/ChannelSelectMenuComponent.js   |   20 +
 .../src/structures/ChannelSelectMenuInteraction.js |   33 +
 .../src/structures/ChatInputCommandInteraction.js  |   41 +
 .../discord.js/src/structures/ClientApplication.js |  222 ++++
 .../discord.js/src/structures/ClientPresence.js    |   90 ++
 .../discord.js/src/structures/ClientUser.js        |  187 +++
 .../src/structures/CommandInteraction.js           |  224 ++++
 .../structures/CommandInteractionOptionResolver.js |  308 +++++
 .../discord.js/src/structures/Component.js         |   47 +
 .../structures/ContextMenuCommandInteraction.js    |   64 +
 .../discord.js/src/structures/DMChannel.js         |  129 ++
 .../discord.js/src/structures/DirectoryChannel.js  |   36 +
 node_modules/discord.js/src/structures/Embed.js    |  220 ++++
 .../discord.js/src/structures/EmbedBuilder.js      |   50 +
 node_modules/discord.js/src/structures/Emoji.js    |  108 ++
 .../discord.js/src/structures/ForumChannel.js      |  264 ++++
 node_modules/discord.js/src/structures/Guild.js    | 1367 ++++++++++++++++++++
 .../discord.js/src/structures/GuildAuditLogs.js    |   91 ++
 .../src/structures/GuildAuditLogsEntry.js          |  528 ++++++++
 node_modules/discord.js/src/structures/GuildBan.js |   59 +
 .../discord.js/src/structures/GuildChannel.js      |  472 +++++++
 .../discord.js/src/structures/GuildEmoji.js        |  148 +++
 .../discord.js/src/structures/GuildMember.js       |  520 ++++++++
 .../discord.js/src/structures/GuildOnboarding.js   |   58 +
 .../src/structures/GuildOnboardingPrompt.js        |   78 ++
 .../src/structures/GuildOnboardingPromptOption.js  |   84 ++
 .../discord.js/src/structures/GuildPreview.js      |  193 +++
 .../discord.js/src/structures/GuildPreviewEmoji.js |   27 +
 .../src/structures/GuildScheduledEvent.js          |  439 +++++++
 .../discord.js/src/structures/GuildTemplate.js     |  241 ++++
 .../discord.js/src/structures/Integration.js       |  220 ++++
 .../src/structures/IntegrationApplication.js       |   85 ++
 .../src/structures/InteractionCollector.js         |  269 ++++
 .../src/structures/InteractionResponse.js          |  102 ++
 .../src/structures/InteractionWebhook.js           |   59 +
 node_modules/discord.js/src/structures/Invite.js   |  322 +++++
 .../discord.js/src/structures/InviteGuild.js       |   22 +
 .../src/structures/InviteStageInstance.js          |   87 ++
 .../src/structures/MentionableSelectMenuBuilder.js |   32 +
 .../structures/MentionableSelectMenuComponent.js   |   11 +
 .../structures/MentionableSelectMenuInteraction.js |   71 +
 node_modules/discord.js/src/structures/Message.js  |  997 ++++++++++++++
 .../discord.js/src/structures/MessageCollector.js  |  146 +++
 .../src/structures/MessageComponentInteraction.js  |  107 ++
 .../MessageContextMenuCommandInteraction.js        |   20 +
 .../discord.js/src/structures/MessageMentions.js   |  297 +++++
 .../discord.js/src/structures/MessagePayload.js    |  299 +++++
 .../discord.js/src/structures/MessageReaction.js   |  142 ++
 .../discord.js/src/structures/ModalBuilder.js      |   34 +
 .../discord.js/src/structures/ModalSubmitFields.js |   55 +
 .../src/structures/ModalSubmitInteraction.js       |  122 ++
 .../discord.js/src/structures/NewsChannel.js       |   32 +
 .../discord.js/src/structures/OAuth2Guild.js       |   28 +
 .../src/structures/PartialGroupDMChannel.js        |   60 +
 .../src/structures/PermissionOverwrites.js         |  196 +++
 node_modules/discord.js/src/structures/Presence.js |  378 ++++++
 .../discord.js/src/structures/ReactionCollector.js |  229 ++++
 .../discord.js/src/structures/ReactionEmoji.js     |   31 +
 node_modules/discord.js/src/structures/Role.js     |  471 +++++++
 .../src/structures/RoleSelectMenuBuilder.js        |   31 +
 .../src/structures/RoleSelectMenuComponent.js      |   11 +
 .../src/structures/RoleSelectMenuInteraction.js    |   33 +
 .../discord.js/src/structures/SelectMenuBuilder.js |   26 +
 .../src/structures/SelectMenuComponent.js          |   26 +
 .../src/structures/SelectMenuInteraction.js        |   26 +
 .../src/structures/SelectMenuOptionBuilder.js      |   26 +
 .../discord.js/src/structures/StageChannel.js      |  112 ++
 .../discord.js/src/structures/StageInstance.js     |  167 +++
 node_modules/discord.js/src/structures/Sticker.js  |  272 ++++
 .../discord.js/src/structures/StickerPack.js       |   95 ++
 .../src/structures/StringSelectMenuBuilder.js      |   79 ++
 .../src/structures/StringSelectMenuComponent.js    |   20 +
 .../src/structures/StringSelectMenuInteraction.js  |   21 +
 .../structures/StringSelectMenuOptionBuilder.js    |   49 +
 node_modules/discord.js/src/structures/Team.js     |  117 ++
 .../discord.js/src/structures/TeamMember.js        |   70 +
 .../discord.js/src/structures/TextChannel.js       |   33 +
 .../discord.js/src/structures/TextInputBuilder.js  |   31 +
 .../src/structures/TextInputComponent.js           |   29 +
 .../discord.js/src/structures/ThreadChannel.js     |  606 +++++++++
 .../discord.js/src/structures/ThreadMember.js      |  113 ++
 node_modules/discord.js/src/structures/Typing.js   |   74 ++
 node_modules/discord.js/src/structures/User.js     |  380 ++++++
 .../UserContextMenuCommandInteraction.js           |   29 +
 .../src/structures/UserSelectMenuBuilder.js        |   31 +
 .../src/structures/UserSelectMenuComponent.js      |   11 +
 .../src/structures/UserSelectMenuInteraction.js    |   51 +
 .../discord.js/src/structures/VoiceChannel.js      |   96 ++
 .../discord.js/src/structures/VoiceRegion.js       |   46 +
 .../discord.js/src/structures/VoiceState.js        |  303 +++++
 node_modules/discord.js/src/structures/Webhook.js  |  479 +++++++
 .../discord.js/src/structures/WelcomeChannel.js    |   60 +
 .../discord.js/src/structures/WelcomeScreen.js     |   49 +
 node_modules/discord.js/src/structures/Widget.js   |   88 ++
 .../discord.js/src/structures/WidgetMember.js      |   99 ++
 .../src/structures/interfaces/Application.js       |  108 ++
 .../src/structures/interfaces/Collector.js         |  335 +++++
 .../structures/interfaces/InteractionResponses.js  |  320 +++++
 .../src/structures/interfaces/TextBasedChannel.js  |  413 ++++++
 122 files changed, 19225 insertions(+)
 create mode 100644 node_modules/discord.js/src/structures/ActionRow.js
 create mode 100644 node_modules/discord.js/src/structures/ActionRowBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/AnonymousGuild.js
 create mode 100644 node_modules/discord.js/src/structures/ApplicationCommand.js
 create mode 100644 node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js
 create mode 100644 node_modules/discord.js/src/structures/Attachment.js
 create mode 100644 node_modules/discord.js/src/structures/AttachmentBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/AutoModerationActionExecution.js
 create mode 100644 node_modules/discord.js/src/structures/AutoModerationRule.js
 create mode 100644 node_modules/discord.js/src/structures/AutocompleteInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/Base.js
 create mode 100644 node_modules/discord.js/src/structures/BaseChannel.js
 create mode 100644 node_modules/discord.js/src/structures/BaseGuild.js
 create mode 100644 node_modules/discord.js/src/structures/BaseGuildEmoji.js
 create mode 100644 node_modules/discord.js/src/structures/BaseGuildTextChannel.js
 create mode 100644 node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js
 create mode 100644 node_modules/discord.js/src/structures/BaseInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/BaseSelectMenuComponent.js
 create mode 100644 node_modules/discord.js/src/structures/ButtonBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/ButtonComponent.js
 create mode 100644 node_modules/discord.js/src/structures/ButtonInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/CategoryChannel.js
 create mode 100644 node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js
 create mode 100644 node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/ChatInputCommandInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/ClientApplication.js
 create mode 100644 node_modules/discord.js/src/structures/ClientPresence.js
 create mode 100644 node_modules/discord.js/src/structures/ClientUser.js
 create mode 100644 node_modules/discord.js/src/structures/CommandInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js
 create mode 100644 node_modules/discord.js/src/structures/Component.js
 create mode 100644 node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/DMChannel.js
 create mode 100644 node_modules/discord.js/src/structures/DirectoryChannel.js
 create mode 100644 node_modules/discord.js/src/structures/Embed.js
 create mode 100644 node_modules/discord.js/src/structures/EmbedBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/Emoji.js
 create mode 100644 node_modules/discord.js/src/structures/ForumChannel.js
 create mode 100644 node_modules/discord.js/src/structures/Guild.js
 create mode 100644 node_modules/discord.js/src/structures/GuildAuditLogs.js
 create mode 100644 node_modules/discord.js/src/structures/GuildAuditLogsEntry.js
 create mode 100644 node_modules/discord.js/src/structures/GuildBan.js
 create mode 100644 node_modules/discord.js/src/structures/GuildChannel.js
 create mode 100644 node_modules/discord.js/src/structures/GuildEmoji.js
 create mode 100644 node_modules/discord.js/src/structures/GuildMember.js
 create mode 100644 node_modules/discord.js/src/structures/GuildOnboarding.js
 create mode 100644 node_modules/discord.js/src/structures/GuildOnboardingPrompt.js
 create mode 100644 node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js
 create mode 100644 node_modules/discord.js/src/structures/GuildPreview.js
 create mode 100644 node_modules/discord.js/src/structures/GuildPreviewEmoji.js
 create mode 100644 node_modules/discord.js/src/structures/GuildScheduledEvent.js
 create mode 100644 node_modules/discord.js/src/structures/GuildTemplate.js
 create mode 100644 node_modules/discord.js/src/structures/Integration.js
 create mode 100644 node_modules/discord.js/src/structures/IntegrationApplication.js
 create mode 100644 node_modules/discord.js/src/structures/InteractionCollector.js
 create mode 100644 node_modules/discord.js/src/structures/InteractionResponse.js
 create mode 100644 node_modules/discord.js/src/structures/InteractionWebhook.js
 create mode 100644 node_modules/discord.js/src/structures/Invite.js
 create mode 100644 node_modules/discord.js/src/structures/InviteGuild.js
 create mode 100644 node_modules/discord.js/src/structures/InviteStageInstance.js
 create mode 100644 node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js
 create mode 100644 node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/Message.js
 create mode 100644 node_modules/discord.js/src/structures/MessageCollector.js
 create mode 100644 node_modules/discord.js/src/structures/MessageComponentInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/MessageMentions.js
 create mode 100644 node_modules/discord.js/src/structures/MessagePayload.js
 create mode 100644 node_modules/discord.js/src/structures/MessageReaction.js
 create mode 100644 node_modules/discord.js/src/structures/ModalBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/ModalSubmitFields.js
 create mode 100644 node_modules/discord.js/src/structures/ModalSubmitInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/NewsChannel.js
 create mode 100644 node_modules/discord.js/src/structures/OAuth2Guild.js
 create mode 100644 node_modules/discord.js/src/structures/PartialGroupDMChannel.js
 create mode 100644 node_modules/discord.js/src/structures/PermissionOverwrites.js
 create mode 100644 node_modules/discord.js/src/structures/Presence.js
 create mode 100644 node_modules/discord.js/src/structures/ReactionCollector.js
 create mode 100644 node_modules/discord.js/src/structures/ReactionEmoji.js
 create mode 100644 node_modules/discord.js/src/structures/Role.js
 create mode 100644 node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/RoleSelectMenuComponent.js
 create mode 100644 node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/SelectMenuBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/SelectMenuComponent.js
 create mode 100644 node_modules/discord.js/src/structures/SelectMenuInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/StageChannel.js
 create mode 100644 node_modules/discord.js/src/structures/StageInstance.js
 create mode 100644 node_modules/discord.js/src/structures/Sticker.js
 create mode 100644 node_modules/discord.js/src/structures/StickerPack.js
 create mode 100644 node_modules/discord.js/src/structures/StringSelectMenuBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/StringSelectMenuComponent.js
 create mode 100644 node_modules/discord.js/src/structures/StringSelectMenuInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/Team.js
 create mode 100644 node_modules/discord.js/src/structures/TeamMember.js
 create mode 100644 node_modules/discord.js/src/structures/TextChannel.js
 create mode 100644 node_modules/discord.js/src/structures/TextInputBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/TextInputComponent.js
 create mode 100644 node_modules/discord.js/src/structures/ThreadChannel.js
 create mode 100644 node_modules/discord.js/src/structures/ThreadMember.js
 create mode 100644 node_modules/discord.js/src/structures/Typing.js
 create mode 100644 node_modules/discord.js/src/structures/User.js
 create mode 100644 node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/UserSelectMenuBuilder.js
 create mode 100644 node_modules/discord.js/src/structures/UserSelectMenuComponent.js
 create mode 100644 node_modules/discord.js/src/structures/UserSelectMenuInteraction.js
 create mode 100644 node_modules/discord.js/src/structures/VoiceChannel.js
 create mode 100644 node_modules/discord.js/src/structures/VoiceRegion.js
 create mode 100644 node_modules/discord.js/src/structures/VoiceState.js
 create mode 100644 node_modules/discord.js/src/structures/Webhook.js
 create mode 100644 node_modules/discord.js/src/structures/WelcomeChannel.js
 create mode 100644 node_modules/discord.js/src/structures/WelcomeScreen.js
 create mode 100644 node_modules/discord.js/src/structures/Widget.js
 create mode 100644 node_modules/discord.js/src/structures/WidgetMember.js
 create mode 100644 node_modules/discord.js/src/structures/interfaces/Application.js
 create mode 100644 node_modules/discord.js/src/structures/interfaces/Collector.js
 create mode 100644 node_modules/discord.js/src/structures/interfaces/InteractionResponses.js
 create mode 100644 node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js

(limited to 'node_modules/discord.js/src/structures')

diff --git a/node_modules/discord.js/src/structures/ActionRow.js b/node_modules/discord.js/src/structures/ActionRow.js
new file mode 100644
index 0000000..3f39691
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ActionRow.js
@@ -0,0 +1,46 @@
+'use strict';
+
+const { deprecate } = require('node:util');
+const { isJSONEncodable } = require('@discordjs/util');
+const Component = require('./Component');
+const { createComponent } = require('../util/Components');
+
+/**
+ * Represents an action row
+ * @extends {Component}
+ */
+class ActionRow extends Component {
+  constructor({ components, ...data }) {
+    super(data);
+
+    /**
+     * The components in this action row
+     * @type {Component[]}
+     * @readonly
+     */
+    this.components = components.map(c => createComponent(c));
+  }
+
+  /**
+   * Creates a new action row builder from JSON data
+   * @method from
+   * @memberof ActionRow
+   * @param {ActionRowBuilder|ActionRow|APIActionRowComponent} other The other data
+   * @returns {ActionRowBuilder}
+   * @deprecated Use {@link ActionRowBuilder.from} instead.
+   */
+  static from = deprecate(
+    other => new this(isJSONEncodable(other) ? other.toJSON() : other),
+    'ActionRow.from() is deprecated. Use ActionRowBuilder.from() instead.',
+  );
+
+  /**
+   * Returns the API-compatible JSON for this component
+   * @returns {APIActionRowComponent}
+   */
+  toJSON() {
+    return { ...this.data, components: this.components.map(c => c.toJSON()) };
+  }
+}
+
+module.exports = ActionRow;
diff --git a/node_modules/discord.js/src/structures/ActionRowBuilder.js b/node_modules/discord.js/src/structures/ActionRowBuilder.js
new file mode 100644
index 0000000..962a378
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ActionRowBuilder.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const { ActionRowBuilder: BuildersActionRow } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { createComponentBuilder } = require('../util/Components');
+const { toSnakeCase } = require('../util/Transformers');
+
+/**
+ * Represents an action row builder.
+ * @extends {BuildersActionRow}
+ */
+class ActionRowBuilder extends BuildersActionRow {
+  constructor({ components, ...data } = {}) {
+    super({
+      ...toSnakeCase(data),
+      components: components?.map(c => createComponentBuilder(c)),
+    });
+  }
+
+  /**
+   * Creates a new action row builder from JSON data
+   * @param {ActionRow|ActionRowBuilder|APIActionRowComponent} other The other data
+   * @returns {ActionRowBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = ActionRowBuilder;
+
+/**
+ * @external BuildersActionRow
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/ActionRowBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/AnonymousGuild.js b/node_modules/discord.js/src/structures/AnonymousGuild.js
new file mode 100644
index 0000000..70931bd
--- /dev/null
+++ b/node_modules/discord.js/src/structures/AnonymousGuild.js
@@ -0,0 +1,97 @@
+'use strict';
+
+const BaseGuild = require('./BaseGuild');
+
+/**
+ * Bundles common attributes and methods between {@link Guild} and {@link InviteGuild}
+ * @extends {BaseGuild}
+ * @abstract
+ */
+class AnonymousGuild extends BaseGuild {
+  constructor(client, data, immediatePatch = true) {
+    super(client, data);
+    if (immediatePatch) this._patch(data);
+  }
+
+  _patch(data) {
+    if ('features' in data) this.features = data.features;
+
+    if ('splash' in data) {
+      /**
+       * The hash of the guild invite splash image
+       * @type {?string}
+       */
+      this.splash = data.splash;
+    }
+
+    if ('banner' in data) {
+      /**
+       * The hash of the guild banner
+       * @type {?string}
+       */
+      this.banner = data.banner;
+    }
+
+    if ('description' in data) {
+      /**
+       * The description of the guild, if any
+       * @type {?string}
+       */
+      this.description = data.description;
+    }
+
+    if ('verification_level' in data) {
+      /**
+       * The verification level of the guild
+       * @type {GuildVerificationLevel}
+       */
+      this.verificationLevel = data.verification_level;
+    }
+
+    if ('vanity_url_code' in data) {
+      /**
+       * The vanity invite code of the guild, if any
+       * @type {?string}
+       */
+      this.vanityURLCode = data.vanity_url_code;
+    }
+
+    if ('nsfw_level' in data) {
+      /**
+       * The NSFW level of this guild
+       * @type {GuildNSFWLevel}
+       */
+      this.nsfwLevel = data.nsfw_level;
+    }
+
+    if ('premium_subscription_count' in data) {
+      /**
+       * The total number of boosts for this server
+       * @type {?number}
+       */
+      this.premiumSubscriptionCount = data.premium_subscription_count;
+    } else {
+      this.premiumSubscriptionCount ??= null;
+    }
+  }
+
+  /**
+   * The URL to this guild's banner.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  bannerURL(options = {}) {
+    return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);
+  }
+
+  /**
+   * The URL to this guild's invite splash image.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  splashURL(options = {}) {
+    return this.splash && this.client.rest.cdn.splash(this.id, this.splash, options);
+  }
+}
+
+module.exports = AnonymousGuild;
diff --git a/node_modules/discord.js/src/structures/ApplicationCommand.js b/node_modules/discord.js/src/structures/ApplicationCommand.js
new file mode 100644
index 0000000..bd87281
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ApplicationCommand.js
@@ -0,0 +1,606 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { ApplicationCommandOptionType } = require('discord-api-types/v10');
+const isEqual = require('fast-deep-equal');
+const Base = require('./Base');
+const ApplicationCommandPermissionsManager = require('../managers/ApplicationCommandPermissionsManager');
+const PermissionsBitField = require('../util/PermissionsBitField');
+
+/**
+ * Represents an application command.
+ * @extends {Base}
+ */
+class ApplicationCommand extends Base {
+  constructor(client, data, guild, guildId) {
+    super(client);
+
+    /**
+     * The command's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The parent application's id
+     * @type {Snowflake}
+     */
+    this.applicationId = data.application_id;
+
+    /**
+     * The guild this command is part of
+     * @type {?Guild}
+     */
+    this.guild = guild ?? null;
+
+    /**
+     * The guild's id this command is part of, this may be non-null when `guild` is `null` if the command
+     * was fetched from the `ApplicationCommandManager`
+     * @type {?Snowflake}
+     */
+    this.guildId = guild?.id ?? guildId ?? null;
+
+    /**
+     * The manager for permissions of this command on its guild or arbitrary guilds when the command is global
+     * @type {ApplicationCommandPermissionsManager}
+     */
+    this.permissions = new ApplicationCommandPermissionsManager(this);
+
+    /**
+     * The type of this application command
+     * @type {ApplicationCommandType}
+     */
+    this.type = data.type;
+
+    /**
+     * Whether this command is age-restricted (18+)
+     * @type {boolean}
+     */
+    this.nsfw = data.nsfw ?? false;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('name' in data) {
+      /**
+       * The name of this command
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('name_localizations' in data) {
+      /**
+       * The name localizations for this command
+       * @type {?Object<Locale, string>}
+       */
+      this.nameLocalizations = data.name_localizations;
+    } else {
+      this.nameLocalizations ??= null;
+    }
+
+    if ('name_localized' in data) {
+      /**
+       * The localized name for this command
+       * @type {?string}
+       */
+      this.nameLocalized = data.name_localized;
+    } else {
+      this.nameLocalized ??= null;
+    }
+
+    if ('description' in data) {
+      /**
+       * The description of this command
+       * @type {string}
+       */
+      this.description = data.description;
+    }
+
+    if ('description_localizations' in data) {
+      /**
+       * The description localizations for this command
+       * @type {?Object<Locale, string>}
+       */
+      this.descriptionLocalizations = data.description_localizations;
+    } else {
+      this.descriptionLocalizations ??= null;
+    }
+
+    if ('description_localized' in data) {
+      /**
+       * The localized description for this command
+       * @type {?string}
+       */
+      this.descriptionLocalized = data.description_localized;
+    } else {
+      this.descriptionLocalized ??= null;
+    }
+
+    if ('options' in data) {
+      /**
+       * The options of this command
+       * @type {ApplicationCommandOption[]}
+       */
+      this.options = data.options.map(o => this.constructor.transformOption(o, true));
+    } else {
+      this.options ??= [];
+    }
+
+    if ('default_member_permissions' in data) {
+      /**
+       * The default bitfield used to determine whether this command be used in a guild
+       * @type {?Readonly<PermissionsBitField>}
+       */
+      this.defaultMemberPermissions = data.default_member_permissions
+        ? new PermissionsBitField(BigInt(data.default_member_permissions)).freeze()
+        : null;
+    } else {
+      this.defaultMemberPermissions ??= null;
+    }
+
+    if ('dm_permission' in data) {
+      /**
+       * Whether the command can be used in DMs
+       * <info>This property is always `null` on guild commands</info>
+       * @type {boolean|null}
+       */
+      this.dmPermission = data.dm_permission;
+    } else {
+      this.dmPermission ??= null;
+    }
+
+    if ('version' in data) {
+      /**
+       * Autoincrementing version identifier updated during substantial record changes
+       * @type {Snowflake}
+       */
+      this.version = data.version;
+    }
+  }
+
+  /**
+   * The timestamp the command was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the command was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The manager that this command belongs to
+   * @type {ApplicationCommandManager}
+   * @readonly
+   */
+  get manager() {
+    return (this.guild ?? this.client.application).commands;
+  }
+
+  /**
+   * Data for creating or editing an application command.
+   * @typedef {Object} ApplicationCommandData
+   * @property {string} name The name of the command, must be in all lowercase if type is
+   * {@link ApplicationCommandType.ChatInput}
+   * @property {Object<Locale, string>} [nameLocalizations] The localizations for the command name
+   * @property {string} description The description of the command, if type is {@link ApplicationCommandType.ChatInput}
+   * @property {boolean} [nsfw] Whether the command is age-restricted
+   * @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the command description,
+   * if type is {@link ApplicationCommandType.ChatInput}
+   * @property {ApplicationCommandType} [type=ApplicationCommandType.ChatInput] The type of the command
+   * @property {ApplicationCommandOptionData[]} [options] Options for the command
+   * @property {?PermissionResolvable} [defaultMemberPermissions] The bitfield used to determine the default permissions
+   * a member needs in order to run the command
+   * @property {boolean} [dmPermission] Whether the command is enabled in DMs
+   */
+
+  /**
+   * An option for an application command or subcommand.
+   * <info>In addition to the listed properties, when used as a parameter,
+   * API style `snake_case` properties can be used for compatibility with generators like `@discordjs/builders`.</info>
+   * <warn>Note that providing a value for the `camelCase` counterpart for any `snake_case` property
+   * will discard the provided `snake_case` property.</warn>
+   * @typedef {Object} ApplicationCommandOptionData
+   * @property {ApplicationCommandOptionType} type The type of the option
+   * @property {string} name The name of the option
+   * @property {Object<Locale, string>} [nameLocalizations] The name localizations for the option
+   * @property {string} description The description of the option
+   * @property {Object<Locale, string>} [descriptionLocalizations] The description localizations for the option
+   * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a
+   * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or
+   * {@link ApplicationCommandOptionType.Number} option
+   * @property {boolean} [required] Whether the option is required
+   * @property {ApplicationCommandOptionChoiceData[]} [choices] The choices of the option for the user to pick from
+   * @property {ApplicationCommandOptionData[]} [options] Additional options if this option is a subcommand (group)
+   * @property {ChannelType[]} [channelTypes] When the option type is channel,
+   * the allowed types of channels that can be selected
+   * @property {number} [minValue] The minimum value for an {@link ApplicationCommandOptionType.Integer} or
+   * {@link ApplicationCommandOptionType.Number} option
+   * @property {number} [maxValue] The maximum value for an {@link ApplicationCommandOptionType.Integer} or
+   * {@link ApplicationCommandOptionType.Number} option
+   * @property {number} [minLength] The minimum length for an {@link ApplicationCommandOptionType.String} option
+   * (maximum of `6000`)
+   * @property {number} [maxLength] The maximum length for an {@link ApplicationCommandOptionType.String} option
+   * (maximum of `6000`)
+   */
+
+  /**
+   * @typedef {Object} ApplicationCommandOptionChoiceData
+   * @property {string} name The name of the choice
+   * @property {Object<Locale, string>} [nameLocalizations] The localized names for this choice
+   * @property {string|number} value The value of the choice
+   */
+
+  /**
+   * Edits this application command.
+   * @param {Partial<ApplicationCommandData>} data The data to update the command with
+   * @returns {Promise<ApplicationCommand>}
+   * @example
+   * // Edit the description of this command
+   * command.edit({
+   *   description: 'New description',
+   * })
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  edit(data) {
+    return this.manager.edit(this, data, this.guildId);
+  }
+
+  /**
+   * Edits the name of this ApplicationCommand
+   * @param {string} name The new name of the command
+   * @returns {Promise<ApplicationCommand>}
+   */
+  setName(name) {
+    return this.edit({ name });
+  }
+
+  /**
+   * Edits the localized names of this ApplicationCommand
+   * @param {Object<Locale, string>} nameLocalizations The new localized names for the command
+   * @returns {Promise<ApplicationCommand>}
+   * @example
+   * // Edit the name localizations of this command
+   * command.setLocalizedNames({
+   *   'en-GB': 'test',
+   *   'pt-BR': 'teste',
+   * })
+   *   .then(console.log)
+   *   .catch(console.error)
+   */
+  setNameLocalizations(nameLocalizations) {
+    return this.edit({ nameLocalizations });
+  }
+
+  /**
+   * Edits the description of this ApplicationCommand
+   * @param {string} description The new description of the command
+   * @returns {Promise<ApplicationCommand>}
+   */
+  setDescription(description) {
+    return this.edit({ description });
+  }
+
+  /**
+   * Edits the localized descriptions of this ApplicationCommand
+   * @param {Object<Locale, string>} descriptionLocalizations The new localized descriptions for the command
+   * @returns {Promise<ApplicationCommand>}
+   * @example
+   * // Edit the description localizations of this command
+   * command.setDescriptionLocalizations({
+   *   'en-GB': 'A test command',
+   *   'pt-BR': 'Um comando de teste',
+   * })
+   *   .then(console.log)
+   *   .catch(console.error)
+   */
+  setDescriptionLocalizations(descriptionLocalizations) {
+    return this.edit({ descriptionLocalizations });
+  }
+
+  /**
+   * Edits the default member permissions of this ApplicationCommand
+   * @param {?PermissionResolvable} defaultMemberPermissions The default member permissions required to run this command
+   * @returns {Promise<ApplicationCommand>}
+   */
+  setDefaultMemberPermissions(defaultMemberPermissions) {
+    return this.edit({ defaultMemberPermissions });
+  }
+
+  /**
+   * Edits the DM permission of this ApplicationCommand
+   * @param {boolean} [dmPermission=true] Whether the command can be used in DMs
+   * @returns {Promise<ApplicationCommand>}
+   */
+  setDMPermission(dmPermission = true) {
+    return this.edit({ dmPermission });
+  }
+
+  /**
+   * Edits the options of this ApplicationCommand
+   * @param {ApplicationCommandOptionData[]} options The options to set for this command
+   * @returns {Promise<ApplicationCommand>}
+   */
+  setOptions(options) {
+    return this.edit({ options });
+  }
+
+  /**
+   * Deletes this command.
+   * @returns {Promise<ApplicationCommand>}
+   * @example
+   * // Delete this command
+   * command.delete()
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  delete() {
+    return this.manager.delete(this, this.guildId);
+  }
+
+  /**
+   * Whether this command equals another command. It compares all properties, so for most operations
+   * it is advisable to just compare `command.id === command2.id` as it is much faster and is often
+   * what most users need.
+   * @param {ApplicationCommand|ApplicationCommandData|APIApplicationCommand} command The command to compare with
+   * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options and choices are in the same
+   * order in the array <info>The client may not always respect this ordering!</info>
+   * @returns {boolean}
+   */
+  equals(command, enforceOptionOrder = false) {
+    // If given an id, check if the id matches
+    if (command.id && this.id !== command.id) return false;
+
+    let defaultMemberPermissions = null;
+    let dmPermission = command.dmPermission ?? command.dm_permission;
+
+    if ('default_member_permissions' in command) {
+      defaultMemberPermissions = command.default_member_permissions
+        ? new PermissionsBitField(BigInt(command.default_member_permissions)).bitfield
+        : null;
+    }
+
+    if ('defaultMemberPermissions' in command) {
+      defaultMemberPermissions =
+        command.defaultMemberPermissions !== null
+          ? new PermissionsBitField(command.defaultMemberPermissions).bitfield
+          : null;
+    }
+
+    // Check top level parameters
+    if (
+      command.name !== this.name ||
+      ('description' in command && command.description !== this.description) ||
+      ('version' in command && command.version !== this.version) ||
+      (command.type && command.type !== this.type) ||
+      ('nsfw' in command && command.nsfw !== this.nsfw) ||
+      // Future proof for options being nullable
+      // TODO: remove ?? 0 on each when nullable
+      (command.options?.length ?? 0) !== (this.options?.length ?? 0) ||
+      defaultMemberPermissions !== (this.defaultMemberPermissions?.bitfield ?? null) ||
+      (dmPermission !== undefined && dmPermission !== this.dmPermission) ||
+      !isEqual(command.nameLocalizations ?? command.name_localizations ?? {}, this.nameLocalizations ?? {}) ||
+      !isEqual(
+        command.descriptionLocalizations ?? command.description_localizations ?? {},
+        this.descriptionLocalizations ?? {},
+      )
+    ) {
+      return false;
+    }
+
+    if (command.options) {
+      return this.constructor.optionsEqual(this.options, command.options, enforceOptionOrder);
+    }
+    return true;
+  }
+
+  /**
+   * Recursively checks that all options for an {@link ApplicationCommand} are equal to the provided options.
+   * In most cases it is better to compare using {@link ApplicationCommand#equals}
+   * @param {ApplicationCommandOptionData[]} existing The options on the existing command,
+   * should be {@link ApplicationCommand#options}
+   * @param {ApplicationCommandOptionData[]|APIApplicationCommandOption[]} options The options to compare against
+   * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options and choices are in the same
+   * order in the array <info>The client may not always respect this ordering!</info>
+   * @returns {boolean}
+   */
+  static optionsEqual(existing, options, enforceOptionOrder = false) {
+    if (existing.length !== options.length) return false;
+    if (enforceOptionOrder) {
+      return existing.every((option, index) => this._optionEquals(option, options[index], enforceOptionOrder));
+    }
+    const newOptions = new Map(options.map(option => [option.name, option]));
+    for (const option of existing) {
+      const foundOption = newOptions.get(option.name);
+      if (!foundOption || !this._optionEquals(option, foundOption)) return false;
+    }
+    return true;
+  }
+
+  /**
+   * Checks that an option for an {@link ApplicationCommand} is equal to the provided option
+   * In most cases it is better to compare using {@link ApplicationCommand#equals}
+   * @param {ApplicationCommandOptionData} existing The option on the existing command,
+   * should be from {@link ApplicationCommand#options}
+   * @param {ApplicationCommandOptionData|APIApplicationCommandOption} option The option to compare against
+   * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options or choices are in the same
+   * order in their array <info>The client may not always respect this ordering!</info>
+   * @returns {boolean}
+   * @private
+   */
+  static _optionEquals(existing, option, enforceOptionOrder = false) {
+    if (
+      option.name !== existing.name ||
+      option.type !== existing.type ||
+      option.description !== existing.description ||
+      option.autocomplete !== existing.autocomplete ||
+      (option.required ??
+        ([ApplicationCommandOptionType.Subcommand, ApplicationCommandOptionType.SubcommandGroup].includes(option.type)
+          ? undefined
+          : false)) !== existing.required ||
+      option.choices?.length !== existing.choices?.length ||
+      option.options?.length !== existing.options?.length ||
+      (option.channelTypes ?? option.channel_types)?.length !== existing.channelTypes?.length ||
+      (option.minValue ?? option.min_value) !== existing.minValue ||
+      (option.maxValue ?? option.max_value) !== existing.maxValue ||
+      (option.minLength ?? option.min_length) !== existing.minLength ||
+      (option.maxLength ?? option.max_length) !== existing.maxLength ||
+      !isEqual(option.nameLocalizations ?? option.name_localizations ?? {}, existing.nameLocalizations ?? {}) ||
+      !isEqual(
+        option.descriptionLocalizations ?? option.description_localizations ?? {},
+        existing.descriptionLocalizations ?? {},
+      )
+    ) {
+      return false;
+    }
+
+    if (existing.choices) {
+      if (
+        enforceOptionOrder &&
+        !existing.choices.every(
+          (choice, index) =>
+            choice.name === option.choices[index].name &&
+            choice.value === option.choices[index].value &&
+            isEqual(
+              choice.nameLocalizations ?? {},
+              option.choices[index].nameLocalizations ?? option.choices[index].name_localizations ?? {},
+            ),
+        )
+      ) {
+        return false;
+      }
+      if (!enforceOptionOrder) {
+        const newChoices = new Map(option.choices.map(choice => [choice.name, choice]));
+        for (const choice of existing.choices) {
+          const foundChoice = newChoices.get(choice.name);
+          if (!foundChoice || foundChoice.value !== choice.value) return false;
+        }
+      }
+    }
+
+    if (existing.channelTypes) {
+      const newTypes = option.channelTypes ?? option.channel_types;
+      for (const type of existing.channelTypes) {
+        if (!newTypes.includes(type)) return false;
+      }
+    }
+
+    if (existing.options) {
+      return this.optionsEqual(existing.options, option.options, enforceOptionOrder);
+    }
+    return true;
+  }
+
+  /**
+   * An option for an application command or subcommand.
+   * @typedef {Object} ApplicationCommandOption
+   * @property {ApplicationCommandOptionType} type The type of the option
+   * @property {string} name The name of the option
+   * @property {Object<Locale, string>} [nameLocalizations] The localizations for the option name
+   * @property {string} [nameLocalized] The localized name for this option
+   * @property {string} description The description of the option
+   * @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the option description
+   * @property {string} [descriptionLocalized] The localized description for this option
+   * @property {boolean} [required] Whether the option is required
+   * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a
+   * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or
+   * {@link ApplicationCommandOptionType.Number} option
+   * @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from
+   * @property {ApplicationCommandOption[]} [options] Additional options if this option is a subcommand (group)
+   * @property {ApplicationCommandOptionAllowedChannelTypes[]} [channelTypes] When the option type is channel,
+   * the allowed types of channels that can be selected
+   * @property {number} [minValue] The minimum value for an {@link ApplicationCommandOptionType.Integer} or
+   * {@link ApplicationCommandOptionType.Number} option
+   * @property {number} [maxValue] The maximum value for an {@link ApplicationCommandOptionType.Integer} or
+   * {@link ApplicationCommandOptionType.Number} option
+   * @property {number} [minLength] The minimum length for an {@link ApplicationCommandOptionType.String} option
+   * (maximum of `6000`)
+   * @property {number} [maxLength] The maximum length for an {@link ApplicationCommandOptionType.String} option
+   * (maximum of `6000`)
+   */
+
+  /**
+   * A choice for an application command option.
+   * @typedef {Object} ApplicationCommandOptionChoice
+   * @property {string} name The name of the choice
+   * @property {?string} nameLocalized The localized name of the choice in the provided locale, if any
+   * @property {?Object<string, string>} [nameLocalizations] The localized names for this choice
+   * @property {string|number} value The value of the choice
+   */
+
+  /**
+   * Transforms an {@link ApplicationCommandOptionData} object into something that can be used with the API.
+   * @param {ApplicationCommandOptionData|ApplicationCommandOption} option The option to transform
+   * @param {boolean} [received] Whether this option has been received from Discord
+   * @returns {APIApplicationCommandOption}
+   * @private
+   */
+  static transformOption(option, received) {
+    const channelTypesKey = received ? 'channelTypes' : 'channel_types';
+    const minValueKey = received ? 'minValue' : 'min_value';
+    const maxValueKey = received ? 'maxValue' : 'max_value';
+    const minLengthKey = received ? 'minLength' : 'min_length';
+    const maxLengthKey = received ? 'maxLength' : 'max_length';
+    const nameLocalizationsKey = received ? 'nameLocalizations' : 'name_localizations';
+    const nameLocalizedKey = received ? 'nameLocalized' : 'name_localized';
+    const descriptionLocalizationsKey = received ? 'descriptionLocalizations' : 'description_localizations';
+    const descriptionLocalizedKey = received ? 'descriptionLocalized' : 'description_localized';
+    return {
+      type: option.type,
+      name: option.name,
+      [nameLocalizationsKey]: option.nameLocalizations ?? option.name_localizations,
+      [nameLocalizedKey]: option.nameLocalized ?? option.name_localized,
+      description: option.description,
+      [descriptionLocalizationsKey]: option.descriptionLocalizations ?? option.description_localizations,
+      [descriptionLocalizedKey]: option.descriptionLocalized ?? option.description_localized,
+      required:
+        option.required ??
+        (option.type === ApplicationCommandOptionType.Subcommand ||
+        option.type === ApplicationCommandOptionType.SubcommandGroup
+          ? undefined
+          : false),
+      autocomplete: option.autocomplete,
+      choices: option.choices?.map(choice => ({
+        name: choice.name,
+        [nameLocalizedKey]: choice.nameLocalized ?? choice.name_localized,
+        [nameLocalizationsKey]: choice.nameLocalizations ?? choice.name_localizations,
+        value: choice.value,
+      })),
+      options: option.options?.map(o => this.transformOption(o, received)),
+      [channelTypesKey]: option.channelTypes ?? option.channel_types,
+      [minValueKey]: option.minValue ?? option.min_value,
+      [maxValueKey]: option.maxValue ?? option.max_value,
+      [minLengthKey]: option.minLength ?? option.min_length,
+      [maxLengthKey]: option.maxLength ?? option.max_length,
+    };
+  }
+}
+
+module.exports = ApplicationCommand;
+
+/* eslint-disable max-len */
+/**
+ * @external APIApplicationCommand
+ * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-structure}
+ */
+
+/**
+ * @external APIApplicationCommandOption
+ * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure}
+ */
+
+/**
+ * @external ApplicationCommandOptionAllowedChannelTypes
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/ApplicationCommandOptionAllowedChannelTypes:TypeAlias}
+ */
diff --git a/node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js b/node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js
new file mode 100644
index 0000000..7ed9b33
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js
@@ -0,0 +1,46 @@
+'use strict';
+
+/**
+ * Role connection metadata object for an application.
+ */
+class ApplicationRoleConnectionMetadata {
+  constructor(data) {
+    /**
+     * The name of this metadata field
+     * @type {string}
+     */
+    this.name = data.name;
+
+    /**
+     * The name localizations for this metadata field
+     * @type {?Object<Locale, string>}
+     */
+    this.nameLocalizations = data.name_localizations ?? null;
+
+    /**
+     * The description of this metadata field
+     * @type {string}
+     */
+    this.description = data.description;
+
+    /**
+     * The description localizations for this metadata field
+     * @type {?Object<Locale, string>}
+     */
+    this.descriptionLocalizations = data.description_localizations ?? null;
+
+    /**
+     * The dictionary key for this metadata field
+     * @type {string}
+     */
+    this.key = data.key;
+
+    /**
+     * The type of this metadata field
+     * @type {ApplicationRoleConnectionMetadataType}
+     */
+    this.type = data.type;
+  }
+}
+
+exports.ApplicationRoleConnectionMetadata = ApplicationRoleConnectionMetadata;
diff --git a/node_modules/discord.js/src/structures/Attachment.js b/node_modules/discord.js/src/structures/Attachment.js
new file mode 100644
index 0000000..2576ff5
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Attachment.js
@@ -0,0 +1,151 @@
+'use strict';
+
+const AttachmentFlagsBitField = require('../util/AttachmentFlagsBitField.js');
+const { basename, flatten } = require('../util/Util');
+
+/**
+ * @typedef {Object} AttachmentPayload
+ * @property {?string} name The name of the attachment
+ * @property {Stream|BufferResolvable} attachment The attachment in this payload
+ * @property {?string} description The description of the attachment
+ */
+
+/**
+ * Represents an attachment
+ */
+class Attachment {
+  constructor(data) {
+    this.attachment = data.url;
+    /**
+     * The name of this attachment
+     * @type {string}
+     */
+    this.name = data.filename;
+    this._patch(data);
+  }
+
+  _patch(data) {
+    /**
+     * The attachment's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    if ('size' in data) {
+      /**
+       * The size of this attachment in bytes
+       * @type {number}
+       */
+      this.size = data.size;
+    }
+
+    if ('url' in data) {
+      /**
+       * The URL to this attachment
+       * @type {string}
+       */
+      this.url = data.url;
+    }
+
+    if ('proxy_url' in data) {
+      /**
+       * The Proxy URL to this attachment
+       * @type {string}
+       */
+      this.proxyURL = data.proxy_url;
+    }
+
+    if ('height' in data) {
+      /**
+       * The height of this attachment (if an image or video)
+       * @type {?number}
+       */
+      this.height = data.height;
+    } else {
+      this.height ??= null;
+    }
+
+    if ('width' in data) {
+      /**
+       * The width of this attachment (if an image or video)
+       * @type {?number}
+       */
+      this.width = data.width;
+    } else {
+      this.width ??= null;
+    }
+
+    if ('content_type' in data) {
+      /**
+       * The media type of this attachment
+       * @type {?string}
+       */
+      this.contentType = data.content_type;
+    } else {
+      this.contentType ??= null;
+    }
+
+    if ('description' in data) {
+      /**
+       * The description (alt text) of this attachment
+       * @type {?string}
+       */
+      this.description = data.description;
+    } else {
+      this.description ??= null;
+    }
+
+    /**
+     * Whether this attachment is ephemeral
+     * @type {boolean}
+     */
+    this.ephemeral = data.ephemeral ?? false;
+
+    if ('duration_secs' in data) {
+      /**
+       * The duration of this attachment in seconds
+       * <info>This will only be available if the attachment is an audio file.</info>
+       * @type {?number}
+       */
+      this.duration = data.duration_secs;
+    } else {
+      this.duration ??= null;
+    }
+
+    if ('waveform' in data) {
+      /**
+       * The base64 encoded byte array representing a sampled waveform
+       * <info>This will only be available if the attachment is an audio file.</info>
+       * @type {?string}
+       */
+      this.waveform = data.waveform;
+    } else {
+      this.waveform ??= null;
+    }
+
+    if ('flags' in data) {
+      /**
+       * The flags of this attachment
+       * @type {Readonly<AttachmentFlagsBitField>}
+       */
+      this.flags = new AttachmentFlagsBitField(data.flags).freeze();
+    } else {
+      this.flags ??= new AttachmentFlagsBitField().freeze();
+    }
+  }
+
+  /**
+   * Whether or not this attachment has been marked as a spoiler
+   * @type {boolean}
+   * @readonly
+   */
+  get spoiler() {
+    return basename(this.url ?? this.name).startsWith('SPOILER_');
+  }
+
+  toJSON() {
+    return flatten(this);
+  }
+}
+
+module.exports = Attachment;
diff --git a/node_modules/discord.js/src/structures/AttachmentBuilder.js b/node_modules/discord.js/src/structures/AttachmentBuilder.js
new file mode 100644
index 0000000..6c63810
--- /dev/null
+++ b/node_modules/discord.js/src/structures/AttachmentBuilder.js
@@ -0,0 +1,116 @@
+'use strict';
+
+const { basename, flatten } = require('../util/Util');
+
+/**
+ * Represents an attachment builder
+ */
+class AttachmentBuilder {
+  /**
+   * @param {BufferResolvable|Stream} attachment The file
+   * @param {AttachmentData} [data] Extra data
+   */
+  constructor(attachment, data = {}) {
+    /**
+     * The file associated with this attachment.
+     * @type {BufferResolvable|Stream}
+     */
+    this.attachment = attachment;
+    /**
+     * The name of this attachment
+     * @type {?string}
+     */
+    this.name = data.name;
+    /**
+     * The description of the attachment
+     * @type {?string}
+     */
+    this.description = data.description;
+  }
+
+  /**
+   * Sets the description of this attachment.
+   * @param {string} description The description of the file
+   * @returns {AttachmentBuilder} This attachment
+   */
+  setDescription(description) {
+    this.description = description;
+    return this;
+  }
+
+  /**
+   * Sets the file of this attachment.
+   * @param {BufferResolvable|Stream} attachment The file
+   * @returns {AttachmentBuilder} This attachment
+   */
+  setFile(attachment) {
+    this.attachment = attachment;
+    return this;
+  }
+
+  /**
+   * Sets the name of this attachment.
+   * @param {string} name The name of the file
+   * @returns {AttachmentBuilder} This attachment
+   */
+  setName(name) {
+    this.name = name;
+    return this;
+  }
+
+  /**
+   * Sets whether this attachment is a spoiler
+   * @param {boolean} [spoiler=true] Whether the attachment should be marked as a spoiler
+   * @returns {AttachmentBuilder} This attachment
+   */
+  setSpoiler(spoiler = true) {
+    if (spoiler === this.spoiler) return this;
+
+    if (!spoiler) {
+      while (this.spoiler) {
+        this.name = this.name.slice('SPOILER_'.length);
+      }
+      return this;
+    }
+    this.name = `SPOILER_${this.name}`;
+    return this;
+  }
+
+  /**
+   * Whether or not this attachment has been marked as a spoiler
+   * @type {boolean}
+   * @readonly
+   */
+  get spoiler() {
+    return basename(this.name).startsWith('SPOILER_');
+  }
+
+  toJSON() {
+    return flatten(this);
+  }
+
+  /**
+   * Makes a new builder instance from a preexisting attachment structure.
+   * @param {AttachmentBuilder|Attachment|AttachmentPayload} other The builder to construct a new instance from
+   * @returns {AttachmentBuilder}
+   */
+  static from(other) {
+    return new AttachmentBuilder(other.attachment, {
+      name: other.name,
+      description: other.description,
+    });
+  }
+}
+
+module.exports = AttachmentBuilder;
+
+/**
+ * @external APIAttachment
+ * @see {@link https://discord.com/developers/docs/resources/channel#attachment-object}
+ */
+
+/**
+ * @typedef {Object} AttachmentData
+ * @property {string} [name] The name of the attachment
+ * @property {string} [description] The description of the attachment
+ */
diff --git a/node_modules/discord.js/src/structures/AutoModerationActionExecution.js b/node_modules/discord.js/src/structures/AutoModerationActionExecution.js
new file mode 100644
index 0000000..fcbc617
--- /dev/null
+++ b/node_modules/discord.js/src/structures/AutoModerationActionExecution.js
@@ -0,0 +1,116 @@
+'use strict';
+
+const { _transformAPIAutoModerationAction } = require('../util/Transformers');
+
+/**
+ * Represents the structure of an executed action when an {@link AutoModerationRule} is triggered.
+ */
+class AutoModerationActionExecution {
+  constructor(data, guild) {
+    /**
+     * The guild where this action was executed from.
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The action that was executed.
+     * @type {AutoModerationAction}
+     */
+    this.action = _transformAPIAutoModerationAction(data.action);
+
+    /**
+     * The id of the auto moderation rule this action belongs to.
+     * @type {Snowflake}
+     */
+    this.ruleId = data.rule_id;
+
+    /**
+     * The trigger type of the auto moderation rule which was triggered.
+     * @type {AutoModerationRuleTriggerType}
+     */
+    this.ruleTriggerType = data.rule_trigger_type;
+
+    /**
+     * The id of the user that triggered this action.
+     * @type {Snowflake}
+     */
+    this.userId = data.user_id;
+
+    /**
+     * The id of the channel where this action was triggered from.
+     * @type {?Snowflake}
+     */
+    this.channelId = data.channel_id ?? null;
+
+    /**
+     * The id of the message that triggered this action.
+     * <info>This will not be present if the message was blocked or the content was not part of any message.</info>
+     * @type {?Snowflake}
+     */
+    this.messageId = data.message_id ?? null;
+
+    /**
+     * The id of any system auto moderation messages posted as a result of this action.
+     * @type {?Snowflake}
+     */
+    this.alertSystemMessageId = data.alert_system_message_id ?? null;
+
+    /**
+     * The content that triggered this action.
+     * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged gateway intent.</info>
+     * @type {string}
+     */
+    this.content = data.content;
+
+    /**
+     * The word or phrase configured in the rule that triggered this action.
+     * @type {?string}
+     */
+    this.matchedKeyword = data.matched_keyword ?? null;
+
+    /**
+     * The substring in content that triggered this action.
+     * @type {?string}
+     */
+    this.matchedContent = data.matched_content ?? null;
+  }
+
+  /**
+   * The auto moderation rule this action belongs to.
+   * @type {?AutoModerationRule}
+   * @readonly
+   */
+  get autoModerationRule() {
+    return this.guild.autoModerationRules.cache.get(this.ruleId) ?? null;
+  }
+
+  /**
+   * The channel where this action was triggered from.
+   * @type {?(GuildTextBasedChannel|ForumChannel)}
+   * @readonly
+   */
+  get channel() {
+    return this.guild.channels.cache.get(this.channelId) ?? null;
+  }
+
+  /**
+   * The user that triggered this action.
+   * @type {?User}
+   * @readonly
+   */
+  get user() {
+    return this.guild.client.users.cache.get(this.userId) ?? null;
+  }
+
+  /**
+   * The guild member that triggered this action.
+   * @type {?GuildMember}
+   * @readonly
+   */
+  get member() {
+    return this.guild.members.cache.get(this.userId) ?? null;
+  }
+}
+
+module.exports = AutoModerationActionExecution;
diff --git a/node_modules/discord.js/src/structures/AutoModerationRule.js b/node_modules/discord.js/src/structures/AutoModerationRule.js
new file mode 100644
index 0000000..e87f547
--- /dev/null
+++ b/node_modules/discord.js/src/structures/AutoModerationRule.js
@@ -0,0 +1,284 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Base = require('./Base');
+const { _transformAPIAutoModerationAction } = require('../util/Transformers');
+
+/**
+ * Represents an auto moderation rule.
+ * @extends {Base}
+ */
+class AutoModerationRule extends Base {
+  constructor(client, data, guild) {
+    super(client);
+
+    /**
+     * The id of this auto moderation rule.
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The guild this auto moderation rule is for.
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The user that created this auto moderation rule.
+     * @type {Snowflake}
+     */
+    this.creatorId = data.creator_id;
+
+    /**
+     * The trigger type of this auto moderation rule.
+     * @type {AutoModerationRuleTriggerType}
+     */
+    this.triggerType = data.trigger_type;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('name' in data) {
+      /**
+       * The name of this auto moderation rule.
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('event_type' in data) {
+      /**
+       * The event type of this auto moderation rule.
+       * @type {AutoModerationRuleEventType}
+       */
+      this.eventType = data.event_type;
+    }
+
+    if ('trigger_metadata' in data) {
+      /**
+       * Additional data used to determine whether an auto moderation rule should be triggered.
+       * @typedef {Object} AutoModerationTriggerMetadata
+       * @property {string[]} keywordFilter The substrings that will be searched for in the content
+       * @property {string[]} regexPatterns The regular expression patterns which will be matched against the content
+       * <info>Only Rust-flavored regular expressions are supported.</info>
+       * @property {AutoModerationRuleKeywordPresetType[]} presets
+       * The internally pre-defined wordsets which will be searched for in the content
+       * @property {string[]} allowList The substrings that will be exempt from triggering
+       * {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset}
+       * @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message
+       * @property {boolean} mentionRaidProtectionEnabled Whether mention raid protection is enabled
+       */
+
+      /**
+       * The trigger metadata of the rule.
+       * @type {AutoModerationTriggerMetadata}
+       */
+      this.triggerMetadata = {
+        keywordFilter: data.trigger_metadata.keyword_filter ?? [],
+        regexPatterns: data.trigger_metadata.regex_patterns ?? [],
+        presets: data.trigger_metadata.presets ?? [],
+        allowList: data.trigger_metadata.allow_list ?? [],
+        mentionTotalLimit: data.trigger_metadata.mention_total_limit ?? null,
+        mentionRaidProtectionEnabled: data.trigger_metadata.mention_raid_protection_enabled ?? false,
+      };
+    }
+
+    if ('actions' in data) {
+      /**
+       * An object containing information about an auto moderation rule action.
+       * @typedef {Object} AutoModerationAction
+       * @property {AutoModerationActionType} type The type of this auto moderation rule action
+       * @property {AutoModerationActionMetadata} metadata Additional metadata needed during execution
+       */
+
+      /**
+       * Additional data used when an auto moderation rule is executed.
+       * @typedef {Object} AutoModerationActionMetadata
+       * @property {?Snowflake} channelId The id of the channel to which content will be logged
+       * @property {?number} durationSeconds The timeout duration in seconds
+       * @property {?string} customMessage The custom message that is shown whenever a message is blocked
+       */
+
+      /**
+       * The actions of this auto moderation rule.
+       * @type {AutoModerationAction[]}
+       */
+      this.actions = data.actions.map(action => _transformAPIAutoModerationAction(action));
+    }
+
+    if ('enabled' in data) {
+      /**
+       * Whether this auto moderation rule is enabled.
+       * @type {boolean}
+       */
+      this.enabled = data.enabled;
+    }
+
+    if ('exempt_roles' in data) {
+      /**
+       * The roles exempt by this auto moderation rule.
+       * @type {Collection<Snowflake, Role>}
+       */
+      this.exemptRoles = new Collection(
+        data.exempt_roles.map(exemptRole => [exemptRole, this.guild.roles.cache.get(exemptRole)]),
+      );
+    }
+
+    if ('exempt_channels' in data) {
+      /**
+       * The channels exempt by this auto moderation rule.
+       * @type {Collection<Snowflake, GuildChannel|ThreadChannel>}
+       */
+      this.exemptChannels = new Collection(
+        data.exempt_channels.map(exemptChannel => [exemptChannel, this.guild.channels.cache.get(exemptChannel)]),
+      );
+    }
+  }
+
+  /**
+   * Edits this auto moderation rule.
+   * @param {AutoModerationRuleEditOptions} options Options for editing this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  edit(options) {
+    return this.guild.autoModerationRules.edit(this.id, options);
+  }
+
+  /**
+   * Deletes this auto moderation rule.
+   * @param {string} [reason] The reason for deleting this auto moderation rule
+   * @returns {Promise<void>}
+   */
+  delete(reason) {
+    return this.guild.autoModerationRules.delete(this.id, reason);
+  }
+
+  /**
+   * Sets the name for this auto moderation rule.
+   * @param {string} name The name of this auto moderation rule
+   * @param {string} [reason] The reason for changing the name of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setName(name, reason) {
+    return this.edit({ name, reason });
+  }
+
+  /**
+   * Sets the event type for this auto moderation rule.
+   * @param {AutoModerationRuleEventType} eventType The event type of this auto moderation rule
+   * @param {string} [reason] The reason for changing the event type of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setEventType(eventType, reason) {
+    return this.edit({ eventType, reason });
+  }
+
+  /**
+   * Sets the keyword filter for this auto moderation rule.
+   * @param {string[]} keywordFilter The keyword filter of this auto moderation rule
+   * @param {string} [reason] The reason for changing the keyword filter of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setKeywordFilter(keywordFilter, reason) {
+    return this.edit({ triggerMetadata: { ...this.triggerMetadata, keywordFilter }, reason });
+  }
+
+  /**
+   * Sets the regular expression patterns for this auto moderation rule.
+   * @param {string[]} regexPatterns The regular expression patterns of this auto moderation rule
+   * <info>Only Rust-flavored regular expressions are supported.</info>
+   * @param {string} [reason] The reason for changing the regular expression patterns of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setRegexPatterns(regexPatterns, reason) {
+    return this.edit({ triggerMetadata: { ...this.triggerMetadata, regexPatterns }, reason });
+  }
+
+  /**
+   * Sets the presets for this auto moderation rule.
+   * @param {AutoModerationRuleKeywordPresetType[]} presets The presets of this auto moderation rule
+   * @param {string} [reason] The reason for changing the presets of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setPresets(presets, reason) {
+    return this.edit({ triggerMetadata: { ...this.triggerMetadata, presets }, reason });
+  }
+
+  /**
+   * Sets the allow list for this auto moderation rule.
+   * @param {string[]} allowList The substrings that will be exempt from triggering
+   * {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset}
+   * @param {string} [reason] The reason for changing the allow list of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setAllowList(allowList, reason) {
+    return this.edit({ triggerMetadata: { ...this.triggerMetadata, allowList }, reason });
+  }
+
+  /**
+   * Sets the mention total limit for this auto moderation rule.
+   * @param {number} mentionTotalLimit The total number of unique role and user mentions allowed per message
+   * @param {string} [reason] The reason for changing the mention total limit of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setMentionTotalLimit(mentionTotalLimit, reason) {
+    return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionTotalLimit }, reason });
+  }
+
+  /**
+   * Sets whether to enable mention raid protection for this auto moderation rule.
+   * @param {boolean} mentionRaidProtectionEnabled
+   * Whether to enable mention raid protection for this auto moderation rule
+   * @param {string} [reason] The reason for changing the mention raid protection of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setMentionRaidProtectionEnabled(mentionRaidProtectionEnabled, reason) {
+    return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionRaidProtectionEnabled }, reason });
+  }
+
+  /**
+   * Sets the actions for this auto moderation rule.
+   * @param {AutoModerationActionOptions[]} actions The actions of this auto moderation rule
+   * @param {string} [reason] The reason for changing the actions of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setActions(actions, reason) {
+    return this.edit({ actions, reason });
+  }
+
+  /**
+   * Sets whether this auto moderation rule should be enabled.
+   * @param {boolean} [enabled=true] Whether to enable this auto moderation rule
+   * @param {string} [reason] The reason for enabling or disabling this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setEnabled(enabled = true, reason) {
+    return this.edit({ enabled, reason });
+  }
+
+  /**
+   * Sets the exempt roles for this auto moderation rule.
+   * @param {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]
+   * The roles that should not be affected by the auto moderation rule
+   * @param {string} [reason] The reason for changing the exempt roles of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setExemptRoles(exemptRoles, reason) {
+    return this.edit({ exemptRoles, reason });
+  }
+
+  /**
+   * Sets the exempt channels for this auto moderation rule.
+   * @param {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
+   * The channels that should not be affected by the auto moderation rule
+   * @param {string} [reason] The reason for changing the exempt channels of this auto moderation rule
+   * @returns {Promise<AutoModerationRule>}
+   */
+  setExemptChannels(exemptChannels, reason) {
+    return this.edit({ exemptChannels, reason });
+  }
+}
+
+module.exports = AutoModerationRule;
diff --git a/node_modules/discord.js/src/structures/AutocompleteInteraction.js b/node_modules/discord.js/src/structures/AutocompleteInteraction.js
new file mode 100644
index 0000000..4b7e39e
--- /dev/null
+++ b/node_modules/discord.js/src/structures/AutocompleteInteraction.js
@@ -0,0 +1,102 @@
+'use strict';
+
+const { InteractionResponseType, Routes } = require('discord-api-types/v10');
+const BaseInteraction = require('./BaseInteraction');
+const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents an autocomplete interaction.
+ * @extends {BaseInteraction}
+ */
+class AutocompleteInteraction extends BaseInteraction {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * The id of the channel this interaction was sent in
+     * @type {Snowflake}
+     * @name AutocompleteInteraction#channelId
+     */
+
+    /**
+     * The invoked application command's id
+     * @type {Snowflake}
+     */
+    this.commandId = data.data.id;
+
+    /**
+     * The invoked application command's name
+     * @type {string}
+     */
+    this.commandName = data.data.name;
+
+    /**
+     * The invoked application command's type
+     * @type {ApplicationCommandType}
+     */
+    this.commandType = data.data.type;
+
+    /**
+     * The id of the guild the invoked application command is registered to
+     * @type {?Snowflake}
+     */
+    this.commandGuildId = data.data.guild_id ?? null;
+
+    /**
+     * Whether this interaction has already received a response
+     * @type {boolean}
+     */
+    this.responded = false;
+
+    /**
+     * The options passed to the command
+     * @type {CommandInteractionOptionResolver}
+     */
+    this.options = new CommandInteractionOptionResolver(this.client, data.data.options ?? []);
+  }
+
+  /**
+   * The invoked application command, if it was fetched before
+   * @type {?ApplicationCommand}
+   */
+  get command() {
+    const id = this.commandId;
+    return this.guild?.commands.cache.get(id) ?? this.client.application.commands.cache.get(id) ?? null;
+  }
+
+  /**
+   * Sends results for the autocomplete of this interaction.
+   * @param {ApplicationCommandOptionChoiceData[]} options The options for the autocomplete
+   * @returns {Promise<void>}
+   * @example
+   * // respond to autocomplete interaction
+   * interaction.respond([
+   *  {
+   *    name: 'Option 1',
+   *    value: 'option1',
+   *  },
+   * ])
+   *  .then(() => console.log('Successfully responded to the autocomplete interaction'))
+   *  .catch(console.error);
+   */
+  async respond(options) {
+    if (this.responded) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
+
+    await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
+      body: {
+        type: InteractionResponseType.ApplicationCommandAutocompleteResult,
+        data: {
+          choices: options.map(({ nameLocalizations, ...option }) => ({
+            ...this.client.options.jsonTransformer(option),
+            name_localizations: nameLocalizations,
+          })),
+        },
+      },
+      auth: false,
+    });
+    this.responded = true;
+  }
+}
+
+module.exports = AutocompleteInteraction;
diff --git a/node_modules/discord.js/src/structures/Base.js b/node_modules/discord.js/src/structures/Base.js
new file mode 100644
index 0000000..102fb21
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Base.js
@@ -0,0 +1,43 @@
+'use strict';
+
+const { flatten } = require('../util/Util');
+
+/**
+ * Represents a data model that is identifiable by a Snowflake (i.e. Discord API data models).
+ * @abstract
+ */
+class Base {
+  constructor(client) {
+    /**
+     * The client that instantiated this
+     * @name Base#client
+     * @type {Client}
+     * @readonly
+     */
+    Object.defineProperty(this, 'client', { value: client });
+  }
+
+  _clone() {
+    return Object.assign(Object.create(this), this);
+  }
+
+  _patch(data) {
+    return data;
+  }
+
+  _update(data) {
+    const clone = this._clone();
+    this._patch(data);
+    return clone;
+  }
+
+  toJSON(...props) {
+    return flatten(this, ...props);
+  }
+
+  valueOf() {
+    return this.id;
+  }
+}
+
+module.exports = Base;
diff --git a/node_modules/discord.js/src/structures/BaseChannel.js b/node_modules/discord.js/src/structures/BaseChannel.js
new file mode 100644
index 0000000..346f763
--- /dev/null
+++ b/node_modules/discord.js/src/structures/BaseChannel.js
@@ -0,0 +1,155 @@
+'use strict';
+
+const { channelLink } = require('@discordjs/builders');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { ChannelType, Routes } = require('discord-api-types/v10');
+const Base = require('./Base');
+const ChannelFlagsBitField = require('../util/ChannelFlagsBitField');
+const { ThreadChannelTypes } = require('../util/Constants');
+
+/**
+ * Represents any channel on Discord.
+ * @extends {Base}
+ * @abstract
+ */
+class BaseChannel extends Base {
+  constructor(client, data, immediatePatch = true) {
+    super(client);
+
+    /**
+     * The type of the channel
+     * @type {ChannelType}
+     */
+    this.type = data.type;
+
+    if (data && immediatePatch) this._patch(data);
+  }
+
+  _patch(data) {
+    if ('flags' in data) {
+      /**
+       * The flags that are applied to the channel.
+       * <info>This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`.</info>
+       * @type {?Readonly<ChannelFlagsBitField>}
+       */
+      this.flags = new ChannelFlagsBitField(data.flags).freeze();
+    } else {
+      this.flags ??= new ChannelFlagsBitField().freeze();
+    }
+
+    /**
+     * The channel's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+  }
+
+  /**
+   * The timestamp the channel was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the channel was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The URL to the channel
+   * @type {string}
+   * @readonly
+   */
+  get url() {
+    return this.isDMBased() ? channelLink(this.id) : channelLink(this.id, this.guildId);
+  }
+
+  /**
+   * Whether this Channel is a partial
+   * <info>This is always false outside of DM channels.</info>
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return false;
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.
+   * @returns {string}
+   * @example
+   * // Logs: Hello from <#123456789012345678>!
+   * console.log(`Hello from ${channel}!`);
+   */
+  toString() {
+    return `<#${this.id}>`;
+  }
+
+  /**
+   * Deletes this channel.
+   * @returns {Promise<BaseChannel>}
+   * @example
+   * // Delete the channel
+   * channel.delete()
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async delete() {
+    await this.client.rest.delete(Routes.channel(this.id));
+    return this;
+  }
+
+  /**
+   * Fetches this channel.
+   * @param {boolean} [force=true] Whether to skip the cache check and request the API
+   * @returns {Promise<BaseChannel>}
+   */
+  fetch(force = true) {
+    return this.client.channels.fetch(this.id, { force });
+  }
+
+  /**
+   * Indicates whether this channel is a {@link ThreadChannel}.
+   * @returns {boolean}
+   */
+  isThread() {
+    return ThreadChannelTypes.includes(this.type);
+  }
+
+  /**
+   * Indicates whether this channel is {@link TextBasedChannels text-based}.
+   * @returns {boolean}
+   */
+  isTextBased() {
+    return 'messages' in this;
+  }
+
+  /**
+   * Indicates whether this channel is DM-based (either a {@link DMChannel} or a {@link PartialGroupDMChannel}).
+   * @returns {boolean}
+   */
+  isDMBased() {
+    return [ChannelType.DM, ChannelType.GroupDM].includes(this.type);
+  }
+
+  /**
+   * Indicates whether this channel is {@link BaseGuildVoiceChannel voice-based}.
+   * @returns {boolean}
+   */
+  isVoiceBased() {
+    return 'bitrate' in this;
+  }
+
+  toJSON(...props) {
+    return super.toJSON({ createdTimestamp: true }, ...props);
+  }
+}
+
+exports.BaseChannel = BaseChannel;
diff --git a/node_modules/discord.js/src/structures/BaseGuild.js b/node_modules/discord.js/src/structures/BaseGuild.js
new file mode 100644
index 0000000..b12ca44
--- /dev/null
+++ b/node_modules/discord.js/src/structures/BaseGuild.js
@@ -0,0 +1,119 @@
+'use strict';
+
+const { makeURLSearchParams } = require('@discordjs/rest');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { Routes, GuildFeature } = require('discord-api-types/v10');
+const Base = require('./Base');
+
+/**
+ * The base class for {@link Guild}, {@link OAuth2Guild} and {@link InviteGuild}.
+ * @extends {Base}
+ * @abstract
+ */
+class BaseGuild extends Base {
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The guild's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The name of this guild
+     * @type {string}
+     */
+    this.name = data.name;
+
+    /**
+     * The icon hash of this guild
+     * @type {?string}
+     */
+    this.icon = data.icon;
+
+    /**
+     * An array of features available to this guild
+     * @type {GuildFeature[]}
+     */
+    this.features = data.features;
+  }
+
+  /**
+   * The timestamp this guild was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time this guild was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The acronym that shows up in place of a guild icon
+   * @type {string}
+   * @readonly
+   */
+  get nameAcronym() {
+    return this.name
+      .replace(/'s /g, ' ')
+      .replace(/\w+/g, e => e[0])
+      .replace(/\s/g, '');
+  }
+
+  /**
+   * Whether this guild is partnered
+   * @type {boolean}
+   * @readonly
+   */
+  get partnered() {
+    return this.features.includes(GuildFeature.Partnered);
+  }
+
+  /**
+   * Whether this guild is verified
+   * @type {boolean}
+   * @readonly
+   */
+  get verified() {
+    return this.features.includes(GuildFeature.Verified);
+  }
+
+  /**
+   * The URL to this guild's icon.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  iconURL(options = {}) {
+    return this.icon && this.client.rest.cdn.icon(this.id, this.icon, options);
+  }
+
+  /**
+   * Fetches this guild.
+   * @returns {Promise<Guild>}
+   */
+  async fetch() {
+    const data = await this.client.rest.get(Routes.guild(this.id), {
+      query: makeURLSearchParams({ with_counts: true }),
+    });
+    return this.client.guilds._add(data);
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the guild's name instead of the Guild object.
+   * @returns {string}
+   */
+  toString() {
+    return this.name;
+  }
+}
+
+module.exports = BaseGuild;
diff --git a/node_modules/discord.js/src/structures/BaseGuildEmoji.js b/node_modules/discord.js/src/structures/BaseGuildEmoji.js
new file mode 100644
index 0000000..5a12bd9
--- /dev/null
+++ b/node_modules/discord.js/src/structures/BaseGuildEmoji.js
@@ -0,0 +1,56 @@
+'use strict';
+
+const { Emoji } = require('./Emoji');
+
+/**
+ * Parent class for {@link GuildEmoji} and {@link GuildPreviewEmoji}.
+ * @extends {Emoji}
+ * @abstract
+ */
+class BaseGuildEmoji extends Emoji {
+  constructor(client, data, guild) {
+    super(client, data);
+
+    /**
+     * The guild this emoji is a part of
+     * @type {Guild|GuildPreview}
+     */
+    this.guild = guild;
+
+    this.requiresColons = null;
+    this.managed = null;
+    this.available = null;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('name' in data) this.name = data.name;
+
+    if ('require_colons' in data) {
+      /**
+       * Whether or not this emoji requires colons surrounding it
+       * @type {?boolean}
+       */
+      this.requiresColons = data.require_colons;
+    }
+
+    if ('managed' in data) {
+      /**
+       * Whether this emoji is managed by an external service
+       * @type {?boolean}
+       */
+      this.managed = data.managed;
+    }
+
+    if ('available' in data) {
+      /**
+       * Whether this emoji is available
+       * @type {?boolean}
+       */
+      this.available = data.available;
+    }
+  }
+}
+
+module.exports = BaseGuildEmoji;
diff --git a/node_modules/discord.js/src/structures/BaseGuildTextChannel.js b/node_modules/discord.js/src/structures/BaseGuildTextChannel.js
new file mode 100644
index 0000000..f7d9d69
--- /dev/null
+++ b/node_modules/discord.js/src/structures/BaseGuildTextChannel.js
@@ -0,0 +1,186 @@
+'use strict';
+
+const GuildChannel = require('./GuildChannel');
+const TextBasedChannel = require('./interfaces/TextBasedChannel');
+const GuildMessageManager = require('../managers/GuildMessageManager');
+const GuildTextThreadManager = require('../managers/GuildTextThreadManager');
+
+/**
+ * Represents a text-based guild channel on Discord.
+ * @extends {GuildChannel}
+ * @implements {TextBasedChannel}
+ */
+class BaseGuildTextChannel extends GuildChannel {
+  constructor(guild, data, client) {
+    super(guild, data, client, false);
+
+    /**
+     * A manager of the messages sent to this channel
+     * @type {GuildMessageManager}
+     */
+    this.messages = new GuildMessageManager(this);
+
+    /**
+     * A manager of the threads belonging to this channel
+     * @type {GuildTextThreadManager}
+     */
+    this.threads = new GuildTextThreadManager(this);
+
+    /**
+     * If the guild considers this channel NSFW
+     * @type {boolean}
+     */
+    this.nsfw = Boolean(data.nsfw);
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    super._patch(data);
+
+    if ('topic' in data) {
+      /**
+       * The topic of the text channel
+       * @type {?string}
+       */
+      this.topic = data.topic;
+    }
+
+    if ('nsfw' in data) {
+      this.nsfw = Boolean(data.nsfw);
+    }
+
+    if ('last_message_id' in data) {
+      /**
+       * The last message id sent in the channel, if one was sent
+       * @type {?Snowflake}
+       */
+      this.lastMessageId = data.last_message_id;
+    }
+
+    if ('last_pin_timestamp' in data) {
+      /**
+       * The timestamp when the last pinned message was pinned, if there was one
+       * @type {?number}
+       */
+      this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;
+    }
+
+    if ('default_auto_archive_duration' in data) {
+      /**
+       * The default auto archive duration for newly created threads in this channel
+       * @type {?ThreadAutoArchiveDuration}
+       */
+      this.defaultAutoArchiveDuration = data.default_auto_archive_duration;
+    }
+
+    if ('messages' in data) {
+      for (const message of data.messages) this.messages._add(message);
+    }
+  }
+
+  /**
+   * Sets the default auto archive duration for all newly created threads in this channel.
+   * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration
+   * @param {string} [reason] Reason for changing the channel's default auto archive duration
+   * @returns {Promise<TextChannel>}
+   */
+  setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) {
+    return this.edit({ defaultAutoArchiveDuration, reason });
+  }
+
+  /**
+   * Sets the type of this channel.
+   * <info>Only conversion between {@link TextChannel} and {@link NewsChannel} is supported.</info>
+   * @param {ChannelType.GuildText|ChannelType.GuildAnnouncement} type The new channel type
+   * @param {string} [reason] Reason for changing the channel's type
+   * @returns {Promise<GuildChannel>}
+   */
+  setType(type, reason) {
+    return this.edit({ type, reason });
+  }
+
+  /**
+   * Sets a new topic for the guild channel.
+   * @param {?string} topic The new topic for the guild channel
+   * @param {string} [reason] Reason for changing the guild channel's topic
+   * @returns {Promise<GuildChannel>}
+   * @example
+   * // Set a new channel topic
+   * channel.setTopic('needs more rate limiting')
+   *   .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
+   *   .catch(console.error);
+   */
+  setTopic(topic, reason) {
+    return this.edit({ topic, reason });
+  }
+
+  /**
+   * Data that can be resolved to an Application. This can be:
+   * * An Application
+   * * An Activity with associated Application
+   * * A Snowflake
+   * @typedef {Application|Snowflake} ApplicationResolvable
+   */
+
+  /**
+   * Options used to create an invite to a guild channel.
+   * @typedef {Object} InviteCreateOptions
+   * @property {boolean} [temporary] Whether members that joined via the invite should be automatically
+   * kicked after 24 hours if they have not yet received a role
+   * @property {number} [maxAge] How long the invite should last (in seconds, 0 for forever)
+   * @property {number} [maxUses] Maximum number of uses
+   * @property {boolean} [unique] Create a unique invite, or use an existing one with similar settings
+   * @property {UserResolvable} [targetUser] The user whose stream to display for this invite,
+   * required if `targetType` is {@link InviteTargetType.Stream}, the user must be streaming in the channel
+   * @property {ApplicationResolvable} [targetApplication] The embedded application to open for this invite,
+   * required if `targetType` is {@link InviteTargetType.Stream}, the application must have the
+   * {@link InviteTargetType.EmbeddedApplication} flag
+   * @property {InviteTargetType} [targetType] The type of the target for this voice channel invite
+   * @property {string} [reason] The reason for creating the invite
+   */
+
+  /**
+   * Creates an invite to this guild channel.
+   * @param {InviteCreateOptions} [options={}] The options for creating the invite
+   * @returns {Promise<Invite>}
+   * @example
+   * // Create an invite to a channel
+   * channel.createInvite()
+   *   .then(invite => console.log(`Created an invite with a code of ${invite.code}`))
+   *   .catch(console.error);
+   */
+  createInvite(options) {
+    return this.guild.invites.create(this.id, options);
+  }
+
+  /**
+   * Fetches a collection of invites to this guild channel.
+   * Resolves with a collection mapping invites by their codes.
+   * @param {boolean} [cache=true] Whether or not to cache the fetched invites
+   * @returns {Promise<Collection<string, Invite>>}
+   */
+  fetchInvites(cache = true) {
+    return this.guild.invites.fetch({ channelId: this.id, cache });
+  }
+
+  // These are here only for documentation purposes - they are implemented by TextBasedChannel
+  /* eslint-disable no-empty-function */
+  get lastMessage() {}
+  get lastPinAt() {}
+  send() {}
+  sendTyping() {}
+  createMessageCollector() {}
+  awaitMessages() {}
+  createMessageComponentCollector() {}
+  awaitMessageComponent() {}
+  bulkDelete() {}
+  fetchWebhooks() {}
+  createWebhook() {}
+  setRateLimitPerUser() {}
+  setNSFW() {}
+}
+
+TextBasedChannel.applyToClass(BaseGuildTextChannel, true);
+
+module.exports = BaseGuildTextChannel;
diff --git a/node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js b/node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js
new file mode 100644
index 0000000..220ac6c
--- /dev/null
+++ b/node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js
@@ -0,0 +1,234 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { PermissionFlagsBits } = require('discord-api-types/v10');
+const GuildChannel = require('./GuildChannel');
+const TextBasedChannel = require('./interfaces/TextBasedChannel');
+const GuildMessageManager = require('../managers/GuildMessageManager');
+
+/**
+ * Represents a voice-based guild channel on Discord.
+ * @extends {GuildChannel}
+ * @implements {TextBasedChannel}
+ */
+class BaseGuildVoiceChannel extends GuildChannel {
+  constructor(guild, data, client) {
+    super(guild, data, client, false);
+    /**
+     * A manager of the messages sent to this channel
+     * @type {GuildMessageManager}
+     */
+    this.messages = new GuildMessageManager(this);
+
+    /**
+     * If the guild considers this channel NSFW
+     * @type {boolean}
+     */
+    this.nsfw = Boolean(data.nsfw);
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    super._patch(data);
+
+    if ('rtc_region' in data) {
+      /**
+       * The RTC region for this voice-based channel. This region is automatically selected if `null`.
+       * @type {?string}
+       */
+      this.rtcRegion = data.rtc_region;
+    }
+
+    if ('bitrate' in data) {
+      /**
+       * The bitrate of this voice-based channel
+       * @type {number}
+       */
+      this.bitrate = data.bitrate;
+    }
+
+    if ('user_limit' in data) {
+      /**
+       * The maximum amount of users allowed in this channel.
+       * @type {number}
+       */
+      this.userLimit = data.user_limit;
+    }
+
+    if ('video_quality_mode' in data) {
+      /**
+       * The camera video quality mode of the channel.
+       * @type {?VideoQualityMode}
+       */
+      this.videoQualityMode = data.video_quality_mode;
+    } else {
+      this.videoQualityMode ??= null;
+    }
+
+    if ('last_message_id' in data) {
+      /**
+       * The last message id sent in the channel, if one was sent
+       * @type {?Snowflake}
+       */
+      this.lastMessageId = data.last_message_id;
+    }
+
+    if ('messages' in data) {
+      for (const message of data.messages) this.messages._add(message);
+    }
+
+    if ('rate_limit_per_user' in data) {
+      /**
+       * The rate limit per user (slowmode) for this channel in seconds
+       * @type {number}
+       */
+      this.rateLimitPerUser = data.rate_limit_per_user;
+    }
+
+    if ('nsfw' in data) {
+      this.nsfw = data.nsfw;
+    }
+  }
+
+  /**
+   * The members in this voice-based channel
+   * @type {Collection<Snowflake, GuildMember>}
+   * @readonly
+   */
+  get members() {
+    const coll = new Collection();
+    for (const state of this.guild.voiceStates.cache.values()) {
+      if (state.channelId === this.id && state.member) {
+        coll.set(state.id, state.member);
+      }
+    }
+    return coll;
+  }
+
+  /**
+   * Checks if the voice-based channel is full
+   * @type {boolean}
+   * @readonly
+   */
+  get full() {
+    return this.userLimit > 0 && this.members.size >= this.userLimit;
+  }
+
+  /**
+   * Whether the channel is joinable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get joinable() {
+    if (!this.viewable) return false;
+    const permissions = this.permissionsFor(this.client.user);
+    if (!permissions) return false;
+
+    // This flag allows joining even if timed out
+    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;
+
+    return (
+      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() &&
+      permissions.has(PermissionFlagsBits.Connect, false)
+    );
+  }
+
+  /**
+   * Creates an invite to this guild channel.
+   * @param {InviteCreateOptions} [options={}] The options for creating the invite
+   * @returns {Promise<Invite>}
+   * @example
+   * // Create an invite to a channel
+   * channel.createInvite()
+   *   .then(invite => console.log(`Created an invite with a code of ${invite.code}`))
+   *   .catch(console.error);
+   */
+  createInvite(options) {
+    return this.guild.invites.create(this.id, options);
+  }
+
+  /**
+   * Fetches a collection of invites to this guild channel.
+   * @param {boolean} [cache=true] Whether to cache the fetched invites
+   * @returns {Promise<Collection<string, Invite>>}
+   */
+  fetchInvites(cache = true) {
+    return this.guild.invites.fetch({ channelId: this.id, cache });
+  }
+
+  /**
+   * Sets the bitrate of the channel.
+   * @param {number} bitrate The new bitrate
+   * @param {string} [reason] Reason for changing the channel's bitrate
+   * @returns {Promise<BaseGuildVoiceChannel>}
+   * @example
+   * // Set the bitrate of a voice channel
+   * channel.setBitrate(48_000)
+   *   .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`))
+   *   .catch(console.error);
+   */
+  setBitrate(bitrate, reason) {
+    return this.edit({ bitrate, reason });
+  }
+
+  /**
+   * Sets the RTC region of the channel.
+   * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
+   * @param {string} [reason] The reason for modifying this region.
+   * @returns {Promise<BaseGuildVoiceChannel>}
+   * @example
+   * // Set the RTC region to sydney
+   * channel.setRTCRegion('sydney');
+   * @example
+   * // Remove a fixed region for this channel - let Discord decide automatically
+   * channel.setRTCRegion(null, 'We want to let Discord decide.');
+   */
+  setRTCRegion(rtcRegion, reason) {
+    return this.edit({ rtcRegion, reason });
+  }
+
+  /**
+   * Sets the user limit of the channel.
+   * @param {number} userLimit The new user limit
+   * @param {string} [reason] Reason for changing the user limit
+   * @returns {Promise<BaseGuildVoiceChannel>}
+   * @example
+   * // Set the user limit of a voice channel
+   * channel.setUserLimit(42)
+   *   .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`))
+   *   .catch(console.error);
+   */
+  setUserLimit(userLimit, reason) {
+    return this.edit({ userLimit, reason });
+  }
+
+  /**
+   * Sets the camera video quality mode of the channel.
+   * @param {VideoQualityMode} videoQualityMode The new camera video quality mode.
+   * @param {string} [reason] Reason for changing the camera video quality mode.
+   * @returns {Promise<BaseGuildVoiceChannel>}
+   */
+  setVideoQualityMode(videoQualityMode, reason) {
+    return this.edit({ videoQualityMode, reason });
+  }
+
+  // These are here only for documentation purposes - they are implemented by TextBasedChannel
+  /* eslint-disable no-empty-function */
+  get lastMessage() {}
+  send() {}
+  sendTyping() {}
+  createMessageCollector() {}
+  awaitMessages() {}
+  createMessageComponentCollector() {}
+  awaitMessageComponent() {}
+  bulkDelete() {}
+  fetchWebhooks() {}
+  createWebhook() {}
+  setRateLimitPerUser() {}
+  setNSFW() {}
+}
+
+TextBasedChannel.applyToClass(BaseGuildVoiceChannel, true, ['lastPinAt']);
+
+module.exports = BaseGuildVoiceChannel;
diff --git a/node_modules/discord.js/src/structures/BaseInteraction.js b/node_modules/discord.js/src/structures/BaseInteraction.js
new file mode 100644
index 0000000..967350f
--- /dev/null
+++ b/node_modules/discord.js/src/structures/BaseInteraction.js
@@ -0,0 +1,344 @@
+'use strict';
+
+const { deprecate } = require('node:util');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { InteractionType, ApplicationCommandType, ComponentType } = require('discord-api-types/v10');
+const Base = require('./Base');
+const { SelectMenuTypes } = require('../util/Constants');
+const PermissionsBitField = require('../util/PermissionsBitField');
+
+/**
+ * Represents an interaction.
+ * @extends {Base}
+ * @abstract
+ */
+class BaseInteraction extends Base {
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The interaction's type
+     * @type {InteractionType}
+     */
+    this.type = data.type;
+
+    /**
+     * The interaction's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The interaction's token
+     * @type {string}
+     * @name BaseInteraction#token
+     * @readonly
+     */
+    Object.defineProperty(this, 'token', { value: data.token });
+
+    /**
+     * The application's id
+     * @type {Snowflake}
+     */
+    this.applicationId = data.application_id;
+
+    /**
+     * The id of the channel this interaction was sent in
+     * @type {?Snowflake}
+     */
+    this.channelId = data.channel?.id ?? null;
+
+    /**
+     * The id of the guild this interaction was sent in
+     * @type {?Snowflake}
+     */
+    this.guildId = data.guild_id ?? null;
+
+    /**
+     * The user who created this interaction
+     * @type {User}
+     */
+    this.user = this.client.users._add(data.user ?? data.member.user);
+
+    /**
+     * If this interaction was sent in a guild, the member which sent it
+     * @type {?(GuildMember|APIGuildMember)}
+     */
+    this.member = data.member ? this.guild?.members._add(data.member) ?? data.member : null;
+
+    /**
+     * The version
+     * @type {number}
+     */
+    this.version = data.version;
+
+    /**
+     * Set of permissions the application or bot has within the channel the interaction was sent from
+     * @type {?Readonly<PermissionsBitField>}
+     */
+    this.appPermissions = data.app_permissions ? new PermissionsBitField(data.app_permissions).freeze() : null;
+
+    /**
+     * The permissions of the member, if one exists, in the channel this interaction was executed in
+     * @type {?Readonly<PermissionsBitField>}
+     */
+    this.memberPermissions = data.member?.permissions
+      ? new PermissionsBitField(data.member.permissions).freeze()
+      : null;
+
+    /**
+     * A Discord locale string, possible values are:
+     * * en-US (English, US)
+     * * en-GB (English, UK)
+     * * bg (Bulgarian)
+     * * zh-CN (Chinese, China)
+     * * zh-TW (Chinese, Taiwan)
+     * * hr (Croatian)
+     * * cs (Czech)
+     * * da (Danish)
+     * * nl (Dutch)
+     * * fi (Finnish)
+     * * fr (French)
+     * * de (German)
+     * * el (Greek)
+     * * hi (Hindi)
+     * * hu (Hungarian)
+     * * it (Italian)
+     * * ja (Japanese)
+     * * ko (Korean)
+     * * lt (Lithuanian)
+     * * no (Norwegian)
+     * * pl (Polish)
+     * * pt-BR (Portuguese, Brazilian)
+     * * ro (Romanian, Romania)
+     * * ru (Russian)
+     * * es-ES (Spanish)
+     * * sv-SE (Swedish)
+     * * th (Thai)
+     * * tr (Turkish)
+     * * uk (Ukrainian)
+     * * vi (Vietnamese)
+     * @see {@link https://discord.com/developers/docs/reference#locales}
+     * @typedef {string} Locale
+     */
+
+    /**
+     * The locale of the user who invoked this interaction
+     * @type {Locale}
+     */
+    this.locale = data.locale;
+
+    /**
+     * The preferred locale from the guild this interaction was sent in
+     * @type {?Locale}
+     */
+    this.guildLocale = data.guild_locale ?? null;
+  }
+
+  /**
+   * The timestamp the interaction was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the interaction was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The channel this interaction was sent in
+   * @type {?TextBasedChannels}
+   * @readonly
+   */
+  get channel() {
+    return this.client.channels.cache.get(this.channelId) ?? null;
+  }
+
+  /**
+   * The guild this interaction was sent in
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.cache.get(this.guildId) ?? null;
+  }
+
+  /**
+   * Indicates whether this interaction is received from a guild.
+   * @returns {boolean}
+   */
+  inGuild() {
+    return Boolean(this.guildId && this.member);
+  }
+
+  /**
+   * Indicates whether or not this interaction is both cached and received from a guild.
+   * @returns {boolean}
+   */
+  inCachedGuild() {
+    return Boolean(this.guild && this.member);
+  }
+
+  /**
+   * Indicates whether or not this interaction is received from an uncached guild.
+   * @returns {boolean}
+   */
+  inRawGuild() {
+    return Boolean(this.guildId && !this.guild && this.member);
+  }
+
+  /**
+   * Indicates whether this interaction is an {@link AutocompleteInteraction}
+   * @returns {boolean}
+   */
+  isAutocomplete() {
+    return this.type === InteractionType.ApplicationCommandAutocomplete;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link CommandInteraction}
+   * @returns {boolean}
+   */
+  isCommand() {
+    return this.type === InteractionType.ApplicationCommand;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link ChatInputCommandInteraction}.
+   * @returns {boolean}
+   */
+  isChatInputCommand() {
+    return this.type === InteractionType.ApplicationCommand && this.commandType === ApplicationCommandType.ChatInput;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link ContextMenuCommandInteraction}
+   * @returns {boolean}
+   */
+  isContextMenuCommand() {
+    return (
+      this.type === InteractionType.ApplicationCommand &&
+      [ApplicationCommandType.User, ApplicationCommandType.Message].includes(this.commandType)
+    );
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link MessageComponentInteraction}
+   * @returns {boolean}
+   */
+  isMessageComponent() {
+    return this.type === InteractionType.MessageComponent;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link ModalSubmitInteraction}
+   * @returns {boolean}
+   */
+  isModalSubmit() {
+    return this.type === InteractionType.ModalSubmit;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link UserContextMenuCommandInteraction}
+   * @returns {boolean}
+   */
+  isUserContextMenuCommand() {
+    return this.isContextMenuCommand() && this.commandType === ApplicationCommandType.User;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link MessageContextMenuCommandInteraction}
+   * @returns {boolean}
+   */
+  isMessageContextMenuCommand() {
+    return this.isContextMenuCommand() && this.commandType === ApplicationCommandType.Message;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link ButtonInteraction}.
+   * @returns {boolean}
+   */
+  isButton() {
+    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.Button;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link StringSelectMenuInteraction}.
+   * @returns {boolean}
+   * @deprecated Use {@link BaseInteraction#isStringSelectMenu} instead.
+   */
+  isSelectMenu() {
+    return this.isStringSelectMenu();
+  }
+
+  /**
+   * Indicates whether this interaction is a select menu of any known type.
+   * @returns {boolean}
+   */
+  isAnySelectMenu() {
+    return this.type === InteractionType.MessageComponent && SelectMenuTypes.includes(this.componentType);
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link StringSelectMenuInteraction}.
+   * @returns {boolean}
+   */
+  isStringSelectMenu() {
+    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.StringSelect;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link UserSelectMenuInteraction}
+   * @returns {boolean}
+   */
+  isUserSelectMenu() {
+    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.UserSelect;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link RoleSelectMenuInteraction}
+   * @returns {boolean}
+   */
+  isRoleSelectMenu() {
+    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.RoleSelect;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link ChannelSelectMenuInteraction}
+   * @returns {boolean}
+   */
+  isChannelSelectMenu() {
+    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.ChannelSelect;
+  }
+
+  /**
+   * Indicates whether this interaction is a {@link MentionableSelectMenuInteraction}
+   * @returns {boolean}
+   */
+  isMentionableSelectMenu() {
+    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.MentionableSelect;
+  }
+
+  /**
+   * Indicates whether this interaction can be replied to.
+   * @returns {boolean}
+   */
+  isRepliable() {
+    return ![InteractionType.Ping, InteractionType.ApplicationCommandAutocomplete].includes(this.type);
+  }
+}
+
+BaseInteraction.prototype.isSelectMenu = deprecate(
+  BaseInteraction.prototype.isSelectMenu,
+  'BaseInteraction#isSelectMenu() is deprecated. Use BaseInteraction#isStringSelectMenu() instead.',
+);
+
+module.exports = BaseInteraction;
diff --git a/node_modules/discord.js/src/structures/BaseSelectMenuComponent.js b/node_modules/discord.js/src/structures/BaseSelectMenuComponent.js
new file mode 100644
index 0000000..7177f43
--- /dev/null
+++ b/node_modules/discord.js/src/structures/BaseSelectMenuComponent.js
@@ -0,0 +1,56 @@
+'use strict';
+
+const Component = require('./Component');
+
+/**
+ * Represents a select menu component
+ * @extends {Component}
+ */
+class BaseSelectMenuComponent extends Component {
+  /**
+   * The placeholder for this select menu
+   * @type {?string}
+   * @readonly
+   */
+  get placeholder() {
+    return this.data.placeholder ?? null;
+  }
+
+  /**
+   * The maximum amount of options that can be selected
+   * @type {?number}
+   * @readonly
+   */
+  get maxValues() {
+    return this.data.max_values ?? null;
+  }
+
+  /**
+   * The minimum amount of options that must be selected
+   * @type {?number}
+   * @readonly
+   */
+  get minValues() {
+    return this.data.min_values ?? null;
+  }
+
+  /**
+   * The custom id of this select menu
+   * @type {string}
+   * @readonly
+   */
+  get customId() {
+    return this.data.custom_id;
+  }
+
+  /**
+   * Whether this select menu is disabled
+   * @type {boolean}
+   * @readonly
+   */
+  get disabled() {
+    return this.data.disabled ?? false;
+  }
+}
+
+module.exports = BaseSelectMenuComponent;
diff --git a/node_modules/discord.js/src/structures/ButtonBuilder.js b/node_modules/discord.js/src/structures/ButtonBuilder.js
new file mode 100644
index 0000000..ada4188
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ButtonBuilder.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const { ButtonBuilder: BuildersButton } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+const { resolvePartialEmoji } = require('../util/Util');
+
+/**
+ * Represents a button builder.
+ * @extends {BuildersButton}
+ */
+class ButtonBuilder extends BuildersButton {
+  constructor({ emoji, ...data } = {}) {
+    super(toSnakeCase({ ...data, emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji }));
+  }
+
+  /**
+   * Sets the emoji to display on this button
+   * @param {string|APIMessageComponentEmoji} emoji The emoji to display on this button
+   * @returns {ButtonBuilder}
+   */
+  setEmoji(emoji) {
+    if (typeof emoji === 'string') {
+      return super.setEmoji(resolvePartialEmoji(emoji));
+    }
+    return super.setEmoji(emoji);
+  }
+
+  /**
+   * Creates a new button builder from JSON data
+   * @param {ButtonBuilder|ButtonComponent|APIButtonComponent} other The other data
+   * @returns {ButtonBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = ButtonBuilder;
+
+/**
+ * @external BuildersButton
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/ButtonBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/ButtonComponent.js b/node_modules/discord.js/src/structures/ButtonComponent.js
new file mode 100644
index 0000000..7319c3a
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ButtonComponent.js
@@ -0,0 +1,65 @@
+'use strict';
+
+const Component = require('./Component');
+
+/**
+ * Represents a button component
+ * @extends {Component}
+ */
+class ButtonComponent extends Component {
+  /**
+   * The style of this button
+   * @type {ButtonStyle}
+   * @readonly
+   */
+  get style() {
+    return this.data.style;
+  }
+
+  /**
+   * The label of this button
+   * @type {?string}
+   * @readonly
+   */
+  get label() {
+    return this.data.label ?? null;
+  }
+
+  /**
+   * The emoji used in this button
+   * @type {?APIMessageComponentEmoji}
+   * @readonly
+   */
+  get emoji() {
+    return this.data.emoji ?? null;
+  }
+
+  /**
+   * Whether this button is disabled
+   * @type {boolean}
+   * @readonly
+   */
+  get disabled() {
+    return this.data.disabled ?? false;
+  }
+
+  /**
+   * The custom id of this button (only defined on non-link buttons)
+   * @type {?string}
+   * @readonly
+   */
+  get customId() {
+    return this.data.custom_id ?? null;
+  }
+
+  /**
+   * The URL of this button (only defined on link buttons)
+   * @type {?string}
+   * @readonly
+   */
+  get url() {
+    return this.data.url ?? null;
+  }
+}
+
+module.exports = ButtonComponent;
diff --git a/node_modules/discord.js/src/structures/ButtonInteraction.js b/node_modules/discord.js/src/structures/ButtonInteraction.js
new file mode 100644
index 0000000..db57592
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ButtonInteraction.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const MessageComponentInteraction = require('./MessageComponentInteraction');
+
+/**
+ * Represents a button interaction.
+ * @extends {MessageComponentInteraction}
+ */
+class ButtonInteraction extends MessageComponentInteraction {}
+
+module.exports = ButtonInteraction;
diff --git a/node_modules/discord.js/src/structures/CategoryChannel.js b/node_modules/discord.js/src/structures/CategoryChannel.js
new file mode 100644
index 0000000..d038044
--- /dev/null
+++ b/node_modules/discord.js/src/structures/CategoryChannel.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const GuildChannel = require('./GuildChannel');
+const CategoryChannelChildManager = require('../managers/CategoryChannelChildManager');
+
+/**
+ * Represents a guild category channel on Discord.
+ * @extends {GuildChannel}
+ */
+class CategoryChannel extends GuildChannel {
+  /**
+   * The id of the parent of this channel.
+   * @name CategoryChannel#parentId
+   * @type {null}
+   */
+
+  /**
+   * The parent of this channel.
+   * @name CategoryChannel#parent
+   * @type {null}
+   * @readonly
+   */
+
+  /**
+   * Sets the category parent of this channel.
+   * <warn>It is not possible to set the parent of a CategoryChannel.</warn>
+   * @method setParent
+   * @memberof CategoryChannel
+   * @instance
+   * @param {?CategoryChannelResolvable} channel The channel to set as parent
+   * @param {SetParentOptions} [options={}] The options for setting the parent
+   * @returns {Promise<GuildChannel>}
+   */
+
+  /**
+   * A manager of the channels belonging to this category
+   * @type {CategoryChannelChildManager}
+   * @readonly
+   */
+  get children() {
+    return new CategoryChannelChildManager(this);
+  }
+}
+
+module.exports = CategoryChannel;
diff --git a/node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js b/node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js
new file mode 100644
index 0000000..6d99474
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const { ChannelSelectMenuBuilder: BuildersChannelSelectMenu } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+
+/**
+ * Class used to build select menu components to be sent through the API
+ * @extends {BuildersChannelSelectMenu}
+ */
+class ChannelSelectMenuBuilder extends BuildersChannelSelectMenu {
+  constructor(data = {}) {
+    super(toSnakeCase(data));
+  }
+
+  /**
+   * Creates a new select menu builder from JSON data
+   * @param {ChannelSelectMenuBuilder|ChannelSelectMenuComponent|APIChannelSelectComponent} other The other data
+   * @returns {ChannelSelectMenuBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = ChannelSelectMenuBuilder;
+
+/**
+ * @external BuildersChannelSelectMenu
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/ChannelSelectMenuBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js b/node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js
new file mode 100644
index 0000000..90a7063
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
+
+/**
+ * Represents a channel select menu component
+ * @extends {BaseSelectMenuComponent}
+ */
+class ChannelSelectMenuComponent extends BaseSelectMenuComponent {
+  /**
+   * The options in this select menu
+   * @type {?(ChannelType[])}
+   * @readonly
+   */
+  get channelTypes() {
+    return this.data.channel_types ?? null;
+  }
+}
+
+module.exports = ChannelSelectMenuComponent;
diff --git a/node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js b/node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js
new file mode 100644
index 0000000..a5e9c99
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js
@@ -0,0 +1,33 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const MessageComponentInteraction = require('./MessageComponentInteraction');
+
+/**
+ * Represents a {@link ComponentType.ChannelSelect} select menu interaction.
+ * @extends {MessageComponentInteraction}
+ */
+class ChannelSelectMenuInteraction extends MessageComponentInteraction {
+  constructor(client, data) {
+    super(client, data);
+    const { resolved, values } = data.data;
+
+    /**
+     * An array of the selected channel ids
+     * @type {Snowflake[]}
+     */
+    this.values = values ?? [];
+
+    /**
+     * Collection of the selected channels
+     * @type {Collection<Snowflake, BaseChannel|APIChannel>}
+     */
+    this.channels = new Collection();
+
+    for (const channel of Object.values(resolved?.channels ?? {})) {
+      this.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel);
+    }
+  }
+}
+
+module.exports = ChannelSelectMenuInteraction;
diff --git a/node_modules/discord.js/src/structures/ChatInputCommandInteraction.js b/node_modules/discord.js/src/structures/ChatInputCommandInteraction.js
new file mode 100644
index 0000000..35175e4
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ChatInputCommandInteraction.js
@@ -0,0 +1,41 @@
+'use strict';
+
+const CommandInteraction = require('./CommandInteraction');
+const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
+
+/**
+ * Represents a command interaction.
+ * @extends {CommandInteraction}
+ */
+class ChatInputCommandInteraction extends CommandInteraction {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * The options passed to the command.
+     * @type {CommandInteractionOptionResolver}
+     */
+    this.options = new CommandInteractionOptionResolver(
+      this.client,
+      data.data.options?.map(option => this.transformOption(option, data.data.resolved)) ?? [],
+      this.transformResolved(data.data.resolved ?? {}),
+    );
+  }
+
+  /**
+   * Returns a string representation of the command interaction.
+   * This can then be copied by a user and executed again in a new command while keeping the option order.
+   * @returns {string}
+   */
+  toString() {
+    const properties = [
+      this.commandName,
+      this.options._group,
+      this.options._subcommand,
+      ...this.options._hoistedOptions.map(o => `${o.name}:${o.value}`),
+    ];
+    return `/${properties.filter(Boolean).join(' ')}`;
+  }
+}
+
+module.exports = ChatInputCommandInteraction;
diff --git a/node_modules/discord.js/src/structures/ClientApplication.js b/node_modules/discord.js/src/structures/ClientApplication.js
new file mode 100644
index 0000000..69f5134
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ClientApplication.js
@@ -0,0 +1,222 @@
+'use strict';
+
+const { Routes } = require('discord-api-types/v10');
+const { ApplicationRoleConnectionMetadata } = require('./ApplicationRoleConnectionMetadata');
+const Team = require('./Team');
+const Application = require('./interfaces/Application');
+const ApplicationCommandManager = require('../managers/ApplicationCommandManager');
+const ApplicationFlagsBitField = require('../util/ApplicationFlagsBitField');
+const PermissionsBitField = require('../util/PermissionsBitField');
+
+/**
+ * @typedef {Object} ClientApplicationInstallParams
+ * @property {OAuth2Scopes[]} scopes The scopes to add the application to the server with
+ * @property {Readonly<PermissionsBitField>} permissions The permissions this bot will request upon joining
+ */
+
+/**
+ * Represents a client application.
+ * @extends {Application}
+ */
+class ClientApplication extends Application {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * The application command manager for this application
+     * @type {ApplicationCommandManager}
+     */
+    this.commands = new ApplicationCommandManager(this.client);
+  }
+
+  _patch(data) {
+    super._patch(data);
+
+    /**
+     * The tags this application has (max of 5)
+     * @type {string[]}
+     */
+    this.tags = data.tags ?? [];
+
+    if ('install_params' in data) {
+      /**
+       * Settings for this application's default in-app authorization
+       * @type {?ClientApplicationInstallParams}
+       */
+      this.installParams = {
+        scopes: data.install_params.scopes,
+        permissions: new PermissionsBitField(data.install_params.permissions).freeze(),
+      };
+    } else {
+      this.installParams ??= null;
+    }
+
+    if ('custom_install_url' in data) {
+      /**
+       * This application's custom installation URL
+       * @type {?string}
+       */
+      this.customInstallURL = data.custom_install_url;
+    } else {
+      this.customInstallURL = null;
+    }
+
+    if ('flags' in data) {
+      /**
+       * The flags this application has
+       * @type {ApplicationFlagsBitField}
+       */
+      this.flags = new ApplicationFlagsBitField(data.flags).freeze();
+    }
+
+    if ('approximate_guild_count' in data) {
+      /**
+       * An approximate amount of guilds this application is in.
+       * @type {?number}
+       */
+      this.approximateGuildCount = data.approximate_guild_count;
+    } else {
+      this.approximateGuildCount ??= null;
+    }
+
+    if ('guild_id' in data) {
+      /**
+       * The id of the guild associated with this application.
+       * @type {?Snowflake}
+       */
+      this.guildId = data.guild_id;
+    } else {
+      this.guildId ??= null;
+    }
+
+    if ('cover_image' in data) {
+      /**
+       * The hash of the application's cover image
+       * @type {?string}
+       */
+      this.cover = data.cover_image;
+    } else {
+      this.cover ??= null;
+    }
+
+    if ('rpc_origins' in data) {
+      /**
+       * The application's RPC origins, if enabled
+       * @type {string[]}
+       */
+      this.rpcOrigins = data.rpc_origins;
+    } else {
+      this.rpcOrigins ??= [];
+    }
+
+    if ('bot_require_code_grant' in data) {
+      /**
+       * If this application's bot requires a code grant when using the OAuth2 flow
+       * @type {?boolean}
+       */
+      this.botRequireCodeGrant = data.bot_require_code_grant;
+    } else {
+      this.botRequireCodeGrant ??= null;
+    }
+
+    if ('bot_public' in data) {
+      /**
+       * If this application's bot is public
+       * @type {?boolean}
+       */
+      this.botPublic = data.bot_public;
+    } else {
+      this.botPublic ??= null;
+    }
+
+    if ('role_connections_verification_url' in data) {
+      /**
+       * This application's role connection verification entry point URL
+       * @type {?string}
+       */
+      this.roleConnectionsVerificationURL = data.role_connections_verification_url;
+    } else {
+      this.roleConnectionsVerificationURL ??= null;
+    }
+
+    /**
+     * The owner of this OAuth application
+     * @type {?(User|Team)}
+     */
+    this.owner = data.team
+      ? new Team(this.client, data.team)
+      : data.owner
+      ? this.client.users._add(data.owner)
+      : this.owner ?? null;
+  }
+
+  /**
+   * The guild associated with this application.
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.cache.get(this.guildId) ?? null;
+  }
+
+  /**
+   * Whether this application is partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return !this.name;
+  }
+
+  /**
+   * Obtains this application from Discord.
+   * @returns {Promise<ClientApplication>}
+   */
+  async fetch() {
+    const data = await this.client.rest.get(Routes.currentApplication());
+    this._patch(data);
+    return this;
+  }
+
+  /**
+   * Gets this application's role connection metadata records
+   * @returns {Promise<ApplicationRoleConnectionMetadata[]>}
+   */
+  async fetchRoleConnectionMetadataRecords() {
+    const metadata = await this.client.rest.get(Routes.applicationRoleConnectionMetadata(this.client.user.id));
+    return metadata.map(data => new ApplicationRoleConnectionMetadata(data));
+  }
+
+  /**
+   * Data for creating or editing an application role connection metadata.
+   * @typedef {Object} ApplicationRoleConnectionMetadataEditOptions
+   * @property {string} name The name of the metadata field
+   * @property {?Object<Locale, string>} [nameLocalizations] The name localizations for the metadata field
+   * @property {string} description The description of the metadata field
+   * @property {?Object<Locale, string>} [descriptionLocalizations] The description localizations for the metadata field
+   * @property {string} key The dictionary key of the metadata field
+   * @property {ApplicationRoleConnectionMetadataType} type The type of the metadata field
+   */
+
+  /**
+   * Updates this application's role connection metadata records
+   * @param {ApplicationRoleConnectionMetadataEditOptions[]} records The new role connection metadata records
+   * @returns {Promise<ApplicationRoleConnectionMetadata[]>}
+   */
+  async editRoleConnectionMetadataRecords(records) {
+    const newRecords = await this.client.rest.put(Routes.applicationRoleConnectionMetadata(this.client.user.id), {
+      body: records.map(record => ({
+        type: record.type,
+        key: record.key,
+        name: record.name,
+        name_localizations: record.nameLocalizations,
+        description: record.description,
+        description_localizations: record.descriptionLocalizations,
+      })),
+    });
+
+    return newRecords.map(data => new ApplicationRoleConnectionMetadata(data));
+  }
+}
+
+module.exports = ClientApplication;
diff --git a/node_modules/discord.js/src/structures/ClientPresence.js b/node_modules/discord.js/src/structures/ClientPresence.js
new file mode 100644
index 0000000..6dd72ee
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ClientPresence.js
@@ -0,0 +1,90 @@
+'use strict';
+
+const { GatewayOpcodes, ActivityType } = require('discord-api-types/v10');
+const { Presence } = require('./Presence');
+const { DiscordjsTypeError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents the client's presence.
+ * @extends {Presence}
+ */
+class ClientPresence extends Presence {
+  constructor(client, data = {}) {
+    super(client, Object.assign(data, { status: data.status ?? 'online', user: { id: null } }));
+  }
+
+  /**
+   * Sets the client's presence
+   * @param {PresenceData} presence The data to set the presence to
+   * @returns {ClientPresence}
+   */
+  set(presence) {
+    const packet = this._parse(presence);
+    this._patch(packet);
+    if (presence.shardId === undefined) {
+      this.client.ws.broadcast({ op: GatewayOpcodes.PresenceUpdate, d: packet });
+    } else if (Array.isArray(presence.shardId)) {
+      for (const shardId of presence.shardId) {
+        this.client.ws.shards.get(shardId).send({ op: GatewayOpcodes.PresenceUpdate, d: packet });
+      }
+    } else {
+      this.client.ws.shards.get(presence.shardId).send({ op: GatewayOpcodes.PresenceUpdate, d: packet });
+    }
+    return this;
+  }
+
+  /**
+   * Parses presence data into a packet ready to be sent to Discord
+   * @param {PresenceData} presence The data to parse
+   * @returns {APIPresence}
+   * @private
+   */
+  _parse({ status, since, afk, activities }) {
+    const data = {
+      activities: [],
+      afk: typeof afk === 'boolean' ? afk : false,
+      since: typeof since === 'number' && !Number.isNaN(since) ? since : null,
+      status: status ?? this.status,
+    };
+    if (activities?.length) {
+      for (const [i, activity] of activities.entries()) {
+        if (typeof activity.name !== 'string') {
+          throw new DiscordjsTypeError(ErrorCodes.InvalidType, `activities[${i}].name`, 'string');
+        }
+
+        activity.type ??= ActivityType.Playing;
+
+        if (activity.type === ActivityType.Custom && !activity.state) {
+          activity.state = activity.name;
+          activity.name = 'Custom Status';
+        }
+
+        data.activities.push({
+          type: activity.type,
+          name: activity.name,
+          state: activity.state,
+          url: activity.url,
+        });
+      }
+    } else if (!activities && (status || afk || since) && this.activities.length) {
+      data.activities.push(
+        ...this.activities.map(a => ({
+          name: a.name,
+          state: a.state ?? undefined,
+          type: a.type,
+          url: a.url ?? undefined,
+        })),
+      );
+    }
+
+    return data;
+  }
+}
+
+module.exports = ClientPresence;
+
+/* eslint-disable max-len */
+/**
+ * @external APIPresence
+ * @see {@link https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields}
+ */
diff --git a/node_modules/discord.js/src/structures/ClientUser.js b/node_modules/discord.js/src/structures/ClientUser.js
new file mode 100644
index 0000000..b93904c
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ClientUser.js
@@ -0,0 +1,187 @@
+'use strict';
+
+const { Routes } = require('discord-api-types/v10');
+const User = require('./User');
+const DataResolver = require('../util/DataResolver');
+
+/**
+ * Represents the logged in client's Discord user.
+ * @extends {User}
+ */
+class ClientUser extends User {
+  _patch(data) {
+    super._patch(data);
+
+    if ('verified' in data) {
+      /**
+       * Whether or not this account has been verified
+       * @type {boolean}
+       */
+      this.verified = data.verified;
+    }
+
+    if ('mfa_enabled' in data) {
+      /**
+       * If the bot's {@link ClientApplication#owner Owner} has MFA enabled on their account
+       * @type {?boolean}
+       */
+      this.mfaEnabled = typeof data.mfa_enabled === 'boolean' ? data.mfa_enabled : null;
+    } else {
+      this.mfaEnabled ??= null;
+    }
+
+    if ('token' in data) this.client.token = data.token;
+  }
+
+  /**
+   * Represents the client user's presence
+   * @type {ClientPresence}
+   * @readonly
+   */
+  get presence() {
+    return this.client.presence;
+  }
+
+  /**
+   * Data used to edit the logged in client
+   * @typedef {Object} ClientUserEditOptions
+   * @property {string} [username] The new username
+   * @property {?(BufferResolvable|Base64Resolvable)} [avatar] The new avatar
+   */
+
+  /**
+   * Edits the logged in client.
+   * @param {ClientUserEditOptions} options The options to provide
+   * @returns {Promise<ClientUser>}
+   */
+  async edit({ username, avatar }) {
+    const data = await this.client.rest.patch(Routes.user(), {
+      body: { username, avatar: avatar && (await DataResolver.resolveImage(avatar)) },
+    });
+
+    this.client.token = data.token;
+    this.client.rest.setToken(data.token);
+    const { updated } = this.client.actions.UserUpdate.handle(data);
+    return updated ?? this;
+  }
+
+  /**
+   * Sets the username of the logged in client.
+   * <info>Changing usernames in Discord is heavily rate limited, with only 2 requests
+   * every hour. Use this sparingly!</info>
+   * @param {string} username The new username
+   * @returns {Promise<ClientUser>}
+   * @example
+   * // Set username
+   * client.user.setUsername('discordjs')
+   *   .then(user => console.log(`My new username is ${user.username}`))
+   *   .catch(console.error);
+   */
+  setUsername(username) {
+    return this.edit({ username });
+  }
+
+  /**
+   * Sets the avatar of the logged in client.
+   * @param {?(BufferResolvable|Base64Resolvable)} avatar The new avatar
+   * @returns {Promise<ClientUser>}
+   * @example
+   * // Set avatar
+   * client.user.setAvatar('./avatar.png')
+   *   .then(user => console.log(`New avatar set!`))
+   *   .catch(console.error);
+   */
+  setAvatar(avatar) {
+    return this.edit({ avatar });
+  }
+
+  /**
+   * Options for setting activities
+   * @typedef {Object} ActivitiesOptions
+   * @property {string} name Name of the activity
+   * @property {string} [state] State of the activity
+   * @property {ActivityType} [type] Type of the activity
+   * @property {string} [url] Twitch / YouTube stream URL
+   */
+
+  /**
+   * Data resembling a raw Discord presence.
+   * @typedef {Object} PresenceData
+   * @property {PresenceStatusData} [status] Status of the user
+   * @property {boolean} [afk] Whether the user is AFK
+   * @property {ActivitiesOptions[]} [activities] Activity the user is playing
+   * @property {number|number[]} [shardId] Shard id(s) to have the activity set on
+   */
+
+  /**
+   * Sets the full presence of the client user.
+   * @param {PresenceData} data Data for the presence
+   * @returns {ClientPresence}
+   * @example
+   * // Set the client user's presence
+   * client.user.setPresence({ activities: [{ name: 'with discord.js' }], status: 'idle' });
+   */
+  setPresence(data) {
+    return this.client.presence.set(data);
+  }
+
+  /**
+   * A user's status. Must be one of:
+   * * `online`
+   * * `idle`
+   * * `invisible`
+   * * `dnd` (do not disturb)
+   * @typedef {string} PresenceStatusData
+   */
+
+  /**
+   * Sets the status of the client user.
+   * @param {PresenceStatusData} status Status to change to
+   * @param {number|number[]} [shardId] Shard id(s) to have the activity set on
+   * @returns {ClientPresence}
+   * @example
+   * // Set the client user's status
+   * client.user.setStatus('idle');
+   */
+  setStatus(status, shardId) {
+    return this.setPresence({ status, shardId });
+  }
+
+  /**
+   * Options for setting an activity.
+   * @typedef {Object} ActivityOptions
+   * @property {string} name Name of the activity
+   * @property {string} [state] State of the activity
+   * @property {string} [url] Twitch / YouTube stream URL
+   * @property {ActivityType} [type] Type of the activity
+   * @property {number|number[]} [shardId] Shard Id(s) to have the activity set on
+   */
+
+  /**
+   * Sets the activity the client user is playing.
+   * @param {string|ActivityOptions} name Activity being played, or options for setting the activity
+   * @param {ActivityOptions} [options] Options for setting the activity
+   * @returns {ClientPresence}
+   * @example
+   * // Set the client user's activity
+   * client.user.setActivity('discord.js', { type: ActivityType.Watching });
+   */
+  setActivity(name, options = {}) {
+    if (!name) return this.setPresence({ activities: [], shardId: options.shardId });
+
+    const activity = Object.assign({}, options, typeof name === 'object' ? name : { name });
+    return this.setPresence({ activities: [activity], shardId: activity.shardId });
+  }
+
+  /**
+   * Sets/removes the AFK flag for the client user.
+   * @param {boolean} [afk=true] Whether or not the user is AFK
+   * @param {number|number[]} [shardId] Shard Id(s) to have the AFK flag set on
+   * @returns {ClientPresence}
+   */
+  setAFK(afk = true, shardId) {
+    return this.setPresence({ afk, shardId });
+  }
+}
+
+module.exports = ClientUser;
diff --git a/node_modules/discord.js/src/structures/CommandInteraction.js b/node_modules/discord.js/src/structures/CommandInteraction.js
new file mode 100644
index 0000000..ec6ef40
--- /dev/null
+++ b/node_modules/discord.js/src/structures/CommandInteraction.js
@@ -0,0 +1,224 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Attachment = require('./Attachment');
+const BaseInteraction = require('./BaseInteraction');
+const InteractionWebhook = require('./InteractionWebhook');
+const InteractionResponses = require('./interfaces/InteractionResponses');
+
+/**
+ * Represents a command interaction.
+ * @extends {BaseInteraction}
+ * @implements {InteractionResponses}
+ * @abstract
+ */
+class CommandInteraction extends BaseInteraction {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * The id of the channel this interaction was sent in
+     * @type {Snowflake}
+     * @name CommandInteraction#channelId
+     */
+
+    /**
+     * The invoked application command's id
+     * @type {Snowflake}
+     */
+    this.commandId = data.data.id;
+
+    /**
+     * The invoked application command's name
+     * @type {string}
+     */
+    this.commandName = data.data.name;
+
+    /**
+     * The invoked application command's type
+     * @type {ApplicationCommandType}
+     */
+    this.commandType = data.data.type;
+
+    /**
+     * The id of the guild the invoked application command is registered to
+     * @type {?Snowflake}
+     */
+    this.commandGuildId = data.data.guild_id ?? null;
+
+    /**
+     * Whether the reply to this interaction has been deferred
+     * @type {boolean}
+     */
+    this.deferred = false;
+
+    /**
+     * Whether this interaction has already been replied to
+     * @type {boolean}
+     */
+    this.replied = false;
+
+    /**
+     * Whether the reply to this interaction is ephemeral
+     * @type {?boolean}
+     */
+    this.ephemeral = null;
+
+    /**
+     * An associated interaction webhook, can be used to further interact with this interaction
+     * @type {InteractionWebhook}
+     */
+    this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);
+  }
+
+  /**
+   * The invoked application command, if it was fetched before
+   * @type {?ApplicationCommand}
+   */
+  get command() {
+    const id = this.commandId;
+    return this.guild?.commands.cache.get(id) ?? this.client.application.commands.cache.get(id) ?? null;
+  }
+
+  /**
+   * Represents the resolved data of a received command interaction.
+   * @typedef {Object} CommandInteractionResolvedData
+   * @property {Collection<Snowflake, User>} [users] The resolved users
+   * @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved guild members
+   * @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles
+   * @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels
+   * @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages
+   * @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
+   */
+
+  /**
+   * Transforms the resolved received from the API.
+   * @param {APIInteractionDataResolved} resolved The received resolved objects
+   * @returns {CommandInteractionResolvedData}
+   * @private
+   */
+  transformResolved({ members, users, channels, roles, messages, attachments }) {
+    const result = {};
+
+    if (members) {
+      result.members = new Collection();
+      for (const [id, member] of Object.entries(members)) {
+        const user = users[id];
+        result.members.set(id, this.guild?.members._add({ user, ...member }) ?? member);
+      }
+    }
+
+    if (users) {
+      result.users = new Collection();
+      for (const user of Object.values(users)) {
+        result.users.set(user.id, this.client.users._add(user));
+      }
+    }
+
+    if (roles) {
+      result.roles = new Collection();
+      for (const role of Object.values(roles)) {
+        result.roles.set(role.id, this.guild?.roles._add(role) ?? role);
+      }
+    }
+
+    if (channels) {
+      result.channels = new Collection();
+      for (const channel of Object.values(channels)) {
+        result.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel);
+      }
+    }
+
+    if (messages) {
+      result.messages = new Collection();
+      for (const message of Object.values(messages)) {
+        result.messages.set(message.id, this.channel?.messages?._add(message) ?? message);
+      }
+    }
+
+    if (attachments) {
+      result.attachments = new Collection();
+      for (const attachment of Object.values(attachments)) {
+        const patched = new Attachment(attachment);
+        result.attachments.set(attachment.id, patched);
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Represents an option of a received command interaction.
+   * @typedef {Object} CommandInteractionOption
+   * @property {string} name The name of the option
+   * @property {ApplicationCommandOptionType} type The type of the option
+   * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a
+   * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or
+   * {@link ApplicationCommandOptionType.Number} option
+   * @property {string|number|boolean} [value] The value of the option
+   * @property {CommandInteractionOption[]} [options] Additional options if this option is a
+   * subcommand (group)
+   * @property {User} [user] The resolved user
+   * @property {GuildMember|APIGuildMember} [member] The resolved member
+   * @property {GuildChannel|ThreadChannel|APIChannel} [channel] The resolved channel
+   * @property {Role|APIRole} [role] The resolved role
+   * @property {Attachment} [attachment] The resolved attachment
+   */
+
+  /**
+   * Transforms an option received from the API.
+   * @param {APIApplicationCommandOption} option The received option
+   * @param {APIInteractionDataResolved} resolved The resolved interaction data
+   * @returns {CommandInteractionOption}
+   * @private
+   */
+  transformOption(option, resolved) {
+    const result = {
+      name: option.name,
+      type: option.type,
+    };
+
+    if ('value' in option) result.value = option.value;
+    if ('options' in option) result.options = option.options.map(opt => this.transformOption(opt, resolved));
+
+    if (resolved) {
+      const user = resolved.users?.[option.value];
+      if (user) result.user = this.client.users._add(user);
+
+      const member = resolved.members?.[option.value];
+      if (member) result.member = this.guild?.members._add({ user, ...member }) ?? member;
+
+      const channel = resolved.channels?.[option.value];
+      if (channel) result.channel = this.client.channels._add(channel, this.guild) ?? channel;
+
+      const role = resolved.roles?.[option.value];
+      if (role) result.role = this.guild?.roles._add(role) ?? role;
+
+      const attachment = resolved.attachments?.[option.value];
+      if (attachment) result.attachment = new Attachment(attachment);
+    }
+
+    return result;
+  }
+
+  // These are here only for documentation purposes - they are implemented by InteractionResponses
+  /* eslint-disable no-empty-function */
+  deferReply() {}
+  reply() {}
+  fetchReply() {}
+  editReply() {}
+  deleteReply() {}
+  followUp() {}
+  showModal() {}
+  awaitModalSubmit() {}
+}
+
+InteractionResponses.applyToClass(CommandInteraction, ['deferUpdate', 'update']);
+
+module.exports = CommandInteraction;
+
+/* eslint-disable max-len */
+/**
+ * @external APIInteractionDataResolved
+ * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-resolved-data-structure}
+ */
diff --git a/node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js b/node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js
new file mode 100644
index 0000000..621dbf4
--- /dev/null
+++ b/node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js
@@ -0,0 +1,308 @@
+'use strict';
+
+const { ApplicationCommandOptionType } = require('discord-api-types/v10');
+const { DiscordjsTypeError, ErrorCodes } = require('../errors');
+
+/**
+ * A resolver for command interaction options.
+ */
+class CommandInteractionOptionResolver {
+  constructor(client, options, resolved) {
+    /**
+     * The client that instantiated this.
+     * @name CommandInteractionOptionResolver#client
+     * @type {Client}
+     * @readonly
+     */
+    Object.defineProperty(this, 'client', { value: client });
+
+    /**
+     * The name of the subcommand group.
+     * @type {?string}
+     * @private
+     */
+    this._group = null;
+
+    /**
+     * The name of the subcommand.
+     * @type {?string}
+     * @private
+     */
+    this._subcommand = null;
+
+    /**
+     * The bottom-level options for the interaction.
+     * If there is a subcommand (or subcommand and group), this is the options for the subcommand.
+     * @type {CommandInteractionOption[]}
+     * @private
+     */
+    this._hoistedOptions = options;
+
+    // Hoist subcommand group if present
+    if (this._hoistedOptions[0]?.type === ApplicationCommandOptionType.SubcommandGroup) {
+      this._group = this._hoistedOptions[0].name;
+      this._hoistedOptions = this._hoistedOptions[0].options ?? [];
+    }
+    // Hoist subcommand if present
+    if (this._hoistedOptions[0]?.type === ApplicationCommandOptionType.Subcommand) {
+      this._subcommand = this._hoistedOptions[0].name;
+      this._hoistedOptions = this._hoistedOptions[0].options ?? [];
+    }
+
+    /**
+     * The interaction options array.
+     * @name CommandInteractionOptionResolver#data
+     * @type {ReadonlyArray<CommandInteractionOption>}
+     * @readonly
+     */
+    Object.defineProperty(this, 'data', { value: Object.freeze([...options]) });
+
+    /**
+     * The interaction resolved data
+     * @name CommandInteractionOptionResolver#resolved
+     * @type {?Readonly<CommandInteractionResolvedData>}
+     */
+    Object.defineProperty(this, 'resolved', { value: resolved ? Object.freeze(resolved) : null });
+  }
+
+  /**
+   * Gets an option by its name.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?CommandInteractionOption} The option, if found.
+   */
+  get(name, required = false) {
+    const option = this._hoistedOptions.find(opt => opt.name === name);
+    if (!option) {
+      if (required) {
+        throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNotFound, name);
+      }
+      return null;
+    }
+    return option;
+  }
+
+  /**
+   * Gets an option by name and property and checks its type.
+   * @param {string} name The name of the option.
+   * @param {ApplicationCommandOptionType[]} allowedTypes The allowed types of the option.
+   * @param {string[]} properties The properties to check for for `required`.
+   * @param {boolean} required Whether to throw an error if the option is not found.
+   * @returns {?CommandInteractionOption} The option, if found.
+   * @private
+   */
+  _getTypedOption(name, allowedTypes, properties, required) {
+    const option = this.get(name, required);
+    if (!option) {
+      return null;
+    } else if (!allowedTypes.includes(option.type)) {
+      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionType, name, option.type, allowedTypes.join(', '));
+    } else if (required && properties.every(prop => option[prop] === null || option[prop] === undefined)) {
+      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionEmpty, name, option.type);
+    }
+    return option;
+  }
+
+  /**
+   * Gets the selected subcommand.
+   * @param {boolean} [required=true] Whether to throw an error if there is no subcommand.
+   * @returns {?string} The name of the selected subcommand, or null if not set and not required.
+   */
+  getSubcommand(required = true) {
+    if (required && !this._subcommand) {
+      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNoSubcommand);
+    }
+    return this._subcommand;
+  }
+
+  /**
+   * Gets the selected subcommand group.
+   * @param {boolean} [required=false] Whether to throw an error if there is no subcommand group.
+   * @returns {?string} The name of the selected subcommand group, or null if not set and not required.
+   */
+  getSubcommandGroup(required = false) {
+    if (required && !this._group) {
+      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNoSubcommandGroup);
+    }
+    return this._group;
+  }
+
+  /**
+   * Gets a boolean option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?boolean} The value of the option, or null if not set and not required.
+   */
+  getBoolean(name, required = false) {
+    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Boolean], ['value'], required);
+    return option?.value ?? null;
+  }
+
+  /**
+   * Gets a channel option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @param {ChannelType[]} [channelTypes=[]] The allowed types of channels. If empty, all channel types are allowed.
+   * @returns {?(GuildChannel|ThreadChannel|APIChannel)}
+   * The value of the option, or null if not set and not required.
+   */
+  getChannel(name, required = false, channelTypes = []) {
+    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Channel], ['channel'], required);
+    const channel = option?.channel ?? null;
+
+    if (channel && channelTypes.length > 0 && !channelTypes.includes(channel.type)) {
+      throw new DiscordjsTypeError(
+        ErrorCodes.CommandInteractionOptionInvalidChannelType,
+        name,
+        channel.type,
+        channelTypes.join(', '),
+      );
+    }
+
+    return channel;
+  }
+
+  /**
+   * Gets a string option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?string} The value of the option, or null if not set and not required.
+   */
+  getString(name, required = false) {
+    const option = this._getTypedOption(name, [ApplicationCommandOptionType.String], ['value'], required);
+    return option?.value ?? null;
+  }
+
+  /**
+   * Gets an integer option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?number} The value of the option, or null if not set and not required.
+   */
+  getInteger(name, required = false) {
+    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Integer], ['value'], required);
+    return option?.value ?? null;
+  }
+
+  /**
+   * Gets a number option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?number} The value of the option, or null if not set and not required.
+   */
+  getNumber(name, required = false) {
+    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Number], ['value'], required);
+    return option?.value ?? null;
+  }
+
+  /**
+   * Gets a user option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?User} The value of the option, or null if not set and not required.
+   */
+  getUser(name, required = false) {
+    const option = this._getTypedOption(
+      name,
+      [ApplicationCommandOptionType.User, ApplicationCommandOptionType.Mentionable],
+      ['user'],
+      required,
+    );
+    return option?.user ?? null;
+  }
+
+  /**
+   * Gets a member option.
+   * @param {string} name The name of the option.
+   * @returns {?(GuildMember|APIGuildMember)}
+   * The value of the option, or null if the user is not present in the guild or the option is not set.
+   */
+  getMember(name) {
+    const option = this._getTypedOption(
+      name,
+      [ApplicationCommandOptionType.User, ApplicationCommandOptionType.Mentionable],
+      ['member'],
+      false,
+    );
+    return option?.member ?? null;
+  }
+
+  /**
+   * Gets a role option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?(Role|APIRole)} The value of the option, or null if not set and not required.
+   */
+  getRole(name, required = false) {
+    const option = this._getTypedOption(
+      name,
+      [ApplicationCommandOptionType.Role, ApplicationCommandOptionType.Mentionable],
+      ['role'],
+      required,
+    );
+    return option?.role ?? null;
+  }
+
+  /**
+   * Gets an attachment option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?Attachment} The value of the option, or null if not set and not required.
+   */
+  getAttachment(name, required = false) {
+    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Attachment], ['attachment'], required);
+    return option?.attachment ?? null;
+  }
+
+  /**
+   * Gets a mentionable option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?(User|GuildMember|APIGuildMember|Role|APIRole)}
+   * The value of the option, or null if not set and not required.
+   */
+  getMentionable(name, required = false) {
+    const option = this._getTypedOption(
+      name,
+      [ApplicationCommandOptionType.Mentionable],
+      ['user', 'member', 'role'],
+      required,
+    );
+    return option?.member ?? option?.user ?? option?.role ?? null;
+  }
+
+  /**
+   * Gets a message option.
+   * @param {string} name The name of the option.
+   * @param {boolean} [required=false] Whether to throw an error if the option is not found.
+   * @returns {?Message}
+   * The value of the option, or null if not set and not required.
+   */
+  getMessage(name, required = false) {
+    const option = this._getTypedOption(name, ['_MESSAGE'], ['message'], required);
+    return option?.message ?? null;
+  }
+
+  /**
+   * The full autocomplete option object.
+   * @typedef {Object} AutocompleteFocusedOption
+   * @property {string} name The name of the option
+   * @property {ApplicationCommandOptionType} type The type of the application command option
+   * @property {string} value The value of the option
+   * @property {boolean} focused Whether this option is currently in focus for autocomplete
+   */
+
+  /**
+   * Gets the focused option.
+   * @param {boolean} [getFull=false] Whether to get the full option object
+   * @returns {string|AutocompleteFocusedOption}
+   * The value of the option, or the whole option if getFull is true
+   */
+  getFocused(getFull = false) {
+    const focusedOption = this._hoistedOptions.find(option => option.focused);
+    if (!focusedOption) throw new DiscordjsTypeError(ErrorCodes.AutocompleteInteractionOptionNoFocusedOption);
+    return getFull ? focusedOption : focusedOption.value;
+  }
+}
+
+module.exports = CommandInteractionOptionResolver;
diff --git a/node_modules/discord.js/src/structures/Component.js b/node_modules/discord.js/src/structures/Component.js
new file mode 100644
index 0000000..10ba27d
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Component.js
@@ -0,0 +1,47 @@
+'use strict';
+
+const isEqual = require('fast-deep-equal');
+
+/**
+ * Represents a component
+ */
+class Component {
+  constructor(data) {
+    /**
+     * The API data associated with this component
+     * @type {APIMessageComponent}
+     */
+    this.data = data;
+  }
+
+  /**
+   * The type of the component
+   * @type {ComponentType}
+   * @readonly
+   */
+  get type() {
+    return this.data.type;
+  }
+
+  /**
+   * Whether or not the given components are equal
+   * @param {Component|APIMessageComponent} other The component to compare against
+   * @returns {boolean}
+   */
+  equals(other) {
+    if (other instanceof Component) {
+      return isEqual(other.data, this.data);
+    }
+    return isEqual(other, this.data);
+  }
+
+  /**
+   * Returns the API-compatible JSON for this component
+   * @returns {APIMessageComponent}
+   */
+  toJSON() {
+    return { ...this.data };
+  }
+}
+
+module.exports = Component;
diff --git a/node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js b/node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js
new file mode 100644
index 0000000..fc49ca5
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js
@@ -0,0 +1,64 @@
+'use strict';
+
+const { lazy } = require('@discordjs/util');
+const { ApplicationCommandOptionType } = require('discord-api-types/v10');
+const CommandInteraction = require('./CommandInteraction');
+const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
+
+const getMessage = lazy(() => require('./Message').Message);
+
+/**
+ * Represents a context menu interaction.
+ * @extends {CommandInteraction}
+ */
+class ContextMenuCommandInteraction extends CommandInteraction {
+  constructor(client, data) {
+    super(client, data);
+    /**
+     * The target of the interaction, parsed into options
+     * @type {CommandInteractionOptionResolver}
+     */
+    this.options = new CommandInteractionOptionResolver(
+      this.client,
+      this.resolveContextMenuOptions(data.data),
+      this.transformResolved(data.data.resolved),
+    );
+
+    /**
+     * The id of the target of this interaction
+     * @type {Snowflake}
+     */
+    this.targetId = data.data.target_id;
+  }
+
+  /**
+   * Resolves and transforms options received from the API for a context menu interaction.
+   * @param {APIApplicationCommandInteractionData} data The interaction data
+   * @returns {CommandInteractionOption[]}
+   * @private
+   */
+  resolveContextMenuOptions({ target_id, resolved }) {
+    const result = [];
+
+    if (resolved.users?.[target_id]) {
+      result.push(
+        this.transformOption({ name: 'user', type: ApplicationCommandOptionType.User, value: target_id }, resolved),
+      );
+    }
+
+    if (resolved.messages?.[target_id]) {
+      result.push({
+        name: 'message',
+        type: '_MESSAGE',
+        value: target_id,
+        message:
+          this.channel?.messages._add(resolved.messages[target_id]) ??
+          new (getMessage())(this.client, resolved.messages[target_id]),
+      });
+    }
+
+    return result;
+  }
+}
+
+module.exports = ContextMenuCommandInteraction;
diff --git a/node_modules/discord.js/src/structures/DMChannel.js b/node_modules/discord.js/src/structures/DMChannel.js
new file mode 100644
index 0000000..2c917c4
--- /dev/null
+++ b/node_modules/discord.js/src/structures/DMChannel.js
@@ -0,0 +1,129 @@
+'use strict';
+
+const { userMention } = require('@discordjs/builders');
+const { ChannelType } = require('discord-api-types/v10');
+const { BaseChannel } = require('./BaseChannel');
+const TextBasedChannel = require('./interfaces/TextBasedChannel');
+const DMMessageManager = require('../managers/DMMessageManager');
+const Partials = require('../util/Partials');
+
+/**
+ * Represents a direct message channel between two users.
+ * @extends {BaseChannel}
+ * @implements {TextBasedChannel}
+ */
+class DMChannel extends BaseChannel {
+  constructor(client, data) {
+    super(client, data);
+
+    // Override the channel type so partials have a known type
+    this.type = ChannelType.DM;
+
+    /**
+     * A manager of the messages belonging to this channel
+     * @type {DMMessageManager}
+     */
+    this.messages = new DMMessageManager(this);
+  }
+
+  _patch(data) {
+    super._patch(data);
+
+    if (data.recipients) {
+      const recipient = data.recipients[0];
+
+      /**
+       * The recipient's id
+       * @type {Snowflake}
+       */
+      this.recipientId = recipient.id;
+
+      if ('username' in recipient || this.client.options.partials.includes(Partials.User)) {
+        this.client.users._add(recipient);
+      }
+    }
+
+    if ('last_message_id' in data) {
+      /**
+       * The channel's last message id, if one was sent
+       * @type {?Snowflake}
+       */
+      this.lastMessageId = data.last_message_id;
+    }
+
+    if ('last_pin_timestamp' in data) {
+      /**
+       * The timestamp when the last pinned message was pinned, if there was one
+       * @type {?number}
+       */
+      this.lastPinTimestamp = Date.parse(data.last_pin_timestamp);
+    } else {
+      this.lastPinTimestamp ??= null;
+    }
+  }
+
+  /**
+   * Whether this DMChannel is a partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return this.lastMessageId === undefined;
+  }
+
+  /**
+   * The recipient on the other end of the DM
+   * @type {?User}
+   * @readonly
+   */
+  get recipient() {
+    return this.client.users.resolve(this.recipientId);
+  }
+
+  /**
+   * Fetch this DMChannel.
+   * @param {boolean} [force=true] Whether to skip the cache check and request the API
+   * @returns {Promise<DMChannel>}
+   */
+  fetch(force = true) {
+    return this.client.users.createDM(this.recipientId, { force });
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the recipient's mention instead of the
+   * DMChannel object.
+   * @returns {string}
+   * @example
+   * // Logs: Hello from <@123456789012345678>!
+   * console.log(`Hello from ${channel}!`);
+   */
+  toString() {
+    return userMention(this.recipientId);
+  }
+
+  // These are here only for documentation purposes - they are implemented by TextBasedChannel
+  /* eslint-disable no-empty-function */
+  get lastMessage() {}
+  get lastPinAt() {}
+  send() {}
+  sendTyping() {}
+  createMessageCollector() {}
+  awaitMessages() {}
+  createMessageComponentCollector() {}
+  awaitMessageComponent() {}
+  // Doesn't work on DM channels; bulkDelete() {}
+  // Doesn't work on DM channels; fetchWebhooks() {}
+  // Doesn't work on DM channels; createWebhook() {}
+  // Doesn't work on DM channels; setRateLimitPerUser() {}
+  // Doesn't work on DM channels; setNSFW() {}
+}
+
+TextBasedChannel.applyToClass(DMChannel, true, [
+  'bulkDelete',
+  'fetchWebhooks',
+  'createWebhook',
+  'setRateLimitPerUser',
+  'setNSFW',
+]);
+
+module.exports = DMChannel;
diff --git a/node_modules/discord.js/src/structures/DirectoryChannel.js b/node_modules/discord.js/src/structures/DirectoryChannel.js
new file mode 100644
index 0000000..870eff9
--- /dev/null
+++ b/node_modules/discord.js/src/structures/DirectoryChannel.js
@@ -0,0 +1,36 @@
+'use strict';
+
+const { BaseChannel } = require('./BaseChannel');
+
+/**
+ * Represents a channel that displays a directory of guilds.
+ * @extends {BaseChannel}
+ */
+class DirectoryChannel extends BaseChannel {
+  constructor(guild, data, client) {
+    super(client, data);
+
+    /**
+     * The guild the channel is in
+     * @type {InviteGuild}
+     */
+    this.guild = guild;
+
+    /**
+     * The id of the guild the channel is in
+     * @type {Snowflake}
+     */
+    this.guildId = guild.id;
+  }
+
+  _patch(data) {
+    super._patch(data);
+    /**
+     * The channel's name
+     * @type {string}
+     */
+    this.name = data.name;
+  }
+}
+
+module.exports = DirectoryChannel;
diff --git a/node_modules/discord.js/src/structures/Embed.js b/node_modules/discord.js/src/structures/Embed.js
new file mode 100644
index 0000000..dd68120
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Embed.js
@@ -0,0 +1,220 @@
+'use strict';
+
+const { embedLength } = require('@discordjs/builders');
+const isEqual = require('fast-deep-equal');
+
+/**
+ * Represents an embed.
+ */
+class Embed {
+  constructor(data) {
+    /**
+     * The API embed data.
+     * @type {APIEmbed}
+     * @readonly
+     */
+    this.data = { ...data };
+  }
+
+  /**
+   * An array of fields of this embed.
+   * @type {Array<APIEmbedField>}
+   * @readonly
+   */
+  get fields() {
+    return this.data.fields ?? [];
+  }
+
+  /**
+   * The title of this embed.
+   * @type {?string}
+   * @readonly
+   */
+  get title() {
+    return this.data.title ?? null;
+  }
+
+  /**
+   * The description of this embed.
+   * @type {?string}
+   * @readonly
+   */
+  get description() {
+    return this.data.description ?? null;
+  }
+
+  /**
+   * The URL of this embed.
+   * @type {?string}
+   * @readonly
+   */
+  get url() {
+    return this.data.url ?? null;
+  }
+
+  /**
+   * The color of this embed.
+   * @type {?number}
+   * @readonly
+   */
+  get color() {
+    return this.data.color ?? null;
+  }
+
+  /**
+   * The timestamp of this embed. This is in an ISO 8601 format.
+   * @type {?string}
+   * @readonly
+   */
+  get timestamp() {
+    return this.data.timestamp ?? null;
+  }
+
+  /**
+   * @typedef {Object} EmbedAssetData
+   * @property {?string} url The URL of the image
+   * @property {?string} proxyURL The proxy URL of the image
+   * @property {?number} height The height of the image
+   * @property {?number} width The width of the image
+   */
+
+  /**
+   * The thumbnail of this embed.
+   * @type {?EmbedAssetData}
+   * @readonly
+   */
+  get thumbnail() {
+    if (!this.data.thumbnail) return null;
+    return {
+      url: this.data.thumbnail.url,
+      proxyURL: this.data.thumbnail.proxy_url,
+      height: this.data.thumbnail.height,
+      width: this.data.thumbnail.width,
+    };
+  }
+
+  /**
+   * The image of this embed.
+   * @type {?EmbedAssetData}
+   * @readonly
+   */
+  get image() {
+    if (!this.data.image) return null;
+    return {
+      url: this.data.image.url,
+      proxyURL: this.data.image.proxy_url,
+      height: this.data.image.height,
+      width: this.data.image.width,
+    };
+  }
+
+  /**
+   * The video of this embed.
+   * @type {?EmbedAssetData}
+   * @readonly
+   */
+  get video() {
+    if (!this.data.video) return null;
+    return {
+      url: this.data.video.url,
+      proxyURL: this.data.video.proxy_url,
+      height: this.data.video.height,
+      width: this.data.video.width,
+    };
+  }
+
+  /**
+   * @typedef {Object} EmbedAuthorData
+   * @property {string} name The name of the author
+   * @property {?string} url The URL of the author
+   * @property {?string} iconURL The icon URL of the author
+   * @property {?string} proxyIconURL The proxy icon URL of the author
+   */
+
+  /**
+   * The author of this embed.
+   * @type {?EmbedAuthorData}
+   * @readonly
+   */
+  get author() {
+    if (!this.data.author) return null;
+    return {
+      name: this.data.author.name,
+      url: this.data.author.url,
+      iconURL: this.data.author.icon_url,
+      proxyIconURL: this.data.author.proxy_icon_url,
+    };
+  }
+
+  /**
+   * The provider of this embed.
+   * @type {?APIEmbedProvider}
+   * @readonly
+   */
+  get provider() {
+    return this.data.provider ?? null;
+  }
+
+  /**
+   * @typedef {Object} EmbedFooterData
+   * @property {string} text The text of the footer
+   * @property {?string} iconURL The URL of the icon
+   * @property {?string} proxyIconURL The proxy URL of the icon
+   */
+
+  /**
+   * The footer of this embed.
+   * @type {?EmbedFooterData}
+   * @readonly
+   */
+  get footer() {
+    if (!this.data.footer) return null;
+    return {
+      text: this.data.footer.text,
+      iconURL: this.data.footer.icon_url,
+      proxyIconURL: this.data.footer.proxy_icon_url,
+    };
+  }
+
+  /**
+   * The accumulated length for the embed title, description, fields, footer text, and author name.
+   * @type {number}
+   * @readonly
+   */
+  get length() {
+    return embedLength(this.data);
+  }
+
+  /**
+   * The hex color of this embed.
+   * @type {?string}
+   * @readonly
+   */
+  get hexColor() {
+    return typeof this.data.color === 'number'
+      ? `#${this.data.color.toString(16).padStart(6, '0')}`
+      : this.data.color ?? null;
+  }
+
+  /**
+   * Returns the API-compatible JSON for this embed.
+   * @returns {APIEmbed}
+   */
+  toJSON() {
+    return { ...this.data };
+  }
+
+  /**
+   * Whether the given embeds are equal.
+   * @param {Embed|APIEmbed} other The embed to compare against
+   * @returns {boolean}
+   */
+  equals(other) {
+    if (other instanceof Embed) {
+      return isEqual(other.data, this.data);
+    }
+    return isEqual(other, this.data);
+  }
+}
+
+module.exports = Embed;
diff --git a/node_modules/discord.js/src/structures/EmbedBuilder.js b/node_modules/discord.js/src/structures/EmbedBuilder.js
new file mode 100644
index 0000000..10e445c
--- /dev/null
+++ b/node_modules/discord.js/src/structures/EmbedBuilder.js
@@ -0,0 +1,50 @@
+'use strict';
+
+const { EmbedBuilder: BuildersEmbed, embedLength } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+const { resolveColor } = require('../util/Util');
+
+/**
+ * Represents an embed builder.
+ * @extends {BuildersEmbed}
+ */
+class EmbedBuilder extends BuildersEmbed {
+  constructor(data) {
+    super(toSnakeCase(data));
+  }
+
+  /**
+   * Sets the color of this embed
+   * @param {?ColorResolvable} color The color of the embed
+   * @returns {EmbedBuilder}
+   */
+  setColor(color) {
+    return super.setColor(color && resolveColor(color));
+  }
+
+  /**
+   * Creates a new embed builder from JSON data
+   * @param {EmbedBuilder|Embed|APIEmbed} other The other data
+   * @returns {EmbedBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+
+  /**
+   * The accumulated length for the embed title, description, fields, footer text, and author name.
+   * @type {number}
+   * @readonly
+   */
+  get length() {
+    return embedLength(this.data);
+  }
+}
+
+module.exports = EmbedBuilder;
+
+/**
+ * @external BuildersEmbed
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/EmbedBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/Emoji.js b/node_modules/discord.js/src/structures/Emoji.js
new file mode 100644
index 0000000..409d292
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Emoji.js
@@ -0,0 +1,108 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const Base = require('./Base');
+
+/**
+ * Represents raw emoji data from the API
+ * @typedef {APIEmoji} RawEmoji
+ * @property {?Snowflake} id The emoji's id
+ * @property {?string} name The emoji's name
+ * @property {?boolean} animated Whether the emoji is animated
+ */
+
+/**
+ * Represents an emoji, see {@link GuildEmoji} and {@link ReactionEmoji}.
+ * @extends {Base}
+ */
+class Emoji extends Base {
+  constructor(client, emoji) {
+    super(client);
+    /**
+     * Whether or not the emoji is animated
+     * @type {?boolean}
+     */
+    this.animated = emoji.animated ?? null;
+
+    /**
+     * The emoji's name
+     * @type {?string}
+     */
+    this.name = emoji.name ?? null;
+
+    /**
+     * The emoji's id
+     * @type {?Snowflake}
+     */
+    this.id = emoji.id;
+  }
+
+  /**
+   * The identifier of this emoji, used for message reactions
+   * @type {string}
+   * @readonly
+   */
+  get identifier() {
+    if (this.id) return `${this.animated ? 'a:' : ''}${this.name}:${this.id}`;
+    return encodeURIComponent(this.name);
+  }
+
+  /**
+   * The URL to the emoji file if it's a custom emoji
+   * @type {?string}
+   * @readonly
+   */
+  get url() {
+    return this.id && this.client.rest.cdn.emoji(this.id, this.animated ? 'gif' : 'png');
+  }
+
+  /**
+   * The timestamp the emoji was created at, or null if unicode
+   * @type {?number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return this.id && DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the emoji was created at, or null if unicode
+   * @type {?Date}
+   * @readonly
+   */
+  get createdAt() {
+    return this.id && new Date(this.createdTimestamp);
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the text required to form a graphical emoji on Discord
+   * instead of the Emoji object.
+   * @returns {string}
+   * @example
+   * // Send a custom emoji from a guild:
+   * const emoji = guild.emojis.cache.first();
+   * msg.channel.send(`Hello! ${emoji}`);
+   * @example
+   * // Send the emoji used in a reaction to the channel the reaction is part of
+   * reaction.message.channel.send(`The emoji used was: ${reaction.emoji}`);
+   */
+  toString() {
+    return this.id ? `<${this.animated ? 'a' : ''}:${this.name}:${this.id}>` : this.name;
+  }
+
+  toJSON() {
+    return super.toJSON({
+      guild: 'guildId',
+      createdTimestamp: true,
+      url: true,
+      identifier: true,
+    });
+  }
+}
+
+exports.Emoji = Emoji;
+
+/**
+ * @external APIEmoji
+ * @see {@link https://discord.com/developers/docs/resources/emoji#emoji-object}
+ */
diff --git a/node_modules/discord.js/src/structures/ForumChannel.js b/node_modules/discord.js/src/structures/ForumChannel.js
new file mode 100644
index 0000000..87e6478
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ForumChannel.js
@@ -0,0 +1,264 @@
+'use strict';
+
+const GuildChannel = require('./GuildChannel');
+const TextBasedChannel = require('./interfaces/TextBasedChannel');
+const GuildForumThreadManager = require('../managers/GuildForumThreadManager');
+const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require('../util/Channels');
+
+/**
+ * @typedef {Object} GuildForumTagEmoji
+ * @property {?Snowflake} id The id of a guild's custom emoji
+ * @property {?string} name The unicode character of the emoji
+ */
+
+/**
+ * @typedef {Object} GuildForumTag
+ * @property {Snowflake} id The id of the tag
+ * @property {string} name The name of the tag
+ * @property {boolean} moderated Whether this tag can only be added to or removed from threads
+ * by a member with the `ManageThreads` permission
+ * @property {?GuildForumTagEmoji} emoji The emoji of this tag
+ */
+
+/**
+ * @typedef {Object} GuildForumTagData
+ * @property {Snowflake} [id] The id of the tag
+ * @property {string} name The name of the tag
+ * @property {boolean} [moderated] Whether this tag can only be added to or removed from threads
+ * by a member with the `ManageThreads` permission
+ * @property {?GuildForumTagEmoji} [emoji] The emoji of this tag
+ */
+
+/**
+ * @typedef {Object} DefaultReactionEmoji
+ * @property {?Snowflake} id The id of a guild's custom emoji
+ * @property {?string} name The unicode character of the emoji
+ */
+
+/**
+ * Represents a channel that only contains threads
+ * @extends {GuildChannel}
+ * @implements {TextBasedChannel}
+ */
+class ForumChannel extends GuildChannel {
+  constructor(guild, data, client) {
+    super(guild, data, client, false);
+
+    /**
+     * A manager of the threads belonging to this channel
+     * @type {GuildForumThreadManager}
+     */
+    this.threads = new GuildForumThreadManager(this);
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    super._patch(data);
+    if ('available_tags' in data) {
+      /**
+       * The set of tags that can be used in this channel.
+       * @type {GuildForumTag[]}
+       */
+      this.availableTags = data.available_tags.map(tag => transformAPIGuildForumTag(tag));
+    } else {
+      this.availableTags ??= [];
+    }
+
+    if ('default_reaction_emoji' in data) {
+      /**
+       * The emoji to show in the add reaction button on a thread in a guild forum channel
+       * @type {?DefaultReactionEmoji}
+       */
+      this.defaultReactionEmoji = data.default_reaction_emoji
+        ? transformAPIGuildDefaultReaction(data.default_reaction_emoji)
+        : null;
+    } else {
+      this.defaultReactionEmoji ??= null;
+    }
+
+    if ('default_thread_rate_limit_per_user' in data) {
+      /**
+       * The initial rate limit per user (slowmode) to set on newly created threads in a channel.
+       * @type {?number}
+       */
+      this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user;
+    } else {
+      this.defaultThreadRateLimitPerUser ??= null;
+    }
+
+    if ('rate_limit_per_user' in data) {
+      /**
+       * The rate limit per user (slowmode) for this channel.
+       * @type {?number}
+       */
+      this.rateLimitPerUser = data.rate_limit_per_user;
+    } else {
+      this.rateLimitPerUser ??= null;
+    }
+
+    if ('default_auto_archive_duration' in data) {
+      /**
+       * The default auto archive duration for newly created threads in this channel.
+       * @type {?ThreadAutoArchiveDuration}
+       */
+      this.defaultAutoArchiveDuration = data.default_auto_archive_duration;
+    } else {
+      this.defaultAutoArchiveDuration ??= null;
+    }
+
+    if ('nsfw' in data) {
+      /**
+       * If this channel is considered NSFW.
+       * @type {boolean}
+       */
+      this.nsfw = data.nsfw;
+    } else {
+      this.nsfw ??= false;
+    }
+
+    if ('topic' in data) {
+      /**
+       * The topic of this channel.
+       * @type {?string}
+       */
+      this.topic = data.topic;
+    }
+
+    if ('default_sort_order' in data) {
+      /**
+       * The default sort order mode used to order posts
+       * @type {?SortOrderType}
+       */
+      this.defaultSortOrder = data.default_sort_order;
+    } else {
+      this.defaultSortOrder ??= null;
+    }
+
+    /**
+     * The default layout type used to display posts
+     * @type {ForumLayoutType}
+     */
+    this.defaultForumLayout = data.default_forum_layout;
+  }
+
+  /**
+   * Sets the available tags for this forum channel
+   * @param {GuildForumTagData[]} availableTags The tags to set as available in this channel
+   * @param {string} [reason] Reason for changing the available tags
+   * @returns {Promise<ForumChannel>}
+   */
+  setAvailableTags(availableTags, reason) {
+    return this.edit({ availableTags, reason });
+  }
+
+  /**
+   * Sets the default reaction emoji for this channel
+   * @param {?DefaultReactionEmoji} defaultReactionEmoji The emoji to set as the default reaction emoji
+   * @param {string} [reason] Reason for changing the default reaction emoji
+   * @returns {Promise<ForumChannel>}
+   */
+  setDefaultReactionEmoji(defaultReactionEmoji, reason) {
+    return this.edit({ defaultReactionEmoji, reason });
+  }
+
+  /**
+   * Sets the default rate limit per user (slowmode) for new threads in this channel
+   * @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel
+   * @param {string} [reason] Reason for changing the default rate limit
+   * @returns {Promise<ForumChannel>}
+   */
+  setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) {
+    return this.edit({ defaultThreadRateLimitPerUser, reason });
+  }
+
+  /**
+   * Creates an invite to this guild channel.
+   * @param {InviteCreateOptions} [options={}] The options for creating the invite
+   * @returns {Promise<Invite>}
+   * @example
+   * // Create an invite to a channel
+   * channel.createInvite()
+   *   .then(invite => console.log(`Created an invite with a code of ${invite.code}`))
+   *   .catch(console.error);
+   */
+  createInvite(options) {
+    return this.guild.invites.create(this.id, options);
+  }
+
+  /**
+   * Fetches a collection of invites to this guild channel.
+   * Resolves with a collection mapping invites by their codes.
+   * @param {boolean} [cache=true] Whether to cache the fetched invites
+   * @returns {Promise<Collection<string, Invite>>}
+   */
+  fetchInvites(cache) {
+    return this.guild.invites.fetch({ channelId: this.id, cache });
+  }
+
+  /**
+   * Sets the default auto archive duration for all newly created threads in this channel.
+   * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration
+   * @param {string} [reason] Reason for changing the channel's default auto archive duration
+   * @returns {Promise<ForumChannel>}
+   */
+  setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) {
+    return this.edit({ defaultAutoArchiveDuration, reason });
+  }
+
+  /**
+   * Sets a new topic for the guild channel.
+   * @param {?string} topic The new topic for the guild channel
+   * @param {string} [reason] Reason for changing the guild channel's topic
+   * @returns {Promise<ForumChannel>}
+   * @example
+   * // Set a new channel topic
+   * channel.setTopic('needs more rate limiting')
+   *   .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
+   *   .catch(console.error);
+   */
+  setTopic(topic, reason) {
+    return this.edit({ topic, reason });
+  }
+
+  /**
+   * Sets the default sort order mode used to order posts
+   * @param {?SortOrderType} defaultSortOrder The default sort order mode to set on this channel
+   * @param {string} [reason] Reason for changing the default sort order
+   * @returns {Promise<ForumChannel>}
+   */
+  setDefaultSortOrder(defaultSortOrder, reason) {
+    return this.edit({ defaultSortOrder, reason });
+  }
+
+  /**
+   * Sets the default forum layout type used to display posts
+   * @param {ForumLayoutType} defaultForumLayout The default forum layout type to set on this channel
+   * @param {string} [reason] Reason for changing the default forum layout
+   * @returns {Promise<ForumChannel>}
+   */
+  setDefaultForumLayout(defaultForumLayout, reason) {
+    return this.edit({ defaultForumLayout, reason });
+  }
+
+  // These are here only for documentation purposes - they are implemented by TextBasedChannel
+  /* eslint-disable no-empty-function */
+  createWebhook() {}
+  fetchWebhooks() {}
+  setNSFW() {}
+  setRateLimitPerUser() {}
+}
+
+TextBasedChannel.applyToClass(ForumChannel, true, [
+  'send',
+  'lastMessage',
+  'lastPinAt',
+  'bulkDelete',
+  'sendTyping',
+  'createMessageCollector',
+  'awaitMessages',
+  'createMessageComponentCollector',
+  'awaitMessageComponent',
+]);
+
+module.exports = ForumChannel;
diff --git a/node_modules/discord.js/src/structures/Guild.js b/node_modules/discord.js/src/structures/Guild.js
new file mode 100644
index 0000000..f07e9b4
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Guild.js
@@ -0,0 +1,1367 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { makeURLSearchParams } = require('@discordjs/rest');
+const { ChannelType, GuildPremiumTier, Routes, GuildFeature } = require('discord-api-types/v10');
+const AnonymousGuild = require('./AnonymousGuild');
+const GuildAuditLogs = require('./GuildAuditLogs');
+const { GuildOnboarding } = require('./GuildOnboarding');
+const GuildPreview = require('./GuildPreview');
+const GuildTemplate = require('./GuildTemplate');
+const Integration = require('./Integration');
+const Webhook = require('./Webhook');
+const WelcomeScreen = require('./WelcomeScreen');
+const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
+const AutoModerationRuleManager = require('../managers/AutoModerationRuleManager');
+const GuildApplicationCommandManager = require('../managers/GuildApplicationCommandManager');
+const GuildBanManager = require('../managers/GuildBanManager');
+const GuildChannelManager = require('../managers/GuildChannelManager');
+const GuildEmojiManager = require('../managers/GuildEmojiManager');
+const GuildInviteManager = require('../managers/GuildInviteManager');
+const GuildMemberManager = require('../managers/GuildMemberManager');
+const GuildScheduledEventManager = require('../managers/GuildScheduledEventManager');
+const GuildStickerManager = require('../managers/GuildStickerManager');
+const PresenceManager = require('../managers/PresenceManager');
+const RoleManager = require('../managers/RoleManager');
+const StageInstanceManager = require('../managers/StageInstanceManager');
+const VoiceStateManager = require('../managers/VoiceStateManager');
+const DataResolver = require('../util/DataResolver');
+const Status = require('../util/Status');
+const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
+const { discordSort, getSortableGroupTypes } = require('../util/Util');
+
+/**
+ * Represents a guild (or a server) on Discord.
+ * <info>It's recommended to see if a guild is available before performing operations or reading data from it. You can
+ * check this with {@link Guild#available}.</info>
+ * @extends {AnonymousGuild}
+ */
+class Guild extends AnonymousGuild {
+  constructor(client, data) {
+    super(client, data, false);
+
+    /**
+     * A manager of the application commands belonging to this guild
+     * @type {GuildApplicationCommandManager}
+     */
+    this.commands = new GuildApplicationCommandManager(this);
+
+    /**
+     * A manager of the members belonging to this guild
+     * @type {GuildMemberManager}
+     */
+    this.members = new GuildMemberManager(this);
+
+    /**
+     * A manager of the channels belonging to this guild
+     * @type {GuildChannelManager}
+     */
+    this.channels = new GuildChannelManager(this);
+
+    /**
+     * A manager of the bans belonging to this guild
+     * @type {GuildBanManager}
+     */
+    this.bans = new GuildBanManager(this);
+
+    /**
+     * A manager of the roles belonging to this guild
+     * @type {RoleManager}
+     */
+    this.roles = new RoleManager(this);
+
+    /**
+     * A manager of the presences belonging to this guild
+     * @type {PresenceManager}
+     */
+    this.presences = new PresenceManager(this.client);
+
+    /**
+     * A manager of the voice states of this guild
+     * @type {VoiceStateManager}
+     */
+    this.voiceStates = new VoiceStateManager(this);
+
+    /**
+     * A manager of the stage instances of this guild
+     * @type {StageInstanceManager}
+     */
+    this.stageInstances = new StageInstanceManager(this);
+
+    /**
+     * A manager of the invites of this guild
+     * @type {GuildInviteManager}
+     */
+    this.invites = new GuildInviteManager(this);
+
+    /**
+     * A manager of the scheduled events of this guild
+     * @type {GuildScheduledEventManager}
+     */
+    this.scheduledEvents = new GuildScheduledEventManager(this);
+
+    /**
+     * A manager of the auto moderation rules of this guild.
+     * @type {AutoModerationRuleManager}
+     */
+    this.autoModerationRules = new AutoModerationRuleManager(this);
+
+    if (!data) return;
+    if (data.unavailable) {
+      /**
+       * Whether the guild is available to access. If it is not available, it indicates a server outage
+       * @type {boolean}
+       */
+      this.available = false;
+    } else {
+      this._patch(data);
+      if (!data.channels) this.available = false;
+    }
+
+    /**
+     * The id of the shard this Guild belongs to.
+     * @type {number}
+     */
+    this.shardId = data.shardId;
+  }
+
+  /**
+   * The Shard this Guild belongs to.
+   * @type {WebSocketShard}
+   * @readonly
+   */
+  get shard() {
+    return this.client.ws.shards.get(this.shardId);
+  }
+
+  _patch(data) {
+    super._patch(data);
+    this.id = data.id;
+    if ('name' in data) this.name = data.name;
+    if ('icon' in data) this.icon = data.icon;
+    if ('unavailable' in data) {
+      this.available = !data.unavailable;
+    } else {
+      this.available ??= true;
+    }
+
+    if ('discovery_splash' in data) {
+      /**
+       * The hash of the guild discovery splash image
+       * @type {?string}
+       */
+      this.discoverySplash = data.discovery_splash;
+    }
+
+    if ('member_count' in data) {
+      /**
+       * The full amount of members in this guild
+       * @type {number}
+       */
+      this.memberCount = data.member_count;
+    }
+
+    if ('large' in data) {
+      /**
+       * Whether the guild is "large" (has more than {@link WebsocketOptions large_threshold} members, 50 by default)
+       * @type {boolean}
+       */
+      this.large = Boolean(data.large);
+    }
+
+    if ('premium_progress_bar_enabled' in data) {
+      /**
+       * Whether this guild has its premium (boost) progress bar enabled
+       * @type {boolean}
+       */
+      this.premiumProgressBarEnabled = data.premium_progress_bar_enabled;
+    }
+
+    if ('application_id' in data) {
+      /**
+       * The id of the application that created this guild (if applicable)
+       * @type {?Snowflake}
+       */
+      this.applicationId = data.application_id;
+    }
+
+    if ('afk_timeout' in data) {
+      /**
+       * The time in seconds before a user is counted as "away from keyboard"
+       * @type {?number}
+       */
+      this.afkTimeout = data.afk_timeout;
+    }
+
+    if ('afk_channel_id' in data) {
+      /**
+       * The id of the voice channel where AFK members are moved
+       * @type {?Snowflake}
+       */
+      this.afkChannelId = data.afk_channel_id;
+    }
+
+    if ('system_channel_id' in data) {
+      /**
+       * The system channel's id
+       * @type {?Snowflake}
+       */
+      this.systemChannelId = data.system_channel_id;
+    }
+
+    if ('premium_tier' in data) {
+      /**
+       * The premium tier of this guild
+       * @type {GuildPremiumTier}
+       */
+      this.premiumTier = data.premium_tier;
+    }
+
+    if ('widget_enabled' in data) {
+      /**
+       * Whether widget images are enabled on this guild
+       * @type {?boolean}
+       */
+      this.widgetEnabled = data.widget_enabled;
+    } else {
+      this.widgetEnabled ??= null;
+    }
+
+    if ('widget_channel_id' in data) {
+      /**
+       * The widget channel's id, if enabled
+       * @type {?string}
+       */
+      this.widgetChannelId = data.widget_channel_id;
+    } else {
+      this.widgetChannelId ??= null;
+    }
+
+    if ('explicit_content_filter' in data) {
+      /**
+       * The explicit content filter level of the guild
+       * @type {GuildExplicitContentFilter}
+       */
+      this.explicitContentFilter = data.explicit_content_filter;
+    }
+
+    if ('mfa_level' in data) {
+      /**
+       * The required MFA level for this guild
+       * @type {GuildMFALevel}
+       */
+      this.mfaLevel = data.mfa_level;
+    }
+
+    if ('joined_at' in data) {
+      /**
+       * The timestamp the client user joined the guild at
+       * @type {number}
+       */
+      this.joinedTimestamp = Date.parse(data.joined_at);
+    }
+
+    if ('default_message_notifications' in data) {
+      /**
+       * The default message notification level of the guild
+       * @type {GuildDefaultMessageNotifications}
+       */
+      this.defaultMessageNotifications = data.default_message_notifications;
+    }
+
+    if ('system_channel_flags' in data) {
+      /**
+       * The value set for the guild's system channel flags
+       * @type {Readonly<SystemChannelFlagsBitField>}
+       */
+      this.systemChannelFlags = new SystemChannelFlagsBitField(data.system_channel_flags).freeze();
+    }
+
+    if ('max_members' in data) {
+      /**
+       * The maximum amount of members the guild can have
+       * @type {?number}
+       */
+      this.maximumMembers = data.max_members;
+    } else {
+      this.maximumMembers ??= null;
+    }
+
+    if ('max_presences' in data) {
+      /**
+       * The maximum amount of presences the guild can have (this is `null` for all but the largest of guilds)
+       * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info>
+       * @type {?number}
+       */
+      this.maximumPresences = data.max_presences;
+    } else {
+      this.maximumPresences ??= null;
+    }
+
+    if ('max_video_channel_users' in data) {
+      /**
+       * The maximum amount of users allowed in a video channel.
+       * @type {?number}
+       */
+      this.maxVideoChannelUsers = data.max_video_channel_users;
+    } else {
+      this.maxVideoChannelUsers ??= null;
+    }
+
+    if ('max_stage_video_channel_users' in data) {
+      /**
+       * The maximum amount of users allowed in a stage video channel.
+       * @type {?number}
+       */
+      this.maxStageVideoChannelUsers = data.max_stage_video_channel_users;
+    } else {
+      this.maxStageVideoChannelUsers ??= null;
+    }
+
+    if ('approximate_member_count' in data) {
+      /**
+       * The approximate amount of members the guild has
+       * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info>
+       * @type {?number}
+       */
+      this.approximateMemberCount = data.approximate_member_count;
+    } else {
+      this.approximateMemberCount ??= null;
+    }
+
+    if ('approximate_presence_count' in data) {
+      /**
+       * The approximate amount of presences the guild has
+       * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info>
+       * @type {?number}
+       */
+      this.approximatePresenceCount = data.approximate_presence_count;
+    } else {
+      this.approximatePresenceCount ??= null;
+    }
+
+    /**
+     * The use count of the vanity URL code of the guild, if any
+     * <info>You will need to fetch this parameter using {@link Guild#fetchVanityData} if you want to receive it</info>
+     * @type {?number}
+     */
+    this.vanityURLUses ??= null;
+
+    if ('rules_channel_id' in data) {
+      /**
+       * The rules channel's id for the guild
+       * @type {?Snowflake}
+       */
+      this.rulesChannelId = data.rules_channel_id;
+    }
+
+    if ('public_updates_channel_id' in data) {
+      /**
+       * The community updates channel's id for the guild
+       * @type {?Snowflake}
+       */
+      this.publicUpdatesChannelId = data.public_updates_channel_id;
+    }
+
+    if ('preferred_locale' in data) {
+      /**
+       * The preferred locale of the guild, defaults to `en-US`
+       * @type {Locale}
+       */
+      this.preferredLocale = data.preferred_locale;
+    }
+
+    if ('safety_alerts_channel_id' in data) {
+      /**
+       * The safety alerts channel's id for the guild
+       * @type {?Snowflake}
+       */
+      this.safetyAlertsChannelId = data.safety_alerts_channel_id;
+    } else {
+      this.safetyAlertsChannelId ??= null;
+    }
+
+    if (data.channels) {
+      this.channels.cache.clear();
+      for (const rawChannel of data.channels) {
+        this.client.channels._add(rawChannel, this);
+      }
+    }
+
+    if (data.threads) {
+      for (const rawThread of data.threads) {
+        this.client.channels._add(rawThread, this);
+      }
+    }
+
+    if (data.roles) {
+      this.roles.cache.clear();
+      for (const role of data.roles) this.roles._add(role);
+    }
+
+    if (data.members) {
+      this.members.cache.clear();
+      for (const guildUser of data.members) this.members._add(guildUser);
+    }
+
+    if ('owner_id' in data) {
+      /**
+       * The user id of this guild's owner
+       * @type {Snowflake}
+       */
+      this.ownerId = data.owner_id;
+    }
+
+    if (data.presences) {
+      for (const presence of data.presences) {
+        this.presences._add(Object.assign(presence, { guild: this }));
+      }
+    }
+
+    if (data.stage_instances) {
+      this.stageInstances.cache.clear();
+      for (const stageInstance of data.stage_instances) {
+        this.stageInstances._add(stageInstance);
+      }
+    }
+
+    if (data.guild_scheduled_events) {
+      this.scheduledEvents.cache.clear();
+      for (const scheduledEvent of data.guild_scheduled_events) {
+        this.scheduledEvents._add(scheduledEvent);
+      }
+    }
+
+    if (data.voice_states) {
+      this.voiceStates.cache.clear();
+      for (const voiceState of data.voice_states) {
+        this.voiceStates._add(voiceState);
+      }
+    }
+
+    if (!this.emojis) {
+      /**
+       * A manager of the emojis belonging to this guild
+       * @type {GuildEmojiManager}
+       */
+      this.emojis = new GuildEmojiManager(this);
+      if (data.emojis) for (const emoji of data.emojis) this.emojis._add(emoji);
+    } else if (data.emojis) {
+      this.client.actions.GuildEmojisUpdate.handle({
+        guild_id: this.id,
+        emojis: data.emojis,
+      });
+    }
+
+    if (!this.stickers) {
+      /**
+       * A manager of the stickers belonging to this guild
+       * @type {GuildStickerManager}
+       */
+      this.stickers = new GuildStickerManager(this);
+      if (data.stickers) for (const sticker of data.stickers) this.stickers._add(sticker);
+    } else if (data.stickers) {
+      this.client.actions.GuildStickersUpdate.handle({
+        guild_id: this.id,
+        stickers: data.stickers,
+      });
+    }
+  }
+
+  /**
+   * The time the client user joined the guild
+   * @type {Date}
+   * @readonly
+   */
+  get joinedAt() {
+    return new Date(this.joinedTimestamp);
+  }
+
+  /**
+   * The URL to this guild's discovery splash image.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  discoverySplashURL(options = {}) {
+    return this.discoverySplash && this.client.rest.cdn.discoverySplash(this.id, this.discoverySplash, options);
+  }
+
+  /**
+   * Fetches the owner of the guild.
+   * If the member object isn't needed, use {@link Guild#ownerId} instead.
+   * @param {BaseFetchOptions} [options] The options for fetching the member
+   * @returns {Promise<GuildMember>}
+   */
+  async fetchOwner(options) {
+    if (!this.ownerId) {
+      throw new DiscordjsError(ErrorCodes.FetchOwnerId);
+    }
+    const member = await this.members.fetch({ ...options, user: this.ownerId });
+    return member;
+  }
+
+  /**
+   * AFK voice channel for this guild
+   * @type {?VoiceChannel}
+   * @readonly
+   */
+  get afkChannel() {
+    return this.client.channels.resolve(this.afkChannelId);
+  }
+
+  /**
+   * System channel for this guild
+   * @type {?TextChannel}
+   * @readonly
+   */
+  get systemChannel() {
+    return this.client.channels.resolve(this.systemChannelId);
+  }
+
+  /**
+   * Widget channel for this guild
+   * @type {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel)}
+   * @readonly
+   */
+  get widgetChannel() {
+    return this.client.channels.resolve(this.widgetChannelId);
+  }
+
+  /**
+   * Rules channel for this guild
+   * @type {?TextChannel}
+   * @readonly
+   */
+  get rulesChannel() {
+    return this.client.channels.resolve(this.rulesChannelId);
+  }
+
+  /**
+   * Public updates channel for this guild
+   * @type {?TextChannel}
+   * @readonly
+   */
+  get publicUpdatesChannel() {
+    return this.client.channels.resolve(this.publicUpdatesChannelId);
+  }
+
+  /**
+   * Safety alerts channel for this guild
+   * @type {?TextChannel}
+   * @readonly
+   */
+  get safetyAlertsChannel() {
+    return this.client.channels.resolve(this.safetyAlertsChannelId);
+  }
+
+  /**
+   * The maximum bitrate available for this guild
+   * @type {number}
+   * @readonly
+   */
+  get maximumBitrate() {
+    if (this.features.includes(GuildFeature.VIPRegions)) {
+      return 384_000;
+    }
+
+    switch (this.premiumTier) {
+      case GuildPremiumTier.Tier1:
+        return 128_000;
+      case GuildPremiumTier.Tier2:
+        return 256_000;
+      case GuildPremiumTier.Tier3:
+        return 384_000;
+      default:
+        return 96_000;
+    }
+  }
+
+  /**
+   * Fetches a collection of integrations to this guild.
+   * Resolves with a collection mapping integrations by their ids.
+   * @returns {Promise<Collection<Snowflake|string, Integration>>}
+   * @example
+   * // Fetch integrations
+   * guild.fetchIntegrations()
+   *   .then(integrations => console.log(`Fetched ${integrations.size} integrations`))
+   *   .catch(console.error);
+   */
+  async fetchIntegrations() {
+    const data = await this.client.rest.get(Routes.guildIntegrations(this.id));
+    return data.reduce(
+      (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)),
+      new Collection(),
+    );
+  }
+
+  /**
+   * Fetches a collection of templates from this guild.
+   * Resolves with a collection mapping templates by their codes.
+   * @returns {Promise<Collection<string, GuildTemplate>>}
+   */
+  async fetchTemplates() {
+    const templates = await this.client.rest.get(Routes.guildTemplates(this.id));
+    return templates.reduce((col, data) => col.set(data.code, new GuildTemplate(this.client, data)), new Collection());
+  }
+
+  /**
+   * Fetches the welcome screen for this guild.
+   * @returns {Promise<WelcomeScreen>}
+   */
+  async fetchWelcomeScreen() {
+    const data = await this.client.rest.get(Routes.guildWelcomeScreen(this.id));
+    return new WelcomeScreen(this, data);
+  }
+
+  /**
+   * Creates a template for the guild.
+   * @param {string} name The name for the template
+   * @param {string} [description] The description for the template
+   * @returns {Promise<GuildTemplate>}
+   */
+  async createTemplate(name, description) {
+    const data = await this.client.rest.post(Routes.guildTemplates(this.id), { body: { name, description } });
+    return new GuildTemplate(this.client, data);
+  }
+
+  /**
+   * Obtains a guild preview for this guild from Discord.
+   * @returns {Promise<GuildPreview>}
+   */
+  async fetchPreview() {
+    const data = await this.client.rest.get(Routes.guildPreview(this.id));
+    return new GuildPreview(this.client, data);
+  }
+
+  /**
+   * An object containing information about a guild's vanity invite.
+   * @typedef {Object} Vanity
+   * @property {?string} code Vanity invite code
+   * @property {number} uses How many times this invite has been used
+   */
+
+  /**
+   * Fetches the vanity URL invite object to this guild.
+   * Resolves with an object containing the vanity URL invite code and the use count
+   * @returns {Promise<Vanity>}
+   * @example
+   * // Fetch invite data
+   * guild.fetchVanityData()
+   *   .then(res => {
+   *     console.log(`Vanity URL: https://discord.gg/${res.code} with ${res.uses} uses`);
+   *   })
+   *   .catch(console.error);
+   */
+  async fetchVanityData() {
+    const data = await this.client.rest.get(Routes.guildVanityUrl(this.id));
+    this.vanityURLCode = data.code;
+    this.vanityURLUses = data.uses;
+
+    return data;
+  }
+
+  /**
+   * Fetches all webhooks for the guild.
+   * @returns {Promise<Collection<Snowflake, Webhook>>}
+   * @example
+   * // Fetch webhooks
+   * guild.fetchWebhooks()
+   *   .then(webhooks => console.log(`Fetched ${webhooks.size} webhooks`))
+   *   .catch(console.error);
+   */
+  async fetchWebhooks() {
+    const apiHooks = await this.client.rest.get(Routes.guildWebhooks(this.id));
+    const hooks = new Collection();
+    for (const hook of apiHooks) hooks.set(hook.id, new Webhook(this.client, hook));
+    return hooks;
+  }
+
+  /**
+   * Fetches the guild widget data, requires the widget to be enabled.
+   * @returns {Promise<Widget>}
+   * @example
+   * // Fetches the guild widget data
+   * guild.fetchWidget()
+   *   .then(widget => console.log(`The widget shows ${widget.channels.size} channels`))
+   *   .catch(console.error);
+   */
+  fetchWidget() {
+    return this.client.fetchGuildWidget(this.id);
+  }
+
+  /**
+   * Data for the Guild Widget Settings object
+   * @typedef {Object} GuildWidgetSettings
+   * @property {boolean} enabled Whether the widget is enabled
+   * @property {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel)} channel The widget invite channel
+   */
+
+  /**
+   * The Guild Widget Settings object
+   * @typedef {Object} GuildWidgetSettingsData
+   * @property {boolean} enabled Whether the widget is enabled
+   * @property {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel|Snowflake)} channel
+   * The widget invite channel
+   */
+
+  /**
+   * Fetches the guild widget settings.
+   * @returns {Promise<GuildWidgetSettings>}
+   * @example
+   * // Fetches the guild widget settings
+   * guild.fetchWidgetSettings()
+   *   .then(widget => console.log(`The widget is ${widget.enabled ? 'enabled' : 'disabled'}`))
+   *   .catch(console.error);
+   */
+  async fetchWidgetSettings() {
+    const data = await this.client.rest.get(Routes.guildWidgetSettings(this.id));
+    this.widgetEnabled = data.enabled;
+    this.widgetChannelId = data.channel_id;
+    return {
+      enabled: data.enabled,
+      channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null,
+    };
+  }
+
+  /**
+   * Options used to fetch audit logs.
+   * @typedef {Object} GuildAuditLogsFetchOptions
+   * @property {Snowflake|GuildAuditLogsEntry} [before] Consider only entries before this entry
+   * @property {Snowflake|GuildAuditLogsEntry} [after] Consider only entries after this entry
+   * @property {number} [limit] The number of entries to return
+   * @property {UserResolvable} [user] Only return entries for actions made by this user
+   * @property {?AuditLogEvent} [type] Only return entries for this action type
+   */
+
+  /**
+   * Fetches audit logs for this guild.
+   * @param {GuildAuditLogsFetchOptions} [options={}] Options for fetching audit logs
+   * @returns {Promise<GuildAuditLogs>}
+   * @example
+   * // Output audit log entries
+   * guild.fetchAuditLogs()
+   *   .then(audit => console.log(audit.entries.first()))
+   *   .catch(console.error);
+   */
+  async fetchAuditLogs({ before, after, limit, user, type } = {}) {
+    const query = makeURLSearchParams({
+      before: before?.id ?? before,
+      after: after?.id ?? after,
+      limit,
+      action_type: type,
+    });
+
+    if (user) {
+      const userId = this.client.users.resolveId(user);
+      if (!userId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');
+      query.set('user_id', userId);
+    }
+
+    const data = await this.client.rest.get(Routes.guildAuditLog(this.id), { query });
+    return new GuildAuditLogs(this, data);
+  }
+
+  /**
+   * Fetches the guild onboarding data for this guild.
+   * @returns {Promise<GuildOnboarding>}
+   */
+  async fetchOnboarding() {
+    const data = await this.client.rest.get(Routes.guildOnboarding(this.id));
+    return new GuildOnboarding(this.client, data);
+  }
+
+  /**
+   * The data for editing a guild.
+   * @typedef {Object} GuildEditOptions
+   * @property {string} [name] The name of the guild
+   * @property {?GuildVerificationLevel} [verificationLevel] The verification level of the guild
+   * @property {?GuildDefaultMessageNotifications} [defaultMessageNotifications] The default message
+   * notification level of the guild
+   * @property {?GuildExplicitContentFilter} [explicitContentFilter] The level of the explicit content filter
+   * @property {?VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
+   * @property {number} [afkTimeout] The AFK timeout of the guild
+   * @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild
+   * @property {GuildMemberResolvable} [owner] The owner of the guild
+   * @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild
+   * @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild
+   * @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
+   * @property {?TextChannelResolvable} [systemChannel] The system channel of the guild
+   * @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild
+   * @property {?TextChannelResolvable} [rulesChannel] The rules channel of the guild
+   * @property {?TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild
+   * @property {?TextChannelResolvable} [safetyAlertsChannel] The safety alerts channel of the guild
+   * @property {?string} [preferredLocale] The preferred locale of the guild
+   * @property {GuildFeature[]} [features] The features of the guild
+   * @property {?string} [description] The discovery description of the guild
+   * @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled
+   * @property {string} [reason] Reason for editing this guild
+   */
+
+  /**
+   * Data that can be resolved to a Text Channel object. This can be:
+   * * A TextChannel
+   * * A Snowflake
+   * @typedef {TextChannel|Snowflake} TextChannelResolvable
+   */
+
+  /**
+   * Data that can be resolved to a Voice Channel object. This can be:
+   * * A VoiceChannel
+   * * A Snowflake
+   * @typedef {VoiceChannel|Snowflake} VoiceChannelResolvable
+   */
+
+  /**
+   * Updates the guild with new information - e.g. a new name.
+   * @param {GuildEditOptions} options The options to provide
+   * @returns {Promise<Guild>}
+   * @example
+   * // Set the guild name
+   * guild.edit({
+   *   name: 'Discord Guild',
+   * })
+   *   .then(updated => console.log(`New guild name ${updated}`))
+   *   .catch(console.error);
+   */
+  async edit({
+    verificationLevel,
+    defaultMessageNotifications,
+    explicitContentFilter,
+    afkChannel,
+    afkTimeout,
+    icon,
+    owner,
+    splash,
+    discoverySplash,
+    banner,
+    systemChannel,
+    systemChannelFlags,
+    rulesChannel,
+    publicUpdatesChannel,
+    preferredLocale,
+    premiumProgressBarEnabled,
+    safetyAlertsChannel,
+    ...options
+  }) {
+    const data = await this.client.rest.patch(Routes.guild(this.id), {
+      body: {
+        ...options,
+        verification_level: verificationLevel,
+        default_message_notifications: defaultMessageNotifications,
+        explicit_content_filter: explicitContentFilter,
+        afk_channel_id: afkChannel && this.client.channels.resolveId(afkChannel),
+        afk_timeout: afkTimeout,
+        icon: icon && (await DataResolver.resolveImage(icon)),
+        owner_id: owner && this.client.users.resolveId(owner),
+        splash: splash && (await DataResolver.resolveImage(splash)),
+        discovery_splash: discoverySplash && (await DataResolver.resolveImage(discoverySplash)),
+        banner: banner && (await DataResolver.resolveImage(banner)),
+        system_channel_id: systemChannel && this.client.channels.resolveId(systemChannel),
+        system_channel_flags:
+          systemChannelFlags === undefined ? undefined : SystemChannelFlagsBitField.resolve(systemChannelFlags),
+        rules_channel_id: rulesChannel && this.client.channels.resolveId(rulesChannel),
+        public_updates_channel_id: publicUpdatesChannel && this.client.channels.resolveId(publicUpdatesChannel),
+        preferred_locale: preferredLocale,
+        premium_progress_bar_enabled: premiumProgressBarEnabled,
+        safety_alerts_channel_id: safetyAlertsChannel && this.client.channels.resolveId(safetyAlertsChannel),
+      },
+      reason: options.reason,
+    });
+
+    return this.client.actions.GuildUpdate.handle(data).updated;
+  }
+
+  /**
+   * Welcome channel data
+   * @typedef {Object} WelcomeChannelData
+   * @property {string} description The description to show for this welcome channel
+   * @property {TextChannel|NewsChannel|ForumChannel|Snowflake} channel The channel to link for this welcome channel
+   * @property {EmojiIdentifierResolvable} [emoji] The emoji to display for this welcome channel
+   */
+
+  /**
+   * Welcome screen edit data
+   * @typedef {Object} WelcomeScreenEditOptions
+   * @property {boolean} [enabled] Whether the welcome screen is enabled
+   * @property {string} [description] The description for the welcome screen
+   * @property {WelcomeChannelData[]} [welcomeChannels] The welcome channel data for the welcome screen
+   */
+
+  /**
+   * Data that can be resolved to a GuildTextChannel object. This can be:
+   * * A TextChannel
+   * * A NewsChannel
+   * * A Snowflake
+   * @typedef {TextChannel|NewsChannel|Snowflake} GuildTextChannelResolvable
+   */
+
+  /**
+   * Data that can be resolved to a GuildVoiceChannel object. This can be:
+   * * A VoiceChannel
+   * * A StageChannel
+   * * A Snowflake
+   * @typedef {VoiceChannel|StageChannel|Snowflake} GuildVoiceChannelResolvable
+   */
+
+  /**
+   * Updates the guild's welcome screen
+   * @param {WelcomeScreenEditOptions} options The options to provide
+   * @returns {Promise<WelcomeScreen>}
+   * @example
+   * guild.editWelcomeScreen({
+   *   description: 'Hello World',
+   *   enabled: true,
+   *   welcomeChannels: [
+   *     {
+   *       description: 'foobar',
+   *       channel: '222197033908436994',
+   *     }
+   *   ],
+   * })
+   */
+  async editWelcomeScreen(options) {
+    const { enabled, description, welcomeChannels } = options;
+    const welcome_channels = welcomeChannels?.map(welcomeChannelData => {
+      const emoji = this.emojis.resolve(welcomeChannelData.emoji);
+      return {
+        emoji_id: emoji?.id,
+        emoji_name: emoji?.name ?? welcomeChannelData.emoji,
+        channel_id: this.channels.resolveId(welcomeChannelData.channel),
+        description: welcomeChannelData.description,
+      };
+    });
+
+    const patchData = await this.client.rest.patch(Routes.guildWelcomeScreen(this.id), {
+      body: {
+        welcome_channels,
+        description,
+        enabled,
+      },
+    });
+    return new WelcomeScreen(this, patchData);
+  }
+
+  /**
+   * Edits the level of the explicit content filter.
+   * @param {?GuildExplicitContentFilter} explicitContentFilter The new level of the explicit content filter
+   * @param {string} [reason] Reason for changing the level of the guild's explicit content filter
+   * @returns {Promise<Guild>}
+   */
+  setExplicitContentFilter(explicitContentFilter, reason) {
+    return this.edit({ explicitContentFilter, reason });
+  }
+
+  /**
+   * Edits the setting of the default message notifications of the guild.
+   * @param {?GuildDefaultMessageNotifications} defaultMessageNotifications
+   * The new default message notification level of the guild
+   * @param {string} [reason] Reason for changing the setting of the default message notifications
+   * @returns {Promise<Guild>}
+   */
+  setDefaultMessageNotifications(defaultMessageNotifications, reason) {
+    return this.edit({ defaultMessageNotifications, reason });
+  }
+
+  /**
+   * Edits the flags of the default message notifications of the guild.
+   * @param {SystemChannelFlagsResolvable} systemChannelFlags The new flags for the default message notifications
+   * @param {string} [reason] Reason for changing the flags of the default message notifications
+   * @returns {Promise<Guild>}
+   */
+  setSystemChannelFlags(systemChannelFlags, reason) {
+    return this.edit({ systemChannelFlags, reason });
+  }
+
+  /**
+   * Edits the name of the guild.
+   * @param {string} name The new name of the guild
+   * @param {string} [reason] Reason for changing the guild's name
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild name
+   * guild.setName('Discord Guild')
+   *  .then(updated => console.log(`Updated guild name to ${updated.name}`))
+   *  .catch(console.error);
+   */
+  setName(name, reason) {
+    return this.edit({ name, reason });
+  }
+
+  /**
+   * Edits the verification level of the guild.
+   * @param {?GuildVerificationLevel} verificationLevel The new verification level of the guild
+   * @param {string} [reason] Reason for changing the guild's verification level
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild verification level
+   * guild.setVerificationLevel(1)
+   *  .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`))
+   *  .catch(console.error);
+   */
+  setVerificationLevel(verificationLevel, reason) {
+    return this.edit({ verificationLevel, reason });
+  }
+
+  /**
+   * Edits the AFK channel of the guild.
+   * @param {?VoiceChannelResolvable} afkChannel The new AFK channel
+   * @param {string} [reason] Reason for changing the guild's AFK channel
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild AFK channel
+   * guild.setAFKChannel(channel)
+   *  .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel.name}`))
+   *  .catch(console.error);
+   */
+  setAFKChannel(afkChannel, reason) {
+    return this.edit({ afkChannel, reason });
+  }
+
+  /**
+   * Edits the system channel of the guild.
+   * @param {?TextChannelResolvable} systemChannel The new system channel
+   * @param {string} [reason] Reason for changing the guild's system channel
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild system channel
+   * guild.setSystemChannel(channel)
+   *  .then(updated => console.log(`Updated guild system channel to ${guild.systemChannel.name}`))
+   *  .catch(console.error);
+   */
+  setSystemChannel(systemChannel, reason) {
+    return this.edit({ systemChannel, reason });
+  }
+
+  /**
+   * Edits the AFK timeout of the guild.
+   * @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK
+   * @param {string} [reason] Reason for changing the guild's AFK timeout
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild AFK channel
+   * guild.setAFKTimeout(60)
+   *  .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`))
+   *  .catch(console.error);
+   */
+  setAFKTimeout(afkTimeout, reason) {
+    return this.edit({ afkTimeout, reason });
+  }
+
+  /**
+   * Sets a new guild icon.
+   * @param {?(Base64Resolvable|BufferResolvable)} icon The new icon of the guild
+   * @param {string} [reason] Reason for changing the guild's icon
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild icon
+   * guild.setIcon('./icon.png')
+   *  .then(updated => console.log('Updated the guild icon'))
+   *  .catch(console.error);
+   */
+  setIcon(icon, reason) {
+    return this.edit({ icon, reason });
+  }
+
+  /**
+   * Sets a new owner of the guild.
+   * @param {GuildMemberResolvable} owner The new owner of the guild
+   * @param {string} [reason] Reason for setting the new owner
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild owner
+   * guild.setOwner(guild.members.cache.first())
+   *  .then(guild => guild.fetchOwner())
+   *  .then(owner => console.log(`Updated the guild owner to ${owner.displayName}`))
+   *  .catch(console.error);
+   */
+  setOwner(owner, reason) {
+    return this.edit({ owner, reason });
+  }
+
+  /**
+   * Sets a new guild invite splash image.
+   * @param {?(Base64Resolvable|BufferResolvable)} splash The new invite splash image of the guild
+   * @param {string} [reason] Reason for changing the guild's invite splash image
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild splash
+   * guild.setSplash('./splash.png')
+   *  .then(updated => console.log('Updated the guild splash'))
+   *  .catch(console.error);
+   */
+  setSplash(splash, reason) {
+    return this.edit({ splash, reason });
+  }
+
+  /**
+   * Sets a new guild discovery splash image.
+   * @param {?(Base64Resolvable|BufferResolvable)} discoverySplash The new discovery splash image of the guild
+   * @param {string} [reason] Reason for changing the guild's discovery splash image
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild discovery splash
+   * guild.setDiscoverySplash('./discoverysplash.png')
+   *   .then(updated => console.log('Updated the guild discovery splash'))
+   *   .catch(console.error);
+   */
+  setDiscoverySplash(discoverySplash, reason) {
+    return this.edit({ discoverySplash, reason });
+  }
+
+  /**
+   * Sets a new guild banner.
+   * @param {?(Base64Resolvable|BufferResolvable)} banner The new banner of the guild
+   * @param {string} [reason] Reason for changing the guild's banner
+   * @returns {Promise<Guild>}
+   * @example
+   * guild.setBanner('./banner.png')
+   *  .then(updated => console.log('Updated the guild banner'))
+   *  .catch(console.error);
+   */
+  setBanner(banner, reason) {
+    return this.edit({ banner, reason });
+  }
+
+  /**
+   * Edits the rules channel of the guild.
+   * @param {?TextChannelResolvable} rulesChannel The new rules channel
+   * @param {string} [reason] Reason for changing the guild's rules channel
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild rules channel
+   * guild.setRulesChannel(channel)
+   *  .then(updated => console.log(`Updated guild rules channel to ${guild.rulesChannel.name}`))
+   *  .catch(console.error);
+   */
+  setRulesChannel(rulesChannel, reason) {
+    return this.edit({ rulesChannel, reason });
+  }
+
+  /**
+   * Edits the community updates channel of the guild.
+   * @param {?TextChannelResolvable} publicUpdatesChannel The new community updates channel
+   * @param {string} [reason] Reason for changing the guild's community updates channel
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild community updates channel
+   * guild.setPublicUpdatesChannel(channel)
+   *  .then(updated => console.log(`Updated guild community updates channel to ${guild.publicUpdatesChannel.name}`))
+   *  .catch(console.error);
+   */
+  setPublicUpdatesChannel(publicUpdatesChannel, reason) {
+    return this.edit({ publicUpdatesChannel, reason });
+  }
+
+  /**
+   * Edits the preferred locale of the guild.
+   * @param {?Locale} preferredLocale The new preferred locale of the guild
+   * @param {string} [reason] Reason for changing the guild's preferred locale
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild preferred locale
+   * guild.setPreferredLocale('en-US')
+   *  .then(updated => console.log(`Updated guild preferred locale to ${guild.preferredLocale}`))
+   *  .catch(console.error);
+   */
+  setPreferredLocale(preferredLocale, reason) {
+    return this.edit({ preferredLocale, reason });
+  }
+
+  /**
+   * Edits the enabled state of the guild's premium progress bar
+   * @param {boolean} [enabled=true] The new enabled state of the guild's premium progress bar
+   * @param {string} [reason] Reason for changing the state of the guild's premium progress bar
+   * @returns {Promise<Guild>}
+   */
+  setPremiumProgressBarEnabled(enabled = true, reason) {
+    return this.edit({ premiumProgressBarEnabled: enabled, reason });
+  }
+
+  /**
+   * Edits the safety alerts channel of the guild.
+   * @param {?TextChannelResolvable} safetyAlertsChannel The new safety alerts channel
+   * @param {string} [reason] Reason for changing the guild's safety alerts channel
+   * @returns {Promise<Guild>}
+   * @example
+   * // Edit the guild safety alerts channel
+   * guild.setSafetyAlertsChannel(channel)
+   *  .then(updated => console.log(`Updated guild safety alerts channel to ${updated.safetyAlertsChannel.name}`))
+   *  .catch(console.error);
+   */
+  setSafetyAlertsChannel(safetyAlertsChannel, reason) {
+    return this.edit({ safetyAlertsChannel, reason });
+  }
+
+  /**
+   * Edits the guild's widget settings.
+   * @param {GuildWidgetSettingsData} settings The widget settings for the guild
+   * @param {string} [reason] Reason for changing the guild's widget settings
+   * @returns {Promise<Guild>}
+   */
+  async setWidgetSettings(settings, reason) {
+    await this.client.rest.patch(Routes.guildWidgetSettings(this.id), {
+      body: {
+        enabled: settings.enabled,
+        channel_id: this.channels.resolveId(settings.channel),
+      },
+      reason,
+    });
+    return this;
+  }
+
+  /**
+   * Sets the guild's MFA level
+   * <info>An elevated MFA level requires guild moderators to have 2FA enabled.</info>
+   * @param {GuildMFALevel} level The MFA level
+   * @param {string} [reason] Reason for changing the guild's MFA level
+   * @returns {Promise<Guild>}
+   * @example
+   * // Set the MFA level of the guild to Elevated
+   * guild.setMFALevel(GuildMFALevel.Elevated)
+   *   .then(guild => console.log("Set guild's MFA level to Elevated"))
+   *   .catch(console.error);
+   */
+  async setMFALevel(level, reason) {
+    await this.client.rest.post(Routes.guildMFA(this.id), {
+      body: {
+        level,
+      },
+      reason,
+    });
+    return this;
+  }
+
+  /**
+   * Leaves the guild.
+   * @returns {Promise<Guild>}
+   * @example
+   * // Leave a guild
+   * guild.leave()
+   *   .then(guild => console.log(`Left the guild: ${guild.name}`))
+   *   .catch(console.error);
+   */
+  async leave() {
+    if (this.ownerId === this.client.user.id) throw new DiscordjsError(ErrorCodes.GuildOwned);
+    await this.client.rest.delete(Routes.userGuild(this.id));
+    return this;
+  }
+
+  /**
+   * Deletes the guild.
+   * @returns {Promise<Guild>}
+   * @example
+   * // Delete a guild
+   * guild.delete()
+   *   .then(g => console.log(`Deleted the guild ${g}`))
+   *   .catch(console.error);
+   */
+  async delete() {
+    await this.client.rest.delete(Routes.guild(this.id));
+    return this;
+  }
+
+  /**
+   * Sets whether this guild's invites are disabled.
+   * @param {boolean} [disabled=true] Whether the invites are disabled
+   * @returns {Promise<Guild>}
+   */
+  async disableInvites(disabled = true) {
+    const features = this.features.filter(feature => feature !== GuildFeature.InvitesDisabled);
+    if (disabled) features.push(GuildFeature.InvitesDisabled);
+    return this.edit({ features });
+  }
+
+  /**
+   * Whether this guild equals another guild. It compares all properties, so for most operations
+   * it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often
+   * what most users need.
+   * @param {Guild} guild The guild to compare with
+   * @returns {boolean}
+   */
+  equals(guild) {
+    return (
+      guild &&
+      guild instanceof this.constructor &&
+      this.id === guild.id &&
+      this.available === guild.available &&
+      this.splash === guild.splash &&
+      this.discoverySplash === guild.discoverySplash &&
+      this.name === guild.name &&
+      this.memberCount === guild.memberCount &&
+      this.large === guild.large &&
+      this.icon === guild.icon &&
+      this.ownerId === guild.ownerId &&
+      this.verificationLevel === guild.verificationLevel &&
+      (this.features === guild.features ||
+        (this.features.length === guild.features.length &&
+          this.features.every((feat, i) => feat === guild.features[i])))
+    );
+  }
+
+  toJSON() {
+    const json = super.toJSON({
+      available: false,
+      createdTimestamp: true,
+      nameAcronym: true,
+      presences: false,
+      voiceStates: false,
+    });
+    json.iconURL = this.iconURL();
+    json.splashURL = this.splashURL();
+    json.discoverySplashURL = this.discoverySplashURL();
+    json.bannerURL = this.bannerURL();
+    return json;
+  }
+
+  /**
+   * The voice state adapter for this guild that can be used with @discordjs/voice to play audio in voice
+   * and stage channels.
+   * @type {Function}
+   * @readonly
+   */
+  get voiceAdapterCreator() {
+    return methods => {
+      this.client.voice.adapters.set(this.id, methods);
+      return {
+        sendPayload: data => {
+          if (this.shard.status !== Status.Ready) return false;
+          this.shard.send(data);
+          return true;
+        },
+        destroy: () => {
+          this.client.voice.adapters.delete(this.id);
+        },
+      };
+    };
+  }
+
+  /**
+   * Creates a collection of this guild's roles, sorted by their position and ids.
+   * @returns {Collection<Snowflake, Role>}
+   * @private
+   */
+  _sortedRoles() {
+    return discordSort(this.roles.cache);
+  }
+
+  /**
+   * Creates a collection of this guild's or a specific category's channels, sorted by their position and ids.
+   * @param {GuildChannel} [channel] Category to get the channels of
+   * @returns {Collection<Snowflake, GuildChannel>}
+   * @private
+   */
+  _sortedChannels(channel) {
+    const channelIsCategory = channel.type === ChannelType.GuildCategory;
+    const types = getSortableGroupTypes(channel.type);
+    return discordSort(
+      this.channels.cache.filter(c => types.includes(c.type) && (channelIsCategory || c.parentId === channel.parentId)),
+    );
+  }
+}
+
+exports.Guild = Guild;
+
+/**
+ * @external APIGuild
+ * @see {@link https://discord.com/developers/docs/resources/guild#guild-object}
+ */
diff --git a/node_modules/discord.js/src/structures/GuildAuditLogs.js b/node_modules/discord.js/src/structures/GuildAuditLogs.js
new file mode 100644
index 0000000..2ce13a8
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildAuditLogs.js
@@ -0,0 +1,91 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const ApplicationCommand = require('./ApplicationCommand');
+const GuildAuditLogsEntry = require('./GuildAuditLogsEntry');
+const Integration = require('./Integration');
+const Webhook = require('./Webhook');
+const { flatten } = require('../util/Util');
+
+/**
+ * Audit logs entries are held in this class.
+ */
+class GuildAuditLogs {
+  constructor(guild, data) {
+    if (data.users) for (const user of data.users) guild.client.users._add(user);
+    if (data.threads) for (const thread of data.threads) guild.client.channels._add(thread, guild);
+    /**
+     * Cached webhooks
+     * @type {Collection<Snowflake, Webhook>}
+     * @private
+     */
+    this.webhooks = new Collection();
+    if (data.webhooks) {
+      for (const hook of data.webhooks) {
+        this.webhooks.set(hook.id, new Webhook(guild.client, hook));
+      }
+    }
+
+    /**
+     * Cached integrations
+     * @type {Collection<Snowflake|string, Integration>}
+     * @private
+     */
+    this.integrations = new Collection();
+    if (data.integrations) {
+      for (const integration of data.integrations) {
+        this.integrations.set(integration.id, new Integration(guild.client, integration, guild));
+      }
+    }
+
+    /**
+     * Cached {@link GuildScheduledEvent}s.
+     * @type {Collection<Snowflake, GuildScheduledEvent>}
+     * @private
+     */
+    this.guildScheduledEvents = data.guild_scheduled_events.reduce(
+      (guildScheduledEvents, guildScheduledEvent) =>
+        guildScheduledEvents.set(guildScheduledEvent.id, guild.scheduledEvents._add(guildScheduledEvent)),
+      new Collection(),
+    );
+
+    /**
+     * Cached application commands, includes application commands from other applications
+     * @type {Collection<Snowflake, ApplicationCommand>}
+     * @private
+     */
+    this.applicationCommands = new Collection();
+    if (data.application_commands) {
+      for (const command of data.application_commands) {
+        this.applicationCommands.set(command.id, new ApplicationCommand(guild.client, command, guild));
+      }
+    }
+
+    /**
+     * Cached auto moderation rules.
+     * @type {Collection<Snowflake, AutoModerationRule>}
+     * @private
+     */
+    this.autoModerationRules = data.auto_moderation_rules.reduce(
+      (autoModerationRules, autoModerationRule) =>
+        autoModerationRules.set(autoModerationRule.id, guild.autoModerationRules._add(autoModerationRule)),
+      new Collection(),
+    );
+
+    /**
+     * The entries for this guild's audit logs
+     * @type {Collection<Snowflake, GuildAuditLogsEntry>}
+     */
+    this.entries = new Collection();
+    for (const item of data.audit_log_entries) {
+      const entry = new GuildAuditLogsEntry(guild, item, this);
+      this.entries.set(entry.id, entry);
+    }
+  }
+
+  toJSON() {
+    return flatten(this);
+  }
+}
+
+module.exports = GuildAuditLogs;
diff --git a/node_modules/discord.js/src/structures/GuildAuditLogsEntry.js b/node_modules/discord.js/src/structures/GuildAuditLogsEntry.js
new file mode 100644
index 0000000..febbd12
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildAuditLogsEntry.js
@@ -0,0 +1,528 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { AuditLogOptionsType, AuditLogEvent } = require('discord-api-types/v10');
+const AutoModerationRule = require('./AutoModerationRule');
+const { GuildScheduledEvent } = require('./GuildScheduledEvent');
+const Integration = require('./Integration');
+const Invite = require('./Invite');
+const { StageInstance } = require('./StageInstance');
+const { Sticker } = require('./Sticker');
+const Webhook = require('./Webhook');
+const Partials = require('../util/Partials');
+const { flatten } = require('../util/Util');
+
+const Targets = {
+  All: 'All',
+  Guild: 'Guild',
+  GuildScheduledEvent: 'GuildScheduledEvent',
+  Channel: 'Channel',
+  User: 'User',
+  Role: 'Role',
+  Invite: 'Invite',
+  Webhook: 'Webhook',
+  Emoji: 'Emoji',
+  Message: 'Message',
+  Integration: 'Integration',
+  StageInstance: 'StageInstance',
+  Sticker: 'Sticker',
+  Thread: 'Thread',
+  ApplicationCommand: 'ApplicationCommand',
+  AutoModeration: 'AutoModeration',
+  Unknown: 'Unknown',
+};
+
+/**
+ * The target of a guild audit log entry. It can be one of:
+ * * A guild
+ * * A channel
+ * * A user
+ * * A role
+ * * An invite
+ * * A webhook
+ * * An emoji
+ * * A message
+ * * An integration
+ * * A stage instance
+ * * A sticker
+ * * A guild scheduled event
+ * * A thread
+ * * An application command
+ * * An auto moderation rule
+ * * An object with an id key if target was deleted or fake entity
+ * * An object where the keys represent either the new value or the old value
+ * @typedef {?(Object|Guild|BaseChannel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker|
+ * GuildScheduledEvent|ApplicationCommand|AutoModerationRule)} AuditLogEntryTarget
+ */
+
+/**
+ * The action type of an entry, e.g. `Create`. Here are the available types:
+ * * Create
+ * * Delete
+ * * Update
+ * * All
+ * @typedef {string} AuditLogActionType
+ */
+
+/**
+ * The target type of an entry. Here are the available types:
+ * * Guild
+ * * Channel
+ * * User
+ * * Role
+ * * Invite
+ * * Webhook
+ * * Emoji
+ * * Message
+ * * Integration
+ * * StageInstance
+ * * Sticker
+ * * Thread
+ * * GuildScheduledEvent
+ * * ApplicationCommandPermission
+ * @typedef {string} AuditLogTargetType
+ */
+
+/**
+ * Audit logs entry.
+ */
+class GuildAuditLogsEntry {
+  /**
+   * Key mirror of all available audit log targets.
+   * @type {Object<string, string>}
+   * @memberof GuildAuditLogsEntry
+   */
+  static Targets = Targets;
+
+  constructor(guild, data, logs) {
+    /**
+     * The target type of this entry
+     * @type {AuditLogTargetType}
+     */
+    this.targetType = GuildAuditLogsEntry.targetType(data.action_type);
+    const targetType = this.targetType;
+
+    /**
+     * The action type of this entry
+     * @type {AuditLogActionType}
+     */
+    this.actionType = GuildAuditLogsEntry.actionType(data.action_type);
+
+    /**
+     * The type of action that occurred.
+     * @type {AuditLogEvent}
+     */
+    this.action = data.action_type;
+
+    /**
+     * The reason of this entry
+     * @type {?string}
+     */
+    this.reason = data.reason ?? null;
+
+    /**
+     * The id of the user that executed this entry
+     * @type {?Snowflake}
+     */
+    this.executorId = data.user_id;
+
+    /**
+     * The user that executed this entry
+     * @type {?User}
+     */
+    this.executor = data.user_id
+      ? guild.client.options.partials.includes(Partials.User)
+        ? guild.client.users._add({ id: data.user_id })
+        : guild.client.users.cache.get(data.user_id) ?? null
+      : null;
+
+    /**
+     * An entry in the audit log representing a specific change.
+     * @typedef {Object} AuditLogChange
+     * @property {string} key The property that was changed, e.g. `nick` for nickname changes
+     * <warn>For application command permissions updates the key is the id of the user, channel,
+     * role, or a permission constant that was updated instead of an actual property name</warn>
+     * @property {*} [old] The old value of the change, e.g. for nicknames, the old nickname
+     * @property {*} [new] The new value of the change, e.g. for nicknames, the new nickname
+     */
+
+    /**
+     * Specific property changes
+     * @type {AuditLogChange[]}
+     */
+    this.changes = data.changes?.map(c => ({ key: c.key, old: c.old_value, new: c.new_value })) ?? [];
+
+    /**
+     * The entry's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * Any extra data from the entry
+     * @type {?(Object|Role|GuildMember)}
+     */
+    this.extra = null;
+    switch (data.action_type) {
+      case AuditLogEvent.MemberPrune:
+        this.extra = {
+          removed: Number(data.options.members_removed),
+          days: Number(data.options.delete_member_days),
+        };
+        break;
+
+      case AuditLogEvent.MemberMove:
+      case AuditLogEvent.MessageDelete:
+      case AuditLogEvent.MessageBulkDelete:
+        this.extra = {
+          channel: guild.channels.cache.get(data.options.channel_id) ?? { id: data.options.channel_id },
+          count: Number(data.options.count),
+        };
+        break;
+
+      case AuditLogEvent.MessagePin:
+      case AuditLogEvent.MessageUnpin:
+        this.extra = {
+          channel: guild.client.channels.cache.get(data.options.channel_id) ?? { id: data.options.channel_id },
+          messageId: data.options.message_id,
+        };
+        break;
+
+      case AuditLogEvent.MemberDisconnect:
+        this.extra = {
+          count: Number(data.options.count),
+        };
+        break;
+
+      case AuditLogEvent.ChannelOverwriteCreate:
+      case AuditLogEvent.ChannelOverwriteUpdate:
+      case AuditLogEvent.ChannelOverwriteDelete:
+        switch (data.options.type) {
+          case AuditLogOptionsType.Role:
+            this.extra = guild.roles.cache.get(data.options.id) ?? {
+              id: data.options.id,
+              name: data.options.role_name,
+              type: AuditLogOptionsType.Role,
+            };
+            break;
+
+          case AuditLogOptionsType.Member:
+            this.extra = guild.members.cache.get(data.options.id) ?? {
+              id: data.options.id,
+              type: AuditLogOptionsType.Member,
+            };
+            break;
+
+          default:
+            break;
+        }
+        break;
+
+      case AuditLogEvent.StageInstanceCreate:
+      case AuditLogEvent.StageInstanceDelete:
+      case AuditLogEvent.StageInstanceUpdate:
+        this.extra = {
+          channel: guild.client.channels.cache.get(data.options?.channel_id) ?? { id: data.options?.channel_id },
+        };
+        break;
+
+      case AuditLogEvent.ApplicationCommandPermissionUpdate:
+        this.extra = {
+          applicationId: data.options.application_id,
+        };
+        break;
+
+      case AuditLogEvent.AutoModerationBlockMessage:
+      case AuditLogEvent.AutoModerationFlagToChannel:
+      case AuditLogEvent.AutoModerationUserCommunicationDisabled:
+        this.extra = {
+          autoModerationRuleName: data.options.auto_moderation_rule_name,
+          autoModerationRuleTriggerType: data.options.auto_moderation_rule_trigger_type,
+          channel: guild.client.channels.cache.get(data.options?.channel_id) ?? { id: data.options?.channel_id },
+        };
+        break;
+
+      default:
+        break;
+    }
+
+    /**
+     * The id of the target of this entry
+     * @type {?Snowflake}
+     */
+    this.targetId = data.target_id;
+
+    /**
+     * The target of this entry
+     * @type {?AuditLogEntryTarget}
+     */
+    this.target = null;
+    if (targetType === Targets.Unknown) {
+      this.target = this.changes.reduce((o, c) => {
+        o[c.key] = c.new ?? c.old;
+        return o;
+      }, {});
+      this.target.id = data.target_id;
+      // MemberDisconnect and similar types do not provide a target_id.
+    } else if (targetType === Targets.User && data.target_id) {
+      this.target = guild.client.options.partials.includes(Partials.User)
+        ? guild.client.users._add({ id: data.target_id })
+        : guild.client.users.cache.get(data.target_id) ?? null;
+    } else if (targetType === Targets.Guild) {
+      this.target = guild.client.guilds.cache.get(data.target_id);
+    } else if (targetType === Targets.Webhook) {
+      this.target =
+        logs?.webhooks.get(data.target_id) ??
+        new Webhook(
+          guild.client,
+          this.changes.reduce(
+            (o, c) => {
+              o[c.key] = c.new ?? c.old;
+              return o;
+            },
+            {
+              id: data.target_id,
+              guild_id: guild.id,
+            },
+          ),
+        );
+    } else if (targetType === Targets.Invite) {
+      let change = this.changes.find(c => c.key === 'code');
+      change = change.new ?? change.old;
+
+      this.target =
+        guild.invites.cache.get(change) ??
+        new Invite(
+          guild.client,
+          this.changes.reduce(
+            (o, c) => {
+              o[c.key] = c.new ?? c.old;
+              return o;
+            },
+            { guild },
+          ),
+        );
+    } else if (targetType === Targets.Message) {
+      // Discord sends a channel id for the MessageBulkDelete action type.
+      this.target =
+        data.action_type === AuditLogEvent.MessageBulkDelete
+          ? guild.channels.cache.get(data.target_id) ?? { id: data.target_id }
+          : guild.client.users.cache.get(data.target_id) ?? null;
+    } else if (targetType === Targets.Integration) {
+      this.target =
+        logs?.integrations.get(data.target_id) ??
+        new Integration(
+          guild.client,
+          this.changes.reduce(
+            (o, c) => {
+              o[c.key] = c.new ?? c.old;
+              return o;
+            },
+            { id: data.target_id },
+          ),
+          guild,
+        );
+    } else if (targetType === Targets.Channel || targetType === Targets.Thread) {
+      this.target =
+        guild.channels.cache.get(data.target_id) ??
+        this.changes.reduce(
+          (o, c) => {
+            o[c.key] = c.new ?? c.old;
+            return o;
+          },
+          { id: data.target_id },
+        );
+    } else if (targetType === Targets.StageInstance) {
+      this.target =
+        guild.stageInstances.cache.get(data.target_id) ??
+        new StageInstance(
+          guild.client,
+          this.changes.reduce(
+            (o, c) => {
+              o[c.key] = c.new ?? c.old;
+              return o;
+            },
+            {
+              id: data.target_id,
+              channel_id: data.options?.channel_id,
+              guild_id: guild.id,
+            },
+          ),
+        );
+    } else if (targetType === Targets.Sticker) {
+      this.target =
+        guild.stickers.cache.get(data.target_id) ??
+        new Sticker(
+          guild.client,
+          this.changes.reduce(
+            (o, c) => {
+              o[c.key] = c.new ?? c.old;
+              return o;
+            },
+            { id: data.target_id },
+          ),
+        );
+    } else if (targetType === Targets.GuildScheduledEvent) {
+      this.target =
+        guild.scheduledEvents.cache.get(data.target_id) ??
+        new GuildScheduledEvent(
+          guild.client,
+          this.changes.reduce(
+            (o, c) => {
+              o[c.key] = c.new ?? c.old;
+              return o;
+            },
+            { id: data.target_id, guild_id: guild.id },
+          ),
+        );
+    } else if (targetType === Targets.ApplicationCommand) {
+      this.target = logs?.applicationCommands.get(data.target_id) ?? { id: data.target_id };
+    } else if (targetType === Targets.AutoModeration) {
+      this.target =
+        guild.autoModerationRules.cache.get(data.target_id) ??
+        new AutoModerationRule(
+          guild.client,
+          this.changes.reduce(
+            (o, c) => {
+              o[c.key] = c.new ?? c.old;
+              return o;
+            },
+            { id: data.target_id, guild_id: guild.id },
+          ),
+          guild,
+        );
+    } else if (data.target_id) {
+      this.target = guild[`${targetType.toLowerCase()}s`]?.cache.get(data.target_id) ?? { id: data.target_id };
+    }
+  }
+
+  /**
+   * Finds the target type of a guild audit log entry.
+   * @param {AuditLogEvent} target The action target
+   * @returns {AuditLogTargetType}
+   */
+  static targetType(target) {
+    if (target < 10) return Targets.Guild;
+    if (target < 20) return Targets.Channel;
+    if (target < 30) return Targets.User;
+    if (target < 40) return Targets.Role;
+    if (target < 50) return Targets.Invite;
+    if (target < 60) return Targets.Webhook;
+    if (target < 70) return Targets.Emoji;
+    if (target < 80) return Targets.Message;
+    if (target < 83) return Targets.Integration;
+    if (target < 86) return Targets.StageInstance;
+    if (target < 100) return Targets.Sticker;
+    if (target < 110) return Targets.GuildScheduledEvent;
+    if (target < 120) return Targets.Thread;
+    if (target < 130) return Targets.ApplicationCommand;
+    if (target >= 140 && target < 150) return Targets.AutoModeration;
+    return Targets.Unknown;
+  }
+
+  /**
+   * Finds the action type from the guild audit log entry action.
+   * @param {AuditLogEvent} action The action target
+   * @returns {AuditLogActionType}
+   */
+  static actionType(action) {
+    if (
+      [
+        AuditLogEvent.ChannelCreate,
+        AuditLogEvent.ChannelOverwriteCreate,
+        AuditLogEvent.MemberBanRemove,
+        AuditLogEvent.BotAdd,
+        AuditLogEvent.RoleCreate,
+        AuditLogEvent.InviteCreate,
+        AuditLogEvent.WebhookCreate,
+        AuditLogEvent.EmojiCreate,
+        AuditLogEvent.MessagePin,
+        AuditLogEvent.IntegrationCreate,
+        AuditLogEvent.StageInstanceCreate,
+        AuditLogEvent.StickerCreate,
+        AuditLogEvent.GuildScheduledEventCreate,
+        AuditLogEvent.ThreadCreate,
+        AuditLogEvent.AutoModerationRuleCreate,
+        AuditLogEvent.AutoModerationBlockMessage,
+      ].includes(action)
+    ) {
+      return 'Create';
+    }
+
+    if (
+      [
+        AuditLogEvent.ChannelDelete,
+        AuditLogEvent.ChannelOverwriteDelete,
+        AuditLogEvent.MemberKick,
+        AuditLogEvent.MemberPrune,
+        AuditLogEvent.MemberBanAdd,
+        AuditLogEvent.MemberDisconnect,
+        AuditLogEvent.RoleDelete,
+        AuditLogEvent.InviteDelete,
+        AuditLogEvent.WebhookDelete,
+        AuditLogEvent.EmojiDelete,
+        AuditLogEvent.MessageDelete,
+        AuditLogEvent.MessageBulkDelete,
+        AuditLogEvent.MessageUnpin,
+        AuditLogEvent.IntegrationDelete,
+        AuditLogEvent.StageInstanceDelete,
+        AuditLogEvent.StickerDelete,
+        AuditLogEvent.GuildScheduledEventDelete,
+        AuditLogEvent.ThreadDelete,
+        AuditLogEvent.AutoModerationRuleDelete,
+      ].includes(action)
+    ) {
+      return 'Delete';
+    }
+
+    if (
+      [
+        AuditLogEvent.GuildUpdate,
+        AuditLogEvent.ChannelUpdate,
+        AuditLogEvent.ChannelOverwriteUpdate,
+        AuditLogEvent.MemberUpdate,
+        AuditLogEvent.MemberRoleUpdate,
+        AuditLogEvent.MemberMove,
+        AuditLogEvent.RoleUpdate,
+        AuditLogEvent.InviteUpdate,
+        AuditLogEvent.WebhookUpdate,
+        AuditLogEvent.EmojiUpdate,
+        AuditLogEvent.IntegrationUpdate,
+        AuditLogEvent.StageInstanceUpdate,
+        AuditLogEvent.StickerUpdate,
+        AuditLogEvent.GuildScheduledEventUpdate,
+        AuditLogEvent.ThreadUpdate,
+        AuditLogEvent.ApplicationCommandPermissionUpdate,
+        AuditLogEvent.AutoModerationRuleUpdate,
+      ].includes(action)
+    ) {
+      return 'Update';
+    }
+
+    return 'All';
+  }
+
+  /**
+   * The timestamp this entry was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time this entry was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  toJSON() {
+    return flatten(this, { createdTimestamp: true });
+  }
+}
+
+module.exports = GuildAuditLogsEntry;
diff --git a/node_modules/discord.js/src/structures/GuildBan.js b/node_modules/discord.js/src/structures/GuildBan.js
new file mode 100644
index 0000000..9c5a10e
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildBan.js
@@ -0,0 +1,59 @@
+'use strict';
+
+const Base = require('./Base');
+
+/**
+ * Represents a ban in a guild on Discord.
+ * @extends {Base}
+ */
+class GuildBan extends Base {
+  constructor(client, data, guild) {
+    super(client);
+
+    /**
+     * The guild in which the ban is
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('user' in data) {
+      /**
+       * The user this ban applies to
+       * @type {User}
+       */
+      this.user = this.client.users._add(data.user, true);
+    }
+
+    if ('reason' in data) {
+      /**
+       * The reason for the ban
+       * @type {?string}
+       */
+      this.reason = data.reason;
+    }
+  }
+
+  /**
+   * Whether this GuildBan is partial. If the reason is not provided the value is null
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return !('reason' in this);
+  }
+
+  /**
+   * Fetches this GuildBan.
+   * @param {boolean} [force=true] Whether to skip the cache check and request the API
+   * @returns {Promise<GuildBan>}
+   */
+  fetch(force = true) {
+    return this.guild.bans.fetch({ user: this.user, cache: true, force });
+  }
+}
+
+module.exports = GuildBan;
diff --git a/node_modules/discord.js/src/structures/GuildChannel.js b/node_modules/discord.js/src/structures/GuildChannel.js
new file mode 100644
index 0000000..c066c71
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildChannel.js
@@ -0,0 +1,472 @@
+'use strict';
+
+const { Snowflake } = require('@sapphire/snowflake');
+const { PermissionFlagsBits, ChannelType } = require('discord-api-types/v10');
+const { BaseChannel } = require('./BaseChannel');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager');
+const { VoiceBasedChannelTypes } = require('../util/Constants');
+const PermissionsBitField = require('../util/PermissionsBitField');
+const { getSortableGroupTypes } = require('../util/Util');
+
+/**
+ * Represents a guild channel from any of the following:
+ * - {@link TextChannel}
+ * - {@link VoiceChannel}
+ * - {@link CategoryChannel}
+ * - {@link NewsChannel}
+ * - {@link StageChannel}
+ * - {@link ForumChannel}
+ * @extends {BaseChannel}
+ * @abstract
+ */
+class GuildChannel extends BaseChannel {
+  constructor(guild, data, client, immediatePatch = true) {
+    super(client, data, false);
+
+    /**
+     * The guild the channel is in
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The id of the guild the channel is in
+     * @type {Snowflake}
+     */
+    this.guildId = guild?.id ?? data.guild_id;
+    /**
+     * A manager of permission overwrites that belong to this channel
+     * @type {PermissionOverwriteManager}
+     */
+    this.permissionOverwrites = new PermissionOverwriteManager(this);
+
+    if (data && immediatePatch) this._patch(data);
+  }
+
+  _patch(data) {
+    super._patch(data);
+
+    if ('name' in data) {
+      /**
+       * The name of the guild channel
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('position' in data) {
+      /**
+       * The raw position of the channel from Discord
+       * @type {number}
+       */
+      this.rawPosition = data.position;
+    }
+
+    if ('guild_id' in data) {
+      this.guildId = data.guild_id;
+    }
+
+    if ('parent_id' in data) {
+      /**
+       * The id of the category parent of this channel
+       * @type {?Snowflake}
+       */
+      this.parentId = data.parent_id;
+    } else {
+      this.parentId ??= null;
+    }
+
+    if ('permission_overwrites' in data) {
+      this.permissionOverwrites.cache.clear();
+      for (const overwrite of data.permission_overwrites) {
+        this.permissionOverwrites._add(overwrite);
+      }
+    }
+  }
+
+  _clone() {
+    const clone = super._clone();
+    clone.permissionOverwrites = new PermissionOverwriteManager(clone, this.permissionOverwrites.cache.values());
+    return clone;
+  }
+
+  /**
+   * The category parent of this channel
+   * @type {?CategoryChannel}
+   * @readonly
+   */
+  get parent() {
+    return this.guild.channels.resolve(this.parentId);
+  }
+
+  /**
+   * If the permissionOverwrites match the parent channel, null if no parent
+   * @type {?boolean}
+   * @readonly
+   */
+  get permissionsLocked() {
+    if (!this.parent) return null;
+
+    // Get all overwrites
+    const overwriteIds = new Set([
+      ...this.permissionOverwrites.cache.keys(),
+      ...this.parent.permissionOverwrites.cache.keys(),
+    ]);
+
+    // Compare all overwrites
+    return [...overwriteIds].every(key => {
+      const channelVal = this.permissionOverwrites.cache.get(key);
+      const parentVal = this.parent.permissionOverwrites.cache.get(key);
+
+      // Handle empty overwrite
+      if (
+        (!channelVal &&
+          parentVal.deny.bitfield === PermissionsBitField.DefaultBit &&
+          parentVal.allow.bitfield === PermissionsBitField.DefaultBit) ||
+        (!parentVal &&
+          channelVal.deny.bitfield === PermissionsBitField.DefaultBit &&
+          channelVal.allow.bitfield === PermissionsBitField.DefaultBit)
+      ) {
+        return true;
+      }
+
+      // Compare overwrites
+      return (
+        channelVal !== undefined &&
+        parentVal !== undefined &&
+        channelVal.deny.bitfield === parentVal.deny.bitfield &&
+        channelVal.allow.bitfield === parentVal.allow.bitfield
+      );
+    });
+  }
+
+  /**
+   * The position of the channel
+   * @type {number}
+   * @readonly
+   */
+  get position() {
+    const selfIsCategory = this.type === ChannelType.GuildCategory;
+    const types = getSortableGroupTypes(this.type);
+
+    let count = 0;
+    for (const channel of this.guild.channels.cache.values()) {
+      if (!types.includes(channel.type)) continue;
+      if (!selfIsCategory && channel.parentId !== this.parentId) continue;
+      if (this.rawPosition === channel.rawPosition) {
+        if (Snowflake.compare(channel.id, this.id) === -1) count++;
+      } else if (this.rawPosition > channel.rawPosition) {
+        count++;
+      }
+    }
+
+    return count;
+  }
+
+  /**
+   * Gets the overall set of permissions for a member or role in this channel, taking into account channel overwrites.
+   * @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for
+   * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission
+   * will return all permissions
+   * @returns {?Readonly<PermissionsBitField>}
+   */
+  permissionsFor(memberOrRole, checkAdmin = true) {
+    const member = this.guild.members.resolve(memberOrRole);
+    if (member) return this.memberPermissions(member, checkAdmin);
+    const role = this.guild.roles.resolve(memberOrRole);
+    return role && this.rolePermissions(role, checkAdmin);
+  }
+
+  overwritesFor(member, verified = false, roles = null) {
+    if (!verified) member = this.guild.members.resolve(member);
+    if (!member) return [];
+
+    roles ??= member.roles.cache;
+    const roleOverwrites = [];
+    let memberOverwrites;
+    let everyoneOverwrites;
+
+    for (const overwrite of this.permissionOverwrites.cache.values()) {
+      if (overwrite.id === this.guild.id) {
+        everyoneOverwrites = overwrite;
+      } else if (roles.has(overwrite.id)) {
+        roleOverwrites.push(overwrite);
+      } else if (overwrite.id === member.id) {
+        memberOverwrites = overwrite;
+      }
+    }
+
+    return {
+      everyone: everyoneOverwrites,
+      roles: roleOverwrites,
+      member: memberOverwrites,
+    };
+  }
+
+  /**
+   * Gets the overall set of permissions for a member in this channel, taking into account channel overwrites.
+   * @param {GuildMember} member The member to obtain the overall permissions for
+   * @param {boolean} checkAdmin Whether having the {@link PermissionFlagsBits.Administrator} permission
+   * will return all permissions
+   * @returns {Readonly<PermissionsBitField>}
+   * @private
+   */
+  memberPermissions(member, checkAdmin) {
+    if (checkAdmin && member.id === this.guild.ownerId) {
+      return new PermissionsBitField(PermissionsBitField.All).freeze();
+    }
+
+    const roles = member.roles.cache;
+    const permissions = new PermissionsBitField(roles.map(role => role.permissions));
+
+    if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) {
+      return new PermissionsBitField(PermissionsBitField.All).freeze();
+    }
+
+    const overwrites = this.overwritesFor(member, true, roles);
+
+    return permissions
+      .remove(overwrites.everyone?.deny ?? PermissionsBitField.DefaultBit)
+      .add(overwrites.everyone?.allow ?? PermissionsBitField.DefaultBit)
+      .remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny) : PermissionsBitField.DefaultBit)
+      .add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow) : PermissionsBitField.DefaultBit)
+      .remove(overwrites.member?.deny ?? PermissionsBitField.DefaultBit)
+      .add(overwrites.member?.allow ?? PermissionsBitField.DefaultBit)
+      .freeze();
+  }
+
+  /**
+   * Gets the overall set of permissions for a role in this channel, taking into account channel overwrites.
+   * @param {Role} role The role to obtain the overall permissions for
+   * @param {boolean} checkAdmin Whether having the {@link PermissionFlagsBits.Administrator} permission
+   * will return all permissions
+   * @returns {Readonly<PermissionsBitField>}
+   * @private
+   */
+  rolePermissions(role, checkAdmin) {
+    if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) {
+      return new PermissionsBitField(PermissionsBitField.All).freeze();
+    }
+
+    const everyoneOverwrites = this.permissionOverwrites.cache.get(this.guild.id);
+    const roleOverwrites = this.permissionOverwrites.cache.get(role.id);
+
+    return role.permissions
+      .remove(everyoneOverwrites?.deny ?? PermissionsBitField.DefaultBit)
+      .add(everyoneOverwrites?.allow ?? PermissionsBitField.DefaultBit)
+      .remove(roleOverwrites?.deny ?? PermissionsBitField.DefaultBit)
+      .add(roleOverwrites?.allow ?? PermissionsBitField.DefaultBit)
+      .freeze();
+  }
+
+  /**
+   * Locks in the permission overwrites from the parent channel.
+   * @returns {Promise<GuildChannel>}
+   */
+  lockPermissions() {
+    if (!this.parent) return Promise.reject(new DiscordjsError(ErrorCodes.GuildChannelOrphan));
+    const permissionOverwrites = this.parent.permissionOverwrites.cache.map(overwrite => overwrite.toJSON());
+    return this.edit({ permissionOverwrites });
+  }
+
+  /**
+   * A collection of cached members of this channel, mapped by their ids.
+   * Members that can view this channel, if the channel is text-based.
+   * Members in the channel, if the channel is voice-based.
+   * @type {Collection<Snowflake, GuildMember>}
+   * @readonly
+   */
+  get members() {
+    return this.guild.members.cache.filter(m => this.permissionsFor(m).has(PermissionFlagsBits.ViewChannel, false));
+  }
+
+  /**
+   * Edits the channel.
+   * @param {GuildChannelEditOptions} options The options to provide
+   * @returns {Promise<GuildChannel>}
+   * @example
+   * // Edit a channel
+   * channel.edit({ name: 'new-channel' })
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  edit(options) {
+    return this.guild.channels.edit(this, options);
+  }
+
+  /**
+   * Sets a new name for the guild channel.
+   * @param {string} name The new name for the guild channel
+   * @param {string} [reason] Reason for changing the guild channel's name
+   * @returns {Promise<GuildChannel>}
+   * @example
+   * // Set a new channel name
+   * channel.setName('not_general')
+   *   .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`))
+   *   .catch(console.error);
+   */
+  setName(name, reason) {
+    return this.edit({ name, reason });
+  }
+
+  /**
+   * Options used to set the parent of a channel.
+   * @typedef {Object} SetParentOptions
+   * @property {boolean} [lockPermissions=true] Whether to lock the permissions to what the parent's permissions are
+   * @property {string} [reason] The reason for modifying the parent of the channel
+   */
+
+  /**
+   * Sets the parent of this channel.
+   * @param {?CategoryChannelResolvable} channel The category channel to set as the parent
+   * @param {SetParentOptions} [options={}] The options for setting the parent
+   * @returns {Promise<GuildChannel>}
+   * @example
+   * // Add a parent to a channel
+   * message.channel.setParent('355908108431917066', { lockPermissions: false })
+   *   .then(channel => console.log(`New parent of ${message.channel.name}: ${channel.name}`))
+   *   .catch(console.error);
+   */
+  setParent(channel, { lockPermissions = true, reason } = {}) {
+    return this.edit({
+      parent: channel ?? null,
+      lockPermissions,
+      reason,
+    });
+  }
+
+  /**
+   * Options used to set the position of a channel.
+   * @typedef {Object} SetChannelPositionOptions
+   * @property {boolean} [relative=false] Whether or not to change the position relative to its current value
+   * @property {string} [reason] The reason for changing the position
+   */
+
+  /**
+   * Sets a new position for the guild channel.
+   * @param {number} position The new position for the guild channel
+   * @param {SetChannelPositionOptions} [options] Options for setting position
+   * @returns {Promise<GuildChannel>}
+   * @example
+   * // Set a new channel position
+   * channel.setPosition(2)
+   *   .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
+   *   .catch(console.error);
+   */
+  setPosition(position, options = {}) {
+    return this.guild.channels.setPosition(this, position, options);
+  }
+
+  /**
+   * Options used to clone a guild channel.
+   * @typedef {GuildChannelCreateOptions} GuildChannelCloneOptions
+   * @property {string} [name=this.name] Name of the new channel
+   */
+
+  /**
+   * Clones this channel.
+   * @param {GuildChannelCloneOptions} [options] The options for cloning this channel
+   * @returns {Promise<GuildChannel>}
+   */
+  clone(options = {}) {
+    return this.guild.channels.create({
+      name: options.name ?? this.name,
+      permissionOverwrites: this.permissionOverwrites.cache,
+      topic: this.topic,
+      type: this.type,
+      nsfw: this.nsfw,
+      parent: this.parent,
+      bitrate: this.bitrate,
+      userLimit: this.userLimit,
+      rateLimitPerUser: this.rateLimitPerUser,
+      position: this.rawPosition,
+      reason: null,
+      ...options,
+    });
+  }
+
+  /**
+   * Checks if this channel has the same type, topic, position, name, overwrites, and id as another channel.
+   * In most cases, a simple `channel.id === channel2.id` will do, and is much faster too.
+   * @param {GuildChannel} channel Channel to compare with
+   * @returns {boolean}
+   */
+  equals(channel) {
+    let equal =
+      channel &&
+      this.id === channel.id &&
+      this.type === channel.type &&
+      this.topic === channel.topic &&
+      this.position === channel.position &&
+      this.name === channel.name;
+
+    if (equal) {
+      if (this.permissionOverwrites && channel.permissionOverwrites) {
+        equal = this.permissionOverwrites.cache.equals(channel.permissionOverwrites.cache);
+      } else {
+        equal = !this.permissionOverwrites && !channel.permissionOverwrites;
+      }
+    }
+
+    return equal;
+  }
+
+  /**
+   * Whether the channel is deletable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get deletable() {
+    return this.manageable && this.guild.rulesChannelId !== this.id && this.guild.publicUpdatesChannelId !== this.id;
+  }
+
+  /**
+   * Whether the channel is manageable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get manageable() {
+    if (this.client.user.id === this.guild.ownerId) return true;
+    const permissions = this.permissionsFor(this.client.user);
+    if (!permissions) return false;
+
+    // This flag allows managing even if timed out
+    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;
+    if (this.guild.members.me.communicationDisabledUntilTimestamp > Date.now()) return false;
+
+    const bitfield = VoiceBasedChannelTypes.includes(this.type)
+      ? PermissionFlagsBits.ManageChannels | PermissionFlagsBits.Connect
+      : PermissionFlagsBits.ViewChannel | PermissionFlagsBits.ManageChannels;
+    return permissions.has(bitfield, false);
+  }
+
+  /**
+   * Whether the channel is viewable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get viewable() {
+    if (this.client.user.id === this.guild.ownerId) return true;
+    const permissions = this.permissionsFor(this.client.user);
+    if (!permissions) return false;
+    return permissions.has(PermissionFlagsBits.ViewChannel, false);
+  }
+
+  /**
+   * Deletes this channel.
+   * @param {string} [reason] Reason for deleting this channel
+   * @returns {Promise<GuildChannel>}
+   * @example
+   * // Delete the channel
+   * channel.delete('making room for new channels')
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async delete(reason) {
+    await this.guild.channels.delete(this.id, reason);
+    return this;
+  }
+}
+
+module.exports = GuildChannel;
diff --git a/node_modules/discord.js/src/structures/GuildEmoji.js b/node_modules/discord.js/src/structures/GuildEmoji.js
new file mode 100644
index 0000000..0035a36
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildEmoji.js
@@ -0,0 +1,148 @@
+'use strict';
+
+const { PermissionFlagsBits } = require('discord-api-types/v10');
+const BaseGuildEmoji = require('./BaseGuildEmoji');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+const GuildEmojiRoleManager = require('../managers/GuildEmojiRoleManager');
+
+/**
+ * Represents a custom emoji.
+ * @extends {BaseGuildEmoji}
+ */
+class GuildEmoji extends BaseGuildEmoji {
+  constructor(client, data, guild) {
+    super(client, data, guild);
+
+    /**
+     * The user who created this emoji
+     * @type {?User}
+     */
+    this.author = null;
+
+    /**
+     * Array of role ids this emoji is active for
+     * @name GuildEmoji#_roles
+     * @type {Snowflake[]}
+     * @private
+     */
+    Object.defineProperty(this, '_roles', { value: [], writable: true });
+
+    this._patch(data);
+  }
+
+  /**
+   * The guild this emoji is part of
+   * @type {Guild}
+   * @name GuildEmoji#guild
+   */
+
+  _clone() {
+    const clone = super._clone();
+    clone._roles = this._roles.slice();
+    return clone;
+  }
+
+  _patch(data) {
+    super._patch(data);
+
+    if (data.user) this.author = this.client.users._add(data.user);
+    if (data.roles) this._roles = data.roles;
+  }
+
+  /**
+   * Whether the emoji is deletable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get deletable() {
+    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);
+    return !this.managed && this.guild.members.me.permissions.has(PermissionFlagsBits.ManageGuildExpressions);
+  }
+
+  /**
+   * A manager for roles this emoji is active for.
+   * @type {GuildEmojiRoleManager}
+   * @readonly
+   */
+  get roles() {
+    return new GuildEmojiRoleManager(this);
+  }
+
+  /**
+   * Fetches the author for this emoji
+   * @returns {Promise<User>}
+   */
+  fetchAuthor() {
+    return this.guild.emojis.fetchAuthor(this);
+  }
+
+  /**
+   * Data for editing an emoji.
+   * @typedef {Object} GuildEmojiEditOptions
+   * @property {string} [name] The name of the emoji
+   * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] Roles to restrict emoji to
+   * @property {string} [reason] Reason for editing this emoji
+   */
+
+  /**
+   * Edits the emoji.
+   * @param {GuildEmojiEditOptions} options The options to provide
+   * @returns {Promise<GuildEmoji>}
+   * @example
+   * // Edit an emoji
+   * emoji.edit({ name: 'newemoji' })
+   *   .then(e => console.log(`Edited emoji ${e}`))
+   *   .catch(console.error);
+   */
+  edit(options) {
+    return this.guild.emojis.edit(this.id, options);
+  }
+
+  /**
+   * Sets the name of the emoji.
+   * @param {string} name The new name for the emoji
+   * @param {string} [reason] Reason for changing the emoji's name
+   * @returns {Promise<GuildEmoji>}
+   */
+  setName(name, reason) {
+    return this.edit({ name, reason });
+  }
+
+  /**
+   * Deletes the emoji.
+   * @param {string} [reason] Reason for deleting the emoji
+   * @returns {Promise<GuildEmoji>}
+   */
+  async delete(reason) {
+    await this.guild.emojis.delete(this.id, reason);
+    return this;
+  }
+
+  /**
+   * Whether this emoji is the same as another one.
+   * @param {GuildEmoji|APIEmoji} other The emoji to compare it to
+   * @returns {boolean}
+   */
+  equals(other) {
+    if (other instanceof GuildEmoji) {
+      return (
+        other.id === this.id &&
+        other.name === this.name &&
+        other.managed === this.managed &&
+        other.available === this.available &&
+        other.requiresColons === this.requiresColons &&
+        other.roles.cache.size === this.roles.cache.size &&
+        other.roles.cache.every(role => this.roles.cache.has(role.id))
+      );
+    } else {
+      return (
+        other.id === this.id &&
+        other.name === this.name &&
+        other.roles.length === this.roles.cache.size &&
+        other.roles.every(role => this.roles.cache.has(role))
+      );
+    }
+  }
+}
+
+module.exports = GuildEmoji;
diff --git a/node_modules/discord.js/src/structures/GuildMember.js b/node_modules/discord.js/src/structures/GuildMember.js
new file mode 100644
index 0000000..8806b50
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildMember.js
@@ -0,0 +1,520 @@
+'use strict';
+
+const { PermissionFlagsBits } = require('discord-api-types/v10');
+const Base = require('./Base');
+const VoiceState = require('./VoiceState');
+const TextBasedChannel = require('./interfaces/TextBasedChannel');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
+const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField');
+const PermissionsBitField = require('../util/PermissionsBitField');
+
+/**
+ * Represents a member of a guild on Discord.
+ * @implements {TextBasedChannel}
+ * @extends {Base}
+ */
+class GuildMember extends Base {
+  constructor(client, data, guild) {
+    super(client);
+
+    /**
+     * The guild that this member is part of
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The timestamp the member joined the guild at
+     * @type {?number}
+     */
+    this.joinedTimestamp = null;
+
+    /**
+     * The last timestamp this member started boosting the guild
+     * @type {?number}
+     */
+    this.premiumSinceTimestamp = null;
+
+    /**
+     * The nickname of this member, if they have one
+     * @type {?string}
+     */
+    this.nickname = null;
+
+    /**
+     * Whether this member has yet to pass the guild's membership gate
+     * @type {?boolean}
+     */
+    this.pending = null;
+
+    /**
+     * The timestamp this member's timeout will be removed
+     * @type {?number}
+     */
+    this.communicationDisabledUntilTimestamp = null;
+
+    /**
+     * The role ids of the member
+     * @name GuildMember#_roles
+     * @type {Snowflake[]}
+     * @private
+     */
+    Object.defineProperty(this, '_roles', { value: [], writable: true });
+
+    if (data) this._patch(data);
+  }
+
+  _patch(data) {
+    if ('user' in data) {
+      /**
+       * The user that this guild member instance represents
+       * @type {?User}
+       */
+      this.user = this.client.users._add(data.user, true);
+    }
+
+    if ('nick' in data) this.nickname = data.nick;
+    if ('avatar' in data) {
+      /**
+       * The guild member's avatar hash
+       * @type {?string}
+       */
+      this.avatar = data.avatar;
+    } else if (typeof this.avatar !== 'string') {
+      this.avatar = null;
+    }
+    if ('joined_at' in data) this.joinedTimestamp = Date.parse(data.joined_at);
+    if ('premium_since' in data) {
+      this.premiumSinceTimestamp = data.premium_since ? Date.parse(data.premium_since) : null;
+    }
+    if ('roles' in data) this._roles = data.roles;
+
+    if ('pending' in data) {
+      this.pending = data.pending;
+    } else if (!this.partial) {
+      // See https://github.com/discordjs/discord.js/issues/6546 for more info.
+      this.pending ??= false;
+    }
+
+    if ('communication_disabled_until' in data) {
+      this.communicationDisabledUntilTimestamp =
+        data.communication_disabled_until && Date.parse(data.communication_disabled_until);
+    }
+
+    if ('flags' in data) {
+      /**
+       * The flags of this member
+       * @type {Readonly<GuildMemberFlagsBitField>}
+       */
+      this.flags = new GuildMemberFlagsBitField(data.flags).freeze();
+    } else {
+      this.flags ??= new GuildMemberFlagsBitField().freeze();
+    }
+  }
+
+  _clone() {
+    const clone = super._clone();
+    clone._roles = this._roles.slice();
+    return clone;
+  }
+
+  /**
+   * Whether this GuildMember is a partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return this.joinedTimestamp === null;
+  }
+
+  /**
+   * A manager for the roles belonging to this member
+   * @type {GuildMemberRoleManager}
+   * @readonly
+   */
+  get roles() {
+    return new GuildMemberRoleManager(this);
+  }
+
+  /**
+   * The voice state of this member
+   * @type {VoiceState}
+   * @readonly
+   */
+  get voice() {
+    return this.guild.voiceStates.cache.get(this.id) ?? new VoiceState(this.guild, { user_id: this.id });
+  }
+
+  /**
+   * A link to the member's guild avatar.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  avatarURL(options = {}) {
+    return this.avatar && this.client.rest.cdn.guildMemberAvatar(this.guild.id, this.id, this.avatar, options);
+  }
+
+  /**
+   * A link to the member's guild avatar if they have one.
+   * Otherwise, a link to their {@link User#displayAvatarURL} will be returned.
+   * @param {ImageURLOptions} [options={}] Options for the Image URL
+   * @returns {string}
+   */
+  displayAvatarURL(options) {
+    return this.avatarURL(options) ?? this.user.displayAvatarURL(options);
+  }
+
+  /**
+   * The time this member joined the guild
+   * @type {?Date}
+   * @readonly
+   */
+  get joinedAt() {
+    return this.joinedTimestamp && new Date(this.joinedTimestamp);
+  }
+
+  /**
+   * The time this member's timeout will be removed
+   * @type {?Date}
+   * @readonly
+   */
+  get communicationDisabledUntil() {
+    return this.communicationDisabledUntilTimestamp && new Date(this.communicationDisabledUntilTimestamp);
+  }
+
+  /**
+   * The last time this member started boosting the guild
+   * @type {?Date}
+   * @readonly
+   */
+  get premiumSince() {
+    return this.premiumSinceTimestamp && new Date(this.premiumSinceTimestamp);
+  }
+
+  /**
+   * The presence of this guild member
+   * @type {?Presence}
+   * @readonly
+   */
+  get presence() {
+    return this.guild.presences.resolve(this.id);
+  }
+
+  /**
+   * The displayed color of this member in base 10
+   * @type {number}
+   * @readonly
+   */
+  get displayColor() {
+    return this.roles.color?.color ?? 0;
+  }
+
+  /**
+   * The displayed color of this member in hexadecimal
+   * @type {string}
+   * @readonly
+   */
+  get displayHexColor() {
+    return this.roles.color?.hexColor ?? '#000000';
+  }
+
+  /**
+   * The member's id
+   * @type {Snowflake}
+   * @readonly
+   */
+  get id() {
+    return this.user.id;
+  }
+
+  /**
+   * The DM between the client's user and this member
+   * @type {?DMChannel}
+   * @readonly
+   */
+  get dmChannel() {
+    return this.client.users.dmChannel(this.id);
+  }
+
+  /**
+   * The nickname of this member, or their user display name if they don't have one
+   * @type {?string}
+   * @readonly
+   */
+  get displayName() {
+    return this.nickname ?? this.user.displayName;
+  }
+
+  /**
+   * The overall set of permissions for this member, taking only roles and owner status into account
+   * @type {Readonly<PermissionsBitField>}
+   * @readonly
+   */
+  get permissions() {
+    if (this.user.id === this.guild.ownerId) return new PermissionsBitField(PermissionsBitField.All).freeze();
+    return new PermissionsBitField(this.roles.cache.map(role => role.permissions)).freeze();
+  }
+
+  /**
+   * Whether the client user is above this user in the hierarchy, according to role position and guild ownership.
+   * This is a prerequisite for many moderative actions.
+   * @type {boolean}
+   * @readonly
+   */
+  get manageable() {
+    if (this.user.id === this.guild.ownerId) return false;
+    if (this.user.id === this.client.user.id) return false;
+    if (this.client.user.id === this.guild.ownerId) return true;
+    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);
+    return this.guild.members.me.roles.highest.comparePositionTo(this.roles.highest) > 0;
+  }
+
+  /**
+   * Whether this member is kickable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get kickable() {
+    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);
+    return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.KickMembers);
+  }
+
+  /**
+   * Whether this member is bannable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get bannable() {
+    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);
+    return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.BanMembers);
+  }
+
+  /**
+   * Whether this member is moderatable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get moderatable() {
+    return (
+      !this.permissions.has(PermissionFlagsBits.Administrator) &&
+      this.manageable &&
+      (this.guild.members.me?.permissions.has(PermissionFlagsBits.ModerateMembers) ?? false)
+    );
+  }
+
+  /**
+   * Whether this member is currently timed out
+   * @returns {boolean}
+   */
+  isCommunicationDisabled() {
+    return this.communicationDisabledUntilTimestamp > Date.now();
+  }
+
+  /**
+   * Returns `channel.permissionsFor(guildMember)`. Returns permissions for a member in a guild channel,
+   * taking into account roles and permission overwrites.
+   * @param {GuildChannelResolvable} channel The guild channel to use as context
+   * @returns {Readonly<PermissionsBitField>}
+   */
+  permissionsIn(channel) {
+    channel = this.guild.channels.resolve(channel);
+    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
+    return channel.permissionsFor(this);
+  }
+
+  /**
+   * Edits this member.
+   * @param {GuildMemberEditOptions} options The options to provide
+   * @returns {Promise<GuildMember>}
+   */
+  edit(options) {
+    return this.guild.members.edit(this, options);
+  }
+
+  /**
+   * Sets the flags for this member.
+   * @param {GuildMemberFlagsResolvable} flags The flags to set
+   * @param {string} [reason] Reason for setting the flags
+   * @returns {Promise<GuildMember>}
+   */
+  setFlags(flags, reason) {
+    return this.edit({ flags, reason });
+  }
+
+  /**
+   * Sets the nickname for this member.
+   * @param {?string} nick The nickname for the guild member, or `null` if you want to reset their nickname
+   * @param {string} [reason] Reason for setting the nickname
+   * @returns {Promise<GuildMember>}
+   * @example
+   * // Set a nickname for a guild member
+   * guildMember.setNickname('cool nickname', 'Needed a new nickname')
+   *   .then(member => console.log(`Set nickname of ${member.user.username}`))
+   *   .catch(console.error);
+   * @example
+   * // Remove a nickname for a guild member
+   * guildMember.setNickname(null, 'No nicknames allowed!')
+   *   .then(member => console.log(`Removed nickname for ${member.user.username}`))
+   *   .catch(console.error);
+   */
+  setNickname(nick, reason) {
+    return this.edit({ nick, reason });
+  }
+
+  /**
+   * Creates a DM channel between the client and this member.
+   * @param {boolean} [force=false] Whether to skip the cache check and request the API
+   * @returns {Promise<DMChannel>}
+   */
+  createDM(force = false) {
+    return this.user.createDM(force);
+  }
+
+  /**
+   * Deletes any DMs with this member.
+   * @returns {Promise<DMChannel>}
+   */
+  deleteDM() {
+    return this.user.deleteDM();
+  }
+
+  /**
+   * Kicks this member from the guild.
+   * @param {string} [reason] Reason for kicking user
+   * @returns {Promise<GuildMember>}
+   */
+  kick(reason) {
+    return this.guild.members.kick(this, reason);
+  }
+
+  /**
+   * Bans this guild member.
+   * @param {BanOptions} [options] Options for the ban
+   * @returns {Promise<GuildMember>}
+   * @example
+   * // Ban a guild member, deleting a week's worth of messages
+   * guildMember.ban({ deleteMessageSeconds: 60 * 60 * 24 * 7, reason: 'They deserved it' })
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  ban(options) {
+    return this.guild.bans.create(this, options);
+  }
+
+  /**
+   * Times this guild member out.
+   * @param {DateResolvable|null} communicationDisabledUntil The date or timestamp
+   * for the member's communication to be disabled until. Provide `null` to remove the timeout.
+   * @param {string} [reason] The reason for this timeout.
+   * @returns {Promise<GuildMember>}
+   * @example
+   * // Time a guild member out for 5 minutes
+   * guildMember.disableCommunicationUntil(Date.now() + (5 * 60 * 1000), 'They deserved it')
+   *   .then(console.log)
+   *   .catch(console.error);
+   * @example
+   * // Remove the timeout of a guild member
+   * guildMember.disableCommunicationUntil(null)
+   *   .then(member => console.log(`Removed timeout for ${member.displayName}`))
+   *   .catch(console.error);
+   */
+  disableCommunicationUntil(communicationDisabledUntil, reason) {
+    return this.edit({ communicationDisabledUntil, reason });
+  }
+
+  /**
+   * Times this guild member out.
+   * @param {number|null} timeout The time in milliseconds
+   * for the member's communication to be disabled until. Provide `null` to remove the timeout.
+   * @param {string} [reason] The reason for this timeout.
+   * @returns {Promise<GuildMember>}
+   * @example
+   * // Time a guild member out for 5 minutes
+   * guildMember.timeout(5 * 60 * 1000, 'They deserved it')
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  timeout(timeout, reason) {
+    return this.disableCommunicationUntil(timeout && Date.now() + timeout, reason);
+  }
+
+  /**
+   * Fetches this GuildMember.
+   * @param {boolean} [force=true] Whether to skip the cache check and request the API
+   * @returns {Promise<GuildMember>}
+   */
+  fetch(force = true) {
+    return this.guild.members.fetch({ user: this.id, cache: true, force });
+  }
+
+  /**
+   * Whether this guild member equals another guild member. It compares all properties, so for most
+   * comparison it is advisable to just compare `member.id === member2.id` as it is significantly faster
+   * and is often what most users need.
+   * @param {GuildMember} member The member to compare with
+   * @returns {boolean}
+   */
+  equals(member) {
+    return (
+      member instanceof this.constructor &&
+      this.id === member.id &&
+      this.partial === member.partial &&
+      this.guild.id === member.guild.id &&
+      this.joinedTimestamp === member.joinedTimestamp &&
+      this.nickname === member.nickname &&
+      this.avatar === member.avatar &&
+      this.pending === member.pending &&
+      this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&
+      this.flags.bitfield === member.flags.bitfield &&
+      (this._roles === member._roles ||
+        (this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i])))
+    );
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object.
+   * @returns {string}
+   * @example
+   * // Logs: Hello from <@123456789012345678>!
+   * console.log(`Hello from ${member}!`);
+   */
+  toString() {
+    return this.user.toString();
+  }
+
+  toJSON() {
+    const json = super.toJSON({
+      guild: 'guildId',
+      user: 'userId',
+      displayName: true,
+      roles: true,
+    });
+    json.avatarURL = this.avatarURL();
+    json.displayAvatarURL = this.displayAvatarURL();
+    return json;
+  }
+}
+
+/**
+ * Sends a message to this user.
+ * @method send
+ * @memberof GuildMember
+ * @instance
+ * @param {string|MessagePayload|MessageCreateOptions} options The options to provide
+ * @returns {Promise<Message>}
+ * @example
+ * // Send a direct message
+ * guildMember.send('Hello!')
+ *   .then(message => console.log(`Sent message: ${message.content} to ${guildMember.displayName}`))
+ *   .catch(console.error);
+ */
+
+TextBasedChannel.applyToClass(GuildMember);
+
+exports.GuildMember = GuildMember;
+
+/**
+ * @external APIGuildMember
+ * @see {@link https://discord.com/developers/docs/resources/guild#guild-member-object}
+ */
diff --git a/node_modules/discord.js/src/structures/GuildOnboarding.js b/node_modules/discord.js/src/structures/GuildOnboarding.js
new file mode 100644
index 0000000..119f905
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildOnboarding.js
@@ -0,0 +1,58 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Base = require('./Base');
+const { GuildOnboardingPrompt } = require('./GuildOnboardingPrompt');
+
+/**
+ * Represents the onboarding data of a guild.
+ * @extends {Base}
+ */
+class GuildOnboarding extends Base {
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The id of the guild this onboarding data is for
+     * @type {Snowflake}
+     */
+    this.guildId = data.guild_id;
+
+    const guild = this.guild;
+
+    /**
+     * The prompts shown during onboarding and in customize community
+     * @type {Collection<Snowflake, GuildOnboardingPrompt>}
+     */
+    this.prompts = data.prompts.reduce(
+      (prompts, prompt) => prompts.set(prompt.id, new GuildOnboardingPrompt(client, prompt, this.guildId)),
+      new Collection(),
+    );
+
+    /**
+     * The ids of the channels that new members get opted into automatically
+     * @type {Collection<Snowflake, GuildChannel>}
+     */
+    this.defaultChannels = data.default_channel_ids.reduce(
+      (channels, channelId) => channels.set(channelId, guild.channels.cache.get(channelId)),
+      new Collection(),
+    );
+
+    /**
+     * Whether onboarding is enabled
+     * @type {boolean}
+     */
+    this.enabled = data.enabled;
+  }
+
+  /**
+   * The guild this onboarding is from
+   * @type {Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.cache.get(this.guildId);
+  }
+}
+
+exports.GuildOnboarding = GuildOnboarding;
diff --git a/node_modules/discord.js/src/structures/GuildOnboardingPrompt.js b/node_modules/discord.js/src/structures/GuildOnboardingPrompt.js
new file mode 100644
index 0000000..4de3f5d
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildOnboardingPrompt.js
@@ -0,0 +1,78 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Base = require('./Base');
+const { GuildOnboardingPromptOption } = require('./GuildOnboardingPromptOption');
+
+/**
+ * Represents the data of a prompt of a guilds onboarding.
+ * @extends {Base}
+ */
+class GuildOnboardingPrompt extends Base {
+  constructor(client, data, guildId) {
+    super(client);
+
+    /**
+     * The id of the guild this onboarding prompt is from
+     * @type {Snowflake}
+     */
+    this.guildId = guildId;
+
+    /**
+     * The id of the prompt
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The options available within the prompt
+     * @type {Collection<Snowflake, GuildOnboardingPromptOption>}
+     */
+    this.options = data.options.reduce(
+      (options, option) => options.set(option.id, new GuildOnboardingPromptOption(client, option, guildId)),
+      new Collection(),
+    );
+
+    /**
+     * The title of the prompt
+     * @type {string}
+     */
+    this.title = data.title;
+
+    /**
+     * Whether users are limited to selecting one option for the prompt
+     * @type {boolean}
+     */
+    this.singleSelect = data.single_select;
+
+    /**
+     * Whether the prompt is required before a user completes the onboarding flow
+     * @type {boolean}
+     */
+    this.required = data.required;
+
+    /**
+     * Whether the prompt is present in the onboarding flow.
+     * If `false`, the prompt will only appear in the Channels & Roles tab
+     * @type {boolean}
+     */
+    this.inOnboarding = data.in_onboarding;
+
+    /**
+     * The type of the prompt
+     * @type {GuildOnboardingPromptType}
+     */
+    this.type = data.type;
+  }
+
+  /**
+   * The guild this onboarding prompt is from
+   * @type {Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.cache.get(this.guildId);
+  }
+}
+
+exports.GuildOnboardingPrompt = GuildOnboardingPrompt;
diff --git a/node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js b/node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js
new file mode 100644
index 0000000..3002144
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js
@@ -0,0 +1,84 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Base = require('./Base');
+const { resolvePartialEmoji } = require('../util/Util');
+
+/**
+ * Represents the data of an option from a prompt of a guilds onboarding.
+ * @extends {Base}
+ */
+class GuildOnboardingPromptOption extends Base {
+  constructor(client, data, guildId) {
+    super(client);
+
+    /**
+     * The id of the guild this onboarding prompt option is from
+     * @type {Snowflake}
+     */
+    this.guildId = guildId;
+
+    const guild = this.guild;
+
+    /**
+     * The id of the option
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The channels a member is added to when the option is selected
+     * @type {Collection<Snowflake, GuildChannel>}
+     */
+    this.channels = data.channel_ids.reduce(
+      (channels, channelId) => channels.set(channelId, guild.channels.cache.get(channelId)),
+      new Collection(),
+    );
+
+    /**
+     * The roles assigned to a member when the option is selected
+     * @type {Collection<Snowflake, Role>}
+     */
+    this.roles = data.role_ids.reduce(
+      (roles, roleId) => roles.set(roleId, guild.roles.cache.get(roleId)),
+      new Collection(),
+    );
+
+    /**
+     * The data for an emoji of a guilds onboarding prompt option
+     * @typedef {Object} GuildOnboardingPromptOptionEmoji
+     * @property {?Snowflake} id The id of the emoji
+     * @property {string} name The name of the emoji
+     * @property {boolean} animated Whether the emoji is animated
+     */
+
+    /**
+     * The emoji of the option
+     * @type {?GuildOnboardingPromptOptionEmoji}
+     */
+    this.emoji = resolvePartialEmoji(data.emoji);
+
+    /**
+     * The title of the option
+     * @type {string}
+     */
+    this.title = data.title;
+
+    /**
+     * The description of the option
+     * @type {?string}
+     */
+    this.description = data.description;
+  }
+
+  /**
+   * The guild this onboarding prompt option is from
+   * @type {Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.cache.get(this.guildId);
+  }
+}
+
+exports.GuildOnboardingPromptOption = GuildOnboardingPromptOption;
diff --git a/node_modules/discord.js/src/structures/GuildPreview.js b/node_modules/discord.js/src/structures/GuildPreview.js
new file mode 100644
index 0000000..6ff2026
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildPreview.js
@@ -0,0 +1,193 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { Routes } = require('discord-api-types/v10');
+const Base = require('./Base');
+const GuildPreviewEmoji = require('./GuildPreviewEmoji');
+const { Sticker } = require('./Sticker');
+
+/**
+ * Represents the data about the guild any bot can preview, connected to the specified guild.
+ * @extends {Base}
+ */
+class GuildPreview extends Base {
+  constructor(client, data) {
+    super(client);
+
+    if (!data) return;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    /**
+     * The id of this guild
+     * @type {string}
+     */
+    this.id = data.id;
+
+    if ('name' in data) {
+      /**
+       * The name of this guild
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('icon' in data) {
+      /**
+       * The icon of this guild
+       * @type {?string}
+       */
+      this.icon = data.icon;
+    }
+
+    if ('splash' in data) {
+      /**
+       * The splash icon of this guild
+       * @type {?string}
+       */
+      this.splash = data.splash;
+    }
+
+    if ('discovery_splash' in data) {
+      /**
+       * The discovery splash icon of this guild
+       * @type {?string}
+       */
+      this.discoverySplash = data.discovery_splash;
+    }
+
+    if ('features' in data) {
+      /**
+       * An array of enabled guild features
+       * @type {GuildFeature[]}
+       */
+      this.features = data.features;
+    }
+
+    if ('approximate_member_count' in data) {
+      /**
+       * The approximate count of members in this guild
+       * @type {number}
+       */
+      this.approximateMemberCount = data.approximate_member_count;
+    }
+
+    if ('approximate_presence_count' in data) {
+      /**
+       * The approximate count of online members in this guild
+       * @type {number}
+       */
+      this.approximatePresenceCount = data.approximate_presence_count;
+    }
+
+    if ('description' in data) {
+      /**
+       * The description for this guild
+       * @type {?string}
+       */
+      this.description = data.description;
+    } else {
+      this.description ??= null;
+    }
+
+    if (!this.emojis) {
+      /**
+       * Collection of emojis belonging to this guild
+       * @type {Collection<Snowflake, GuildPreviewEmoji>}
+       */
+      this.emojis = new Collection();
+    } else {
+      this.emojis.clear();
+    }
+    for (const emoji of data.emojis) {
+      this.emojis.set(emoji.id, new GuildPreviewEmoji(this.client, emoji, this));
+    }
+
+    /**
+     * Collection of stickers belonging to this guild
+     * @type {Collection<Snowflake, Sticker>}
+     */
+    this.stickers = data.stickers.reduce(
+      (stickers, sticker) => stickers.set(sticker.id, new Sticker(this.client, sticker)),
+      new Collection(),
+    );
+  }
+
+  /**
+   * The timestamp this guild was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time this guild was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The URL to this guild's splash.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  splashURL(options = {}) {
+    return this.splash && this.client.rest.cdn.splash(this.id, this.splash, options);
+  }
+
+  /**
+   * The URL to this guild's discovery splash.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  discoverySplashURL(options = {}) {
+    return this.discoverySplash && this.client.rest.cdn.discoverySplash(this.id, this.discoverySplash, options);
+  }
+
+  /**
+   * The URL to this guild's icon.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  iconURL(options = {}) {
+    return this.icon && this.client.rest.cdn.icon(this.id, this.icon, options);
+  }
+
+  /**
+   * Fetches this guild.
+   * @returns {Promise<GuildPreview>}
+   */
+  async fetch() {
+    const data = await this.client.rest.get(Routes.guildPreview(this.id));
+    this._patch(data);
+    return this;
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the guild's name instead of the Guild object.
+   * @returns {string}
+   * @example
+   * // Logs: Hello from My Guild!
+   * console.log(`Hello from ${previewGuild}!`);
+   */
+  toString() {
+    return this.name;
+  }
+
+  toJSON() {
+    const json = super.toJSON();
+    json.iconURL = this.iconURL();
+    json.splashURL = this.splashURL();
+    return json;
+  }
+}
+
+module.exports = GuildPreview;
diff --git a/node_modules/discord.js/src/structures/GuildPreviewEmoji.js b/node_modules/discord.js/src/structures/GuildPreviewEmoji.js
new file mode 100644
index 0000000..144b41d
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildPreviewEmoji.js
@@ -0,0 +1,27 @@
+'use strict';
+
+const BaseGuildEmoji = require('./BaseGuildEmoji');
+
+/**
+ * Represents an instance of an emoji belonging to a public guild obtained through Discord's preview endpoint.
+ * @extends {BaseGuildEmoji}
+ */
+class GuildPreviewEmoji extends BaseGuildEmoji {
+  /**
+   * The public guild this emoji is part of
+   * @type {GuildPreview}
+   * @name GuildPreviewEmoji#guild
+   */
+
+  constructor(client, data, guild) {
+    super(client, data, guild);
+
+    /**
+     * The roles this emoji is active for
+     * @type {Snowflake[]}
+     */
+    this.roles = data.roles;
+  }
+}
+
+module.exports = GuildPreviewEmoji;
diff --git a/node_modules/discord.js/src/structures/GuildScheduledEvent.js b/node_modules/discord.js/src/structures/GuildScheduledEvent.js
new file mode 100644
index 0000000..e9a37b2
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildScheduledEvent.js
@@ -0,0 +1,439 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { GuildScheduledEventStatus, GuildScheduledEventEntityType, RouteBases } = require('discord-api-types/v10');
+const Base = require('./Base');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents a scheduled event in a {@link Guild}.
+ * @extends {Base}
+ */
+class GuildScheduledEvent extends Base {
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The id of the guild scheduled event
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The id of the guild this guild scheduled event belongs to
+     * @type {Snowflake}
+     */
+    this.guildId = data.guild_id;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('channel_id' in data) {
+      /**
+       * The channel id in which the scheduled event will be hosted,
+       * or `null` if entity type is {@link GuildScheduledEventEntityType.External}
+       * @type {?Snowflake}
+       */
+      this.channelId = data.channel_id;
+    } else {
+      this.channelId ??= null;
+    }
+
+    if ('creator_id' in data) {
+      /**
+       * The id of the user that created this guild scheduled event
+       * @type {?Snowflake}
+       */
+      this.creatorId = data.creator_id;
+    } else {
+      this.creatorId ??= null;
+    }
+
+    /**
+     * The name of the guild scheduled event
+     * @type {string}
+     */
+    this.name = data.name;
+
+    if ('description' in data) {
+      /**
+       * The description of the guild scheduled event
+       * @type {?string}
+       */
+      this.description = data.description;
+    } else {
+      this.description ??= null;
+    }
+
+    /**
+     * The timestamp the guild scheduled event will start at
+     * <info>This can be potentially `null` only when it's an {@link AuditLogEntryTarget}</info>
+     * @type {?number}
+     */
+    this.scheduledStartTimestamp = data.scheduled_start_time ? Date.parse(data.scheduled_start_time) : null;
+
+    /**
+     * The timestamp the guild scheduled event will end at,
+     * or `null` if the event does not have a scheduled time to end
+     * @type {?number}
+     */
+    this.scheduledEndTimestamp = data.scheduled_end_time ? Date.parse(data.scheduled_end_time) : null;
+
+    /**
+     * The privacy level of the guild scheduled event
+     * @type {GuildScheduledEventPrivacyLevel}
+     */
+    this.privacyLevel = data.privacy_level;
+
+    /**
+     * The status of the guild scheduled event
+     * @type {GuildScheduledEventStatus}
+     */
+    this.status = data.status;
+
+    /**
+     * The type of hosting entity associated with the scheduled event
+     * @type {GuildScheduledEventEntityType}
+     */
+    this.entityType = data.entity_type;
+
+    if ('entity_id' in data) {
+      /**
+       * The id of the hosting entity associated with the scheduled event
+       * @type {?Snowflake}
+       */
+      this.entityId = data.entity_id;
+    } else {
+      this.entityId ??= null;
+    }
+
+    if ('user_count' in data) {
+      /**
+       * The number of users who are subscribed to this guild scheduled event
+       * @type {?number}
+       */
+      this.userCount = data.user_count;
+    } else {
+      this.userCount ??= null;
+    }
+
+    if ('creator' in data) {
+      /**
+       * The user that created this guild scheduled event
+       * @type {?User}
+       */
+      this.creator = this.client.users._add(data.creator);
+    } else {
+      this.creator ??= this.client.users.resolve(this.creatorId);
+    }
+
+    /* eslint-disable max-len */
+    /**
+     * Represents the additional metadata for a {@link GuildScheduledEvent}
+     * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata}
+     * @typedef {Object} GuildScheduledEventEntityMetadata
+     * @property {?string} location The location of the guild scheduled event
+     */
+    /* eslint-enable max-len */
+
+    if ('entity_metadata' in data) {
+      if (data.entity_metadata) {
+        /**
+         * Additional metadata
+         * @type {?GuildScheduledEventEntityMetadata}
+         */
+        this.entityMetadata = {
+          location: data.entity_metadata.location ?? this.entityMetadata?.location ?? null,
+        };
+      } else {
+        this.entityMetadata = null;
+      }
+    } else {
+      this.entityMetadata ??= null;
+    }
+
+    if ('image' in data) {
+      /**
+       * The cover image hash for this scheduled event
+       * @type {?string}
+       */
+      this.image = data.image;
+    } else {
+      this.image ??= null;
+    }
+  }
+
+  /**
+   * The URL of this scheduled event's cover image
+   * @param {BaseImageURLOptions} [options={}] Options for image URL
+   * @returns {?string}
+   */
+  coverImageURL(options = {}) {
+    return this.image && this.client.rest.cdn.guildScheduledEventCover(this.id, this.image, options);
+  }
+
+  /**
+   * The timestamp the guild scheduled event was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the guild scheduled event was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The time the guild scheduled event will start at
+   * <info>This can be potentially `null` only when it's an {@link AuditLogEntryTarget}</info>
+   * @type {?Date}
+   * @readonly
+   */
+  get scheduledStartAt() {
+    return this.scheduledStartTimestamp && new Date(this.scheduledStartTimestamp);
+  }
+
+  /**
+   * The time the guild scheduled event will end at,
+   * or `null` if the event does not have a scheduled time to end
+   * @type {?Date}
+   * @readonly
+   */
+  get scheduledEndAt() {
+    return this.scheduledEndTimestamp && new Date(this.scheduledEndTimestamp);
+  }
+
+  /**
+   * The channel associated with this scheduled event
+   * @type {?(VoiceChannel|StageChannel)}
+   * @readonly
+   */
+  get channel() {
+    return this.client.channels.resolve(this.channelId);
+  }
+
+  /**
+   * The guild this scheduled event belongs to
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.resolve(this.guildId);
+  }
+
+  /**
+   * The URL to the guild scheduled event
+   * @type {string}
+   * @readonly
+   */
+  get url() {
+    return `${RouteBases.scheduledEvent}/${this.guildId}/${this.id}`;
+  }
+
+  /**
+   * Options used to create an invite URL to a {@link GuildScheduledEvent}
+   * @typedef {InviteCreateOptions} GuildScheduledEventInviteURLCreateOptions
+   * @property {GuildInvitableChannelResolvable} [channel] The channel to create the invite in.
+   * <warn>This is required when the `entityType` of `GuildScheduledEvent` is
+   * {@link GuildScheduledEventEntityType.External}, gets ignored otherwise</warn>
+   */
+
+  /**
+   * Creates an invite URL to this guild scheduled event.
+   * @param {GuildScheduledEventInviteURLCreateOptions} [options] The options to create the invite
+   * @returns {Promise<string>}
+   */
+  async createInviteURL(options) {
+    let channelId = this.channelId;
+    if (this.entityType === GuildScheduledEventEntityType.External) {
+      if (!options?.channel) throw new DiscordjsError(ErrorCodes.InviteOptionsMissingChannel);
+      channelId = this.guild.channels.resolveId(options.channel);
+      if (!channelId) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
+    }
+    const invite = await this.guild.invites.create(channelId, options);
+    return `${RouteBases.invite}/${invite.code}?event=${this.id}`;
+  }
+
+  /**
+   * Edits this guild scheduled event.
+   * @param {GuildScheduledEventEditOptions} options The options to edit the guild scheduled event
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Edit a guild scheduled event
+   * guildScheduledEvent.edit({ name: 'Party' })
+   *  .then(guildScheduledEvent => console.log(guildScheduledEvent))
+   *  .catch(console.error);
+   */
+  edit(options) {
+    return this.guild.scheduledEvents.edit(this.id, options);
+  }
+
+  /**
+   * Deletes this guild scheduled event.
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Delete a guild scheduled event
+   * guildScheduledEvent.delete()
+   *  .then(guildScheduledEvent => console.log(guildScheduledEvent))
+   *  .catch(console.error);
+   */
+  async delete() {
+    await this.guild.scheduledEvents.delete(this.id);
+    return this;
+  }
+
+  /**
+   * Sets a new name for the guild scheduled event.
+   * @param {string} name The new name of the guild scheduled event
+   * @param {string} [reason] The reason for changing the name
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Set name of a guild scheduled event
+   * guildScheduledEvent.setName('Birthday Party')
+   *  .then(guildScheduledEvent => console.log(`Set the name to: ${guildScheduledEvent.name}`))
+   *  .catch(console.error);
+   */
+  setName(name, reason) {
+    return this.edit({ name, reason });
+  }
+
+  /**
+   * Sets a new time to schedule the event at.
+   * @param {DateResolvable} scheduledStartTime The time to schedule the event at
+   * @param {string} [reason] The reason for changing the scheduled start time
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Set start time of a guild scheduled event
+   * guildScheduledEvent.setScheduledStartTime('2022-09-24T00:00:00+05:30')
+   *  .then(guildScheduledEvent => console.log(`Set the start time to: ${guildScheduledEvent.scheduledStartTime}`))
+   *  .catch(console.error);
+   */
+  setScheduledStartTime(scheduledStartTime, reason) {
+    return this.edit({ scheduledStartTime, reason });
+  }
+
+  // TODO: scheduledEndTime gets reset on passing null but it hasn't been documented
+  /**
+   * Sets a new time to end the event at.
+   * @param {DateResolvable} scheduledEndTime The time to end the event at
+   * @param {string} [reason] The reason for changing the scheduled end time
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Set end time of a guild scheduled event
+   * guildScheduledEvent.setScheduledEndTime('2022-09-25T00:00:00+05:30')
+   *  .then(guildScheduledEvent => console.log(`Set the end time to: ${guildScheduledEvent.scheduledEndTime}`))
+   *  .catch(console.error);
+   */
+  setScheduledEndTime(scheduledEndTime, reason) {
+    return this.edit({ scheduledEndTime, reason });
+  }
+
+  /**
+   * Sets the new description of the guild scheduled event.
+   * @param {string} description The description of the guild scheduled event
+   * @param {string} [reason] The reason for changing the description
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Set description of a guild scheduled event
+   * guildScheduledEvent.setDescription('A virtual birthday party')
+   *  .then(guildScheduledEvent => console.log(`Set the description to: ${guildScheduledEvent.description}`))
+   *  .catch(console.error);
+   */
+  setDescription(description, reason) {
+    return this.edit({ description, reason });
+  }
+
+  /**
+   * Sets the new status of the guild scheduled event.
+   * <info>If you're working with TypeScript, use this method in conjunction with status type-guards
+   * like {@link GuildScheduledEvent#isScheduled} to get only valid status as suggestion</info>
+   * @param {GuildScheduledEventStatus} status The status of the guild scheduled event
+   * @param {string} [reason] The reason for changing the status
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Set status of a guild scheduled event
+   * guildScheduledEvent.setStatus(GuildScheduledEventStatus.Active)
+   *  .then(guildScheduledEvent => console.log(`Set the status to: ${guildScheduledEvent.status}`))
+   *  .catch(console.error);
+   */
+  setStatus(status, reason) {
+    return this.edit({ status, reason });
+  }
+
+  /**
+   * Sets the new location of the guild scheduled event.
+   * @param {string} location The location of the guild scheduled event
+   * @param {string} [reason] The reason for changing the location
+   * @returns {Promise<GuildScheduledEvent>}
+   * @example
+   * // Set location of a guild scheduled event
+   * guildScheduledEvent.setLocation('Earth')
+   *  .then(guildScheduledEvent => console.log(`Set the location to: ${guildScheduledEvent.entityMetadata.location}`))
+   *  .catch(console.error);
+   */
+  setLocation(location, reason) {
+    return this.edit({ entityMetadata: { location }, reason });
+  }
+
+  /**
+   * Fetches subscribers of this guild scheduled event.
+   * @param {FetchGuildScheduledEventSubscribersOptions} [options] Options for fetching the subscribers
+   * @returns {Promise<Collection<Snowflake, GuildScheduledEventUser>>}
+   */
+  fetchSubscribers(options) {
+    return this.guild.scheduledEvents.fetchSubscribers(this.id, options);
+  }
+
+  /**
+   * When concatenated with a string, this automatically concatenates the event's URL instead of the object.
+   * @returns {string}
+   * @example
+   * // Logs: Event: https://discord.com/events/412345678901234567/499876543211234567
+   * console.log(`Event: ${guildScheduledEvent}`);
+   */
+  toString() {
+    return this.url;
+  }
+
+  /**
+   * Indicates whether this guild scheduled event has an {@link GuildScheduledEventStatus.Active} status.
+   * @returns {boolean}
+   */
+  isActive() {
+    return this.status === GuildScheduledEventStatus.Active;
+  }
+
+  /**
+   * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Canceled} status.
+   * @returns {boolean}
+   */
+  isCanceled() {
+    return this.status === GuildScheduledEventStatus.Canceled;
+  }
+
+  /**
+   * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Completed} status.
+   * @returns {boolean}
+   */
+  isCompleted() {
+    return this.status === GuildScheduledEventStatus.Completed;
+  }
+
+  /**
+   * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Scheduled} status.
+   * @returns {boolean}
+   */
+  isScheduled() {
+    return this.status === GuildScheduledEventStatus.Scheduled;
+  }
+}
+
+exports.GuildScheduledEvent = GuildScheduledEvent;
diff --git a/node_modules/discord.js/src/structures/GuildTemplate.js b/node_modules/discord.js/src/structures/GuildTemplate.js
new file mode 100644
index 0000000..c1e219b
--- /dev/null
+++ b/node_modules/discord.js/src/structures/GuildTemplate.js
@@ -0,0 +1,241 @@
+'use strict';
+
+const { setTimeout, clearTimeout } = require('node:timers');
+const { RouteBases, Routes } = require('discord-api-types/v10');
+const Base = require('./Base');
+const DataResolver = require('../util/DataResolver');
+const Events = require('../util/Events');
+
+/**
+ * Represents the template for a guild.
+ * @extends {Base}
+ */
+class GuildTemplate extends Base {
+  /**
+   * A regular expression that matches guild template links.
+   * The `code` group property is present on the `exec()` result of this expression.
+   * @type {RegExp}
+   * @memberof GuildTemplate
+   */
+  static GuildTemplatesPattern = /discord(?:app)?\.(?:com\/template|new)\/(?<code>[\w-]{2,255})/i;
+
+  constructor(client, data) {
+    super(client);
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('code' in data) {
+      /**
+       * The unique code of this template
+       * @type {string}
+       */
+      this.code = data.code;
+    }
+
+    if ('name' in data) {
+      /**
+       * The name of this template
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('description' in data) {
+      /**
+       * The description of this template
+       * @type {?string}
+       */
+      this.description = data.description;
+    }
+
+    if ('usage_count' in data) {
+      /**
+       * The amount of times this template has been used
+       * @type {number}
+       */
+      this.usageCount = data.usage_count;
+    }
+
+    if ('creator_id' in data) {
+      /**
+       * The id of the user that created this template
+       * @type {Snowflake}
+       */
+      this.creatorId = data.creator_id;
+    }
+
+    if ('creator' in data) {
+      /**
+       * The user that created this template
+       * @type {User}
+       */
+      this.creator = this.client.users._add(data.creator);
+    }
+
+    if ('created_at' in data) {
+      /**
+       * The timestamp of when this template was created at
+       * @type {number}
+       */
+      this.createdTimestamp = Date.parse(data.created_at);
+    }
+
+    if ('updated_at' in data) {
+      /**
+       * The timestamp of when this template was last synced to the guild
+       * @type {number}
+       */
+      this.updatedTimestamp = Date.parse(data.updated_at);
+    }
+
+    if ('source_guild_id' in data) {
+      /**
+       * The id of the guild that this template belongs to
+       * @type {Snowflake}
+       */
+      this.guildId = data.source_guild_id;
+    }
+
+    if ('serialized_source_guild' in data) {
+      /**
+       * The data of the guild that this template would create
+       * @type {APIGuild}
+       */
+      this.serializedGuild = data.serialized_source_guild;
+    }
+
+    /**
+     * Whether this template has unsynced changes
+     * @type {?boolean}
+     */
+    this.unSynced = 'is_dirty' in data ? Boolean(data.is_dirty) : null;
+
+    return this;
+  }
+
+  /**
+   * Creates a guild based on this template.
+   * <warn>This is only available to bots in fewer than 10 guilds.</warn>
+   * @param {string} name The name of the guild
+   * @param {BufferResolvable|Base64Resolvable} [icon] The icon for the guild
+   * @returns {Promise<Guild>}
+   */
+  async createGuild(name, icon) {
+    const { client } = this;
+    const data = await client.rest.post(Routes.template(this.code), {
+      body: {
+        name,
+        icon: await DataResolver.resolveImage(icon),
+      },
+    });
+
+    if (client.guilds.cache.has(data.id)) return client.guilds.cache.get(data.id);
+
+    return new Promise(resolve => {
+      const resolveGuild = guild => {
+        client.off(Events.GuildCreate, handleGuild);
+        client.decrementMaxListeners();
+        resolve(guild);
+      };
+
+      const handleGuild = guild => {
+        if (guild.id === data.id) {
+          clearTimeout(timeout);
+          resolveGuild(guild);
+        }
+      };
+
+      client.incrementMaxListeners();
+      client.on(Events.GuildCreate, handleGuild);
+
+      const timeout = setTimeout(() => resolveGuild(client.guilds._add(data)), 10_000).unref();
+    });
+  }
+
+  /**
+   * Options used to edit a guild template.
+   * @typedef {Object} GuildTemplateEditOptions
+   * @property {string} [name] The name of this template
+   * @property {string} [description] The description of this template
+   */
+
+  /**
+   * Updates the metadata of this template.
+   * @param {GuildTemplateEditOptions} [options] Options for editing the template
+   * @returns {Promise<GuildTemplate>}
+   */
+  async edit({ name, description } = {}) {
+    const data = await this.client.rest.patch(Routes.guildTemplate(this.guildId, this.code), {
+      body: { name, description },
+    });
+    return this._patch(data);
+  }
+
+  /**
+   * Deletes this template.
+   * @returns {Promise<GuildTemplate>}
+   */
+  async delete() {
+    await this.client.rest.delete(Routes.guildTemplate(this.guildId, this.code));
+    return this;
+  }
+
+  /**
+   * Syncs this template to the current state of the guild.
+   * @returns {Promise<GuildTemplate>}
+   */
+  async sync() {
+    const data = await this.client.rest.put(Routes.guildTemplate(this.guildId, this.code));
+    return this._patch(data);
+  }
+
+  /**
+   * The time when this template was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The time when this template was last synced to the guild
+   * @type {Date}
+   * @readonly
+   */
+  get updatedAt() {
+    return new Date(this.updatedTimestamp);
+  }
+
+  /**
+   * The guild that this template belongs to
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.resolve(this.guildId);
+  }
+
+  /**
+   * The URL of this template
+   * @type {string}
+   * @readonly
+   */
+  get url() {
+    return `${RouteBases.template}/${this.code}`;
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the template's code instead of the template object.
+   * @returns {string}
+   * @example
+   * // Logs: Template: FKvmczH2HyUf
+   * console.log(`Template: ${guildTemplate}!`);
+   */
+  toString() {
+    return this.code;
+  }
+}
+
+module.exports = GuildTemplate;
diff --git a/node_modules/discord.js/src/structures/Integration.js b/node_modules/discord.js/src/structures/Integration.js
new file mode 100644
index 0000000..fa9777b
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Integration.js
@@ -0,0 +1,220 @@
+'use strict';
+
+const { Routes } = require('discord-api-types/v10');
+const Base = require('./Base');
+const IntegrationApplication = require('./IntegrationApplication');
+
+/**
+ * The information account for an integration
+ * @typedef {Object} IntegrationAccount
+ * @property {Snowflake|string} id The id of the account
+ * @property {string} name The name of the account
+ */
+
+/**
+ * The type of an {@link Integration}. This can be:
+ * * `twitch`
+ * * `youtube`
+ * * `discord`
+ * * `guild_subscription`
+ * @typedef {string} IntegrationType
+ */
+
+/**
+ * Represents a guild integration.
+ * @extends {Base}
+ */
+class Integration extends Base {
+  constructor(client, data, guild) {
+    super(client);
+
+    /**
+     * The guild this integration belongs to
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The integration id
+     * @type {Snowflake|string}
+     */
+    this.id = data.id;
+
+    /**
+     * The integration name
+     * @type {string}
+     */
+    this.name = data.name;
+
+    /**
+     * The integration type
+     * @type {IntegrationType}
+     */
+    this.type = data.type;
+
+    /**
+     * Whether this integration is enabled
+     * @type {?boolean}
+     */
+    this.enabled = data.enabled ?? null;
+
+    if ('syncing' in data) {
+      /**
+       * Whether this integration is syncing
+       * @type {?boolean}
+       */
+      this.syncing = data.syncing;
+    } else {
+      this.syncing ??= null;
+    }
+
+    /**
+     * The role that this integration uses for subscribers
+     * @type {?Role}
+     */
+    this.role = this.guild.roles.resolve(data.role_id);
+
+    if ('enable_emoticons' in data) {
+      /**
+       * Whether emoticons should be synced for this integration (twitch only currently)
+       * @type {?boolean}
+       */
+      this.enableEmoticons = data.enable_emoticons;
+    } else {
+      this.enableEmoticons ??= null;
+    }
+
+    if (data.user) {
+      /**
+       * The user for this integration
+       * @type {?User}
+       */
+      this.user = this.client.users._add(data.user);
+    } else {
+      this.user ??= null;
+    }
+
+    /**
+     * The account integration information
+     * @type {IntegrationAccount}
+     */
+    this.account = data.account;
+
+    if ('synced_at' in data) {
+      /**
+       * The timestamp at which this integration was last synced at
+       * @type {?number}
+       */
+      this.syncedTimestamp = Date.parse(data.synced_at);
+    } else {
+      this.syncedTimestamp ??= null;
+    }
+
+    if ('subscriber_count' in data) {
+      /**
+       * How many subscribers this integration has
+       * @type {?number}
+       */
+      this.subscriberCount = data.subscriber_count;
+    } else {
+      this.subscriberCount ??= null;
+    }
+
+    if ('revoked' in data) {
+      /**
+       * Whether this integration has been revoked
+       * @type {?boolean}
+       */
+      this.revoked = data.revoked;
+    } else {
+      this.revoked ??= null;
+    }
+
+    this._patch(data);
+  }
+
+  /**
+   * The date at which this integration was last synced at
+   * @type {?Date}
+   * @readonly
+   */
+  get syncedAt() {
+    return this.syncedTimestamp && new Date(this.syncedTimestamp);
+  }
+
+  /**
+   * All roles that are managed by this integration
+   * @type {Collection<Snowflake, Role>}
+   * @readonly
+   */
+  get roles() {
+    const roles = this.guild.roles.cache;
+    return roles.filter(role => role.tags?.integrationId === this.id);
+  }
+
+  _patch(data) {
+    if ('expire_behavior' in data) {
+      /**
+       * The behavior of expiring subscribers
+       * @type {?IntegrationExpireBehavior}
+       */
+      this.expireBehavior = data.expire_behavior;
+    } else {
+      this.expireBehavior ??= null;
+    }
+
+    if ('expire_grace_period' in data) {
+      /**
+       * The grace period (in days) before expiring subscribers
+       * @type {?number}
+       */
+      this.expireGracePeriod = data.expire_grace_period;
+    } else {
+      this.expireGracePeriod ??= null;
+    }
+
+    if ('application' in data) {
+      if (this.application) {
+        this.application._patch(data.application);
+      } else {
+        /**
+         * The application for this integration
+         * @type {?IntegrationApplication}
+         */
+        this.application = new IntegrationApplication(this.client, data.application);
+      }
+    } else {
+      this.application ??= null;
+    }
+
+    if ('scopes' in data) {
+      /**
+       * The scopes this application has been authorized for
+       * @type {OAuth2Scopes[]}
+       */
+      this.scopes = data.scopes;
+    } else {
+      this.scopes ??= [];
+    }
+  }
+
+  /**
+   * Deletes this integration.
+   * @returns {Promise<Integration>}
+   * @param {string} [reason] Reason for deleting this integration
+   */
+  async delete(reason) {
+    await this.client.rest.delete(Routes.guildIntegration(this.guild.id, this.id), { reason });
+    return this;
+  }
+
+  toJSON() {
+    return super.toJSON({
+      role: 'roleId',
+      guild: 'guildId',
+      user: 'userId',
+    });
+  }
+}
+
+module.exports = Integration;
diff --git a/node_modules/discord.js/src/structures/IntegrationApplication.js b/node_modules/discord.js/src/structures/IntegrationApplication.js
new file mode 100644
index 0000000..4985008
--- /dev/null
+++ b/node_modules/discord.js/src/structures/IntegrationApplication.js
@@ -0,0 +1,85 @@
+'use strict';
+
+const Application = require('./interfaces/Application');
+
+/**
+ * Represents an Integration's OAuth2 Application.
+ * @extends {Application}
+ */
+class IntegrationApplication extends Application {
+  _patch(data) {
+    super._patch(data);
+
+    if ('bot' in data) {
+      /**
+       * The bot user for this application
+       * @type {?User}
+       */
+      this.bot = this.client.users._add(data.bot);
+    } else {
+      this.bot ??= null;
+    }
+
+    if ('terms_of_service_url' in data) {
+      /**
+       * The URL of the application's terms of service
+       * @type {?string}
+       */
+      this.termsOfServiceURL = data.terms_of_service_url;
+    } else {
+      this.termsOfServiceURL ??= null;
+    }
+
+    if ('privacy_policy_url' in data) {
+      /**
+       * The URL of the application's privacy policy
+       * @type {?string}
+       */
+      this.privacyPolicyURL = data.privacy_policy_url;
+    } else {
+      this.privacyPolicyURL ??= null;
+    }
+
+    if ('rpc_origins' in data) {
+      /**
+       * The Array of RPC origin URLs
+       * @type {string[]}
+       */
+      this.rpcOrigins = data.rpc_origins;
+    } else {
+      this.rpcOrigins ??= [];
+    }
+
+    if ('hook' in data) {
+      /**
+       * Whether the application can be default hooked by the client
+       * @type {?boolean}
+       */
+      this.hook = data.hook;
+    } else {
+      this.hook ??= null;
+    }
+
+    if ('cover_image' in data) {
+      /**
+       * The hash of the application's cover image
+       * @type {?string}
+       */
+      this.cover = data.cover_image;
+    } else {
+      this.cover ??= null;
+    }
+
+    if ('verify_key' in data) {
+      /**
+       * The hex-encoded key for verification in interactions and the GameSDK's GetTicket
+       * @type {?string}
+       */
+      this.verifyKey = data.verify_key;
+    } else {
+      this.verifyKey ??= null;
+    }
+  }
+}
+
+module.exports = IntegrationApplication;
diff --git a/node_modules/discord.js/src/structures/InteractionCollector.js b/node_modules/discord.js/src/structures/InteractionCollector.js
new file mode 100644
index 0000000..bb8e6c7
--- /dev/null
+++ b/node_modules/discord.js/src/structures/InteractionCollector.js
@@ -0,0 +1,269 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Collector = require('./interfaces/Collector');
+const Events = require('../util/Events');
+
+/**
+ * @typedef {CollectorOptions} InteractionCollectorOptions
+ * @property {TextBasedChannelsResolvable} [channel] The channel to listen to interactions from
+ * @property {ComponentType} [componentType] The type of component to listen for
+ * @property {GuildResolvable} [guild] The guild to listen to interactions from
+ * @property {InteractionType} [interactionType] The type of interaction to listen for
+ * @property {number} [max] The maximum total amount of interactions to collect
+ * @property {number} [maxComponents] The maximum number of components to collect
+ * @property {number} [maxUsers] The maximum number of users to interact
+ * @property {Message|APIMessage} [message] The message to listen to interactions from
+ * @property {InteractionResponse} [interactionResponse] The interaction response to listen
+ * to message component interactions from
+ */
+
+/**
+ * Collects interactions.
+ * Will automatically stop if the message ({@link Client#event:messageDelete messageDelete} or
+ * {@link Client#event:messageDeleteBulk messageDeleteBulk}),
+ * channel ({@link Client#event:channelDelete channelDelete}), or
+ * guild ({@link Client#event:guildDelete guildDelete}) is deleted.
+ * <info>Interaction collectors that do not specify `time` or `idle` may be prone to always running.
+ * Ensure your interaction collectors end via either of these options or manual cancellation.</info>
+ * @extends {Collector}
+ */
+class InteractionCollector extends Collector {
+  /**
+   * @param {Client} client The client on which to collect interactions
+   * @param {InteractionCollectorOptions} [options={}] The options to apply to this collector
+   */
+  constructor(client, options = {}) {
+    super(client, options);
+
+    /**
+     * The message from which to collect interactions, if provided
+     * @type {?Snowflake}
+     */
+    this.messageId = options.message?.id ?? options.interactionResponse?.interaction.message?.id ?? null;
+
+    /**
+     * The message interaction id from which to collect interactions, if provided
+     * @type {?Snowflake}
+     */
+    this.messageInteractionId = options.interactionResponse?.id ?? null;
+
+    /**
+     * The channel from which to collect interactions, if provided
+     * @type {?Snowflake}
+     */
+    this.channelId =
+      options.interactionResponse?.interaction.channelId ??
+      options.message?.channelId ??
+      options.message?.channel_id ??
+      this.client.channels.resolveId(options.channel);
+
+    /**
+     * The guild from which to collect interactions, if provided
+     * @type {?Snowflake}
+     */
+    this.guildId =
+      options.interactionResponse?.interaction.guildId ??
+      options.message?.guildId ??
+      options.message?.guild_id ??
+      this.client.guilds.resolveId(options.channel?.guild) ??
+      this.client.guilds.resolveId(options.guild);
+
+    /**
+     * The type of interaction to collect
+     * @type {?InteractionType}
+     */
+    this.interactionType = options.interactionType ?? null;
+
+    /**
+     * The type of component to collect
+     * @type {?ComponentType}
+     */
+    this.componentType = options.componentType ?? null;
+
+    /**
+     * The users that have interacted with this collector
+     * @type {Collection<Snowflake, User>}
+     */
+    this.users = new Collection();
+
+    /**
+     * The total number of interactions collected
+     * @type {number}
+     */
+    this.total = 0;
+
+    this.client.incrementMaxListeners();
+
+    const bulkDeleteListener = messages => {
+      if (messages.has(this.messageId)) this.stop('messageDelete');
+    };
+
+    if (this.messageId || this.messageInteractionId) {
+      this._handleMessageDeletion = this._handleMessageDeletion.bind(this);
+      this.client.on(Events.MessageDelete, this._handleMessageDeletion);
+      this.client.on(Events.MessageBulkDelete, bulkDeleteListener);
+    }
+
+    if (this.channelId) {
+      this._handleChannelDeletion = this._handleChannelDeletion.bind(this);
+      this._handleThreadDeletion = this._handleThreadDeletion.bind(this);
+      this.client.on(Events.ChannelDelete, this._handleChannelDeletion);
+      this.client.on(Events.ThreadDelete, this._handleThreadDeletion);
+    }
+
+    if (this.guildId) {
+      this._handleGuildDeletion = this._handleGuildDeletion.bind(this);
+      this.client.on(Events.GuildDelete, this._handleGuildDeletion);
+    }
+
+    this.client.on(Events.InteractionCreate, this.handleCollect);
+
+    this.once('end', () => {
+      this.client.removeListener(Events.InteractionCreate, this.handleCollect);
+      this.client.removeListener(Events.MessageDelete, this._handleMessageDeletion);
+      this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener);
+      this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion);
+      this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion);
+      this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion);
+      this.client.decrementMaxListeners();
+    });
+
+    this.on('collect', interaction => {
+      this.total++;
+      this.users.set(interaction.user.id, interaction.user);
+    });
+  }
+
+  /**
+   * Handles an incoming interaction for possible collection.
+   * @param {BaseInteraction} interaction The interaction to possibly collect
+   * @returns {?Snowflake}
+   * @private
+   */
+  collect(interaction) {
+    /**
+     * Emitted whenever an interaction is collected.
+     * @event InteractionCollector#collect
+     * @param {BaseInteraction} interaction The interaction that was collected
+     */
+
+    if (this.interactionType && interaction.type !== this.interactionType) return null;
+    if (this.componentType && interaction.componentType !== this.componentType) return null;
+    if (this.messageId && interaction.message?.id !== this.messageId) return null;
+    if (
+      this.messageInteractionId &&
+      interaction.message?.interaction?.id &&
+      interaction.message.interaction.id !== this.messageInteractionId
+    ) {
+      return null;
+    }
+    if (this.channelId && interaction.channelId !== this.channelId) return null;
+    if (this.guildId && interaction.guildId !== this.guildId) return null;
+
+    return interaction.id;
+  }
+
+  /**
+   * Handles an interaction for possible disposal.
+   * @param {BaseInteraction} interaction The interaction that could be disposed of
+   * @returns {?Snowflake}
+   */
+  dispose(interaction) {
+    /**
+     * Emitted whenever an interaction is disposed of.
+     * @event InteractionCollector#dispose
+     * @param {BaseInteraction} interaction The interaction that was disposed of
+     */
+    if (this.type && interaction.type !== this.type) return null;
+    if (this.componentType && interaction.componentType !== this.componentType) return null;
+    if (this.messageId && interaction.message?.id !== this.messageId) return null;
+    if (
+      this.messageInteractionId &&
+      interaction.message?.interaction?.id &&
+      interaction.message.interaction.id !== this.messageInteractionId
+    ) {
+      return null;
+    }
+    if (this.channelId && interaction.channelId !== this.channelId) return null;
+    if (this.guildId && interaction.guildId !== this.guildId) return null;
+
+    return interaction.id;
+  }
+
+  /**
+   * Empties this interaction collector.
+   */
+  empty() {
+    this.total = 0;
+    this.collected.clear();
+    this.users.clear();
+    this.checkEnd();
+  }
+
+  /**
+   * The reason this collector has ended with, or null if it hasn't ended yet
+   * @type {?string}
+   * @readonly
+   */
+  get endReason() {
+    if (this.options.max && this.total >= this.options.max) return 'limit';
+    if (this.options.maxComponents && this.collected.size >= this.options.maxComponents) return 'componentLimit';
+    if (this.options.maxUsers && this.users.size >= this.options.maxUsers) return 'userLimit';
+    return super.endReason;
+  }
+
+  /**
+   * Handles checking if the message has been deleted, and if so, stops the collector with the reason 'messageDelete'.
+   * @private
+   * @param {Message} message The message that was deleted
+   * @returns {void}
+   */
+  _handleMessageDeletion(message) {
+    if (message.id === this.messageId) {
+      this.stop('messageDelete');
+    }
+
+    if (message.interaction?.id === this.messageInteractionId) {
+      this.stop('messageDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'.
+   * @private
+   * @param {GuildChannel} channel The channel that was deleted
+   * @returns {void}
+   */
+  _handleChannelDeletion(channel) {
+    if (channel.id === this.channelId || channel.threads?.cache.has(this.channelId)) {
+      this.stop('channelDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'.
+   * @private
+   * @param {ThreadChannel} thread The thread that was deleted
+   * @returns {void}
+   */
+  _handleThreadDeletion(thread) {
+    if (thread.id === this.channelId) {
+      this.stop('threadDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'.
+   * @private
+   * @param {Guild} guild The guild that was deleted
+   * @returns {void}
+   */
+  _handleGuildDeletion(guild) {
+    if (guild.id === this.guildId) {
+      this.stop('guildDelete');
+    }
+  }
+}
+
+module.exports = InteractionCollector;
diff --git a/node_modules/discord.js/src/structures/InteractionResponse.js b/node_modules/discord.js/src/structures/InteractionResponse.js
new file mode 100644
index 0000000..9b372e3
--- /dev/null
+++ b/node_modules/discord.js/src/structures/InteractionResponse.js
@@ -0,0 +1,102 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { InteractionType } = require('discord-api-types/v10');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents an interaction's response
+ */
+class InteractionResponse {
+  constructor(interaction, id) {
+    /**
+     * The interaction associated with the interaction response
+     * @type {BaseInteraction}
+     */
+    this.interaction = interaction;
+    /**
+     * The id of the original interaction response
+     * @type {Snowflake}
+     */
+    this.id = id ?? interaction.id;
+    this.client = interaction.client;
+  }
+
+  /**
+   * The timestamp the interaction response was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the interaction response was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * Collects a single component interaction that passes the filter.
+   * The Promise will reject if the time expires.
+   * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector
+   * @returns {Promise<MessageComponentInteraction>}
+   */
+  awaitMessageComponent(options = {}) {
+    const _options = { ...options, max: 1 };
+    return new Promise((resolve, reject) => {
+      const collector = this.createMessageComponentCollector(_options);
+      collector.once('end', (interactions, reason) => {
+        const interaction = interactions.first();
+        if (interaction) resolve(interaction);
+        else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason));
+      });
+    });
+  }
+
+  /**
+   * Creates a message component interaction collector
+   * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
+   * @returns {InteractionCollector}
+   */
+  createMessageComponentCollector(options = {}) {
+    return new InteractionCollector(this.client, {
+      ...options,
+      interactionResponse: this,
+      interactionType: InteractionType.MessageComponent,
+    });
+  }
+
+  /**
+   * Fetches the response as a {@link Message} object.
+   * @returns {Promise<Message>}
+   */
+  fetch() {
+    return this.interaction.fetchReply();
+  }
+
+  /**
+   * Deletes the response.
+   * @returns {Promise<void>}
+   */
+  delete() {
+    return this.interaction.deleteReply();
+  }
+
+  /**
+   * Edits the response.
+   * @param {string|MessagePayload|WebhookMessageEditOptions} options The new options for the response.
+   * @returns {Promise<Message>}
+   */
+  edit(options) {
+    return this.interaction.editReply(options);
+  }
+}
+
+// eslint-disable-next-line import/order
+const InteractionCollector = require('./InteractionCollector');
+module.exports = InteractionResponse;
diff --git a/node_modules/discord.js/src/structures/InteractionWebhook.js b/node_modules/discord.js/src/structures/InteractionWebhook.js
new file mode 100644
index 0000000..58eb531
--- /dev/null
+++ b/node_modules/discord.js/src/structures/InteractionWebhook.js
@@ -0,0 +1,59 @@
+'use strict';
+
+const Webhook = require('./Webhook');
+
+/**
+ * Represents a webhook for an Interaction
+ * @implements {Webhook}
+ */
+class InteractionWebhook {
+  /**
+   * @param {Client} client The instantiating client
+   * @param {Snowflake} id The application's id
+   * @param {string} token The interaction's token
+   */
+  constructor(client, id, token) {
+    /**
+     * The client that instantiated the interaction webhook
+     * @name InteractionWebhook#client
+     * @type {Client}
+     * @readonly
+     */
+    Object.defineProperty(this, 'client', { value: client });
+    this.id = id;
+    Object.defineProperty(this, 'token', { value: token, writable: true, configurable: true });
+  }
+
+  // These are here only for documentation purposes - they are implemented by Webhook
+  /* eslint-disable no-empty-function */
+  /**
+   * Sends a message with this webhook.
+   * @param {string|MessagePayload|InteractionReplyOptions} options The content for the reply
+   * @returns {Promise<Message>}
+   */
+
+  send() {}
+
+  /**
+   * Gets a message that was sent by this webhook.
+   * @param {Snowflake|'@original'} message The id of the message to fetch
+   * @returns {Promise<Message>} Returns the message sent by this webhook
+   */
+
+  fetchMessage() {}
+
+  /**
+   * Edits a message that was sent by this webhook.
+   * @param {MessageResolvable|'@original'} message The message to edit
+   * @param {string|MessagePayload|WebhookMessageEditOptions} options The options to provide
+   * @returns {Promise<Message>} Returns the message edited by this webhook
+   */
+
+  editMessage() {}
+  deleteMessage() {}
+  get url() {}
+}
+
+Webhook.applyToClass(InteractionWebhook, ['sendSlackMessage', 'edit', 'delete', 'createdTimestamp', 'createdAt']);
+
+module.exports = InteractionWebhook;
diff --git a/node_modules/discord.js/src/structures/Invite.js b/node_modules/discord.js/src/structures/Invite.js
new file mode 100644
index 0000000..19014ff
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Invite.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const { RouteBases, Routes, PermissionFlagsBits } = require('discord-api-types/v10');
+const Base = require('./Base');
+const { GuildScheduledEvent } = require('./GuildScheduledEvent');
+const IntegrationApplication = require('./IntegrationApplication');
+const InviteStageInstance = require('./InviteStageInstance');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents an invitation to a guild channel.
+ * @extends {Base}
+ */
+class Invite extends Base {
+  /**
+   * A regular expression that matches Discord invite links.
+   * The `code` group property is present on the `exec()` result of this expression.
+   * @type {RegExp}
+   * @memberof Invite
+   */
+  static InvitesPattern = /discord(?:(?:app)?\.com\/invite|\.gg(?:\/invite)?)\/(?<code>[\w-]{2,255})/i;
+
+  constructor(client, data) {
+    super(client);
+    this._patch(data);
+  }
+
+  _patch(data) {
+    const InviteGuild = require('./InviteGuild');
+    /**
+     * The guild the invite is for including welcome screen data if present
+     * @type {?(Guild|InviteGuild)}
+     */
+    this.guild ??= null;
+    if (data.guild) {
+      this.guild = this.client.guilds.resolve(data.guild.id) ?? new InviteGuild(this.client, data.guild);
+    }
+
+    if ('code' in data) {
+      /**
+       * The code for this invite
+       * @type {string}
+       */
+      this.code = data.code;
+    }
+
+    if ('approximate_presence_count' in data) {
+      /**
+       * The approximate number of online members of the guild this invite is for
+       * <info>This is only available when the invite was fetched through {@link Client#fetchInvite}.</info>
+       * @type {?number}
+       */
+      this.presenceCount = data.approximate_presence_count;
+    } else {
+      this.presenceCount ??= null;
+    }
+
+    if ('approximate_member_count' in data) {
+      /**
+       * The approximate total number of members of the guild this invite is for
+       * <info>This is only available when the invite was fetched through {@link Client#fetchInvite}.</info>
+       * @type {?number}
+       */
+      this.memberCount = data.approximate_member_count;
+    } else {
+      this.memberCount ??= null;
+    }
+
+    if ('temporary' in data) {
+      /**
+       * Whether or not this invite only grants temporary membership
+       * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}
+       * or created through {@link GuildInviteManager#create}.</info>
+       * @type {?boolean}
+       */
+      this.temporary = data.temporary ?? null;
+    } else {
+      this.temporary ??= null;
+    }
+
+    if ('max_age' in data) {
+      /**
+       * The maximum age of the invite, in seconds, 0 if never expires
+       * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}
+       * or created through {@link GuildInviteManager#create}.</info>
+       * @type {?number}
+       */
+      this.maxAge = data.max_age;
+    } else {
+      this.maxAge ??= null;
+    }
+
+    if ('uses' in data) {
+      /**
+       * How many times this invite has been used
+       * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}
+       * or created through {@link GuildInviteManager#create}.</info>
+       * @type {?number}
+       */
+      this.uses = data.uses;
+    } else {
+      this.uses ??= null;
+    }
+
+    if ('max_uses' in data) {
+      /**
+       * The maximum uses of this invite
+       * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}
+       * or created through {@link GuildInviteManager#create}.</info>
+       * @type {?number}
+       */
+      this.maxUses = data.max_uses;
+    } else {
+      this.maxUses ??= null;
+    }
+
+    if ('inviter_id' in data) {
+      /**
+       * The user's id who created this invite
+       * @type {?Snowflake}
+       */
+      this.inviterId = data.inviter_id;
+    } else {
+      this.inviterId ??= null;
+    }
+
+    if ('inviter' in data) {
+      this.client.users._add(data.inviter);
+      this.inviterId = data.inviter.id;
+    }
+
+    if ('target_user' in data) {
+      /**
+       * The user whose stream to display for this voice channel stream invite
+       * @type {?User}
+       */
+      this.targetUser = this.client.users._add(data.target_user);
+    } else {
+      this.targetUser ??= null;
+    }
+
+    if ('target_application' in data) {
+      /**
+       * The embedded application to open for this voice channel embedded application invite
+       * @type {?IntegrationApplication}
+       */
+      this.targetApplication = new IntegrationApplication(this.client, data.target_application);
+    } else {
+      this.targetApplication ??= null;
+    }
+
+    if ('target_type' in data) {
+      /**
+       * The target type
+       * @type {?InviteTargetType}
+       */
+      this.targetType = data.target_type;
+    } else {
+      this.targetType ??= null;
+    }
+
+    if ('channel_id' in data) {
+      /**
+       * The id of the channel this invite is for
+       * @type {?Snowflake}
+       */
+      this.channelId = data.channel_id;
+    }
+
+    if ('channel' in data) {
+      /**
+       * The channel this invite is for
+       * @type {?BaseChannel}
+       */
+      this.channel =
+        this.client.channels._add(data.channel, this.guild, { cache: false }) ??
+        this.client.channels.resolve(this.channelId);
+
+      this.channelId ??= data.channel.id;
+    }
+
+    if ('created_at' in data) {
+      /**
+       * The timestamp this invite was created at
+       * @type {?number}
+       */
+      this.createdTimestamp = Date.parse(data.created_at);
+    } else {
+      this.createdTimestamp ??= null;
+    }
+
+    if ('expires_at' in data) {
+      this._expiresTimestamp = data.expires_at && Date.parse(data.expires_at);
+    } else {
+      this._expiresTimestamp ??= null;
+    }
+
+    if ('stage_instance' in data) {
+      /**
+       * The stage instance data if there is a public {@link StageInstance} in the stage channel this invite is for
+       * @type {?InviteStageInstance}
+       * @deprecated
+       */
+      this.stageInstance = new InviteStageInstance(this.client, data.stage_instance, this.channel.id, this.guild.id);
+    } else {
+      this.stageInstance ??= null;
+    }
+
+    if ('guild_scheduled_event' in data) {
+      /**
+       * The guild scheduled event data if there is a {@link GuildScheduledEvent} in the channel this invite is for
+       * @type {?GuildScheduledEvent}
+       */
+      this.guildScheduledEvent = new GuildScheduledEvent(this.client, data.guild_scheduled_event);
+    } else {
+      this.guildScheduledEvent ??= null;
+    }
+  }
+
+  /**
+   * The time the invite was created at
+   * @type {?Date}
+   * @readonly
+   */
+  get createdAt() {
+    return this.createdTimestamp && new Date(this.createdTimestamp);
+  }
+
+  /**
+   * Whether the invite is deletable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get deletable() {
+    const guild = this.guild;
+    if (!guild || !this.client.guilds.cache.has(guild.id)) return false;
+    if (!guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);
+    return Boolean(
+      this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageChannels, false) ||
+        guild.members.me.permissions.has(PermissionFlagsBits.ManageGuild),
+    );
+  }
+
+  /**
+   * The timestamp the invite will expire at
+   * @type {?number}
+   * @readonly
+   */
+  get expiresTimestamp() {
+    return (
+      this._expiresTimestamp ??
+      (this.createdTimestamp && this.maxAge ? this.createdTimestamp + this.maxAge * 1_000 : null)
+    );
+  }
+
+  /**
+   * The time the invite will expire at
+   * @type {?Date}
+   * @readonly
+   */
+  get expiresAt() {
+    return this.expiresTimestamp && new Date(this.expiresTimestamp);
+  }
+
+  /**
+   * The user who created this invite
+   * @type {?User}
+   * @readonly
+   */
+  get inviter() {
+    return this.inviterId && this.client.users.resolve(this.inviterId);
+  }
+
+  /**
+   * The URL to the invite
+   * @type {string}
+   * @readonly
+   */
+  get url() {
+    return `${RouteBases.invite}/${this.code}`;
+  }
+
+  /**
+   * Deletes this invite.
+   * @param {string} [reason] Reason for deleting this invite
+   * @returns {Promise<Invite>}
+   */
+  async delete(reason) {
+    await this.client.rest.delete(Routes.invite(this.code), { reason });
+    return this;
+  }
+
+  /**
+   * When concatenated with a string, this automatically concatenates the invite's URL instead of the object.
+   * @returns {string}
+   * @example
+   * // Logs: Invite: https://discord.gg/A1b2C3
+   * console.log(`Invite: ${invite}`);
+   */
+  toString() {
+    return this.url;
+  }
+
+  toJSON() {
+    return super.toJSON({
+      url: true,
+      expiresTimestamp: true,
+      presenceCount: false,
+      memberCount: false,
+      uses: false,
+      channel: 'channelId',
+      inviter: 'inviterId',
+      guild: 'guildId',
+    });
+  }
+
+  valueOf() {
+    return this.code;
+  }
+}
+
+module.exports = Invite;
diff --git a/node_modules/discord.js/src/structures/InviteGuild.js b/node_modules/discord.js/src/structures/InviteGuild.js
new file mode 100644
index 0000000..8efd980
--- /dev/null
+++ b/node_modules/discord.js/src/structures/InviteGuild.js
@@ -0,0 +1,22 @@
+'use strict';
+
+const AnonymousGuild = require('./AnonymousGuild');
+const WelcomeScreen = require('./WelcomeScreen');
+
+/**
+ * Represents a guild received from an invite, includes welcome screen data if available.
+ * @extends {AnonymousGuild}
+ */
+class InviteGuild extends AnonymousGuild {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * The welcome screen for this invite guild
+     * @type {?WelcomeScreen}
+     */
+    this.welcomeScreen = data.welcome_screen !== undefined ? new WelcomeScreen(this, data.welcome_screen) : null;
+  }
+}
+
+module.exports = InviteGuild;
diff --git a/node_modules/discord.js/src/structures/InviteStageInstance.js b/node_modules/discord.js/src/structures/InviteStageInstance.js
new file mode 100644
index 0000000..21ede43
--- /dev/null
+++ b/node_modules/discord.js/src/structures/InviteStageInstance.js
@@ -0,0 +1,87 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Base = require('./Base');
+
+/**
+ * Represents the data about a public {@link StageInstance} in an {@link Invite}.
+ * @extends {Base}
+ * @deprecated
+ */
+class InviteStageInstance extends Base {
+  constructor(client, data, channelId, guildId) {
+    super(client);
+
+    /**
+     * The id of the stage channel this invite is for
+     * @type {Snowflake}
+     */
+    this.channelId = channelId;
+
+    /**
+     * The stage channel's guild id
+     * @type {Snowflake}
+     */
+    this.guildId = guildId;
+
+    /**
+     * The members speaking in the stage channel
+     * @type {Collection<Snowflake, GuildMember>}
+     */
+    this.members = new Collection();
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('topic' in data) {
+      /**
+       * The topic of the stage instance
+       * @type {string}
+       */
+      this.topic = data.topic;
+    }
+
+    if ('participant_count' in data) {
+      /**
+       * The number of users in the stage channel
+       * @type {number}
+       */
+      this.participantCount = data.participant_count;
+    }
+
+    if ('speaker_count' in data) {
+      /**
+       * The number of users speaking in the stage channel
+       * @type {number}
+       */
+      this.speakerCount = data.speaker_count;
+    }
+
+    this.members.clear();
+    for (const rawMember of data.members) {
+      const member = this.guild.members._add(rawMember);
+      this.members.set(member.id, member);
+    }
+  }
+
+  /**
+   * The stage channel this invite is for
+   * @type {?StageChannel}
+   * @readonly
+   */
+  get channel() {
+    return this.client.channels.resolve(this.channelId);
+  }
+
+  /**
+   * The guild of the stage channel this invite is for
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.resolve(this.guildId);
+  }
+}
+
+module.exports = InviteStageInstance;
diff --git a/node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js b/node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js
new file mode 100644
index 0000000..b22f600
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js
@@ -0,0 +1,32 @@
+'use strict';
+
+const { MentionableSelectMenuBuilder: BuildersMentionableSelectMenu } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+
+/**
+ * Class used to build select menu components to be sent through the API
+ * @extends {BuildersMentionableSelectMenu}
+ */
+class MentionableSelectMenuBuilder extends BuildersMentionableSelectMenu {
+  constructor(data = {}) {
+    super(toSnakeCase(data));
+  }
+
+  /**
+   * Creates a new select menu builder from JSON data
+   * @param {MentionableSelectMenuBuilder|MentionableSelectMenuComponent|APIMentionableSelectComponent} other
+   * The other data
+   * @returns {MentionableSelectMenuBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = MentionableSelectMenuBuilder;
+
+/**
+ * @external BuildersMentionableSelectMenu
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/MentionableSelectMenuBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js b/node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js
new file mode 100644
index 0000000..d0f75c3
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
+
+/**
+ * Represents a mentionable select menu component
+ * @extends {BaseSelectMenuComponent}
+ */
+class MentionableSelectMenuComponent extends BaseSelectMenuComponent {}
+
+module.exports = MentionableSelectMenuComponent;
diff --git a/node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js b/node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js
new file mode 100644
index 0000000..416d5ce
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js
@@ -0,0 +1,71 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const MessageComponentInteraction = require('./MessageComponentInteraction');
+const Events = require('../util/Events');
+
+/**
+ * Represents a {@link ComponentType.MentionableSelect} select menu interaction.
+ * @extends {MessageComponentInteraction}
+ */
+class MentionableSelectMenuInteraction extends MessageComponentInteraction {
+  constructor(client, data) {
+    super(client, data);
+    const { resolved, values } = data.data;
+    const { members, users, roles } = resolved ?? {};
+
+    /**
+     * An array of the selected user and role ids
+     * @type {Snowflake[]}
+     */
+    this.values = values ?? [];
+
+    /**
+     * Collection of the selected users
+     * @type {Collection<Snowflake, User>}
+     */
+    this.users = new Collection();
+
+    /**
+     * Collection of the selected users
+     * @type {Collection<Snowflake, GuildMember|APIGuildMember>}
+     */
+    this.members = new Collection();
+
+    /**
+     * Collection of the selected roles
+     * @type {Collection<Snowflake, Role|APIRole>}
+     */
+    this.roles = new Collection();
+
+    if (members) {
+      for (const [id, member] of Object.entries(members)) {
+        const user = users[id];
+        if (!user) {
+          this.client.emit(
+            Events.Debug,
+            `[MentionableSelectMenuInteraction] Received a member without a user, skipping ${id}`,
+          );
+
+          continue;
+        }
+
+        this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member });
+      }
+    }
+
+    if (users) {
+      for (const user of Object.values(users)) {
+        this.users.set(user.id, this.client.users._add(user));
+      }
+    }
+
+    if (roles) {
+      for (const role of Object.values(roles)) {
+        this.roles.set(role.id, this.guild?.roles._add(role) ?? role);
+      }
+    }
+  }
+}
+
+module.exports = MentionableSelectMenuInteraction;
diff --git a/node_modules/discord.js/src/structures/Message.js b/node_modules/discord.js/src/structures/Message.js
new file mode 100644
index 0000000..c82c177
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Message.js
@@ -0,0 +1,997 @@
+'use strict';
+
+const { messageLink } = require('@discordjs/builders');
+const { Collection } = require('@discordjs/collection');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const {
+  InteractionType,
+  ChannelType,
+  MessageType,
+  MessageFlags,
+  PermissionFlagsBits,
+} = require('discord-api-types/v10');
+const Attachment = require('./Attachment');
+const Base = require('./Base');
+const ClientApplication = require('./ClientApplication');
+const Embed = require('./Embed');
+const InteractionCollector = require('./InteractionCollector');
+const Mentions = require('./MessageMentions');
+const MessagePayload = require('./MessagePayload');
+const ReactionCollector = require('./ReactionCollector');
+const { Sticker } = require('./Sticker');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+const ReactionManager = require('../managers/ReactionManager');
+const { createComponent } = require('../util/Components');
+const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, DeletableMessageTypes } = require('../util/Constants');
+const MessageFlagsBitField = require('../util/MessageFlagsBitField');
+const PermissionsBitField = require('../util/PermissionsBitField');
+const { cleanContent, resolvePartialEmoji } = require('../util/Util');
+
+/**
+ * Represents a message on Discord.
+ * @extends {Base}
+ */
+class Message extends Base {
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The id of the channel the message was sent in
+     * @type {Snowflake}
+     */
+    this.channelId = data.channel_id;
+
+    /**
+     * The id of the guild the message was sent in, if any
+     * @type {?Snowflake}
+     */
+    this.guildId = data.guild_id ?? this.channel?.guild?.id ?? null;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    /**
+     * The message's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    /**
+     * The timestamp the message was sent at
+     * @type {number}
+     */
+    this.createdTimestamp = DiscordSnowflake.timestampFrom(this.id);
+
+    if ('type' in data) {
+      /**
+       * The type of the message
+       * @type {?MessageType}
+       */
+      this.type = data.type;
+
+      /**
+       * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications)
+       * @type {?boolean}
+       */
+      this.system = !NonSystemMessageTypes.includes(this.type);
+    } else {
+      this.system ??= null;
+      this.type ??= null;
+    }
+
+    if ('content' in data) {
+      /**
+       * The content of the message.
+       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent
+       * in a guild for messages that do not mention the client.</info>
+       * @type {?string}
+       */
+      this.content = data.content;
+    } else {
+      this.content ??= null;
+    }
+
+    if ('author' in data) {
+      /**
+       * The author of the message
+       * @type {?User}
+       */
+      this.author = this.client.users._add(data.author, !data.webhook_id);
+    } else {
+      this.author ??= null;
+    }
+
+    if ('pinned' in data) {
+      /**
+       * Whether or not this message is pinned
+       * @type {?boolean}
+       */
+      this.pinned = Boolean(data.pinned);
+    } else {
+      this.pinned ??= null;
+    }
+
+    if ('tts' in data) {
+      /**
+       * Whether or not the message was Text-To-Speech
+       * @type {?boolean}
+       */
+      this.tts = data.tts;
+    } else {
+      this.tts ??= null;
+    }
+
+    if ('nonce' in data) {
+      /**
+       * A random number or string used for checking message delivery
+       * <warn>This is only received after the message was sent successfully, and
+       * lost if re-fetched</warn>
+       * @type {?string}
+       */
+      this.nonce = data.nonce;
+    } else {
+      this.nonce ??= null;
+    }
+
+    if ('embeds' in data) {
+      /**
+       * An array of embeds in the message - e.g. YouTube Player.
+       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent
+       * in a guild for messages that do not mention the client.</info>
+       * @type {Embed[]}
+       */
+      this.embeds = data.embeds.map(e => new Embed(e));
+    } else {
+      this.embeds = this.embeds?.slice() ?? [];
+    }
+
+    if ('components' in data) {
+      /**
+       * An array of of action rows in the message.
+       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent
+       * in a guild for messages that do not mention the client.</info>
+       * @type {ActionRow[]}
+       */
+      this.components = data.components.map(c => createComponent(c));
+    } else {
+      this.components = this.components?.slice() ?? [];
+    }
+
+    if ('attachments' in data) {
+      /**
+       * A collection of attachments in the message - e.g. Pictures - mapped by their ids.
+       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent
+       * in a guild for messages that do not mention the client.</info>
+       * @type {Collection<Snowflake, Attachment>}
+       */
+      this.attachments = new Collection();
+      if (data.attachments) {
+        for (const attachment of data.attachments) {
+          this.attachments.set(attachment.id, new Attachment(attachment));
+        }
+      }
+    } else {
+      this.attachments = new Collection(this.attachments);
+    }
+
+    if ('sticker_items' in data || 'stickers' in data) {
+      /**
+       * A collection of stickers in the message
+       * @type {Collection<Snowflake, Sticker>}
+       */
+      this.stickers = new Collection(
+        (data.sticker_items ?? data.stickers)?.map(s => [s.id, new Sticker(this.client, s)]),
+      );
+    } else {
+      this.stickers = new Collection(this.stickers);
+    }
+
+    if ('position' in data) {
+      /**
+       * A generally increasing integer (there may be gaps or duplicates) that represents
+       * the approximate position of the message in a thread.
+       * @type {?number}
+       */
+      this.position = data.position;
+    } else {
+      this.position ??= null;
+    }
+
+    if ('role_subscription_data' in data) {
+      /**
+       * Role subscription data found on {@link MessageType.RoleSubscriptionPurchase} messages.
+       * @typedef {Object} RoleSubscriptionData
+       * @property {Snowflake} roleSubscriptionListingId The id of the SKU and listing the user is subscribed to
+       * @property {string} tierName The name of the tier the user is subscribed to
+       * @property {number} totalMonthsSubscribed The total number of months the user has been subscribed for
+       * @property {boolean} isRenewal Whether this notification is a renewal
+       */
+
+      /**
+       * The data of the role subscription purchase or renewal.
+       * <info>This is present on {@link MessageType.RoleSubscriptionPurchase} messages.</info>
+       * @type {?RoleSubscriptionData}
+       */
+      this.roleSubscriptionData = {
+        roleSubscriptionListingId: data.role_subscription_data.role_subscription_listing_id,
+        tierName: data.role_subscription_data.tier_name,
+        totalMonthsSubscribed: data.role_subscription_data.total_months_subscribed,
+        isRenewal: data.role_subscription_data.is_renewal,
+      };
+    } else {
+      this.roleSubscriptionData ??= null;
+    }
+
+    // Discord sends null if the message has not been edited
+    if (data.edited_timestamp) {
+      /**
+       * The timestamp the message was last edited at (if applicable)
+       * @type {?number}
+       */
+      this.editedTimestamp = Date.parse(data.edited_timestamp);
+    } else {
+      this.editedTimestamp ??= null;
+    }
+
+    if ('reactions' in data) {
+      /**
+       * A manager of the reactions belonging to this message
+       * @type {ReactionManager}
+       */
+      this.reactions = new ReactionManager(this);
+      if (data.reactions?.length > 0) {
+        for (const reaction of data.reactions) {
+          this.reactions._add(reaction);
+        }
+      }
+    } else {
+      this.reactions ??= new ReactionManager(this);
+    }
+
+    if (!this.mentions) {
+      /**
+       * All valid mentions that the message contains
+       * @type {MessageMentions}
+       */
+      this.mentions = new Mentions(
+        this,
+        data.mentions,
+        data.mention_roles,
+        data.mention_everyone,
+        data.mention_channels,
+        data.referenced_message?.author,
+      );
+    } else {
+      this.mentions = new Mentions(
+        this,
+        data.mentions ?? this.mentions.users,
+        data.mention_roles ?? this.mentions.roles,
+        data.mention_everyone ?? this.mentions.everyone,
+        data.mention_channels ?? this.mentions.crosspostedChannels,
+        data.referenced_message?.author ?? this.mentions.repliedUser,
+      );
+    }
+
+    if ('webhook_id' in data) {
+      /**
+       * The id of the webhook that sent the message, if applicable
+       * @type {?Snowflake}
+       */
+      this.webhookId = data.webhook_id;
+    } else {
+      this.webhookId ??= null;
+    }
+
+    if ('application' in data) {
+      /**
+       * Supplemental application information for group activities
+       * @type {?ClientApplication}
+       */
+      this.groupActivityApplication = new ClientApplication(this.client, data.application);
+    } else {
+      this.groupActivityApplication ??= null;
+    }
+
+    if ('application_id' in data) {
+      /**
+       * The id of the application of the interaction that sent this message, if any
+       * @type {?Snowflake}
+       */
+      this.applicationId = data.application_id;
+    } else {
+      this.applicationId ??= null;
+    }
+
+    if ('activity' in data) {
+      /**
+       * Group activity
+       * @type {?MessageActivity}
+       */
+      this.activity = {
+        partyId: data.activity.party_id,
+        type: data.activity.type,
+      };
+    } else {
+      this.activity ??= null;
+    }
+
+    if ('thread' in data) {
+      this.client.channels._add(data.thread, this.guild);
+    }
+
+    if (this.member && data.member) {
+      this.member._patch(data.member);
+    } else if (data.member && this.guild && this.author) {
+      this.guild.members._add(Object.assign(data.member, { user: this.author }));
+    }
+
+    if ('flags' in data) {
+      /**
+       * Flags that are applied to the message
+       * @type {Readonly<MessageFlagsBitField>}
+       */
+      this.flags = new MessageFlagsBitField(data.flags).freeze();
+    } else {
+      this.flags = new MessageFlagsBitField(this.flags).freeze();
+    }
+
+    /**
+     * Reference data sent in a message that contains ids identifying the referenced message.
+     * This can be present in the following types of message:
+     * * Crossposted messages (`MessageFlags.Crossposted`)
+     * * {@link MessageType.ChannelFollowAdd}
+     * * {@link MessageType.ChannelPinnedMessage}
+     * * {@link MessageType.Reply}
+     * * {@link MessageType.ThreadStarterMessage}
+     * @see {@link https://discord.com/developers/docs/resources/channel#message-types}
+     * @typedef {Object} MessageReference
+     * @property {Snowflake} channelId The channel's id the message was referenced
+     * @property {?Snowflake} guildId The guild's id the message was referenced
+     * @property {?Snowflake} messageId The message's id that was referenced
+     */
+
+    if ('message_reference' in data) {
+      /**
+       * Message reference data
+       * @type {?MessageReference}
+       */
+      this.reference = {
+        channelId: data.message_reference.channel_id,
+        guildId: data.message_reference.guild_id,
+        messageId: data.message_reference.message_id,
+      };
+    } else {
+      this.reference ??= null;
+    }
+
+    if (data.referenced_message) {
+      this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });
+    }
+
+    /**
+     * Partial data of the interaction that a message is a reply to
+     * @typedef {Object} MessageInteraction
+     * @property {Snowflake} id The interaction's id
+     * @property {InteractionType} type The type of the interaction
+     * @property {string} commandName The name of the interaction's application command,
+     * as well as the subcommand and subcommand group, where applicable
+     * @property {User} user The user that invoked the interaction
+     */
+
+    if (data.interaction) {
+      /**
+       * Partial data of the interaction that this message is a reply to
+       * @type {?MessageInteraction}
+       */
+      this.interaction = {
+        id: data.interaction.id,
+        type: data.interaction.type,
+        commandName: data.interaction.name,
+        user: this.client.users._add(data.interaction.user),
+      };
+    } else {
+      this.interaction ??= null;
+    }
+  }
+
+  /**
+   * The channel that the message was sent in
+   * @type {TextBasedChannels}
+   * @readonly
+   */
+  get channel() {
+    return this.client.channels.resolve(this.channelId);
+  }
+
+  /**
+   * Whether or not this message is a partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return typeof this.content !== 'string' || !this.author;
+  }
+
+  /**
+   * Represents the author of the message as a guild member.
+   * Only available if the message comes from a guild where the author is still a member
+   * @type {?GuildMember}
+   * @readonly
+   */
+  get member() {
+    return this.guild?.members.resolve(this.author) ?? null;
+  }
+
+  /**
+   * The time the message was sent at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The time the message was last edited at (if applicable)
+   * @type {?Date}
+   * @readonly
+   */
+  get editedAt() {
+    return this.editedTimestamp && new Date(this.editedTimestamp);
+  }
+
+  /**
+   * The guild the message was sent in (if in a guild channel)
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.resolve(this.guildId) ?? this.channel?.guild ?? null;
+  }
+
+  /**
+   * Whether this message has a thread associated with it
+   * @type {boolean}
+   * @readonly
+   */
+  get hasThread() {
+    return this.flags.has(MessageFlags.HasThread);
+  }
+
+  /**
+   * The thread started by this message
+   * <info>This property is not suitable for checking whether a message has a thread,
+   * use {@link Message#hasThread} instead.</info>
+   * @type {?ThreadChannel}
+   * @readonly
+   */
+  get thread() {
+    return this.channel?.threads?.resolve(this.id) ?? null;
+  }
+
+  /**
+   * The URL to jump to this message
+   * @type {string}
+   * @readonly
+   */
+  get url() {
+    return this.inGuild() ? messageLink(this.channelId, this.id, this.guildId) : messageLink(this.channelId, this.id);
+  }
+
+  /**
+   * The message contents with all mentions replaced by the equivalent text.
+   * If mentions cannot be resolved to a name, the relevant mention in the message content will not be converted.
+   * @type {?string}
+   * @readonly
+   */
+  get cleanContent() {
+    // eslint-disable-next-line eqeqeq
+    return this.content != null ? cleanContent(this.content, this.channel) : null;
+  }
+
+  /**
+   * Creates a reaction collector.
+   * @param {ReactionCollectorOptions} [options={}] Options to send to the collector
+   * @returns {ReactionCollector}
+   * @example
+   * // Create a reaction collector
+   * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId';
+   * const collector = message.createReactionCollector({ filter, time: 15_000 });
+   * collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
+   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+   */
+  createReactionCollector(options = {}) {
+    return new ReactionCollector(this, options);
+  }
+
+  /**
+   * An object containing the same properties as CollectorOptions, but a few more:
+   * @typedef {ReactionCollectorOptions} AwaitReactionsOptions
+   * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
+   */
+
+  /**
+   * Similar to createReactionCollector but in promise form.
+   * Resolves with a collection of reactions that pass the specified filter.
+   * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
+   * @returns {Promise<Collection<string | Snowflake, MessageReaction>>}
+   * @example
+   * // Create a reaction collector
+   * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'
+   * message.awaitReactions({ filter, time: 15_000 })
+   *   .then(collected => console.log(`Collected ${collected.size} reactions`))
+   *   .catch(console.error);
+   */
+  awaitReactions(options = {}) {
+    return new Promise((resolve, reject) => {
+      const collector = this.createReactionCollector(options);
+      collector.once('end', (reactions, reason) => {
+        if (options.errors?.includes(reason)) reject(reactions);
+        else resolve(reactions);
+      });
+    });
+  }
+
+  /**
+   * @typedef {CollectorOptions} MessageComponentCollectorOptions
+   * @property {ComponentType} [componentType] The type of component to listen for
+   * @property {number} [max] The maximum total amount of interactions to collect
+   * @property {number} [maxComponents] The maximum number of components to collect
+   * @property {number} [maxUsers] The maximum number of users to interact
+   */
+
+  /**
+   * Creates a message component interaction collector.
+   * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
+   * @returns {InteractionCollector}
+   * @example
+   * // Create a message component interaction collector
+   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
+   * const collector = message.createMessageComponentCollector({ filter, time: 15_000 });
+   * collector.on('collect', i => console.log(`Collected ${i.customId}`));
+   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+   */
+  createMessageComponentCollector(options = {}) {
+    return new InteractionCollector(this.client, {
+      ...options,
+      interactionType: InteractionType.MessageComponent,
+      message: this,
+    });
+  }
+
+  /**
+   * An object containing the same properties as CollectorOptions, but a few more:
+   * @typedef {Object} AwaitMessageComponentOptions
+   * @property {CollectorFilter} [filter] The filter applied to this collector
+   * @property {number} [time] Time to wait for an interaction before rejecting
+   * @property {ComponentType} [componentType] The type of component interaction to collect
+   * @property {number} [idle] Time to wait without another message component interaction before ending the collector
+   * @property {boolean} [dispose] Whether to remove the message component interaction after collecting
+   * @property {InteractionResponse} [interactionResponse] The interaction response to collect interactions from
+   */
+
+  /**
+   * Collects a single component interaction that passes the filter.
+   * The Promise will reject if the time expires.
+   * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector
+   * @returns {Promise<MessageComponentInteraction>}
+   * @example
+   * // Collect a message component interaction
+   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
+   * message.awaitMessageComponent({ filter, time: 15_000 })
+   *   .then(interaction => console.log(`${interaction.customId} was clicked!`))
+   *   .catch(console.error);
+   */
+  awaitMessageComponent(options = {}) {
+    const _options = { ...options, max: 1 };
+    return new Promise((resolve, reject) => {
+      const collector = this.createMessageComponentCollector(_options);
+      collector.once('end', (interactions, reason) => {
+        const interaction = interactions.first();
+        if (interaction) resolve(interaction);
+        else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason));
+      });
+    });
+  }
+
+  /**
+   * Whether the message is editable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get editable() {
+    const precheck = Boolean(this.author.id === this.client.user.id && (!this.guild || this.channel?.viewable));
+
+    // Regardless of permissions thread messages cannot be edited if
+    // the thread is archived or the thread is locked and the bot does not have permission to manage threads.
+    if (this.channel?.isThread()) {
+      if (this.channel.archived) return false;
+      if (this.channel.locked) {
+        const permissions = this.channel.permissionsFor(this.client.user);
+        if (!permissions?.has(PermissionFlagsBits.ManageThreads, true)) return false;
+      }
+    }
+
+    return precheck;
+  }
+
+  /**
+   * Whether the message is deletable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get deletable() {
+    if (!DeletableMessageTypes.includes(this.type)) return false;
+
+    if (!this.guild) {
+      return this.author.id === this.client.user.id;
+    }
+    // DMChannel does not have viewable property, so check viewable after proved that message is on a guild.
+    if (!this.channel?.viewable) {
+      return false;
+    }
+
+    const permissions = this.channel?.permissionsFor(this.client.user);
+    if (!permissions) return false;
+    // This flag allows deleting even if timed out
+    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;
+
+    // The auto moderation action message author is the reference message author
+    return (
+      (this.type !== MessageType.AutoModerationAction && this.author.id === this.client.user.id) ||
+      (permissions.has(PermissionFlagsBits.ManageMessages, false) && !this.guild.members.me.isCommunicationDisabled())
+    );
+  }
+
+  /**
+   * Whether the message is bulk deletable by the client user
+   * @type {boolean}
+   * @readonly
+   * @example
+   * // Filter for bulk deletable messages
+   * channel.bulkDelete(messages.filter(message => message.bulkDeletable));
+   */
+  get bulkDeletable() {
+    return (
+      (this.inGuild() &&
+        Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
+        this.deletable &&
+        this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageMessages, false)) ??
+      false
+    );
+  }
+
+  /**
+   * Whether the message is pinnable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get pinnable() {
+    const { channel } = this;
+    return Boolean(
+      !this.system &&
+        (!this.guild ||
+          (channel?.viewable &&
+            channel?.permissionsFor(this.client.user)?.has(PermissionFlagsBits.ManageMessages, false))),
+    );
+  }
+
+  /**
+   * Fetches the Message this crosspost/reply/pin-add references, if available to the client
+   * @returns {Promise<Message>}
+   */
+  async fetchReference() {
+    if (!this.reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
+    const { channelId, messageId } = this.reference;
+    const channel = this.client.channels.resolve(channelId);
+    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
+    const message = await channel.messages.fetch(messageId);
+    return message;
+  }
+
+  /**
+   * Whether the message is crosspostable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get crosspostable() {
+    const bitfield =
+      PermissionFlagsBits.SendMessages |
+      (this.author.id === this.client.user.id ? PermissionsBitField.DefaultBit : PermissionFlagsBits.ManageMessages);
+    const { channel } = this;
+    return Boolean(
+      channel?.type === ChannelType.GuildAnnouncement &&
+        !this.flags.has(MessageFlags.Crossposted) &&
+        this.type === MessageType.Default &&
+        channel.viewable &&
+        channel.permissionsFor(this.client.user)?.has(bitfield, false),
+    );
+  }
+
+  /**
+   * Edits the content of the message.
+   * @param {string|MessagePayload|MessageEditOptions} options The options to provide
+   * @returns {Promise<Message>}
+   * @example
+   * // Update the content of a message
+   * message.edit('This is my new content!')
+   *   .then(msg => console.log(`Updated the content of a message to ${msg.content}`))
+   *   .catch(console.error);
+   */
+  edit(options) {
+    if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
+    return this.channel.messages.edit(this, options);
+  }
+
+  /**
+   * Publishes a message in an announcement channel to all channels following it.
+   * @returns {Promise<Message>}
+   * @example
+   * // Crosspost a message
+   * if (message.channel.type === ChannelType.GuildAnnouncement) {
+   *   message.crosspost()
+   *     .then(() => console.log('Crossposted message'))
+   *     .catch(console.error);
+   * }
+   */
+  crosspost() {
+    if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
+    return this.channel.messages.crosspost(this.id);
+  }
+
+  /**
+   * Pins this message to the channel's pinned messages.
+   * @param {string} [reason] Reason for pinning
+   * @returns {Promise<Message>}
+   * @example
+   * // Pin a message
+   * message.pin()
+   *   .then(console.log)
+   *   .catch(console.error)
+   */
+  async pin(reason) {
+    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
+    await this.channel.messages.pin(this.id, reason);
+    return this;
+  }
+
+  /**
+   * Unpins this message from the channel's pinned messages.
+   * @param {string} [reason] Reason for unpinning
+   * @returns {Promise<Message>}
+   * @example
+   * // Unpin a message
+   * message.unpin()
+   *   .then(console.log)
+   *   .catch(console.error)
+   */
+  async unpin(reason) {
+    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
+    await this.channel.messages.unpin(this.id, reason);
+    return this;
+  }
+
+  /**
+   * Adds a reaction to the message.
+   * @param {EmojiIdentifierResolvable} emoji The emoji to react with
+   * @returns {Promise<MessageReaction>}
+   * @example
+   * // React to a message with a unicode emoji
+   * message.react('🤔')
+   *   .then(console.log)
+   *   .catch(console.error);
+   * @example
+   * // React to a message with a custom emoji
+   * message.react(message.guild.emojis.cache.get('123456789012345678'))
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async react(emoji) {
+    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
+    await this.channel.messages.react(this.id, emoji);
+
+    return this.client.actions.MessageReactionAdd.handle(
+      {
+        [this.client.actions.injectedUser]: this.client.user,
+        [this.client.actions.injectedChannel]: this.channel,
+        [this.client.actions.injectedMessage]: this,
+        emoji: resolvePartialEmoji(emoji),
+      },
+      true,
+    ).reaction;
+  }
+
+  /**
+   * Deletes the message.
+   * @returns {Promise<Message>}
+   * @example
+   * // Delete a message
+   * message.delete()
+   *   .then(msg => console.log(`Deleted message from ${msg.author.username}`))
+   *   .catch(console.error);
+   */
+  async delete() {
+    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
+    await this.channel.messages.delete(this.id);
+    return this;
+  }
+
+  /**
+   * Options provided when sending a message as an inline reply.
+   * @typedef {BaseMessageCreateOptions} MessageReplyOptions
+   * @property {boolean} [failIfNotExists=this.client.options.failIfNotExists] Whether to error if the referenced
+   * message does not exist (creates a standard message in this case when false)
+   */
+
+  /**
+   * Send an inline reply to this message.
+   * @param {string|MessagePayload|MessageReplyOptions} options The options to provide
+   * @returns {Promise<Message>}
+   * @example
+   * // Reply to a message
+   * message.reply('This is a reply!')
+   *   .then(() => console.log(`Replied to message "${message.content}"`))
+   *   .catch(console.error);
+   */
+  reply(options) {
+    if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
+    let data;
+
+    if (options instanceof MessagePayload) {
+      data = options;
+    } else {
+      data = MessagePayload.create(this, options, {
+        reply: {
+          messageReference: this,
+          failIfNotExists: options?.failIfNotExists ?? this.client.options.failIfNotExists,
+        },
+      });
+    }
+    return this.channel.send(data);
+  }
+
+  /**
+   * Options for starting a thread on a message.
+   * @typedef {Object} StartThreadOptions
+   * @property {string} name The name of the new thread
+   * @property {ThreadAutoArchiveDuration} [autoArchiveDuration=this.channel.defaultAutoArchiveDuration] The amount of
+   * time after which the thread should automatically archive in case of no recent activity
+   * @property {string} [reason] Reason for creating the thread
+   * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds
+   */
+
+  /**
+   * Create a new public thread from this message
+   * @see GuildTextThreadManager#create
+   * @param {StartThreadOptions} [options] Options for starting a thread on this message
+   * @returns {Promise<ThreadChannel>}
+   */
+  startThread(options = {}) {
+    if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
+    if (![ChannelType.GuildText, ChannelType.GuildAnnouncement].includes(this.channel.type)) {
+      return Promise.reject(new DiscordjsError(ErrorCodes.MessageThreadParent));
+    }
+    if (this.hasThread) return Promise.reject(new DiscordjsError(ErrorCodes.MessageExistingThread));
+    return this.channel.threads.create({ ...options, startMessage: this });
+  }
+
+  /**
+   * Fetch this message.
+   * @param {boolean} [force=true] Whether to skip the cache check and request the API
+   * @returns {Promise<Message>}
+   */
+  fetch(force = true) {
+    if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
+    return this.channel.messages.fetch({ message: this.id, force });
+  }
+
+  /**
+   * Fetches the webhook used to create this message.
+   * @returns {Promise<?Webhook>}
+   */
+  fetchWebhook() {
+    if (!this.webhookId) return Promise.reject(new DiscordjsError(ErrorCodes.WebhookMessage));
+    if (this.webhookId === this.applicationId) return Promise.reject(new DiscordjsError(ErrorCodes.WebhookApplication));
+    return this.client.fetchWebhook(this.webhookId);
+  }
+
+  /**
+   * Suppresses or unsuppresses embeds on a message.
+   * @param {boolean} [suppress=true] If the embeds should be suppressed or not
+   * @returns {Promise<Message>}
+   */
+  suppressEmbeds(suppress = true) {
+    const flags = new MessageFlagsBitField(this.flags.bitfield);
+
+    if (suppress) {
+      flags.add(MessageFlags.SuppressEmbeds);
+    } else {
+      flags.remove(MessageFlags.SuppressEmbeds);
+    }
+
+    return this.edit({ flags });
+  }
+
+  /**
+   * Removes the attachments from this message.
+   * @returns {Promise<Message>}
+   */
+  removeAttachments() {
+    return this.edit({ attachments: [] });
+  }
+
+  /**
+   * Resolves a component by a custom id.
+   * @param {string} customId The custom id to resolve against
+   * @returns {?MessageActionRowComponent}
+   */
+  resolveComponent(customId) {
+    return this.components.flatMap(row => row.components).find(component => component.customId === customId) ?? null;
+  }
+
+  /**
+   * Used mainly internally. Whether two messages are identical in properties. If you want to compare messages
+   * without checking all the properties, use `message.id === message2.id`, which is much more efficient. This
+   * method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties.
+   * @param {Message} message The message to compare it to
+   * @param {APIMessage} rawData Raw data passed through the WebSocket about this message
+   * @returns {boolean}
+   */
+  equals(message, rawData) {
+    if (!message) return false;
+    const embedUpdate = !message.author && !message.attachments;
+    if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
+
+    let equal =
+      this.id === message.id &&
+      this.author.id === message.author.id &&
+      this.content === message.content &&
+      this.tts === message.tts &&
+      this.nonce === message.nonce &&
+      this.embeds.length === message.embeds.length &&
+      this.attachments.length === message.attachments.length;
+
+    if (equal && rawData) {
+      equal =
+        this.mentions.everyone === message.mentions.everyone &&
+        this.createdTimestamp === Date.parse(rawData.timestamp) &&
+        this.editedTimestamp === Date.parse(rawData.edited_timestamp);
+    }
+
+    return equal;
+  }
+
+  /**
+   * Whether this message is from a guild.
+   * @returns {boolean}
+   */
+  inGuild() {
+    return Boolean(this.guildId);
+  }
+
+  /**
+   * When concatenated with a string, this automatically concatenates the message's content instead of the object.
+   * @returns {string}
+   * @example
+   * // Logs: Message: This is a message!
+   * console.log(`Message: ${message}`);
+   */
+  toString() {
+    return this.content;
+  }
+
+  toJSON() {
+    return super.toJSON({
+      channel: 'channelId',
+      author: 'authorId',
+      groupActivityApplication: 'groupActivityApplicationId',
+      guild: 'guildId',
+      cleanContent: true,
+      member: false,
+      reactions: false,
+    });
+  }
+}
+
+exports.Message = Message;
diff --git a/node_modules/discord.js/src/structures/MessageCollector.js b/node_modules/discord.js/src/structures/MessageCollector.js
new file mode 100644
index 0000000..7101965
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MessageCollector.js
@@ -0,0 +1,146 @@
+'use strict';
+
+const Collector = require('./interfaces/Collector');
+const Events = require('../util/Events');
+
+/**
+ * @typedef {CollectorOptions} MessageCollectorOptions
+ * @property {number} max The maximum amount of messages to collect
+ * @property {number} maxProcessed The maximum amount of messages to process
+ */
+
+/**
+ * Collects messages on a channel.
+ * Will automatically stop if the channel ({@link Client#event:channelDelete channelDelete}),
+ * thread ({@link Client#event:threadDelete threadDelete}), or
+ * guild ({@link Client#event:guildDelete guildDelete}) is deleted.
+ * @extends {Collector}
+ */
+class MessageCollector extends Collector {
+  /**
+   * @param {TextBasedChannels} channel The channel
+   * @param {MessageCollectorOptions} options The options to be applied to this collector
+   * @emits MessageCollector#message
+   */
+  constructor(channel, options = {}) {
+    super(channel.client, options);
+
+    /**
+     * The channel
+     * @type {TextBasedChannels}
+     */
+    this.channel = channel;
+
+    /**
+     * Total number of messages that were received in the channel during message collection
+     * @type {number}
+     */
+    this.received = 0;
+
+    const bulkDeleteListener = messages => {
+      for (const message of messages.values()) this.handleDispose(message);
+    };
+
+    this._handleChannelDeletion = this._handleChannelDeletion.bind(this);
+    this._handleThreadDeletion = this._handleThreadDeletion.bind(this);
+    this._handleGuildDeletion = this._handleGuildDeletion.bind(this);
+
+    this.client.incrementMaxListeners();
+    this.client.on(Events.MessageCreate, this.handleCollect);
+    this.client.on(Events.MessageDelete, this.handleDispose);
+    this.client.on(Events.MessageBulkDelete, bulkDeleteListener);
+    this.client.on(Events.ChannelDelete, this._handleChannelDeletion);
+    this.client.on(Events.ThreadDelete, this._handleThreadDeletion);
+    this.client.on(Events.GuildDelete, this._handleGuildDeletion);
+
+    this.once('end', () => {
+      this.client.removeListener(Events.MessageCreate, this.handleCollect);
+      this.client.removeListener(Events.MessageDelete, this.handleDispose);
+      this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener);
+      this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion);
+      this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion);
+      this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion);
+      this.client.decrementMaxListeners();
+    });
+  }
+
+  /**
+   * Handles a message for possible collection.
+   * @param {Message} message The message that could be collected
+   * @returns {?Snowflake}
+   * @private
+   */
+  collect(message) {
+    /**
+     * Emitted whenever a message is collected.
+     * @event MessageCollector#collect
+     * @param {Message} message The message that was collected
+     */
+    if (message.channelId !== this.channel.id) return null;
+    this.received++;
+    return message.id;
+  }
+
+  /**
+   * Handles a message for possible disposal.
+   * @param {Message} message The message that could be disposed of
+   * @returns {?Snowflake}
+   */
+  dispose(message) {
+    /**
+     * Emitted whenever a message is disposed of.
+     * @event MessageCollector#dispose
+     * @param {Message} message The message that was disposed of
+     */
+    return message.channelId === this.channel.id ? message.id : null;
+  }
+
+  /**
+   * The reason this collector has ended with, or null if it hasn't ended yet
+   * @type {?string}
+   * @readonly
+   */
+  get endReason() {
+    if (this.options.max && this.collected.size >= this.options.max) return 'limit';
+    if (this.options.maxProcessed && this.received === this.options.maxProcessed) return 'processedLimit';
+    return super.endReason;
+  }
+
+  /**
+   * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'.
+   * @private
+   * @param {GuildChannel} channel The channel that was deleted
+   * @returns {void}
+   */
+  _handleChannelDeletion(channel) {
+    if (channel.id === this.channel.id || channel.id === this.channel.parentId) {
+      this.stop('channelDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'.
+   * @private
+   * @param {ThreadChannel} thread The thread that was deleted
+   * @returns {void}
+   */
+  _handleThreadDeletion(thread) {
+    if (thread.id === this.channel.id) {
+      this.stop('threadDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'.
+   * @private
+   * @param {Guild} guild The guild that was deleted
+   * @returns {void}
+   */
+  _handleGuildDeletion(guild) {
+    if (guild.id === this.channel.guild?.id) {
+      this.stop('guildDelete');
+    }
+  }
+}
+
+module.exports = MessageCollector;
diff --git a/node_modules/discord.js/src/structures/MessageComponentInteraction.js b/node_modules/discord.js/src/structures/MessageComponentInteraction.js
new file mode 100644
index 0000000..47b31e0
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MessageComponentInteraction.js
@@ -0,0 +1,107 @@
+'use strict';
+
+const { lazy } = require('@discordjs/util');
+const BaseInteraction = require('./BaseInteraction');
+const InteractionWebhook = require('./InteractionWebhook');
+const InteractionResponses = require('./interfaces/InteractionResponses');
+
+const getMessage = lazy(() => require('./Message').Message);
+
+/**
+ * Represents a message component interaction.
+ * @extends {BaseInteraction}
+ * @implements {InteractionResponses}
+ */
+class MessageComponentInteraction extends BaseInteraction {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * The id of the channel this interaction was sent in
+     * @type {Snowflake}
+     * @name MessageComponentInteraction#channelId
+     */
+
+    /**
+     * The message to which the component was attached
+     * @type {Message}
+     */
+    this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(client, data.message);
+
+    /**
+     * The custom id of the component which was interacted with
+     * @type {string}
+     */
+    this.customId = data.data.custom_id;
+
+    /**
+     * The type of component which was interacted with
+     * @type {ComponentType}
+     */
+    this.componentType = data.data.component_type;
+
+    /**
+     * Whether the reply to this interaction has been deferred
+     * @type {boolean}
+     */
+    this.deferred = false;
+
+    /**
+     * Whether the reply to this interaction is ephemeral
+     * @type {?boolean}
+     */
+    this.ephemeral = null;
+
+    /**
+     * Whether this interaction has already been replied to
+     * @type {boolean}
+     */
+    this.replied = false;
+
+    /**
+     * An associated interaction webhook, can be used to further interact with this interaction
+     * @type {InteractionWebhook}
+     */
+    this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);
+  }
+
+  /**
+   * Components that can be placed in an action row for messages.
+   * * ButtonComponent
+   * * StringSelectMenuComponent
+   * * UserSelectMenuComponent
+   * * RoleSelectMenuComponent
+   * * MentionableSelectMenuComponent
+   * * ChannelSelectMenuComponent
+   * @typedef {ButtonComponent|StringSelectMenuComponent|UserSelectMenuComponent|
+   * RoleSelectMenuComponent|MentionableSelectMenuComponent|ChannelSelectMenuComponent} MessageActionRowComponent
+   */
+
+  /**
+   * The component which was interacted with
+   * @type {MessageActionRowComponent|APIMessageActionRowComponent}
+   * @readonly
+   */
+  get component() {
+    return this.message.components
+      .flatMap(row => row.components)
+      .find(component => (component.customId ?? component.custom_id) === this.customId);
+  }
+
+  // These are here only for documentation purposes - they are implemented by InteractionResponses
+  /* eslint-disable no-empty-function */
+  deferReply() {}
+  reply() {}
+  fetchReply() {}
+  editReply() {}
+  deleteReply() {}
+  followUp() {}
+  deferUpdate() {}
+  update() {}
+  showModal() {}
+  awaitModalSubmit() {}
+}
+
+InteractionResponses.applyToClass(MessageComponentInteraction);
+
+module.exports = MessageComponentInteraction;
diff --git a/node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js b/node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js
new file mode 100644
index 0000000..1100591
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const ContextMenuCommandInteraction = require('./ContextMenuCommandInteraction');
+
+/**
+ * Represents a message context menu interaction.
+ * @extends {ContextMenuCommandInteraction}
+ */
+class MessageContextMenuCommandInteraction extends ContextMenuCommandInteraction {
+  /**
+   * The message this interaction was sent from
+   * @type {Message|APIMessage}
+   * @readonly
+   */
+  get targetMessage() {
+    return this.options.getMessage('message');
+  }
+}
+
+module.exports = MessageContextMenuCommandInteraction;
diff --git a/node_modules/discord.js/src/structures/MessageMentions.js b/node_modules/discord.js/src/structures/MessageMentions.js
new file mode 100644
index 0000000..a07e77f
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MessageMentions.js
@@ -0,0 +1,297 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { FormattingPatterns } = require('discord-api-types/v10');
+const { flatten } = require('../util/Util');
+
+/**
+ * Keeps track of mentions in a {@link Message}.
+ */
+class MessageMentions {
+  /**
+   * A regular expression that matches `@everyone` and `@here`.
+   * The `mention` group property is present on the `exec` result of this expression.
+   * @type {RegExp}
+   * @memberof MessageMentions
+   */
+  static EveryonePattern = /@(?<mention>everyone|here)/;
+
+  /**
+   * A regular expression that matches user mentions like `<@81440962496172032>`.
+   * The `id` group property is present on the `exec` result of this expression.
+   * @type {RegExp}
+   * @memberof MessageMentions
+   */
+  static UsersPattern = FormattingPatterns.UserWithOptionalNickname;
+
+  /**
+   * A regular expression that matches role mentions like `<@&297577916114403338>`.
+   * The `id` group property is present on the `exec` result of this expression.
+   * @type {RegExp}
+   * @memberof MessageMentions
+   */
+  static RolesPattern = FormattingPatterns.Role;
+
+  /**
+   * A regular expression that matches channel mentions like `<#222079895583457280>`.
+   * The `id` group property is present on the `exec` result of this expression.
+   * @type {RegExp}
+   * @memberof MessageMentions
+   */
+  static ChannelsPattern = FormattingPatterns.Channel;
+
+  /**
+   * A global regular expression variant of {@link MessageMentions.ChannelsPattern}.
+   * @type {RegExp}
+   * @memberof MessageMentions
+   * @private
+   */
+  static GlobalChannelsPattern = new RegExp(this.ChannelsPattern.source, 'g');
+
+  /**
+   * A global regular expression variant of {@link MessageMentions.UsersPattern}.
+   * @type {RegExp}
+   * @memberof MessageMentions
+   * @private
+   */
+  static GlobalUsersPattern = new RegExp(this.UsersPattern.source, 'g');
+
+  constructor(message, users, roles, everyone, crosspostedChannels, repliedUser) {
+    /**
+     * The client the message is from
+     * @type {Client}
+     * @readonly
+     */
+    Object.defineProperty(this, 'client', { value: message.client });
+
+    /**
+     * The guild the message is in
+     * @type {?Guild}
+     * @readonly
+     */
+    Object.defineProperty(this, 'guild', { value: message.guild });
+
+    /**
+     * The initial message content
+     * @type {string}
+     * @readonly
+     * @private
+     */
+    Object.defineProperty(this, '_content', { value: message.content });
+
+    /**
+     * Whether `@everyone` or `@here` were mentioned
+     * @type {boolean}
+     */
+    this.everyone = Boolean(everyone);
+
+    if (users) {
+      if (users instanceof Collection) {
+        /**
+         * Any users that were mentioned
+         * <info>Order as received from the API, not as they appear in the message content</info>
+         * @type {Collection<Snowflake, User>}
+         */
+        this.users = new Collection(users);
+      } else {
+        this.users = new Collection();
+        for (const mention of users) {
+          if (mention.member && message.guild) {
+            message.guild.members._add(Object.assign(mention.member, { user: mention }));
+          }
+          const user = message.client.users._add(mention);
+          this.users.set(user.id, user);
+        }
+      }
+    } else {
+      this.users = new Collection();
+    }
+
+    if (roles instanceof Collection) {
+      /**
+       * Any roles that were mentioned
+       * <info>Order as received from the API, not as they appear in the message content</info>
+       * @type {Collection<Snowflake, Role>}
+       */
+      this.roles = new Collection(roles);
+    } else if (roles) {
+      this.roles = new Collection();
+      const guild = message.guild;
+      if (guild) {
+        for (const mention of roles) {
+          const role = guild.roles.cache.get(mention);
+          if (role) this.roles.set(role.id, role);
+        }
+      }
+    } else {
+      this.roles = new Collection();
+    }
+
+    /**
+     * Cached members for {@link MessageMentions#members}
+     * @type {?Collection<Snowflake, GuildMember>}
+     * @private
+     */
+    this._members = null;
+
+    /**
+     * Cached channels for {@link MessageMentions#channels}
+     * @type {?Collection<Snowflake, BaseChannel>}
+     * @private
+     */
+    this._channels = null;
+
+    /**
+     * Cached users for {@link MessageMentions#parsedUsers}
+     * @type {?Collection<Snowflake, User>}
+     * @private
+     */
+    this._parsedUsers = null;
+
+    /**
+     * Crossposted channel data.
+     * @typedef {Object} CrosspostedChannel
+     * @property {Snowflake} channelId The mentioned channel's id
+     * @property {Snowflake} guildId The id of the guild that has the channel
+     * @property {ChannelType} type The channel's type
+     * @property {string} name The channel's name
+     */
+
+    if (crosspostedChannels) {
+      if (crosspostedChannels instanceof Collection) {
+        /**
+         * A collection of crossposted channels
+         * <info>Order as received from the API, not as they appear in the message content</info>
+         * @type {Collection<Snowflake, CrosspostedChannel>}
+         */
+        this.crosspostedChannels = new Collection(crosspostedChannels);
+      } else {
+        this.crosspostedChannels = new Collection();
+        for (const d of crosspostedChannels) {
+          this.crosspostedChannels.set(d.id, {
+            channelId: d.id,
+            guildId: d.guild_id,
+            type: d.type,
+            name: d.name,
+          });
+        }
+      }
+    } else {
+      this.crosspostedChannels = new Collection();
+    }
+
+    /**
+     * The author of the message that this message is a reply to
+     * @type {?User}
+     */
+    this.repliedUser = repliedUser ? this.client.users._add(repliedUser) : null;
+  }
+
+  /**
+   * Any members that were mentioned (only in {@link Guild}s)
+   * <info>Order as received from the API, not as they appear in the message content</info>
+   * @type {?Collection<Snowflake, GuildMember>}
+   * @readonly
+   */
+  get members() {
+    if (this._members) return this._members;
+    if (!this.guild) return null;
+    this._members = new Collection();
+    this.users.forEach(user => {
+      const member = this.guild.members.resolve(user);
+      if (member) this._members.set(member.user.id, member);
+    });
+    return this._members;
+  }
+
+  /**
+   * Any channels that were mentioned
+   * <info>Order as they appear first in the message content</info>
+   * @type {Collection<Snowflake, BaseChannel>}
+   * @readonly
+   */
+  get channels() {
+    if (this._channels) return this._channels;
+    this._channels = new Collection();
+    let matches;
+
+    while ((matches = this.constructor.GlobalChannelsPattern.exec(this._content)) !== null) {
+      const channel = this.client.channels.cache.get(matches.groups.id);
+      if (channel) this._channels.set(channel.id, channel);
+    }
+
+    return this._channels;
+  }
+
+  /**
+   * Any user mentions that were included in the message content
+   * <info>Order as they appear first in the message content</info>
+   * @type {Collection<Snowflake, User>}
+   * @readonly
+   */
+  get parsedUsers() {
+    if (this._parsedUsers) return this._parsedUsers;
+    this._parsedUsers = new Collection();
+    let matches;
+    while ((matches = this.constructor.GlobalUsersPattern.exec(this._content)) !== null) {
+      const user = this.client.users.cache.get(matches[1]);
+      if (user) this._parsedUsers.set(user.id, user);
+    }
+    return this._parsedUsers;
+  }
+
+  /**
+   * Options used to check for a mention.
+   * @typedef {Object} MessageMentionsHasOptions
+   * @property {boolean} [ignoreDirect=false] Whether to ignore direct mentions to the item
+   * @property {boolean} [ignoreRoles=false] Whether to ignore role mentions to a guild member
+   * @property {boolean} [ignoreRepliedUser=false] Whether to ignore replied user mention to an user
+   * @property {boolean} [ignoreEveryone=false] Whether to ignore `@everyone`/`@here` mentions
+   */
+
+  /**
+   * Checks if a user, guild member, thread member, role, or channel is mentioned.
+   * Takes into account user mentions, role mentions, channel mentions,
+   * replied user mention, and `@everyone`/`@here` mentions.
+   * @param {UserResolvable|RoleResolvable|ChannelResolvable} data The User/Role/Channel to check for
+   * @param {MessageMentionsHasOptions} [options] The options for the check
+   * @returns {boolean}
+   */
+  has(data, { ignoreDirect = false, ignoreRoles = false, ignoreRepliedUser = false, ignoreEveryone = false } = {}) {
+    const user = this.client.users.resolve(data);
+
+    if (!ignoreEveryone && user && this.everyone) return true;
+
+    const userWasRepliedTo = user && this.repliedUser?.id === user.id;
+
+    if (!ignoreRepliedUser && userWasRepliedTo && this.users.has(user.id)) return true;
+
+    if (!ignoreDirect) {
+      if (user && (!ignoreRepliedUser || this.parsedUsers.has(user.id)) && this.users.has(user.id)) return true;
+
+      const role = this.guild?.roles.resolve(data);
+      if (role && this.roles.has(role.id)) return true;
+
+      const channel = this.client.channels.resolve(data);
+      if (channel && this.channels.has(channel.id)) return true;
+    }
+
+    if (!ignoreRoles) {
+      const member = this.guild?.members.resolve(data);
+      if (member) {
+        for (const mentionedRole of this.roles.values()) if (member.roles.cache.has(mentionedRole.id)) return true;
+      }
+    }
+
+    return false;
+  }
+
+  toJSON() {
+    return flatten(this, {
+      members: true,
+      channels: true,
+    });
+  }
+}
+
+module.exports = MessageMentions;
diff --git a/node_modules/discord.js/src/structures/MessagePayload.js b/node_modules/discord.js/src/structures/MessagePayload.js
new file mode 100644
index 0000000..e237309
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MessagePayload.js
@@ -0,0 +1,299 @@
+'use strict';
+
+const { Buffer } = require('node:buffer');
+const { lazy, isJSONEncodable } = require('@discordjs/util');
+const { MessageFlags } = require('discord-api-types/v10');
+const ActionRowBuilder = require('./ActionRowBuilder');
+const { DiscordjsRangeError, ErrorCodes } = require('../errors');
+const DataResolver = require('../util/DataResolver');
+const MessageFlagsBitField = require('../util/MessageFlagsBitField');
+const { basename, verifyString } = require('../util/Util');
+
+const getBaseInteraction = lazy(() => require('./BaseInteraction'));
+
+/**
+ * Represents a message to be sent to the API.
+ */
+class MessagePayload {
+  /**
+   * @param {MessageTarget} target The target for this message to be sent to
+   * @param {MessagePayloadOption} options The payload of this message
+   */
+  constructor(target, options) {
+    /**
+     * The target for this message to be sent to
+     * @type {MessageTarget}
+     */
+    this.target = target;
+
+    /**
+     * The payload of this message.
+     * @type {MessagePayloadOption}
+     */
+    this.options = options;
+
+    /**
+     * Body sendable to the API
+     * @type {?APIMessage}
+     */
+    this.body = null;
+
+    /**
+     * Files sendable to the API
+     * @type {?RawFile[]}
+     */
+    this.files = null;
+  }
+
+  /**
+   * Whether or not the target is a {@link Webhook} or a {@link WebhookClient}
+   * @type {boolean}
+   * @readonly
+   */
+  get isWebhook() {
+    const Webhook = require('./Webhook');
+    const WebhookClient = require('../client/WebhookClient');
+    return this.target instanceof Webhook || this.target instanceof WebhookClient;
+  }
+
+  /**
+   * Whether or not the target is a {@link User}
+   * @type {boolean}
+   * @readonly
+   */
+  get isUser() {
+    const User = require('./User');
+    const { GuildMember } = require('./GuildMember');
+    return this.target instanceof User || this.target instanceof GuildMember;
+  }
+
+  /**
+   * Whether or not the target is a {@link Message}
+   * @type {boolean}
+   * @readonly
+   */
+  get isMessage() {
+    const { Message } = require('./Message');
+    return this.target instanceof Message;
+  }
+
+  /**
+   * Whether or not the target is a {@link MessageManager}
+   * @type {boolean}
+   * @readonly
+   */
+  get isMessageManager() {
+    const MessageManager = require('../managers/MessageManager');
+    return this.target instanceof MessageManager;
+  }
+
+  /**
+   * Whether or not the target is an {@link BaseInteraction} or an {@link InteractionWebhook}
+   * @type {boolean}
+   * @readonly
+   */
+  get isInteraction() {
+    const BaseInteraction = getBaseInteraction();
+    const InteractionWebhook = require('./InteractionWebhook');
+    return this.target instanceof BaseInteraction || this.target instanceof InteractionWebhook;
+  }
+
+  /**
+   * Makes the content of this message.
+   * @returns {?string}
+   */
+  makeContent() {
+    let content;
+    if (this.options.content === null) {
+      content = '';
+    } else if (this.options.content !== undefined) {
+      content = verifyString(this.options.content, DiscordjsRangeError, ErrorCodes.MessageContentType, true);
+    }
+
+    return content;
+  }
+
+  /**
+   * Resolves the body.
+   * @returns {MessagePayload}
+   */
+  resolveBody() {
+    if (this.body) return this;
+    const isInteraction = this.isInteraction;
+    const isWebhook = this.isWebhook;
+
+    const content = this.makeContent();
+    const tts = Boolean(this.options.tts);
+
+    let nonce;
+    if (this.options.nonce !== undefined) {
+      nonce = this.options.nonce;
+      if (typeof nonce === 'number' ? !Number.isInteger(nonce) : typeof nonce !== 'string') {
+        throw new DiscordjsRangeError(ErrorCodes.MessageNonceType);
+      }
+    }
+
+    const components = this.options.components?.map(c => (isJSONEncodable(c) ? c : new ActionRowBuilder(c)).toJSON());
+
+    let username;
+    let avatarURL;
+    let threadName;
+    if (isWebhook) {
+      username = this.options.username ?? this.target.name;
+      if (this.options.avatarURL) avatarURL = this.options.avatarURL;
+      if (this.options.threadName) threadName = this.options.threadName;
+    }
+
+    let flags;
+    if (
+      this.options.flags !== undefined ||
+      (this.isMessage && this.options.reply === undefined) ||
+      this.isMessageManager
+    ) {
+      flags =
+        // eslint-disable-next-line eqeqeq
+        this.options.flags != null
+          ? new MessageFlagsBitField(this.options.flags).bitfield
+          : this.target.flags?.bitfield;
+    }
+
+    if (isInteraction && this.options.ephemeral) {
+      flags |= MessageFlags.Ephemeral;
+    }
+
+    let allowedMentions =
+      this.options.allowedMentions === undefined
+        ? this.target.client.options.allowedMentions
+        : this.options.allowedMentions;
+
+    if (allowedMentions?.repliedUser !== undefined) {
+      allowedMentions = { ...allowedMentions, replied_user: allowedMentions.repliedUser };
+      delete allowedMentions.repliedUser;
+    }
+
+    let message_reference;
+    if (typeof this.options.reply === 'object') {
+      const reference = this.options.reply.messageReference;
+      const message_id = this.isMessage ? reference.id ?? reference : this.target.messages.resolveId(reference);
+      if (message_id) {
+        message_reference = {
+          message_id,
+          fail_if_not_exists: this.options.reply.failIfNotExists ?? this.target.client.options.failIfNotExists,
+        };
+      }
+    }
+
+    const attachments = this.options.files?.map((file, index) => ({
+      id: index.toString(),
+      description: file.description,
+    }));
+    if (Array.isArray(this.options.attachments)) {
+      this.options.attachments.push(...(attachments ?? []));
+    } else {
+      this.options.attachments = attachments;
+    }
+
+    this.body = {
+      content,
+      tts,
+      nonce,
+      embeds: this.options.embeds?.map(embed =>
+        isJSONEncodable(embed) ? embed.toJSON() : this.target.client.options.jsonTransformer(embed),
+      ),
+      components,
+      username,
+      avatar_url: avatarURL,
+      allowed_mentions: content === undefined && message_reference === undefined ? undefined : allowedMentions,
+      flags,
+      message_reference,
+      attachments: this.options.attachments,
+      sticker_ids: this.options.stickers?.map(sticker => sticker.id ?? sticker),
+      thread_name: threadName,
+    };
+    return this;
+  }
+
+  /**
+   * Resolves files.
+   * @returns {Promise<MessagePayload>}
+   */
+  async resolveFiles() {
+    if (this.files) return this;
+
+    this.files = await Promise.all(this.options.files?.map(file => this.constructor.resolveFile(file)) ?? []);
+    return this;
+  }
+
+  /**
+   * Resolves a single file into an object sendable to the API.
+   * @param {AttachmentPayload|BufferResolvable|Stream} fileLike Something that could be resolved to a file
+   * @returns {Promise<RawFile>}
+   */
+  static async resolveFile(fileLike) {
+    let attachment;
+    let name;
+
+    const findName = thing => {
+      if (typeof thing === 'string') {
+        return basename(thing);
+      }
+
+      if (thing.path) {
+        return basename(thing.path);
+      }
+
+      return 'file.jpg';
+    };
+
+    const ownAttachment =
+      typeof fileLike === 'string' || fileLike instanceof Buffer || typeof fileLike.pipe === 'function';
+    if (ownAttachment) {
+      attachment = fileLike;
+      name = findName(attachment);
+    } else {
+      attachment = fileLike.attachment;
+      name = fileLike.name ?? findName(attachment);
+    }
+
+    const { data, contentType } = await DataResolver.resolveFile(attachment);
+    return { data, name, contentType };
+  }
+
+  /**
+   * Creates a {@link MessagePayload} from user-level arguments.
+   * @param {MessageTarget} target Target to send to
+   * @param {string|MessagePayloadOption} options Options or content to use
+   * @param {MessagePayloadOption} [extra={}] Extra options to add onto specified options
+   * @returns {MessagePayload}
+   */
+  static create(target, options, extra = {}) {
+    return new this(
+      target,
+      typeof options !== 'object' || options === null ? { content: options, ...extra } : { ...options, ...extra },
+    );
+  }
+}
+
+module.exports = MessagePayload;
+
+/**
+ * A target for a message.
+ * @typedef {TextBasedChannels|User|GuildMember|Webhook|WebhookClient|BaseInteraction|InteractionWebhook|
+ * Message|MessageManager} MessageTarget
+ */
+
+/**
+ * A possible payload option.
+ * @typedef {MessageCreateOptions|MessageEditOptions|WebhookMessageCreateOptions|WebhookMessageEditOptions|
+ * InteractionReplyOptions|InteractionUpdateOptions} MessagePayloadOption
+ */
+
+/**
+ * @external APIMessage
+ * @see {@link https://discord.com/developers/docs/resources/channel#message-object}
+ */
+
+/**
+ * @external RawFile
+ * @see {@link https://discord.js.org/docs/packages/rest/stable/RawFile:Interface}
+ */
diff --git a/node_modules/discord.js/src/structures/MessageReaction.js b/node_modules/discord.js/src/structures/MessageReaction.js
new file mode 100644
index 0000000..43f05e3
--- /dev/null
+++ b/node_modules/discord.js/src/structures/MessageReaction.js
@@ -0,0 +1,142 @@
+'use strict';
+
+const { Routes } = require('discord-api-types/v10');
+const GuildEmoji = require('./GuildEmoji');
+const ReactionEmoji = require('./ReactionEmoji');
+const ReactionUserManager = require('../managers/ReactionUserManager');
+const { flatten } = require('../util/Util');
+
+/**
+ * Represents a reaction to a message.
+ */
+class MessageReaction {
+  constructor(client, data, message) {
+    /**
+     * The client that instantiated this message reaction
+     * @name MessageReaction#client
+     * @type {Client}
+     * @readonly
+     */
+    Object.defineProperty(this, 'client', { value: client });
+
+    /**
+     * The message that this reaction refers to
+     * @type {Message}
+     */
+    this.message = message;
+
+    /**
+     * Whether the client has given this reaction
+     * @type {boolean}
+     */
+    this.me = data.me;
+
+    /**
+     * A manager of the users that have given this reaction
+     * @type {ReactionUserManager}
+     */
+    this.users = new ReactionUserManager(this, this.me ? [client.user] : []);
+
+    this._emoji = new ReactionEmoji(this, data.emoji);
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('count' in data) {
+      /**
+       * The number of people that have given the same reaction
+       * @type {?number}
+       */
+      this.count ??= data.count;
+    }
+  }
+
+  /**
+   * Makes the client user react with this reaction
+   * @returns {Promise<MessageReaction>}
+   */
+  react() {
+    return this.message.react(this.emoji);
+  }
+
+  /**
+   * Removes all users from this reaction.
+   * @returns {Promise<MessageReaction>}
+   */
+  async remove() {
+    await this.client.rest.delete(
+      Routes.channelMessageReaction(this.message.channelId, this.message.id, this._emoji.identifier),
+    );
+    return this;
+  }
+
+  /**
+   * The emoji of this reaction. Either a {@link GuildEmoji} object for known custom emojis, or a {@link ReactionEmoji}
+   * object which has fewer properties. Whatever the prototype of the emoji, it will still have
+   * `name`, `id`, `identifier` and `toString()`
+   * @type {GuildEmoji|ReactionEmoji}
+   * @readonly
+   */
+  get emoji() {
+    if (this._emoji instanceof GuildEmoji) return this._emoji;
+    // Check to see if the emoji has become known to the client
+    if (this._emoji.id) {
+      const emojis = this.message.client.emojis.cache;
+      if (emojis.has(this._emoji.id)) {
+        const emoji = emojis.get(this._emoji.id);
+        this._emoji = emoji;
+        return emoji;
+      }
+    }
+    return this._emoji;
+  }
+
+  /**
+   * Whether or not this reaction is a partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return this.count === null;
+  }
+
+  /**
+   * Fetch this reaction.
+   * @returns {Promise<MessageReaction>}
+   */
+  async fetch() {
+    const message = await this.message.fetch();
+    const existing = message.reactions.cache.get(this.emoji.id ?? this.emoji.name);
+    // The reaction won't get set when it has been completely removed
+    this._patch(existing ?? { count: 0 });
+    return this;
+  }
+
+  toJSON() {
+    return flatten(this, { emoji: 'emojiId', message: 'messageId' });
+  }
+
+  valueOf() {
+    return this._emoji.id ?? this._emoji.name;
+  }
+
+  _add(user) {
+    if (this.partial) return;
+    this.users.cache.set(user.id, user);
+    if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++;
+    this.me ||= user.id === this.message.client.user.id;
+  }
+
+  _remove(user) {
+    if (this.partial) return;
+    this.users.cache.delete(user.id);
+    if (!this.me || user.id !== this.message.client.user.id) this.count--;
+    if (user.id === this.message.client.user.id) this.me = false;
+    if (this.count <= 0 && this.users.cache.size === 0) {
+      this.message.reactions.cache.delete(this.emoji.id ?? this.emoji.name);
+    }
+  }
+}
+
+module.exports = MessageReaction;
diff --git a/node_modules/discord.js/src/structures/ModalBuilder.js b/node_modules/discord.js/src/structures/ModalBuilder.js
new file mode 100644
index 0000000..535b4a5
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ModalBuilder.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const { ModalBuilder: BuildersModal, ComponentBuilder } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+
+/**
+ * Represents a modal builder.
+ * @extends {BuildersModal}
+ */
+class ModalBuilder extends BuildersModal {
+  constructor({ components, ...data } = {}) {
+    super({
+      ...toSnakeCase(data),
+      components: components?.map(c => (c instanceof ComponentBuilder ? c : toSnakeCase(c))),
+    });
+  }
+
+  /**
+   * Creates a new modal builder from JSON data
+   * @param {ModalBuilder|APIModalComponent} other The other data
+   * @returns {ModalBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = ModalBuilder;
+
+/**
+ * @external BuildersModal
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/ModalBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/ModalSubmitFields.js b/node_modules/discord.js/src/structures/ModalSubmitFields.js
new file mode 100644
index 0000000..8e67b21
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ModalSubmitFields.js
@@ -0,0 +1,55 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { ComponentType } = require('discord-api-types/v10');
+const { DiscordjsTypeError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents the serialized fields from a modal submit interaction
+ */
+class ModalSubmitFields {
+  constructor(components) {
+    /**
+     * The components within the modal
+     * @type {ActionRowModalData[]}
+     */
+    this.components = components;
+
+    /**
+     * The extracted fields from the modal
+     * @type {Collection<string, ModalData>}
+     */
+    this.fields = components.reduce((accumulator, next) => {
+      next.components.forEach(c => accumulator.set(c.customId, c));
+      return accumulator;
+    }, new Collection());
+  }
+
+  /**
+   * Gets a field given a custom id from a component
+   * @param {string} customId The custom id of the component
+   * @param {ComponentType} [type] The type of the component
+   * @returns {ModalData}
+   */
+  getField(customId, type) {
+    const field = this.fields.get(customId);
+    if (!field) throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldNotFound, customId);
+
+    if (type !== undefined && type !== field.type) {
+      throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldType, customId, field.type, type);
+    }
+
+    return field;
+  }
+
+  /**
+   * Gets the value of a text input component given a custom id
+   * @param {string} customId The custom id of the text input component
+   * @returns {string}
+   */
+  getTextInputValue(customId) {
+    return this.getField(customId, ComponentType.TextInput).value;
+  }
+}
+
+module.exports = ModalSubmitFields;
diff --git a/node_modules/discord.js/src/structures/ModalSubmitInteraction.js b/node_modules/discord.js/src/structures/ModalSubmitInteraction.js
new file mode 100644
index 0000000..8f0ccf1
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ModalSubmitInteraction.js
@@ -0,0 +1,122 @@
+'use strict';
+
+const { lazy } = require('@discordjs/util');
+const BaseInteraction = require('./BaseInteraction');
+const InteractionWebhook = require('./InteractionWebhook');
+const ModalSubmitFields = require('./ModalSubmitFields');
+const InteractionResponses = require('./interfaces/InteractionResponses');
+
+const getMessage = lazy(() => require('./Message').Message);
+
+/**
+ * @typedef {Object} ModalData
+ * @property {string} value The value of the field
+ * @property {ComponentType} type The component type of the field
+ * @property {string} customId The custom id of the field
+ */
+
+/**
+ * @typedef {Object} ActionRowModalData
+ * @property {ModalData[]} components The components of this action row
+ * @property {ComponentType} type The component type of the action row
+ */
+
+/**
+ * Represents a modal interaction
+ * @extends {BaseInteraction}
+ * @implements {InteractionResponses}
+ */
+class ModalSubmitInteraction extends BaseInteraction {
+  constructor(client, data) {
+    super(client, data);
+    /**
+     * The custom id of the modal.
+     * @type {string}
+     */
+    this.customId = data.data.custom_id;
+
+    if ('message' in data) {
+      /**
+       * The message associated with this interaction
+       * @type {?Message}
+       */
+      this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(this.client, data.message);
+    } else {
+      this.message = null;
+    }
+
+    /**
+     * The components within the modal
+     * @type {ActionRowModalData[]}
+     */
+    this.components = data.data.components?.map(c => ModalSubmitInteraction.transformComponent(c));
+
+    /**
+     * The fields within the modal
+     * @type {ModalSubmitFields}
+     */
+    this.fields = new ModalSubmitFields(this.components);
+
+    /**
+     * Whether the reply to this interaction has been deferred
+     * @type {boolean}
+     */
+    this.deferred = false;
+
+    /**
+     * Whether this interaction has already been replied to
+     * @type {boolean}
+     */
+    this.replied = false;
+
+    /**
+     * Whether the reply to this interaction is ephemeral
+     * @type {?boolean}
+     */
+    this.ephemeral = null;
+
+    /**
+     * An associated interaction webhook, can be used to further interact with this interaction
+     * @type {InteractionWebhook}
+     */
+    this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);
+  }
+
+  /**
+   * Transforms component data to discord.js-compatible data
+   * @param {*} rawComponent The data to transform
+   * @returns {ModalData[]}
+   */
+  static transformComponent(rawComponent) {
+    return rawComponent.components
+      ? { type: rawComponent.type, components: rawComponent.components.map(c => this.transformComponent(c)) }
+      : {
+          value: rawComponent.value,
+          type: rawComponent.type,
+          customId: rawComponent.custom_id,
+        };
+  }
+
+  /**
+   * Whether this is from a {@link MessageComponentInteraction}.
+   * @returns {boolean}
+   */
+  isFromMessage() {
+    return Boolean(this.message);
+  }
+
+  // These are here only for documentation purposes - they are implemented by InteractionResponses
+  /* eslint-disable no-empty-function */
+  deferReply() {}
+  reply() {}
+  fetchReply() {}
+  editReply() {}
+  deleteReply() {}
+  followUp() {}
+  deferUpdate() {}
+  update() {}
+}
+
+InteractionResponses.applyToClass(ModalSubmitInteraction, 'showModal');
+
+module.exports = ModalSubmitInteraction;
diff --git a/node_modules/discord.js/src/structures/NewsChannel.js b/node_modules/discord.js/src/structures/NewsChannel.js
new file mode 100644
index 0000000..3f5aff3
--- /dev/null
+++ b/node_modules/discord.js/src/structures/NewsChannel.js
@@ -0,0 +1,32 @@
+'use strict';
+
+const { Routes } = require('discord-api-types/v10');
+const BaseGuildTextChannel = require('./BaseGuildTextChannel');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents a guild news channel on Discord.
+ * @extends {BaseGuildTextChannel}
+ */
+class NewsChannel extends BaseGuildTextChannel {
+  /**
+   * Adds the target to this channel's followers.
+   * @param {TextChannelResolvable} channel The channel where the webhook should be created
+   * @param {string} [reason] Reason for creating the webhook
+   * @returns {Promise<NewsChannel>}
+   * @example
+   * if (channel.type === ChannelType.GuildAnnouncement) {
+   *   channel.addFollower('222197033908436994', 'Important announcements')
+   *     .then(() => console.log('Added follower'))
+   *     .catch(console.error);
+   * }
+   */
+  async addFollower(channel, reason) {
+    const channelId = this.guild.channels.resolveId(channel);
+    if (!channelId) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
+    await this.client.rest.post(Routes.channelFollowers(this.id), { body: { webhook_channel_id: channelId }, reason });
+    return this;
+  }
+}
+
+module.exports = NewsChannel;
diff --git a/node_modules/discord.js/src/structures/OAuth2Guild.js b/node_modules/discord.js/src/structures/OAuth2Guild.js
new file mode 100644
index 0000000..d5104ac
--- /dev/null
+++ b/node_modules/discord.js/src/structures/OAuth2Guild.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const BaseGuild = require('./BaseGuild');
+const PermissionsBitField = require('../util/PermissionsBitField');
+
+/**
+ * A partial guild received when using {@link GuildManager#fetch} to fetch multiple guilds.
+ * @extends {BaseGuild}
+ */
+class OAuth2Guild extends BaseGuild {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * Whether the client user is the owner of the guild
+     * @type {boolean}
+     */
+    this.owner = data.owner;
+
+    /**
+     * The permissions that the client user has in this guild
+     * @type {Readonly<PermissionsBitField>}
+     */
+    this.permissions = new PermissionsBitField(BigInt(data.permissions)).freeze();
+  }
+}
+
+module.exports = OAuth2Guild;
diff --git a/node_modules/discord.js/src/structures/PartialGroupDMChannel.js b/node_modules/discord.js/src/structures/PartialGroupDMChannel.js
new file mode 100644
index 0000000..ecbb878
--- /dev/null
+++ b/node_modules/discord.js/src/structures/PartialGroupDMChannel.js
@@ -0,0 +1,60 @@
+'use strict';
+
+const { BaseChannel } = require('./BaseChannel');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents a Partial Group DM Channel on Discord.
+ * @extends {BaseChannel}
+ */
+class PartialGroupDMChannel extends BaseChannel {
+  constructor(client, data) {
+    super(client, data);
+
+    // No flags are present when fetching partial group DM channels.
+    this.flags = null;
+
+    /**
+     * The name of this Group DM Channel
+     * @type {?string}
+     */
+    this.name = data.name;
+
+    /**
+     * The hash of the channel icon
+     * @type {?string}
+     */
+    this.icon = data.icon;
+
+    /**
+     * Recipient data received in a {@link PartialGroupDMChannel}.
+     * @typedef {Object} PartialRecipient
+     * @property {string} username The username of the recipient
+     */
+
+    /**
+     * The recipients of this Group DM Channel.
+     * @type {PartialRecipient[]}
+     */
+    this.recipients = data.recipients;
+  }
+
+  /**
+   * The URL to this channel's icon.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  iconURL(options = {}) {
+    return this.icon && this.client.rest.cdn.channelIcon(this.id, this.icon, options);
+  }
+
+  delete() {
+    return Promise.reject(new DiscordjsError(ErrorCodes.DeleteGroupDMChannel));
+  }
+
+  fetch() {
+    return Promise.reject(new DiscordjsError(ErrorCodes.FetchGroupDMChannel));
+  }
+}
+
+module.exports = PartialGroupDMChannel;
diff --git a/node_modules/discord.js/src/structures/PermissionOverwrites.js b/node_modules/discord.js/src/structures/PermissionOverwrites.js
new file mode 100644
index 0000000..2cdc827
--- /dev/null
+++ b/node_modules/discord.js/src/structures/PermissionOverwrites.js
@@ -0,0 +1,196 @@
+'use strict';
+
+const { OverwriteType } = require('discord-api-types/v10');
+const Base = require('./Base');
+const { Role } = require('./Role');
+const { DiscordjsTypeError, ErrorCodes } = require('../errors');
+const PermissionsBitField = require('../util/PermissionsBitField');
+
+/**
+ * Represents a permission overwrite for a role or member in a guild channel.
+ * @extends {Base}
+ */
+class PermissionOverwrites extends Base {
+  constructor(client, data, channel) {
+    super(client);
+
+    /**
+     * The GuildChannel this overwrite is for
+     * @name PermissionOverwrites#channel
+     * @type {GuildChannel}
+     * @readonly
+     */
+    Object.defineProperty(this, 'channel', { value: channel });
+
+    if (data) this._patch(data);
+  }
+
+  _patch(data) {
+    /**
+     * The overwrite's id, either a {@link User} or a {@link Role} id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    if ('type' in data) {
+      /**
+       * The type of this overwrite
+       * @type {OverwriteType}
+       */
+      this.type = data.type;
+    }
+
+    if ('deny' in data) {
+      /**
+       * The permissions that are denied for the user or role.
+       * @type {Readonly<PermissionsBitField>}
+       */
+      this.deny = new PermissionsBitField(BigInt(data.deny)).freeze();
+    }
+
+    if ('allow' in data) {
+      /**
+       * The permissions that are allowed for the user or role.
+       * @type {Readonly<PermissionsBitField>}
+       */
+      this.allow = new PermissionsBitField(BigInt(data.allow)).freeze();
+    }
+  }
+
+  /**
+   * Edits this Permission Overwrite.
+   * @param {PermissionOverwriteOptions} options The options for the update
+   * @param {string} [reason] Reason for creating/editing this overwrite
+   * @returns {Promise<PermissionOverwrites>}
+   * @example
+   * // Update permission overwrites
+   * permissionOverwrites.edit({
+   *   SendMessages: false
+   * })
+   *   .then(channel => console.log(channel.permissionOverwrites.get(message.author.id)))
+   *   .catch(console.error);
+   */
+  async edit(options, reason) {
+    await this.channel.permissionOverwrites.upsert(this.id, options, { type: this.type, reason }, this);
+    return this;
+  }
+
+  /**
+   * Deletes this Permission Overwrite.
+   * @param {string} [reason] Reason for deleting this overwrite
+   * @returns {Promise<PermissionOverwrites>}
+   */
+  async delete(reason) {
+    await this.channel.permissionOverwrites.delete(this.id, reason);
+    return this;
+  }
+
+  toJSON() {
+    return {
+      id: this.id,
+      type: this.type,
+      allow: this.allow,
+      deny: this.deny,
+    };
+  }
+
+  /**
+   * An object mapping permission flags to `true` (enabled), `null` (unset) or `false` (disabled).
+   * ```js
+   * {
+   *  'SendMessages': true,
+   *  'EmbedLinks': null,
+   *  'AttachFiles': false,
+   * }
+   * ```
+   * @typedef {Object} PermissionOverwriteOptions
+   */
+
+  /**
+   * @typedef {Object} ResolvedOverwriteOptions
+   * @property {PermissionsBitField} allow The allowed permissions
+   * @property {PermissionsBitField} deny The denied permissions
+   */
+
+  /**
+   * Resolves bitfield permissions overwrites from an object.
+   * @param {PermissionOverwriteOptions} options The options for the update
+   * @param {ResolvedOverwriteOptions} initialPermissions The initial permissions
+   * @returns {ResolvedOverwriteOptions}
+   */
+  static resolveOverwriteOptions(options, { allow, deny } = {}) {
+    allow = new PermissionsBitField(allow);
+    deny = new PermissionsBitField(deny);
+
+    for (const [perm, value] of Object.entries(options)) {
+      if (value === true) {
+        allow.add(perm);
+        deny.remove(perm);
+      } else if (value === false) {
+        allow.remove(perm);
+        deny.add(perm);
+      } else if (value === null) {
+        allow.remove(perm);
+        deny.remove(perm);
+      }
+    }
+
+    return { allow, deny };
+  }
+
+  /**
+   * The raw data for a permission overwrite
+   * @typedef {Object} RawOverwriteData
+   * @property {Snowflake} id The id of the {@link Role} or {@link User} this overwrite belongs to
+   * @property {string} allow The permissions to allow
+   * @property {string} deny The permissions to deny
+   * @property {number} type The type of this OverwriteData
+   */
+
+  /**
+   * Data that can be resolved into {@link RawOverwriteData}. This can be:
+   * * PermissionOverwrites
+   * * OverwriteData
+   * @typedef {PermissionOverwrites|OverwriteData} OverwriteResolvable
+   */
+
+  /**
+   * Data that can be used for a permission overwrite
+   * @typedef {Object} OverwriteData
+   * @property {GuildMemberResolvable|RoleResolvable} id Member or role this overwrite is for
+   * @property {PermissionResolvable} [allow] The permissions to allow
+   * @property {PermissionResolvable} [deny] The permissions to deny
+   * @property {OverwriteType} [type] The type of this OverwriteData
+   */
+
+  /**
+   * Resolves an overwrite into {@link RawOverwriteData}.
+   * @param {OverwriteResolvable} overwrite The overwrite-like data to resolve
+   * @param {Guild} [guild] The guild to resolve from
+   * @returns {RawOverwriteData}
+   */
+  static resolve(overwrite, guild) {
+    if (overwrite instanceof this) return overwrite.toJSON();
+    if (typeof overwrite.id === 'string' && overwrite.type in OverwriteType) {
+      return {
+        id: overwrite.id,
+        type: overwrite.type,
+        allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(),
+        deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(),
+      };
+    }
+
+    const userOrRole = guild.roles.resolve(overwrite.id) ?? guild.client.users.resolve(overwrite.id);
+    if (!userOrRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role');
+    const type = userOrRole instanceof Role ? OverwriteType.Role : OverwriteType.Member;
+
+    return {
+      id: userOrRole.id,
+      type,
+      allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(),
+      deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(),
+    };
+  }
+}
+
+module.exports = PermissionOverwrites;
diff --git a/node_modules/discord.js/src/structures/Presence.js b/node_modules/discord.js/src/structures/Presence.js
new file mode 100644
index 0000000..79ecb29
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Presence.js
@@ -0,0 +1,378 @@
+'use strict';
+
+const Base = require('./Base');
+const { Emoji } = require('./Emoji');
+const ActivityFlagsBitField = require('../util/ActivityFlagsBitField');
+const { flatten } = require('../util/Util');
+
+/**
+ * Activity sent in a message.
+ * @typedef {Object} MessageActivity
+ * @property {string} [partyId] Id of the party represented in activity
+ * @property {MessageActivityType} type Type of activity sent
+ */
+
+/**
+ * The status of this presence:
+ * * **`online`** - user is online
+ * * **`idle`** - user is AFK
+ * * **`offline`** - user is offline or invisible
+ * * **`dnd`** - user is in Do Not Disturb
+ * @typedef {string} PresenceStatus
+ */
+
+/**
+ * The status of this presence:
+ * * **`online`** - user is online
+ * * **`idle`** - user is AFK
+ * * **`dnd`** - user is in Do Not Disturb
+ * @typedef {string} ClientPresenceStatus
+ */
+
+/**
+ * Represents a user's presence.
+ * @extends {Base}
+ */
+class Presence extends Base {
+  constructor(client, data = {}) {
+    super(client);
+
+    /**
+     * The presence's user id
+     * @type {Snowflake}
+     */
+    this.userId = data.user.id;
+
+    /**
+     * The guild this presence is in
+     * @type {?Guild}
+     */
+    this.guild = data.guild ?? null;
+
+    this._patch(data);
+  }
+
+  /**
+   * The user of this presence
+   * @type {?User}
+   * @readonly
+   */
+  get user() {
+    return this.client.users.resolve(this.userId);
+  }
+
+  /**
+   * The member of this presence
+   * @type {?GuildMember}
+   * @readonly
+   */
+  get member() {
+    return this.guild.members.resolve(this.userId);
+  }
+
+  _patch(data) {
+    if ('status' in data) {
+      /**
+       * The status of this presence
+       * @type {PresenceStatus}
+       */
+      this.status = data.status;
+    } else {
+      this.status ??= 'offline';
+    }
+
+    if ('activities' in data) {
+      /**
+       * The activities of this presence
+       * @type {Activity[]}
+       */
+      this.activities = data.activities.map(activity => new Activity(this, activity));
+    } else {
+      this.activities ??= [];
+    }
+
+    if ('client_status' in data) {
+      /**
+       * The devices this presence is on
+       * @type {?Object}
+       * @property {?ClientPresenceStatus} web The current presence in the web application
+       * @property {?ClientPresenceStatus} mobile The current presence in the mobile application
+       * @property {?ClientPresenceStatus} desktop The current presence in the desktop application
+       */
+      this.clientStatus = data.client_status;
+    } else {
+      this.clientStatus ??= null;
+    }
+
+    return this;
+  }
+
+  _clone() {
+    const clone = Object.assign(Object.create(this), this);
+    clone.activities = this.activities.map(activity => activity._clone());
+    return clone;
+  }
+
+  /**
+   * Whether this presence is equal to another.
+   * @param {Presence} presence The presence to compare with
+   * @returns {boolean}
+   */
+  equals(presence) {
+    return (
+      this === presence ||
+      (presence &&
+        this.status === presence.status &&
+        this.activities.length === presence.activities.length &&
+        this.activities.every((activity, index) => activity.equals(presence.activities[index])) &&
+        this.clientStatus?.web === presence.clientStatus?.web &&
+        this.clientStatus?.mobile === presence.clientStatus?.mobile &&
+        this.clientStatus?.desktop === presence.clientStatus?.desktop)
+    );
+  }
+
+  toJSON() {
+    return flatten(this);
+  }
+}
+
+/**
+ * Represents an activity that is part of a user's presence.
+ */
+class Activity {
+  constructor(presence, data) {
+    /**
+     * The presence of the Activity
+     * @type {Presence}
+     * @readonly
+     * @name Activity#presence
+     */
+    Object.defineProperty(this, 'presence', { value: presence });
+
+    /**
+     * The activity's name
+     * @type {string}
+     */
+    this.name = data.name;
+
+    /**
+     * The activity status's type
+     * @type {ActivityType}
+     */
+    this.type = data.type;
+
+    /**
+     * If the activity is being streamed, a link to the stream
+     * @type {?string}
+     */
+    this.url = data.url ?? null;
+
+    /**
+     * Details about the activity
+     * @type {?string}
+     */
+    this.details = data.details ?? null;
+
+    /**
+     * State of the activity
+     * @type {?string}
+     */
+    this.state = data.state ?? null;
+
+    /**
+     * The id of the application associated with this activity
+     * @type {?Snowflake}
+     */
+    this.applicationId = data.application_id ?? null;
+
+    /**
+     * Represents timestamps of an activity
+     * @typedef {Object} ActivityTimestamps
+     * @property {?Date} start When the activity started
+     * @property {?Date} end When the activity will end
+     */
+
+    /**
+     * Timestamps for the activity
+     * @type {?ActivityTimestamps}
+     */
+    this.timestamps = data.timestamps
+      ? {
+          start: data.timestamps.start ? new Date(Number(data.timestamps.start)) : null,
+          end: data.timestamps.end ? new Date(Number(data.timestamps.end)) : null,
+        }
+      : null;
+
+    /**
+     * Represents a party of an activity
+     * @typedef {Object} ActivityParty
+     * @property {?string} id The party's id
+     * @property {number[]} size Size of the party as `[current, max]`
+     */
+
+    /**
+     * Party of the activity
+     * @type {?ActivityParty}
+     */
+    this.party = data.party ?? null;
+
+    /**
+     * Assets for rich presence
+     * @type {?RichPresenceAssets}
+     */
+    this.assets = data.assets ? new RichPresenceAssets(this, data.assets) : null;
+
+    /**
+     * Flags that describe the activity
+     * @type {Readonly<ActivityFlagsBitField>}
+     */
+    this.flags = new ActivityFlagsBitField(data.flags).freeze();
+
+    /**
+     * Emoji for a custom activity
+     * @type {?Emoji}
+     */
+    this.emoji = data.emoji ? new Emoji(presence.client, data.emoji) : null;
+
+    /**
+     * The labels of the buttons of this rich presence
+     * @type {string[]}
+     */
+    this.buttons = data.buttons ?? [];
+
+    /**
+     * Creation date of the activity
+     * @type {number}
+     */
+    this.createdTimestamp = data.created_at;
+  }
+
+  /**
+   * Whether this activity is equal to another activity.
+   * @param {Activity} activity The activity to compare with
+   * @returns {boolean}
+   */
+  equals(activity) {
+    return (
+      this === activity ||
+      (activity &&
+        this.name === activity.name &&
+        this.type === activity.type &&
+        this.url === activity.url &&
+        this.state === activity.state &&
+        this.details === activity.details &&
+        this.emoji?.id === activity.emoji?.id &&
+        this.emoji?.name === activity.emoji?.name)
+    );
+  }
+
+  /**
+   * The time the activity was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the activity's name instead of the Activity object.
+   * @returns {string}
+   */
+  toString() {
+    return this.name;
+  }
+
+  _clone() {
+    return Object.assign(Object.create(this), this);
+  }
+}
+
+/**
+ * Assets for a rich presence
+ */
+class RichPresenceAssets {
+  constructor(activity, assets) {
+    /**
+     * The activity of the RichPresenceAssets
+     * @type {Activity}
+     * @readonly
+     * @name RichPresenceAssets#activity
+     */
+    Object.defineProperty(this, 'activity', { value: activity });
+
+    /**
+     * Hover text for the large image
+     * @type {?string}
+     */
+    this.largeText = assets.large_text ?? null;
+
+    /**
+     * Hover text for the small image
+     * @type {?string}
+     */
+    this.smallText = assets.small_text ?? null;
+
+    /**
+     * The large image asset's id
+     * @type {?Snowflake}
+     */
+    this.largeImage = assets.large_image ?? null;
+
+    /**
+     * The small image asset's id
+     * @type {?Snowflake}
+     */
+    this.smallImage = assets.small_image ?? null;
+  }
+
+  /**
+   * Gets the URL of the small image asset
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  smallImageURL(options = {}) {
+    if (!this.smallImage) return null;
+    if (this.smallImage.includes(':')) {
+      const [platform, id] = this.smallImage.split(':');
+      switch (platform) {
+        case 'mp':
+          return `https://media.discordapp.net/${id}`;
+        default:
+          return null;
+      }
+    }
+
+    return this.activity.presence.client.rest.cdn.appAsset(this.activity.applicationId, this.smallImage, options);
+  }
+
+  /**
+   * Gets the URL of the large image asset
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  largeImageURL(options = {}) {
+    if (!this.largeImage) return null;
+    if (this.largeImage.includes(':')) {
+      const [platform, id] = this.largeImage.split(':');
+      switch (platform) {
+        case 'mp':
+          return `https://media.discordapp.net/${id}`;
+        case 'spotify':
+          return `https://i.scdn.co/image/${id}`;
+        case 'youtube':
+          return `https://i.ytimg.com/vi/${id}/hqdefault_live.jpg`;
+        case 'twitch':
+          return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${id}.png`;
+        default:
+          return null;
+      }
+    }
+
+    return this.activity.presence.client.rest.cdn.appAsset(this.activity.applicationId, this.largeImage, options);
+  }
+}
+
+exports.Presence = Presence;
+exports.Activity = Activity;
+exports.RichPresenceAssets = RichPresenceAssets;
diff --git a/node_modules/discord.js/src/structures/ReactionCollector.js b/node_modules/discord.js/src/structures/ReactionCollector.js
new file mode 100644
index 0000000..924b33b
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ReactionCollector.js
@@ -0,0 +1,229 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Collector = require('./interfaces/Collector');
+const Events = require('../util/Events');
+
+/**
+ * @typedef {CollectorOptions} ReactionCollectorOptions
+ * @property {number} max The maximum total amount of reactions to collect
+ * @property {number} maxEmojis The maximum number of emojis to collect
+ * @property {number} maxUsers The maximum number of users to react
+ */
+
+/**
+ * Collects reactions on messages.
+ * Will automatically stop if the message ({@link Client#event:messageDelete messageDelete} or
+ * {@link Client#event:messageDeleteBulk messageDeleteBulk}),
+ * channel ({@link Client#event:channelDelete channelDelete}),
+ * thread ({@link Client#event:threadDelete threadDelete}), or
+ * guild ({@link Client#event:guildDelete guildDelete}) is deleted.
+ * @extends {Collector}
+ */
+class ReactionCollector extends Collector {
+  /**
+   * @param {Message} message The message upon which to collect reactions
+   * @param {ReactionCollectorOptions} [options={}] The options to apply to this collector
+   */
+  constructor(message, options = {}) {
+    super(message.client, options);
+
+    /**
+     * The message upon which to collect reactions
+     * @type {Message}
+     */
+    this.message = message;
+
+    /**
+     * The users that have reacted to this message
+     * @type {Collection}
+     */
+    this.users = new Collection();
+
+    /**
+     * The total number of reactions collected
+     * @type {number}
+     */
+    this.total = 0;
+
+    this.empty = this.empty.bind(this);
+    this._handleChannelDeletion = this._handleChannelDeletion.bind(this);
+    this._handleThreadDeletion = this._handleThreadDeletion.bind(this);
+    this._handleGuildDeletion = this._handleGuildDeletion.bind(this);
+    this._handleMessageDeletion = this._handleMessageDeletion.bind(this);
+
+    const bulkDeleteListener = messages => {
+      if (messages.has(this.message.id)) this.stop('messageDelete');
+    };
+
+    this.client.incrementMaxListeners();
+    this.client.on(Events.MessageReactionAdd, this.handleCollect);
+    this.client.on(Events.MessageReactionRemove, this.handleDispose);
+    this.client.on(Events.MessageReactionRemoveAll, this.empty);
+    this.client.on(Events.MessageDelete, this._handleMessageDeletion);
+    this.client.on(Events.MessageBulkDelete, bulkDeleteListener);
+    this.client.on(Events.ChannelDelete, this._handleChannelDeletion);
+    this.client.on(Events.ThreadDelete, this._handleThreadDeletion);
+    this.client.on(Events.GuildDelete, this._handleGuildDeletion);
+
+    this.once('end', () => {
+      this.client.removeListener(Events.MessageReactionAdd, this.handleCollect);
+      this.client.removeListener(Events.MessageReactionRemove, this.handleDispose);
+      this.client.removeListener(Events.MessageReactionRemoveAll, this.empty);
+      this.client.removeListener(Events.MessageDelete, this._handleMessageDeletion);
+      this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener);
+      this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion);
+      this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion);
+      this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion);
+      this.client.decrementMaxListeners();
+    });
+
+    this.on('collect', (reaction, user) => {
+      /**
+       * Emitted whenever a reaction is newly created on a message. Will emit only when a new reaction is
+       * added to the message, as opposed to {@link Collector#collect} which will
+       * be emitted even when a reaction has already been added to the message.
+       * @event ReactionCollector#create
+       * @param {MessageReaction} reaction The reaction that was added
+       * @param {User} user The user that added the reaction
+       */
+      if (reaction.count === 1) {
+        this.emit('create', reaction, user);
+      }
+      this.total++;
+      this.users.set(user.id, user);
+    });
+
+    this.on('remove', (reaction, user) => {
+      this.total--;
+      if (!this.collected.some(r => r.users.cache.has(user.id))) this.users.delete(user.id);
+    });
+  }
+
+  /**
+   * Handles an incoming reaction for possible collection.
+   * @param {MessageReaction} reaction The reaction to possibly collect
+   * @param {User} user The user that added the reaction
+   * @returns {?(Snowflake|string)}
+   * @private
+   */
+  collect(reaction) {
+    /**
+     * Emitted whenever a reaction is collected.
+     * @event ReactionCollector#collect
+     * @param {MessageReaction} reaction The reaction that was collected
+     * @param {User} user The user that added the reaction
+     */
+    if (reaction.message.id !== this.message.id) return null;
+
+    return ReactionCollector.key(reaction);
+  }
+
+  /**
+   * Handles a reaction deletion for possible disposal.
+   * @param {MessageReaction} reaction The reaction to possibly dispose of
+   * @param {User} user The user that removed the reaction
+   * @returns {?(Snowflake|string)}
+   */
+  dispose(reaction, user) {
+    /**
+     * Emitted when the reaction had all the users removed and the `dispose` option is set to true.
+     * @event ReactionCollector#dispose
+     * @param {MessageReaction} reaction The reaction that was disposed of
+     * @param {User} user The user that removed the reaction
+     */
+    if (reaction.message.id !== this.message.id) return null;
+
+    /**
+     * Emitted when the reaction had one user removed and the `dispose` option is set to true.
+     * @event ReactionCollector#remove
+     * @param {MessageReaction} reaction The reaction that was removed
+     * @param {User} user The user that removed the reaction
+     */
+    if (this.collected.has(ReactionCollector.key(reaction)) && this.users.has(user.id)) {
+      this.emit('remove', reaction, user);
+    }
+    return reaction.count ? null : ReactionCollector.key(reaction);
+  }
+
+  /**
+   * Empties this reaction collector.
+   */
+  empty() {
+    this.total = 0;
+    this.collected.clear();
+    this.users.clear();
+    this.checkEnd();
+  }
+
+  /**
+   * The reason this collector has ended with, or null if it hasn't ended yet
+   * @type {?string}
+   * @readonly
+   */
+  get endReason() {
+    if (this.options.max && this.total >= this.options.max) return 'limit';
+    if (this.options.maxEmojis && this.collected.size >= this.options.maxEmojis) return 'emojiLimit';
+    if (this.options.maxUsers && this.users.size >= this.options.maxUsers) return 'userLimit';
+    return super.endReason;
+  }
+
+  /**
+   * Handles checking if the message has been deleted, and if so, stops the collector with the reason 'messageDelete'.
+   * @private
+   * @param {Message} message The message that was deleted
+   * @returns {void}
+   */
+  _handleMessageDeletion(message) {
+    if (message.id === this.message.id) {
+      this.stop('messageDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'.
+   * @private
+   * @param {GuildChannel} channel The channel that was deleted
+   * @returns {void}
+   */
+  _handleChannelDeletion(channel) {
+    if (channel.id === this.message.channelId || channel.threads?.cache.has(this.message.channelId)) {
+      this.stop('channelDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'.
+   * @private
+   * @param {ThreadChannel} thread The thread that was deleted
+   * @returns {void}
+   */
+  _handleThreadDeletion(thread) {
+    if (thread.id === this.message.channelId) {
+      this.stop('threadDelete');
+    }
+  }
+
+  /**
+   * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'.
+   * @private
+   * @param {Guild} guild The guild that was deleted
+   * @returns {void}
+   */
+  _handleGuildDeletion(guild) {
+    if (guild.id === this.message.guild?.id) {
+      this.stop('guildDelete');
+    }
+  }
+
+  /**
+   * Gets the collector key for a reaction.
+   * @param {MessageReaction} reaction The message reaction to get the key for
+   * @returns {Snowflake|string}
+   */
+  static key(reaction) {
+    return reaction.emoji.id ?? reaction.emoji.name;
+  }
+}
+
+module.exports = ReactionCollector;
diff --git a/node_modules/discord.js/src/structures/ReactionEmoji.js b/node_modules/discord.js/src/structures/ReactionEmoji.js
new file mode 100644
index 0000000..08e2ea0
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ReactionEmoji.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const { Emoji } = require('./Emoji');
+const { flatten } = require('../util/Util');
+
+/**
+ * Represents a limited emoji set used for both custom and unicode emojis. Custom emojis
+ * will use this class opposed to the Emoji class when the client doesn't know enough
+ * information about them.
+ * @extends {Emoji}
+ */
+class ReactionEmoji extends Emoji {
+  constructor(reaction, emoji) {
+    super(reaction.message.client, emoji);
+    /**
+     * The message reaction this emoji refers to
+     * @type {MessageReaction}
+     */
+    this.reaction = reaction;
+  }
+
+  toJSON() {
+    return flatten(this, { identifier: true });
+  }
+
+  valueOf() {
+    return this.id;
+  }
+}
+
+module.exports = ReactionEmoji;
diff --git a/node_modules/discord.js/src/structures/Role.js b/node_modules/discord.js/src/structures/Role.js
new file mode 100644
index 0000000..09a2a52
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Role.js
@@ -0,0 +1,471 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { PermissionFlagsBits } = require('discord-api-types/v10');
+const Base = require('./Base');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+const PermissionsBitField = require('../util/PermissionsBitField');
+const RoleFlagsBitField = require('../util/RoleFlagsBitField');
+
+/**
+ * Represents a role on Discord.
+ * @extends {Base}
+ */
+class Role extends Base {
+  constructor(client, data, guild) {
+    super(client);
+
+    /**
+     * The guild that the role belongs to
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The icon hash of the role
+     * @type {?string}
+     */
+    this.icon = null;
+
+    /**
+     * The unicode emoji for the role
+     * @type {?string}
+     */
+    this.unicodeEmoji = null;
+
+    if (data) this._patch(data);
+  }
+
+  _patch(data) {
+    /**
+     * The role's id (unique to the guild it is part of)
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+    if ('name' in data) {
+      /**
+       * The name of the role
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('color' in data) {
+      /**
+       * The base 10 color of the role
+       * @type {number}
+       */
+      this.color = data.color;
+    }
+
+    if ('hoist' in data) {
+      /**
+       * If true, users that are part of this role will appear in a separate category in the users list
+       * @type {boolean}
+       */
+      this.hoist = data.hoist;
+    }
+
+    if ('position' in data) {
+      /**
+       * The raw position of the role from the API
+       * @type {number}
+       */
+      this.rawPosition = data.position;
+    }
+
+    if ('permissions' in data) {
+      /**
+       * The permissions of the role
+       * @type {Readonly<PermissionsBitField>}
+       */
+      this.permissions = new PermissionsBitField(BigInt(data.permissions)).freeze();
+    }
+
+    if ('managed' in data) {
+      /**
+       * Whether or not the role is managed by an external service
+       * @type {boolean}
+       */
+      this.managed = data.managed;
+    }
+
+    if ('mentionable' in data) {
+      /**
+       * Whether or not the role can be mentioned by anyone
+       * @type {boolean}
+       */
+      this.mentionable = data.mentionable;
+    }
+
+    if ('icon' in data) this.icon = data.icon;
+
+    if ('unicode_emoji' in data) this.unicodeEmoji = data.unicode_emoji;
+
+    if ('flags' in data) {
+      /**
+       * The flags of this role
+       * @type {Readonly<RoleFlagsBitField>}
+       */
+      this.flags = new RoleFlagsBitField(data.flags).freeze();
+    } else {
+      this.flags ??= new RoleFlagsBitField().freeze();
+    }
+
+    /**
+     * The tags this role has
+     * @type {?Object}
+     * @property {Snowflake} [botId] The id of the bot this role belongs to
+     * @property {Snowflake|string} [integrationId] The id of the integration this role belongs to
+     * @property {true} [premiumSubscriberRole] Whether this is the guild's premium subscription role
+     * @property {Snowflake} [subscriptionListingId] The id of this role's subscription SKU and listing
+     * @property {true} [availableForPurchase] Whether this role is available for purchase
+     * @property {true} [guildConnections] Whether this role is a guild's linked role
+     */
+    this.tags = data.tags ? {} : null;
+    if (data.tags) {
+      if ('bot_id' in data.tags) {
+        this.tags.botId = data.tags.bot_id;
+      }
+      if ('integration_id' in data.tags) {
+        this.tags.integrationId = data.tags.integration_id;
+      }
+      if ('premium_subscriber' in data.tags) {
+        this.tags.premiumSubscriberRole = true;
+      }
+      if ('subscription_listing_id' in data.tags) {
+        this.tags.subscriptionListingId = data.tags.subscription_listing_id;
+      }
+      if ('available_for_purchase' in data.tags) {
+        this.tags.availableForPurchase = true;
+      }
+      if ('guild_connections' in data.tags) {
+        this.tags.guildConnections = true;
+      }
+    }
+  }
+
+  /**
+   * The timestamp the role was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the role was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The hexadecimal version of the role color, with a leading hashtag
+   * @type {string}
+   * @readonly
+   */
+  get hexColor() {
+    return `#${this.color.toString(16).padStart(6, '0')}`;
+  }
+
+  /**
+   * The cached guild members that have this role
+   * @type {Collection<Snowflake, GuildMember>}
+   * @readonly
+   */
+  get members() {
+    return this.id === this.guild.id
+      ? this.guild.members.cache.clone()
+      : this.guild.members.cache.filter(m => m._roles.includes(this.id));
+  }
+
+  /**
+   * Whether the role is editable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get editable() {
+    if (this.managed) return false;
+    const clientMember = this.guild.members.resolve(this.client.user);
+    if (!clientMember.permissions.has(PermissionFlagsBits.ManageRoles)) return false;
+    return clientMember.roles.highest.comparePositionTo(this) > 0;
+  }
+
+  /**
+   * The position of the role in the role manager
+   * @type {number}
+   * @readonly
+   */
+  get position() {
+    return this.guild.roles.cache.reduce(
+      (acc, role) =>
+        acc +
+        (this.rawPosition === role.rawPosition
+          ? BigInt(this.id) > BigInt(role.id)
+          : this.rawPosition > role.rawPosition),
+      0,
+    );
+  }
+
+  /**
+   * Compares this role's position to another role's.
+   * @param {RoleResolvable} role Role to compare to this one
+   * @returns {number} Negative number if this role's position is lower (other role's is higher),
+   * positive number if this one is higher (other's is lower), 0 if equal
+   * @example
+   * // Compare the position of a role to another
+   * const roleCompare = role.comparePositionTo(otherRole);
+   * if (roleCompare >= 1) console.log(`${role.name} is higher than ${otherRole.name}`);
+   */
+  comparePositionTo(role) {
+    return this.guild.roles.comparePositions(this, role);
+  }
+
+  /**
+   * The data for a role.
+   * @typedef {Object} RoleData
+   * @property {string} [name] The name of the role
+   * @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number
+   * @property {boolean} [hoist] Whether or not the role should be hoisted
+   * @property {number} [position] The position of the role
+   * @property {PermissionResolvable} [permissions] The permissions of the role
+   * @property {boolean} [mentionable] Whether or not the role should be mentionable
+   * @property {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} [icon] The icon for the role
+   * <warn>The `EmojiResolvable` should belong to the same guild as the role.
+   * If not, pass the emoji's URL directly</warn>
+   * @property {?string} [unicodeEmoji] The unicode emoji for the role
+   */
+
+  /**
+   * Edits the role.
+   * @param {RoleEditOptions} options The options to provide
+   * @returns {Promise<Role>}
+   * @example
+   * // Edit a role
+   * role.edit({ name: 'new role' })
+   *   .then(updated => console.log(`Edited role name to ${updated.name}`))
+   *   .catch(console.error);
+   */
+  edit(options) {
+    return this.guild.roles.edit(this, options);
+  }
+
+  /**
+   * Returns `channel.permissionsFor(role)`. Returns permissions for a role in a guild channel,
+   * taking into account permission overwrites.
+   * @param {GuildChannel|Snowflake} channel The guild channel to use as context
+   * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission
+   * will return all permissions
+   * @returns {Readonly<PermissionsBitField>}
+   */
+  permissionsIn(channel, checkAdmin = true) {
+    channel = this.guild.channels.resolve(channel);
+    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
+    return channel.rolePermissions(this, checkAdmin);
+  }
+
+  /**
+   * Sets a new name for the role.
+   * @param {string} name The new name of the role
+   * @param {string} [reason] Reason for changing the role's name
+   * @returns {Promise<Role>}
+   * @example
+   * // Set the name of the role
+   * role.setName('new role')
+   *   .then(updated => console.log(`Updated role name to ${updated.name}`))
+   *   .catch(console.error);
+   */
+  setName(name, reason) {
+    return this.edit({ name, reason });
+  }
+
+  /**
+   * Sets a new color for the role.
+   * @param {ColorResolvable} color The color of the role
+   * @param {string} [reason] Reason for changing the role's color
+   * @returns {Promise<Role>}
+   * @example
+   * // Set the color of a role
+   * role.setColor('#FF0000')
+   *   .then(updated => console.log(`Set color of role to ${updated.color}`))
+   *   .catch(console.error);
+   */
+  setColor(color, reason) {
+    return this.edit({ color, reason });
+  }
+
+  /**
+   * Sets whether or not the role should be hoisted.
+   * @param {boolean} [hoist=true] Whether or not to hoist the role
+   * @param {string} [reason] Reason for setting whether or not the role should be hoisted
+   * @returns {Promise<Role>}
+   * @example
+   * // Set the hoist of the role
+   * role.setHoist(true)
+   *   .then(updated => console.log(`Role hoisted: ${updated.hoist}`))
+   *   .catch(console.error);
+   */
+  setHoist(hoist = true, reason) {
+    return this.edit({ hoist, reason });
+  }
+
+  /**
+   * Sets the permissions of the role.
+   * @param {PermissionResolvable} permissions The permissions of the role
+   * @param {string} [reason] Reason for changing the role's permissions
+   * @returns {Promise<Role>}
+   * @example
+   * // Set the permissions of the role
+   * role.setPermissions([PermissionFlagsBits.KickMembers, PermissionFlagsBits.BanMembers])
+   *   .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`))
+   *   .catch(console.error);
+   * @example
+   * // Remove all permissions from a role
+   * role.setPermissions(0n)
+   *   .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`))
+   *   .catch(console.error);
+   */
+  setPermissions(permissions, reason) {
+    return this.edit({ permissions, reason });
+  }
+
+  /**
+   * Sets whether this role is mentionable.
+   * @param {boolean} [mentionable=true] Whether this role should be mentionable
+   * @param {string} [reason] Reason for setting whether or not this role should be mentionable
+   * @returns {Promise<Role>}
+   * @example
+   * // Make the role mentionable
+   * role.setMentionable(true)
+   *   .then(updated => console.log(`Role updated ${updated.name}`))
+   *   .catch(console.error);
+   */
+  setMentionable(mentionable = true, reason) {
+    return this.edit({ mentionable, reason });
+  }
+
+  /**
+   * Sets a new icon for the role.
+   * @param {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} icon The icon for the role
+   * <warn>The `EmojiResolvable` should belong to the same guild as the role.
+   * If not, pass the emoji's URL directly</warn>
+   * @param {string} [reason] Reason for changing the role's icon
+   * @returns {Promise<Role>}
+   */
+  setIcon(icon, reason) {
+    return this.edit({ icon, reason });
+  }
+
+  /**
+   * Sets a new unicode emoji for the role.
+   * @param {?string} unicodeEmoji The new unicode emoji for the role
+   * @param {string} [reason] Reason for changing the role's unicode emoji
+   * @returns {Promise<Role>}
+   * @example
+   * // Set a new unicode emoji for the role
+   * role.setUnicodeEmoji('🤖')
+   *   .then(updated => console.log(`Set unicode emoji for the role to ${updated.unicodeEmoji}`))
+   *   .catch(console.error);
+   */
+  setUnicodeEmoji(unicodeEmoji, reason) {
+    return this.edit({ unicodeEmoji, reason });
+  }
+
+  /**
+   * Options used to set the position of a role.
+   * @typedef {Object} SetRolePositionOptions
+   * @property {boolean} [relative=false] Whether to change the position relative to its current value or not
+   * @property {string} [reason] The reason for changing the position
+   */
+
+  /**
+   * Sets the new position of the role.
+   * @param {number} position The new position for the role
+   * @param {SetRolePositionOptions} [options] Options for setting the position
+   * @returns {Promise<Role>}
+   * @example
+   * // Set the position of the role
+   * role.setPosition(1)
+   *   .then(updated => console.log(`Role position: ${updated.position}`))
+   *   .catch(console.error);
+   */
+  setPosition(position, options = {}) {
+    return this.guild.roles.setPosition(this, position, options);
+  }
+
+  /**
+   * Deletes the role.
+   * @param {string} [reason] Reason for deleting this role
+   * @returns {Promise<Role>}
+   * @example
+   * // Delete a role
+   * role.delete('The role needed to go')
+   *   .then(deleted => console.log(`Deleted role ${deleted.name}`))
+   *   .catch(console.error);
+   */
+  async delete(reason) {
+    await this.guild.roles.delete(this.id, reason);
+    return this;
+  }
+
+  /**
+   * A link to the role's icon
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  iconURL(options = {}) {
+    return this.icon && this.client.rest.cdn.roleIcon(this.id, this.icon, options);
+  }
+
+  /**
+   * Whether this role equals another role. It compares all properties, so for most operations
+   * it is advisable to just compare `role.id === role2.id` as it is much faster and is often
+   * what most users need.
+   * @param {Role} role Role to compare with
+   * @returns {boolean}
+   */
+  equals(role) {
+    return (
+      role &&
+      this.id === role.id &&
+      this.name === role.name &&
+      this.color === role.color &&
+      this.hoist === role.hoist &&
+      this.position === role.position &&
+      this.permissions.bitfield === role.permissions.bitfield &&
+      this.managed === role.managed &&
+      this.icon === role.icon &&
+      this.unicodeEmoji === role.unicodeEmoji
+    );
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the role's mention instead of the Role object.
+   * @returns {string}
+   * @example
+   * // Logs: Role: <@&123456789012345678>
+   * console.log(`Role: ${role}`);
+   */
+  toString() {
+    if (this.id === this.guild.id) return '@everyone';
+    return `<@&${this.id}>`;
+  }
+
+  toJSON() {
+    return {
+      ...super.toJSON({ createdTimestamp: true }),
+      permissions: this.permissions.toJSON(),
+    };
+  }
+}
+
+exports.Role = Role;
+
+/**
+ * @external APIRole
+ * @see {@link https://discord.com/developers/docs/topics/permissions#role-object}
+ */
diff --git a/node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js b/node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js
new file mode 100644
index 0000000..0d80de5
--- /dev/null
+++ b/node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const { RoleSelectMenuBuilder: BuildersRoleSelectMenu } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+
+/**
+ * Class used to build select menu components to be sent through the API
+ * @extends {BuildersRoleSelectMenu}
+ */
+class RoleSelectMenuBuilder extends BuildersRoleSelectMenu {
+  constructor(data = {}) {
+    super(toSnakeCase(data));
+  }
+
+  /**
+   * Creates a new select menu builder from JSON data
+   * @param {RoleSelectMenuBuilder|RoleSelectMenuComponent|APIRoleSelectComponent} other The other data
+   * @returns {RoleSelectMenuBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = RoleSelectMenuBuilder;
+
+/**
+ * @external BuildersRoleSelectMenu
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/RoleSelectMenuBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/RoleSelectMenuComponent.js b/node_modules/discord.js/src/structures/RoleSelectMenuComponent.js
new file mode 100644
index 0000000..1b27942
--- /dev/null
+++ b/node_modules/discord.js/src/structures/RoleSelectMenuComponent.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
+
+/**
+ * Represents a role select menu component
+ * @extends {BaseSelectMenuComponent}
+ */
+class RoleSelectMenuComponent extends BaseSelectMenuComponent {}
+
+module.exports = RoleSelectMenuComponent;
diff --git a/node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js b/node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js
new file mode 100644
index 0000000..eb42eff
--- /dev/null
+++ b/node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js
@@ -0,0 +1,33 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const MessageComponentInteraction = require('./MessageComponentInteraction');
+
+/**
+ * Represents a {@link ComponentType.RoleSelect} select menu interaction.
+ * @extends {MessageComponentInteraction}
+ */
+class RoleSelectMenuInteraction extends MessageComponentInteraction {
+  constructor(client, data) {
+    super(client, data);
+    const { resolved, values } = data.data;
+
+    /**
+     * An array of the selected role ids
+     * @type {Snowflake[]}
+     */
+    this.values = values ?? [];
+
+    /**
+     * Collection of the selected roles
+     * @type {Collection<Snowflake, Role|APIRole>}
+     */
+    this.roles = new Collection();
+
+    for (const role of Object.values(resolved?.roles ?? {})) {
+      this.roles.set(role.id, this.guild?.roles._add(role) ?? role);
+    }
+  }
+}
+
+module.exports = RoleSelectMenuInteraction;
diff --git a/node_modules/discord.js/src/structures/SelectMenuBuilder.js b/node_modules/discord.js/src/structures/SelectMenuBuilder.js
new file mode 100644
index 0000000..a779370
--- /dev/null
+++ b/node_modules/discord.js/src/structures/SelectMenuBuilder.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const process = require('node:process');
+const StringSelectMenuBuilder = require('./StringSelectMenuBuilder');
+
+let deprecationEmitted = false;
+
+/**
+ * @deprecated Use {@link StringSelectMenuBuilder} instead.
+ * @extends {StringSelectMenuBuilder}
+ */
+class SelectMenuBuilder extends StringSelectMenuBuilder {
+  constructor(...params) {
+    super(...params);
+
+    if (!deprecationEmitted) {
+      process.emitWarning(
+        'The SelectMenuBuilder class is deprecated. Use StringSelectMenuBuilder instead.',
+        'DeprecationWarning',
+      );
+      deprecationEmitted = true;
+    }
+  }
+}
+
+module.exports = SelectMenuBuilder;
diff --git a/node_modules/discord.js/src/structures/SelectMenuComponent.js b/node_modules/discord.js/src/structures/SelectMenuComponent.js
new file mode 100644
index 0000000..2cd8097
--- /dev/null
+++ b/node_modules/discord.js/src/structures/SelectMenuComponent.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const process = require('node:process');
+const StringSelectMenuComponent = require('./StringSelectMenuComponent');
+
+let deprecationEmitted = false;
+
+/**
+ * @deprecated Use {@link StringSelectMenuComponent} instead.
+ * @extends {StringSelectMenuComponent}
+ */
+class SelectMenuComponent extends StringSelectMenuComponent {
+  constructor(...params) {
+    super(...params);
+
+    if (!deprecationEmitted) {
+      process.emitWarning(
+        'The SelectMenuComponent class is deprecated. Use StringSelectMenuComponent instead.',
+        'DeprecationWarning',
+      );
+      deprecationEmitted = true;
+    }
+  }
+}
+
+module.exports = SelectMenuComponent;
diff --git a/node_modules/discord.js/src/structures/SelectMenuInteraction.js b/node_modules/discord.js/src/structures/SelectMenuInteraction.js
new file mode 100644
index 0000000..a096559
--- /dev/null
+++ b/node_modules/discord.js/src/structures/SelectMenuInteraction.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const process = require('node:process');
+const StringSelectMenuInteraction = require('./StringSelectMenuInteraction');
+
+let deprecationEmitted = false;
+
+/**
+ * @deprecated Use {@link StringSelectMenuInteraction} instead.
+ * @extends {StringSelectMenuInteraction}
+ */
+class SelectMenuInteraction extends StringSelectMenuInteraction {
+  constructor(...params) {
+    super(...params);
+
+    if (!deprecationEmitted) {
+      process.emitWarning(
+        'The SelectMenuInteraction class is deprecated. Use StringSelectMenuInteraction instead.',
+        'DeprecationWarning',
+      );
+      deprecationEmitted = true;
+    }
+  }
+}
+
+module.exports = SelectMenuInteraction;
diff --git a/node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js b/node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js
new file mode 100644
index 0000000..85309d1
--- /dev/null
+++ b/node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const process = require('node:process');
+const StringSelectMenuOptionBuilder = require('./StringSelectMenuOptionBuilder');
+
+let deprecationEmitted = false;
+
+/**
+ * @deprecated Use {@link StringSelectMenuOptionBuilder} instead.
+ * @extends {StringSelectMenuOptionBuilder}
+ */
+class SelectMenuOptionBuilder extends StringSelectMenuOptionBuilder {
+  constructor(...params) {
+    super(...params);
+
+    if (!deprecationEmitted) {
+      process.emitWarning(
+        'The SelectMenuOptionBuilder class is deprecated. Use StringSelectMenuOptionBuilder instead.',
+        'DeprecationWarning',
+      );
+      deprecationEmitted = true;
+    }
+  }
+}
+
+module.exports = SelectMenuOptionBuilder;
diff --git a/node_modules/discord.js/src/structures/StageChannel.js b/node_modules/discord.js/src/structures/StageChannel.js
new file mode 100644
index 0000000..2661489
--- /dev/null
+++ b/node_modules/discord.js/src/structures/StageChannel.js
@@ -0,0 +1,112 @@
+'use strict';
+
+const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel');
+
+/**
+ * Represents a guild stage channel on Discord.
+ * @extends {BaseGuildVoiceChannel}
+ */
+class StageChannel extends BaseGuildVoiceChannel {
+  _patch(data) {
+    super._patch(data);
+
+    if ('topic' in data) {
+      /**
+       * The topic of the stage channel
+       * @type {?string}
+       */
+      this.topic = data.topic;
+    }
+  }
+
+  /**
+   * The stage instance of this stage channel, if it exists
+   * @type {?StageInstance}
+   * @readonly
+   */
+  get stageInstance() {
+    return this.guild.stageInstances.cache.find(stageInstance => stageInstance.channelId === this.id) ?? null;
+  }
+
+  /**
+   * Creates a stage instance associated with this stage channel.
+   * @param {StageInstanceCreateOptions} options The options to create the stage instance
+   * @returns {Promise<StageInstance>}
+   */
+  createStageInstance(options) {
+    return this.guild.stageInstances.create(this.id, options);
+  }
+
+  /**
+   * Sets a new topic for the guild channel.
+   * @param {?string} topic The new topic for the guild channel
+   * @param {string} [reason] Reason for changing the guild channel's topic
+   * @returns {Promise<StageChannel>}
+   * @example
+   * // Set a new channel topic
+   * stageChannel.setTopic('needs more rate limiting')
+   *   .then(channel => console.log(`Channel's new topic is ${channel.topic}`))
+   *   .catch(console.error);
+   */
+  setTopic(topic, reason) {
+    return this.edit({ topic, reason });
+  }
+}
+
+/**
+ * Sets the bitrate of the channel.
+ * @method setBitrate
+ * @memberof StageChannel
+ * @instance
+ * @param {number} bitrate The new bitrate
+ * @param {string} [reason] Reason for changing the channel's bitrate
+ * @returns {Promise<StageChannel>}
+ * @example
+ * // Set the bitrate of a voice channel
+ * stageChannel.setBitrate(48_000)
+ *   .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`))
+ *   .catch(console.error);
+ */
+
+/**
+ * Sets the RTC region of the channel.
+ * @method setRTCRegion
+ * @memberof StageChannel
+ * @instance
+ * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
+ * @param {string} [reason] The reason for modifying this region.
+ * @returns {Promise<StageChannel>}
+ * @example
+ * // Set the RTC region to sydney
+ * stageChannel.setRTCRegion('sydney');
+ * @example
+ * // Remove a fixed region for this channel - let Discord decide automatically
+ * stageChannel.setRTCRegion(null, 'We want to let Discord decide.');
+ */
+
+/**
+ * Sets the user limit of the channel.
+ * @method setUserLimit
+ * @memberof StageChannel
+ * @instance
+ * @param {number} userLimit The new user limit
+ * @param {string} [reason] Reason for changing the user limit
+ * @returns {Promise<StageChannel>}
+ * @example
+ * // Set the user limit of a voice channel
+ * stageChannel.setUserLimit(42)
+ *   .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`))
+ *   .catch(console.error);
+ */
+
+/**
+ * Sets the camera video quality mode of the channel.
+ * @method setVideoQualityMode
+ * @memberof StageChannel
+ * @instance
+ * @param {VideoQualityMode} videoQualityMode The new camera video quality mode.
+ * @param {string} [reason] Reason for changing the camera video quality mode.
+ * @returns {Promise<StageChannel>}
+ */
+
+module.exports = StageChannel;
diff --git a/node_modules/discord.js/src/structures/StageInstance.js b/node_modules/discord.js/src/structures/StageInstance.js
new file mode 100644
index 0000000..97f65df
--- /dev/null
+++ b/node_modules/discord.js/src/structures/StageInstance.js
@@ -0,0 +1,167 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const Base = require('./Base');
+
+/**
+ * Represents a stage instance.
+ * @extends {Base}
+ */
+class StageInstance extends Base {
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The stage instance's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('guild_id' in data) {
+      /**
+       * The id of the guild associated with the stage channel
+       * @type {Snowflake}
+       */
+      this.guildId = data.guild_id;
+    }
+
+    if ('channel_id' in data) {
+      /**
+       * The id of the channel associated with the stage channel
+       * @type {Snowflake}
+       */
+      this.channelId = data.channel_id;
+    }
+
+    if ('topic' in data) {
+      /**
+       * The topic of the stage instance
+       * @type {string}
+       */
+      this.topic = data.topic;
+    }
+
+    if ('privacy_level' in data) {
+      /**
+       * The privacy level of the stage instance
+       * @type {StageInstancePrivacyLevel}
+       */
+      this.privacyLevel = data.privacy_level;
+    }
+
+    if ('discoverable_disabled' in data) {
+      /**
+       * Whether or not stage discovery is disabled
+       * @type {?boolean}
+       * @deprecated See https://github.com/discord/discord-api-docs/pull/4296 for more information
+       */
+      this.discoverableDisabled = data.discoverable_disabled;
+    } else {
+      this.discoverableDisabled ??= null;
+    }
+
+    if ('guild_scheduled_event_id' in data) {
+      /**
+       * The associated guild scheduled event id of this stage instance
+       * @type {?Snowflake}
+       */
+      this.guildScheduledEventId = data.guild_scheduled_event_id;
+    } else {
+      this.guildScheduledEventId ??= null;
+    }
+  }
+
+  /**
+   * The stage channel associated with this stage instance
+   * @type {?StageChannel}
+   * @readonly
+   */
+  get channel() {
+    return this.client.channels.resolve(this.channelId);
+  }
+
+  /**
+   * The guild this stage instance belongs to
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.resolve(this.guildId);
+  }
+
+  /**
+   * The associated guild scheduled event of this stage instance
+   * @type {?GuildScheduledEvent}
+   * @readonly
+   */
+  get guildScheduledEvent() {
+    return this.guild?.scheduledEvents.resolve(this.guildScheduledEventId) ?? null;
+  }
+
+  /**
+   * Edits this stage instance.
+   * @param {StageInstanceEditOptions} options The options to edit the stage instance
+   * @returns {Promise<StageInstance>}
+   * @example
+   * // Edit a stage instance
+   * stageInstance.edit({ topic: 'new topic' })
+   *  .then(stageInstance => console.log(stageInstance))
+   *  .catch(console.error)
+   */
+  edit(options) {
+    return this.guild.stageInstances.edit(this.channelId, options);
+  }
+
+  /**
+   * Deletes this stage instance.
+   * @returns {Promise<StageInstance>}
+   * @example
+   * // Delete a stage instance
+   * stageInstance.delete()
+   *  .then(stageInstance => console.log(stageInstance))
+   *  .catch(console.error);
+   */
+  async delete() {
+    await this.guild.stageInstances.delete(this.channelId);
+    const clone = this._clone();
+    return clone;
+  }
+
+  /**
+   * Sets the topic of this stage instance.
+   * @param {string} topic The topic for the stage instance
+   * @returns {Promise<StageInstance>}
+   * @example
+   * // Set topic of a stage instance
+   * stageInstance.setTopic('new topic')
+   *  .then(stageInstance => console.log(`Set the topic to: ${stageInstance.topic}`))
+   *  .catch(console.error);
+   */
+  setTopic(topic) {
+    return this.guild.stageInstances.edit(this.channelId, { topic });
+  }
+
+  /**
+   * The timestamp this stage instances was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time this stage instance was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+}
+
+exports.StageInstance = StageInstance;
diff --git a/node_modules/discord.js/src/structures/Sticker.js b/node_modules/discord.js/src/structures/Sticker.js
new file mode 100644
index 0000000..b0f2ef6
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Sticker.js
@@ -0,0 +1,272 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { Routes } = require('discord-api-types/v10');
+const Base = require('./Base');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+const { StickerFormatExtensionMap } = require('../util/Constants');
+
+/**
+ * Represents a Sticker.
+ * @extends {Base}
+ */
+class Sticker extends Base {
+  constructor(client, sticker) {
+    super(client);
+
+    this._patch(sticker);
+  }
+
+  _patch(sticker) {
+    /**
+     * The sticker's id
+     * @type {Snowflake}
+     */
+    this.id = sticker.id;
+
+    if ('description' in sticker) {
+      /**
+       * The description of the sticker
+       * @type {?string}
+       */
+      this.description = sticker.description;
+    } else {
+      this.description ??= null;
+    }
+
+    if ('type' in sticker) {
+      /**
+       * The type of the sticker
+       * @type {?StickerType}
+       */
+      this.type = sticker.type;
+    } else {
+      this.type ??= null;
+    }
+
+    if ('format_type' in sticker) {
+      /**
+       * The format of the sticker
+       * @type {StickerFormatType}
+       */
+      this.format = sticker.format_type;
+    }
+
+    if ('name' in sticker) {
+      /**
+       * The name of the sticker
+       * @type {string}
+       */
+      this.name = sticker.name;
+    }
+
+    if ('pack_id' in sticker) {
+      /**
+       * The id of the pack the sticker is from, for standard stickers
+       * @type {?Snowflake}
+       */
+      this.packId = sticker.pack_id;
+    } else {
+      this.packId ??= null;
+    }
+
+    if ('tags' in sticker) {
+      /**
+       * Autocomplete/suggestions for the sticker
+       * @type {?string}
+       */
+      this.tags = sticker.tags;
+    } else {
+      this.tags ??= null;
+    }
+
+    if ('available' in sticker) {
+      /**
+       * Whether or not the guild sticker is available
+       * @type {?boolean}
+       */
+      this.available = sticker.available;
+    } else {
+      this.available ??= null;
+    }
+
+    if ('guild_id' in sticker) {
+      /**
+       * The id of the guild that owns this sticker
+       * @type {?Snowflake}
+       */
+      this.guildId = sticker.guild_id;
+    } else {
+      this.guildId ??= null;
+    }
+
+    if ('user' in sticker) {
+      /**
+       * The user that uploaded the guild sticker
+       * @type {?User}
+       */
+      this.user = this.client.users._add(sticker.user);
+    } else {
+      this.user ??= null;
+    }
+
+    if ('sort_value' in sticker) {
+      /**
+       * The standard sticker's sort order within its pack
+       * @type {?number}
+       */
+      this.sortValue = sticker.sort_value;
+    } else {
+      this.sortValue ??= null;
+    }
+  }
+
+  /**
+   * The timestamp the sticker was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the sticker was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * Whether this sticker is partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return !this.type;
+  }
+
+  /**
+   * The guild that owns this sticker
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.client.guilds.resolve(this.guildId);
+  }
+
+  /**
+   * A link to the sticker
+   * <info>If the sticker's format is {@link StickerFormatType.Lottie}, it returns
+   * the URL of the Lottie JSON file.</info>
+   * @type {string}
+   * @readonly
+   */
+  get url() {
+    return this.client.rest.cdn.sticker(this.id, StickerFormatExtensionMap[this.format]);
+  }
+
+  /**
+   * Fetches this sticker.
+   * @returns {Promise<Sticker>}
+   */
+  async fetch() {
+    const data = await this.client.rest.get(Routes.sticker(this.id));
+    this._patch(data);
+    return this;
+  }
+
+  /**
+   * Fetches the pack this sticker is part of from Discord, if this is a Nitro sticker.
+   * @returns {Promise<?StickerPack>}
+   */
+  async fetchPack() {
+    return (this.packId && (await this.client.fetchPremiumStickerPacks()).get(this.packId)) ?? null;
+  }
+
+  /**
+   * Fetches the user who uploaded this sticker, if this is a guild sticker.
+   * @returns {Promise<?User>}
+   */
+  async fetchUser() {
+    if (this.partial) await this.fetch();
+    if (!this.guildId) throw new DiscordjsError(ErrorCodes.NotGuildSticker);
+    return this.guild.stickers.fetchUser(this);
+  }
+
+  /**
+   * Data for editing a sticker.
+   * @typedef {Object} GuildStickerEditOptions
+   * @property {string} [name] The name of the sticker
+   * @property {?string} [description] The description of the sticker
+   * @property {string} [tags] The Discord name of a unicode emoji representing the sticker's expression
+   * @property {string} [reason] Reason for editing this sticker
+   */
+
+  /**
+   * Edits the sticker.
+   * @param {GuildStickerEditOptions} options The options to provide
+   * @returns {Promise<Sticker>}
+   * @example
+   * // Update the name of a sticker
+   * sticker.edit({ name: 'new name' })
+   *   .then(s => console.log(`Updated the name of the sticker to ${s.name}`))
+   *   .catch(console.error);
+   */
+  edit(options) {
+    return this.guild.stickers.edit(this, options);
+  }
+
+  /**
+   * Deletes the sticker.
+   * @returns {Promise<Sticker>}
+   * @param {string} [reason] Reason for deleting this sticker
+   * @example
+   * // Delete a message
+   * sticker.delete()
+   *   .then(s => console.log(`Deleted sticker ${s.name}`))
+   *   .catch(console.error);
+   */
+  async delete(reason) {
+    await this.guild.stickers.delete(this, reason);
+    return this;
+  }
+
+  /**
+   * Whether this sticker is the same as another one.
+   * @param {Sticker|APISticker} other The sticker to compare it to
+   * @returns {boolean}
+   */
+  equals(other) {
+    if (other instanceof Sticker) {
+      return (
+        other.id === this.id &&
+        other.description === this.description &&
+        other.type === this.type &&
+        other.format === this.format &&
+        other.name === this.name &&
+        other.packId === this.packId &&
+        other.tags === this.tags &&
+        other.available === this.available &&
+        other.guildId === this.guildId &&
+        other.sortValue === this.sortValue
+      );
+    } else {
+      return (
+        other.id === this.id &&
+        other.description === this.description &&
+        other.name === this.name &&
+        other.tags === this.tags
+      );
+    }
+  }
+}
+
+exports.Sticker = Sticker;
+
+/**
+ * @external APISticker
+ * @see {@link https://discord.com/developers/docs/resources/sticker#sticker-object}
+ */
diff --git a/node_modules/discord.js/src/structures/StickerPack.js b/node_modules/discord.js/src/structures/StickerPack.js
new file mode 100644
index 0000000..7e599b7
--- /dev/null
+++ b/node_modules/discord.js/src/structures/StickerPack.js
@@ -0,0 +1,95 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const Base = require('./Base');
+const { Sticker } = require('./Sticker');
+
+/**
+ * Represents a pack of standard stickers.
+ * @extends {Base}
+ */
+class StickerPack extends Base {
+  constructor(client, pack) {
+    super(client);
+    /**
+     * The Sticker pack's id
+     * @type {Snowflake}
+     */
+    this.id = pack.id;
+
+    /**
+     * The stickers in the pack
+     * @type {Collection<Snowflake, Sticker>}
+     */
+    this.stickers = new Collection(pack.stickers.map(s => [s.id, new Sticker(client, s)]));
+
+    /**
+     * The name of the sticker pack
+     * @type {string}
+     */
+    this.name = pack.name;
+
+    /**
+     * The id of the pack's SKU
+     * @type {Snowflake}
+     */
+    this.skuId = pack.sku_id;
+
+    /**
+     * The id of a sticker in the pack which is shown as the pack's icon
+     * @type {?Snowflake}
+     */
+    this.coverStickerId = pack.cover_sticker_id ?? null;
+
+    /**
+     * The description of the sticker pack
+     * @type {string}
+     */
+    this.description = pack.description;
+
+    /**
+     * The id of the sticker pack's banner image
+     * @type {?Snowflake}
+     */
+    this.bannerId = pack.banner_asset_id ?? null;
+  }
+
+  /**
+   * The timestamp the sticker was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the sticker was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The sticker which is shown as the pack's icon
+   * @type {?Sticker}
+   * @readonly
+   */
+  get coverSticker() {
+    return this.coverStickerId && this.stickers.get(this.coverStickerId);
+  }
+
+  /**
+   * The URL to this sticker pack's banner.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  bannerURL(options = {}) {
+    return this.bannerId && this.client.rest.cdn.stickerPackBanner(this.bannerId, options);
+  }
+}
+
+module.exports = StickerPack;
diff --git a/node_modules/discord.js/src/structures/StringSelectMenuBuilder.js b/node_modules/discord.js/src/structures/StringSelectMenuBuilder.js
new file mode 100644
index 0000000..ac555e7
--- /dev/null
+++ b/node_modules/discord.js/src/structures/StringSelectMenuBuilder.js
@@ -0,0 +1,79 @@
+'use strict';
+
+const { SelectMenuBuilder: BuildersSelectMenu, normalizeArray } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+const { resolvePartialEmoji } = require('../util/Util');
+
+/**
+ * Class used to build select menu components to be sent through the API
+ * @extends {BuildersSelectMenu}
+ */
+class StringSelectMenuBuilder extends BuildersSelectMenu {
+  constructor({ options, ...data } = {}) {
+    super(
+      toSnakeCase({
+        ...data,
+        options: options?.map(({ emoji, ...option }) => ({
+          ...option,
+          emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
+        })),
+      }),
+    );
+  }
+
+  /**
+   * Normalizes a select menu option emoji
+   * @param {SelectMenuOptionData|APISelectMenuOption} selectMenuOption The option to normalize
+   * @returns {SelectMenuOptionBuilder|APISelectMenuOption}
+   * @private
+   */
+  static normalizeEmoji(selectMenuOption) {
+    if (isJSONEncodable(selectMenuOption)) {
+      return selectMenuOption;
+    }
+
+    const { emoji, ...option } = selectMenuOption;
+    return {
+      ...option,
+      emoji: typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
+    };
+  }
+
+  /**
+   * Adds options to this select menu
+   * @param {RestOrArray<APISelectMenuOption>} options The options to add to this select menu
+   * @returns {StringSelectMenuBuilder}
+   */
+  addOptions(...options) {
+    return super.addOptions(normalizeArray(options).map(option => StringSelectMenuBuilder.normalizeEmoji(option)));
+  }
+
+  /**
+   * Sets the options on this select menu
+   * @param {RestOrArray<APISelectMenuOption>} options The options to set on this select menu
+   * @returns {StringSelectMenuBuilder}
+   */
+  setOptions(...options) {
+    return super.setOptions(normalizeArray(options).map(option => StringSelectMenuBuilder.normalizeEmoji(option)));
+  }
+
+  /**
+   * Creates a new select menu builder from json data
+   * @param {StringSelectMenuBuilder|StringSelectMenuComponent|APIStringSelectComponent} other The other data
+   * @returns {StringSelectMenuBuilder}
+   */
+  static from(other) {
+    if (isJSONEncodable(other)) {
+      return new this(other.toJSON());
+    }
+    return new this(other);
+  }
+}
+
+module.exports = StringSelectMenuBuilder;
+
+/**
+ * @external BuildersSelectMenu
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/StringSelectMenuBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/StringSelectMenuComponent.js b/node_modules/discord.js/src/structures/StringSelectMenuComponent.js
new file mode 100644
index 0000000..e008ae5
--- /dev/null
+++ b/node_modules/discord.js/src/structures/StringSelectMenuComponent.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
+
+/**
+ * Represents a string select menu component
+ * @extends {BaseSelectMenuComponent}
+ */
+class StringSelectMenuComponent extends BaseSelectMenuComponent {
+  /**
+   * The options in this select menu
+   * @type {APISelectMenuOption[]}
+   * @readonly
+   */
+  get options() {
+    return this.data.options;
+  }
+}
+
+module.exports = StringSelectMenuComponent;
diff --git a/node_modules/discord.js/src/structures/StringSelectMenuInteraction.js b/node_modules/discord.js/src/structures/StringSelectMenuInteraction.js
new file mode 100644
index 0000000..1db8c28
--- /dev/null
+++ b/node_modules/discord.js/src/structures/StringSelectMenuInteraction.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const MessageComponentInteraction = require('./MessageComponentInteraction');
+
+/**
+ * Represents a {@link ComponentType.StringSelect} select menu interaction.
+ * @extends {MessageComponentInteraction}
+ */
+class StringSelectMenuInteraction extends MessageComponentInteraction {
+  constructor(client, data) {
+    super(client, data);
+
+    /**
+     * The values selected
+     * @type {string[]}
+     */
+    this.values = data.data.values ?? [];
+  }
+}
+
+module.exports = StringSelectMenuInteraction;
diff --git a/node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js b/node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js
new file mode 100644
index 0000000..cc85750
--- /dev/null
+++ b/node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js
@@ -0,0 +1,49 @@
+'use strict';
+
+const { SelectMenuOptionBuilder: BuildersSelectMenuOption } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+const { resolvePartialEmoji } = require('../util/Util');
+
+/**
+ * Represents a select menu option builder.
+ * @extends {BuildersSelectMenuOption}
+ */
+class StringSelectMenuOptionBuilder extends BuildersSelectMenuOption {
+  constructor({ emoji, ...data } = {}) {
+    super(
+      toSnakeCase({
+        ...data,
+        emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
+      }),
+    );
+  }
+
+  /**
+   * Sets the emoji to display on this option
+   * @param {ComponentEmojiResolvable} emoji The emoji to display on this option
+   * @returns {StringSelectMenuOptionBuilder}
+   */
+  setEmoji(emoji) {
+    if (typeof emoji === 'string') {
+      return super.setEmoji(resolvePartialEmoji(emoji));
+    }
+    return super.setEmoji(emoji);
+  }
+
+  /**
+   * Creates a new select menu option builder from JSON data
+   * @param {StringSelectMenuOptionBuilder|APISelectMenuOption} other The other data
+   * @returns {StringSelectMenuOptionBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = StringSelectMenuOptionBuilder;
+
+/**
+ * @external BuildersSelectMenuOption
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/StringSelectMenuOptionBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/Team.js b/node_modules/discord.js/src/structures/Team.js
new file mode 100644
index 0000000..98eb199
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Team.js
@@ -0,0 +1,117 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const Base = require('./Base');
+const TeamMember = require('./TeamMember');
+
+/**
+ * Represents a Client OAuth2 Application Team.
+ * @extends {Base}
+ */
+class Team extends Base {
+  constructor(client, data) {
+    super(client);
+    this._patch(data);
+  }
+
+  _patch(data) {
+    /**
+     * The Team's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    if ('name' in data) {
+      /**
+       * The name of the Team
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('icon' in data) {
+      /**
+       * The Team's icon hash
+       * @type {?string}
+       */
+      this.icon = data.icon;
+    } else {
+      this.icon ??= null;
+    }
+
+    if ('owner_user_id' in data) {
+      /**
+       * The Team's owner id
+       * @type {?Snowflake}
+       */
+      this.ownerId = data.owner_user_id;
+    } else {
+      this.ownerId ??= null;
+    }
+    /**
+     * The Team's members
+     * @type {Collection<Snowflake, TeamMember>}
+     */
+    this.members = new Collection();
+
+    for (const memberData of data.members) {
+      const member = new TeamMember(this, memberData);
+      this.members.set(member.id, member);
+    }
+  }
+
+  /**
+   * The owner of this team
+   * @type {?TeamMember}
+   * @readonly
+   */
+  get owner() {
+    return this.members.get(this.ownerId) ?? null;
+  }
+
+  /**
+   * The timestamp the team was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the team was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * A link to the team's icon.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  iconURL(options = {}) {
+    return this.icon && this.client.rest.cdn.teamIcon(this.id, this.icon, options);
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the Team's name instead of the
+   * Team object.
+   * @returns {string}
+   * @example
+   * // Logs: Team name: My Team
+   * console.log(`Team name: ${team}`);
+   */
+  toString() {
+    return this.name;
+  }
+
+  toJSON() {
+    return super.toJSON({ createdTimestamp: true });
+  }
+}
+
+module.exports = Team;
diff --git a/node_modules/discord.js/src/structures/TeamMember.js b/node_modules/discord.js/src/structures/TeamMember.js
new file mode 100644
index 0000000..9270418
--- /dev/null
+++ b/node_modules/discord.js/src/structures/TeamMember.js
@@ -0,0 +1,70 @@
+'use strict';
+
+const Base = require('./Base');
+
+/**
+ * Represents a Client OAuth2 Application Team Member.
+ * @extends {Base}
+ */
+class TeamMember extends Base {
+  constructor(team, data) {
+    super(team.client);
+
+    /**
+     * The Team this member is part of
+     * @type {Team}
+     */
+    this.team = team;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('permissions' in data) {
+      /**
+       * The permissions this Team Member has with regard to the team
+       * @type {string[]}
+       */
+      this.permissions = data.permissions;
+    }
+
+    if ('membership_state' in data) {
+      /**
+       * The permissions this Team Member has with regard to the team
+       * @type {TeamMemberMembershipState}
+       */
+      this.membershipState = data.membership_state;
+    }
+
+    if ('user' in data) {
+      /**
+       * The user for this Team Member
+       * @type {User}
+       */
+      this.user = this.client.users._add(data.user);
+    }
+  }
+
+  /**
+   * The Team Member's id
+   * @type {Snowflake}
+   * @readonly
+   */
+  get id() {
+    return this.user.id;
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the team member's mention instead of the
+   * TeamMember object.
+   * @returns {string}
+   * @example
+   * // Logs: Team Member's mention: <@123456789012345678>
+   * console.log(`Team Member's mention: ${teamMember}`);
+   */
+  toString() {
+    return this.user.toString();
+  }
+}
+
+module.exports = TeamMember;
diff --git a/node_modules/discord.js/src/structures/TextChannel.js b/node_modules/discord.js/src/structures/TextChannel.js
new file mode 100644
index 0000000..66cc8c4
--- /dev/null
+++ b/node_modules/discord.js/src/structures/TextChannel.js
@@ -0,0 +1,33 @@
+'use strict';
+
+const BaseGuildTextChannel = require('./BaseGuildTextChannel');
+
+/**
+ * Represents a guild text channel on Discord.
+ * @extends {BaseGuildTextChannel}
+ */
+class TextChannel extends BaseGuildTextChannel {
+  _patch(data) {
+    super._patch(data);
+
+    if ('rate_limit_per_user' in data) {
+      /**
+       * The rate limit per user (slowmode) for this channel in seconds
+       * @type {number}
+       */
+      this.rateLimitPerUser = data.rate_limit_per_user;
+    }
+  }
+
+  /**
+   * Sets the rate limit per user (slowmode) for this channel.
+   * @param {number} rateLimitPerUser The new rate limit in seconds
+   * @param {string} [reason] Reason for changing the channel's rate limit
+   * @returns {Promise<TextChannel>}
+   */
+  setRateLimitPerUser(rateLimitPerUser, reason) {
+    return this.edit({ rateLimitPerUser, reason });
+  }
+}
+
+module.exports = TextChannel;
diff --git a/node_modules/discord.js/src/structures/TextInputBuilder.js b/node_modules/discord.js/src/structures/TextInputBuilder.js
new file mode 100644
index 0000000..9382154
--- /dev/null
+++ b/node_modules/discord.js/src/structures/TextInputBuilder.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const { TextInputBuilder: BuildersTextInput } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+
+/**
+ * Represents a text input builder.
+ * @extends {BuildersTextInput}
+ */
+class TextInputBuilder extends BuildersTextInput {
+  constructor(data) {
+    super(toSnakeCase(data));
+  }
+
+  /**
+   * Creates a new text input builder from JSON data
+   * @param {TextInputBuilder|TextInputComponent|APITextInputComponent} other The other data
+   * @returns {TextInputBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = TextInputBuilder;
+
+/**
+ * @external BuildersTextInput
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/TextInputBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/TextInputComponent.js b/node_modules/discord.js/src/structures/TextInputComponent.js
new file mode 100644
index 0000000..3cc3115
--- /dev/null
+++ b/node_modules/discord.js/src/structures/TextInputComponent.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const Component = require('./Component');
+
+/**
+ * Represents a text input component.
+ * @extends {Component}
+ */
+class TextInputComponent extends Component {
+  /**
+   * The custom id of this text input
+   * @type {string}
+   * @readonly
+   */
+  get customId() {
+    return this.data.custom_id;
+  }
+
+  /**
+   * The value for this text input
+   * @type {string}
+   * @readonly
+   */
+  get value() {
+    return this.data.value;
+  }
+}
+
+module.exports = TextInputComponent;
diff --git a/node_modules/discord.js/src/structures/ThreadChannel.js b/node_modules/discord.js/src/structures/ThreadChannel.js
new file mode 100644
index 0000000..96b4087
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ThreadChannel.js
@@ -0,0 +1,606 @@
+'use strict';
+
+const { ChannelType, PermissionFlagsBits, Routes, ChannelFlags } = require('discord-api-types/v10');
+const { BaseChannel } = require('./BaseChannel');
+const TextBasedChannel = require('./interfaces/TextBasedChannel');
+const { DiscordjsRangeError, ErrorCodes } = require('../errors');
+const GuildMessageManager = require('../managers/GuildMessageManager');
+const ThreadMemberManager = require('../managers/ThreadMemberManager');
+const ChannelFlagsBitField = require('../util/ChannelFlagsBitField');
+
+/**
+ * Represents a thread channel on Discord.
+ * @extends {BaseChannel}
+ * @implements {TextBasedChannel}
+ */
+class ThreadChannel extends BaseChannel {
+  constructor(guild, data, client) {
+    super(guild?.client ?? client, data, false);
+
+    /**
+     * The guild the thread is in
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The id of the guild the channel is in
+     * @type {Snowflake}
+     */
+    this.guildId = guild?.id ?? data.guild_id;
+
+    /**
+     * A manager of the messages sent to this thread
+     * @type {GuildMessageManager}
+     */
+    this.messages = new GuildMessageManager(this);
+
+    /**
+     * A manager of the members that are part of this thread
+     * @type {ThreadMemberManager}
+     */
+    this.members = new ThreadMemberManager(this);
+    if (data) this._patch(data);
+  }
+
+  _patch(data) {
+    super._patch(data);
+
+    if ('message' in data) this.messages._add(data.message);
+
+    if ('name' in data) {
+      /**
+       * The name of the thread
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('guild_id' in data) {
+      this.guildId = data.guild_id;
+    }
+
+    if ('parent_id' in data) {
+      /**
+       * The id of the parent channel of this thread
+       * @type {?Snowflake}
+       */
+      this.parentId = data.parent_id;
+    } else {
+      this.parentId ??= null;
+    }
+
+    if ('thread_metadata' in data) {
+      /**
+       * Whether the thread is locked
+       * @type {?boolean}
+       */
+      this.locked = data.thread_metadata.locked ?? false;
+
+      /**
+       * Whether members without the {@link PermissionFlagsBits.ManageThreads} permission
+       * can invite other members to this thread.
+       * <info>This property is always `null` in public threads.</info>
+       * @type {?boolean}
+       */
+      this.invitable = this.type === ChannelType.PrivateThread ? data.thread_metadata.invitable ?? false : null;
+
+      /**
+       * Whether the thread is archived
+       * @type {?boolean}
+       */
+      this.archived = data.thread_metadata.archived;
+
+      /**
+       * The amount of time (in minutes) after which the thread will automatically archive in case of no recent activity
+       * @type {?ThreadAutoArchiveDuration}
+       */
+      this.autoArchiveDuration = data.thread_metadata.auto_archive_duration;
+
+      /**
+       * The timestamp when the thread's archive status was last changed
+       * <info>If the thread was never archived or unarchived, this is the timestamp at which the thread was
+       * created</info>
+       * @type {?number}
+       */
+      this.archiveTimestamp = Date.parse(data.thread_metadata.archive_timestamp);
+
+      if ('create_timestamp' in data.thread_metadata) {
+        // Note: this is needed because we can't assign directly to getters
+        this._createdTimestamp = Date.parse(data.thread_metadata.create_timestamp);
+      }
+    } else {
+      this.locked ??= null;
+      this.archived ??= null;
+      this.autoArchiveDuration ??= null;
+      this.archiveTimestamp ??= null;
+      this.invitable ??= null;
+    }
+
+    this._createdTimestamp ??= this.type === ChannelType.PrivateThread ? super.createdTimestamp : null;
+
+    if ('owner_id' in data) {
+      /**
+       * The id of the member who created this thread
+       * @type {?Snowflake}
+       */
+      this.ownerId = data.owner_id;
+    } else {
+      this.ownerId ??= null;
+    }
+
+    if ('last_message_id' in data) {
+      /**
+       * The last message id sent in this thread, if one was sent
+       * @type {?Snowflake}
+       */
+      this.lastMessageId = data.last_message_id;
+    } else {
+      this.lastMessageId ??= null;
+    }
+
+    if ('last_pin_timestamp' in data) {
+      /**
+       * The timestamp when the last pinned message was pinned, if there was one
+       * @type {?number}
+       */
+      this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;
+    } else {
+      this.lastPinTimestamp ??= null;
+    }
+
+    if ('rate_limit_per_user' in data) {
+      /**
+       * The rate limit per user (slowmode) for this thread in seconds
+       * @type {?number}
+       */
+      this.rateLimitPerUser = data.rate_limit_per_user ?? 0;
+    } else {
+      this.rateLimitPerUser ??= null;
+    }
+
+    if ('message_count' in data) {
+      /**
+       * The approximate count of messages in this thread
+       * <info>Threads created before July 1, 2022 may have an inaccurate count.
+       * If you need an approximate value higher than that, use `ThreadChannel#messages.cache.size`</info>
+       * @type {?number}
+       */
+      this.messageCount = data.message_count;
+    } else {
+      this.messageCount ??= null;
+    }
+
+    if ('member_count' in data) {
+      /**
+       * The approximate count of users in this thread
+       * <info>This stops counting at 50. If you need an approximate value higher than that, use
+       * `ThreadChannel#members.cache.size`</info>
+       * @type {?number}
+       */
+      this.memberCount = data.member_count;
+    } else {
+      this.memberCount ??= null;
+    }
+
+    if ('total_message_sent' in data) {
+      /**
+       * The number of messages ever sent in a thread, similar to {@link ThreadChannel#messageCount} except it
+       * will not decrement whenever a message is deleted
+       * @type {?number}
+       */
+      this.totalMessageSent = data.total_message_sent;
+    } else {
+      this.totalMessageSent ??= null;
+    }
+
+    if (data.member && this.client.user) this.members._add({ user_id: this.client.user.id, ...data.member });
+    if (data.messages) for (const message of data.messages) this.messages._add(message);
+
+    if ('applied_tags' in data) {
+      /**
+       * The tags applied to this thread
+       * @type {Snowflake[]}
+       */
+      this.appliedTags = data.applied_tags;
+    } else {
+      this.appliedTags ??= [];
+    }
+  }
+
+  /**
+   * The timestamp when this thread was created. This isn't available for threads
+   * created before 2022-01-09
+   * @type {?number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return this._createdTimestamp;
+  }
+
+  /**
+   * A collection of associated guild member objects of this thread's members
+   * @type {Collection<Snowflake, GuildMember>}
+   * @readonly
+   */
+  get guildMembers() {
+    return this.members.cache.mapValues(member => member.guildMember);
+  }
+
+  /**
+   * The time at which this thread's archive status was last changed
+   * <info>If the thread was never archived or unarchived, this is the time at which the thread was created</info>
+   * @type {?Date}
+   * @readonly
+   */
+  get archivedAt() {
+    return this.archiveTimestamp && new Date(this.archiveTimestamp);
+  }
+
+  /**
+   * The time the thread was created at
+   * @type {?Date}
+   * @readonly
+   */
+  get createdAt() {
+    return this.createdTimestamp && new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The parent channel of this thread
+   * @type {?(NewsChannel|TextChannel|ForumChannel)}
+   * @readonly
+   */
+  get parent() {
+    return this.guild.channels.resolve(this.parentId);
+  }
+
+  /**
+   * Makes the client user join the thread.
+   * @returns {Promise<ThreadChannel>}
+   */
+  async join() {
+    await this.members.add('@me');
+    return this;
+  }
+
+  /**
+   * Makes the client user leave the thread.
+   * @returns {Promise<ThreadChannel>}
+   */
+  async leave() {
+    await this.members.remove('@me');
+    return this;
+  }
+
+  /**
+   * Gets the overall set of permissions for a member or role in this thread's parent channel, taking overwrites into
+   * account.
+   * @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for
+   * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission
+   * will return all permissions
+   * @returns {?Readonly<PermissionsBitField>}
+   */
+  permissionsFor(memberOrRole, checkAdmin) {
+    return this.parent?.permissionsFor(memberOrRole, checkAdmin) ?? null;
+  }
+
+  /**
+   * Fetches the owner of this thread. If the thread member object isn't needed,
+   * use {@link ThreadChannel#ownerId} instead.
+   * @param {BaseFetchOptions} [options] The options for fetching the member
+   * @returns {Promise<?ThreadMember>}
+   */
+  async fetchOwner({ cache = true, force = false } = {}) {
+    if (!force) {
+      const existing = this.members.cache.get(this.ownerId);
+      if (existing) return existing;
+    }
+
+    // We cannot fetch a single thread member, as of this commit's date, Discord API responds with 405
+    const members = await this.members.fetch({ cache });
+    return members.get(this.ownerId) ?? null;
+  }
+
+  /**
+   * Fetches the message that started this thread, if any.
+   * <info>The `Promise` will reject if the original message in a forum post is deleted
+   * or when the original message in the parent channel is deleted.
+   * If you just need the id of that message, use {@link ThreadChannel#id} instead.</info>
+   * @param {BaseFetchOptions} [options] Additional options for this fetch
+   * @returns {Promise<Message<true>|null>}
+   */
+  // eslint-disable-next-line require-await
+  async fetchStarterMessage(options) {
+    const channel = this.parent?.type === ChannelType.GuildForum ? this : this.parent;
+    return channel?.messages.fetch({ message: this.id, ...options }) ?? null;
+  }
+
+  /**
+   * The options used to edit a thread channel
+   * @typedef {Object} ThreadEditOptions
+   * @property {string} [name] The new name for the thread
+   * @property {boolean} [archived] Whether the thread is archived
+   * @property {ThreadAutoArchiveDuration} [autoArchiveDuration] The amount of time after which the thread
+   * should automatically archive in case of no recent activity
+   * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds
+   * @property {boolean} [locked] Whether the thread is locked
+   * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to a thread
+   * <info>Can only be edited on {@link ChannelType.PrivateThread}</info>
+   * @property {Snowflake[]} [appliedTags] The tags to apply to the thread
+   * @property {ChannelFlagsResolvable} [flags] The flags to set on the channel
+   * @property {string} [reason] Reason for editing the thread
+   */
+
+  /**
+   * Edits this thread.
+   * @param {ThreadEditOptions} options The options to provide
+   * @returns {Promise<ThreadChannel>}
+   * @example
+   * // Edit a thread
+   * thread.edit({ name: 'new-thread' })
+   *   .then(editedThread => console.log(editedThread))
+   *   .catch(console.error);
+   */
+  async edit(options) {
+    const newData = await this.client.rest.patch(Routes.channel(this.id), {
+      body: {
+        name: (options.name ?? this.name).trim(),
+        archived: options.archived,
+        auto_archive_duration: options.autoArchiveDuration,
+        rate_limit_per_user: options.rateLimitPerUser,
+        locked: options.locked,
+        invitable: this.type === ChannelType.PrivateThread ? options.invitable : undefined,
+        applied_tags: options.appliedTags,
+        flags: 'flags' in options ? ChannelFlagsBitField.resolve(options.flags) : undefined,
+      },
+      reason: options.reason,
+    });
+
+    return this.client.actions.ChannelUpdate.handle(newData).updated;
+  }
+
+  /**
+   * Sets whether the thread is archived.
+   * @param {boolean} [archived=true] Whether the thread is archived
+   * @param {string} [reason] Reason for archiving or unarchiving
+   * @returns {Promise<ThreadChannel>}
+   * @example
+   * // Archive the thread
+   * thread.setArchived(true)
+   *   .then(newThread => console.log(`Thread is now ${newThread.archived ? 'archived' : 'active'}`))
+   *   .catch(console.error);
+   */
+  setArchived(archived = true, reason) {
+    return this.edit({ archived, reason });
+  }
+
+  /**
+   * Sets the duration after which the thread will automatically archive in case of no recent activity.
+   * @param {ThreadAutoArchiveDuration} autoArchiveDuration The amount of time after which the thread
+   * should automatically archive in case of no recent activity
+   * @param {string} [reason] Reason for changing the auto archive duration
+   * @returns {Promise<ThreadChannel>}
+   * @example
+   * // Set the thread's auto archive time to 1 hour
+   * thread.setAutoArchiveDuration(ThreadAutoArchiveDuration.OneHour)
+   *   .then(newThread => {
+   *     console.log(`Thread will now archive after ${newThread.autoArchiveDuration} minutes of inactivity`);
+   *    });
+   *   .catch(console.error);
+   */
+  setAutoArchiveDuration(autoArchiveDuration, reason) {
+    return this.edit({ autoArchiveDuration, reason });
+  }
+
+  /**
+   * Sets whether members without the {@link PermissionFlagsBits.ManageThreads} permission
+   * can invite other members to this thread.
+   * @param {boolean} [invitable=true] Whether non-moderators can invite non-moderators to this thread
+   * @param {string} [reason] Reason for changing invite
+   * @returns {Promise<ThreadChannel>}
+   */
+  setInvitable(invitable = true, reason) {
+    if (this.type !== ChannelType.PrivateThread) {
+      return Promise.reject(new DiscordjsRangeError(ErrorCodes.ThreadInvitableType, this.type));
+    }
+    return this.edit({ invitable, reason });
+  }
+
+  /**
+   * Sets whether the thread can be **unarchived** by anyone with the
+   * {@link PermissionFlagsBits.SendMessages} permission. When a thread is locked, only members with the
+   * {@link PermissionFlagsBits.ManageThreads} permission can unarchive it.
+   * @param {boolean} [locked=true] Whether the thread is locked
+   * @param {string} [reason] Reason for locking or unlocking the thread
+   * @returns {Promise<ThreadChannel>}
+   * @example
+   * // Set the thread to locked
+   * thread.setLocked(true)
+   *   .then(newThread => console.log(`Thread is now ${newThread.locked ? 'locked' : 'unlocked'}`))
+   *   .catch(console.error);
+   */
+  setLocked(locked = true, reason) {
+    return this.edit({ locked, reason });
+  }
+
+  /**
+   * Sets a new name for this thread.
+   * @param {string} name The new name for the thread
+   * @param {string} [reason] Reason for changing the thread's name
+   * @returns {Promise<ThreadChannel>}
+   * @example
+   * // Change the thread's name
+   * thread.setName('not_general')
+   *   .then(newThread => console.log(`Thread's new name is ${newThread.name}`))
+   *   .catch(console.error);
+   */
+  setName(name, reason) {
+    return this.edit({ name, reason });
+  }
+
+  /**
+   * Sets the rate limit per user (slowmode) for this thread.
+   * @param {number} rateLimitPerUser The new rate limit in seconds
+   * @param {string} [reason] Reason for changing the thread's rate limit
+   * @returns {Promise<ThreadChannel>}
+   */
+  setRateLimitPerUser(rateLimitPerUser, reason) {
+    return this.edit({ rateLimitPerUser, reason });
+  }
+
+  /**
+   * Set the applied tags for this channel (only applicable to forum threads)
+   * @param {Snowflake[]} appliedTags The tags to set for this channel
+   * @param {string} [reason] Reason for changing the thread's applied tags
+   * @returns {Promise<ThreadChannel>}
+   */
+  setAppliedTags(appliedTags, reason) {
+    return this.edit({ appliedTags, reason });
+  }
+
+  /**
+   * Pins this thread from the forum channel (only applicable to forum threads).
+   * @param {string} [reason] Reason for pinning
+   * @returns {Promise<ThreadChannel>}
+   */
+  pin(reason) {
+    return this.edit({ flags: this.flags.add(ChannelFlags.Pinned), reason });
+  }
+
+  /**
+   * Unpins this thread from the forum channel (only applicable to forum threads).
+   * @param {string} [reason] Reason for unpinning
+   * @returns {Promise<ThreadChannel>}
+   */
+  unpin(reason) {
+    return this.edit({ flags: this.flags.remove(ChannelFlags.Pinned), reason });
+  }
+
+  /**
+   * Whether the client user is a member of the thread.
+   * @type {boolean}
+   * @readonly
+   */
+  get joined() {
+    return this.members.cache.has(this.client.user?.id);
+  }
+
+  /**
+   * Whether the thread is editable by the client user (name, archived, autoArchiveDuration)
+   * @type {boolean}
+   * @readonly
+   */
+  get editable() {
+    return (
+      (this.ownerId === this.client.user.id && (this.type !== ChannelType.PrivateThread || this.joined)) ||
+      this.manageable
+    );
+  }
+
+  /**
+   * Whether the thread is joinable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get joinable() {
+    return (
+      !this.archived &&
+      !this.joined &&
+      this.permissionsFor(this.client.user)?.has(
+        this.type === ChannelType.PrivateThread ? PermissionFlagsBits.ManageThreads : PermissionFlagsBits.ViewChannel,
+        false,
+      )
+    );
+  }
+
+  /**
+   * Whether the thread is manageable by the client user, for deleting or editing rateLimitPerUser or locked.
+   * @type {boolean}
+   * @readonly
+   */
+  get manageable() {
+    const permissions = this.permissionsFor(this.client.user);
+    if (!permissions) return false;
+    // This flag allows managing even if timed out
+    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;
+
+    return (
+      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() &&
+      permissions.has(PermissionFlagsBits.ManageThreads, false)
+    );
+  }
+
+  /**
+   * Whether the thread is viewable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get viewable() {
+    if (this.client.user.id === this.guild.ownerId) return true;
+    const permissions = this.permissionsFor(this.client.user);
+    if (!permissions) return false;
+    return permissions.has(PermissionFlagsBits.ViewChannel, false);
+  }
+
+  /**
+   * Whether the client user can send messages in this thread
+   * @type {boolean}
+   * @readonly
+   */
+  get sendable() {
+    const permissions = this.permissionsFor(this.client.user);
+    if (!permissions) return false;
+    // This flag allows sending even if timed out
+    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;
+
+    return (
+      !(this.archived && this.locked && !this.manageable) &&
+      (this.type !== ChannelType.PrivateThread || this.joined || this.manageable) &&
+      permissions.has(PermissionFlagsBits.SendMessagesInThreads, false) &&
+      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()
+    );
+  }
+
+  /**
+   * Whether the thread is unarchivable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get unarchivable() {
+    return this.archived && this.sendable && (!this.locked || this.manageable);
+  }
+
+  /**
+   * Deletes this thread.
+   * @param {string} [reason] Reason for deleting this thread
+   * @returns {Promise<ThreadChannel>}
+   * @example
+   * // Delete the thread
+   * thread.delete('cleaning out old threads')
+   *   .then(deletedThread => console.log(deletedThread))
+   *   .catch(console.error);
+   */
+  async delete(reason) {
+    await this.guild.channels.delete(this.id, reason);
+    return this;
+  }
+
+  // These are here only for documentation purposes - they are implemented by TextBasedChannel
+  /* eslint-disable no-empty-function */
+  get lastMessage() {}
+  get lastPinAt() {}
+  send() {}
+  sendTyping() {}
+  createMessageCollector() {}
+  awaitMessages() {}
+  createMessageComponentCollector() {}
+  awaitMessageComponent() {}
+  bulkDelete() {}
+  // Doesn't work on Thread channels; setRateLimitPerUser() {}
+  // Doesn't work on Thread channels; setNSFW() {}
+}
+
+TextBasedChannel.applyToClass(ThreadChannel, true, ['fetchWebhooks', 'setRateLimitPerUser', 'setNSFW']);
+
+module.exports = ThreadChannel;
diff --git a/node_modules/discord.js/src/structures/ThreadMember.js b/node_modules/discord.js/src/structures/ThreadMember.js
new file mode 100644
index 0000000..fc79dd0
--- /dev/null
+++ b/node_modules/discord.js/src/structures/ThreadMember.js
@@ -0,0 +1,113 @@
+'use strict';
+
+const Base = require('./Base');
+const ThreadMemberFlagsBitField = require('../util/ThreadMemberFlagsBitField');
+
+/**
+ * Represents a Member for a Thread.
+ * @extends {Base}
+ */
+class ThreadMember extends Base {
+  constructor(thread, data, extra = {}) {
+    super(thread.client);
+
+    /**
+     * The thread that this member is a part of
+     * @type {ThreadChannel}
+     */
+    this.thread = thread;
+
+    /**
+     * The timestamp the member last joined the thread at
+     * @type {?number}
+     */
+    this.joinedTimestamp = null;
+
+    /**
+     * The flags for this thread member. This will be `null` if partial.
+     * @type {?ThreadMemberFlagsBitField}
+     */
+    this.flags = null;
+
+    /**
+     * The id of the thread member
+     * @type {Snowflake}
+     */
+    this.id = data.user_id;
+
+    this._patch(data, extra);
+  }
+
+  _patch(data, extra = {}) {
+    if ('join_timestamp' in data) this.joinedTimestamp = Date.parse(data.join_timestamp);
+    if ('flags' in data) this.flags = new ThreadMemberFlagsBitField(data.flags).freeze();
+
+    if ('member' in data) {
+      /**
+       * The guild member associated with this thread member.
+       * @type {?GuildMember}
+       * @private
+       */
+      this.member = this.thread.guild.members._add(data.member, extra.cache);
+    } else {
+      this.member ??= null;
+    }
+  }
+
+  /**
+   * Whether this thread member is a partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return this.flags === null;
+  }
+
+  /**
+   * The guild member associated with this thread member
+   * @type {?GuildMember}
+   * @readonly
+   */
+  get guildMember() {
+    return this.member ?? this.thread.guild.members.resolve(this.id);
+  }
+
+  /**
+   * The last time this member joined the thread
+   * @type {?Date}
+   * @readonly
+   */
+  get joinedAt() {
+    return this.joinedTimestamp && new Date(this.joinedTimestamp);
+  }
+
+  /**
+   * The user associated with this thread member
+   * @type {?User}
+   * @readonly
+   */
+  get user() {
+    return this.client.users.resolve(this.id);
+  }
+
+  /**
+   * Whether the client user can manage this thread member
+   * @type {boolean}
+   * @readonly
+   */
+  get manageable() {
+    return !this.thread.archived && this.thread.editable;
+  }
+
+  /**
+   * Removes this member from the thread.
+   * @param {string} [reason] Reason for removing the member
+   * @returns {ThreadMember}
+   */
+  async remove(reason) {
+    await this.thread.members.remove(this.id, reason);
+    return this;
+  }
+}
+
+module.exports = ThreadMember;
diff --git a/node_modules/discord.js/src/structures/Typing.js b/node_modules/discord.js/src/structures/Typing.js
new file mode 100644
index 0000000..341d7ca
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Typing.js
@@ -0,0 +1,74 @@
+'use strict';
+
+const Base = require('./Base');
+
+/**
+ * Represents a typing state for a user in a channel.
+ * @extends {Base}
+ */
+class Typing extends Base {
+  constructor(channel, user, data) {
+    super(channel.client);
+
+    /**
+     * The channel the status is from
+     * @type {TextBasedChannels}
+     */
+    this.channel = channel;
+
+    /**
+     * The user who is typing
+     * @type {User}
+     */
+    this.user = user;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('timestamp' in data) {
+      /**
+       * The UNIX timestamp in milliseconds the user started typing at
+       * @type {number}
+       */
+      this.startedTimestamp = data.timestamp * 1_000;
+    }
+  }
+
+  /**
+   * Indicates whether the status is received from a guild.
+   * @returns {boolean}
+   */
+  inGuild() {
+    return this.guild !== null;
+  }
+
+  /**
+   * The time the user started typing at
+   * @type {Date}
+   * @readonly
+   */
+  get startedAt() {
+    return new Date(this.startedTimestamp);
+  }
+
+  /**
+   * The guild the status is from
+   * @type {?Guild}
+   * @readonly
+   */
+  get guild() {
+    return this.channel.guild ?? null;
+  }
+
+  /**
+   * The member who is typing
+   * @type {?GuildMember}
+   * @readonly
+   */
+  get member() {
+    return this.guild?.members.resolve(this.user) ?? null;
+  }
+}
+
+module.exports = Typing;
diff --git a/node_modules/discord.js/src/structures/User.js b/node_modules/discord.js/src/structures/User.js
new file mode 100644
index 0000000..4e38d2d
--- /dev/null
+++ b/node_modules/discord.js/src/structures/User.js
@@ -0,0 +1,380 @@
+'use strict';
+
+const { userMention } = require('@discordjs/builders');
+const { calculateUserDefaultAvatarIndex } = require('@discordjs/rest');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const Base = require('./Base');
+const TextBasedChannel = require('./interfaces/TextBasedChannel');
+const UserFlagsBitField = require('../util/UserFlagsBitField');
+
+/**
+ * Represents a user on Discord.
+ * @implements {TextBasedChannel}
+ * @extends {Base}
+ */
+class User extends Base {
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The user's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    this.bot = null;
+
+    this.system = null;
+
+    this.flags = null;
+
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('username' in data) {
+      /**
+       * The username of the user
+       * @type {?string}
+       */
+      this.username = data.username;
+    } else {
+      this.username ??= null;
+    }
+
+    if ('global_name' in data) {
+      /**
+       * The global name of this user
+       * @type {?string}
+       */
+      this.globalName = data.global_name;
+    } else {
+      this.globalName ??= null;
+    }
+
+    if ('bot' in data) {
+      /**
+       * Whether or not the user is a bot
+       * @type {?boolean}
+       */
+      this.bot = Boolean(data.bot);
+    } else if (!this.partial && typeof this.bot !== 'boolean') {
+      this.bot = false;
+    }
+
+    if ('discriminator' in data) {
+      /**
+       * The discriminator of this user
+       * <info>`'0'`, or a 4-digit stringified number if they're using the legacy username system</info>
+       * @type {?string}
+       */
+      this.discriminator = data.discriminator;
+    } else {
+      this.discriminator ??= null;
+    }
+
+    if ('avatar' in data) {
+      /**
+       * The user avatar's hash
+       * @type {?string}
+       */
+      this.avatar = data.avatar;
+    } else {
+      this.avatar ??= null;
+    }
+
+    if ('banner' in data) {
+      /**
+       * The user banner's hash
+       * <info>The user must be force fetched for this property to be present or be updated</info>
+       * @type {?string}
+       */
+      this.banner = data.banner;
+    } else if (this.banner !== null) {
+      this.banner ??= undefined;
+    }
+
+    if ('accent_color' in data) {
+      /**
+       * The base 10 accent color of the user's banner
+       * <info>The user must be force fetched for this property to be present or be updated</info>
+       * @type {?number}
+       */
+      this.accentColor = data.accent_color;
+    } else if (this.accentColor !== null) {
+      this.accentColor ??= undefined;
+    }
+
+    if ('system' in data) {
+      /**
+       * Whether the user is an Official Discord System user (part of the urgent message system)
+       * @type {?boolean}
+       */
+      this.system = Boolean(data.system);
+    } else if (!this.partial && typeof this.system !== 'boolean') {
+      this.system = false;
+    }
+
+    if ('public_flags' in data) {
+      /**
+       * The flags for this user
+       * @type {?UserFlagsBitField}
+       */
+      this.flags = new UserFlagsBitField(data.public_flags);
+    }
+
+    if ('avatar_decoration' in data) {
+      /**
+       * The user avatar decoration's hash
+       * @type {?string}
+       */
+      this.avatarDecoration = data.avatar_decoration;
+    } else {
+      this.avatarDecoration ??= null;
+    }
+  }
+
+  /**
+   * Whether this User is a partial
+   * @type {boolean}
+   * @readonly
+   */
+  get partial() {
+    return typeof this.username !== 'string';
+  }
+
+  /**
+   * The timestamp the user was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the user was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * A link to the user's avatar.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  avatarURL(options = {}) {
+    return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options);
+  }
+
+  /**
+   * A link to the user's avatar decoration.
+   * @param {BaseImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  avatarDecorationURL(options = {}) {
+    return this.avatarDecoration && this.client.rest.cdn.avatarDecoration(this.id, this.avatarDecoration, options);
+  }
+
+  /**
+   * A link to the user's default avatar
+   * @type {string}
+   * @readonly
+   */
+  get defaultAvatarURL() {
+    const index = this.discriminator === '0' ? calculateUserDefaultAvatarIndex(this.id) : this.discriminator % 5;
+    return this.client.rest.cdn.defaultAvatar(index);
+  }
+
+  /**
+   * A link to the user's avatar if they have one.
+   * Otherwise a link to their default avatar will be returned.
+   * @param {ImageURLOptions} [options={}] Options for the Image URL
+   * @returns {string}
+   */
+  displayAvatarURL(options) {
+    return this.avatarURL(options) ?? this.defaultAvatarURL;
+  }
+
+  /**
+   * The hexadecimal version of the user accent color, with a leading hash
+   * <info>The user must be force fetched for this property to be present</info>
+   * @type {?string}
+   * @readonly
+   */
+  get hexAccentColor() {
+    if (typeof this.accentColor !== 'number') return this.accentColor;
+    return `#${this.accentColor.toString(16).padStart(6, '0')}`;
+  }
+
+  /**
+   * A link to the user's banner. See {@link User#banner} for more info
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  bannerURL(options = {}) {
+    return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);
+  }
+
+  /**
+   * The tag of this user
+   * <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
+   * if they're using the legacy username system</info>
+   * @type {?string}
+   * @readonly
+   */
+  get tag() {
+    return typeof this.username === 'string'
+      ? this.discriminator === '0'
+        ? this.username
+        : `${this.username}#${this.discriminator}`
+      : null;
+  }
+
+  /**
+   * The global name of this user, or their username if they don't have one
+   * @type {?string}
+   * @readonly
+   */
+  get displayName() {
+    return this.globalName ?? this.username;
+  }
+
+  /**
+   * The DM between the client's user and this user
+   * @type {?DMChannel}
+   * @readonly
+   */
+  get dmChannel() {
+    return this.client.users.dmChannel(this.id);
+  }
+
+  /**
+   * Creates a DM channel between the client and the user.
+   * @param {boolean} [force=false] Whether to skip the cache check and request the API
+   * @returns {Promise<DMChannel>}
+   */
+  createDM(force = false) {
+    return this.client.users.createDM(this.id, { force });
+  }
+
+  /**
+   * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful.
+   * @returns {Promise<DMChannel>}
+   */
+  deleteDM() {
+    return this.client.users.deleteDM(this.id);
+  }
+
+  /**
+   * Checks if the user is equal to another.
+   * It compares id, username, discriminator, avatar, banner, accent color, and bot flags.
+   * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties.
+   * @param {User} user User to compare with
+   * @returns {boolean}
+   */
+  equals(user) {
+    return (
+      user &&
+      this.id === user.id &&
+      this.username === user.username &&
+      this.discriminator === user.discriminator &&
+      this.globalName === user.globalName &&
+      this.avatar === user.avatar &&
+      this.flags?.bitfield === user.flags?.bitfield &&
+      this.banner === user.banner &&
+      this.accentColor === user.accentColor
+    );
+  }
+
+  /**
+   * Compares the user with an API user object
+   * @param {APIUser} user The API user object to compare
+   * @returns {boolean}
+   * @private
+   */
+  _equals(user) {
+    return (
+      user &&
+      this.id === user.id &&
+      this.username === user.username &&
+      this.discriminator === user.discriminator &&
+      this.globalName === user.global_name &&
+      this.avatar === user.avatar &&
+      this.flags?.bitfield === user.public_flags &&
+      ('banner' in user ? this.banner === user.banner : true) &&
+      ('accent_color' in user ? this.accentColor === user.accent_color : true)
+    );
+  }
+
+  /**
+   * Fetches this user's flags.
+   * @param {boolean} [force=false] Whether to skip the cache check and request the API
+   * @returns {Promise<UserFlagsBitField>}
+   */
+  fetchFlags(force = false) {
+    return this.client.users.fetchFlags(this.id, { force });
+  }
+
+  /**
+   * Fetches this user.
+   * @param {boolean} [force=true] Whether to skip the cache check and request the API
+   * @returns {Promise<User>}
+   */
+  fetch(force = true) {
+    return this.client.users.fetch(this.id, { force });
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the user's mention instead of the User object.
+   * @returns {string}
+   * @example
+   * // Logs: Hello from <@123456789012345678>!
+   * console.log(`Hello from ${user}!`);
+   */
+  toString() {
+    return userMention(this.id);
+  }
+
+  toJSON(...props) {
+    const json = super.toJSON(
+      {
+        createdTimestamp: true,
+        defaultAvatarURL: true,
+        hexAccentColor: true,
+        tag: true,
+      },
+      ...props,
+    );
+    json.avatarURL = this.avatarURL();
+    json.displayAvatarURL = this.displayAvatarURL();
+    json.bannerURL = this.banner ? this.bannerURL() : this.banner;
+    return json;
+  }
+}
+
+/**
+ * Sends a message to this user.
+ * @method send
+ * @memberof User
+ * @instance
+ * @param {string|MessagePayload|MessageCreateOptions} options The options to provide
+ * @returns {Promise<Message>}
+ * @example
+ * // Send a direct message
+ * user.send('Hello!')
+ *   .then(message => console.log(`Sent message: ${message.content} to ${user.tag}`))
+ *   .catch(console.error);
+ */
+
+TextBasedChannel.applyToClass(User);
+
+module.exports = User;
+
+/**
+ * @external APIUser
+ * @see {@link https://discord.com/developers/docs/resources/user#user-object}
+ */
diff --git a/node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js b/node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js
new file mode 100644
index 0000000..2e9dc7c
--- /dev/null
+++ b/node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const ContextMenuCommandInteraction = require('./ContextMenuCommandInteraction');
+
+/**
+ * Represents a user context menu interaction.
+ * @extends {ContextMenuCommandInteraction}
+ */
+class UserContextMenuCommandInteraction extends ContextMenuCommandInteraction {
+  /**
+   * The target user from this interaction
+   * @type {User}
+   * @readonly
+   */
+  get targetUser() {
+    return this.options.getUser('user');
+  }
+
+  /**
+   * The target member from this interaction
+   * @type {?(GuildMember|APIGuildMember)}
+   * @readonly
+   */
+  get targetMember() {
+    return this.options.getMember('user');
+  }
+}
+
+module.exports = UserContextMenuCommandInteraction;
diff --git a/node_modules/discord.js/src/structures/UserSelectMenuBuilder.js b/node_modules/discord.js/src/structures/UserSelectMenuBuilder.js
new file mode 100644
index 0000000..61bdbb8
--- /dev/null
+++ b/node_modules/discord.js/src/structures/UserSelectMenuBuilder.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const { UserSelectMenuBuilder: BuildersUserSelectMenu } = require('@discordjs/builders');
+const { isJSONEncodable } = require('@discordjs/util');
+const { toSnakeCase } = require('../util/Transformers');
+
+/**
+ * Class used to build select menu components to be sent through the API
+ * @extends {BuildersUserSelectMenu}
+ */
+class UserSelectMenuBuilder extends BuildersUserSelectMenu {
+  constructor(data = {}) {
+    super(toSnakeCase(data));
+  }
+
+  /**
+   * Creates a new select menu builder from JSON data
+   * @param {UserSelectMenuBuilder|UserSelectMenuComponent|APIUserSelectComponent} other The other data
+   * @returns {UserSelectMenuBuilder}
+   */
+  static from(other) {
+    return new this(isJSONEncodable(other) ? other.toJSON() : other);
+  }
+}
+
+module.exports = UserSelectMenuBuilder;
+
+/**
+ * @external BuildersUserSelectMenu
+ * @see {@link https://discord.js.org/docs/packages/builders/stable/UserSelectMenuBuilder:Class}
+ */
diff --git a/node_modules/discord.js/src/structures/UserSelectMenuComponent.js b/node_modules/discord.js/src/structures/UserSelectMenuComponent.js
new file mode 100644
index 0000000..0acacdf
--- /dev/null
+++ b/node_modules/discord.js/src/structures/UserSelectMenuComponent.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
+
+/**
+ * Represents a user select menu component
+ * @extends {BaseSelectMenuComponent}
+ */
+class UserSelectMenuComponent extends BaseSelectMenuComponent {}
+
+module.exports = UserSelectMenuComponent;
diff --git a/node_modules/discord.js/src/structures/UserSelectMenuInteraction.js b/node_modules/discord.js/src/structures/UserSelectMenuInteraction.js
new file mode 100644
index 0000000..5e23239
--- /dev/null
+++ b/node_modules/discord.js/src/structures/UserSelectMenuInteraction.js
@@ -0,0 +1,51 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const MessageComponentInteraction = require('./MessageComponentInteraction');
+const Events = require('../util/Events');
+
+/**
+ * Represents a {@link ComponentType.UserSelect} select menu interaction.
+ * @extends {MessageComponentInteraction}
+ */
+class UserSelectMenuInteraction extends MessageComponentInteraction {
+  constructor(client, data) {
+    super(client, data);
+    const { resolved, values } = data.data;
+
+    /**
+     * An array of the selected user ids
+     * @type {Snowflake[]}
+     */
+    this.values = values ?? [];
+
+    /**
+     * Collection of the selected users
+     * @type {Collection<Snowflake, User>}
+     */
+    this.users = new Collection();
+
+    /**
+     * Collection of the selected members
+     * @type {Collection<Snowflake, GuildMember|APIGuildMember>}
+     */
+    this.members = new Collection();
+
+    for (const user of Object.values(resolved?.users ?? {})) {
+      this.users.set(user.id, this.client.users._add(user));
+    }
+
+    for (const [id, member] of Object.entries(resolved?.members ?? {})) {
+      const user = resolved.users[id];
+
+      if (!user) {
+        this.client.emit(Events.Debug, `[UserSelectMenuInteraction] Received a member without a user, skipping ${id}`);
+        continue;
+      }
+
+      this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member });
+    }
+  }
+}
+
+module.exports = UserSelectMenuInteraction;
diff --git a/node_modules/discord.js/src/structures/VoiceChannel.js b/node_modules/discord.js/src/structures/VoiceChannel.js
new file mode 100644
index 0000000..d4f33ca
--- /dev/null
+++ b/node_modules/discord.js/src/structures/VoiceChannel.js
@@ -0,0 +1,96 @@
+'use strict';
+
+const { PermissionFlagsBits } = require('discord-api-types/v10');
+const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel');
+
+/**
+ * Represents a guild voice channel on Discord.
+ * @extends {BaseGuildVoiceChannel}
+ */
+class VoiceChannel extends BaseGuildVoiceChannel {
+  /**
+   * Whether the channel is joinable by the client user
+   * @type {boolean}
+   * @readonly
+   */
+  get joinable() {
+    if (!super.joinable) return false;
+    if (this.full && !this.permissionsFor(this.client.user).has(PermissionFlagsBits.MoveMembers, false)) return false;
+    return true;
+  }
+
+  /**
+   * Checks if the client has permission to send audio to the voice channel
+   * @type {boolean}
+   * @readonly
+   */
+  get speakable() {
+    const permissions = this.permissionsFor(this.client.user);
+    if (!permissions) return false;
+    // This flag allows speaking even if timed out
+    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;
+
+    return (
+      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() &&
+      permissions.has(PermissionFlagsBits.Speak, false)
+    );
+  }
+}
+
+/**
+ * Sets the bitrate of the channel.
+ * @method setBitrate
+ * @memberof VoiceChannel
+ * @instance
+ * @param {number} bitrate The new bitrate
+ * @param {string} [reason] Reason for changing the channel's bitrate
+ * @returns {Promise<VoiceChannel>}
+ * @example
+ * // Set the bitrate of a voice channel
+ * voiceChannel.setBitrate(48_000)
+ *   .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`))
+ *   .catch(console.error);
+ */
+
+/**
+ * Sets the RTC region of the channel.
+ * @method setRTCRegion
+ * @memberof VoiceChannel
+ * @instance
+ * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
+ * @param {string} [reason] The reason for modifying this region.
+ * @returns {Promise<VoiceChannel>}
+ * @example
+ * // Set the RTC region to sydney
+ * voiceChannel.setRTCRegion('sydney');
+ * @example
+ * // Remove a fixed region for this channel - let Discord decide automatically
+ * voiceChannel.setRTCRegion(null, 'We want to let Discord decide.');
+ */
+
+/**
+ * Sets the user limit of the channel.
+ * @method setUserLimit
+ * @memberof VoiceChannel
+ * @instance
+ * @param {number} userLimit The new user limit
+ * @param {string} [reason] Reason for changing the user limit
+ * @returns {Promise<VoiceChannel>}
+ * @example
+ * // Set the user limit of a voice channel
+ * voiceChannel.setUserLimit(42)
+ *   .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`))
+ *   .catch(console.error);
+ */
+
+/**
+ * Sets the camera video quality mode of the channel.
+ * @method setVideoQualityMode
+ * @memberof VoiceChannel
+ * @instance
+ * @param {VideoQualityMode} videoQualityMode The new camera video quality mode.
+ * @param {string} [reason] Reason for changing the camera video quality mode.
+ * @returns {Promise<VoiceChannel>}
+ */
+
+module.exports = VoiceChannel;
diff --git a/node_modules/discord.js/src/structures/VoiceRegion.js b/node_modules/discord.js/src/structures/VoiceRegion.js
new file mode 100644
index 0000000..1f5652a
--- /dev/null
+++ b/node_modules/discord.js/src/structures/VoiceRegion.js
@@ -0,0 +1,46 @@
+'use strict';
+
+const { flatten } = require('../util/Util');
+
+/**
+ * Represents a Discord voice region for guilds.
+ */
+class VoiceRegion {
+  constructor(data) {
+    /**
+     * The region's id
+     * @type {string}
+     */
+    this.id = data.id;
+
+    /**
+     * Name of the region
+     * @type {string}
+     */
+    this.name = data.name;
+
+    /**
+     * Whether the region is deprecated
+     * @type {boolean}
+     */
+    this.deprecated = data.deprecated;
+
+    /**
+     * Whether the region is optimal
+     * @type {boolean}
+     */
+    this.optimal = data.optimal;
+
+    /**
+     * Whether the region is custom
+     * @type {boolean}
+     */
+    this.custom = data.custom;
+  }
+
+  toJSON() {
+    return flatten(this);
+  }
+}
+
+module.exports = VoiceRegion;
diff --git a/node_modules/discord.js/src/structures/VoiceState.js b/node_modules/discord.js/src/structures/VoiceState.js
new file mode 100644
index 0000000..ae510f2
--- /dev/null
+++ b/node_modules/discord.js/src/structures/VoiceState.js
@@ -0,0 +1,303 @@
+'use strict';
+
+const { ChannelType, Routes } = require('discord-api-types/v10');
+const Base = require('./Base');
+const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
+
+/**
+ * Represents the voice state for a Guild Member.
+ * @extends {Base}
+ */
+class VoiceState extends Base {
+  constructor(guild, data) {
+    super(guild.client);
+    /**
+     * The guild of this voice state
+     * @type {Guild}
+     */
+    this.guild = guild;
+    /**
+     * The id of the member of this voice state
+     * @type {Snowflake}
+     */
+    this.id = data.user_id;
+    this._patch(data);
+  }
+
+  _patch(data) {
+    if ('deaf' in data) {
+      /**
+       * Whether this member is deafened server-wide
+       * @type {?boolean}
+       */
+      this.serverDeaf = data.deaf;
+    } else {
+      this.serverDeaf ??= null;
+    }
+
+    if ('mute' in data) {
+      /**
+       * Whether this member is muted server-wide
+       * @type {?boolean}
+       */
+      this.serverMute = data.mute;
+    } else {
+      this.serverMute ??= null;
+    }
+
+    if ('self_deaf' in data) {
+      /**
+       * Whether this member is self-deafened
+       * @type {?boolean}
+       */
+      this.selfDeaf = data.self_deaf;
+    } else {
+      this.selfDeaf ??= null;
+    }
+
+    if ('self_mute' in data) {
+      /**
+       * Whether this member is self-muted
+       * @type {?boolean}
+       */
+      this.selfMute = data.self_mute;
+    } else {
+      this.selfMute ??= null;
+    }
+
+    if ('self_video' in data) {
+      /**
+       * Whether this member's camera is enabled
+       * @type {?boolean}
+       */
+      this.selfVideo = data.self_video;
+    } else {
+      this.selfVideo ??= null;
+    }
+
+    if ('session_id' in data) {
+      /**
+       * The session id for this member's connection
+       * @type {?string}
+       */
+      this.sessionId = data.session_id;
+    } else {
+      this.sessionId ??= null;
+    }
+
+    // The self_stream is property is omitted if false, check for another property
+    // here to avoid incorrectly clearing this when partial data is specified
+    if ('self_video' in data) {
+      /**
+       * Whether this member is streaming using "Screen Share"
+       * @type {?boolean}
+       */
+      this.streaming = data.self_stream ?? false;
+    } else {
+      this.streaming ??= null;
+    }
+
+    if ('channel_id' in data) {
+      /**
+       * The {@link VoiceChannel} or {@link StageChannel} id the member is in
+       * @type {?Snowflake}
+       */
+      this.channelId = data.channel_id;
+    } else {
+      this.channelId ??= null;
+    }
+
+    if ('suppress' in data) {
+      /**
+       * Whether this member is suppressed from speaking. This property is specific to stage channels only.
+       * @type {?boolean}
+       */
+      this.suppress = data.suppress;
+    } else {
+      this.suppress ??= null;
+    }
+
+    if ('request_to_speak_timestamp' in data) {
+      /**
+       * The time at which the member requested to speak. This property is specific to stage channels only.
+       * @type {?number}
+       */
+      this.requestToSpeakTimestamp = data.request_to_speak_timestamp && Date.parse(data.request_to_speak_timestamp);
+    } else {
+      this.requestToSpeakTimestamp ??= null;
+    }
+
+    return this;
+  }
+
+  /**
+   * The member that this voice state belongs to
+   * @type {?GuildMember}
+   * @readonly
+   */
+  get member() {
+    return this.guild.members.cache.get(this.id) ?? null;
+  }
+
+  /**
+   * The channel that the member is connected to
+   * @type {?(VoiceChannel|StageChannel)}
+   * @readonly
+   */
+  get channel() {
+    return this.guild.channels.cache.get(this.channelId) ?? null;
+  }
+
+  /**
+   * Whether this member is either self-deafened or server-deafened
+   * @type {?boolean}
+   * @readonly
+   */
+  get deaf() {
+    return this.serverDeaf || this.selfDeaf;
+  }
+
+  /**
+   * Whether this member is either self-muted or server-muted
+   * @type {?boolean}
+   * @readonly
+   */
+  get mute() {
+    return this.serverMute || this.selfMute;
+  }
+
+  /**
+   * Mutes/unmutes the member of this voice state.
+   * @param {boolean} [mute=true] Whether or not the member should be muted
+   * @param {string} [reason] Reason for muting or unmuting
+   * @returns {Promise<GuildMember>}
+   */
+  setMute(mute = true, reason) {
+    return this.guild.members.edit(this.id, { mute, reason });
+  }
+
+  /**
+   * Deafens/undeafens the member of this voice state.
+   * @param {boolean} [deaf=true] Whether or not the member should be deafened
+   * @param {string} [reason] Reason for deafening or undeafening
+   * @returns {Promise<GuildMember>}
+   */
+  setDeaf(deaf = true, reason) {
+    return this.guild.members.edit(this.id, { deaf, reason });
+  }
+
+  /**
+   * Disconnects the member from the channel.
+   * @param {string} [reason] Reason for disconnecting the member from the channel
+   * @returns {Promise<GuildMember>}
+   */
+  disconnect(reason) {
+    return this.setChannel(null, reason);
+  }
+
+  /**
+   * Moves the member to a different channel, or disconnects them from the one they're in.
+   * @param {GuildVoiceChannelResolvable|null} channel Channel to move the member to, or `null` if you want to
+   * disconnect them from voice.
+   * @param {string} [reason] Reason for moving member to another channel or disconnecting
+   * @returns {Promise<GuildMember>}
+   */
+  setChannel(channel, reason) {
+    return this.guild.members.edit(this.id, { channel, reason });
+  }
+
+  /**
+   * Data to edit the logged in user's own voice state with, when in a stage channel
+   * @typedef {Object} VoiceStateEditOptions
+   * @property {boolean} [requestToSpeak] Whether or not the client is requesting to become a speaker.
+   * <info>Only available to the logged in user's own voice state.</info>
+   * @property {boolean} [suppressed] Whether or not the user should be suppressed.
+   */
+
+  /**
+   * Edits this voice state. Currently only available when in a stage channel
+   * @param {VoiceStateEditOptions} options The options to provide
+   * @returns {Promise<VoiceState>}
+   */
+  async edit(options) {
+    if (this.channel?.type !== ChannelType.GuildStageVoice) throw new DiscordjsError(ErrorCodes.VoiceNotStageChannel);
+
+    const target = this.client.user.id === this.id ? '@me' : this.id;
+
+    if (target !== '@me' && options.requestToSpeak !== undefined) {
+      throw new DiscordjsError(ErrorCodes.VoiceStateNotOwn);
+    }
+
+    if (!['boolean', 'undefined'].includes(typeof options.requestToSpeak)) {
+      throw new DiscordjsTypeError(ErrorCodes.VoiceStateInvalidType, 'requestToSpeak');
+    }
+
+    if (!['boolean', 'undefined'].includes(typeof options.suppressed)) {
+      throw new DiscordjsTypeError(ErrorCodes.VoiceStateInvalidType, 'suppressed');
+    }
+
+    await this.client.rest.patch(Routes.guildVoiceState(this.guild.id, target), {
+      body: {
+        channel_id: this.channelId,
+        request_to_speak_timestamp: options.requestToSpeak
+          ? new Date().toISOString()
+          : options.requestToSpeak === false
+          ? null
+          : undefined,
+        suppress: options.suppressed,
+      },
+    });
+    return this;
+  }
+
+  /**
+   * Toggles the request to speak in the channel.
+   * Only applicable for stage channels and for the client's own voice state.
+   * @param {boolean} [requestToSpeak=true] Whether or not the client is requesting to become a speaker.
+   * @example
+   * // Making the client request to speak in a stage channel (raise its hand)
+   * guild.members.me.voice.setRequestToSpeak(true);
+   * @example
+   * // Making the client cancel a request to speak
+   * guild.members.me.voice.setRequestToSpeak(false);
+   * @returns {Promise<VoiceState>}
+   */
+  setRequestToSpeak(requestToSpeak = true) {
+    return this.edit({ requestToSpeak });
+  }
+
+  /**
+   * Suppress/unsuppress the user. Only applicable for stage channels.
+   * @param {boolean} [suppressed=true] Whether or not the user should be suppressed.
+   * @example
+   * // Making the client a speaker
+   * guild.members.me.voice.setSuppressed(false);
+   * @example
+   * // Making the client an audience member
+   * guild.members.me.voice.setSuppressed(true);
+   * @example
+   * // Inviting another user to speak
+   * voiceState.setSuppressed(false);
+   * @example
+   * // Moving another user to the audience, or cancelling their invite to speak
+   * voiceState.setSuppressed(true);
+   * @returns {Promise<VoiceState>}
+   */
+  setSuppressed(suppressed = true) {
+    return this.edit({ suppressed });
+  }
+
+  toJSON() {
+    return super.toJSON({
+      id: true,
+      serverDeaf: true,
+      serverMute: true,
+      selfDeaf: true,
+      selfMute: true,
+      sessionId: true,
+      channelId: 'channel',
+    });
+  }
+}
+
+module.exports = VoiceState;
diff --git a/node_modules/discord.js/src/structures/Webhook.js b/node_modules/discord.js/src/structures/Webhook.js
new file mode 100644
index 0000000..738d9e7
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Webhook.js
@@ -0,0 +1,479 @@
+'use strict';
+
+const { makeURLSearchParams } = require('@discordjs/rest');
+const { lazy } = require('@discordjs/util');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { Routes, WebhookType } = require('discord-api-types/v10');
+const MessagePayload = require('./MessagePayload');
+const { DiscordjsError, ErrorCodes } = require('../errors');
+const DataResolver = require('../util/DataResolver');
+
+const getMessage = lazy(() => require('./Message').Message);
+
+/**
+ * Represents a webhook.
+ */
+class Webhook {
+  constructor(client, data) {
+    /**
+     * The client that instantiated the webhook
+     * @name Webhook#client
+     * @type {Client}
+     * @readonly
+     */
+    Object.defineProperty(this, 'client', { value: client });
+    if (data) this._patch(data);
+  }
+
+  _patch(data) {
+    if ('name' in data) {
+      /**
+       * The name of the webhook
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    /**
+     * The token for the webhook, unavailable for follower webhooks and webhooks owned by another application.
+     * @name Webhook#token
+     * @type {?string}
+     */
+    Object.defineProperty(this, 'token', {
+      value: data.token ?? null,
+      writable: true,
+      configurable: true,
+    });
+
+    if ('avatar' in data) {
+      /**
+       * The avatar for the webhook
+       * @type {?string}
+       */
+      this.avatar = data.avatar;
+    }
+
+    /**
+     * The webhook's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    if ('type' in data) {
+      /**
+       * The type of the webhook
+       * @type {WebhookType}
+       */
+      this.type = data.type;
+    }
+
+    if ('guild_id' in data) {
+      /**
+       * The guild the webhook belongs to
+       * @type {Snowflake}
+       */
+      this.guildId = data.guild_id;
+    }
+
+    if ('channel_id' in data) {
+      /**
+       * The id of the channel the webhook belongs to
+       * @type {Snowflake}
+       */
+      this.channelId = data.channel_id;
+    }
+
+    if ('user' in data) {
+      /**
+       * The owner of the webhook
+       * @type {?(User|APIUser)}
+       */
+      this.owner = this.client.users?._add(data.user) ?? data.user;
+    } else {
+      this.owner ??= null;
+    }
+
+    if ('application_id' in data) {
+      /**
+       * The application that created this webhook
+       * @type {?Snowflake}
+       */
+      this.applicationId = data.application_id;
+    } else {
+      this.applicationId ??= null;
+    }
+
+    if ('source_guild' in data) {
+      /**
+       * The source guild of the webhook
+       * @type {?(Guild|APIGuild)}
+       */
+      this.sourceGuild = this.client.guilds?.resolve(data.source_guild.id) ?? data.source_guild;
+    } else {
+      this.sourceGuild ??= null;
+    }
+
+    if ('source_channel' in data) {
+      /**
+       * The source channel of the webhook
+       * @type {?(NewsChannel|APIChannel)}
+       */
+      this.sourceChannel = this.client.channels?.resolve(data.source_channel?.id) ?? data.source_channel;
+    } else {
+      this.sourceChannel ??= null;
+    }
+  }
+
+  /**
+   * Options that can be passed into send.
+   * @typedef {BaseMessageOptions} WebhookMessageCreateOptions
+   * @property {boolean} [tts=false] Whether the message should be spoken aloud
+   * @property {MessageFlags} [flags] Which flags to set for the message.
+   * <info>Only the {@link MessageFlags.SuppressEmbeds} flag can be set.</info>
+   * @property {string} [username=this.name] Username override for the message
+   * @property {string} [avatarURL] Avatar URL override for the message
+   * @property {Snowflake} [threadId] The id of the thread in the channel to send to.
+   * <info>For interaction webhooks, this property is ignored</info>
+   * @property {string} [threadName] Name of the thread to create (only available if webhook is in a forum channel)
+   */
+
+  /**
+   * Options that can be passed into editMessage.
+   * @typedef {BaseMessageOptions} WebhookMessageEditOptions
+   * @property {Attachment[]} [attachments] Attachments to send with the message
+   * @property {Snowflake} [threadId] The id of the thread this message belongs to
+   * <info>For interaction webhooks, this property is ignored</info>
+   */
+
+  /**
+   * The channel the webhook belongs to
+   * @type {?(TextChannel|VoiceChannel|StageChannel|NewsChannel|ForumChannel)}
+   * @readonly
+   */
+  get channel() {
+    return this.client.channels.resolve(this.channelId);
+  }
+
+  /**
+   * Sends a message with this webhook.
+   * @param {string|MessagePayload|WebhookMessageCreateOptions} options The options to provide
+   * @returns {Promise<Message>}
+   * @example
+   * // Send a basic message
+   * webhook.send('hello!')
+   *   .then(message => console.log(`Sent message: ${message.content}`))
+   *   .catch(console.error);
+   * @example
+   * // Send a basic message in a thread
+   * webhook.send({ content: 'hello!', threadId: '836856309672348295' })
+   *   .then(message => console.log(`Sent message: ${message.content}`))
+   *   .catch(console.error);
+   * @example
+   * // Send a remote file
+   * webhook.send({
+   *   files: ['https://cdn.discordapp.com/icons/222078108977594368/6e1019b3179d71046e463a75915e7244.png?size=2048']
+   * })
+   *   .then(console.log)
+   *   .catch(console.error);
+   * @example
+   * // Send a local file
+   * webhook.send({
+   *   files: [{
+   *     attachment: 'entire/path/to/file.jpg',
+   *     name: 'file.jpg'
+   *   }]
+   * })
+   *   .then(console.log)
+   *   .catch(console.error);
+   * @example
+   * // Send an embed with a local image inside
+   * webhook.send({
+   *   content: 'This is an embed',
+   *   embeds: [{
+   *     thumbnail: {
+   *          url: 'attachment://file.jpg'
+   *       }
+   *    }],
+   *    files: [{
+   *       attachment: 'entire/path/to/file.jpg',
+   *       name: 'file.jpg'
+   *    }]
+   * })
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async send(options) {
+    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);
+
+    let messagePayload;
+
+    if (options instanceof MessagePayload) {
+      messagePayload = options.resolveBody();
+    } else {
+      messagePayload = MessagePayload.create(this, options).resolveBody();
+    }
+
+    const query = makeURLSearchParams({
+      wait: true,
+      thread_id: messagePayload.options.threadId,
+    });
+
+    const { body, files } = await messagePayload.resolveFiles();
+    const d = await this.client.rest.post(Routes.webhook(this.id, this.token), {
+      body,
+      files,
+      query,
+      auth: false,
+    });
+
+    if (!this.client.channels) return d;
+    return this.client.channels.cache.get(d.channel_id)?.messages._add(d, false) ?? new (getMessage())(this.client, d);
+  }
+
+  /**
+   * Sends a raw slack message with this webhook.
+   * @param {Object} body The raw body to send
+   * @returns {Promise<boolean>}
+   * @example
+   * // Send a slack message
+   * webhook.sendSlackMessage({
+   *   'username': 'Wumpus',
+   *   'attachments': [{
+   *     'pretext': 'this looks pretty cool',
+   *     'color': '#F0F',
+   *     'footer_icon': 'http://snek.s3.amazonaws.com/topSnek.png',
+   *     'footer': 'Powered by sneks',
+   *     'ts': Date.now() / 1_000
+   *   }]
+   * }).catch(console.error);
+   * @see {@link https://api.slack.com/messaging/webhooks}
+   */
+  async sendSlackMessage(body) {
+    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);
+
+    const data = await this.client.rest.post(Routes.webhookPlatform(this.id, this.token, 'slack'), {
+      query: makeURLSearchParams({ wait: true }),
+      auth: false,
+      body,
+    });
+    return data.toString() === 'ok';
+  }
+
+  /**
+   * Options used to edit a {@link Webhook}.
+   * @typedef {Object} WebhookEditOptions
+   * @property {string} [name=this.name] The new name for the webhook
+   * @property {?(BufferResolvable)} [avatar] The new avatar for the webhook
+   * @property {GuildTextChannelResolvable|VoiceChannel|StageChannel|ForumChannel} [channel]
+   * The new channel for the webhook
+   * @property {string} [reason] Reason for editing the webhook
+   */
+
+  /**
+   * Edits this webhook.
+   * @param {WebhookEditOptions} options Options for editing the webhook
+   * @returns {Promise<Webhook>}
+   */
+  async edit({ name = this.name, avatar, channel, reason }) {
+    if (avatar && !(typeof avatar === 'string' && avatar.startsWith('data:'))) {
+      avatar = await DataResolver.resolveImage(avatar);
+    }
+    channel &&= channel.id ?? channel;
+    const data = await this.client.rest.patch(Routes.webhook(this.id, channel ? undefined : this.token), {
+      body: { name, avatar, channel_id: channel },
+      reason,
+      auth: !this.token || Boolean(channel),
+    });
+
+    this.name = data.name;
+    this.avatar = data.avatar;
+    this.channelId = data.channel_id;
+    return this;
+  }
+
+  /**
+   * Options that can be passed into fetchMessage.
+   * @typedef {options} WebhookFetchMessageOptions
+   * @property {boolean} [cache=true] Whether to cache the message.
+   * @property {Snowflake} [threadId] The id of the thread this message belongs to.
+   * <info>For interaction webhooks, this property is ignored</info>
+   */
+
+  /**
+   * Gets a message that was sent by this webhook.
+   * @param {Snowflake|'@original'} message The id of the message to fetch
+   * @param {WebhookFetchMessageOptions} [options={}] The options to provide to fetch the message.
+   * @returns {Promise<Message>} Returns the message sent by this webhook
+   */
+  async fetchMessage(message, { threadId } = {}) {
+    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);
+
+    const data = await this.client.rest.get(Routes.webhookMessage(this.id, this.token, message), {
+      query: threadId ? makeURLSearchParams({ thread_id: threadId }) : undefined,
+      auth: false,
+    });
+
+    if (!this.client.channels) return data;
+    return (
+      this.client.channels.cache.get(data.channel_id)?.messages._add(data, false) ??
+      new (getMessage())(this.client, data)
+    );
+  }
+
+  /**
+   * Edits a message that was sent by this webhook.
+   * @param {MessageResolvable|'@original'} message The message to edit
+   * @param {string|MessagePayload|WebhookMessageEditOptions} options The options to provide
+   * @returns {Promise<Message>} Returns the message edited by this webhook
+   */
+  async editMessage(message, options) {
+    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);
+
+    let messagePayload;
+
+    if (options instanceof MessagePayload) messagePayload = options;
+    else messagePayload = MessagePayload.create(this, options);
+
+    const { body, files } = await messagePayload.resolveBody().resolveFiles();
+
+    const d = await this.client.rest.patch(
+      Routes.webhookMessage(this.id, this.token, typeof message === 'string' ? message : message.id),
+      {
+        body,
+        files,
+        query: messagePayload.options.threadId
+          ? makeURLSearchParams({ thread_id: messagePayload.options.threadId })
+          : undefined,
+        auth: false,
+      },
+    );
+
+    const channelManager = this.client.channels;
+    if (!channelManager) return d;
+
+    const messageManager = channelManager.cache.get(d.channel_id)?.messages;
+    if (!messageManager) return new (getMessage())(this.client, d);
+
+    const existing = messageManager.cache.get(d.id);
+    if (!existing) return messageManager._add(d);
+
+    const clone = existing._clone();
+    clone._patch(d);
+    return clone;
+  }
+
+  /**
+   * Deletes the webhook.
+   * @param {string} [reason] Reason for deleting this webhook
+   * @returns {Promise<void>}
+   */
+  delete(reason) {
+    return this.client.deleteWebhook(this.id, { token: this.token, reason });
+  }
+
+  /**
+   * Delete a message that was sent by this webhook.
+   * @param {MessageResolvable|'@original'} message The message to delete
+   * @param {Snowflake} [threadId] The id of the thread this message belongs to
+   * @returns {Promise<void>}
+   */
+  async deleteMessage(message, threadId) {
+    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);
+
+    await this.client.rest.delete(
+      Routes.webhookMessage(this.id, this.token, typeof message === 'string' ? message : message.id),
+      {
+        query: threadId ? makeURLSearchParams({ thread_id: threadId }) : undefined,
+        auth: false,
+      },
+    );
+  }
+
+  /**
+   * The timestamp the webhook was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the webhook was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * The URL of this webhook
+   * @type {string}
+   * @readonly
+   */
+  get url() {
+    return this.client.options.rest.api + Routes.webhook(this.id, this.token);
+  }
+
+  /**
+   * A link to the webhook's avatar.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  avatarURL(options = {}) {
+    return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options);
+  }
+
+  /**
+   * Whether this webhook is created by a user.
+   * @returns {boolean}
+   */
+  isUserCreated() {
+    return Boolean(this.type === WebhookType.Incoming && this.owner && !this.owner.bot);
+  }
+
+  /**
+   * Whether this webhook is created by an application.
+   * @returns {boolean}
+   */
+  isApplicationCreated() {
+    return this.type === WebhookType.Application;
+  }
+
+  /**
+   * Whether or not this webhook is a channel follower webhook.
+   * @returns {boolean}
+   */
+  isChannelFollower() {
+    return this.type === WebhookType.ChannelFollower;
+  }
+
+  /**
+   * Whether or not this webhook is an incoming webhook.
+   * @returns {boolean}
+   */
+  isIncoming() {
+    return this.type === WebhookType.Incoming;
+  }
+
+  static applyToClass(structure, ignore = []) {
+    for (const prop of [
+      'send',
+      'sendSlackMessage',
+      'fetchMessage',
+      'edit',
+      'editMessage',
+      'delete',
+      'deleteMessage',
+      'createdTimestamp',
+      'createdAt',
+      'url',
+    ]) {
+      if (ignore.includes(prop)) continue;
+      Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(Webhook.prototype, prop));
+    }
+  }
+}
+
+module.exports = Webhook;
diff --git a/node_modules/discord.js/src/structures/WelcomeChannel.js b/node_modules/discord.js/src/structures/WelcomeChannel.js
new file mode 100644
index 0000000..d783e06
--- /dev/null
+++ b/node_modules/discord.js/src/structures/WelcomeChannel.js
@@ -0,0 +1,60 @@
+'use strict';
+
+const Base = require('./Base');
+const { Emoji } = require('./Emoji');
+
+/**
+ * Represents a channel link in a guild's welcome screen.
+ * @extends {Base}
+ */
+class WelcomeChannel extends Base {
+  constructor(guild, data) {
+    super(guild.client);
+
+    /**
+     * The guild for this welcome channel
+     * @type {Guild|InviteGuild}
+     */
+    this.guild = guild;
+
+    /**
+     * The description of this welcome channel
+     * @type {string}
+     */
+    this.description = data.description;
+
+    /**
+     * The raw emoji data
+     * @type {Object}
+     * @private
+     */
+    this._emoji = {
+      name: data.emoji_name,
+      id: data.emoji_id,
+    };
+
+    /**
+     * The id of this welcome channel
+     * @type {Snowflake}
+     */
+    this.channelId = data.channel_id;
+  }
+
+  /**
+   * The channel of this welcome channel
+   * @type {?(TextChannel|NewsChannel|ForumChannel)}
+   */
+  get channel() {
+    return this.client.channels.resolve(this.channelId);
+  }
+
+  /**
+   * The emoji of this welcome channel
+   * @type {GuildEmoji|Emoji}
+   */
+  get emoji() {
+    return this.client.emojis.resolve(this._emoji.id) ?? new Emoji(this.client, this._emoji);
+  }
+}
+
+module.exports = WelcomeChannel;
diff --git a/node_modules/discord.js/src/structures/WelcomeScreen.js b/node_modules/discord.js/src/structures/WelcomeScreen.js
new file mode 100644
index 0000000..9ff79bc
--- /dev/null
+++ b/node_modules/discord.js/src/structures/WelcomeScreen.js
@@ -0,0 +1,49 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { GuildFeature } = require('discord-api-types/v10');
+const Base = require('./Base');
+const WelcomeChannel = require('./WelcomeChannel');
+
+/**
+ * Represents a welcome screen.
+ * @extends {Base}
+ */
+class WelcomeScreen extends Base {
+  constructor(guild, data) {
+    super(guild.client);
+
+    /**
+     * The guild for this welcome screen
+     * @type {Guild}
+     */
+    this.guild = guild;
+
+    /**
+     * The description of this welcome screen
+     * @type {?string}
+     */
+    this.description = data.description ?? null;
+
+    /**
+     * Collection of welcome channels belonging to this welcome screen
+     * @type {Collection<Snowflake, WelcomeChannel>}
+     */
+    this.welcomeChannels = new Collection();
+
+    for (const channel of data.welcome_channels) {
+      const welcomeChannel = new WelcomeChannel(this.guild, channel);
+      this.welcomeChannels.set(welcomeChannel.channelId, welcomeChannel);
+    }
+  }
+
+  /**
+   * Whether the welcome screen is enabled on the guild
+   * @type {boolean}
+   */
+  get enabled() {
+    return this.guild.features.includes(GuildFeature.WelcomeScreenEnabled);
+  }
+}
+
+module.exports = WelcomeScreen;
diff --git a/node_modules/discord.js/src/structures/Widget.js b/node_modules/discord.js/src/structures/Widget.js
new file mode 100644
index 0000000..344c81a
--- /dev/null
+++ b/node_modules/discord.js/src/structures/Widget.js
@@ -0,0 +1,88 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { Routes } = require('discord-api-types/v10');
+const Base = require('./Base');
+const WidgetMember = require('./WidgetMember');
+
+/**
+ * Represents a Widget.
+ * @extends {Base}
+ */
+class Widget extends Base {
+  constructor(client, data) {
+    super(client);
+    this._patch(data);
+  }
+
+  /**
+   * Represents a channel in a Widget
+   * @typedef {Object} WidgetChannel
+   * @property {Snowflake} id Id of the channel
+   * @property {string} name Name of the channel
+   * @property {number} position Position of the channel
+   */
+
+  _patch(data) {
+    /**
+     * The id of the guild.
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    if ('name' in data) {
+      /**
+       * The name of the guild.
+       * @type {string}
+       */
+      this.name = data.name;
+    }
+
+    if ('instant_invite' in data) {
+      /**
+       * The invite of the guild.
+       * @type {?string}
+       */
+      this.instantInvite = data.instant_invite;
+    }
+
+    /**
+     * The list of channels in the guild.
+     * @type {Collection<Snowflake, WidgetChannel>}
+     */
+    this.channels = new Collection();
+    for (const channel of data.channels) {
+      this.channels.set(channel.id, channel);
+    }
+
+    /**
+     * The list of members in the guild.
+     * These strings are just arbitrary numbers, they aren't Snowflakes.
+     * @type {Collection<string, WidgetMember>}
+     */
+    this.members = new Collection();
+    for (const member of data.members) {
+      this.members.set(member.id, new WidgetMember(this.client, member));
+    }
+
+    if ('presence_count' in data) {
+      /**
+       * The number of members online.
+       * @type {number}
+       */
+      this.presenceCount = data.presence_count;
+    }
+  }
+
+  /**
+   * Update the Widget.
+   * @returns {Promise<Widget>}
+   */
+  async fetch() {
+    const data = await this.client.rest.get(Routes.guildWidgetJSON(this.id));
+    this._patch(data);
+    return this;
+  }
+}
+
+module.exports = Widget;
diff --git a/node_modules/discord.js/src/structures/WidgetMember.js b/node_modules/discord.js/src/structures/WidgetMember.js
new file mode 100644
index 0000000..d7aca21
--- /dev/null
+++ b/node_modules/discord.js/src/structures/WidgetMember.js
@@ -0,0 +1,99 @@
+'use strict';
+
+const Base = require('./Base');
+
+/**
+ * Represents a WidgetMember.
+ * @extends {Base}
+ */
+class WidgetMember extends Base {
+  /**
+   * Activity sent in a {@link WidgetMember}.
+   * @typedef {Object} WidgetActivity
+   * @property {string} name The name of the activity
+   */
+
+  constructor(client, data) {
+    super(client);
+
+    /**
+     * The id of the user. It's an arbitrary number.
+     * @type {string}
+     */
+    this.id = data.id;
+
+    /**
+     * The username of the member.
+     * @type {string}
+     */
+    this.username = data.username;
+
+    /**
+     * The discriminator of the member.
+     * @type {string}
+     */
+    this.discriminator = data.discriminator;
+
+    /**
+     * The avatar of the member.
+     * @type {?string}
+     */
+    this.avatar = data.avatar;
+
+    /**
+     * The status of the member.
+     * @type {PresenceStatus}
+     */
+    this.status = data.status;
+
+    /**
+     * If the member is server deafened
+     * @type {?boolean}
+     */
+    this.deaf = data.deaf ?? null;
+
+    /**
+     * If the member is server muted
+     * @type {?boolean}
+     */
+    this.mute = data.mute ?? null;
+
+    /**
+     * If the member is self deafened
+     * @type {?boolean}
+     */
+    this.selfDeaf = data.self_deaf ?? null;
+
+    /**
+     * If the member is self muted
+     * @type {?boolean}
+     */
+    this.selfMute = data.self_mute ?? null;
+
+    /**
+     * If the member is suppressed
+     * @type {?boolean}
+     */
+    this.suppress = data.suppress ?? null;
+
+    /**
+     * The id of the voice channel the member is in, if any
+     * @type {?Snowflake}
+     */
+    this.channelId = data.channel_id ?? null;
+
+    /**
+     * The avatar URL of the member.
+     * @type {string}
+     */
+    this.avatarURL = data.avatar_url;
+
+    /**
+     * The activity of the member.
+     * @type {?WidgetActivity}
+     */
+    this.activity = data.activity ?? null;
+  }
+}
+
+module.exports = WidgetMember;
diff --git a/node_modules/discord.js/src/structures/interfaces/Application.js b/node_modules/discord.js/src/structures/interfaces/Application.js
new file mode 100644
index 0000000..5e81465
--- /dev/null
+++ b/node_modules/discord.js/src/structures/interfaces/Application.js
@@ -0,0 +1,108 @@
+'use strict';
+
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const Base = require('../Base');
+
+/**
+ * Represents an OAuth2 Application.
+ * @extends {Base}
+ * @abstract
+ */
+class Application extends Base {
+  constructor(client, data) {
+    super(client);
+    this._patch(data);
+  }
+
+  _patch(data) {
+    /**
+     * The application's id
+     * @type {Snowflake}
+     */
+    this.id = data.id;
+
+    if ('name' in data) {
+      /**
+       * The name of the application
+       * @type {?string}
+       */
+      this.name = data.name;
+    } else {
+      this.name ??= null;
+    }
+
+    if ('description' in data) {
+      /**
+       * The application's description
+       * @type {?string}
+       */
+      this.description = data.description;
+    } else {
+      this.description ??= null;
+    }
+
+    if ('icon' in data) {
+      /**
+       * The application's icon hash
+       * @type {?string}
+       */
+      this.icon = data.icon;
+    } else {
+      this.icon ??= null;
+    }
+  }
+
+  /**
+   * The timestamp the application was created at
+   * @type {number}
+   * @readonly
+   */
+  get createdTimestamp() {
+    return DiscordSnowflake.timestampFrom(this.id);
+  }
+
+  /**
+   * The time the application was created at
+   * @type {Date}
+   * @readonly
+   */
+  get createdAt() {
+    return new Date(this.createdTimestamp);
+  }
+
+  /**
+   * A link to the application's icon.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  iconURL(options = {}) {
+    return this.icon && this.client.rest.cdn.appIcon(this.id, this.icon, options);
+  }
+
+  /**
+   * A link to this application's cover image.
+   * @param {ImageURLOptions} [options={}] Options for the image URL
+   * @returns {?string}
+   */
+  coverURL(options = {}) {
+    return this.cover && this.client.rest.cdn.appIcon(this.id, this.cover, options);
+  }
+
+  /**
+   * When concatenated with a string, this automatically returns the application's name instead of the
+   * Application object.
+   * @returns {?string}
+   * @example
+   * // Logs: Application name: My App
+   * console.log(`Application name: ${application}`);
+   */
+  toString() {
+    return this.name;
+  }
+
+  toJSON() {
+    return super.toJSON({ createdTimestamp: true });
+  }
+}
+
+module.exports = Application;
diff --git a/node_modules/discord.js/src/structures/interfaces/Collector.js b/node_modules/discord.js/src/structures/interfaces/Collector.js
new file mode 100644
index 0000000..65f4117
--- /dev/null
+++ b/node_modules/discord.js/src/structures/interfaces/Collector.js
@@ -0,0 +1,335 @@
+'use strict';
+
+const EventEmitter = require('node:events');
+const { setTimeout, clearTimeout } = require('node:timers');
+const { Collection } = require('@discordjs/collection');
+const { DiscordjsTypeError, ErrorCodes } = require('../../errors');
+const { flatten } = require('../../util/Util');
+
+/**
+ * Filter to be applied to the collector.
+ * @typedef {Function} CollectorFilter
+ * @param {...*} args Any arguments received by the listener
+ * @param {Collection} collection The items collected by this collector
+ * @returns {boolean|Promise<boolean>}
+ */
+
+/**
+ * Options to be applied to the collector.
+ * @typedef {Object} CollectorOptions
+ * @property {CollectorFilter} [filter] The filter applied to this collector
+ * @property {number} [time] How long to run the collector for in milliseconds
+ * @property {number} [idle] How long to stop the collector after inactivity in milliseconds
+ * @property {boolean} [dispose=false] Whether to dispose data when it's deleted
+ */
+
+/**
+ * Abstract class for defining a new Collector.
+ * @extends {EventEmitter}
+ * @abstract
+ */
+class Collector extends EventEmitter {
+  constructor(client, options = {}) {
+    super();
+
+    /**
+     * The client that instantiated this Collector
+     * @name Collector#client
+     * @type {Client}
+     * @readonly
+     */
+    Object.defineProperty(this, 'client', { value: client });
+
+    /**
+     * The filter applied to this collector
+     * @type {CollectorFilter}
+     * @returns {boolean|Promise<boolean>}
+     */
+    this.filter = options.filter ?? (() => true);
+
+    /**
+     * The options of this collector
+     * @type {CollectorOptions}
+     */
+    this.options = options;
+
+    /**
+     * The items collected by this collector
+     * @type {Collection}
+     */
+    this.collected = new Collection();
+
+    /**
+     * Whether this collector has finished collecting
+     * @type {boolean}
+     */
+    this.ended = false;
+
+    /**
+     * Timeout for cleanup
+     * @type {?Timeout}
+     * @private
+     */
+    this._timeout = null;
+
+    /**
+     * Timeout for cleanup due to inactivity
+     * @type {?Timeout}
+     * @private
+     */
+    this._idletimeout = null;
+
+    /**
+     * The reason the collector ended
+     * @type {string|null}
+     * @private
+     */
+    this._endReason = null;
+
+    if (typeof this.filter !== 'function') {
+      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options.filter', 'function');
+    }
+
+    this.handleCollect = this.handleCollect.bind(this);
+    this.handleDispose = this.handleDispose.bind(this);
+
+    if (options.time) this._timeout = setTimeout(() => this.stop('time'), options.time).unref();
+    if (options.idle) this._idletimeout = setTimeout(() => this.stop('idle'), options.idle).unref();
+
+    /**
+     * The timestamp at which this collector last collected an item
+     * @type {?number}
+     */
+    this.lastCollectedTimestamp = null;
+  }
+
+  /**
+   * The Date at which this collector last collected an item
+   * @type {?Date}
+   */
+  get lastCollectedAt() {
+    return this.lastCollectedTimestamp && new Date(this.lastCollectedTimestamp);
+  }
+
+  /**
+   * Call this to handle an event as a collectable element. Accepts any event data as parameters.
+   * @param {...*} args The arguments emitted by the listener
+   * @returns {Promise<void>}
+   * @emits Collector#collect
+   */
+  async handleCollect(...args) {
+    const collectedId = await this.collect(...args);
+
+    if (collectedId) {
+      const filterResult = await this.filter(...args, this.collected);
+      if (filterResult) {
+        this.collected.set(collectedId, args[0]);
+
+        /**
+         * Emitted whenever an element is collected.
+         * @event Collector#collect
+         * @param {...*} args The arguments emitted by the listener
+         */
+        this.emit('collect', ...args);
+
+        this.lastCollectedTimestamp = Date.now();
+        if (this._idletimeout) {
+          clearTimeout(this._idletimeout);
+          this._idletimeout = setTimeout(() => this.stop('idle'), this.options.idle).unref();
+        }
+      } else {
+        /**
+         * Emitted whenever an element is not collected by the collector.
+         * @event Collector#ignore
+         * @param {...*} args The arguments emitted by the listener
+         */
+        this.emit('ignore', ...args);
+      }
+    }
+    this.checkEnd();
+  }
+
+  /**
+   * Call this to remove an element from the collection. Accepts any event data as parameters.
+   * @param {...*} args The arguments emitted by the listener
+   * @returns {Promise<void>}
+   * @emits Collector#dispose
+   */
+  async handleDispose(...args) {
+    if (!this.options.dispose) return;
+
+    const dispose = this.dispose(...args);
+    if (!dispose || !(await this.filter(...args)) || !this.collected.has(dispose)) return;
+    this.collected.delete(dispose);
+
+    /**
+     * Emitted whenever an element is disposed of.
+     * @event Collector#dispose
+     * @param {...*} args The arguments emitted by the listener
+     */
+    this.emit('dispose', ...args);
+    this.checkEnd();
+  }
+
+  /**
+   * Returns a promise that resolves with the next collected element;
+   * rejects with collected elements if the collector finishes without receiving a next element
+   * @type {Promise}
+   * @readonly
+   */
+  get next() {
+    return new Promise((resolve, reject) => {
+      if (this.ended) {
+        reject(this.collected);
+        return;
+      }
+
+      const cleanup = () => {
+        this.removeListener('collect', onCollect);
+        this.removeListener('end', onEnd);
+      };
+
+      const onCollect = item => {
+        cleanup();
+        resolve(item);
+      };
+
+      const onEnd = () => {
+        cleanup();
+        reject(this.collected);
+      };
+
+      this.on('collect', onCollect);
+      this.on('end', onEnd);
+    });
+  }
+
+  /**
+   * Stops this collector and emits the `end` event.
+   * @param {string} [reason='user'] The reason this collector is ending
+   * @emits Collector#end
+   */
+  stop(reason = 'user') {
+    if (this.ended) return;
+
+    if (this._timeout) {
+      clearTimeout(this._timeout);
+      this._timeout = null;
+    }
+    if (this._idletimeout) {
+      clearTimeout(this._idletimeout);
+      this._idletimeout = null;
+    }
+
+    this._endReason = reason;
+    this.ended = true;
+
+    /**
+     * Emitted when the collector is finished collecting.
+     * @event Collector#end
+     * @param {Collection} collected The elements collected by the collector
+     * @param {string} reason The reason the collector ended
+     */
+    this.emit('end', this.collected, reason);
+  }
+
+  /**
+   * Options used to reset the timeout and idle timer of a {@link Collector}.
+   * @typedef {Object} CollectorResetTimerOptions
+   * @property {number} [time] How long to run the collector for (in milliseconds)
+   * @property {number} [idle] How long to wait to stop the collector after inactivity (in milliseconds)
+   */
+
+  /**
+   * Resets the collector's timeout and idle timer.
+   * @param {CollectorResetTimerOptions} [options] Options for resetting
+   */
+  resetTimer({ time, idle } = {}) {
+    if (this._timeout) {
+      clearTimeout(this._timeout);
+      this._timeout = setTimeout(() => this.stop('time'), time ?? this.options.time).unref();
+    }
+    if (this._idletimeout) {
+      clearTimeout(this._idletimeout);
+      this._idletimeout = setTimeout(() => this.stop('idle'), idle ?? this.options.idle).unref();
+    }
+  }
+
+  /**
+   * Checks whether the collector should end, and if so, ends it.
+   * @returns {boolean} Whether the collector ended or not
+   */
+  checkEnd() {
+    const reason = this.endReason;
+    if (reason) this.stop(reason);
+    return Boolean(reason);
+  }
+
+  /**
+   * Allows collectors to be consumed with for-await-of loops
+   * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of}
+   */
+  async *[Symbol.asyncIterator]() {
+    const queue = [];
+    const onCollect = (...item) => queue.push(item);
+    this.on('collect', onCollect);
+
+    try {
+      while (queue.length || !this.ended) {
+        if (queue.length) {
+          yield queue.shift();
+        } else {
+          // eslint-disable-next-line no-await-in-loop
+          await new Promise(resolve => {
+            const tick = () => {
+              this.removeListener('collect', tick);
+              this.removeListener('end', tick);
+              return resolve();
+            };
+            this.on('collect', tick);
+            this.on('end', tick);
+          });
+        }
+      }
+    } finally {
+      this.removeListener('collect', onCollect);
+    }
+  }
+
+  toJSON() {
+    return flatten(this);
+  }
+
+  /* eslint-disable no-empty-function */
+  /**
+   * The reason this collector has ended with, or null if it hasn't ended yet
+   * @type {?string}
+   * @readonly
+   */
+  get endReason() {
+    return this._endReason;
+  }
+
+  /**
+   * Handles incoming events from the `handleCollect` function. Returns null if the event should not
+   * be collected, or returns an object describing the data that should be stored.
+   * @see Collector#handleCollect
+   * @param {...*} args Any args the event listener emits
+   * @returns {?(*|Promise<?*>)} Data to insert into collection, if any
+   * @abstract
+   */
+  collect() {}
+
+  /**
+   * Handles incoming events from the `handleDispose`. Returns null if the event should not
+   * be disposed, or returns the key that should be removed.
+   * @see Collector#handleDispose
+   * @param {...*} args Any args the event listener emits
+   * @returns {?*} Key to remove from the collection, if any
+   * @abstract
+   */
+  dispose() {}
+  /* eslint-enable no-empty-function */
+}
+
+module.exports = Collector;
diff --git a/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js b/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js
new file mode 100644
index 0000000..15256e3
--- /dev/null
+++ b/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js
@@ -0,0 +1,320 @@
+'use strict';
+
+const { isJSONEncodable } = require('@discordjs/util');
+const { InteractionResponseType, MessageFlags, Routes, InteractionType } = require('discord-api-types/v10');
+const { DiscordjsError, ErrorCodes } = require('../../errors');
+const InteractionCollector = require('../InteractionCollector');
+const InteractionResponse = require('../InteractionResponse');
+const MessagePayload = require('../MessagePayload');
+
+/**
+ * @typedef {Object} ModalComponentData
+ * @property {string} title The title of the modal
+ * @property {string} customId The custom id of the modal
+ * @property {ActionRow[]} components The components within this modal
+ */
+
+/**
+ * Interface for classes that support shared interaction response types.
+ * @interface
+ */
+class InteractionResponses {
+  /**
+   * Options for deferring the reply to an {@link BaseInteraction}.
+   * @typedef {Object} InteractionDeferReplyOptions
+   * @property {boolean} [ephemeral] Whether the reply should be ephemeral
+   * @property {boolean} [fetchReply] Whether to fetch the reply
+   */
+
+  /**
+   * Options for deferring and updating the reply to a {@link MessageComponentInteraction}.
+   * @typedef {Object} InteractionDeferUpdateOptions
+   * @property {boolean} [fetchReply] Whether to fetch the reply
+   */
+
+  /**
+   * Options for a reply to a {@link BaseInteraction}.
+   * @typedef {BaseMessageOptions} InteractionReplyOptions
+   * @property {boolean} [tts=false] Whether the message should be spoken aloud
+   * @property {boolean} [ephemeral] Whether the reply should be ephemeral
+   * @property {boolean} [fetchReply] Whether to fetch the reply
+   * @property {MessageFlags} [flags] Which flags to set for the message.
+   * <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.Ephemeral` can be set.</info>
+   */
+
+  /**
+   * Options for updating the message received from a {@link MessageComponentInteraction}.
+   * @typedef {MessageEditOptions} InteractionUpdateOptions
+   * @property {boolean} [fetchReply] Whether to fetch the reply
+   */
+
+  /**
+   * Defers the reply to this interaction.
+   * @param {InteractionDeferReplyOptions} [options] Options for deferring the reply to this interaction
+   * @returns {Promise<Message|InteractionResponse>}
+   * @example
+   * // Defer the reply to this interaction
+   * interaction.deferReply()
+   *   .then(console.log)
+   *   .catch(console.error)
+   * @example
+   * // Defer to send an ephemeral reply later
+   * interaction.deferReply({ ephemeral: true })
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async deferReply(options = {}) {
+    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
+    this.ephemeral = options.ephemeral ?? false;
+    await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
+      body: {
+        type: InteractionResponseType.DeferredChannelMessageWithSource,
+        data: {
+          flags: options.ephemeral ? MessageFlags.Ephemeral : undefined,
+        },
+      },
+      auth: false,
+    });
+    this.deferred = true;
+
+    return options.fetchReply ? this.fetchReply() : new InteractionResponse(this);
+  }
+
+  /**
+   * Creates a reply to this interaction.
+   * <info>Use the `fetchReply` option to get the bot's reply message.</info>
+   * @param {string|MessagePayload|InteractionReplyOptions} options The options for the reply
+   * @returns {Promise<Message|InteractionResponse>}
+   * @example
+   * // Reply to the interaction and fetch the response
+   * interaction.reply({ content: 'Pong!', fetchReply: true })
+   *   .then((message) => console.log(`Reply sent with content ${message.content}`))
+   *   .catch(console.error);
+   * @example
+   * // Create an ephemeral reply with an embed
+   * const embed = new EmbedBuilder().setDescription('Pong!');
+   *
+   * interaction.reply({ embeds: [embed], ephemeral: true })
+   *   .then(() => console.log('Reply sent.'))
+   *   .catch(console.error);
+   */
+  async reply(options) {
+    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
+    this.ephemeral = options.ephemeral ?? false;
+
+    let messagePayload;
+    if (options instanceof MessagePayload) messagePayload = options;
+    else messagePayload = MessagePayload.create(this, options);
+
+    const { body: data, files } = await messagePayload.resolveBody().resolveFiles();
+
+    await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
+      body: {
+        type: InteractionResponseType.ChannelMessageWithSource,
+        data,
+      },
+      files,
+      auth: false,
+    });
+    this.replied = true;
+
+    return options.fetchReply ? this.fetchReply() : new InteractionResponse(this);
+  }
+
+  /**
+   * Fetches a reply to this interaction.
+   * @see Webhook#fetchMessage
+   * @param {Snowflake|'@original'} [message='@original'] The response to fetch
+   * @returns {Promise<Message>}
+   * @example
+   * // Fetch the initial reply to this interaction
+   * interaction.fetchReply()
+   *   .then(reply => console.log(`Replied with ${reply.content}`))
+   *   .catch(console.error);
+   */
+  fetchReply(message = '@original') {
+    return this.webhook.fetchMessage(message);
+  }
+
+  /**
+   * Options that can be passed into {@link InteractionResponses#editReply}.
+   * @typedef {WebhookMessageEditOptions} InteractionEditReplyOptions
+   * @property {MessageResolvable|'@original'} [message='@original'] The response to edit
+   */
+
+  /**
+   * Edits a reply to this interaction.
+   * @see Webhook#editMessage
+   * @param {string|MessagePayload|InteractionEditReplyOptions} options The new options for the message
+   * @returns {Promise<Message>}
+   * @example
+   * // Edit the initial reply to this interaction
+   * interaction.editReply('New content')
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async editReply(options) {
+    if (!this.deferred && !this.replied) throw new DiscordjsError(ErrorCodes.InteractionNotReplied);
+    const msg = await this.webhook.editMessage(options.message ?? '@original', options);
+    this.replied = true;
+    return msg;
+  }
+
+  /**
+   * Deletes a reply to this interaction.
+   * @see Webhook#deleteMessage
+   * @param {MessageResolvable|'@original'} [message='@original'] The response to delete
+   * @returns {Promise<void>}
+   * @example
+   * // Delete the initial reply to this interaction
+   * interaction.deleteReply()
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async deleteReply(message = '@original') {
+    await this.webhook.deleteMessage(message);
+  }
+
+  /**
+   * Send a follow-up message to this interaction.
+   * @param {string|MessagePayload|InteractionReplyOptions} options The options for the reply
+   * @returns {Promise<Message>}
+   */
+  followUp(options) {
+    if (!this.deferred && !this.replied) return Promise.reject(new DiscordjsError(ErrorCodes.InteractionNotReplied));
+    return this.webhook.send(options);
+  }
+
+  /**
+   * Defers an update to the message to which the component was attached.
+   * @param {InteractionDeferUpdateOptions} [options] Options for deferring the update to this interaction
+   * @returns {Promise<Message|InteractionResponse>}
+   * @example
+   * // Defer updating and reset the component's loading state
+   * interaction.deferUpdate()
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async deferUpdate(options = {}) {
+    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
+    await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
+      body: {
+        type: InteractionResponseType.DeferredMessageUpdate,
+      },
+      auth: false,
+    });
+    this.deferred = true;
+
+    return options.fetchReply ? this.fetchReply() : new InteractionResponse(this, this.message?.interaction?.id);
+  }
+
+  /**
+   * Updates the original message of the component on which the interaction was received on.
+   * @param {string|MessagePayload|InteractionUpdateOptions} options The options for the updated message
+   * @returns {Promise<Message|void>}
+   * @example
+   * // Remove the components from the message
+   * interaction.update({
+   *   content: "A component interaction was received",
+   *   components: []
+   * })
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async update(options) {
+    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
+
+    let messagePayload;
+    if (options instanceof MessagePayload) messagePayload = options;
+    else messagePayload = MessagePayload.create(this, options);
+
+    const { body: data, files } = await messagePayload.resolveBody().resolveFiles();
+
+    await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
+      body: {
+        type: InteractionResponseType.UpdateMessage,
+        data,
+      },
+      files,
+      auth: false,
+    });
+    this.replied = true;
+
+    return options.fetchReply ? this.fetchReply() : new InteractionResponse(this, this.message.interaction?.id);
+  }
+
+  /**
+   * Shows a modal component
+   * @param {ModalBuilder|ModalComponentData|APIModalInteractionResponseCallbackData} modal The modal to show
+   * @returns {Promise<void>}
+   */
+  async showModal(modal) {
+    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
+    await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
+      body: {
+        type: InteractionResponseType.Modal,
+        data: isJSONEncodable(modal) ? modal.toJSON() : this.client.options.jsonTransformer(modal),
+      },
+      auth: false,
+    });
+    this.replied = true;
+  }
+
+  /**
+   * An object containing the same properties as {@link CollectorOptions}, but a few less:
+   * @typedef {Object} AwaitModalSubmitOptions
+   * @property {CollectorFilter} [filter] The filter applied to this collector
+   * @property {number} time Time in milliseconds to wait for an interaction before rejecting
+   */
+
+  /**
+   * Collects a single modal submit interaction that passes the filter.
+   * The Promise will reject if the time expires.
+   * @param {AwaitModalSubmitOptions} options Options to pass to the internal collector
+   * @returns {Promise<ModalSubmitInteraction>}
+   * @example
+   * // Collect a modal submit interaction
+   * const filter = (interaction) => interaction.customId === 'modal';
+   * interaction.awaitModalSubmit({ filter, time: 15_000 })
+   *   .then(interaction => console.log(`${interaction.customId} was submitted!`))
+   *   .catch(console.error);
+   */
+  awaitModalSubmit(options) {
+    if (typeof options.time !== 'number') throw new DiscordjsError(ErrorCodes.InvalidType, 'time', 'number');
+    const _options = { ...options, max: 1, interactionType: InteractionType.ModalSubmit };
+    return new Promise((resolve, reject) => {
+      const collector = new InteractionCollector(this.client, _options);
+      collector.once('end', (interactions, reason) => {
+        const interaction = interactions.first();
+        if (interaction) resolve(interaction);
+        else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason));
+      });
+    });
+  }
+
+  static applyToClass(structure, ignore = []) {
+    const props = [
+      'deferReply',
+      'reply',
+      'fetchReply',
+      'editReply',
+      'deleteReply',
+      'followUp',
+      'deferUpdate',
+      'update',
+      'showModal',
+      'awaitModalSubmit',
+    ];
+
+    for (const prop of props) {
+      if (ignore.includes(prop)) continue;
+      Object.defineProperty(
+        structure.prototype,
+        prop,
+        Object.getOwnPropertyDescriptor(InteractionResponses.prototype, prop),
+      );
+    }
+  }
+}
+
+module.exports = InteractionResponses;
diff --git a/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js b/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js
new file mode 100644
index 0000000..cf455b9
--- /dev/null
+++ b/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js
@@ -0,0 +1,413 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const { DiscordSnowflake } = require('@sapphire/snowflake');
+const { InteractionType, Routes } = require('discord-api-types/v10');
+const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../../errors');
+const { MaxBulkDeletableMessageAge } = require('../../util/Constants');
+const InteractionCollector = require('../InteractionCollector');
+const MessageCollector = require('../MessageCollector');
+const MessagePayload = require('../MessagePayload');
+
+/**
+ * Interface for classes that have text-channel-like features.
+ * @interface
+ */
+class TextBasedChannel {
+  constructor() {
+    /**
+     * A manager of the messages sent to this channel
+     * @type {GuildMessageManager}
+     */
+    this.messages = new GuildMessageManager(this);
+
+    /**
+     * The channel's last message id, if one was sent
+     * @type {?Snowflake}
+     */
+    this.lastMessageId = null;
+
+    /**
+     * The timestamp when the last pinned message was pinned, if there was one
+     * @type {?number}
+     */
+    this.lastPinTimestamp = null;
+  }
+
+  /**
+   * The Message object of the last message in the channel, if one was sent
+   * @type {?Message}
+   * @readonly
+   */
+  get lastMessage() {
+    return this.messages.resolve(this.lastMessageId);
+  }
+
+  /**
+   * The date when the last pinned message was pinned, if there was one
+   * @type {?Date}
+   * @readonly
+   */
+  get lastPinAt() {
+    return this.lastPinTimestamp && new Date(this.lastPinTimestamp);
+  }
+
+  /**
+   * The base message options for messages.
+   * @typedef {Object} BaseMessageOptions
+   * @property {string|null} [content=''] The content for the message. This can only be `null` when editing a message.
+   * @property {Array<(EmbedBuilder|Embed|APIEmbed)>} [embeds] The embeds for the message
+   * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content
+   * (see [here](https://discord.com/developers/docs/resources/channel#allowed-mentions-object) for more details)
+   * @property {Array<(AttachmentBuilder|Attachment|AttachmentPayload|BufferResolvable)>} [files]
+   * The files to send with the message.
+   * @property {Array<(ActionRowBuilder|ActionRow|APIActionRowComponent)>} [components]
+   * Action rows containing interactive components for the message (buttons, select menus)
+   */
+
+  /**
+   * Options for sending a message with a reply.
+   * @typedef {Object} ReplyOptions
+   * @property {MessageResolvable} messageReference The message to reply to (must be in the same channel and not system)
+   * @property {boolean} [failIfNotExists=this.client.options.failIfNotExists] Whether to error if the referenced
+   * message does not exist (creates a standard message in this case when false)
+   */
+
+  /**
+   * The options for sending a message.
+   * @typedef {BaseMessageOptions} BaseMessageCreateOptions
+   * @property {boolean} [tts=false] Whether the message should be spoken aloud
+   * @property {string} [nonce=''] The nonce for the message
+   * @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message
+   * @property {MessageFlags} [flags] Which flags to set for the message.
+   * <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.</info>
+   */
+
+  /**
+   * The options for sending a message.
+   * @typedef {BaseMessageCreateOptions} MessageCreateOptions
+   * @property {ReplyOptions} [reply] The options for replying to a message
+   */
+
+  /**
+   * Options provided to control parsing of mentions by Discord
+   * @typedef {Object} MessageMentionOptions
+   * @property {MessageMentionTypes[]} [parse] Types of mentions to be parsed
+   * @property {Snowflake[]} [users] Snowflakes of Users to be parsed as mentions
+   * @property {Snowflake[]} [roles] Snowflakes of Roles to be parsed as mentions
+   * @property {boolean} [repliedUser=true] Whether the author of the Message being replied to should be pinged
+   */
+
+  /**
+   * Types of mentions to enable in MessageMentionOptions.
+   * - `roles`
+   * - `users`
+   * - `everyone`
+   * @typedef {string} MessageMentionTypes
+   */
+
+  /**
+   * @typedef {Object} FileOptions
+   * @property {BufferResolvable} attachment File to attach
+   * @property {string} [name='file.jpg'] Filename of the attachment
+   * @property {string} description The description of the file
+   */
+
+  /**
+   * Sends a message to this channel.
+   * @param {string|MessagePayload|MessageCreateOptions} options The options to provide
+   * @returns {Promise<Message>}
+   * @example
+   * // Send a basic message
+   * channel.send('hello!')
+   *   .then(message => console.log(`Sent message: ${message.content}`))
+   *   .catch(console.error);
+   * @example
+   * // Send a remote file
+   * channel.send({
+   *   files: ['https://cdn.discordapp.com/icons/222078108977594368/6e1019b3179d71046e463a75915e7244.png?size=2048']
+   * })
+   *   .then(console.log)
+   *   .catch(console.error);
+   * @example
+   * // Send a local file
+   * channel.send({
+   *   files: [{
+   *     attachment: 'entire/path/to/file.jpg',
+   *     name: 'file.jpg',
+   *     description: 'A description of the file'
+   *   }]
+   * })
+   *   .then(console.log)
+   *   .catch(console.error);
+   */
+  async send(options) {
+    const User = require('../User');
+    const { GuildMember } = require('../GuildMember');
+
+    if (this instanceof User || this instanceof GuildMember) {
+      const dm = await this.createDM();
+      return dm.send(options);
+    }
+
+    let messagePayload;
+
+    if (options instanceof MessagePayload) {
+      messagePayload = options.resolveBody();
+    } else {
+      messagePayload = MessagePayload.create(this, options).resolveBody();
+    }
+
+    const { body, files } = await messagePayload.resolveFiles();
+    const d = await this.client.rest.post(Routes.channelMessages(this.id), { body, files });
+
+    return this.messages.cache.get(d.id) ?? this.messages._add(d);
+  }
+
+  /**
+   * Sends a typing indicator in the channel.
+   * @returns {Promise<void>} Resolves upon the typing status being sent
+   * @example
+   * // Start typing in a channel
+   * channel.sendTyping();
+   */
+  async sendTyping() {
+    await this.client.rest.post(Routes.channelTyping(this.id));
+  }
+
+  /**
+   * Creates a Message Collector.
+   * @param {MessageCollectorOptions} [options={}] The options to pass to the collector
+   * @returns {MessageCollector}
+   * @example
+   * // Create a message collector
+   * const filter = m => m.content.includes('discord');
+   * const collector = channel.createMessageCollector({ filter, time: 15_000 });
+   * collector.on('collect', m => console.log(`Collected ${m.content}`));
+   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+   */
+  createMessageCollector(options = {}) {
+    return new MessageCollector(this, options);
+  }
+
+  /**
+   * An object containing the same properties as CollectorOptions, but a few more:
+   * @typedef {MessageCollectorOptions} AwaitMessagesOptions
+   * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
+   */
+
+  /**
+   * Similar to createMessageCollector but in promise form.
+   * Resolves with a collection of messages that pass the specified filter.
+   * @param {AwaitMessagesOptions} [options={}] Optional options to pass to the internal collector
+   * @returns {Promise<Collection<Snowflake, Message>>}
+   * @example
+   * // Await !vote messages
+   * const filter = m => m.content.startsWith('!vote');
+   * // Errors: ['time'] treats ending because of the time limit as an error
+   * channel.awaitMessages({ filter, max: 4, time: 60_000, errors: ['time'] })
+   *   .then(collected => console.log(collected.size))
+   *   .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`));
+   */
+  awaitMessages(options = {}) {
+    return new Promise((resolve, reject) => {
+      const collector = this.createMessageCollector(options);
+      collector.once('end', (collection, reason) => {
+        if (options.errors?.includes(reason)) {
+          reject(collection);
+        } else {
+          resolve(collection);
+        }
+      });
+    });
+  }
+
+  /**
+   * Creates a component interaction collector.
+   * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
+   * @returns {InteractionCollector}
+   * @example
+   * // Create a button interaction collector
+   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
+   * const collector = channel.createMessageComponentCollector({ filter, time: 15_000 });
+   * collector.on('collect', i => console.log(`Collected ${i.customId}`));
+   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+   */
+  createMessageComponentCollector(options = {}) {
+    return new InteractionCollector(this.client, {
+      ...options,
+      interactionType: InteractionType.MessageComponent,
+      channel: this,
+    });
+  }
+
+  /**
+   * Collects a single component interaction that passes the filter.
+   * The Promise will reject if the time expires.
+   * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector
+   * @returns {Promise<MessageComponentInteraction>}
+   * @example
+   * // Collect a message component interaction
+   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
+   * channel.awaitMessageComponent({ filter, time: 15_000 })
+   *   .then(interaction => console.log(`${interaction.customId} was clicked!`))
+   *   .catch(console.error);
+   */
+  awaitMessageComponent(options = {}) {
+    const _options = { ...options, max: 1 };
+    return new Promise((resolve, reject) => {
+      const collector = this.createMessageComponentCollector(_options);
+      collector.once('end', (interactions, reason) => {
+        const interaction = interactions.first();
+        if (interaction) resolve(interaction);
+        else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason));
+      });
+    });
+  }
+
+  /**
+   * Bulk deletes given messages that are newer than two weeks.
+   * @param {Collection<Snowflake, Message>|MessageResolvable[]|number} messages
+   * Messages or number of messages to delete
+   * @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
+   * @returns {Promise<Collection<Snowflake, Message|undefined>>} Returns the deleted messages
+   * @example
+   * // Bulk delete messages
+   * channel.bulkDelete(5)
+   *   .then(messages => console.log(`Bulk deleted ${messages.size} messages`))
+   *   .catch(console.error);
+   */
+  async bulkDelete(messages, filterOld = false) {
+    if (Array.isArray(messages) || messages instanceof Collection) {
+      let messageIds = messages instanceof Collection ? [...messages.keys()] : messages.map(m => m.id ?? m);
+      if (filterOld) {
+        messageIds = messageIds.filter(
+          id => Date.now() - DiscordSnowflake.timestampFrom(id) < MaxBulkDeletableMessageAge,
+        );
+      }
+      if (messageIds.length === 0) return new Collection();
+      if (messageIds.length === 1) {
+        const message = this.client.actions.MessageDelete.getMessage(
+          {
+            message_id: messageIds[0],
+          },
+          this,
+        );
+        await this.client.rest.delete(Routes.channelMessage(this.id, messageIds[0]));
+        return message ? new Collection([[message.id, message]]) : new Collection();
+      }
+      await this.client.rest.post(Routes.channelBulkDelete(this.id), { body: { messages: messageIds } });
+      return messageIds.reduce(
+        (col, id) =>
+          col.set(
+            id,
+            this.client.actions.MessageDeleteBulk.getMessage(
+              {
+                message_id: id,
+              },
+              this,
+            ),
+          ),
+        new Collection(),
+      );
+    }
+    if (!isNaN(messages)) {
+      const msgs = await this.messages.fetch({ limit: messages });
+      return this.bulkDelete(msgs, filterOld);
+    }
+    throw new DiscordjsTypeError(ErrorCodes.MessageBulkDeleteType);
+  }
+
+  /**
+   * Fetches all webhooks for the channel.
+   * @returns {Promise<Collection<Snowflake, Webhook>>}
+   * @example
+   * // Fetch webhooks
+   * channel.fetchWebhooks()
+   *   .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
+   *   .catch(console.error);
+   */
+  fetchWebhooks() {
+    return this.guild.channels.fetchWebhooks(this.id);
+  }
+
+  /**
+   * Options used to create a {@link Webhook}.
+   * @typedef {Object} ChannelWebhookCreateOptions
+   * @property {string} name The name of the webhook
+   * @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook
+   * @property {string} [reason] Reason for creating the webhook
+   */
+
+  /**
+   * Creates a webhook for the channel.
+   * @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook
+   * @returns {Promise<Webhook>} Returns the created Webhook
+   * @example
+   * // Create a webhook for the current channel
+   * channel.createWebhook({
+   *   name: 'Snek',
+   *   avatar: 'https://i.imgur.com/mI8XcpG.jpg',
+   *   reason: 'Needed a cool new Webhook'
+   * })
+   *   .then(console.log)
+   *   .catch(console.error)
+   */
+  createWebhook(options) {
+    return this.guild.channels.createWebhook({ channel: this.id, ...options });
+  }
+
+  /**
+   * Sets the rate limit per user (slowmode) for this channel.
+   * @param {number} rateLimitPerUser The new rate limit in seconds
+   * @param {string} [reason] Reason for changing the channel's rate limit
+   * @returns {Promise<this>}
+   */
+  setRateLimitPerUser(rateLimitPerUser, reason) {
+    return this.edit({ rateLimitPerUser, reason });
+  }
+
+  /**
+   * Sets whether this channel is flagged as NSFW.
+   * @param {boolean} [nsfw=true] Whether the channel should be considered NSFW
+   * @param {string} [reason] Reason for changing the channel's NSFW flag
+   * @returns {Promise<this>}
+   */
+  setNSFW(nsfw = true, reason) {
+    return this.edit({ nsfw, reason });
+  }
+
+  static applyToClass(structure, full = false, ignore = []) {
+    const props = ['send'];
+    if (full) {
+      props.push(
+        'lastMessage',
+        'lastPinAt',
+        'bulkDelete',
+        'sendTyping',
+        'createMessageCollector',
+        'awaitMessages',
+        'createMessageComponentCollector',
+        'awaitMessageComponent',
+        'fetchWebhooks',
+        'createWebhook',
+        'setRateLimitPerUser',
+        'setNSFW',
+      );
+    }
+    for (const prop of props) {
+      if (ignore.includes(prop)) continue;
+      Object.defineProperty(
+        structure.prototype,
+        prop,
+        Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop),
+      );
+    }
+  }
+}
+
+module.exports = TextBasedChannel;
+
+// Fixes Circular
+// eslint-disable-next-line import/order
+const GuildMessageManager = require('../../managers/GuildMessageManager');
-- 
cgit v1.2.3