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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { Buffer } = require('node:buffer');
|
|
4
4
|
const BaseMessageComponent = require('./BaseMessageComponent');
|
|
5
5
|
const MessageEmbed = require('./MessageEmbed');
|
|
6
|
-
const
|
|
6
|
+
const MessagePoll = require('./MessagePoll');
|
|
7
7
|
const { RangeError } = require('../errors');
|
|
8
8
|
const ActivityFlags = require('../util/ActivityFlags');
|
|
9
9
|
const DataResolver = require('../util/DataResolver');
|
|
@@ -42,7 +42,6 @@ class MessagePayload {
|
|
|
42
42
|
* @property {Buffer|string|Stream} attachment The original attachment that generated this file
|
|
43
43
|
* @property {string} name The name of this file
|
|
44
44
|
* @property {Buffer|Stream} file The file to be sent to the API
|
|
45
|
-
* @extends {APIAttachment}
|
|
46
45
|
*/
|
|
47
46
|
|
|
48
47
|
/**
|
|
@@ -52,15 +51,6 @@ class MessagePayload {
|
|
|
52
51
|
this.files = null;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
/**
|
|
56
|
-
* Whether or not using new API to upload files
|
|
57
|
-
* @type {boolean}
|
|
58
|
-
* @readonly
|
|
59
|
-
*/
|
|
60
|
-
get usingNewAttachmentAPI() {
|
|
61
|
-
return Boolean(this.options?.usingNewAttachmentAPI);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
54
|
/**
|
|
65
55
|
* Whether or not the target is a {@link Webhook} or a {@link WebhookClient}
|
|
66
56
|
* @type {boolean}
|
|
@@ -133,12 +123,12 @@ class MessagePayload {
|
|
|
133
123
|
* Resolves data.
|
|
134
124
|
* @returns {MessagePayload}
|
|
135
125
|
*/
|
|
136
|
-
|
|
126
|
+
resolveData() {
|
|
137
127
|
if (this.data) return this;
|
|
138
128
|
const isInteraction = this.isInteraction;
|
|
139
129
|
const isWebhook = this.isWebhook;
|
|
140
130
|
|
|
141
|
-
|
|
131
|
+
const content = this.makeContent();
|
|
142
132
|
const tts = Boolean(this.options.tts);
|
|
143
133
|
|
|
144
134
|
let nonce;
|
|
@@ -208,37 +198,6 @@ class MessagePayload {
|
|
|
208
198
|
this.options.attachments = attachments;
|
|
209
199
|
}
|
|
210
200
|
|
|
211
|
-
if (this.options.embeds) {
|
|
212
|
-
if (!Array.isArray(this.options.embeds)) {
|
|
213
|
-
this.options.embeds = [this.options.embeds];
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const webembeds = this.options.embeds.filter(e => e instanceof WebEmbed);
|
|
217
|
-
this.options.embeds = this.options.embeds.filter(e => !(e instanceof WebEmbed));
|
|
218
|
-
|
|
219
|
-
if (webembeds.length > 0) {
|
|
220
|
-
if (!content) content = '';
|
|
221
|
-
// Add hidden embed link
|
|
222
|
-
content += `\n${WebEmbed.hiddenEmbed} \n`;
|
|
223
|
-
if (webembeds.length > 1) {
|
|
224
|
-
console.warn('[WARN] Multiple webembeds are not supported, this will be ignored.');
|
|
225
|
-
}
|
|
226
|
-
// Const embed = webembeds[0];
|
|
227
|
-
for (const webE of webembeds) {
|
|
228
|
-
const data = await webE.toMessage();
|
|
229
|
-
content += `\n${data}`;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
// Check content
|
|
233
|
-
if (typeof content == 'string' && content.length > 2000) {
|
|
234
|
-
console.warn('[WARN] Content is longer than 2000 characters.');
|
|
235
|
-
}
|
|
236
|
-
if (typeof content == 'string' && content.length > 4000) {
|
|
237
|
-
// Max length if user has nitro boost
|
|
238
|
-
throw new RangeError('MESSAGE_EMBED_LINK_LENGTH');
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
201
|
// Activity
|
|
243
202
|
let activity;
|
|
244
203
|
if (
|
|
@@ -247,7 +206,7 @@ class MessagePayload {
|
|
|
247
206
|
this.options.activity.type
|
|
248
207
|
) {
|
|
249
208
|
const type = ActivityFlags.resolve(this.options.activity.type);
|
|
250
|
-
const sessionId = this.target.client.
|
|
209
|
+
const sessionId = this.target.client.sessionId;
|
|
251
210
|
const partyId = this.options.activity.partyId;
|
|
252
211
|
activity = {
|
|
253
212
|
type,
|
|
@@ -272,6 +231,7 @@ class MessagePayload {
|
|
|
272
231
|
attachments: this.options.attachments,
|
|
273
232
|
sticker_ids: this.options.stickers?.map(sticker => sticker.id ?? sticker),
|
|
274
233
|
thread_name: threadName,
|
|
234
|
+
poll: this.options.poll instanceof MessagePoll ? this.options.poll.toJSON() : this.options.poll,
|
|
275
235
|
};
|
|
276
236
|
return this;
|
|
277
237
|
}
|
|
@@ -348,7 +308,7 @@ module.exports = MessagePayload;
|
|
|
348
308
|
|
|
349
309
|
/**
|
|
350
310
|
* A target for a message.
|
|
351
|
-
* @typedef {TextBasedChannels|
|
|
311
|
+
* @typedef {TextBasedChannels|User|GuildMember|Webhook|WebhookClient|Interaction|InteractionWebhook|
|
|
352
312
|
* Message|MessageManager} MessageTarget
|
|
353
313
|
*/
|
|
354
314
|
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Collection } = require('@discordjs/collection');
|
|
4
|
+
const { MessagePollLayoutTypes } = require('../util/Constants');
|
|
5
|
+
const Util = require('../util/Util');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents the poll object has a lot of levels and nested structures. It was also designed to support future extensibility, so some fields may appear to be more complex than necessary.
|
|
9
|
+
*/
|
|
10
|
+
class MessagePoll {
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object} data Message poll to clone or raw data
|
|
13
|
+
*/
|
|
14
|
+
constructor(data = {}) {
|
|
15
|
+
this._patch(data);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_patch(data = {}) {
|
|
19
|
+
if (data?.constructor?.name == 'MessagePoll') data = data.toJSON();
|
|
20
|
+
/**
|
|
21
|
+
* The poll media object is a common object that backs both the question and answers. For now, `question` only supports `text`, while `answers` can have an optional `emoji`.
|
|
22
|
+
* @see {@link https://docs.discord.sex/resources/message#poll-media-structure}
|
|
23
|
+
* @typedef {Object} MessagePollMedia
|
|
24
|
+
* @property {?string} text The text of the field (max 300 characters for question, 55 characters for answer)
|
|
25
|
+
* @property {?RawEmoji} emoji The emoji of the field
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
if ('question' in data) {
|
|
29
|
+
/**
|
|
30
|
+
* The question of the poll
|
|
31
|
+
* @type {?MessagePollMedia}
|
|
32
|
+
*/
|
|
33
|
+
this.question = this._resolvePollMedia(data.question);
|
|
34
|
+
} else {
|
|
35
|
+
this.question ??= null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (data.answers?.length) {
|
|
39
|
+
/**
|
|
40
|
+
* The answers available in the poll
|
|
41
|
+
* @type {Collection<number, MessagePollMedia>}
|
|
42
|
+
*/
|
|
43
|
+
this.answers = new Collection();
|
|
44
|
+
|
|
45
|
+
data.answers.forEach((obj, index) => {
|
|
46
|
+
this.answers.set(obj?.answer_id || index + 1, this._resolvePollMedia(obj.poll_media));
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
this.answers ??= new Collection();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if ('layout_type' in data) {
|
|
53
|
+
/**
|
|
54
|
+
* The layout type of the poll
|
|
55
|
+
* @type {?MessagePollLayoutTypes}
|
|
56
|
+
*/
|
|
57
|
+
this.layoutType = MessagePollLayoutTypes[data.layout_type];
|
|
58
|
+
} else {
|
|
59
|
+
this.layoutType ??= MessagePollLayoutTypes[1]; // Default type
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if ('allow_multiselect' in data) {
|
|
63
|
+
/**
|
|
64
|
+
* Whether a user can select multiple answers
|
|
65
|
+
* @type {boolean}
|
|
66
|
+
*/
|
|
67
|
+
this.allowMultiSelect = !!data.allow_multiselect;
|
|
68
|
+
} else {
|
|
69
|
+
this.allowMultiSelect ??= false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if ('expiry' in data) {
|
|
73
|
+
/**
|
|
74
|
+
* When the poll ends
|
|
75
|
+
* @type {?Date}
|
|
76
|
+
*/
|
|
77
|
+
this.expiry = new Date(data.expiry);
|
|
78
|
+
} else {
|
|
79
|
+
this.expiry ??= null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if ('duration' in data) {
|
|
83
|
+
/**
|
|
84
|
+
* Number of hours the poll should be open for (max 32 days, default 1)
|
|
85
|
+
* @type {?Number}
|
|
86
|
+
*/
|
|
87
|
+
this.duration = data.duration;
|
|
88
|
+
} else {
|
|
89
|
+
this.duration ??= null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ('results' in data) {
|
|
93
|
+
/**
|
|
94
|
+
* Poll Results Structure
|
|
95
|
+
* @see {@link https://docs.discord.sex/resources/message#poll-results-structure}
|
|
96
|
+
* @typedef {Object} MessagePollResult
|
|
97
|
+
* @property {boolean} isFinalized Whether the votes have been precisely counted
|
|
98
|
+
* @property {Collection<number, MessagePollResultAnswerCount>} answerCounts The counts for each answer
|
|
99
|
+
*/
|
|
100
|
+
/**
|
|
101
|
+
* Poll Answer Count Structure
|
|
102
|
+
* @see {@link https://docs.discord.sex/resources/message#poll-answer-count-structure}
|
|
103
|
+
* @typedef {Object} MessagePollResultAnswerCount
|
|
104
|
+
* @property {MessagePollMedia} answer answer
|
|
105
|
+
* @property {number} count The number of votes for this answer
|
|
106
|
+
* @property {boolean} selfVoted Whether the current user voted for this answer
|
|
107
|
+
*/
|
|
108
|
+
/**
|
|
109
|
+
* In a nutshell, this contains the number of votes for each answer.
|
|
110
|
+
* The `results` field may be not present in certain responses where, as an implementation detail,
|
|
111
|
+
* Discord does not fetch the poll results in the backend.
|
|
112
|
+
* This should be treated as "unknown results", as opposed to "no results".
|
|
113
|
+
* You can keep using the results if you have previously received them through other means.
|
|
114
|
+
* Due to the intricacies of counting at scale, while a poll is in progress the results may not
|
|
115
|
+
* be perfectly accurate. They usually are accurate, and shouldn't deviate significantly — it's
|
|
116
|
+
* just difficult to make guarantees. To compensate for this, after a poll is finished there is
|
|
117
|
+
* a background job which performs a final, accurate tally of votes. This tally concludes once
|
|
118
|
+
* `is_finalized` is `true`. Polls that have ended will also always contain results.
|
|
119
|
+
* If `answer_counts` does not contain an entry for a particular answer, then there are no votes
|
|
120
|
+
* for that answer.
|
|
121
|
+
* @type {?MessagePollResult}
|
|
122
|
+
*/
|
|
123
|
+
this.results = {
|
|
124
|
+
isFinalized: data.results.is_finalized,
|
|
125
|
+
answerCounts: new Collection(),
|
|
126
|
+
};
|
|
127
|
+
data.results.answer_counts.forEach(obj => {
|
|
128
|
+
this.results.answerCounts.set(obj.id, {
|
|
129
|
+
count: obj.count,
|
|
130
|
+
selfVoted: obj.me_voted,
|
|
131
|
+
answer: this.answers.get(obj.id),
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
} else {
|
|
135
|
+
this.results ??= null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_resolvePollMedia(obj) {
|
|
140
|
+
return {
|
|
141
|
+
text: obj.text,
|
|
142
|
+
emoji: Util.resolvePartialEmoji(obj.emoji),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Convert to JSON
|
|
148
|
+
* @returns {Object}
|
|
149
|
+
*/
|
|
150
|
+
toJSON() {
|
|
151
|
+
const data = {
|
|
152
|
+
question: {
|
|
153
|
+
text: this.question.text,
|
|
154
|
+
emoji: this.question.emoji,
|
|
155
|
+
},
|
|
156
|
+
expiry: this.expiry?.toISOString(),
|
|
157
|
+
allow_multiselect: this.allowMultiSelect,
|
|
158
|
+
layout_type: typeof this.layoutType == 'number' ? this.layoutType : MessagePollLayoutTypes[this.layoutType],
|
|
159
|
+
answers: Array.from(this.answers.entries()).map(([id, data]) => ({
|
|
160
|
+
answer_id: id,
|
|
161
|
+
poll_media: {
|
|
162
|
+
text: data.text,
|
|
163
|
+
emoji: data.emoji,
|
|
164
|
+
},
|
|
165
|
+
})),
|
|
166
|
+
duration: this.duration ?? 1,
|
|
167
|
+
};
|
|
168
|
+
if (this.results) {
|
|
169
|
+
data.results = {
|
|
170
|
+
is_finalized: this.results.isFinalized,
|
|
171
|
+
answer_counts: Array.from(this.results.answerCounts.entries()).map(([id, data]) => ({
|
|
172
|
+
id: id,
|
|
173
|
+
count: data.count,
|
|
174
|
+
me_voted: data.selfVoted,
|
|
175
|
+
})),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return data;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Set question
|
|
183
|
+
* @param {string} text question
|
|
184
|
+
* @returns {MessagePoll}
|
|
185
|
+
*/
|
|
186
|
+
setQuestion(text) {
|
|
187
|
+
this.question = {
|
|
188
|
+
text,
|
|
189
|
+
};
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Set answers
|
|
195
|
+
* @param {MessagePollMedia[]} answers answers
|
|
196
|
+
* @returns {MessagePoll}
|
|
197
|
+
*/
|
|
198
|
+
setAnswers(answers) {
|
|
199
|
+
this.answers.clear();
|
|
200
|
+
answers.forEach((obj, index) => {
|
|
201
|
+
this.answers.set(index + 1, this._resolvePollMedia(obj));
|
|
202
|
+
});
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Add answer
|
|
208
|
+
* @param {MessagePollMedia} answer answer
|
|
209
|
+
* @returns {MessagePoll}
|
|
210
|
+
*/
|
|
211
|
+
addAnswer(answer) {
|
|
212
|
+
this.answers.set(this.answers.size + 1, answer);
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Set allow multi select
|
|
218
|
+
* @param {boolean} state state
|
|
219
|
+
* @returns {MessagePoll}
|
|
220
|
+
*/
|
|
221
|
+
setAllowMultiSelect(state) {
|
|
222
|
+
this.allowMultiSelect = state;
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Set duration
|
|
228
|
+
* @param {number} duration duration (hours)
|
|
229
|
+
* @returns {MessagePoll}
|
|
230
|
+
*/
|
|
231
|
+
setDuration(duration) {
|
|
232
|
+
// [1, 4, 8, 24, 72, 168, 336];
|
|
233
|
+
this.duration = duration;
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
module.exports = MessagePoll;
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { setTimeout } = require('node:timers');
|
|
4
3
|
const BaseMessageComponent = require('./BaseMessageComponent');
|
|
5
|
-
const {
|
|
6
|
-
ChannelTypes,
|
|
7
|
-
MessageComponentTypes,
|
|
8
|
-
SelectMenuComponentTypes,
|
|
9
|
-
InteractionTypes,
|
|
10
|
-
} = require('../util/Constants');
|
|
11
|
-
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
|
12
|
-
const { lazy } = require('../util/Util');
|
|
13
|
-
const Message = lazy(() => require('./Message').Message);
|
|
4
|
+
const { ChannelTypes, MessageComponentTypes } = require('../util/Constants');
|
|
14
5
|
const Util = require('../util/Util');
|
|
15
6
|
|
|
16
7
|
/**
|
|
@@ -103,130 +94,6 @@ class MessageSelectMenu extends BaseMessageComponent {
|
|
|
103
94
|
) ?? [];
|
|
104
95
|
}
|
|
105
96
|
|
|
106
|
-
/**
|
|
107
|
-
* Adds the channel types to the select menu
|
|
108
|
-
* @param {...ChannelType[]} channelTypes Added channel types
|
|
109
|
-
* @returns {MessageSelectMenu}
|
|
110
|
-
*/
|
|
111
|
-
addChannelTypes(...channelTypes) {
|
|
112
|
-
if (!channelTypes.every(channelType => ChannelTypes[channelType])) {
|
|
113
|
-
throw new TypeError('INVALID_TYPE', 'channelTypes', 'Rest<ChannelTypes[]>');
|
|
114
|
-
}
|
|
115
|
-
this.channelTypes.push(
|
|
116
|
-
...channelTypes.map(channelType => (typeof channelType === 'string' ? channelType : ChannelTypes[channelType])),
|
|
117
|
-
);
|
|
118
|
-
return this;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Sets the channel types of the select menu
|
|
123
|
-
* @param {...ChannelType[]} channelTypes An array of new channel types
|
|
124
|
-
* @returns {MessageSelectMenu}
|
|
125
|
-
*/
|
|
126
|
-
setChannelTypes(...channelTypes) {
|
|
127
|
-
if (!channelTypes.every(channelType => ChannelTypes[channelType])) {
|
|
128
|
-
throw new TypeError('INVALID_TYPE', 'channelTypes', 'Rest<ChannelTypes[]>');
|
|
129
|
-
}
|
|
130
|
-
this.channelTypes = channelTypes.map(channelType =>
|
|
131
|
-
typeof channelType === 'string' ? channelType : ChannelTypes[channelType],
|
|
132
|
-
);
|
|
133
|
-
return this;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Sets the custom id of this select menu
|
|
138
|
-
* @param {string} customId A unique string to be sent in the interaction when clicked
|
|
139
|
-
* @returns {MessageSelectMenu}
|
|
140
|
-
*/
|
|
141
|
-
setCustomId(customId) {
|
|
142
|
-
this.customId = Util.verifyString(customId, RangeError, 'SELECT_MENU_CUSTOM_ID');
|
|
143
|
-
return this;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Sets the interactive status of the select menu
|
|
148
|
-
* @param {boolean} [disabled=true] Whether this select menu should be disabled
|
|
149
|
-
* @returns {MessageSelectMenu}
|
|
150
|
-
*/
|
|
151
|
-
setDisabled(disabled = true) {
|
|
152
|
-
this.disabled = disabled;
|
|
153
|
-
return this;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Sets the maximum number of selections allowed for this select menu
|
|
158
|
-
* @param {number} maxValues Number of selections to be allowed
|
|
159
|
-
* @returns {MessageSelectMenu}
|
|
160
|
-
*/
|
|
161
|
-
setMaxValues(maxValues) {
|
|
162
|
-
this.maxValues = maxValues;
|
|
163
|
-
return this;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Sets the minimum number of selections required for this select menu
|
|
168
|
-
* <info>This will default the maxValues to the number of options, unless manually set</info>
|
|
169
|
-
* @param {number} minValues Number of selections to be required
|
|
170
|
-
* @returns {MessageSelectMenu}
|
|
171
|
-
*/
|
|
172
|
-
setMinValues(minValues) {
|
|
173
|
-
this.minValues = minValues;
|
|
174
|
-
return this;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Sets the placeholder of this select menu
|
|
179
|
-
* @param {string} placeholder Custom placeholder text to display when nothing is selected
|
|
180
|
-
* @returns {MessageSelectMenu}
|
|
181
|
-
*/
|
|
182
|
-
setPlaceholder(placeholder) {
|
|
183
|
-
this.placeholder = Util.verifyString(placeholder, RangeError, 'SELECT_MENU_PLACEHOLDER');
|
|
184
|
-
return this;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Sets the type of the select menu
|
|
189
|
-
* @param {SelectMenuComponentType} type Type of the select menu
|
|
190
|
-
* @returns {MessageSelectMenu}
|
|
191
|
-
*/
|
|
192
|
-
setType(type) {
|
|
193
|
-
if (!SelectMenuComponentTypes[type]) throw new TypeError('INVALID_TYPE', 'type', 'SelectMenuComponentType');
|
|
194
|
-
this.type = BaseMessageComponent.resolveType(type);
|
|
195
|
-
return this;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Adds options to the select menu.
|
|
200
|
-
* @param {...MessageSelectOptionData|MessageSelectOptionData[]} options The options to add
|
|
201
|
-
* @returns {MessageSelectMenu}
|
|
202
|
-
*/
|
|
203
|
-
addOptions(...options) {
|
|
204
|
-
this.options.push(...this.constructor.normalizeOptions(options));
|
|
205
|
-
return this;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Sets the options of the select menu.
|
|
210
|
-
* @param {...MessageSelectOptionData|MessageSelectOptionData[]} options The options to set
|
|
211
|
-
* @returns {MessageSelectMenu}
|
|
212
|
-
*/
|
|
213
|
-
setOptions(...options) {
|
|
214
|
-
this.spliceOptions(0, this.options.length, options);
|
|
215
|
-
return this;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Removes, replaces, and inserts options in the select menu.
|
|
220
|
-
* @param {number} index The index to start at
|
|
221
|
-
* @param {number} deleteCount The number of options to remove
|
|
222
|
-
* @param {...MessageSelectOptionData|MessageSelectOptionData[]} [options] The replacing option objects
|
|
223
|
-
* @returns {MessageSelectMenu}
|
|
224
|
-
*/
|
|
225
|
-
spliceOptions(index, deleteCount, ...options) {
|
|
226
|
-
this.options.splice(index, deleteCount, ...this.constructor.normalizeOptions(...options));
|
|
227
|
-
return this;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
97
|
/**
|
|
231
98
|
* Transforms the select menu into a plain object
|
|
232
99
|
* @returns {APIMessageSelectMenu} The raw data of this select menu
|
|
@@ -268,124 +135,6 @@ class MessageSelectMenu extends BaseMessageComponent {
|
|
|
268
135
|
static normalizeOptions(...options) {
|
|
269
136
|
return options.flat(Infinity).map(option => this.normalizeOption(option));
|
|
270
137
|
}
|
|
271
|
-
|
|
272
|
-
// Add
|
|
273
|
-
/**
|
|
274
|
-
* Mesage select menu
|
|
275
|
-
* @param {Message} message The message this select menu is for
|
|
276
|
-
* @param {Array<any>} values The values of the select menu
|
|
277
|
-
* @returns {Promise<InteractionResponse>}
|
|
278
|
-
*/
|
|
279
|
-
async select(message, values) {
|
|
280
|
-
if (!(message instanceof Message())) throw new Error('[UNKNOWN_MESSAGE] Please pass a valid Message');
|
|
281
|
-
if (!Array.isArray(values)) throw new TypeError('[INVALID_VALUES] Please pass an array of values');
|
|
282
|
-
if (!this.customId || this.disabled) {
|
|
283
|
-
throw new Error('[INVALID_MENU] Menu does not contain Id or has been disabled');
|
|
284
|
-
} // Disabled or null customID
|
|
285
|
-
if (values.length < this.minValues) {
|
|
286
|
-
throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${this.minValues}`);
|
|
287
|
-
}
|
|
288
|
-
if (values.length > this.maxValues) {
|
|
289
|
-
throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${this.maxValues}`);
|
|
290
|
-
}
|
|
291
|
-
const parseValues = value => {
|
|
292
|
-
switch (this.type) {
|
|
293
|
-
case 'SELECT_MENU':
|
|
294
|
-
case 'STRING_SELECT': {
|
|
295
|
-
if (typeof value !== 'string') throw new TypeError('[INVALID_VALUE] Please pass a string value');
|
|
296
|
-
const value_ = this.options.find(obj => obj.value === value || obj.label === value);
|
|
297
|
-
if (!value_) throw new Error('[INVALID_VALUE] Please pass a valid value');
|
|
298
|
-
return value_.value;
|
|
299
|
-
}
|
|
300
|
-
case 'USER_SELECT': {
|
|
301
|
-
const userId = this.client.users.resolveId(value);
|
|
302
|
-
if (!userId) throw new Error('[INVALID_VALUE] Please pass a valid user');
|
|
303
|
-
return userId;
|
|
304
|
-
}
|
|
305
|
-
case 'ROLE_SELECT': {
|
|
306
|
-
const roleId = this.client.roles.resolveId(value);
|
|
307
|
-
if (!roleId) throw new Error('[INVALID_VALUE] Please pass a valid role');
|
|
308
|
-
return roleId;
|
|
309
|
-
}
|
|
310
|
-
case 'MENTIONABLE_SELECT': {
|
|
311
|
-
const mentionableId = this.client.users.resolveId(value) || this.client.roles.resolveId(value);
|
|
312
|
-
if (!mentionableId) throw new Error('[INVALID_VALUE] Please pass a valid mentionable');
|
|
313
|
-
return mentionableId;
|
|
314
|
-
}
|
|
315
|
-
case 'CHANNEL_SELECT': {
|
|
316
|
-
const channel = this.client.channels.resolve(value);
|
|
317
|
-
if (!channel) throw new Error('[INVALID_VALUE] Please pass a valid channel');
|
|
318
|
-
if (!this.channelTypes.includes(channel.type)) {
|
|
319
|
-
throw new Error(
|
|
320
|
-
`[INVALID_VALUE] Please pass a valid channel type (Got: ${channel.type}, allow: ${this.channelTypes.join(
|
|
321
|
-
', ',
|
|
322
|
-
)})`,
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
|
-
return channel.id;
|
|
326
|
-
}
|
|
327
|
-
default: {
|
|
328
|
-
throw new Error(`[INVALID_TYPE] Please pass a valid select menu type (Got ${this.type})`);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
const nonce = SnowflakeUtil.generate();
|
|
334
|
-
const data = {
|
|
335
|
-
type: InteractionTypes.MESSAGE_COMPONENT,
|
|
336
|
-
guild_id: message.guild?.id ?? null,
|
|
337
|
-
channel_id: message.channel.id,
|
|
338
|
-
message_id: message.id,
|
|
339
|
-
application_id: message.applicationId ?? message.author.id,
|
|
340
|
-
session_id: message.client.session_id,
|
|
341
|
-
message_flags: message.flags.bitfield,
|
|
342
|
-
data: {
|
|
343
|
-
component_type: MessageComponentTypes[this.type],
|
|
344
|
-
custom_id: this.customId,
|
|
345
|
-
type: MessageComponentTypes[this.type],
|
|
346
|
-
values: values?.length ? values.map(parseValues) : [],
|
|
347
|
-
},
|
|
348
|
-
nonce,
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
await message.client.api.interactions.post({
|
|
352
|
-
data,
|
|
353
|
-
});
|
|
354
|
-
message.client._interactionCache.set(nonce, {
|
|
355
|
-
channelId: message.channelId,
|
|
356
|
-
guildId: message.guildId,
|
|
357
|
-
metadata: data,
|
|
358
|
-
});
|
|
359
|
-
return new Promise((resolve, reject) => {
|
|
360
|
-
const handler = data => {
|
|
361
|
-
timeout.refresh();
|
|
362
|
-
if (data.metadata?.nonce !== nonce) return;
|
|
363
|
-
clearTimeout(timeout);
|
|
364
|
-
message.client.removeListener('interactionResponse', handler);
|
|
365
|
-
message.client.decrementMaxListeners();
|
|
366
|
-
if (data.status) {
|
|
367
|
-
resolve(data.metadata);
|
|
368
|
-
} else {
|
|
369
|
-
reject(
|
|
370
|
-
new Error('INTERACTION_ERROR', {
|
|
371
|
-
cause: data,
|
|
372
|
-
}),
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
const timeout = setTimeout(() => {
|
|
377
|
-
message.client.removeListener('interactionResponse', handler);
|
|
378
|
-
message.client.decrementMaxListeners();
|
|
379
|
-
reject(
|
|
380
|
-
new Error('INTERACTION_TIMEOUT', {
|
|
381
|
-
cause: data,
|
|
382
|
-
}),
|
|
383
|
-
);
|
|
384
|
-
}, message.client.options.interactionTimeout).unref();
|
|
385
|
-
message.client.incrementMaxListeners();
|
|
386
|
-
message.client.on('interactionResponse', handler);
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
138
|
}
|
|
390
139
|
|
|
391
140
|
module.exports = MessageSelectMenu;
|