djs-selfbot-v13 3.1.6 → 3.1.7

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 (148) hide show
  1. package/README.md +31 -16
  2. package/package.json +15 -8
  3. package/src/client/BaseClient.js +3 -2
  4. package/src/client/Client.js +539 -187
  5. package/src/client/actions/Action.js +13 -18
  6. package/src/client/actions/ActionsManager.js +1 -7
  7. package/src/client/actions/AutoModerationActionExecution.js +0 -1
  8. package/src/client/actions/AutoModerationRuleCreate.js +0 -1
  9. package/src/client/actions/AutoModerationRuleDelete.js +0 -1
  10. package/src/client/actions/AutoModerationRuleUpdate.js +0 -1
  11. package/src/client/actions/InteractionCreate.js +115 -0
  12. package/src/client/actions/MessageCreate.js +4 -0
  13. package/src/client/actions/PresenceUpdate.js +16 -17
  14. package/src/client/websocket/WebSocketManager.js +31 -11
  15. package/src/client/websocket/WebSocketShard.js +38 -39
  16. package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +23 -0
  17. package/src/client/websocket/handlers/CALL_CREATE.js +3 -3
  18. package/src/client/websocket/handlers/CALL_DELETE.js +2 -2
  19. package/src/client/websocket/handlers/CALL_UPDATE.js +2 -2
  20. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +13 -16
  21. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
  22. package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +11 -0
  23. package/src/client/websocket/handlers/GUILD_CREATE.js +0 -7
  24. package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +55 -0
  25. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
  26. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
  27. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
  28. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
  29. package/src/client/websocket/handlers/INTERACTION_CREATE.js +16 -0
  30. package/src/client/websocket/handlers/INTERACTION_FAILURE.js +18 -0
  31. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +0 -1
  32. package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +30 -0
  33. package/src/client/websocket/handlers/MESSAGE_ACK.js +16 -0
  34. package/src/client/websocket/handlers/READY.js +137 -47
  35. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +5 -7
  36. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +4 -6
  37. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +9 -32
  38. package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
  39. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +8 -2
  40. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
  41. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +5 -1
  42. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
  43. package/src/client/websocket/handlers/index.js +20 -15
  44. package/src/errors/Messages.js +69 -24
  45. package/src/index.js +43 -12
  46. package/src/managers/ApplicationCommandManager.js +12 -9
  47. package/src/managers/ApplicationCommandPermissionsManager.js +11 -3
  48. package/src/managers/ChannelManager.js +4 -2
  49. package/src/managers/ClientUserSettingManager.js +279 -161
  50. package/src/managers/DeveloperPortalManager.js +104 -0
  51. package/src/managers/GuildApplicationCommandManager.js +28 -0
  52. package/src/managers/GuildBanManager.js +1 -1
  53. package/src/managers/GuildChannelManager.js +0 -2
  54. package/src/managers/GuildFolderManager.js +24 -0
  55. package/src/managers/GuildForumThreadManager.js +28 -22
  56. package/src/managers/GuildMemberManager.js +216 -40
  57. package/src/managers/GuildSettingManager.js +15 -22
  58. package/src/managers/MessageManager.js +44 -42
  59. package/src/managers/PermissionOverwriteManager.js +1 -1
  60. package/src/managers/ReactionUserManager.js +5 -5
  61. package/src/managers/RelationshipManager.js +74 -81
  62. package/src/managers/SessionManager.js +57 -0
  63. package/src/managers/ThreadManager.js +45 -12
  64. package/src/managers/ThreadMemberManager.js +1 -1
  65. package/src/managers/UserManager.js +10 -6
  66. package/src/rest/APIRequest.js +20 -42
  67. package/src/rest/CaptchaSolver.js +132 -0
  68. package/src/rest/DiscordAPIError.js +16 -17
  69. package/src/rest/RESTManager.js +21 -1
  70. package/src/rest/RequestHandler.js +21 -35
  71. package/src/structures/ApplicationCommand.js +456 -19
  72. package/src/structures/ApplicationRoleConnectionMetadata.js +0 -3
  73. package/src/structures/AutoModerationRule.js +5 -5
  74. package/src/structures/AutocompleteInteraction.js +0 -1
  75. package/src/structures/BaseGuildTextChannel.js +12 -10
  76. package/src/structures/BaseGuildVoiceChannel.js +18 -16
  77. package/src/structures/{CallState.js → Call.js} +12 -17
  78. package/src/structures/CategoryChannel.js +0 -2
  79. package/src/structures/Channel.js +3 -2
  80. package/src/structures/ClientApplication.js +204 -0
  81. package/src/structures/ClientPresence.js +8 -12
  82. package/src/structures/ClientUser.js +336 -117
  83. package/src/structures/ContextMenuInteraction.js +1 -1
  84. package/src/structures/DMChannel.js +92 -29
  85. package/src/structures/DeveloperPortalApplication.js +520 -0
  86. package/src/structures/ForumChannel.js +10 -0
  87. package/src/structures/Guild.js +271 -135
  88. package/src/structures/GuildAuditLogs.js +5 -0
  89. package/src/structures/GuildChannel.js +2 -16
  90. package/src/structures/GuildFolder.js +75 -0
  91. package/src/structures/GuildMember.js +145 -27
  92. package/src/structures/Interaction.js +62 -1
  93. package/src/structures/InteractionResponse.js +114 -0
  94. package/src/structures/Invite.js +52 -35
  95. package/src/structures/Message.js +202 -222
  96. package/src/structures/MessageAttachment.js +0 -11
  97. package/src/structures/MessageButton.js +67 -1
  98. package/src/structures/MessageEmbed.js +1 -1
  99. package/src/structures/MessageMentions.js +2 -3
  100. package/src/structures/MessagePayload.js +46 -4
  101. package/src/structures/MessageReaction.js +1 -1
  102. package/src/structures/MessageSelectMenu.js +252 -1
  103. package/src/structures/Modal.js +180 -75
  104. package/src/structures/PartialGroupDMChannel.js +433 -0
  105. package/src/structures/Presence.js +2 -2
  106. package/src/structures/RichPresence.js +34 -14
  107. package/src/structures/Role.js +2 -18
  108. package/src/structures/SelectMenuInteraction.js +151 -2
  109. package/src/structures/Session.js +81 -0
  110. package/src/structures/Team.js +49 -0
  111. package/src/structures/TextInputComponent.js +70 -0
  112. package/src/structures/ThreadChannel.js +19 -0
  113. package/src/structures/User.js +345 -117
  114. package/src/structures/UserContextMenuInteraction.js +2 -2
  115. package/src/structures/VoiceState.js +39 -74
  116. package/src/structures/WebEmbed.js +52 -38
  117. package/src/structures/Webhook.js +11 -17
  118. package/src/structures/interfaces/Application.js +23 -146
  119. package/src/structures/interfaces/TextBasedChannel.js +256 -411
  120. package/src/util/ApplicationFlags.js +1 -1
  121. package/src/util/Constants.js +284 -106
  122. package/src/util/Formatters.js +2 -16
  123. package/src/util/LimitedCollection.js +1 -1
  124. package/src/util/Options.js +68 -48
  125. package/src/util/Permissions.js +0 -5
  126. package/src/util/PurchasedFlags.js +0 -2
  127. package/src/util/RemoteAuth.js +356 -221
  128. package/src/util/Sweepers.js +1 -1
  129. package/src/util/Util.js +36 -76
  130. package/src/util/Voice.js +1456 -0
  131. package/src/util/arRPC/index.js +229 -0
  132. package/src/util/arRPC/process/detectable.json +1 -0
  133. package/src/util/arRPC/process/index.js +102 -0
  134. package/src/util/arRPC/process/native/index.js +5 -0
  135. package/src/util/arRPC/process/native/linux.js +37 -0
  136. package/src/util/arRPC/process/native/win32.js +25 -0
  137. package/src/util/arRPC/transports/ipc.js +281 -0
  138. package/src/util/arRPC/transports/websocket.js +128 -0
  139. package/typings/enums.d.ts +73 -18
  140. package/typings/index.d.ts +1249 -897
  141. package/typings/rawDataTypes.d.ts +9 -68
  142. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +0 -78
  143. package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +0 -12
  144. package/src/managers/UserNoteManager.js +0 -53
  145. package/src/structures/GroupDMChannel.js +0 -387
  146. package/src/util/AttachmentFlags.js +0 -38
  147. package/src/util/InviteFlags.js +0 -29
  148. package/src/util/RoleFlags.js +0 -37
