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