summaryrefslogtreecommitdiff
path: root/node_modules/discord.js/src/structures
diff options
context:
space:
mode:
authorsowgro <tpoke.ferrari@gmail.com>2023-09-02 19:12:47 -0400
committersowgro <tpoke.ferrari@gmail.com>2023-09-02 19:12:47 -0400
commite4450c8417624b71d779cb4f41692538f9165e10 (patch)
treeb70826542223ecdf8a7a259f61b0a1abb8a217d8 /node_modules/discord.js/src/structures
downloadsowbot3-e4450c8417624b71d779cb4f41692538f9165e10.tar.gz
sowbot3-e4450c8417624b71d779cb4f41692538f9165e10.tar.bz2
sowbot3-e4450c8417624b71d779cb4f41692538f9165e10.zip
first commit
Diffstat (limited to 'node_modules/discord.js/src/structures')
-rw-r--r--node_modules/discord.js/src/structures/ActionRow.js46
-rw-r--r--node_modules/discord.js/src/structures/ActionRowBuilder.js35
-rw-r--r--node_modules/discord.js/src/structures/AnonymousGuild.js97
-rw-r--r--node_modules/discord.js/src/structures/ApplicationCommand.js606
-rw-r--r--node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js46
-rw-r--r--node_modules/discord.js/src/structures/Attachment.js151
-rw-r--r--node_modules/discord.js/src/structures/AttachmentBuilder.js116
-rw-r--r--node_modules/discord.js/src/structures/AutoModerationActionExecution.js116
-rw-r--r--node_modules/discord.js/src/structures/AutoModerationRule.js284
-rw-r--r--node_modules/discord.js/src/structures/AutocompleteInteraction.js102
-rw-r--r--node_modules/discord.js/src/structures/Base.js43
-rw-r--r--node_modules/discord.js/src/structures/BaseChannel.js155
-rw-r--r--node_modules/discord.js/src/structures/BaseGuild.js119
-rw-r--r--node_modules/discord.js/src/structures/BaseGuildEmoji.js56
-rw-r--r--node_modules/discord.js/src/structures/BaseGuildTextChannel.js186
-rw-r--r--node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js234
-rw-r--r--node_modules/discord.js/src/structures/BaseInteraction.js344
-rw-r--r--node_modules/discord.js/src/structures/BaseSelectMenuComponent.js56
-rw-r--r--node_modules/discord.js/src/structures/ButtonBuilder.js44
-rw-r--r--node_modules/discord.js/src/structures/ButtonComponent.js65
-rw-r--r--node_modules/discord.js/src/structures/ButtonInteraction.js11
-rw-r--r--node_modules/discord.js/src/structures/CategoryChannel.js45
-rw-r--r--node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js31
-rw-r--r--node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js20
-rw-r--r--node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js33
-rw-r--r--node_modules/discord.js/src/structures/ChatInputCommandInteraction.js41
-rw-r--r--node_modules/discord.js/src/structures/ClientApplication.js222
-rw-r--r--node_modules/discord.js/src/structures/ClientPresence.js90
-rw-r--r--node_modules/discord.js/src/structures/ClientUser.js187
-rw-r--r--node_modules/discord.js/src/structures/CommandInteraction.js224
-rw-r--r--node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js308
-rw-r--r--node_modules/discord.js/src/structures/Component.js47
-rw-r--r--node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js64
-rw-r--r--node_modules/discord.js/src/structures/DMChannel.js129
-rw-r--r--node_modules/discord.js/src/structures/DirectoryChannel.js36
-rw-r--r--node_modules/discord.js/src/structures/Embed.js220
-rw-r--r--node_modules/discord.js/src/structures/EmbedBuilder.js50
-rw-r--r--node_modules/discord.js/src/structures/Emoji.js108
-rw-r--r--node_modules/discord.js/src/structures/ForumChannel.js264
-rw-r--r--node_modules/discord.js/src/structures/Guild.js1367
-rw-r--r--node_modules/discord.js/src/structures/GuildAuditLogs.js91
-rw-r--r--node_modules/discord.js/src/structures/GuildAuditLogsEntry.js528
-rw-r--r--node_modules/discord.js/src/structures/GuildBan.js59
-rw-r--r--node_modules/discord.js/src/structures/GuildChannel.js472
-rw-r--r--node_modules/discord.js/src/structures/GuildEmoji.js148
-rw-r--r--node_modules/discord.js/src/structures/GuildMember.js520
-rw-r--r--node_modules/discord.js/src/structures/GuildOnboarding.js58
-rw-r--r--node_modules/discord.js/src/structures/GuildOnboardingPrompt.js78
-rw-r--r--node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js84
-rw-r--r--node_modules/discord.js/src/structures/GuildPreview.js193
-rw-r--r--node_modules/discord.js/src/structures/GuildPreviewEmoji.js27
-rw-r--r--node_modules/discord.js/src/structures/GuildScheduledEvent.js439
-rw-r--r--node_modules/discord.js/src/structures/GuildTemplate.js241
-rw-r--r--node_modules/discord.js/src/structures/Integration.js220
-rw-r--r--node_modules/discord.js/src/structures/IntegrationApplication.js85
-rw-r--r--node_modules/discord.js/src/structures/InteractionCollector.js269
-rw-r--r--node_modules/discord.js/src/structures/InteractionResponse.js102
-rw-r--r--node_modules/discord.js/src/structures/InteractionWebhook.js59
-rw-r--r--node_modules/discord.js/src/structures/Invite.js322
-rw-r--r--node_modules/discord.js/src/structures/InviteGuild.js22
-rw-r--r--node_modules/discord.js/src/structures/InviteStageInstance.js87
-rw-r--r--node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js32
-rw-r--r--node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js11
-rw-r--r--node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js71
-rw-r--r--node_modules/discord.js/src/structures/Message.js997
-rw-r--r--node_modules/discord.js/src/structures/MessageCollector.js146
-rw-r--r--node_modules/discord.js/src/structures/MessageComponentInteraction.js107
-rw-r--r--node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js20
-rw-r--r--node_modules/discord.js/src/structures/MessageMentions.js297
-rw-r--r--node_modules/discord.js/src/structures/MessagePayload.js299
-rw-r--r--node_modules/discord.js/src/structures/MessageReaction.js142
-rw-r--r--node_modules/discord.js/src/structures/ModalBuilder.js34
-rw-r--r--node_modules/discord.js/src/structures/ModalSubmitFields.js55
-rw-r--r--node_modules/discord.js/src/structures/ModalSubmitInteraction.js122
-rw-r--r--node_modules/discord.js/src/structures/NewsChannel.js32
-rw-r--r--node_modules/discord.js/src/structures/OAuth2Guild.js28
-rw-r--r--node_modules/discord.js/src/structures/PartialGroupDMChannel.js60
-rw-r--r--node_modules/discord.js/src/structures/PermissionOverwrites.js196
-rw-r--r--node_modules/discord.js/src/structures/Presence.js378
-rw-r--r--node_modules/discord.js/src/structures/ReactionCollector.js229
-rw-r--r--node_modules/discord.js/src/structures/ReactionEmoji.js31
-rw-r--r--node_modules/discord.js/src/structures/Role.js471
-rw-r--r--node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js31
-rw-r--r--node_modules/discord.js/src/structures/RoleSelectMenuComponent.js11
-rw-r--r--node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js33
-rw-r--r--node_modules/discord.js/src/structures/SelectMenuBuilder.js26
-rw-r--r--node_modules/discord.js/src/structures/SelectMenuComponent.js26
-rw-r--r--node_modules/discord.js/src/structures/SelectMenuInteraction.js26
-rw-r--r--node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js26
-rw-r--r--node_modules/discord.js/src/structures/StageChannel.js112
-rw-r--r--node_modules/discord.js/src/structures/StageInstance.js167
-rw-r--r--node_modules/discord.js/src/structures/Sticker.js272
-rw-r--r--node_modules/discord.js/src/structures/StickerPack.js95
-rw-r--r--node_modules/discord.js/src/structures/StringSelectMenuBuilder.js79
-rw-r--r--node_modules/discord.js/src/structures/StringSelectMenuComponent.js20
-rw-r--r--node_modules/discord.js/src/structures/StringSelectMenuInteraction.js21
-rw-r--r--node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js49
-rw-r--r--node_modules/discord.js/src/structures/Team.js117
-rw-r--r--node_modules/discord.js/src/structures/TeamMember.js70
-rw-r--r--node_modules/discord.js/src/structures/TextChannel.js33
-rw-r--r--node_modules/discord.js/src/structures/TextInputBuilder.js31
-rw-r--r--node_modules/discord.js/src/structures/TextInputComponent.js29
-rw-r--r--node_modules/discord.js/src/structures/ThreadChannel.js606
-rw-r--r--node_modules/discord.js/src/structures/ThreadMember.js113
-rw-r--r--node_modules/discord.js/src/structures/Typing.js74
-rw-r--r--node_modules/discord.js/src/structures/User.js380
-rw-r--r--node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js29
-rw-r--r--node_modules/discord.js/src/structures/UserSelectMenuBuilder.js31
-rw-r--r--node_modules/discord.js/src/structures/UserSelectMenuComponent.js11
-rw-r--r--node_modules/discord.js/src/structures/UserSelectMenuInteraction.js51
-rw-r--r--node_modules/discord.js/src/structures/VoiceChannel.js96
-rw-r--r--node_modules/discord.js/src/structures/VoiceRegion.js46
-rw-r--r--node_modules/discord.js/src/structures/VoiceState.js303
-rw-r--r--node_modules/discord.js/src/structures/Webhook.js479
-rw-r--r--node_modules/discord.js/src/structures/WelcomeChannel.js60
-rw-r--r--node_modules/discord.js/src/structures/WelcomeScreen.js49
-rw-r--r--node_modules/discord.js/src/structures/Widget.js88
-rw-r--r--node_modules/discord.js/src/structures/WidgetMember.js99
-rw-r--r--node_modules/discord.js/src/structures/interfaces/Application.js108
-rw-r--r--node_modules/discord.js/src/structures/interfaces/Collector.js335
-rw-r--r--node_modules/discord.js/src/structures/interfaces/InteractionResponses.js320
-rw-r--r--node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js413
122 files changed, 19225 insertions, 0 deletions
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');