djs-selfbot-v13 3.1.8 → 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 (43) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +18 -8
  3. package/package.json +85 -71
  4. package/src/client/BaseClient.js +1 -1
  5. package/src/client/Client.js +81 -10
  6. package/src/client/actions/GuildMemberRemove.js +0 -1
  7. package/src/client/actions/GuildMemberUpdate.js +0 -1
  8. package/src/client/websocket/WebSocketShard.js +3 -3
  9. package/src/client/websocket/handlers/GUILD_CREATE.js +13 -14
  10. package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +0 -1
  11. package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_ADD.js +22 -0
  12. package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_REMOVE.js +12 -0
  13. package/src/client/websocket/handlers/READY.js +61 -21
  14. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +1 -1
  15. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +1 -1
  16. package/src/client/websocket/handlers/index.js +2 -0
  17. package/src/errors/Messages.js +1 -0
  18. package/src/index.js +4 -3
  19. package/src/managers/ChannelManager.js +1 -1
  20. package/src/managers/ClientUserSettingManager.js +2 -2
  21. package/src/managers/GuildBanManager.js +46 -0
  22. package/src/managers/GuildChannelManager.js +0 -16
  23. package/src/managers/GuildForumThreadManager.js +3 -3
  24. package/src/managers/GuildManager.js +1 -1
  25. package/src/managers/GuildMemberManager.js +11 -7
  26. package/src/managers/RelationshipManager.js +3 -3
  27. package/src/rest/APIRequest.js +13 -7
  28. package/src/structures/ClientPresence.js +9 -12
  29. package/src/structures/ClientUser.js +0 -2
  30. package/src/structures/Message.js +67 -76
  31. package/src/structures/MessagePayload.js +2 -0
  32. package/src/structures/MessagePoll.js +238 -0
  33. package/src/structures/Modal.js +11 -24
  34. package/src/structures/Presence.js +786 -128
  35. package/src/structures/User.js +35 -1
  36. package/src/structures/interfaces/TextBasedChannel.js +21 -23
  37. package/src/util/Constants.js +17 -4
  38. package/src/util/Options.js +1 -7
  39. package/src/util/Permissions.js +10 -0
  40. package/src/util/Util.js +88 -2
  41. package/typings/enums.d.ts +7 -1
  42. package/typings/index.d.ts +112 -70
  43. package/src/structures/RichPresence.js +0 -702
package/src/index.js CHANGED
@@ -150,9 +150,10 @@ exports.WelcomeScreen = require('./structures/WelcomeScreen');
150
150
 
151
151
  exports.WebSocket = require('./WebSocket');
152
152
 
153
- exports.CustomStatus = require('./structures/RichPresence').CustomStatus;
154
- exports.RichPresence = require('./structures/RichPresence').RichPresence;
155
- exports.SpotifyRPC = require('./structures/RichPresence').SpotifyRPC;
153
+ exports.CustomStatus = require('./structures/Presence').CustomStatus;
154
+ exports.RichPresence = require('./structures/Presence').RichPresence;
155
+ exports.SpotifyRPC = require('./structures/Presence').SpotifyRPC;
156
156
  exports.WebEmbed = require('./structures/WebEmbed');
157
157
  exports.DiscordAuthWebsocket = require('./util/RemoteAuth');
158
158
  exports.PurchasedFlags = require('./util/PurchasedFlags');
