djs-selfbot-v13 3.1.7 → 3.2.2

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 (155) hide show
  1. package/README.md +18 -35
  2. package/package.json +85 -100
  3. package/src/client/BaseClient.js +3 -4
  4. package/src/client/Client.js +249 -530
  5. package/src/client/actions/Action.js +18 -13
  6. package/src/client/actions/ActionsManager.js +7 -1
  7. package/src/client/actions/AutoModerationActionExecution.js +1 -0
  8. package/src/client/actions/AutoModerationRuleCreate.js +1 -0
  9. package/src/client/actions/AutoModerationRuleDelete.js +1 -0
  10. package/src/client/actions/AutoModerationRuleUpdate.js +1 -0
  11. package/src/client/actions/GuildMemberRemove.js +0 -1
  12. package/src/client/actions/GuildMemberUpdate.js +0 -1
  13. package/src/client/actions/MessageCreate.js +0 -4
  14. package/src/client/actions/PresenceUpdate.js +17 -16
  15. package/src/client/websocket/WebSocketManager.js +11 -31
  16. package/src/client/websocket/WebSocketShard.js +39 -38
  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 +16 -13
  21. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
  22. package/src/client/websocket/handlers/GUILD_CREATE.js +19 -13
  23. package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +0 -1
  24. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +1 -0
  25. package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_ADD.js +22 -0
  26. package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_REMOVE.js +12 -0
  27. package/src/client/websocket/handlers/READY.js +90 -140
  28. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +7 -5
  29. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +7 -5
  30. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +32 -9
  31. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +2 -8
  32. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
  33. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +78 -0
  34. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +1 -5
  35. package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +12 -0
  36. package/src/client/websocket/handlers/index.js +17 -20
  37. package/src/errors/Messages.js +25 -69
  38. package/src/index.js +13 -43
  39. package/src/managers/ApplicationCommandManager.js +9 -12
  40. package/src/managers/ApplicationCommandPermissionsManager.js +3 -11
  41. package/src/managers/ChannelManager.js +2 -3
  42. package/src/managers/ClientUserSettingManager.js +162 -280
  43. package/src/managers/GuildBanManager.js +47 -1
  44. package/src/managers/GuildChannelManager.js +2 -16
  45. package/src/managers/GuildForumThreadManager.js +24 -30
  46. package/src/managers/GuildManager.js +1 -1
  47. package/src/managers/GuildMemberManager.js +50 -222
  48. package/src/managers/GuildSettingManager.js +22 -15
  49. package/src/managers/MessageManager.js +42 -44
  50. package/src/managers/PermissionOverwriteManager.js +1 -1
  51. package/src/managers/ReactionUserManager.js +5 -5
  52. package/src/managers/RelationshipManager.js +83 -76
  53. package/src/managers/ThreadManager.js +12 -45
  54. package/src/managers/ThreadMemberManager.js +1 -1
  55. package/src/managers/UserManager.js +6 -10
  56. package/src/managers/UserNoteManager.js +53 -0
  57. package/src/rest/APIRequest.js +48 -20
  58. package/src/rest/DiscordAPIError.js +17 -16
  59. package/src/rest/RESTManager.js +1 -21
  60. package/src/rest/RequestHandler.js +35 -21
  61. package/src/structures/ApplicationCommand.js +19 -456
  62. package/src/structures/ApplicationRoleConnectionMetadata.js +3 -0
  63. package/src/structures/AutoModerationRule.js +5 -5
  64. package/src/structures/AutocompleteInteraction.js +1 -0
  65. package/src/structures/BaseGuildTextChannel.js +10 -12
  66. package/src/structures/BaseGuildVoiceChannel.js +16 -18
  67. package/src/structures/{Call.js → CallState.js} +17 -12
  68. package/src/structures/CategoryChannel.js +2 -0
  69. package/src/structures/Channel.js +2 -3
  70. package/src/structures/ClientPresence.js +20 -19
  71. package/src/structures/ClientUser.js +117 -338
  72. package/src/structures/ContextMenuInteraction.js +1 -1
  73. package/src/structures/DMChannel.js +29 -92
  74. package/src/structures/ForumChannel.js +0 -10
  75. package/src/structures/GroupDMChannel.js +387 -0
  76. package/src/structures/Guild.js +135 -271
  77. package/src/structures/GuildAuditLogs.js +0 -5
  78. package/src/structures/GuildChannel.js +16 -2
  79. package/src/structures/GuildMember.js +27 -145
  80. package/src/structures/Interaction.js +1 -62
  81. package/src/structures/Invite.js +35 -52
  82. package/src/structures/Message.js +220 -203
  83. package/src/structures/MessageAttachment.js +11 -0
  84. package/src/structures/MessageButton.js +1 -67
  85. package/src/structures/MessageEmbed.js +1 -1
  86. package/src/structures/MessageMentions.js +3 -2
  87. package/src/structures/MessagePayload.js +6 -46
  88. package/src/structures/MessagePoll.js +238 -0
  89. package/src/structures/MessageReaction.js +1 -1
  90. package/src/structures/MessageSelectMenu.js +1 -252
  91. package/src/structures/Modal.js +70 -188
  92. package/src/structures/Presence.js +787 -129
  93. package/src/structures/Role.js +18 -2
  94. package/src/structures/SelectMenuInteraction.js +2 -151
  95. package/src/structures/Team.js +0 -49
  96. package/src/structures/TextInputComponent.js +0 -70
  97. package/src/structures/ThreadChannel.js +0 -19
  98. package/src/structures/User.js +145 -339
  99. package/src/structures/UserContextMenuInteraction.js +2 -2
  100. package/src/structures/VoiceState.js +74 -39
  101. package/src/structures/WebEmbed.js +38 -52
  102. package/src/structures/Webhook.js +17 -11
  103. package/src/structures/interfaces/Application.js +146 -23
  104. package/src/structures/interfaces/TextBasedChannel.js +409 -256
  105. package/src/util/ApplicationFlags.js +1 -1
  106. package/src/util/AttachmentFlags.js +38 -0
  107. package/src/util/Constants.js +120 -285
  108. package/src/util/Formatters.js +16 -2
  109. package/src/util/InviteFlags.js +29 -0
  110. package/src/util/LimitedCollection.js +1 -1
  111. package/src/util/Options.js +48 -74
  112. package/src/util/Permissions.js +15 -0
  113. package/src/util/PurchasedFlags.js +2 -0
  114. package/src/util/RemoteAuth.js +221 -356
  115. package/src/util/RoleFlags.js +37 -0
  116. package/src/util/Sweepers.js +1 -1
  117. package/src/util/Util.js +158 -32
  118. package/typings/enums.d.ts +24 -73
  119. package/typings/index.d.ts +978 -1288
  120. package/typings/rawDataTypes.d.ts +68 -9
  121. package/src/client/actions/InteractionCreate.js +0 -115
  122. package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +0 -23
  123. package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +0 -11
  124. package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +0 -55
  125. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
  126. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
  127. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
  128. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
  129. package/src/client/websocket/handlers/INTERACTION_CREATE.js +0 -16
  130. package/src/client/websocket/handlers/INTERACTION_FAILURE.js +0 -18
  131. package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +0 -30
  132. package/src/client/websocket/handlers/MESSAGE_ACK.js +0 -16
  133. package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
  134. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
  135. package/src/managers/DeveloperPortalManager.js +0 -104
  136. package/src/managers/GuildApplicationCommandManager.js +0 -28
  137. package/src/managers/GuildFolderManager.js +0 -24
  138. package/src/managers/SessionManager.js +0 -57
  139. package/src/rest/CaptchaSolver.js +0 -132
  140. package/src/structures/ClientApplication.js +0 -204
  141. package/src/structures/DeveloperPortalApplication.js +0 -520
  142. package/src/structures/GuildFolder.js +0 -75
  143. package/src/structures/InteractionResponse.js +0 -114
  144. package/src/structures/PartialGroupDMChannel.js +0 -433
  145. package/src/structures/RichPresence.js +0 -722
  146. package/src/structures/Session.js +0 -81
  147. package/src/util/Voice.js +0 -1456
  148. package/src/util/arRPC/index.js +0 -229
  149. package/src/util/arRPC/process/detectable.json +0 -1
  150. package/src/util/arRPC/process/index.js +0 -102
  151. package/src/util/arRPC/process/native/index.js +0 -5
  152. package/src/util/arRPC/process/native/linux.js +0 -37
  153. package/src/util/arRPC/process/native/win32.js +0 -25
  154. package/src/util/arRPC/transports/ipc.js +0 -281
  155. package/src/util/arRPC/transports/websocket.js +0 -128
