djs-selfbot-v13 3.1.5 → 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 (152) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +42 -15
  3. package/package.json +24 -9
  4. package/src/client/BaseClient.js +3 -2
  5. package/src/client/Client.js +539 -187
  6. package/src/client/actions/Action.js +13 -18
  7. package/src/client/actions/ActionsManager.js +1 -7
  8. package/src/client/actions/AutoModerationActionExecution.js +0 -1
  9. package/src/client/actions/AutoModerationRuleCreate.js +0 -1
  10. package/src/client/actions/AutoModerationRuleDelete.js +0 -1
  11. package/src/client/actions/AutoModerationRuleUpdate.js +0 -1
  12. package/src/client/actions/GuildMemberRemove.js +1 -1
  13. package/src/client/actions/GuildMemberUpdate.js +1 -1
  14. package/src/client/actions/InteractionCreate.js +115 -0
  15. package/src/client/actions/MessageCreate.js +4 -0
  16. package/src/client/actions/PresenceUpdate.js +16 -17
  17. package/src/client/websocket/WebSocketManager.js +31 -11
  18. package/src/client/websocket/WebSocketShard.js +38 -39
  19. package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +23 -0
  20. package/src/client/websocket/handlers/CALL_CREATE.js +3 -3
  21. package/src/client/websocket/handlers/CALL_DELETE.js +2 -2
  22. package/src/client/websocket/handlers/CALL_UPDATE.js +2 -2
  23. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +13 -16
  24. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
  25. package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +11 -0
  26. package/src/client/websocket/handlers/GUILD_CREATE.js +0 -7
  27. package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +1 -1
  28. package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +55 -0
  29. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
  30. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
  31. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
  32. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
  33. package/src/client/websocket/handlers/INTERACTION_CREATE.js +16 -0
  34. package/src/client/websocket/handlers/INTERACTION_FAILURE.js +18 -0
  35. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +0 -1
  36. package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +30 -0
  37. package/src/client/websocket/handlers/MESSAGE_ACK.js +16 -0
  38. package/src/client/websocket/handlers/READY.js +137 -47
  39. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +5 -7
  40. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +4 -6
  41. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +9 -32
  42. package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
  43. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +8 -2
  44. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
  45. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +5 -1
  46. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
  47. package/src/client/websocket/handlers/index.js +20 -15
  48. package/src/errors/Messages.js +69 -24
  49. package/src/index.js +43 -12
  50. package/src/managers/ApplicationCommandManager.js +12 -9
  51. package/src/managers/ApplicationCommandPermissionsManager.js +11 -3
  52. package/src/managers/ChannelManager.js +4 -2
  53. package/src/managers/ClientUserSettingManager.js +279 -161
  54. package/src/managers/DeveloperPortalManager.js +104 -0
  55. package/src/managers/GuildApplicationCommandManager.js +28 -0
  56. package/src/managers/GuildBanManager.js +1 -1
  57. package/src/managers/GuildChannelManager.js +0 -2
  58. package/src/managers/GuildFolderManager.js +24 -0
  59. package/src/managers/GuildForumThreadManager.js +28 -22
  60. package/src/managers/GuildMemberManager.js +216 -40
  61. package/src/managers/GuildSettingManager.js +15 -22
  62. package/src/managers/MessageManager.js +44 -42
  63. package/src/managers/PermissionOverwriteManager.js +1 -1
  64. package/src/managers/ReactionUserManager.js +5 -5
  65. package/src/managers/RelationshipManager.js +74 -81
  66. package/src/managers/SessionManager.js +57 -0
  67. package/src/managers/ThreadManager.js +45 -12
  68. package/src/managers/ThreadMemberManager.js +1 -1
  69. package/src/managers/UserManager.js +10 -6
  70. package/src/rest/APIRequest.js +20 -42
  71. package/src/rest/CaptchaSolver.js +132 -0
  72. package/src/rest/DiscordAPIError.js +16 -17
  73. package/src/rest/RESTManager.js +21 -1
  74. package/src/rest/RequestHandler.js +21 -35
  75. package/src/structures/ApplicationCommand.js +456 -19
  76. package/src/structures/ApplicationRoleConnectionMetadata.js +0 -3
  77. package/src/structures/AutoModerationRule.js +5 -5
  78. package/src/structures/AutocompleteInteraction.js +0 -1
  79. package/src/structures/BaseGuildTextChannel.js +12 -10
  80. package/src/structures/BaseGuildVoiceChannel.js +18 -16
  81. package/src/structures/{CallState.js → Call.js} +12 -17
  82. package/src/structures/CategoryChannel.js +0 -2
  83. package/src/structures/Channel.js +3 -2
  84. package/src/structures/ClientApplication.js +204 -0
  85. package/src/structures/ClientPresence.js +8 -12
  86. package/src/structures/ClientUser.js +338 -117
  87. package/src/structures/ContextMenuInteraction.js +1 -1
  88. package/src/structures/DMChannel.js +92 -29
  89. package/src/structures/DeveloperPortalApplication.js +520 -0
  90. package/src/structures/ForumChannel.js +10 -0
  91. package/src/structures/Guild.js +271 -135
  92. package/src/structures/GuildAuditLogs.js +5 -0
  93. package/src/structures/GuildChannel.js +2 -16
  94. package/src/structures/GuildFolder.js +75 -0
  95. package/src/structures/GuildMember.js +145 -27
  96. package/src/structures/Interaction.js +62 -1
  97. package/src/structures/InteractionResponse.js +114 -0
  98. package/src/structures/Invite.js +52 -35
  99. package/src/structures/Message.js +202 -222
  100. package/src/structures/MessageAttachment.js +0 -11
  101. package/src/structures/MessageButton.js +67 -1
  102. package/src/structures/MessageEmbed.js +1 -1
  103. package/src/structures/MessageMentions.js +2 -3
  104. package/src/structures/MessagePayload.js +46 -4
  105. package/src/structures/MessageReaction.js +1 -1
  106. package/src/structures/MessageSelectMenu.js +252 -1
  107. package/src/structures/Modal.js +180 -75
  108. package/src/structures/PartialGroupDMChannel.js +433 -0
  109. package/src/structures/Presence.js +2 -2
  110. package/src/structures/RichPresence.js +34 -14
  111. package/src/structures/Role.js +2 -18
  112. package/src/structures/SelectMenuInteraction.js +151 -2
  113. package/src/structures/Session.js +81 -0
  114. package/src/structures/Team.js +49 -0
  115. package/src/structures/TextInputComponent.js +70 -0
  116. package/src/structures/ThreadChannel.js +19 -0
  117. package/src/structures/User.js +345 -117
  118. package/src/structures/UserContextMenuInteraction.js +2 -2
  119. package/src/structures/VoiceState.js +39 -74
  120. package/src/structures/WebEmbed.js +52 -38
  121. package/src/structures/Webhook.js +11 -17
  122. package/src/structures/interfaces/Application.js +23 -146
  123. package/src/structures/interfaces/TextBasedChannel.js +256 -411
  124. package/src/util/ApplicationFlags.js +1 -1
  125. package/src/util/Constants.js +284 -106
  126. package/src/util/Formatters.js +2 -16
  127. package/src/util/LimitedCollection.js +1 -1
  128. package/src/util/Options.js +68 -48
  129. package/src/util/Permissions.js +0 -5
  130. package/src/util/PurchasedFlags.js +0 -2
  131. package/src/util/RemoteAuth.js +356 -221
  132. package/src/util/Sweepers.js +1 -1
  133. package/src/util/Util.js +36 -76
  134. package/src/util/Voice.js +1456 -0
  135. package/src/util/arRPC/index.js +229 -0
  136. package/src/util/arRPC/process/detectable.json +1 -0
  137. package/src/util/arRPC/process/index.js +102 -0
  138. package/src/util/arRPC/process/native/index.js +5 -0
  139. package/src/util/arRPC/process/native/linux.js +37 -0
  140. package/src/util/arRPC/process/native/win32.js +25 -0
  141. package/src/util/arRPC/transports/ipc.js +281 -0
  142. package/src/util/arRPC/transports/websocket.js +128 -0
  143. package/typings/enums.d.ts +73 -18
  144. package/typings/index.d.ts +1250 -898
  145. package/typings/rawDataTypes.d.ts +9 -68
  146. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +0 -78
  147. package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +0 -12
  148. package/src/managers/UserNoteManager.js +0 -53
  149. package/src/structures/GroupDMChannel.js +0 -387
  150. package/src/util/AttachmentFlags.js +0 -38
  151. package/src/util/InviteFlags.js +0 -29
  152. package/src/util/RoleFlags.js +0 -37