159
+ exports.MessagePoll = require('./structures/MessagePoll');
@@ -127,7 +127,7 @@ class ChannelManager extends CachedManager {
127
127
  recipients = recipients
128
128
  .map(r => this.client.users.resolveId(r))
129
129
  .filter(r => r && this.client.relationships.cache.get(r) == RelationshipTypes.FRIEND);
130
- if (recipients.length < 1 || recipients.length > 9) throw new Error('Invalid Users length (1 - 9)');
130
+ if (recipients.length > 9) throw new Error('Invalid Users length (2 - 9)');
131
131
  const data = await this.client.api.users['@me'].channels.post({
132
132
  data: { recipients },
133
133
  });
@@ -3,7 +3,7 @@
3
3
  const { Collection } = require('@discordjs/collection');
4
4
  const BaseManager = require('./BaseManager');
5
5
  const { TypeError } = require('../errors/DJSError');
6
- const { CustomStatus } = require('../structures/RichPresence');
6
+ const { CustomStatus } = require('../structures/Presence');
7
7
  const { ActivityTypes } = require('../util/Constants');
8
8
 
9
9
  /**
@@ -189,7 +189,7 @@ class ClientUserSettingManager extends BaseManager {
189
189
  a => ![ActivityTypes.CUSTOM, 'CUSTOM'].includes(a.type),
190
190
  );
191
191
  if (data.custom_status) {
192
- const custom = new CustomStatus();
192
+ const custom = new CustomStatus(this.client);
193
193
  custom.setState(data.custom_status.text);
194
194
  let emoji;
195
195
  if (data.custom_status.emoji_id) {
@@ -199,6 +199,52 @@ class GuildBanManager extends CachedManager {
199
199
  await this.client.api.guilds(this.guild.id).bans(id).delete({ reason });
200
200
  return this.client.users.resolve(user);
201
201
  }
202
+
203
+
204
+ /**
205
+ * Options used for bulk banning users from a guild.
206
+ * @typedef {Object} BulkBanOptions
207
+ * @property {number} [deleteMessageSeconds] Number of seconds of messages to delete,
208
+ * must be between 0 and 604800 (7 days), inclusive
209
+ * @property {string} [reason] The reason for the bans
210
+ */
211
+
212
+ /**
213
+ * Result of bulk banning users from a guild.
214
+ * @typedef {Object} BulkBanResult
215
+ * @property {Snowflake[]} bannedUsers IDs of the banned users
216
+ * @property {Snowflake[]} failedUsers IDs of the users that could not be banned or were already banned
217
+ */
218
+
219
+ /**
220
+ * Bulk ban users from a guild, and optionally delete previous messages sent by them.
221
+ * @param {Collection<Snowflake, UserResolvable>|UserResolvable[]} users The users to ban
222
+ * @param {BulkBanOptions} [options] The options for bulk banning users
223
+ * @returns {Promise<BulkBanResult>} Returns an object with `bannedUsers` key containing the IDs of the banned users
224
+ * and the key `failedUsers` with the IDs that could not be banned or were already banned.
225
+ * @example
226
+ * // Bulk ban users by ids (or with user/guild member objects) and delete all their messages from the past 7 days
227
+ * guild.bans.bulkCreate(['84484653687267328'], { deleteMessageSeconds: 7 * 24 * 60 * 60 })
228
+ * .then(result => {
229
+ * console.log(`Banned ${result.bannedUsers.length} users, failed to ban ${result.failedUsers.length} users.`)
230
+ * })
231
+ * .catch(console.error);
232
+ */
233
+ async bulkCreate(users, options = {}) {
234
+ if (!users || !(Array.isArray(users) || users instanceof Collection)) {
235
+ throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'users', 'Array or Collection of UserResolvable', true);
236
+ }
237
+ if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);
238
+
239
+ const userIds = users.map(user => this.client.users.resolveId(user));
240
+ if (userIds.length === 0) throw new DiscordjsError(ErrorCodes.BulkBanUsersOptionEmpty);
241
+
242
+ const result = await this.client.rest.post(Routes.guildBulkBan(this.guild.id), {
243
+ body: { delete_message_seconds: options.deleteMessageSeconds, user_ids: userIds },
244
+ reason: options.reason,
245
+ });
246
+ return { bannedUsers: result.banned_users, failedUsers: result.failed_users };
247
+ }
202
248
  }
203
249
 
204
250
  module.exports = GuildBanManager;
@@ -3,7 +3,6 @@
3
3
  const process = require('node:process');
4
4
  const { Collection } = require('@discordjs/collection');
5
5
  const CachedManager = require('./CachedManager');
6
- const ThreadManager = require('./ThreadManager');
7
6
  const { Error, TypeError } = require('../errors');
8
7
  const GuildChannel = require('../structures/GuildChannel');
