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
@@ -1,17 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  /* eslint-disable import/order */
4
- const InteractionManager = require('../../managers/InteractionManager');
5
4
  const MessageCollector = require('../MessageCollector');
6
5
  const MessagePayload = require('../MessagePayload');
6
+ const { InteractionTypes, ApplicationCommandOptionTypes, Events } = require('../../util/Constants');
7
+ const { Error } = require('../../errors');
7
8
  const SnowflakeUtil = require('../../util/SnowflakeUtil');
8
- const { Collection } = require('@discordjs/collection');
9
- const { InteractionTypes, MaxBulkDeletableMessageAge } = require('../../util/Constants');
10
- const { TypeError, Error } = require('../../errors');
11
- const InteractionCollector = require('../InteractionCollector');
12
- const { lazy, getAttachments, uploadFile } = require('../../util/Util');
13
- const Message = lazy(() => require('../Message').Message);
9
+ const { setTimeout } = require('node:timers');
14
10
  const { s } = require('@sapphire/shapeshift');
11
+ const Util = require('../../util/Util');
15
12
  const validateName = stringName =>
16
13
  s.string
17
14
  .lengthGreaterThanOrEqual(1)
@@ -32,12 +29,6 @@ class TextBasedChannel {
32
29
  */
33
30
  this.messages = new MessageManager(this);
34
31
 
35
- /**
36
- * A manager of the interactions sent to this channel
37
- * @type {InteractionManager}
38
- */
39
- this.interactions = new InteractionManager(this);
40
-
41
32
  /**
42
33
  * The channel's last message id, if one was sent
43
34
  * @type {?Snowflake}
@@ -76,7 +67,7 @@ class TextBasedChannel {
76
67
  * @property {boolean} [tts=false] Whether or not the message should be spoken aloud
77
68
  * @property {string} [nonce=''] The nonce for the message
78
69
  * @property {string} [content=''] The content for the message
79
- * @property {Array<(MessageEmbed|APIEmbed|WebEmbed)>} [embeds] The embeds for the message
70
+ * @property {Array<(MessageEmbed|APIEmbed)>} [embeds] The embeds for the message
80
71
  * (see [here](https://discord.com/developers/docs/resources/channel#embed-object) for more details)
81
72
  * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content
82
73
  * (see [here](https://discord.com/developers/docs/resources/channel#allowed-mentions-object) for more details)
@@ -84,7 +75,7 @@ class TextBasedChannel {
84
75
  * @property {Array<(MessageActionRow|MessageActionRowOptions)>} [components]
85
76
  * Action rows containing interactive components for the message (buttons, select menus)
86
77
  * @property {MessageAttachment[]} [attachments] Attachments to send in the message
87
- * @property {boolean} [usingNewAttachmentAPI] Whether to use the new attachment API (`channels/:id/attachments`)
78
+ * @property {MessagePoll} [poll] A poll!
88
79
  */
89
80
 
90
81
  /**
@@ -168,39 +159,190 @@ class TextBasedChannel {
168
159
  let messagePayload;
169
160
 
170
161
  if (options instanceof MessagePayload) {
171
- messagePayload = await options.resolveData();
162
+ messagePayload = options.resolveData();
172
163
  } else {
173
- messagePayload = await MessagePayload.create(this, options).resolveData();
164
+ messagePayload = MessagePayload.create(this, options).resolveData();
174
165
  }
175
166
 
176
- let { data, files } = await messagePayload.resolveFiles();
167
+ const { data, files } = await messagePayload.resolveFiles();
168
+ // New API
169
+ const attachments = await Util.getUploadURL(this.client, this.id, files);
170
+ const requestPromises = attachments.map(async attachment => {
171
+ await Util.uploadFile(files[attachment.id].file, attachment.upload_url);
172
+ return {
173
+ id: attachment.id,
174
+ filename: files[attachment.id].name,
175
+ uploaded_filename: attachment.upload_filename,
176
+ description: files[attachment.id].description,
177
+ duration_secs: files[attachment.id].duration_secs,
178
+ waveform: files[attachment.id].waveform,
179
+ };
180
+ });
181
+ const attachmentsData = await Promise.all(requestPromises);
182
+ attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
183
+ data.attachments = attachmentsData;
184
+ // Empty Files
185
+ const d = await this.client.api.channels[this.id].messages.post({ data });
177
186
 
178
- if (typeof options == 'object' && typeof options.usingNewAttachmentAPI !== 'boolean') {
179
- options.usingNewAttachmentAPI = this.client.options.usingNewAttachmentAPI;
180
- }
187
+ return this.messages.cache.get(d.id) ?? this.messages._add(d);
188
+ }
181
189
 
182
- if (options?.usingNewAttachmentAPI === true) {
183
- const attachments = await getAttachments(this.client, this.id, ...files);
184
- const requestPromises = attachments.map(async attachment => {
185
- await uploadFile(files[attachment.id].file, attachment.upload_url);
186
- return {
187
- id: attachment.id,
188
- filename: files[attachment.id].name,
189
- uploaded_filename: attachment.upload_filename,
190
- description: files[attachment.id].description,
191
- duration_secs: files[attachment.id].duration_secs,
192
- waveform: files[attachment.id].waveform,
193
- };
194
- });
195
- const attachmentsData = await Promise.all(requestPromises);
196
- attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
197
- data.attachments = attachmentsData;
198
- files = [];
199
- }
190
+ searchInteractionFromGuildAndPrivateChannel() {
191
+ // Support Slash / ContextMenu
192
+ // API https://canary.discord.com/api/v9/guilds/:id/application-command-index // Guild
193
+ // https://canary.discord.com/api/v9/channels/:id/application-command-index // DM Channel
194
+ // Updated: 07/01/2023
195
+ return this.client.api[this.guild ? 'guilds' : 'channels'][this.guild?.id || this.id][
196
+ 'application-command-index'
197
+ ].get();
198
+ }
200
199
 
201
- const d = await this.client.api.channels[this.id].messages.post({ data, files });
200
+ searchInteractionUserApps() {
201
+ return this.client.api.users['@me']['application-command-index'].get();
202
+ }
202
203
 
203
- return this.messages.cache.get(d.id) ?? this.messages._add(d);
204
+ searchInteraction() {
205
+ return Promise.all([this.searchInteractionFromGuildAndPrivateChannel(), this.searchInteractionUserApps()]).then(
206
+ ([dataA, dataB]) => ({
207
+ applications: [...dataA.applications, ...dataB.applications],
208
+ application_commands: [...dataA.application_commands, ...dataB.application_commands],
209
+ }),
210
+ );
211
+ }
212
+
213
+ async sendSlash(botOrApplicationId, commandNameString, ...args) {
214
+ // Parse commandName /role add user
215
+ const cmd = commandNameString.trim().split(' ');
216
+ // Ex: role add user => [role, add, user]
217
+ // Parse: name, subGr, sub
218
+ const commandName = validateName(cmd[0]);
219
+ // Parse: role
220
+ const sub = cmd.slice(1);
221
+ // Parse: [add, user]
222
+ for (let i = 0; i < sub.length; i++) {
223
+ if (sub.length > 2) {
224
+ throw new Error('INVALID_COMMAND_NAME', cmd);
225
+ }
226
+ validateName(sub[i]);
227
+ }
228
+ // Search all
229
+ const data = await this.searchInteraction();
230
+ // Find command...
231
+ const filterCommand = data.application_commands.filter(obj =>
232
+ // Filter: name | name_default
233
+ [obj.name, obj.name_default].includes(commandName),
234
+ );
235
+ // Filter Bot
236
+ botOrApplicationId = this.client.users.resolveId(botOrApplicationId);
237
+ const application = data.applications.find(
238
+ obj => obj.id == botOrApplicationId || obj.bot?.id == botOrApplicationId,
239
+ );
240
+ // Find Command with application
241
+ const command = filterCommand.find(command => command.application_id == application.id);
242
+ if (!command) {
243
+ throw new Error('INVALID_APPLICATION_COMMAND', application.id);
244
+ }
245
+ args = args.flat(2);
246
+ let optionFormat = [];
247
+ let attachments = [];
248
+ let optionsMaxdepth, subGroup, subCommand;
249
+ if (sub.length == 2) {
250
+ // Subcommand Group > Subcommand
251
+ // Find Sub group
252
+ subGroup = command.options.find(
253
+ obj =>
254
+ obj.type == ApplicationCommandOptionTypes.SUB_COMMAND_GROUP && [obj.name, obj.name_default].includes(sub[0]),
255
+ );
256
+ if (!subGroup) throw new Error('SLASH_COMMAND_SUB_COMMAND_GROUP_INVALID', sub[0]);
257
+ // Find Sub
258
+ subCommand = subGroup.options.find(
259
+ obj => obj.type == ApplicationCommandOptionTypes.SUB_COMMAND && [obj.name, obj.name_default].includes(sub[1]),
260
+ );
261
+ if (!subCommand) throw new Error('SLASH_COMMAND_SUB_COMMAND_INVALID', sub[1]);
262
+ // Options
263
+ optionsMaxdepth = subCommand.options;
264
+ } else if (sub.length == 1) {
265
+ // Subcommand
266
+ subCommand = command.options.find(
267
+ obj => obj.type == ApplicationCommandOptionTypes.SUB_COMMAND && [obj.name, obj.name_default].includes(sub[0]),
268
+ );
269
+ if (!subCommand) throw new Error('SLASH_COMMAND_SUB_COMMAND_INVALID', sub[0]);
270
+ // Options
271
+ optionsMaxdepth = subCommand.options;
272
+ } else {
273
+ optionsMaxdepth = command.options;
274
+ }
275
+ const valueRequired = optionsMaxdepth?.filter(o => o.required).length || 0;
276
+ for (let i = 0; i < Math.min(args.length, optionsMaxdepth?.length || 0); i++) {
277
+ const optionInput = optionsMaxdepth[i];
278
+ const value = args[i];
279
+ const parseData = await parseOption(
280
+ this.client,
281
+ optionInput,
282
+ value,
283
+ optionFormat,
284
+ attachments,
285
+ command,
286
+ application.id,
287
+ this.guild?.id,
288
+ this.id,
289
+ subGroup,
290
+ subCommand,
291
+ );
292
+ optionFormat = parseData.optionFormat;
293
+ attachments = parseData.attachments;
294
+ }
295
+ if (valueRequired > args.length) {
296
+ throw new Error('SLASH_COMMAND_REQUIRED_OPTIONS_MISSING', valueRequired, optionFormat.length);
297
+ }
298
+ // Post
299
+ let postData;
300
+ if (subGroup) {
301
+ postData = [
302
+ {
303
+ type: ApplicationCommandOptionTypes.SUB_COMMAND_GROUP,
304
+ name: subGroup.name,
305
+ options: [
306
+ {
307
+ type: ApplicationCommandOptionTypes.SUB_COMMAND,
308
+ name: subCommand.name,
309
+ options: optionFormat,
310
+ },
311
+ ],
312
+ },
313
+ ];
314
+ } else if (subCommand) {
315
+ postData = [
316
+ {
317
+ type: ApplicationCommandOptionTypes.SUB_COMMAND,
318
+ name: subCommand.name,
319
+ options: optionFormat,
320
+ },
321
+ ];
322
+ } else {
323
+ postData = optionFormat;
324
+ }
325
+ const nonce = SnowflakeUtil.generate();
326
+ const body = createPostData(
327
+ this.client,
328
+ false,
329
+ application.id,
330
+ nonce,
331
+ this.guild?.id,
332
+ Boolean(command.guild_id),
333
+ this.id,
334
+ command.version,
335
+ command.id,
336
+ command.name_default || command.name,
337
+ command.type,
338
+ postData,
339
+ attachments,
340
+ );
341
+ this.client.api.interactions.post({
342
+ data: body,
343
+ usePayloadJSON: true,
344
+ });
345
+ return Util.createPromiseInteraction(this.client, nonce, 5000);
204
346
  }
205
347
 
206
348
  /**
@@ -261,101 +403,6 @@ class TextBasedChannel {
261
403
  });
262
404
  }
263
405
 
264
- /**
265
- * Creates a component interaction collector.
266
- * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
267
- * @returns {InteractionCollector}
268
- * @example
269
- * // Create a button interaction collector
270
- * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
271
- * const collector = channel.createMessageComponentCollector({ filter, time: 15_000 });
272
- * collector.on('collect', i => console.log(`Collected ${i.customId}`));
273
- * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
274
- */
275
- createMessageComponentCollector(options = {}) {
276
- return new InteractionCollector(this.client, {
277
- ...options,
278
- interactionType: InteractionTypes.MESSAGE_COMPONENT,
279
- channel: this,
280
- });
281
- }
282
-
283
- /**
284
- * Collects a single component interaction that passes the filter.
285
- * The Promise will reject if the time expires.
286
- * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector
287
- * @returns {Promise<MessageComponentInteraction>}
288
- * @example
289
- * // Collect a message component interaction
290
- * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';
291
- * channel.awaitMessageComponent({ filter, time: 15_000 })
292
- * .then(interaction => console.log(`${interaction.customId} was clicked!`))
293
- * .catch(console.error);
294
- */
295
- awaitMessageComponent(options = {}) {
296
- const _options = { ...options, max: 1 };
297
- return new Promise((resolve, reject) => {
298
- const collector = this.createMessageComponentCollector(_options);
299
- collector.once('end', (interactions, reason) => {
300
- const interaction = interactions.first();
301
- if (interaction) resolve(interaction);
302
- else reject(new Error('INTERACTION_COLLECTOR_ERROR', reason));
303
- });
304
- });
305
- }
306
-
307
- /**
308
- * Bulk deletes given messages that are newer than two weeks.
309
- * @param {Collection<Snowflake, Message>|MessageResolvable[]|number} messages
310
- * Messages or number of messages to delete
311
- * @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
312
- * @returns {Promise<Collection<Snowflake, Message|undefined>>} Returns the deleted messages
313
- * @example
314
- * // Bulk delete messages
315
- * channel.bulkDelete(5)
316
- * .then(messages => console.log(`Bulk deleted ${messages.size} messages`))
317
- * .catch(console.error);
318
- */
319
- async bulkDelete(messages, filterOld = false) {
320
- if (!this.client.user.bot) throw new Error('INVALID_USER_METHOD');
321
- if (Array.isArray(messages) || messages instanceof Collection) {
322
- let messageIds = messages instanceof Collection ? [...messages.keys()] : messages.map(m => m.id ?? m);
323
- if (filterOld) {
324
- messageIds = messageIds.filter(id => Date.now() - SnowflakeUtil.timestampFrom(id) < MaxBulkDeletableMessageAge);
325
- }
326
- if (messageIds.length === 0) return new Collection();
327
- if (messageIds.length === 1) {
328
- await this.client.api.channels(this.id).messages(messageIds[0]).delete();
329
- const message = this.client.actions.MessageDelete.getMessage(
330
- {
331
- message_id: messageIds[0],
332
- },
333
- this,
334
- );
335
- return message ? new Collection([[message.id, message]]) : new Collection();
336
- }
337
- await this.client.api.channels[this.id].messages['bulk-delete'].post({ data: { messages: messageIds } });
338
- return messageIds.reduce(
339
- (col, id) =>
340
- col.set(
341
- id,
342
- this.client.actions.MessageDeleteBulk.getMessage(
343
- {
344
- message_id: id,
345
- },
346
- this,
347
- ),
348
- ),
349
- new Collection(),
350
- );
351
- }
352
- if (!isNaN(messages)) {
353
- const msgs = await this.messages.fetch({ limit: messages });
354
- return this.bulkDelete(msgs, filterOld);
355
- }
356
- throw new TypeError('MESSAGE_BULK_DELETE_TYPE');
357
- }
358
-
359
406
  /**
360
407
  * Fetches all webhooks for the channel.
361
408
  * @returns {Promise<Collection<Snowflake, Webhook>>}
@@ -414,139 +461,23 @@ class TextBasedChannel {
414
461
  return this.edit({ nsfw }, reason);
415
462
  }
416
463
 
417
- /**
418
- * Search Slash Command (return raw data)
419
- * @param {Snowflake} applicationId Application ID
420
- * @param {?ApplicationCommandType} type Command Type
421
- * @returns {Object}
422
- */
423
- searchInteraction(applicationId, type = 'CHAT_INPUT') {
424
- switch (type) {
425
- case 'USER':
426
- case 2:
427
- type = 2;
428
- break;
429
- case 'MESSAGE':
430
- case 3:
431
- type = 3;
432
- break;
433
- default:
434
- type = 1;
435
- break;
436
- }
437
- return this.client.api.channels[this.id]['application-commands'].search.get({
438
- query: {
439
- type,
440
- application_id: applicationId,
441
- },
442
- });
443
- }
444
-
445
- /**
446
- * Send Slash to this channel
447
- * @param {UserResolvable} bot Bot user (BotID, not applicationID)
448
- * @param {string} commandString Command name (and sub / group formats)
449
- * @param {...?any|any[]} args Command arguments
450
- * @returns {Promise<InteractionResponse>}
451
- * @example
452
- * // Send a basic slash
453
- * channel.sendSlash('botid', 'ping')
454
- * .then(console.log)
455
- * .catch(console.error);
456
- * @example
457
- * // Send a remote file
458
- * channel.sendSlash('botid', 'emoji upload', 'https://cdn.discordapp.com/icons/222078108977594368/6e1019b3179d71046e463a75915e7244.png?size=2048', 'test')
459
- * .then(console.log)
460
- * .catch(console.error);
461
- * @see {@link https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/SlashCommand.md}
462
- */
463
- async sendSlash(bot, commandString, ...args) {
464
- const perms =
465
- this.type != 'DM'
466
- ? this.permissionsFor(this.client.user).toArray()
467
- : ['USE_APPLICATION_COMMANDS', `${this.recipient.relationships == 'BLOCKED' ? '' : 'SEND_MESSAGES'}`];
468
- if (!perms.includes('SEND_MESSAGES')) {
469
- throw new Error(
470
- 'INTERACTION_SEND_FAILURE',
471
- `Cannot send Slash to ${this.toString()} ${
472
- this.recipient ? 'because bot has been blocked' : 'due to missing SEND_MESSAGES permission'
473
- }`,
474
- );
475
- }
476
- if (!perms.includes('USE_APPLICATION_COMMANDS')) {
477
- throw new Error(
478
- 'INTERACTION_SEND_FAILURE',
479
- `Cannot send Slash to ${this.toString()} due to missing USE_APPLICATION_COMMANDS permission`,
480
- );
481
- }
482
- args = args.flat(2);
483
- const cmd = commandString.trim().split(' ');
484
- // Validate CommandName
485
- const commandName = validateName(cmd[0]);
486
- const sub = cmd.slice(1);
487
- for (let i = 0; i < sub.length; i++) {
488
- if (sub.length > 2) {
489
- throw new Error('INVALID_COMMAND_NAME', cmd);
490
- }
491
- validateName(sub[i]);
492
- }
493
- if (!bot) throw new Error('MUST_SPECIFY_BOT');
494
- const botId = this.client.users.resolveId(bot);
495
- const user = await this.client.users.fetch(botId).catch(() => {});
496
- if (!user || !user.bot || !user.application) {
497
- throw new Error('botId is not a bot or does not have an application slash command');
498
- }
499
- if (user._partial) await user.getProfile().catch(() => {});
500
- if (!commandName || typeof commandName !== 'string') throw new Error('Command name is required');
501
- const data = await this.searchInteraction(user.application?.id ?? user.id, 'CHAT_INPUT');
502
- for (const command of data.application_commands) {
503
- if (user.id == command.application_id || user.application.id == command.application_id) {
504
- user.application?.commands?._add(command, true);
505
- }
506
- }
507
- // Remove
508
- const commandTarget = user.application?.commands?.cache.find(
509
- c => c.name === commandName && c.type === 'CHAT_INPUT',
510
- );
511
- if (!commandTarget) {
512
- throw new Error(
513
- 'INTERACTION_SEND_FAILURE',
514
- `SlashCommand ${commandName} is not found (With search)\nDebug:\n+ botId: ${botId} (ApplicationId: ${
515
- user.application?.id
516
- })\n+ args: ${args.join(' | ') || null}`,
517
- );
518
- }
519
- return commandTarget.sendSlashCommand(
520
- new (Message())(this.client, {
521
- channel_id: this.id,
522
- guild_id: this.guild?.id || null,
523
- author: this.client.user,
524
- content: '',
525
- id: this.client.user.id,
526
- }),
527
- sub && sub.length > 0 ? sub : [],
528
- args && args.length ? args : [],
529
- );
530
- }
531
-
532
464
  static applyToClass(structure, full = false, ignore = []) {
533
465
  const props = ['send'];
534
466
  if (full) {
535
467
  props.push(
468
+ 'sendSlash',
469
+ 'searchInteraction',
470
+ 'searchInteractionFromGuildAndPrivateChannel',
471
+ 'searchInteractionUserApps',
536
472
  'lastMessage',
537
473
  'lastPinAt',
538
- 'bulkDelete',
539
474
  'sendTyping',
540
475
  'createMessageCollector',
541
476
  'awaitMessages',
542
- 'createMessageComponentCollector',
543
- 'awaitMessageComponent',
544
477
  'fetchWebhooks',
545
478
  'createWebhook',
546
479
  'setRateLimitPerUser',
547
480
  'setNSFW',
548
- 'sendSlash',
549
- 'searchInteraction',
550
481
  );
551
482
  }
552
483
  for (const prop of props) {
@@ -564,3 +495,225 @@ module.exports = TextBasedChannel;
564
495
 
565
496
  // Fixes Circular
566
497
  const MessageManager = require('../../managers/MessageManager');
498
+
499
+ // Utils
500
+ function parseChoices(parent, list_choices, value) {
501
+ if (value !== undefined) {
502
+ if (Array.isArray(list_choices) && list_choices.length) {
503
+ const choice = list_choices.find(c => [c.name, c.value].includes(value));
504
+ if (choice) {
505
+ return choice.value;
506
+ } else {
507
+ throw new Error('INVALID_SLASH_COMMAND_CHOICES', parent, value);
508
+ }
509
+ } else {
510
+ return value;
511
+ }
512
+ } else {
513
+ return undefined;
514
+ }
515
+ }
516
+
517
+ async function addDataFromAttachment(value, client, channelId, attachments) {
518
+ value = await MessagePayload.resolveFile(value);
519
+ if (!value?.file) {
520
+ throw new TypeError('The attachment data must be a BufferResolvable or Stream or FileOptions of MessageAttachment');
521
+ }
522
+ const data = await Util.getUploadURL(client, channelId, [value]);
523
+ await Util.uploadFile(value.file, data[0].upload_url);
524
+ const id = attachments.length;
525
+ attachments.push({
526
+ id,
527
+ filename: value.name,
528
+ uploaded_filename: data[0].upload_filename,
529
+ });
530
+ return {
531
+ id,
532
+ attachments,
533
+ };
534
+ }
535
+
536
+ async function parseOption(
537
+ client,
538
+ optionCommand,
539
+ value,
540
+ optionFormat,
541
+ attachments,
542
+ command,
543
+ applicationId,
544
+ guildId,
545
+ channelId,
546
+ subGroup,
547
+ subCommand,
548
+ ) {
549
+ const data = {
550
+ type: optionCommand.type,
551
+ name: optionCommand.name,
552
+ };
553
+ if (value !== undefined) {
554
+ switch (optionCommand.type) {
555
+ case ApplicationCommandOptionTypes.BOOLEAN:
556
+ case 'BOOLEAN': {
557
+ data.value = Boolean(value);
558
+ break;
559
+ }
560
+ case ApplicationCommandOptionTypes.INTEGER:
561
+ case 'INTEGER': {
562
+ data.value = Number(value);
563
+ break;
564
+ }
565
+ case ApplicationCommandOptionTypes.ATTACHMENT:
566
+ case 'ATTACHMENT': {
567
+ const parseData = await addDataFromAttachment(value, client, channelId, attachments);
568
+ data.value = parseData.id;
569
+ attachments = parseData.attachments;
570
+ break;
571
+ }
572
+ case ApplicationCommandOptionTypes.SUB_COMMAND_GROUP:
573
+ case 'SUB_COMMAND_GROUP': {
574
+ break;
575
+ }
576
+ default: {
577
+ value = parseChoices(optionCommand.name, optionCommand.choices, value);
578
+ if (optionCommand.autocomplete) {
579
+ const nonce = SnowflakeUtil.generate();
580
+ // Post
581
+ let postData;
582
+ if (subGroup) {
583
+ postData = [
584
+ {
585
+ type: ApplicationCommandOptionTypes.SUB_COMMAND_GROUP,
586
+ name: subGroup.name,
587
+ options: [
588
+ {
589
+ type: ApplicationCommandOptionTypes.SUB_COMMAND,
590
+ name: subCommand.name,
591
+ options: [
592
+ {
593
+ type: optionCommand.type,
594
+ name: optionCommand.name,
595
+ value,
596
+ focused: true,
597
+ },
598
+ ],
599
+ },
600
+ ],
601
+ },
602
+ ];
603
+ } else if (subCommand) {
604
+ postData = [
605
+ {
606
+ type: ApplicationCommandOptionTypes.SUB_COMMAND,
607
+ name: subCommand.name,
608
+ options: [
609
+ {
610
+ type: optionCommand.type,
611
+ name: optionCommand.name,
612
+ value,
613
+ focused: true,
614
+ },
615
+ ],
616
+ },
617
+ ];
618
+ } else {
619
+ postData = [
620
+ {
621
+ type: optionCommand.type,
622
+ name: optionCommand.name,
623
+ value,
624
+ focused: true,
625
+ },
626
+ ];
627
+ }
628
+ const body = createPostData(
629
+ client,
630
+ true,
631
+ applicationId,
632
+ nonce,
633
+ guildId,
634
+ Boolean(command.guild_id),
635
+ channelId,
636
+ command.version,
637
+ command.id,
638
+ command.name_default || command.name,
639
+ command.type,
640
+ postData,
641
+ [],
642
+ );
643
+ await client.api.interactions.post({
644
+ data: body,
645
+ });
646
+ data.value = await awaitAutocomplete(client, nonce, value);
647
+ } else {
648
+ data.value = value;
649
+ }
650
+ }
651
+ }
652
+ optionFormat.push(data);
653
+ }
654
+ return {
655
+ optionFormat,
656
+ attachments,
657
+ };
658
+ }
659
+
660
+ function awaitAutocomplete(client, nonce, defaultValue) {
661
+ return new Promise(resolve => {
662
+ const handler = data => {
663
+ if (data.t !== 'APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE') return;
664
+ if (data.d?.nonce !== nonce) return;
665
+ clearTimeout(timeout);
666
+ client.removeListener(Events.UNHANDLED_PACKET, handler);
667
+ client.decrementMaxListeners();
668
+ if (data.d.choices.length >= 1) {
669
+ resolve(data.d.choices[0].value);
670
+ } else {
671
+ resolve(defaultValue);
672
+ }
673
+ };
674
+ const timeout = setTimeout(() => {
675
+ client.removeListener(Events.UNHANDLED_PACKET, handler);
676
+ client.decrementMaxListeners();
677
+ resolve(defaultValue);
678
+ }, 5_000).unref();
679
+ client.incrementMaxListeners();
680
+ client.on(Events.UNHANDLED_PACKET, handler);
681
+ });
682
+ }
683
+
684
+ function createPostData(
685
+ client,
686
+ isAutocomplete = false,
687
+ applicationId,
688
+ nonce,
689
+ guildId,
690
+ isGuildCommand,
691
+ channelId,
692
+ commandVersion,
693
+ commandId,
694
+ commandName,
695
+ commandType,
696
+ postData,
697
+ attachments = [],
698
+ ) {
699
+ const data = {
700
+ type: isAutocomplete ? InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE : InteractionTypes.APPLICATION_COMMAND,
701
+ application_id: applicationId,
702
+ guild_id: guildId,
703
+ channel_id: channelId,
704
+ session_id: client.sessionId,
705
+ data: {
706
+ version: commandVersion,
707
+ id: commandId,
708
+ name: commandName,
709
+ type: commandType,
710
+ options: postData,
711
+ attachments: attachments,
712
+ },
713
+ nonce,
714
+ };
715
+ if (isGuildCommand) {
716
+ data.data.guild_id = guildId;
717
+ }
718
+ return data;
719
+ }