@@ -4,19 +4,17 @@ const process = require('node:process');
4
4
  const { Collection } = require('@discordjs/collection');
5
5
  const Base = require('./Base');
6
6
  const BaseMessageComponent = require('./BaseMessageComponent');
7
- const ClientApplication = require('./ClientApplication');
8
- const InteractionCollector = require('./InteractionCollector');
9
7
  const MessageAttachment = require('./MessageAttachment');
10
- const MessageButton = require('./MessageButton');
11
8
  const Embed = require('./MessageEmbed');
12
9
  const Mentions = require('./MessageMentions');
13
10
  const MessagePayload = require('./MessagePayload');
14
- const MessageSelectMenu = require('./MessageSelectMenu');
11
+ const MessagePoll = require('./MessagePoll');
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 { InteractionTypes, MessageTypes, SystemMessageTypes, MessageComponentTypes } = require('../util/Constants');
20
18
  const MessageFlags = require('../util/MessageFlags');
21
19
  const Permissions = require('../util/Permissions');
22
20
  const SnowflakeUtil = require('../util/SnowflakeUtil');
@@ -253,12 +251,22 @@ class Message extends Base {
253
251
  this.webhookId ??= null;
254
252
  }
255
253
 
254
+ /**
255
+ * A poll!
256
+ * @type {?MessagePoll}
257
+ */
258
+ if ('poll' in data) {
259
+ this.poll = new MessagePoll(data.poll, this.client);
260
+ } else {
261
+ this.poll = null;
262
+ }
263
+
256
264
  if ('application' in data) {
257
265
  /**
258
266
  * Supplemental application information for group activities
259
- * @type {?ClientApplication}
267
+ * @type {?Application}
260
268
  */
261
- this.groupActivityApplication = new ClientApplication(this.client, data.application);
269
+ this.groupActivityApplication = new Application(this.client, data.application);
262
270
  } else {
263
271
  this.groupActivityApplication ??= null;
264
272
  }