9
8
  const PermissionOverwrites = require('../structures/PermissionOverwrites');
@@ -468,21 +467,6 @@ class GuildChannelManager extends CachedManager {
468
467
  }).guild;
469
468
  }
470
469
 
471
- /**
472
- * Obtains all active thread channels in the guild from Discord
473
- * @param {boolean} [cache=true] Whether to cache the fetched data
474
- * @returns {Promise<FetchedThreads>}
475
- * @example
476
- * // Fetch all threads from the guild
477
- * message.guild.channels.fetchActiveThreads()
478
- * .then(fetched => console.log(`There are ${fetched.threads.size} threads.`))
479
- * .catch(console.error);
480
- */
481
- async fetchActiveThreads(cache = true) {
482
- const raw = await this.client.api.guilds(this.guild.id).threads.active.get();
483
- return ThreadManager._mapThreads(raw, this.client, { guild: this.guild, cache });
484
- }
485
-
486
470
  /**
487
471
  * Deletes the channel.
488
472
  * @param {GuildChannelResolvable} channel The channel to delete
@@ -85,23 +85,23 @@ class GuildForumThreadManager extends ThreadManager {
85
85
  });
86
86
  const attachmentsData = await Promise.all(requestPromises);
87
87
  attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
88
- data.attachments = attachmentsData;
89
88
 
90
89
  if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild);
91
90
 
92
- const data = await this.client.api.channels(this.channel.id).threads.post({
91
+ const post_data = await this.client.api.channels(this.channel.id).threads.post({
93
92
  data: {
94
93
  name,
95
94
  auto_archive_duration: autoArchiveDuration,
96
95
  rate_limit_per_user: rateLimitPerUser,
97
96
  applied_tags: appliedTags,
98
97
  message: body,
98
+ attachments: attachmentsData,
99
99
  },
100
100
  files: [],
101
101
  reason,
102
102
  });
103
103
 
104
- return this.client.actions.ThreadCreate.handle(data).thread;
104
+ return this.client.actions.ThreadCreate.handle(post_data).thread;
105
105
  }
106
106
  }
107
107
 
@@ -162,7 +162,6 @@ class GuildManager extends CachedManager {
162
162
 
163
163
  /**
164
164
  * Creates a guild.
165
- * <warn>This is only available to bots in fewer than 10 guilds.</warn>
166
165
  * @param {string} name The name of the guild
167
166
  * @param {GuildCreateOptions} [options] Options for creating the guild
168
167
  * @returns {Promise<Guild>} The guild that was created
@@ -238,6 +237,7 @@ class GuildManager extends CachedManager {
238
237
  afk_timeout: afkTimeout,
239
238
  system_channel_id: systemChannelId,
240
239
  system_channel_flags: systemChannelFlags,
240
+ guild_template_code: '2TffvPucqHkN', // From Discord
241
241
  },
242
242
  });
243
243
 
@@ -503,13 +503,17 @@ class GuildMemberManager extends CachedManager {
503
503
  fetchByMemberSafety(timeout = 15_000) {
504
504
  return new Promise(resolve => {
505
505
  const nonce = SnowflakeUtil.generate();
506
+ const fetchedMembers = new Collection();
506
507
  let timeout_ = setTimeout(() => {
507
- this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
508
- resolve(this.guild.members.cache);
508
+ this.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler);
509
+ resolve(fetchedMembers);
509
510
  }, timeout).unref();
510
- const handler = (members, guild, raw) => {
511
- if (guild.id == this.guild.id && raw.nonce == nonce) {
511
+ const handler = (members, guild, chunk) => {
512
+ if (guild.id == this.guild.id && chunk.nonce == nonce) {
512
513
  if (members.size > 0) {
514
+ for (const member of members.values()) {
515
+ fetchedMembers.set(member.id, member);
516
+ }
513
517
  this.client.ws.broadcast({
514
518
  op: Opcodes.SEARCH_RECENT_MEMBERS,
515
519
  d: {
@@ -521,12 +525,12 @@ class GuildMemberManager extends CachedManager {
521
525
  });
522
526
  } else {
523
527
  clearTimeout(timeout_);
524
- this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
525
- resolve(this.guild.members.cache);
528
+ this.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler);
529
+ resolve(fetchedMembers);
526
530
  }
527
531
  }
528
532
  };
529
- this.client.on('guildMembersChunk', handler);
533
+ this.client.on(Events.GUILD_MEMBERS_CHUNK, handler);
530
534
  this.client.ws.broadcast({
531
535
  op: Opcodes.SEARCH_RECENT_MEMBERS,
532
536
  d: {
@@ -16,7 +16,7 @@ class RelationshipManager extends BaseManager {
16
16
  super(client);
17
17
  /**
18
18
  * A collection of users this manager is caching. (Type: Number)
19
- * @type {Collection<Snowflake, RelationshipTypes>}
19
+ * @type {Collection<Snowflake, RelationshipType>}
20
20
  */
