This commit is contained in:
Elysia 2024-01-14 09:10:25 +07:00
parent 14b76367bc
commit 39a74b22dc
9 changed files with 380 additions and 1201 deletions

View File

@ -2,7 +2,7 @@
const { Presence } = require('./Presence'); const { Presence } = require('./Presence');
const { TypeError } = require('../errors'); const { TypeError } = require('../errors');
const { Opcodes, ActivityTypes } = require('../util/Constants'); const { ActivityTypes, Opcodes } = require('../util/Constants');
const CustomStatusActivityTypes = [ActivityTypes.CUSTOM, ActivityTypes[ActivityTypes.CUSTOM]]; const CustomStatusActivityTypes = [ActivityTypes.CUSTOM, ActivityTypes[ActivityTypes.CUSTOM]];
@ -22,7 +22,6 @@ class ClientPresence extends Presence {
*/ */
set(presence) { set(presence) {
const packet = this._parse(presence); const packet = this._parse(presence);
// Parse with custom class
this._patch(packet, true); this._patch(packet, true);
if (typeof presence.shardId === 'undefined') { if (typeof presence.shardId === 'undefined') {
this.client.ws.broadcast({ op: Opcodes.STATUS_UPDATE, d: packet }); this.client.ws.broadcast({ op: Opcodes.STATUS_UPDATE, d: packet });
@ -33,8 +32,6 @@ class ClientPresence extends Presence {
} else { } else {
this.client.ws.shards.get(presence.shardId).send({ op: Opcodes.STATUS_UPDATE, d: packet }); this.client.ws.shards.get(presence.shardId).send({ op: Opcodes.STATUS_UPDATE, d: packet });
} }
// Parse with default class
// this._patch(packet, false);
return this; return this;
} }
@ -48,14 +45,13 @@ class ClientPresence extends Presence {
const data = { const data = {
activities: [], activities: [],
afk: typeof afk === 'boolean' ? afk : false, afk: typeof afk === 'boolean' ? afk : false,
since: 0, since: typeof since === 'number' && !Number.isNaN(since) ? since : null,
status: status ?? this.status, status: status ?? this.status,
}; };
if (activities?.length) { if (activities?.length) {
for (const [i, activity] of activities.entries()) { for (const [i, activity] of activities.entries()) {
if (![ActivityTypes.CUSTOM, 'CUSTOM'].includes(activity.type) && typeof activity.name !== 'string') { if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string');
throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string');
}
activity.type ??= ActivityTypes.PLAYING; activity.type ??= ActivityTypes.PLAYING;
if (CustomStatusActivityTypes.includes(activity.type) && !activity.state) { if (CustomStatusActivityTypes.includes(activity.type) && !activity.state) {

View File

@ -3,19 +3,24 @@
const { setInterval } = require('node:timers'); const { setInterval } = require('node:timers');
const { Collection } = require('@discordjs/collection'); const { Collection } = require('@discordjs/collection');
const Invite = require('./Invite'); const Invite = require('./Invite');
const { Message } = require('./Message');
const User = require('./User'); const User = require('./User');
const { Util } = require('..');
const { Error: Error_ } = require('../errors');
const { Opcodes, NitroType, HypeSquadType } = require('../util/Constants');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const PremiumUsageFlags = require('../util/PremiumUsageFlags'); const PremiumUsageFlags = require('../util/PremiumUsageFlags');
const PurchasedFlags = require('../util/PurchasedFlags'); const PurchasedFlags = require('../util/PurchasedFlags');
const Util = require('../util/Util');
/** /**
* Represents the logged in client's Discord user. * Represents the logged in client's Discord user.
* @extends {User} * @extends {User}
*/ */
class ClientUser extends User { class ClientUser extends User {
#packageName = null;
#intervalSamsungPresence = setInterval(() => {
this.client.emit('debug', `[UPDATE] Samsung Presence: ${this.#packageName}`);
if (!this.#packageName) return;
this.setSamsungActivity(this.#packageName, 'UPDATE');
}, 1000 * 60 * 10).unref();
_patch(data) { _patch(data) {
super._patch(data); super._patch(data);
@ -29,7 +34,7 @@ class ClientUser extends User {
if ('mfa_enabled' in data) { if ('mfa_enabled' in data) {
/** /**
* If the bot's {@link ClientApplication#owner Owner} has MFA enabled on their account * If the bot's {@link Application#owner Owner} has MFA enabled on their account
* @type {?boolean} * @type {?boolean}
*/ */
this.mfaEnabled = typeof data.mfa_enabled === 'boolean' ? data.mfa_enabled : null; this.mfaEnabled = typeof data.mfa_enabled === 'boolean' ? data.mfa_enabled : null;
@ -39,16 +44,6 @@ class ClientUser extends User {
if ('token' in data) this.client.token = data.token; if ('token' in data) this.client.token = data.token;
// Todo: Add (Selfbot)
if ('premium_type' in data) {
const nitro = NitroType[data.premium_type ?? 0];
/**
* Nitro type of the client user.
* @type {NitroType}
*/
this.nitroType = nitro ?? `UNKNOWN_TYPE_${data.premium_type}`;
}
if ('purchased_flags' in data) { if ('purchased_flags' in data) {
/** /**
* Purchased state of the client user. * Purchased state of the client user.
@ -70,7 +65,7 @@ class ClientUser extends User {
* Phone number of the client user. * Phone number of the client user.
* @type {?string} * @type {?string}
*/ */
this.phoneNumber = data.phone; this.phone = data.phone;
} }
if ('nsfw_allowed' in data) { if ('nsfw_allowed' in data) {
@ -86,48 +81,35 @@ class ClientUser extends User {
* Email address of the client user. * Email address of the client user.
* @type {?string} * @type {?string}
*/ */
this.emailAddress = data.email; this.email = data.email;
} }
if ('bio' in data) { if ('bio' in data) {
/**
* About me (User)
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?string}
*/
this.bio = data.bio; this.bio = data.bio;
} }
if ('pronouns' in data) { if ('pronouns' in data) {
/**
* Pronouns (User)
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?string}
*/
this.pronouns = data.pronouns; this.pronouns = data.pronouns;
} }
if (!this.friendNicknames?.size) { if ('premium_type' in data) {
/** /**
* The friend nicknames cache of the client user. * Premium types denote the level of premium a user has.
* @type {Collection<Snowflake, string>} * @type {number}
* @private * @see {@link https://discord-userdoccers.vercel.app/resources/user#premium-type}
*/ */
this.friendNicknames = new Collection(); this.premiumType = data.premium_type;
} }
if (!this._intervalSamsungPresence) {
this._intervalSamsungPresence = setInterval(() => {
this.client.emit('debug', `Samsung Presence: ${this._packageName}`);
if (!this._packageName) return;
this.setSamsungActivity(this._packageName, 'UPDATE');
}, 1000 * 60 * 10).unref();
// 20 minutes max
}
}
/**
* Patch note
* @param {Object} data Note data
* @private
*/
_patchNote(data) {
/**
* The notes cache of the client user.
* @type {Collection<Snowflake, string>}
* @private
*/
this.notes = data ? new Collection(Object.entries(data)) : new Collection();
} }
/** /**
@ -165,7 +147,6 @@ class ClientUser extends User {
* <info>Changing usernames in Discord is heavily rate limited, with only 2 requests * <info>Changing usernames in Discord is heavily rate limited, with only 2 requests
* every hour. Use this sparingly!</info> * every hour. Use this sparingly!</info>
* @param {string} username The new username * @param {string} username The new username
* @param {string} password The password of the account
* @returns {Promise<ClientUser>} * @returns {Promise<ClientUser>}
* @example * @example
* // Set username * // Set username
@ -173,14 +154,8 @@ class ClientUser extends User {
* .then(user => console.log(`My new username is ${user.username}`)) * .then(user => console.log(`My new username is ${user.username}`))
* .catch(console.error); * .catch(console.error);
*/ */
setUsername(username, password) { setUsername(username) {
if (!password && !this.client.password) { return this.edit({ username });
throw new Error('A password is required to change a username.');
}
return this.edit({
username,
password: this.client.password ? this.client.password : password,
});
} }
/** /**
@ -197,186 +172,6 @@ class ClientUser extends User {
avatar = avatar && (await DataResolver.resolveImage(avatar)); avatar = avatar && (await DataResolver.resolveImage(avatar));
return this.edit({ avatar }); return this.edit({ avatar });
} }
/**
* Sets the banner of the logged in client.
* @param {?(BufferResolvable|Base64Resolvable)} banner The new banner
* @returns {Promise<ClientUser>}
* @example
* // Set banner
* client.user.setBanner('./banner.png')
* .then(user => console.log(`New banner set!`))
* .catch(console.error);
*/
async setBanner(banner) {
if (this.nitroType !== 'NITRO_BOOST') {
throw new Error('You must be a Nitro Boosted User to change your banner.');
}
banner = banner && (await DataResolver.resolveImage(banner));
return this.edit({ banner });
}
/**
* Set HyperSquad House
* @param {HypeSquadType} type
* * `LEAVE`: 0
* * `HOUSE_BRAVERY`: 1
* * `HOUSE_BRILLIANCE`: 2
* * `HOUSE_BALANCE`: 3
* @returns {Promise<void>}
* @example
* // Set HyperSquad HOUSE_BRAVERY
* client.user.setHypeSquad(1); || client.user.setHypeSquad('HOUSE_BRAVERY');
* // Leave
* client.user.setHypeSquad(0);
*/
async setHypeSquad(type) {
const id = typeof type === 'string' ? HypeSquadType[type] : type;
if (!id && id !== 0) throw new Error('Invalid HypeSquad type.');
if (id !== 0) {
const data = await this.client.api.hypesquad.online.post({
data: { house_id: id },
});
return data;
} else {
const data = await this.client.api.hypesquad.online.delete();
return data;
}
}
/**
* Set Accent color
* @param {ColorResolvable} color Color to set
* @returns {Promise<ClientUser>}
*/
setAccentColor(color = null) {
return this.edit({ accent_color: color ? Util.resolveColor(color) : null });
}
/**
* Set discriminator
* @param {User.discriminator} discriminator It is #1234
* @param {string} password The password of the account
* @returns {Promise<ClientUser>}
*/
setDiscriminator(discriminator, password) {
if (this.nitroType == 'NONE') throw new Error('You must be a Nitro User to change your discriminator.');
if (!password && !this.client.password) {
throw new Error('A password is required to change a discriminator.');
}
return this.edit({
discriminator,
username: this.username,
password: this.client.password ? this.client.password : password,
});
}
/**
* Set About me
* @param {string | null} bio Bio to set
* @returns {Promise<ClientUser>}
*/
setAboutMe(bio = null) {
return this.edit({
bio,
});
}
/**
* Change the email
* @param {Email<string>} email Email to change
* @param {string} password Password of the account
* @returns {Promise<ClientUser>}
*/
setEmail(email, password) {
throw new Error('This method is not available yet. Please use the official Discord client to change your email.');
// eslint-disable-next-line no-unreachable
if (!password && !this.client.password) {
throw new Error('A password is required to change a email.');
}
return this.edit({
email,
password: this.client.password ? this.client.password : password,
});
}
/**
* Set new password
* @param {string} oldPassword Old password
* @param {string} newPassword New password to set
* @returns {Promise<ClientUser>}
*/
setPassword(oldPassword, newPassword) {
if (!oldPassword && !this.client.password) {
throw new Error('A password is required to change a password.');
}
if (!newPassword) throw new Error('New password is required.');
return this.edit({
password: this.client.password ? this.client.password : oldPassword,
new_password: newPassword,
});
}
/**
* Disable account
* @param {string} password Password of the account
* @returns {Promise<ClientUser>}
*/
async disableAccount(password) {
if (!password && !this.client.password) {
throw new Error('A password is required to disable an account.');
}
const data = await this.client.api.users['@me'].disable.post({
data: {
password: this.client.password ? this.client.password : password,
},
});
return data;
}
/**
* Set selfdeaf (Global)
* @param {boolean} status Whether or not the ClientUser is deafened
* @returns {boolean}
*/
setDeaf(status) {
if (typeof status !== 'boolean') throw new Error('Deaf status must be a boolean.');
this.client.ws.broadcast({
op: Opcodes.VOICE_STATE_UPDATE,
d: { self_deaf: status },
});
return status;
}
/**
* Set selfmute (Global)
* @param {boolean} status Whether or not the ClientUser is muted
* @returns {boolean}
*/
setMute(status) {
if (typeof status !== 'boolean') throw new Error('Mute status must be a boolean.');
this.client.ws.broadcast({
op: Opcodes.VOICE_STATE_UPDATE,
d: { self_mute: status },
});
return status;
}
/**
* Delete account. Warning: Cannot be changed once used!
* @param {string} password Password of the account
* @returns {Promise<ClientUser>}
*/
async deleteAccount(password) {
if (!password && !this.client.password) {
throw new Error('A password is required to delete an account.');
}
const data = await this.client.api.users['@me/delete'].post({
data: {
password: this.client.password ? this.client.password : password,
},
});
return data;
}
/** /**
* Options for setting activities * Options for setting activities
@ -392,7 +187,7 @@ class ClientUser extends User {
* @typedef {Object} PresenceData * @typedef {Object} PresenceData
* @property {PresenceStatusData} [status] Status of the user * @property {PresenceStatusData} [status] Status of the user
* @property {boolean} [afk] Whether the user is AFK * @property {boolean} [afk] Whether the user is AFK
* @property {ActivitiesOptions[]|CustomStatus[]|RichPresence[]|SpotifyRPC[]} [activities] Activity the user is playing * @property {(ActivitiesOptions|CustomStatus|RichPresence|SpotifyRPC)[]} [activities] Activity the user is playing
* @property {number|number[]} [shardId] Shard id(s) to have the activity set on * @property {number|number[]} [shardId] Shard id(s) to have the activity set on
*/ */
@ -451,15 +246,10 @@ class ClientUser extends User {
* @see {@link https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/RichPresence.md} * @see {@link https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/RichPresence.md}
*/ */
setActivity(name, options = {}) { setActivity(name, options = {}) {
if (!name) { if (!name) return this.setPresence({ activities: [], shardId: options.shardId });
return this.setPresence({ activities: [], shardId: options.shardId });
}
const activity = Object.assign({}, options, typeof name === 'object' ? name : { name }); const activity = Object.assign({}, options, typeof name === 'object' ? name : { name });
return this.setPresence({ return this.setPresence({ activities: [activity], shardId: activity.shardId });
activities: [activity],
shardId: activity.shardId,
});
} }
/** /**
@ -472,6 +262,81 @@ class ClientUser extends User {
return this.setPresence({ afk, shardId }); return this.setPresence({ afk, shardId });
} }
/**
* Sets the banner of the logged in client.
* @param {?(BufferResolvable|Base64Resolvable)} banner The new banner
* @returns {Promise<ClientUser>}
* @example
* // Set banner
* client.user.setBanner('./banner.png')
* .then(user => console.log(`New banner set!`))
* .catch(console.error);
*/
async setBanner(banner) {
banner = banner && (await DataResolver.resolveImage(banner));
return this.edit({ banner });
}
/**
* Set HyperSquad House
* @param {string|number} type
* * `LEAVE`: 0
* * `HOUSE_BRAVERY`: 1
* * `HOUSE_BRILLIANCE`: 2
* * `HOUSE_BALANCE`: 3
* @returns {Promise<void>}
* @example
* // Set HyperSquad HOUSE_BRAVERY
* client.user.setHypeSquad(1); || client.user.setHypeSquad('HOUSE_BRAVERY');
* // Leave
* client.user.setHypeSquad(0);
*/
setHypeSquad(type) {
switch (type) {
case 'LEAVE': {
type = 0;
break;
}
case 'HOUSE_BRAVERY': {
type = 1;
break;
}
case 'HOUSE_BRILLIANCE': {
type = 2;
break;
}
case 'HOUSE_BALANCE': {
type = 3;
break;
}
}
if (type == 0) {
return this.client.api.hypesquad.online.delete();
} else {
return this.client.api.hypesquad.online.post({
data: { house_id: type },
});
}
}
/**
* Set Accent color
* @param {ColorResolvable} color Color to set
* @returns {Promise<ClientUser>}
*/
setAccentColor(color = null) {
return this.edit({ accent_color: color ? Util.resolveColor(color) : null });
}
/**
* Set About me
* @param {string} [bio=null] Bio to set
* @returns {Promise<ClientUser>}
*/
setAboutMe(bio = null) {
return this.edit({ bio });
}
/** /**
* Create an invite [Friend Invites] * Create an invite [Friend Invites]
* maxAge: 604800 | maxUses: 1 * maxAge: 604800 | maxUses: 1
@ -505,63 +370,10 @@ class ClientUser extends User {
/** /**
* Revoke all friend invites * Revoke all friend invites
* @returns {Promise<Collection<string, Invite>>} * @returns {Promise<void>}
*/ */
async revokeAllFriendInvites() { revokeAllFriendInvites() {
const data = await this.client.api.users['@me'].invites.delete(); return this.client.api.users['@me'].invites.delete();
const collection = new Collection();
for (const invite of data) {
collection.set(invite.code, new Invite(this.client, invite));
}
return collection;
}
/**
* Get a collection of messages mentioning clientUser
* @param {number} [limit=25] Maximum number of messages to get
* @param {boolean} [mentionRoles=true] Whether or not to mention roles
* @param {boolean} [mentionEveryone=true] Whether or not to mention `@everyone`
* @returns {Promise<Collection<Snowflake, Message>>}
*/
async getMentions(limit = 25, mentionRoles = true, mentionEveryone = true) {
// https://canary.discord.com/api/v9/users/@me/mentions?limit=25&roles=true&everyone=true
const data = await this.client.api.users['@me'].mentions.get({
query: {
limit,
roles: mentionRoles,
everyone: mentionEveryone,
},
});
const collection = new Collection();
for (const msg of data) {
collection.set(msg.id, new Message(this.client, msg));
}
return collection;
}
/**
* Change Theme color
* @param {ColorResolvable} primary The primary color of the user's profile
* @param {ColorResolvable} accent The accent color of the user's profile
* @returns {Promise<ClientUser>}
*/
async setThemeColors(primary, accent) {
if (!primary || !accent) throw new Error('PRIMARY_COLOR or ACCENT_COLOR are required.');
// Check nitro
if (this.nitroType !== 'NITRO_BOOST') {
throw new Error_('NITRO_BOOST_REQUIRED', 'themeColors');
}
primary = Util.resolveColor(primary) || this.themeColors[0];
accent = Util.resolveColor(accent) || this.themeColors[1];
const data_ = await this.client.api.users['@me'].profile.patch({
data: {
theme_colors: [primary, accent],
},
});
this._ProfilePatch({
user_profile: data_,
});
return this;
} }
/** /**
@ -587,8 +399,8 @@ class ClientUser extends User {
update: type, update: type,
}, },
}); });
if (type !== 'STOP') this._packageName = packageName; if (type !== 'STOP') this.#packageName = packageName;
else this._packageName = null; else this.#packageName = null;
return this; return this;
} }
@ -598,9 +410,7 @@ class ClientUser extends User {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
stopRinging(channel) { stopRinging(channel) {
const id = this.client.channels.resolveId(channel); return this.client.api.channels(this.client.channels.resolveId(channel)).call['stop-ringing'].post({
if (!channel) return false;
return this.client.api.channels(id).call['stop-ringing'].post({
data: {}, data: {},
}); });
} }

View File

@ -8,7 +8,6 @@ const { Error } = require('../errors');
const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager'); const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
const GuildMemberFlags = require('../util/GuildMemberFlags'); const GuildMemberFlags = require('../util/GuildMemberFlags');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
const Util = require('../util/Util');
/** /**
* @type {WeakSet<GuildMember>} * @type {WeakSet<GuildMember>}
@ -102,7 +101,6 @@ class GuildMember extends Base {
this.communicationDisabledUntilTimestamp = this.communicationDisabledUntilTimestamp =
data.communication_disabled_until && Date.parse(data.communication_disabled_until); data.communication_disabled_until && Date.parse(data.communication_disabled_until);
} }
if ('flags' in data) { if ('flags' in data) {
/** /**
* The flags of this member * The flags of this member
@ -114,51 +112,6 @@ class GuildMember extends Base {
} }
} }
_ProfilePatch(data) {
if ('accent_color' in data) {
/**
* The member's accent color
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?number}
*/
this.accentColor = data.accent_color;
}
if ('banner' in data) {
/**
* The member's banner hash
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?string}
*/
this.banner = data.banner;
}
if ('bio' in data) {
/**
* The member's biography (About me)
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?string}
*/
this.bio = data.bio;
}
if ('theme_colors' in data) {
/**
* The member's theme colors (Profile theme) [Primary, Accent]
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?Array<number>}
*/
this.themeColors = data.theme_colors;
}
}
/**
* The hexadecimal version of the user theme color, with a leading hash [Primary, Accent]
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?Array<string>}
* @readonly
*/
get hexThemeColor() {
return this.themeColors?.map(c => `#${c.toString(16).padStart(6, '0')}`) || null;
}
_clone() { _clone() {
const clone = super._clone(); const clone = super._clone();
clone._roles = this._roles.slice(); clone._roles = this._roles.slice();
@ -232,21 +185,6 @@ class GuildMember extends Base {
return this.client.rest.cdn.GuildMemberAvatar(this.guild.id, this.id, this.avatar, format, size, dynamic); return this.client.rest.cdn.GuildMemberAvatar(this.guild.id, this.id, this.avatar, format, size, dynamic);
} }
/**
* A link to the user's banner.
* <info>This method will throw an error if called before the user is force fetched Profile.
* See {@link GuildMember#banner} for more info</info>
* @param {ImageURLOptions} [options={}] Options for the Image URL
* @returns {?string}
*/
bannerURL({ format, size, dynamic } = {}) {
if (typeof this.banner === 'undefined') {
throw new Error('USER_BANNER_NOT_FETCHED');
}
if (!this.banner) return null;
return this.client.rest.cdn.GuildMemberBanner(this.guild.id, this.id, this.banner, format, size, dynamic);
}
/** /**
* A link to the member's guild avatar if they have one. * A link to the member's guild avatar if they have one.
* Otherwise, a link to their {@link User#displayAvatarURL} will be returned. * Otherwise, a link to their {@link User#displayAvatarURL} will be returned.
@ -444,79 +382,6 @@ class GuildMember extends Base {
return this.edit({ flags, reason }); return this.edit({ flags, reason });
} }
/**
* Sets the guild avatar of the logged in client.
* @param {?(BufferResolvable|Base64Resolvable)} avatar The new avatar
* @returns {Promise<GuildMember>}
*/
setAvatar(avatar) {
if (this.user.id !== this.client.user.id) {
throw new Error('ONLY_ME');
}
if (this.client.user.nitroType !== 'NITRO_BOOST') {
throw new Error('NITRO_BOOST_REQUIRED', 'avatar');
}
return this.edit({ avatar });
}
/**
* Sets the guild banner of the logged in client.
* @param {?(BufferResolvable|Base64Resolvable)} banner The new banner
* @returns {Promise<GuildMember>}
*/
setBanner(banner) {
if (this.user.id !== this.client.user.id) {
throw new Error('ONLY_ME');
}
if (this.client.user.nitroType !== 'NITRO_BOOST') {
throw new Error('NITRO_BOOST_REQUIRED', 'banner');
}
return this.edit({ banner });
}
/**
* Set Guild About me
* @param {string | null} bio Bio to set
* @returns {Promise<GuildMember>}
*/
setAboutMe(bio = null) {
if (this.user.id !== this.client.user.id) {
throw new Error('ONLY_ME');
}
if (this.client.user.nitroType !== 'NITRO_BOOST') {
throw new Error('NITRO_BOOST_REQUIRED', 'bio');
}
return this.edit({ bio });
}
/**
* Change Theme color
* @param {ColorResolvable} primary The primary color of the user's profile
* @param {ColorResolvable} accent The accent color of the user's profile
* @returns {Promise<GuildMember>}
*/
async setThemeColors(primary, accent) {
if (this.user.id !== this.client.user.id) {
throw new Error('ONLY_ME');
}
if (!primary || !accent) throw new Error('PRIMARY_COLOR or ACCENT_COLOR are required.');
// Check nitro
if (this.nitroType !== 'NITRO_BOOST') {
throw new Error('NITRO_BOOST_REQUIRED', 'themeColors');
}
primary = Util.resolveColor(primary) || this.themeColors ? this.themeColors[0] : 0;
accent = Util.resolveColor(accent) || this.themeColors ? this.themeColors[1] : 0;
const data_ = await this.client.api.guilds[this.guild.id].profile['@me'].patch({
data: {
theme_colors: [primary, accent],
},
});
this._ProfilePatch({
guild_member_profile: data_,
});
return this;
}
/** /**
* Creates a DM channel between the client and this member. * Creates a DM channel between the client and this member.
* @param {boolean} [force=false] Whether to skip the cache check and request the API * @param {boolean} [force=false] Whether to skip the cache check and request the API
@ -619,8 +484,6 @@ class GuildMember extends Base {
this.joinedTimestamp === member.joinedTimestamp && this.joinedTimestamp === member.joinedTimestamp &&
this.nickname === member.nickname && this.nickname === member.nickname &&
this.avatar === member.avatar && this.avatar === member.avatar &&
this.accentColor === member.accentColor &&
this.bio === member.bio &&
this.pending === member.pending && this.pending === member.pending &&
this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp && this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&
this.flags.equals(member.flags) && this.flags.equals(member.flags) &&
@ -629,14 +492,6 @@ class GuildMember extends Base {
); );
} }
/**
* Get profile guildMember
* @returns {Promise<User>}
*/
getProfile() {
return this.user.getProfile(this.guild.id);
}
/** /**
* When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object. * When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object.
* @returns {string} * @returns {string}
@ -659,6 +514,33 @@ class GuildMember extends Base {
json.displayAvatarURL = this.displayAvatarURL(); json.displayAvatarURL = this.displayAvatarURL();
return json; return json;
} }
/**
* Sets the guild avatar of the logged in client.
* @param {?(BufferResolvable|Base64Resolvable)} avatar The new avatar
* @returns {Promise<GuildMember>}
*/
setAvatar(avatar) {
return this.edit({ avatar });
}
/**
* Sets the guild banner of the logged in client.
* @param {?(BufferResolvable|Base64Resolvable)} banner The new banner
* @returns {Promise<GuildMember>}
*/
setBanner(banner) {
return this.edit({ banner });
}
/**
* Set Guild About me
* @param {string | null} bio Bio to set
* @returns {Promise<GuildMember>}
*/
setAboutMe(bio = null) {
return this.edit({ bio });
}
} }
/** /**

View File

@ -1,12 +1,11 @@
'use strict'; 'use strict';
const Buffer = require('node:buffer').Buffer;
const Base = require('./Base'); const Base = require('./Base');
const { GuildScheduledEvent } = require('./GuildScheduledEvent'); const { GuildScheduledEvent } = require('./GuildScheduledEvent');
const IntegrationApplication = require('./IntegrationApplication'); const IntegrationApplication = require('./IntegrationApplication');
const InviteStageInstance = require('./InviteStageInstance'); const InviteStageInstance = require('./InviteStageInstance');
const { Error } = require('../errors'); const { Error } = require('../errors');
const { ChannelTypes, Endpoints } = require('../util/Constants'); const { Endpoints } = require('../util/Constants');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
// TODO: Convert `inviter` and `channel` in this class to a getter. // TODO: Convert `inviter` and `channel` in this class to a getter.
@ -179,7 +178,7 @@ class Invite extends Base {
this.channel = this.client.channels.cache.get(data.channel_id); this.channel = this.client.channels.cache.get(data.channel_id);
} }
if ('channel' in data && data.channel) { if ('channel' in data) {
/** /**
* The channel this invite is for * The channel this invite is for
* @type {Channel} * @type {Channel}
@ -317,53 +316,6 @@ class Invite extends Base {
valueOf() { valueOf() {
return this.code; return this.code;
} }
/**
* Join this Guild using this invite.
* @param {boolean} [autoVerify] Whether to automatically verify member
* @returns {Promise<Guild>}
* @example
* await client.fetchInvite('code').then(async invite => {
* await invite.acceptInvite();
* });
*/
async acceptInvite(autoVerify = false) {
if (!this.guild) throw new Error('INVITE_NO_GUILD');
if (this.client.guilds.cache.get(this.guild.id)) return this.guild;
const dataHeader = {
location: 'Join Guild',
location_guild_id: this.guild?.id,
location_channel_id: this.channelId,
location_channel_type: ChannelTypes[this.channel?.type] ?? 0,
};
await this.client.api.invites(this.code).post({
data: {
session_id: this.client.sessionId,
},
headers: {
'X-Context-Properties': Buffer.from(JSON.stringify(dataHeader), 'utf8').toString('base64'),
},
});
const guild = this.client.guilds.cache.get(this.guild.id);
/*
//
if (autoVerify) {
console.warn('Feature is under maintenance - Invite#acceptInvite(true)');
}
*/
if (autoVerify) {
const getForm = await this.client.api
.guilds(this.guild.id)
['member-verification'].get({ query: { with_guild: false, invite_code: this.code } })
.catch(() => {});
if (!getForm) return guild;
const form = Object.assign(getForm.form_fields[0], { response: true });
// Respond to the form
// https://discord.com/api/v9/guilds/:id/requests/@me
await this.client.api.guilds(this.guild.id).requests['@me'].put({ data: { form_fields: [form] } });
}
return guild;
}
} }
/** /**

View File

@ -91,7 +91,7 @@ class Presence extends Base {
if ('activities' in data) { if ('activities' in data) {
/** /**
* The activities of this presence * The activities of this presence
* @type {Activity[]} * @type {(Activity|CustomStatus|SpotifyRPC|RichPresence)[]}
*/ */
this.activities = data.activities.map(activity => { this.activities = data.activities.map(activity => {
if (fromClient === true) { if (fromClient === true) {

View File

@ -1,11 +1,8 @@
'use strict'; 'use strict';
const { randomUUID } = require('node:crypto');
const { ActivityTypes } = require('../util/Constants'); const { ActivityTypes } = require('../util/Constants');
const { resolvePartialEmoji } = require('../util/Util'); const { resolvePartialEmoji } = require('../util/Util');
// eslint-disable-next-line
const getUUID = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, a => (a ^ ((Math.random() * 16) >> (a / 4))).toString(16));
// Function check url valid (ok copilot)
// eslint-disable-next-line // eslint-disable-next-line
const checkUrl = url => { const checkUrl = url => {
try { try {
@ -351,7 +348,7 @@ https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Documents/RichP
if (!party.max || typeof party.max != 'number') throw new Error('Party must have max number'); if (!party.max || typeof party.max != 'number') throw new Error('Party must have max number');
if (!party.current || typeof party.current != 'number') throw new Error('Party must have current'); if (!party.current || typeof party.current != 'number') throw new Error('Party must have current');
if (party.current > party.max) throw new Error('Party current must be less than max number'); if (party.current > party.max) throw new Error('Party current must be less than max number');
if (!party.id || typeof party.id != 'string') party.id = getUUID(); if (!party.id || typeof party.id != 'string') party.id = randomUUID();
this.party = { this.party = {
size: [party.current, party.max], size: [party.current, party.max],
id: party.id, id: party.id,
@ -488,16 +485,6 @@ https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Documents/RichP
} }
} }
/**
* Get random UUID string (Util)
* @returns {string}
*/
static getUUID() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, a =>
(a ^ ((Math.random() * 16) >> (a / 4))).toString(16),
);
}
/** /**
* Get Assets from a RichPresence (Util) * Get Assets from a RichPresence (Util)
* @param {Client} client Discord Client * @param {Client} client Discord Client
@ -718,5 +705,4 @@ module.exports = {
CustomStatus, CustomStatus,
RichPresence, RichPresence,
SpotifyRPC, SpotifyRPC,
getUUID,
}; };

View File

@ -1,12 +1,10 @@
'use strict'; 'use strict';
const { Collection } = require('@discordjs/collection');
const Base = require('./Base'); const Base = require('./Base');
const ClientApplication = require('./ClientApplication');
const VoiceState = require('./VoiceState'); const VoiceState = require('./VoiceState');
const TextBasedChannel = require('./interfaces/TextBasedChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { Error } = require('../errors'); const { Error } = require('../errors');
const { RelationshipTypes, NitroType } = require('../util/Constants'); const { RelationshipTypes } = require('../util/Constants');
const SnowflakeUtil = require('../util/SnowflakeUtil'); const SnowflakeUtil = require('../util/SnowflakeUtil');
const UserFlags = require('../util/UserFlags'); const UserFlags = require('../util/UserFlags');
const Util = require('../util/Util'); const Util = require('../util/Util');
@ -17,8 +15,9 @@ const Util = require('../util/Util');
* @extends {Base} * @extends {Base}
*/ */
class User extends Base { class User extends Base {
constructor(client, data, application) { constructor(client, data) {
super(client); super(client);
/** /**
* The user's id * The user's id
* @type {Snowflake} * @type {Snowflake}
@ -31,52 +30,6 @@ class User extends Base {
this.flags = null; this.flags = null;
/**
* An array of object (connected accounts), containing the following properties:
* @property {string} type The account type (twitch, youtube, etc)
* @property {string} name The account name
* @property {string} id The account id
* @property {boolean} verified Whether the account is verified
* @see {@link https://discord.com/developers/docs/resources/user#connection-object}
* @typedef {Object} ConnectionAccount
*/
/**
* Accounts connected to this user
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?ConnectionAccount[]}
*/
this.connectedAccounts = [];
/**
* Time that User has nitro (Unix Timestamp)
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?number}
*/
this.premiumSince = null;
/**
* Time that User has nitro and boost server (Unix Timestamp)
* @type {?number}
*/
this.premiumGuildSince = null;
/**
* About me (User)
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?string}
*/
this.bio = null;
/**
* Pronouns (User)
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?string}
*/
this.pronouns = null;
this._mutualGuilds = [];
/**
* [Bot] Application
* @type {?ClientApplication}
*/
this.application = application ? new ClientApplication(this.client, application, this) : null;
this._partial = true;
this._patch(data); this._patch(data);
} }
@ -107,10 +60,6 @@ class User extends Base {
* @type {?boolean} * @type {?boolean}
*/ */
this.bot = Boolean(data.bot); this.bot = Boolean(data.bot);
if (this.bot === true && !this.application) {
this.application = new ClientApplication(this.client, { id: this.id }, this);
this.botInGuildsCount = null;
}
} else if (!this.partial && typeof this.bot !== 'boolean') { } else if (!this.partial && typeof this.bot !== 'boolean') {
this.bot = false; this.bot = false;
} }
@ -147,6 +96,17 @@ class User extends Base {
this.banner ??= undefined; this.banner ??= undefined;
} }
if ('banner_color' in data) {
/**
* The user banner's hex
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?string}
*/
this.bannerColor = data.banner_color;
} else if (this.bannerColor !== null) {
this.bannerColor ??= undefined;
}
if ('accent_color' in data) { if ('accent_color' in data) {
/** /**
* The base 10 accent color of the user's banner * The base 10 accent color of the user's banner
@ -176,252 +136,23 @@ class User extends Base {
this.flags = new UserFlags(data.public_flags); this.flags = new UserFlags(data.public_flags);
} }
if ('approximate_guild_count' in data) { if ('avatar_decoration_data' in data) {
/**
* Check how many guilds the bot is in (Probably only approximate) (application.fetch() first)
* @type {?number}
*/
this.botInGuildsCount = data.approximate_guild_count;
}
if ('avatar_decoration' in data) {
/** /**
* The user avatar decoration's hash * The user avatar decoration's hash
* @type {?string} * @type {?string}
*/ */
this.avatarDecoration = data.avatar_decoration; this.avatarDecoration = data.avatar_decoration_data?.asset;
/**
* The ID of the avatar decoration's SKU
* @type {?Snowflake}
*/
this.avatarDecorationSKUId = data.avatar_decoration_data?.sku_id;
} else { } else {
this.avatarDecoration ??= null; this.avatarDecoration ??= null;
this.avatarDecorationSKUId ??= null;
} }
} }
/**
* This user is on the same servers as Client User
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {Collection<Snowflake, Guild>}
* @readonly
*/
get mutualGuilds() {
return new Collection(this._mutualGuilds.map(obj => [obj.id, obj]));
}
/**
* Get all mutual friends (Client -> User)
* @type {Promise<Collection<Snowflake, User>>}
* @readonly
*/
get mutualFriends() {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async resolve => {
const all = new Collection();
if (this.bot || this.client.user.id === this.id) return resolve(all);
const data = await this.client.api.users(this.id).relationships.get();
for (const u of data) {
all.set(u.id, this.client.users._add(u));
}
return resolve(all);
});
}
/**
* Check relationship status (Client -> User)
* @type {RelationshipTypes}
* @readonly
*/
get relationships() {
const i = this.client.relationships.cache.get(this.id) ?? 0;
return RelationshipTypes[parseInt(i)];
}
/**
* Check note
* @type {?string}
* @readonly
*/
get note() {
return this.client.user.notes.get(this.id);
}
/**
* Get friend nickname
* @type {?string}
* @readonly
*/
get nickname() {
return this.client.user.friendNicknames.get(this.id);
}
/**
* The voice state of this member
* @type {VoiceState}
* @readonly
*/
get voice() {
return (
this.client.voiceStates.cache.get(this.id) ??
this.client.guilds.cache.find(g => g?.voiceStates?.cache?.get(this.id))?.voiceStates?.cache?.get(this.id) ??
new VoiceState({ client: this.client }, { user_id: this.id })
);
}
_ProfilePatch(data) {
if (!data) return;
this._partial = false;
if (data.connected_accounts.length > 0) {
this.connectedAccounts = data.connected_accounts;
}
if ('premium_since' in data) {
const date = new Date(data.premium_since);
this.premiumSince = date.getTime();
}
if ('premium_guild_since' in data) {
const date = new Date(data.premium_guild_since);
this.premiumGuildSince = date.getTime();
}
if ('premium_type' in data) {
const nitro = NitroType[data.premium_type ?? 0];
/**
* Nitro type of the user.
* @type {NitroType}
*/
this.nitroType = nitro ?? `UNKNOWN_TYPE_${data.premium_type}`;
}
if ('user_profile' in data) {
this.bio = data.user_profile.bio;
/**
* The user's theme colors (Profile theme) [Primary, Accent]
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?Array<number>}
*/
this.themeColors = data.user_profile.theme_colors;
this.pronouns = data.user_profile.pronouns;
}
if ('guild_member_profile' in data && 'guild_member' in data) {
const guild = this.client.guilds.cache.get(data.guild_member_profile.guild_id);
const member = guild?.members._add(data.guild_member);
member._ProfilePatch(data.guild_member_profile);
}
if ('application' in data) {
this.application = new ClientApplication(this.client, data.application, this);
}
if ('badges' in data) {
/**
* @callback BadgeIcon
* @returns {string}
*/
/**
* @typedef {Object} UserBadge
* @property {string} id The id of the badge
* @property {string} description The description of the badge
* @property {string} icon The icon hash of the badge
* @property {?string} link The link of the badge
* @property {BadgeIcon} iconURL The iconURL of the badge
*/
/**
* User badges (Boost, Slash, AutoMod, etc.)
* @type {?Array<UserBadge>}
*/
this.badges = data.badges.map(o => ({ ...o, iconURL: () => this.client.rest.cdn.BadgeIcon(o.icon) }));
}
if ('guild_badges' in data) {
// Unknown
}
if ('mutual_guilds' in data) {
this._mutualGuilds = data.mutual_guilds;
}
}
/**
* Get profile from Discord, if client is in a server with the target.
* @type {User}
* @param {Snowflake | null} guildId The guild id to get the profile from
* @returns {Promise<User>}
*/
async getProfile(guildId) {
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
const query = guildId
? {
with_mutual_guilds: true,
guild_id: guildId,
}
: {
with_mutual_guilds: true,
};
const data = await this.client.api.users(this.id).profile.get({
query,
});
this._ProfilePatch(data);
return this;
}
/**
* Friends the user [If incoming request]
* @type {boolean}
* @returns {Promise<boolean>}
*/
setFriend() {
return this.client.relationships.addFriend(this);
}
/**
* Changes the nickname of the friend
* @param {?string} nickname The nickname to change
* @type {boolean}
* @returns {Promise<boolean>}
*/
setNickname(nickname) {
return this.client.relationships.setNickname(this.id, nickname);
}
/**
* Send Friend Request to the user
* @type {boolean}
* @returns {Promise<boolean>}
*/
sendFriendRequest() {
return this.client.relationships.sendFriendRequest(this.username, this.discriminator);
}
/**
* Blocks the user
* @type {boolean}
* @returns {Promise<boolean>}
*/
setBlock() {
return this.client.relationships.addBlocked(this);
}
/**
* Removes the user from your blocks list
* @type {boolean}
* @returns {Promise<boolean>}
*/
unBlock() {
return this.client.relationships.deleteBlocked(this);
}
/**
* Removes the user from your friends list
* @type {boolean}
* @returns {Promise<boolean>}
*/
unFriend() {
return this.client.relationships.deleteFriend(this);
}
/** /**
* Whether this User is a partial * Whether this User is a partial
* @type {boolean} * @type {boolean}
@ -508,40 +239,11 @@ class User extends Base {
* @returns {?string} * @returns {?string}
*/ */
bannerURL({ format, size, dynamic } = {}) { bannerURL({ format, size, dynamic } = {}) {
if (typeof this.banner === 'undefined') { if (typeof this.banner === 'undefined') throw new Error('USER_BANNER_NOT_FETCHED');
throw new Error('USER_BANNER_NOT_FETCHED');
}
if (!this.banner) return null; if (!this.banner) return null;
return this.client.rest.cdn.Banner(this.id, this.banner, format, size, dynamic); return this.client.rest.cdn.Banner(this.id, this.banner, format, size, dynamic);
} }
/**
* Ring the user's phone / PC (call)
* @returns {Promise<any>}
* @deprecated
*/
ring() {
if (this.relationships !== 'FRIEND') return Promise.reject(new Error('USER_NOT_FRIEND'));
if (!this.client.user.voice?.channelId || !this.client.callVoice) {
return Promise.reject(new Error('CLIENT_NO_CALL'));
}
return this.client.api.channels(this.dmChannel.id).call.ring.post({
data: {
recipients: [this.id],
},
});
}
/**
* The hexadecimal version of the user theme color, with a leading hash [Primary, Accent]
* <info>The user must be force fetched for this property to be present or be updated</info>
* @type {?Array<string>}
* @readonly
*/
get hexThemeColor() {
return this.themeColors?.map(c => `#${c.toString(16).padStart(6, '0')}`) || null;
}
/** /**
* The tag of this user * The tag of this user
* <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`) * <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
@ -609,8 +311,7 @@ class User extends Base {
this.avatar === user.avatar && this.avatar === user.avatar &&
this.flags?.bitfield === user.flags?.bitfield && this.flags?.bitfield === user.flags?.bitfield &&
this.banner === user.banner && this.banner === user.banner &&
this.accentColor === user.accentColor && this.accentColor === user.accentColor
this.bio === user.bio
); );
} }
@ -652,6 +353,28 @@ class User extends Base {
return this.client.users.fetch(this.id, { force }); return this.client.users.fetch(this.id, { force });
} }
/**
* Returns a user profile object for a given user ID.
* <info>This endpoint requires one of the following:
* - The user is a bot
* - The user shares a mutual guild with the current user
* - The user is a friend of the current user
* - The user is a friend suggestion of the current user
* - The user has an outgoing friend request to the current user</info>
* @param {Snowflake} [guildId] The guild ID to get the user's member profile in
* @returns {Promise<Object>}
* @see {@link https://discord-userdoccers.vercel.app/resources/user#response-body}
*/
getProfile(guildId) {
return this.client.api.users(this.id).profile.get({
query: {
with_mutual_guilds: true,
with_mutual_friends_count: true,
guild_id: guildId,
},
});
}
/** /**
* When concatenated with a string, this automatically returns the user's mention instead of the User object. * When concatenated with a string, this automatically returns the user's mention instead of the User object.
* @returns {string} * @returns {string}
@ -680,29 +403,85 @@ class User extends Base {
} }
/** /**
* Set note to user * The function updates the note of a user and returns the updated user.
* @param {string} note Note to set * @param {string|null|undefined} [note=null] - The `note` parameter is the new value that you want to set for the note of the
* @returns {Promise<User>} * user. It is an optional parameter and its default value is `null`.
* @returns {Promise<User>} The `setNote` method is returning the `User` object.
*/ */
async setNote(note = null) { async setNote(note = null) {
await this.client.api.users['@me'].notes(this.id).put({ data: { note } }); await this.client.notes.updateNote(this.id, note);
return this; return this;
} }
/** /**
* Get presence (~ v12) * The function returns the note associated with a specific client ID from a cache.
* @returns {Promise<Presence | null>} * @type {?string} The note that corresponds to the given id.
*/ */
async presenceFetch() { get note() {
let data = null; return this.client.notes.cache.get(this.id);
await Promise.all( }
this.client.guilds.cache.map(async guild => {
const res_ = await guild.presences.resolve(this.id); /**
if (res_) return (data = res_); * The voice state of this member
return true; * @type {VoiceState}
}), * @readonly
*/
get voice() {
return (
this.client.voiceStates.cache.get(this.id) ??
this.client.guilds.cache.find(g => g?.voiceStates?.cache?.get(this.id))?.voiceStates?.cache?.get(this.id) ??
new VoiceState({ client: this.client }, { user_id: this.id })
); );
return data; }
/**
* Ring the user's phone / PC (call)
* @returns {Promise<void>}
* @deprecated
*/
ring() {
return this.client.api.channels(this.dmChannel.id).call.ring.post({
data: {
recipients: [this.id],
},
});
}
/**
* Send Friend Request to the user
* @type {boolean}
* @returns {Promise<boolean>}
*/
sendFriendRequest() {
return this.client.relationships.sendFriendRequest({ user: this });
}
/**
* Unblock / Unfriend / Cancels a friend request
* @type {boolean}
* @returns {Promise<boolean>}
*/
deleteRelationship() {
return this.client.relationships.deleteRelationship(this);
}
/**
* Check relationship status (Client -> User)
* @type {RelationshipTypes}
* @readonly
*/
get relationship() {
const i = this.client.relationships.cache.get(this.id) ?? 0;
return RelationshipTypes[parseInt(i)];
}
/**
* Get friend nickname
* @type {?string}
* @readonly
*/
get friendNickname() {
return this.client.relationships.friendNicknames.get(this.id);
} }
} }

View File

@ -1,12 +1,6 @@
'use strict'; 'use strict';
/* Not used:
const process = require('node:process');
const Package = (exports.Package = require('../../package.json'));
*/
const { Error, RangeError, TypeError } = require('../errors');
exports.defaultUA = const { Error, RangeError, TypeError } = require('../errors');
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.9023 Chrome/108.0.5359.215 Electron/22.3.26 Safari/537.36';
/** /**
* Max bulk deletable message age * Max bulk deletable message age
@ -14,121 +8,8 @@ exports.defaultUA =
*/ */
exports.MaxBulkDeletableMessageAge = 1_209_600_000; exports.MaxBulkDeletableMessageAge = 1_209_600_000;
/** exports.UserAgent =
* API captcha solver 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.9023 Chrome/108.0.5359.215 Electron/22.3.26 Safari/537.36';
* * `2captcha` - 2captcha.com
* * `capmonster` - capmonster.cloud
* @typedef {string[]} captchaServices
*/
exports.captchaServices = ['2captcha', 'capmonster', 'custom'];
/**
* Automatically scan and delete direct messages you receive that contain explicit media content.
* * `NOT_SCAN` - Direct messages will not be scanned for explicit content.
* * `NOT_FRIEND` - Scan direct messages from everyone unless they are a friend.
* * `EVERYONE` - Scan direct messages from everyone.
* @typedef {string} DMScanLevel
*/
exports.DMScanLevel = createEnum(['NOT_SCAN', 'NOT_FRIEND', 'EVERYONE']);
/**
* This controls when stickers animate:
* * `ALWAYS` - Always animate.
* * `INTERACTION` - On the desktop client, stickers will animate on hover or focus. On mobile clients, stickers will animate on long-press.
* * `NEVER` - Never animate.
* @typedef {string} stickerAnimationMode
*/
exports.stickerAnimationMode = createEnum(['ALWAYS', 'INTERACTION', 'NEVER']);
/**
* All available nitro types:
* * `NONE` - None
* * `NITRO_CLASSIC` - Nitro Classic
* * `NITRO_BOOST` - Nitro
* * `NITRO_BASIC` - Nitro Basic
* * `UNKNOWN` - Unknown
* @typedef {string} NitroType
* @see {@link https://discord.com/developers/docs/resources/user#user-object-premium-types}
*/
exports.NitroType = createEnum(['NONE', 'NITRO_CLASSIC', 'NITRO_BOOST', 'NITRO_BASIC']);
/**
* All available HypeSquad types:
* * `LEAVE` - None
* * `HOUSE_BRAVERY` - HypeSquad Bravery
* * `HOUSE_BRILLIANCE` - HypeSquad Brilliance
* * `HOUSE_BALANCE` - HypeSquad Balance
* @typedef {string} HypeSquadType
*/
exports.HypeSquadType = createEnum(['LEAVE', 'HOUSE_BRAVERY', 'HOUSE_BRILLIANCE', 'HOUSE_BALANCE']);
/**
* All locale codes:
* * `DANISH`
* * `GERMAN`
* * `ENGLISH_UK`
* * `ENGLISH_US`
* * `SPANISH`
* * `FRENCH`
* * `CROATIAN`
* * `ITALIAN`
* * `LITHUANIAN`
* * `HUNGARIAN`
* * `DUTCH`
* * `NORWEGIAN`
* * `POLISH`
* * `BRAZILIAN_PORTUGUESE`
* * `ROMANIA_ROMANIAN`
* * `FINNISH`
* * `SWEDISH`
* * `VIETNAMESE`
* * `TURKISH`
* * `CZECH`
* * `GREEK`
* * `BULGARIAN`
* * `RUSSIAN`
* * `UKRAINIAN`
* * `HINDI`
* * `THAI`
* * `CHINA_CHINESE`
* * `JAPANESE`
* * `TAIWAN_CHINESE`
* * `KOREAN`
* @typedef {Object<string, string>} localeSetting
* @see {@link https://discord.com/developers/docs/reference#locales}
*/
exports.localeSetting = {
da: 'DANISH',
de: 'GERMAN',
'en-GB': 'ENGLISH_UK',
'en-US': 'ENGLISH_US',
'es-ES': 'SPANISH',
fr: 'FRENCH',
hr: 'CROATIAN',
it: 'ITALIAN',
lt: 'LITHUANIAN',
hu: 'HUNGARIAN',
nl: 'DUTCH',
no: 'NORWEGIAN',
pl: 'POLISH',
'pt-BR': 'BRAZILIAN_PORTUGUESE',
ro: 'ROMANIA_ROMANIAN',
fi: 'FINNISH',
'sv-SE': 'SWEDISH',
vi: 'VIETNAMESE',
tr: 'TURKISH',
cs: 'CZECH',
el: 'GREEK',
bg: 'BULGARIAN',
ru: 'RUSSIAN',
uk: 'UKRAINIAN',
hi: 'HINDI',
th: 'THAI',
'zh-CN': 'CHINA_CHINESE',
ja: 'JAPANESE',
'zh-TW': 'TAIWAN_CHINESE',
ko: 'KOREAN',
};
/** /**
* The types of WebSocket error codes: * The types of WebSocket error codes:
@ -197,10 +78,6 @@ exports.Endpoints = {
if (dynamic && hash.startsWith('a_')) format = 'gif'; if (dynamic && hash.startsWith('a_')) format = 'gif';
return makeImageUrl(`${root}/guilds/${guildId}/users/${memberId}/avatars/${hash}`, { format, size }); return makeImageUrl(`${root}/guilds/${guildId}/users/${memberId}/avatars/${hash}`, { format, size });
}, },
GuildMemberBanner: (guildId, memberId, hash, format = 'webp', size, dynamic = false) => {
if (dynamic && hash.startsWith('a_')) format = 'gif';
return makeImageUrl(`${root}/guilds/${guildId}/users/${memberId}/banners/${hash}`, { format, size });
},
Banner: (id, hash, format, size, dynamic = false) => { Banner: (id, hash, format, size, dynamic = false) => {
if (dynamic && hash.startsWith('a_')) format = 'gif'; if (dynamic && hash.startsWith('a_')) format = 'gif';
return makeImageUrl(`${root}/banners/${id}/${hash}`, { format, size }); return makeImageUrl(`${root}/banners/${id}/${hash}`, { format, size });
@ -227,14 +104,11 @@ exports.Endpoints = {
makeImageUrl(`${root}/role-icons/${roleId}/${hash}`, { size, format }), makeImageUrl(`${root}/role-icons/${roleId}/${hash}`, { size, format }),
guildScheduledEventCover: (scheduledEventId, coverHash, format, size) => guildScheduledEventCover: (scheduledEventId, coverHash, format, size) =>
makeImageUrl(`${root}/guild-events/${scheduledEventId}/${coverHash}`, { size, format }), makeImageUrl(`${root}/guild-events/${scheduledEventId}/${coverHash}`, { size, format }),
// Test only
BadgeIcon: hash => makeImageUrl(`${root}/badge-icons/${hash}`, { format: 'png' }),
}; };
}, },
invite: (root, code, eventId) => (eventId ? `${root}/${code}?event=${eventId}` : `${root}/${code}`), invite: (root, code, eventId) => (eventId ? `${root}/${code}?event=${eventId}` : `${root}/${code}`),
scheduledEvent: (root, guildId, eventId) => `${root}/${guildId}/${eventId}`, scheduledEvent: (root, guildId, eventId) => `${root}/${guildId}/${eventId}`,
botGateway: '/gateway/bot', botGateway: '/gateway',
userGateway: '/gateway',
}; };
/** /**
@ -348,7 +222,6 @@ exports.Opcodes = {
* * API_RESPONSE: apiResponse * * API_RESPONSE: apiResponse
* * API_REQUEST: apiRequest * * API_REQUEST: apiRequest
* * CLIENT_READY: ready * * CLIENT_READY: ready
* * APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE: applicationCommandAutocompleteResponse
* * APPLICATION_COMMAND_CREATE: applicationCommandCreate (deprecated) * * APPLICATION_COMMAND_CREATE: applicationCommandCreate (deprecated)
* * APPLICATION_COMMAND_DELETE: applicationCommandDelete (deprecated) * * APPLICATION_COMMAND_DELETE: applicationCommandDelete (deprecated)
* * APPLICATION_COMMAND_UPDATE: applicationCommandUpdate (deprecated) * * APPLICATION_COMMAND_UPDATE: applicationCommandUpdate (deprecated)
@ -357,9 +230,6 @@ exports.Opcodes = {
* * AUTO_MODERATION_RULE_CREATE: autoModerationRuleCreate * * AUTO_MODERATION_RULE_CREATE: autoModerationRuleCreate
* * AUTO_MODERATION_RULE_DELETE: autoModerationRuleDelete * * AUTO_MODERATION_RULE_DELETE: autoModerationRuleDelete
* * AUTO_MODERATION_RULE_UPDATE: autoModerationRuleUpdate * * AUTO_MODERATION_RULE_UPDATE: autoModerationRuleUpdate
* * CALL_CREATE: callCreate
* * CALL_DELETE: callDelete
* * CALL_UPDATE: callUpdate
* * GUILD_AVAILABLE: guildAvailable * * GUILD_AVAILABLE: guildAvailable
* * GUILD_CREATE: guildCreate * * GUILD_CREATE: guildCreate
* * GUILD_DELETE: guildDelete * * GUILD_DELETE: guildDelete
@ -385,9 +255,6 @@ exports.Opcodes = {
* * CHANNEL_DELETE: channelDelete * * CHANNEL_DELETE: channelDelete
* * CHANNEL_UPDATE: channelUpdate * * CHANNEL_UPDATE: channelUpdate
* * CHANNEL_PINS_UPDATE: channelPinsUpdate * * CHANNEL_PINS_UPDATE: channelPinsUpdate
* * CHANNEL_RECIPIENT_REMOVE: channelRecipientRemove
* * CHANNEL_RECIPIENT_ADD: channelRecipientAdd
* * MESSAGE_ACK: messageAck
* * MESSAGE_CREATE: messageCreate * * MESSAGE_CREATE: messageCreate
* * MESSAGE_DELETE: messageDelete * * MESSAGE_DELETE: messageDelete
* * MESSAGE_UPDATE: messageUpdate * * MESSAGE_UPDATE: messageUpdate
@ -408,7 +275,6 @@ exports.Opcodes = {
* * VOICE_STATE_UPDATE: voiceStateUpdate * * VOICE_STATE_UPDATE: voiceStateUpdate
* * TYPING_START: typingStart * * TYPING_START: typingStart
* * WEBHOOKS_UPDATE: webhookUpdate * * WEBHOOKS_UPDATE: webhookUpdate
* * INTERACTION_CREATE: interactionCreate
* * ERROR: error * * ERROR: error
* * WARN: warn * * WARN: warn
* * DEBUG: debug * * DEBUG: debug
@ -432,6 +298,16 @@ exports.Opcodes = {
* * GUILD_SCHEDULED_EVENT_USER_ADD: guildScheduledEventUserAdd * * GUILD_SCHEDULED_EVENT_USER_ADD: guildScheduledEventUserAdd
* * GUILD_SCHEDULED_EVENT_USER_REMOVE: guildScheduledEventUserRemove * * GUILD_SCHEDULED_EVENT_USER_REMOVE: guildScheduledEventUserRemove
* * GUILD_AUDIT_LOG_ENTRY_CREATE: guildAuditLogEntryCreate * * GUILD_AUDIT_LOG_ENTRY_CREATE: guildAuditLogEntryCreate
* * UNHANDLED_PACKET: unhandledPacket
* * RELATIONSHIP_ADD: relationshipAdd
* * RELATIONSHIP_REMOVE: relationshipRemove
* * RELATIONSHIP_UPDATE: relationshipUpdate
* * CHANNEL_RECIPIENT_ADD: channelRecipientAdd
* * CHANNEL_RECIPIENT_REMOVE: channelRecipientRemove
* * INTERACTION_MODAL_CREATE: interactionModalCreate
* * CALL_CREATE: callCreate
* * CALL_UPDATE: callUpdate
* * CALL_DELETE: callDelete
* @typedef {Object<string, string>} Events * @typedef {Object<string, string>} Events
*/ */
exports.Events = { exports.Events = {
@ -440,7 +316,6 @@ exports.Events = {
API_RESPONSE: 'apiResponse', API_RESPONSE: 'apiResponse',
API_REQUEST: 'apiRequest', API_REQUEST: 'apiRequest',
CLIENT_READY: 'ready', CLIENT_READY: 'ready',
APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE: 'applicationCommandAutocompleteResponse',
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate', APPLICATION_COMMAND_CREATE: 'applicationCommandCreate',
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete', APPLICATION_COMMAND_DELETE: 'applicationCommandDelete',
APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate', APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate',
@ -449,21 +324,16 @@ exports.Events = {
AUTO_MODERATION_RULE_CREATE: 'autoModerationRuleCreate', AUTO_MODERATION_RULE_CREATE: 'autoModerationRuleCreate',
AUTO_MODERATION_RULE_DELETE: 'autoModerationRuleDelete', AUTO_MODERATION_RULE_DELETE: 'autoModerationRuleDelete',
AUTO_MODERATION_RULE_UPDATE: 'autoModerationRuleUpdate', AUTO_MODERATION_RULE_UPDATE: 'autoModerationRuleUpdate',
CALL_CREATE: 'callCreate',
CALL_DELETE: 'callDelete',
CALL_UPDATE: 'callUpdate',
GUILD_AVAILABLE: 'guildAvailable', GUILD_AVAILABLE: 'guildAvailable',
GUILD_CREATE: 'guildCreate', GUILD_CREATE: 'guildCreate',
GUILD_DELETE: 'guildDelete', GUILD_DELETE: 'guildDelete',
GUILD_UPDATE: 'guildUpdate', GUILD_UPDATE: 'guildUpdate',
GUILD_APPLICATION_COMMANDS_UPDATE: 'guildApplicationCommandUpdate',
GUILD_UNAVAILABLE: 'guildUnavailable', GUILD_UNAVAILABLE: 'guildUnavailable',
GUILD_MEMBER_ADD: 'guildMemberAdd', GUILD_MEMBER_ADD: 'guildMemberAdd',
GUILD_MEMBER_REMOVE: 'guildMemberRemove', GUILD_MEMBER_REMOVE: 'guildMemberRemove',
GUILD_MEMBER_UPDATE: 'guildMemberUpdate', GUILD_MEMBER_UPDATE: 'guildMemberUpdate',
GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable', GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable',
GUILD_MEMBERS_CHUNK: 'guildMembersChunk', GUILD_MEMBERS_CHUNK: 'guildMembersChunk',
GUILD_MEMBER_LIST_UPDATE: 'guildMemberListUpdate',
GUILD_INTEGRATIONS_UPDATE: 'guildIntegrationsUpdate', GUILD_INTEGRATIONS_UPDATE: 'guildIntegrationsUpdate',
GUILD_ROLE_CREATE: 'roleCreate', GUILD_ROLE_CREATE: 'roleCreate',
GUILD_ROLE_DELETE: 'roleDelete', GUILD_ROLE_DELETE: 'roleDelete',
@ -479,9 +349,6 @@ exports.Events = {
CHANNEL_DELETE: 'channelDelete', CHANNEL_DELETE: 'channelDelete',
CHANNEL_UPDATE: 'channelUpdate', CHANNEL_UPDATE: 'channelUpdate',
CHANNEL_PINS_UPDATE: 'channelPinsUpdate', CHANNEL_PINS_UPDATE: 'channelPinsUpdate',
CHANNEL_RECIPIENT_REMOVE: 'channelRecipientRemove',
CHANNEL_RECIPIENT_ADD: 'channelRecipientAdd',
MESSAGE_ACK: 'messageAck',
MESSAGE_CREATE: 'messageCreate', MESSAGE_CREATE: 'messageCreate',
MESSAGE_DELETE: 'messageDelete', MESSAGE_DELETE: 'messageDelete',
MESSAGE_UPDATE: 'messageUpdate', MESSAGE_UPDATE: 'messageUpdate',
@ -497,17 +364,11 @@ exports.Events = {
THREAD_MEMBER_UPDATE: 'threadMemberUpdate', THREAD_MEMBER_UPDATE: 'threadMemberUpdate',
THREAD_MEMBERS_UPDATE: 'threadMembersUpdate', THREAD_MEMBERS_UPDATE: 'threadMembersUpdate',
USER_UPDATE: 'userUpdate', USER_UPDATE: 'userUpdate',
USER_SETTINGS_UPDATE: 'userSettingsUpdate',
USER_GUILD_SETTINGS_UPDATE: 'userGuildSettingsUpdate',
PRESENCE_UPDATE: 'presenceUpdate', PRESENCE_UPDATE: 'presenceUpdate',
VOICE_SERVER_UPDATE: 'voiceServerUpdate', VOICE_SERVER_UPDATE: 'voiceServerUpdate',
VOICE_STATE_UPDATE: 'voiceStateUpdate', VOICE_STATE_UPDATE: 'voiceStateUpdate',
TYPING_START: 'typingStart', TYPING_START: 'typingStart',
WEBHOOKS_UPDATE: 'webhookUpdate', WEBHOOKS_UPDATE: 'webhookUpdate',
INTERACTION_CREATE: 'interactionCreate',
INTERACTION_SUCCESS: 'interactionSuccess',
INTERACTION_FAILURE: 'interactionFailure',
INTERACTION_MODAL_CREATE: 'interactionModalCreate',
ERROR: 'error', ERROR: 'error',
WARN: 'warn', WARN: 'warn',
DEBUG: 'debug', DEBUG: 'debug',
@ -531,18 +392,16 @@ exports.Events = {
GUILD_SCHEDULED_EVENT_USER_ADD: 'guildScheduledEventUserAdd', GUILD_SCHEDULED_EVENT_USER_ADD: 'guildScheduledEventUserAdd',
GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove', GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove',
GUILD_AUDIT_LOG_ENTRY_CREATE: 'guildAuditLogEntryCreate', GUILD_AUDIT_LOG_ENTRY_CREATE: 'guildAuditLogEntryCreate',
RELATIONSHIP_ADD: 'relationshipAdd',
RELATIONSHIP_REMOVE: 'relationshipRemove',
RELATIONSHIP_UPDATE: 'relationshipUpdate',
UNHANDLED_PACKET: 'unhandledPacket', UNHANDLED_PACKET: 'unhandledPacket',
CAPTCHA_REQUIRED: 'captchaRequired', RELATIONSHIP_ADD: 'relationshipAdd',
// ! TODO: Add more events RELATIONSHIP_UPDATE: 'relationshipUpdate',
SOUNDBOARD_SOUNDS: 'soundboardSounds', RELATIONSHIP_REMOVE: 'relationshipRemove',
VOICE_CHANNEL_EFFECT_SEND: 'voiceChannelEffectSend', CHANNEL_RECIPIENT_ADD: 'channelRecipientAdd',
GUILD_SOUNDBOARD_SOUND_CREATE: 'guildSoundboardSoundCreate', CHANNEL_RECIPIENT_REMOVE: 'channelRecipientRemove',
GUILD_SOUNDBOARD_SOUND_UPDATE: 'guildSoundboardSoundUpdate', INTERACTION_MODAL_CREATE: 'interactionModalCreate',
GUILD_SOUNDBOARD_SOUNDS_UPDATE: 'guildSoundboardSoundsUpdate', CALL_CREATE: 'callCreate',
GUILD_SOUNDBOARD_SOUND_DELETE: 'guildSoundboardSoundDelete', CALL_UPDATE: 'callUpdate',
CALL_DELETE: 'callDelete',
}; };
/** /**
@ -582,11 +441,10 @@ exports.PartialTypes = keyMirror(['USER', 'CHANNEL', 'GUILD_MEMBER', 'MESSAGE',
* The type of a WebSocket message event, e.g. `MESSAGE_CREATE`. Here are the available events: * The type of a WebSocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
* * READY * * READY
* * RESUMED * * RESUMED
* * APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE
* * APPLICATION_COMMAND_CREATE (deprecated) * * APPLICATION_COMMAND_CREATE (deprecated)
* * APPLICATION_COMMAND_DELETE (deprecated) * * APPLICATION_COMMAND_DELETE (deprecated)
* * APPLICATION_COMMAND_UPDATE (deprecated)
* * APPLICATION_COMMAND_PERMISSIONS_UPDATE * * APPLICATION_COMMAND_PERMISSIONS_UPDATE
* * APPLICATION_COMMAND_UPDATE (deprecated)
* * AUTO_MODERATION_ACTION_EXECUTION * * AUTO_MODERATION_ACTION_EXECUTION
* * AUTO_MODERATION_RULE_CREATE * * AUTO_MODERATION_RULE_CREATE
* * AUTO_MODERATION_RULE_DELETE * * AUTO_MODERATION_RULE_DELETE
@ -631,7 +489,6 @@ exports.PartialTypes = keyMirror(['USER', 'CHANNEL', 'GUILD_MEMBER', 'MESSAGE',
* * VOICE_STATE_UPDATE * * VOICE_STATE_UPDATE
* * VOICE_SERVER_UPDATE * * VOICE_SERVER_UPDATE
* * WEBHOOKS_UPDATE * * WEBHOOKS_UPDATE
* * INTERACTION_CREATE
* * STAGE_INSTANCE_CREATE * * STAGE_INSTANCE_CREATE
* * STAGE_INSTANCE_UPDATE * * STAGE_INSTANCE_UPDATE
* * STAGE_INSTANCE_DELETE * * STAGE_INSTANCE_DELETE
@ -648,7 +505,6 @@ exports.PartialTypes = keyMirror(['USER', 'CHANNEL', 'GUILD_MEMBER', 'MESSAGE',
exports.WSEvents = keyMirror([ exports.WSEvents = keyMirror([
'READY', 'READY',
'RESUMED', 'RESUMED',
'APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE',
'APPLICATION_COMMAND_CREATE', 'APPLICATION_COMMAND_CREATE',
'APPLICATION_COMMAND_DELETE', 'APPLICATION_COMMAND_DELETE',
'APPLICATION_COMMAND_UPDATE', 'APPLICATION_COMMAND_UPDATE',
@ -697,7 +553,6 @@ exports.WSEvents = keyMirror([
'VOICE_STATE_UPDATE', 'VOICE_STATE_UPDATE',
'VOICE_SERVER_UPDATE', 'VOICE_SERVER_UPDATE',
'WEBHOOKS_UPDATE', 'WEBHOOKS_UPDATE',
'INTERACTION_CREATE',
'STAGE_INSTANCE_CREATE', 'STAGE_INSTANCE_CREATE',
'STAGE_INSTANCE_UPDATE', 'STAGE_INSTANCE_UPDATE',
'STAGE_INSTANCE_DELETE', 'STAGE_INSTANCE_DELETE',
@ -725,6 +580,7 @@ exports.WSEvents = keyMirror([
* * `guilds.join`: allows the bot to join the user to any guild it is in using Guild#addMember * * `guilds.join`: allows the bot to join the user to any guild it is in using Guild#addMember
* * `gdm.join`: allows joining the user to a group dm * * `gdm.join`: allows joining the user to a group dm
* * `webhook.incoming`: generates a webhook to a channel * * `webhook.incoming`: generates a webhook to a channel
* * `role_connections.write`: allows your app to update a user's connection and metadata for the app
* @typedef {string} InviteScope * @typedef {string} InviteScope
* @see {@link https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes} * @see {@link https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes}
*/ */
@ -741,6 +597,7 @@ exports.InviteScopes = [
'guilds.join', 'guilds.join',
'gdm.join', 'gdm.join',
'webhook.incoming', 'webhook.incoming',
'role_connections.write',
]; ];
// TODO: change Integration#expireBehavior to this and clean up Integration // TODO: change Integration#expireBehavior to this and clean up Integration
@ -892,7 +749,7 @@ exports.ActivityTypes = createEnum(['PLAYING', 'STREAMING', 'LISTENING', 'WATCHI
* * `GUILD_PRIVATE_THREAD` - a guild text channel's private thread channel * * `GUILD_PRIVATE_THREAD` - a guild text channel's private thread channel
* * `GUILD_STAGE_VOICE` - a guild stage voice channel * * `GUILD_STAGE_VOICE` - a guild stage voice channel
* * `GUILD_DIRECTORY` - the channel in a hub containing guilds * * `GUILD_DIRECTORY` - the channel in a hub containing guilds
* * `GUILD_FORUM` - a guild channel that only contains threads * * `GUILD_FORUM` - a channel that can only contain threads
* * `UNKNOWN` - a generic channel of unknown type, could be Channel or GuildChannel * * `UNKNOWN` - a generic channel of unknown type, could be Channel or GuildChannel
* @typedef {string} ChannelType * @typedef {string} ChannelType
* @see {@link https://discord.com/developers/docs/resources/channel#channel-object-channel-types} * @see {@link https://discord.com/developers/docs/resources/channel#channel-object-channel-types}
@ -1131,7 +988,6 @@ exports.VerificationLevels = createEnum(['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_
* * MAXIMUM_PINS * * MAXIMUM_PINS
* * MAXIMUM_RECIPIENTS * * MAXIMUM_RECIPIENTS
* * MAXIMUM_ROLES * * MAXIMUM_ROLES
* * MAXIMUM_USERNAMES
* * MAXIMUM_WEBHOOKS * * MAXIMUM_WEBHOOKS
* * MAXIMUM_EMOJIS * * MAXIMUM_EMOJIS
* * MAXIMUM_REACTIONS * * MAXIMUM_REACTIONS
@ -1188,7 +1044,6 @@ exports.VerificationLevels = createEnum(['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_
* * INVALID_API_VERSION * * INVALID_API_VERSION
* * FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE * * FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE
* * INVALID_FILE_UPLOADED * * INVALID_FILE_UPLOADED
* * GIFT_CODE_CLAIMED
* * CANNOT_SELF_REDEEM_GIFT * * CANNOT_SELF_REDEEM_GIFT
* * INVALID_GUILD * * INVALID_GUILD
* * INVALID_MESSAGE_TYPE * * INVALID_MESSAGE_TYPE
@ -1203,7 +1058,6 @@ exports.VerificationLevels = createEnum(['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_
* * INSUFFICIENT_BOOSTS * * INSUFFICIENT_BOOSTS
* * INVALID_JSON * * INVALID_JSON
* * TWO_FACTOR_REQUIRED * * TWO_FACTOR_REQUIRED
* * INVALID_TWO_FACTOR_CODE
* * NO_USERS_WITH_DISCORDTAG_EXIST * * NO_USERS_WITH_DISCORDTAG_EXIST
* * REACTION_BLOCKED * * REACTION_BLOCKED
* * RESOURCE_OVERLOADED * * RESOURCE_OVERLOADED
@ -1269,27 +1123,20 @@ exports.APIErrors = {
UNKNOWN_GUILD_SCHEDULED_EVENT_USER: 10071, UNKNOWN_GUILD_SCHEDULED_EVENT_USER: 10071,
BOT_PROHIBITED_ENDPOINT: 20001, BOT_PROHIBITED_ENDPOINT: 20001,
BOT_ONLY_ENDPOINT: 20002, BOT_ONLY_ENDPOINT: 20002,
RPC_PROXY_DISALLOWED: 20003,
CANNOT_SEND_EXPLICIT_CONTENT: 20009, CANNOT_SEND_EXPLICIT_CONTENT: 20009,
ACCOUNT_SCHEDULED_FOR_DELETION: 20011,
NOT_AUTHORIZED: 20012, NOT_AUTHORIZED: 20012,
ACCOUNT_DISABLED: 20013,
SLOWMODE_RATE_LIMIT: 20016, SLOWMODE_RATE_LIMIT: 20016,
ACCOUNT_OWNER_ONLY: 20018, ACCOUNT_OWNER_ONLY: 20018,
ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED: 20022, ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED: 20022,
UNDER_MINIMUM_AGE: 20024,
QUARANTINED: 20026,
CHANNEL_HIT_WRITE_RATELIMIT: 20028, CHANNEL_HIT_WRITE_RATELIMIT: 20028,
SERVER_HIT_WRITE_RATELIMIT: 20029, SERVER_HIT_WRITE_RATELIMIT: 20029,
CONTENT_NOT_ALLOWED: 20031, CONTENT_NOT_ALLOWED: 20031,
GUILD_PREMIUM_LEVEL_TOO_LOW: 20035, GUILD_PREMIUM_LEVEL_TOO_LOW: 20035,
VANITY_URL_REQUIRED_FOR_PUBLISHED_GUILDS: 20040,
MAXIMUM_GUILDS: 30001, MAXIMUM_GUILDS: 30001,
MAXIMUM_FRIENDS: 30002, MAXIMUM_FRIENDS: 30002,
MAXIMUM_PINS: 30003, MAXIMUM_PINS: 30003,
MAXIMUM_RECIPIENTS: 30004, MAXIMUM_RECIPIENTS: 30004,
MAXIMUM_ROLES: 30005, MAXIMUM_ROLES: 30005,
MAXIMUN_USERNAMES: 30006,
MAXIMUM_WEBHOOKS: 30007, MAXIMUM_WEBHOOKS: 30007,
MAXIMUM_EMOJIS: 30008, MAXIMUM_EMOJIS: 30008,
MAXIMUM_REACTIONS: 30010, MAXIMUM_REACTIONS: 30010,
@ -1298,7 +1145,6 @@ exports.APIErrors = {
MAXIMUM_INVITES: 30016, MAXIMUM_INVITES: 30016,
MAXIMUM_ANIMATED_EMOJIS: 30018, MAXIMUM_ANIMATED_EMOJIS: 30018,
MAXIMUM_SERVER_MEMBERS: 30019, MAXIMUM_SERVER_MEMBERS: 30019,
NOT_ENOUGH_GUILD_MEMBERS: 30029,
MAXIMUM_NUMBER_OF_SERVER_CATEGORIES: 30030, MAXIMUM_NUMBER_OF_SERVER_CATEGORIES: 30030,
GUILD_ALREADY_HAS_TEMPLATE: 30031, GUILD_ALREADY_HAS_TEMPLATE: 30031,
MAXIMUM_THREAD_PARTICIPANTS: 30033, MAXIMUM_THREAD_PARTICIPANTS: 30033,
@ -1312,16 +1158,11 @@ exports.APIErrors = {
UNAUTHORIZED: 40001, UNAUTHORIZED: 40001,
ACCOUNT_VERIFICATION_REQUIRED: 40002, ACCOUNT_VERIFICATION_REQUIRED: 40002,
DIRECT_MESSAGES_TOO_FAST: 40003, DIRECT_MESSAGES_TOO_FAST: 40003,
SEND_MESSAGE_TEMPORARILY_DISABLED: 40004,
REQUEST_ENTITY_TOO_LARGE: 40005, REQUEST_ENTITY_TOO_LARGE: 40005,
FEATURE_TEMPORARILY_DISABLED: 40006, FEATURE_TEMPORARILY_DISABLED: 40006,
USER_BANNED: 40007, USER_BANNED: 40007,
CONNECTION_REVOKED: 40012,
DELETE_ACCOUNT_TRANSFER_TEAM_OWNERSHIP: 40028,
TARGET_USER_NOT_CONNECTED_TO_VOICE: 40032, TARGET_USER_NOT_CONNECTED_TO_VOICE: 40032,
ALREADY_CROSSPOSTED: 40033, ALREADY_CROSSPOSTED: 40033,
TAG_REQUIRED: 40067,
INVITES_DISABLED: 40069,
MISSING_ACCESS: 50001, MISSING_ACCESS: 50001,
INVALID_ACCOUNT_TYPE: 50002, INVALID_ACCOUNT_TYPE: 50002,
CANNOT_EXECUTE_ON_DM: 50003, CANNOT_EXECUTE_ON_DM: 50003,
@ -1338,13 +1179,9 @@ exports.APIErrors = {
INVALID_AUTHENTICATION_TOKEN: 50014, INVALID_AUTHENTICATION_TOKEN: 50014,
NOTE_TOO_LONG: 50015, NOTE_TOO_LONG: 50015,
INVALID_BULK_DELETE_QUANTITY: 50016, INVALID_BULK_DELETE_QUANTITY: 50016,
INVALID_MFA_LEVEL: 50017,
INVALID_PASSWORD: 50018,
CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: 50019, CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: 50019,
INVALID_OR_TAKEN_INVITE_CODE: 50020, INVALID_OR_TAKEN_INVITE_CODE: 50020,
CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: 50021, CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: 50021,
INVALID_PHONE_NUMBER: 50022,
INVALID_CLIENT_ID: 50023,
CANNOT_EXECUTE_ON_CHANNEL_TYPE: 50024, CANNOT_EXECUTE_ON_CHANNEL_TYPE: 50024,
INVALID_OAUTH_TOKEN: 50025, INVALID_OAUTH_TOKEN: 50025,
MISSING_OAUTH_SCOPE: 50026, MISSING_OAUTH_SCOPE: 50026,
@ -1357,8 +1194,6 @@ exports.APIErrors = {
INVALID_API_VERSION: 50041, INVALID_API_VERSION: 50041,
FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE: 50045, FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE: 50045,
INVALID_FILE_UPLOADED: 50046, INVALID_FILE_UPLOADED: 50046,
GIFT_CODE_CLAIMED: 50050,
INVALID_GIFT_REDEMPTION_OWNED: 50051,
CANNOT_SELF_REDEEM_GIFT: 50054, CANNOT_SELF_REDEEM_GIFT: 50054,
INVALID_GUILD: 50055, INVALID_GUILD: 50055,
INVALID_MESSAGE_TYPE: 50068, INVALID_MESSAGE_TYPE: 50068,
@ -1369,15 +1204,9 @@ exports.APIErrors = {
INVALID_THREAD_NOTIFICATION_SETTINGS: 50084, INVALID_THREAD_NOTIFICATION_SETTINGS: 50084,
PARAMETER_EARLIER_THAN_CREATION: 50085, PARAMETER_EARLIER_THAN_CREATION: 50085,
GUILD_NOT_AVAILABLE_IN_LOCATION: 50095, GUILD_NOT_AVAILABLE_IN_LOCATION: 50095,
INVALID_CANNOT_FRIEND_SELF: 50096,
GUILD_MONETIZATION_REQUIRED: 50097, GUILD_MONETIZATION_REQUIRED: 50097,
INSUFFICIENT_BOOSTS: 50101, INSUFFICIENT_BOOSTS: 50101,
INVALID_USER_SETTINGS_DATA: 50105,
INVALID_ACTIVITY_LAUNCH_NO_ACCESS: 50106,
INVALID_ACTIVITY_LAUNCH_PREMIUM_TIER: 50107,
INVALID_ACTIVITY_LAUNCH_CONCURRENT_ACTIVITIES: 50108,
INVALID_JSON: 50109, INVALID_JSON: 50109,
INVALID_FILE_ASSET_SIZE_RESIZE_GIF: 50138,
CANNOT_MIX_SUBSCRIPTION_AND_NON_SUBSCRIPTION_ROLES_FOR_EMOJI: 50144, CANNOT_MIX_SUBSCRIPTION_AND_NON_SUBSCRIPTION_ROLES_FOR_EMOJI: 50144,
CANNOT_CONVERT_PREMIUM_EMOJI_TO_NORMAL_EMOJI: 50145, CANNOT_CONVERT_PREMIUM_EMOJI_TO_NORMAL_EMOJI: 50145,
VOICE_MESSAGES_DO_NOT_SUPPORT_ADDITIONAL_CONTENT: 50159, VOICE_MESSAGES_DO_NOT_SUPPORT_ADDITIONAL_CONTENT: 50159,
@ -1385,30 +1214,9 @@ exports.APIErrors = {
VOICE_MESSAGES_MUST_HAVE_SUPPORTING_METADATA: 50161, VOICE_MESSAGES_MUST_HAVE_SUPPORTING_METADATA: 50161,
VOICE_MESSAGES_CANNOT_BE_EDITED: 50162, VOICE_MESSAGES_CANNOT_BE_EDITED: 50162,
YOU_CANNOT_SEND_VOICE_MESSAGES_IN_THIS_CHANNEL: 50173, YOU_CANNOT_SEND_VOICE_MESSAGES_IN_THIS_CHANNEL: 50173,
TWO_FACTOR_ENABLED: 60001,
TWO_FACTOR_DISABLED: 60002,
TWO_FACTOR_REQUIRED: 60003, TWO_FACTOR_REQUIRED: 60003,
TWO_FACTOR_UNVERIFIED: 60004,
TWO_FACTOR_INVALID_SECRET: 60005,
TWO_FACTOR_INVALID_TICKET: 60006,
INVALID_TWO_FACTOR_CODE: 60008,
TWO_FACTOR_INVALID_SESSION: 60009,
PHONE_NUMBER_UNABLE_TO_SEND: 70003,
PHONE_VERIFICATION_REQUIRED: 70007,
RELATIONSHIP_INCOMING_DISABLED: 80000,
RELATIONSHIP_INCOMING_BLOCKED: 80001,
RELATIONSHIP_INVALUD_USER_BOT: 80002,
RELATIONSHIP_INVALID_SELF: 80003,
NO_USERS_WITH_DISCORDTAG_EXIST: 80004, NO_USERS_WITH_DISCORDTAG_EXIST: 80004,
RELATIONSHIP_ALREADY_FRIENDS: 80007,
REACTION_BLOCKED: 90001, REACTION_BLOCKED: 90001,
INVALID_GIFT_REDEMPTION_SUBSCRIPTION_MANAGED: 100021,
INVALID_GIFT_REDEMPTION_SUBSCRIPTION_INCOMPATIBLE: 100023,
INVALID_GIFT_REDEMPTION_INVOICE_OPEN: 100024,
BILLING_NON_REFUNDABLE_PAYMENT_SOURCE: 100060,
LISTING_ALREADY_JOINED: 120000,
LISTING_TOO_MANY_MEMBERS: 120001,
LISTING_JOIN_BLOCKED: 120002,
RESOURCE_OVERLOADED: 130000, RESOURCE_OVERLOADED: 130000,
STAGE_ALREADY_OPEN: 150006, STAGE_ALREADY_OPEN: 150006,
CANNOT_REPLY_WITHOUT_READ_MESSAGE_HISTORY_PERMISSION: 160002, CANNOT_REPLY_WITHOUT_READ_MESSAGE_HISTORY_PERMISSION: 160002,
@ -1423,12 +1231,8 @@ exports.APIErrors = {
LOTTIE_ANIMATION_MAXIMUM_DIMENSIONS_EXCEEDED: 170005, LOTTIE_ANIMATION_MAXIMUM_DIMENSIONS_EXCEEDED: 170005,
STICKER_FRAME_RATE_IS_TOO_SMALL_OR_TOO_LARGE: 170006, STICKER_FRAME_RATE_IS_TOO_SMALL_OR_TOO_LARGE: 170006,
STICKER_ANIMATION_DURATION_EXCEEDS_MAXIMUM_OF_5_SECONDS: 170007, STICKER_ANIMATION_DURATION_EXCEEDS_MAXIMUM_OF_5_SECONDS: 170007,
POGGERMODE_TEMPORARILY_DISABLED: 170008,
CANNOT_UPDATE_A_FINISHED_EVENT: 180000, CANNOT_UPDATE_A_FINISHED_EVENT: 180000,
FAILED_TO_CREATE_STAGE_NEEDED_FOR_STAGE_EVENT: 180002, FAILED_TO_CREATE_STAGE_NEEDED_FOR_STAGE_EVENT: 180002,
AUTOMOD_MESSAGE_BLOCKED: 200000,
AUTOMOD_TITLE_BLOCKED: 200001,
HARMFUL_LINK_MESSAGE_BLOCKED: 240000,
}; };
/** /**
@ -1607,7 +1411,6 @@ exports.AutoModerationActionTypes = createEnum([null, 'BLOCK_MESSAGE', 'SEND_ALE
*/ */
exports.AutoModerationRuleEventTypes = createEnum([null, 'MESSAGE_SEND']); exports.AutoModerationRuleEventTypes = createEnum([null, 'MESSAGE_SEND']);
/** /**
* The type of an {@link Interaction} object: * The type of an {@link Interaction} object:
* * PING * * PING
@ -1656,18 +1459,16 @@ exports.InteractionResponseTypes = createEnum([
* The type of a message component * The type of a message component
* * ACTION_ROW * * ACTION_ROW
* * BUTTON * * BUTTON
* * TEXT_INPUT
* * STRING_SELECT * * STRING_SELECT
* * TEXT_INPUT
* * USER_SELECT * * USER_SELECT
* * ROLE_SELECT * * ROLE_SELECT
* * MENTIONABLE_SELECT * * MENTIONABLE_SELECT
* * CHANNEL_SELECT * * CHANNEL_SELECT
* * SELECT_MENU (deprecated)
* @typedef {string} MessageComponentType * @typedef {string} MessageComponentType
* @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types} * @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
*/ */
exports.MessageComponentTypes = { exports.MessageComponentTypes = createEnum([
...createEnum([
null, null,
'ACTION_ROW', 'ACTION_ROW',
'BUTTON', 'BUTTON',
@ -1677,16 +1478,10 @@ exports.MessageComponentTypes = {
'ROLE_SELECT', 'ROLE_SELECT',
'MENTIONABLE_SELECT', 'MENTIONABLE_SELECT',
'CHANNEL_SELECT', 'CHANNEL_SELECT',
]), ]);
/** @deprecated Use `STRING_SELECT` instead */
SELECT_MENU: 3,
/** @deprecated Use `STRING_SELECT` instead */
3: 'SELECT_MENU',
};
/** /**
* The types of components that are select menus. The available types are: * The types of components that are select menus. The available types are:
* * SELECT_MENU (deprecated)
* * STRING_MENU * * STRING_MENU
* * USER_SELECT * * USER_SELECT
* * ROLE_SELECT * * ROLE_SELECT
@ -1695,8 +1490,7 @@ exports.MessageComponentTypes = {
* @typedef {string} SelectMenuComponentType * @typedef {string} SelectMenuComponentType
* @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types} * @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
*/ */
exports.SelectMenuComponentTypes = { exports.SelectMenuComponentTypes = createEnum([
...createEnum([
...new Array(3).fill(null), ...new Array(3).fill(null),
'STRING_MENU', 'STRING_MENU',
null, null,
@ -1704,10 +1498,7 @@ exports.SelectMenuComponentTypes = {
'ROLE_SELECT', 'ROLE_SELECT',
'MENTIONABLE_SELECT', 'MENTIONABLE_SELECT',
'CHANNEL_SELECT', 'CHANNEL_SELECT',
]), ]);
/** @deprecated Use `STRING_SELECT` instead */
SELECT_MENU: 3,
};
/** /**
* The style of a message button * The style of a message button
@ -1767,27 +1558,6 @@ exports.TextInputStyles = createEnum([null, 'SHORT', 'PARAGRAPH']);
*/ */
exports.GuildScheduledEventPrivacyLevels = createEnum([null, null, 'GUILD_ONLY']); exports.GuildScheduledEventPrivacyLevels = createEnum([null, null, 'GUILD_ONLY']);
/**
* Relationship Enums:
* * 0: NONE
* * 1: FRIEND
* * 2: BLOCKED
* * 3: PENDING_INCOMING
* * 4: PENDING_OUTGOING
* * 5: IMPLICIT
* @typedef {string} RelationshipTypes
* @see {@link https://luna.gitlab.io/discord-unofficial-docs/relationships.html}
*/
exports.RelationshipTypes = createEnum([
'NONE',
'FRIEND',
'BLOCKED',
'PENDING_INCOMING',
'PENDING_OUTGOING',
'IMPLICIT',
]);
/** /**
* The premium tier (Server Boost level) of a guild: * The premium tier (Server Boost level) of a guild:
* * NONE * * NONE
@ -1821,6 +1591,7 @@ exports.GuildScheduledEventStatuses = createEnum([null, 'SCHEDULED', 'ACTIVE', '
*/ */
exports.GuildScheduledEventEntityTypes = createEnum([null, 'STAGE_INSTANCE', 'VOICE', 'EXTERNAL']); exports.GuildScheduledEventEntityTypes = createEnum([null, 'STAGE_INSTANCE', 'VOICE', 'EXTERNAL']);
/* eslint-enable max-len */ /* eslint-enable max-len */
/** /**
* The camera video quality mode of a {@link VoiceChannel}: * The camera video quality mode of a {@link VoiceChannel}:
* * AUTO * * AUTO
@ -1831,7 +1602,7 @@ exports.GuildScheduledEventEntityTypes = createEnum([null, 'STAGE_INSTANCE', 'VO
exports.VideoQualityModes = createEnum([null, 'AUTO', 'FULL']); exports.VideoQualityModes = createEnum([null, 'AUTO', 'FULL']);
/** /**
* Sort {@link ForumChannel} posts by ? * Sort {@link ForumChannel} posts by creation time or activity
* * LATEST_ACTIVITY * * LATEST_ACTIVITY
* * CREATION_DATE * * CREATION_DATE
* @typedef {string} SortOrderType * @typedef {string} SortOrderType
@ -1849,10 +1620,31 @@ exports.SortOrderTypes = createEnum([null, 'LATEST_ACTIVITY', 'CREATION_DATE']);
*/ */
exports.ForumLayoutTypes = createEnum(['NOT_SET', 'LIST_VIEW', 'GALLERY_VIEW']); exports.ForumLayoutTypes = createEnum(['NOT_SET', 'LIST_VIEW', 'GALLERY_VIEW']);
/**
* Relationship Enums:
* * 0: NONE
* * 1: FRIEND
* * 2: BLOCKED
* * 3: PENDING_INCOMING
* * 4: PENDING_OUTGOING
* * 5: IMPLICIT
* @typedef {string} RelationshipTypes
* @see {@link https://luna.gitlab.io/discord-unofficial-docs/relationships.html}
*/
exports.RelationshipTypes = createEnum([
'NONE',
'FRIEND',
'BLOCKED',
'PENDING_INCOMING',
'PENDING_OUTGOING',
'IMPLICIT',
]);
exports._cleanupSymbol = Symbol('djsCleanup'); exports._cleanupSymbol = Symbol('djsCleanup');
function keyMirror(arr) { function keyMirror(arr) {
const tmp = Object.create(null); let tmp = Object.create(null);
for (const value of arr) tmp[value] = value; for (const value of arr) tmp[value] = value;
return tmp; return tmp;
} }
@ -1907,12 +1699,11 @@ function createEnum(keys) {
* @property {Object<InteractionResponseType, number>} InteractionResponseTypes The type of an interaction response. * @property {Object<InteractionResponseType, number>} InteractionResponseTypes The type of an interaction response.
* @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object. * @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object.
* @property {InviteScope[]} InviteScopes The scopes of an invite. * @property {InviteScope[]} InviteScopes The scopes of an invite.
* @property {number} MaxBulkDeletableMessageAge Max bulk deletable message age (Unavailable to selfbots) * @property {Object<RelationshipTypes, number>} RelationshipTypes Relationship Enums
* @property {Object<MembershipState, number>} MembershipStates The value set for a team members membership state. * @property {Object<MembershipState, number>} MembershipStates The value set for a team members membership state.
* @property {Object<MessageButtonStyle, number>} MessageButtonStyles The style of a message button. * @property {Object<MessageButtonStyle, number>} MessageButtonStyles The style of a message button.
* @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component. * @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component.
* @property {MessageType[]} MessageTypes The type of a {@link Message} object. * @property {MessageType[]} MessageTypes The type of a {@link Message} object.
* @property {Object<SelectMenuComponentType, number>} SelectMenuComponentTypes The type of any select menu.
* @property {Object<MFALevel, number>} MFALevels The required MFA level for a guild. * @property {Object<MFALevel, number>} MFALevels The required MFA level for a guild.
* @property {Object<NSFWLevel, number>} NSFWLevels NSFW level of a guild. * @property {Object<NSFWLevel, number>} NSFWLevels NSFW level of a guild.
* @property {Opcodes} Opcodes The types of Opcodes sent to the Gateway. * @property {Opcodes} Opcodes The types of Opcodes sent to the Gateway.
@ -1923,6 +1714,7 @@ function createEnum(keys) {
* @property {Object<PrivacyLevel, number>} PrivacyLevels Privacy level of a {@link StageInstance} object. * @property {Object<PrivacyLevel, number>} PrivacyLevels Privacy level of a {@link StageInstance} object.
* @property {ShardEvents} ShardEvents The type of events emitted by a Shard. * @property {ShardEvents} ShardEvents The type of events emitted by a Shard.
* @property {Status} Status The available statuses of the client. * @property {Status} Status The available statuses of the client.
* @property {Object<SelectMenuComponentType, number>} SelectMenuComponentTypes The type of any select menu.
* @property {Object<StickerFormatType, number>} StickerFormatTypes The value set for a stickers format type. * @property {Object<StickerFormatType, number>} StickerFormatTypes The value set for a stickers format type.
* @property {Object<StickerType, number>} StickerTypes The value set for a stickers type. * @property {Object<StickerType, number>} StickerTypes The value set for a stickers type.
* @property {SweeperKey[]} SweeperKeys The name of an item to be swept in Sweepers. * @property {SweeperKey[]} SweeperKeys The name of an item to be swept in Sweepers.

View File

@ -1,8 +1,8 @@
'use strict'; 'use strict';
const JSONBig = require('json-bigint'); const { UserAgent } = require('./Constants');
const Intents = require('./Intents'); const Intents = require('./Intents');
const { defaultUA } = require('../util/Constants');
/** /**
* Rate limit data * Rate limit data
* @typedef {Object} RateLimitData * @typedef {Object} RateLimitData
@ -28,28 +28,34 @@ const { defaultUA } = require('../util/Constants');
* @returns {Collection} A Collection used to store the cache of the manager. * @returns {Collection} A Collection used to store the cache of the manager.
*/ */
/**
* @typedef {Function} CaptchaSolver
* @param {Captcha} captcha Discord Captcha
* @param {string} UserAgent Current UserAgent
* @returns {Promise<string>} HCaptcha Token
* @example
* const Captcha = require("2captcha")
* // A new 'solver' instance with our API key
* const solver = new Captcha.Solver("<Your 2captcha api key>")
* function solveCaptcha(captcha, UA) {
* return solver.hcaptcha(captcha.captcha_sitekey, 'discord.com', {
* invisible: 1,
* userAgent: UA,
* data: captcha.captcha_rqdata,
* }).then(res => res.data)
* }
*/
/** /**
* 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, * @property {number} [messageCreateEventGuildTimeout=100] The amount of time in milliseconds that the Client to register for messages with each guild
* the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the * @property {number} [DMChannelVoiceStatusSync=0] The amount of time in milliseconds that the Client to register the event with each DM channel (0=Disable)
* recommended amount of shards from Discord and spawn that amount * @property {number} [captchaRetryLimit=3] Captcha retry limit
* @property {CaptchaSolver} [captchaSolver] Captcha Solver
* @property {number} [closeTimeout=5000] The amount of time in milliseconds to wait for the close frame to be received * @property {number} [closeTimeout=5000] 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. Its best to have it between 2_000-6_000 ms. * from the WebSocket.
* @property {boolean} [checkUpdate=true] Display module update information on the screen * <info>Don't have this too high/low. It's best to have it between 2000-6000 ms.</info>
* @property {boolean} [syncStatus=true] Sync state with Discord Client
* @property {boolean} [patchVoice=false] Automatically patch @discordjs/voice module (support for call)
* @property {string} [captchaService=null] Captcha service to use for solving captcha {@link captchaServices}
* @property {string} [captchaKey=null] Captcha service key
* @property {string} [captchaRetryLimit=3] Captcha retry limit
* @property {string} [captchaWithProxy=false] Whether to use proxy for captcha solving
* @property {string} [password=null] Your Discord account password
* @property {boolean} [usingNewAttachmentAPI=true] Use new attachment API
* @property {string} [interactionTimeout=15000] The amount of time in milliseconds to wait for an interaction response, before rejecting
* @property {boolean} [autoRedeemNitro=false] Automaticlly redeems nitro codes <NOTE: there is no cooldown on the auto redeem>
* @property {string} [proxy] Proxy to use for the WebSocket + REST connection (proxy-agent uri type) {@link https://www.npmjs.com/package/proxy-agent}.
* @property {boolean} [DMSync=false] Automatically synchronize call status (DM and group) at startup (event synchronization) [Warning: May cause rate limit to gateway)
* @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) * (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.
@ -86,23 +92,12 @@ const { defaultUA } = require('../util/Constants');
* @property {boolean} [failIfNotExists=true] Default value for {@link ReplyMessageOptions#failIfNotExists} * @property {boolean} [failIfNotExists=true] Default value for {@link ReplyMessageOptions#failIfNotExists}
* @property {string[]} [userAgentSuffix] An array of additional bot info to be appended to the end of the required * @property {string[]} [userAgentSuffix] An array of additional bot info to be appended to the end of the required
* [User Agent](https://discord.com/developers/docs/reference#user-agent) header * [User Agent](https://discord.com/developers/docs/reference#user-agent) header
* @property {PresenceData} [presence={}] Presence data to use upon login * @property {PresenceData} [presence={ status: 'online', since: 0, activities: [], afk: false }] Presence data to use upon login
* @property {IntentsResolvable} [intents=131071] Intents to enable for this connection (but not using) * @property {number} [waitGuildTimeout=15_000] Time in milliseconds that Clients with the GUILDS intent should wait for
* @property {number} [waitGuildTimeout=15000] Time in milliseconds that Clients with the GUILDS intent should wait for * missing guilds to be received before starting the bot. If not specified, the default is 15 seconds.
* @property {number} [messageCreateEventGuildTimeout=100] Time in milliseconds that Clients to register for messages with each guild
* missing guilds to be received before starting the bot. If not specified, the default is 100 milliseconds.
* @property {SweeperOptions} [sweepers={}] Options for cache sweeping * @property {SweeperOptions} [sweepers={}] Options for cache sweeping
* @property {WebsocketOptions} [ws] Options for the WebSocket * @property {WebsocketOptions} [ws] Options for the WebSocket
* @property {HTTPOptions} [http] HTTP options * @property {HTTPOptions} [http] HTTP options
* @property {CustomCaptchaSolver} [captchaSolver] Function to solve a captcha (custom)
*/
/**
* Function to solve a captcha
* @typedef {function} CustomCaptchaSolver
* @param {Captcha} captcha The captcha to solve
* @param {string} userAgent The user agent to use for the request
* @returns {Promise<string>} hcaptcha token
*/ */
/** /**
@ -124,6 +119,7 @@ const { defaultUA } = require('../util/Constants');
/** /**
* WebSocket options (these are left as snake_case to match the API) * WebSocket options (these are left as snake_case to match the API)
* @typedef {Object} WebsocketOptions * @typedef {Object} WebsocketOptions
* @property {AgentOptions} [agent={}] HTTPS Agent options (WS Proxy)
* @property {boolean} [compress=false] Whether to compress data sent on the connection * @property {boolean} [compress=false] Whether to compress data sent on the connection
* @property {WebSocketProperties} [properties] Properties to identify the client with * @property {WebSocketProperties} [properties] Properties to identify the client with
*/ */
@ -158,23 +154,12 @@ class Options extends null {
*/ */
static createDefault() { static createDefault() {
return { return {
jsonTransformer: object => JSONBig.stringify(object),
captchaSolver: captcha => Promise.reject(new Error('CAPTCHA_SOLVER_NOT_IMPLEMENTED', captcha)),
closeTimeout: 5_000,
checkUpdate: true,
syncStatus: true,
autoRedeemNitro: false,
captchaService: '',
captchaKey: null,
captchaRetryLimit: 3,
captchaWithProxy: false,
DMSync: false,
patchVoice: false,
password: null,
usingNewAttachmentAPI: true,
interactionTimeout: 15_000,
waitGuildTimeout: 15_000,
messageCreateEventGuildTimeout: 100, messageCreateEventGuildTimeout: 100,
DMChannelVoiceStatusSync: 0,
captchaRetryLimit: 3,
captchaSolver: () => Promise.reject(new Error('CAPTCHA_SOLVER_NOT_IMPLEMENTED')),
closeTimeout: 5_000,
waitGuildTimeout: 15_000,
shardCount: 1, shardCount: 1,
makeCache: this.cacheWithLimits(this.defaultMakeCacheSettings), makeCache: this.cacheWithLimits(this.defaultMakeCacheSettings),
messageCacheLifetime: 0, messageCacheLifetime: 0,
@ -188,13 +173,11 @@ class Options extends null {
retryLimit: 1, retryLimit: 1,
restTimeOffset: 500, restTimeOffset: 500,
restSweepInterval: 60, restSweepInterval: 60,
failIfNotExists: false, failIfNotExists: true,
userAgentSuffix: [], userAgentSuffix: [],
presence: { status: 'online', since: 0, activities: [], afk: false }, presence: { status: 'online', since: 0, activities: [], afk: false },
sweepers: {}, sweepers: {},
proxy: '',
ws: { ws: {
// eslint-disable-next-line no-undef
capabilities: 0, // https://discord-userdoccers.vercel.app/topics/gateway#gateway-capabilities capabilities: 0, // https://discord-userdoccers.vercel.app/topics/gateway#gateway-capabilities
properties: { properties: {
os: 'Windows', os: 'Windows',
@ -205,7 +188,7 @@ class Options extends null {
os_arch: 'x64', os_arch: 'x64',
app_arch: 'ia32', app_arch: 'ia32',
system_locale: 'en-US', system_locale: 'en-US',
browser_user_agent: defaultUA, browser_user_agent: UserAgent,
browser_version: '22.3.26', browser_version: '22.3.26',
client_build_number: 244874, client_build_number: 244874,
native_build_number: 39515, native_build_number: 39515,
@ -223,11 +206,12 @@ class Options extends null {
api_code_version: 0, api_code_version: 0,
}, },
version: 9, version: 9,
agent: {},
}, },
http: { http: {
agent: {}, agent: {},
headers: { headers: {
'User-Agent': defaultUA, 'User-Agent': UserAgent,
}, },
version: 9, version: 9,
api: 'https://discord.com/api', api: 'https://discord.com/api',
@ -328,7 +312,6 @@ class Options extends null {
static get defaultMakeCacheSettings() { static get defaultMakeCacheSettings() {
return { return {
MessageManager: 200, MessageManager: 200,
/*
ChannelManager: { ChannelManager: {
sweepInterval: 3600, sweepInterval: 3600,
sweepFilter: require('./Util').archivedThreadSweepFilter(), sweepFilter: require('./Util').archivedThreadSweepFilter(),
@ -341,7 +324,6 @@ class Options extends null {
sweepInterval: 3600, sweepInterval: 3600,
sweepFilter: require('./Util').archivedThreadSweepFilter(), sweepFilter: require('./Util').archivedThreadSweepFilter(),
}, },
*/
}; };
} }
} }