Downgrade to v13

[vi] cảm giác đau khổ
This commit is contained in:
March 7th
2022-03-24 17:55:32 +07:00
parent 9596b1a210
commit 7dfdef46a5
218 changed files with 8584 additions and 9108 deletions

View File

@@ -2,7 +2,6 @@
const EventEmitter = require('node:events');
const RESTManager = require('../rest/RESTManager');
const { TypeError } = require('../errors');
const Options = require('../util/Options');
const Util = require('../util/Util');
@@ -12,11 +11,7 @@ const Util = require('../util/Util');
*/
class BaseClient extends EventEmitter {
constructor(options = {}) {
super({ captureRejections: true });
if (typeof options !== 'object' || options === null) {
throw new TypeError('INVALID_TYPE', 'options', 'object', true);
}
super();
/**
* The options the client was instantiated with
@@ -26,11 +21,18 @@ class BaseClient extends EventEmitter {
/**
* The REST manager of the client
* @type {REST}
* @type {RESTManager}
* @private
*/
this.rest = new RESTManager(this);
}
/**
* API shortcut
* @type {Object}
* @readonly
* @private
*/
get api() {
return this.rest.api;
}
@@ -40,7 +42,7 @@ class BaseClient extends EventEmitter {
* @returns {void}
*/
destroy() {
if(this.rest.sweepInterval) clearInterval(this.rest.sweepInterval);
if (this.rest.sweepInterval) clearInterval(this.rest.sweepInterval);
}
/**
@@ -73,6 +75,7 @@ class BaseClient extends EventEmitter {
module.exports = BaseClient;
/**
* @external REST
* @see {@link https://discord.js.org/#/docs/rest/main/class/REST}
* Emitted for general debugging information.
* @event BaseClient#debug
* @param {string} info The debug information
*/

View File

@@ -1,8 +1,8 @@
'use strict';
const process = require('node:process');
const { setInterval } = require('node:timers');
const { Collection } = require('@discordjs/collection');
const { OAuth2Scopes, Routes } = require('discord-api-types/v9');
const BaseClient = require('./BaseClient');
const ActionsManager = require('./actions/ActionsManager');
const ClientVoiceManager = require('./voice/ClientVoiceManager');
@@ -12,9 +12,6 @@ const BaseGuildEmojiManager = require('../managers/BaseGuildEmojiManager');
const ChannelManager = require('../managers/ChannelManager');
const GuildManager = require('../managers/GuildManager');
const UserManager = require('../managers/UserManager');
const FriendsManager = require('../managers/FriendsManager');
const BlockedManager = require('../managers/BlockedManager');
const ClientUserSettingManager = require('../managers/ClientUserSettingManager');
const ShardClientUtil = require('../sharding/ShardClientUtil');
const ClientPresence = require('../structures/ClientPresence');
const GuildPreview = require('../structures/GuildPreview');
@@ -25,13 +22,16 @@ const StickerPack = require('../structures/StickerPack');
const VoiceRegion = require('../structures/VoiceRegion');
const Webhook = require('../structures/Webhook');
const Widget = require('../structures/Widget');
const { Events, InviteScopes, Status } = require('../util/Constants');
const DataResolver = require('../util/DataResolver');
const Events = require('../util/Events');
const IntentsBitField = require('../util/IntentsBitField');
const Intents = require('../util/Intents');
const Options = require('../util/Options');
const PermissionsBitField = require('../util/PermissionsBitField');
const Status = require('../util/Status');
const Permissions = require('../util/Permissions');
const Sweepers = require('../util/Sweepers');
// Patch
const FriendsManager = require('../managers/FriendsManager');
const BlockedManager = require('../managers/BlockedManager');
const ClientUserSettingManager = require('../managers/ClientUserSettingManager');
/**
* The main hub for interacting with the Discord API, and the starting point for any bot.
@@ -79,6 +79,20 @@ class Client extends BaseClient {
this._validateOptions();
/**
* Functions called when a cache is garbage collected or the Client is destroyed
* @type {Set<Function>}
* @private
*/
this._cleanups = new Set();
/**
* The finalizers used to cleanup items.
* @type {FinalizationRegistry}
* @private
*/
this._finalizers = new FinalizationRegistry(this._finalize.bind(this));
/**
* The WebSocket manager of the client
* @type {WebSocketManager}
@@ -111,6 +125,10 @@ class Client extends BaseClient {
* @type {UserManager}
*/
this.users = new UserManager(this);
/** Patch
*
*/
this.friends = new FriendsManager(this);
this.blocked = new BlockedManager(this);
this.setting = new ClientUserSettingManager(this);
@@ -156,12 +174,6 @@ class Client extends BaseClient {
this.token = null;
}
/**
* used for interacitons
* @type {?String}
*/
this.session_id = null;
/**
* User that the client is logged in as
* @type {?ClientUser}
@@ -173,13 +185,24 @@ class Client extends BaseClient {
* @type {?ClientApplication}
*/
this.application = null;
this.bot = null;
/**
* Timestamp of the time the client was last `READY` at
* @type {?number}
* Time at which the client was last regarded as being in the `READY` state
* (each time the client disconnects and successfully reconnects, this will be overwritten)
* @type {?Date}
*/
this.readyTimestamp = null;
this.readyAt = null;
if (this.options.messageSweepInterval > 0) {
process.emitWarning(
'The message sweeping client options are deprecated, use the global sweepers instead.',
'DeprecationWarning',
);
this.sweepMessageInterval = setInterval(
this.sweepMessages.bind(this),
this.options.messageSweepInterval * 1_000,
).unref();
}
}
/**
@@ -196,13 +219,12 @@ class Client extends BaseClient {
}
/**
* Time at which the client was last regarded as being in the `READY` state
* (each time the client disconnects and successfully reconnects, this will be overwritten)
* @type {?Date}
* Timestamp of the time the client was last `READY` at
* @type {?number}
* @readonly
*/
get readyAt() {
return this.readyTimestamp && new Date(this.readyTimestamp);
get readyTimestamp() {
return this.readyAt?.getTime() ?? null;
}
/**
@@ -211,23 +233,21 @@ class Client extends BaseClient {
* @readonly
*/
get uptime() {
return this.readyTimestamp && Date.now() - this.readyTimestamp;
return this.readyAt ? Date.now() - this.readyAt : null;
}
/**
* Logs the client in, establishing a WebSocket connection to Discord.
* @param {string} [token=this.token] Token of the account to log in with
* @param {Boolean} [bot=false] Wether the token used is a bot account or not
* @returns {Promise<string>} Token of the account used
* @example
* client.login('my token');
*/
async login(token = this.token, bot = false) {
async login(token = this.token) {
if (!token || typeof token !== 'string') throw new Error('TOKEN_INVALID');
this.token = token = token.replace(/^(Bot|Bearer)\s*/i, '');
this.bot = bot;
this.emit(
Events.Debug,
Events.DEBUG,
`Provided token: ${token
.split('.')
.map((val, i) => (i > 1 ? val.replace(/./g, '*') : val))
@@ -238,7 +258,7 @@ class Client extends BaseClient {
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...');
try {
await this.ws.connect();
@@ -255,7 +275,7 @@ class Client extends BaseClient {
* @returns {boolean}
*/
isReady() {
return this.ws.status === Status.Ready;
return this.ws.status === Status.READY;
}
/**
@@ -265,10 +285,14 @@ class Client extends BaseClient {
destroy() {
super.destroy();
for (const fn of this._cleanups) fn();
this._cleanups.clear();
if (this.sweepMessageInterval) clearInterval(this.sweepMessageInterval);
this.sweepers.destroy();
this.ws.destroy();
this.token = null;
//this.rest.setToken(null);
}
/**
@@ -290,14 +314,9 @@ class Client extends BaseClient {
*/
async fetchInvite(invite, options) {
const code = DataResolver.resolveInviteCode(invite);
const query = new URLSearchParams({
with_counts: true,
with_expiration: true,
const data = await this.api.invites(code).get({
query: { with_counts: true, with_expiration: true, guild_scheduled_event_id: options?.guildScheduledEventId },
});
if (options?.guildScheduledEventId) {
query.set('guild_scheduled_event_id', options.guildScheduledEventId);
}
const data = await this.api.invites(code).get({ query });
return new Invite(this, data);
}
@@ -327,7 +346,7 @@ class Client extends BaseClient {
* .catch(console.error);
*/
async fetchWebhook(id, token) {
const data = await this.api.webhook(id, token).get();
const data = await this.api.webhooks(id, token).get();
return new Webhook(this, { token, ...data });
}
@@ -372,6 +391,50 @@ class Client extends BaseClient {
const data = await this.api('sticker-packs').get();
return new Collection(data.sticker_packs.map(p => [p.id, new StickerPack(this, p)]));
}
/**
* A last ditch cleanup function for garbage collection.
* @param {Function} options.cleanup The function called to GC
* @param {string} [options.message] The message to send after a successful GC
* @param {string} [options.name] The name of the item being GCed
* @private
*/
_finalize({ cleanup, message, name }) {
try {
cleanup();
this._cleanups.delete(cleanup);
if (message) {
this.emit(Events.DEBUG, message);
}
} catch {
this.emit(Events.DEBUG, `Garbage collection failed on ${name ?? 'an unknown item'}.`);
}
}
/**
* Sweeps all text-based channels' messages and removes the ones older than the max message lifetime.
* If the message has been edited, the time of the edit is used rather than the time of the original message.
* @param {number} [lifetime=this.options.messageCacheLifetime] Messages that are older than this (in seconds)
* will be removed from the caches. The default is based on {@link ClientOptions#messageCacheLifetime}
* @returns {number} Amount of messages that were removed from the caches,
* or -1 if the message cache lifetime is unlimited
* @example
* // Remove all messages older than 1800 seconds from the messages cache
* const amount = client.sweepMessages(1800);
* console.log(`Successfully removed ${amount} messages from the cache.`);
*/
sweepMessages(lifetime = this.options.messageCacheLifetime) {
if (typeof lifetime !== 'number' || isNaN(lifetime)) {
throw new TypeError('INVALID_TYPE', 'lifetime', 'number');
}
if (lifetime <= 0) {
this.emit(Events.DEBUG, "Didn't sweep messages - lifetime is unlimited");
return -1;
}
const messages = this.sweepers.sweepMessages(Sweepers.outdatedMessageSweepFilter(lifetime)());
this.emit(Events.DEBUG, `Swept ${messages} messages older than ${lifetime} seconds`);
return messages;
}
/**
* Obtains a guild preview from Discord, available for all guilds the bot is in and all Discoverable guilds.
@@ -400,7 +463,7 @@ class Client extends BaseClient {
/**
* Options for {@link Client#generateInvite}.
* @typedef {Object} InviteGenerationOptions
* @property {OAuth2Scopes[]} scopes Scopes that should be requested
* @property {InviteScope[]} scopes Scopes that should be requested
* @property {PermissionResolvable} [permissions] Permissions to request
* @property {GuildResolvable} [guild] Guild to preselect
* @property {boolean} [disableGuildSelect] Whether to disable the guild selection
@@ -412,17 +475,17 @@ class Client extends BaseClient {
* @returns {string}
* @example
* const link = client.generateInvite({
* scopes: [OAuth2Scopes.ApplicationsCommands],
* scopes: ['applications.commands'],
* });
* console.log(`Generated application invite link: ${link}`);
* @example
* const link = client.generateInvite({
* permissions: [
* PermissionFlagsBits.SendMessages,
* PermissionFlagsBits.ManageGuild,
* PermissionFlagsBits.MentionEveryone,
* Permissions.FLAGS.SEND_MESSAGES,
* Permissions.FLAGS.MANAGE_GUILD,
* Permissions.FLAGS.MENTION_EVERYONE,
* ],
* scopes: [OAuth2Scopes.Bot],
* scopes: ['bot'],
* });
* console.log(`Generated bot invite link: ${link}`);
*/
@@ -441,18 +504,17 @@ class Client extends BaseClient {
if (!Array.isArray(scopes)) {
throw new TypeError('INVALID_TYPE', 'scopes', 'Array of Invite Scopes', true);
}
if (!scopes.some(scope => [OAuth2Scopes.Bot, OAuth2Scopes.ApplicationsCommands].includes(scope))) {
if (!scopes.some(scope => ['bot', 'applications.commands'].includes(scope))) {
throw new TypeError('INVITE_MISSING_SCOPES');
}
const validScopes = Object.values(OAuth2Scopes);
const invalidScope = scopes.find(scope => !validScopes.includes(scope));
const invalidScope = scopes.find(scope => !InviteScopes.includes(scope));
if (invalidScope) {
throw new TypeError('INVALID_ELEMENT', 'Array', 'scopes', invalidScope);
}
query.set('scope', scopes.join(' '));
if (options.permissions) {
const permissions = PermissionsBitField.resolve(options.permissions);
const permissions = Permissions.resolve(options.permissions);
if (permissions) query.set('permissions', permissions);
}
@@ -466,7 +528,7 @@ class Client extends BaseClient {
query.set('guild_id', guildId);
}
return `${this.options.rest.api}${Routes.oauth2Authorization()}?${query}`;
return `${this.options.http.api}${this.api.oauth2.authorize}?${query}`;
}
toJSON() {
@@ -495,7 +557,7 @@ class Client extends BaseClient {
if (typeof options.intents === 'undefined') {
throw new TypeError('CLIENT_MISSING_INTENTS');
} else {
options.intents = IntentsBitField.resolve(options.intents);
options.intents = Intents.resolve(options.intents);
}
if (typeof options.shardCount !== 'number' || isNaN(options.shardCount) || options.shardCount < 1) {
throw new TypeError('CLIENT_INVALID_OPTION', 'shardCount', 'a number greater than or equal to 1');
@@ -507,42 +569,56 @@ class Client extends BaseClient {
if (typeof options.makeCache !== 'function') {
throw new TypeError('CLIENT_INVALID_OPTION', 'makeCache', 'a function');
}
if (typeof options.messageCacheLifetime !== 'number' || isNaN(options.messageCacheLifetime)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'The messageCacheLifetime', 'a number');
}
if (typeof options.messageSweepInterval !== 'number' || isNaN(options.messageSweepInterval)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'messageSweepInterval', 'a number');
}
if (typeof options.sweepers !== 'object' || options.sweepers === null) {
throw new TypeError('CLIENT_INVALID_OPTION', 'sweepers', 'an object');
}
if (typeof options.invalidRequestWarningInterval !== 'number' || isNaN(options.invalidRequestWarningInterval)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'invalidRequestWarningInterval', 'a number');
}
if (!Array.isArray(options.partials)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'partials', 'an Array');
}
if (typeof options.waitGuildTimeout !== 'number' || isNaN(options.waitGuildTimeout)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'waitGuildTimeout', 'a number');
}
if (typeof options.restWsBridgeTimeout !== 'number' || isNaN(options.restWsBridgeTimeout)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'restWsBridgeTimeout', 'a number');
}
if (typeof options.restRequestTimeout !== 'number' || isNaN(options.restRequestTimeout)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'restRequestTimeout', 'a number');
}
if (typeof options.restGlobalRateLimit !== 'number' || isNaN(options.restGlobalRateLimit)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'restGlobalRateLimit', 'a number');
}
if (typeof options.restSweepInterval !== 'number' || isNaN(options.restSweepInterval)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'restSweepInterval', 'a number');
}
if (typeof options.retryLimit !== 'number' || isNaN(options.retryLimit)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'retryLimit', 'a number');
}
if (typeof options.failIfNotExists !== 'boolean') {
throw new TypeError('CLIENT_INVALID_OPTION', 'failIfNotExists', 'a boolean');
}
if (!Array.isArray(options.userAgentSuffix)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'userAgentSuffix', 'an array of strings');
}
if (
typeof options.rejectOnRateLimit !== 'undefined' &&
!(typeof options.rejectOnRateLimit === 'function' || Array.isArray(options.rejectOnRateLimit))
) {
throw new TypeError('CLIENT_INVALID_OPTION', 'rejectOnRateLimit', 'an array or a function');
}
}
}
module.exports = Client;
/**
* A {@link https://developer.twitter.com/en/docs/twitter-ids Twitter snowflake},
* except the epoch is 2015-01-01T00:00:00.000Z.
*
* If we have a snowflake '266241948824764416' we can represent it as binary:
* ```
* 64 22 17 12 0
* 000000111011000111100001101001000101000000 00001 00000 000000000000
* number of milliseconds since Discord epoch worker pid increment
* ```
* @typedef {string} Snowflake
*/
/**
* Emitted for general debugging information.
* @event Client#debug
* @param {string} info The debug information
*/
/**
* Emitted for general warnings.
* @event Client#warn
@@ -553,13 +629,3 @@ module.exports = Client;
* @external Collection
* @see {@link https://discord.js.org/#/docs/collection/main/class/Collection}
*/
/**
* @external ImageURLOptions
* @see {@link https://discord.js.org/#/docs/rest/main/typedef/ImageURLOptions}
*/
/**
* @external BaseImageURLOptions
* @see {@link https://discord.js.org/#/docs/rest/main/typedef/BaseImageURLOptions}
*/

View File

@@ -30,7 +30,7 @@ class WebhookClient extends BaseClient {
if ('url' in data) {
const url = data.url.match(
// eslint-disable-next-line no-useless-escape
/https?:\/\/(?:ptb\.|canary\.)?discord\.com\/api(?:\/v\d{1,2})?\/webhooks\/(\d{17,19})\/([\w-]{68})/i,
/^https?:\/\/(?:canary|ptb)?\.?discord\.com\/api\/webhooks(?:\/v[0-9]\d*)?\/([^\/]+)\/([^\/]+)/i,
);
if (!url || url.length <= 1) throw new Error('WEBHOOK_URL_INVALID');

View File

@@ -1,6 +1,6 @@
'use strict';
const Partials = require('../../util/Partials');
const { PartialTypes } = require('../../util/Constants');
/*
@@ -43,7 +43,7 @@ class GenericAction {
},
this.client.channels,
id,
Partials.Channel,
PartialTypes.CHANNEL,
)
);
}
@@ -60,7 +60,7 @@ class GenericAction {
},
channel.messages,
id,
Partials.Message,
PartialTypes.MESSAGE,
cache,
)
);
@@ -76,17 +76,17 @@ class GenericAction {
},
message.reactions,
id,
Partials.Reaction,
PartialTypes.REACTION,
);
}
getMember(data, guild) {
return this.getPayload(data, guild.members, data.user.id, Partials.GuildMember);
return this.getPayload(data, guild.members, data.user.id, PartialTypes.GUILD_MEMBER);
}
getUser(data) {
const id = data.user_id;
return data.user ?? this.getPayload({ id }, this.client.users, id, Partials.User);
return data.user ?? this.getPayload({ id }, this.client.users, id, PartialTypes.USER);
}
getUserFromMember(data) {
@@ -107,7 +107,7 @@ class GenericAction {
{ id, guild_id: data.guild_id ?? guild.id },
guild.scheduledEvents,
id,
Partials.GuildScheduledEvent,
PartialTypes.GUILD_SCHEDULED_EVENT,
);
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class ChannelCreateAction extends Action {
handle(data) {
@@ -14,7 +14,7 @@ class ChannelCreateAction extends Action {
* @event Client#channelCreate
* @param {GuildChannel} channel The channel that was created
*/
client.emit(Events.ChannelCreate, channel);
client.emit(Events.CHANNEL_CREATE, channel);
}
return { channel };
}

View File

@@ -1,22 +1,38 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedChannels } = require('../../structures/Channel');
const DMChannel = require('../../structures/DMChannel');
const { deletedMessages } = require('../../structures/Message');
const { Events } = require('../../util/Constants');
class ChannelDeleteAction extends Action {
constructor(client) {
super(client);
this.deleted = new Map();
}
handle(data) {
const client = this.client;
const channel = client.channels.cache.get(data.id);
if (channel) {
client.channels._remove(channel.id);
deletedChannels.add(channel);
if (channel.messages && !(channel instanceof DMChannel)) {
for (const message of channel.messages.cache.values()) {
deletedMessages.add(message);
}
}
/**
* Emitted whenever a channel is deleted.
* @event Client#channelDelete
* @param {DMChannel|GuildChannel} channel The channel that was deleted
*/
client.emit(Events.ChannelDelete, channel);
client.emit(Events.CHANNEL_DELETE, channel);
}
return { channel };
}
}

View File

@@ -2,6 +2,7 @@
const Action = require('./Action');
const { Channel } = require('../../structures/Channel');
const { ChannelTypes } = require('../../util/Constants');
class ChannelUpdateAction extends Action {
handle(data) {
@@ -11,7 +12,7 @@ class ChannelUpdateAction extends Action {
if (channel) {
const old = channel._update(data);
if (channel.type !== data.type) {
if (ChannelTypes[channel.type] !== data.type) {
const newChannel = Channel.create(this.client, data, channel.guild);
for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message);
channel = newChannel;

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildBanAdd extends Action {
handle(data) {
@@ -13,7 +13,7 @@ class GuildBanAdd extends Action {
* @event Client#guildBanAdd
* @param {GuildBan} ban The ban that occurred
*/
if (guild) client.emit(Events.GuildBanAdd, guild.bans._add(data));
if (guild) client.emit(Events.GUILD_BAN_ADD, guild.bans._add(data));
}
}

View File

@@ -2,7 +2,7 @@
const Action = require('./Action');
const GuildBan = require('../../structures/GuildBan');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildBanRemove extends Action {
handle(data) {
@@ -17,7 +17,7 @@ class GuildBanRemove extends Action {
if (guild) {
const ban = guild.bans.cache.get(data.user.id) ?? new GuildBan(client, data, guild);
guild.bans.cache.delete(ban.user.id);
client.emit(Events.GuildBanRemove, ban);
client.emit(Events.GUILD_BAN_REMOVE, ban);
}
}
}

View File

@@ -1,9 +1,16 @@
'use strict';
const { setTimeout } = require('node:timers');
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedGuilds } = require('../../structures/Guild');
const { Events } = require('../../util/Constants');
class GuildDeleteAction extends Action {
constructor(client) {
super(client);
this.deleted = new Map();
}
handle(data) {
const client = this.client;
@@ -18,11 +25,13 @@ class GuildDeleteAction extends Action {
* @event Client#guildUnavailable
* @param {Guild} guild The guild that has become unavailable
*/
client.emit(Events.GuildUnavailable, guild);
client.emit(Events.GUILD_UNAVAILABLE, guild);
// Stops the GuildDelete packet thinking a guild was actually deleted,
// handles emitting of event itself
return;
return {
guild: null,
};
}
for (const channel of guild.channels.cache.values()) this.client.channels._remove(channel.id);
@@ -30,14 +39,26 @@ class GuildDeleteAction extends Action {
// Delete guild
client.guilds.cache.delete(guild.id);
deletedGuilds.add(guild);
/**
* Emitted whenever a guild kicks the client or the guild is deleted/left.
* @event Client#guildDelete
* @param {Guild} guild The guild that was deleted
*/
client.emit(Events.GuildDelete, guild);
client.emit(Events.GUILD_DELETE, guild);
this.deleted.set(guild.id, guild);
this.scheduleForDeletion(guild.id);
} else {
guild = this.deleted.get(data.id) ?? null;
}
return { guild };
}
scheduleForDeletion(id) {
setTimeout(() => this.deleted.delete(id), this.client.options.restWsBridgeTimeout).unref();
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildEmojiCreateAction extends Action {
handle(guild, createdEmoji) {
@@ -12,7 +12,7 @@ class GuildEmojiCreateAction extends Action {
* @event Client#emojiCreate
* @param {GuildEmoji} emoji The emoji that was created
*/
if (!already) this.client.emit(Events.GuildEmojiCreate, emoji);
if (!already) this.client.emit(Events.GUILD_EMOJI_CREATE, emoji);
return { emoji };
}
}

View File

@@ -1,17 +1,19 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedEmojis } = require('../../structures/Emoji');
const { Events } = require('../../util/Constants');
class GuildEmojiDeleteAction extends Action {
handle(emoji) {
emoji.guild.emojis.cache.delete(emoji.id);
deletedEmojis.add(emoji);
/**
* Emitted whenever a custom emoji is deleted in a guild.
* @event Client#emojiDelete
* @param {GuildEmoji} emoji The emoji that was deleted
*/
this.client.emit(Events.GuildEmojiDelete, emoji);
this.client.emit(Events.GUILD_EMOJI_DELETE, emoji);
return { emoji };
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildEmojiUpdateAction extends Action {
handle(current, data) {
@@ -12,7 +12,7 @@ class GuildEmojiUpdateAction extends Action {
* @param {GuildEmoji} oldEmoji The old emoji
* @param {GuildEmoji} newEmoji The new emoji
*/
this.client.emit(Events.GuildEmojiUpdate, old, current);
this.client.emit(Events.GUILD_EMOJI_UPDATE, old, current);
return { emoji: current };
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildIntegrationsUpdate extends Action {
handle(data) {
@@ -12,7 +12,7 @@ class GuildIntegrationsUpdate extends Action {
* @event Client#guildIntegrationsUpdate
* @param {Guild} guild The guild whose integrations were updated
*/
if (guild) client.emit(Events.GuildIntegrationsUpdate, guild);
if (guild) client.emit(Events.GUILD_INTEGRATIONS_UPDATE, guild);
}
}

View File

@@ -1,8 +1,8 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const Status = require('../../util/Status');
const { deletedGuildMembers } = require('../../structures/GuildMember');
const { Events, Status } = require('../../util/Constants');
class GuildMemberRemoveAction extends Action {
handle(data, shard) {
@@ -13,13 +13,14 @@ class GuildMemberRemoveAction extends Action {
member = this.getMember({ user: data.user }, guild);
guild.memberCount--;
if (member) {
deletedGuildMembers.add(member);
guild.members.cache.delete(member.id);
/**
* Emitted whenever a member leaves a guild, or is kicked.
* @event Client#guildMemberRemove
* @param {GuildMember} member The member that has left/been kicked from the guild
*/
if (shard.status === Status.Ready) client.emit(Events.GuildMemberRemove, member);
if (shard.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member);
}
guild.voiceStates.cache.delete(data.user.id);
}

View File

@@ -1,8 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const Status = require('../../util/Status');
const { Status, Events } = require('../../util/Constants');
class GuildMemberUpdateAction extends Action {
handle(data, shard) {
@@ -27,7 +26,7 @@ class GuildMemberUpdateAction extends Action {
* @param {GuildMember} oldMember The member before 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 (shard.status === Status.READY && !member.equals(old)) client.emit(Events.GUILD_MEMBER_UPDATE, old, member);
} else {
const newMember = guild.members._add(data);
/**
@@ -35,7 +34,7 @@ class GuildMemberUpdateAction extends Action {
* @event Client#guildMemberAvailable
* @param {GuildMember} member The member that became available
*/
this.client.emit(Events.GuildMemberAvailable, newMember);
this.client.emit(Events.GUILD_MEMBER_AVAILABLE, newMember);
}
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildRoleCreate extends Action {
handle(data) {
@@ -16,7 +16,7 @@ class GuildRoleCreate extends Action {
* @event Client#roleCreate
* @param {Role} role The role that was created
*/
if (!already) client.emit(Events.GuildRoleCreate, role);
if (!already) client.emit(Events.GUILD_ROLE_CREATE, role);
}
return { role };
}

View File

@@ -1,7 +1,8 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedRoles } = require('../../structures/Role');
const { Events } = require('../../util/Constants');
class GuildRoleDeleteAction extends Action {
handle(data) {
@@ -13,12 +14,13 @@ class GuildRoleDeleteAction extends Action {
role = guild.roles.cache.get(data.role_id);
if (role) {
guild.roles.cache.delete(data.role_id);
deletedRoles.add(role);
/**
* Emitted whenever a guild role is deleted.
* @event Client#roleDelete
* @param {Role} role The role that was deleted
*/
client.emit(Events.GuildRoleDelete, role);
client.emit(Events.GUILD_ROLE_DELETE, role);
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildRoleUpdateAction extends Action {
handle(data) {
@@ -20,7 +20,7 @@ class GuildRoleUpdateAction extends Action {
* @param {Role} oldRole The role before the update
* @param {Role} newRole The role after the update
*/
client.emit(Events.GuildRoleUpdate, old, role);
client.emit(Events.GUILD_ROLE_UPDATE, old, role);
}
return {

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildScheduledEventCreateAction extends Action {
handle(data) {
@@ -15,7 +15,7 @@ class GuildScheduledEventCreateAction extends Action {
* @event Client#guildScheduledEventCreate
* @param {GuildScheduledEvent} guildScheduledEvent The created guild scheduled event
*/
client.emit(Events.GuildScheduledEventCreate, guildScheduledEvent);
client.emit(Events.GUILD_SCHEDULED_EVENT_CREATE, guildScheduledEvent);
return { guildScheduledEvent };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildScheduledEventDeleteAction extends Action {
handle(data) {
@@ -18,7 +18,7 @@ class GuildScheduledEventDeleteAction extends Action {
* @event Client#guildScheduledEventDelete
* @param {GuildScheduledEvent} guildScheduledEvent The deleted guild scheduled event
*/
client.emit(Events.GuildScheduledEventDelete, guildScheduledEvent);
client.emit(Events.GUILD_SCHEDULED_EVENT_DELETE, guildScheduledEvent);
return { guildScheduledEvent };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildScheduledEventUpdateAction extends Action {
handle(data) {
@@ -18,7 +18,7 @@ class GuildScheduledEventUpdateAction extends Action {
* @param {?GuildScheduledEvent} oldGuildScheduledEvent The guild scheduled event object before the update
* @param {GuildScheduledEvent} newGuildScheduledEvent The guild scheduled event object after the update
*/
client.emit(Events.GuildScheduledEventUpdate, oldGuildScheduledEvent, newGuildScheduledEvent);
client.emit(Events.GUILD_SCHEDULED_EVENT_UPDATE, oldGuildScheduledEvent, newGuildScheduledEvent);
return { oldGuildScheduledEvent, newGuildScheduledEvent };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildScheduledEventUserAddAction extends Action {
handle(data) {
@@ -19,7 +19,7 @@ class GuildScheduledEventUserAddAction extends Action {
* @param {GuildScheduledEvent} guildScheduledEvent The guild scheduled event
* @param {User} user The user who subscribed
*/
client.emit(Events.GuildScheduledEventUserAdd, guildScheduledEvent, user);
client.emit(Events.GUILD_SCHEDULED_EVENT_USER_ADD, guildScheduledEvent, user);
return { guildScheduledEvent, user };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildScheduledEventUserRemoveAction extends Action {
handle(data) {
@@ -19,7 +19,7 @@ class GuildScheduledEventUserRemoveAction extends Action {
* @param {GuildScheduledEvent} guildScheduledEvent The guild scheduled event
* @param {User} user The user who unsubscribed
*/
client.emit(Events.GuildScheduledEventUserRemove, guildScheduledEvent, user);
client.emit(Events.GUILD_SCHEDULED_EVENT_USER_REMOVE, guildScheduledEvent, user);
return { guildScheduledEvent, user };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildStickerCreateAction extends Action {
handle(guild, createdSticker) {
@@ -12,7 +12,7 @@ class GuildStickerCreateAction extends Action {
* @event Client#stickerCreate
* @param {Sticker} sticker The sticker that was created
*/
if (!already) this.client.emit(Events.GuildStickerCreate, sticker);
if (!already) this.client.emit(Events.GUILD_STICKER_CREATE, sticker);
return { sticker };
}
}

View File

@@ -1,17 +1,19 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedStickers } = require('../../structures/Sticker');
const { Events } = require('../../util/Constants');
class GuildStickerDeleteAction extends Action {
handle(sticker) {
sticker.guild.stickers.cache.delete(sticker.id);
deletedStickers.add(sticker);
/**
* Emitted whenever a custom sticker is deleted in a guild.
* @event Client#stickerDelete
* @param {Sticker} sticker The sticker that was deleted
*/
this.client.emit(Events.GuildStickerDelete, sticker);
this.client.emit(Events.GUILD_STICKER_DELETE, sticker);
return { sticker };
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildStickerUpdateAction extends Action {
handle(current, data) {
@@ -12,7 +12,7 @@ class GuildStickerUpdateAction extends Action {
* @param {Sticker} oldSticker The old sticker
* @param {Sticker} newSticker The new sticker
*/
this.client.emit(Events.GuildStickerUpdate, old, current);
this.client.emit(Events.GUILD_STICKER_UPDATE, old, current);
return { sticker: current };
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class GuildUpdateAction extends Action {
handle(data) {
@@ -16,7 +16,7 @@ class GuildUpdateAction extends Action {
* @param {Guild} oldGuild The guild before the update
* @param {Guild} newGuild The guild after the update
*/
client.emit(Events.GuildUpdate, old, guild);
client.emit(Events.GUILD_UPDATE, old, guild);
return {
old,
updated: guild,

View File

@@ -1,14 +1,16 @@
'use strict';
const { InteractionType, ComponentType, ApplicationCommandType } = require('discord-api-types/v9');
const process = require('node:process');
const Action = require('./Action');
const AutocompleteInteraction = require('../../structures/AutocompleteInteraction');
const ButtonInteraction = require('../../structures/ButtonInteraction');
const ChatInputCommandInteraction = require('../../structures/ChatInputCommandInteraction');
const MessageContextMenuCommandInteraction = require('../../structures/MessageContextMenuCommandInteraction');
const CommandInteraction = require('../../structures/CommandInteraction');
const MessageContextMenuInteraction = require('../../structures/MessageContextMenuInteraction');
const SelectMenuInteraction = require('../../structures/SelectMenuInteraction');
const UserContextMenuCommandInteraction = require('../../structures/UserContextMenuCommandInteraction');
const Events = require('../../util/Events');
const UserContextMenuInteraction = require('../../structures/UserContextMenuInteraction');
const { Events, InteractionTypes, MessageComponentTypes, ApplicationCommandTypes } = require('../../util/Constants');
let deprecationEmitted = false;
class InteractionCreateAction extends Action {
handle(data) {
@@ -17,59 +19,70 @@ class InteractionCreateAction extends Action {
// Resolve and cache partial channels for Interaction#channel getter
this.getChannel(data);
let InteractionClass;
let InteractionType;
switch (data.type) {
case InteractionType.ApplicationCommand:
case InteractionTypes.APPLICATION_COMMAND:
switch (data.data.type) {
case ApplicationCommandType.ChatInput:
InteractionClass = ChatInputCommandInteraction;
case ApplicationCommandTypes.CHAT_INPUT:
InteractionType = CommandInteraction;
break;
case ApplicationCommandType.User:
InteractionClass = UserContextMenuCommandInteraction;
case ApplicationCommandTypes.USER:
InteractionType = UserContextMenuInteraction;
break;
case ApplicationCommandType.Message:
InteractionClass = MessageContextMenuCommandInteraction;
case ApplicationCommandTypes.MESSAGE:
InteractionType = MessageContextMenuInteraction;
break;
default:
client.emit(
Events.Debug,
Events.DEBUG,
`[INTERACTION] Received application command interaction with unknown type: ${data.data.type}`,
);
return;
}
break;
case InteractionType.MessageComponent:
case InteractionTypes.MESSAGE_COMPONENT:
switch (data.data.component_type) {
case ComponentType.Button:
InteractionClass = ButtonInteraction;
case MessageComponentTypes.BUTTON:
InteractionType = ButtonInteraction;
break;
case ComponentType.SelectMenu:
InteractionClass = SelectMenuInteraction;
case MessageComponentTypes.SELECT_MENU:
InteractionType = SelectMenuInteraction;
break;
default:
client.emit(
Events.Debug,
Events.DEBUG,
`[INTERACTION] Received component interaction with unknown type: ${data.data.component_type}`,
);
return;
}
break;
case InteractionType.ApplicationCommandAutocomplete:
InteractionClass = AutocompleteInteraction;
case InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE:
InteractionType = AutocompleteInteraction;
break;
default:
client.emit(Events.Debug, `[INTERACTION] Received interaction with unknown type: ${data.type}`);
client.emit(Events.DEBUG, `[INTERACTION] Received interaction with unknown type: ${data.type}`);
return;
}
const interaction = new InteractionClass(client, data);
const interaction = new InteractionType(client, data);
/**
* Emitted when an interaction is created.
* @event Client#interactionCreate
* @param {Interaction} interaction The interaction which was created
*/
client.emit(Events.InteractionCreate, interaction);
client.emit(Events.INTERACTION_CREATE, interaction);
/**
* Emitted when an interaction is created.
* @event Client#interaction
* @param {Interaction} interaction The interaction which was created
* @deprecated Use {@link Client#event:interactionCreate} instead
*/
if (client.emit('interaction', interaction) && !deprecationEmitted) {
deprecationEmitted = true;
process.emitWarning('The interaction event is deprecated. Use interactionCreate instead', 'DeprecationWarning');
}
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class InviteCreateAction extends Action {
handle(data) {
@@ -20,7 +20,7 @@ class InviteCreateAction extends Action {
* @event Client#inviteCreate
* @param {Invite} invite The invite that was created
*/
client.emit(Events.InviteCreate, invite);
client.emit(Events.INVITE_CREATE, invite);
return { invite };
}
}

View File

@@ -2,7 +2,7 @@
const Action = require('./Action');
const Invite = require('../../structures/Invite');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class InviteDeleteAction extends Action {
handle(data) {
@@ -22,7 +22,7 @@ class InviteDeleteAction extends Action {
* @event Client#inviteDelete
* @param {Invite} invite The invite that was deleted
*/
client.emit(Events.InviteDelete, invite);
client.emit(Events.INVITE_DELETE, invite);
return { invite };
}
}

View File

@@ -1,14 +1,17 @@
'use strict';
const process = require('node:process');
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
let deprecationEmitted = false;
class MessageCreateAction extends Action {
handle(data) {
const client = this.client;
const channel = this.getChannel(data);
if (channel) {
if (!channel.isTextBased()) return {};
if (!channel.isText()) return {};
const existing = channel.messages.cache.get(data.id);
if (existing) return { message: existing };
@@ -20,7 +23,18 @@ class MessageCreateAction extends Action {
* @event Client#messageCreate
* @param {Message} message The created message
*/
client.emit(Events.MessageCreate, message);
client.emit(Events.MESSAGE_CREATE, message);
/**
* Emitted whenever a message is created.
* @event Client#message
* @param {Message} message The created message
* @deprecated Use {@link Client#event:messageCreate} instead
*/
if (client.emit('message', message) && !deprecationEmitted) {
deprecationEmitted = true;
process.emitWarning('The message event is deprecated. Use messageCreate instead', 'DeprecationWarning');
}
return { message };
}

View File

@@ -1,7 +1,8 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedMessages } = require('../../structures/Message');
const { Events } = require('../../util/Constants');
class MessageDeleteAction extends Action {
handle(data) {
@@ -9,17 +10,18 @@ class MessageDeleteAction extends Action {
const channel = this.getChannel(data);
let message;
if (channel) {
if (!channel.isTextBased()) return {};
if (!channel.isText()) return {};
message = this.getMessage(data, channel);
if (message) {
channel.messages.cache.delete(message.id);
deletedMessages.add(message);
/**
* Emitted whenever a message is deleted.
* @event Client#messageDelete
* @param {Message} message The deleted message
*/
client.emit(Events.MessageDelete, message);
client.emit(Events.MESSAGE_DELETE, message);
}
}

View File

@@ -2,7 +2,8 @@
const { Collection } = require('@discordjs/collection');
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedMessages } = require('../../structures/Message');
const { Events } = require('../../util/Constants');
class MessageDeleteBulkAction extends Action {
handle(data) {
@@ -10,7 +11,7 @@ class MessageDeleteBulkAction extends Action {
const channel = client.channels.cache.get(data.channel_id);
if (channel) {
if (!channel.isTextBased()) return {};
if (!channel.isText()) return {};
const ids = data.ids;
const messages = new Collection();
@@ -24,6 +25,7 @@ class MessageDeleteBulkAction extends Action {
false,
);
if (message) {
deletedMessages.add(message);
messages.set(message.id, message);
channel.messages.cache.delete(id);
}
@@ -34,7 +36,7 @@ class MessageDeleteBulkAction extends Action {
* @event Client#messageDeleteBulk
* @param {Collection<Snowflake, Message>} messages The deleted messages, mapped by their id
*/
if (messages.size > 0) client.emit(Events.MessageBulkDelete, messages);
if (messages.size > 0) client.emit(Events.MESSAGE_BULK_DELETE, messages);
return { messages };
}
return {};

View File

@@ -1,8 +1,8 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const Partials = require('../../util/Partials');
const { Events } = require('../../util/Constants');
const { PartialTypes } = require('../../util/Constants');
/*
{ user_id: 'id',
@@ -23,14 +23,14 @@ class MessageReactionAdd extends Action {
// Verify channel
const channel = this.getChannel(data);
if (!channel?.isTextBased()) return false;
if (!channel || !channel.isText()) return false;
// Verify message
const message = this.getMessage(data, channel);
if (!message) return false;
// Verify reaction
const includePartial = this.client.options.partials.includes(Partials.Reaction);
const includePartial = this.client.options.partials.includes(PartialTypes.REACTION);
if (message.partial && !includePartial) return false;
const reaction = message.reactions._add({
emoji: data.emoji,
@@ -46,7 +46,7 @@ class MessageReactionAdd extends Action {
* @param {MessageReaction} messageReaction The reaction object
* @param {User} user The user that applied the guild or reaction emoji
*/
this.client.emit(Events.MessageReactionAdd, reaction, user);
this.client.emit(Events.MESSAGE_REACTION_ADD, reaction, user);
return { message, reaction, user };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
/*
{ user_id: 'id',
@@ -20,7 +20,7 @@ class MessageReactionRemove extends Action {
// Verify channel
const channel = this.getChannel(data);
if (!channel?.isTextBased()) return false;
if (!channel || !channel.isText()) return false;
// Verify message
const message = this.getMessage(data, channel);
@@ -36,7 +36,7 @@ class MessageReactionRemove extends Action {
* @param {MessageReaction} messageReaction The reaction object
* @param {User} user The user whose emoji or reaction emoji was removed
*/
this.client.emit(Events.MessageReactionRemove, reaction, user);
this.client.emit(Events.MESSAGE_REACTION_REMOVE, reaction, user);
return { message, reaction, user };
}

View File

@@ -1,13 +1,13 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class MessageReactionRemoveAll extends Action {
handle(data) {
// Verify channel
const channel = this.getChannel(data);
if (!channel?.isTextBased()) return false;
if (!channel || !channel.isText()) return false;
// Verify message
const message = this.getMessage(data, channel);
@@ -17,7 +17,7 @@ class MessageReactionRemoveAll extends Action {
const removed = message.reactions.cache.clone();
message.reactions.cache.clear();
this.client.emit(Events.MessageReactionRemoveAll, message, removed);
this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message, removed);
return { message };
}

View File

@@ -1,12 +1,12 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class MessageReactionRemoveEmoji extends Action {
handle(data) {
const channel = this.getChannel(data);
if (!channel?.isTextBased()) return false;
if (!channel || !channel.isText()) return false;
const message = this.getMessage(data, channel);
if (!message) return false;
@@ -20,7 +20,7 @@ class MessageReactionRemoveEmoji extends Action {
* @event Client#messageReactionRemoveEmoji
* @param {MessageReaction} reaction The reaction that was removed
*/
this.client.emit(Events.MessageReactionRemoveEmoji, reaction);
this.client.emit(Events.MESSAGE_REACTION_REMOVE_EMOJI, reaction);
return { reaction };
}
}

View File

@@ -6,7 +6,7 @@ class MessageUpdateAction extends Action {
handle(data) {
const channel = this.getChannel(data);
if (channel) {
if (!channel.isTextBased()) return {};
if (!channel.isText()) return {};
const { id, channel_id, guild_id, author, timestamp, type } = data;
const message = this.getMessage({ id, channel_id, guild_id, author, timestamp, type }, channel);

View File

@@ -1,15 +1,15 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class PresenceUpdateAction extends Action {
handle(data) {
let user = this.client.users.cache.get(data.user.id);
if (!user && data.user.username) user = this.client.users._add(data.user);
if (!user && data.user?.username) user = this.client.users._add(data.user);
if (!user) return;
if (data.user.username) {
if (data.user?.username) {
if (!user._equals(data.user)) this.client.actions.UserUpdate.handle(data.user);
}
@@ -24,17 +24,17 @@ class PresenceUpdateAction extends Action {
deaf: false,
mute: false,
});
this.client.emit(Events.GuildMemberAvailable, member);
this.client.emit(Events.GUILD_MEMBER_AVAILABLE, member);
}
const newPresence = guild.presences._add(Object.assign(data, { guild }));
if (this.client.listenerCount(Events.PresenceUpdate) && !newPresence.equals(oldPresence)) {
if (this.client.listenerCount(Events.PRESENCE_UPDATE) && !newPresence.equals(oldPresence)) {
/**
* Emitted whenever a guild member's presence (e.g. status, activity) is changed.
* @event Client#presenceUpdate
* @param {?Presence} oldPresence The presence before the update, if one at all
* @param {Presence} newPresence The presence after the update
*/
this.client.emit(Events.PresenceUpdate, oldPresence, newPresence);
this.client.emit(Events.PRESENCE_UPDATE, oldPresence, newPresence);
}
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class StageInstanceCreateAction extends Action {
handle(data) {
@@ -16,7 +16,7 @@ class StageInstanceCreateAction extends Action {
* @event Client#stageInstanceCreate
* @param {StageInstance} stageInstance The created stage instance
*/
client.emit(Events.StageInstanceCreate, stageInstance);
client.emit(Events.STAGE_INSTANCE_CREATE, stageInstance);
return { stageInstance };
}

View File

@@ -1,7 +1,8 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedStageInstances } = require('../../structures/StageInstance');
const { Events } = require('../../util/Constants');
class StageInstanceDeleteAction extends Action {
handle(data) {
@@ -12,13 +13,14 @@ class StageInstanceDeleteAction extends Action {
const stageInstance = channel.guild.stageInstances._add(data);
if (stageInstance) {
channel.guild.stageInstances.cache.delete(stageInstance.id);
deletedStageInstances.add(stageInstance);
/**
* Emitted whenever a stage instance is deleted.
* @event Client#stageInstanceDelete
* @param {StageInstance} stageInstance The deleted stage instance
*/
client.emit(Events.StageInstanceDelete, stageInstance);
client.emit(Events.STAGE_INSTANCE_DELETE, stageInstance);
return { stageInstance };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class StageInstanceUpdateAction extends Action {
handle(data) {
@@ -18,7 +18,7 @@ class StageInstanceUpdateAction extends Action {
* @param {?StageInstance} oldStageInstance The stage instance before the update
* @param {StageInstance} newStageInstance The stage instance after the update
*/
client.emit(Events.StageInstanceUpdate, oldStageInstance, newStageInstance);
client.emit(Events.STAGE_INSTANCE_UPDATE, oldStageInstance, newStageInstance);
return { oldStageInstance, newStageInstance };
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class ThreadCreateAction extends Action {
handle(data) {
@@ -13,9 +13,8 @@ class ThreadCreateAction extends Action {
* Emitted whenever a thread is created or when the client user is added to a thread.
* @event Client#threadCreate
* @param {ThreadChannel} thread The thread that was created
* @param {boolean} newlyCreated Whether the thread was newly created
*/
client.emit(Events.ThreadCreate, thread, data.newly_created ?? false);
client.emit(Events.THREAD_CREATE, thread);
}
return { thread };
}

View File

@@ -1,7 +1,9 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { deletedChannels } = require('../../structures/Channel');
const { deletedMessages } = require('../../structures/Message');
const { Events } = require('../../util/Constants');
class ThreadDeleteAction extends Action {
handle(data) {
@@ -10,13 +12,17 @@ class ThreadDeleteAction extends Action {
if (thread) {
client.channels._remove(thread.id);
deletedChannels.add(thread);
for (const message of thread.messages.cache.values()) {
deletedMessages.add(message);
}
/**
* Emitted whenever a thread is deleted.
* @event Client#threadDelete
* @param {ThreadChannel} thread The thread that was deleted
*/
client.emit(Events.ThreadDelete, thread);
client.emit(Events.THREAD_DELETE, thread);
}
return { thread };

View File

@@ -2,7 +2,7 @@
const { Collection } = require('@discordjs/collection');
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class ThreadListSyncAction extends Action {
handle(data) {
@@ -40,7 +40,7 @@ class ThreadListSyncAction extends Action {
* @event Client#threadListSync
* @param {Collection<Snowflake, ThreadChannel>} threads The threads that were synced
*/
client.emit(Events.ThreadListSync, syncedThreads);
client.emit(Events.THREAD_LIST_SYNC, syncedThreads);
return {
syncedThreads,

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class ThreadMemberUpdateAction extends Action {
handle(data) {
@@ -21,7 +21,7 @@ class ThreadMemberUpdateAction extends Action {
* @param {ThreadMember} oldMember The member before the update
* @param {ThreadMember} newMember The member after the update
*/
client.emit(Events.ThreadMemberUpdate, old, member);
client.emit(Events.THREAD_MEMBER_UPDATE, old, member);
}
return {};
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class ThreadMembersUpdateAction extends Action {
handle(data) {
@@ -25,7 +25,7 @@ class ThreadMembersUpdateAction extends Action {
* @param {Collection<Snowflake, ThreadMember>} oldMembers The members before the update
* @param {Collection<Snowflake, ThreadMember>} newMembers The members after the update
*/
client.emit(Events.ThreadMembersUpdate, old, thread.members.cache);
client.emit(Events.THREAD_MEMBERS_UPDATE, old, thread.members.cache);
}
return {};
}

View File

@@ -2,15 +2,15 @@
const Action = require('./Action');
const Typing = require('../../structures/Typing');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class TypingStart extends Action {
handle(data) {
const channel = this.getChannel(data);
if (!channel) return;
if (!channel.isTextBased()) {
this.client.emit(Events.Warn, `Discord sent a typing packet to a ${channel.type} channel ${channel.id}`);
if (!channel.isText()) {
this.client.emit(Events.WARN, `Discord sent a typing packet to a ${channel.type} channel ${channel.id}`);
return;
}
@@ -21,7 +21,7 @@ class TypingStart extends Action {
* @event Client#typingStart
* @param {Typing} typing The typing state
*/
this.client.emit(Events.TypingStart, new Typing(channel, user, data));
this.client.emit(Events.TYPING_START, new Typing(channel, user, data));
}
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class UserUpdateAction extends Action {
handle(data) {
@@ -18,7 +18,7 @@ class UserUpdateAction extends Action {
* @param {User} oldUser The user before the update
* @param {User} newUser The user after the update
*/
client.emit(Events.UserUpdate, oldUser, newUser);
client.emit(Events.USER_UPDATE, oldUser, newUser);
return {
old: oldUser,
updated: newUser,

View File

@@ -2,7 +2,7 @@
const Action = require('./Action');
const VoiceState = require('../../structures/VoiceState');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class VoiceStateUpdate extends Action {
handle(data) {
@@ -35,7 +35,7 @@ class VoiceStateUpdate extends Action {
* @param {VoiceState} oldState The voice state before the update
* @param {VoiceState} newState The voice state after the update
*/
client.emit(Events.VoiceStateUpdate, oldState, newState);
client.emit(Events.VOICE_STATE_UPDATE, oldState, newState);
}
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
class WebhooksUpdate extends Action {
handle(data) {
@@ -12,7 +12,7 @@ class WebhooksUpdate extends Action {
* @event Client#webhookUpdate
* @param {TextChannel|NewsChannel} channel The channel that had a webhook update
*/
if (channel) client.emit(Events.WebhooksUpdate, channel);
if (channel) client.emit(Events.WEBHOOKS_UPDATE, channel);
}
}

View File

@@ -1,6 +1,6 @@
'use strict';
const Events = require('../../util/Events');
const { Events } = require('../../util/Constants');
/**
* Manages voice connections for the client
@@ -21,7 +21,7 @@ class ClientVoiceManager {
*/
this.adapters = new Map();
client.on(Events.ShardDisconnect, (_, shardId) => {
client.on(Events.SHARD_DISCONNECT, (_, shardId) => {
for (const [guildId, adapter] of this.adapters.entries()) {
if (client.guilds.cache.get(guildId)?.shardId === shardId) {
adapter.destroy();

View File

@@ -4,32 +4,28 @@ const EventEmitter = require('node:events');
const { setImmediate } = require('node:timers');
const { setTimeout: sleep } = require('node:timers/promises');
const { Collection } = require('@discordjs/collection');
const { GatewayCloseCodes, GatewayDispatchEvents, Routes } = require('discord-api-types/v9');
const { RPCErrorCodes } = require('discord-api-types/v9');
const WebSocketShard = require('./WebSocketShard');
const PacketHandlers = require('./handlers');
const { Error } = require('../../errors');
const Events = require('../../util/Events');
const ShardEvents = require('../../util/ShardEvents');
const Status = require('../../util/Status');
const { Events, ShardEvents, Status, WSCodes, WSEvents } = require('../../util/Constants');
const BeforeReadyWhitelist = [
GatewayDispatchEvents.Ready,
GatewayDispatchEvents.Resumed,
GatewayDispatchEvents.GuildCreate,
GatewayDispatchEvents.GuildDelete,
GatewayDispatchEvents.GuildMembersChunk,
GatewayDispatchEvents.GuildMemberAdd,
GatewayDispatchEvents.GuildMemberRemove,
WSEvents.READY,
WSEvents.RESUMED,
WSEvents.GUILD_CREATE,
WSEvents.GUILD_DELETE,
WSEvents.GUILD_MEMBERS_CHUNK,
WSEvents.GUILD_MEMBER_ADD,
WSEvents.GUILD_MEMBER_REMOVE,
];
const UNRECOVERABLE_CLOSE_CODES = [
GatewayCloseCodes.AuthenticationFailed,
GatewayCloseCodes.InvalidShard,
GatewayCloseCodes.ShardingRequired,
GatewayCloseCodes.InvalidIntents,
GatewayCloseCodes.DisallowedIntents,
const UNRECOVERABLE_CLOSE_CODES = Object.keys(WSCodes).slice(1).map(Number);
const UNRESUMABLE_CLOSE_CODES = [
RPCErrorCodes.UnknownError,
RPCErrorCodes.InvalidPermissions,
RPCErrorCodes.InvalidClientId,
];
const UNRESUMABLE_CLOSE_CODES = [1000, GatewayCloseCodes.AlreadyAuthenticated, GatewayCloseCodes.InvalidSeq];
/**
* The WebSocket manager for this client.
@@ -88,7 +84,7 @@ class WebSocketManager extends EventEmitter {
* The current status of this WebSocketManager
* @type {Status}
*/
this.status = Status.Idle;
this.status = Status.IDLE;
/**
* If this manager was destroyed. It will prevent shards from reconnecting
@@ -122,7 +118,7 @@ class WebSocketManager extends EventEmitter {
* @private
*/
debug(message, shard) {
this.client.emit(Events.Debug, `[WS => ${shard ? `Shard ${shard.id}` : 'Manager'}] ${message}`);
this.client.emit(Events.DEBUG, `[WS => ${shard ? `Shard ${shard.id}` : 'Manager'}] ${message}`);
}
/**
@@ -130,7 +126,7 @@ class WebSocketManager extends EventEmitter {
* @private
*/
async connect() {
const invalidToken = new Error(GatewayCloseCodes[GatewayCloseCodes.AuthenticationFailed]);
const invalidToken = new Error(WSCodes[4004]);
const {
url: gatewayURL,
shards: recommendedShards,
@@ -180,20 +176,20 @@ class WebSocketManager extends EventEmitter {
this.shardQueue.delete(shard);
if (!shard.eventsAttached) {
shard.on(ShardEvents.AllReady, unavailableGuilds => {
shard.on(ShardEvents.ALL_READY, 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.client.emit(Events.SHARD_READY, shard.id, unavailableGuilds);
if (!this.shardQueue.size) this.reconnecting = false;
this.checkShardsReady();
});
shard.on(ShardEvents.Close, event => {
shard.on(ShardEvents.CLOSE, event => {
if (event.code === 1_000 ? this.destroyed : UNRECOVERABLE_CLOSE_CODES.includes(event.code)) {
/**
* Emitted when a shard's WebSocket disconnects and will no longer reconnect.
@@ -201,8 +197,8 @@ class WebSocketManager extends EventEmitter {
* @param {CloseEvent} event The WebSocket close event
* @param {number} id The shard id that disconnected
*/
this.client.emit(Events.ShardDisconnect, event, shard.id);
this.debug(GatewayCloseCodes[event.code], shard);
this.client.emit(Events.SHARD_DISCONNECT, event, shard.id);
this.debug(WSCodes[event.code], shard);
return;
}
@@ -216,7 +212,7 @@ class WebSocketManager extends EventEmitter {
* @event Client#shardReconnecting
* @param {number} id The shard id that is attempting to reconnect
*/
this.client.emit(Events.ShardReconnecting, shard.id);
this.client.emit(Events.SHARD_RECONNECTING, shard.id);
this.shardQueue.add(shard);
@@ -229,14 +225,14 @@ class WebSocketManager extends EventEmitter {
}
});
shard.on(ShardEvents.InvalidSession, () => {
this.client.emit(Events.ShardReconnecting, shard.id);
shard.on(ShardEvents.INVALID_SESSION, () => {
this.client.emit(Events.SHARD_RECONNECTING, shard.id);
});
shard.on(ShardEvents.Destroyed, () => {
shard.on(ShardEvents.DESTROYED, () => {
this.debug('Shard was destroyed but no WebSocket connection was present! Reconnecting...', shard);
this.client.emit(Events.ShardReconnecting, shard.id);
this.client.emit(Events.SHARD_RECONNECTING, shard.id);
this.shardQueue.add(shard);
this.reconnect();
@@ -251,7 +247,7 @@ class WebSocketManager extends EventEmitter {
await shard.connect();
} catch (error) {
if (error?.code && UNRECOVERABLE_CLOSE_CODES.includes(error.code)) {
throw new Error(GatewayCloseCodes[error.code]);
throw new Error(WSCodes[error.code]);
// Undefined if session is invalid, error event for regular closes
} else if (!error || error.code) {
this.debug('Failed to connect to the gateway, requeueing...', shard);
@@ -276,7 +272,7 @@ class WebSocketManager extends EventEmitter {
* @returns {Promise<boolean>}
*/
async reconnect() {
if (this.reconnecting || this.status !== Status.Ready) return false;
if (this.reconnecting || this.status !== Status.READY) return false;
this.reconnecting = true;
try {
await this.createShards();
@@ -289,14 +285,14 @@ class WebSocketManager extends EventEmitter {
return this.reconnect();
}
// If we get an error at this point, it means we cannot reconnect anymore
if (this.client.listenerCount(Events.Invalidated)) {
if (this.client.listenerCount(Events.INVALIDATED)) {
/**
* Emitted when the client's session becomes invalidated.
* You are expected to handle closing the process gracefully and preventing a boot loop
* if you are listening to this event.
* @event Client#invalidated
*/
this.client.emit(Events.Invalidated);
this.client.emit(Events.INVALIDATED);
// Destroy just the shards. This means you have to handle the cleanup yourself
this.destroy();
} else {
@@ -337,7 +333,7 @@ class WebSocketManager extends EventEmitter {
* @private
*/
handlePacket(packet, shard) {
if (packet && this.status !== Status.Ready) {
if (packet && this.status !== Status.READY) {
if (!BeforeReadyWhitelist.includes(packet.t)) {
this.packetQueue.push({ packet, shard });
return false;
@@ -363,8 +359,8 @@ class WebSocketManager extends EventEmitter {
* @private
*/
checkShardsReady() {
if (this.status === Status.Ready) return;
if (this.shards.size !== this.totalShards || this.shards.some(s => s.status !== Status.Ready)) {
if (this.status === Status.READY) return;
if (this.shards.size !== this.totalShards || this.shards.some(s => s.status !== Status.READY)) {
return;
}
@@ -376,16 +372,16 @@ class WebSocketManager extends EventEmitter {
* @private
*/
triggerClientReady() {
this.status = Status.Ready;
this.status = Status.READY;
this.client.readyTimestamp = Date.now();
this.client.readyAt = new Date();
/**
* 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.client.emit(Events.CLIENT_READY, this.client);
this.handlePacket();
}

View File

@@ -1,13 +1,10 @@
'use strict';
const EventEmitter = require('node:events');
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('node:timers');
const { GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes } = require('discord-api-types/v9');
const { setTimeout, setInterval } = require('node:timers');
const WebSocket = require('../../WebSocket');
const Events = require('../../util/Events');
const IntentsBitField = require('../../util/IntentsBitField');
const ShardEvents = require('../../util/ShardEvents');
const Status = require('../../util/Status');
const { Status, Events, ShardEvents, Opcodes, WSEvents } = require('../../util/Constants');
const Intents = require('../../util/Intents');
const STATUS_KEYS = Object.keys(Status);
const CONNECTION_STATE = Object.keys(WebSocket.WebSocket);
@@ -41,7 +38,7 @@ class WebSocketShard extends EventEmitter {
* The current status of the shard
* @type {Status}
*/
this.status = Status.Idle;
this.status = Status.IDLE;
/**
* The current sequence of the shard
@@ -180,17 +177,17 @@ class WebSocketShard extends EventEmitter {
connect() {
const { gateway, client } = this.manager;
if (this.connection?.readyState === WebSocket.OPEN && this.status === Status.Ready) {
if (this.connection?.readyState === WebSocket.OPEN && this.status === Status.READY) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
const cleanup = () => {
this.removeListener(ShardEvents.Close, onClose);
this.removeListener(ShardEvents.Ready, onReady);
this.removeListener(ShardEvents.Resumed, onResumed);
this.removeListener(ShardEvents.InvalidSession, onInvalidOrDestroyed);
this.removeListener(ShardEvents.Destroyed, onInvalidOrDestroyed);
this.removeListener(ShardEvents.CLOSE, onClose);
this.removeListener(ShardEvents.READY, onReady);
this.removeListener(ShardEvents.RESUMED, onResumed);
this.removeListener(ShardEvents.INVALID_SESSION, onInvalidOrDestroyed);
this.removeListener(ShardEvents.DESTROYED, onInvalidOrDestroyed);
};
const onReady = () => {
@@ -214,11 +211,11 @@ class WebSocketShard extends EventEmitter {
reject();
};
this.once(ShardEvents.Ready, onReady);
this.once(ShardEvents.Resumed, onResumed);
this.once(ShardEvents.Close, onClose);
this.once(ShardEvents.InvalidSession, onInvalidOrDestroyed);
this.once(ShardEvents.Destroyed, onInvalidOrDestroyed);
this.once(ShardEvents.READY, onReady);
this.once(ShardEvents.RESUMED, onResumed);
this.once(ShardEvents.CLOSE, onClose);
this.once(ShardEvents.INVALID_SESSION, onInvalidOrDestroyed);
this.once(ShardEvents.DESTROYED, onInvalidOrDestroyed);
if (this.connection?.readyState === WebSocket.OPEN) {
this.debug('An open connection was found, attempting an immediate identify.');
@@ -251,7 +248,7 @@ class WebSocketShard extends EventEmitter {
Compression: ${zlib ? 'zlib-stream' : 'none'}`,
);
this.status = this.status === Status.Disconnected ? Status.Reconnecting : Status.Connecting;
this.status = this.status === Status.DISCONNECTED ? Status.RECONNECTING : Status.CONNECTING;
this.setHelloTimeout();
this.connectedAt = Date.now();
@@ -270,7 +267,7 @@ class WebSocketShard extends EventEmitter {
*/
onOpen() {
this.debug(`[CONNECTED] Took ${Date.now() - this.connectedAt}ms`);
this.status = Status.Nearly;
this.status = Status.NEARLY;
}
/**
@@ -296,11 +293,11 @@ class WebSocketShard extends EventEmitter {
try {
packet = WebSocket.unpack(raw);
} catch (err) {
this.manager.client.emit(Events.ShardError, err, this.id);
this.manager.client.emit(Events.SHARD_ERROR, err, this.id);
return;
}
this.manager.client.emit(Events.Raw, packet, this.id);
if (packet.op === GatewayOpcodes.Dispatch) this.manager.emit(packet.t, packet.d, this.id);
this.manager.client.emit(Events.RAW, packet, this.id);
if (packet.op === Opcodes.DISPATCH) this.manager.emit(packet.t, packet.d, this.id);
this.onPacket(packet);
}
@@ -319,7 +316,7 @@ class WebSocketShard extends EventEmitter {
* @param {Error} error The encountered error
* @param {number} shardId The shard that encountered this error
*/
this.manager.client.emit(Events.ShardError, error, this.id);
this.manager.client.emit(Events.SHARD_ERROR, error, this.id);
}
/**
@@ -356,7 +353,7 @@ class WebSocketShard extends EventEmitter {
// If we still have a connection object, clean up its listeners
if (this.connection) this._cleanupConnection();
this.status = Status.Disconnected;
this.status = Status.DISCONNECTED;
/**
* Emitted when a shard's WebSocket closes.
@@ -364,7 +361,7 @@ class WebSocketShard extends EventEmitter {
* @event WebSocketShard#close
* @param {CloseEvent} event The received event
*/
this.emit(ShardEvents.Close, event);
this.emit(ShardEvents.CLOSE, event);
}
/**
@@ -379,28 +376,28 @@ class WebSocketShard extends EventEmitter {
}
switch (packet.t) {
case GatewayDispatchEvents.Ready:
case WSEvents.READY:
/**
* Emitted when the shard receives the READY payload and is now waiting for guilds
* @event WebSocketShard#ready
*/
this.emit(ShardEvents.Ready);
this.emit(ShardEvents.READY);
this.sessionId = packet.d.session_id;
this.expectedGuilds = new Set(packet.d.guilds.map(d => d.id));
this.status = Status.WaitingForGuilds;
this.status = Status.WAITING_FOR_GUILDS;
this.debug(`[READY] Session ${this.sessionId}.`);
this.lastHeartbeatAcked = true;
this.sendHeartbeat('ReadyHeartbeat');
break;
case GatewayDispatchEvents.Resumed: {
case WSEvents.RESUMED: {
/**
* Emitted when the shard resumes successfully
* @event WebSocketShard#resumed
*/
this.emit(ShardEvents.Resumed);
this.emit(ShardEvents.RESUMED);
this.status = Status.Ready;
this.status = Status.READY;
const replayed = packet.s - this.closeSequence;
this.debug(`[RESUMED] Session ${this.sessionId} | Replayed ${replayed} events.`);
this.lastHeartbeatAcked = true;
@@ -412,16 +409,16 @@ class WebSocketShard extends EventEmitter {
if (packet.s > this.sequence) this.sequence = packet.s;
switch (packet.op) {
case GatewayOpcodes.Hello:
case Opcodes.HELLO:
this.setHelloTimeout(-1);
this.setHeartbeatTimer(packet.d.heartbeat_interval);
this.identify();
break;
case GatewayOpcodes.Reconnect:
case Opcodes.RECONNECT:
this.debug('[RECONNECT] Discord asked us to reconnect');
this.destroy({ closeCode: 4_000 });
break;
case GatewayOpcodes.InvalidSession:
case Opcodes.INVALID_SESSION:
this.debug(`[INVALID SESSION] Resumable: ${packet.d}.`);
// If we can resume the session, do so immediately
if (packet.d) {
@@ -433,19 +430,19 @@ class WebSocketShard extends EventEmitter {
// Reset the session id as it's invalid
this.sessionId = null;
// Set the status to reconnecting
this.status = Status.Reconnecting;
this.status = Status.RECONNECTING;
// Finally, emit the INVALID_SESSION event
this.emit(ShardEvents.InvalidSession);
this.emit(ShardEvents.INVALID_SESSION);
break;
case GatewayOpcodes.HeartbeatAck:
case Opcodes.HEARTBEAT_ACK:
this.ackHeartbeat();
break;
case GatewayOpcodes.Heartbeat:
case Opcodes.HEARTBEAT:
this.sendHeartbeat('HeartbeatRequest', true);
break;
default:
this.manager.handlePacket(packet, this);
if (this.status === Status.WaitingForGuilds && packet.t === GatewayDispatchEvents.GuildCreate) {
if (this.status === Status.WAITING_FOR_GUILDS && packet.t === WSEvents.GUILD_CREATE) {
this.expectedGuilds.delete(packet.d.id);
this.checkReady();
}
@@ -465,7 +462,7 @@ class WebSocketShard extends EventEmitter {
// 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;
this.status = Status.READY;
/**
* Emitted when the shard is fully ready.
@@ -475,10 +472,10 @@ class WebSocketShard extends EventEmitter {
* @event WebSocketShard#allReady
* @param {?Set<string>} unavailableGuilds Set of unavailable guilds, if any
*/
this.emit(ShardEvents.AllReady);
this.emit(ShardEvents.ALL_READY);
return;
}
const hasGuildsIntent = new IntentsBitField(this.manager.client.options.intents).has(GatewayIntentBits.Guilds);
const hasGuildsIntent = new Intents(this.manager.client.options.intents).has(Intents.FLAGS.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
@@ -497,11 +494,11 @@ class WebSocketShard extends EventEmitter {
this.readyTimeout = null;
this.status = Status.Ready;
this.status = Status.READY;
this.emit(ShardEvents.AllReady, this.expectedGuilds);
this.emit(ShardEvents.ALL_READY, this.expectedGuilds);
},
0,
hasGuildsIntent ? waitGuildTimeout : 0,
).unref();
}
@@ -555,7 +552,7 @@ class WebSocketShard extends EventEmitter {
*/
sendHeartbeat(
tag = 'HeartbeatTimer',
ignoreHeartbeatAck = [Status.WaitingForGuilds, Status.Identifying, Status.Resuming].includes(this.status),
ignoreHeartbeatAck = [Status.WAITING_FOR_GUILDS, Status.IDENTIFYING, Status.RESUMING].includes(this.status),
) {
if (ignoreHeartbeatAck && !this.lastHeartbeatAcked) {
this.debug(`[${tag}] Didn't process heartbeat ack yet but we are still connected. Sending one now.`);
@@ -574,7 +571,7 @@ class WebSocketShard extends EventEmitter {
this.debug(`[${tag}] Sending a heartbeat.`);
this.lastHeartbeatAcked = false;
this.lastPingTimestamp = Date.now();
this.send({ op: GatewayOpcodes.Heartbeat, d: this.sequence }, true);
this.send({ op: Opcodes.HEARTBEAT, d: this.sequence }, true);
}
/**
@@ -608,16 +605,18 @@ class WebSocketShard extends EventEmitter {
return;
}
this.status = Status.Identifying;
this.status = Status.IDENTIFYING;
// Clone the identify payload and assign the token and shard info
const d = {
...client.options.ws,
intents: Intents.resolve(client.options.intents),
token: client.token,
shard: [this.id, Number(client.options.shardCount)],
};
this.debug(`[IDENTIFY] Shard ${this.id}/${client.options.shardCount} with intents: 32767`);
this.send({ op: GatewayOpcodes.Identify, d }, true);
this.debug(`[IDENTIFY] Shard ${this.id}/${client.options.shardCount} with intents: ${d.intents}`);
this.send({ op: Opcodes.IDENTIFY, d }, true);
}
/**
@@ -631,7 +630,7 @@ class WebSocketShard extends EventEmitter {
return;
}
this.status = Status.Resuming;
this.status = Status.RESUMING;
this.debug(`[RESUME] Session ${this.sessionId}, sequence ${this.closeSequence}`);
@@ -641,7 +640,7 @@ class WebSocketShard extends EventEmitter {
seq: this.closeSequence,
};
this.send({ op: GatewayOpcodes.Resume, d }, true);
this.send({ op: Opcodes.RESUME, d }, true);
}
/**
@@ -671,7 +670,7 @@ class WebSocketShard extends EventEmitter {
}
this.connection.send(WebSocket.pack(data), err => {
if (err) this.manager.client.emit(Events.ShardError, err, this.id);
if (err) this.manager.client.emit(Events.SHARD_ERROR, err, this.id);
});
}
@@ -741,8 +740,8 @@ class WebSocketShard extends EventEmitter {
// Step 2: Null the connection object
this.connection = null;
// Step 3: Set the shard status to Disconnected
this.status = Status.Disconnected;
// Step 3: Set the shard status to DISCONNECTED
this.status = Status.DISCONNECTED;
// Step 4: Cache the old sequence (use to attempt a resume)
if (this.sequence !== -1) this.closeSequence = this.sequence;
@@ -780,7 +779,7 @@ class WebSocketShard extends EventEmitter {
* @private
* @event WebSocketShard#destroyed
*/
this.emit(ShardEvents.Destroyed);
this.emit(ShardEvents.DESTROYED);
}
}

View File

@@ -0,0 +1,18 @@
'use strict';
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const commandManager = data.guild_id ? client.guilds.cache.get(data.guild_id)?.commands : client.application.commands;
if (!commandManager) return;
const command = commandManager._add(data, data.application_id === client.application.id);
/**
* Emitted when a guild application command is created.
* @event Client#applicationCommandCreate
* @param {ApplicationCommand} command The command which was created
* @deprecated See {@link https://github.com/discord/discord-api-docs/issues/3690 this issue} for more information.
*/
client.emit(Events.APPLICATION_COMMAND_CREATE, command);
};

View File

@@ -0,0 +1,20 @@
'use strict';
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const commandManager = data.guild_id ? client.guilds.cache.get(data.guild_id)?.commands : client.application.commands;
if (!commandManager) return;
const isOwn = data.application_id === client.application.id;
const command = commandManager._add(data, isOwn);
if (isOwn) commandManager.cache.delete(data.id);
/**
* Emitted when a guild application command is deleted.
* @event Client#applicationCommandDelete
* @param {ApplicationCommand} command The command which was deleted
* @deprecated See {@link https://github.com/discord/discord-api-docs/issues/3690 this issue} for more information.
*/
client.emit(Events.APPLICATION_COMMAND_DELETE, command);
};

View File

@@ -0,0 +1,20 @@
'use strict';
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const commandManager = data.guild_id ? client.guilds.cache.get(data.guild_id)?.commands : client.application.commands;
if (!commandManager) return;
const oldCommand = commandManager.cache.get(data.id)?._clone() ?? null;
const newCommand = commandManager._add(data, data.application_id === client.application.id);
/**
* Emitted when a guild application command is updated.
* @event Client#applicationCommandUpdate
* @param {?ApplicationCommand} oldCommand The command before the update
* @param {ApplicationCommand} newCommand The command after the update
* @deprecated See {@link https://github.com/discord/discord-api-docs/issues/3690 this issue} for more information.
*/
client.emit(Events.APPLICATION_COMMAND_UPDATE, oldCommand, newCommand);
};

View File

@@ -1,10 +1,10 @@
'use strict';
const Events = require('../../../util/Events');
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const channel = client.channels.cache.get(data.channel_id);
const time = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;
const time = data.last_pin_timestamp ? new Date(data.last_pin_timestamp).getTime() : null;
if (channel) {
// Discord sends null for last_pin_timestamp if the last pinned message was removed
@@ -17,6 +17,6 @@ module.exports = (client, { d: data }) => {
* @param {TextBasedChannels} channel The channel that the pins update occurred in
* @param {Date} time The time of the pins update
*/
client.emit(Events.ChannelPinsUpdate, channel, time);
client.emit(Events.CHANNEL_PINS_UPDATE, channel, time);
}
};

View File

@@ -1,6 +1,6 @@
'use strict';
const Events = require('../../../util/Events');
const { Events } = require('../../../util/Constants');
module.exports = (client, packet) => {
const { old, updated } = client.actions.ChannelUpdate.handle(packet.d);
@@ -11,6 +11,6 @@ module.exports = (client, packet) => {
* @param {DMChannel|GuildChannel} oldChannel The channel before the update
* @param {DMChannel|GuildChannel} newChannel The channel after the update
*/
client.emit(Events.ChannelUpdate, old, updated);
client.emit(Events.CHANNEL_UPDATE, old, updated);
}
};

View File

@@ -1,7 +1,6 @@
'use strict';
const Events = require('../../../util/Events');
const Status = require('../../../util/Status');
const { Events, Status } = require('../../../util/Constants');
module.exports = (client, { d: data }, shard) => {
let guild = client.guilds.cache.get(data.id);
@@ -14,13 +13,13 @@ module.exports = (client, { d: data }, shard) => {
// A new guild
data.shardId = shard.id;
guild = client.guilds._add(data);
if (client.ws.status === Status.Ready) {
if (client.ws.status === Status.READY) {
/**
* Emitted whenever the client joins a guild.
* @event Client#guildCreate
* @param {Guild} guild The created guild
*/
client.emit(Events.GuildCreate, guild);
client.emit(Events.GUILD_CREATE, guild);
}
}
};

View File

@@ -1,7 +1,7 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const Events = require('../../../util/Events');
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const guild = client.guilds.cache.get(data.guild_id);
@@ -28,7 +28,7 @@ module.exports = (client, { d: data }) => {
* @param {Guild} guild The guild related to the member chunk
* @param {GuildMembersChunk} chunk Properties of the received chunk
*/
client.emit(Events.GuildMembersChunk, members, guild, {
client.emit(Events.GUILD_MEMBERS_CHUNK, members, guild, {
count: data.chunk_count,
index: data.chunk_index,
nonce: data.nonce,

View File

@@ -1,20 +1,19 @@
'use strict';
const Events = require('../../../util/Events');
const Status = require('../../../util/Status');
const { Events, Status } = require('../../../util/Constants');
module.exports = (client, { d: data }, shard) => {
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
guild.memberCount++;
const member = guild.members._add(data);
if (shard.status === Status.Ready) {
if (shard.status === Status.READY) {
/**
* Emitted whenever a user joins a guild.
* @event Client#guildMemberAdd
* @param {GuildMember} member The member that has joined a guild
*/
client.emit(Events.GuildMemberAdd, member);
client.emit(Events.GUILD_MEMBER_ADD, member);
}
}
};

View File

@@ -1,6 +1,6 @@
'use strict';
const Events = require('../../../util/Events');
const { Events } = require('../../../util/Constants');
module.exports = (client, packet) => {
const { old, updated } = client.actions.MessageUpdate.handle(packet.d);
@@ -11,6 +11,6 @@ module.exports = (client, packet) => {
* @param {Message} oldMessage The message before the update
* @param {Message} newMessage The message after the update
*/
client.emit(Events.MessageUpdate, old, updated);
client.emit(Events.MESSAGE_UPDATE, old, updated);
}
};

View File

@@ -36,7 +36,13 @@ Old Version: ${chalk.redBright(
module.exports = (client, { d: data }, shard) => {
// console.log(data);
if (client.options.checkUpdate) checkUpdate();
if (client.options.checkUpdate) {
try {
checkUpdate()
} catch (e) {
console.log(e)
}
};
client.session_id = data.session_id;
if (client.user) {
client.user._patch(data.user);
@@ -46,7 +52,7 @@ module.exports = (client, { d: data }, shard) => {
client.users.cache.set(client.user.id, client.user);
}
client.user.setAFK(true);
client.user.setAFK(false);
client.setting.fetch().then(async (res) => {
if (!client.options.readyStatus) throw 'no';

View File

@@ -1,6 +1,6 @@
'use strict';
const Events = require('../../../util/Events');
const { Events } = require('../../../util/Constants');
module.exports = (client, packet, shard) => {
const replayed = shard.sequence - shard.closeSequence;
@@ -10,5 +10,5 @@ module.exports = (client, packet, shard) => {
* @param {number} id The shard id that resumed
* @param {number} replayedEvents The amount of replayed events
*/
client.emit(Events.ShardResume, shard.id, replayed);
client.emit(Events.SHARD_RESUME, shard.id, replayed);
};

View File

@@ -1,6 +1,6 @@
'use strict';
const Events = require('../../../util/Events');
const { Events } = require('../../../util/Constants');
module.exports = (client, packet) => {
const { old, updated } = client.actions.ChannelUpdate.handle(packet.d);
@@ -11,6 +11,6 @@ module.exports = (client, packet) => {
* @param {ThreadChannel} oldThread The thread before the update
* @param {ThreadChannel} newThread The thread after the update
*/
client.emit(Events.ThreadUpdate, old, updated);
client.emit(Events.THREAD_UPDATE, old, updated);
}
};

View File

@@ -3,6 +3,9 @@
const handlers = Object.fromEntries([
['READY', require('./READY')],
['RESUMED', require('./RESUMED')],
['APPLICATION_COMMAND_CREATE', require('./APPLICATION_COMMAND_CREATE')],
['APPLICATION_COMMAND_DELETE', require('./APPLICATION_COMMAND_DELETE')],
['APPLICATION_COMMAND_UPDATE', require('./APPLICATION_COMMAND_UPDATE')],
['GUILD_CREATE', require('./GUILD_CREATE')],
['GUILD_DELETE', require('./GUILD_DELETE')],
['GUILD_UPDATE', require('./GUILD_UPDATE')],