mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
refactor!: fully integrate /ws into mainlib (#10420)
BREAKING CHANGE: `Client#ws` is now a `@discordjs/ws#WebSocketManager` BREAKING CHANGE: `WebSocketManager` and `WebSocketShard` are now re-exports from `@discordjs/ws` BREAKING CHANGE: Removed the `WebSocketShardEvents` enum BREAKING CHANGE: Renamed the `Client#ready` event to `Client#clientReady` event to not confuse it with the gateway `READY` event BREAKING CHANGE: Added `Client#ping` to replace the old `WebSocketManager#ping` BREAKING CHANGE: Removed the `Shard#reconnecting` event which wasn’t emitted anymore since 14.8.0 anyway BREAKING CHANGE: Removed `ShardClientUtil#ids` and `ShardClientUtil#count` in favor of `Client#ws#getShardIds()` and `Client#ws#getShardCount()` BREAKING CHANGE: `ClientUser#setPresence()` and `ClientPresence#set()` now return a Promise which resolves when the gateway call was sent successfully BREAKING CHANGE: Removed `Guild#shard` as `WebSocketShard`s are now handled by `@discordjs/ws` BREAKING CHANGE: Removed the following deprecated `Client` events: `raw`, `shardDisconnect`, `shardError`, `shardReady`, `shardReconnecting`, `shardResume` in favor of events from `@discordjs/ws#WebSocketManager` BREAKING CHANGE: Removed `ClientOptions#shards` and `ClientOptions#shardCount` in favor of `ClientOptions#ws#shardIds` and `ClientOptions#ws#shardCount`
This commit is contained in:
@@ -70,7 +70,7 @@
|
|||||||
"@discordjs/formatters": "workspace:^",
|
"@discordjs/formatters": "workspace:^",
|
||||||
"@discordjs/rest": "workspace:^",
|
"@discordjs/rest": "workspace:^",
|
||||||
"@discordjs/util": "workspace:^",
|
"@discordjs/util": "workspace:^",
|
||||||
"@discordjs/ws": "1.1.1",
|
"@discordjs/ws": "workspace:^",
|
||||||
"@sapphire/snowflake": "3.5.3",
|
"@sapphire/snowflake": "3.5.3",
|
||||||
"discord-api-types": "^0.37.101",
|
"discord-api-types": "^0.37.101",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const process = require('node:process');
|
const process = require('node:process');
|
||||||
|
const { clearTimeout, setImmediate, setTimeout } = require('node:timers');
|
||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const { makeURLSearchParams } = require('@discordjs/rest');
|
const { makeURLSearchParams } = require('@discordjs/rest');
|
||||||
const { OAuth2Scopes, Routes } = require('discord-api-types/v10');
|
const { WebSocketManager, WebSocketShardEvents, WebSocketShardStatus } = require('@discordjs/ws');
|
||||||
|
const { GatewayDispatchEvents, GatewayIntentBits, OAuth2Scopes, Routes } = require('discord-api-types/v10');
|
||||||
const BaseClient = require('./BaseClient');
|
const BaseClient = require('./BaseClient');
|
||||||
const ActionsManager = require('./actions/ActionsManager');
|
const ActionsManager = require('./actions/ActionsManager');
|
||||||
const ClientVoiceManager = require('./voice/ClientVoiceManager');
|
const ClientVoiceManager = require('./voice/ClientVoiceManager');
|
||||||
const WebSocketManager = require('./websocket/WebSocketManager');
|
const PacketHandlers = require('./websocket/handlers');
|
||||||
const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors');
|
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
|
||||||
const BaseGuildEmojiManager = require('../managers/BaseGuildEmojiManager');
|
const BaseGuildEmojiManager = require('../managers/BaseGuildEmojiManager');
|
||||||
const ChannelManager = require('../managers/ChannelManager');
|
const ChannelManager = require('../managers/ChannelManager');
|
||||||
const GuildManager = require('../managers/GuildManager');
|
const GuildManager = require('../managers/GuildManager');
|
||||||
@@ -31,6 +33,17 @@ const PermissionsBitField = require('../util/PermissionsBitField');
|
|||||||
const Status = require('../util/Status');
|
const Status = require('../util/Status');
|
||||||
const Sweepers = require('../util/Sweepers');
|
const Sweepers = require('../util/Sweepers');
|
||||||
|
|
||||||
|
const WaitingForGuildEvents = [GatewayDispatchEvents.GuildCreate, GatewayDispatchEvents.GuildDelete];
|
||||||
|
const BeforeReadyWhitelist = [
|
||||||
|
GatewayDispatchEvents.Ready,
|
||||||
|
GatewayDispatchEvents.Resumed,
|
||||||
|
GatewayDispatchEvents.GuildCreate,
|
||||||
|
GatewayDispatchEvents.GuildDelete,
|
||||||
|
GatewayDispatchEvents.GuildMembersChunk,
|
||||||
|
GatewayDispatchEvents.GuildMemberAdd,
|
||||||
|
GatewayDispatchEvents.GuildMemberRemove,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main hub for interacting with the Discord API, and the starting point for any bot.
|
* The main hub for interacting with the Discord API, and the starting point for any bot.
|
||||||
* @extends {BaseClient}
|
* @extends {BaseClient}
|
||||||
@@ -45,43 +58,45 @@ class Client extends BaseClient {
|
|||||||
const data = require('node:worker_threads').workerData ?? process.env;
|
const data = require('node:worker_threads').workerData ?? process.env;
|
||||||
const defaults = Options.createDefault();
|
const defaults = Options.createDefault();
|
||||||
|
|
||||||
if (this.options.shards === defaults.shards) {
|
if (this.options.ws.shardIds === defaults.ws.shardIds && 'SHARDS' in data) {
|
||||||
if ('SHARDS' in data) {
|
this.options.ws.shardIds = JSON.parse(data.SHARDS);
|
||||||
this.options.shards = JSON.parse(data.SHARDS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.shardCount === defaults.shardCount) {
|
if (this.options.ws.shardCount === defaults.ws.shardCount && 'SHARD_COUNT' in data) {
|
||||||
if ('SHARD_COUNT' in data) {
|
this.options.ws.shardCount = Number(data.SHARD_COUNT);
|
||||||
this.options.shardCount = Number(data.SHARD_COUNT);
|
|
||||||
} else if (Array.isArray(this.options.shards)) {
|
|
||||||
this.options.shardCount = this.options.shards.length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeofShards = typeof this.options.shards;
|
/**
|
||||||
|
* The presence of the Client
|
||||||
if (typeofShards === 'undefined' && typeof this.options.shardCount === 'number') {
|
* @private
|
||||||
this.options.shards = Array.from({ length: this.options.shardCount }, (_, i) => i);
|
* @type {ClientPresence}
|
||||||
}
|
*/
|
||||||
|
this.presence = new ClientPresence(this, this.options.ws.initialPresence ?? this.options.presence);
|
||||||
if (typeofShards === 'number') this.options.shards = [this.options.shards];
|
|
||||||
|
|
||||||
if (Array.isArray(this.options.shards)) {
|
|
||||||
this.options.shards = [
|
|
||||||
...new Set(
|
|
||||||
this.options.shards.filter(item => !isNaN(item) && item >= 0 && item < Infinity && item === (item | 0)),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
this._validateOptions();
|
this._validateOptions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The WebSocket manager of the client
|
* The current status of this Client
|
||||||
* @type {WebSocketManager}
|
* @type {Status}
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
this.ws = new WebSocketManager(this);
|
this.status = Status.Idle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of guild ids this Client expects to receive
|
||||||
|
* @name Client#expectedGuilds
|
||||||
|
* @type {Set<string>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Object.defineProperty(this, 'expectedGuilds', { value: new Set(), writable: true });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ready timeout
|
||||||
|
* @name Client#readyTimeout
|
||||||
|
* @type {?NodeJS.Timeout}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Object.defineProperty(this, 'readyTimeout', { value: null, writable: true });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The action manager of the client
|
* The action manager of the client
|
||||||
@@ -90,12 +105,6 @@ class Client extends BaseClient {
|
|||||||
*/
|
*/
|
||||||
this.actions = new ActionsManager(this);
|
this.actions = new ActionsManager(this);
|
||||||
|
|
||||||
/**
|
|
||||||
* The voice manager of the client
|
|
||||||
* @type {ClientVoiceManager}
|
|
||||||
*/
|
|
||||||
this.voice = new ClientVoiceManager(this);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shard helpers for the client (only if the process was spawned from a {@link ShardingManager})
|
* Shard helpers for the client (only if the process was spawned from a {@link ShardingManager})
|
||||||
* @type {?ShardClientUtil}
|
* @type {?ShardClientUtil}
|
||||||
@@ -119,7 +128,7 @@ class Client extends BaseClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* All of the {@link BaseChannel}s that the client is currently handling, mapped by their ids -
|
* All of the {@link BaseChannel}s that the client is currently handling, mapped by their ids -
|
||||||
* as long as sharding isn't being used, this will be *every* channel in *every* guild the bot
|
* as long as no sharding manager is being used, this will be *every* channel in *every* guild the bot
|
||||||
* is a member of. Note that DM channels will not be initially cached, and thus not be present
|
* is a member of. Note that DM channels will not be initially cached, and thus not be present
|
||||||
* in the Manager without their explicit fetching or use.
|
* in the Manager without their explicit fetching or use.
|
||||||
* @type {ChannelManager}
|
* @type {ChannelManager}
|
||||||
@@ -132,13 +141,6 @@ class Client extends BaseClient {
|
|||||||
*/
|
*/
|
||||||
this.sweepers = new Sweepers(this, this.options.sweepers);
|
this.sweepers = new Sweepers(this, this.options.sweepers);
|
||||||
|
|
||||||
/**
|
|
||||||
* The presence of the Client
|
|
||||||
* @private
|
|
||||||
* @type {ClientPresence}
|
|
||||||
*/
|
|
||||||
this.presence = new ClientPresence(this, this.options.presence);
|
|
||||||
|
|
||||||
Object.defineProperty(this, 'token', { writable: true });
|
Object.defineProperty(this, 'token', { writable: true });
|
||||||
if (!this.token && 'DISCORD_TOKEN' in process.env) {
|
if (!this.token && 'DISCORD_TOKEN' in process.env) {
|
||||||
/**
|
/**
|
||||||
@@ -148,10 +150,31 @@ class Client extends BaseClient {
|
|||||||
* @type {?string}
|
* @type {?string}
|
||||||
*/
|
*/
|
||||||
this.token = process.env.DISCORD_TOKEN;
|
this.token = process.env.DISCORD_TOKEN;
|
||||||
|
} else if (this.options.ws.token) {
|
||||||
|
this.token = this.options.ws.token;
|
||||||
} else {
|
} else {
|
||||||
this.token = null;
|
this.token = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wsOptions = {
|
||||||
|
...this.options.ws,
|
||||||
|
intents: this.options.intents.bitfield,
|
||||||
|
rest: this.rest,
|
||||||
|
token: this.token,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The WebSocket manager of the client
|
||||||
|
* @type {WebSocketManager}
|
||||||
|
*/
|
||||||
|
this.ws = new WebSocketManager(wsOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The voice manager of the client
|
||||||
|
* @type {ClientVoiceManager}
|
||||||
|
*/
|
||||||
|
this.voice = new ClientVoiceManager(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User that the client is logged in as
|
* User that the client is logged in as
|
||||||
* @type {?ClientUser}
|
* @type {?ClientUser}
|
||||||
@@ -164,11 +187,33 @@ class Client extends BaseClient {
|
|||||||
*/
|
*/
|
||||||
this.application = null;
|
this.application = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The latencies of the WebSocketShard connections
|
||||||
|
* @type {Collection<number, number>}
|
||||||
|
*/
|
||||||
|
this.pings = new Collection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last time a ping was sent (a timestamp) for each WebSocketShard connection
|
||||||
|
* @type {Collection<number,number>}
|
||||||
|
*/
|
||||||
|
this.lastPingTimestamps = new Collection();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timestamp of the time the client was last {@link Status.Ready} at
|
* Timestamp of the time the client was last {@link Status.Ready} at
|
||||||
* @type {?number}
|
* @type {?number}
|
||||||
*/
|
*/
|
||||||
this.readyTimestamp = null;
|
this.readyTimestamp = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of queued events before this Client became ready
|
||||||
|
* @type {Object[]}
|
||||||
|
* @private
|
||||||
|
* @name Client#incomingPacketQueue
|
||||||
|
*/
|
||||||
|
Object.defineProperty(this, 'incomingPacketQueue', { value: [] });
|
||||||
|
|
||||||
|
this._attachEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,13 +260,10 @@ class Client extends BaseClient {
|
|||||||
this.token = token = token.replace(/^(Bot|Bearer)\s*/i, '');
|
this.token = token = token.replace(/^(Bot|Bearer)\s*/i, '');
|
||||||
this.rest.setToken(token);
|
this.rest.setToken(token);
|
||||||
this.emit(Events.Debug, `Provided token: ${this._censoredToken}`);
|
this.emit(Events.Debug, `Provided token: ${this._censoredToken}`);
|
||||||
|
|
||||||
if (this.options.presence) {
|
|
||||||
this.options.ws.presence = this.presence._parse(this.options.presence);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit(Events.Debug, 'Preparing to connect to the gateway...');
|
this.emit(Events.Debug, 'Preparing to connect to the gateway...');
|
||||||
|
|
||||||
|
this.ws.setToken(this.token);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.ws.connect();
|
await this.ws.connect();
|
||||||
return this.token;
|
return this.token;
|
||||||
@@ -231,13 +273,150 @@ class Client extends BaseClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the client can be marked as ready
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _checkReady() {
|
||||||
|
// Step 0. Clear the ready timeout, if it exists
|
||||||
|
if (this.readyTimeout) {
|
||||||
|
clearTimeout(this.readyTimeout);
|
||||||
|
this.readyTimeout = null;
|
||||||
|
}
|
||||||
|
// Step 1. If we don't have any other guilds pending, we are ready
|
||||||
|
if (
|
||||||
|
!this.expectedGuilds.size &&
|
||||||
|
(await this.ws.fetchStatus()).every(status => status === WebSocketShardStatus.Ready)
|
||||||
|
) {
|
||||||
|
this.emit(Events.Debug, 'Client received all its guilds. Marking as fully ready.');
|
||||||
|
this.status = Status.Ready;
|
||||||
|
|
||||||
|
this._triggerClientReady();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hasGuildsIntent = this.options.intents.has(GatewayIntentBits.Guilds);
|
||||||
|
// Step 2. Create a timeout that will mark the client as ready if there are still unavailable guilds
|
||||||
|
// * The timeout is 15 seconds by default
|
||||||
|
// * This can be optionally changed in the client options via the `waitGuildTimeout` option
|
||||||
|
// * a timeout time of zero will skip this timeout, which potentially could cause the Client to miss guilds.
|
||||||
|
|
||||||
|
this.readyTimeout = setTimeout(
|
||||||
|
() => {
|
||||||
|
this.emit(
|
||||||
|
Events.Debug,
|
||||||
|
`${
|
||||||
|
hasGuildsIntent
|
||||||
|
? `Client did not receive any guild packets in ${this.options.waitGuildTimeout} ms.`
|
||||||
|
: 'Client will not receive anymore guild packets.'
|
||||||
|
}\nUnavailable guild count: ${this.expectedGuilds.size}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.readyTimeout = null;
|
||||||
|
this.status = Status.Ready;
|
||||||
|
|
||||||
|
this._triggerClientReady();
|
||||||
|
},
|
||||||
|
hasGuildsIntent ? this.options.waitGuildTimeout : 0,
|
||||||
|
).unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches event handlers to the WebSocketShardManager from `@discordjs/ws`.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_attachEvents() {
|
||||||
|
this.ws.on(WebSocketShardEvents.Debug, (message, shardId) =>
|
||||||
|
this.emit(Events.Debug, `[WS => ${typeof shardId === 'number' ? `Shard ${shardId}` : 'Manager'}] ${message}`),
|
||||||
|
);
|
||||||
|
this.ws.on(WebSocketShardEvents.Dispatch, this._handlePacket.bind(this));
|
||||||
|
|
||||||
|
this.ws.on(WebSocketShardEvents.Ready, data => {
|
||||||
|
for (const guild of data.guilds) {
|
||||||
|
this.expectedGuilds.add(guild.id);
|
||||||
|
}
|
||||||
|
this.status = Status.WaitingForGuilds;
|
||||||
|
this._checkReady();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on(WebSocketShardEvents.HeartbeatComplete, ({ heartbeatAt, latency }, shardId) => {
|
||||||
|
this.emit(Events.Debug, `[WS => Shard ${shardId}] Heartbeat acknowledged, latency of ${latency}ms.`);
|
||||||
|
this.lastPingTimestamps.set(shardId, heartbeatAt);
|
||||||
|
this.pings.set(shardId, latency);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a packet and queues it if this WebSocketManager is not ready.
|
||||||
|
* @param {GatewayDispatchPayload} packet The packet to be handled
|
||||||
|
* @param {number} shardId The shardId that received this packet
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_handlePacket(packet, shardId) {
|
||||||
|
if (this.status !== Status.Ready && !BeforeReadyWhitelist.includes(packet.t)) {
|
||||||
|
this.incomingPacketQueue.push({ packet, shardId });
|
||||||
|
} else {
|
||||||
|
if (this.incomingPacketQueue.length) {
|
||||||
|
const item = this.incomingPacketQueue.shift();
|
||||||
|
setImmediate(() => {
|
||||||
|
this._handlePacket(item.packet, item.shardId);
|
||||||
|
}).unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PacketHandlers[packet.t]) {
|
||||||
|
PacketHandlers[packet.t](this, packet, shardId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(packet.t)) {
|
||||||
|
this.expectedGuilds.delete(packet.d.id);
|
||||||
|
this._checkReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcasts a packet to every shard of this client handles.
|
||||||
|
* @param {Object} packet The packet to send
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _broadcast(packet) {
|
||||||
|
const shardIds = await this.ws.getShardIds();
|
||||||
|
return Promise.all(shardIds.map(shardId => this.ws.send(shardId, packet)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Causes the client to be marked as ready and emits the ready event.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_triggerClientReady() {
|
||||||
|
this.status = Status.Ready;
|
||||||
|
|
||||||
|
this.readyTimestamp = Date.now();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when the client becomes ready to start working.
|
||||||
|
* @event Client#clientReady
|
||||||
|
* @param {Client} client The client
|
||||||
|
*/
|
||||||
|
this.emit(Events.ClientReady, this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the client has logged in, indicative of being able to access
|
* Returns whether the client has logged in, indicative of being able to access
|
||||||
* properties such as `user` and `application`.
|
* properties such as `user` and `application`.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isReady() {
|
isReady() {
|
||||||
return !this.ws.destroyed && this.ws.status === Status.Ready;
|
return this.status === Status.Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The average ping of all WebSocketShards
|
||||||
|
* @type {number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get ping() {
|
||||||
|
const sum = this.pings.reduce((a, b) => a + b, 0);
|
||||||
|
return sum / this.pings.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -505,20 +684,10 @@ class Client extends BaseClient {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_validateOptions(options = this.options) {
|
_validateOptions(options = this.options) {
|
||||||
if (options.intents === undefined) {
|
if (options.intents === undefined && options.ws?.intents === undefined) {
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientMissingIntents);
|
throw new DiscordjsTypeError(ErrorCodes.ClientMissingIntents);
|
||||||
} else {
|
} else {
|
||||||
options.intents = new IntentsBitField(options.intents).freeze();
|
options.intents = new IntentsBitField(options.intents ?? options.ws.intents).freeze();
|
||||||
}
|
|
||||||
if (typeof options.shardCount !== 'number' || isNaN(options.shardCount) || options.shardCount < 1) {
|
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shardCount', 'a number greater than or equal to 1');
|
|
||||||
}
|
|
||||||
if (options.shards && !(options.shards === 'auto' || Array.isArray(options.shards))) {
|
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shards', "'auto', a number or array of numbers");
|
|
||||||
}
|
|
||||||
if (options.shards && !options.shards.length) throw new DiscordjsRangeError(ErrorCodes.ClientInvalidProvidedShards);
|
|
||||||
if (typeof options.makeCache !== 'function') {
|
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'makeCache', 'a function');
|
|
||||||
}
|
}
|
||||||
if (typeof options.sweepers !== 'object' || options.sweepers === null) {
|
if (typeof options.sweepers !== 'object' || options.sweepers === null) {
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'sweepers', 'an object');
|
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'sweepers', 'an object');
|
||||||
@@ -541,12 +710,17 @@ class Client extends BaseClient {
|
|||||||
) {
|
) {
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'allowedMentions', 'an object');
|
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'allowedMentions', 'an object');
|
||||||
}
|
}
|
||||||
if (typeof options.presence !== 'object' || options.presence === null) {
|
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'presence', 'an object');
|
|
||||||
}
|
|
||||||
if (typeof options.ws !== 'object' || options.ws === null) {
|
if (typeof options.ws !== 'object' || options.ws === null) {
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'ws', 'an object');
|
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'ws', 'an object');
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
(typeof options.presence !== 'object' || options.presence === null) &&
|
||||||
|
options.ws.initialPresence === undefined
|
||||||
|
) {
|
||||||
|
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'presence', 'an object');
|
||||||
|
} else {
|
||||||
|
options.ws.initialPresence = options.ws.initialPresence ?? this.presence._parse(this.options.presence);
|
||||||
|
}
|
||||||
if (typeof options.rest !== 'object' || options.rest === null) {
|
if (typeof options.rest !== 'object' || options.rest === null) {
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'rest', 'an object');
|
throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'rest', 'an object');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
const Action = require('./Action');
|
const Action = require('./Action');
|
||||||
const Events = require('../../util/Events');
|
const Events = require('../../util/Events');
|
||||||
const Status = require('../../util/Status');
|
|
||||||
|
|
||||||
class GuildMemberRemoveAction extends Action {
|
class GuildMemberRemoveAction extends Action {
|
||||||
handle(data, shard) {
|
handle(data) {
|
||||||
const client = this.client;
|
const client = this.client;
|
||||||
const guild = client.guilds.cache.get(data.guild_id);
|
const guild = client.guilds.cache.get(data.guild_id);
|
||||||
let member = null;
|
let member = null;
|
||||||
@@ -19,7 +18,7 @@ class GuildMemberRemoveAction extends Action {
|
|||||||
* @event Client#guildMemberRemove
|
* @event Client#guildMemberRemove
|
||||||
* @param {GuildMember} member The member that has left/been kicked from the guild
|
* @param {GuildMember} member The member that has left/been kicked from the guild
|
||||||
*/
|
*/
|
||||||
if (shard.status === Status.Ready) client.emit(Events.GuildMemberRemove, member);
|
client.emit(Events.GuildMemberRemove, member);
|
||||||
}
|
}
|
||||||
guild.presences.cache.delete(data.user.id);
|
guild.presences.cache.delete(data.user.id);
|
||||||
guild.voiceStates.cache.delete(data.user.id);
|
guild.voiceStates.cache.delete(data.user.id);
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
const Action = require('./Action');
|
const Action = require('./Action');
|
||||||
const Events = require('../../util/Events');
|
const Events = require('../../util/Events');
|
||||||
const Status = require('../../util/Status');
|
|
||||||
|
|
||||||
class GuildMemberUpdateAction extends Action {
|
class GuildMemberUpdateAction extends Action {
|
||||||
handle(data, shard) {
|
handle(data) {
|
||||||
const { client } = this;
|
const { client } = this;
|
||||||
if (data.user.username) {
|
if (data.user.username) {
|
||||||
const user = client.users.cache.get(data.user.id);
|
const user = client.users.cache.get(data.user.id);
|
||||||
@@ -27,7 +26,7 @@ class GuildMemberUpdateAction extends Action {
|
|||||||
* @param {GuildMember} oldMember The member before the update
|
* @param {GuildMember} oldMember The member before the update
|
||||||
* @param {GuildMember} newMember The member after the update
|
* @param {GuildMember} newMember The member after the update
|
||||||
*/
|
*/
|
||||||
if (shard.status === Status.Ready && !member.equals(old)) client.emit(Events.GuildMemberUpdate, old, member);
|
if (!member.equals(old)) client.emit(Events.GuildMemberUpdate, old, member);
|
||||||
} else {
|
} else {
|
||||||
const newMember = guild.members._add(data);
|
const newMember = guild.members._add(data);
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Events = require('../../util/Events');
|
const { WebSocketShardEvents, CloseCodes } = require('@discordjs/ws');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages voice connections for the client
|
* Manages voice connections for the client
|
||||||
@@ -21,10 +21,12 @@ class ClientVoiceManager {
|
|||||||
*/
|
*/
|
||||||
this.adapters = new Map();
|
this.adapters = new Map();
|
||||||
|
|
||||||
client.on(Events.ShardDisconnect, (_, shardId) => {
|
client.ws.on(WebSocketShardEvents.Closed, (code, shardId) => {
|
||||||
for (const [guildId, adapter] of this.adapters.entries()) {
|
if (code === CloseCodes.Normal) {
|
||||||
if (client.guilds.cache.get(guildId)?.shardId === shardId) {
|
for (const [guildId, adapter] of this.adapters.entries()) {
|
||||||
adapter.destroy();
|
if (client.guilds.cache.get(guildId)?.shardId === shardId) {
|
||||||
|
adapter.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,387 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const EventEmitter = require('node:events');
|
|
||||||
const process = require('node:process');
|
|
||||||
const { setImmediate } = require('node:timers');
|
|
||||||
const { Collection } = require('@discordjs/collection');
|
|
||||||
const {
|
|
||||||
WebSocketManager: WSWebSocketManager,
|
|
||||||
WebSocketShardEvents: WSWebSocketShardEvents,
|
|
||||||
CompressionMethod,
|
|
||||||
CloseCodes,
|
|
||||||
} = require('@discordjs/ws');
|
|
||||||
const { GatewayCloseCodes, GatewayDispatchEvents } = require('discord-api-types/v10');
|
|
||||||
const WebSocketShard = require('./WebSocketShard');
|
|
||||||
const PacketHandlers = require('./handlers');
|
|
||||||
const { DiscordjsError, ErrorCodes } = require('../../errors');
|
|
||||||
const Events = require('../../util/Events');
|
|
||||||
const Status = require('../../util/Status');
|
|
||||||
const WebSocketShardEvents = require('../../util/WebSocketShardEvents');
|
|
||||||
|
|
||||||
let zlib;
|
|
||||||
|
|
||||||
try {
|
|
||||||
zlib = require('zlib-sync');
|
|
||||||
} catch {} // eslint-disable-line no-empty
|
|
||||||
|
|
||||||
const BeforeReadyWhitelist = [
|
|
||||||
GatewayDispatchEvents.Ready,
|
|
||||||
GatewayDispatchEvents.Resumed,
|
|
||||||
GatewayDispatchEvents.GuildCreate,
|
|
||||||
GatewayDispatchEvents.GuildDelete,
|
|
||||||
GatewayDispatchEvents.GuildMembersChunk,
|
|
||||||
GatewayDispatchEvents.GuildMemberAdd,
|
|
||||||
GatewayDispatchEvents.GuildMemberRemove,
|
|
||||||
];
|
|
||||||
|
|
||||||
const WaitingForGuildEvents = [GatewayDispatchEvents.GuildCreate, GatewayDispatchEvents.GuildDelete];
|
|
||||||
|
|
||||||
const UNRESUMABLE_CLOSE_CODES = [
|
|
||||||
CloseCodes.Normal,
|
|
||||||
GatewayCloseCodes.AlreadyAuthenticated,
|
|
||||||
GatewayCloseCodes.InvalidSeq,
|
|
||||||
];
|
|
||||||
|
|
||||||
const reasonIsDeprecated = 'the reason property is deprecated, use the code property to determine the reason';
|
|
||||||
let deprecationEmittedForInvalidSessionEvent = false;
|
|
||||||
let deprecationEmittedForDestroyedEvent = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The WebSocket manager for this client.
|
|
||||||
* <info>This class forwards raw dispatch events,
|
|
||||||
* read more about it here {@link https://discord.com/developers/docs/topics/gateway}</info>
|
|
||||||
* @extends {EventEmitter}
|
|
||||||
*/
|
|
||||||
class WebSocketManager extends EventEmitter {
|
|
||||||
constructor(client) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The client that instantiated this WebSocketManager
|
|
||||||
* @type {Client}
|
|
||||||
* @readonly
|
|
||||||
* @name WebSocketManager#client
|
|
||||||
*/
|
|
||||||
Object.defineProperty(this, 'client', { value: client });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The gateway this manager uses
|
|
||||||
* @type {?string}
|
|
||||||
*/
|
|
||||||
this.gateway = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A collection of all shards this manager handles
|
|
||||||
* @type {Collection<number, WebSocketShard>}
|
|
||||||
*/
|
|
||||||
this.shards = new Collection();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of queued events before this WebSocketManager became ready
|
|
||||||
* @type {Object[]}
|
|
||||||
* @private
|
|
||||||
* @name WebSocketManager#packetQueue
|
|
||||||
*/
|
|
||||||
Object.defineProperty(this, 'packetQueue', { value: [] });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current status of this WebSocketManager
|
|
||||||
* @type {Status}
|
|
||||||
*/
|
|
||||||
this.status = Status.Idle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If this manager was destroyed. It will prevent shards from reconnecting
|
|
||||||
* @type {boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.destroyed = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The internal WebSocketManager from `@discordjs/ws`.
|
|
||||||
* @type {WSWebSocketManager}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._ws = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The average ping of all WebSocketShards
|
|
||||||
* @type {number}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get ping() {
|
|
||||||
const sum = this.shards.reduce((a, b) => a + b.ping, 0);
|
|
||||||
return sum / this.shards.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a debug message.
|
|
||||||
* @param {string[]} messages The debug message
|
|
||||||
* @param {?number} [shardId] The id of the shard that emitted this message, if any
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
debug(messages, shardId) {
|
|
||||||
this.client.emit(
|
|
||||||
Events.Debug,
|
|
||||||
`[WS => ${typeof shardId === 'number' ? `Shard ${shardId}` : 'Manager'}] ${messages.join('\n\t')}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connects this manager to the gateway.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
async connect() {
|
|
||||||
const invalidToken = new DiscordjsError(ErrorCodes.TokenInvalid);
|
|
||||||
const { shards, shardCount, intents, ws } = this.client.options;
|
|
||||||
if (this._ws && this._ws.options.token !== this.client.token) {
|
|
||||||
await this._ws.destroy({ code: CloseCodes.Normal, reason: 'Login with differing token requested' });
|
|
||||||
this._ws = null;
|
|
||||||
}
|
|
||||||
if (!this._ws) {
|
|
||||||
const wsOptions = {
|
|
||||||
intents: intents.bitfield,
|
|
||||||
rest: this.client.rest,
|
|
||||||
token: this.client.token,
|
|
||||||
largeThreshold: ws.large_threshold,
|
|
||||||
version: ws.version,
|
|
||||||
shardIds: shards === 'auto' ? null : shards,
|
|
||||||
shardCount: shards === 'auto' ? null : shardCount,
|
|
||||||
initialPresence: ws.presence,
|
|
||||||
retrieveSessionInfo: shardId => this.shards.get(shardId).sessionInfo,
|
|
||||||
updateSessionInfo: (shardId, sessionInfo) => {
|
|
||||||
this.shards.get(shardId).sessionInfo = sessionInfo;
|
|
||||||
},
|
|
||||||
compression: zlib ? CompressionMethod.ZlibStream : null,
|
|
||||||
};
|
|
||||||
if (ws.buildIdentifyThrottler) wsOptions.buildIdentifyThrottler = ws.buildIdentifyThrottler;
|
|
||||||
if (ws.buildStrategy) wsOptions.buildStrategy = ws.buildStrategy;
|
|
||||||
this._ws = new WSWebSocketManager(wsOptions);
|
|
||||||
this.attachEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
url: gatewayURL,
|
|
||||||
shards: recommendedShards,
|
|
||||||
session_start_limit: sessionStartLimit,
|
|
||||||
} = await this._ws.fetchGatewayInformation().catch(error => {
|
|
||||||
throw error.status === 401 ? invalidToken : error;
|
|
||||||
});
|
|
||||||
|
|
||||||
const { total, remaining } = sessionStartLimit;
|
|
||||||
this.debug(['Fetched Gateway Information', `URL: ${gatewayURL}`, `Recommended Shards: ${recommendedShards}`]);
|
|
||||||
this.debug(['Session Limit Information', `Total: ${total}`, `Remaining: ${remaining}`]);
|
|
||||||
this.gateway = `${gatewayURL}/`;
|
|
||||||
|
|
||||||
this.client.options.shardCount = await this._ws.getShardCount();
|
|
||||||
this.client.options.shards = await this._ws.getShardIds();
|
|
||||||
this.totalShards = this.client.options.shards.length;
|
|
||||||
for (const id of this.client.options.shards) {
|
|
||||||
if (!this.shards.has(id)) {
|
|
||||||
const shard = new WebSocketShard(this, id);
|
|
||||||
this.shards.set(id, shard);
|
|
||||||
|
|
||||||
shard.on(WebSocketShardEvents.AllReady, unavailableGuilds => {
|
|
||||||
/**
|
|
||||||
* Emitted when a shard turns ready.
|
|
||||||
* @event Client#shardReady
|
|
||||||
* @param {number} id The shard id that turned ready
|
|
||||||
* @param {?Set<Snowflake>} unavailableGuilds Set of unavailable guild ids, if any
|
|
||||||
*/
|
|
||||||
this.client.emit(Events.ShardReady, shard.id, unavailableGuilds);
|
|
||||||
|
|
||||||
this.checkShardsReady();
|
|
||||||
});
|
|
||||||
shard.status = Status.Connecting;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._ws.connect();
|
|
||||||
|
|
||||||
this.shards.forEach(shard => {
|
|
||||||
if (shard.listenerCount(WebSocketShardEvents.InvalidSession) > 0 && !deprecationEmittedForInvalidSessionEvent) {
|
|
||||||
process.emitWarning(
|
|
||||||
'The WebSocketShard#invalidSession event is deprecated and will never emit.',
|
|
||||||
'DeprecationWarning',
|
|
||||||
);
|
|
||||||
|
|
||||||
deprecationEmittedForInvalidSessionEvent = true;
|
|
||||||
}
|
|
||||||
if (shard.listenerCount(WebSocketShardEvents.Destroyed) > 0 && !deprecationEmittedForDestroyedEvent) {
|
|
||||||
process.emitWarning(
|
|
||||||
'The WebSocketShard#destroyed event is deprecated and will never emit.',
|
|
||||||
'DeprecationWarning',
|
|
||||||
);
|
|
||||||
|
|
||||||
deprecationEmittedForDestroyedEvent = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attaches event handlers to the internal WebSocketShardManager from `@discordjs/ws`.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
attachEvents() {
|
|
||||||
this._ws.on(WSWebSocketShardEvents.Debug, ({ message, shardId }) => this.debug([message], shardId));
|
|
||||||
this._ws.on(WSWebSocketShardEvents.Dispatch, ({ data, shardId }) => {
|
|
||||||
this.client.emit(Events.Raw, data, shardId);
|
|
||||||
this.emit(data.t, data.d, shardId);
|
|
||||||
const shard = this.shards.get(shardId);
|
|
||||||
this.handlePacket(data, shard);
|
|
||||||
if (shard.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(data.t)) {
|
|
||||||
shard.gotGuild(data.d.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this._ws.on(WSWebSocketShardEvents.Ready, ({ data, shardId }) => {
|
|
||||||
this.shards.get(shardId).onReadyPacket(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._ws.on(WSWebSocketShardEvents.Closed, ({ code, shardId }) => {
|
|
||||||
const shard = this.shards.get(shardId);
|
|
||||||
shard.emit(WebSocketShardEvents.Close, { code, reason: reasonIsDeprecated, wasClean: true });
|
|
||||||
if (UNRESUMABLE_CLOSE_CODES.includes(code) && this.destroyed) {
|
|
||||||
shard.status = Status.Disconnected;
|
|
||||||
/**
|
|
||||||
* Emitted when a shard's WebSocket disconnects and will no longer reconnect.
|
|
||||||
* @event Client#shardDisconnect
|
|
||||||
* @param {CloseEvent} event The WebSocket close event
|
|
||||||
* @param {number} id The shard id that disconnected
|
|
||||||
*/
|
|
||||||
this.client.emit(Events.ShardDisconnect, { code, reason: reasonIsDeprecated, wasClean: true }, shardId);
|
|
||||||
this.debug([`Shard not resumable: ${code} (${GatewayCloseCodes[code] ?? CloseCodes[code]})`], shardId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.shards.get(shardId).status = Status.Connecting;
|
|
||||||
/**
|
|
||||||
* Emitted when a shard is attempting to reconnect or re-identify.
|
|
||||||
* @event Client#shardReconnecting
|
|
||||||
* @param {number} id The shard id that is attempting to reconnect
|
|
||||||
*/
|
|
||||||
this.client.emit(Events.ShardReconnecting, shardId);
|
|
||||||
});
|
|
||||||
this._ws.on(WSWebSocketShardEvents.Hello, ({ shardId }) => {
|
|
||||||
const shard = this.shards.get(shardId);
|
|
||||||
if (shard.sessionInfo) {
|
|
||||||
shard.closeSequence = shard.sessionInfo.sequence;
|
|
||||||
shard.status = Status.Resuming;
|
|
||||||
} else {
|
|
||||||
shard.status = Status.Identifying;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this._ws.on(WSWebSocketShardEvents.Resumed, ({ shardId }) => {
|
|
||||||
const shard = this.shards.get(shardId);
|
|
||||||
shard.status = Status.Ready;
|
|
||||||
/**
|
|
||||||
* Emitted when the shard resumes successfully
|
|
||||||
* @event WebSocketShard#resumed
|
|
||||||
*/
|
|
||||||
shard.emit(WebSocketShardEvents.Resumed);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._ws.on(WSWebSocketShardEvents.HeartbeatComplete, ({ heartbeatAt, latency, shardId }) => {
|
|
||||||
this.debug([`Heartbeat acknowledged, latency of ${latency}ms.`], shardId);
|
|
||||||
const shard = this.shards.get(shardId);
|
|
||||||
shard.lastPingTimestamp = heartbeatAt;
|
|
||||||
shard.ping = latency;
|
|
||||||
});
|
|
||||||
|
|
||||||
this._ws.on(WSWebSocketShardEvents.Error, ({ error, shardId }) => {
|
|
||||||
/**
|
|
||||||
* Emitted whenever a shard's WebSocket encounters a connection error.
|
|
||||||
* @event Client#shardError
|
|
||||||
* @param {Error} error The encountered error
|
|
||||||
* @param {number} shardId The shard that encountered this error
|
|
||||||
*/
|
|
||||||
this.client.emit(Events.ShardError, error, shardId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcasts a packet to every shard this manager handles.
|
|
||||||
* @param {Object} packet The packet to send
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
broadcast(packet) {
|
|
||||||
for (const shardId of this.shards.keys()) this._ws.send(shardId, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys this manager and all its shards.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
async destroy() {
|
|
||||||
if (this.destroyed) return;
|
|
||||||
// TODO: Make a util for getting a stack
|
|
||||||
this.debug([Object.assign(new Error(), { name: 'Manager was destroyed:' }).stack]);
|
|
||||||
this.destroyed = true;
|
|
||||||
await this._ws?.destroy({ code: CloseCodes.Normal, reason: 'Manager was destroyed' });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes a packet and queues it if this WebSocketManager is not ready.
|
|
||||||
* @param {Object} [packet] The packet to be handled
|
|
||||||
* @param {WebSocketShard} [shard] The shard that will handle this packet
|
|
||||||
* @returns {boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
handlePacket(packet, shard) {
|
|
||||||
if (packet && this.status !== Status.Ready) {
|
|
||||||
if (!BeforeReadyWhitelist.includes(packet.t)) {
|
|
||||||
this.packetQueue.push({ packet, shard });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.packetQueue.length) {
|
|
||||||
const item = this.packetQueue.shift();
|
|
||||||
setImmediate(() => {
|
|
||||||
this.handlePacket(item.packet, item.shard);
|
|
||||||
}).unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet && PacketHandlers[packet.t]) {
|
|
||||||
PacketHandlers[packet.t](this.client, packet, shard);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the client is ready to be marked as ready.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
checkShardsReady() {
|
|
||||||
if (this.status === Status.Ready) return;
|
|
||||||
if (this.shards.size !== this.totalShards || this.shards.some(shard => shard.status !== Status.Ready)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.triggerClientReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Causes the client to be marked as ready and emits the ready event.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
triggerClientReady() {
|
|
||||||
this.status = Status.Ready;
|
|
||||||
|
|
||||||
this.client.readyTimestamp = Date.now();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when the client becomes ready to start working.
|
|
||||||
* @event Client#ready
|
|
||||||
* @param {Client} client The client
|
|
||||||
*/
|
|
||||||
this.client.emit(Events.ClientReady, this.client);
|
|
||||||
|
|
||||||
this.handlePacket();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = WebSocketManager;
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const EventEmitter = require('node:events');
|
|
||||||
const process = require('node:process');
|
|
||||||
const { setTimeout, clearTimeout } = require('node:timers');
|
|
||||||
const { GatewayIntentBits } = require('discord-api-types/v10');
|
|
||||||
const Status = require('../../util/Status');
|
|
||||||
const WebSocketShardEvents = require('../../util/WebSocketShardEvents');
|
|
||||||
|
|
||||||
let deprecationEmittedForImportant = false;
|
|
||||||
/**
|
|
||||||
* Represents a Shard's WebSocket connection
|
|
||||||
* @extends {EventEmitter}
|
|
||||||
*/
|
|
||||||
class WebSocketShard extends EventEmitter {
|
|
||||||
constructor(manager, id) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The WebSocketManager of the shard
|
|
||||||
* @type {WebSocketManager}
|
|
||||||
*/
|
|
||||||
this.manager = manager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The shard's id
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current status of the shard
|
|
||||||
* @type {Status}
|
|
||||||
*/
|
|
||||||
this.status = Status.Idle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The sequence of the shard after close
|
|
||||||
* @type {number}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.closeSequence = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The previous heartbeat ping of the shard
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.ping = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last time a ping was sent (a timestamp)
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.lastPingTimestamp = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of guild ids this shard expects to receive
|
|
||||||
* @name WebSocketShard#expectedGuilds
|
|
||||||
* @type {?Set<string>}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Object.defineProperty(this, 'expectedGuilds', { value: null, writable: true });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ready timeout
|
|
||||||
* @name WebSocketShard#readyTimeout
|
|
||||||
* @type {?NodeJS.Timeout}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Object.defineProperty(this, 'readyTimeout', { value: null, writable: true });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @external SessionInfo
|
|
||||||
* @see {@link https://discord.js.org/docs/packages/ws/stable/SessionInfo:Interface}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The session info used by `@discordjs/ws` package.
|
|
||||||
* @name WebSocketShard#sessionInfo
|
|
||||||
* @type {?SessionInfo}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Object.defineProperty(this, 'sessionInfo', { value: null, writable: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a debug event.
|
|
||||||
* @param {string[]} messages The debug message
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
debug(messages) {
|
|
||||||
this.manager.debug(messages, this.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @external CloseEvent
|
|
||||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is responsible to emit close event for this shard.
|
|
||||||
* This method helps the shard reconnect.
|
|
||||||
* @param {CloseEvent} [event] Close event that was received
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
emitClose(
|
|
||||||
event = {
|
|
||||||
code: 1011,
|
|
||||||
reason: 'INTERNAL_ERROR',
|
|
||||||
wasClean: false,
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
this.debug([
|
|
||||||
'[CLOSE]',
|
|
||||||
`Event Code: ${event.code}`,
|
|
||||||
`Clean : ${event.wasClean}`,
|
|
||||||
`Reason : ${event.reason ?? 'No reason received'}`,
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when a shard's WebSocket closes.
|
|
||||||
* @private
|
|
||||||
* @event WebSocketShard#close
|
|
||||||
* @param {CloseEvent} event The received event
|
|
||||||
*/
|
|
||||||
this.emit(WebSocketShardEvents.Close, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the shard receives the READY payload.
|
|
||||||
* @param {Object} packet The received packet
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
onReadyPacket(packet) {
|
|
||||||
if (!packet) {
|
|
||||||
this.debug([`Received broken packet: '${packet}'.`]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when the shard receives the READY payload and is now waiting for guilds
|
|
||||||
* @event WebSocketShard#ready
|
|
||||||
*/
|
|
||||||
this.emit(WebSocketShardEvents.Ready);
|
|
||||||
|
|
||||||
this.expectedGuilds = new Set(packet.guilds.map(guild => guild.id));
|
|
||||||
this.status = Status.WaitingForGuilds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a GuildCreate or GuildDelete for this shard was sent after READY payload was received,
|
|
||||||
* but before we emitted the READY event.
|
|
||||||
* @param {Snowflake} guildId the id of the Guild sent in the payload
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
gotGuild(guildId) {
|
|
||||||
this.expectedGuilds.delete(guildId);
|
|
||||||
this.checkReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the shard can be marked as ready
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
checkReady() {
|
|
||||||
// Step 0. Clear the ready timeout, if it exists
|
|
||||||
if (this.readyTimeout) {
|
|
||||||
clearTimeout(this.readyTimeout);
|
|
||||||
this.readyTimeout = null;
|
|
||||||
}
|
|
||||||
// Step 1. If we don't have any other guilds pending, we are ready
|
|
||||||
if (!this.expectedGuilds.size) {
|
|
||||||
this.debug(['Shard received all its guilds. Marking as fully ready.']);
|
|
||||||
this.status = Status.Ready;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when the shard is fully ready.
|
|
||||||
* This event is emitted if:
|
|
||||||
* * all guilds were received by this shard
|
|
||||||
* * the ready timeout expired, and some guilds are unavailable
|
|
||||||
* @event WebSocketShard#allReady
|
|
||||||
* @param {?Set<string>} unavailableGuilds Set of unavailable guilds, if any
|
|
||||||
*/
|
|
||||||
this.emit(WebSocketShardEvents.AllReady);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const hasGuildsIntent = this.manager.client.options.intents.has(GatewayIntentBits.Guilds);
|
|
||||||
// Step 2. Create a timeout that will mark the shard as ready if there are still unavailable guilds
|
|
||||||
// * The timeout is 15 seconds by default
|
|
||||||
// * This can be optionally changed in the client options via the `waitGuildTimeout` option
|
|
||||||
// * a timeout time of zero will skip this timeout, which potentially could cause the Client to miss guilds.
|
|
||||||
|
|
||||||
const { waitGuildTimeout } = this.manager.client.options;
|
|
||||||
|
|
||||||
this.readyTimeout = setTimeout(
|
|
||||||
() => {
|
|
||||||
this.debug([
|
|
||||||
hasGuildsIntent
|
|
||||||
? `Shard did not receive any guild packets in ${waitGuildTimeout} ms.`
|
|
||||||
: 'Shard will not receive anymore guild packets.',
|
|
||||||
`Unavailable guild count: ${this.expectedGuilds.size}`,
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.readyTimeout = null;
|
|
||||||
this.status = Status.Ready;
|
|
||||||
|
|
||||||
this.emit(WebSocketShardEvents.AllReady, this.expectedGuilds);
|
|
||||||
},
|
|
||||||
hasGuildsIntent ? waitGuildTimeout : 0,
|
|
||||||
).unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a packet to the queue to be sent to the gateway.
|
|
||||||
* <warn>If you use this method, make sure you understand that you need to provide
|
|
||||||
* a full [Payload](https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-commands).
|
|
||||||
* Do not use this method if you don't know what you're doing.</warn>
|
|
||||||
* @param {Object} data The full packet to send
|
|
||||||
* @param {boolean} [important=false] If this packet should be added first in queue
|
|
||||||
* <warn>This parameter is **deprecated**. Important payloads are determined by their opcode instead.</warn>
|
|
||||||
*/
|
|
||||||
send(data, important = false) {
|
|
||||||
if (important && !deprecationEmittedForImportant) {
|
|
||||||
process.emitWarning(
|
|
||||||
'Sending important payloads explicitly is deprecated. They are determined by their opcode implicitly now.',
|
|
||||||
'DeprecationWarning',
|
|
||||||
);
|
|
||||||
deprecationEmittedForImportant = true;
|
|
||||||
}
|
|
||||||
this.manager._ws.send(this.id, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = WebSocketShard;
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
const Events = require('../../../util/Events');
|
const Events = require('../../../util/Events');
|
||||||
const Status = require('../../../util/Status');
|
const Status = require('../../../util/Status');
|
||||||
|
|
||||||
module.exports = (client, { d: data }, shard) => {
|
module.exports = (client, { d: data }, shardId) => {
|
||||||
let guild = client.guilds.cache.get(data.id);
|
let guild = client.guilds.cache.get(data.id);
|
||||||
if (guild) {
|
if (guild) {
|
||||||
if (!guild.available && !data.unavailable) {
|
if (!guild.available && !data.unavailable) {
|
||||||
@@ -19,9 +19,9 @@ module.exports = (client, { d: data }, shard) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// A new guild
|
// A new guild
|
||||||
data.shardId = shard.id;
|
data.shardId = shardId;
|
||||||
guild = client.guilds._add(data);
|
guild = client.guilds._add(data);
|
||||||
if (client.ws.status === Status.Ready) {
|
if (client.status === Status.Ready) {
|
||||||
/**
|
/**
|
||||||
* Emitted whenever the client joins a guild.
|
* Emitted whenever the client joins a guild.
|
||||||
* @event Client#guildCreate
|
* @event Client#guildCreate
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Events = require('../../../util/Events');
|
const Events = require('../../../util/Events');
|
||||||
const Status = require('../../../util/Status');
|
|
||||||
|
|
||||||
module.exports = (client, { d: data }, shard) => {
|
module.exports = (client, { d: data }) => {
|
||||||
const guild = client.guilds.cache.get(data.guild_id);
|
const guild = client.guilds.cache.get(data.guild_id);
|
||||||
if (guild) {
|
if (guild) {
|
||||||
guild.memberCount++;
|
guild.memberCount++;
|
||||||
const member = guild.members._add(data);
|
const member = guild.members._add(data);
|
||||||
if (shard.status === Status.Ready) {
|
/**
|
||||||
/**
|
* Emitted whenever a user joins a guild.
|
||||||
* Emitted whenever a user joins a guild.
|
* @event Client#guildMemberAdd
|
||||||
* @event Client#guildMemberAdd
|
* @param {GuildMember} member The member that has joined a guild
|
||||||
* @param {GuildMember} member The member that has joined a guild
|
*/
|
||||||
*/
|
client.emit(Events.GuildMemberAdd, member);
|
||||||
client.emit(Events.GuildMemberAdd, member);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = (client, packet, shard) => {
|
module.exports = (client, packet) => {
|
||||||
client.actions.GuildMemberRemove.handle(packet.d, shard);
|
client.actions.GuildMemberRemove.handle(packet.d);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = (client, packet, shard) => {
|
module.exports = (client, packet) => {
|
||||||
client.actions.GuildMemberUpdate.handle(packet.d, shard);
|
client.actions.GuildMemberUpdate.handle(packet.d);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
const ClientApplication = require('../../../structures/ClientApplication');
|
const ClientApplication = require('../../../structures/ClientApplication');
|
||||||
let ClientUser;
|
let ClientUser;
|
||||||
|
|
||||||
module.exports = (client, { d: data }, shard) => {
|
module.exports = (client, { d: data }, shardId) => {
|
||||||
if (client.user) {
|
if (client.user) {
|
||||||
client.user._patch(data.user);
|
client.user._patch(data.user);
|
||||||
} else {
|
} else {
|
||||||
@@ -13,7 +13,7 @@ module.exports = (client, { d: data }, shard) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const guild of data.guilds) {
|
for (const guild of data.guilds) {
|
||||||
guild.shardId = shard.id;
|
guild.shardId = shardId;
|
||||||
client.guilds._add(guild);
|
client.guilds._add(guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,6 +22,4 @@ module.exports = (client, { d: data }, shard) => {
|
|||||||
} else {
|
} else {
|
||||||
client.application = new ClientApplication(client, data.application);
|
client.application = new ClientApplication(client, data.application);
|
||||||
}
|
}
|
||||||
|
|
||||||
shard.checkReady();
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const Events = require('../../../util/Events');
|
|
||||||
|
|
||||||
module.exports = (client, packet, shard) => {
|
|
||||||
const replayed = shard.sessionInfo.sequence - shard.closeSequence;
|
|
||||||
/**
|
|
||||||
* Emitted when a shard resumes successfully.
|
|
||||||
* @event Client#shardResume
|
|
||||||
* @param {number} id The shard id that resumed
|
|
||||||
* @param {number} replayedEvents The amount of replayed events
|
|
||||||
*/
|
|
||||||
client.emit(Events.ShardResume, shard.id, replayed);
|
|
||||||
};
|
|
||||||
@@ -49,7 +49,6 @@ const handlers = Object.fromEntries([
|
|||||||
['MESSAGE_UPDATE', require('./MESSAGE_UPDATE')],
|
['MESSAGE_UPDATE', require('./MESSAGE_UPDATE')],
|
||||||
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')],
|
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')],
|
||||||
['READY', require('./READY')],
|
['READY', require('./READY')],
|
||||||
['RESUMED', require('./RESUMED')],
|
|
||||||
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
|
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
|
||||||
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
|
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
|
||||||
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],
|
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],
|
||||||
|
|||||||
@@ -12,8 +12,25 @@
|
|||||||
* @property {'TokenMissing'} TokenMissing
|
* @property {'TokenMissing'} TokenMissing
|
||||||
* @property {'ApplicationCommandPermissionsTokenMissing'} ApplicationCommandPermissionsTokenMissing
|
* @property {'ApplicationCommandPermissionsTokenMissing'} ApplicationCommandPermissionsTokenMissing
|
||||||
|
|
||||||
* @property {'BitFieldInvalid'} BitFieldInvalid
|
* @property {'WSCloseRequested'} WSCloseRequested
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'WSConnectionExists'} WSConnectionExists
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'WSNotOpen'} WSNotOpen
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'ManagerDestroyed'} ManagerDestroyed
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
|
||||||
|
* @property {'BitFieldInvalid'} BitFieldInvalid
|
||||||
|
|
||||||
|
* @property {'ShardingInvalid'} ShardingInvalid
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'ShardingRequired'} ShardingRequired
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'InvalidIntents'} InvalidIntents
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'DisallowedIntents'} DisallowedIntents
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
* @property {'ShardingNoShards'} ShardingNoShards
|
* @property {'ShardingNoShards'} ShardingNoShards
|
||||||
* @property {'ShardingInProcess'} ShardingInProcess
|
* @property {'ShardingInProcess'} ShardingInProcess
|
||||||
* @property {'ShardingInvalidEvalBroadcast'} ShardingInvalidEvalBroadcast
|
* @property {'ShardingInvalidEvalBroadcast'} ShardingInvalidEvalBroadcast
|
||||||
@@ -32,10 +49,30 @@
|
|||||||
|
|
||||||
* @property {'InviteOptionsMissingChannel'} InviteOptionsMissingChannel
|
* @property {'InviteOptionsMissingChannel'} InviteOptionsMissingChannel
|
||||||
|
|
||||||
|
* @property {'ButtonLabel'} ButtonLabel
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'ButtonURL'} ButtonURL
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'ButtonCustomId'} ButtonCustomId
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
|
||||||
|
* @property {'SelectMenuCustomId'} SelectMenuCustomId
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'SelectMenuPlaceholder'} SelectMenuPlaceholder
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'SelectOptionLabel'} SelectOptionLabel
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'SelectOptionValue'} SelectOptionValue
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'SelectOptionDescription'} SelectOptionDescription
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
|
||||||
* @property {'InteractionCollectorError'} InteractionCollectorError
|
* @property {'InteractionCollectorError'} InteractionCollectorError
|
||||||
|
|
||||||
* @property {'FileNotFound'} FileNotFound
|
* @property {'FileNotFound'} FileNotFound
|
||||||
|
|
||||||
|
* @property {'UserBannerNotFetched'} UserBannerNotFetched
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
* @property {'UserNoDMChannel'} UserNoDMChannel
|
* @property {'UserNoDMChannel'} UserNoDMChannel
|
||||||
|
|
||||||
* @property {'VoiceNotStageChannel'} VoiceNotStageChannel
|
* @property {'VoiceNotStageChannel'} VoiceNotStageChannel
|
||||||
@@ -45,11 +82,19 @@
|
|||||||
|
|
||||||
* @property {'ReqResourceType'} ReqResourceType
|
* @property {'ReqResourceType'} ReqResourceType
|
||||||
|
|
||||||
|
* @property {'ImageFormat'} ImageFormat
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
* @property {'ImageSize'} ImageSize
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
|
||||||
* @property {'MessageBulkDeleteType'} MessageBulkDeleteType
|
* @property {'MessageBulkDeleteType'} MessageBulkDeleteType
|
||||||
* @property {'MessageContentType'} MessageContentType
|
* @property {'MessageContentType'} MessageContentType
|
||||||
* @property {'MessageNonceRequired'} MessageNonceRequired
|
* @property {'MessageNonceRequired'} MessageNonceRequired
|
||||||
* @property {'MessageNonceType'} MessageNonceType
|
* @property {'MessageNonceType'} MessageNonceType
|
||||||
|
|
||||||
|
* @property {'SplitMaxLen'} SplitMaxLen
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
|
||||||
* @property {'BanResolveId'} BanResolveId
|
* @property {'BanResolveId'} BanResolveId
|
||||||
* @property {'FetchBanResolveId'} FetchBanResolveId
|
* @property {'FetchBanResolveId'} FetchBanResolveId
|
||||||
|
|
||||||
@@ -83,11 +128,16 @@
|
|||||||
* @property {'EmojiType'} EmojiType
|
* @property {'EmojiType'} EmojiType
|
||||||
* @property {'EmojiManaged'} EmojiManaged
|
* @property {'EmojiManaged'} EmojiManaged
|
||||||
* @property {'MissingManageGuildExpressionsPermission'} MissingManageGuildExpressionsPermission
|
* @property {'MissingManageGuildExpressionsPermission'} MissingManageGuildExpressionsPermission
|
||||||
|
* @property {'MissingManageEmojisAndStickersPermission'} MissingManageEmojisAndStickersPermission
|
||||||
|
* <warn>This property is deprecated. Use `MissingManageGuildExpressionsPermission` instead.</warn>
|
||||||
*
|
*
|
||||||
* @property {'NotGuildSticker'} NotGuildSticker
|
* @property {'NotGuildSticker'} NotGuildSticker
|
||||||
|
|
||||||
* @property {'ReactionResolveUser'} ReactionResolveUser
|
* @property {'ReactionResolveUser'} ReactionResolveUser
|
||||||
|
|
||||||
|
* @property {'VanityURL'} VanityURL
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
|
||||||
* @property {'InviteResolveCode'} InviteResolveCode
|
* @property {'InviteResolveCode'} InviteResolveCode
|
||||||
|
|
||||||
* @property {'InviteNotFound'} InviteNotFound
|
* @property {'InviteNotFound'} InviteNotFound
|
||||||
@@ -102,6 +152,8 @@
|
|||||||
|
|
||||||
* @property {'InteractionAlreadyReplied'} InteractionAlreadyReplied
|
* @property {'InteractionAlreadyReplied'} InteractionAlreadyReplied
|
||||||
* @property {'InteractionNotReplied'} InteractionNotReplied
|
* @property {'InteractionNotReplied'} InteractionNotReplied
|
||||||
|
* @property {'InteractionEphemeralReplied'} InteractionEphemeralReplied
|
||||||
|
* <warn>This property is deprecated.</warn>
|
||||||
|
|
||||||
* @property {'CommandInteractionOptionNotFound'} CommandInteractionOptionNotFound
|
* @property {'CommandInteractionOptionNotFound'} CommandInteractionOptionNotFound
|
||||||
* @property {'CommandInteractionOptionType'} CommandInteractionOptionType
|
* @property {'CommandInteractionOptionType'} CommandInteractionOptionType
|
||||||
@@ -140,8 +192,17 @@ const keys = [
|
|||||||
'TokenMissing',
|
'TokenMissing',
|
||||||
'ApplicationCommandPermissionsTokenMissing',
|
'ApplicationCommandPermissionsTokenMissing',
|
||||||
|
|
||||||
|
'WSCloseRequested',
|
||||||
|
'WSConnectionExists',
|
||||||
|
'WSNotOpen',
|
||||||
|
'ManagerDestroyed',
|
||||||
|
|
||||||
'BitFieldInvalid',
|
'BitFieldInvalid',
|
||||||
|
|
||||||
|
'ShardingInvalid',
|
||||||
|
'ShardingRequired',
|
||||||
|
'InvalidIntents',
|
||||||
|
'DisallowedIntents',
|
||||||
'ShardingNoShards',
|
'ShardingNoShards',
|
||||||
'ShardingInProcess',
|
'ShardingInProcess',
|
||||||
'ShardingInvalidEvalBroadcast',
|
'ShardingInvalidEvalBroadcast',
|
||||||
@@ -160,10 +221,21 @@ const keys = [
|
|||||||
|
|
||||||
'InviteOptionsMissingChannel',
|
'InviteOptionsMissingChannel',
|
||||||
|
|
||||||
|
'ButtonLabel',
|
||||||
|
'ButtonURL',
|
||||||
|
'ButtonCustomId',
|
||||||
|
|
||||||
|
'SelectMenuCustomId',
|
||||||
|
'SelectMenuPlaceholder',
|
||||||
|
'SelectOptionLabel',
|
||||||
|
'SelectOptionValue',
|
||||||
|
'SelectOptionDescription',
|
||||||
|
|
||||||
'InteractionCollectorError',
|
'InteractionCollectorError',
|
||||||
|
|
||||||
'FileNotFound',
|
'FileNotFound',
|
||||||
|
|
||||||
|
'UserBannerNotFetched',
|
||||||
'UserNoDMChannel',
|
'UserNoDMChannel',
|
||||||
|
|
||||||
'VoiceNotStageChannel',
|
'VoiceNotStageChannel',
|
||||||
@@ -173,11 +245,16 @@ const keys = [
|
|||||||
|
|
||||||
'ReqResourceType',
|
'ReqResourceType',
|
||||||
|
|
||||||
|
'ImageFormat',
|
||||||
|
'ImageSize',
|
||||||
|
|
||||||
'MessageBulkDeleteType',
|
'MessageBulkDeleteType',
|
||||||
'MessageContentType',
|
'MessageContentType',
|
||||||
'MessageNonceRequired',
|
'MessageNonceRequired',
|
||||||
'MessageNonceType',
|
'MessageNonceType',
|
||||||
|
|
||||||
|
'SplitMaxLen',
|
||||||
|
|
||||||
'BanResolveId',
|
'BanResolveId',
|
||||||
'FetchBanResolveId',
|
'FetchBanResolveId',
|
||||||
|
|
||||||
@@ -211,11 +288,14 @@ const keys = [
|
|||||||
'EmojiType',
|
'EmojiType',
|
||||||
'EmojiManaged',
|
'EmojiManaged',
|
||||||
'MissingManageGuildExpressionsPermission',
|
'MissingManageGuildExpressionsPermission',
|
||||||
|
'MissingManageEmojisAndStickersPermission',
|
||||||
|
|
||||||
'NotGuildSticker',
|
'NotGuildSticker',
|
||||||
|
|
||||||
'ReactionResolveUser',
|
'ReactionResolveUser',
|
||||||
|
|
||||||
|
'VanityURL',
|
||||||
|
|
||||||
'InviteResolveCode',
|
'InviteResolveCode',
|
||||||
|
|
||||||
'InviteNotFound',
|
'InviteNotFound',
|
||||||
@@ -230,6 +310,7 @@ const keys = [
|
|||||||
|
|
||||||
'InteractionAlreadyReplied',
|
'InteractionAlreadyReplied',
|
||||||
'InteractionNotReplied',
|
'InteractionNotReplied',
|
||||||
|
'InteractionEphemeralReplied',
|
||||||
|
|
||||||
'CommandInteractionOptionNotFound',
|
'CommandInteractionOptionNotFound',
|
||||||
'CommandInteractionOptionType',
|
'CommandInteractionOptionType',
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ exports.SystemChannelFlagsBitField = require('./util/SystemChannelFlagsBitField'
|
|||||||
exports.ThreadMemberFlagsBitField = require('./util/ThreadMemberFlagsBitField');
|
exports.ThreadMemberFlagsBitField = require('./util/ThreadMemberFlagsBitField');
|
||||||
exports.UserFlagsBitField = require('./util/UserFlagsBitField');
|
exports.UserFlagsBitField = require('./util/UserFlagsBitField');
|
||||||
__exportStar(require('./util/Util.js'), exports);
|
__exportStar(require('./util/Util.js'), exports);
|
||||||
exports.WebSocketShardEvents = require('./util/WebSocketShardEvents');
|
|
||||||
exports.version = require('../package.json').version;
|
exports.version = require('../package.json').version;
|
||||||
|
|
||||||
// Managers
|
// Managers
|
||||||
@@ -88,8 +87,6 @@ exports.ThreadManager = require('./managers/ThreadManager');
|
|||||||
exports.ThreadMemberManager = require('./managers/ThreadMemberManager');
|
exports.ThreadMemberManager = require('./managers/ThreadMemberManager');
|
||||||
exports.UserManager = require('./managers/UserManager');
|
exports.UserManager = require('./managers/UserManager');
|
||||||
exports.VoiceStateManager = require('./managers/VoiceStateManager');
|
exports.VoiceStateManager = require('./managers/VoiceStateManager');
|
||||||
exports.WebSocketManager = require('./client/websocket/WebSocketManager');
|
|
||||||
exports.WebSocketShard = require('./client/websocket/WebSocketShard');
|
|
||||||
|
|
||||||
// Structures
|
// Structures
|
||||||
exports.ActionRow = require('./structures/ActionRow');
|
exports.ActionRow = require('./structures/ActionRow');
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ class GuildManager extends CachedManager {
|
|||||||
const data = await this.client.rest.get(Routes.guild(id), {
|
const data = await this.client.rest.get(Routes.guild(id), {
|
||||||
query: makeURLSearchParams({ with_counts: options.withCounts ?? true }),
|
query: makeURLSearchParams({ with_counts: options.withCounts ?? true }),
|
||||||
});
|
});
|
||||||
data.shardId = ShardClientUtil.shardIdForGuildId(id, this.client.options.shardCount);
|
data.shardId = ShardClientUtil.shardIdForGuildId(id, await this.client.ws.fetchShardCount());
|
||||||
return this._add(data, options.cache);
|
return this._add(data, options.cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!query && !users) query = '';
|
if (!query && !users) query = '';
|
||||||
this.guild.shard.send({
|
this.guild.client.ws.send(this.guild.shardId, {
|
||||||
op: GatewayOpcodes.RequestGuildMembers,
|
op: GatewayOpcodes.RequestGuildMembers,
|
||||||
d: {
|
d: {
|
||||||
guild_id: this.guild.id,
|
guild_id: this.guild.id,
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ class Shard extends EventEmitter {
|
|||||||
if (message._ready) {
|
if (message._ready) {
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
/**
|
/**
|
||||||
* Emitted upon the shard's {@link Client#event:shardReady} event.
|
* Emitted upon the shard's {@link Client#event:clientReady} event.
|
||||||
* @event Shard#ready
|
* @event Shard#ready
|
||||||
*/
|
*/
|
||||||
this.emit(ShardEvents.Ready);
|
this.emit(ShardEvents.Ready);
|
||||||
@@ -363,29 +363,18 @@ class Shard extends EventEmitter {
|
|||||||
if (message._disconnect) {
|
if (message._disconnect) {
|
||||||
this.ready = false;
|
this.ready = false;
|
||||||
/**
|
/**
|
||||||
* Emitted upon the shard's {@link Client#event:shardDisconnect} event.
|
* Emitted upon the shard's {@link WebSocketShardEvents#Closed} event.
|
||||||
* @event Shard#disconnect
|
* @event Shard#disconnect
|
||||||
*/
|
*/
|
||||||
this.emit(ShardEvents.Disconnect);
|
this.emit(ShardEvents.Disconnect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shard is attempting to reconnect
|
|
||||||
if (message._reconnecting) {
|
|
||||||
this.ready = false;
|
|
||||||
/**
|
|
||||||
* Emitted upon the shard's {@link Client#event:shardReconnecting} event.
|
|
||||||
* @event Shard#reconnecting
|
|
||||||
*/
|
|
||||||
this.emit(ShardEvents.Reconnecting);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shard has resumed
|
// Shard has resumed
|
||||||
if (message._resume) {
|
if (message._resume) {
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
/**
|
/**
|
||||||
* Emitted upon the shard's {@link Client#event:shardResume} event.
|
* Emitted upon the shard's {@link WebSocketShardEvents#Resumed} event.
|
||||||
* @event Shard#resume
|
* @event Shard#resume
|
||||||
*/
|
*/
|
||||||
this.emit(ShardEvents.Resume);
|
this.emit(ShardEvents.Resume);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const process = require('node:process');
|
const process = require('node:process');
|
||||||
const { calculateShardId } = require('@discordjs/util');
|
const { calculateShardId } = require('@discordjs/util');
|
||||||
|
const { WebSocketShardEvents } = require('@discordjs/ws');
|
||||||
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
|
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
|
||||||
const Events = require('../util/Events');
|
const Events = require('../util/Events');
|
||||||
const { makeError, makePlainError } = require('../util/Util');
|
const { makeError, makePlainError } = require('../util/Util');
|
||||||
@@ -33,56 +34,32 @@ class ShardClientUtil {
|
|||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 'process':
|
case 'process':
|
||||||
process.on('message', this._handleMessage.bind(this));
|
process.on('message', this._handleMessage.bind(this));
|
||||||
client.on(Events.ShardReady, () => {
|
client.on(Events.ClientReady, () => {
|
||||||
process.send({ _ready: true });
|
process.send({ _ready: true });
|
||||||
});
|
});
|
||||||
client.on(Events.ShardDisconnect, () => {
|
client.ws.on(WebSocketShardEvents.Closed, () => {
|
||||||
process.send({ _disconnect: true });
|
process.send({ _disconnect: true });
|
||||||
});
|
});
|
||||||
client.on(Events.ShardReconnecting, () => {
|
client.ws.on(WebSocketShardEvents.Resumed, () => {
|
||||||
process.send({ _reconnecting: true });
|
|
||||||
});
|
|
||||||
client.on(Events.ShardResume, () => {
|
|
||||||
process.send({ _resume: true });
|
process.send({ _resume: true });
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'worker':
|
case 'worker':
|
||||||
this.parentPort = require('node:worker_threads').parentPort;
|
this.parentPort = require('node:worker_threads').parentPort;
|
||||||
this.parentPort.on('message', this._handleMessage.bind(this));
|
this.parentPort.on('message', this._handleMessage.bind(this));
|
||||||
client.on(Events.ShardReady, () => {
|
client.on(Events.ClientReady, () => {
|
||||||
this.parentPort.postMessage({ _ready: true });
|
this.parentPort.postMessage({ _ready: true });
|
||||||
});
|
});
|
||||||
client.on(Events.ShardDisconnect, () => {
|
client.ws.on(WebSocketShardEvents.Closed, () => {
|
||||||
this.parentPort.postMessage({ _disconnect: true });
|
this.parentPort.postMessage({ _disconnect: true });
|
||||||
});
|
});
|
||||||
client.on(Events.ShardReconnecting, () => {
|
client.ws.on(WebSocketShardEvents.Resumed, () => {
|
||||||
this.parentPort.postMessage({ _reconnecting: true });
|
|
||||||
});
|
|
||||||
client.on(Events.ShardResume, () => {
|
|
||||||
this.parentPort.postMessage({ _resume: true });
|
this.parentPort.postMessage({ _resume: true });
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of shard ids of this client
|
|
||||||
* @type {number[]}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get ids() {
|
|
||||||
return this.client.options.shards;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total number of shards
|
|
||||||
* @type {number}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get count() {
|
|
||||||
return this.client.options.shardCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to the master process.
|
* Sends a message to the master process.
|
||||||
* @param {*} message Message to send
|
* @param {*} message Message to send
|
||||||
|
|||||||
@@ -16,19 +16,19 @@ class ClientPresence extends Presence {
|
|||||||
/**
|
/**
|
||||||
* Sets the client's presence
|
* Sets the client's presence
|
||||||
* @param {PresenceData} presence The data to set the presence to
|
* @param {PresenceData} presence The data to set the presence to
|
||||||
* @returns {ClientPresence}
|
* @returns {Promise<ClientPresence>}
|
||||||
*/
|
*/
|
||||||
set(presence) {
|
async set(presence) {
|
||||||
const packet = this._parse(presence);
|
const packet = this._parse(presence);
|
||||||
this._patch(packet);
|
this._patch(packet);
|
||||||
if (presence.shardId === undefined) {
|
if (presence.shardId === undefined) {
|
||||||
this.client.ws.broadcast({ op: GatewayOpcodes.PresenceUpdate, d: packet });
|
await this.client._broadcast({ op: GatewayOpcodes.PresenceUpdate, d: packet });
|
||||||
} else if (Array.isArray(presence.shardId)) {
|
} else if (Array.isArray(presence.shardId)) {
|
||||||
for (const shardId of presence.shardId) {
|
await Promise.all(
|
||||||
this.client.ws.shards.get(shardId).send({ op: GatewayOpcodes.PresenceUpdate, d: packet });
|
presence.shardId.map(shardId => this.client.ws.send(shardId, { op: GatewayOpcodes.PresenceUpdate, d: packet })),
|
||||||
}
|
);
|
||||||
} else {
|
} else {
|
||||||
this.client.ws.shards.get(presence.shardId).send({ op: GatewayOpcodes.PresenceUpdate, d: packet });
|
await this.client.ws.send(presence.shardId, { op: GatewayOpcodes.PresenceUpdate, d: packet });
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class ClientUser extends User {
|
|||||||
/**
|
/**
|
||||||
* Sets the full presence of the client user.
|
* Sets the full presence of the client user.
|
||||||
* @param {PresenceData} data Data for the presence
|
* @param {PresenceData} data Data for the presence
|
||||||
* @returns {ClientPresence}
|
* @returns {Promise<ClientPresence>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the client user's presence
|
* // Set the client user's presence
|
||||||
* client.user.setPresence({ activities: [{ name: 'with discord.js' }], status: 'idle' });
|
* client.user.setPresence({ activities: [{ name: 'with discord.js' }], status: 'idle' });
|
||||||
@@ -157,7 +157,7 @@ class ClientUser extends User {
|
|||||||
* Sets the status of the client user.
|
* Sets the status of the client user.
|
||||||
* @param {PresenceStatusData} status Status to change to
|
* @param {PresenceStatusData} status Status to change to
|
||||||
* @param {number|number[]} [shardId] Shard id(s) to have the activity set on
|
* @param {number|number[]} [shardId] Shard id(s) to have the activity set on
|
||||||
* @returns {ClientPresence}
|
* @returns {Promise<ClientPresence>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the client user's status
|
* // Set the client user's status
|
||||||
* client.user.setStatus('idle');
|
* client.user.setStatus('idle');
|
||||||
@@ -180,7 +180,7 @@ class ClientUser extends User {
|
|||||||
* Sets the activity the client user is playing.
|
* Sets the activity the client user is playing.
|
||||||
* @param {string|ActivityOptions} name Activity being played, or options for setting the activity
|
* @param {string|ActivityOptions} name Activity being played, or options for setting the activity
|
||||||
* @param {ActivityOptions} [options] Options for setting the activity
|
* @param {ActivityOptions} [options] Options for setting the activity
|
||||||
* @returns {ClientPresence}
|
* @returns {Promise<ClientPresence>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the client user's activity
|
* // Set the client user's activity
|
||||||
* client.user.setActivity('discord.js', { type: ActivityType.Watching });
|
* client.user.setActivity('discord.js', { type: ActivityType.Watching });
|
||||||
@@ -196,7 +196,7 @@ class ClientUser extends User {
|
|||||||
* Sets/removes the AFK flag for the client user.
|
* Sets/removes the AFK flag for the client user.
|
||||||
* @param {boolean} [afk=true] Whether or not the user is AFK
|
* @param {boolean} [afk=true] Whether or not the user is AFK
|
||||||
* @param {number|number[]} [shardId] Shard Id(s) to have the AFK flag set on
|
* @param {number|number[]} [shardId] Shard Id(s) to have the AFK flag set on
|
||||||
* @returns {ClientPresence}
|
* @returns {Promise<ClientPresence>}
|
||||||
*/
|
*/
|
||||||
setAFK(afk = true, shardId) {
|
setAFK(afk = true, shardId) {
|
||||||
return this.setPresence({ afk, shardId });
|
return this.setPresence({ afk, shardId });
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ const RoleManager = require('../managers/RoleManager');
|
|||||||
const StageInstanceManager = require('../managers/StageInstanceManager');
|
const StageInstanceManager = require('../managers/StageInstanceManager');
|
||||||
const VoiceStateManager = require('../managers/VoiceStateManager');
|
const VoiceStateManager = require('../managers/VoiceStateManager');
|
||||||
const { resolveImage } = require('../util/DataResolver');
|
const { resolveImage } = require('../util/DataResolver');
|
||||||
const Status = require('../util/Status');
|
|
||||||
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
|
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
|
||||||
const { discordSort, getSortableGroupTypes, resolvePartialEmoji } = require('../util/Util');
|
const { discordSort, getSortableGroupTypes, resolvePartialEmoji } = require('../util/Util');
|
||||||
|
|
||||||
@@ -126,15 +125,6 @@ class Guild extends AnonymousGuild {
|
|||||||
this.shardId = data.shardId;
|
this.shardId = data.shardId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Shard this Guild belongs to.
|
|
||||||
* @type {WebSocketShard}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get shard() {
|
|
||||||
return this.client.ws.shards.get(this.shardId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_patch(data) {
|
_patch(data) {
|
||||||
super._patch(data);
|
super._patch(data);
|
||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
@@ -1418,8 +1408,7 @@ class Guild extends AnonymousGuild {
|
|||||||
this.client.voice.adapters.set(this.id, methods);
|
this.client.voice.adapters.set(this.id, methods);
|
||||||
return {
|
return {
|
||||||
sendPayload: data => {
|
sendPayload: data => {
|
||||||
if (this.shard.status !== Status.Ready) return false;
|
this.client.ws.send(this.shardId, data);
|
||||||
this.shard.send(data);
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
destroy: () => {
|
destroy: () => {
|
||||||
|
|||||||
@@ -325,6 +325,10 @@
|
|||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayDispatchEvents}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayDispatchEvents}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external GatewayDispatchPayload
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#GatewayDispatchPayload}
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* @external GatewayIntentBits
|
* @external GatewayIntentBits
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayIntentBits}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayIntentBits}
|
||||||
|
|||||||
@@ -61,11 +61,6 @@
|
|||||||
* @property {string} MessageReactionRemoveEmoji messageReactionRemoveEmoji
|
* @property {string} MessageReactionRemoveEmoji messageReactionRemoveEmoji
|
||||||
* @property {string} MessageUpdate messageUpdate
|
* @property {string} MessageUpdate messageUpdate
|
||||||
* @property {string} PresenceUpdate presenceUpdate
|
* @property {string} PresenceUpdate presenceUpdate
|
||||||
* @property {string} ShardDisconnect shardDisconnect
|
|
||||||
* @property {string} ShardError shardError
|
|
||||||
* @property {string} ShardReady shardReady
|
|
||||||
* @property {string} ShardReconnecting shardReconnecting
|
|
||||||
* @property {string} ShardResume shardResume
|
|
||||||
* @property {string} StageInstanceCreate stageInstanceCreate
|
* @property {string} StageInstanceCreate stageInstanceCreate
|
||||||
* @property {string} StageInstanceDelete stageInstanceDelete
|
* @property {string} StageInstanceDelete stageInstanceDelete
|
||||||
* @property {string} StageInstanceUpdate stageInstanceUpdate
|
* @property {string} StageInstanceUpdate stageInstanceUpdate
|
||||||
@@ -99,7 +94,7 @@ module.exports = {
|
|||||||
ChannelDelete: 'channelDelete',
|
ChannelDelete: 'channelDelete',
|
||||||
ChannelPinsUpdate: 'channelPinsUpdate',
|
ChannelPinsUpdate: 'channelPinsUpdate',
|
||||||
ChannelUpdate: 'channelUpdate',
|
ChannelUpdate: 'channelUpdate',
|
||||||
ClientReady: 'ready',
|
ClientReady: 'clientReady',
|
||||||
Debug: 'debug',
|
Debug: 'debug',
|
||||||
EntitlementCreate: 'entitlementCreate',
|
EntitlementCreate: 'entitlementCreate',
|
||||||
EntitlementUpdate: 'entitlementUpdate',
|
EntitlementUpdate: 'entitlementUpdate',
|
||||||
@@ -148,12 +143,6 @@ module.exports = {
|
|||||||
MessageReactionRemoveEmoji: 'messageReactionRemoveEmoji',
|
MessageReactionRemoveEmoji: 'messageReactionRemoveEmoji',
|
||||||
MessageUpdate: 'messageUpdate',
|
MessageUpdate: 'messageUpdate',
|
||||||
PresenceUpdate: 'presenceUpdate',
|
PresenceUpdate: 'presenceUpdate',
|
||||||
Raw: 'raw',
|
|
||||||
ShardDisconnect: 'shardDisconnect',
|
|
||||||
ShardError: 'shardError',
|
|
||||||
ShardReady: 'shardReady',
|
|
||||||
ShardReconnecting: 'shardReconnecting',
|
|
||||||
ShardResume: 'shardResume',
|
|
||||||
StageInstanceCreate: 'stageInstanceCreate',
|
StageInstanceCreate: 'stageInstanceCreate',
|
||||||
StageInstanceDelete: 'stageInstanceDelete',
|
StageInstanceDelete: 'stageInstanceDelete',
|
||||||
StageInstanceUpdate: 'stageInstanceUpdate',
|
StageInstanceUpdate: 'stageInstanceUpdate',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { DefaultRestOptions, DefaultUserAgentAppendix } = require('@discordjs/rest');
|
const { DefaultRestOptions, DefaultUserAgentAppendix } = require('@discordjs/rest');
|
||||||
|
const { DefaultWebSocketManagerOptions } = require('@discordjs/ws');
|
||||||
const { toSnakeCase } = require('./Transformers');
|
const { toSnakeCase } = require('./Transformers');
|
||||||
const { version } = require('../../package.json');
|
const { version } = require('../../package.json');
|
||||||
|
|
||||||
@@ -16,13 +17,8 @@ const { version } = require('../../package.json');
|
|||||||
/**
|
/**
|
||||||
* Options for a client.
|
* Options for a client.
|
||||||
* @typedef {Object} ClientOptions
|
* @typedef {Object} ClientOptions
|
||||||
* @property {number|number[]|string} [shards] The shard's id to run, or an array of shard ids. If not specified,
|
|
||||||
* the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the
|
|
||||||
* recommended amount of shards from Discord and spawn that amount
|
|
||||||
* @property {number} [closeTimeout=5_000] The amount of time in milliseconds to wait for the close frame to be received
|
* @property {number} [closeTimeout=5_000] The amount of time in milliseconds to wait for the close frame to be received
|
||||||
* from the WebSocket. Don't have this too high/low. It's best to have it between 2_000-6_000 ms.
|
* from the WebSocket. Don't have this too high/low. It's best to have it between 2_000-6_000 ms.
|
||||||
* @property {number} [shardCount=1] The total amount of shards used by all processes of this bot
|
|
||||||
* (e.g. recommended shard count, shard count of the ShardingManager)
|
|
||||||
* @property {CacheFactory} [makeCache] Function to create a cache.
|
* @property {CacheFactory} [makeCache] Function to create a cache.
|
||||||
* You can use your own function, or the {@link Options} class to customize the Collection used for the cache.
|
* You can use your own function, or the {@link Options} class to customize the Collection used for the cache.
|
||||||
* <warn>Overriding the cache used in `GuildManager`, `ChannelManager`, `GuildChannelManager`, `RoleManager`,
|
* <warn>Overriding the cache used in `GuildManager`, `ChannelManager`, `GuildChannelManager`, `RoleManager`,
|
||||||
@@ -33,12 +29,12 @@ const { version } = require('../../package.json');
|
|||||||
* [guide](https://discordjs.guide/popular-topics/partials.html) for some
|
* [guide](https://discordjs.guide/popular-topics/partials.html) for some
|
||||||
* important usage information, as partials require you to put checks in place when handling data.
|
* important usage information, as partials require you to put checks in place when handling data.
|
||||||
* @property {boolean} [failIfNotExists=true] The default value for {@link MessageReplyOptions#failIfNotExists}
|
* @property {boolean} [failIfNotExists=true] The default value for {@link MessageReplyOptions#failIfNotExists}
|
||||||
* @property {PresenceData} [presence={}] Presence data to use upon login
|
* @property {PresenceData} [presence] Presence data to use upon login
|
||||||
* @property {IntentsResolvable} intents Intents to enable for this connection
|
* @property {IntentsResolvable} intents Intents to enable for this connection
|
||||||
* @property {number} [waitGuildTimeout=15_000] Time in milliseconds that clients with the
|
* @property {number} [waitGuildTimeout=15_000] Time in milliseconds that clients with the
|
||||||
* {@link GatewayIntentBits.Guilds} gateway intent should wait for missing guilds to be received before being ready.
|
* {@link GatewayIntentBits.Guilds} gateway intent should wait for missing guilds to be received before being ready.
|
||||||
* @property {SweeperOptions} [sweepers=this.DefaultSweeperSettings] Options for cache sweeping
|
* @property {SweeperOptions} [sweepers=this.DefaultSweeperSettings] Options for cache sweeping
|
||||||
* @property {WebsocketOptions} [ws] Options for the WebSocket
|
* @property {WebSocketManagerOptions} [ws] Options for the WebSocketManager
|
||||||
* @property {RESTOptions} [rest] Options for the REST manager
|
* @property {RESTOptions} [rest] Options for the REST manager
|
||||||
* @property {Function} [jsonTransformer] A function used to transform outgoing json data
|
* @property {Function} [jsonTransformer] A function used to transform outgoing json data
|
||||||
* @property {boolean} [enforceNonce=false] The default value for {@link MessageReplyOptions#enforceNonce}
|
* @property {boolean} [enforceNonce=false] The default value for {@link MessageReplyOptions#enforceNonce}
|
||||||
@@ -60,40 +56,6 @@ const { version } = require('../../package.json');
|
|||||||
* <info>This property is optional when the key is `invites`, `messages`, or `threads` and `lifetime` is set</info>
|
* <info>This property is optional when the key is `invites`, `messages`, or `threads` and `lifetime` is set</info>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* A function to determine what strategy to use for sharding internally.
|
|
||||||
* ```js
|
|
||||||
* (manager) => new WorkerShardingStrategy(manager, { shardsPerWorker: 2 })
|
|
||||||
* ```
|
|
||||||
* @typedef {Function} BuildStrategyFunction
|
|
||||||
* @param {WSWebSocketManager} manager The WebSocketManager that is going to initiate the sharding
|
|
||||||
* @returns {IShardingStrategy} The strategy to use for sharding
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function to change the concurrency handling for shard identifies of this manager
|
|
||||||
* ```js
|
|
||||||
* async (manager) => {
|
|
||||||
* const gateway = await manager.fetchGatewayInformation();
|
|
||||||
* return new SimpleIdentifyThrottler(gateway.session_start_limit.max_concurrency);
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* @typedef {Function} IdentifyThrottlerFunction
|
|
||||||
* @param {WSWebSocketManager} manager The WebSocketManager that is going to initiate the sharding
|
|
||||||
* @returns {Awaitable<IIdentifyThrottler>} The identify throttler that this ws manager will use
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebSocket options (these are left as snake_case to match the API)
|
|
||||||
* @typedef {Object} WebsocketOptions
|
|
||||||
* @property {number} [large_threshold=50] Number of members in a guild after which offline users will no longer be
|
|
||||||
* sent in the initial guild member list, must be between 50 and 250
|
|
||||||
* @property {number} [version=10] The Discord gateway version to use <warn>Changing this can break the library;
|
|
||||||
* only set this if you know what you are doing</warn>
|
|
||||||
* @property {BuildStrategyFunction} [buildStrategy] Builds the strategy to use for sharding
|
|
||||||
* @property {IdentifyThrottlerFunction} [buildIdentifyThrottler] Builds the identify throttler to use for sharding
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains various utilities for client options.
|
* Contains various utilities for client options.
|
||||||
*/
|
*/
|
||||||
@@ -114,15 +76,14 @@ class Options extends null {
|
|||||||
return {
|
return {
|
||||||
closeTimeout: 5_000,
|
closeTimeout: 5_000,
|
||||||
waitGuildTimeout: 15_000,
|
waitGuildTimeout: 15_000,
|
||||||
shardCount: 1,
|
|
||||||
makeCache: this.cacheWithLimits(this.DefaultMakeCacheSettings),
|
makeCache: this.cacheWithLimits(this.DefaultMakeCacheSettings),
|
||||||
partials: [],
|
partials: [],
|
||||||
failIfNotExists: true,
|
failIfNotExists: true,
|
||||||
enforceNonce: false,
|
enforceNonce: false,
|
||||||
presence: {},
|
|
||||||
sweepers: this.DefaultSweeperSettings,
|
sweepers: this.DefaultSweeperSettings,
|
||||||
ws: {
|
ws: {
|
||||||
large_threshold: 50,
|
...DefaultWebSocketManagerOptions,
|
||||||
|
largeThreshold: 50,
|
||||||
version: 10,
|
version: 10,
|
||||||
},
|
},
|
||||||
rest: {
|
rest: {
|
||||||
@@ -224,7 +185,7 @@ module.exports = Options;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external WSWebSocketManager
|
* @external WebSocketManager
|
||||||
* @see {@link https://discord.js.org/docs/packages/ws/stable/WebSocketManager:Class}
|
* @see {@link https://discord.js.org/docs/packages/ws/stable/WebSocketManager:Class}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,8 @@ const { createEnum } = require('./Enums');
|
|||||||
/**
|
/**
|
||||||
* @typedef {Object} Status
|
* @typedef {Object} Status
|
||||||
* @property {number} Ready
|
* @property {number} Ready
|
||||||
* @property {number} Connecting
|
|
||||||
* @property {number} Reconnecting
|
|
||||||
* @property {number} Idle
|
* @property {number} Idle
|
||||||
* @property {number} Nearly
|
|
||||||
* @property {number} Disconnected
|
|
||||||
* @property {number} WaitingForGuilds
|
* @property {number} WaitingForGuilds
|
||||||
* @property {number} Identifying
|
|
||||||
* @property {number} Resuming
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// JSDoc for IntelliSense purposes
|
// JSDoc for IntelliSense purposes
|
||||||
@@ -20,14 +14,4 @@ const { createEnum } = require('./Enums');
|
|||||||
* @type {Status}
|
* @type {Status}
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
module.exports = createEnum([
|
module.exports = createEnum(['Ready', 'Idle', 'WaitingForGuilds']);
|
||||||
'Ready',
|
|
||||||
'Connecting',
|
|
||||||
'Reconnecting',
|
|
||||||
'Idle',
|
|
||||||
'Nearly',
|
|
||||||
'Disconnected',
|
|
||||||
'WaitingForGuilds',
|
|
||||||
'Identifying',
|
|
||||||
'Resuming',
|
|
||||||
]);
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} WebSocketShardEvents
|
|
||||||
* @property {string} Close close
|
|
||||||
* @property {string} Destroyed destroyed
|
|
||||||
* @property {string} InvalidSession invalidSession
|
|
||||||
* @property {string} Ready ready
|
|
||||||
* @property {string} Resumed resumed
|
|
||||||
* @property {string} AllReady allReady
|
|
||||||
*/
|
|
||||||
|
|
||||||
// JSDoc for IntelliSense purposes
|
|
||||||
/**
|
|
||||||
* @type {WebSocketShardEvents}
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
module.exports = {
|
|
||||||
Close: 'close',
|
|
||||||
Destroyed: 'destroyed',
|
|
||||||
InvalidSession: 'invalidSession',
|
|
||||||
Ready: 'ready',
|
|
||||||
Resumed: 'resumed',
|
|
||||||
AllReady: 'allReady',
|
|
||||||
};
|
|
||||||
124
packages/discord.js/typings/index.d.ts
vendored
124
packages/discord.js/typings/index.d.ts
vendored
@@ -20,12 +20,7 @@ import {
|
|||||||
import { Awaitable, JSONEncodable } from '@discordjs/util';
|
import { Awaitable, JSONEncodable } from '@discordjs/util';
|
||||||
import { Collection, ReadonlyCollection } from '@discordjs/collection';
|
import { Collection, ReadonlyCollection } from '@discordjs/collection';
|
||||||
import { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest';
|
import { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest';
|
||||||
import {
|
import { WebSocketManager, WebSocketManagerOptions } from '@discordjs/ws';
|
||||||
WebSocketManager as WSWebSocketManager,
|
|
||||||
IShardingStrategy,
|
|
||||||
IIdentifyThrottler,
|
|
||||||
SessionInfo,
|
|
||||||
} from '@discordjs/ws';
|
|
||||||
import {
|
import {
|
||||||
APIActionRowComponent,
|
APIActionRowComponent,
|
||||||
APIApplicationCommandInteractionData,
|
APIApplicationCommandInteractionData,
|
||||||
@@ -50,7 +45,6 @@ import {
|
|||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
ChannelType,
|
ChannelType,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
GatewayDispatchEvents,
|
|
||||||
GatewayVoiceServerUpdateDispatchData,
|
GatewayVoiceServerUpdateDispatchData,
|
||||||
GatewayVoiceStateUpdateDispatchData,
|
GatewayVoiceStateUpdateDispatchData,
|
||||||
GuildFeature,
|
GuildFeature,
|
||||||
@@ -170,6 +164,8 @@ import {
|
|||||||
GuildScheduledEventRecurrenceRuleWeekday,
|
GuildScheduledEventRecurrenceRuleWeekday,
|
||||||
GuildScheduledEventRecurrenceRuleMonth,
|
GuildScheduledEventRecurrenceRuleMonth,
|
||||||
GuildScheduledEventRecurrenceRuleFrequency,
|
GuildScheduledEventRecurrenceRuleFrequency,
|
||||||
|
GatewaySendPayload,
|
||||||
|
GatewayDispatchPayload,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import { ChildProcess } from 'node:child_process';
|
import { ChildProcess } from 'node:child_process';
|
||||||
import { EventEmitter } from 'node:events';
|
import { EventEmitter } from 'node:events';
|
||||||
@@ -956,8 +952,16 @@ export type If<Value extends boolean, TrueResult, FalseResult = null> = Value ex
|
|||||||
export class Client<Ready extends boolean = boolean> extends BaseClient {
|
export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||||
public constructor(options: ClientOptions);
|
public constructor(options: ClientOptions);
|
||||||
private actions: unknown;
|
private actions: unknown;
|
||||||
|
private expectedGuilds: Set<Snowflake>;
|
||||||
|
private readonly packetQueue: unknown[];
|
||||||
private presence: ClientPresence;
|
private presence: ClientPresence;
|
||||||
|
private pings: Collection<number, number>;
|
||||||
|
private readyTimeout: NodeJS.Timeout | null;
|
||||||
|
private _broadcast(packet: GatewaySendPayload): void;
|
||||||
private _eval(script: string): unknown;
|
private _eval(script: string): unknown;
|
||||||
|
private _handlePacket(packet?: GatewayDispatchPayload, shardId?: number): boolean;
|
||||||
|
private _checkReady(): void;
|
||||||
|
private _triggerClientReady(): void;
|
||||||
private _validateOptions(options: ClientOptions): void;
|
private _validateOptions(options: ClientOptions): void;
|
||||||
private get _censoredToken(): string | null;
|
private get _censoredToken(): string | null;
|
||||||
// This a technique used to brand the ready state. Or else we'll get `never` errors on typeguard checks.
|
// This a technique used to brand the ready state. Or else we'll get `never` errors on typeguard checks.
|
||||||
@@ -979,17 +983,21 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
|||||||
public channels: ChannelManager;
|
public channels: ChannelManager;
|
||||||
public get emojis(): BaseGuildEmojiManager;
|
public get emojis(): BaseGuildEmojiManager;
|
||||||
public guilds: GuildManager;
|
public guilds: GuildManager;
|
||||||
|
public lastPingTimestamp: number;
|
||||||
public options: Omit<ClientOptions, 'intents'> & { intents: IntentsBitField };
|
public options: Omit<ClientOptions, 'intents'> & { intents: IntentsBitField };
|
||||||
|
public get ping(): number;
|
||||||
public get readyAt(): If<Ready, Date>;
|
public get readyAt(): If<Ready, Date>;
|
||||||
public readyTimestamp: If<Ready, number>;
|
public readyTimestamp: If<Ready, number>;
|
||||||
public sweepers: Sweepers;
|
public sweepers: Sweepers;
|
||||||
public shard: ShardClientUtil | null;
|
public shard: ShardClientUtil | null;
|
||||||
|
public status: Status;
|
||||||
public token: If<Ready, string, string | null>;
|
public token: If<Ready, string, string | null>;
|
||||||
public get uptime(): If<Ready, number>;
|
public get uptime(): If<Ready, number>;
|
||||||
public user: If<Ready, ClientUser>;
|
public user: If<Ready, ClientUser>;
|
||||||
public users: UserManager;
|
public users: UserManager;
|
||||||
public voice: ClientVoiceManager;
|
public voice: ClientVoiceManager;
|
||||||
public ws: WebSocketManager;
|
public ws: WebSocketManager;
|
||||||
|
|
||||||
public destroy(): Promise<void>;
|
public destroy(): Promise<void>;
|
||||||
public deleteWebhook(id: Snowflake, options?: WebhookDeleteOptions): Promise<void>;
|
public deleteWebhook(id: Snowflake, options?: WebhookDeleteOptions): Promise<void>;
|
||||||
public fetchGuildPreview(guild: GuildResolvable): Promise<GuildPreview>;
|
public fetchGuildPreview(guild: GuildResolvable): Promise<GuildPreview>;
|
||||||
@@ -1431,7 +1439,6 @@ export class Guild extends AnonymousGuild {
|
|||||||
public get safetyAlertsChannel(): TextChannel | null;
|
public get safetyAlertsChannel(): TextChannel | null;
|
||||||
public safetyAlertsChannelId: Snowflake | null;
|
public safetyAlertsChannelId: Snowflake | null;
|
||||||
public scheduledEvents: GuildScheduledEventManager;
|
public scheduledEvents: GuildScheduledEventManager;
|
||||||
public get shard(): WebSocketShard;
|
|
||||||
public shardId: number;
|
public shardId: number;
|
||||||
public stageInstances: StageInstanceManager;
|
public stageInstances: StageInstanceManager;
|
||||||
public stickers: GuildStickerManager;
|
public stickers: GuildStickerManager;
|
||||||
@@ -3632,70 +3639,6 @@ export class WebhookClient extends BaseClient {
|
|||||||
public send(options: string | MessagePayload | WebhookMessageCreateOptions): Promise<APIMessage>;
|
public send(options: string | MessagePayload | WebhookMessageCreateOptions): Promise<APIMessage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WebSocketManager extends EventEmitter {
|
|
||||||
private constructor(client: Client);
|
|
||||||
private readonly packetQueue: unknown[];
|
|
||||||
private destroyed: boolean;
|
|
||||||
|
|
||||||
public readonly client: Client;
|
|
||||||
public gateway: string | null;
|
|
||||||
public shards: Collection<number, WebSocketShard>;
|
|
||||||
public status: Status;
|
|
||||||
public get ping(): number;
|
|
||||||
|
|
||||||
public on(event: GatewayDispatchEvents, listener: (data: any, shardId: number) => void): this;
|
|
||||||
public once(event: GatewayDispatchEvents, listener: (data: any, shardId: number) => void): this;
|
|
||||||
|
|
||||||
private debug(messages: readonly string[], shardId?: number): void;
|
|
||||||
private connect(): Promise<void>;
|
|
||||||
private broadcast(packet: unknown): void;
|
|
||||||
private destroy(): Promise<void>;
|
|
||||||
private handlePacket(packet?: unknown, shard?: WebSocketShard): boolean;
|
|
||||||
private checkShardsReady(): void;
|
|
||||||
private triggerClientReady(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebSocketShardEventTypes {
|
|
||||||
ready: [];
|
|
||||||
resumed: [];
|
|
||||||
invalidSession: [];
|
|
||||||
destroyed: [];
|
|
||||||
close: [event: CloseEvent];
|
|
||||||
allReady: [unavailableGuilds?: Set<Snowflake>];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WebSocketShard extends EventEmitter {
|
|
||||||
private constructor(manager: WebSocketManager, id: number);
|
|
||||||
private closeSequence: number;
|
|
||||||
private sessionInfo: SessionInfo | null;
|
|
||||||
public lastPingTimestamp: number;
|
|
||||||
private expectedGuilds: Set<Snowflake> | null;
|
|
||||||
private readyTimeout: NodeJS.Timeout | null;
|
|
||||||
|
|
||||||
public manager: WebSocketManager;
|
|
||||||
public id: number;
|
|
||||||
public status: Status;
|
|
||||||
public ping: number;
|
|
||||||
|
|
||||||
private debug(messages: readonly string[]): void;
|
|
||||||
private onReadyPacket(packet: unknown): void;
|
|
||||||
private gotGuild(guildId: Snowflake): void;
|
|
||||||
private checkReady(): void;
|
|
||||||
private emitClose(event?: CloseEvent): void;
|
|
||||||
|
|
||||||
public send(data: unknown, important?: boolean): void;
|
|
||||||
|
|
||||||
public on<Event extends keyof WebSocketShardEventTypes>(
|
|
||||||
event: Event,
|
|
||||||
listener: (...args: WebSocketShardEventTypes[Event]) => void,
|
|
||||||
): this;
|
|
||||||
|
|
||||||
public once<Event extends keyof WebSocketShardEventTypes>(
|
|
||||||
event: Event,
|
|
||||||
listener: (...args: WebSocketShardEventTypes[Event]) => void,
|
|
||||||
): this;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Widget extends Base {
|
export class Widget extends Base {
|
||||||
private constructor(client: Client<true>, data: RawWidgetData);
|
private constructor(client: Client<true>, data: RawWidgetData);
|
||||||
private _patch(data: RawWidgetData): void;
|
private _patch(data: RawWidgetData): void;
|
||||||
@@ -5133,6 +5076,7 @@ export interface ClientEvents {
|
|||||||
oldChannel: DMChannel | NonThreadGuildBasedChannel,
|
oldChannel: DMChannel | NonThreadGuildBasedChannel,
|
||||||
newChannel: DMChannel | NonThreadGuildBasedChannel,
|
newChannel: DMChannel | NonThreadGuildBasedChannel,
|
||||||
];
|
];
|
||||||
|
clientReady: [client: Client<true>];
|
||||||
debug: [message: string];
|
debug: [message: string];
|
||||||
warn: [message: string];
|
warn: [message: string];
|
||||||
emojiCreate: [emoji: GuildEmoji];
|
emojiCreate: [emoji: GuildEmoji];
|
||||||
@@ -5186,7 +5130,6 @@ export interface ClientEvents {
|
|||||||
newMessage: OmitPartialGroupDMChannel<Message>,
|
newMessage: OmitPartialGroupDMChannel<Message>,
|
||||||
];
|
];
|
||||||
presenceUpdate: [oldPresence: Presence | null, newPresence: Presence];
|
presenceUpdate: [oldPresence: Presence | null, newPresence: Presence];
|
||||||
ready: [client: Client<true>];
|
|
||||||
invalidated: [];
|
invalidated: [];
|
||||||
roleCreate: [role: Role];
|
roleCreate: [role: Role];
|
||||||
roleDelete: [role: Role];
|
roleDelete: [role: Role];
|
||||||
@@ -5206,11 +5149,6 @@ export interface ClientEvents {
|
|||||||
voiceStateUpdate: [oldState: VoiceState, newState: VoiceState];
|
voiceStateUpdate: [oldState: VoiceState, newState: VoiceState];
|
||||||
webhooksUpdate: [channel: TextChannel | NewsChannel | VoiceChannel | ForumChannel | MediaChannel];
|
webhooksUpdate: [channel: TextChannel | NewsChannel | VoiceChannel | ForumChannel | MediaChannel];
|
||||||
interactionCreate: [interaction: Interaction];
|
interactionCreate: [interaction: Interaction];
|
||||||
shardDisconnect: [closeEvent: CloseEvent, shardId: number];
|
|
||||||
shardError: [error: Error, shardId: number];
|
|
||||||
shardReady: [shardId: number, unavailableGuilds: Set<Snowflake> | undefined];
|
|
||||||
shardReconnecting: [shardId: number];
|
|
||||||
shardResume: [shardId: number, replayedEvents: number];
|
|
||||||
stageInstanceCreate: [stageInstance: StageInstance];
|
stageInstanceCreate: [stageInstance: StageInstance];
|
||||||
stageInstanceUpdate: [oldStageInstance: StageInstance | null, newStageInstance: StageInstance];
|
stageInstanceUpdate: [oldStageInstance: StageInstance | null, newStageInstance: StageInstance];
|
||||||
stageInstanceDelete: [stageInstance: StageInstance];
|
stageInstanceDelete: [stageInstance: StageInstance];
|
||||||
@@ -5232,8 +5170,6 @@ export interface ClientFetchInviteOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientOptions {
|
export interface ClientOptions {
|
||||||
shards?: number | readonly number[] | 'auto';
|
|
||||||
shardCount?: number;
|
|
||||||
closeTimeout?: number;
|
closeTimeout?: number;
|
||||||
makeCache?: CacheFactory;
|
makeCache?: CacheFactory;
|
||||||
allowedMentions?: MessageMentionOptions;
|
allowedMentions?: MessageMentionOptions;
|
||||||
@@ -5243,7 +5179,7 @@ export interface ClientOptions {
|
|||||||
intents: BitFieldResolvable<GatewayIntentsString, number>;
|
intents: BitFieldResolvable<GatewayIntentsString, number>;
|
||||||
waitGuildTimeout?: number;
|
waitGuildTimeout?: number;
|
||||||
sweepers?: SweeperOptions;
|
sweepers?: SweeperOptions;
|
||||||
ws?: WebSocketOptions;
|
ws?: Partial<WebSocketManagerOptions>;
|
||||||
rest?: Partial<RESTOptions>;
|
rest?: Partial<RESTOptions>;
|
||||||
jsonTransformer?: (obj: unknown) => unknown;
|
jsonTransformer?: (obj: unknown) => unknown;
|
||||||
enforceNonce?: boolean;
|
enforceNonce?: boolean;
|
||||||
@@ -5263,14 +5199,6 @@ export interface ClientUserEditOptions {
|
|||||||
banner?: BufferResolvable | Base64Resolvable | null;
|
banner?: BufferResolvable | Base64Resolvable | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CloseEvent {
|
|
||||||
/** @deprecated Not used anymore since using {@link @discordjs/ws#(WebSocketManager:class)} internally */
|
|
||||||
wasClean: boolean;
|
|
||||||
code: number;
|
|
||||||
/** @deprecated Not used anymore since using {@link @discordjs/ws#(WebSocketManager:class)} internally */
|
|
||||||
reason: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CollectorFilter<Arguments extends unknown[]> = (...args: Arguments) => Awaitable<boolean>;
|
export type CollectorFilter<Arguments extends unknown[]> = (...args: Arguments) => Awaitable<boolean>;
|
||||||
|
|
||||||
export interface CollectorOptions<FilterArguments extends unknown[]> {
|
export interface CollectorOptions<FilterArguments extends unknown[]> {
|
||||||
@@ -5364,7 +5292,7 @@ export enum Events {
|
|||||||
AutoModerationRuleCreate = 'autoModerationRuleCreate',
|
AutoModerationRuleCreate = 'autoModerationRuleCreate',
|
||||||
AutoModerationRuleDelete = 'autoModerationRuleDelete',
|
AutoModerationRuleDelete = 'autoModerationRuleDelete',
|
||||||
AutoModerationRuleUpdate = 'autoModerationRuleUpdate',
|
AutoModerationRuleUpdate = 'autoModerationRuleUpdate',
|
||||||
ClientReady = 'ready',
|
ClientReady = 'clientReady',
|
||||||
EntitlementCreate = 'entitlementCreate',
|
EntitlementCreate = 'entitlementCreate',
|
||||||
EntitlementDelete = 'entitlementDelete',
|
EntitlementDelete = 'entitlementDelete',
|
||||||
EntitlementUpdate = 'entitlementUpdate',
|
EntitlementUpdate = 'entitlementUpdate',
|
||||||
@@ -5452,15 +5380,6 @@ export enum ShardEvents {
|
|||||||
Spawn = 'spawn',
|
Spawn = 'spawn',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum WebSocketShardEvents {
|
|
||||||
Close = 'close',
|
|
||||||
Destroyed = 'destroyed',
|
|
||||||
InvalidSession = 'invalidSession',
|
|
||||||
Ready = 'ready',
|
|
||||||
Resumed = 'resumed',
|
|
||||||
AllReady = 'allReady',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Status {
|
export enum Status {
|
||||||
Ready = 0,
|
Ready = 0,
|
||||||
Connecting = 1,
|
Connecting = 1,
|
||||||
@@ -6879,13 +6798,6 @@ export interface WebhookMessageCreateOptions extends Omit<MessageCreateOptions,
|
|||||||
appliedTags?: readonly Snowflake[];
|
appliedTags?: readonly Snowflake[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebSocketOptions {
|
|
||||||
large_threshold?: number;
|
|
||||||
version?: number;
|
|
||||||
buildStrategy?(manager: WSWebSocketManager): IShardingStrategy;
|
|
||||||
buildIdentifyThrottler?(manager: WSWebSocketManager): Awaitable<IIdentifyThrottler>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WidgetActivity {
|
export interface WidgetActivity {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import {
|
|||||||
Client,
|
Client,
|
||||||
ClientApplication,
|
ClientApplication,
|
||||||
ClientUser,
|
ClientUser,
|
||||||
CloseEvent,
|
|
||||||
Collection,
|
Collection,
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
CommandInteractionOption,
|
CommandInteractionOption,
|
||||||
@@ -100,7 +99,6 @@ import {
|
|||||||
User,
|
User,
|
||||||
VoiceChannel,
|
VoiceChannel,
|
||||||
Shard,
|
Shard,
|
||||||
WebSocketShard,
|
|
||||||
Collector,
|
Collector,
|
||||||
GuildAuditLogsEntry,
|
GuildAuditLogsEntry,
|
||||||
GuildAuditLogs,
|
GuildAuditLogs,
|
||||||
@@ -112,7 +110,6 @@ import {
|
|||||||
RepliableInteraction,
|
RepliableInteraction,
|
||||||
ThreadChannelType,
|
ThreadChannelType,
|
||||||
Events,
|
Events,
|
||||||
WebSocketShardEvents,
|
|
||||||
Status,
|
Status,
|
||||||
CategoryChannelChildManager,
|
CategoryChannelChildManager,
|
||||||
ActionRowData,
|
ActionRowData,
|
||||||
@@ -677,7 +674,7 @@ client.on('presenceUpdate', (oldPresence, { client }) => {
|
|||||||
declare const slashCommandBuilder: SlashCommandBuilder;
|
declare const slashCommandBuilder: SlashCommandBuilder;
|
||||||
declare const contextMenuCommandBuilder: ContextMenuCommandBuilder;
|
declare const contextMenuCommandBuilder: ContextMenuCommandBuilder;
|
||||||
|
|
||||||
client.on('ready', async client => {
|
client.on('clientReady', async client => {
|
||||||
expectType<Client<true>>(client);
|
expectType<Client<true>>(client);
|
||||||
console.log(`Client is logged in as ${client.user.tag} and ready!`);
|
console.log(`Client is logged in as ${client.user.tag} and ready!`);
|
||||||
|
|
||||||
@@ -1305,8 +1302,8 @@ client.on('guildCreate', async g => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// EventEmitter static method overrides
|
// EventEmitter static method overrides
|
||||||
expectType<Promise<[Client<true>]>>(Client.once(client, 'ready'));
|
expectType<Promise<[Client<true>]>>(Client.once(client, 'clientReady'));
|
||||||
expectType<AsyncIterableIterator<[Client<true>]>>(Client.on(client, 'ready'));
|
expectType<AsyncIterableIterator<[Client<true>]>>(Client.on(client, 'clientReady'));
|
||||||
|
|
||||||
client.login('absolutely-valid-token');
|
client.login('absolutely-valid-token');
|
||||||
|
|
||||||
@@ -1426,7 +1423,6 @@ reactionCollector.on('dispose', (...args) => {
|
|||||||
// Make sure the properties are typed correctly, and that no backwards properties
|
// Make sure the properties are typed correctly, and that no backwards properties
|
||||||
// (K -> V and V -> K) exist:
|
// (K -> V and V -> K) exist:
|
||||||
expectAssignable<'messageCreate'>(Events.MessageCreate);
|
expectAssignable<'messageCreate'>(Events.MessageCreate);
|
||||||
expectAssignable<'close'>(WebSocketShardEvents.Close);
|
|
||||||
expectAssignable<'death'>(ShardEvents.Death);
|
expectAssignable<'death'>(ShardEvents.Death);
|
||||||
expectAssignable<1>(Status.Connecting);
|
expectAssignable<1>(Status.Connecting);
|
||||||
|
|
||||||
@@ -2100,12 +2096,6 @@ shard.on('death', process => {
|
|||||||
expectType<ChildProcess | Worker>(process);
|
expectType<ChildProcess | Worker>(process);
|
||||||
});
|
});
|
||||||
|
|
||||||
declare const webSocketShard: WebSocketShard;
|
|
||||||
|
|
||||||
webSocketShard.on('close', event => {
|
|
||||||
expectType<CloseEvent>(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
declare const collector: Collector<string, Interaction, string[]>;
|
declare const collector: Collector<string, Interaction, string[]>;
|
||||||
|
|
||||||
collector.on('collect', (collected, ...other) => {
|
collector.on('collect', (collected, ...other) => {
|
||||||
|
|||||||
62
pnpm-lock.yaml
generated
62
pnpm-lock.yaml
generated
@@ -932,8 +932,8 @@ importers:
|
|||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../util
|
version: link:../util
|
||||||
'@discordjs/ws':
|
'@discordjs/ws':
|
||||||
specifier: 1.1.1
|
specifier: workspace:^
|
||||||
version: 1.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
version: link:../ws
|
||||||
'@sapphire/snowflake':
|
'@sapphire/snowflake':
|
||||||
specifier: 3.5.3
|
specifier: 3.5.3
|
||||||
version: 3.5.3
|
version: 3.5.3
|
||||||
@@ -2609,10 +2609,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==}
|
resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==}
|
||||||
engines: {node: '>=16.11.0'}
|
engines: {node: '>=16.11.0'}
|
||||||
|
|
||||||
'@discordjs/collection@2.1.0':
|
|
||||||
resolution: {integrity: sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
'@discordjs/formatters@0.5.0':
|
'@discordjs/formatters@0.5.0':
|
||||||
resolution: {integrity: sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==}
|
resolution: {integrity: sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -2625,22 +2621,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NEE76A96FtQ5YuoAVlOlB3ryMPrkXbUCTQICHGKb8ShtjXyubGicjRMouHtP1RpuDdm16cDa+oI3aAMo1zQRUQ==}
|
resolution: {integrity: sha512-NEE76A96FtQ5YuoAVlOlB3ryMPrkXbUCTQICHGKb8ShtjXyubGicjRMouHtP1RpuDdm16cDa+oI3aAMo1zQRUQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
'@discordjs/rest@2.3.0':
|
|
||||||
resolution: {integrity: sha512-C1kAJK8aSYRv3ZwMG8cvrrW4GN0g5eMdP8AuN8ODH5DyOCbHgJspze1my3xHOAgwLJdKUbWNVyAeJ9cEdduqIg==}
|
|
||||||
engines: {node: '>=16.11.0'}
|
|
||||||
|
|
||||||
'@discordjs/util@1.1.0':
|
|
||||||
resolution: {integrity: sha512-IndcI5hzlNZ7GS96RV3Xw1R2kaDuXEp7tRIy/KlhidpN/BQ1qh1NZt3377dMLTa44xDUNKT7hnXkA/oUAzD/lg==}
|
|
||||||
engines: {node: '>=16.11.0'}
|
|
||||||
|
|
||||||
'@discordjs/util@1.1.1':
|
'@discordjs/util@1.1.1':
|
||||||
resolution: {integrity: sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==}
|
resolution: {integrity: sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@discordjs/ws@1.1.1':
|
|
||||||
resolution: {integrity: sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==}
|
|
||||||
engines: {node: '>=16.11.0'}
|
|
||||||
|
|
||||||
'@edge-runtime/format@2.2.1':
|
'@edge-runtime/format@2.2.1':
|
||||||
resolution: {integrity: sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==}
|
resolution: {integrity: sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@@ -7631,9 +7615,6 @@ packages:
|
|||||||
discord-api-types@0.37.101:
|
discord-api-types@0.37.101:
|
||||||
resolution: {integrity: sha512-2wizd94t7G3A8U5Phr3AiuL4gSvhqistDwWnlk1VLTit8BI1jWUncFqFQNdPbHqS3661+Nx/iEyIwtVjPuBP3w==}
|
resolution: {integrity: sha512-2wizd94t7G3A8U5Phr3AiuL4gSvhqistDwWnlk1VLTit8BI1jWUncFqFQNdPbHqS3661+Nx/iEyIwtVjPuBP3w==}
|
||||||
|
|
||||||
discord-api-types@0.37.83:
|
|
||||||
resolution: {integrity: sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==}
|
|
||||||
|
|
||||||
discord-api-types@0.37.97:
|
discord-api-types@0.37.97:
|
||||||
resolution: {integrity: sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==}
|
resolution: {integrity: sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==}
|
||||||
|
|
||||||
@@ -13035,10 +13016,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==}
|
resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==}
|
||||||
engines: {node: '>=14.0'}
|
engines: {node: '>=14.0'}
|
||||||
|
|
||||||
undici@6.13.0:
|
|
||||||
resolution: {integrity: sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==}
|
|
||||||
engines: {node: '>=18.0'}
|
|
||||||
|
|
||||||
undici@6.19.8:
|
undici@6.19.8:
|
||||||
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
|
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
|
||||||
engines: {node: '>=18.17'}
|
engines: {node: '>=18.17'}
|
||||||
@@ -14857,8 +14834,6 @@ snapshots:
|
|||||||
|
|
||||||
'@discordjs/collection@1.5.3': {}
|
'@discordjs/collection@1.5.3': {}
|
||||||
|
|
||||||
'@discordjs/collection@2.1.0': {}
|
|
||||||
|
|
||||||
'@discordjs/formatters@0.5.0':
|
'@discordjs/formatters@0.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
discord-api-types: 0.37.97
|
discord-api-types: 0.37.97
|
||||||
@@ -14886,37 +14861,8 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@discordjs/rest@2.3.0':
|
|
||||||
dependencies:
|
|
||||||
'@discordjs/collection': 2.1.0
|
|
||||||
'@discordjs/util': 1.1.0
|
|
||||||
'@sapphire/async-queue': 1.5.3
|
|
||||||
'@sapphire/snowflake': 3.5.3
|
|
||||||
'@vladfrangu/async_event_emitter': 2.4.6
|
|
||||||
discord-api-types: 0.37.83
|
|
||||||
magic-bytes.js: 1.10.0
|
|
||||||
tslib: 2.6.3
|
|
||||||
undici: 6.13.0
|
|
||||||
|
|
||||||
'@discordjs/util@1.1.0': {}
|
|
||||||
|
|
||||||
'@discordjs/util@1.1.1': {}
|
'@discordjs/util@1.1.1': {}
|
||||||
|
|
||||||
'@discordjs/ws@1.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
|
|
||||||
dependencies:
|
|
||||||
'@discordjs/collection': 2.1.0
|
|
||||||
'@discordjs/rest': 2.3.0
|
|
||||||
'@discordjs/util': 1.1.0
|
|
||||||
'@sapphire/async-queue': 1.5.3
|
|
||||||
'@types/ws': 8.5.12
|
|
||||||
'@vladfrangu/async_event_emitter': 2.4.6
|
|
||||||
discord-api-types: 0.37.83
|
|
||||||
tslib: 2.6.3
|
|
||||||
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- bufferutil
|
|
||||||
- utf-8-validate
|
|
||||||
|
|
||||||
'@edge-runtime/format@2.2.1': {}
|
'@edge-runtime/format@2.2.1': {}
|
||||||
|
|
||||||
'@edge-runtime/node-utils@2.3.0': {}
|
'@edge-runtime/node-utils@2.3.0': {}
|
||||||
@@ -21518,8 +21464,6 @@ snapshots:
|
|||||||
|
|
||||||
discord-api-types@0.37.101: {}
|
discord-api-types@0.37.101: {}
|
||||||
|
|
||||||
discord-api-types@0.37.83: {}
|
|
||||||
|
|
||||||
discord-api-types@0.37.97: {}
|
discord-api-types@0.37.97: {}
|
||||||
|
|
||||||
dlv@1.1.3: {}
|
dlv@1.1.3: {}
|
||||||
@@ -28791,8 +28735,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@fastify/busboy': 2.1.1
|
'@fastify/busboy': 2.1.1
|
||||||
|
|
||||||
undici@6.13.0: {}
|
|
||||||
|
|
||||||
undici@6.19.8: {}
|
undici@6.19.8: {}
|
||||||
|
|
||||||
unicode-canonical-property-names-ecmascript@2.0.0: {}
|
unicode-canonical-property-names-ecmascript@2.0.0: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user