discord-sb.js 1.2.2 → 1.3.0
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/package.json +13 -12
- package/src/client/BaseClient.js +24 -0
- package/src/client/actions/Action.js +39 -22
- package/src/client/actions/InviteCreate.js +1 -1
- package/src/client/actions/InviteDelete.js +1 -1
- package/src/client/actions/MessageCreate.js +6 -6
- package/src/client/actions/MessageDelete.js +3 -1
- package/src/client/actions/MessageDeleteBulk.js +6 -9
- package/src/client/actions/MessageReactionAdd.js +12 -9
- package/src/client/actions/MessageReactionRemove.js +3 -14
- package/src/client/actions/MessageReactionRemoveAll.js +8 -5
- package/src/client/actions/MessageReactionRemoveEmoji.js +3 -1
- package/src/client/actions/MessageUpdate.js +3 -1
- package/src/client/actions/PresenceUpdate.js +8 -3
- package/src/client/actions/ThreadListSync.js +6 -5
- package/src/client/actions/ThreadMembersUpdate.js +10 -6
- package/src/client/actions/TypingStart.js +3 -1
- package/src/client/actions/VoiceStateUpdate.js +20 -7
- package/src/client/voice/ClientVoiceManager.js +18 -7
- package/src/client/voice/StreamEventRouter.js +60 -0
- package/src/client/voice/VoiceConnection.js +77 -159
- package/src/client/voice/networking/VoiceUDPClient.js +25 -11
- package/src/client/voice/networking/VoiceWebSocket.js +84 -22
- package/src/client/websocket/DispatchTable.js +7 -0
- package/src/client/websocket/GatewaySendScheduler.js +107 -0
- package/src/client/websocket/WebSocketManager.js +24 -16
- package/src/client/websocket/WebSocketShard.js +161 -51
- package/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +8 -2
- package/src/client/websocket/handlers/READY.js +30 -42
- package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +13 -9
- package/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js +7 -1
- package/src/managers/MessageManager.js +27 -23
- package/src/managers/QuestManager.js +7 -9
- package/src/rest/APIRequest.js +40 -43
- package/src/rest/APIRouter.js +1 -1
- package/src/rest/RESTManager.js +69 -2
- package/src/rest/RateLimitCoordinator.js +156 -0
- package/src/rest/RequestHandler.js +162 -91
- package/src/structures/GroupDMChannel.js +18 -0
- package/src/structures/interfaces/Collector.js +2 -1
- package/src/util/FastQueue.js +93 -0
- package/src/util/ListenerUtil.js +12 -0
- package/src/util/Options.js +2 -2
- package/typings/index.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discord-sb.js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "An unofficial discord.js fork for creating selfbots",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"types": "./typings/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"all": "bun run build && bun publish",
|
|
9
9
|
"test": "bun run lint:all && bun run docs:test && bun run test:typescript",
|
|
10
|
+
"test:unit": "bun test",
|
|
10
11
|
"fix:all": "bun run lint:fix && bun run lint:typings:fix && bun run format",
|
|
11
12
|
"test:typescript": "tsc --noEmit && tsd",
|
|
12
13
|
"lint": "eslint .",
|
|
@@ -51,35 +52,35 @@
|
|
|
51
52
|
},
|
|
52
53
|
"homepage": "https://github.com/sqlu/discord-sb.js#readme",
|
|
53
54
|
"dependencies": {
|
|
54
|
-
"@discordjs/builders": "^1.
|
|
55
|
+
"@discordjs/builders": "^1.13.1",
|
|
55
56
|
"@discordjs/collection": "^2.1.1",
|
|
56
57
|
"@sapphire/async-queue": "^1.5.5",
|
|
57
58
|
"@sapphire/shapeshift": "^4.0.0",
|
|
58
59
|
"debug": "^4.4.3",
|
|
59
|
-
"discord-api-types": "^0.38.
|
|
60
|
+
"discord-api-types": "^0.38.38",
|
|
60
61
|
"otplib": "^12.0.1",
|
|
61
62
|
"prism-media": "^1.3.5",
|
|
62
63
|
"qrcode": "^1.5.4",
|
|
63
|
-
"werift-rtp": "^0.8.
|
|
64
|
+
"werift-rtp": "^0.8.8"
|
|
64
65
|
},
|
|
65
66
|
"engines": {
|
|
66
67
|
"bun": ">=1.3.5"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
70
|
"@discordjs/docgen": "^0.11.1",
|
|
70
|
-
"@types/bun": "^1.
|
|
71
|
+
"@types/bun": "^1.3.8",
|
|
71
72
|
"@types/debug": "^4.1.12",
|
|
72
|
-
"@types/node": "^22.10
|
|
73
|
+
"@types/node": "^22.19.10",
|
|
73
74
|
"dtslint": "^4.2.1",
|
|
74
|
-
"eslint": "^8.
|
|
75
|
-
"eslint-config-prettier": "^8.
|
|
76
|
-
"eslint-plugin-import": "^2.
|
|
77
|
-
"eslint-plugin-prettier": "^4.2.
|
|
78
|
-
"patch-package": "^8.0.
|
|
75
|
+
"eslint": "^8.57.1",
|
|
76
|
+
"eslint-config-prettier": "^8.10.2",
|
|
77
|
+
"eslint-plugin-import": "^2.32.0",
|
|
78
|
+
"eslint-plugin-prettier": "^4.2.5",
|
|
79
|
+
"patch-package": "^8.0.1",
|
|
79
80
|
"prettier": "^2.8.8",
|
|
80
81
|
"tsd": "^0.32.0",
|
|
81
82
|
"tslint": "^6.1.3",
|
|
82
|
-
"typescript": "^5.
|
|
83
|
+
"typescript": "^5.9.3"
|
|
83
84
|
},
|
|
84
85
|
"packageManager": "bun@1.3.5"
|
|
85
86
|
}
|
package/src/client/BaseClient.js
CHANGED
|
@@ -14,6 +14,10 @@ class BaseClient extends EventEmitter {
|
|
|
14
14
|
constructor(options = {}) {
|
|
15
15
|
super({ captureRejections: true });
|
|
16
16
|
|
|
17
|
+
this._listenerCountsFast = new Map();
|
|
18
|
+
this.on('newListener', this._onNewListener.bind(this));
|
|
19
|
+
this.on('removeListener', this._onRemoveListener.bind(this));
|
|
20
|
+
|
|
17
21
|
if (options.intents) {
|
|
18
22
|
process.emitWarning('Intents is not available.', 'DeprecationWarning');
|
|
19
23
|
}
|
|
@@ -32,6 +36,26 @@ class BaseClient extends EventEmitter {
|
|
|
32
36
|
this.rest = new RESTManager(this);
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
_onNewListener(event) {
|
|
40
|
+
if (event === 'newListener' || event === 'removeListener') return;
|
|
41
|
+
const current = this._listenerCountsFast.get(event) ?? 0;
|
|
42
|
+
this._listenerCountsFast.set(event, current + 1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_onRemoveListener(event) {
|
|
46
|
+
if (event === 'newListener' || event === 'removeListener') return;
|
|
47
|
+
const current = this._listenerCountsFast.get(event) ?? 0;
|
|
48
|
+
if (current <= 1) {
|
|
49
|
+
this._listenerCountsFast.delete(event);
|
|
50
|
+
} else {
|
|
51
|
+
this._listenerCountsFast.set(event, current - 1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
hasListenerFast(event) {
|
|
56
|
+
return (this._listenerCountsFast.get(event) ?? 0) > 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
35
59
|
/**
|
|
36
60
|
* API shortcut
|
|
37
61
|
* @type {Object}
|
|
@@ -17,6 +17,7 @@ that WebSocket events don't clash with REST methods.
|
|
|
17
17
|
class GenericAction {
|
|
18
18
|
constructor(client) {
|
|
19
19
|
this.client = client;
|
|
20
|
+
this._partials = new Set(client.options.partials);
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
handle(data) {
|
|
@@ -25,45 +26,55 @@ class GenericAction {
|
|
|
25
26
|
|
|
26
27
|
getPayload(data, manager, id, partialType, cache) {
|
|
27
28
|
const existing = manager.cache.get(id);
|
|
28
|
-
if (!existing && this.
|
|
29
|
+
if (!existing && this._partials.has(partialType)) {
|
|
29
30
|
return manager._add(data, cache);
|
|
30
31
|
}
|
|
31
32
|
return existing;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
getChannel(data) {
|
|
35
|
-
const
|
|
36
|
+
const injected = data[this.client.actions.injectedChannel];
|
|
37
|
+
if (injected) return injected;
|
|
38
|
+
|
|
36
39
|
const id = data.channel_id ?? data.id;
|
|
40
|
+
const existing = this.client.channels.cache.get(id);
|
|
41
|
+
if (existing) return existing;
|
|
37
42
|
|
|
38
|
-
|
|
43
|
+
let recipients;
|
|
44
|
+
if (!('recipients' in data) && this.client.user) {
|
|
39
45
|
// Try to resolve the recipient, but do not add the client user.
|
|
40
46
|
const recipient = data.author ?? data.user ?? { id: data.user_id };
|
|
41
|
-
if (recipient.id !== this.client.user.id)
|
|
47
|
+
if (recipient.id !== this.client.user.id) recipients = [recipient];
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
if (id
|
|
50
|
+
if (id === data.id && !recipients) {
|
|
51
|
+
return this.getPayload(data, this.client.channels, id, PartialTypes.CHANNEL);
|
|
52
|
+
}
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
54
|
+
const payload = { ...data, id };
|
|
55
|
+
if (recipients) payload.recipients = recipients;
|
|
56
|
+
|
|
57
|
+
return this.getPayload(payload, this.client.channels, id, PartialTypes.CHANNEL);
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
getMessage(data, channel, cache) {
|
|
61
|
+
const injected = data[this.client.actions.injectedMessage];
|
|
62
|
+
if (injected) return injected;
|
|
63
|
+
|
|
53
64
|
const id = data.message_id ?? data.id;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
channel_id: channel.id,
|
|
60
|
-
guild_id: data.guild_id ?? channel.guild?.id,
|
|
61
|
-
},
|
|
62
|
-
channel.messages,
|
|
65
|
+
const existing = channel.messages.cache.get(id);
|
|
66
|
+
if (existing) return existing;
|
|
67
|
+
|
|
68
|
+
return this.getPayload(
|
|
69
|
+
{
|
|
63
70
|
id,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
channel_id: channel.id,
|
|
72
|
+
guild_id: data.guild_id ?? channel.guild?.id,
|
|
73
|
+
},
|
|
74
|
+
channel.messages,
|
|
75
|
+
id,
|
|
76
|
+
PartialTypes.MESSAGE,
|
|
77
|
+
cache,
|
|
67
78
|
);
|
|
68
79
|
}
|
|
69
80
|
|
|
@@ -86,8 +97,14 @@ class GenericAction {
|
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
getUser(data) {
|
|
100
|
+
const injected = data[this.client.actions.injectedUser];
|
|
101
|
+
if (injected) return injected;
|
|
102
|
+
|
|
89
103
|
const id = data.user_id;
|
|
90
|
-
|
|
104
|
+
const existing = this.client.users.cache.get(id);
|
|
105
|
+
if (existing) return existing;
|
|
106
|
+
|
|
107
|
+
return this.getPayload({ id }, this.client.users, id, PartialTypes.USER);
|
|
91
108
|
}
|
|
92
109
|
|
|
93
110
|
getUserFromMember(data) {
|
|
@@ -10,7 +10,7 @@ class InviteCreateAction extends Action {
|
|
|
10
10
|
const guild = client.guilds.cache.get(data.guild_id);
|
|
11
11
|
if (!channel) return false;
|
|
12
12
|
|
|
13
|
-
const inviteData = Object.assign(data, { channel, guild });
|
|
13
|
+
const inviteData = Object.assign({}, data, { channel, guild });
|
|
14
14
|
const invite = guild.invites._add(inviteData);
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -11,7 +11,7 @@ class InviteDeleteAction extends Action {
|
|
|
11
11
|
const guild = client.guilds.cache.get(data.guild_id);
|
|
12
12
|
if (!channel) return false;
|
|
13
13
|
|
|
14
|
-
const inviteData = Object.assign(data, { channel, guild });
|
|
14
|
+
const inviteData = Object.assign({}, data, { channel, guild });
|
|
15
15
|
const invite = new Invite(client, inviteData);
|
|
16
16
|
guild.invites.cache.delete(invite.code);
|
|
17
17
|
|
|
@@ -3,17 +3,16 @@
|
|
|
3
3
|
const process = require('node:process');
|
|
4
4
|
const Action = require('./Action');
|
|
5
5
|
const { Events } = require('../../util/Constants');
|
|
6
|
+
const { hasListener } = require('../../util/ListenerUtil');
|
|
6
7
|
|
|
7
8
|
let deprecationEmitted = false;
|
|
8
9
|
|
|
9
10
|
class MessageCreateAction extends Action {
|
|
10
11
|
handle(data) {
|
|
11
12
|
const client = this.client;
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
...('guild_id' in data && { guild_id: data.guild_id }),
|
|
16
|
-
});
|
|
13
|
+
const channelData = { id: data.channel_id, author: data.author };
|
|
14
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
15
|
+
const channel = this.getChannel(channelData);
|
|
17
16
|
if (channel) {
|
|
18
17
|
if (!channel.isText()) return {};
|
|
19
18
|
|
|
@@ -35,7 +34,8 @@ class MessageCreateAction extends Action {
|
|
|
35
34
|
* @param {Message} message The created message
|
|
36
35
|
* @deprecated Use {@link Client#event:messageCreate} instead
|
|
37
36
|
*/
|
|
38
|
-
|
|
37
|
+
const hasMessageListener = hasListener(client, 'message');
|
|
38
|
+
if (hasMessageListener && client.emit('message', message) && !deprecationEmitted) {
|
|
39
39
|
deprecationEmitted = true;
|
|
40
40
|
process.emitWarning('The message event is deprecated. Use messageCreate instead', 'DeprecationWarning');
|
|
41
41
|
}
|
|
@@ -7,7 +7,9 @@ const { Events } = require('../../util/Constants');
|
|
|
7
7
|
class MessageDeleteAction extends Action {
|
|
8
8
|
handle(data) {
|
|
9
9
|
const client = this.client;
|
|
10
|
-
const
|
|
10
|
+
const channelData = { id: data.channel_id };
|
|
11
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
12
|
+
const channel = this.getChannel(channelData);
|
|
11
13
|
let message;
|
|
12
14
|
if (channel) {
|
|
13
15
|
if (!channel.isText()) return {};
|
|
@@ -14,20 +14,17 @@ class MessageDeleteBulkAction extends Action {
|
|
|
14
14
|
if (!channel.isText()) return {};
|
|
15
15
|
|
|
16
16
|
const ids = data.ids;
|
|
17
|
+
const { cache } = channel.messages;
|
|
18
|
+
const channelId = channel.id;
|
|
19
|
+
const guildId = data.guild_id;
|
|
17
20
|
const messages = new Collection();
|
|
18
21
|
for (const id of ids) {
|
|
19
|
-
const message =
|
|
20
|
-
{
|
|
21
|
-
id,
|
|
22
|
-
guild_id: data.guild_id,
|
|
23
|
-
},
|
|
24
|
-
channel,
|
|
25
|
-
false,
|
|
26
|
-
);
|
|
22
|
+
const message =
|
|
23
|
+
cache.get(id) ?? this.getMessage({ id, channel_id: channelId, guild_id: guildId }, channel, false);
|
|
27
24
|
if (message) {
|
|
28
25
|
deletedMessages.add(message);
|
|
29
26
|
messages.set(message.id, message);
|
|
30
|
-
|
|
27
|
+
cache.delete(id);
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
30
|
|
|
@@ -22,12 +22,9 @@ class MessageReactionAdd extends Action {
|
|
|
22
22
|
const user = this.getUserFromMember(data);
|
|
23
23
|
if (!user) return false;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
user_id: data.user_id,
|
|
29
|
-
...('guild_id' in data && { guild_id: data.guild_id }),
|
|
30
|
-
});
|
|
25
|
+
const channelData = { id: data.channel_id, user_id: data.user_id };
|
|
26
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
27
|
+
const channel = this.getChannel(channelData);
|
|
31
28
|
if (!channel || !channel.isText()) return false;
|
|
32
29
|
|
|
33
30
|
// Verify message
|
|
@@ -37,12 +34,18 @@ class MessageReactionAdd extends Action {
|
|
|
37
34
|
// Verify reaction
|
|
38
35
|
const includePartial = this.client.options.partials.includes(PartialTypes.REACTION);
|
|
39
36
|
if (message.partial && !includePartial) return false;
|
|
40
|
-
const
|
|
37
|
+
const reactionData = {
|
|
41
38
|
emoji: data.emoji,
|
|
42
39
|
count: message.partial ? null : 0,
|
|
43
40
|
me: user.id === this.client.user.id,
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
};
|
|
42
|
+
if ('count' in data) reactionData.count = data.count;
|
|
43
|
+
if ('me' in data) reactionData.me = data.me;
|
|
44
|
+
if ('me_burst' in data) reactionData.me_burst = data.me_burst;
|
|
45
|
+
if ('burst_colors' in data) reactionData.burst_colors = data.burst_colors;
|
|
46
|
+
if ('count_details' in data) reactionData.count_details = data.count_details;
|
|
47
|
+
|
|
48
|
+
const reaction = message.reactions._add(reactionData);
|
|
46
49
|
if (!reaction) return false;
|
|
47
50
|
reaction._add(user, data.burst);
|
|
48
51
|
if (fromStructure) return { message, reaction, user };
|
|
@@ -3,14 +3,6 @@
|
|
|
3
3
|
const Action = require('./Action');
|
|
4
4
|
const { Events } = require('../../util/Constants');
|
|
5
5
|
|
|
6
|
-
/*
|
|
7
|
-
{ user_id: 'id',
|
|
8
|
-
message_id: 'id',
|
|
9
|
-
emoji: { name: '�', id: null },
|
|
10
|
-
channel_id: 'id',
|
|
11
|
-
guild_id: 'id' }
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
6
|
class MessageReactionRemove extends Action {
|
|
15
7
|
handle(data) {
|
|
16
8
|
if (!data.emoji) return false;
|
|
@@ -18,12 +10,9 @@ class MessageReactionRemove extends Action {
|
|
|
18
10
|
const user = this.getUser(data);
|
|
19
11
|
if (!user) return false;
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
user_id: data.user_id,
|
|
25
|
-
...('guild_id' in data && { guild_id: data.guild_id }),
|
|
26
|
-
});
|
|
13
|
+
const channelData = { id: data.channel_id, user_id: data.user_id };
|
|
14
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
15
|
+
const channel = this.getChannel(channelData);
|
|
27
16
|
if (!channel || !channel.isText()) return false;
|
|
28
17
|
|
|
29
18
|
// Verify message
|
|
@@ -2,22 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
const Action = require('./Action');
|
|
4
4
|
const { Events } = require('../../util/Constants');
|
|
5
|
+
const { hasListener } = require('../../util/ListenerUtil');
|
|
5
6
|
|
|
6
7
|
class MessageReactionRemoveAll extends Action {
|
|
7
8
|
handle(data) {
|
|
8
|
-
|
|
9
|
-
const
|
|
9
|
+
const hasReactionListener = hasListener(this.client, Events.MESSAGE_REACTION_REMOVE_ALL);
|
|
10
|
+
const channelData = { id: data.channel_id };
|
|
11
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
12
|
+
const channel = this.getChannel(channelData);
|
|
10
13
|
if (!channel || !channel.isText()) return false;
|
|
11
14
|
|
|
12
15
|
// Verify message
|
|
13
16
|
const message = this.getMessage(data, channel);
|
|
14
17
|
if (!message) return false;
|
|
15
18
|
|
|
16
|
-
// Copy removed reactions
|
|
17
|
-
const removed = message.reactions.cache.clone();
|
|
19
|
+
// Copy removed reactions only when needed for the event payload.
|
|
20
|
+
const removed = hasReactionListener ? message.reactions.cache.clone() : null;
|
|
18
21
|
|
|
19
22
|
message.reactions.cache.clear();
|
|
20
|
-
this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message, removed);
|
|
23
|
+
if (hasReactionListener) this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message, removed);
|
|
21
24
|
|
|
22
25
|
return { message };
|
|
23
26
|
}
|
|
@@ -5,7 +5,9 @@ const { Events } = require('../../util/Constants');
|
|
|
5
5
|
|
|
6
6
|
class MessageReactionRemoveEmoji extends Action {
|
|
7
7
|
handle(data) {
|
|
8
|
-
const
|
|
8
|
+
const channelData = { id: data.channel_id };
|
|
9
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
10
|
+
const channel = this.getChannel(channelData);
|
|
9
11
|
if (!channel || !channel.isText()) return false;
|
|
10
12
|
|
|
11
13
|
const message = this.getMessage(data, channel);
|
|
@@ -4,7 +4,9 @@ const Action = require('./Action');
|
|
|
4
4
|
|
|
5
5
|
class MessageUpdateAction extends Action {
|
|
6
6
|
handle(data) {
|
|
7
|
-
const
|
|
7
|
+
const channelData = { id: data.channel_id };
|
|
8
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
9
|
+
const channel = this.getChannel(channelData);
|
|
8
10
|
if (channel) {
|
|
9
11
|
if (!channel.isText()) return {};
|
|
10
12
|
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
const Action = require('./Action');
|
|
4
4
|
const { Events } = require('../../util/Constants');
|
|
5
5
|
const { PartialTypes } = require('../../util/Constants');
|
|
6
|
+
const { hasListener } = require('../../util/ListenerUtil');
|
|
6
7
|
|
|
7
8
|
class PresenceUpdateAction extends Action {
|
|
8
9
|
handle(data) {
|
|
10
|
+
const hasPresenceUpdateListener = hasListener(this.client, Events.PRESENCE_UPDATE);
|
|
11
|
+
|
|
9
12
|
let user = this.client.users.cache.get(data.user.id);
|
|
10
13
|
if (!user && data.user?.username) user = this.client.users._add(data.user);
|
|
11
14
|
if (!user && ('username' in data.user || this.client.options.partials.includes(PartialTypes.USER))) {
|
|
@@ -31,11 +34,13 @@ class PresenceUpdateAction extends Action {
|
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
const oldPresence =
|
|
37
|
+
const oldPresence = hasPresenceUpdateListener
|
|
38
|
+
? (guild || this.client).presences.cache.get(user.id)?._clone() ?? null
|
|
39
|
+
: null;
|
|
35
40
|
|
|
36
|
-
const newPresence = (guild || this.client).presences._add(Object.assign(data, { guild }));
|
|
41
|
+
const newPresence = (guild || this.client).presences._add(Object.assign({}, data, { guild }));
|
|
37
42
|
|
|
38
|
-
if (
|
|
43
|
+
if (hasPresenceUpdateListener && !newPresence.equals(oldPresence)) {
|
|
39
44
|
/**
|
|
40
45
|
* Emitted whenever a guild member's presence (e.g. status, activity) is changed.
|
|
41
46
|
* @event Client#presenceUpdate
|
|
@@ -22,10 +22,11 @@ class ThreadListSyncAction extends Action {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const syncedThreads =
|
|
25
|
+
const syncedThreads = new Collection();
|
|
26
|
+
for (const rawThread of data.threads) {
|
|
26
27
|
const thread = client.channels._add(rawThread);
|
|
27
|
-
|
|
28
|
-
}
|
|
28
|
+
syncedThreads.set(thread.id, thread);
|
|
29
|
+
}
|
|
29
30
|
|
|
30
31
|
for (const rawMember of Object.values(data.members || {})) {
|
|
31
32
|
// Discord sends the thread id as id in this object
|
|
@@ -48,11 +49,11 @@ class ThreadListSyncAction extends Action {
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
removeStale(channel) {
|
|
51
|
-
channel.threads?.cache
|
|
52
|
+
for (const thread of channel.threads?.cache?.values() ?? []) {
|
|
52
53
|
if (!thread.archived) {
|
|
53
54
|
this.client.channels._remove(thread.id);
|
|
54
55
|
}
|
|
55
|
-
}
|
|
56
|
+
}
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -2,22 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
const Action = require('./Action');
|
|
4
4
|
const { Events } = require('../../util/Constants');
|
|
5
|
+
const { hasListener } = require('../../util/ListenerUtil');
|
|
5
6
|
|
|
6
7
|
class ThreadMembersUpdateAction extends Action {
|
|
7
8
|
handle(data) {
|
|
8
9
|
const client = this.client;
|
|
9
10
|
const thread = client.channels.cache.get(data.id);
|
|
10
11
|
if (thread) {
|
|
11
|
-
const
|
|
12
|
+
const hasThreadMembersListener = hasListener(client, Events.THREAD_MEMBERS_UPDATE);
|
|
13
|
+
const old = hasThreadMembersListener ? thread.members.cache.clone() : null;
|
|
12
14
|
thread.memberCount = data.member_count;
|
|
13
15
|
|
|
14
|
-
data.added_members
|
|
16
|
+
for (const rawMember of data.added_members ?? []) {
|
|
15
17
|
thread.members._add(rawMember);
|
|
16
|
-
}
|
|
18
|
+
}
|
|
17
19
|
|
|
18
|
-
data.removed_member_ids
|
|
20
|
+
for (const memberId of data.removed_member_ids ?? []) {
|
|
19
21
|
thread.members.cache.delete(memberId);
|
|
20
|
-
}
|
|
22
|
+
}
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Emitted whenever members are added or removed from a thread. Requires `GUILD_MEMBERS` privileged intent
|
|
@@ -25,7 +27,9 @@ class ThreadMembersUpdateAction extends Action {
|
|
|
25
27
|
* @param {Collection<Snowflake, ThreadMember>} oldMembers The members before the update
|
|
26
28
|
* @param {Collection<Snowflake, ThreadMember>} newMembers The members after the update
|
|
27
29
|
*/
|
|
28
|
-
|
|
30
|
+
if (hasThreadMembersListener) {
|
|
31
|
+
client.emit(Events.THREAD_MEMBERS_UPDATE, old, thread.members.cache);
|
|
32
|
+
}
|
|
29
33
|
}
|
|
30
34
|
return {};
|
|
31
35
|
}
|
|
@@ -6,7 +6,9 @@ const { Events } = require('../../util/Constants');
|
|
|
6
6
|
|
|
7
7
|
class TypingStart extends Action {
|
|
8
8
|
handle(data) {
|
|
9
|
-
const
|
|
9
|
+
const channelData = { id: data.channel_id };
|
|
10
|
+
if ('guild_id' in data) channelData.guild_id = data.guild_id;
|
|
11
|
+
const channel = this.getChannel(channelData);
|
|
10
12
|
if (!channel) return;
|
|
11
13
|
|
|
12
14
|
if (!channel.isText()) {
|
|
@@ -3,15 +3,19 @@
|
|
|
3
3
|
const Action = require('./Action');
|
|
4
4
|
const VoiceState = require('../../structures/VoiceState');
|
|
5
5
|
const { Events } = require('../../util/Constants');
|
|
6
|
+
const { hasListener } = require('../../util/ListenerUtil');
|
|
6
7
|
|
|
7
8
|
class VoiceStateUpdate extends Action {
|
|
8
9
|
handle(data) {
|
|
9
10
|
const client = this.client;
|
|
11
|
+
const hasVoiceStateListener = hasListener(client, Events.VOICE_STATE_UPDATE);
|
|
10
12
|
const guild = client.guilds.cache.get(data.guild_id);
|
|
11
13
|
if (guild) {
|
|
12
14
|
// Update the state
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
+
const previous = guild.voiceStates.cache.get(data.user_id);
|
|
16
|
+
const oldState = hasVoiceStateListener
|
|
17
|
+
? previous?._clone() ?? new VoiceState(guild, { user_id: data.user_id })
|
|
18
|
+
: null;
|
|
15
19
|
|
|
16
20
|
const newState = guild.voiceStates._add(data);
|
|
17
21
|
|
|
@@ -29,19 +33,28 @@ class VoiceStateUpdate extends Action {
|
|
|
29
33
|
* @param {VoiceState} oldState The voice state before the update
|
|
30
34
|
* @param {VoiceState} newState The voice state after the update
|
|
31
35
|
*/
|
|
32
|
-
|
|
36
|
+
if (hasVoiceStateListener) {
|
|
37
|
+
client.emit(Events.VOICE_STATE_UPDATE, oldState, newState);
|
|
38
|
+
}
|
|
33
39
|
} else {
|
|
34
40
|
// Update the state
|
|
35
|
-
const
|
|
36
|
-
|
|
41
|
+
const previous = client.voiceStates.cache.get(data.user_id);
|
|
42
|
+
const oldState = hasVoiceStateListener
|
|
43
|
+
? previous?._clone() ?? new VoiceState({ client }, { user_id: data.user_id })
|
|
44
|
+
: null;
|
|
37
45
|
|
|
38
46
|
const newState = client.voiceStates._add(data);
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
if (hasVoiceStateListener) {
|
|
49
|
+
client.emit(Events.VOICE_STATE_UPDATE, oldState, newState);
|
|
50
|
+
}
|
|
41
51
|
}
|
|
42
52
|
// Emit event
|
|
43
53
|
if (data.user_id === client.user?.id) {
|
|
44
|
-
|
|
54
|
+
const hasDebugListener = hasListener(client, Events.DEBUG);
|
|
55
|
+
if (hasDebugListener) {
|
|
56
|
+
client.emit(Events.DEBUG, `[VOICE] received voice state update: ${JSON.stringify(data)}`);
|
|
57
|
+
}
|
|
45
58
|
client.voice.onVoiceStateUpdate(data);
|
|
46
59
|
}
|
|
47
60
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const VoiceConnection = require('./VoiceConnection');
|
|
4
4
|
const { Error } = require('../../errors');
|
|
5
5
|
const { Events } = require('../../util/Constants');
|
|
6
|
+
const { hasListener } = require('../../util/ListenerUtil');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Manages voice connections for the client
|
|
@@ -42,8 +43,7 @@ class ClientVoiceManager {
|
|
|
42
43
|
|
|
43
44
|
onVoiceServer(payload) {
|
|
44
45
|
const { guild_id, channel_id, token, endpoint } = payload;
|
|
45
|
-
this.
|
|
46
|
-
'debug',
|
|
46
|
+
this._debug(
|
|
47
47
|
`[VOICE] voiceServer ${channel_id ? 'channel' : 'guild'}: ${
|
|
48
48
|
channel_id || guild_id
|
|
49
49
|
} token: ${token} endpoint: ${endpoint}`,
|
|
@@ -68,7 +68,7 @@ class ClientVoiceManager {
|
|
|
68
68
|
}
|
|
69
69
|
// Main lib
|
|
70
70
|
const connection = this.connection;
|
|
71
|
-
this.
|
|
71
|
+
this._debug(`[VOICE] connection? ${!!connection}, ${guild_id} ${session_id} ${channel_id}`);
|
|
72
72
|
if (!connection) return;
|
|
73
73
|
if (!channel_id) {
|
|
74
74
|
connection._disconnect();
|
|
@@ -80,7 +80,7 @@ class ClientVoiceManager {
|
|
|
80
80
|
connection.channel = channel;
|
|
81
81
|
connection.setSessionId(session_id);
|
|
82
82
|
} else {
|
|
83
|
-
this.
|
|
83
|
+
this._debug(`[VOICE] disconnecting from guild ${guild_id} as channel ${channel_id} is uncached`);
|
|
84
84
|
connection.disconnect();
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -117,9 +117,14 @@ class ClientVoiceManager {
|
|
|
117
117
|
} else {
|
|
118
118
|
connection = new VoiceConnection(this, channel);
|
|
119
119
|
if (config?.videoCodec) connection.setVideoCodec(config.videoCodec);
|
|
120
|
-
|
|
121
|
-
this.client
|
|
122
|
-
|
|
120
|
+
const forwardDebug = msg => {
|
|
121
|
+
if (hasListener(this.client, Events.DEBUG)) {
|
|
122
|
+
this.client.emit(Events.DEBUG, `[VOICE (${channel.guild?.id || channel.id}:${connection.status})]: ${msg}`);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
forwardDebug.__voiceForwarder = true;
|
|
126
|
+
connection.on('debug', forwardDebug);
|
|
127
|
+
connection._voiceDebugForwarder = forwardDebug;
|
|
123
128
|
connection.authenticate({
|
|
124
129
|
self_mute: Boolean(config.selfMute),
|
|
125
130
|
self_deaf: Boolean(config.selfDeaf),
|
|
@@ -146,6 +151,12 @@ class ClientVoiceManager {
|
|
|
146
151
|
});
|
|
147
152
|
});
|
|
148
153
|
}
|
|
154
|
+
|
|
155
|
+
_debug(message) {
|
|
156
|
+
if (hasListener(this.client, Events.DEBUG)) {
|
|
157
|
+
this.client.emit(Events.DEBUG, message);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
149
160
|
}
|
|
150
161
|
|
|
151
162
|
module.exports = ClientVoiceManager;
|