21
21
  this.cache = new Collection();
22
22
  /**
@@ -81,7 +81,7 @@ class RelationshipManager extends BaseManager {
81
81
  /**
82
82
  * @typedef {Object} RelationshipJSONData
83
83
  * @property {Snowflake} id The ID of the target user
84
- * @property {RelationshipTypes} type The type of relationship
84
+ * @property {RelationshipType} type The type of relationship
85
85
  * @property {string | null} nickname The nickname of the user in this relationship (1-32 characters)
86
86
  * @property {string} since When the user requested a relationship (ISO8601 timestamp)
87
87
  */
@@ -130,7 +130,7 @@ class RelationshipManager extends BaseManager {
130
130
  * Obtains a user from Discord, or the user cache if it's already available.
131
131
  * @param {UserResolvable} [user] The user to fetch
132
132
  * @param {BaseFetchOptions} [options] Additional options for this fetch
133
- * @returns {Promise<RelationshipTypes|RelationshipManager>}
133
+ * @returns {Promise<RelationshipType|RelationshipManager>}
134
134
  */
135
135
  async fetch(user, { force = false } = {}) {
136
136
  if (user) {
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const Buffer = require('node:buffer').Buffer;
4
- const http = require('node:http');
5
4
  const https = require('node:https');
6
5
  const { setTimeout } = require('node:timers');
7
6
  const makeFetchCookie = require('fetch-cookie');
@@ -9,6 +8,7 @@ const FormData = require('form-data');
9
8
  const fetchOriginal = require('node-fetch');
10
9
  const { CookieJar } = require('tough-cookie');
11
10
  const { ciphers } = require('../util/Constants');
11
+ const Util = require('../util/Util');
12
12
 
13
13
  const cookieJar = new CookieJar();
14
14
  const fetch = makeFetchCookie(fetchOriginal, cookieJar);
@@ -40,18 +40,24 @@ class APIRequest {
40
40
 
41
41
  make(captchaKey, captchaRqToken) {
42
42
  if (!agent) {
43
- if (this.client.options.http.agent instanceof http.Agent) {
44
- this.client.options.http.agent.options.keepAlive = true;
45
- this.client.options.http.agent.options.honorCipherOrder = true;
46
- this.client.options.http.agent.options.minVersion = 'TLSv1.2';
47
- this.client.options.http.agent.options.ciphers = ciphers.join(':');
43
+ if (Util.verifyProxyAgent(this.client.options.http.agent)) {
44
+ // Bad code
45
+ for (const [k, v] of Object.entries({
46
+ keepAlive: true,
47
+ honorCipherOrder: true,
48
+ secureProtocol: 'TLSv1_2_method',
49
+ ciphers: ciphers.join(':'),
50
+ })) {
51
+ this.client.options.http.agent.options[k] = v;
52
+ this.client.options.http.agent.httpsAgent.options.options[k] = v;
53
+ }
48
54
  agent = this.client.options.http.agent;
49
55
  } else {
50
56
  agent = new https.Agent({
51
57
  ...this.client.options.http.agent,
52
58
  keepAlive: true,
53
59
  honorCipherOrder: true,
54
- minVersion: 'TLSv1.2',
60
+ secureProtocol: 'TLSv1_2_method',
55
61
  ciphers: ciphers.join(':'),
56
62
  });
57
63
  }
@@ -22,7 +22,8 @@ class ClientPresence extends Presence {
22
22
  */
23
23
  set(presence) {
24
24
  const packet = this._parse(presence);
25
- this._patch(packet, true);
25
+ this._patch(packet);
26
+ packet.activities = this.activities.map(a => a.toJSON());
26
27
  if (typeof presence.shardId === 'undefined') {
27
28
  this.client.ws.broadcast({ op: Opcodes.STATUS_UPDATE, d: packet });
28
29
  } else if (Array.isArray(presence.shardId)) {
@@ -45,7 +46,7 @@ class ClientPresence extends Presence {
45
46
  const data = {
46
47
  activities: [],
47
48
  afk: typeof afk === 'boolean' ? afk : false,
48
- since: typeof since === 'number' && !Number.isNaN(since) ? since : null,
49
+ since: typeof since === 'number' && !Number.isNaN(since) ? since : 0,
49
50
  status: status ?? this.status,
50
51
  };
51
52
  if (activities?.length) {
@@ -53,25 +54,21 @@ class ClientPresence extends Presence {
53
54
  if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string');
54
55
 
55
56
  activity.type ??= ActivityTypes.PLAYING;
57
+ if (typeof activity.type === 'string') activity.type = ActivityTypes[activity.type];
56
58
 
57
59
  if (CustomStatusActivityTypes.includes(activity.type) && !activity.state) {
58
60
  activity.state = activity.name;
59
61
  activity.name = 'Custom Status';
60
62
  }
61
63
 
62
- data.activities.push(
63
- Object.assign(activity, {
64
- type: typeof activity.type === 'number' ? activity.type : ActivityTypes[activity.type],
65
- }),
66
- );
64
+ data.activities.push(activity);
67
65
  }
68
66
  } else if (!activities && (status || afk || since) && this.activities.length) {
69
67
  data.activities.push(
70
- ...this.activities.map(a =>
71
- Object.assign(a, {
72
- type: typeof a.type === 'number' ? a.type : ActivityTypes[a.type],
73
- }),
74
- ),
68
+ ...this.activities.map(a => {
69
+ if (typeof a.type === 'string') a.type = ActivityTypes[a.type];
70
+ return a;
71
+ }),
75
72
  );
76
73
  }
77
74
 
@@ -203,7 +203,6 @@ class ClientUser extends User {
203
203
  * @example
204
204
  * // Set the client user's presence
205
205
  * client.user.setPresence({ activities: [{ name: 'with discord.js' }], status: 'idle' });
206
- * @see {@link https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/RichPresence.md}
207
206
  */
208
207
  setPresence(data) {
209
208
  return this.client.presence.set(data);
@@ -248,7 +247,6 @@ class ClientUser extends User {
248
247
  * @example
249
248
  * // Set the client user's activity
250
249
  * client.user.setActivity('discord.js', { type: 'WATCHING' });
251
- * @see {@link https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/RichPresence.md}
252
250
  */
253
251
  setActivity(name, options = {}) {
254
252
  if (!name) return this.setPresence({ activities: [], shardId: options.shardId });
@@ -1,7 +1,6 @@
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');
@@ -9,18 +8,13 @@ const MessageAttachment = require('./MessageAttachment');
9
8
  const Embed = require('./MessageEmbed');
10
9
  const Mentions = require('./MessageMentions');
11
10
  const MessagePayload = require('./MessagePayload');
11
+ const MessagePoll = require('./MessagePoll');
12
12
  const ReactionCollector = require('./ReactionCollector');
13
13
  const { Sticker } = require('./Sticker');
14
14
  const Application = require('./interfaces/Application');
15
15
  const { Error } = require('../errors');
16
16
  const ReactionManager = require('../managers/ReactionManager');
17
- const {
18
- InteractionTypes,
19
- MessageTypes,
20
- SystemMessageTypes,
21
- MessageComponentTypes,
22
- Events,
23
- } = require('../util/Constants');
17
+ const { InteractionTypes, MessageTypes, SystemMessageTypes, MessageComponentTypes } = require('../util/Constants');
24
18
  const MessageFlags = require('../util/MessageFlags');
25
19
  const Permissions = require('../util/Permissions');
26
20
  const SnowflakeUtil = require('../util/SnowflakeUtil');
@@ -257,6 +251,16 @@ class Message extends Base {
257
251
  this.webhookId ??= null;
258
252
  }
259
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
+
260
264
  if ('application' in data) {
261
265
  /**
262
266
  * Supplemental application information for group activities
@@ -846,6 +850,55 @@ class Message extends Base {
846
850
  return this.channel.threads.create({ ...options, startMessage: this });
847
851
  }
848
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
+
849
902
  /**
850
903
  * Fetch this message.
851
904
  * @param {boolean} [force=true] Whether to skip the cache check and request the API
@@ -1014,8 +1067,8 @@ class Message extends Base {
1014
1067
  } else {
1015
1068
  button = this.components[button.Y]?.components[button.X];
1016
1069
  }
1017
- button = button.toJSON();
1018
1070
  if (!button) throw new TypeError('BUTTON_NOT_FOUND');
1071
+ button = button.toJSON();
1019
1072
  if (!button.custom_id || button.disabled) throw new TypeError('BUTTON_CANNOT_CLICK');
1020
1073
  const nonce = SnowflakeUtil.generate();
1021
1074
  const data = {
@@ -1035,38 +1088,7 @@ class Message extends Base {
1035
1088
  this.client.api.interactions.post({
1036
1089
  data,
1037
1090
  });
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
- });
1091
+ return Util.createPromiseInteraction(this.client, nonce, 5_000, true, this);
1070
1092
  }
1071
1093
 
1072
1094
  /**
@@ -1076,10 +1098,10 @@ class Message extends Base {
1076
1098
  * @returns {Promise<Message|Modal>}
1077
1099
  */
1078
1100
  selectMenu(menu, values = []) {
1079
- let selectMenu;
1101
+ let selectMenu = menu;
1080
1102
  if (/[0-4]/.test(menu)) {
1081
1103
  selectMenu = this.components[menu]?.components[0];
1082
- } else {
1104
+ } else if (typeof menu == 'string') {
1083
1105
  selectMenu = this.components
1084
1106
  .flatMap(row => row.components)
1085
1107
  .find(
@@ -1092,7 +1114,7 @@ class Message extends Base {
1092
1114
  if (values.length < selectMenu.minValues) {
1093
1115
  throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${selectMenu.minValues}`);
1094
1116
  }
1095
- if (values.length > selectMenu.maxValues) {
1117
+ if (values.length > selectMenu?.maxValues) {
1096
1118
  throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${selectMenu.maxValues}`);
1097
1119
  }
1098
1120
  values = values.map(value => {
@@ -1137,38 +1159,7 @@ class Message extends Base {
1137
1159
  this.client.api.interactions.post({
1138
1160
  data,
1139
1161
  });
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
- });
1162
+ return Util.createPromiseInteraction(this.client, nonce, 5_000, true, this);
1172
1163
  }
1173
1164
 
1174
1165
  /**
@@ -3,6 +3,7 @@
3
3
  const { Buffer } = require('node:buffer');
4
4
  const BaseMessageComponent = require('./BaseMessageComponent');
5
5
  const MessageEmbed = require('./MessageEmbed');
6
+ const MessagePoll = require('./MessagePoll');
6
7
  const { RangeError } = require('../errors');
7
8
  const ActivityFlags = require('../util/ActivityFlags');
8
9
  const DataResolver = require('../util/DataResolver');
@@ -230,6 +231,7 @@ class MessagePayload {
230
231
  attachments: this.options.attachments,
231
232
  sticker_ids: this.options.stickers?.map(sticker => sticker.id ?? sticker),
232
233
  thread_name: threadName,
234
+ poll: this.options.poll instanceof MessagePoll ? this.options.poll.toJSON() : this.options.poll,
233
235
  };
234
236
  return this;
235
237
  }