@@ -1,26 +1,22 @@
1
1
  'use strict';
2
2
 
3
3
  const process = require('node:process');
4
- const { setTimeout } = require('node:timers');
5
4
  const { Collection } = require('@discordjs/collection');
6
5
  const Base = require('./Base');
7
6
  const BaseMessageComponent = require('./BaseMessageComponent');
7
+ const ClientApplication = require('./ClientApplication');
8
+ const InteractionCollector = require('./InteractionCollector');
8
9
  const MessageAttachment = require('./MessageAttachment');
10
+ const MessageButton = require('./MessageButton');
9
11
  const Embed = require('./MessageEmbed');
10
12
  const Mentions = require('./MessageMentions');
11
13
  const MessagePayload = require('./MessagePayload');
14
+ const MessageSelectMenu = require('./MessageSelectMenu');
12
15
  const ReactionCollector = require('./ReactionCollector');
13
16
  const { Sticker } = require('./Sticker');
14
- const Application = require('./interfaces/Application');
15
17
  const { Error } = require('../errors');
16
18
  const ReactionManager = require('../managers/ReactionManager');
17
- const {
18
- InteractionTypes,
19
- MessageTypes,
20
- SystemMessageTypes,
21
- MessageComponentTypes,
22
- Events,
23
- } = require('../util/Constants');
19
+ const { InteractionTypes, MessageTypes, SystemMessageTypes, MaxBulkDeletableMessageAge } = require('../util/Constants');
24
20
  const MessageFlags = require('../util/MessageFlags');
