diff options
author | sowgro <tpoke.ferrari@gmail.com> | 2023-09-02 19:12:47 -0400 |
---|---|---|
committer | sowgro <tpoke.ferrari@gmail.com> | 2023-09-02 19:12:47 -0400 |
commit | e4450c8417624b71d779cb4f41692538f9165e10 (patch) | |
tree | b70826542223ecdf8a7a259f61b0a1abb8a217d8 /node_modules/discord.js/src/util | |
download | sowbot3-e4450c8417624b71d779cb4f41692538f9165e10.tar.gz sowbot3-e4450c8417624b71d779cb4f41692538f9165e10.tar.bz2 sowbot3-e4450c8417624b71d779cb4f41692538f9165e10.zip |
first commit
Diffstat (limited to 'node_modules/discord.js/src/util')
32 files changed, 3813 insertions, 0 deletions
diff --git a/node_modules/discord.js/src/util/APITypes.js b/node_modules/discord.js/src/util/APITypes.js new file mode 100644 index 0000000..e8ab25a --- /dev/null +++ b/node_modules/discord.js/src/util/APITypes.js @@ -0,0 +1,476 @@ +/* eslint-disable max-len */ + +/** + * @external ActivityFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityFlags} + */ + +/** + * @external ActivityType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityType} + */ + +/** + * @external APIActionRowComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIActionRowComponent} + */ + +/** + * @external APIApplication + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIApplication} + */ + +/** + * @external APIApplicationCommand + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIApplicationCommand} + */ + +/** + * @external APIApplicationCommandOption + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIApplicationCommandOption} + */ + +/** + * @external APIAutoModerationAction + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIAutoModerationAction} + */ + +/** + * @external APIButtonComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIButtonComponent} + */ + +/** + * @external APIChannel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannel} + */ + +/** + * @external APIChannelSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannelSelectComponent} + */ + +/** + * @external APIEmbed + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbed} + */ + +/** + * @external APIEmbedField + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbedField} + */ + +/** + * @external APIEmbedProvider + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbedProvider} + */ + +/** + * @external APIEmoji + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmoji} + */ + +/** + * @external APIGuild + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuild} + */ + +/** + * @external APIGuildForumDefaultReactionEmoji + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumDefaultReactionEmoji} + */ + +/** + * @external APIGuildForumTag + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumTag} + */ + +/** + * @external APIInteraction + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIInteraction} + */ + +/** + * @external APIInteractionDataResolvedChannel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionDataResolvedChannel} + */ + +/** + * @external APIInteractionDataResolvedGuildMember + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionDataResolvedGuildMember} + */ + +/** + * @external APIInteractionGuildMember + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionGuildMember} + */ + +/** + * @external APIMentionableSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMentionableSelectComponent} + */ + +/** + * @external APIMessage + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessage} + */ + +/** + * @external APIMessageActionRowComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageActionRowComponent} + */ + +/** + * @external APIMessageComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageComponent} + */ + +/** + * @external APIMessageComponentEmoji + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageComponentEmoji} + */ + +/** + * @external APIModalInteractionResponse + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse} + */ + +/** + * @external APIModalInteractionResponseCallbackData + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponseCallbackData} + */ + +/** + * @external APIModalComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIModalComponent} + */ + +/** + * @external APIModalSubmission + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalSubmission} + */ + +/** + * @external APIPresence + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIPresence} + */ + +/** + * @external APIRoleSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIRoleSelectComponent} + */ + +/** + * @external APISelectMenuOption + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption} + */ + +/** + * @external APIStringSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIStringSelectComponent} + */ + +/** + * @external APITextInputComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APITextInputComponent} + */ + +/** + * @external APIUser + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUser} + */ + +/** + * @external APIUserSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIUserSelectComponent} + */ + +/** + * @external ApplicationCommandType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandType} + */ + +/** + * @external ApplicationCommandOptionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandOptionType} + */ + +/** + * @external ApplicationCommandPermissionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandPermissionType} + */ + +/** + * @external ApplicationFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationFlags} + */ + +/** + * @external ApplicationRoleConnectionMetadataType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationRoleConnectionMetadataType} + */ + +/** + * @external AttachmentFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AttachmentFlags} + */ + +/** + * @external AutoModerationActionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationActionType} + */ + +/** + * @external AutoModerationRuleEventType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleEventType} + */ + +/** + * @external AutoModerationRuleTriggerType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleTriggerType} + */ + +/** + * @external AutoModerationRuleKeywordPresetType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleKeywordPresetType} + */ + +/** + * @external AuditLogEvent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AuditLogEvent} + */ + +/** + * @external ButtonStyle + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ButtonStyle} + */ + +/** + * @external ChannelFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelFlags} + */ + +/** + * @external ChannelType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelType} + */ + +/** + * @external ComponentType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ComponentType} + */ + +/** + * @external ForumLayoutType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ForumLayoutType} + */ + +/** + * @external GatewayCloseCodes + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayCloseCodes} + */ + +/** + * @external GatewayDispatchEvents + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayDispatchEvents} + */ + +/** + * @external GatewayIntentBits + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayIntentBits} + */ + +/** + * @external GatewayOpcodes + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayOpcodes} + */ + +/** + * @external GuildDefaultMessageNotifications + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildDefaultMessageNotifications} + */ + +/** + * @external GuildExplicitContentFilter + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildExplicitContentFilter} + */ + +/** + * @external GuildFeature + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildFeature} + */ + +/** + * @external GuildMFALevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMFALevel} + */ + +/** + * @external GuildMemberFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMemberFlags} + */ + +/** + * @external GuildNSFWLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildNSFWLevel} + */ + +/** + * @external GuildOnboardingPromptType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildOnboardingPromptType} + */ + +/** + * @external GuildPremiumTier + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildPremiumTier} + */ + +/** + * @external GuildScheduledEventEntityType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventEntityType} + */ + +/** + * @external GuildScheduledEventPrivacyLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventPrivacyLevel} + */ + +/** + * @external GuildScheduledEventStatus + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventStatus} + */ + +/** + * @external GuildSystemChannelFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildSystemChannelFlags} + */ + +/** + * @external GuildVerificationLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildVerificationLevel} + */ + +/** + * @external IntegrationExpireBehavior + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/IntegrationExpireBehavior} + */ + +/** + * @external InteractionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionType} + */ + +/** + * @external InteractionResponseType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionResponseType} + */ + +/** + * @external InviteTargetType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InviteTargetType} + */ + +/** + * @external Locale + * @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common/enum/Locale} + */ + +/** + * @external LocaleString + * @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common#LocaleString} + */ + +/** + * @external MessageActivityType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageActivityType} + */ + +/** + * @external MessageType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageType} + */ + +/** + * @external MessageFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageFlags} + */ + +/** + * @external OAuth2Scopes + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OAuth2Scopes} + */ + +/** + * @external OverwriteType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OverwriteType} + */ + +/** + * @external PermissionFlagsBits + * @see {@link https://discord-api-types.dev/api/discord-api-types-payloads/common#PermissionFlagsBits} + */ + +/** + * @external RoleFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/RoleFlags} + */ + +/** + * @external RESTGetAPIGuildThreadsResult + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#RESTGetAPIGuildThreadsResult} + */ + +/** + * @external RESTJSONErrorCodes + * @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common/enum/RESTJSONErrorCodes} + */ + +/** + * @external SortOrderType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/SortOrderType} + */ + +/** + * @external StageInstancePrivacyLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StageInstancePrivacyLevel} + */ + +/** + * @external StickerType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StickerType} + */ + +/** + * @external StickerFormatType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StickerFormatType} + */ + +/** + * @external TeamMemberMembershipState + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/TeamMemberMembershipState} + */ + +/** + * @external TextInputStyle + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/TextInputStyle} + */ + +/** + * @external ThreadAutoArchiveDuration + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadAutoArchiveDuration} + */ + +/** + * @external UserFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags} + */ + +/** + * @external VideoQualityMode + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/VideoQualityMode} + */ + +/** + * @external WebhookType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/WebhookType} + */ diff --git a/node_modules/discord.js/src/util/ActivityFlagsBitField.js b/node_modules/discord.js/src/util/ActivityFlagsBitField.js new file mode 100644 index 0000000..7c0ef76 --- /dev/null +++ b/node_modules/discord.js/src/util/ActivityFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { ActivityFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with an {@link Activity#flags} bitfield. + * @extends {BitField} + */ +class ActivityFlagsBitField extends BitField { + /** + * Numeric activity flags. + * @type {ActivityFlags} + * @memberof ActivityFlagsBitField + */ + static Flags = ActivityFlags; +} + +/** + * @name ActivityFlagsBitField + * @kind constructor + * @memberof ActivityFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = ActivityFlagsBitField; diff --git a/node_modules/discord.js/src/util/ApplicationFlagsBitField.js b/node_modules/discord.js/src/util/ApplicationFlagsBitField.js new file mode 100644 index 0000000..6a5a9fe --- /dev/null +++ b/node_modules/discord.js/src/util/ApplicationFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { ApplicationFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link ClientApplication#flags} bitfield. + * @extends {BitField} + */ +class ApplicationFlagsBitField extends BitField { + /** + * Numeric application flags. All available properties: + * @type {ApplicationFlags} + * @memberof ApplicationFlagsBitField + */ + static Flags = ApplicationFlags; +} + +/** + * @name ApplicationFlagsBitField + * @kind constructor + * @memberof ApplicationFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = ApplicationFlagsBitField; diff --git a/node_modules/discord.js/src/util/AttachmentFlagsBitField.js b/node_modules/discord.js/src/util/AttachmentFlagsBitField.js new file mode 100644 index 0000000..f7f2bd2 --- /dev/null +++ b/node_modules/discord.js/src/util/AttachmentFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { AttachmentFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with an {@link Attachment#flags} bitfield. + * @extends {BitField} + */ +class AttachmentFlagsBitField extends BitField { + /** + * Numeric attachment flags. + * @type {AttachmentFlags} + * @memberof AttachmentFlagsBitField + */ + static Flags = AttachmentFlags; +} + +/** + * @name AttachmentFlagsBitField + * @kind constructor + * @memberof AttachmentFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = AttachmentFlagsBitField; diff --git a/node_modules/discord.js/src/util/BitField.js b/node_modules/discord.js/src/util/BitField.js new file mode 100644 index 0000000..f0778f6 --- /dev/null +++ b/node_modules/discord.js/src/util/BitField.js @@ -0,0 +1,176 @@ +'use strict'; + +const { DiscordjsRangeError, ErrorCodes } = require('../errors'); + +/** + * Data structure that makes it easy to interact with a bitfield. + */ +class BitField { + /** + * Numeric bitfield flags. + * <info>Defined in extension classes</info> + * @type {Object} + * @memberof BitField + * @abstract + */ + static Flags = {}; + + /** + * @type {number|bigint} + * @memberof BitField + * @private + */ + static DefaultBit = 0; + + /** + * @param {BitFieldResolvable} [bits=this.constructor.DefaultBit] Bit(s) to read from + */ + constructor(bits = this.constructor.DefaultBit) { + /** + * Bitfield of the packed bits + * @type {number|bigint} + */ + this.bitfield = this.constructor.resolve(bits); + } + + /** + * Checks whether the bitfield has a bit, or any of multiple bits. + * @param {BitFieldResolvable} bit Bit(s) to check for + * @returns {boolean} + */ + any(bit) { + return (this.bitfield & this.constructor.resolve(bit)) !== this.constructor.DefaultBit; + } + + /** + * Checks if this bitfield equals another + * @param {BitFieldResolvable} bit Bit(s) to check for + * @returns {boolean} + */ + equals(bit) { + return this.bitfield === this.constructor.resolve(bit); + } + + /** + * Checks whether the bitfield has a bit, or multiple bits. + * @param {BitFieldResolvable} bit Bit(s) to check for + * @returns {boolean} + */ + has(bit) { + bit = this.constructor.resolve(bit); + return (this.bitfield & bit) === bit; + } + + /** + * Gets all given bits that are missing from the bitfield. + * @param {BitFieldResolvable} bits Bit(s) to check for + * @param {...*} hasParams Additional parameters for the has method, if any + * @returns {string[]} + */ + missing(bits, ...hasParams) { + return new this.constructor(bits).remove(this).toArray(...hasParams); + } + + /** + * Freezes these bits, making them immutable. + * @returns {Readonly<BitField>} + */ + freeze() { + return Object.freeze(this); + } + + /** + * Adds bits to these ones. + * @param {...BitFieldResolvable} [bits] Bits to add + * @returns {BitField} These bits or new BitField if the instance is frozen. + */ + add(...bits) { + let total = this.constructor.DefaultBit; + for (const bit of bits) { + total |= this.constructor.resolve(bit); + } + if (Object.isFrozen(this)) return new this.constructor(this.bitfield | total); + this.bitfield |= total; + return this; + } + + /** + * Removes bits from these. + * @param {...BitFieldResolvable} [bits] Bits to remove + * @returns {BitField} These bits or new BitField if the instance is frozen. + */ + remove(...bits) { + let total = this.constructor.DefaultBit; + for (const bit of bits) { + total |= this.constructor.resolve(bit); + } + if (Object.isFrozen(this)) return new this.constructor(this.bitfield & ~total); + this.bitfield &= ~total; + return this; + } + + /** + * Gets an object mapping field names to a {@link boolean} indicating whether the + * bit is available. + * @param {...*} hasParams Additional parameters for the has method, if any + * @returns {Object} + */ + serialize(...hasParams) { + const serialized = {}; + for (const [flag, bit] of Object.entries(this.constructor.Flags)) { + if (isNaN(flag)) serialized[flag] = this.has(bit, ...hasParams); + } + return serialized; + } + + /** + * Gets an {@link Array} of bitfield names based on the bits available. + * @param {...*} hasParams Additional parameters for the has method, if any + * @returns {string[]} + */ + toArray(...hasParams) { + return [...this[Symbol.iterator](...hasParams)]; + } + + toJSON() { + return typeof this.bitfield === 'number' ? this.bitfield : this.bitfield.toString(); + } + + valueOf() { + return this.bitfield; + } + + *[Symbol.iterator](...hasParams) { + for (const bitName of Object.keys(this.constructor.Flags)) { + if (isNaN(bitName) && this.has(bitName, ...hasParams)) yield bitName; + } + } + + /** + * Data that can be resolved to give a bitfield. This can be: + * * A bit number (this can be a number literal or a value taken from {@link BitField.Flags}) + * * A string bit number + * * An instance of BitField + * * An Array of BitFieldResolvable + * @typedef {number|string|bigint|BitField|BitFieldResolvable[]} BitFieldResolvable + */ + + /** + * Resolves bitfields to their numeric form. + * @param {BitFieldResolvable} [bit] bit(s) to resolve + * @returns {number|bigint} + */ + static resolve(bit) { + const { DefaultBit } = this; + if (typeof DefaultBit === typeof bit && bit >= DefaultBit) return bit; + if (bit instanceof BitField) return bit.bitfield; + if (Array.isArray(bit)) return bit.map(p => this.resolve(p)).reduce((prev, p) => prev | p, DefaultBit); + if (typeof bit === 'string') { + if (!isNaN(bit)) return typeof DefaultBit === 'bigint' ? BigInt(bit) : Number(bit); + if (this.Flags[bit] !== undefined) return this.Flags[bit]; + } + throw new DiscordjsRangeError(ErrorCodes.BitFieldInvalid, bit); + } +} + +module.exports = BitField; diff --git a/node_modules/discord.js/src/util/ChannelFlagsBitField.js b/node_modules/discord.js/src/util/ChannelFlagsBitField.js new file mode 100644 index 0000000..ad987e1 --- /dev/null +++ b/node_modules/discord.js/src/util/ChannelFlagsBitField.js @@ -0,0 +1,41 @@ +'use strict'; + +const { ChannelFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link BaseChannel#flags} bitfield. + * @extends {BitField} + */ +class ChannelFlagsBitField extends BitField { + /** + * Numeric guild channel flags. + * @type {ChannelFlags} + * @memberof ChannelFlagsBitField + */ + static Flags = ChannelFlags; +} + +/** + * @name ChannelFlagsBitField + * @kind constructor + * @memberof ChannelFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name ChannelFlagsBitField#bitfield + */ + +/** + * Data that can be resolved to give a channel flag bitfield. This can be: + * * A string (see {@link ChannelFlagsBitField.Flags}) + * * A channel flag + * * An instance of ChannelFlagsBitField + * * An Array of ChannelFlagsResolvable + * @typedef {string|number|ChannelFlagsBitField|ChannelFlagsResolvable[]} ChannelFlagsResolvable + */ + +module.exports = ChannelFlagsBitField; diff --git a/node_modules/discord.js/src/util/Channels.js b/node_modules/discord.js/src/util/Channels.js new file mode 100644 index 0000000..8d070bd --- /dev/null +++ b/node_modules/discord.js/src/util/Channels.js @@ -0,0 +1,150 @@ +'use strict'; + +const { lazy } = require('@discordjs/util'); +const { ChannelType } = require('discord-api-types/v10'); + +const getCategoryChannel = lazy(() => require('../structures/CategoryChannel')); +const getDMChannel = lazy(() => require('../structures/DMChannel')); +const getNewsChannel = lazy(() => require('../structures/NewsChannel')); +const getStageChannel = lazy(() => require('../structures/StageChannel')); +const getTextChannel = lazy(() => require('../structures/TextChannel')); +const getThreadChannel = lazy(() => require('../structures/ThreadChannel')); +const getVoiceChannel = lazy(() => require('../structures/VoiceChannel')); +const getDirectoryChannel = lazy(() => require('../structures/DirectoryChannel')); +const getPartialGroupDMChannel = lazy(() => require('../structures/PartialGroupDMChannel')); +const getForumChannel = lazy(() => require('../structures/ForumChannel')); + +/** + * Creates a discord.js channel from data received from the API. + * @param {Client} client The client + * @param {APIChannel} data The data of the channel to create + * @param {Guild} [guild] The guild where this channel belongs + * @param {Object} [extras] Extra information to supply for creating this channel + * @returns {BaseChannel} Any kind of channel. + * @ignore + */ +function createChannel(client, data, guild, { allowUnknownGuild } = {}) { + let channel; + if (!data.guild_id && !guild) { + if ((data.recipients && data.type !== ChannelType.GroupDM) || data.type === ChannelType.DM) { + channel = new (getDMChannel())(client, data); + } else if (data.type === ChannelType.GroupDM) { + channel = new (getPartialGroupDMChannel())(client, data); + } + } else { + guild ??= client.guilds.cache.get(data.guild_id); + + if (guild || allowUnknownGuild) { + switch (data.type) { + case ChannelType.GuildText: { + channel = new (getTextChannel())(guild, data, client); + break; + } + case ChannelType.GuildVoice: { + channel = new (getVoiceChannel())(guild, data, client); + break; + } + case ChannelType.GuildCategory: { + channel = new (getCategoryChannel())(guild, data, client); + break; + } + case ChannelType.GuildAnnouncement: { + channel = new (getNewsChannel())(guild, data, client); + break; + } + case ChannelType.GuildStageVoice: { + channel = new (getStageChannel())(guild, data, client); + break; + } + case ChannelType.AnnouncementThread: + case ChannelType.PublicThread: + case ChannelType.PrivateThread: { + channel = new (getThreadChannel())(guild, data, client); + if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel); + break; + } + case ChannelType.GuildDirectory: + channel = new (getDirectoryChannel())(guild, data, client); + break; + case ChannelType.GuildForum: + channel = new (getForumChannel())(guild, data, client); + break; + } + if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel); + } + } + return channel; +} + +/** + * Transforms an API guild forum tag to camel-cased guild forum tag. + * @param {APIGuildForumTag} tag The tag to transform + * @returns {GuildForumTag} + * @ignore + */ +function transformAPIGuildForumTag(tag) { + return { + id: tag.id, + name: tag.name, + moderated: tag.moderated, + emoji: + tag.emoji_id ?? tag.emoji_name + ? { + id: tag.emoji_id, + name: tag.emoji_name, + } + : null, + }; +} + +/** + * Transforms a camel-cased guild forum tag to an API guild forum tag. + * @param {GuildForumTag} tag The tag to transform + * @returns {APIGuildForumTag} + * @ignore + */ +function transformGuildForumTag(tag) { + return { + id: tag.id, + name: tag.name, + moderated: tag.moderated, + emoji_id: tag.emoji?.id ?? null, + emoji_name: tag.emoji?.name ?? null, + }; +} + +/** + * Transforms an API guild forum default reaction object to a + * camel-cased guild forum default reaction object. + * @param {APIGuildForumDefaultReactionEmoji} defaultReaction The default reaction to transform + * @returns {DefaultReactionEmoji} + * @ignore + */ +function transformAPIGuildDefaultReaction(defaultReaction) { + return { + id: defaultReaction.emoji_id, + name: defaultReaction.emoji_name, + }; +} + +/** + * Transforms a camel-cased guild forum default reaction object to an + * API guild forum default reaction object. + * @param {DefaultReactionEmoji} defaultReaction The default reaction to transform + * @returns {APIGuildForumDefaultReactionEmoji} + * @ignore + */ +function transformGuildDefaultReaction(defaultReaction) { + return { + emoji_id: defaultReaction.id, + emoji_name: defaultReaction.name, + }; +} + +module.exports = { + createChannel, + transformAPIGuildForumTag, + transformGuildForumTag, + transformAPIGuildDefaultReaction, + transformGuildDefaultReaction, +}; diff --git a/node_modules/discord.js/src/util/Colors.js b/node_modules/discord.js/src/util/Colors.js new file mode 100644 index 0000000..a2d35e5 --- /dev/null +++ b/node_modules/discord.js/src/util/Colors.js @@ -0,0 +1,73 @@ +'use strict'; + +/** + * @typedef {Object} Colors + * @property {number} Default 0x000000 | rgb(0,0,0) + * @property {number} White 0xFFFFFF | rgb(255,255,255) + * @property {number} Aqua 0x1ABC9C | rgb(26,188,156) + * @property {number} Green 0x57F287 | rgb(87,242,135) + * @property {number} Blue 0x3498DB | rgb(52,152,219) + * @property {number} Yellow 0xFEE75C | rgb(254,231,92) + * @property {number} Purple 0x9B59B6 | rgb(155,89,182) + * @property {number} LuminousVividPink 0xE91E63 | rgb(233,30,99) + * @property {number} Fuchsia 0xEB459E | rgb(235,69,158) + * @property {number} Gold 0xF1C40F | rgb(241,196,15) + * @property {number} Orange 0xE67E22 | rgb(230,126,34) + * @property {number} Red 0xED4245 | rgb(237,66,69) + * @property {number} Grey 0x95A5A6 | rgb(149,165,166) + * @property {number} Navy 0x34495E | rgb(52,73,94) + * @property {number} DarkAqua 0x11806A | rgb(17,128,106) + * @property {number} DarkGreen 0x1F8B4C | rgb(31,139,76) + * @property {number} DarkBlue 0x206694 | rgb(32,102,148) + * @property {number} DarkPurple 0x71368A | rgb(113,54,138) + * @property {number} DarkVividPink 0xAD1457 | rgb(173,20,87) + * @property {number} DarkGold 0xC27C0E | rgb(194,124,14) + * @property {number} DarkOrange 0xA84300 | rgb(168,67,0) + * @property {number} DarkRed 0x992D22 | rgb(153,45,34) + * @property {number} DarkGrey 0x979C9F | rgb(151,156,159) + * @property {number} DarkerGrey 0x7F8C8D | rgb(127,140,141) + * @property {number} LightGrey 0xBCC0C0 | rgb(188,192,192) + * @property {number} DarkNavy 0x2C3E50 | rgb(44,62,80) + * @property {number} Blurple 0x5865F2 | rgb(88,101,242) + * @property {number} Greyple 0x99AAb5 | rgb(153,170,181) + * @property {number} DarkButNotBlack 0x2C2F33 | rgb(44,47,51) + * @property {number} NotQuiteBlack 0x23272A | rgb(35,39,42) + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Colors} + * @ignore + */ +module.exports = { + Default: 0x000000, + White: 0xffffff, + Aqua: 0x1abc9c, + Green: 0x57f287, + Blue: 0x3498db, + Yellow: 0xfee75c, + Purple: 0x9b59b6, + LuminousVividPink: 0xe91e63, + Fuchsia: 0xeb459e, + Gold: 0xf1c40f, + Orange: 0xe67e22, + Red: 0xed4245, + Grey: 0x95a5a6, + Navy: 0x34495e, + DarkAqua: 0x11806a, + DarkGreen: 0x1f8b4c, + DarkBlue: 0x206694, + DarkPurple: 0x71368a, + DarkVividPink: 0xad1457, + DarkGold: 0xc27c0e, + DarkOrange: 0xa84300, + DarkRed: 0x992d22, + DarkGrey: 0x979c9f, + DarkerGrey: 0x7f8c8d, + LightGrey: 0xbcc0c0, + DarkNavy: 0x2c3e50, + Blurple: 0x5865f2, + Greyple: 0x99aab5, + DarkButNotBlack: 0x2c2f33, + NotQuiteBlack: 0x23272a, +}; diff --git a/node_modules/discord.js/src/util/Components.js b/node_modules/discord.js/src/util/Components.js new file mode 100644 index 0000000..1a2ccbc --- /dev/null +++ b/node_modules/discord.js/src/util/Components.js @@ -0,0 +1,152 @@ +'use strict'; + +// This file contains the typedefs for camel-cased JSON data +const { ComponentBuilder } = require('@discordjs/builders'); +const { ComponentType } = require('discord-api-types/v10'); +/** + * @typedef {Object} BaseComponentData + * @property {ComponentType} type The type of component + */ + +/** + * @typedef {BaseComponentData} ActionRowData + * @property {ComponentData[]} components The components in this action row + */ + +/** + * @typedef {BaseComponentData} ButtonComponentData + * @property {ButtonStyle} style The style of the button + * @property {?boolean} disabled Whether this button is disabled + * @property {string} label The label of this button + * @property {?APIMessageComponentEmoji} emoji The emoji on this button + * @property {?string} customId The custom id of the button + * @property {?string} url The URL of the button + */ + +/** + * @typedef {object} SelectMenuComponentOptionData + * @property {string} label The label of the option + * @property {string} value The value of the option + * @property {?string} description The description of the option + * @property {?APIMessageComponentEmoji} emoji The emoji on the option + * @property {?boolean} default Whether this option is selected by default + */ + +/** + * @typedef {BaseComponentData} SelectMenuComponentData + * @property {string} customId The custom id of the select menu + * @property {?boolean} disabled Whether the select menu is disabled or not + * @property {?number} maxValues The maximum amount of options that can be selected + * @property {?number} minValues The minimum amount of options that can be selected + * @property {?SelectMenuComponentOptionData[]} options The options in this select menu + * @property {?string} placeholder The placeholder of the select menu + */ + +/** + * @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData} MessageComponentData + */ + +/** + * @typedef {BaseComponentData} TextInputComponentData + * @property {string} customId The custom id of the text input + * @property {TextInputStyle} style The style of the text input + * @property {string} label The text that appears on top of the text input field + * @property {?number} minLength The minimum number of characters that can be entered in the text input + * @property {?number} maxLength The maximum number of characters that can be entered in the text input + * @property {?boolean} required Whether or not the text input is required or not + * @property {?string} value The pre-filled text in the text input + * @property {?string} placeholder Placeholder for the text input + */ + +/** + * @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData|TextInputComponentData} ComponentData + */ + +/** + * Any emoji data that can be used within a button + * @typedef {APIMessageComponentEmoji|string} ComponentEmojiResolvable + */ + +/** + * Transforms API data into a component + * @param {APIMessageComponent|Component} data The data to create the component from + * @returns {Component} + */ +function createComponent(data) { + if (data instanceof Component) { + return data; + } + + switch (data.type) { + case ComponentType.ActionRow: + return new ActionRow(data); + case ComponentType.Button: + return new ButtonComponent(data); + case ComponentType.StringSelect: + return new StringSelectMenuComponent(data); + case ComponentType.TextInput: + return new TextInputComponent(data); + case ComponentType.UserSelect: + return new UserSelectMenuComponent(data); + case ComponentType.RoleSelect: + return new RoleSelectMenuComponent(data); + case ComponentType.MentionableSelect: + return new MentionableSelectMenuComponent(data); + case ComponentType.ChannelSelect: + return new ChannelSelectMenuComponent(data); + default: + return new Component(data); + } +} + +/** + * Transforms API data into a component builder + * @param {APIMessageComponent|ComponentBuilder} data The data to create the component from + * @returns {ComponentBuilder} + */ +function createComponentBuilder(data) { + if (data instanceof ComponentBuilder) { + return data; + } + + switch (data.type) { + case ComponentType.ActionRow: + return new ActionRowBuilder(data); + case ComponentType.Button: + return new ButtonBuilder(data); + case ComponentType.StringSelect: + return new StringSelectMenuBuilder(data); + case ComponentType.TextInput: + return new TextInputBuilder(data); + case ComponentType.UserSelect: + return new UserSelectMenuBuilder(data); + case ComponentType.RoleSelect: + return new RoleSelectMenuBuilder(data); + case ComponentType.MentionableSelect: + return new MentionableSelectMenuBuilder(data); + case ComponentType.ChannelSelect: + return new ChannelSelectMenuBuilder(data); + default: + return new ComponentBuilder(data); + } +} + +module.exports = { createComponent, createComponentBuilder }; + +const ActionRow = require('../structures/ActionRow'); +const ActionRowBuilder = require('../structures/ActionRowBuilder'); +const ButtonBuilder = require('../structures/ButtonBuilder'); +const ButtonComponent = require('../structures/ButtonComponent'); +const ChannelSelectMenuBuilder = require('../structures/ChannelSelectMenuBuilder'); +const ChannelSelectMenuComponent = require('../structures/ChannelSelectMenuComponent'); +const Component = require('../structures/Component'); +const MentionableSelectMenuBuilder = require('../structures/MentionableSelectMenuBuilder'); +const MentionableSelectMenuComponent = require('../structures/MentionableSelectMenuComponent'); +const RoleSelectMenuBuilder = require('../structures/RoleSelectMenuBuilder'); +const RoleSelectMenuComponent = require('../structures/RoleSelectMenuComponent'); +const StringSelectMenuBuilder = require('../structures/StringSelectMenuBuilder'); +const StringSelectMenuComponent = require('../structures/StringSelectMenuComponent'); +const TextInputBuilder = require('../structures/TextInputBuilder'); +const TextInputComponent = require('../structures/TextInputComponent'); +const UserSelectMenuBuilder = require('../structures/UserSelectMenuBuilder'); +const UserSelectMenuComponent = require('../structures/UserSelectMenuComponent'); diff --git a/node_modules/discord.js/src/util/Constants.js b/node_modules/discord.js/src/util/Constants.js new file mode 100644 index 0000000..c2d3da9 --- /dev/null +++ b/node_modules/discord.js/src/util/Constants.js @@ -0,0 +1,230 @@ +'use strict'; + +const { ChannelType, MessageType, ComponentType, ImageFormat, StickerFormatType } = require('discord-api-types/v10'); + +/** + * Max bulk deletable message age + * @typedef {number} MaxBulkDeletableMessageAge + */ +exports.MaxBulkDeletableMessageAge = 1_209_600_000; + +/** + * The name of an item to be swept in Sweepers + * * `autoModerationRules` + * * `applicationCommands` - both global and guild commands + * * `bans` + * * `emojis` + * * `invites` - accepts the `lifetime` property, using it will sweep based on expires timestamp + * * `guildMembers` + * * `messages` - accepts the `lifetime` property, using it will sweep based on edited or created timestamp + * * `presences` + * * `reactions` + * * `stageInstances` + * * `stickers` + * * `threadMembers` + * * `threads` - accepts the `lifetime` property, using it will sweep archived threads based on archived timestamp + * * `users` + * * `voiceStates` + * @typedef {string} SweeperKey + */ +exports.SweeperKeys = [ + 'autoModerationRules', + 'applicationCommands', + 'bans', + 'emojis', + 'invites', + 'guildMembers', + 'messages', + 'presences', + 'reactions', + 'stageInstances', + 'stickers', + 'threadMembers', + 'threads', + 'users', + 'voiceStates', +]; + +/** + * The types of messages that are not `System`. The available types are: + * * {@link MessageType.Default} + * * {@link MessageType.Reply} + * * {@link MessageType.ChatInputCommand} + * * {@link MessageType.ContextMenuCommand} + * @typedef {MessageType[]} NonSystemMessageTypes + */ +exports.NonSystemMessageTypes = [ + MessageType.Default, + MessageType.Reply, + MessageType.ChatInputCommand, + MessageType.ContextMenuCommand, +]; + +/** + * The guild channels that are text-based. + * * TextChannel + * * NewsChannel + * * ThreadChannel + * * VoiceChannel + * * StageChannel + * @typedef {TextChannel|NewsChannel|ThreadChannel|VoiceChannel|StageChannel} GuildTextBasedChannel + */ + +/** + * The types of guild channels that are text-based. The available types are: + * * {@link ChannelType.GuildText} + * * {@link ChannelType.GuildAnnouncement} + * * {@link ChannelType.AnnouncementThread} + * * {@link ChannelType.PublicThread} + * * {@link ChannelType.PrivateThread} + * * {@link ChannelType.GuildVoice} + * * {@link ChannelType.GuildStageVoice} + * @typedef {ChannelType[]} GuildTextBasedChannelTypes + */ +exports.GuildTextBasedChannelTypes = [ + ChannelType.GuildText, + ChannelType.GuildAnnouncement, + ChannelType.AnnouncementThread, + ChannelType.PublicThread, + ChannelType.PrivateThread, + ChannelType.GuildVoice, + ChannelType.GuildStageVoice, +]; + +/** + * The channels that are text-based. + * * DMChannel + * * GuildTextBasedChannel + * @typedef {DMChannel|GuildTextBasedChannel} TextBasedChannels + */ + +/** + * Data that resolves to give a text-based channel. This can be: + * * A text-based channel + * * A snowflake + * @typedef {TextBasedChannels|Snowflake} TextBasedChannelsResolvable + */ + +/** + * The types of channels that are text-based. The available types are: + * * {@link ChannelType.DM} + * * {@link ChannelType.GuildText} + * * {@link ChannelType.GuildAnnouncement} + * * {@link ChannelType.AnnouncementThread} + * * {@link ChannelType.PublicThread} + * * {@link ChannelType.PrivateThread} + * * {@link ChannelType.GuildVoice} + * * {@link ChannelType.GuildStageVoice} + * @typedef {ChannelType[]} TextBasedChannelTypes + */ +exports.TextBasedChannelTypes = [...exports.GuildTextBasedChannelTypes, ChannelType.DM]; + +/** + * The types of channels that are threads. The available types are: + * * {@link ChannelType.AnnouncementThread} + * * {@link ChannelType.PublicThread} + * * {@link ChannelType.PrivateThread} + * @typedef {ChannelType[]} ThreadChannelTypes + */ +exports.ThreadChannelTypes = [ChannelType.AnnouncementThread, ChannelType.PublicThread, ChannelType.PrivateThread]; + +/** + * The types of channels that are voice-based. The available types are: + * * {@link ChannelType.GuildVoice} + * * {@link ChannelType.GuildStageVoice} + * @typedef {ChannelType[]} VoiceBasedChannelTypes + */ +exports.VoiceBasedChannelTypes = [ChannelType.GuildVoice, ChannelType.GuildStageVoice]; + +/** + * The types of select menus. The available types are: + * * {@link ComponentType.StringSelect} + * * {@link ComponentType.UserSelect} + * * {@link ComponentType.RoleSelect} + * * {@link ComponentType.MentionableSelect} + * * {@link ComponentType.ChannelSelect} + * @typedef {ComponentType[]} SelectMenuTypes + */ +exports.SelectMenuTypes = [ + ComponentType.StringSelect, + ComponentType.UserSelect, + ComponentType.RoleSelect, + ComponentType.MentionableSelect, + ComponentType.ChannelSelect, +]; + +/** + * The types of messages that can be deleted. The available types are: + * * {@link MessageType.AutoModerationAction} + * * {@link MessageType.ChannelFollowAdd} + * * {@link MessageType.ChannelPinnedMessage} + * * {@link MessageType.ChatInputCommand} + * * {@link MessageType.ContextMenuCommand} + * * {@link MessageType.Default} + * * {@link MessageType.GuildBoost} + * * {@link MessageType.GuildBoostTier1} + * * {@link MessageType.GuildBoostTier2} + * * {@link MessageType.GuildBoostTier3} + * * {@link MessageType.GuildInviteReminder} + * * {@link MessageType.InteractionPremiumUpsell} + * * {@link MessageType.Reply} + * * {@link MessageType.RoleSubscriptionPurchase} + * * {@link MessageType.StageEnd} + * * {@link MessageType.StageRaiseHand} + * * {@link MessageType.StageSpeaker} + * * {@link MessageType.StageStart} + * * {@link MessageType.StageTopic} + * * {@link MessageType.ThreadCreated} + * * {@link MessageType.UserJoin} + * @typedef {MessageType[]} DeletableMessageTypes + */ +exports.DeletableMessageTypes = [ + MessageType.AutoModerationAction, + MessageType.ChannelFollowAdd, + MessageType.ChannelPinnedMessage, + MessageType.ChatInputCommand, + MessageType.ContextMenuCommand, + MessageType.Default, + MessageType.GuildBoost, + MessageType.GuildBoostTier1, + MessageType.GuildBoostTier2, + MessageType.GuildBoostTier3, + MessageType.GuildInviteReminder, + MessageType.InteractionPremiumUpsell, + MessageType.Reply, + MessageType.RoleSubscriptionPurchase, + MessageType.StageEnd, + MessageType.StageRaiseHand, + MessageType.StageSpeaker, + MessageType.StageStart, + MessageType.StageTopic, + MessageType.ThreadCreated, + MessageType.UserJoin, +]; + +/** + * A mapping between sticker formats and their respective image formats. + * * {@link StickerFormatType.PNG} -> {@link ImageFormat.PNG} + * * {@link StickerFormatType.APNG} -> {@link ImageFormat.PNG} + * * {@link StickerFormatType.Lottie} -> {@link ImageFormat.Lottie} + * * {@link StickerFormatType.GIF} -> {@link ImageFormat.GIF} + * @typedef {Object} StickerFormatExtensionMap + */ +exports.StickerFormatExtensionMap = { + [StickerFormatType.PNG]: ImageFormat.PNG, + [StickerFormatType.APNG]: ImageFormat.PNG, + [StickerFormatType.Lottie]: ImageFormat.Lottie, + [StickerFormatType.GIF]: ImageFormat.GIF, +}; + +/** + * @typedef {Object} Constants Constants that can be used in an enum or object-like way. + * @property {number} MaxBulkDeletableMessageAge Max bulk deletable message age + * @property {SweeperKey[]} SweeperKeys The possible names of items that can be swept in sweepers + * @property {NonSystemMessageTypes} NonSystemMessageTypes The types of messages that are not deemed a system type + * @property {TextBasedChannelTypes} TextBasedChannelTypes The types of channels that are text-based + * @property {ThreadChannelTypes} ThreadChannelTypes The types of channels that are threads + * @property {VoiceBasedChannelTypes} VoiceBasedChannelTypes The types of channels that are voice-based + * @property {SelectMenuTypes} SelectMenuTypes The types of components that are select menus. + * @property {Object} StickerFormatExtensionMap A mapping between sticker formats and their respective image formats. + */ diff --git a/node_modules/discord.js/src/util/DataResolver.js b/node_modules/discord.js/src/util/DataResolver.js new file mode 100644 index 0000000..6b8a64c --- /dev/null +++ b/node_modules/discord.js/src/util/DataResolver.js @@ -0,0 +1,140 @@ +'use strict'; + +const { Buffer } = require('node:buffer'); +const fs = require('node:fs/promises'); +const path = require('node:path'); +const { fetch } = require('undici'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const Invite = require('../structures/Invite'); + +/** + * The DataResolver identifies different objects and tries to resolve a specific piece of information from them. + * @private + */ +class DataResolver extends null { + /** + * Data that can be resolved to give an invite code. This can be: + * * An invite code + * * An invite URL + * @typedef {string} InviteResolvable + */ + + /** + * Data that can be resolved to give a template code. This can be: + * * A template code + * * A template URL + * @typedef {string} GuildTemplateResolvable + */ + + /** + * Resolves the string to a code based on the passed regex. + * @param {string} data The string to resolve + * @param {RegExp} regex The RegExp used to extract the code + * @returns {string} + */ + static resolveCode(data, regex) { + return regex.exec(data)?.[1] ?? data; + } + + /** + * Resolves InviteResolvable to an invite code. + * @param {InviteResolvable} data The invite resolvable to resolve + * @returns {string} + */ + static resolveInviteCode(data) { + return this.resolveCode(data, Invite.InvitesPattern); + } + + /** + * Resolves GuildTemplateResolvable to a template code. + * @param {GuildTemplateResolvable} data The template resolvable to resolve + * @returns {string} + */ + static resolveGuildTemplateCode(data) { + const GuildTemplate = require('../structures/GuildTemplate'); + return this.resolveCode(data, GuildTemplate.GuildTemplatesPattern); + } + + /** + * Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image. + * @param {BufferResolvable|Base64Resolvable} image The image to be resolved + * @returns {Promise<?string>} + */ + static async resolveImage(image) { + if (!image) return null; + if (typeof image === 'string' && image.startsWith('data:')) { + return image; + } + const file = await this.resolveFile(image); + return this.resolveBase64(file.data); + } + + /** + * Data that resolves to give a Base64 string, typically for image uploading. This can be: + * * A Buffer + * * A base64 string + * @typedef {Buffer|string} Base64Resolvable + */ + + /** + * Resolves a Base64Resolvable to a Base 64 image. + * @param {Base64Resolvable} data The base 64 resolvable you want to resolve + * @returns {?string} + */ + static resolveBase64(data) { + if (Buffer.isBuffer(data)) return `data:image/jpg;base64,${data.toString('base64')}`; + return data; + } + + /** + * Data that can be resolved to give a Buffer. This can be: + * * A Buffer + * * The path to a local file + * * A URL <warn>When provided a URL, discord.js will fetch the URL internally in order to create a Buffer. + * This can pose a security risk when the URL has not been sanitized</warn> + * @typedef {string|Buffer} BufferResolvable + */ + + /** + * @external Stream + * @see {@link https://nodejs.org/api/stream.html} + */ + + /** + * @typedef {Object} ResolvedFile + * @property {Buffer} data Buffer containing the file data + * @property {string} [contentType] Content type of the file + */ + + /** + * Resolves a BufferResolvable to a Buffer. + * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve + * @returns {Promise<ResolvedFile>} + */ + static async resolveFile(resource) { + if (Buffer.isBuffer(resource)) return { data: resource }; + + if (typeof resource[Symbol.asyncIterator] === 'function') { + const buffers = []; + for await (const data of resource) buffers.push(Buffer.from(data)); + return { data: Buffer.concat(buffers) }; + } + + if (typeof resource === 'string') { + if (/^https?:\/\//.test(resource)) { + const res = await fetch(resource); + return { data: Buffer.from(await res.arrayBuffer()), contentType: res.headers.get('content-type') }; + } + + const file = path.resolve(resource); + + const stats = await fs.stat(file); + if (!stats.isFile()) throw new DiscordjsError(ErrorCodes.FileNotFound, file); + return { data: await fs.readFile(file) }; + } + + throw new DiscordjsTypeError(ErrorCodes.ReqResourceType); + } +} + +module.exports = DataResolver; diff --git a/node_modules/discord.js/src/util/Enums.js b/node_modules/discord.js/src/util/Enums.js new file mode 100644 index 0000000..e3e5cac --- /dev/null +++ b/node_modules/discord.js/src/util/Enums.js @@ -0,0 +1,13 @@ +'use strict'; + +function createEnum(keys) { + const obj = {}; + for (const [index, key] of keys.entries()) { + if (key === null) continue; + obj[key] = index; + obj[index] = key; + } + return obj; +} + +module.exports = { createEnum }; diff --git a/node_modules/discord.js/src/util/Events.js b/node_modules/discord.js/src/util/Events.js new file mode 100644 index 0000000..1a83ec8 --- /dev/null +++ b/node_modules/discord.js/src/util/Events.js @@ -0,0 +1,162 @@ +'use strict'; + +/** + * @typedef {Object} Events + * @property {string} ApplicationCommandPermissionsUpdate applicationCommandPermissionsUpdate + * @property {string} AutoModerationActionExecution autoModerationActionExecution + * @property {string} AutoModerationRuleCreate autoModerationRuleCreate + * @property {string} AutoModerationRuleDelete autoModerationRuleDelete + * @property {string} AutoModerationRuleUpdate autoModerationRuleUpdate + * @property {string} CacheSweep cacheSweep + * @property {string} ChannelCreate channelCreate + * @property {string} ChannelDelete channelDelete + * @property {string} ChannelPinsUpdate channelPinsUpdate + * @property {string} ChannelUpdate channelUpdate + * @property {string} ClientReady ready + * @property {string} Debug debug + * @property {string} Error error + * @property {string} GuildAuditLogEntryCreate guildAuditLogEntryCreate + * @property {string} GuildAvailable guildAvailable + * @property {string} GuildBanAdd guildBanAdd + * @property {string} GuildBanRemove guildBanRemove + * @property {string} GuildCreate guildCreate + * @property {string} GuildDelete guildDelete + * @property {string} GuildEmojiCreate emojiCreate + * @property {string} GuildEmojiDelete emojiDelete + * @property {string} GuildEmojiUpdate emojiUpdate + * @property {string} GuildIntegrationsUpdate guildIntegrationsUpdate + * @property {string} GuildMemberAdd guildMemberAdd + * @property {string} GuildMemberAvailable guildMemberAvailable + * @property {string} GuildMemberRemove guildMemberRemove + * @property {string} GuildMembersChunk guildMembersChunk + * @property {string} GuildMemberUpdate guildMemberUpdate + * @property {string} GuildRoleCreate roleCreate + * @property {string} GuildRoleDelete roleDelete + * @property {string} GuildRoleUpdate roleUpdate + * @property {string} GuildScheduledEventCreate guildScheduledEventCreate + * @property {string} GuildScheduledEventDelete guildScheduledEventDelete + * @property {string} GuildScheduledEventUpdate guildScheduledEventUpdate + * @property {string} GuildScheduledEventUserAdd guildScheduledEventUserAdd + * @property {string} GuildScheduledEventUserRemove guildScheduledEventUserRemove + * @property {string} GuildStickerCreate stickerCreate + * @property {string} GuildStickerDelete stickerDelete + * @property {string} GuildStickerUpdate stickerUpdate + * @property {string} GuildUnavailable guildUnavailable + * @property {string} GuildUpdate guildUpdate + * @property {string} InteractionCreate interactionCreate + * @property {string} Invalidated invalidated + * @property {string} InviteCreate inviteCreate + * @property {string} InviteDelete inviteDelete + * @property {string} MessageBulkDelete messageDeleteBulk + * @property {string} MessageCreate messageCreate + * @property {string} MessageDelete messageDelete + * @property {string} MessageReactionAdd messageReactionAdd + * @property {string} MessageReactionRemove messageReactionRemove + * @property {string} MessageReactionRemoveAll messageReactionRemoveAll + * @property {string} MessageReactionRemoveEmoji messageReactionRemoveEmoji + * @property {string} MessageUpdate messageUpdate + * @property {string} PresenceUpdate presenceUpdate + * @property {string} ShardDisconnect shardDisconnect + * @property {string} ShardError shardError + * @property {string} ShardReady shardReady + * @property {string} ShardReconnecting shardReconnecting + * @property {string} ShardResume shardResume + * @property {string} StageInstanceCreate stageInstanceCreate + * @property {string} StageInstanceDelete stageInstanceDelete + * @property {string} StageInstanceUpdate stageInstanceUpdate + * @property {string} ThreadCreate threadCreate + * @property {string} ThreadDelete threadDelete + * @property {string} ThreadListSync threadListSync + * @property {string} ThreadMembersUpdate threadMembersUpdate + * @property {string} ThreadMemberUpdate threadMemberUpdate + * @property {string} ThreadUpdate threadUpdate + * @property {string} TypingStart typingStart + * @property {string} UserUpdate userUpdate + * @property {string} VoiceServerUpdate voiceServerUpdate + * @property {string} VoiceStateUpdate voiceStateUpdate + * @property {string} Warn warn + * @property {string} WebhooksUpdate webhookUpdate + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Events} + * @ignore + */ +module.exports = { + ApplicationCommandPermissionsUpdate: 'applicationCommandPermissionsUpdate', + AutoModerationActionExecution: 'autoModerationActionExecution', + AutoModerationRuleCreate: 'autoModerationRuleCreate', + AutoModerationRuleDelete: 'autoModerationRuleDelete', + AutoModerationRuleUpdate: 'autoModerationRuleUpdate', + CacheSweep: 'cacheSweep', + ChannelCreate: 'channelCreate', + ChannelDelete: 'channelDelete', + ChannelPinsUpdate: 'channelPinsUpdate', + ChannelUpdate: 'channelUpdate', + ClientReady: 'ready', + Debug: 'debug', + Error: 'error', + GuildAuditLogEntryCreate: 'guildAuditLogEntryCreate', + GuildAvailable: 'guildAvailable', + GuildBanAdd: 'guildBanAdd', + GuildBanRemove: 'guildBanRemove', + GuildCreate: 'guildCreate', + GuildDelete: 'guildDelete', + GuildEmojiCreate: 'emojiCreate', + GuildEmojiDelete: 'emojiDelete', + GuildEmojiUpdate: 'emojiUpdate', + GuildIntegrationsUpdate: 'guildIntegrationsUpdate', + GuildMemberAdd: 'guildMemberAdd', + GuildMemberAvailable: 'guildMemberAvailable', + GuildMemberRemove: 'guildMemberRemove', + GuildMembersChunk: 'guildMembersChunk', + GuildMemberUpdate: 'guildMemberUpdate', + GuildRoleCreate: 'roleCreate', + GuildRoleDelete: 'roleDelete', + GuildRoleUpdate: 'roleUpdate', + GuildScheduledEventCreate: 'guildScheduledEventCreate', + GuildScheduledEventDelete: 'guildScheduledEventDelete', + GuildScheduledEventUpdate: 'guildScheduledEventUpdate', + GuildScheduledEventUserAdd: 'guildScheduledEventUserAdd', + GuildScheduledEventUserRemove: 'guildScheduledEventUserRemove', + GuildStickerCreate: 'stickerCreate', + GuildStickerDelete: 'stickerDelete', + GuildStickerUpdate: 'stickerUpdate', + GuildUnavailable: 'guildUnavailable', + GuildUpdate: 'guildUpdate', + InteractionCreate: 'interactionCreate', + Invalidated: 'invalidated', + InviteCreate: 'inviteCreate', + InviteDelete: 'inviteDelete', + MessageBulkDelete: 'messageDeleteBulk', + MessageCreate: 'messageCreate', + MessageDelete: 'messageDelete', + MessageReactionAdd: 'messageReactionAdd', + MessageReactionRemove: 'messageReactionRemove', + MessageReactionRemoveAll: 'messageReactionRemoveAll', + MessageReactionRemoveEmoji: 'messageReactionRemoveEmoji', + MessageUpdate: 'messageUpdate', + PresenceUpdate: 'presenceUpdate', + Raw: 'raw', + ShardDisconnect: 'shardDisconnect', + ShardError: 'shardError', + ShardReady: 'shardReady', + ShardReconnecting: 'shardReconnecting', + ShardResume: 'shardResume', + StageInstanceCreate: 'stageInstanceCreate', + StageInstanceDelete: 'stageInstanceDelete', + StageInstanceUpdate: 'stageInstanceUpdate', + ThreadCreate: 'threadCreate', + ThreadDelete: 'threadDelete', + ThreadListSync: 'threadListSync', + ThreadMembersUpdate: 'threadMembersUpdate', + ThreadMemberUpdate: 'threadMemberUpdate', + ThreadUpdate: 'threadUpdate', + TypingStart: 'typingStart', + UserUpdate: 'userUpdate', + VoiceServerUpdate: 'voiceServerUpdate', + VoiceStateUpdate: 'voiceStateUpdate', + Warn: 'warn', + WebhooksUpdate: 'webhookUpdate', +}; diff --git a/node_modules/discord.js/src/util/Formatters.js b/node_modules/discord.js/src/util/Formatters.js new file mode 100644 index 0000000..bd93a36 --- /dev/null +++ b/node_modules/discord.js/src/util/Formatters.js @@ -0,0 +1,413 @@ +'use strict'; + +const { deprecate } = require('node:util'); +const { + blockQuote, + bold, + channelMention, + codeBlock, + formatEmoji, + hideLinkEmbed, + hyperlink, + inlineCode, + italic, + quote, + roleMention, + spoiler, + strikethrough, + time, + TimestampStyles, + underscore, + userMention, +} = require('@discordjs/builders'); + +/** + * Formats an application command name and id into an application command mention. + * @method chatInputApplicationCommandMention + * @param {string} commandName The name of the application command + * @param {string|Snowflake} subcommandGroupOrSubOrId + * The subcommand group name, subcommand name, or application command id + * @param {string|Snowflake} [subcommandNameOrId] The subcommand name or application command id + * @param {string} [commandId] The id of the application command + * @returns {string} + */ + +/** + * Wraps the content inside a code block with an optional language. + * @method codeBlock + * @param {string} contentOrLanguage The language to use or content if a second parameter isn't provided + * @param {string} [content] The content to wrap + * @returns {string} + */ + +/** + * Wraps the content inside \`backticks\`, which formats it as inline code. + * @method inlineCode + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into italic text. + * @method italic + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into bold text. + * @method bold + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into underscored text. + * @method underscore + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into strike-through text. + * @method strikethrough + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into a quote. + * <info>This needs to be at the start of the line for Discord to format it.</info> + * @method quote + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into a block quote. + * <info>This needs to be at the start of the line for Discord to format it.</info> + * @method blockQuote + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Wraps the URL into `<>`, which stops it from embedding. + * @method hideLinkEmbed + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content and the URL into a masked URL with an optional title. + * @method hyperlink + * @param {string} content The content to display + * @param {string} url The URL the content links to + * @param {string} [title] The title shown when hovering on the masked link + * @returns {string} + */ + +/** + * Formats the content into spoiler text. + * @method spoiler + * @param {string} content The content to spoiler + * @returns {string} + */ + +/** + * Formats a user id into a user mention. + * @method userMention + * @param {Snowflake} userId The user id to format + * @returns {string} + */ + +/** + * Formats a channel id into a channel mention. + * @method channelMention + * @param {Snowflake} channelId The channel id to format + * @returns {string} + */ + +/** + * Formats a role id into a role mention. + * @method roleMention + * @param {Snowflake} roleId The role id to format + * @returns {string} + */ + +/** + * Formats an emoji id into a fully qualified emoji identifier. + * @method formatEmoji + * @param {Snowflake} emojiId The emoji id to format + * @param {boolean} [animated=false] Whether the emoji is animated + * @returns {string} + */ + +/** + * Formats a channel link for a channel. + * @method channelLink + * @param {Snowflake} channelId The id of the channel + * @param {Snowflake} [guildId] The id of the guild + * @returns {string} + */ + +/** + * Formats a message link for a channel. + * @method messageLink + * @param {Snowflake} channelId The id of the channel + * @param {Snowflake} messageId The id of the message + * @param {Snowflake} [guildId] The id of the guild + * @returns {string} + */ + +/** + * A message formatting timestamp style, as defined in + * [here](https://discord.com/developers/docs/reference#message-formatting-timestamp-styles). + * * `t` Short time format, consisting of hours and minutes, e.g. 16:20. + * * `T` Long time format, consisting of hours, minutes, and seconds, e.g. 16:20:30. + * * `d` Short date format, consisting of day, month, and year, e.g. 20/04/2021. + * * `D` Long date format, consisting of day, month, and year, e.g. 20 April 2021. + * * `f` Short date-time format, consisting of short date and short time formats, e.g. 20 April 2021 16:20. + * * `F` Long date-time format, consisting of long date and short time formats, e.g. Tuesday, 20 April 2021 16:20. + * * `R` Relative time format, consisting of a relative duration format, e.g. 2 months ago. + * @typedef {string} TimestampStylesString + */ + +/** + * Formats a date into a short date-time string. + * @method time + * @param {number|Date} [date] The date to format + * @param {TimestampStylesString} [style] The style to use + * @returns {string} + */ + +/** + * Contains various Discord-specific functions for formatting messages. + * @deprecated This class is redundant as all methods of the class can be imported from discord.js directly. + */ +class Formatters extends null { + /** + * Formats the content into a block quote. + * <info>This needs to be at the start of the line for Discord to format it.</info> + * @method blockQuote + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static blockQuote = deprecate( + blockQuote, + 'Formatters.blockQuote() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into bold text. + * @method bold + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static bold = deprecate( + bold, + 'Formatters.bold() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a channel id into a channel mention. + * @method channelMention + * @memberof Formatters + * @param {Snowflake} channelId The channel id to format + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static channelMention = deprecate( + channelMention, + 'Formatters.channelMention() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Wraps the content inside a code block with an optional language. + * @method codeBlock + * @memberof Formatters + * @param {string} contentOrLanguage The language to use or content if a second parameter isn't provided + * @param {string} [content] The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static codeBlock = deprecate( + codeBlock, + 'Formatters.codeBlock() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats an emoji id into a fully qualified emoji identifier. + * @method formatEmoji + * @memberof Formatters + * @param {string} emojiId The emoji id to format + * @param {boolean} [animated=false] Whether the emoji is animated + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static formatEmoji = deprecate( + formatEmoji, + 'Formatters.formatEmoji() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Wraps the URL into `<>`, which stops it from embedding. + * @method hideLinkEmbed + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static hideLinkEmbed = deprecate( + hideLinkEmbed, + 'Formatters.hideLinkEmbed() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content and the URL into a masked URL with an optional title. + * @method hyperlink + * @memberof Formatters + * @param {string} content The content to display + * @param {string} url The URL the content links to + * @param {string} [title] The title shown when hovering on the masked link + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static hyperlink = deprecate( + hyperlink, + 'Formatters.hyperlink() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Wraps the content inside \`backticks\`, which formats it as inline code. + * @method inlineCode + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static inlineCode = deprecate( + inlineCode, + 'Formatters.inlineCode() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into italic text. + * @method italic + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static italic = deprecate( + italic, + 'Formatters.italic() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into a quote. This needs to be at the start of the line for Discord to format it. + * @method quote + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static quote = deprecate( + quote, + 'Formatters.quote() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a role id into a role mention. + * @method roleMention + * @memberof Formatters + * @param {Snowflake} roleId The role id to format + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static roleMention = deprecate( + roleMention, + 'Formatters.roleMention() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into spoiler text. + * @method spoiler + * @memberof Formatters + * @param {string} content The content to spoiler + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static spoiler = deprecate( + spoiler, + 'Formatters.spoiler() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into strike-through text. + * @method strikethrough + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static strikethrough = deprecate( + strikethrough, + 'Formatters.strikethrough() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a date into a short date-time string. + * @method time + * @memberof Formatters + * @param {number|Date} [date] The date to format + * @param {TimestampStylesString} [style] The style to use + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static time = deprecate( + time, + 'Formatters.time() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * The message formatting timestamp + * [styles](https://discord.com/developers/docs/reference#message-formatting-timestamp-styles) supported by Discord. + * @type {Object<string, TimestampStylesString>} + * @memberof Formatters + * @deprecated Import this property directly from discord.js instead. + */ + static TimestampStyles = TimestampStyles; + + /** + * Formats the content into underscored text. + * @method underscore + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static underscore = deprecate( + underscore, + 'Formatters.underscore() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a user id into a user mention. + * @method userMention + * @memberof Formatters + * @param {Snowflake} userId The user id to format + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static userMention = deprecate( + userMention, + 'Formatters.userMention() is deprecated. Import this method directly from discord.js instead.', + ); +} + +module.exports = Formatters; diff --git a/node_modules/discord.js/src/util/GuildMemberFlagsBitField.js b/node_modules/discord.js/src/util/GuildMemberFlagsBitField.js new file mode 100644 index 0000000..84ce6b9 --- /dev/null +++ b/node_modules/discord.js/src/util/GuildMemberFlagsBitField.js @@ -0,0 +1,41 @@ +'use strict'; + +const { GuildMemberFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link GuildMember#flags} bitfield. + * @extends {BitField} + */ +class GuildMemberFlagsBitField extends BitField { + /** + * Numeric guild guild member flags. + * @type {GuildMemberFlags} + * @memberof GuildMemberFlagsBitField + */ + static Flags = GuildMemberFlags; +} + +/** + * @name GuildMemberFlagsBitField + * @kind constructor + * @memberof GuildMemberFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name GuildMemberFlagsBitField#bitfield + */ + +/** + * Data that can be resolved to give a guild member flag bitfield. This can be: + * * A string (see {@link GuildMemberFlagsBitField.Flags}) + * * A guild member flag + * * An instance of GuildMemberFlagsBitField + * * An Array of GuildMemberFlagsResolvable + * @typedef {string|number|GuildMemberFlagsBitField|GuildMemberFlagsResolvable[]} GuildMemberFlagsResolvable + */ + +exports.GuildMemberFlagsBitField = GuildMemberFlagsBitField; diff --git a/node_modules/discord.js/src/util/IntentsBitField.js b/node_modules/discord.js/src/util/IntentsBitField.js new file mode 100644 index 0000000..ea908b6 --- /dev/null +++ b/node_modules/discord.js/src/util/IntentsBitField.js @@ -0,0 +1,34 @@ +'use strict'; +const { GatewayIntentBits } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to calculate intents. + * @extends {BitField} + */ +class IntentsBitField extends BitField { + /** + * Numeric WebSocket intents + * @type {GatewayIntentBits} + * @memberof IntentsBitField + */ + static Flags = GatewayIntentBits; +} + +/** + * @name IntentsBitField + * @kind constructor + * @memberof IntentsBitField + * @param {IntentsResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Data that can be resolved to give a permission number. This can be: + * * A string (see {@link IntentsBitField.Flags}) + * * An intents flag + * * An instance of {@link IntentsBitField} + * * An array of IntentsResolvable + * @typedef {string|number|IntentsBitField|IntentsResolvable[]} IntentsResolvable + */ + +module.exports = IntentsBitField; diff --git a/node_modules/discord.js/src/util/LimitedCollection.js b/node_modules/discord.js/src/util/LimitedCollection.js new file mode 100644 index 0000000..12a8360 --- /dev/null +++ b/node_modules/discord.js/src/util/LimitedCollection.js @@ -0,0 +1,68 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Options for defining the behavior of a LimitedCollection + * @typedef {Object} LimitedCollectionOptions + * @property {?number} [maxSize=Infinity] The maximum size of the Collection + * @property {?Function} [keepOverLimit=null] A function, which is passed the value and key of an entry, ran to decide + * to keep an entry past the maximum size + */ + +/** + * A Collection which holds a max amount of entries. + * @extends {Collection} + * @param {LimitedCollectionOptions} [options={}] Options for constructing the Collection. + * @param {Iterable} [iterable=null] Optional entries passed to the Map constructor. + */ +class LimitedCollection extends Collection { + constructor(options = {}, iterable) { + if (typeof options !== 'object' || options === null) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + } + const { maxSize = Infinity, keepOverLimit = null } = options; + + if (typeof maxSize !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'maxSize', 'number'); + } + if (keepOverLimit !== null && typeof keepOverLimit !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'keepOverLimit', 'function'); + } + + super(iterable); + + /** + * The max size of the Collection. + * @type {number} + */ + this.maxSize = maxSize; + + /** + * A function called to check if an entry should be kept when the Collection is at max size. + * @type {?Function} + */ + this.keepOverLimit = keepOverLimit; + } + + set(key, value) { + if (this.maxSize === 0 && !this.keepOverLimit?.(value, key, this)) return this; + if (this.size >= this.maxSize && !this.has(key)) { + for (const [k, v] of this.entries()) { + const keep = this.keepOverLimit?.(v, k, this) ?? false; + if (!keep) { + this.delete(k); + break; + } + } + } + return super.set(key, value); + } + + static get [Symbol.species]() { + return Collection; + } +} + +module.exports = LimitedCollection; diff --git a/node_modules/discord.js/src/util/MessageFlagsBitField.js b/node_modules/discord.js/src/util/MessageFlagsBitField.js new file mode 100644 index 0000000..71f1fd6 --- /dev/null +++ b/node_modules/discord.js/src/util/MessageFlagsBitField.js @@ -0,0 +1,32 @@ +'use strict'; + +const { MessageFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link Message#flags} bitfield. + * @extends {BitField} + */ +class MessageFlagsBitField extends BitField { + /** + * Numeric message flags. + * @type {MessageFlags} + * @memberof MessageFlagsBitField + */ + static Flags = MessageFlags; +} + +/** + * @name MessageFlagsBitField + * @kind constructor + * @memberof MessageFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name MessageFlagsBitField#bitfield + */ + +module.exports = MessageFlagsBitField; diff --git a/node_modules/discord.js/src/util/Options.js b/node_modules/discord.js/src/util/Options.js new file mode 100644 index 0000000..9d1ce50 --- /dev/null +++ b/node_modules/discord.js/src/util/Options.js @@ -0,0 +1,237 @@ +'use strict'; + +const { DefaultRestOptions, DefaultUserAgentAppendix } = require('@discordjs/rest'); +const { toSnakeCase } = require('./Transformers'); +const { version } = require('../../package.json'); + +// TODO(ckohen): switch order of params so full manager is first and "type" is optional +/** + * @typedef {Function} CacheFactory + * @param {Function} managerType The base manager class the cache is being requested from. + * @param {Function} holds The class that the cache will hold. + * @param {Function} manager The fully extended manager class the cache is being requested from. + * @returns {Collection} A Collection used to store the cache of the manager. + */ + +/** + * Options for a client. + * @typedef {Object} ClientOptions + * @property {number|number[]|string} [shards] The shard's id to run, or an array of shard ids. If not specified, + * the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the + * recommended amount of shards from Discord and spawn that amount + * @property {number} [closeTimeout=5_000] The amount of time in milliseconds to wait for the close frame to be received + * from the WebSocket. Don't have this too high/low. Its best to have it between 2_000-6_000 ms. + * @property {number} [shardCount=1] The total amount of shards used by all processes of this bot + * (e.g. recommended shard count, shard count of the ShardingManager) + * @property {CacheFactory} [makeCache] Function to create a cache. + * You can use your own function, or the {@link Options} class to customize the Collection used for the cache. + * <warn>Overriding the cache used in `GuildManager`, `ChannelManager`, `GuildChannelManager`, `RoleManager`, + * and `PermissionOverwriteManager` is unsupported and **will** break functionality</warn> + * @property {MessageMentionOptions} [allowedMentions] The default value for {@link BaseMessageOptions#allowedMentions} + * @property {Partials[]} [partials] Structures allowed to be partial. This means events can be emitted even when + * they're missing all the data for a particular structure. See the "Partial Structures" topic on the + * [guide](https://discordjs.guide/popular-topics/partials.html) for some + * important usage information, as partials require you to put checks in place when handling data. + * @property {boolean} [failIfNotExists=true] The default value for {@link MessageReplyOptions#failIfNotExists} + * @property {PresenceData} [presence={}] Presence data to use upon login + * @property {IntentsResolvable} intents Intents to enable for this connection + * @property {number} [waitGuildTimeout=15_000] Time in milliseconds that clients with the + * {@link GatewayIntentBits.Guilds} gateway intent should wait for missing guilds to be received before being ready. + * @property {SweeperOptions} [sweepers=this.DefaultSweeperSettings] Options for cache sweeping + * @property {WebsocketOptions} [ws] Options for the WebSocket + * @property {RESTOptions} [rest] Options for the REST manager + * @property {Function} [jsonTransformer] A function used to transform outgoing json data + */ + +/** + * Options for {@link Sweepers} defining the behavior of cache sweeping + * @typedef {Object<SweeperKey, SweepOptions>} SweeperOptions + */ + +/** + * Options for sweeping a single type of item from cache + * @typedef {Object} SweepOptions + * @property {number} interval The interval (in seconds) at which to perform sweeping of the item + * @property {number} [lifetime] How long an item should stay in cache until it is considered sweepable. + * <warn>This property is only valid for the `invites`, `messages`, and `threads` keys. The `filter` property + * is mutually exclusive to this property and takes priority</warn> + * @property {GlobalSweepFilter} filter The function used to determine the function passed to the sweep method + * <info>This property is optional when the key is `invites`, `messages`, or `threads` and `lifetime` is set</info> + */ + +/** + * A function to determine what strategy to use for sharding internally. + * ```js + * (manager) => new WorkerShardingStrategy(manager, { shardsPerWorker: 2 }) + * ``` + * @typedef {Function} BuildStrategyFunction + * @param {WSWebSocketManager} manager The WebSocketManager that is going to initiate the sharding + * @returns {IShardingStrategy} The strategy to use for sharding + */ + +/** + * A function to change the concurrency handling for shard identifies of this manager + * ```js + * async (manager) => { + * const gateway = await manager.fetchGatewayInformation(); + * return new SimpleIdentifyThrottler(gateway.session_start_limit.max_concurrency); + * } + * ``` + * @typedef {Function} IdentifyThrottlerFunction + * @param {WSWebSocketManager} manager The WebSocketManager that is going to initiate the sharding + * @returns {Awaitable<IIdentifyThrottler>} The identify throttler that this ws manager will use + */ + +/** + * WebSocket options (these are left as snake_case to match the API) + * @typedef {Object} WebsocketOptions + * @property {number} [large_threshold=50] Number of members in a guild after which offline users will no longer be + * sent in the initial guild member list, must be between 50 and 250 + * @property {number} [version=10] The Discord gateway version to use <warn>Changing this can break the library; + * only set this if you know what you are doing</warn> + * @property {BuildStrategyFunction} [buildStrategy] Builds the strategy to use for sharding + * @property {IdentifyThrottlerFunction} [buildIdentifyThrottler] Builds the identify throttler to use for sharding + */ + +/** + * Contains various utilities for client options. + */ +class Options extends null { + /** + * The default user agent appendix. + * @type {string} + * @memberof Options + * @private + */ + static userAgentAppendix = `discord.js/${version} ${DefaultUserAgentAppendix}`.trimEnd(); + + /** + * The default client options. + * @returns {ClientOptions} + */ + static createDefault() { + return { + closeTimeout: 5_000, + waitGuildTimeout: 15_000, + shardCount: 1, + makeCache: this.cacheWithLimits(this.DefaultMakeCacheSettings), + partials: [], + failIfNotExists: true, + presence: {}, + sweepers: this.DefaultSweeperSettings, + ws: { + large_threshold: 50, + version: 10, + }, + rest: { + ...DefaultRestOptions, + userAgentAppendix: this.userAgentAppendix, + }, + jsonTransformer: toSnakeCase, + }; + } + + /** + * Create a cache factory using predefined settings to sweep or limit. + * @param {Object<string, LimitedCollectionOptions|number>} [settings={}] Settings passed to the relevant constructor. + * If no setting is provided for a manager, it uses Collection. + * If a number is provided for a manager, it uses that number as the max size for a LimitedCollection. + * If LimitedCollectionOptions are provided for a manager, it uses those settings to form a LimitedCollection. + * @returns {CacheFactory} + * @example + * // Store up to 200 messages per channel and 200 members per guild, always keeping the client member. + * Options.cacheWithLimits({ + * MessageManager: 200, + * GuildMemberManager: { + * maxSize: 200, + * keepOverLimit: (member) => member.id === client.user.id, + * }, + * }); + */ + static cacheWithLimits(settings = {}) { + const { Collection } = require('@discordjs/collection'); + const LimitedCollection = require('./LimitedCollection'); + + return (managerType, _, manager) => { + const setting = settings[manager.name] ?? settings[managerType.name]; + /* eslint-disable-next-line eqeqeq */ + if (setting == null) { + return new Collection(); + } + if (typeof setting === 'number') { + if (setting === Infinity) { + return new Collection(); + } + return new LimitedCollection({ maxSize: setting }); + } + /* eslint-disable-next-line eqeqeq */ + const noLimit = setting.maxSize == null || setting.maxSize === Infinity; + if (noLimit) { + return new Collection(); + } + return new LimitedCollection(setting); + }; + } + + /** + * Create a cache factory that always caches everything. + * @returns {CacheFactory} + */ + static cacheEverything() { + const { Collection } = require('@discordjs/collection'); + return () => new Collection(); + } + + /** + * The default settings passed to {@link ClientOptions.makeCache}. + * The caches that this changes are: + * * `MessageManager` - Limit to 200 messages + * <info>If you want to keep default behavior and add on top of it you can use this object and add on to it, e.g. + * `makeCache: Options.cacheWithLimits({ ...Options.DefaultMakeCacheSettings, ReactionManager: 0 })`</info> + * @type {Object<string, LimitedCollectionOptions|number>} + */ + static get DefaultMakeCacheSettings() { + return { + MessageManager: 200, + }; + } + + /** + * The default settings passed to {@link ClientOptions.sweepers}. + * The sweepers that this changes are: + * * `threads` - Sweep archived threads every hour, removing those archived more than 4 hours ago + * <info>If you want to keep default behavior and add on top of it you can use this object and add on to it, e.g. + * `sweepers: { ...Options.DefaultSweeperSettings, messages: { interval: 300, lifetime: 600 } }`</info> + * @type {SweeperOptions} + */ + static get DefaultSweeperSettings() { + return { + threads: { + interval: 3600, + lifetime: 14400, + }, + }; + } +} + +module.exports = Options; + +/** + * @external RESTOptions + * @see {@link https://discord.js.org/docs/packages/rest/stable/RESTOptions:Interface} + */ + +/** + * @external WSWebSocketManager + * @see {@link https://discord.js.org/docs/packages/ws/stable/WebSocketManager:Class} + */ + +/** + * @external IShardingStrategy + * @see {@link https://discord.js.org/docs/packages/ws/stable/IShardingStrategy:Interface} + */ + +/** + * @external IIdentifyThrottler + * @see {@link https://discord.js.org/docs/packages/ws/stable/IIdentifyThrottler:Interface} + */ diff --git a/node_modules/discord.js/src/util/Partials.js b/node_modules/discord.js/src/util/Partials.js new file mode 100644 index 0000000..31d9223 --- /dev/null +++ b/node_modules/discord.js/src/util/Partials.js @@ -0,0 +1,44 @@ +'use strict'; + +const { createEnum } = require('./Enums'); + +/** + * The enumeration for partials. + * ```js + * import { Client, Partials } from 'discord.js'; + * + * const client = new Client({ + * intents: [ + * // Intents... + * ], + * partials: [ + * Partials.User, // We want to receive uncached users! + * Partials.Message // We want to receive uncached messages! + * ] + * }); + * ``` + * @typedef {Object} Partials + * @property {number} User The partial to receive uncached users. + * @property {number} Channel The partial to receive uncached channels. + * <info>This is required to receive direct messages!</info> + * @property {number} GuildMember The partial to receive uncached guild members. + * @property {number} Message The partial to receive uncached messages. + * @property {number} Reaction The partial to receive uncached reactions. + * @property {number} GuildScheduledEvent The partial to receive uncached guild scheduled events. + * @property {number} ThreadMember The partial to receive uncached thread members. + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Partials} + * @ignore + */ +module.exports = createEnum([ + 'User', + 'Channel', + 'GuildMember', + 'Message', + 'Reaction', + 'GuildScheduledEvent', + 'ThreadMember', +]); diff --git a/node_modules/discord.js/src/util/PermissionsBitField.js b/node_modules/discord.js/src/util/PermissionsBitField.js new file mode 100644 index 0000000..c1ec72d --- /dev/null +++ b/node_modules/discord.js/src/util/PermissionsBitField.js @@ -0,0 +1,104 @@ +'use strict'; + +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of + * permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member + * that override their default permissions. + * @extends {BitField} + */ +class PermissionsBitField extends BitField { + /** + * Numeric permission flags. + * @type {PermissionFlagsBits} + * @memberof PermissionsBitField + * @see {@link https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags} + */ + static Flags = PermissionFlagsBits; + + /** + * Bitfield representing every permission combined + * @type {bigint} + * @memberof PermissionsBitField + */ + static All = Object.values(PermissionFlagsBits).reduce((all, p) => all | p, 0n); + + /** + * Bitfield representing the default permissions for users + * @type {bigint} + * @memberof PermissionsBitField + */ + static Default = BigInt(104324673); + + /** + * Bitfield representing the permissions required for moderators of stage channels + * @type {bigint} + * @memberof PermissionsBitField + */ + static StageModerator = + PermissionFlagsBits.ManageChannels | PermissionFlagsBits.MuteMembers | PermissionFlagsBits.MoveMembers; + + /** + * @type {bigint} + * @memberof PermissionsBitField + * @private + */ + static DefaultBit = BigInt(0); + + /** + * Bitfield of the packed bits + * @type {bigint} + * @name PermissionsBitField#bitfield + */ + + /** + * Data that can be resolved to give a permission number. This can be: + * * A string (see {@link PermissionsBitField.Flags}) + * * A permission number + * * An instance of {@link PermissionsBitField} + * * An Array of PermissionResolvable + * @typedef {string|bigint|PermissionsBitField|PermissionResolvable[]} PermissionResolvable + */ + + /** + * Gets all given bits that are missing from the bitfield. + * @param {BitFieldResolvable} bits Bit(s) to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {string[]} + */ + missing(bits, checkAdmin = true) { + return checkAdmin && this.has(PermissionFlagsBits.Administrator) ? [] : super.missing(bits); + } + + /** + * Checks whether the bitfield has a permission, or any of multiple permissions. + * @param {PermissionResolvable} permission Permission(s) to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {boolean} + */ + any(permission, checkAdmin = true) { + return (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.any(permission); + } + + /** + * Checks whether the bitfield has a permission, or multiple permissions. + * @param {PermissionResolvable} permission Permission(s) to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {boolean} + */ + has(permission, checkAdmin = true) { + return (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.has(permission); + } + + /** + * Gets an {@link Array} of bitfield names based on the permissions available. + * @returns {string[]} + */ + toArray() { + return super.toArray(false); + } +} + +module.exports = PermissionsBitField; diff --git a/node_modules/discord.js/src/util/RoleFlagsBitField.js b/node_modules/discord.js/src/util/RoleFlagsBitField.js new file mode 100644 index 0000000..1e0f895 --- /dev/null +++ b/node_modules/discord.js/src/util/RoleFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { RoleFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link Role#flags} bitfield. + * @extends {BitField} + */ +class RoleFlagsBitField extends BitField { + /** + * Numeric role flags. + * @type {RoleFlags} + * @memberof RoleFlagsBitField + */ + static Flags = RoleFlags; +} + +/** + * @name RoleFlagsBitField + * @kind constructor + * @memberof RoleFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = RoleFlagsBitField; diff --git a/node_modules/discord.js/src/util/ShardEvents.js b/node_modules/discord.js/src/util/ShardEvents.js new file mode 100644 index 0000000..f5ba961 --- /dev/null +++ b/node_modules/discord.js/src/util/ShardEvents.js @@ -0,0 +1,29 @@ +'use strict'; + +/** + * @typedef {Object} ShardEvents + * @property {string} Death death + * @property {string} Disconnect disconnect + * @property {string} Error error + * @property {string} Message message + * @property {string} Ready ready + * @property {string} Reconnecting reconnecting + * @property {string} Resume resume + * @property {string} Spawn spawn + */ + +// JSDoc for IntelliSense purposes +/** + * @type {ShardEvents} + * @ignore + */ +module.exports = { + Death: 'death', + Disconnect: 'disconnect', + Error: 'error', + Message: 'message', + Ready: 'ready', + Reconnecting: 'reconnecting', + Resume: 'resume', + Spawn: 'spawn', +}; diff --git a/node_modules/discord.js/src/util/Status.js b/node_modules/discord.js/src/util/Status.js new file mode 100644 index 0000000..e524197 --- /dev/null +++ b/node_modules/discord.js/src/util/Status.js @@ -0,0 +1,33 @@ +'use strict'; + +const { createEnum } = require('./Enums'); + +/** + * @typedef {Object} Status + * @property {number} Ready + * @property {number} Connecting + * @property {number} Reconnecting + * @property {number} Idle + * @property {number} Nearly + * @property {number} Disconnected + * @property {number} WaitingForGuilds + * @property {number} Identifying + * @property {number} Resuming + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Status} + * @ignore + */ +module.exports = createEnum([ + 'Ready', + 'Connecting', + 'Reconnecting', + 'Idle', + 'Nearly', + 'Disconnected', + 'WaitingForGuilds', + 'Identifying', + 'Resuming', +]); diff --git a/node_modules/discord.js/src/util/Sweepers.js b/node_modules/discord.js/src/util/Sweepers.js new file mode 100644 index 0000000..6eb2dc6 --- /dev/null +++ b/node_modules/discord.js/src/util/Sweepers.js @@ -0,0 +1,467 @@ +'use strict'; + +const { setInterval, clearInterval } = require('node:timers'); +const { ThreadChannelTypes, SweeperKeys } = require('./Constants'); +const Events = require('./Events'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * @typedef {Function} GlobalSweepFilter + * @returns {Function|null} Return `null` to skip sweeping, otherwise a function passed to `sweep()`, + * See {@link [Collection#sweep](https://discord.js.org/docs/packages/collection/stable/Collection:Class#sweep)} + * for the definition of this function. + */ + +/** + * A container for all cache sweeping intervals and their associated sweep methods. + */ +class Sweepers { + constructor(client, options) { + /** + * The client that instantiated this + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + + /** + * The options the sweepers were instantiated with + * @type {SweeperOptions} + */ + this.options = options; + + /** + * A record of interval timeout that is used to sweep the indicated items, or null if not being swept + * @type {Object<SweeperKey, ?Timeout>} + */ + this.intervals = Object.fromEntries(SweeperKeys.map(key => [key, null])); + + for (const key of SweeperKeys) { + if (!(key in options)) continue; + + this._validateProperties(key); + + const clonedOptions = { ...this.options[key] }; + + // Handle cases that have a "lifetime" + if (!('filter' in clonedOptions)) { + switch (key) { + case 'invites': + clonedOptions.filter = this.constructor.expiredInviteSweepFilter(clonedOptions.lifetime); + break; + case 'messages': + clonedOptions.filter = this.constructor.outdatedMessageSweepFilter(clonedOptions.lifetime); + break; + case 'threads': + clonedOptions.filter = this.constructor.archivedThreadSweepFilter(clonedOptions.lifetime); + } + } + + this._initInterval(key, `sweep${key[0].toUpperCase()}${key.slice(1)}`, clonedOptions); + } + } + + /** + * Sweeps all guild and global application commands and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which commands will be removed from the caches. + * @returns {number} Amount of commands that were removed from the caches + */ + sweepApplicationCommands(filter) { + const { guilds, items: guildCommands } = this._sweepGuildDirectProp('commands', filter, { emit: false }); + + const globalCommands = this.client.application?.commands.cache.sweep(filter) ?? 0; + + this.client.emit( + Events.CacheSweep, + `Swept ${globalCommands} global application commands and ${guildCommands} guild commands in ${guilds} guilds.`, + ); + return guildCommands + globalCommands; + } + + /** + * Sweeps all auto moderation rules and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine + * which auto moderation rules will be removed from the caches + * @returns {number} Amount of auto moderation rules that were removed from the caches + */ + sweepAutoModerationRules(filter) { + return this._sweepGuildDirectProp('autoModerationRules', filter).items; + } + + /** + * Sweeps all guild bans and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which bans will be removed from the caches. + * @returns {number} Amount of bans that were removed from the caches + */ + sweepBans(filter) { + return this._sweepGuildDirectProp('bans', filter).items; + } + + /** + * Sweeps all guild emojis and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which emojis will be removed from the caches. + * @returns {number} Amount of emojis that were removed from the caches + */ + sweepEmojis(filter) { + return this._sweepGuildDirectProp('emojis', filter).items; + } + + /** + * Sweeps all guild invites and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which invites will be removed from the caches. + * @returns {number} Amount of invites that were removed from the caches + */ + sweepInvites(filter) { + return this._sweepGuildDirectProp('invites', filter).items; + } + + /** + * Sweeps all guild members and removes the ones which are indicated by the filter. + * <info>It is highly recommended to keep the client guild member cached</info> + * @param {Function} filter The function used to determine which guild members will be removed from the caches. + * @returns {number} Amount of guild members that were removed from the caches + */ + sweepGuildMembers(filter) { + return this._sweepGuildDirectProp('members', filter, { outputName: 'guild members' }).items; + } + + /** + * Sweeps all text-based channels' messages and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which messages will be removed from the caches. + * @returns {number} Amount of messages that were removed from the caches + * @example + * // Remove all messages older than 1800 seconds from the messages cache + * const amount = sweepers.sweepMessages( + * Sweepers.filterByLifetime({ + * lifetime: 1800, + * getComparisonTimestamp: m => m.editedTimestamp ?? m.createdTimestamp, + * })(), + * ); + * console.log(`Successfully removed ${amount} messages from the cache.`); + */ + sweepMessages(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + let channels = 0; + let messages = 0; + + for (const channel of this.client.channels.cache.values()) { + if (!channel.isTextBased()) continue; + + channels++; + messages += channel.messages.cache.sweep(filter); + } + this.client.emit(Events.CacheSweep, `Swept ${messages} messages in ${channels} text-based channels.`); + return messages; + } + + /** + * Sweeps all presences and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which presences will be removed from the caches. + * @returns {number} Amount of presences that were removed from the caches + */ + sweepPresences(filter) { + return this._sweepGuildDirectProp('presences', filter).items; + } + + /** + * Sweeps all message reactions and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which reactions will be removed from the caches. + * @returns {number} Amount of reactions that were removed from the caches + */ + sweepReactions(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + let channels = 0; + let messages = 0; + let reactions = 0; + + for (const channel of this.client.channels.cache.values()) { + if (!channel.isTextBased()) continue; + channels++; + + for (const message of channel.messages.cache.values()) { + messages++; + reactions += message.reactions.cache.sweep(filter); + } + } + this.client.emit( + Events.CacheSweep, + `Swept ${reactions} reactions on ${messages} messages in ${channels} text-based channels.`, + ); + return reactions; + } + + /** + * Sweeps all guild stage instances and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which stage instances will be removed from the caches. + * @returns {number} Amount of stage instances that were removed from the caches + */ + sweepStageInstances(filter) { + return this._sweepGuildDirectProp('stageInstances', filter, { outputName: 'stage instances' }).items; + } + + /** + * Sweeps all guild stickers and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which stickers will be removed from the caches. + * @returns {number} Amount of stickers that were removed from the caches + */ + sweepStickers(filter) { + return this._sweepGuildDirectProp('stickers', filter).items; + } + + /** + * Sweeps all thread members and removes the ones which are indicated by the filter. + * <info>It is highly recommended to keep the client thread member cached</info> + * @param {Function} filter The function used to determine which thread members will be removed from the caches. + * @returns {number} Amount of thread members that were removed from the caches + */ + sweepThreadMembers(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + let threads = 0; + let members = 0; + for (const channel of this.client.channels.cache.values()) { + if (!ThreadChannelTypes.includes(channel.type)) continue; + threads++; + members += channel.members.cache.sweep(filter); + } + this.client.emit(Events.CacheSweep, `Swept ${members} thread members in ${threads} threads.`); + return members; + } + + /** + * Sweeps all threads and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which threads will be removed from the caches. + * @returns {number} filter Amount of threads that were removed from the caches + * @example + * // Remove all threads archived greater than 1 day ago from all the channel caches + * const amount = sweepers.sweepThreads( + * Sweepers.filterByLifetime({ + * getComparisonTimestamp: t => t.archivedTimestamp, + * excludeFromSweep: t => !t.archived, + * })(), + * ); + * console.log(`Successfully removed ${amount} threads from the cache.`); + */ + sweepThreads(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + let threads = 0; + for (const [key, val] of this.client.channels.cache.entries()) { + if (!ThreadChannelTypes.includes(val.type)) continue; + if (filter(val, key, this.client.channels.cache)) { + threads++; + this.client.channels._remove(key); + } + } + this.client.emit(Events.CacheSweep, `Swept ${threads} threads.`); + return threads; + } + + /** + * Sweeps all users and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which users will be removed from the caches. + * @returns {number} Amount of users that were removed from the caches + */ + sweepUsers(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + const users = this.client.users.cache.sweep(filter); + + this.client.emit(Events.CacheSweep, `Swept ${users} users.`); + + return users; + } + + /** + * Sweeps all guild voice states and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which voice states will be removed from the caches. + * @returns {number} Amount of voice states that were removed from the caches + */ + sweepVoiceStates(filter) { + return this._sweepGuildDirectProp('voiceStates', filter, { outputName: 'voice states' }).items; + } + + /** + * Cancels all sweeping intervals + * @returns {void} + */ + destroy() { + for (const key of SweeperKeys) { + if (this.intervals[key]) clearInterval(this.intervals[key]); + } + } + + /** + * Options for generating a filter function based on lifetime + * @typedef {Object} LifetimeFilterOptions + * @property {number} [lifetime=14400] How long, in seconds, an entry should stay in the collection + * before it is considered sweepable. + * @property {Function} [getComparisonTimestamp=e => e?.createdTimestamp] A function that takes an entry, key, + * and the collection and returns a timestamp to compare against in order to determine the lifetime of the entry. + * @property {Function} [excludeFromSweep=() => false] A function that takes an entry, key, and the collection + * and returns a boolean, `true` when the entry should not be checked for sweepability. + */ + + /** + * Create a sweepFilter function that uses a lifetime to determine sweepability. + * @param {LifetimeFilterOptions} [options={}] The options used to generate the filter function + * @returns {GlobalSweepFilter} + */ + static filterByLifetime({ + lifetime = 14400, + getComparisonTimestamp = e => e?.createdTimestamp, + excludeFromSweep = () => false, + } = {}) { + if (typeof lifetime !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'lifetime', 'number'); + } + if (typeof getComparisonTimestamp !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'getComparisonTimestamp', 'function'); + } + if (typeof excludeFromSweep !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'excludeFromSweep', 'function'); + } + return () => { + if (lifetime <= 0) return null; + const lifetimeMs = lifetime * 1_000; + const now = Date.now(); + return (entry, key, coll) => { + if (excludeFromSweep(entry, key, coll)) { + return false; + } + const comparisonTimestamp = getComparisonTimestamp(entry, key, coll); + if (!comparisonTimestamp || typeof comparisonTimestamp !== 'number') return false; + return now - comparisonTimestamp > lifetimeMs; + }; + }; + } + + /** + * Creates a sweep filter that sweeps archived threads + * @param {number} [lifetime=14400] How long a thread has to be archived to be valid for sweeping + * @returns {GlobalSweepFilter} + */ + static archivedThreadSweepFilter(lifetime = 14400) { + return this.filterByLifetime({ + lifetime, + getComparisonTimestamp: e => e.archiveTimestamp, + excludeFromSweep: e => !e.archived, + }); + } + + /** + * Creates a sweep filter that sweeps expired invites + * @param {number} [lifetime=14400] How long ago an invite has to have expired to be valid for sweeping + * @returns {GlobalSweepFilter} + */ + static expiredInviteSweepFilter(lifetime = 14400) { + return this.filterByLifetime({ + lifetime, + getComparisonTimestamp: i => i.expiresTimestamp, + }); + } + + /** + * Creates a sweep filter that sweeps outdated messages (edits taken into account) + * @param {number} [lifetime=3600] How long ago a message has to have been sent or edited to be valid for sweeping + * @returns {GlobalSweepFilter} + */ + static outdatedMessageSweepFilter(lifetime = 3600) { + return this.filterByLifetime({ + lifetime, + getComparisonTimestamp: m => m.editedTimestamp ?? m.createdTimestamp, + }); + } + + /** + * Configuration options for emitting the cache sweep client event + * @typedef {Object} SweepEventOptions + * @property {boolean} [emit=true] Whether to emit the client event in this method + * @property {string} [outputName] A name to output in the client event if it should differ from the key + * @private + */ + + /** + * Sweep a direct sub property of all guilds + * @param {string} key The name of the property + * @param {Function} filter Filter function passed to sweep + * @param {SweepEventOptions} [eventOptions={}] Options for the Client event emitted here + * @returns {Object} Object containing the number of guilds swept and the number of items swept + * @private + */ + _sweepGuildDirectProp(key, filter, { emit = true, outputName } = {}) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + let guilds = 0; + let items = 0; + + for (const guild of this.client.guilds.cache.values()) { + const { cache } = guild[key]; + + guilds++; + items += cache.sweep(filter); + } + + if (emit) { + this.client.emit(Events.CacheSweep, `Swept ${items} ${outputName ?? key} in ${guilds} guilds.`); + } + + return { guilds, items }; + } + + /** + * Validates a set of properties + * @param {string} key Key of the options object to check + * @private + */ + _validateProperties(key) { + const props = this.options[key]; + if (typeof props !== 'object') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}`, 'object', true); + } + if (typeof props.interval !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.interval`, 'number'); + } + // Invites, Messages, and Threads can be provided a lifetime parameter, which we use to generate the filter + if (['invites', 'messages', 'threads'].includes(key) && !('filter' in props)) { + if (typeof props.lifetime !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.lifetime`, 'number'); + } + return; + } + if (typeof props.filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.filter`, 'function'); + } + } + + /** + * Initialize an interval for sweeping + * @param {string} intervalKey The name of the property that stores the interval for this sweeper + * @param {string} sweepKey The name of the function that sweeps the desired caches + * @param {Object} opts Validated options for a sweep + * @private + */ + _initInterval(intervalKey, sweepKey, opts) { + if (opts.interval <= 0 || opts.interval === Infinity) return; + this.intervals[intervalKey] = setInterval(() => { + const sweepFn = opts.filter(); + if (sweepFn === null) return; + if (typeof sweepFn !== 'function') throw new DiscordjsTypeError(ErrorCodes.SweepFilterReturn); + this[sweepKey](sweepFn); + }, opts.interval * 1_000).unref(); + } +} + +module.exports = Sweepers; diff --git a/node_modules/discord.js/src/util/Symbols.js b/node_modules/discord.js/src/util/Symbols.js new file mode 100644 index 0000000..36d4ed8 --- /dev/null +++ b/node_modules/discord.js/src/util/Symbols.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.MakeCacheOverrideSymbol = Symbol('djs.managers.makeCacheOverride'); diff --git a/node_modules/discord.js/src/util/SystemChannelFlagsBitField.js b/node_modules/discord.js/src/util/SystemChannelFlagsBitField.js new file mode 100644 index 0000000..cbca48f --- /dev/null +++ b/node_modules/discord.js/src/util/SystemChannelFlagsBitField.js @@ -0,0 +1,43 @@ +'use strict'; + +const { GuildSystemChannelFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link Guild#systemChannelFlags} bitfield. + * <info>Note that all event message types are enabled by default, + * and by setting their corresponding flags you are disabling them</info> + * @extends {BitField} + */ +class SystemChannelFlagsBitField extends BitField { + /** + * Numeric system channel flags. + * @type {GuildSystemChannelFlags} + * @memberof SystemChannelFlagsBitField + */ + static Flags = GuildSystemChannelFlags; +} + +/** + * @name SystemChannelFlagsBitField + * @kind constructor + * @memberof SystemChannelFlagsBitField + * @param {SystemChannelFlagsResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name SystemChannelFlagsBitField#bitfield + */ + +/** + * Data that can be resolved to give a system channel flag bitfield. This can be: + * * A string (see {@link SystemChannelFlagsBitField.Flags}) + * * A system channel flag + * * An instance of SystemChannelFlagsBitField + * * An Array of SystemChannelFlagsResolvable + * @typedef {string|number|SystemChannelFlagsBitField|SystemChannelFlagsResolvable[]} SystemChannelFlagsResolvable + */ + +module.exports = SystemChannelFlagsBitField; diff --git a/node_modules/discord.js/src/util/ThreadMemberFlagsBitField.js b/node_modules/discord.js/src/util/ThreadMemberFlagsBitField.js new file mode 100644 index 0000000..c5073a8 --- /dev/null +++ b/node_modules/discord.js/src/util/ThreadMemberFlagsBitField.js @@ -0,0 +1,31 @@ +'use strict'; + +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link ThreadMember#flags} bitfield. + * @extends {BitField} + */ +class ThreadMemberFlagsBitField extends BitField { + /** + * Numeric thread member flags. There are currently no bitflags relevant to bots for this. + * @type {Object<string, number>} + * @memberof ThreadMemberFlagsBitField + */ + static Flags = {}; +} + +/** + * @name ThreadMemberFlagsBitField + * @kind constructor + * @memberof ThreadMemberFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name ThreadMemberFlagsBitField#bitfield + */ + +module.exports = ThreadMemberFlagsBitField; diff --git a/node_modules/discord.js/src/util/Transformers.js b/node_modules/discord.js/src/util/Transformers.js new file mode 100644 index 0000000..f4d7af0 --- /dev/null +++ b/node_modules/discord.js/src/util/Transformers.js @@ -0,0 +1,36 @@ +'use strict'; + +const { isJSONEncodable } = require('@discordjs/util'); +const snakeCase = require('lodash.snakecase'); + +/** + * Transforms camel-cased keys into snake cased keys + * @param {*} obj The object to transform + * @returns {*} + */ +function toSnakeCase(obj) { + if (typeof obj !== 'object' || !obj) return obj; + if (obj instanceof Date) return obj; + if (isJSONEncodable(obj)) return toSnakeCase(obj.toJSON()); + if (Array.isArray(obj)) return obj.map(toSnakeCase); + return Object.fromEntries(Object.entries(obj).map(([key, value]) => [snakeCase(key), toSnakeCase(value)])); +} + +/** + * Transforms an API auto moderation action object to a camel-cased variant. + * @param {APIAutoModerationAction} autoModerationAction The action to transform + * @returns {AutoModerationAction} + * @ignore + */ +function _transformAPIAutoModerationAction(autoModerationAction) { + return { + type: autoModerationAction.type, + metadata: { + durationSeconds: autoModerationAction.metadata.duration_seconds ?? null, + channelId: autoModerationAction.metadata.channel_id ?? null, + customMessage: autoModerationAction.metadata.custom_message ?? null, + }, + }; +} + +module.exports = { toSnakeCase, _transformAPIAutoModerationAction }; diff --git a/node_modules/discord.js/src/util/UserFlagsBitField.js b/node_modules/discord.js/src/util/UserFlagsBitField.js new file mode 100644 index 0000000..ea9f835 --- /dev/null +++ b/node_modules/discord.js/src/util/UserFlagsBitField.js @@ -0,0 +1,32 @@ +'use strict'; + +const { UserFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link User#flags} bitfield. + * @extends {BitField} + */ +class UserFlagsBitField extends BitField { + /** + * Numeric user flags. + * @type {UserFlags} + * @memberof UserFlagsBitField + */ + static Flags = UserFlags; +} + +/** + * @name UserFlagsBitField + * @kind constructor + * @memberof UserFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name UserFlagsBitField#bitfield + */ + +module.exports = UserFlagsBitField; diff --git a/node_modules/discord.js/src/util/Util.js b/node_modules/discord.js/src/util/Util.js new file mode 100644 index 0000000..e42bc5a --- /dev/null +++ b/node_modules/discord.js/src/util/Util.js @@ -0,0 +1,424 @@ +'use strict'; + +const { parse } = require('node:path'); +const { Collection } = require('@discordjs/collection'); +const { ChannelType, RouteBases, Routes } = require('discord-api-types/v10'); +const { fetch } = require('undici'); +const Colors = require('./Colors'); +const { DiscordjsError, DiscordjsRangeError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const isObject = d => typeof d === 'object' && d !== null; + +/** + * Flatten an object. Any properties that are collections will get converted to an array of keys. + * @param {Object} obj The object to flatten. + * @param {...Object<string, boolean|string>} [props] Specific properties to include/exclude. + * @returns {Object} + */ +function flatten(obj, ...props) { + if (!isObject(obj)) return obj; + + const objProps = Object.keys(obj) + .filter(k => !k.startsWith('_')) + .map(k => ({ [k]: true })); + + props = objProps.length ? Object.assign(...objProps, ...props) : Object.assign({}, ...props); + + const out = {}; + + for (let [prop, newProp] of Object.entries(props)) { + if (!newProp) continue; + newProp = newProp === true ? prop : newProp; + + const element = obj[prop]; + const elemIsObj = isObject(element); + const valueOf = elemIsObj && typeof element.valueOf === 'function' ? element.valueOf() : null; + const hasToJSON = elemIsObj && typeof element.toJSON === 'function'; + + // If it's a Collection, make the array of keys + if (element instanceof Collection) out[newProp] = Array.from(element.keys()); + // If the valueOf is a Collection, use its array of keys + else if (valueOf instanceof Collection) out[newProp] = Array.from(valueOf.keys()); + // If it's an array, call toJSON function on each element if present, otherwise flatten each element + else if (Array.isArray(element)) out[newProp] = element.map(e => e.toJSON?.() ?? flatten(e)); + // If it's an object with a primitive `valueOf`, use that value + else if (typeof valueOf !== 'object') out[newProp] = valueOf; + // If it's an object with a toJSON function, use the return value of it + else if (hasToJSON) out[newProp] = element.toJSON(); + // If element is an object, use the flattened version of it + else if (typeof element === 'object') out[newProp] = flatten(element); + // If it's a primitive + else if (!elemIsObj) out[newProp] = element; + } + + return out; +} + +/** + * @typedef {Object} FetchRecommendedShardCountOptions + * @property {number} [guildsPerShard=1000] Number of guilds assigned per shard + * @property {number} [multipleOf=1] The multiple the shard count should round up to. (16 for large bot sharding) + */ + +/** + * Gets the recommended shard count from Discord. + * @param {string} token Discord auth token + * @param {FetchRecommendedShardCountOptions} [options] Options for fetching the recommended shard count + * @returns {Promise<number>} The recommended number of shards + */ +async function fetchRecommendedShardCount(token, { guildsPerShard = 1_000, multipleOf = 1 } = {}) { + if (!token) throw new DiscordjsError(ErrorCodes.TokenMissing); + const response = await fetch(RouteBases.api + Routes.gatewayBot(), { + method: 'GET', + headers: { Authorization: `Bot ${token.replace(/^Bot\s*/i, '')}` }, + }); + if (!response.ok) { + if (response.status === 401) throw new DiscordjsError(ErrorCodes.TokenInvalid); + throw response; + } + const { shards } = await response.json(); + return Math.ceil((shards * (1_000 / guildsPerShard)) / multipleOf) * multipleOf; +} + +/** + * Parses emoji info out of a string. The string must be one of: + * * A UTF-8 emoji (no id) + * * A URL-encoded UTF-8 emoji (no id) + * * A Discord custom emoji (`<:name:id>` or `<a:name:id>`) + * @param {string} text Emoji string to parse + * @returns {APIEmoji} Object with `animated`, `name`, and `id` properties + */ +function parseEmoji(text) { + if (text.includes('%')) text = decodeURIComponent(text); + if (!text.includes(':')) return { animated: false, name: text, id: undefined }; + const match = text.match(/<?(?:(a):)?(\w{2,32}):(\d{17,19})?>?/); + return match && { animated: Boolean(match[1]), name: match[2], id: match[3] }; +} + +/** + * Resolves a partial emoji object from an {@link EmojiIdentifierResolvable}, without checking a Client. + * @param {EmojiIdentifierResolvable} emoji Emoji identifier to resolve + * @returns {?RawEmoji} + * @private + */ +function resolvePartialEmoji(emoji) { + if (!emoji) return null; + if (typeof emoji === 'string') return /^\d{17,19}$/.test(emoji) ? { id: emoji } : parseEmoji(emoji); + const { id, name, animated } = emoji; + if (!id && !name) return null; + return { id, name, animated: Boolean(animated) }; +} + +/** + * Sets default properties on an object that aren't already specified. + * @param {Object} def Default properties + * @param {Object} given Object to assign defaults to + * @returns {Object} + * @private + */ +function mergeDefault(def, given) { + if (!given) return def; + for (const key in def) { + if (!Object.hasOwn(given, key) || given[key] === undefined) { + given[key] = def[key]; + } else if (given[key] === Object(given[key])) { + given[key] = mergeDefault(def[key], given[key]); + } + } + + return given; +} + +/** + * Options used to make an error object. + * @typedef {Object} MakeErrorOptions + * @property {string} name Error type + * @property {string} message Message for the error + * @property {string} stack Stack for the error + */ + +/** + * Makes an Error from a plain info object. + * @param {MakeErrorOptions} obj Error info + * @returns {Error} + * @private + */ +function makeError(obj) { + const err = new Error(obj.message); + err.name = obj.name; + err.stack = obj.stack; + return err; +} + +/** + * Makes a plain error info object from an Error. + * @param {Error} err Error to get info from + * @returns {MakeErrorOptions} + * @private + */ +function makePlainError(err) { + return { + name: err.name, + message: err.message, + stack: err.stack, + }; +} + +const TextSortableGroupTypes = [ChannelType.GuildText, ChannelType.GuildAnnouncement, ChannelType.GuildForum]; +const VoiceSortableGroupTypes = [ChannelType.GuildVoice, ChannelType.GuildStageVoice]; +const CategorySortableGroupTypes = [ChannelType.GuildCategory]; + +/** + * Gets an array of the channel types that can be moved in the channel group. For example, a GuildText channel would + * return an array containing the types that can be ordered within the text channels (always at the top), and a voice + * channel would return an array containing the types that can be ordered within the voice channels (always at the + * bottom). + * @param {ChannelType} type The type of the channel + * @returns {ChannelType[]} + * @private + */ +function getSortableGroupTypes(type) { + switch (type) { + case ChannelType.GuildText: + case ChannelType.GuildAnnouncement: + case ChannelType.GuildForum: + return TextSortableGroupTypes; + case ChannelType.GuildVoice: + case ChannelType.GuildStageVoice: + return VoiceSortableGroupTypes; + case ChannelType.GuildCategory: + return CategorySortableGroupTypes; + default: + return [type]; + } +} + +/** + * Moves an element in an array *in place*. + * @param {Array<*>} array Array to modify + * @param {*} element Element to move + * @param {number} newIndex Index or offset to move the element to + * @param {boolean} [offset=false] Move the element by an offset amount rather than to a set index + * @returns {number} + * @private + */ +function moveElementInArray(array, element, newIndex, offset = false) { + const index = array.indexOf(element); + newIndex = (offset ? index : 0) + newIndex; + if (newIndex > -1 && newIndex < array.length) { + const removedElement = array.splice(index, 1)[0]; + array.splice(newIndex, 0, removedElement); + } + return array.indexOf(element); +} + +/** + * Verifies the provided data is a string, otherwise throws provided error. + * @param {string} data The string resolvable to resolve + * @param {Function} [error] The Error constructor to instantiate. Defaults to Error + * @param {string} [errorMessage] The error message to throw with. Defaults to "Expected string, got <data> instead." + * @param {boolean} [allowEmpty=true] Whether an empty string should be allowed + * @returns {string} + */ +function verifyString( + data, + error = Error, + errorMessage = `Expected a string, got ${data} instead.`, + allowEmpty = true, +) { + if (typeof data !== 'string') throw new error(errorMessage); + if (!allowEmpty && data.length === 0) throw new error(errorMessage); + return data; +} + +/** + * Can be a number, hex string, an RGB array like: + * ```js + * [255, 0, 255] // purple + * ``` + * or one of the following strings: + * - `Default` + * - `White` + * - `Aqua` + * - `Green` + * - `Blue` + * - `Yellow` + * - `Purple` + * - `LuminousVividPink` + * - `Fuchsia` + * - `Gold` + * - `Orange` + * - `Red` + * - `Grey` + * - `Navy` + * - `DarkAqua` + * - `DarkGreen` + * - `DarkBlue` + * - `DarkPurple` + * - `DarkVividPink` + * - `DarkGold` + * - `DarkOrange` + * - `DarkRed` + * - `DarkGrey` + * - `DarkerGrey` + * - `LightGrey` + * - `DarkNavy` + * - `Blurple` + * - `Greyple` + * - `DarkButNotBlack` + * - `NotQuiteBlack` + * - `Random` + * @typedef {string|number|number[]} ColorResolvable + */ + +/** + * Resolves a ColorResolvable into a color number. + * @param {ColorResolvable} color Color to resolve + * @returns {number} A color + */ +function resolveColor(color) { + if (typeof color === 'string') { + if (color === 'Random') return Math.floor(Math.random() * (0xffffff + 1)); + if (color === 'Default') return 0; + if (/^#?[\da-f]{6}$/i.test(color)) return parseInt(color.replace('#', ''), 16); + color = Colors[color]; + } else if (Array.isArray(color)) { + color = (color[0] << 16) + (color[1] << 8) + color[2]; + } + + if (color < 0 || color > 0xffffff) throw new DiscordjsRangeError(ErrorCodes.ColorRange); + if (typeof color !== 'number' || Number.isNaN(color)) throw new DiscordjsTypeError(ErrorCodes.ColorConvert); + + return color; +} + +/** + * Sorts by Discord's position and id. + * @param {Collection} collection Collection of objects to sort + * @returns {Collection} + */ +function discordSort(collection) { + const isGuildChannel = collection.first() instanceof GuildChannel; + return collection.sorted( + isGuildChannel + ? (a, b) => a.rawPosition - b.rawPosition || Number(BigInt(a.id) - BigInt(b.id)) + : (a, b) => a.rawPosition - b.rawPosition || Number(BigInt(b.id) - BigInt(a.id)), + ); +} + +/** + * Sets the position of a Channel or Role. + * @param {BaseChannel|Role} item Object to set the position of + * @param {number} position New position for the object + * @param {boolean} relative Whether `position` is relative to its current position + * @param {Collection<string, BaseChannel|Role>} sorted A collection of the objects sorted properly + * @param {Client} client The client to use to patch the data + * @param {string} route Route to call PATCH on + * @param {string} [reason] Reason for the change + * @returns {Promise<BaseChannel[]|Role[]>} Updated item list, with `id` and `position` properties + * @private + */ +async function setPosition(item, position, relative, sorted, client, route, reason) { + let updatedItems = [...sorted.values()]; + moveElementInArray(updatedItems, item, position, relative); + updatedItems = updatedItems.map((r, i) => ({ id: r.id, position: i })); + await client.rest.patch(route, { body: updatedItems, reason }); + return updatedItems; +} + +/** + * Alternative to Node's `path.basename`, removing query string after the extension if it exists. + * @param {string} path Path to get the basename of + * @param {string} [ext] File extension to remove + * @returns {string} Basename of the path + * @private + */ +function basename(path, ext) { + const res = parse(path); + return ext && res.ext.startsWith(ext) ? res.name : res.base.split('?')[0]; +} + +/** + * The content to have all mentions replaced by the equivalent text. + * @param {string} str The string to be converted + * @param {TextBasedChannels} channel The channel the string was sent in + * @returns {string} + */ +function cleanContent(str, channel) { + return str.replaceAll(/<(@[!&]?|#)(\d{17,19})>/g, (match, type, id) => { + switch (type) { + case '@': + case '@!': { + const member = channel.guild?.members.cache.get(id); + if (member) { + return `@${member.displayName}`; + } + + const user = channel.client.users.cache.get(id); + return user ? `@${user.username}` : match; + } + case '@&': { + if (channel.type === ChannelType.DM) return match; + const role = channel.guild.roles.cache.get(id); + return role ? `@${role.name}` : match; + } + case '#': { + const mentionedChannel = channel.client.channels.cache.get(id); + return mentionedChannel ? `#${mentionedChannel.name}` : match; + } + default: { + return match; + } + } + }); +} + +/** + * The content to put in a code block with all code block fences replaced by the equivalent backticks. + * @param {string} text The string to be converted + * @returns {string} + */ +function cleanCodeBlockContent(text) { + return text.replaceAll('```', '`\u200b``'); +} + +/** + * Parses a webhook URL for the id and token. + * @param {string} url The URL to parse + * @returns {?WebhookClientDataIdWithToken} `null` if the URL is invalid, otherwise the id and the token + */ +function parseWebhookURL(url) { + const matches = url.match( + /https?:\/\/(?:ptb\.|canary\.)?discord\.com\/api(?:\/v\d{1,2})?\/webhooks\/(\d{17,19})\/([\w-]{68})/i, + ); + + if (!matches || matches.length <= 2) return null; + + const [, id, token] = matches; + return { + id, + token, + }; +} + +module.exports = { + flatten, + fetchRecommendedShardCount, + parseEmoji, + resolvePartialEmoji, + mergeDefault, + makeError, + makePlainError, + getSortableGroupTypes, + moveElementInArray, + verifyString, + resolveColor, + discordSort, + setPosition, + basename, + cleanContent, + cleanCodeBlockContent, + parseWebhookURL, +}; + +// Fixes Circular +const GuildChannel = require('../structures/GuildChannel'); diff --git a/node_modules/discord.js/src/util/WebSocketShardEvents.js b/node_modules/discord.js/src/util/WebSocketShardEvents.js new file mode 100644 index 0000000..81e05f2 --- /dev/null +++ b/node_modules/discord.js/src/util/WebSocketShardEvents.js @@ -0,0 +1,25 @@ +'use strict'; + +/** + * @typedef {Object} WebSocketShardEvents + * @property {string} Close close + * @property {string} Destroyed destroyed + * @property {string} InvalidSession invalidSession + * @property {string} Ready ready + * @property {string} Resumed resumed + * @property {string} AllReady allReady + */ + +// JSDoc for IntelliSense purposes +/** + * @type {WebSocketShardEvents} + * @ignore + */ +module.exports = { + Close: 'close', + Destroyed: 'destroyed', + InvalidSession: 'invalidSession', + Ready: 'ready', + Resumed: 'resumed', + AllReady: 'allReady', +}; |