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.
- package/README.md +18 -35
- package/package.json +85 -100
- package/src/client/BaseClient.js +3 -4
- package/src/client/Client.js +249 -530
- package/src/client/actions/Action.js +18 -13
- package/src/client/actions/ActionsManager.js +7 -1
- package/src/client/actions/AutoModerationActionExecution.js +1 -0
- package/src/client/actions/AutoModerationRuleCreate.js +1 -0
- package/src/client/actions/AutoModerationRuleDelete.js +1 -0
- package/src/client/actions/AutoModerationRuleUpdate.js +1 -0
- package/src/client/actions/GuildMemberRemove.js +0 -1
- package/src/client/actions/GuildMemberUpdate.js +0 -1
- package/src/client/actions/MessageCreate.js +0 -4
- package/src/client/actions/PresenceUpdate.js +17 -16
- package/src/client/websocket/WebSocketManager.js +11 -31
- package/src/client/websocket/WebSocketShard.js +39 -38
- package/src/client/websocket/handlers/CALL_CREATE.js +3 -3
- package/src/client/websocket/handlers/CALL_DELETE.js +2 -2
- package/src/client/websocket/handlers/CALL_UPDATE.js +2 -2
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +16 -13
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
- package/src/client/websocket/handlers/GUILD_CREATE.js +19 -13
- package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +0 -1
- package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +1 -0
- package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_ADD.js +22 -0
- package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_REMOVE.js +12 -0
- package/src/client/websocket/handlers/READY.js +90 -140
- package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +7 -5
- package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +7 -5
- package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +32 -9
- package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +2 -8
- package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
- package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +78 -0
- package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +1 -5
- package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +12 -0
- package/src/client/websocket/handlers/index.js +17 -20
- package/src/errors/Messages.js +25 -69
- package/src/index.js +13 -43
- package/src/managers/ApplicationCommandManager.js +9 -12
- package/src/managers/ApplicationCommandPermissionsManager.js +3 -11
- package/src/managers/ChannelManager.js +2 -3
- package/src/managers/ClientUserSettingManager.js +162 -280
- package/src/managers/GuildBanManager.js +47 -1
- package/src/managers/GuildChannelManager.js +2 -16
- package/src/managers/GuildForumThreadManager.js +24 -30
- package/src/managers/GuildManager.js +1 -1
- package/src/managers/GuildMemberManager.js +50 -222
- package/src/managers/GuildSettingManager.js +22 -15
- package/src/managers/MessageManager.js +42 -44
- package/src/managers/PermissionOverwriteManager.js +1 -1
- package/src/managers/ReactionUserManager.js +5 -5
- package/src/managers/RelationshipManager.js +83 -76
- package/src/managers/ThreadManager.js +12 -45
- package/src/managers/ThreadMemberManager.js +1 -1
- package/src/managers/UserManager.js +6 -10
- package/src/managers/UserNoteManager.js +53 -0
- package/src/rest/APIRequest.js +48 -20
- package/src/rest/DiscordAPIError.js +17 -16
- package/src/rest/RESTManager.js +1 -21
- package/src/rest/RequestHandler.js +35 -21
- package/src/structures/ApplicationCommand.js +19 -456
- package/src/structures/ApplicationRoleConnectionMetadata.js +3 -0
- package/src/structures/AutoModerationRule.js +5 -5
- package/src/structures/AutocompleteInteraction.js +1 -0
- package/src/structures/BaseGuildTextChannel.js +10 -12
- package/src/structures/BaseGuildVoiceChannel.js +16 -18
- package/src/structures/{Call.js → CallState.js} +17 -12
- package/src/structures/CategoryChannel.js +2 -0
- package/src/structures/Channel.js +2 -3
- package/src/structures/ClientPresence.js +20 -19
- package/src/structures/ClientUser.js +117 -338
- package/src/structures/ContextMenuInteraction.js +1 -1
- package/src/structures/DMChannel.js +29 -92
- package/src/structures/ForumChannel.js +0 -10
- package/src/structures/GroupDMChannel.js +387 -0
- package/src/structures/Guild.js +135 -271
- package/src/structures/GuildAuditLogs.js +0 -5
- package/src/structures/GuildChannel.js +16 -2
- package/src/structures/GuildMember.js +27 -145
- package/src/structures/Interaction.js +1 -62
- package/src/structures/Invite.js +35 -52
- package/src/structures/Message.js +220 -203
- package/src/structures/MessageAttachment.js +11 -0
- package/src/structures/MessageButton.js +1 -67
- package/src/structures/MessageEmbed.js +1 -1
- package/src/structures/MessageMentions.js +3 -2
- package/src/structures/MessagePayload.js +6 -46
- package/src/structures/MessagePoll.js +238 -0
- package/src/structures/MessageReaction.js +1 -1
- package/src/structures/MessageSelectMenu.js +1 -252
- package/src/structures/Modal.js +70 -188
- package/src/structures/Presence.js +787 -129
- package/src/structures/Role.js +18 -2
- package/src/structures/SelectMenuInteraction.js +2 -151
- package/src/structures/Team.js +0 -49
- package/src/structures/TextInputComponent.js +0 -70
- package/src/structures/ThreadChannel.js +0 -19
- package/src/structures/User.js +145 -339
- package/src/structures/UserContextMenuInteraction.js +2 -2
- package/src/structures/VoiceState.js +74 -39
- package/src/structures/WebEmbed.js +38 -52
- package/src/structures/Webhook.js +17 -11
- package/src/structures/interfaces/Application.js +146 -23
- package/src/structures/interfaces/TextBasedChannel.js +409 -256
- package/src/util/ApplicationFlags.js +1 -1
- package/src/util/AttachmentFlags.js +38 -0
- package/src/util/Constants.js +120 -285
- package/src/util/Formatters.js +16 -2
- package/src/util/InviteFlags.js +29 -0
- package/src/util/LimitedCollection.js +1 -1
- package/src/util/Options.js +48 -74
- package/src/util/Permissions.js +15 -0
- package/src/util/PurchasedFlags.js +2 -0
- package/src/util/RemoteAuth.js +221 -356
- package/src/util/RoleFlags.js +37 -0
- package/src/util/Sweepers.js +1 -1
- package/src/util/Util.js +158 -32
- package/typings/enums.d.ts +24 -73
- package/typings/index.d.ts +978 -1288
- package/typings/rawDataTypes.d.ts +68 -9
- package/src/client/actions/InteractionCreate.js +0 -115
- package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +0 -23
- package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +0 -11
- package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +0 -55
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
- package/src/client/websocket/handlers/INTERACTION_CREATE.js +0 -16
- package/src/client/websocket/handlers/INTERACTION_FAILURE.js +0 -18
- package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +0 -30
- package/src/client/websocket/handlers/MESSAGE_ACK.js +0 -16
- package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
- package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
- package/src/managers/DeveloperPortalManager.js +0 -104
- package/src/managers/GuildApplicationCommandManager.js +0 -28
- package/src/managers/GuildFolderManager.js +0 -24
- package/src/managers/SessionManager.js +0 -57
- package/src/rest/CaptchaSolver.js +0 -132
- package/src/structures/ClientApplication.js +0 -204
- package/src/structures/DeveloperPortalApplication.js +0 -520
- package/src/structures/GuildFolder.js +0 -75
- package/src/structures/InteractionResponse.js +0 -114
- package/src/structures/PartialGroupDMChannel.js +0 -433
- package/src/structures/RichPresence.js +0 -722
- package/src/structures/Session.js +0 -81
- package/src/util/Voice.js +0 -1456
- package/src/util/arRPC/index.js +0 -229
- package/src/util/arRPC/process/detectable.json +0 -1
- package/src/util/arRPC/process/index.js +0 -102
- package/src/util/arRPC/process/native/index.js +0 -5
- package/src/util/arRPC/process/native/linux.js +0 -37
- package/src/util/arRPC/process/native/win32.js +0 -25
- package/src/util/arRPC/transports/ipc.js +0 -281
- 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 {
|
|
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
|
|
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 {
|
|
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 =
|
|
162
|
+
messagePayload = options.resolveData();
|
|
172
163
|
} else {
|
|
173
|
-
messagePayload =
|
|
164
|
+
messagePayload = MessagePayload.create(this, options).resolveData();
|
|
174
165
|
}
|
|
175
166
|
|
|
176
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
187
|
+
return this.messages.cache.get(d.id) ?? this.messages._add(d);
|
|
188
|
+
}
|
|
181
189
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
200
|
+
searchInteractionUserApps() {
|
|
201
|
+
return this.client.api.users['@me']['application-command-index'].get();
|
|
202
|
+
}
|
|
202
203
|
|
|
203
|
-
|
|
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
|
+
}
|