djs-selfbot-v13 3.1.7 → 3.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +18 -45
  3. package/package.json +8 -37
  4. package/src/client/BaseClient.js +2 -3
  5. package/src/client/Client.js +187 -539
  6. package/src/client/actions/Action.js +18 -13
  7. package/src/client/actions/ActionsManager.js +7 -1
  8. package/src/client/actions/AutoModerationActionExecution.js +1 -0
  9. package/src/client/actions/AutoModerationRuleCreate.js +1 -0
  10. package/src/client/actions/AutoModerationRuleDelete.js +1 -0
  11. package/src/client/actions/AutoModerationRuleUpdate.js +1 -0
  12. package/src/client/actions/MessageCreate.js +0 -4
  13. package/src/client/actions/PresenceUpdate.js +17 -16
  14. package/src/client/websocket/WebSocketManager.js +11 -31
  15. package/src/client/websocket/WebSocketShard.js +39 -38
  16. package/src/client/websocket/handlers/CALL_CREATE.js +3 -3
  17. package/src/client/websocket/handlers/CALL_DELETE.js +2 -2
  18. package/src/client/websocket/handlers/CALL_UPDATE.js +2 -2
  19. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +16 -13
  20. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
  21. package/src/client/websocket/handlers/GUILD_CREATE.js +7 -0
  22. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +1 -0
  23. package/src/client/websocket/handlers/READY.js +47 -137
  24. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +7 -5
  25. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +6 -4
  26. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +32 -9
  27. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +2 -8
  28. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
  29. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +78 -0
  30. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +1 -5
  31. package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +12 -0
  32. package/src/client/websocket/handlers/index.js +15 -20
  33. package/src/errors/Messages.js +24 -69
  34. package/src/index.js +12 -43
  35. package/src/managers/ApplicationCommandManager.js +9 -12
  36. package/src/managers/ApplicationCommandPermissionsManager.js +3 -11
  37. package/src/managers/ChannelManager.js +3 -4
  38. package/src/managers/ClientUserSettingManager.js +161 -279
  39. package/src/managers/GuildBanManager.js +1 -1
  40. package/src/managers/GuildChannelManager.js +2 -0
  41. package/src/managers/GuildForumThreadManager.js +22 -28
  42. package/src/managers/GuildMemberManager.js +40 -216
  43. package/src/managers/GuildSettingManager.js +22 -15
  44. package/src/managers/MessageManager.js +42 -44
  45. package/src/managers/PermissionOverwriteManager.js +1 -1
  46. package/src/managers/ReactionUserManager.js +5 -5
  47. package/src/managers/RelationshipManager.js +81 -74
  48. package/src/managers/ThreadManager.js +12 -45
  49. package/src/managers/ThreadMemberManager.js +1 -1
  50. package/src/managers/UserManager.js +6 -10
  51. package/src/managers/UserNoteManager.js +53 -0
  52. package/src/rest/APIRequest.js +42 -20
  53. package/src/rest/DiscordAPIError.js +17 -16
  54. package/src/rest/RESTManager.js +1 -21
  55. package/src/rest/RequestHandler.js +35 -21
  56. package/src/structures/ApplicationCommand.js +19 -456
  57. package/src/structures/ApplicationRoleConnectionMetadata.js +3 -0
  58. package/src/structures/AutoModerationRule.js +5 -5
  59. package/src/structures/AutocompleteInteraction.js +1 -0
  60. package/src/structures/BaseGuildTextChannel.js +10 -12
  61. package/src/structures/BaseGuildVoiceChannel.js +16 -18
  62. package/src/structures/{Call.js → CallState.js} +17 -12
  63. package/src/structures/CategoryChannel.js +2 -0
  64. package/src/structures/Channel.js +2 -3
  65. package/src/structures/ClientPresence.js +12 -8
  66. package/src/structures/ClientUser.js +117 -336
  67. package/src/structures/ContextMenuInteraction.js +1 -1
  68. package/src/structures/DMChannel.js +29 -92
  69. package/src/structures/ForumChannel.js +0 -10
  70. package/src/structures/GroupDMChannel.js +387 -0
  71. package/src/structures/Guild.js +135 -271
  72. package/src/structures/GuildAuditLogs.js +0 -5
  73. package/src/structures/GuildChannel.js +16 -2
  74. package/src/structures/GuildMember.js +27 -145
  75. package/src/structures/Interaction.js +1 -62
  76. package/src/structures/Invite.js +35 -52
  77. package/src/structures/Message.js +228 -202
  78. package/src/structures/MessageAttachment.js +11 -0
  79. package/src/structures/MessageButton.js +1 -67
  80. package/src/structures/MessageEmbed.js +1 -1
  81. package/src/structures/MessageMentions.js +3 -2
  82. package/src/structures/MessagePayload.js +4 -46
  83. package/src/structures/MessageReaction.js +1 -1
  84. package/src/structures/MessageSelectMenu.js +1 -252
  85. package/src/structures/Modal.js +75 -180
  86. package/src/structures/Presence.js +2 -2
  87. package/src/structures/RichPresence.js +14 -34
  88. package/src/structures/Role.js +18 -2
  89. package/src/structures/SelectMenuInteraction.js +2 -151
  90. package/src/structures/Team.js +0 -49
  91. package/src/structures/TextInputComponent.js +0 -70
  92. package/src/structures/ThreadChannel.js +0 -19
  93. package/src/structures/User.js +117 -345
  94. package/src/structures/UserContextMenuInteraction.js +2 -2
  95. package/src/structures/VoiceState.js +74 -39
  96. package/src/structures/WebEmbed.js +38 -52
  97. package/src/structures/Webhook.js +17 -11
  98. package/src/structures/interfaces/Application.js +146 -23
  99. package/src/structures/interfaces/TextBasedChannel.js +411 -256
  100. package/src/util/ApplicationFlags.js +1 -1
  101. package/src/util/AttachmentFlags.js +38 -0
  102. package/src/util/Constants.js +106 -284
  103. package/src/util/Formatters.js +16 -2
  104. package/src/util/InviteFlags.js +29 -0
  105. package/src/util/LimitedCollection.js +1 -1
  106. package/src/util/Options.js +48 -68
  107. package/src/util/Permissions.js +5 -0
  108. package/src/util/PurchasedFlags.js +2 -0
  109. package/src/util/RemoteAuth.js +221 -356
  110. package/src/util/RoleFlags.js +37 -0
  111. package/src/util/Sweepers.js +1 -1
  112. package/src/util/Util.js +76 -36
  113. package/typings/enums.d.ts +18 -73
  114. package/typings/index.d.ts +873 -1225
  115. package/typings/rawDataTypes.d.ts +68 -9
  116. package/src/client/actions/InteractionCreate.js +0 -115
  117. package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +0 -23
  118. package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +0 -11
  119. package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +0 -55
  120. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
  121. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
  122. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
  123. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
  124. package/src/client/websocket/handlers/INTERACTION_CREATE.js +0 -16
  125. package/src/client/websocket/handlers/INTERACTION_FAILURE.js +0 -18
  126. package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +0 -30
  127. package/src/client/websocket/handlers/MESSAGE_ACK.js +0 -16
  128. package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
  129. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
  130. package/src/managers/DeveloperPortalManager.js +0 -104
  131. package/src/managers/GuildApplicationCommandManager.js +0 -28
  132. package/src/managers/GuildFolderManager.js +0 -24
  133. package/src/managers/SessionManager.js +0 -57
  134. package/src/rest/CaptchaSolver.js +0 -132
  135. package/src/structures/ClientApplication.js +0 -204
  136. package/src/structures/DeveloperPortalApplication.js +0 -520
  137. package/src/structures/GuildFolder.js +0 -75
  138. package/src/structures/InteractionResponse.js +0 -114
  139. package/src/structures/PartialGroupDMChannel.js +0 -433
  140. package/src/structures/Session.js +0 -81
  141. package/src/util/Voice.js +0 -1456
  142. package/src/util/arRPC/index.js +0 -229
  143. package/src/util/arRPC/process/detectable.json +0 -1
  144. package/src/util/arRPC/process/index.js +0 -102
  145. package/src/util/arRPC/process/native/index.js +0 -5
  146. package/src/util/arRPC/process/native/linux.js +0 -37
  147. package/src/util/arRPC/process/native/win32.js +0 -25
  148. package/src/util/arRPC/transports/ipc.js +0 -281
  149. package/src/util/arRPC/transports/websocket.js +0 -128