@@ -130,7 +130,7 @@ class GuildBanManager extends CachedManager {
130
130
  * @typedef {Object} BanOptions
131
131
  * @property {number} [days=0] Number of days of messages to delete, must be between 0 and 7, inclusive
132
132
  * <warn>This property is deprecated. Use `deleteMessageSeconds` instead.</warn>
133
- * @property {number} [deleteMessageSeconds] Number of seconds of messages to delete,
133
+ * @property {number} [deleteMessageSeconds=0] Number of seconds of messages to delete,
134
134
  * must be between 0 and 604800 (7 days), inclusive
135
135
  * @property {string} [reason] The reason for the ban
136
136
  */
@@ -150,7 +150,6 @@ class GuildChannelManager extends CachedManager {
150
150
  defaultReactionEmoji,
151
151
  defaultSortOrder,
152
152
  defaultForumLayout,
153
- defaultThreadRateLimitPerUser,
154
153
  reason,
155
154
  } = {},
156
155
  ) {
@@ -192,7 +191,6 @@ class GuildChannelManager extends CachedManager {
192
191
  default_reaction_emoji: defaultReactionEmoji && transformGuildDefaultReaction(defaultReactionEmoji),
193
192
  default_sort_order: sortMode,
194
193
  default_forum_layout: layoutMode,
195
- default_thread_rate_limit_per_user: defaultThreadRateLimitPerUser,
196
194
  },
197
195
  reason,
198
196
  });
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const { Collection } = require('@discordjs/collection');
4
+ const BaseManager = require('./BaseManager');
5
+
6
+ /**
7
+ * Manages API methods for users and stores their cache.
8
+ * @extends {BaseManager}
9
+ */
10
+ class GuildFolderManager extends BaseManager {
11
+ constructor(client) {
12
+ super(client);
13
+ /**
14
+ * The guild folder cache (Index, GuildFolder)
15
+ * @type {Collection<number, GuildFolder>}
16
+ */
17
+ this.cache = new Collection();
18
+ }
19
+ _refresh() {
20
+ this.cache.clear();
21
+ }
22
+ }
23
+
24
+ module.exports = GuildFolderManager;
@@ -3,7 +3,7 @@
3
3
  const ThreadManager = require('./ThreadManager');
