discord.js 15.0.0-dev.1763078518-9f18cb212 → 15.0.0-dev.1763205226-9d5c6b458
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 +9 -9
- package/src/client/Client.js +107 -14
- package/src/client/websocket/handlers/RATE_LIMITED.js +24 -0
- package/src/client/websocket/handlers/index.js +1 -0
- package/src/index.js +0 -1
- package/src/managers/GuildMemberManager.js +44 -23
- package/src/managers/MessageManager.js +2 -2
- package/src/structures/MessagePayload.js +12 -10
- package/src/structures/interfaces/TextBasedChannel.js +5 -7
- package/src/util/Components.js +50 -40
- package/src/util/DataResolver.js +5 -2
- package/src/util/Util.js +9 -12
- package/typings/index.d.mts +8 -13
- package/typings/index.d.ts +8 -13
- package/src/client/BaseClient.js +0 -131
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "discord.js",
|
|
4
|
-
"version": "15.0.0-dev.
|
|
4
|
+
"version": "15.0.0-dev.1763205226-9d5c6b458",
|
|
5
5
|
"description": "A powerful library for interacting with the Discord API",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"types": "./typings/index.d.ts",
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"magic-bytes.js": "^1.12.1",
|
|
62
62
|
"tslib": "^2.8.1",
|
|
63
63
|
"undici": "7.16.0",
|
|
64
|
-
"@discordjs/
|
|
65
|
-
"@discordjs/
|
|
66
|
-
"@discordjs/
|
|
67
|
-
"@discordjs/
|
|
68
|
-
"@discordjs/ws": "3.0.0-dev.
|
|
69
|
-
"@discordjs/util": "2.0.0-dev.
|
|
64
|
+
"@discordjs/builders": "2.0.0-dev.1763205226-9d5c6b458",
|
|
65
|
+
"@discordjs/collection": "3.0.0-dev.1763205226-9d5c6b458",
|
|
66
|
+
"@discordjs/formatters": "1.0.0-dev.1763205226-9d5c6b458",
|
|
67
|
+
"@discordjs/rest": "3.0.0-dev.1763205226-9d5c6b458",
|
|
68
|
+
"@discordjs/ws": "3.0.0-dev.1763205226-9d5c6b458",
|
|
69
|
+
"@discordjs/util": "2.0.0-dev.1763205226-9d5c6b458"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@favware/cliff-jumper": "^4.1.0",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"turbo": "^2.5.8",
|
|
84
84
|
"typescript": "~5.9.3",
|
|
85
85
|
"@discordjs/api-extractor": "7.52.7",
|
|
86
|
-
"@discordjs/
|
|
87
|
-
"@discordjs/
|
|
86
|
+
"@discordjs/docgen": "0.12.1",
|
|
87
|
+
"@discordjs/scripts": "0.1.0"
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|
|
90
90
|
"node": ">=22.12.0"
|
package/src/client/Client.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
const process = require('node:process');
|
|
4
4
|
const { clearTimeout, setImmediate, setTimeout } = require('node:timers');
|
|
5
5
|
const { Collection } = require('@discordjs/collection');
|
|
6
|
-
const { makeURLSearchParams } = require('@discordjs/rest');
|
|
6
|
+
const { REST, RESTEvents, makeURLSearchParams } = require('@discordjs/rest');
|
|
7
7
|
const { WebSocketManager, WebSocketShardEvents, WebSocketShardStatus } = require('@discordjs/ws');
|
|
8
|
+
const { AsyncEventEmitter } = require('@vladfrangu/async_event_emitter');
|
|
8
9
|
const { GatewayDispatchEvents, GatewayIntentBits, OAuth2Scopes, Routes } = require('discord-api-types/v10');
|
|
9
10
|
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
|
10
11
|
const { ChannelManager } = require('../managers/ChannelManager.js');
|
|
@@ -28,7 +29,7 @@ const { Options } = require('../util/Options.js');
|
|
|
28
29
|
const { PermissionsBitField } = require('../util/PermissionsBitField.js');
|
|
29
30
|
const { Status } = require('../util/Status.js');
|
|
30
31
|
const { Sweepers } = require('../util/Sweepers.js');
|
|
31
|
-
const {
|
|
32
|
+
const { flatten } = require('../util/Util.js');
|
|
32
33
|
const { ActionsManager } = require('./actions/ActionsManager.js');
|
|
33
34
|
const { ClientVoiceManager } = require('./voice/ClientVoiceManager.js');
|
|
34
35
|
const { PacketHandlers } = require('./websocket/handlers/index.js');
|
|
@@ -47,24 +48,66 @@ const BeforeReadyWhitelist = [
|
|
|
47
48
|
/**
|
|
48
49
|
* The main hub for interacting with the Discord API, and the starting point for any bot.
|
|
49
50
|
*
|
|
50
|
-
* @extends {
|
|
51
|
+
* @extends {AsyncEventEmitter}
|
|
51
52
|
*/
|
|
52
|
-
class Client extends
|
|
53
|
+
class Client extends AsyncEventEmitter {
|
|
53
54
|
/**
|
|
54
55
|
* @param {ClientOptions} options Options for the client
|
|
55
56
|
*/
|
|
56
57
|
constructor(options) {
|
|
57
|
-
super(
|
|
58
|
+
super();
|
|
59
|
+
|
|
60
|
+
if (typeof options !== 'object' || options === null) {
|
|
61
|
+
throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const defaultOptions = Options.createDefault();
|
|
65
|
+
/**
|
|
66
|
+
* The options the client was instantiated with
|
|
67
|
+
*
|
|
68
|
+
* @type {ClientOptions}
|
|
69
|
+
*/
|
|
70
|
+
this.options = {
|
|
71
|
+
...defaultOptions,
|
|
72
|
+
...options,
|
|
73
|
+
presence: {
|
|
74
|
+
...defaultOptions.presence,
|
|
75
|
+
...options.presence,
|
|
76
|
+
},
|
|
77
|
+
sweepers: {
|
|
78
|
+
...defaultOptions.sweepers,
|
|
79
|
+
...options.sweepers,
|
|
80
|
+
},
|
|
81
|
+
ws: {
|
|
82
|
+
...defaultOptions.ws,
|
|
83
|
+
...options.ws,
|
|
84
|
+
},
|
|
85
|
+
rest: {
|
|
86
|
+
...defaultOptions.rest,
|
|
87
|
+
...options.rest,
|
|
88
|
+
userAgentAppendix: options.rest?.userAgentAppendix
|
|
89
|
+
? `${Options.userAgentAppendix} ${options.rest.userAgentAppendix}`
|
|
90
|
+
: Options.userAgentAppendix,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The REST manager of the client
|
|
96
|
+
*
|
|
97
|
+
* @type {REST}
|
|
98
|
+
*/
|
|
99
|
+
this.rest = new REST(this.options.rest);
|
|
100
|
+
|
|
101
|
+
this.rest.on(RESTEvents.Debug, message => this.emit(Events.Debug, message));
|
|
58
102
|
|
|
59
103
|
const data = require('node:worker_threads').workerData ?? process.env;
|
|
60
|
-
const defaults = Options.createDefault();
|
|
61
104
|
|
|
62
|
-
if (this.options.ws.shardIds ===
|
|
105
|
+
if (this.options.ws.shardIds === defaultOptions.ws.shardIds && 'SHARDS' in data) {
|
|
63
106
|
const shards = JSON.parse(data.SHARDS);
|
|
64
107
|
this.options.ws.shardIds = Array.isArray(shards) ? shards : [shards];
|
|
65
108
|
}
|
|
66
109
|
|
|
67
|
-
if (this.options.ws.shardCount ===
|
|
110
|
+
if (this.options.ws.shardCount === defaultOptions.ws.shardCount && 'SHARD_COUNT' in data) {
|
|
68
111
|
this.options.ws.shardCount = Number(data.SHARD_COUNT);
|
|
69
112
|
}
|
|
70
113
|
|
|
@@ -442,12 +485,56 @@ class Client extends BaseClient {
|
|
|
442
485
|
}
|
|
443
486
|
|
|
444
487
|
/**
|
|
445
|
-
*
|
|
488
|
+
* Options used for deleting a webhook.
|
|
489
|
+
*
|
|
490
|
+
* @typedef {Object} WebhookDeleteOptions
|
|
491
|
+
* @property {string} [token] Token of the webhook
|
|
492
|
+
* @property {string} [reason] The reason for deleting the webhook
|
|
493
|
+
*/
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Deletes a webhook.
|
|
497
|
+
*
|
|
498
|
+
* @param {Snowflake} id The webhook's id
|
|
499
|
+
* @param {WebhookDeleteOptions} [options] Options for deleting the webhook
|
|
500
|
+
* @returns {Promise<void>}
|
|
501
|
+
*/
|
|
502
|
+
async deleteWebhook(id, { token, reason } = {}) {
|
|
503
|
+
await this.rest.delete(Routes.webhook(id, token), { auth: !token, reason });
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Increments max listeners by one, if they are not zero.
|
|
508
|
+
*
|
|
509
|
+
* @private
|
|
510
|
+
*/
|
|
511
|
+
incrementMaxListeners() {
|
|
512
|
+
const maxListeners = this.getMaxListeners();
|
|
513
|
+
if (maxListeners !== 0) {
|
|
514
|
+
this.setMaxListeners(maxListeners + 1);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Decrements max listeners by one, if they are not zero.
|
|
520
|
+
*
|
|
521
|
+
* @private
|
|
522
|
+
*/
|
|
523
|
+
decrementMaxListeners() {
|
|
524
|
+
const maxListeners = this.getMaxListeners();
|
|
525
|
+
if (maxListeners !== 0) {
|
|
526
|
+
this.setMaxListeners(maxListeners - 1);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Destroys all assets used by the client.
|
|
446
532
|
*
|
|
447
533
|
* @returns {Promise<void>}
|
|
448
534
|
*/
|
|
449
535
|
async destroy() {
|
|
450
|
-
|
|
536
|
+
this.rest.clearHashSweeper();
|
|
537
|
+
this.rest.clearHandlerSweeper();
|
|
451
538
|
|
|
452
539
|
this.sweepers.destroy();
|
|
453
540
|
await this.ws.destroy();
|
|
@@ -701,10 +788,7 @@ class Client extends BaseClient {
|
|
|
701
788
|
}
|
|
702
789
|
|
|
703
790
|
toJSON() {
|
|
704
|
-
return
|
|
705
|
-
actions: false,
|
|
706
|
-
presence: false,
|
|
707
|
-
});
|
|
791
|
+
return flatten(this, { actions: false, presence: false });
|
|
708
792
|
}
|
|
709
793
|
|
|
710
794
|
/**
|
|
@@ -797,6 +881,10 @@ class Client extends BaseClient {
|
|
|
797
881
|
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'jsonTransformer', 'a function');
|
|
798
882
|
}
|
|
799
883
|
}
|
|
884
|
+
|
|
885
|
+
async [Symbol.asyncDispose]() {
|
|
886
|
+
await this.destroy();
|
|
887
|
+
}
|
|
800
888
|
}
|
|
801
889
|
|
|
802
890
|
exports.Client = Client;
|
|
@@ -846,6 +934,11 @@ exports.Client = Client;
|
|
|
846
934
|
* @see {@link https://discord.js.org/docs/packages/collection/stable/Collection:Class}
|
|
847
935
|
*/
|
|
848
936
|
|
|
937
|
+
/**
|
|
938
|
+
* @external REST
|
|
939
|
+
* @see {@link https://discord.js.org/docs/packages/rest/stable/REST:Class}
|
|
940
|
+
*/
|
|
941
|
+
|
|
849
942
|
/**
|
|
850
943
|
* @external ImageURLOptions
|
|
851
944
|
* @see {@link https://discord.js.org/docs/packages/rest/stable/ImageURLOptions:Interface}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const process = require('node:process');
|
|
4
|
+
const { GatewayOpcodes } = require('discord-api-types/v10');
|
|
5
|
+
|
|
6
|
+
const emittedFor = new Set();
|
|
7
|
+
|
|
8
|
+
module.exports = (client, { d: data }) => {
|
|
9
|
+
switch (data.opcode) {
|
|
10
|
+
case GatewayOpcodes.RequestGuildMembers: {
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
default: {
|
|
15
|
+
if (!emittedFor.has(data.opcode)) {
|
|
16
|
+
process.emitWarning(
|
|
17
|
+
`Hit a gateway rate limit on opcode ${data.opcode} (${GatewayOpcodes[data.opcode]}). If the discord.js version you're using is up-to-date, please open an issue on GitHub.`,
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
emittedFor.add(data.opcode);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -52,6 +52,7 @@ const PacketHandlers = Object.fromEntries([
|
|
|
52
52
|
['MESSAGE_REACTION_REMOVE_EMOJI', require('./MESSAGE_REACTION_REMOVE_EMOJI.js')],
|
|
53
53
|
['MESSAGE_UPDATE', require('./MESSAGE_UPDATE.js')],
|
|
54
54
|
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE.js')],
|
|
55
|
+
['RATE_LIMITED', require('./RATE_LIMITED.js')],
|
|
55
56
|
['READY', require('./READY.js')],
|
|
56
57
|
['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS.js')],
|
|
57
58
|
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE.js')],
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { __exportStar } = require('tslib');
|
|
4
4
|
|
|
5
5
|
// "Root" classes (starting points)
|
|
6
|
-
exports.BaseClient = require('./client/BaseClient.js').BaseClient;
|
|
7
6
|
exports.Client = require('./client/Client.js').Client;
|
|
8
7
|
exports.Shard = require('./sharding/Shard.js').Shard;
|
|
9
8
|
exports.ShardClientUtil = require('./sharding/ShardClientUtil.js').ShardClientUtil;
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
const { setTimeout, clearTimeout } = require('node:timers');
|
|
4
4
|
const { Collection } = require('@discordjs/collection');
|
|
5
5
|
const { makeURLSearchParams } = require('@discordjs/rest');
|
|
6
|
+
const { GatewayRateLimitError } = require('@discordjs/util');
|
|
7
|
+
const { WebSocketShardEvents } = require('@discordjs/ws');
|
|
6
8
|
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
|
7
|
-
const { Routes, GatewayOpcodes } = require('discord-api-types/v10');
|
|
9
|
+
const { Routes, GatewayOpcodes, GatewayDispatchEvents } = require('discord-api-types/v10');
|
|
8
10
|
const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors/index.js');
|
|
9
11
|
const { BaseGuildVoiceChannel } = require('../structures/BaseGuildVoiceChannel.js');
|
|
10
12
|
const { GuildMember } = require('../structures/GuildMember.js');
|
|
@@ -246,24 +248,27 @@ class GuildMemberManager extends CachedManager {
|
|
|
246
248
|
const query = initialQuery ?? (users ? undefined : '');
|
|
247
249
|
|
|
248
250
|
return new Promise((resolve, reject) => {
|
|
249
|
-
this.guild.client.ws.send(this.guild.shardId, {
|
|
250
|
-
op: GatewayOpcodes.RequestGuildMembers,
|
|
251
|
-
// eslint-disable-next-line id-length
|
|
252
|
-
d: {
|
|
253
|
-
guild_id: this.guild.id,
|
|
254
|
-
presences,
|
|
255
|
-
user_ids: users,
|
|
256
|
-
query,
|
|
257
|
-
nonce,
|
|
258
|
-
limit,
|
|
259
|
-
},
|
|
260
|
-
});
|
|
261
251
|
const fetchedMembers = new Collection();
|
|
262
252
|
let index = 0;
|
|
253
|
+
|
|
254
|
+
const cleanup = () => {
|
|
255
|
+
/* eslint-disable no-use-before-define */
|
|
256
|
+
clearTimeout(timeout);
|
|
257
|
+
|
|
258
|
+
this.client.ws.removeListener(WebSocketShardEvents.Dispatch, rateLimitHandler);
|
|
259
|
+
this.client.removeListener(Events.GuildMembersChunk, handler);
|
|
260
|
+
this.client.decrementMaxListeners();
|
|
261
|
+
/* eslint-enable no-use-before-define */
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const timeout = setTimeout(() => {
|
|
265
|
+
cleanup();
|
|
266
|
+
reject(new DiscordjsError(ErrorCodes.GuildMembersTimeout));
|
|
267
|
+
}, time).unref();
|
|
268
|
+
|
|
263
269
|
const handler = (members, _, chunk) => {
|
|
264
270
|
if (chunk.nonce !== nonce) return;
|
|
265
271
|
|
|
266
|
-
// eslint-disable-next-line no-use-before-define
|
|
267
272
|
timeout.refresh();
|
|
268
273
|
index++;
|
|
269
274
|
for (const member of members.values()) {
|
|
@@ -271,21 +276,37 @@ class GuildMemberManager extends CachedManager {
|
|
|
271
276
|
}
|
|
272
277
|
|
|
273
278
|
if (members.size < 1_000 || (limit && fetchedMembers.size >= limit) || index === chunk.count) {
|
|
274
|
-
|
|
275
|
-
clearTimeout(timeout);
|
|
276
|
-
this.client.removeListener(Events.GuildMembersChunk, handler);
|
|
277
|
-
this.client.decrementMaxListeners();
|
|
279
|
+
cleanup();
|
|
278
280
|
resolve(users && !Array.isArray(users) && fetchedMembers.size ? fetchedMembers.first() : fetchedMembers);
|
|
279
281
|
}
|
|
280
282
|
};
|
|
281
283
|
|
|
282
|
-
const
|
|
283
|
-
this.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
284
|
+
const requestData = {
|
|
285
|
+
guild_id: this.guild.id,
|
|
286
|
+
presences,
|
|
287
|
+
user_ids: users,
|
|
288
|
+
query,
|
|
289
|
+
nonce,
|
|
290
|
+
limit,
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const rateLimitHandler = payload => {
|
|
294
|
+
if (payload.t === GatewayDispatchEvents.RateLimited && payload.d.meta.nonce === nonce) {
|
|
295
|
+
cleanup();
|
|
296
|
+
reject(new GatewayRateLimitError(payload.d, requestData));
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
this.client.ws.on(WebSocketShardEvents.Dispatch, rateLimitHandler);
|
|
301
|
+
|
|
287
302
|
this.client.incrementMaxListeners();
|
|
288
303
|
this.client.on(Events.GuildMembersChunk, handler);
|
|
304
|
+
|
|
305
|
+
this.guild.client.ws.send(this.guild.shardId, {
|
|
306
|
+
op: GatewayOpcodes.RequestGuildMembers,
|
|
307
|
+
// eslint-disable-next-line id-length
|
|
308
|
+
d: requestData,
|
|
309
|
+
});
|
|
289
310
|
});
|
|
290
311
|
}
|
|
291
312
|
|
|
@@ -150,8 +150,8 @@ class MessageManager extends CachedManager {
|
|
|
150
150
|
*/
|
|
151
151
|
|
|
152
152
|
/**
|
|
153
|
-
* Fetches the pinned messages of this channel
|
|
154
|
-
* <info>The returned
|
|
153
|
+
* Fetches the pinned messages of this channel, returning a paginated result.
|
|
154
|
+
* <info>The returned messages do not contain any reaction data.
|
|
155
155
|
* Those need to be fetched separately.</info>
|
|
156
156
|
*
|
|
157
157
|
* @param {FetchPinnedMessagesOptions} [options={}] Options for fetching pinned messages
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { Buffer } = require('node:buffer');
|
|
4
|
-
const { isJSONEncodable } = require('@discordjs/util');
|
|
4
|
+
const { isJSONEncodable, lazy } = require('@discordjs/util');
|
|
5
5
|
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
|
6
6
|
const { DiscordjsError, DiscordjsRangeError, ErrorCodes } = require('../errors/index.js');
|
|
7
7
|
const { resolveFile } = require('../util/DataResolver.js');
|
|
8
8
|
const { MessageFlagsBitField } = require('../util/MessageFlagsBitField.js');
|
|
9
9
|
const { findName, verifyString, resolvePartialEmoji } = require('../util/Util.js');
|
|
10
10
|
|
|
11
|
+
// Fixes circular dependencies.
|
|
12
|
+
const getWebhook = lazy(() => require('./Webhook.js').Webhook);
|
|
13
|
+
const getUser = lazy(() => require('./User.js').User);
|
|
14
|
+
const getGuildMember = lazy(() => require('./GuildMember.js').GuildMember);
|
|
15
|
+
const getMessage = lazy(() => require('./Message.js').Message);
|
|
16
|
+
const getMessageManager = lazy(() => require('../managers/MessageManager.js').MessageManager);
|
|
17
|
+
|
|
11
18
|
/**
|
|
12
19
|
* Represents a message to be sent to the API.
|
|
13
20
|
*/
|
|
@@ -53,8 +60,7 @@ class MessagePayload {
|
|
|
53
60
|
* @readonly
|
|
54
61
|
*/
|
|
55
62
|
get isWebhook() {
|
|
56
|
-
|
|
57
|
-
return this.target instanceof Webhook;
|
|
63
|
+
return this.target instanceof getWebhook();
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
/**
|
|
@@ -64,9 +70,7 @@ class MessagePayload {
|
|
|
64
70
|
* @readonly
|
|
65
71
|
*/
|
|
66
72
|
get isUser() {
|
|
67
|
-
|
|
68
|
-
const { GuildMember } = require('./GuildMember.js');
|
|
69
|
-
return this.target instanceof User || this.target instanceof GuildMember;
|
|
73
|
+
return this.target instanceof getUser() || this.target instanceof getGuildMember();
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
/**
|
|
@@ -76,8 +80,7 @@ class MessagePayload {
|
|
|
76
80
|
* @readonly
|
|
77
81
|
*/
|
|
78
82
|
get isMessage() {
|
|
79
|
-
|
|
80
|
-
return this.target instanceof Message;
|
|
83
|
+
return this.target instanceof getMessage();
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
/**
|
|
@@ -87,8 +90,7 @@ class MessagePayload {
|
|
|
87
90
|
* @readonly
|
|
88
91
|
*/
|
|
89
92
|
get isMessageManager() {
|
|
90
|
-
|
|
91
|
-
return this.target instanceof MessageManager;
|
|
93
|
+
return this.target instanceof getMessageManager();
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
/**
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { Collection } = require('@discordjs/collection');
|
|
4
|
+
const { lazy } = require('@discordjs/util');
|
|
4
5
|
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
|
5
6
|
const { InteractionType, Routes } = require('discord-api-types/v10');
|
|
6
7
|
const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../../errors/index.js');
|
|
7
8
|
const { MaxBulkDeletableMessageAge } = require('../../util/Constants.js');
|
|
8
9
|
const { InteractionCollector } = require('../InteractionCollector.js');
|
|
9
|
-
// eslint-disable-next-line import-x/order
|
|
10
10
|
const { MessageCollector } = require('../MessageCollector.js');
|
|
11
11
|
|
|
12
|
+
// Fixes circular dependencies.
|
|
13
|
+
const getGuildMessageManager = lazy(() => require('../../managers/GuildMessageManager.js').GuildMessageManager);
|
|
14
|
+
|
|
12
15
|
/**
|
|
13
16
|
* Interface for classes that have text-channel-like features.
|
|
14
17
|
*
|
|
@@ -21,8 +24,7 @@ class TextBasedChannel {
|
|
|
21
24
|
*
|
|
22
25
|
* @type {GuildMessageManager}
|
|
23
26
|
*/
|
|
24
|
-
|
|
25
|
-
this.messages = new GuildMessageManager(this);
|
|
27
|
+
this.messages = new (getGuildMessageManager())(this);
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* The channel's last message id, if one was sent
|
|
@@ -427,7 +429,3 @@ class TextBasedChannel {
|
|
|
427
429
|
}
|
|
428
430
|
|
|
429
431
|
exports.TextBasedChannel = TextBasedChannel;
|
|
430
|
-
|
|
431
|
-
// Fixes Circular
|
|
432
|
-
// eslint-disable-next-line import-x/order
|
|
433
|
-
const { GuildMessageManager } = require('../../managers/GuildMessageManager.js');
|
package/src/util/Components.js
CHANGED
|
@@ -1,9 +1,37 @@
|
|
|
1
|
-
/* eslint-disable no-use-before-define */
|
|
2
1
|
'use strict';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
const { lazy } = require('@discordjs/util');
|
|
5
4
|
const { ComponentType } = require('discord-api-types/v10');
|
|
6
5
|
|
|
6
|
+
// Fixes circular dependencies.
|
|
7
|
+
const getActionRow = lazy(() => require('../structures/ActionRow.js').ActionRow);
|
|
8
|
+
const getButtonComponent = lazy(() => require('../structures/ButtonComponent.js').ButtonComponent);
|
|
9
|
+
const getChannelSelectMenuComponent = lazy(
|
|
10
|
+
() => require('../structures/ChannelSelectMenuComponent.js').ChannelSelectMenuComponent,
|
|
11
|
+
);
|
|
12
|
+
const getComponent = lazy(() => require('../structures/Component.js').Component);
|
|
13
|
+
const getContainerComponent = lazy(() => require('../structures/ContainerComponent.js').ContainerComponent);
|
|
14
|
+
const getFileComponent = lazy(() => require('../structures/FileComponent.js').FileComponent);
|
|
15
|
+
const getLabelComponent = lazy(() => require('../structures/LabelComponent.js').LabelComponent);
|
|
16
|
+
const getMediaGalleryComponent = lazy(() => require('../structures/MediaGalleryComponent.js').MediaGalleryComponent);
|
|
17
|
+
const getMentionableSelectMenuComponent = lazy(
|
|
18
|
+
() => require('../structures/MentionableSelectMenuComponent.js').MentionableSelectMenuComponent,
|
|
19
|
+
);
|
|
20
|
+
const getRoleSelectMenuComponent = lazy(
|
|
21
|
+
() => require('../structures/RoleSelectMenuComponent.js').RoleSelectMenuComponent,
|
|
22
|
+
);
|
|
23
|
+
const getSectionComponent = lazy(() => require('../structures/SectionComponent.js').SectionComponent);
|
|
24
|
+
const getSeparatorComponent = lazy(() => require('../structures/SeparatorComponent.js').SeparatorComponent);
|
|
25
|
+
const getStringSelectMenuComponent = lazy(
|
|
26
|
+
() => require('../structures/StringSelectMenuComponent.js').StringSelectMenuComponent,
|
|
27
|
+
);
|
|
28
|
+
const getTextDisplayComponent = lazy(() => require('../structures/TextDisplayComponent.js').TextDisplayComponent);
|
|
29
|
+
const getTextInputComponent = lazy(() => require('../structures/TextInputComponent.js').TextInputComponent);
|
|
30
|
+
const getThumbnailComponent = lazy(() => require('../structures/ThumbnailComponent.js').ThumbnailComponent);
|
|
31
|
+
const getUserSelectMenuComponent = lazy(
|
|
32
|
+
() => require('../structures/UserSelectMenuComponent.js').UserSelectMenuComponent,
|
|
33
|
+
);
|
|
34
|
+
|
|
7
35
|
/**
|
|
8
36
|
* @typedef {Object} BaseComponentData
|
|
9
37
|
* @property {number} [id] the id of this component
|
|
@@ -192,6 +220,25 @@ const { ComponentType } = require('discord-api-types/v10');
|
|
|
192
220
|
* SectionComponent|SeparatorComponent|TextDisplayComponent} MessageTopLevelComponent
|
|
193
221
|
*/
|
|
194
222
|
|
|
223
|
+
const ComponentTypeToClass = {
|
|
224
|
+
[ComponentType.ActionRow]: getActionRow,
|
|
225
|
+
[ComponentType.Button]: getButtonComponent,
|
|
226
|
+
[ComponentType.StringSelect]: getStringSelectMenuComponent,
|
|
227
|
+
[ComponentType.TextInput]: getTextInputComponent,
|
|
228
|
+
[ComponentType.UserSelect]: getUserSelectMenuComponent,
|
|
229
|
+
[ComponentType.RoleSelect]: getRoleSelectMenuComponent,
|
|
230
|
+
[ComponentType.MentionableSelect]: getMentionableSelectMenuComponent,
|
|
231
|
+
[ComponentType.ChannelSelect]: getChannelSelectMenuComponent,
|
|
232
|
+
[ComponentType.Container]: getContainerComponent,
|
|
233
|
+
[ComponentType.TextDisplay]: getTextDisplayComponent,
|
|
234
|
+
[ComponentType.File]: getFileComponent,
|
|
235
|
+
[ComponentType.MediaGallery]: getMediaGalleryComponent,
|
|
236
|
+
[ComponentType.Section]: getSectionComponent,
|
|
237
|
+
[ComponentType.Separator]: getSeparatorComponent,
|
|
238
|
+
[ComponentType.Thumbnail]: getThumbnailComponent,
|
|
239
|
+
[ComponentType.Label]: getLabelComponent,
|
|
240
|
+
};
|
|
241
|
+
|
|
195
242
|
/**
|
|
196
243
|
* Transforms API data into a component
|
|
197
244
|
*
|
|
@@ -200,7 +247,7 @@ const { ComponentType } = require('discord-api-types/v10');
|
|
|
200
247
|
* @ignore
|
|
201
248
|
*/
|
|
202
249
|
function createComponent(data) {
|
|
203
|
-
return data instanceof
|
|
250
|
+
return data instanceof getComponent() ? data : new (ComponentTypeToClass[data.type]?.() ?? getComponent())(data);
|
|
204
251
|
}
|
|
205
252
|
|
|
206
253
|
/**
|
|
@@ -241,40 +288,3 @@ function findComponentByCustomId(components, customId) {
|
|
|
241
288
|
|
|
242
289
|
exports.createComponent = createComponent;
|
|
243
290
|
exports.findComponentByCustomId = findComponentByCustomId;
|
|
244
|
-
|
|
245
|
-
const { ActionRow } = require('../structures/ActionRow.js');
|
|
246
|
-
const { ButtonComponent } = require('../structures/ButtonComponent.js');
|
|
247
|
-
const { ChannelSelectMenuComponent } = require('../structures/ChannelSelectMenuComponent.js');
|
|
248
|
-
const { Component } = require('../structures/Component.js');
|
|
249
|
-
const { ContainerComponent } = require('../structures/ContainerComponent.js');
|
|
250
|
-
const { FileComponent } = require('../structures/FileComponent.js');
|
|
251
|
-
const { LabelComponent } = require('../structures/LabelComponent.js');
|
|
252
|
-
const { MediaGalleryComponent } = require('../structures/MediaGalleryComponent.js');
|
|
253
|
-
const { MentionableSelectMenuComponent } = require('../structures/MentionableSelectMenuComponent.js');
|
|
254
|
-
const { RoleSelectMenuComponent } = require('../structures/RoleSelectMenuComponent.js');
|
|
255
|
-
const { SectionComponent } = require('../structures/SectionComponent.js');
|
|
256
|
-
const { SeparatorComponent } = require('../structures/SeparatorComponent.js');
|
|
257
|
-
const { StringSelectMenuComponent } = require('../structures/StringSelectMenuComponent.js');
|
|
258
|
-
const { TextDisplayComponent } = require('../structures/TextDisplayComponent.js');
|
|
259
|
-
const { TextInputComponent } = require('../structures/TextInputComponent.js');
|
|
260
|
-
const { ThumbnailComponent } = require('../structures/ThumbnailComponent.js');
|
|
261
|
-
const { UserSelectMenuComponent } = require('../structures/UserSelectMenuComponent.js');
|
|
262
|
-
|
|
263
|
-
const ComponentTypeToClass = {
|
|
264
|
-
[ComponentType.ActionRow]: ActionRow,
|
|
265
|
-
[ComponentType.Button]: ButtonComponent,
|
|
266
|
-
[ComponentType.StringSelect]: StringSelectMenuComponent,
|
|
267
|
-
[ComponentType.TextInput]: TextInputComponent,
|
|
268
|
-
[ComponentType.UserSelect]: UserSelectMenuComponent,
|
|
269
|
-
[ComponentType.RoleSelect]: RoleSelectMenuComponent,
|
|
270
|
-
[ComponentType.MentionableSelect]: MentionableSelectMenuComponent,
|
|
271
|
-
[ComponentType.ChannelSelect]: ChannelSelectMenuComponent,
|
|
272
|
-
[ComponentType.Container]: ContainerComponent,
|
|
273
|
-
[ComponentType.TextDisplay]: TextDisplayComponent,
|
|
274
|
-
[ComponentType.File]: FileComponent,
|
|
275
|
-
[ComponentType.MediaGallery]: MediaGalleryComponent,
|
|
276
|
-
[ComponentType.Section]: SectionComponent,
|
|
277
|
-
[ComponentType.Separator]: SeparatorComponent,
|
|
278
|
-
[ComponentType.Thumbnail]: ThumbnailComponent,
|
|
279
|
-
[ComponentType.Label]: LabelComponent,
|
|
280
|
-
};
|
package/src/util/DataResolver.js
CHANGED
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
const { Buffer } = require('node:buffer');
|
|
4
4
|
const fs = require('node:fs/promises');
|
|
5
5
|
const path = require('node:path');
|
|
6
|
+
const { lazy } = require('@discordjs/util');
|
|
6
7
|
const { fetch } = require('undici');
|
|
7
8
|
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
|
8
9
|
const { BaseInvite } = require('../structures/BaseInvite.js');
|
|
9
10
|
|
|
11
|
+
// Fixes circular dependencies.
|
|
12
|
+
const getGuildTemplate = lazy(() => require('../structures/GuildTemplate.js').GuildTemplate);
|
|
13
|
+
|
|
10
14
|
/**
|
|
11
15
|
* Data that can be resolved to give an invite code. This can be:
|
|
12
16
|
* - An invite code
|
|
@@ -54,8 +58,7 @@ function resolveInviteCode(data) {
|
|
|
54
58
|
* @private
|
|
55
59
|
*/
|
|
56
60
|
function resolveGuildTemplateCode(data) {
|
|
57
|
-
|
|
58
|
-
return resolveCode(data, GuildTemplate.GuildTemplatesPattern);
|
|
61
|
+
return resolveCode(data, getGuildTemplate().GuildTemplatesPattern);
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
/**
|
package/src/util/Util.js
CHANGED
|
@@ -2,13 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
const { parse } = require('node:path');
|
|
4
4
|
const { Collection } = require('@discordjs/collection');
|
|
5
|
+
const { lazy } = require('@discordjs/util');
|
|
5
6
|
const { ChannelType, RouteBases, Routes } = require('discord-api-types/v10');
|
|
6
7
|
const { fetch } = require('undici');
|
|
7
|
-
// eslint-disable-next-line import-x/order
|
|
8
8
|
const { Colors } = require('./Colors.js');
|
|
9
9
|
// eslint-disable-next-line import-x/order
|
|
10
10
|
const { DiscordjsError, DiscordjsRangeError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
|
11
11
|
|
|
12
|
+
// Fixes circular dependencies.
|
|
13
|
+
const getAttachment = lazy(() => require('../structures/Attachment.js').Attachment);
|
|
14
|
+
const getGuildChannel = lazy(() => require('../structures/GuildChannel.js').GuildChannel);
|
|
15
|
+
const getSKU = lazy(() => require('../structures/SKU.js').SKU);
|
|
16
|
+
|
|
12
17
|
const isObject = data => typeof data === 'object' && data !== null;
|
|
13
18
|
|
|
14
19
|
/**
|
|
@@ -352,8 +357,7 @@ function resolveColor(color) {
|
|
|
352
357
|
* @returns {Collection}
|
|
353
358
|
*/
|
|
354
359
|
function discordSort(collection) {
|
|
355
|
-
|
|
356
|
-
const isGuildChannel = collection.first() instanceof GuildChannel;
|
|
360
|
+
const isGuildChannel = collection.first() instanceof getGuildChannel();
|
|
357
361
|
return collection.toSorted(
|
|
358
362
|
isGuildChannel
|
|
359
363
|
? (a, b) => a.rawPosition - b.rawPosition || Number(BigInt(a.id) - BigInt(b.id))
|
|
@@ -555,8 +559,7 @@ function transformResolved(
|
|
|
555
559
|
if (attachments) {
|
|
556
560
|
result.attachments = new Collection();
|
|
557
561
|
for (const attachment of Object.values(attachments)) {
|
|
558
|
-
|
|
559
|
-
const patched = new Attachment(attachment);
|
|
562
|
+
const patched = new (getAttachment())(attachment);
|
|
560
563
|
result.attachments.set(attachment.id, patched);
|
|
561
564
|
}
|
|
562
565
|
}
|
|
@@ -572,8 +575,7 @@ function transformResolved(
|
|
|
572
575
|
*/
|
|
573
576
|
function resolveSKUId(resolvable) {
|
|
574
577
|
if (typeof resolvable === 'string') return resolvable;
|
|
575
|
-
|
|
576
|
-
if (resolvable instanceof SKU) return resolvable.id;
|
|
578
|
+
if (resolvable instanceof getSKU()) return resolvable.id;
|
|
577
579
|
return null;
|
|
578
580
|
}
|
|
579
581
|
|
|
@@ -600,8 +602,3 @@ exports.setPosition = setPosition;
|
|
|
600
602
|
exports.basename = basename;
|
|
601
603
|
exports.findName = findName;
|
|
602
604
|
exports.transformResolved = transformResolved;
|
|
603
|
-
|
|
604
|
-
// Fixes Circular
|
|
605
|
-
const { Attachment } = require('../structures/Attachment.js');
|
|
606
|
-
const { GuildChannel } = require('../structures/GuildChannel.js');
|
|
607
|
-
const { SKU } = require('../structures/SKU.js');
|
package/typings/index.d.mts
CHANGED
|
@@ -492,18 +492,6 @@ export abstract class Base {
|
|
|
492
492
|
public valueOf(): string;
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
export class BaseClient<Events extends {}> extends AsyncEventEmitter<Events> implements AsyncDisposable {
|
|
496
|
-
public constructor(options?: ClientOptions);
|
|
497
|
-
private decrementMaxListeners(): void;
|
|
498
|
-
private incrementMaxListeners(): void;
|
|
499
|
-
|
|
500
|
-
public options: ClientOptions;
|
|
501
|
-
public rest: REST;
|
|
502
|
-
public destroy(): void;
|
|
503
|
-
public toJSON(...props: Record<string, boolean | string>[]): unknown;
|
|
504
|
-
public [Symbol.asyncDispose](): Promise<void>;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
495
|
export type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer<
|
|
508
496
|
Cached,
|
|
509
497
|
Message<true>,
|
|
@@ -913,7 +901,10 @@ export type If<Value extends boolean, TrueResult, FalseResult = null> = Value ex
|
|
|
913
901
|
? FalseResult
|
|
914
902
|
: FalseResult | TrueResult;
|
|
915
903
|
|
|
916
|
-
export class Client<Ready extends boolean = boolean>
|
|
904
|
+
export class Client<Ready extends boolean = boolean>
|
|
905
|
+
extends AsyncEventEmitter<ClientEventTypes>
|
|
906
|
+
implements AsyncDisposable
|
|
907
|
+
{
|
|
917
908
|
public constructor(options: ClientOptions);
|
|
918
909
|
private readonly actions: unknown;
|
|
919
910
|
private readonly expectedGuilds: Set<Snowflake>;
|
|
@@ -928,6 +919,8 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
|
|
|
928
919
|
private _triggerClientReady(): void;
|
|
929
920
|
private _validateOptions(options: ClientOptions): void;
|
|
930
921
|
private get _censoredToken(): string | null;
|
|
922
|
+
private decrementMaxListeners(): void;
|
|
923
|
+
private incrementMaxListeners(): void;
|
|
931
924
|
// This a technique used to brand the ready state. Or else we'll get `never` errors on typeguard checks.
|
|
932
925
|
private readonly _ready: Ready;
|
|
933
926
|
|
|
@@ -939,6 +932,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
|
|
|
939
932
|
public get ping(): number | null;
|
|
940
933
|
public get readyAt(): If<Ready, Date>;
|
|
941
934
|
public readyTimestamp: If<Ready, number>;
|
|
935
|
+
public rest: REST;
|
|
942
936
|
public sweepers: Sweepers;
|
|
943
937
|
public shard: ShardClientUtil | null;
|
|
944
938
|
public status: Status;
|
|
@@ -969,6 +963,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
|
|
|
969
963
|
public login(token?: string): Promise<string>;
|
|
970
964
|
public isReady(): this is Client<true>;
|
|
971
965
|
public toJSON(): unknown;
|
|
966
|
+
public [Symbol.asyncDispose](): Promise<void>;
|
|
972
967
|
}
|
|
973
968
|
|
|
974
969
|
export interface StickerPackFetchOptions {
|
package/typings/index.d.ts
CHANGED
|
@@ -492,18 +492,6 @@ export abstract class Base {
|
|
|
492
492
|
public valueOf(): string;
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
export class BaseClient<Events extends {}> extends AsyncEventEmitter<Events> implements AsyncDisposable {
|
|
496
|
-
public constructor(options?: ClientOptions);
|
|
497
|
-
private decrementMaxListeners(): void;
|
|
498
|
-
private incrementMaxListeners(): void;
|
|
499
|
-
|
|
500
|
-
public options: ClientOptions;
|
|
501
|
-
public rest: REST;
|
|
502
|
-
public destroy(): void;
|
|
503
|
-
public toJSON(...props: Record<string, boolean | string>[]): unknown;
|
|
504
|
-
public [Symbol.asyncDispose](): Promise<void>;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
495
|
export type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer<
|
|
508
496
|
Cached,
|
|
509
497
|
Message<true>,
|
|
@@ -913,7 +901,10 @@ export type If<Value extends boolean, TrueResult, FalseResult = null> = Value ex
|
|
|
913
901
|
? FalseResult
|
|
914
902
|
: FalseResult | TrueResult;
|
|
915
903
|
|
|
916
|
-
export class Client<Ready extends boolean = boolean>
|
|
904
|
+
export class Client<Ready extends boolean = boolean>
|
|
905
|
+
extends AsyncEventEmitter<ClientEventTypes>
|
|
906
|
+
implements AsyncDisposable
|
|
907
|
+
{
|
|
917
908
|
public constructor(options: ClientOptions);
|
|
918
909
|
private readonly actions: unknown;
|
|
919
910
|
private readonly expectedGuilds: Set<Snowflake>;
|
|
@@ -928,6 +919,8 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
|
|
|
928
919
|
private _triggerClientReady(): void;
|
|
929
920
|
private _validateOptions(options: ClientOptions): void;
|
|
930
921
|
private get _censoredToken(): string | null;
|
|
922
|
+
private decrementMaxListeners(): void;
|
|
923
|
+
private incrementMaxListeners(): void;
|
|
931
924
|
// This a technique used to brand the ready state. Or else we'll get `never` errors on typeguard checks.
|
|
932
925
|
private readonly _ready: Ready;
|
|
933
926
|
|
|
@@ -939,6 +932,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
|
|
|
939
932
|
public get ping(): number | null;
|
|
940
933
|
public get readyAt(): If<Ready, Date>;
|
|
941
934
|
public readyTimestamp: If<Ready, number>;
|
|
935
|
+
public rest: REST;
|
|
942
936
|
public sweepers: Sweepers;
|
|
943
937
|
public shard: ShardClientUtil | null;
|
|
944
938
|
public status: Status;
|
|
@@ -969,6 +963,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
|
|
|
969
963
|
public login(token?: string): Promise<string>;
|
|
970
964
|
public isReady(): this is Client<true>;
|
|
971
965
|
public toJSON(): unknown;
|
|
966
|
+
public [Symbol.asyncDispose](): Promise<void>;
|
|
972
967
|
}
|
|
973
968
|
|
|
974
969
|
export interface StickerPackFetchOptions {
|
package/src/client/BaseClient.js
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { REST, RESTEvents } = require('@discordjs/rest');
|
|
4
|
-
const { AsyncEventEmitter } = require('@vladfrangu/async_event_emitter');
|
|
5
|
-
const { Routes } = require('discord-api-types/v10');
|
|
6
|
-
const { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
|
7
|
-
const { Events } = require('../util/Events.js');
|
|
8
|
-
const { Options } = require('../util/Options.js');
|
|
9
|
-
const { flatten } = require('../util/Util.js');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The base class for all clients.
|
|
13
|
-
*
|
|
14
|
-
* @extends {AsyncEventEmitter}
|
|
15
|
-
*/
|
|
16
|
-
class BaseClient extends AsyncEventEmitter {
|
|
17
|
-
constructor(options = {}) {
|
|
18
|
-
super();
|
|
19
|
-
|
|
20
|
-
if (typeof options !== 'object' || options === null) {
|
|
21
|
-
throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const defaultOptions = Options.createDefault();
|
|
25
|
-
/**
|
|
26
|
-
* The options the client was instantiated with
|
|
27
|
-
*
|
|
28
|
-
* @type {ClientOptions}
|
|
29
|
-
*/
|
|
30
|
-
this.options = {
|
|
31
|
-
...defaultOptions,
|
|
32
|
-
...options,
|
|
33
|
-
presence: {
|
|
34
|
-
...defaultOptions.presence,
|
|
35
|
-
...options.presence,
|
|
36
|
-
},
|
|
37
|
-
sweepers: {
|
|
38
|
-
...defaultOptions.sweepers,
|
|
39
|
-
...options.sweepers,
|
|
40
|
-
},
|
|
41
|
-
ws: {
|
|
42
|
-
...defaultOptions.ws,
|
|
43
|
-
...options.ws,
|
|
44
|
-
},
|
|
45
|
-
rest: {
|
|
46
|
-
...defaultOptions.rest,
|
|
47
|
-
...options.rest,
|
|
48
|
-
userAgentAppendix: options.rest?.userAgentAppendix
|
|
49
|
-
? `${Options.userAgentAppendix} ${options.rest.userAgentAppendix}`
|
|
50
|
-
: Options.userAgentAppendix,
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* The REST manager of the client
|
|
56
|
-
*
|
|
57
|
-
* @type {REST}
|
|
58
|
-
*/
|
|
59
|
-
this.rest = new REST(this.options.rest);
|
|
60
|
-
|
|
61
|
-
this.rest.on(RESTEvents.Debug, message => this.emit(Events.Debug, message));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Destroys all assets used by the base client.
|
|
66
|
-
*
|
|
67
|
-
* @returns {void}
|
|
68
|
-
*/
|
|
69
|
-
destroy() {
|
|
70
|
-
this.rest.clearHashSweeper();
|
|
71
|
-
this.rest.clearHandlerSweeper();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Options used for deleting a webhook.
|
|
76
|
-
*
|
|
77
|
-
* @typedef {Object} WebhookDeleteOptions
|
|
78
|
-
* @property {string} [token] Token of the webhook
|
|
79
|
-
* @property {string} [reason] The reason for deleting the webhook
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Deletes a webhook.
|
|
84
|
-
*
|
|
85
|
-
* @param {Snowflake} id The webhook's id
|
|
86
|
-
* @param {WebhookDeleteOptions} [options] Options for deleting the webhook
|
|
87
|
-
* @returns {Promise<void>}
|
|
88
|
-
*/
|
|
89
|
-
async deleteWebhook(id, { token, reason } = {}) {
|
|
90
|
-
await this.rest.delete(Routes.webhook(id, token), { auth: !token, reason });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Increments max listeners by one, if they are not zero.
|
|
95
|
-
*
|
|
96
|
-
* @private
|
|
97
|
-
*/
|
|
98
|
-
incrementMaxListeners() {
|
|
99
|
-
const maxListeners = this.getMaxListeners();
|
|
100
|
-
if (maxListeners !== 0) {
|
|
101
|
-
this.setMaxListeners(maxListeners + 1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Decrements max listeners by one, if they are not zero.
|
|
107
|
-
*
|
|
108
|
-
* @private
|
|
109
|
-
*/
|
|
110
|
-
decrementMaxListeners() {
|
|
111
|
-
const maxListeners = this.getMaxListeners();
|
|
112
|
-
if (maxListeners !== 0) {
|
|
113
|
-
this.setMaxListeners(maxListeners - 1);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
toJSON(...props) {
|
|
118
|
-
return flatten(this, ...props);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async [Symbol.asyncDispose]() {
|
|
122
|
-
await this.destroy();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
exports.BaseClient = BaseClient;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* @external REST
|
|
130
|
-
* @see {@link https://discord.js.org/docs/packages/rest/stable/REST:Class}
|
|
131
|
-
*/
|