@@ -1,22 +1,26 @@
1
1
  'use strict';
2
2
 
3
3
  const process = require('node:process');
4
+ const { setTimeout } = require('node:timers');
4
5
  const { Collection } = require('@discordjs/collection');
5
6
  const Base = require('./Base');
6
7
  const BaseMessageComponent = require('./BaseMessageComponent');
7
- const ClientApplication = require('./ClientApplication');
8
- const InteractionCollector = require('./InteractionCollector');
9
8
  const MessageAttachment = require('./MessageAttachment');
10
- const MessageButton = require('./MessageButton');
11
9
  const Embed = require('./MessageEmbed');
12
10
  const Mentions = require('./MessageMentions');
13
11
  const MessagePayload = require('./MessagePayload');
14
- const MessageSelectMenu = require('./MessageSelectMenu');
15
12
  const ReactionCollector = require('./ReactionCollector');
16
13
  const { Sticker } = require('./Sticker');
14
+ const Application = require('./interfaces/Application');
17
15
  const { Error } = require('../errors');
18
16
  const ReactionManager = require('../managers/ReactionManager');
19
- const { InteractionTypes, MessageTypes, SystemMessageTypes, MaxBulkDeletableMessageAge } = require('../util/Constants');
17
+ const {
18
+ InteractionTypes,
19
+ MessageTypes,
20
+ SystemMessageTypes,
21
+ MessageComponentTypes,
22
+ Events,
23
+ } = require('../util/Constants');
20
24
  const MessageFlags = require('../util/MessageFlags');
