diff --git a/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js b/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js index fc46539..b89bcbb 100644 --- a/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +++ b/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js @@ -1,16 +1,19 @@ 'use strict'; -const { Events } = require('../../../util/Constants'); -module.exports = (client, packet) => { - /** - * Emitted whenever a recipient is added from a group DM. - * @event Client#channelRecipientAdd - * @param {PartialGroupDMChannel} channel Group DM channel - * @param {User} user User - */ +const { Events, Status } = require('../../../util/Constants'); +module.exports = (client, packet, shard) => { const channel = client.channels.cache.get(packet.d.channel_id); - if (!channel) return; - if (!channel._recipients) channel._recipients = []; - channel._recipients.push(packet.d.user); - const user = client.users._add(packet.d.user); - client.emit(Events.CHANNEL_RECIPIENT_ADD, channel, user); + if (channel) { + if (!channel._recipients) channel._recipients = []; + channel._recipients.push(packet.d.user); + const user = client.users._add(packet.d.user); + if (shard.status == Status.READY) { + /** + * Emitted whenever a recipient is added from a group DM. + * @event Client#channelRecipientAdd + * @param {GroupDMChannel} channel Group DM channel + * @param {User} user User + */ + client.emit(Events.CHANNEL_RECIPIENT_ADD, channel, user); + } + } }; diff --git a/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js b/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js index 5a2c917..22b3f98 100644 --- a/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +++ b/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js @@ -1,16 +1,16 @@ 'use strict'; const { Events } = require('../../../util/Constants'); module.exports = (client, packet) => { - /** - * Emitted whenever a recipient is removed from a group DM. - * @event Client#channelRecipientRemove - * @param {PartialGroupDMChannel} channel Group DM channel - * @param {User} user User - */ const channel = client.channels.cache.get(packet.d.channel_id); - if (!channel) return; - if (!channel._recipients) channel._recipients = []; - channel._recipients = channel._recipients.filter(r => r !== packet.d.user.id); - const user = client.users._add(packet.d.user); - client.emit(Events.CHANNEL_RECIPIENT_REMOVE, channel, user); + if (channel) { + if (!channel._recipients) channel._recipients = []; + channel._recipients = channel._recipients.filter(u => u.id !== packet.d.user.id); + /** + * Emitted whenever a recipient is removed from a group DM. + * @event Client#channelRecipientRemove + * @param {GroupDMChannel} channel Group DM channel + * @param {User} user User + */ + client.emit(Events.CHANNEL_RECIPIENT_REMOVE, channel, client.users._add(packet.d.user)); + } }; diff --git a/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js b/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js deleted file mode 100644 index 1a1865d..00000000 --- a/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; -const { Events } = require('../../../util/Constants'); - -module.exports = (client, { d: data }) => { - for (const command of data.application_commands) { - const user = client.users.cache.get(command.application_id); - if (!user || !user.bot) continue; - user.application?.commands?._add(command, true); - } - client.emit(Events.GUILD_APPLICATION_COMMANDS_UPDATE, data); -}; diff --git a/src/client/websocket/handlers/MESSAGE_ACK.js b/src/client/websocket/handlers/MESSAGE_ACK.js deleted file mode 100644 index cae8c5b..00000000 --- a/src/client/websocket/handlers/MESSAGE_ACK.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const { Events } = require('../../../util/Constants'); - -module.exports = (client, { d: data }) => { - const channel = client.channels.cache.get(data.channel_id); - /** - * Emitted whenever message is acknowledged (mark read / unread) - * @event Client#messageAck - * @param {TextChannel} channel Channel - * @param {Snowflake} message_id Message ID - * @param {boolean} isRead Whether the message is read - * @param {Object} raw Raw data - */ - client.emit(Events.MESSAGE_ACK, channel, data.message_id, !data.manual, data); -}; diff --git a/src/client/websocket/handlers/USER_NOTE_UPDATE.js b/src/client/websocket/handlers/USER_NOTE_UPDATE.js index 5e36745..daa1708 100644 --- a/src/client/websocket/handlers/USER_NOTE_UPDATE.js +++ b/src/client/websocket/handlers/USER_NOTE_UPDATE.js @@ -1,5 +1,5 @@ 'use strict'; module.exports = (client, { d: data }) => { - client.user.notes.set(data.id, data.note); + client.notes.cache.set(data.id, data.note); }; diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index e0a40d9..543ed1d 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -130,7 +130,7 @@ class GuildBanManager extends CachedManager { * @typedef {Object} BanOptions * @property {number} [days=0] Number of days of messages to delete, must be between 0 and 7, inclusive * This property is deprecated. Use `deleteMessageSeconds` instead. - * @property {number} [deleteMessageSeconds=0] Number of seconds of messages to delete, + * @property {number} [deleteMessageSeconds] Number of seconds of messages to delete, * must be between 0 and 604800 (7 days), inclusive * @property {string} [reason] The reason for the ban */ diff --git a/src/managers/PermissionOverwriteManager.js b/src/managers/PermissionOverwriteManager.js index 5793073..d71badf 100644 --- a/src/managers/PermissionOverwriteManager.js +++ b/src/managers/PermissionOverwriteManager.js @@ -89,7 +89,7 @@ class PermissionOverwriteManager extends CachedManager { * @private */ async upsert(userOrRole, options, overwriteOptions = {}, existing) { - const userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole); + let userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole); let { type, reason } = overwriteOptions; if (typeof type !== 'number') { userOrRole = this.channel.guild.roles.resolve(userOrRole) ?? this.client.users.resolve(userOrRole); diff --git a/src/managers/ThreadMemberManager.js b/src/managers/ThreadMemberManager.js index be3f89f..b6d3809 100644 --- a/src/managers/ThreadMemberManager.js +++ b/src/managers/ThreadMemberManager.js @@ -179,7 +179,7 @@ class ThreadMemberManager extends CachedManager { const id = this.resolveId(member); return id ? this._fetchOne(id, options) - : this._fetchMany(typeof member !== 'boolean' ? member : { ...options, cache: member }); + : this._fetchMany(typeof member === 'boolean' ? { ...options, cache: member } : options); } } diff --git a/src/structures/ApplicationRoleConnectionMetadata.js b/src/structures/ApplicationRoleConnectionMetadata.js index 037c190..aaa7da6 100644 --- a/src/structures/ApplicationRoleConnectionMetadata.js +++ b/src/structures/ApplicationRoleConnectionMetadata.js @@ -2,6 +2,9 @@ const { ApplicationRoleConnectionMetadataTypes } = require('../util/Constants'); +/** + * Role connection metadata object for an application. + */ class ApplicationRoleConnectionMetadata { constructor(data) { /** diff --git a/src/structures/AutoModerationRule.js b/src/structures/AutoModerationRule.js index bfc1b98..838a0f9 100644 --- a/src/structures/AutoModerationRule.js +++ b/src/structures/AutoModerationRule.js @@ -194,7 +194,7 @@ class AutoModerationRule extends Base { * @returns {Promise} */ setKeywordFilter(keywordFilter, reason) { - return this.edit({ triggerMetadata: { keywordFilter }, reason }); + return this.edit({ triggerMetadata: { ...this.triggerMetadata, keywordFilter }, reason }); } /** @@ -205,7 +205,7 @@ class AutoModerationRule extends Base { * @returns {Promise} */ setRegexPatterns(regexPatterns, reason) { - return this.edit({ triggerMetadata: { regexPatterns }, reason }); + return this.edit({ triggerMetadata: { ...this.triggerMetadata, regexPatterns }, reason }); } /** @@ -215,7 +215,7 @@ class AutoModerationRule extends Base { * @returns {Promise} */ setPresets(presets, reason) { - return this.edit({ triggerMetadata: { presets }, reason }); + return this.edit({ triggerMetadata: { ...this.triggerMetadata, presets }, reason }); } /** @@ -225,7 +225,7 @@ class AutoModerationRule extends Base { * @returns {Promise} */ setAllowList(allowList, reason) { - return this.edit({ triggerMetadata: { allowList }, reason }); + return this.edit({ triggerMetadata: { ...this.triggerMetadata, allowList }, reason }); } /** @@ -235,7 +235,7 @@ class AutoModerationRule extends Base { * @returns {Promise} */ setMentionTotalLimit(mentionTotalLimit, reason) { - return this.edit({ triggerMetadata: { mentionTotalLimit }, reason }); + return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionTotalLimit }, reason }); } /** diff --git a/src/structures/AutocompleteInteraction.js b/src/structures/AutocompleteInteraction.js index 41900ab..4d57ebf 100644 --- a/src/structures/AutocompleteInteraction.js +++ b/src/structures/AutocompleteInteraction.js @@ -2,6 +2,7 @@ const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver'); const Interaction = require('./Interaction'); +const { Error } = require('../errors'); const { InteractionResponseTypes, ApplicationCommandOptionTypes } = require('../util/Constants'); /** diff --git a/src/structures/BaseMessageComponent.js b/src/structures/BaseMessageComponent.js index 4075827..8ae40df 100644 --- a/src/structures/BaseMessageComponent.js +++ b/src/structures/BaseMessageComponent.js @@ -76,7 +76,11 @@ class BaseMessageComponent { component = data instanceof MessageButton ? data : new MessageButton(data); break; } - case MessageComponentTypes.SELECT_MENU: { + case MessageComponentTypes.STRING_SELECT: + case MessageComponentTypes.USER_SELECT: + case MessageComponentTypes.ROLE_SELECT: + case MessageComponentTypes.MENTIONABLE_SELECT: + case MessageComponentTypes.CHANNEL_SELECT: { const MessageSelectMenu = require('./MessageSelectMenu'); component = data instanceof MessageSelectMenu ? data : new MessageSelectMenu(data); break; diff --git a/src/structures/Channel.js b/src/structures/Channel.js index cdffc3a..7370087 100644 --- a/src/structures/Channel.js +++ b/src/structures/Channel.js @@ -53,7 +53,6 @@ class Channel extends Base { if ('flags' in data) { /** * The flags that are applied to the channel. - * This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`. * @type {?Readonly} */ this.flags = new ChannelFlags(data.flags).freeze(); @@ -203,8 +202,8 @@ class Channel extends Base { if ((data.recipients && data.type !== ChannelTypes.GROUP_DM) || data.type === ChannelTypes.DM) { channel = new DMChannel(client, data); } else if (data.type === ChannelTypes.GROUP_DM) { - const PartialGroupDMChannel = require('./PartialGroupDMChannel'); - channel = new PartialGroupDMChannel(client, data); + const GroupDMChannel = require('./GroupDMChannel'); + channel = new GroupDMChannel(client, data); } } else { guild ??= client.guilds.cache.get(data.guild_id); diff --git a/src/structures/ContextMenuInteraction.js b/src/structures/ContextMenuInteraction.js index f4f6ef4..2ddcb90 100644 --- a/src/structures/ContextMenuInteraction.js +++ b/src/structures/ContextMenuInteraction.js @@ -22,7 +22,7 @@ class ContextMenuInteraction extends BaseCommandInteraction { ); /** - * The id of the target of the interaction + * The id of the target of this interaction * @type {Snowflake} */ this.targetId = data.data.target_id; diff --git a/src/structures/ForumChannel.js b/src/structures/ForumChannel.js index 61723e4..589b01f 100644 --- a/src/structures/ForumChannel.js +++ b/src/structures/ForumChannel.js @@ -3,7 +3,6 @@ const GuildChannel = require('./GuildChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); const GuildForumThreadManager = require('../managers/GuildForumThreadManager'); -const InteractionManager = require('../managers/InteractionManager'); const { SortOrderTypes, ForumLayoutTypes } = require('../util/Constants'); const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require('../util/Util'); @@ -46,12 +45,6 @@ class ForumChannel extends GuildChannel { constructor(guild, data, client) { super(guild, data, client, false); - /** - * A manager of the interactions sent to this channel - * @type {InteractionManager} - */ - this.interactions = new InteractionManager(this); - /** * A manager of the threads belonging to this channel * @type {GuildForumThreadManager} @@ -260,12 +253,9 @@ TextBasedChannel.applyToClass(ForumChannel, true, [ 'send', 'lastMessage', 'lastPinAt', - 'bulkDelete', 'sendTyping', 'createMessageCollector', 'awaitMessages', - 'createMessageComponentCollector', - 'awaitMessageComponent', ]); module.exports = ForumChannel; diff --git a/src/structures/GroupDMChannel.js b/src/structures/GroupDMChannel.js index 207715e..723f2ec 100644 --- a/src/structures/GroupDMChannel.js +++ b/src/structures/GroupDMChannel.js @@ -299,8 +299,6 @@ class GroupDMChannel extends Channel { sendTyping() {} createMessageCollector() {} awaitMessages() {} - createMessageComponentCollector() {} - awaitMessageComponent() {} // Doesn't work on DM channels; setRateLimitPerUser() {} // Doesn't work on DM channels; setNSFW() {} } diff --git a/src/structures/Interaction.js b/src/structures/Interaction.js index 1cbc74c..393fb60 100644 --- a/src/structures/Interaction.js +++ b/src/structures/Interaction.js @@ -269,71 +269,10 @@ class Interaction extends Base { * Indicates whether this interaction is a {@link SelectMenuInteraction}. * @returns {boolean} */ - isAnySelectMenu() { - return InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT && typeof this.values !== 'undefined'; - } - - /** - * Indicates whether this interaction is a {@link SelectMenuInteraction} with a `STRING_SELECT` type. - * @returns {boolean} - * @deprecated Use {@link Interaction#isStringSelect()} instead - */ isSelectMenu() { - return this.isStringSelect(); - } - - /** - * Indicates whether this interaction is a {@link SelectMenuInteraction} with a `STRING_SELECT` type. - * @returns {boolean} - */ - isStringSelect() { return ( InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT && - MessageComponentTypes[this.componentType] === MessageComponentTypes.STRING_SELECT - ); - } - - /** - * Indicates whether this interaction is a {@link SelectMenuInteraction} with a `USER_SELECT` type. - * @returns {boolean} - */ - isUserSelect() { - return ( - InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT && - MessageComponentTypes[this.componentType] === MessageComponentTypes.USER_SELECT - ); - } - - /** - * Indicates whether this interaction is a {@link SelectMenuInteraction} with a `ROLE_SELECT` type. - * @returns {boolean} - */ - isRoleSelect() { - return ( - InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT && - MessageComponentTypes[this.componentType] === MessageComponentTypes.ROLE_SELECT - ); - } - - /** - * Indicates whether this interaction is a {@link SelectMenuInteraction} with a `MENTIONABLE_SELECT` type. - * @returns {boolean} - */ - isMentionableSelect() { - return ( - InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT && - MessageComponentTypes[this.componentType] === MessageComponentTypes.MENTIONABLE_SELECT - ); - } - - /** - * Indicates whether this interaction is a {@link SelectMenuInteraction} with a `CHANNEL_SELECT` type. - * @returns {boolean} - */ - isChannelSelect() { - return ( - InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT && - MessageComponentTypes[this.componentType] === MessageComponentTypes.CHANNEL_SELECT + MessageComponentTypes[this.componentType] === MessageComponentTypes.SELECT_MENU ); } diff --git a/src/structures/MessageButton.js b/src/structures/MessageButton.js index c3a0613..a94c1ec 100644 --- a/src/structures/MessageButton.js +++ b/src/structures/MessageButton.js @@ -1,13 +1,9 @@ 'use strict'; -const { setTimeout } = require('node:timers'); const BaseMessageComponent = require('./BaseMessageComponent'); const { RangeError } = require('../errors'); -const { MessageButtonStyles, MessageComponentTypes, InteractionTypes } = require('../util/Constants'); -const SnowflakeUtil = require('../util/SnowflakeUtil'); +const { MessageButtonStyles, MessageComponentTypes } = require('../util/Constants'); const Util = require('../util/Util'); -const { lazy } = require('../util/Util'); -const Message = lazy(() => require('../structures/Message').Message); /** * Represents a button message component. @@ -164,68 +160,6 @@ class MessageButton extends BaseMessageComponent { static resolveStyle(style) { return typeof style === 'string' ? style : MessageButtonStyles[style]; } - // Patch Click - /** - * Click the button - * @param {Message} message Discord Message - * @returns {Promise} - */ - async click(message) { - const nonce = SnowflakeUtil.generate(); - if (!(message instanceof Message())) throw new Error('[UNKNOWN_MESSAGE] Please pass a valid Message'); - if (!this.customId || this.style == MessageButtonStyles.LINK || this.disabled) return false; - const data = { - type: InteractionTypes.MESSAGE_COMPONENT, - nonce, - guild_id: message.guild?.id ?? null, - channel_id: message.channel.id, - message_id: message.id, - application_id: message.applicationId ?? message.author.id, - session_id: message.client.sessionId, - message_flags: message.flags.bitfield, - data: { - component_type: MessageComponentTypes.BUTTON, - custom_id: this.customId, - }, - }; - await message.client.api.interactions.post({ - data, - }); - message.client._interactionCache.set(nonce, { - channelId: message.channelId, - guildId: message.guildId, - metadata: data, - }); - return new Promise((resolve, reject) => { - const handler = data => { - timeout.refresh(); - if (data.metadata?.nonce !== nonce) return; - clearTimeout(timeout); - message.client.removeListener('interactionResponse', handler); - message.client.decrementMaxListeners(); - if (data.status) { - resolve(data.metadata); - } else { - reject( - new Error('INTERACTION_ERROR', { - cause: data, - }), - ); - } - }; - const timeout = setTimeout(() => { - message.client.removeListener('interactionResponse', handler); - message.client.decrementMaxListeners(); - reject( - new Error('INTERACTION_TIMEOUT', { - cause: data, - }), - ); - }, message.client.options.interactionTimeout).unref(); - message.client.incrementMaxListeners(); - message.client.on('interactionResponse', handler); - }); - } } module.exports = MessageButton; diff --git a/src/structures/MessageSelectMenu.js b/src/structures/MessageSelectMenu.js index cfeeb52..3a118dd 100644 --- a/src/structures/MessageSelectMenu.js +++ b/src/structures/MessageSelectMenu.js @@ -1,16 +1,7 @@ 'use strict'; -const { setTimeout } = require('node:timers'); const BaseMessageComponent = require('./BaseMessageComponent'); -const { - ChannelTypes, - MessageComponentTypes, - SelectMenuComponentTypes, - InteractionTypes, -} = require('../util/Constants'); -const SnowflakeUtil = require('../util/SnowflakeUtil'); -const { lazy } = require('../util/Util'); -const Message = lazy(() => require('./Message').Message); +const { ChannelTypes, MessageComponentTypes } = require('../util/Constants'); const Util = require('../util/Util'); /** @@ -103,130 +94,6 @@ class MessageSelectMenu extends BaseMessageComponent { ) ?? []; } - /** - * Adds the channel types to the select menu - * @param {...ChannelType[]} channelTypes Added channel types - * @returns {MessageSelectMenu} - */ - addChannelTypes(...channelTypes) { - if (!channelTypes.every(channelType => ChannelTypes[channelType])) { - throw new TypeError('INVALID_TYPE', 'channelTypes', 'Rest'); - } - this.channelTypes.push( - ...channelTypes.map(channelType => (typeof channelType === 'string' ? channelType : ChannelTypes[channelType])), - ); - return this; - } - - /** - * Sets the channel types of the select menu - * @param {...ChannelType[]} channelTypes An array of new channel types - * @returns {MessageSelectMenu} - */ - setChannelTypes(...channelTypes) { - if (!channelTypes.every(channelType => ChannelTypes[channelType])) { - throw new TypeError('INVALID_TYPE', 'channelTypes', 'Rest'); - } - this.channelTypes = channelTypes.map(channelType => - typeof channelType === 'string' ? channelType : ChannelTypes[channelType], - ); - return this; - } - - /** - * Sets the custom id of this select menu - * @param {string} customId A unique string to be sent in the interaction when clicked - * @returns {MessageSelectMenu} - */ - setCustomId(customId) { - this.customId = Util.verifyString(customId, RangeError, 'SELECT_MENU_CUSTOM_ID'); - return this; - } - - /** - * Sets the interactive status of the select menu - * @param {boolean} [disabled=true] Whether this select menu should be disabled - * @returns {MessageSelectMenu} - */ - setDisabled(disabled = true) { - this.disabled = disabled; - return this; - } - - /** - * Sets the maximum number of selections allowed for this select menu - * @param {number} maxValues Number of selections to be allowed - * @returns {MessageSelectMenu} - */ - setMaxValues(maxValues) { - this.maxValues = maxValues; - return this; - } - - /** - * Sets the minimum number of selections required for this select menu - * This will default the maxValues to the number of options, unless manually set - * @param {number} minValues Number of selections to be required - * @returns {MessageSelectMenu} - */ - setMinValues(minValues) { - this.minValues = minValues; - return this; - } - - /** - * Sets the placeholder of this select menu - * @param {string} placeholder Custom placeholder text to display when nothing is selected - * @returns {MessageSelectMenu} - */ - setPlaceholder(placeholder) { - this.placeholder = Util.verifyString(placeholder, RangeError, 'SELECT_MENU_PLACEHOLDER'); - return this; - } - - /** - * Sets the type of the select menu - * @param {SelectMenuComponentType} type Type of the select menu - * @returns {MessageSelectMenu} - */ - setType(type) { - if (!SelectMenuComponentTypes[type]) throw new TypeError('INVALID_TYPE', 'type', 'SelectMenuComponentType'); - this.type = BaseMessageComponent.resolveType(type); - return this; - } - - /** - * Adds options to the select menu. - * @param {...MessageSelectOptionData|MessageSelectOptionData[]} options The options to add - * @returns {MessageSelectMenu} - */ - addOptions(...options) { - this.options.push(...this.constructor.normalizeOptions(options)); - return this; - } - - /** - * Sets the options of the select menu. - * @param {...MessageSelectOptionData|MessageSelectOptionData[]} options The options to set - * @returns {MessageSelectMenu} - */ - setOptions(...options) { - this.spliceOptions(0, this.options.length, options); - return this; - } - - /** - * Removes, replaces, and inserts options in the select menu. - * @param {number} index The index to start at - * @param {number} deleteCount The number of options to remove - * @param {...MessageSelectOptionData|MessageSelectOptionData[]} [options] The replacing option objects - * @returns {MessageSelectMenu} - */ - spliceOptions(index, deleteCount, ...options) { - this.options.splice(index, deleteCount, ...this.constructor.normalizeOptions(...options)); - return this; - } - /** * Transforms the select menu into a plain object * @returns {APIMessageSelectMenu} The raw data of this select menu @@ -268,124 +135,6 @@ class MessageSelectMenu extends BaseMessageComponent { static normalizeOptions(...options) { return options.flat(Infinity).map(option => this.normalizeOption(option)); } - - // Add - /** - * Mesage select menu - * @param {Message} message The message this select menu is for - * @param {Array} values The values of the select menu - * @returns {Promise} - */ - async select(message, values) { - if (!(message instanceof Message())) throw new Error('[UNKNOWN_MESSAGE] Please pass a valid Message'); - if (!Array.isArray(values)) throw new TypeError('[INVALID_VALUES] Please pass an array of values'); - if (!this.customId || this.disabled) { - throw new Error('[INVALID_MENU] Menu does not contain Id or has been disabled'); - } // Disabled or null customID - if (values.length < this.minValues) { - throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${this.minValues}`); - } - if (values.length > this.maxValues) { - throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${this.maxValues}`); - } - const parseValues = value => { - switch (this.type) { - case 'SELECT_MENU': - case 'STRING_SELECT': { - if (typeof value !== 'string') throw new TypeError('[INVALID_VALUE] Please pass a string value'); - const value_ = this.options.find(obj => obj.value === value || obj.label === value); - if (!value_) throw new Error('[INVALID_VALUE] Please pass a valid value'); - return value_.value; - } - case 'USER_SELECT': { - const userId = this.client.users.resolveId(value); - if (!userId) throw new Error('[INVALID_VALUE] Please pass a valid user'); - return userId; - } - case 'ROLE_SELECT': { - const roleId = this.client.roles.resolveId(value); - if (!roleId) throw new Error('[INVALID_VALUE] Please pass a valid role'); - return roleId; - } - case 'MENTIONABLE_SELECT': { - const mentionableId = this.client.users.resolveId(value) || this.client.roles.resolveId(value); - if (!mentionableId) throw new Error('[INVALID_VALUE] Please pass a valid mentionable'); - return mentionableId; - } - case 'CHANNEL_SELECT': { - const channel = this.client.channels.resolve(value); - if (!channel) throw new Error('[INVALID_VALUE] Please pass a valid channel'); - if (!this.channelTypes.includes(channel.type)) { - throw new Error( - `[INVALID_VALUE] Please pass a valid channel type (Got: ${channel.type}, allow: ${this.channelTypes.join( - ', ', - )})`, - ); - } - return channel.id; - } - default: { - throw new Error(`[INVALID_TYPE] Please pass a valid select menu type (Got ${this.type})`); - } - } - }; - - const nonce = SnowflakeUtil.generate(); - const data = { - type: InteractionTypes.MESSAGE_COMPONENT, - guild_id: message.guild?.id ?? null, - channel_id: message.channel.id, - message_id: message.id, - application_id: message.applicationId ?? message.author.id, - session_id: message.client.sessionId, - message_flags: message.flags.bitfield, - data: { - component_type: MessageComponentTypes[this.type], - custom_id: this.customId, - type: MessageComponentTypes[this.type], - values: values?.length ? values.map(parseValues) : [], - }, - nonce, - }; - - await message.client.api.interactions.post({ - data, - }); - message.client._interactionCache.set(nonce, { - channelId: message.channelId, - guildId: message.guildId, - metadata: data, - }); - return new Promise((resolve, reject) => { - const handler = data => { - timeout.refresh(); - if (data.metadata?.nonce !== nonce) return; - clearTimeout(timeout); - message.client.removeListener('interactionResponse', handler); - message.client.decrementMaxListeners(); - if (data.status) { - resolve(data.metadata); - } else { - reject( - new Error('INTERACTION_ERROR', { - cause: data, - }), - ); - } - }; - const timeout = setTimeout(() => { - message.client.removeListener('interactionResponse', handler); - message.client.decrementMaxListeners(); - reject( - new Error('INTERACTION_TIMEOUT', { - cause: data, - }), - ); - }, message.client.options.interactionTimeout).unref(); - message.client.incrementMaxListeners(); - message.client.on('interactionResponse', handler); - }); - } } module.exports = MessageSelectMenu; diff --git a/src/structures/Modal.js b/src/structures/Modal.js index 697195e..47226c4 100644 --- a/src/structures/Modal.js +++ b/src/structures/Modal.js @@ -138,7 +138,7 @@ class Modal { data: postData, }); return new Promise((resolve, reject) => { - const timeoutMs = 15_000; + const timeoutMs = 5_000; // Waiting for MsgCreate / ModalCreate const handler = data => { if (data.nonce !== nonce) return; diff --git a/src/structures/TextInputComponent.js b/src/structures/TextInputComponent.js index 7218048..af60ac1 100644 --- a/src/structures/TextInputComponent.js +++ b/src/structures/TextInputComponent.js @@ -82,76 +82,6 @@ class TextInputComponent extends BaseMessageComponent { this.value = data.value ?? null; } - /** - * Sets the custom id of this text input component - * @param {string} customId A unique string to be sent in the interaction when submitted - * @returns {TextInputComponent} - */ - setCustomId(customId) { - this.customId = Util.verifyString(customId, RangeError, 'TEXT_INPUT_CUSTOM_ID'); - return this; - } - - /** - * Sets the label of this text input component - * @param {string} label The text to be displayed above this text input component - * @returns {TextInputComponent} - */ - setLabel(label) { - this.label = Util.verifyString(label, RangeError, 'TEXT_INPUT_LABEL'); - return this; - } - - /** - * Sets the text input component to be required for modal submission - * @param {boolean} [required=true] Whether this text input component is required - * @returns {TextInputComponent} - */ - setRequired(required = true) { - this.required = required; - return this; - } - - /** - * Sets the maximum length of text input required in this text input component - * @param {number} maxLength Maximum length of text to be required - * @returns {TextInputComponent} - */ - setMaxLength(maxLength) { - this.maxLength = maxLength; - return this; - } - - /** - * Sets the minimum length of text input required in this text input component - * @param {number} minLength Minimum length of text to be required - * @returns {TextInputComponent} - */ - setMinLength(minLength) { - this.minLength = minLength; - return this; - } - - /** - * Sets the placeholder of this text input component - * @param {string} placeholder Custom placeholder text to display when no text is entered - * @returns {TextInputComponent} - */ - setPlaceholder(placeholder) { - this.placeholder = Util.verifyString(placeholder, RangeError, 'TEXT_INPUT_PLACEHOLDER'); - return this; - } - - /** - * Sets the style of this text input component - * @param {TextInputStyleResolvable} style The style of this text input component - * @returns {TextInputComponent} - */ - setStyle(style) { - this.style = TextInputComponent.resolveStyle(style); - return this; - } - /** * Sets the value of this text input component * @param {string} value Value of this text input component