discord-selfbot-v13.js 0.0.1-security → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of discord-selfbot-v13.js might be problematic. Click here for more details.
- package/LICENSE +674 -0
- package/README.md +128 -5
- package/package.json +98 -3
- package/src/WebSocket.js +39 -0
- package/src/client/BaseClient.js +87 -0
- package/src/client/Client.js +1124 -0
- package/src/client/WebhookClient.js +61 -0
- package/src/client/actions/Action.js +120 -0
- package/src/client/actions/ActionsManager.js +78 -0
- package/src/client/actions/ApplicationCommandPermissionsUpdate.js +34 -0
- package/src/client/actions/AutoModerationActionExecution.js +26 -0
- package/src/client/actions/AutoModerationRuleCreate.js +27 -0
- package/src/client/actions/AutoModerationRuleDelete.js +31 -0
- package/src/client/actions/AutoModerationRuleUpdate.js +29 -0
- package/src/client/actions/ChannelCreate.js +23 -0
- package/src/client/actions/ChannelDelete.js +39 -0
- package/src/client/actions/ChannelUpdate.js +43 -0
- package/src/client/actions/GuildAuditLogEntryCreate.js +29 -0
- package/src/client/actions/GuildBanAdd.js +20 -0
- package/src/client/actions/GuildBanRemove.js +25 -0
- package/src/client/actions/GuildChannelsPositionUpdate.js +21 -0
- package/src/client/actions/GuildDelete.js +65 -0
- package/src/client/actions/GuildEmojiCreate.js +20 -0
- package/src/client/actions/GuildEmojiDelete.js +21 -0
- package/src/client/actions/GuildEmojiUpdate.js +20 -0
- package/src/client/actions/GuildEmojisUpdate.js +34 -0
- package/src/client/actions/GuildIntegrationsUpdate.js +19 -0
- package/src/client/actions/GuildMemberRemove.js +33 -0
- package/src/client/actions/GuildMemberUpdate.js +44 -0
- package/src/client/actions/GuildRoleCreate.js +25 -0
- package/src/client/actions/GuildRoleDelete.js +31 -0
- package/src/client/actions/GuildRoleUpdate.js +39 -0
- package/src/client/actions/GuildRolesPositionUpdate.js +21 -0
- package/src/client/actions/GuildScheduledEventCreate.js +27 -0
- package/src/client/actions/GuildScheduledEventDelete.js +31 -0
- package/src/client/actions/GuildScheduledEventUpdate.js +30 -0
- package/src/client/actions/GuildScheduledEventUserAdd.js +32 -0
- package/src/client/actions/GuildScheduledEventUserRemove.js +32 -0
- package/src/client/actions/GuildStickerCreate.js +20 -0
- package/src/client/actions/GuildStickerDelete.js +21 -0
- package/src/client/actions/GuildStickerUpdate.js +20 -0
- package/src/client/actions/GuildStickersUpdate.js +34 -0
- package/src/client/actions/GuildUpdate.js +33 -0
- package/src/client/actions/InteractionCreate.js +115 -0
- package/src/client/actions/InviteCreate.js +28 -0
- package/src/client/actions/InviteDelete.js +30 -0
- package/src/client/actions/MessageCreate.js +61 -0
- package/src/client/actions/MessageDelete.js +32 -0
- package/src/client/actions/MessageDeleteBulk.js +46 -0
- package/src/client/actions/MessageReactionAdd.js +56 -0
- package/src/client/actions/MessageReactionRemove.js +45 -0
- package/src/client/actions/MessageReactionRemoveAll.js +33 -0
- package/src/client/actions/MessageReactionRemoveEmoji.js +28 -0
- package/src/client/actions/MessageUpdate.js +26 -0
- package/src/client/actions/PresenceUpdate.js +45 -0
- package/src/client/actions/StageInstanceCreate.js +28 -0
- package/src/client/actions/StageInstanceDelete.js +33 -0
- package/src/client/actions/StageInstanceUpdate.js +30 -0
- package/src/client/actions/ThreadCreate.js +24 -0
- package/src/client/actions/ThreadDelete.js +32 -0
- package/src/client/actions/ThreadListSync.js +59 -0
- package/src/client/actions/ThreadMemberUpdate.js +30 -0
- package/src/client/actions/ThreadMembersUpdate.js +34 -0
- package/src/client/actions/TypingStart.js +29 -0
- package/src/client/actions/UserUpdate.js +35 -0
- package/src/client/actions/VoiceStateUpdate.js +57 -0
- package/src/client/actions/WebhooksUpdate.js +20 -0
- package/src/client/voice/ClientVoiceManager.js +51 -0
- package/src/client/websocket/WebSocketManager.js +412 -0
- package/src/client/websocket/WebSocketShard.js +905 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +23 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_CREATE.js +18 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_DELETE.js +20 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_UPDATE.js +20 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js +5 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js +5 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js +5 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/CALL_CREATE.js +14 -0
- package/src/client/websocket/handlers/CALL_DELETE.js +11 -0
- package/src/client/websocket/handlers/CALL_UPDATE.js +11 -0
- package/src/client/websocket/handlers/CHANNEL_CREATE.js +5 -0
- package/src/client/websocket/handlers/CHANNEL_DELETE.js +5 -0
- package/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js +22 -0
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +16 -0
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +16 -0
- package/src/client/websocket/handlers/CHANNEL_UPDATE.js +16 -0
- package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +11 -0
- package/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_BAN_ADD.js +5 -0
- package/src/client/websocket/handlers/GUILD_BAN_REMOVE.js +5 -0
- package/src/client/websocket/handlers/GUILD_CREATE.js +53 -0
- package/src/client/websocket/handlers/GUILD_DELETE.js +5 -0
- package/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +39 -0
- package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +20 -0
- package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +55 -0
- package/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js +5 -0
- package/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_ROLE_CREATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_ROLE_DELETE.js +5 -0
- package/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
- package/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_UPDATE.js +5 -0
- package/src/client/websocket/handlers/INTERACTION_CREATE.js +16 -0
- package/src/client/websocket/handlers/INTERACTION_FAILURE.js +18 -0
- package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +11 -0
- package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +30 -0
- package/src/client/websocket/handlers/INVITE_CREATE.js +5 -0
- package/src/client/websocket/handlers/INVITE_DELETE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_ACK.js +16 -0
- package/src/client/websocket/handlers/MESSAGE_CREATE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_DELETE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_UPDATE.js +16 -0
- package/src/client/websocket/handlers/PRESENCE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/READY.js +171 -0
- package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +17 -0
- package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +15 -0
- package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +18 -0
- package/src/client/websocket/handlers/RESUMED.js +14 -0
- package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
- package/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js +5 -0
- package/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js +5 -0
- package/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_CREATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_DELETE.js +5 -0
- package/src/client/websocket/handlers/THREAD_LIST_SYNC.js +5 -0
- package/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_UPDATE.js +16 -0
- package/src/client/websocket/handlers/TYPING_START.js +5 -0
- package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +12 -0
- package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +5 -0
- package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +9 -0
- package/src/client/websocket/handlers/USER_UPDATE.js +5 -0
- package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
- package/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js +6 -0
- package/src/client/websocket/handlers/VOICE_STATE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/WEBHOOKS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/index.js +87 -0
- package/src/errors/DJSError.js +61 -0
- package/src/errors/Messages.js +228 -0
- package/src/errors/index.js +4 -0
- package/src/index.js +194 -0
- package/src/managers/ApplicationCommandManager.js +267 -0
- package/src/managers/ApplicationCommandPermissionsManager.js +425 -0
- package/src/managers/AutoModerationRuleManager.js +296 -0
- package/src/managers/BaseGuildEmojiManager.js +80 -0
- package/src/managers/BaseManager.js +19 -0
- package/src/managers/BillingManager.js +66 -0
- package/src/managers/CachedManager.js +71 -0
- package/src/managers/ChannelManager.js +139 -0
- package/src/managers/ClientUserSettingManager.js +490 -0
- package/src/managers/DataManager.js +61 -0
- package/src/managers/DeveloperPortalManager.js +104 -0
- package/src/managers/GuildApplicationCommandManager.js +28 -0
- package/src/managers/GuildBanManager.js +204 -0
- package/src/managers/GuildChannelManager.js +504 -0
- package/src/managers/GuildEmojiManager.js +171 -0
- package/src/managers/GuildEmojiRoleManager.js +118 -0
- package/src/managers/GuildFolderManager.js +24 -0
- package/src/managers/GuildForumThreadManager.js +114 -0
- package/src/managers/GuildInviteManager.js +213 -0
- package/src/managers/GuildManager.js +304 -0
- package/src/managers/GuildMemberManager.js +772 -0
- package/src/managers/GuildMemberRoleManager.js +191 -0
- package/src/managers/GuildScheduledEventManager.js +296 -0
- package/src/managers/GuildSettingManager.js +148 -0
- package/src/managers/GuildStickerManager.js +179 -0
- package/src/managers/GuildTextThreadManager.js +98 -0
- package/src/managers/InteractionManager.js +39 -0
- package/src/managers/MessageManager.js +393 -0
- package/src/managers/PermissionOverwriteManager.js +166 -0
- package/src/managers/PresenceManager.js +58 -0
- package/src/managers/ReactionManager.js +67 -0
- package/src/managers/ReactionUserManager.js +71 -0
- package/src/managers/RelationshipManager.js +258 -0
- package/src/managers/RoleManager.js +352 -0
- package/src/managers/SessionManager.js +57 -0
- package/src/managers/StageInstanceManager.js +162 -0
- package/src/managers/ThreadManager.js +207 -0
- package/src/managers/ThreadMemberManager.js +186 -0
- package/src/managers/UserManager.js +150 -0
- package/src/managers/VoiceStateManager.js +37 -0
- package/src/rest/APIRequest.js +133 -0
- package/src/rest/APIRouter.js +53 -0
- package/src/rest/CaptchaSolver.js +139 -0
- package/src/rest/DiscordAPIError.js +103 -0
- package/src/rest/HTTPError.js +62 -0
- package/src/rest/RESTManager.js +82 -0
- package/src/rest/RateLimitError.js +55 -0
- package/src/rest/RequestHandler.js +430 -0
- package/src/sharding/Shard.js +443 -0
- package/src/sharding/ShardClientUtil.js +275 -0
- package/src/sharding/ShardingManager.js +318 -0
- package/src/structures/AnonymousGuild.js +98 -0
- package/src/structures/ApplicationCommand.js +1030 -0
- package/src/structures/ApplicationRoleConnectionMetadata.js +45 -0
- package/src/structures/AutoModerationActionExecution.js +89 -0
- package/src/structures/AutoModerationRule.js +294 -0
- package/src/structures/AutocompleteInteraction.js +106 -0
- package/src/structures/Base.js +43 -0
- package/src/structures/BaseCommandInteraction.js +211 -0
- package/src/structures/BaseGuild.js +116 -0
- package/src/structures/BaseGuildEmoji.js +56 -0
- package/src/structures/BaseGuildTextChannel.js +203 -0
- package/src/structures/BaseGuildVoiceChannel.js +243 -0
- package/src/structures/BaseMessageComponent.js +114 -0
- package/src/structures/ButtonInteraction.js +11 -0
- package/src/structures/Call.js +58 -0
- package/src/structures/CategoryChannel.js +85 -0
- package/src/structures/Channel.js +271 -0
- package/src/structures/ClientApplication.js +233 -0
- package/src/structures/ClientPresence.js +92 -0
- package/src/structures/ClientUser.js +635 -0
- package/src/structures/CommandInteraction.js +41 -0
- package/src/structures/CommandInteractionOptionResolver.js +276 -0
- package/src/structures/ContextMenuInteraction.js +65 -0
- package/src/structures/DMChannel.js +289 -0
- package/src/structures/DeveloperPortalApplication.js +520 -0
- package/src/structures/DirectoryChannel.js +20 -0
- package/src/structures/Emoji.js +148 -0
- package/src/structures/ForumChannel.js +271 -0
- package/src/structures/Guild.js +1744 -0
- package/src/structures/GuildAuditLogs.js +734 -0
- package/src/structures/GuildBan.js +59 -0
- package/src/structures/GuildBoost.js +108 -0
- package/src/structures/GuildChannel.js +468 -0
- package/src/structures/GuildEmoji.js +161 -0
- package/src/structures/GuildFolder.js +75 -0
- package/src/structures/GuildMember.js +686 -0
- package/src/structures/GuildPreview.js +191 -0
- package/src/structures/GuildPreviewEmoji.js +27 -0
- package/src/structures/GuildScheduledEvent.js +441 -0
- package/src/structures/GuildTemplate.js +236 -0
- package/src/structures/Integration.js +188 -0
- package/src/structures/IntegrationApplication.js +96 -0
- package/src/structures/Interaction.js +351 -0
- package/src/structures/InteractionCollector.js +248 -0
- package/src/structures/InteractionResponse.js +114 -0
- package/src/structures/InteractionWebhook.js +43 -0
- package/src/structures/Invite.js +375 -0
- package/src/structures/InviteGuild.js +23 -0
- package/src/structures/InviteStageInstance.js +86 -0
- package/src/structures/Message.js +1188 -0
- package/src/structures/MessageActionRow.js +103 -0
- package/src/structures/MessageAttachment.js +204 -0
- package/src/structures/MessageButton.js +231 -0
- package/src/structures/MessageCollector.js +146 -0
- package/src/structures/MessageComponentInteraction.js +120 -0
- package/src/structures/MessageContextMenuInteraction.js +20 -0
- package/src/structures/MessageEmbed.js +586 -0
- package/src/structures/MessageMentions.js +272 -0
- package/src/structures/MessagePayload.js +358 -0
- package/src/structures/MessageReaction.js +171 -0
- package/src/structures/MessageSelectMenu.js +391 -0
- package/src/structures/Modal.js +279 -0
- package/src/structures/ModalSubmitFieldsResolver.js +53 -0
- package/src/structures/ModalSubmitInteraction.js +119 -0
- package/src/structures/NewsChannel.js +32 -0
- package/src/structures/OAuth2Guild.js +28 -0
- package/src/structures/PartialGroupDMChannel.js +449 -0
- package/src/structures/PermissionOverwrites.js +196 -0
- package/src/structures/Presence.js +443 -0
- package/src/structures/ReactionCollector.js +229 -0
- package/src/structures/ReactionEmoji.js +31 -0
- package/src/structures/RichPresence.js +722 -0
- package/src/structures/Role.js +531 -0
- package/src/structures/SelectMenuInteraction.js +170 -0
- package/src/structures/Session.js +81 -0
- package/src/structures/StageChannel.js +104 -0
- package/src/structures/StageInstance.js +208 -0
- package/src/structures/Sticker.js +310 -0
- package/src/structures/StickerPack.js +95 -0
- package/src/structures/StoreChannel.js +56 -0
- package/src/structures/Team.js +167 -0
- package/src/structures/TeamMember.js +71 -0
- package/src/structures/TextChannel.js +33 -0
- package/src/structures/TextInputComponent.js +201 -0
- package/src/structures/ThreadChannel.js +626 -0
- package/src/structures/ThreadMember.js +105 -0
- package/src/structures/Typing.js +74 -0
- package/src/structures/User.js +730 -0
- package/src/structures/UserContextMenuInteraction.js +29 -0
- package/src/structures/VoiceChannel.js +110 -0
- package/src/structures/VoiceRegion.js +53 -0
- package/src/structures/VoiceState.js +353 -0
- package/src/structures/WebEmbed.js +412 -0
- package/src/structures/Webhook.js +461 -0
- package/src/structures/WelcomeChannel.js +60 -0
- package/src/structures/WelcomeScreen.js +48 -0
- package/src/structures/Widget.js +87 -0
- package/src/structures/WidgetMember.js +99 -0
- package/src/structures/interfaces/Application.js +190 -0
- package/src/structures/interfaces/Collector.js +300 -0
- package/src/structures/interfaces/InteractionResponses.js +313 -0
- package/src/structures/interfaces/TextBasedChannel.js +566 -0
- package/src/util/ActivityFlags.js +44 -0
- package/src/util/ApplicationFlags.js +76 -0
- package/src/util/AttachmentFlags.js +38 -0
- package/src/util/BitField.js +170 -0
- package/src/util/ChannelFlags.js +45 -0
- package/src/util/Constants.js +1940 -0
- package/src/util/DataResolver.js +145 -0
- package/src/util/Formatters.js +214 -0
- package/src/util/GuildMemberFlags.js +43 -0
- package/src/util/Intents.js +74 -0
- package/src/util/LimitedCollection.js +131 -0
- package/src/util/MessageFlags.js +54 -0
- package/src/util/Options.js +364 -0
- package/src/util/Permissions.js +187 -0
- package/src/util/PremiumUsageFlags.js +31 -0
- package/src/util/PurchasedFlags.js +31 -0
- package/src/util/RemoteAuth.js +514 -0
- package/src/util/RoleFlags.js +37 -0
- package/src/util/SnowflakeUtil.js +92 -0
- package/src/util/Sweepers.js +466 -0
- package/src/util/SystemChannelFlags.js +55 -0
- package/src/util/ThreadMemberFlags.js +30 -0
- package/src/util/UserFlags.js +104 -0
- package/src/util/Util.js +882 -0
- package/src/util/Voice.js +1456 -0
- package/src/util/arRPC/index.js +229 -0
- package/src/util/arRPC/process/detectable.json +1 -0
- package/src/util/arRPC/process/index.js +102 -0
- package/src/util/arRPC/process/native/index.js +5 -0
- package/src/util/arRPC/process/native/linux.js +37 -0
- package/src/util/arRPC/process/native/win32.js +25 -0
- package/src/util/arRPC/transports/ipc.js +281 -0
- package/src/util/arRPC/transports/websocket.js +128 -0
- package/typings/enums.d.ts +346 -0
- package/typings/index.d.ts +7776 -0
- package/typings/index.test-d.ts +0 -0
- package/typings/rawDataTypes.d.ts +283 -0
@@ -0,0 +1,1188 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const process = require('node:process');
|
4
|
+
const { Collection } = require('@discordjs/collection');
|
5
|
+
const Base = require('./Base');
|
6
|
+
const BaseMessageComponent = require('./BaseMessageComponent');
|
7
|
+
const ClientApplication = require('./ClientApplication');
|
8
|
+
const InteractionCollector = require('./InteractionCollector');
|
9
|
+
const MessageAttachment = require('./MessageAttachment');
|
10
|
+
const MessageButton = require('./MessageButton');
|
11
|
+
const Embed = require('./MessageEmbed');
|
12
|
+
const Mentions = require('./MessageMentions');
|
13
|
+
const MessagePayload = require('./MessagePayload');
|
14
|
+
const MessageSelectMenu = require('./MessageSelectMenu');
|
15
|
+
const ReactionCollector = require('./ReactionCollector');
|
16
|
+
const { Sticker } = require('./Sticker');
|
17
|
+
const { Error } = require('../errors');
|
18
|
+
const ReactionManager = require('../managers/ReactionManager');
|
19
|
+
const { InteractionTypes, MessageTypes, SystemMessageTypes, MaxBulkDeletableMessageAge } = require('../util/Constants');
|
20
|
+
const MessageFlags = require('../util/MessageFlags');
|
21
|
+
const Permissions = require('../util/Permissions');
|
22
|
+
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
23
|
+
const Util = require('../util/Util');
|
24
|
+
|
25
|
+
/**
|
26
|
+
* @type {WeakSet<Message>}
|
27
|
+
* @private
|
28
|
+
* @internal
|
29
|
+
*/
|
30
|
+
const deletedMessages = new WeakSet();
|
31
|
+
let deprecationEmittedForDeleted = false;
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Represents a message on Discord.
|
35
|
+
* @extends {Base}
|
36
|
+
*/
|
37
|
+
class Message extends Base {
|
38
|
+
constructor(client, data) {
|
39
|
+
super(client);
|
40
|
+
|
41
|
+
/**
|
42
|
+
* The id of the channel the message was sent in
|
43
|
+
* @type {Snowflake}
|
44
|
+
*/
|
45
|
+
this.channelId = data.channel_id;
|
46
|
+
|
47
|
+
/**
|
48
|
+
* The id of the guild the message was sent in, if any
|
49
|
+
* @type {?Snowflake}
|
50
|
+
*/
|
51
|
+
this.guildId = data.guild_id ?? this.channel?.guild?.id ?? null;
|
52
|
+
|
53
|
+
this._patch(data);
|
54
|
+
}
|
55
|
+
|
56
|
+
_patch(data) {
|
57
|
+
/**
|
58
|
+
* The message's id
|
59
|
+
* @type {Snowflake}
|
60
|
+
*/
|
61
|
+
this.id = data.id;
|
62
|
+
|
63
|
+
if ('position' in data) {
|
64
|
+
/**
|
65
|
+
* A generally increasing integer (there may be gaps or duplicates) that represents
|
66
|
+
* the approximate position of the message in a thread.
|
67
|
+
* @type {?number}
|
68
|
+
*/
|
69
|
+
this.position = data.position;
|
70
|
+
} else {
|
71
|
+
this.position ??= null;
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* The timestamp the message was sent at
|
76
|
+
* @type {number}
|
77
|
+
*/
|
78
|
+
this.createdTimestamp = SnowflakeUtil.timestampFrom(this.id);
|
79
|
+
|
80
|
+
if ('type' in data) {
|
81
|
+
/**
|
82
|
+
* The type of the message
|
83
|
+
* @type {?MessageType}
|
84
|
+
*/
|
85
|
+
this.type = MessageTypes[data.type];
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications)
|
89
|
+
* @type {?boolean}
|
90
|
+
*/
|
91
|
+
this.system = SystemMessageTypes.includes(this.type);
|
92
|
+
} else {
|
93
|
+
this.system ??= null;
|
94
|
+
this.type ??= null;
|
95
|
+
}
|
96
|
+
|
97
|
+
if ('content' in data) {
|
98
|
+
/**
|
99
|
+
* The content of the message
|
100
|
+
* @type {?string}
|
101
|
+
*/
|
102
|
+
this.content = data.content;
|
103
|
+
} else {
|
104
|
+
this.content ??= null;
|
105
|
+
}
|
106
|
+
|
107
|
+
if ('author' in data) {
|
108
|
+
/**
|
109
|
+
* The author of the message
|
110
|
+
* @type {?User}
|
111
|
+
*/
|
112
|
+
this.author = this.client.users._add(data.author, !data.webhook_id);
|
113
|
+
} else {
|
114
|
+
this.author ??= null;
|
115
|
+
}
|
116
|
+
|
117
|
+
if ('pinned' in data) {
|
118
|
+
/**
|
119
|
+
* Whether or not this message is pinned
|
120
|
+
* @type {?boolean}
|
121
|
+
*/
|
122
|
+
this.pinned = Boolean(data.pinned);
|
123
|
+
} else {
|
124
|
+
this.pinned ??= null;
|
125
|
+
}
|
126
|
+
|
127
|
+
if ('tts' in data) {
|
128
|
+
/**
|
129
|
+
* Whether or not the message was Text-To-Speech
|
130
|
+
* @type {?boolean}
|
131
|
+
*/
|
132
|
+
this.tts = data.tts;
|
133
|
+
} else {
|
134
|
+
this.tts ??= null;
|
135
|
+
}
|
136
|
+
|
137
|
+
if ('nonce' in data) {
|
138
|
+
/**
|
139
|
+
* A random number or string used for checking message delivery
|
140
|
+
* <warn>This is only received after the message was sent successfully, and
|
141
|
+
* lost if re-fetched</warn>
|
142
|
+
* @type {?string}
|
143
|
+
*/
|
144
|
+
this.nonce = data.nonce;
|
145
|
+
} else {
|
146
|
+
this.nonce ??= null;
|
147
|
+
}
|
148
|
+
|
149
|
+
if ('embeds' in data) {
|
150
|
+
/**
|
151
|
+
* A list of embeds in the message - e.g. YouTube Player
|
152
|
+
* @type {MessageEmbed[]}
|
153
|
+
*/
|
154
|
+
this.embeds = data.embeds.map(e => new Embed(e, true));
|
155
|
+
} else {
|
156
|
+
this.embeds = this.embeds?.slice() ?? [];
|
157
|
+
}
|
158
|
+
|
159
|
+
if ('components' in data) {
|
160
|
+
/**
|
161
|
+
* A list of MessageActionRows in the message
|
162
|
+
* @type {MessageActionRow[]}
|
163
|
+
*/
|
164
|
+
this.components = data.components.map(c => BaseMessageComponent.create(c, this.client));
|
165
|
+
} else {
|
166
|
+
this.components = this.components?.slice() ?? [];
|
167
|
+
}
|
168
|
+
|
169
|
+
if ('attachments' in data) {
|
170
|
+
/**
|
171
|
+
* A collection of attachments in the message - e.g. Pictures - mapped by their ids
|
172
|
+
* @type {Collection<Snowflake, MessageAttachment>}
|
173
|
+
*/
|
174
|
+
this.attachments = new Collection();
|
175
|
+
if (data.attachments) {
|
176
|
+
for (const attachment of data.attachments) {
|
177
|
+
this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
|
178
|
+
}
|
179
|
+
}
|
180
|
+
} else {
|
181
|
+
this.attachments = new Collection(this.attachments);
|
182
|
+
}
|
183
|
+
|
184
|
+
if ('sticker_items' in data || 'stickers' in data) {
|
185
|
+
/**
|
186
|
+
* A collection of stickers in the message
|
187
|
+
* @type {Collection<Snowflake, Sticker>}
|
188
|
+
*/
|
189
|
+
this.stickers = new Collection(
|
190
|
+
(data.sticker_items ?? data.stickers)?.map(s => [s.id, new Sticker(this.client, s)]),
|
191
|
+
);
|
192
|
+
} else {
|
193
|
+
this.stickers = new Collection(this.stickers);
|
194
|
+
}
|
195
|
+
|
196
|
+
// Discord sends null if the message has not been edited
|
197
|
+
if (data.edited_timestamp) {
|
198
|
+
/**
|
199
|
+
* The timestamp the message was last edited at (if applicable)
|
200
|
+
* @type {?number}
|
201
|
+
*/
|
202
|
+
this.editedTimestamp = new Date(data.edited_timestamp).getTime();
|
203
|
+
} else {
|
204
|
+
this.editedTimestamp ??= null;
|
205
|
+
}
|
206
|
+
|
207
|
+
if ('reactions' in data) {
|
208
|
+
/**
|
209
|
+
* A manager of the reactions belonging to this message
|
210
|
+
* @type {ReactionManager}
|
211
|
+
*/
|
212
|
+
this.reactions = new ReactionManager(this);
|
213
|
+
if (data.reactions?.length > 0) {
|
214
|
+
for (const reaction of data.reactions) {
|
215
|
+
this.reactions._add(reaction);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
} else {
|
219
|
+
this.reactions ??= new ReactionManager(this);
|
220
|
+
}
|
221
|
+
|
222
|
+
if (!this.mentions) {
|
223
|
+
/**
|
224
|
+
* All valid mentions that the message contains
|
225
|
+
* @type {MessageMentions}
|
226
|
+
*/
|
227
|
+
this.mentions = new Mentions(
|
228
|
+
this,
|
229
|
+
data.mentions,
|
230
|
+
data.mention_roles,
|
231
|
+
data.mention_everyone,
|
232
|
+
data.mention_channels,
|
233
|
+
data.referenced_message?.author,
|
234
|
+
);
|
235
|
+
} else {
|
236
|
+
this.mentions = new Mentions(
|
237
|
+
this,
|
238
|
+
data.mentions ?? this.mentions.users,
|
239
|
+
data.mention_roles ?? this.mentions.roles,
|
240
|
+
data.mention_everyone ?? this.mentions.everyone,
|
241
|
+
data.mention_channels ?? this.mentions.crosspostedChannels,
|
242
|
+
data.referenced_message?.author ?? this.mentions.repliedUser,
|
243
|
+
);
|
244
|
+
}
|
245
|
+
|
246
|
+
if ('webhook_id' in data) {
|
247
|
+
/**
|
248
|
+
* The id of the webhook that sent the message, if applicable
|
249
|
+
* @type {?Snowflake}
|
250
|
+
*/
|
251
|
+
this.webhookId = data.webhook_id;
|
252
|
+
} else {
|
253
|
+
this.webhookId ??= null;
|
254
|
+
}
|
255
|
+
|
256
|
+
if ('application' in data) {
|
257
|
+
/**
|
258
|
+
* Supplemental application information for group activities
|
259
|
+
* @type {?ClientApplication}
|
260
|
+
*/
|
261
|
+
this.groupActivityApplication = new ClientApplication(this.client, data.application);
|
262
|
+
} else {
|
263
|
+
this.groupActivityApplication ??= null;
|
264
|
+
}
|
265
|
+
|
266
|
+
if ('application_id' in data) {
|
267
|
+
/**
|
268
|
+
* The id of the application of the interaction that sent this message, if any
|
269
|
+
* @type {?Snowflake}
|
270
|
+
*/
|
271
|
+
this.applicationId = data.application_id;
|
272
|
+
} else {
|
273
|
+
this.applicationId ??= null;
|
274
|
+
}
|
275
|
+
|
276
|
+
if ('activity' in data) {
|
277
|
+
/**
|
278
|
+
* Group activity
|
279
|
+
* @type {?MessageActivity}
|
280
|
+
*/
|
281
|
+
this.activity = {
|
282
|
+
partyId: data.activity.party_id,
|
283
|
+
type: data.activity.type,
|
284
|
+
};
|
285
|
+
} else {
|
286
|
+
this.activity ??= null;
|
287
|
+
}
|
288
|
+
|
289
|
+
if ('thread' in data) {
|
290
|
+
this.client.channels._add(data.thread, this.guild);
|
291
|
+
}
|
292
|
+
|
293
|
+
if (this.member && data.member) {
|
294
|
+
this.member._patch(data.member);
|
295
|
+
} else if (data.member && this.guild && this.author) {
|
296
|
+
this.guild.members._add(Object.assign(data.member, { user: this.author }));
|
297
|
+
}
|
298
|
+
|
299
|
+
if ('flags' in data) {
|
300
|
+
/**
|
301
|
+
* Flags that are applied to the message
|
302
|
+
* @type {Readonly<MessageFlags>}
|
303
|
+
*/
|
304
|
+
this.flags = new MessageFlags(data.flags).freeze();
|
305
|
+
} else {
|
306
|
+
this.flags = new MessageFlags(this.flags).freeze();
|
307
|
+
}
|
308
|
+
|
309
|
+
/**
|
310
|
+
* Reference data sent in a message that contains ids identifying the referenced message.
|
311
|
+
* This can be present in the following types of message:
|
312
|
+
* * Crossposted messages (IS_CROSSPOST {@link MessageFlags.FLAGS message flag})
|
313
|
+
* * CHANNEL_FOLLOW_ADD
|
314
|
+
* * CHANNEL_PINNED_MESSAGE
|
315
|
+
* * REPLY
|
316
|
+
* * THREAD_STARTER_MESSAGE
|
317
|
+
* @see {@link https://discord.com/developers/docs/resources/channel#message-types}
|
318
|
+
* @typedef {Object} MessageReference
|
319
|
+
* @property {Snowflake} channelId The channel's id the message was referenced
|
320
|
+
* @property {?Snowflake} guildId The guild's id the message was referenced
|
321
|
+
* @property {?Snowflake} messageId The message's id that was referenced
|
322
|
+
*/
|
323
|
+
|
324
|
+
if ('message_reference' in data) {
|
325
|
+
/**
|
326
|
+
* Message reference data
|
327
|
+
* @type {?MessageReference}
|
328
|
+
*/
|
329
|
+
this.reference = {
|
330
|
+
channelId: data.message_reference.channel_id,
|
331
|
+
guildId: data.message_reference.guild_id,
|
332
|
+
messageId: data.message_reference.message_id,
|
333
|
+
};
|
334
|
+
} else {
|
335
|
+
this.reference ??= null;
|
336
|
+
}
|
337
|
+
|
338
|
+
if (data.referenced_message) {
|
339
|
+
this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });
|
340
|
+
}
|
341
|
+
|
342
|
+
/**
|
343
|
+
* Partial data of the interaction that a message is a reply to
|
344
|
+
* @typedef {Object} MessageInteraction
|
345
|
+
* @property {Snowflake} id The interaction's id
|
346
|
+
* @property {InteractionType} type The type of the interaction
|
347
|
+
* @property {string} commandName The name of the interaction's application command,
|
348
|
+
* as well as the subcommand and subcommand group, where applicable
|
349
|
+
* @property {User} user The user that invoked the interaction
|
350
|
+
*/
|
351
|
+
|
352
|
+
if (data.interaction) {
|
353
|
+
/**
|
354
|
+
* Partial data of the interaction that this message is a reply to
|
355
|
+
* @type {?MessageInteraction}
|
356
|
+
*/
|
357
|
+
this.interaction = {
|
358
|
+
id: data.interaction.id,
|
359
|
+
type: InteractionTypes[data.interaction.type],
|
360
|
+
commandName: data.interaction.name,
|
361
|
+
user: this.client.users._add(data.interaction.user),
|
362
|
+
};
|
363
|
+
} else {
|
364
|
+
this.interaction ??= null;
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
/**
|
369
|
+
* Whether or not the structure has been deleted
|
370
|
+
* @type {boolean}
|
371
|
+
* @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091
|
372
|
+
*/
|
373
|
+
get deleted() {
|
374
|
+
if (!deprecationEmittedForDeleted) {
|
375
|
+
deprecationEmittedForDeleted = true;
|
376
|
+
process.emitWarning(
|
377
|
+
'Message#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
|
378
|
+
'DeprecationWarning',
|
379
|
+
);
|
380
|
+
}
|
381
|
+
|
382
|
+
return deletedMessages.has(this);
|
383
|
+
}
|
384
|
+
|
385
|
+
set deleted(value) {
|
386
|
+
if (!deprecationEmittedForDeleted) {
|
387
|
+
deprecationEmittedForDeleted = true;
|
388
|
+
process.emitWarning(
|
389
|
+
'Message#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
|
390
|
+
'DeprecationWarning',
|
391
|
+
);
|
392
|
+
}
|
393
|
+
|
394
|
+
if (value) deletedMessages.add(this);
|
395
|
+
else deletedMessages.delete(this);
|
396
|
+
}
|
397
|
+
|
398
|
+
/**
|
399
|
+
* The channel that the message was sent in
|
400
|
+
* @type {TextBasedChannels}
|
401
|
+
* @readonly
|
402
|
+
*/
|
403
|
+
get channel() {
|
404
|
+
return this.client.channels.resolve(this.channelId);
|
405
|
+
}
|
406
|
+
|
407
|
+
/**
|
408
|
+
* Whether or not this message is a partial
|
409
|
+
* @type {boolean}
|
410
|
+
* @readonly
|
411
|
+
*/
|
412
|
+
get partial() {
|
413
|
+
return typeof this.content !== 'string' || !this.author;
|
414
|
+
}
|
415
|
+
|
416
|
+
/**
|
417
|
+
* Represents the author of the message as a guild member.
|
418
|
+
* Only available if the message comes from a guild where the author is still a member
|
419
|
+
* @type {?GuildMember}
|
420
|
+
* @readonly
|
421
|
+
*/
|
422
|
+
get member() {
|
423
|
+
return this.guild?.members.resolve(this.author) ?? null;
|
424
|
+
}
|
425
|
+
|
426
|
+
/**
|
427
|
+
* The time the message was sent at
|
428
|
+
* @type {Date}
|
429
|
+
* @readonly
|
430
|
+
*/
|
431
|
+
get createdAt() {
|
432
|
+
return new Date(this.createdTimestamp);
|
433
|
+
}
|
434
|
+
|
435
|
+
/**
|
436
|
+
* The time the message was last edited at (if applicable)
|
437
|
+
* @type {?Date}
|
438
|
+
* @readonly
|
439
|
+
*/
|
440
|
+
get editedAt() {
|
441
|
+
return this.editedTimestamp ? new Date(this.editedTimestamp) : null;
|
442
|
+
}
|
443
|
+
|
444
|
+
/**
|
445
|
+
* The guild the message was sent in (if in a guild channel)
|
446
|
+
* @type {?Guild}
|
447
|
+
* @readonly
|
448
|
+
*/
|
449
|
+
get guild() {
|
450
|
+
return this.client.guilds.resolve(this.guildId) ?? this.channel?.guild ?? null;
|
451
|
+
}
|
452
|
+
|
453
|
+
/**
|
454
|
+
* Whether this message has a thread associated with it
|
455
|
+
* @type {boolean}
|
456
|
+
* @readonly
|
457
|
+
*/
|
458
|
+
get hasThread() {
|
459
|
+
return this.flags.has(MessageFlags.FLAGS.HAS_THREAD);
|
460
|
+
}
|
461
|
+
|
462
|
+
/**
|
463
|
+
* The thread started by this message
|
464
|
+
* <info>This property is not suitable for checking whether a message has a thread,
|
465
|
+
* use {@link Message#hasThread} instead.</info>
|
466
|
+
* @type {?ThreadChannel}
|
467
|
+
* @readonly
|
468
|
+
*/
|
469
|
+
get thread() {
|
470
|
+
return this.channel?.threads?.resolve(this.id) ?? null;
|
471
|
+
}
|
472
|
+
|
473
|
+
/**
|
474
|
+
* The URL to jump to this message
|
475
|
+
* @type {string}
|
476
|
+
* @readonly
|
477
|
+
*/
|
478
|
+
get url() {
|
479
|
+
return `https://discord.com/channels/${this.guildId ?? '@me'}/${this.channelId}/${this.id}`;
|
480
|
+
}
|
481
|
+
|
482
|
+
/**
|
483
|
+
* The message contents with all mentions replaced by the equivalent text.
|
484
|
+
* If mentions cannot be resolved to a name, the relevant mention in the message content will not be converted.
|
485
|
+
* @type {?string}
|
486
|
+
* @readonly
|
487
|
+
*/
|
488
|
+
get cleanContent() {
|
489
|
+
// eslint-disable-next-line eqeqeq
|
490
|
+
return this.content != null ? Util.cleanContent(this.content, this.channel) : null;
|
491
|
+
}
|
492
|
+
|
493
|
+
/**
|
494
|
+
* Creates a reaction collector.
|
495
|
+
* @param {ReactionCollectorOptions} [options={}] Options to send to the collector
|
496
|
+
* @returns {ReactionCollector}
|
497
|
+
* @example
|
498
|
+
* // Create a reaction collector
|
499
|
+
* const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId';
|
500
|
+
* const collector = message.createReactionCollector({ filter, time: 15_000 });
|
501
|
+
* collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
|
502
|
+
* collector.on('end', collected => console.log(`Collected ${collected.size} items`));
|
503
|
+
*/
|
504
|
+
createReactionCollector(options = {}) {
|
505
|
+
return new ReactionCollector(this, options);
|
506
|
+
}
|
507
|
+
|
508
|
+
/**
|
509
|
+
* An object containing the same properties as CollectorOptions, but a few more:
|
510
|
+
* @typedef {ReactionCollectorOptions} AwaitReactionsOptions
|
511
|
+
* @property {string[]} [errors] Stop/end reasons that cause the promise to reject
|
512
|
+
*/
|
513
|
+
|
514
|
+
/**
|
515
|
+
* Similar to createReactionCollector but in promise form.
|
516
|
+
* Resolves with a collection of reactions that pass the specified filter.
|
517
|
+
* @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
|
518
|
+
* @returns {Promise<Collection<string | Snowflake, MessageReaction>>}
|
519
|
+
* @example
|
520
|
+
* // Create a reaction collector
|
521
|
+
* const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'
|
522
|
+
* message.awaitReactions({ filter, time: 15_000 })
|
523
|
+
* .then(collected => console.log(`Collected ${collected.size} reactions`))
|
524
|
+
* .catch(console.error);
|
525
|
+
*/
|
526
|
+
awaitReactions(options = {}) {
|
527
|
+
return new Promise((resolve, reject) => {
|
528
|
+
const collector = this.createReactionCollector(options);
|
529
|
+
collector.once('end', (reactions, reason) => {
|
530
|
+
if (options.errors?.includes(reason)) reject(reactions);
|
531
|
+
else resolve(reactions);
|
532
|
+
});
|
533
|
+
});
|
534
|
+
}
|
535
|
+
|
536
|
+
/**
|
537
|
+
* @typedef {CollectorOptions} MessageComponentCollectorOptions
|
538
|
+
* @property {MessageComponentType} [componentType] The type of component to listen for
|
539
|
+
* @property {number} [max] The maximum total amount of interactions to collect
|
540
|
+
* @property {number} [maxComponents] The maximum number of components to collect
|
541
|
+
* @property {number} [maxUsers] The maximum number of users to interact
|
542
|
+
*/
|
543
|
+
|
544
|
+
/**
|
545
|
+
* Creates a message component interaction collector.
|
546
|
+
* @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
|
547
|
+
* @returns {InteractionCollector}
|
548
|
+
* @example
|
549
|
+
* // Create a message component interaction collector
|
550
|
+
* const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
|
551
|
+
* const collector = message.createMessageComponentCollector({ filter, time: 15_000 });
|
552
|
+
* collector.on('collect', i => console.log(`Collected ${i.customId}`));
|
553
|
+
* collector.on('end', collected => console.log(`Collected ${collected.size} items`));
|
554
|
+
*/
|
555
|
+
createMessageComponentCollector(options = {}) {
|
556
|
+
return new InteractionCollector(this.client, {
|
557
|
+
...options,
|
558
|
+
interactionType: InteractionTypes.MESSAGE_COMPONENT,
|
559
|
+
message: this,
|
560
|
+
});
|
561
|
+
}
|
562
|
+
|
563
|
+
/**
|
564
|
+
* An object containing the same properties as CollectorOptions, but a few more:
|
565
|
+
* @typedef {Object} AwaitMessageComponentOptions
|
566
|
+
* @property {CollectorFilter} [filter] The filter applied to this collector
|
567
|
+
* @property {number} [time] Time to wait for an interaction before rejecting
|
568
|
+
* @property {MessageComponentType} [componentType] The type of component interaction to collect
|
569
|
+
*/
|
570
|
+
|
571
|
+
/**
|
572
|
+
* Collects a single component interaction that passes the filter.
|
573
|
+
* The Promise will reject if the time expires.
|
574
|
+
* @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector
|
575
|
+
* @returns {Promise<MessageComponentInteraction>}
|
576
|
+
* @example
|
577
|
+
* // Collect a message component interaction
|
578
|
+
* const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
|
579
|
+
* message.awaitMessageComponent({ filter, time: 15_000 })
|
580
|
+
* .then(interaction => console.log(`${interaction.customId} was clicked!`))
|
581
|
+
* .catch(console.error);
|
582
|
+
*/
|
583
|
+
awaitMessageComponent(options = {}) {
|
584
|
+
const _options = { ...options, max: 1 };
|
585
|
+
return new Promise((resolve, reject) => {
|
586
|
+
const collector = this.createMessageComponentCollector(_options);
|
587
|
+
collector.once('end', (interactions, reason) => {
|
588
|
+
const interaction = interactions.first();
|
589
|
+
if (interaction) resolve(interaction);
|
590
|
+
else reject(new Error('INTERACTION_COLLECTOR_ERROR', reason));
|
591
|
+
});
|
592
|
+
});
|
593
|
+
}
|
594
|
+
|
595
|
+
/**
|
596
|
+
* Whether the message is editable by the client user
|
597
|
+
* @type {boolean}
|
598
|
+
* @readonly
|
599
|
+
*/
|
600
|
+
get editable() {
|
601
|
+
const precheck = Boolean(
|
602
|
+
this.author.id === this.client.user.id && !deletedMessages.has(this) && (!this.guild || this.channel?.viewable),
|
603
|
+
);
|
604
|
+
|
605
|
+
// Regardless of permissions thread messages cannot be edited if
|
606
|
+
// the thread is archived or the thread is locked and the bot does not have permission to manage threads.
|
607
|
+
if (this.channel?.isThread()) {
|
608
|
+
if (this.channel.archived) return false;
|
609
|
+
if (this.channel.locked) {
|
610
|
+
const permissions = this.channel.permissionsFor(this.client.user);
|
611
|
+
if (!permissions?.has(Permissions.FLAGS.MANAGE_THREADS, true)) return false;
|
612
|
+
}
|
613
|
+
}
|
614
|
+
|
615
|
+
return precheck;
|
616
|
+
}
|
617
|
+
|
618
|
+
/**
|
619
|
+
* Whether the message is deletable by the client user
|
620
|
+
* @type {boolean}
|
621
|
+
* @readonly
|
622
|
+
*/
|
623
|
+
get deletable() {
|
624
|
+
if (deletedMessages.has(this)) {
|
625
|
+
return false;
|
626
|
+
}
|
627
|
+
if (!this.guild) {
|
628
|
+
return this.author.id === this.client.user.id;
|
629
|
+
}
|
630
|
+
// DMChannel does not have viewable property, so check viewable after proved that message is on a guild.
|
631
|
+
if (!this.channel?.viewable) {
|
632
|
+
return false;
|
633
|
+
}
|
634
|
+
|
635
|
+
const permissions = this.channel?.permissionsFor(this.client.user);
|
636
|
+
if (!permissions) return false;
|
637
|
+
// This flag allows deleting even if timed out
|
638
|
+
if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true;
|
639
|
+
|
640
|
+
return Boolean(
|
641
|
+
this.author.id === this.client.user.id ||
|
642
|
+
(permissions.has(Permissions.FLAGS.MANAGE_MESSAGES, false) &&
|
643
|
+
this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()),
|
644
|
+
);
|
645
|
+
}
|
646
|
+
|
647
|
+
/**
|
648
|
+
* Whether the message is bulk deletable by the client user
|
649
|
+
* @type {boolean}
|
650
|
+
* @readonly
|
651
|
+
* @example
|
652
|
+
* // Filter for bulk deletable messages
|
653
|
+
* channel.bulkDelete(messages.filter(message => message.bulkDeletable));
|
654
|
+
*/
|
655
|
+
get bulkDeletable() {
|
656
|
+
return (
|
657
|
+
(this.inGuild() &&
|
658
|
+
this.client.user.bot &&
|
659
|
+
Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
|
660
|
+
this.deletable &&
|
661
|
+
this.channel?.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES, false)) ??
|
662
|
+
false
|
663
|
+
);
|
664
|
+
}
|
665
|
+
|
666
|
+
/**
|
667
|
+
* Whether the message is pinnable by the client user
|
668
|
+
* @type {boolean}
|
669
|
+
* @readonly
|
670
|
+
*/
|
671
|
+
get pinnable() {
|
672
|
+
const { channel } = this;
|
673
|
+
return Boolean(
|
674
|
+
!this.system &&
|
675
|
+
!deletedMessages.has(this) &&
|
676
|
+
(!this.guild ||
|
677
|
+
(channel?.viewable &&
|
678
|
+
channel?.permissionsFor(this.client.user)?.has(Permissions.FLAGS.MANAGE_MESSAGES, false))),
|
679
|
+
);
|
680
|
+
}
|
681
|
+
|
682
|
+
/**
|
683
|
+
* Fetches the Message this crosspost/reply/pin-add references, if available to the client
|
684
|
+
* @returns {Promise<Message>}
|
685
|
+
*/
|
686
|
+
async fetchReference() {
|
687
|
+
if (!this.reference) throw new Error('MESSAGE_REFERENCE_MISSING');
|
688
|
+
const { channelId, messageId } = this.reference;
|
689
|
+
const channel = this.client.channels.resolve(channelId);
|
690
|
+
if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE');
|
691
|
+
const message = await channel.messages.fetch(messageId);
|
692
|
+
return message;
|
693
|
+
}
|
694
|
+
|
695
|
+
/**
|
696
|
+
* Whether the message is crosspostable by the client user
|
697
|
+
* @type {boolean}
|
698
|
+
* @readonly
|
699
|
+
*/
|
700
|
+
get crosspostable() {
|
701
|
+
const bitfield =
|
702
|
+
Permissions.FLAGS.SEND_MESSAGES |
|
703
|
+
(this.author.id === this.client.user.id ? Permissions.defaultBit : Permissions.FLAGS.MANAGE_MESSAGES);
|
704
|
+
const { channel } = this;
|
705
|
+
return Boolean(
|
706
|
+
channel?.type === 'GUILD_NEWS' &&
|
707
|
+
!this.flags.has(MessageFlags.FLAGS.CROSSPOSTED) &&
|
708
|
+
this.type === 'DEFAULT' &&
|
709
|
+
channel.viewable &&
|
710
|
+
channel.permissionsFor(this.client.user)?.has(bitfield, false) &&
|
711
|
+
!deletedMessages.has(this),
|
712
|
+
);
|
713
|
+
}
|
714
|
+
|
715
|
+
/**
|
716
|
+
* Options that can be passed into {@link Message#edit}.
|
717
|
+
* @typedef {Object} MessageEditOptions
|
718
|
+
* @property {?string} [content] Content to be edited
|
719
|
+
* @property {MessageEmbed[]|APIEmbed[]} [embeds] Embeds to be added/edited
|
720
|
+
* @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content
|
721
|
+
* @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be edited.
|
722
|
+
* @property {MessageAttachment[]} [attachments] An array of attachments to keep,
|
723
|
+
* all attachments will be kept if omitted
|
724
|
+
* @property {FileOptions[]|BufferResolvable[]|MessageAttachment[]} [files] Files to add to the message
|
725
|
+
* @property {Array<(MessageActionRow|MessageActionRowOptions)>} [components]
|
726
|
+
* Action rows containing interactive components for the message (buttons, select menus)
|
727
|
+
*/
|
728
|
+
|
729
|
+
/**
|
730
|
+
* Edits the content of the message.
|
731
|
+
* @param {string|MessagePayload|MessageEditOptions} options The options to provide
|
732
|
+
* @returns {Promise<Message>}
|
733
|
+
* @example
|
734
|
+
* // Update the content of a message
|
735
|
+
* message.edit('This is my new content!')
|
736
|
+
* .then(msg => console.log(`Updated the content of a message to ${msg.content}`))
|
737
|
+
* .catch(console.error);
|
738
|
+
*/
|
739
|
+
edit(options) {
|
740
|
+
if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
|
741
|
+
return this.channel.messages.edit(this, options);
|
742
|
+
}
|
743
|
+
|
744
|
+
/**
|
745
|
+
* Publishes a message in an announcement channel to all channels following it.
|
746
|
+
* @returns {Promise<Message>}
|
747
|
+
* @example
|
748
|
+
* // Crosspost a message
|
749
|
+
* if (message.channel.type === 'GUILD_NEWS') {
|
750
|
+
* message.crosspost()
|
751
|
+
* .then(() => console.log('Crossposted message'))
|
752
|
+
* .catch(console.error);
|
753
|
+
* }
|
754
|
+
*/
|
755
|
+
crosspost() {
|
756
|
+
if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
|
757
|
+
return this.channel.messages.crosspost(this.id);
|
758
|
+
}
|
759
|
+
|
760
|
+
/**
|
761
|
+
* Pins this message to the channel's pinned messages.
|
762
|
+
* @param {string} [reason] Reason for pinning
|
763
|
+
* @returns {Promise<Message>}
|
764
|
+
* @example
|
765
|
+
* // Pin a message
|
766
|
+
* message.pin()
|
767
|
+
* .then(console.log)
|
768
|
+
* .catch(console.error)
|
769
|
+
*/
|
770
|
+
async pin(reason) {
|
771
|
+
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
772
|
+
await this.channel.messages.pin(this.id, reason);
|
773
|
+
return this;
|
774
|
+
}
|
775
|
+
|
776
|
+
/**
|
777
|
+
* Unpins this message from the channel's pinned messages.
|
778
|
+
* @param {string} [reason] Reason for unpinning
|
779
|
+
* @returns {Promise<Message>}
|
780
|
+
* @example
|
781
|
+
* // Unpin a message
|
782
|
+
* message.unpin()
|
783
|
+
* .then(console.log)
|
784
|
+
* .catch(console.error)
|
785
|
+
*/
|
786
|
+
async unpin(reason) {
|
787
|
+
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
788
|
+
await this.channel.messages.unpin(this.id, reason);
|
789
|
+
return this;
|
790
|
+
}
|
791
|
+
|
792
|
+
/**
|
793
|
+
* Adds a reaction to the message.
|
794
|
+
* @param {EmojiIdentifierResolvable} emoji The emoji to react with
|
795
|
+
* @param {boolean} [burst=false] Super Reactions (Discord Nitro only)
|
796
|
+
* @returns {Promise<MessageReaction>}
|
797
|
+
* @example
|
798
|
+
* // React to a message with a unicode emoji
|
799
|
+
* message.react('🤔')
|
800
|
+
* .then(console.log)
|
801
|
+
* .catch(console.error);
|
802
|
+
* @example
|
803
|
+
* // React to a message with a custom emoji
|
804
|
+
* message.react(message.guild.emojis.cache.get('123456789012345678'))
|
805
|
+
* .then(console.log)
|
806
|
+
* .catch(console.error);
|
807
|
+
*/
|
808
|
+
async react(emoji, burst = false) {
|
809
|
+
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
810
|
+
await this.channel.messages.react(this.id, emoji, burst);
|
811
|
+
|
812
|
+
return this.client.actions.MessageReactionAdd.handle(
|
813
|
+
{
|
814
|
+
[this.client.actions.injectedUser]: this.client.user,
|
815
|
+
[this.client.actions.injectedChannel]: this.channel,
|
816
|
+
[this.client.actions.injectedMessage]: this,
|
817
|
+
emoji: Util.resolvePartialEmoji(emoji),
|
818
|
+
me_burst: burst,
|
819
|
+
},
|
820
|
+
true,
|
821
|
+
).reaction;
|
822
|
+
}
|
823
|
+
|
824
|
+
/**
|
825
|
+
* Deletes the message.
|
826
|
+
* @returns {Promise<Message>}
|
827
|
+
* @example
|
828
|
+
* // Delete a message
|
829
|
+
* message.delete()
|
830
|
+
* .then(msg => console.log(`Deleted message from ${msg.author.username}`))
|
831
|
+
* .catch(console.error);
|
832
|
+
*/
|
833
|
+
async delete() {
|
834
|
+
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
835
|
+
await this.channel.messages.delete(this.id);
|
836
|
+
return this;
|
837
|
+
}
|
838
|
+
|
839
|
+
/**
|
840
|
+
* Options provided when sending a message as an inline reply.
|
841
|
+
* @typedef {BaseMessageOptions} ReplyMessageOptions
|
842
|
+
* @property {boolean} [failIfNotExists=true] Whether to error if the referenced message
|
843
|
+
* does not exist (creates a standard message in this case when false)
|
844
|
+
* @property {StickerResolvable[]} [stickers=[]] Stickers to send in the message
|
845
|
+
*/
|
846
|
+
|
847
|
+
/**
|
848
|
+
* Send an inline reply to this message.
|
849
|
+
* @param {string|MessagePayload|ReplyMessageOptions} options The options to provide
|
850
|
+
* @returns {Promise<Message>}
|
851
|
+
* @example
|
852
|
+
* // Reply to a message
|
853
|
+
* message.reply('This is a reply!')
|
854
|
+
* .then(() => console.log(`Replied to message "${message.content}"`))
|
855
|
+
* .catch(console.error);
|
856
|
+
*/
|
857
|
+
reply(options) {
|
858
|
+
if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
|
859
|
+
let data;
|
860
|
+
|
861
|
+
if (options instanceof MessagePayload) {
|
862
|
+
data = options;
|
863
|
+
} else {
|
864
|
+
data = MessagePayload.create(this, options, {
|
865
|
+
reply: {
|
866
|
+
messageReference: this,
|
867
|
+
failIfNotExists: options?.failIfNotExists ?? this.client.options.failIfNotExists,
|
868
|
+
},
|
869
|
+
});
|
870
|
+
}
|
871
|
+
return this.channel.send(data);
|
872
|
+
}
|
873
|
+
|
874
|
+
/**
|
875
|
+
* A number that is allowed to be the duration (in minutes) of inactivity after which a thread is automatically
|
876
|
+
* archived. This can be:
|
877
|
+
* * `60` (1 hour)
|
878
|
+
* * `1440` (1 day)
|
879
|
+
* * `4320` (3 days)
|
880
|
+
* * `10080` (7 days)
|
881
|
+
* * `'MAX'` (7 days)
|
882
|
+
* <warn>This option is deprecated and will be removed in the next major version.</warn>
|
883
|
+
* @typedef {number|string} ThreadAutoArchiveDuration
|
884
|
+
*/
|
885
|
+
|
886
|
+
/**
|
887
|
+
* Options for starting a thread on a message.
|
888
|
+
* @typedef {Object} StartThreadOptions
|
889
|
+
* @property {string} name The name of the new thread
|
890
|
+
* @property {ThreadAutoArchiveDuration} [autoArchiveDuration=this.channel.defaultAutoArchiveDuration] The amount of
|
891
|
+
* time (in minutes) after which the thread should automatically archive in case of no recent activity
|
892
|
+
* @property {string} [reason] Reason for creating the thread
|
893
|
+
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds
|
894
|
+
*/
|
895
|
+
|
896
|
+
/**
|
897
|
+
* Create a new public thread from this message
|
898
|
+
* @see GuildTextThreadManager#create
|
899
|
+
* @param {StartThreadOptions} [options] Options for starting a thread on this message
|
900
|
+
* @returns {Promise<ThreadChannel>}
|
901
|
+
*/
|
902
|
+
startThread(options = {}) {
|
903
|
+
if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
|
904
|
+
if (!['GUILD_TEXT', 'GUILD_NEWS'].includes(this.channel.type)) {
|
905
|
+
return Promise.reject(new Error('MESSAGE_THREAD_PARENT'));
|
906
|
+
}
|
907
|
+
if (this.hasThread) return Promise.reject(new Error('MESSAGE_EXISTING_THREAD'));
|
908
|
+
return this.channel.threads.create({ ...options, startMessage: this });
|
909
|
+
}
|
910
|
+
|
911
|
+
/**
|
912
|
+
* Fetch this message.
|
913
|
+
* @param {boolean} [force=true] Whether to skip the cache check and request the API
|
914
|
+
* @returns {Promise<Message>}
|
915
|
+
*/
|
916
|
+
fetch(force = true) {
|
917
|
+
if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
|
918
|
+
return this.channel.messages.fetch(this.id, { force });
|
919
|
+
}
|
920
|
+
|
921
|
+
/**
|
922
|
+
* Fetches the webhook used to create this message.
|
923
|
+
* @returns {Promise<?Webhook>}
|
924
|
+
*/
|
925
|
+
fetchWebhook() {
|
926
|
+
if (!this.webhookId) return Promise.reject(new Error('WEBHOOK_MESSAGE'));
|
927
|
+
if (this.webhookId === this.applicationId) return Promise.reject(new Error('WEBHOOK_APPLICATION'));
|
928
|
+
return this.client.fetchWebhook(this.webhookId);
|
929
|
+
}
|
930
|
+
|
931
|
+
/**
|
932
|
+
* Suppresses or unsuppresses embeds on a message.
|
933
|
+
* @param {boolean} [suppress=true] If the embeds should be suppressed or not
|
934
|
+
* @returns {Promise<Message>}
|
935
|
+
*/
|
936
|
+
suppressEmbeds(suppress = true) {
|
937
|
+
const flags = new MessageFlags(this.flags.bitfield);
|
938
|
+
|
939
|
+
if (suppress) {
|
940
|
+
flags.add(MessageFlags.FLAGS.SUPPRESS_EMBEDS);
|
941
|
+
} else {
|
942
|
+
flags.remove(MessageFlags.FLAGS.SUPPRESS_EMBEDS);
|
943
|
+
}
|
944
|
+
|
945
|
+
return this.edit({ flags });
|
946
|
+
}
|
947
|
+
|
948
|
+
/**
|
949
|
+
* Removes the attachments from this message.
|
950
|
+
* @returns {Promise<Message>}
|
951
|
+
*/
|
952
|
+
removeAttachments() {
|
953
|
+
return this.edit({ attachments: [] });
|
954
|
+
}
|
955
|
+
|
956
|
+
/**
|
957
|
+
* Resolves a component by a custom id.
|
958
|
+
* @param {string} customId The custom id to resolve against
|
959
|
+
* @returns {?MessageActionRowComponent}
|
960
|
+
*/
|
961
|
+
resolveComponent(customId) {
|
962
|
+
return this.components.flatMap(row => row.components).find(component => component.customId === customId) ?? null;
|
963
|
+
}
|
964
|
+
|
965
|
+
/**
|
966
|
+
* Used mainly internally. Whether two messages are identical in properties. If you want to compare messages
|
967
|
+
* without checking all the properties, use `message.id === message2.id`, which is much more efficient. This
|
968
|
+
* method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties.
|
969
|
+
* @param {Message} message The message to compare it to
|
970
|
+
* @param {APIMessage} rawData Raw data passed through the WebSocket about this message
|
971
|
+
* @returns {boolean}
|
972
|
+
*/
|
973
|
+
equals(message, rawData) {
|
974
|
+
if (!message) return false;
|
975
|
+
const embedUpdate = !message.author && !message.attachments;
|
976
|
+
if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
|
977
|
+
|
978
|
+
let equal =
|
979
|
+
this.id === message.id &&
|
980
|
+
this.author.id === message.author.id &&
|
981
|
+
this.content === message.content &&
|
982
|
+
this.tts === message.tts &&
|
983
|
+
this.nonce === message.nonce &&
|
984
|
+
this.embeds.length === message.embeds.length &&
|
985
|
+
this.attachments.length === message.attachments.length;
|
986
|
+
|
987
|
+
if (equal && rawData) {
|
988
|
+
equal =
|
989
|
+
this.mentions.everyone === message.mentions.everyone &&
|
990
|
+
this.createdTimestamp === new Date(rawData.timestamp).getTime() &&
|
991
|
+
this.editedTimestamp === new Date(rawData.edited_timestamp).getTime();
|
992
|
+
}
|
993
|
+
|
994
|
+
return equal;
|
995
|
+
}
|
996
|
+
|
997
|
+
/**
|
998
|
+
* Whether this message is from a guild.
|
999
|
+
* @returns {boolean}
|
1000
|
+
*/
|
1001
|
+
inGuild() {
|
1002
|
+
return Boolean(this.guildId);
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
/**
|
1006
|
+
* When concatenated with a string, this automatically concatenates the message's content instead of the object.
|
1007
|
+
* @returns {string}
|
1008
|
+
* @example
|
1009
|
+
* // Logs: Message: This is a message!
|
1010
|
+
* console.log(`Message: ${message}`);
|
1011
|
+
*/
|
1012
|
+
toString() {
|
1013
|
+
return this.content;
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
toJSON() {
|
1017
|
+
return super.toJSON({
|
1018
|
+
channel: 'channelId',
|
1019
|
+
author: 'authorId',
|
1020
|
+
groupActivityApplication: 'groupActivityApplicationId',
|
1021
|
+
guild: 'guildId',
|
1022
|
+
cleanContent: true,
|
1023
|
+
member: false,
|
1024
|
+
reactions: false,
|
1025
|
+
});
|
1026
|
+
}
|
1027
|
+
// Added
|
1028
|
+
/**
|
1029
|
+
* Marks the message as unread.
|
1030
|
+
* @returns {Promise<boolean>}
|
1031
|
+
*/
|
1032
|
+
async markUnread() {
|
1033
|
+
await this.client.api.channels[this.channelId].messages[this.id].ack.post({
|
1034
|
+
data: {
|
1035
|
+
manual: true,
|
1036
|
+
mention_count:
|
1037
|
+
this.mentions.everyone ||
|
1038
|
+
this.mentions.repliedUser?.id === this.client.user.id ||
|
1039
|
+
this.mentions.users.has(this.client.user.id) ||
|
1040
|
+
(this.guildId && this.mentions.roles.some(r => this.guild.members.me._roles?.includes(r.id)))
|
1041
|
+
? 1
|
1042
|
+
: 0,
|
1043
|
+
},
|
1044
|
+
});
|
1045
|
+
return true;
|
1046
|
+
}
|
1047
|
+
|
1048
|
+
/**
|
1049
|
+
* Marks the message as read.
|
1050
|
+
* @returns {Promise<boolean>}
|
1051
|
+
*/
|
1052
|
+
async markRead() {
|
1053
|
+
await this.client.api.channels[this.channelId].messages[this.id].ack.post({
|
1054
|
+
data: {
|
1055
|
+
token: null,
|
1056
|
+
},
|
1057
|
+
});
|
1058
|
+
return true;
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
/**
|
1062
|
+
* @typedef {Object} MessageButtonLocation
|
1063
|
+
* @property {number} row Index of the row
|
1064
|
+
* @property {number} col Index of the column
|
1065
|
+
*/
|
1066
|
+
|
1067
|
+
/**
|
1068
|
+
* Click specific button or automatically click first button if no button is specified.
|
1069
|
+
* @param {MessageButton|MessageButtonLocation|string} button Button ID
|
1070
|
+
* @returns {Promise<InteractionResponse>}
|
1071
|
+
* @example
|
1072
|
+
* client.on('messageCreate', async message => {
|
1073
|
+
* if (message.components.length) {
|
1074
|
+
* // Find first button and click it
|
1075
|
+
* await message.clickButton();
|
1076
|
+
* // Click with button ID
|
1077
|
+
* await message.clickButton('button-id');
|
1078
|
+
* // Click with button location
|
1079
|
+
* await message.clickButton({ row: 0, col: 0 });
|
1080
|
+
* // Click with class MessageButton
|
1081
|
+
* const button = message.components[0].components[0];
|
1082
|
+
* await message.clickButton(button);
|
1083
|
+
* // Click with class MessageButton (2)
|
1084
|
+
* button.click(message);
|
1085
|
+
* }
|
1086
|
+
* });
|
1087
|
+
*/
|
1088
|
+
clickButton(button) {
|
1089
|
+
if (!button) {
|
1090
|
+
button = this.components.flatMap(row => row.components).find(b => b.type === 'BUTTON')?.customId;
|
1091
|
+
} else if (button instanceof MessageButton) {
|
1092
|
+
button = button.customId;
|
1093
|
+
} else if (typeof button === 'object') {
|
1094
|
+
if (!('row' in button) || !('col' in button)) throw new TypeError('INVALID_BUTTON_LOCATION');
|
1095
|
+
button = this.components[button.row]?.components[button.col]?.customId;
|
1096
|
+
}
|
1097
|
+
if (!button) throw new TypeError('BUTTON_NOT_FOUND');
|
1098
|
+
button = this.components.flatMap(row => row.components).find(b => b.customId === button && b.type === 'BUTTON');
|
1099
|
+
return button ? button.click(this) : Promise.reject(new TypeError('BUTTON_NOT_FOUND'));
|
1100
|
+
}
|
1101
|
+
/**
|
1102
|
+
* Select specific menu or First Menu
|
1103
|
+
* @param {MessageSelectMenu|string|number|Array<any>} menuID MenuId / MessageSelectMenu / Row of Menu / Array of Values (first menu)
|
1104
|
+
* @param {Array<any>} options Array of Values
|
1105
|
+
* @returns {Promise<InteractionResponse>}
|
1106
|
+
* @example
|
1107
|
+
* client.on('messageCreate', async message => {
|
1108
|
+
* if (message.components.length) {
|
1109
|
+
* // Row
|
1110
|
+
* await message.selectMenu(1, [message.channel]); // row 1, type: Channel, multi: false
|
1111
|
+
* // Id
|
1112
|
+
* await message.selectMenu('menu-id', ['uid1', client.user, message.member]); // MenuId, type: User, multi: true
|
1113
|
+
* // First Menu
|
1114
|
+
* await message.selectMenu(['role-id']); // First Menu, type: role, multi: false
|
1115
|
+
* // class MessageSelectMenu
|
1116
|
+
* const menu = message.components[0].components[0];
|
1117
|
+
* await message.selectMenu(menu, ['option1', 'option2']);
|
1118
|
+
* // MessageSelectMenu (2)
|
1119
|
+
* menu.select(message, ['option1', 'option2']);
|
1120
|
+
* }
|
1121
|
+
* });
|
1122
|
+
*/
|
1123
|
+
selectMenu(menuID, options = []) {
|
1124
|
+
if (!this.components[0]) throw new TypeError('MESSAGE_NO_COMPONENTS');
|
1125
|
+
if (menuID instanceof MessageSelectMenu) {
|
1126
|
+
//
|
1127
|
+
} else if (/[0-4]/.test(menuID)) {
|
1128
|
+
menuID = this.components[menuID]?.components[0];
|
1129
|
+
} else {
|
1130
|
+
const menuAll = this.components
|
1131
|
+
.flatMap(row => row.components)
|
1132
|
+
.filter(b =>
|
1133
|
+
[
|
1134
|
+
'STRING_SELECT',
|
1135
|
+
'USER_SELECT',
|
1136
|
+
'ROLE_SELECT',
|
1137
|
+
'MENTIONABLE_SELECT',
|
1138
|
+
'CHANNEL_SELECT',
|
1139
|
+
'SELECT_MENU',
|
1140
|
+
].includes(b.type),
|
1141
|
+
);
|
1142
|
+
if (menuAll.length == 0) throw new TypeError('MENU_NOT_FOUND');
|
1143
|
+
if (menuID) {
|
1144
|
+
menuID = menuAll.find(b => b.customId === menuID);
|
1145
|
+
} else {
|
1146
|
+
menuID = menuAll[0];
|
1147
|
+
}
|
1148
|
+
}
|
1149
|
+
if (!menuID.type.includes('SELECT')) throw new TypeError('MENU_NOT_FOUND');
|
1150
|
+
return menuID.select(this, Array.isArray(menuID) ? menuID : options);
|
1151
|
+
}
|
1152
|
+
//
|
1153
|
+
/**
|
1154
|
+
* Send context Menu v2
|
1155
|
+
* @param {Snowflake} botId Bot id
|
1156
|
+
* @param {string} commandName Command name in Context Menu
|
1157
|
+
* @returns {Promise<InteractionResponse>}
|
1158
|
+
*/
|
1159
|
+
async contextMenu(botId, commandName) {
|
1160
|
+
if (!botId) throw new Error('Bot ID is required');
|
1161
|
+
const user = await this.client.users.fetch(botId).catch(() => {});
|
1162
|
+
if (!user || !user.bot || !user.application) {
|
1163
|
+
throw new Error('BotID is not a bot or does not have an application slash command');
|
1164
|
+
}
|
1165
|
+
if (!commandName || typeof commandName !== 'string') {
|
1166
|
+
throw new Error('Command name is required');
|
1167
|
+
}
|
1168
|
+
let contextCMD;
|
1169
|
+
const data = await this.channel.searchInteraction(botId, 'MESSAGE');
|
1170
|
+
for (const command of data.application_commands) {
|
1171
|
+
user.application?.commands?._add(command, true);
|
1172
|
+
}
|
1173
|
+
contextCMD = user.application?.commands?.cache.find(c => c.name == commandName && c.type === 'MESSAGE');
|
1174
|
+
if (!contextCMD) {
|
1175
|
+
throw new Error(
|
1176
|
+
'INTERACTION_SEND_FAILURE',
|
1177
|
+
`Command ${commandName} is not found (with search)\nList command avalible: ${user.application?.commands?.cache
|
1178
|
+
.filter(a => a.type == 'MESSAGE')
|
1179
|
+
.map(a => a.name)
|
1180
|
+
.join(', ')}`,
|
1181
|
+
);
|
1182
|
+
}
|
1183
|
+
return contextCMD.sendContextMenu(this, true);
|
1184
|
+
}
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
exports.Message = Message;
|
1188
|
+
exports.deletedMessages = deletedMessages;
|