21
25
  const Permissions = require('../util/Permissions');
22
26
  const SnowflakeUtil = require('../util/SnowflakeUtil');
@@ -256,9 +260,9 @@ class Message extends Base {
256
260
  if ('application' in data) {
257
261
  /**
258
262
  * Supplemental application information for group activities
259
- * @type {?ClientApplication}
263
+ * @type {?Application}
260
264
  */
261
- this.groupActivityApplication = new ClientApplication(this.client, data.application);
265
+ this.groupActivityApplication = new Application(this.client, data.application);
262
266
  } else {
263
267
  this.groupActivityApplication ??= null;
264
268
  }
@@ -533,65 +537,6 @@ class Message extends Base {
533
537
  });
534
538
  }
535
539
 
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
540
  /**
596
541
  * Whether the message is editable by the client user
597
542
  * @type {boolean}
@@ -653,14 +598,7 @@ class Message extends Base {
653
598
  * channel.bulkDelete(messages.filter(message => message.bulkDeletable));
654
599
  */
655
600
  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
- );
601
+ return false;
664
602
  }
665
603
 
666
604
  /**
@@ -722,7 +660,7 @@ class Message extends Base {
722
660
  * @property {MessageAttachment[]} [attachments] An array of attachments to keep,
723
661
  * all attachments will be kept if omitted
724
662
  * @property {FileOptions[]|BufferResolvable[]|MessageAttachment[]} [files] Files to add to the message
725
- * @property {Array<(MessageActionRow|MessageActionRowOptions)>} [components]
663
+ * @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
726
664
  * Action rows containing interactive components for the message (buttons, select menus)
727
665
  */
728
666
 