25
21
  const Permissions = require('../util/Permissions');
26
22
  const SnowflakeUtil = require('../util/SnowflakeUtil');
@@ -260,9 +256,9 @@ class Message extends Base {
260
256
  if ('application' in data) {
261
257
  /**
262
258
  * Supplemental application information for group activities
263
- * @type {?Application}
259
+ * @type {?ClientApplication}
264
260
  */
265
- this.groupActivityApplication = new Application(this.client, data.application);
261
+ this.groupActivityApplication = new ClientApplication(this.client, data.application);
266
262
  } else {
267
263
  this.groupActivityApplication ??= null;
268
264
  }
@@ -537,6 +533,65 @@ class Message extends Base {
537
533
  });
538
534
  }
539
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
+
540
595
  /**
541
596
  * Whether the message is editable by the client user
542
597
  * @type {boolean}
@@ -598,7 +653,14 @@ class Message extends Base {
598
653
  * channel.bulkDelete(messages.filter(message => message.bulkDeletable));
599
654
  */
600
655
  get bulkDeletable() {
601
- return false;
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
+ );
602
664
  }
603
665
 
604
666
  /**
@@ -660,7 +722,7 @@ class Message extends Base {
660
722
  * @property {MessageAttachment[]} [attachments] An array of attachments to keep,
661
723
  * all attachments will be kept if omitted
662
724
  * @property {FileOptions[]|BufferResolvable[]|MessageAttachment[]} [files] Files to add to the message
663
- * @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
725
+ * @property {Array<(MessageActionRow|MessageActionRowOptions)>} [components]
664
726
  * Action rows containing interactive components for the message (buttons, select menus)
665
727
  */