4
4
  const { TypeError } = require('../errors');
5
5
  const MessagePayload = require('../structures/MessagePayload');
6
- const { resolveAutoArchiveMaxLimit, getUploadURL, uploadFile } = require('../util/Util');
6
+ const { resolveAutoArchiveMaxLimit, getAttachments, uploadFile } = require('../util/Util');
7
7
 
8
8
  /**
9
9
  * Manages API methods for threads in forum channels and stores their cache.
@@ -20,7 +20,7 @@ class GuildForumThreadManager extends ThreadManager {
20
20
  * @typedef {BaseMessageOptions} GuildForumThreadMessageCreateOptions
21
21
  * @property {StickerResolvable} [stickers] The stickers to send with the message
22
22
  * @property {BitFieldResolvable} [flags] The flags to send with the message.
23
- * Only `SUPPRESS_EMBEDS` and `SUPPRESS_NOTIFICATIONS` can be set.
23
+ * Only `SUPPRESS_EMBEDS`, `SUPPRESS_NOTIFICATIONS` and `IS_VOICE_MESSAGE` can be set.
24
24
  */
25
25
 
26
26
  /**
@@ -63,29 +63,35 @@ class GuildForumThreadManager extends ThreadManager {
63
63
  let messagePayload;
64
64
 
65
65
  if (message instanceof MessagePayload) {
66
- messagePayload = message.resolveData();
66
+ messagePayload = await message.resolveData();
67
67
  } else {
68
- messagePayload = MessagePayload.create(this, message).resolveData();
68
+ messagePayload = await MessagePayload.create(this, message).resolveData();
69
69
  }
70
70
 
71
- const { data: body, files } = await messagePayload.resolveFiles();
71
+ let { data: body, files } = await messagePayload.resolveFiles();
72
72
 
73
- // New API
74
- const attachments = await getUploadURL(this.client, this.channel.id, files);
75
- const requestPromises = attachments.map(async attachment => {
76
- await uploadFile(files[attachment.id].file, attachment.upload_url);
77
- return {
78
- id: attachment.id,
79
- filename: files[attachment.id].name,
80
- uploaded_filename: attachment.upload_filename,
81
- description: files[attachment.id].description,
82
- duration_secs: files[attachment.id].duration_secs,
83
- waveform: files[attachment.id].waveform,
84
- };
85
- });
86
- const attachmentsData = await Promise.all(requestPromises);
87
- attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
88
- data.attachments = attachmentsData;
73
+ if (typeof message == 'object' && typeof message.usingNewAttachmentAPI !== 'boolean') {
74
+ message.usingNewAttachmentAPI = this.client.options.usingNewAttachmentAPI;
75
+ }
76
+
77
+ if (message?.usingNewAttachmentAPI === true) {
78
+ const attachments = await getAttachments(this.client, this.channel.id, ...files);
79
+ const requestPromises = attachments.map(async attachment => {
80
+ await uploadFile(files[attachment.id].file, attachment.upload_url);
81
+ return {
82
+ id: attachment.id,
83
+ filename: files[attachment.id].name,
84
+ uploaded_filename: attachment.upload_filename,
85
+ description: files[attachment.id].description,
86
+ duration_secs: files[attachment.id].duration_secs,
87
+ waveform: files[attachment.id].waveform,
88
+ };
89
+ });
90
+ const attachmentsData = await Promise.all(requestPromises);
91
+ attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
92
+ body.attachments = attachmentsData;
93
+ files = [];
94
+ }
89
95
 
90
96
  if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild);
91
97
 
@@ -97,7 +103,7 @@ class GuildForumThreadManager extends ThreadManager {
97
103
  applied_tags: appliedTags,
98
104
  message: body,
99
105
  },
100
- files: [],
106
+ files,
101
107
  reason,
102
108
  });
103
109
 
@@ -1,9 +1,10 @@
1
- /* eslint-disable newline-per-chained-call */
2
1
  'use strict';