@@ -792,7 +730,7 @@ class Message extends Base {
792
730
  /**
793
731
  * Adds a reaction to the message.
794
732
  * @param {EmojiIdentifierResolvable} emoji The emoji to react with
795
- * @param {boolean} [burst=false] Super Reactions (Discord Nitro only)
733
+ * @param {boolean} [burst=false] Super Reactions
796
734
  * @returns {Promise<MessageReaction>}
797
735
  * @example
798
736
  * // React to a message with a unicode emoji
@@ -811,9 +749,9 @@ class Message extends Base {
811
749
 
812
750
  return this.client.actions.MessageReactionAdd.handle(
813
751
  {
814
- user: this.client.user,
815
- channel: this.channel,
816
- message: this,
752
+ [this.client.actions.injectedUser]: this.client.user,
753
+ [this.client.actions.injectedChannel]: this.channel,
754
+ [this.client.actions.injectedMessage]: this,
817
755
  emoji: Util.resolvePartialEmoji(emoji),
818
756
  me_burst: burst,
819
757
  },
@@ -1024,157 +962,244 @@ class Message extends Base {
1024
962
  reactions: false,
1025
963
  });
1026
964
  }
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: 1,
1037
- },
1038
- });
1039
- return true;
1040
- }
1041
965
 
966
+ // TypeScript
1042
967
  /**
1043
- * Marks the message as read.
1044
- * @returns {Promise<boolean>}
968
+ * Check data
969
+ * @type {boolean}
970
+ * @readonly
1045
971
  */
1046
- async markRead() {
1047
- await this.client.api.channels[this.channelId].messages[this.id].ack.post({
1048
- data: {
1049
- token: null,
1050
- },
1051
- });
972
+ get isMessage() {
1052
973
  return true;
1053
974
  }
1054
975
 
1055
976
  /**
977
+ * Click specific button with X and Y
1056
978
  * @typedef {Object} MessageButtonLocation
1057
- * @property {number} row Index of the row
1058
- * @property {number} col Index of the column
979
+ * @property {number} X Index of the row
980
+ * @property {number} Y Index of the column
1059
981
  */
1060
982
 
1061
983
  /**
1062
984
  * Click specific button or automatically click first button if no button is specified.
1063
- * @param {MessageButton|MessageButtonLocation|string} button Button ID
1064
- * @returns {Promise<InteractionResponse>}
985
+ * @param {MessageButtonLocation|string|undefined} button button
986
+ * @returns {Promise<Message|Modal>}
1065
987
  * @example
1066
- * client.on('messageCreate', async message => {
1067
- * if (message.components.length) {
1068
- * // Find first button and click it
1069
- * await message.clickButton();
1070
- * // Click with button ID
1071
- * await message.clickButton('button-id');
1072
- * // Click with button location
1073
- * await message.clickButton({ row: 0, col: 0 });
1074
- * // Click with class MessageButton
1075
- * const button = message.components[0].components[0];
1076
- * await message.clickButton(button);
1077
- * // Click with class MessageButton (2)
1078
- * button.click(message);
1079
- * }
988
+ * // Demo msg
989
+ * Some content
990
+ * ――――――――――――――――――――――――――――――――> X from 0
991
+ * [button1] [button2] [button3]
992
+ * [button4] [button5] [button6]
993
+ *
994
+ * Y from 0
995
+ * // Click button6 with X and Y
996
+ * [0,0] [1,0] [2,0]
997
+ * [0,1] [1,1] [2,1]
998
+ * // Code
999
+ * message.clickButton({
1000
+ * X: 2, Y: 1,
1080
1001
  * });
1002
+ * // Click button with customId (Ex button 5)
1003
+ * message.clickButton('button5');
1004
+ * // Click button 1
1005
+ * message.clickButton();
1081
1006
  */
1082
1007
  clickButton(button) {
1083
- if (!button) {
1084
- button = this.components.flatMap(row => row.components).find(b => b.type === 'BUTTON')?.customId;
1085
- } else if (button instanceof MessageButton) {
1086
- button = button.customId;
1087
- } else if (typeof button === 'object') {
1088
- if (!('row' in button) || !('col' in button)) throw new TypeError('INVALID_BUTTON_LOCATION');
1089
- button = this.components[button.row]?.components[button.col]?.customId;
1008
+ if (typeof button == 'undefined') {
1009
+ button = this.components
1010
+ .flatMap(row => row.components)
1011
+ .find(b => b.type === 'BUTTON' && b.customId && !b.disabled);
1012
+ } else if (typeof button == 'string') {
1013
+ button = this.components.flatMap(row => row.components).find(b => b.type === 'BUTTON' && b.customId == button);
1014
+ } else {
1015
+ button = this.components[button.Y]?.components[button.X];
1090
1016
  }
1017
+ button = button.toJSON();
1091
1018
  if (!button) throw new TypeError('BUTTON_NOT_FOUND');
1092
- button = this.components.flatMap(row => row.components).find(b => b.customId === button && b.type === 'BUTTON');
1093
- return button ? button.click(this) : Promise.reject(new TypeError('BUTTON_NOT_FOUND'));
1019
+ if (!button.custom_id || button.disabled) throw new TypeError('BUTTON_CANNOT_CLICK');
1020
+ const nonce = SnowflakeUtil.generate();
1021
+ const data = {
1022
+ type: InteractionTypes.MESSAGE_COMPONENT,
1023
+ nonce,
1024
+ guild_id: this.guildId,
1025
+ channel_id: this.channelId,
1026
+ message_id: this.id,
1027
+ application_id: this.applicationId ?? this.author.id,
1028
+ session_id: this.client.sessionId,
1029
+ message_flags: this.flags.bitfield,
1030
+ data: {
1031
+ component_type: MessageComponentTypes.BUTTON,
1032
+ custom_id: button.custom_id,
1033
+ },
1034
+ };
1035
+ this.client.api.interactions.post({
1036
+ data,
1037
+ });
1038
+ return new Promise((resolve, reject) => {
1039
+ const timeoutMs = 5_000;
1040
+ // Waiting for MsgCreate / ModalCreate
1041
+ const handler = data => {
1042
+ // UnhandledPacket
1043
+ if (data.d?.nonce == nonce && data.t == 'INTERACTION_SUCCESS') {
1044
+ // Interaction#deferUpdate
1045
+ this.client.removeListener(Events.MESSAGE_CREATE, handler);
1046
+ this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1047
+ this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1048
+ resolve(this);
1049
+ }
1050
+ if (data.nonce !== nonce) return;
1051
+ clearTimeout(timeout);
1052
+ this.client.removeListener(Events.MESSAGE_CREATE, handler);
1053
+ this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1054
+ this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1055
+ this.client.decrementMaxListeners();
1056
+ resolve(data);
1057
+ };
1058
+ const timeout = setTimeout(() => {
1059
+ this.client.removeListener(Events.MESSAGE_CREATE, handler);
1060
+ this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1061
+ this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1062
+ this.client.decrementMaxListeners();
1063
+ reject(new Error('INTERACTION_FAILED'));
1064
+ }, timeoutMs).unref();
1065
+ this.client.incrementMaxListeners();
1066
+ this.client.on(Events.MESSAGE_CREATE, handler);
1067
+ this.client.on(Events.UNHANDLED_PACKET, handler);
1068
+ this.client.on(Events.INTERACTION_MODAL_CREATE, handler);
1069
+ });
1094
1070
  }
1071
+
1095
1072
  /**
1096
- * Select specific menu or First Menu
1097
- * @param {MessageSelectMenu|string|number|Array<any>} menuID MenuId / MessageSelectMenu / Row of Menu / Array of Values (first menu)
1098
- * @param {Array<any>} options Array of Values
1099
- * @returns {Promise<InteractionResponse>}
1100
- * @example
1101
- * client.on('messageCreate', async message => {
1102
- * if (message.components.length) {
1103
- * // Row
1104
- * await message.selectMenu(1, [message.channel]); // row 1, type: Channel, multi: false
1105
- * // Id
1106
- * await message.selectMenu('menu-id', ['uid1', client.user, message.member]); // MenuId, type: User, multi: true
1107
- * // First Menu
1108
- * await message.selectMenu(['role-id']); // First Menu, type: role, multi: false
1109
- * // class MessageSelectMenu
1110
- * const menu = message.components[0].components[0];
1111
- * await message.selectMenu(menu, ['option1', 'option2']);
1112
- * // MessageSelectMenu (2)
1113
- * menu.select(message, ['option1', 'option2']);
1114
- * }
1115
- * });
1073
+ * Select specific menu
1074
+ * @param {number|string} menu Target
1075
+ * @param {Array<UserResolvable | RoleResolvable | ChannelResolvable | string>} values Any value
1076
+ * @returns {Promise<Message|Modal>}
1116
1077
  */
1117
- selectMenu(menuID, options = []) {
1118
- if (!this.components[0]) throw new TypeError('MESSAGE_NO_COMPONENTS');
1119
- if (menuID instanceof MessageSelectMenu) {
1120
- //
1121
- } else if (/[0-4]/.test(menuID)) {
1122
- menuID = this.components[menuID]?.components[0];
1078
+ selectMenu(menu, values = []) {
1079
+ let selectMenu;
1080
+ if (/[0-4]/.test(menu)) {
1081
+ selectMenu = this.components[menu]?.components[0];
1123
1082
  } else {
1124
- const menuAll = this.components
1083
+ selectMenu = this.components
1125
1084
  .flatMap(row => row.components)
1126
- .filter(b =>
1127
- [
1128
- 'STRING_SELECT',
1129
- 'USER_SELECT',
1130
- 'ROLE_SELECT',
1131
- 'MENTIONABLE_SELECT',
1132
- 'CHANNEL_SELECT',
1133
- 'SELECT_MENU',
1134
- ].includes(b.type),
1085
+ .find(
1086
+ b =>
1087
+ ['STRING_SELECT', 'USER_SELECT', 'ROLE_SELECT', 'MENTIONABLE_SELECT', 'CHANNEL_SELECT'].includes(b.type) &&
1088
+ b.customId == menu &&
1089
+ !b.disabled,
1135
1090
  );
1136
- if (menuAll.length == 0) throw new TypeError('MENU_NOT_FOUND');
1137
- if (menuID) {
1138
- menuID = menuAll.find(b => b.customId === menuID);
1139
- } else {
1140
- menuID = menuAll[0];
1141
- }
1142
1091
  }
1143
- if (!menuID.type.includes('SELECT')) throw new TypeError('MENU_NOT_FOUND');
1144
- return menuID.select(this, Array.isArray(menuID) ? menuID : options);
1092
+ if (values.length < selectMenu.minValues) {
1093
+ throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${selectMenu.minValues}`);
1094
+ }
1095
+ if (values.length > selectMenu.maxValues) {
1096
+ throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${selectMenu.maxValues}`);
1097
+ }
1098
+ values = values.map(value => {
1099
+ switch (selectMenu.type) {
1100
+ case 'STRING_SELECT': {
1101
+ return selectMenu.options.find(obj => obj.value === value || obj.label === value).value;
1102
+ }
1103
+ case 'USER_SELECT': {
1104
+ return this.client.users.resolveId(value);
1105
+ }
1106
+ case 'ROLE_SELECT': {
1107
+ return this.guild.roles.resolveId(value);
1108
+ }
1109
+ case 'MENTIONABLE_SELECT': {
1110
+ return this.client.users.resolveId(value) || this.guild.roles.resolveId(value);
1111
+ }
1112
+ case 'CHANNEL_SELECT': {
1113
+ return this.client.channels.resolveId(value);
1114
+ }
1115
+ default: {
1116
+ return value;
1117
+ }
1118
+ }
1119
+ });
1120
+ const nonce = SnowflakeUtil.generate();
1121
+ const data = {
1122
+ type: InteractionTypes.MESSAGE_COMPONENT,
1123
+ guild_id: this.guildId,
1124
+ channel_id: this.channelId,
1125
+ message_id: this.id,
1126
+ application_id: this.applicationId ?? this.author.id,
1127
+ session_id: this.client.sessionId,
1128
+ message_flags: this.flags.bitfield,
1129
+ data: {
1130
+ component_type: MessageComponentTypes[selectMenu.type],
1131
+ custom_id: selectMenu.customId,
1132
+ type: MessageComponentTypes[selectMenu.type],
1133
+ values,
1134
+ },
1135
+ nonce,
1136
+ };
1137
+ this.client.api.interactions.post({
1138
+ data,
1139
+ });
1140
+ return new Promise((resolve, reject) => {
1141
+ const timeoutMs = 5_000;
1142
+ // Waiting for MsgCreate / ModalCreate
1143
+ const handler = data => {
1144
+ // UnhandledPacket
1145
+ if (data.d?.nonce == nonce && data.t == 'INTERACTION_SUCCESS') {
1146
+ // Interaction#deferUpdate
1147
+ this.client.removeListener(Events.MESSAGE_CREATE, handler);
1148
+ this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1149
+ this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1150
+ resolve(this);
1151
+ }
1152
+ if (data.nonce !== nonce) return;
1153
+ clearTimeout(timeout);
1154
+ this.client.removeListener(Events.MESSAGE_CREATE, handler);
1155
+ this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1156
+ this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1157
+ this.client.decrementMaxListeners();
1158
+ resolve(data);
1159
+ };
1160
+ const timeout = setTimeout(() => {
1161
+ this.client.removeListener(Events.MESSAGE_CREATE, handler);
1162
+ this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1163
+ this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1164
+ this.client.decrementMaxListeners();
1165
+ reject(new Error('INTERACTION_FAILED'));
1166
+ }, timeoutMs).unref();
1167
+ this.client.incrementMaxListeners();
1168
+ this.client.on(Events.MESSAGE_CREATE, handler);
1169
+ this.client.on(Events.UNHANDLED_PACKET, handler);
1170
+ this.client.on(Events.INTERACTION_MODAL_CREATE, handler);
1171
+ });
1145
1172
  }
1146
- //
1173
+
1147
1174
  /**
1148
- * Send context Menu v2
1149
- * @param {Snowflake} botId Bot id
1150
- * @param {string} commandName Command name in Context Menu
1151
- * @returns {Promise<InteractionResponse>}
1175
+ * Marks the message as unread.
1176
+ * @returns {Promise<void>}
1152
1177
  */
1153
- async contextMenu(botId, commandName) {
1154
- if (!botId) throw new Error('Bot ID is required');
1155
- const user = await this.client.users.fetch(botId).catch(() => {});
1156
- if (!user || !user.bot || !user.application) {
1157
- throw new Error('BotID is not a bot or does not have an application slash command');
1158
- }
1159
- if (!commandName || typeof commandName !== 'string') {
1160
- throw new Error('Command name is required');
1161
- }
1162
- let contextCMD;
1163
- const data = await this.channel.searchInteraction(botId, 'MESSAGE');
1164
- for (const command of data.application_commands) {
1165
- user.application?.commands?._add(command, true);
1166
- }
1167
- contextCMD = user.application?.commands?.cache.find(c => c.name == commandName && c.type === 'MESSAGE');
1168
- if (!contextCMD) {
1169
- throw new Error(
1170
- 'INTERACTION_SEND_FAILURE',
1171
- `Command ${commandName} is not found (with search)\nList command avalible: ${user.application?.commands?.cache
1172
- .filter(a => a.type == 'MESSAGE')
1173
- .map(a => a.name)
1174
- .join(', ')}`,
1175
- );
1176
- }
1177
- return contextCMD.sendContextMenu(this, true);
1178
+ markUnread() {
1179
+ return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1180
+ data: {
1181
+ manual: true,
1182
+ mention_count:
1183
+ this.mentions.everyone ||
1184
+ this.mentions.repliedUser?.id === this.client.user.id ||
1185
+ this.mentions.users.has(this.client.user.id) ||
1186
+ (this.guildId && this.mentions.roles.some(r => this.guild.members.me._roles?.includes(r.id)))
1187
+ ? 1
1188
+ : 1,
1189
+ },
1190
+ });
1191
+ }
1192
+
1193
+ /**
1194
+ * Marks the message as read.
1195
+ * @returns {Promise<void>}
1196
+ */
1197
+ markRead() {
1198
+ return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1199
+ data: {
1200
+ token: null,
1201
+ },
1202
+ });
1178
1203
  }
1179
1204
 
1180
1205
  /**
@@ -1183,6 +1208,7 @@ class Message extends Base {
1183
1208
  * @param {Object} [elements={}] Metadata
1184
1209
  * @returns {Promise<{ report_id: Snowflake }>}
1185
1210
  * @example
1211
+ * // GET https://discord.com/api/v9/reporting/menu/message?variant=4
1186
1212
  * // Report Category
1187
1213
  * // - <hidden>MESSAGE_WELCOME (3)</hidden>
1188
1214
  * // - Something else (28)
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const AttachmentFlags = require('../util/AttachmentFlags');
3
4
  const Util = require('../util/Util');
4
5
 
5
6
  /**
@@ -169,6 +170,16 @@ class MessageAttachment {
169
170
  } else {
170
171
  this.waveform ??= null;
171
172
  }
173
+
174
+ if ('flags' in data) {
175
+ /**
176
+ * The flags of this attachment
177
+ * @type {Readonly<AttachmentFlags>}
178
+ */
179
+ this.flags = new AttachmentFlags(data.flags).freeze();
180
+ } else {
181
+ this.flags ??= new AttachmentFlags().freeze();
182
+ }
172
183
  }