@@ -533,65 +541,6 @@ class Message extends Base {
533
541
  });
534
542
  }
535
543
 
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
544
  /**
596
545
  * Whether the message is editable by the client user
597
546
  * @type {boolean}
@@ -653,14 +602,7 @@ class Message extends Base {
653
602
  * channel.bulkDelete(messages.filter(message => message.bulkDeletable));
654
603
  */
655
604
  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
- );
605
+ return false;
664
606
  }
665
607
 
666
608
  /**
@@ -722,7 +664,7 @@ class Message extends Base {
722
664
  * @property {MessageAttachment[]} [attachments] An array of attachments to keep,
723
665
  * all attachments will be kept if omitted
724
666
  * @property {FileOptions[]|BufferResolvable[]|MessageAttachment[]} [files] Files to add to the message
725
- * @property {Array<(MessageActionRow|MessageActionRowOptions)>} [components]
667
+ * @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
726
668
  * Action rows containing interactive components for the message (buttons, select menus)
727
669
  */
728
670
 
@@ -792,7 +734,7 @@ class Message extends Base {
792
734
  /**
793
735
  * Adds a reaction to the message.
794
736
  * @param {EmojiIdentifierResolvable} emoji The emoji to react with
795
- * @param {boolean} [burst=false] Super Reactions (Discord Nitro only)
737
+ * @param {boolean} [burst=false] Super Reactions
796
738
  * @returns {Promise<MessageReaction>}
797
739
  * @example
798
740
  * // React to a message with a unicode emoji
@@ -811,9 +753,9 @@ class Message extends Base {
811
753
 
812
754
  return this.client.actions.MessageReactionAdd.handle(
813
755
  {
814
- user: this.client.user,
815
- channel: this.channel,
816
- message: this,
756
+ [this.client.actions.injectedUser]: this.client.user,
757
+ [this.client.actions.injectedChannel]: this.channel,
758
+ [this.client.actions.injectedMessage]: this,
817
759
  emoji: Util.resolvePartialEmoji(emoji),
818
760
  me_burst: burst,
819
761
  },
@@ -908,6 +850,55 @@ class Message extends Base {
908
850
  return this.channel.threads.create({ ...options, startMessage: this });
909
851
  }
910
852
 
853
+ /**
854
+ * Submits a poll vote for the current user. Returns a 204 empty response on success.
855
+ * @param {...number[]} ids ID of the answer
856
+ * @returns {Promise<void>}
857
+ * @example
858
+ * // Vote multi choices
859
+ * message.vote(1,2);
860
+ * // Remove vote
861
+ * message.vote();
862
+ */
863
+ vote(...ids) {
864
+ return this.client.api
865
+ .channels(this.channel.id)
866
+ .polls(this.id)
867
+ .answers['@me'].put({
868
+ data: {
869
+ answer_ids: ids.flat(1).map(value => value.toString()),
870
+ },
871
+ });
872
+ }
873
+
874
+ /**
875
+ * Immediately ends the poll. You cannot end polls from other users.
876
+ * @returns {Promise<RawMessage>}
877
+ */
878
+ endPoll() {
879
+ return this.client.api.channels(this.channel.id).polls(this.id).expire.post();
880
+ }
881
+
882
+ /**
883
+ * Get a list of users that voted for this specific answer.
884
+ * @param {number} answerId Answer Id
885
+ * @param {Snowflake} [afterUserId] Get users after this user ID
886
+ * @param {number} [limit=25] Max number of users to return (1-100, default 25)
887
+ * @returns {Promise<{ users: Partial<RawUser> }>}
888
+ */
889
+ getAnswerVoter(answerId, afterUserId, limit = 25) {
890
+ return this.client.api
891
+ .channels(this.channel.id)
892
+ .polls(this.id)
893
+ .answers(answerId)
894
+ .get({
895
+ query: {
896
+ after: afterUserId,
897
+ limit,
898
+ },
899
+ });
900
+ }
901
+
911
902
  /**
912
903
  * Fetch this message.
913
904
  * @param {boolean} [force=true] Whether to skip the cache check and request the API
@@ -1024,157 +1015,182 @@ class Message extends Base {
1024
1015
  reactions: false,
1025
1016
  });
1026
1017
  }
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
1018
 
1019
+ // TypeScript
1042
1020
  /**
1043
- * Marks the message as read.
1044
- * @returns {Promise<boolean>}
1021
+ * Check data
1022
+ * @type {boolean}
1023
+ * @readonly
1045
1024
  */
1046
- async markRead() {
1047
- await this.client.api.channels[this.channelId].messages[this.id].ack.post({
1048
- data: {
1049
- token: null,
1050
- },
1051
- });
1025
+ get isMessage() {
1052
1026
  return true;
1053
1027
  }
1054
1028
 
1055
1029
  /**
1030
+ * Click specific button with X and Y
1056
1031
  * @typedef {Object} MessageButtonLocation
1057
- * @property {number} row Index of the row
1058
- * @property {number} col Index of the column
1032
+ * @property {number} X Index of the row
1033
+ * @property {number} Y Index of the column
1059
1034
  */
1060
1035
 
1061
1036
  /**
1062
1037
  * 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>}
1038
+ * @param {MessageButtonLocation|string|undefined} button button
1039
+ * @returns {Promise<Message|Modal>}
1065
1040
  * @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
- * }
1041
+ * // Demo msg
1042
+ * Some content
1043
+ * ――――――――――――――――――――――――――――――――> X from 0
1044
+ * [button1] [button2] [button3]
1045
+ * [button4] [button5] [button6]
1046
+ *
1047
+ * Y from 0
1048
+ * // Click button6 with X and Y
1049
+ * [0,0] [1,0] [2,0]
1050
+ * [0,1] [1,1] [2,1]
1051
+ * // Code
1052
+ * message.clickButton({
1053
+ * X: 2, Y: 1,
1080
1054
  * });
1055
+ * // Click button with customId (Ex button 5)
1056
+ * message.clickButton('button5');
1057
+ * // Click button 1
1058
+ * message.clickButton();
1081
1059
  */
1082
1060
  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;
1061
+ if (typeof button == 'undefined') {
1062
+ button = this.components
1063
+ .flatMap(row => row.components)
1064
+ .find(b => b.type === 'BUTTON' && b.customId && !b.disabled);
1065
+ } else if (typeof button == 'string') {
1066
+ button = this.components.flatMap(row => row.components).find(b => b.type === 'BUTTON' && b.customId == button);
1067
+ } else {
1068
+ button = this.components[button.Y]?.components[button.X];
1090
1069
  }
1091
1070
  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'));
1071
+ button = button.toJSON();
1072
+ if (!button.custom_id || button.disabled) throw new TypeError('BUTTON_CANNOT_CLICK');
1073
+ const nonce = SnowflakeUtil.generate();
1074
+ const data = {
1075
+ type: InteractionTypes.MESSAGE_COMPONENT,
1076
+ nonce,
1077
+ guild_id: this.guildId,
1078
+ channel_id: this.channelId,
1079
+ message_id: this.id,
1080
+ application_id: this.applicationId ?? this.author.id,
1081
+ session_id: this.client.sessionId,
1082
+ message_flags: this.flags.bitfield,
1083
+ data: {
1084
+ component_type: MessageComponentTypes.BUTTON,
1085
+ custom_id: button.custom_id,
1086
+ },
1087
+ };
1088
+ this.client.api.interactions.post({
1089
+ data,
1090
+ });
1091
+ return Util.createPromiseInteraction(this.client, nonce, 5_000, true, this);
1094
1092
  }
1093
+
1095
1094
  /**
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
- * });
1095
+ * Select specific menu
1096
+ * @param {number|string} menu Target
1097
+ * @param {Array<UserResolvable | RoleResolvable | ChannelResolvable | string>} values Any value
1098
+ * @returns {Promise<Message|Modal>}
1116
1099
  */
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];
1123
- } else {
1124
- const menuAll = this.components
1100
+ selectMenu(menu, values = []) {
1101
+ let selectMenu = menu;
1102
+ if (/[0-4]/.test(menu)) {
1103
+ selectMenu = this.components[menu]?.components[0];
1104
+ } else if (typeof menu == 'string') {
1105
+ selectMenu = this.components
1125
1106
  .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),
1107
+ .find(
1108
+ b =>
1109
+ ['STRING_SELECT', 'USER_SELECT', 'ROLE_SELECT', 'MENTIONABLE_SELECT', 'CHANNEL_SELECT'].includes(b.type) &&
1110
+ b.customId == menu &&
1111
+ !b.disabled,
1135
1112
  );
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
1113
  }
1143
- if (!menuID.type.includes('SELECT')) throw new TypeError('MENU_NOT_FOUND');
1144
- return menuID.select(this, Array.isArray(menuID) ? menuID : options);
1114
+ if (values.length < selectMenu.minValues) {
1115
+ throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${selectMenu.minValues}`);
1116
+ }
1117
+ if (values.length > selectMenu?.maxValues) {
1118
+ throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${selectMenu.maxValues}`);
1119
+ }
1120
+ values = values.map(value => {
1121
+ switch (selectMenu.type) {
1122
+ case 'STRING_SELECT': {
1123
+ return selectMenu.options.find(obj => obj.value === value || obj.label === value).value;
1124
+ }
1125
+ case 'USER_SELECT': {
1126
+ return this.client.users.resolveId(value);
1127
+ }
1128
+ case 'ROLE_SELECT': {
1129
+ return this.guild.roles.resolveId(value);
1130
+ }
1131
+ case 'MENTIONABLE_SELECT': {
1132
+ return this.client.users.resolveId(value) || this.guild.roles.resolveId(value);
1133
+ }
1134
+ case 'CHANNEL_SELECT': {
1135
+ return this.client.channels.resolveId(value);
1136
+ }
1137
+ default: {
1138
+ return value;
1139
+ }
1140
+ }
1141
+ });
1142
+ const nonce = SnowflakeUtil.generate();
1143
+ const data = {
1144
+ type: InteractionTypes.MESSAGE_COMPONENT,
1145
+ guild_id: this.guildId,
1146
+ channel_id: this.channelId,
1147
+ message_id: this.id,
1148
+ application_id: this.applicationId ?? this.author.id,
1149
+ session_id: this.client.sessionId,
1150
+ message_flags: this.flags.bitfield,
1151
+ data: {
1152
+ component_type: MessageComponentTypes[selectMenu.type],
1153
+ custom_id: selectMenu.customId,
1154
+ type: MessageComponentTypes[selectMenu.type],
1155
+ values,
1156
+ },
1157
+ nonce,
1158
+ };
1159
+ this.client.api.interactions.post({
1160
+ data,
1161
+ });
1162
+ return Util.createPromiseInteraction(this.client, nonce, 5_000, true, this);
1145
1163
  }