666
728
 
@@ -730,7 +792,7 @@ class Message extends Base {
730
792
  /**
731
793
  * Adds a reaction to the message.
732
794
  * @param {EmojiIdentifierResolvable} emoji The emoji to react with
733
- * @param {boolean} [burst=false] Super Reactions
795
+ * @param {boolean} [burst=false] Super Reactions (Discord Nitro only)
734
796
  * @returns {Promise<MessageReaction>}
735
797
  * @example
736
798
  * // React to a message with a unicode emoji
@@ -749,9 +811,9 @@ class Message extends Base {
749
811
 
750
812
  return this.client.actions.MessageReactionAdd.handle(
751
813
  {
752
- [this.client.actions.injectedUser]: this.client.user,
753
- [this.client.actions.injectedChannel]: this.channel,
754
- [this.client.actions.injectedMessage]: this,
814
+ user: this.client.user,
815
+ channel: this.channel,
816
+ message: this,
755
817
  emoji: Util.resolvePartialEmoji(emoji),
756
818
  me_burst: burst,
757
819
  },
@@ -962,238 +1024,157 @@ class Message extends Base {
962
1024
  reactions: false,
963
1025
  });
964
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: 1,
1037
+ },
1038
+ });
1039
+ return true;
1040
+ }
965
1041
 
966
- // TypeScript
967
1042
  /**
968
- * Check data
969
- * @type {boolean}
970
- * @readonly
1043
+ * Marks the message as read.
1044
+ * @returns {Promise<boolean>}
971
1045
  */
972
- get isMessage() {
1046
+ async markRead() {
1047
+ await this.client.api.channels[this.channelId].messages[this.id].ack.post({
1048
+ data: {
1049
+ token: null,
1050
+ },
1051
+ });
973
1052
  return true;
974
1053
  }
975
1054
 
976
1055
  /**
977
- * Click specific button with X and Y
978
1056
  * @typedef {Object} MessageButtonLocation
979
- * @property {number} X Index of the row
980
- * @property {number} Y Index of the column
1057
+ * @property {number} row Index of the row
1058
+ * @property {number} col Index of the column
981
1059
  */
982
1060
 
983
1061
  /**
984
1062
  * Click specific button or automatically click first button if no button is specified.
985
- * @param {MessageButtonLocation|string|undefined} button button
986
- * @returns {Promise<Message|Modal>}
1063
+ * @param {MessageButton|MessageButtonLocation|string} button Button ID
1064
+ * @returns {Promise<InteractionResponse>}
987
1065
  * @example
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,
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
+ * }
1001
1080
  * });
1002
- * // Click button with customId (Ex button 5)
1003
- * message.clickButton('button5');
1004
- * // Click button 1
1005
- * message.clickButton();
1006
1081
  */
1007
1082
  clickButton(button) {
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];
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;
1016
1090
  }
1017
- button = button.toJSON();
1018
1091
  if (!button) throw 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
- });
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'));
1070
1094
  }
1071
-
1072
1095
  /**
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>}
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
+ * });
1077
1116
  */
1078
- selectMenu(menu, values = []) {
1079
- let selectMenu;
1080
- if (/[0-4]/.test(menu)) {
1081
- selectMenu = this.components[menu]?.components[0];
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];
1082
1123
  } else {
1083
- selectMenu = this.components
1124
+ const menuAll = this.components
1084
1125
  .flatMap(row => row.components)
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,
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),
1090
1135
  );
1091
- }
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
- }
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];
1118
1141
  }
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
- });
1142
+ }
1143
+ if (!menuID.type.includes('SELECT')) throw new TypeError('MENU_NOT_FOUND');
1144
+ return menuID.select(this, Array.isArray(menuID) ? menuID : options);
1172
1145
  }