173
184
 
174
185
  /**
@@ -1,13 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const { setTimeout } = require('node:timers');
4
3
  const BaseMessageComponent = require('./BaseMessageComponent');
5
4
  const { RangeError } = require('../errors');
6
- const { MessageButtonStyles, MessageComponentTypes, InteractionTypes } = require('../util/Constants');
7
- const SnowflakeUtil = require('../util/SnowflakeUtil');
5
+ const { MessageButtonStyles, MessageComponentTypes } = require('../util/Constants');
8
6
  const Util = require('../util/Util');
9
- const { lazy } = require('../util/Util');
10
- const Message = lazy(() => require('../structures/Message').Message);
11
7
 
12
8
  /**
13
9
  * Represents a button message component.
@@ -164,68 +160,6 @@ class MessageButton extends BaseMessageComponent {
164
160
  static resolveStyle(style) {
165
161
  return typeof style === 'string' ? style : MessageButtonStyles[style];
166
162
  }
167
- // Patch Click
168
- /**
169
- * Click the button
170
- * @param {Message} message Discord Message
171
- * @returns {Promise<InteractionResponse>}
172
- */
173
- async click(message) {
174
- const nonce = SnowflakeUtil.generate();
175
- if (!(message instanceof Message())) throw new Error('[UNKNOWN_MESSAGE] Please pass a valid Message');
176
- if (!this.customId || this.style == MessageButtonStyles.LINK || this.disabled) return false;
177
- const data = {
178
- type: InteractionTypes.MESSAGE_COMPONENT,
179
- nonce,
180
- guild_id: message.guild?.id ?? null,
181
- channel_id: message.channel.id,
182
- message_id: message.id,
183
- application_id: message.applicationId ?? message.author.id,
184
- session_id: message.client.session_id,
185
- message_flags: message.flags.bitfield,
186
- data: {
187
- component_type: MessageComponentTypes.BUTTON,
188
- custom_id: this.customId,
189
- },
190
- };
191
- await message.client.api.interactions.post({
192
- data,
193
- });
194
- message.client._interactionCache.set(nonce, {
195
- channelId: message.channelId,
196
- guildId: message.guildId,
197
- metadata: data,
198
- });
199
- return new Promise((resolve, reject) => {
200
- const handler = data => {
201
- timeout.refresh();
202
- if (data.metadata?.nonce !== nonce) return;
203
- clearTimeout(timeout);
204
- message.client.removeListener('interactionResponse', handler);
205
- message.client.decrementMaxListeners();
206
- if (data.status) {
207
- resolve(data.metadata);
208
- } else {
209
- reject(
210
- new Error('INTERACTION_ERROR', {
211
- cause: data,
212
- }),
213
- );
214
- }
215
- };
216
- const timeout = setTimeout(() => {
217
- message.client.removeListener('interactionResponse', handler);
218
- message.client.decrementMaxListeners();
219
- reject(
220
- new Error('INTERACTION_TIMEOUT', {
221
- cause: data,
222
- }),
223
- );
224
- }, message.client.options.interactionTimeout).unref();
225
- message.client.incrementMaxListeners();
226
- message.client.on('interactionResponse', handler);
227
- });
228
- }
229
163
  }