1146
- //
1164
+
1147
1165
  /**
1148
- * Send context Menu v2
1149
- * @param {Snowflake} botId Bot id
1150
- * @param {string} commandName Command name in Context Menu
1151
- * @returns {Promise<InteractionResponse>}
1166
+ * Marks the message as unread.
1167
+ * @returns {Promise<void>}
1152
1168
  */
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);
1169
+ markUnread() {
1170
+ return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1171
+ data: {
1172
+ manual: true,
1173
+ mention_count:
1174
+ this.mentions.everyone ||
1175
+ this.mentions.repliedUser?.id === this.client.user.id ||
1176
+ this.mentions.users.has(this.client.user.id) ||
1177
+ (this.guildId && this.mentions.roles.some(r => this.guild.members.me._roles?.includes(r.id)))
1178
+ ? 1
1179
+ : 1,
1180
+ },
1181
+ });
1182
+ }
1183
+
1184
+ /**
1185
+ * Marks the message as read.
1186
+ * @returns {Promise<void>}
1187
+ */
1188
+ markRead() {
1189
+ return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1190
+ data: {
1191
+ token: null,
1192
+ },
1193
+ });
1178
1194
  }
1179
1195
 
1180
1196
  /**
@@ -1183,6 +1199,7 @@ class Message extends Base {
1183
1199
  * @param {Object} [elements={}] Metadata
1184
1200
  * @returns {Promise<{ report_id: Snowflake }>}
1185
1201
  * @example
1202
+ * // GET https://discord.com/api/v9/reporting/menu/message?variant=4
1186
1203
  * // Report Category
1187
1204
  * // - <hidden>MESSAGE_WELCOME (3)</hidden>
1188
1205
  * // - 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) {