1173
-
1146
+ //
1174
1147
  /**
1175
- * Marks the message as unread.
1176
- * @returns {Promise<void>}
1148
+ * Send context Menu v2
1149
+ * @param {Snowflake} botId Bot id
1150
+ * @param {string} commandName Command name in Context Menu
1151
+ * @returns {Promise<InteractionResponse>}
1177
1152
  */
1178
- markUnread() {
1179
- return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1180
- data: {
1181
- manual: true,
1182
- mention_count: 1,
1183
- },
1184
- });
1185
- }
1186
-
1187
- /**
1188
- * Marks the message as read.
1189
- * @returns {Promise<void>}
1190
- */
1191
- markRead() {
1192
- return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1193
- data: {
1194
- token: null,
1195
- },
1196
- });
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);
1197
1178
  }
1198
1179
 
1199
1180
  /**
@@ -1202,7 +1183,6 @@ class Message extends Base {
1202
1183
  * @param {Object} [elements={}] Metadata
1203
1184
  * @returns {Promise<{ report_id: Snowflake }>}
1204
1185
  * @example
1205
- * // GET https://discord.com/api/v9/reporting/menu/message?variant=4
1206
1186
  * // Report Category
1207
1187
  * // - <hidden>MESSAGE_WELCOME (3)</hidden>
1208
1188
  * // - Something else (28)
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const AttachmentFlags = require('../util/AttachmentFlags');
4
3
  const Util = require('../util/Util');
5
4
 
6
5
  /**
@@ -170,16 +169,6 @@ class MessageAttachment {
170
169
  } else {
171
170
  this.waveform ??= null;
172
171
  }
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
- }
183
172
  }
184
173
 
185
174
  /**
@@ -1,9 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ const { setTimeout } = require('node:timers');
3
4
  const BaseMessageComponent = require('./BaseMessageComponent');
4
5
  const { RangeError } = require('../errors');
5
- const { MessageButtonStyles, MessageComponentTypes } = require('../util/Constants');
6
+ const { MessageButtonStyles, MessageComponentTypes, InteractionTypes } = require('../util/Constants');
7
+ const SnowflakeUtil = require('../util/SnowflakeUtil');
6
8
  const Util = require('../util/Util');
9
+ const { lazy } = require('../util/Util');
10
+ const Message = lazy(() => require('../structures/Message').Message);
7
11
 
8
12
  /**
9
13
  * Represents a button message component.
@@ -160,6 +164,68 @@ class MessageButton extends BaseMessageComponent {
160
164
  static resolveStyle(style) {
161
165
  return typeof style === 'string' ? style : MessageButtonStyles[style];
162
166
  }
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
+ }
163
229
  }
164
230
 
165
231
  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()` and `setFooter()`.
11
+ // TODO: Remove the deprecated code for `setAuthor()`, `setFooter()` and `addField()`.
12
12
 
13
13
  /**
14
14
  * Represents an embed in a message (image/video preview, rich embed, etc.)
@@ -211,13 +211,12 @@ 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
-
215
214
  if (!ignoreEveryone && user && this.everyone) return true;
216
215
 
217
216
  const userWasRepliedTo = user && this.repliedUser?.id === user.id;
218
217
 
219
218
  if (!ignoreRepliedUser && userWasRepliedTo && this.users.has(user.id)) return true;
220
-
219
+ if (!ignoreRepliedUser && this.users.has(this.repliedUser?.id) && this.repliedUser?.id === user?.id) return true;
221
220
  if (!ignoreDirect) {
222
221
  if (user && (!ignoreRepliedUser || this.parsedUsers.has(user.id)) && this.users.has(user.id)) return true;
223
222
 
@@ -227,7 +226,7 @@ class MessageMentions {
227
226
  const channel = this.client.channels.resolve(data);
228
227
  if (channel && this.channels.has(channel.id)) return true;
229
228
  }
230
-
229
+ if (user && !ignoreEveryone && this.everyone) return true;
231
230
  if (!ignoreRoles) {
232
231
  const member = this.guild?.members.resolve(data);
233
232
  if (member) {