3
2
 
4
3
  const { Buffer } = require('node:buffer');
5
4
  const { setTimeout } = require('node:timers');
6
5
  const { Collection } = require('@discordjs/collection');
6
+ require('lodash.permutations');
7
+ const _ = require('lodash');
7
8
  const CachedManager = require('./CachedManager');
8
9
  const { Error, TypeError, RangeError } = require('../errors');
9
10
  const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel');
@@ -190,17 +191,26 @@ class GuildMemberManager extends CachedManager {
190
191
  * guild.members.fetch({ query: 'hydra', limit: 1 })
191
192
  * .then(console.log)
192
193
  * .catch(console.error);
194
+ * @see {@link https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/FetchGuildMember.md}
193
195
  */
194
196
  fetch(options) {
195
- if (!options) {
197
+ if (!options || (typeof options === 'object' && !('user' in options) && !('query' in options))) {
196
198
  if (
197
- this.me.permissions.has('KICK_MEMBERS') ||
198
- this.me.permissions.has('BAN_MEMBERS') ||
199
- this.me.permissions.has('MANAGE_ROLES')
199
+ this.guild.members.me.permissions.has('KICK_MEMBERS') ||
200
+ this.guild.members.me.permissions.has('BAN_MEMBERS') ||
201
+ this.guild.members.me.permissions.has('MANAGE_ROLES')
200
202
  ) {
201
203
  return this._fetchMany();
202
204
  } else {
203
205
  return this.fetchByMemberSafety();
206
+ /*
207
+ NOTE: This is a very slow method, and can take up to 999+ minutes to complete.
208
+ this.fetchBruteforce({
209
+ delay: 50,
210
+ skipWarn: true,
211
+ depth: 1,
212
+ });
213
+ */
204
214
  }
205
215
  }
206
216
  const user = this.client.users.resolveId(options);
@@ -463,60 +473,92 @@ class GuildMemberManager extends CachedManager {
463
473
  }
464
474
 
465
475
  /**
466
- * Adds a role to a member.
467
- * @param {GuildMemberResolvable} user The user to add the role from
468
- * @param {RoleResolvable} role The role to add
469
- * @param {string} [reason] Reason for adding the role
470
- * @returns {Promise<GuildMember|User|Snowflake>}
476
+ * Options used to fetch multiple members from a guild.
477
+ * @typedef {Object} BruteforceOptions
478
+ * @property {number} [limit=100] Maximum number of members per request
479
+ * @property {number} [delay=500] Timeout for new requests in ms
480
+ * @property {number} [depth=1] Permutations length
471
481
  */
472
- async addRole(user, role, reason) {
473
- const userId = this.guild.members.resolveId(user);
474
- const roleId = this.guild.roles.resolveId(role);
475
-
476
- await this.client.api.guilds(this.guild.id).members(userId).roles(roleId).put({ reason });
477
-
478
- return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
479
- }
480
482
 
481
483
  /**
482
- * Removes a role from a member.
483
- * @param {UserResolvable} user The user to remove the role from
484
- * @param {RoleResolvable} role The role to remove
485
- * @param {string} [reason] Reason for removing the role
486
- * @returns {Promise<GuildMember|User|Snowflake>}
484
+ * Fetches multiple members from the guild.
485
+ * @param {BruteforceOptions} options Options for the bruteforce
486
+ * @returns {Collection<Snowflake, GuildMember>} (All) members in the guild
487
+ * @see https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/FetchGuildMember.md
488
+ * @example
489
+ * guild.members.fetchBruteforce()
490
+ * .then(members => console.log(`Fetched ${members.size} members`))
491
+ * .catch(console.error);
487
492
  */
488
- async removeRole(user, role, reason) {
489
- const userId = this.guild.members.resolveId(user);
490
- const roleId = this.guild.roles.resolveId(role);
491
-
492
- await this.client.api.guilds(this.guild.id).members(userId).roles(roleId).delete({ reason });
493
-
494
- return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
493
+ fetchBruteforce(options = {}) {
494
+ const defaultQuery = 'abcdefghijklmnopqrstuvwxyz0123456789!"#$%&\'()*+,-./:;<=>?@[]^_`{|}~ ';
495
+ let dictionary;
496
+ let limit = 100;
497
+ let delay = 500;
498
+ let depth = 1;
499
+ if (options?.limit) limit = options?.limit;
500
+ if (options?.delay) delay = options?.delay;
501
+ if (options?.depth) depth = options?.depth;
502
+ if (typeof limit !== 'number') throw new TypeError('INVALID_TYPE', 'limit', 'Number');
503
+ if (limit < 1 || limit > 100) throw new RangeError('INVALID_RANGE_QUERY_MEMBER');
504
+ if (typeof delay !== 'number') throw new TypeError('INVALID_TYPE', 'delay', 'Number');
505
+ if (typeof depth !== 'number') throw new TypeError('INVALID_TYPE', 'depth', 'Number');
506
+ if (depth < 1) throw new RangeError('INVALID_RANGE_QUERY_MEMBER');
507
+ if (depth > 2) {
508
+ console.warn(`[WARNING] GuildMemberManager#fetchBruteforce: depth greater than 2, can lead to very slow speeds`);
509
+ }
510
+ if (delay < 500 && !options?.skipWarn) {
511
+ console.warn(
512
+ `[WARNING] GuildMemberManager#fetchBruteforce: delay is less than 500ms, this may cause rate limits.`,
513
+ );
514
+ }
515
+ let skipValues = [];
516
+ // eslint-disable-next-line no-async-promise-executor
517
+ return new Promise(async (resolve, reject) => {
518
+ for (let i = 1; i <= depth; i++) {
519
+ dictionary = _(defaultQuery)
520
+ .permutations(i)
521
+ .map(v => _.join(v, ''))
522
+ .value();
523
+ for (const query of dictionary) {
524
+ if (this.guild.members.cache.size >= this.guild.memberCount) break;
525
+ this.client.emit(
526
+ 'debug',
527
+ `[INFO] GuildMemberManager#fetchBruteforce: Querying ${query}, Skip: [${skipValues.join(', ')}]`,
528
+ );
529
+ if (skipValues.some(v => query.startsWith(v))) continue;
530
+ await this._fetchMany({ query, limit })
531
+ .then(members => {
532
+ if (members.size === 0) skipValues.push(query);
533
+ })
534
+ .catch(reject);
535
+ await this.guild.client.sleep(delay);
536
+ }
537
+ }
538
+ resolve(this.guild.members.cache);
539
+ });
495
540
  }
496
541
 
497
542
  /**
498
- * Experimental method to fetch members from the guild.
499
- * <info>Lists up to 10000 members of the guild.</info>
500
- * @param {number} [timeout=15_000] Timeout for receipt of members in ms
543
+ * Experimental method to fetch all members from the guild.
544
+ * @param {number} [timeout=120000] Timeout for receipt of members in ms
501
545
  * @returns {Promise<Collection<Snowflake, GuildMember>>}
502
546
  */
503
- fetchByMemberSafety(timeout = 15_000) {
547
+ fetchByMemberSafety(timeout = 120_000) {
504
548
  return new Promise(resolve => {
505
- const nonce = SnowflakeUtil.generate();
506
549
  let timeout_ = setTimeout(() => {
507
550
  this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
508
551
  resolve(this.guild.members.cache);
509
552
  }, timeout).unref();
510
553
  const handler = (members, guild, raw) => {
511
- if (guild.id == this.guild.id && raw.nonce == nonce) {
554
+ if (guild.id == this.guild.id && !raw.nonce && raw.index == 0 && raw.count == 1) {
512
555
  if (members.size > 0) {
513
556
  this.client.ws.broadcast({
514
- op: Opcodes.SEARCH_RECENT_MEMBERS,
557
+ op: 35,
515
558
  d: {
516
559
  guild_id: this.guild.id,
517
560
  query: '',
518
561
  continuation_token: members.first()?.id,
519
- nonce,
520
562
  },
521
563
  });
522
564
  } else {
@@ -528,17 +570,151 @@ class GuildMemberManager extends CachedManager {
528
570
  };
529
571
  this.client.on('guildMembersChunk', handler);
530
572
  this.client.ws.broadcast({
531
- op: Opcodes.SEARCH_RECENT_MEMBERS,
573
+ op: 35,
532
574
  d: {
533
575
  guild_id: this.guild.id,
534
576
  query: '',
535
577
  continuation_token: null,
536
- nonce,
537
578
  },
538
579
  });
539
580
  });
540
581
  }
541
582
 
583
+ /**
584
+ * Fetches multiple members from the guild in the channel.
585
+ * @param {GuildTextChannelResolvable} channel The channel to get members from (Members has VIEW_CHANNEL permission)
586
+ * @param {number} [offset=0] Start index of the members to get
587
+ * @param {boolean} [double=false] Whether to use double range
588
+ * @param {number} [retryMax=3] Number of retries
589
+ * @param {number} [time=10e3] Timeout for receipt of members
590
+ * @returns {Collection<Snowflake, GuildMember>} Members in the guild
591
+ * @see {@link https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/FetchGuildMember.md}
592
+ * @example
593
+ * const guild = client.guilds.cache.get('id');
594
+ * const channel = guild.channels.cache.get('id');
595
+ * // Overlap (slow)
596
+ * for (let index = 0; index <= guild.memberCount; index += 100) {
597
+ * await guild.members.fetchMemberList(channel, index, index !== 100).catch(() => {});
598
+ * await client.sleep(500);
599
+ * }
600
+ * // Non-overlap (fast)
601
+ * for (let index = 0; index <= guild.memberCount; index += 200) {
602
+ * await guild.members.fetchMemberList(channel, index == 0 ? 100 : index, index !== 100).catch(() => {});
603
+ * await client.sleep(500);
604
+ * }
605
+ * console.log(guild.members.cache.size); // will print the number of members in the guild
606
+ */
607
+ fetchMemberList(channel, offset = 0, double = false, retryMax = 3, time = 10_000) {
608
+ const channel_ = this.guild.channels.resolve(channel);
609
+ if (!channel_?.isText()) throw new TypeError('INVALID_TYPE', 'channel', 'GuildTextChannelResolvable');
610
+ if (typeof offset !== 'number') throw new TypeError('INVALID_TYPE', 'offset', 'Number');
611
+ if (typeof time !== 'number') throw new TypeError('INVALID_TYPE', 'time', 'Number');
612
+ if (typeof retryMax !== 'number') throw new TypeError('INVALID_TYPE', 'retryMax', 'Number');
613
+ if (retryMax < 1) throw new RangeError('INVALID_RANGE_RETRY');
614
+ if (typeof double !== 'boolean') throw new TypeError('INVALID_TYPE', 'double', 'Boolean');
615
+ // TODO: if (this.guild.large) throw new Error('GUILD_IS_LARGE');
616
+ return new Promise((resolve, reject) => {
617
+ const default_ = [[0, 99]];
618
+ const fetchedMembers = new Collection();
619
+ if (offset > 99) {
620
+ // eslint-disable-next-line no-unused-expressions
621
+ double
622
+ ? default_.push([offset, offset + 99], [offset + 100, offset + 199])
623
+ : default_.push([offset, offset + 99]);
624
+ }
625
+ let retry = 0;
626
+ const handler = (members, guild, type, raw) => {
627
+ timeout.refresh();
628
+ if (guild.id !== this.guild.id) return;
629
+ if (type == 'INVALIDATE' && offset > 100) {
630
+ if (retry < retryMax) {
631
+ this.guild.shard.send({
632
+ op: Opcodes.GUILD_SUBSCRIPTIONS,
633
+ d: {
634
+ guild_id: this.guild.id,
635
+ typing: true,
636
+ threads: true,
637
+ activities: true,
638
+ channels: {
639
+ [channel_.id]: default_,
640
+ },
641
+ thread_member_lists: [],
642
+ members: [],
643
+ },
644
+ });
645
+ retry++;
646
+ } else {
647
+ clearTimeout(timeout);
648
+ this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
649
+ this.client.decrementMaxListeners();
650
+ reject(new Error('INVALIDATE_MEMBER', raw.ops[0].range));
651
+ }
652
+ } else {
653
+ for (const member of members.values()) {
654
+ fetchedMembers.set(member.id, member);
655
+ }
656
+ clearTimeout(timeout);
657
+ this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
658
+ this.client.decrementMaxListeners();
659
+ resolve(fetchedMembers);
660
+ }
661
+ };
662
+ const timeout = setTimeout(() => {
663
+ this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
664
+ this.client.decrementMaxListeners();
665
+ reject(new Error('GUILD_MEMBERS_TIMEOUT'));
666
+ }, time).unref();
667
+ this.client.incrementMaxListeners();
668
+ this.client.on(Events.GUILD_MEMBER_LIST_UPDATE, handler);
669
+ this.guild.shard.send({
670
+ op: Opcodes.GUILD_SUBSCRIPTIONS,
671
+ d: {
672
+ guild_id: this.guild.id,
673
+ typing: true,
674
+ threads: true,
675
+ activities: true,
676
+ channels: {
677
+ [channel_.id]: default_,
678
+ },
679
+ thread_member_lists: [],
680
+ members: [],
681
+ },
682
+ });
683
+ });
684
+ }
685
+
686
+ /**
687
+ * Adds a role to a member.
688
+ * @param {GuildMemberResolvable} user The user to add the role from
689
+ * @param {RoleResolvable} role The role to add
690
+ * @param {string} [reason] Reason for adding the role
691
+ * @returns {Promise<GuildMember|User|Snowflake>}
692
+ */
693
+ async addRole(user, role, reason) {
694
+ const userId = this.guild.members.resolveId(user);
695
+ const roleId = this.guild.roles.resolveId(role);
696
+
697
+ await this.client.api.guilds(this.guild.id).members(userId).roles(roleId).put({ reason });
698
+
699
+ return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
700
+ }
701
+
702
+ /**
703
+ * Removes a role from a member.
704
+ * @param {UserResolvable} user The user to remove the role from
705
+ * @param {RoleResolvable} role The role to remove
706
+ * @param {string} [reason] Reason for removing the role
707
+ * @returns {Promise<GuildMember|User|Snowflake>}
708
+ */
709
+ async removeRole(user, role, reason) {
710
+ const userId = this.guild.members.resolveId(user);
711
+ const roleId = this.guild.roles.resolveId(role);
712
+
713
+ await this.client.api.guilds(this.guild.id).members(userId).roles(roleId).delete({ reason });
714
+
715
+ return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
716
+ }
717
+
542
718
  _fetchMany({
543
719
  limit = 0,
544
720
  withPresences: presences = true,
@@ -7,24 +7,19 @@ const BaseManager = require('./BaseManager');
7
7
  * @see {@link https://luna.gitlab.io/discord-unofficial-docs/user_settings.html}
8
8
  */
9
9
  class GuildSettingManager extends BaseManager {
10
- #rawSetting = {};
11
- constructor(guild) {
12
- super(guild.client);
10
+ constructor(client, guildId = null) {
11
+ super(client);
12
+ /**
13
+ * Raw data
14
+ * @type {Object}
15
+ */
16
+ this.rawSetting = {};
13
17
  /**
14
18
  * Guild Id
15
19
  * @type {?Snowflake}
16
20
  */
17
- this.guildId = guild.id;
18
- }
19
-
20
- /**
21
- * Raw data
22
- * @type {Object}
23
- */
24
- get raw() {
25
- return this.#rawSetting;
21
+ this.guildId = guildId;
26
22
  }
27
-
28
23
  /**
29
24
  * Get the guild
30
25
  * @type {?Guild}
@@ -33,15 +28,13 @@ class GuildSettingManager extends BaseManager {
33
28
  get guild() {
34
29
  return this.client.guilds.cache.get(this.guildId);
35
30
  }
36
-
37
31
  /**
38
32
  * Patch data file
39
33
  * @private
40
34
  * @param {Object} data Raw Data to patch
41
35
  */
42
36
  _patch(data = {}) {
43
- this.#rawSetting = Object.assign(this.#rawSetting, data);
44
- this.client.emit('debug', `[SETTING > Guild ${this.guildId}] Sync setting`);
37
+ this.rawSetting = Object.assign(this.rawSetting, data);
45
38
  if ('suppress_everyone' in data) {
46
39
  /**
47
40
  * Notification setting > Suppress `@everyone` and `@here`
@@ -66,9 +59,9 @@ class GuildSettingManager extends BaseManager {
66
59
  if ('message_notifications' in data) {
67
60
  /**
68
61
  * Notification setting > Message notifications
69
- * * `0`: All messages
70
- * * `1`: Only @mentions
71
- * * `2`: Nothing
62
+ * * `0` = All messages
63
+ * * `1` = Only @mentions
64
+ * * `2` = Nothing
72
65
  * @type {?number}
73
66
  */
74
67
  this.messageNotifications = data.message_notifications;
@@ -125,9 +118,9 @@ class GuildSettingManager extends BaseManager {
125
118
  if ('notify_highlights' in data) {
126
119
  /**
127
120
  * Notification setting > Suppress highlights
128
- * * `0`: ??? (unknown)
129
- * * `1`: Enable
130
- * * `2`: Disable
121
+ * * `0` = ??? (unknown)
122
+ * * `1` = Enable
123
+ * * `2` = Disable
131
124
  * @type {?number}
132
125
  */
133
126
  this.notifyHighlights = data.notify_highlights;
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { Collection } = require('@discordjs/collection');
4
4
  const CachedManager = require('./CachedManager');
5
- const { TypeError } = require('../errors');
5
+ const { TypeError, Error } = require('../errors');
6
6
  const { Message } = require('../structures/Message');
7
7
  const MessagePayload = require('../structures/MessagePayload');
8
8
  const Util = require('../util/Util');
@@ -123,32 +123,38 @@ class MessageManager extends CachedManager {
123
123
  const messageId = this.resolveId(message);
124
124
  if (!messageId) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
125
125
 
126
- const { data, files } = await (options instanceof MessagePayload
127
- ? options
128
- : MessagePayload.create(message instanceof Message ? message : this, options)
129
- )
130
- .resolveData()
131
- .resolveFiles();
132
-
133
- // New API
134
- const attachments = await Util.getUploadURL(this.client, this.channel.id, files);
135
- const requestPromises = attachments.map(async attachment => {
136
- await Util.uploadFile(files[attachment.id].file, attachment.upload_url);
137
- return {
138
- id: attachment.id,
139
- filename: files[attachment.id].name,
140
- uploaded_filename: attachment.upload_filename,
141
- description: files[attachment.id].description,
142
- duration_secs: files[attachment.id].duration_secs,
143
- waveform: files[attachment.id].waveform,
144
- };
145
- });
146
- const attachmentsData = await Promise.all(requestPromises);
147
- attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
148
- data.attachments = attachmentsData;
149
- // Empty Files
126
+ let messagePayload;
127
+ if (options instanceof MessagePayload) {
128
+ messagePayload = await options.resolveData();
129
+ } else {
130
+ messagePayload = await MessagePayload.create(message instanceof Message ? message : this, options).resolveData();
131
+ }
132
+ let { data, files } = await messagePayload.resolveFiles();
133
+
134
+ if (typeof options == 'object' && typeof options.usingNewAttachmentAPI !== 'boolean') {
135
+ options.usingNewAttachmentAPI = this.client.options.usingNewAttachmentAPI;
136
+ }
150
137
 
151
- const d = await this.client.api.channels[this.channel.id].messages[messageId].patch({ data });
138
+ if (options?.usingNewAttachmentAPI === true) {
139
+ const attachments = await Util.getAttachments(this.client, this.channel.id, ...files);
140
+ const requestPromises = attachments.map(async attachment => {
141
+ await Util.uploadFile(files[attachment.id].file, attachment.upload_url);
142
+ return {
143
+ id: attachment.id,
144
+ filename: files[attachment.id].name,
145
+ uploaded_filename: attachment.upload_filename,
146
+ description: files[attachment.id].description,
147
+ duration_secs: files[attachment.id].duration_secs,
148
+ waveform: files[attachment.id].waveform,
149
+ };
150
+ });
151
+ const attachmentsData = await Promise.all(requestPromises);
152
+ attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
153
+ data.attachments = attachmentsData;
154
+ files = [];
155
+ }
156
+
157
+ const d = await this.client.api.channels[this.channel.id].messages[messageId].patch({ data, files });
152
158
 
153
159
  const existing = this.cache.get(messageId);
154
160
  if (existing) {
@@ -245,16 +251,12 @@ class MessageManager extends CachedManager {
245
251
  const existing = this.cache.get(messageId);
246
252
  if (existing && !existing.partial) return existing;
247
253
  }
248
-
249
254
  // https://discord.com/api/v9/channels/:id/messages?limit=50&around=:msgid
250
255
  return new Promise((resolve, reject) => {
251
- this._fetchMany(
252
- {
253
- around: messageId,
254
- limit: 50,
255
- },
256
- cache,
257
- )
256
+ this._fetchMany({
257
+ around: messageId,
258
+ limit: 50,
259
+ })
258
260
  .then(data_ =>
259
261
  data_.has(messageId) ? resolve(data_.get(messageId)) : reject(new Error('MESSAGE_ID_NOT_FOUND')),
260
262
  )
@@ -262,6 +264,13 @@ class MessageManager extends CachedManager {
262
264
  });
263
265
  }
264
266
 
267
+ async _fetchMany(options = {}, cache) {
268
+ const data = await this.client.api.channels[this.channel.id].messages.get({ query: options });
269
+ const messages = new Collection();
270
+ for (const message of data) messages.set(message.id, this._add(message, cache));
271
+ return messages;
272
+ }
273
+
265
274
  /**
266
275
  * @typedef {object} MessageSearchOptions
267
276
  * @property {Array<UserResolvable>} [authors] An array of author to filter by
@@ -372,20 +381,13 @@ class MessageManager extends CachedManager {
372
381
  stringQuery = stringQuery.filter(v => !v.startsWith('channel_id') && !v.startsWith('include_nsfw'));
373
382
  data = await this.client.api.channels[this.channel.id].messages[`search?${stringQuery.join('&')}`].get();
374
383
  }
375
-
384
+ console.log(stringQuery);
376
385
  for await (const message of data.messages) result.set(message[0].id, new Message(this.client, message[0]));
377
386
  return {
378
387
  messages: result,
379
388
  total: data.total_results,
380
389
  };
381
390
  }
382
-
383
- async _fetchMany(options = {}, cache) {
384
- const data = await this.client.api.channels[this.channel.id].messages.get({ query: options });
385
- const messages = new Collection();
386
- for (const message of data) messages.set(message.id, this._add(message, cache));
387
- return messages;
388
- }
389
391
  }
390
392
 
391
393
  module.exports = MessageManager;
@@ -89,7 +89,7 @@ class PermissionOverwriteManager extends CachedManager {
89
89
  * @private
90
90
  */
91
91
  async upsert(userOrRole, options, overwriteOptions = {}, existing) {
92
- let userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole);
92
+ const userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole);
93
93
  let { type, reason } = overwriteOptions;
94
94
  if (typeof type !== 'number') {
95
95
  userOrRole = this.channel.guild.roles.resolve(userOrRole) ?? this.client.users.resolve(userOrRole);