230
164
 
231
165
  module.exports = MessageButton;
@@ -8,7 +8,7 @@ let deprecationEmittedForSetAuthor = false;
8
8
  let deprecationEmittedForSetFooter = false;
9
9
  let deprecationEmittedForAddField = false;
10
10
 
11
- // TODO: Remove the deprecated code for `setAuthor()`, `setFooter()` and `addField()`.
11
+ // TODO: Remove the deprecated code for `setAuthor()` and `setFooter()`.
12
12
 
13
13
  /**
14
14
  * Represents an embed in a message (image/video preview, rich embed, etc.)
@@ -211,12 +211,13 @@ class MessageMentions {
211
211
  */
212
212
  has(data, { ignoreDirect = false, ignoreRoles = false, ignoreRepliedUser = false, ignoreEveryone = false } = {}) {
213
213
  const user = this.client.users.resolve(data);
214
+
214
215
  if (!ignoreEveryone && user && this.everyone) return true;
215
216
 
216
217
  const userWasRepliedTo = user && this.repliedUser?.id === user.id;
217
218
 
218
219
  if (!ignoreRepliedUser && userWasRepliedTo && this.users.has(user.id)) return true;
219
- if (!ignoreRepliedUser && this.users.has(this.repliedUser?.id) && this.repliedUser?.id === user?.id) return true;
220
+
220
221
  if (!ignoreDirect) {
221
222
  if (user && (!ignoreRepliedUser || this.parsedUsers.has(user.id)) && this.users.has(user.id)) return true;
222
223
 
@@ -226,7 +227,7 @@ class MessageMentions {
226
227
  const channel = this.client.channels.resolve(data);
227
228
  if (channel && this.channels.has(channel.id)) return true;
228
229
  }
229
- if (user && !ignoreEveryone && this.everyone) return true;
230
+
230
231
  if (!ignoreRoles) {
231
232
  const member = this.guild?.members.resolve(data);
232
233
  if (member) {