From 24918a363bcb9f589c87ab888f423371484f495d Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 4 Jan 2021 16:06:30 +0100 Subject: [PATCH 01/39] feat(GuildBanManager): add GuildBanManager --- esm/discord.mjs | 2 + src/client/actions/ActionsManager.js | 1 + src/client/actions/GuildBanAdd.js | 24 +++ src/client/actions/GuildBanRemove.js | 6 +- .../websocket/handlers/GUILD_BAN_ADD.js | 15 +- src/index.js | 2 + src/managers/GuildBanManager.js | 151 ++++++++++++++++++ src/managers/GuildMemberManager.js | 54 ------- src/structures/Guild.js | 52 +----- src/structures/GuildBan.js | 64 ++++++++ src/structures/GuildMember.js | 2 +- typings/index.d.ts | 33 +++- 12 files changed, 290 insertions(+), 116 deletions(-) create mode 100644 src/client/actions/GuildBanAdd.js create mode 100644 src/managers/GuildBanManager.js create mode 100644 src/structures/GuildBan.js diff --git a/esm/discord.mjs b/esm/discord.mjs index d4625a0b9448..e1eacbd1b02b 100644 --- a/esm/discord.mjs +++ b/esm/discord.mjs @@ -30,6 +30,7 @@ export const { version, BaseGuildEmojiManager, ChannelManager, + GuildBanManager, GuildChannelManager, GuildEmojiManager, GuildEmojiRoleManager, @@ -62,6 +63,7 @@ export const { Emoji, Guild, GuildAuditLogs, + GuildBan, GuildChannel, GuildEmoji, GuildMember, diff --git a/src/client/actions/ActionsManager.js b/src/client/actions/ActionsManager.js index 4055795aa92c..3a239595e9d1 100644 --- a/src/client/actions/ActionsManager.js +++ b/src/client/actions/ActionsManager.js @@ -21,6 +21,7 @@ class ActionsManager { this.register(require('./InviteDelete')); this.register(require('./GuildMemberRemove')); this.register(require('./GuildMemberUpdate')); + this.register(require('./GuildBanAdd')); this.register(require('./GuildBanRemove')); this.register(require('./GuildRoleCreate')); this.register(require('./GuildRoleDelete')); diff --git a/src/client/actions/GuildBanAdd.js b/src/client/actions/GuildBanAdd.js new file mode 100644 index 000000000000..8091d962b5ef --- /dev/null +++ b/src/client/actions/GuildBanAdd.js @@ -0,0 +1,24 @@ +'use strict'; + +const Action = require('./Action'); +const { Events } = require('../../util/Constants'); + +class GuildBanAdd extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + const user = client.users.add(data.user); + + /** + * Emitted whenever a member is banned from a guild. + * @event Client#guildBanAdd + * @param {GuildBan} guild The guild that the ban occurred in + */ + if (guild && user) { + let d = guild.bans.add({ user: user, reason: data.reason }); + client.emit(Events.GUILD_BAN_ADD, d); + } + } +} + +module.exports = GuildBanAdd; diff --git a/src/client/actions/GuildBanRemove.js b/src/client/actions/GuildBanRemove.js index fc28e113f66b..2a8e3658339b 100644 --- a/src/client/actions/GuildBanRemove.js +++ b/src/client/actions/GuildBanRemove.js @@ -14,7 +14,11 @@ class GuildBanRemove extends Action { * @param {Guild} guild The guild that the unban occurred in * @param {User} user The user that was unbanned */ - if (guild && user) client.emit(Events.GUILD_BAN_REMOVE, guild, user); + if (guild && user) { + let d = guild.bans.cache.get(user.id); + guild.bans.cache.delete(user.id); + client.emit(Events.GUILD_BAN_REMOVE, d); + } } } diff --git a/src/client/websocket/handlers/GUILD_BAN_ADD.js b/src/client/websocket/handlers/GUILD_BAN_ADD.js index 5d4a0965c7b5..d8dc0f9da746 100644 --- a/src/client/websocket/handlers/GUILD_BAN_ADD.js +++ b/src/client/websocket/handlers/GUILD_BAN_ADD.js @@ -1,16 +1,5 @@ 'use strict'; -const { Events } = require('../../../util/Constants'); - -module.exports = (client, { d: data }) => { - const guild = client.guilds.cache.get(data.guild_id); - const user = client.users.add(data.user); - - /** - * Emitted whenever a member is banned from a guild. - * @event Client#guildBanAdd - * @param {Guild} guild The guild that the ban occurred in - * @param {User} user The user that was banned - */ - if (guild && user) client.emit(Events.GUILD_BAN_ADD, guild, user); +module.exports = (client, packet) => { + client.actions.GuildBanAdd.handle(packet.d); }; diff --git a/src/index.js b/src/index.js index d83e1bfa83e6..c8881640b84d 100644 --- a/src/index.js +++ b/src/index.js @@ -35,6 +35,7 @@ module.exports = { // Managers BaseGuildEmojiManager: require('./managers/BaseGuildEmojiManager'), ChannelManager: require('./managers/ChannelManager'), + GuildBanManager: require('./managers/GuildBanManager'), GuildChannelManager: require('./managers/GuildChannelManager'), GuildEmojiManager: require('./managers/GuildEmojiManager'), GuildEmojiRoleManager: require('./managers/GuildEmojiRoleManager'), @@ -74,6 +75,7 @@ module.exports = { Emoji: require('./structures/Emoji'), Guild: require('./structures/Guild'), GuildAuditLogs: require('./structures/GuildAuditLogs'), + GuildBan: require('./structures/GuildBan'), GuildChannel: require('./structures/GuildChannel'), GuildEmoji: require('./structures/GuildEmoji'), GuildMember: require('./structures/GuildMember'), diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js new file mode 100644 index 000000000000..36e9fa143d32 --- /dev/null +++ b/src/managers/GuildBanManager.js @@ -0,0 +1,151 @@ +'use strict'; + +const BaseManager = require('./BaseManager'); +const GuildBan = require('../structures/GuildBan'); +const GuildMember = require('../structures/GuildMember'); + +/** + * Manages API methods for Guilds bans and stores their cache. + * @extends {BaseManager} + */ +class GuildBanManager extends BaseManager { + constructor(guild, iterable) { + super(guild.client, iterable, GuildBan); + + /** + * The guild this Manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this Manager + * @type {Collection} + * @name GuildBanManager#cache + */ + + add(data, cache = true) { + return super.add(data, cache, { id: data.user.id, extras: [this.guild] }); + } + + /** + * Options used to fetch a single ban from a guild. + * @typedef {Object} FetchBanOptions + * @property {UserResolvable} user The ban to fetch + * @property {boolean} [cache=true] Whether or not to cache the ban + * @property {boolean} [force=false] Whether to skip the cache check and request the API + */ + + /** + * Fetches bans from Discord. + * @param {UserResolvable|FetchBanOptions} [options] If provided fetches a single ban. + * If undefined, fetches all bans. + * @returns {Promise>} + * @example + * // Fetch all bans from a guild + * guild.bans.fetch() + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single member + * guild.bans.fetch('66564597481480192') + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single ban without checking cache + * guild.bans.fetch({ user, force: true }) + * .then(console.log) + * .catch(console.error) + * @example + * // Fetch a single ban without caching + * guild.bans.fetch({ user, cache: false }) + * .then(console.log) + * .catch(console.error); + */ + fetch(options) { + if (!options) return this._fetchMany(); + const user = this.client.users.resolveID(options); + if (user) return this._fetchSingle({ user, cache: true }); + if (options.user) { + options.user = this.client.users.resolveID(options.user); + } + if (!options.user) throw new Error('FETCH_BAN_RESOLVE_ID'); + return this._fetchSingle(options); + } + + _fetchSingle({ user, cache, force = false }) { + if (!force) { + const existing = this.cache.get(user); + if (existing && !existing.partial) return Promise.resolve(existing); + } + + return this.client.api + .guilds(this.guild.id) + .bans(user) + .get() + .then(data => this.add(data, cache)); + } + + async _fetchMany() { + const data = await this.client.api.guilds(this.guild.id).bans().get(); + for (let ban of data) this.add(ban); + return this.cache; + } + + /** + * Bans a user from the guild. + * @param {UserResolvable} user The user to ban + * @param {Object} [options] Options for the ban + * @param {number} [options.days=0] Number of days of messages to delete, must be between 0 and 7 + * @param {string} [options.reason] Reason for banning + * @returns {Promise} Result object will be resolved as specifically as possible. + * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot + * be resolved, the user ID will be the result. + * @example + * // Ban a user by ID (or with a user/guild member object) + * guild.bans.ban('84484653687267328') + * .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`)) + * .catch(console.error); + */ + ban(user, options = { days: 0 }) { + if (typeof options !== 'object') return Promise.reject(new TypeError('INVALID_TYPE', 'options', 'object', true)); + if (options.days) options.delete_message_days = options.days; + const id = this.client.users.resolveID(user); + if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID', true)); + return this.client.api + .guilds(this.guild.id) + .bans[id].put({ data: options }) + .then(() => { + if (user instanceof GuildMember) return user; + const _user = this.client.users.resolve(id); + if (_user) { + const member = this.resolve(_user); + return member || _user; + } + return id; + }); + } + + /** + * Unbans a user from the guild. + * @param {UserResolvable} user The user to unban + * @param {string} [reason] Reason for unbanning user + * @returns {Promise} + * @example + * // Unban a user by ID (or with a user/guild member object) + * guild.bans.unban('84484653687267328') + * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`)) + * .catch(console.error); + */ + unban(user, reason) { + const id = this.client.users.resolveID(user); + if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID')); + return this.client.api + .guilds(this.guild.id) + .bans[id].delete({ reason }) + .then(() => this.client.users.resolve(user)); + } +} + +module.exports = GuildBanManager; diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index dcdecf277d77..67f44d2e1ce1 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -194,60 +194,6 @@ class GuildMemberManager extends BaseManager { .then(data => data.pruned); } - /** - * Bans a user from the guild. - * @param {UserResolvable} user The user to ban - * @param {Object} [options] Options for the ban - * @param {number} [options.days=0] Number of days of messages to delete, must be between 0 and 7 - * @param {string} [options.reason] Reason for banning - * @returns {Promise} Result object will be resolved as specifically as possible. - * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot - * be resolved, the user ID will be the result. - * @example - * // Ban a user by ID (or with a user/guild member object) - * guild.members.ban('84484653687267328') - * .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`)) - * .catch(console.error); - */ - ban(user, options = { days: 0 }) { - if (typeof options !== 'object') return Promise.reject(new TypeError('INVALID_TYPE', 'options', 'object', true)); - if (options.days) options.delete_message_days = options.days; - const id = this.client.users.resolveID(user); - if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID', true)); - return this.client.api - .guilds(this.guild.id) - .bans[id].put({ data: options }) - .then(() => { - if (user instanceof GuildMember) return user; - const _user = this.client.users.resolve(id); - if (_user) { - const member = this.resolve(_user); - return member || _user; - } - return id; - }); - } - - /** - * Unbans a user from the guild. - * @param {UserResolvable} user The user to unban - * @param {string} [reason] Reason for unbanning user - * @returns {Promise} - * @example - * // Unban a user by ID (or with a user/guild member object) - * guild.members.unban('84484653687267328') - * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`)) - * .catch(console.error); - */ - unban(user, reason) { - const id = this.client.users.resolveID(user); - if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID')); - return this.client.api - .guilds(this.guild.id) - .bans[id].delete({ reason }) - .then(() => this.client.users.resolve(user)); - } - _fetchSingle({ user, cache, force = false }) { if (!force) { const existing = this.cache.get(user); diff --git a/src/structures/Guild.js b/src/structures/Guild.js index ee0d70c1fd0f..2498f9f4a279 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -10,6 +10,7 @@ const Invite = require('./Invite'); const VoiceRegion = require('./VoiceRegion'); const Webhook = require('./Webhook'); const { Error, TypeError } = require('../errors'); +const GuildBanManager = require('../managers/GuildBanManager'); const GuildChannelManager = require('../managers/GuildChannelManager'); const GuildEmojiManager = require('../managers/GuildEmojiManager'); const GuildMemberManager = require('../managers/GuildMemberManager'); @@ -55,6 +56,12 @@ class Guild extends Base { */ this.channels = new GuildChannelManager(this); + /** + * A manager of the bans belonging to this guild + * @type {GuildBanManager} + */ + this.bans = new GuildBanManager(this); + /** * A manager of the roles belonging to this guild * @type {RoleManager} @@ -518,6 +525,7 @@ class Guild extends Base { * @readonly */ get nameAcronym() { + if (!this.name) return null; return this.name .replace(/'s /g, ' ') .replace(/\w+/g, e => e[0]) @@ -641,50 +649,6 @@ class Guild extends Base { }); } - /** - * An object containing information about a guild member's ban. - * @typedef {Object} BanInfo - * @property {User} user User that was banned - * @property {?string} reason Reason the user was banned - */ - - /** - * Fetches information on a banned user from this guild. - * @param {UserResolvable} user The User to fetch the ban info of - * @returns {Promise} - */ - fetchBan(user) { - const id = this.client.users.resolveID(user); - if (!id) throw new Error('FETCH_BAN_RESOLVE_ID'); - return this.client.api - .guilds(this.id) - .bans(id) - .get() - .then(ban => ({ - reason: ban.reason, - user: this.client.users.add(ban.user), - })); - } - - /** - * Fetches a collection of banned users in this guild. - * @returns {Promise>} - */ - fetchBans() { - return this.client.api - .guilds(this.id) - .bans.get() - .then(bans => - bans.reduce((collection, ban) => { - collection.set(ban.user.id, { - reason: ban.reason, - user: this.client.users.add(ban.user), - }); - return collection; - }, new Collection()), - ); - } - /** * Fetches a collection of integrations to this guild. * Resolves with a collection mapping integrations by their ids. diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js new file mode 100644 index 000000000000..804eaa5403f0 --- /dev/null +++ b/src/structures/GuildBan.js @@ -0,0 +1,64 @@ +'use strict'; + +const Base = require('./Base'); + +/** + * Represents a ban of a guild on Discord. + * @extends {Base} + */ +class GuildBan extends Base { + /** + * @param {Client} client The instantiating client + * @param {Object} data The data for the ban + * @param {Guild} guild The guild the ban is part of + */ + constructor(client, data, guild) { + super(client); + + /** + * The guild that this member is part of + * @type {Guild} + */ + this.guild = guild; + + /** + * The reason for the ban + * @type {?string} + */ + this.reason = null; + + /** + * The user this ban applies to + * @type {User} + */ + this.user = null; + + if (data) this._patch(data); + } + + _patch(data) { + if ('user' in data) this.user = this.client.users.add(data.user, true); + if ('reason' in data) this.reason = data.reason; + } + + /** + * Whether this GuildBan is a partial + * If the reason is not provided the value is null + * @type {boolean} + * @readonly + */ + get partial() { + return this.reason === undefined; + } + + /** + * Fetches this GuildBan. + * @param {boolean} [force=false] Whether to skip the cache check and request the API + * @returns {Promise} + */ + fetch(force = false) { + return this.guild.bans.fetch({ user: this.user, cache: true, force }); + } +} + +module.exports = GuildBan; diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index f29c9ff7db23..07a57ca304cc 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -362,7 +362,7 @@ class GuildMember extends Base { * .catch(console.error); */ ban(options) { - return this.guild.members.ban(this, options); + return this.guild.bans.ban(this, options); } /** diff --git a/typings/index.d.ts b/typings/index.d.ts index 9cf19cce4c66..5a58b27f8383 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -579,6 +579,7 @@ declare module 'discord.js' { public approximatePresenceCount: number | null; public available: boolean; public banner: string | null; + public bans: GuildBanManager; public channels: GuildChannelManager; public readonly createdAt: Date; public readonly createdTimestamp: number; @@ -731,6 +732,15 @@ declare module 'discord.js' { public toJSON(): object; } + export class GuildBan { + constructor(client: Client, data: object, guild: Guild); + public readonly guild: Guild; + public readonly user: User; + public readonly partial: boolean; + public readonly reason?: string; + public fetch(force?: boolean): Promise; + } + export class GuildChannel extends Channel { constructor(guild: Guild, data?: object); private memberPermissions(member: GuildMember): Readonly; @@ -1939,13 +1949,22 @@ declare module 'discord.js' { export class GuildMemberManager extends BaseManager { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; - public ban(user: UserResolvable, options?: BanOptions): Promise; public fetch( options: UserResolvable | FetchMemberOptions | (FetchMembersOptions & { user: UserResolvable }), ): Promise; public fetch(options?: FetchMembersOptions): Promise>; public prune(options: GuildPruneMembersOptions & { dry?: false; count: false }): Promise; public prune(options?: GuildPruneMembersOptions): Promise; + } + + export class GuildBanManager extends BaseManager { + constructor(guild: Guild, iterable?: Iterable); + public guild: Guild; + public ban(user: UserResolvable, options?: BanOptions): Promise; + public fetch( + options: UserResolvable | FetchBanOptions | (UserResolvable & { user: UserResolvable }), + ): Promise; + public fetch(): Promise>; public unban(user: UserResolvable, reason?: string): Promise; } @@ -2376,8 +2395,8 @@ declare module 'discord.js' { emojiDelete: [emoji: GuildEmoji]; emojiUpdate: [oldEmoji: GuildEmoji, newEmoji: GuildEmoji]; error: [error: Error]; - guildBanAdd: [guild: Guild, user: User]; - guildBanRemove: [guild: Guild, user: User]; + guildBanAdd: [ban: GuildBan]; + guildBanRemove: [ban: GuildBan]; guildCreate: [guild: Guild]; guildDelete: [guild: Guild]; guildUnavailable: [guild: Guild]; @@ -2570,6 +2589,12 @@ declare module 'discord.js' { User: typeof User; } + interface FetchBanOptions { + user: UserResolvable; + cache?: boolean; + force?: boolean; + } + interface FetchIntegrationsOptions { includeApplications?: boolean; } @@ -2661,6 +2686,8 @@ declare module 'discord.js' { UNKNOWN?: string; } + type GuildBanResolvable = GuildBan | UserResolvable; + type GuildChannelResolvable = Snowflake | GuildChannel; interface GuildCreateChannelOptions { From 6e2986c170c7d013796f7a8e1d754f44a4d83a4d Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sun, 31 Jan 2021 23:06:30 +0100 Subject: [PATCH 02/39] fix(GuildBanManager): _fetchMany cache option --- src/managers/GuildBanManager.js | 40 +++++++++++++++++++++++++-------- src/structures/GuildBan.js | 6 ++--- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 36e9fa143d32..9531f255b700 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -3,6 +3,7 @@ const BaseManager = require('./BaseManager'); const GuildBan = require('../structures/GuildBan'); const GuildMember = require('../structures/GuildMember'); +const Collection = require('../util/Collection'); /** * Manages API methods for Guilds bans and stores their cache. @@ -29,27 +30,47 @@ class GuildBanManager extends BaseManager { return super.add(data, cache, { id: data.user.id, extras: [this.guild] }); } + /** + * Data that resolves to give a GuildBan object. This can be: + * * A GuildBan object + * * A User resolvable + * @typedef {GuildBan|UserResolvable} GuildBanResolvable + */ + + /** + * Resolves a GuildBanResolvable to a GuildBan object. + * @param {GuildBanResolvable} ban The ban that is in the guild + * @returns {?GuildBan} + */ + resolve(ban) { + const banResolvable = super.resolve(ban); + if (banResolvable) return banResolvable; + const userResolvable = this.client.users.resolveID(ban); + if (userResolvable) return super.resolve(userResolvable); + return null; + } + /** * Options used to fetch a single ban from a guild. * @typedef {Object} FetchBanOptions * @property {UserResolvable} user The ban to fetch - * @property {boolean} [cache=true] Whether or not to cache the ban + * @property {boolean} [cache=true] Whether or not to cache the fetched ban * @property {boolean} [force=false] Whether to skip the cache check and request the API */ /** - * Fetches bans from Discord. + * Fetches ban(s) from Discord. * @param {UserResolvable|FetchBanOptions} [options] If provided fetches a single ban. * If undefined, fetches all bans. - * @returns {Promise>} + * @returns {Promise|Promise>} * @example * // Fetch all bans from a guild * guild.bans.fetch() * .then(console.log) * .catch(console.error); * @example - * // Fetch a single member - * guild.bans.fetch('66564597481480192') + * // Fetch a single ban + * guild.bans.fetch('351871113346809860') * .then(console.log) * .catch(console.error); * @example @@ -64,7 +85,7 @@ class GuildBanManager extends BaseManager { * .catch(console.error); */ fetch(options) { - if (!options) return this._fetchMany(); + if (!options) return this._fetchMany(options.cache); const user = this.client.users.resolveID(options); if (user) return this._fetchSingle({ user, cache: true }); if (options.user) { @@ -87,10 +108,11 @@ class GuildBanManager extends BaseManager { .then(data => this.add(data, cache)); } - async _fetchMany() { + async _fetchMany(cache) { const data = await this.client.api.guilds(this.guild.id).bans().get(); - for (let ban of data) this.add(ban); - return this.cache; + const bans = new Collection(); + for (const ban of data) bans.set(ban.user.id, this.add(ban, cache)); + return bans; } /** diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js index 804eaa5403f0..08221d17d620 100644 --- a/src/structures/GuildBan.js +++ b/src/structures/GuildBan.js @@ -3,20 +3,20 @@ const Base = require('./Base'); /** - * Represents a ban of a guild on Discord. + * Represents a ban in a guild on Discord. * @extends {Base} */ class GuildBan extends Base { /** * @param {Client} client The instantiating client * @param {Object} data The data for the ban - * @param {Guild} guild The guild the ban is part of + * @param {Guild} guild The guild in which the ban is */ constructor(client, data, guild) { super(client); /** - * The guild that this member is part of + * The guild in which the ban is * @type {Guild} */ this.guild = guild; From 09b8752272f21db5e1426b224c557e56d11bae31 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 1 Feb 2021 22:50:33 +0100 Subject: [PATCH 03/39] fix(GuildBanAdd): don't create unnecessary variable Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> --- src/client/actions/GuildBanAdd.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/actions/GuildBanAdd.js b/src/client/actions/GuildBanAdd.js index 8091d962b5ef..5b1674152135 100644 --- a/src/client/actions/GuildBanAdd.js +++ b/src/client/actions/GuildBanAdd.js @@ -15,8 +15,7 @@ class GuildBanAdd extends Action { * @param {GuildBan} guild The guild that the ban occurred in */ if (guild && user) { - let d = guild.bans.add({ user: user, reason: data.reason }); - client.emit(Events.GUILD_BAN_ADD, d); + client.emit(Events.GUILD_BAN_ADD, guild.bans.add({ user: user, reason: data.reason })); } } } From d25a9e5726e0a7f576b52c8c2b0529b6611a2060 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 1 Feb 2021 22:51:13 +0100 Subject: [PATCH 04/39] fix(GuildBan): use typeof instead of === Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> --- src/structures/GuildBan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js index 08221d17d620..15ef55cb0908 100644 --- a/src/structures/GuildBan.js +++ b/src/structures/GuildBan.js @@ -48,7 +48,7 @@ class GuildBan extends Base { * @readonly */ get partial() { - return this.reason === undefined; + return typeof this.reason === 'undefined'; } /** From 4e04ed5d1c64408c9b5a715ec012a45a53faab32 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 1 Feb 2021 22:52:05 +0100 Subject: [PATCH 05/39] style(GuildBanRemove): let -> const and variable name Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> --- src/client/actions/GuildBanRemove.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/actions/GuildBanRemove.js b/src/client/actions/GuildBanRemove.js index 2a8e3658339b..18a0dca4017e 100644 --- a/src/client/actions/GuildBanRemove.js +++ b/src/client/actions/GuildBanRemove.js @@ -15,9 +15,9 @@ class GuildBanRemove extends Action { * @param {User} user The user that was unbanned */ if (guild && user) { - let d = guild.bans.cache.get(user.id); + const ban = guild.bans.cache.get(user.id); guild.bans.cache.delete(user.id); - client.emit(Events.GUILD_BAN_REMOVE, d); + client.emit(Events.GUILD_BAN_REMOVE, ban); } } } From 11a7b2ebcc51e09096921856b3accbc0f6e8a2cc Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 1 Feb 2021 22:54:53 +0100 Subject: [PATCH 06/39] style(GuildBanManager): remove unnecessary () Co-authored-by: Jan <66554238+vaporox@users.noreply.github.com> --- src/managers/GuildBanManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 9531f255b700..91da19ae665a 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -109,7 +109,7 @@ class GuildBanManager extends BaseManager { } async _fetchMany(cache) { - const data = await this.client.api.guilds(this.guild.id).bans().get(); + const data = await this.client.api.guilds(this.guild.id).bans.get(); const bans = new Collection(); for (const ban of data) bans.set(ban.user.id, this.add(ban, cache)); return bans; From ff49f2ce133d83e461e36f77f293fef6edbc25de Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 1 Feb 2021 23:10:47 +0100 Subject: [PATCH 07/39] fix(GuildBanAdd): pass user instead of creating it --- src/client/actions/GuildBanAdd.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/client/actions/GuildBanAdd.js b/src/client/actions/GuildBanAdd.js index 5b1674152135..31eea6562577 100644 --- a/src/client/actions/GuildBanAdd.js +++ b/src/client/actions/GuildBanAdd.js @@ -7,15 +7,14 @@ class GuildBanAdd extends Action { handle(data) { const client = this.client; const guild = client.guilds.cache.get(data.guild_id); - const user = client.users.add(data.user); /** * Emitted whenever a member is banned from a guild. * @event Client#guildBanAdd - * @param {GuildBan} guild The guild that the ban occurred in + * @param {GuildBan} ban The ban that occurred */ - if (guild && user) { - client.emit(Events.GUILD_BAN_ADD, guild.bans.add({ user: user, reason: data.reason })); + if (guild) { + client.emit(Events.GUILD_BAN_ADD, guild.bans.add({ user: data.user, reason: data.reason })); } } } From b7aad426be20fe89f2f2569449c03de636767216 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 1 Feb 2021 23:22:27 +0100 Subject: [PATCH 08/39] revert(Guild): remove nameAcronym fix --- src/structures/Guild.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 2498f9f4a279..055f065d63cc 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -525,7 +525,6 @@ class Guild extends Base { * @readonly */ get nameAcronym() { - if (!this.name) return null; return this.name .replace(/'s /g, ' ') .replace(/\w+/g, e => e[0]) From 28505d785c7255db49fc4798ae9899b18957c6a5 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Mon, 1 Feb 2021 23:39:57 +0100 Subject: [PATCH 09/39] fix(GuildBanManager): remove default value for cache in add method Co-authored-by: Jan <66554238+vaporox@users.noreply.github.com> --- src/managers/GuildBanManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 91da19ae665a..dd4e292dc27a 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -26,7 +26,7 @@ class GuildBanManager extends BaseManager { * @name GuildBanManager#cache */ - add(data, cache = true) { + add(data, cache) { return super.add(data, cache, { id: data.user.id, extras: [this.guild] }); } From a12994319f9c8f4cd12de50b745d800704566980 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 2 Feb 2021 00:08:08 +0100 Subject: [PATCH 10/39] fix(GuildBanManager): add ability to fetch all bans without caching --- src/managers/GuildBanManager.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index dd4e292dc27a..521f3b112db6 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -85,13 +85,16 @@ class GuildBanManager extends BaseManager { * .catch(console.error); */ fetch(options) { - if (!options) return this._fetchMany(options.cache); + if (!options) return this._fetchMany(); const user = this.client.users.resolveID(options); if (user) return this._fetchSingle({ user, cache: true }); if (options.user) { options.user = this.client.users.resolveID(options.user); } - if (!options.user) throw new Error('FETCH_BAN_RESOLVE_ID'); + if (!options.user) { + if ('cache' in options) return this._fetchMany(options.cache); + throw new Error('FETCH_BAN_RESOLVE_ID'); + } return this._fetchSingle(options); } From b76e2b53818b77916e2b1513b3f3c15509dec40b Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 2 Feb 2021 16:00:22 +0100 Subject: [PATCH 11/39] fix(GuildBanRemove): create GuildBan in case its not cached + jsdoc --- src/client/actions/GuildBanRemove.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/client/actions/GuildBanRemove.js b/src/client/actions/GuildBanRemove.js index 18a0dca4017e..b7932c3909ed 100644 --- a/src/client/actions/GuildBanRemove.js +++ b/src/client/actions/GuildBanRemove.js @@ -1,22 +1,23 @@ 'use strict'; const Action = require('./Action'); +const GuildBan = require('../../structures/GuildBan'); const { Events } = require('../../util/Constants'); class GuildBanRemove extends Action { handle(data) { const client = this.client; const guild = client.guilds.cache.get(data.guild_id); - const user = client.users.add(data.user); + /** * Emitted whenever a member is unbanned from a guild. * @event Client#guildBanRemove - * @param {Guild} guild The guild that the unban occurred in - * @param {User} user The user that was unbanned + * @param {GuildBan} ban The ban that was removed */ - if (guild && user) { - const ban = guild.bans.cache.get(user.id); - guild.bans.cache.delete(user.id); + if (guild) { + const ban = + guild.bans.cache.get(data.user.id) ?? new GuildBan(client, { user: data.user, reason: data.reason }, guild); + guild.bans.cache.delete(ban.user.id); client.emit(Events.GUILD_BAN_REMOVE, ban); } } From b6bb51d46376b9c1bb05c519e846cb523ce1927e Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 2 Feb 2021 20:38:23 +0100 Subject: [PATCH 12/39] refactor(GuildBanManager): make methods async --- src/managers/GuildBanManager.js | 47 +++++++++++++-------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 521f3b112db6..0dadb9181235 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -98,17 +98,14 @@ class GuildBanManager extends BaseManager { return this._fetchSingle(options); } - _fetchSingle({ user, cache, force = false }) { + async _fetchSingle({ user, cache, force = false }) { if (!force) { const existing = this.cache.get(user); - if (existing && !existing.partial) return Promise.resolve(existing); + if (existing && !existing.partial) return existing; } - return this.client.api - .guilds(this.guild.id) - .bans(user) - .get() - .then(data => this.add(data, cache)); + const data = await this.client.api.guilds(this.guild.id).bans(user).get(); + return this.add(data, cache); } async _fetchMany(cache) { @@ -133,23 +130,19 @@ class GuildBanManager extends BaseManager { * .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`)) * .catch(console.error); */ - ban(user, options = { days: 0 }) { - if (typeof options !== 'object') return Promise.reject(new TypeError('INVALID_TYPE', 'options', 'object', true)); + async ban(user, options = { days: 0 }) { + if (typeof options !== 'object') throw new TypeError('INVALID_TYPE', 'options', 'object', true); if (options.days) options.delete_message_days = options.days; const id = this.client.users.resolveID(user); - if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID', true)); - return this.client.api - .guilds(this.guild.id) - .bans[id].put({ data: options }) - .then(() => { - if (user instanceof GuildMember) return user; - const _user = this.client.users.resolve(id); - if (_user) { - const member = this.resolve(_user); - return member || _user; - } - return id; - }); + if (!id) throw new Error('BAN_RESOLVE_ID', true); + await this.client.api.guilds(this.guild.id).bans[id].put({ data: options }); + if (user instanceof GuildMember) return user; + const _user = this.client.users.resolve(id); + if (_user) { + const member = this.resolve(_user); + return member || _user; + } + return id; } /** @@ -163,13 +156,11 @@ class GuildBanManager extends BaseManager { * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`)) * .catch(console.error); */ - unban(user, reason) { + async unban(user, reason) { const id = this.client.users.resolveID(user); - if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID')); - return this.client.api - .guilds(this.guild.id) - .bans[id].delete({ reason }) - .then(() => this.client.users.resolve(user)); + if (!id) throw new Error('BAN_RESOLVE_ID'); + await this.client.api.guilds(this.guild.id).bans[id].delete({ reason }); + return this.client.users.resolve(user); } } From 92ce509f17b7dbb5c0046eb5a6eac87c232e3923 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 2 Feb 2021 22:02:34 +0100 Subject: [PATCH 13/39] fix(GuildBanManager): use reject instead of throw Co-authored-by: Jan <66554238+vaporox@users.noreply.github.com> --- src/managers/GuildBanManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 0dadb9181235..a68111da3225 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -93,7 +93,7 @@ class GuildBanManager extends BaseManager { } if (!options.user) { if ('cache' in options) return this._fetchMany(options.cache); - throw new Error('FETCH_BAN_RESOLVE_ID'); + return Promise.reject(new Error('FETCH_BAN_RESOLVE_ID')); } return this._fetchSingle(options); } From a73f6ffd77962ae3c0e148158de81613ab2980b9 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 21:50:39 +0100 Subject: [PATCH 14/39] fix(GuildBan): remove reason & user from constructor & if data check --- src/structures/GuildBan.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js index 15ef55cb0908..9e892ee0f293 100644 --- a/src/structures/GuildBan.js +++ b/src/structures/GuildBan.js @@ -21,19 +21,7 @@ class GuildBan extends Base { */ this.guild = guild; - /** - * The reason for the ban - * @type {?string} - */ - this.reason = null; - - /** - * The user this ban applies to - * @type {User} - */ - this.user = null; - - if (data) this._patch(data); + this._patch(data); } _patch(data) { From bb141f4d4fa8c01a584257263426ca661ae6d3a5 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 21:57:35 +0100 Subject: [PATCH 15/39] docs(GuildBan): remove readonly from guild, user & reason --- typings/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 5a58b27f8383..b8715586b8b0 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -734,10 +734,10 @@ declare module 'discord.js' { export class GuildBan { constructor(client: Client, data: object, guild: Guild); - public readonly guild: Guild; - public readonly user: User; + public guild: Guild; + public user: User; public readonly partial: boolean; - public readonly reason?: string; + public reason?: string | null; public fetch(force?: boolean): Promise; } From 3f60821b86ef0074c15c9dced56e9e04461b039b Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 22:24:14 +0100 Subject: [PATCH 16/39] fix(GuildBan): add back jsdoc for user & reason fields --- src/structures/GuildBan.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js index 9e892ee0f293..a2b40b0d0bef 100644 --- a/src/structures/GuildBan.js +++ b/src/structures/GuildBan.js @@ -25,8 +25,20 @@ class GuildBan extends Base { } _patch(data) { - if ('user' in data) this.user = this.client.users.add(data.user, true); - if ('reason' in data) this.reason = data.reason; + if ('user' in data) { + /** + * The user this ban applies to + * @type {User} + */ + this.user = this.client.users.add(data.user, true); + } + if ('reason' in data) { + /** + * The reason for the ban + * @type {?string} + */ + this.reason = data.reason; + } } /** From a7927ae1ac8b3a85839eaa353bd3ae33554657c0 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 22:27:48 +0100 Subject: [PATCH 17/39] fix(GuildBanRemove): pass data directly Co-authored-by: Jan <66554238+vaporox@users.noreply.github.com> --- src/client/actions/GuildBanRemove.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/actions/GuildBanRemove.js b/src/client/actions/GuildBanRemove.js index b7932c3909ed..515473599197 100644 --- a/src/client/actions/GuildBanRemove.js +++ b/src/client/actions/GuildBanRemove.js @@ -15,8 +15,7 @@ class GuildBanRemove extends Action { * @param {GuildBan} ban The ban that was removed */ if (guild) { - const ban = - guild.bans.cache.get(data.user.id) ?? new GuildBan(client, { user: data.user, reason: data.reason }, guild); + const ban = guild.bans.cache.get(data.user.id) ?? new GuildBan(client, data, guild); guild.bans.cache.delete(ban.user.id); client.emit(Events.GUILD_BAN_REMOVE, ban); } From 1e834c2f159d1b4ca76d7fbfa38a63da191cf2fd Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 22:32:42 +0100 Subject: [PATCH 18/39] fix(GuildBanAdd): pass data directly --- src/client/actions/GuildBanAdd.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/client/actions/GuildBanAdd.js b/src/client/actions/GuildBanAdd.js index 31eea6562577..2efe1634737d 100644 --- a/src/client/actions/GuildBanAdd.js +++ b/src/client/actions/GuildBanAdd.js @@ -13,9 +13,7 @@ class GuildBanAdd extends Action { * @event Client#guildBanAdd * @param {GuildBan} ban The ban that occurred */ - if (guild) { - client.emit(Events.GUILD_BAN_ADD, guild.bans.add({ user: data.user, reason: data.reason })); - } + if (guild) client.emit(Events.GUILD_BAN_ADD, guild.bans.add(data)); } } From 94d778e133db9983113e6098186ee174b1c15b6a Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 23:05:34 +0100 Subject: [PATCH 19/39] fix(GuildBan): remove if user in data check since it will always be Co-authored-by: Jan <66554238+vaporox@users.noreply.github.com> --- src/structures/GuildBan.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js index a2b40b0d0bef..5b7d8b0a6ce3 100644 --- a/src/structures/GuildBan.js +++ b/src/structures/GuildBan.js @@ -25,13 +25,12 @@ class GuildBan extends Base { } _patch(data) { - if ('user' in data) { - /** - * The user this ban applies to - * @type {User} - */ - this.user = this.client.users.add(data.user, true); - } + /** + * The user this ban applies to + * @type {User} + */ + this.user = this.client.users.add(data.user, true); + if ('reason' in data) { /** * The reason for the ban From 26ebfde89c7f8d81ef882058f41d869637e42dd2 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 23:08:19 +0100 Subject: [PATCH 20/39] style(GuildBan): replace `typeof` with `in this` Co-authored-by: Jan <66554238+vaporox@users.noreply.github.com> --- src/structures/GuildBan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js index 5b7d8b0a6ce3..7f0ec3787011 100644 --- a/src/structures/GuildBan.js +++ b/src/structures/GuildBan.js @@ -47,7 +47,7 @@ class GuildBan extends Base { * @readonly */ get partial() { - return typeof this.reason === 'undefined'; + return 'reason' in this; } /** From c90bd1503638516f6767da73caed9f4124ef78e6 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 6 Feb 2021 23:16:34 +0100 Subject: [PATCH 21/39] fix(GuildBan): revert the value of reason in this --- src/structures/GuildBan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/GuildBan.js b/src/structures/GuildBan.js index 7f0ec3787011..f83ca496b22e 100644 --- a/src/structures/GuildBan.js +++ b/src/structures/GuildBan.js @@ -47,7 +47,7 @@ class GuildBan extends Base { * @readonly */ get partial() { - return 'reason' in this; + return !('reason' in this); } /** From 1f7a901f7c0b3708c2e0e2baa8ddc64cc4900fc0 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sun, 7 Feb 2021 16:43:36 +0100 Subject: [PATCH 22/39] docs(GuildBanManager): fix fetch options --- typings/index.d.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index b8715586b8b0..dc3d012ee498 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1961,10 +1961,8 @@ declare module 'discord.js' { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; public ban(user: UserResolvable, options?: BanOptions): Promise; - public fetch( - options: UserResolvable | FetchBanOptions | (UserResolvable & { user: UserResolvable }), - ): Promise; - public fetch(): Promise>; + public fetch(options: UserResolvable | FetchBanOptions): Promise; + public fetch(options?: FetchBansOptions): Promise>; public unban(user: UserResolvable, reason?: string): Promise; } @@ -2595,6 +2593,10 @@ declare module 'discord.js' { force?: boolean; } + interface FetchBansOptions { + cache?: boolean; + } + interface FetchIntegrationsOptions { includeApplications?: boolean; } From 3bfcb339cc5b700affd6520f52d741884a42f2a6 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:25:04 +0100 Subject: [PATCH 23/39] style(GuildBanManager): clean up resolve method Co-authored-by: izexi <43889168+izexi@users.noreply.github.com> --- src/managers/GuildBanManager.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index a68111da3225..ae79ba1cb765 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -43,11 +43,7 @@ class GuildBanManager extends BaseManager { * @returns {?GuildBan} */ resolve(ban) { - const banResolvable = super.resolve(ban); - if (banResolvable) return banResolvable; - const userResolvable = this.client.users.resolveID(ban); - if (userResolvable) return super.resolve(userResolvable); - return null; + return super.resolve(ban) ?? super.resolve(this.client.users.resolveID(ban)); } /** From 45ec354e31eaed8fc1c21c8d87cffeeb0995e7d6 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:28:39 +0100 Subject: [PATCH 24/39] style(GuildBanManager): use reduce to create the ban collection Co-authored-by: izexi <43889168+izexi@users.noreply.github.com> --- src/managers/GuildBanManager.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index ae79ba1cb765..4fec410493dd 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -106,9 +106,7 @@ class GuildBanManager extends BaseManager { async _fetchMany(cache) { const data = await this.client.api.guilds(this.guild.id).bans.get(); - const bans = new Collection(); - for (const ban of data) bans.set(ban.user.id, this.add(ban, cache)); - return bans; + return data.reduce((col, ban) => col.set(ban.user.id, this.add(ban, cache)), new Collection()); } /** From e508b062c24c83dd553b21e4d314cf5623c5d7b5 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:32:49 +0100 Subject: [PATCH 25/39] fix(GuildBanManager): resolve to member not GuildBan Co-authored-by: izexi <43889168+izexi@users.noreply.github.com> --- src/managers/GuildBanManager.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 4fec410493dd..cb8a4379af90 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -133,8 +133,7 @@ class GuildBanManager extends BaseManager { if (user instanceof GuildMember) return user; const _user = this.client.users.resolve(id); if (_user) { - const member = this.resolve(_user); - return member || _user; + return this.guild.members.resolve(_user) ?? _user; } return id; } From ec240997d232fba392d0235749c2b73d8af0bc3f Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:33:43 +0100 Subject: [PATCH 26/39] style(GuildBanManager): Use ( instead of [ Co-authored-by: izexi <43889168+izexi@users.noreply.github.com> --- src/managers/GuildBanManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index cb8a4379af90..bbb016c81765 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -152,7 +152,7 @@ class GuildBanManager extends BaseManager { async unban(user, reason) { const id = this.client.users.resolveID(user); if (!id) throw new Error('BAN_RESOLVE_ID'); - await this.client.api.guilds(this.guild.id).bans[id].delete({ reason }); + await this.client.api.guilds(this.guild.id).bans(id).delete({ reason }); return this.client.users.resolve(user); } } From c50c1d7a0e7c2c90b68a00892b9a2b05d999737b Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:39:39 +0100 Subject: [PATCH 27/39] fix(GuildBanManager): remove options mutating Co-authored-by: izexi <43889168+izexi@users.noreply.github.com> --- src/managers/GuildBanManager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index bbb016c81765..2f41f3ec390a 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -126,7 +126,6 @@ class GuildBanManager extends BaseManager { */ async ban(user, options = { days: 0 }) { if (typeof options !== 'object') throw new TypeError('INVALID_TYPE', 'options', 'object', true); - if (options.days) options.delete_message_days = options.days; const id = this.client.users.resolveID(user); if (!id) throw new Error('BAN_RESOLVE_ID', true); await this.client.api.guilds(this.guild.id).bans[id].put({ data: options }); From a013e4c7f2902cf1390f582c2a020f3dc0af6c52 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:41:45 +0100 Subject: [PATCH 28/39] style(GuildBanManager): use ( instead of [ Co-authored-by: izexi <43889168+izexi@users.noreply.github.com> --- src/managers/GuildBanManager.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 2f41f3ec390a..bd6a8ebb9d1d 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -128,7 +128,15 @@ class GuildBanManager extends BaseManager { if (typeof options !== 'object') throw new TypeError('INVALID_TYPE', 'options', 'object', true); const id = this.client.users.resolveID(user); if (!id) throw new Error('BAN_RESOLVE_ID', true); - await this.client.api.guilds(this.guild.id).bans[id].put({ data: options }); + await this.client.api + .guilds(this.guild.id) + .bans(id) + .put({ + data: { + reason: options.reason, + delete_message_days: options.days, + }, + }); if (user instanceof GuildMember) return user; const _user = this.client.users.resolve(id); if (_user) { From f3fca29f3b4c2cda91fc12e1808013fde962e547 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 16:03:13 +0100 Subject: [PATCH 29/39] docs(GuildBanManager): document fetching all members without caching --- src/managers/GuildBanManager.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index bd6a8ebb9d1d..dbff3fef160d 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -54,10 +54,15 @@ class GuildBanManager extends BaseManager { * @property {boolean} [force=false] Whether to skip the cache check and request the API */ + /** + * Options used to fetch all bans from a guild. + * @typedef {Object} FetchBansOptions + * @property {boolean} cache Whether or not to cache the fetched bans + */ + /** * Fetches ban(s) from Discord. - * @param {UserResolvable|FetchBanOptions} [options] If provided fetches a single ban. - * If undefined, fetches all bans. + * @param {UserResolvable|FetchBanOptions|FetchBansOptions} [options] Options for fetching guild ban(s) * @returns {Promise|Promise>} * @example * // Fetch all bans from a guild @@ -65,6 +70,11 @@ class GuildBanManager extends BaseManager { * .then(console.log) * .catch(console.error); * @example + * // Fetch all bans from a guild without caching + * guild.bans.fetch({ cache: false }) + * .then(console.log) + * .catch(console.error); + * @example * // Fetch a single ban * guild.bans.fetch('351871113346809860') * .then(console.log) From 8badd2d25e8cc63013f3f4a50559229b7e74bc3d Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 16:05:07 +0100 Subject: [PATCH 30/39] docs(FetchBansOptions): make cache not optional --- typings/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index dc3d012ee498..410d94a9c076 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -2594,7 +2594,7 @@ declare module 'discord.js' { } interface FetchBansOptions { - cache?: boolean; + cache: boolean; } interface FetchIntegrationsOptions { From 714c322bfb304288fdea9af1fcfd2e1419995ce1 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 18:19:24 +0100 Subject: [PATCH 31/39] refactor(GuildBanManager): rename ban methods& add them to MemberManager --- src/managers/GuildBanManager.js | 10 ++++----- src/managers/GuildMemberManager.js | 36 ++++++++++++++++++++++++++++++ src/structures/GuildMember.js | 2 +- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index dbff3fef160d..bbc8f377f83f 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -130,11 +130,11 @@ class GuildBanManager extends BaseManager { * be resolved, the user ID will be the result. * @example * // Ban a user by ID (or with a user/guild member object) - * guild.bans.ban('84484653687267328') - * .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`)) + * guild.bans.create('84484653687267328') + * .then(user => console.log(`Banned ${user.username ?? user.id ?? user} from ${guild.name}`)) * .catch(console.error); */ - async ban(user, options = { days: 0 }) { + async create(user, options = { days: 0 }) { if (typeof options !== 'object') throw new TypeError('INVALID_TYPE', 'options', 'object', true); const id = this.client.users.resolveID(user); if (!id) throw new Error('BAN_RESOLVE_ID', true); @@ -162,11 +162,11 @@ class GuildBanManager extends BaseManager { * @returns {Promise} * @example * // Unban a user by ID (or with a user/guild member object) - * guild.bans.unban('84484653687267328') + * guild.bans.remove('84484653687267328') * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`)) * .catch(console.error); */ - async unban(user, reason) { + async remove(user, reason) { const id = this.client.users.resolveID(user); if (!id) throw new Error('BAN_RESOLVE_ID'); await this.client.api.guilds(this.guild.id).bans(id).delete({ reason }); diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index 67f44d2e1ce1..d64b4265d8b1 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -194,6 +194,42 @@ class GuildMemberManager extends BaseManager { .then(data => data.pruned); } + /** + * Bans a user from the guild. + * @param {UserResolvable} user The user to ban + * @param {Object} [options] Options for the ban + * @param {number} [options.days=0] Number of days of messages to delete, must be between 0 and 7 + * @param {string} [options.reason] Reason for banning + * @returns {Promise} Result object will be resolved as specifically as possible. + * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot + * be resolved, the user ID will be the result. + * Internally calls the GuildBanManager#create method. + * @example + * // Ban a user by ID (or with a user/guild member object) + * guild.members.ban('84484653687267328') + * .then(user => console.log(`Banned ${user.username ?? user.id ?? user} from ${guild.name}`)) + * .catch(console.error); + */ + ban(user, options = { days: 0 }) { + return this.guild.bans.create(user, options); + } + + /** + * Unbans a user from the guild. + * @param {UserResolvable} user The user to unban + * @param {string} [reason] Reason for unbanning user + * @returns {Promise} + * Internally calls the GuildBanManager#remove method. + * @example + * // Unban a user by ID (or with a user/guild member object) + * guild.members.unban('84484653687267328') + * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`)) + * .catch(console.error); + */ + unban(user, reason) { + return this.guild.bans.remove(user, reason); + } + _fetchSingle({ user, cache, force = false }) { if (!force) { const existing = this.cache.get(user); diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 07a57ca304cc..f29c9ff7db23 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -362,7 +362,7 @@ class GuildMember extends Base { * .catch(console.error); */ ban(options) { - return this.guild.bans.ban(this, options); + return this.guild.members.ban(this, options); } /** From 3fd7df93bc0e894d7071df51135e60c6bb3feb58 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Tue, 9 Feb 2021 18:27:45 +0100 Subject: [PATCH 32/39] types(GuildBanManager): rename ban methods & add them to MemberManager --- typings/index.d.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 410d94a9c076..8d7f854dd97b 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1949,21 +1949,23 @@ declare module 'discord.js' { export class GuildMemberManager extends BaseManager { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; + public ban(user: UserResolvable, options?: BanOptions): Promise; public fetch( options: UserResolvable | FetchMemberOptions | (FetchMembersOptions & { user: UserResolvable }), ): Promise; public fetch(options?: FetchMembersOptions): Promise>; public prune(options: GuildPruneMembersOptions & { dry?: false; count: false }): Promise; public prune(options?: GuildPruneMembersOptions): Promise; + public unban(user: UserResolvable, reason?: string): Promise; } export class GuildBanManager extends BaseManager { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; - public ban(user: UserResolvable, options?: BanOptions): Promise; + public create(user: UserResolvable, options?: BanOptions): Promise; public fetch(options: UserResolvable | FetchBanOptions): Promise; public fetch(options?: FetchBansOptions): Promise>; - public unban(user: UserResolvable, reason?: string): Promise; + public remove(user: UserResolvable, reason?: string): Promise; } export class GuildMemberRoleManager extends OverridableManager { From 598ba38178ee992de9782bc86ef86466099a0f30 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Thu, 11 Feb 2021 20:24:17 +0100 Subject: [PATCH 33/39] feat(*): merge v8 --- src/client/Client.js | 25 ++++- src/client/actions/ChannelCreate.js | 4 +- src/client/actions/MessageCreate.js | 2 +- src/client/actions/PresenceUpdate.js | 1 - src/client/websocket/WebSocketShard.js | 4 +- src/errors/Messages.js | 2 + src/managers/GuildManager.js | 2 +- src/managers/RoleManager.js | 2 +- src/rest/RequestHandler.js | 2 +- src/structures/ClientPresence.js | 74 +++++-------- src/structures/ClientUser.js | 41 +++---- src/structures/Guild.js | 103 +++--------------- src/structures/GuildAuditLogs.js | 19 ++-- src/structures/GuildChannel.js | 52 +++++---- src/structures/PermissionOverwrites.js | 68 +++++++----- src/structures/Role.js | 4 +- src/structures/User.js | 7 +- src/util/BitField.js | 34 +++--- src/util/Constants.js | 62 ++++++++++- src/util/MessageFlags.js | 6 ++ src/util/Permissions.js | 83 ++++++++------- src/util/Speaking.js | 6 ++ src/util/SystemChannelFlags.js | 6 ++ src/util/UserFlags.js | 6 ++ test/createGuild.js | 6 +- test/random.js | 4 +- test/sendtest.js | 4 +- test/shard.js | 8 +- test/tester1000.js | 1 + test/voice.js | 5 +- test/webhooktest.js | 4 +- typings/index.d.ts | 142 +++++++++++++++---------- typings/index.ts | 6 +- 33 files changed, 433 insertions(+), 362 deletions(-) diff --git a/src/client/Client.js b/src/client/Client.js index 4ac6da82c614..f38a0c0fb4ba 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -17,7 +17,7 @@ const Invite = require('../structures/Invite'); const VoiceRegion = require('../structures/VoiceRegion'); const Webhook = require('../structures/Webhook'); const Collection = require('../util/Collection'); -const { Events, DefaultOptions } = require('../util/Constants'); +const { Events, DefaultOptions, InviteScopes } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); const Intents = require('../util/Intents'); const Permissions = require('../util/Permissions'); @@ -29,9 +29,9 @@ const Structures = require('../util/Structures'); */ class Client extends BaseClient { /** - * @param {ClientOptions} [options] Options for the client + * @param {ClientOptions} options Options for the client */ - constructor(options = {}) { + constructor(options) { super(Object.assign({ _tokenType: 'Bot' }, options)); // Obtain shard details from environment or if present, worker threads @@ -377,6 +377,7 @@ class Client extends BaseClient { * @property {PermissionResolvable} [permissions] Permissions to request * @property {GuildResolvable} [guild] Guild to preselect * @property {boolean} [disableGuildSelect] Whether to disable the guild selection + * @property {InviteScope[]} [additionalScopes] Whether any additional scopes should be requested */ /** @@ -418,6 +419,18 @@ class Client extends BaseClient { query.set('guild_id', guildID); } + if (options.additionalScopes) { + const scopes = options.additionalScopes; + if (!Array.isArray(scopes)) { + throw new TypeError('INVALID_TYPE', 'additionalScopes', 'Array of Invite Scopes', true); + } + const invalidScope = scopes.find(scope => !InviteScopes.includes(scope)); + if (invalidScope) { + throw new TypeError('INVALID_ELEMENT', 'Array', 'additionalScopes', invalidScope); + } + query.set('scope', ['bot', ...scopes].join(' ')); + } + return `${this.options.http.api}${this.api.oauth2.authorize}?${query}`; } @@ -444,8 +457,10 @@ class Client extends BaseClient { * @private */ _validateOptions(options = this.options) { - if (typeof options.ws.intents !== 'undefined') { - options.ws.intents = Intents.resolve(options.ws.intents); + if (typeof options.intents === 'undefined') { + throw new TypeError('CLIENT_MISSING_INTENTS'); + } else { + options.intents = Intents.resolve(options.intents); } if (typeof options.shardCount !== 'number' || isNaN(options.shardCount) || options.shardCount < 1) { throw new TypeError('CLIENT_INVALID_OPTION', 'shardCount', 'a number greater than or equal to 1'); diff --git a/src/client/actions/ChannelCreate.js b/src/client/actions/ChannelCreate.js index fa60a0b39508..d1660aa76d6b 100644 --- a/src/client/actions/ChannelCreate.js +++ b/src/client/actions/ChannelCreate.js @@ -10,9 +10,9 @@ class ChannelCreateAction extends Action { const channel = client.channels.add(data); if (!existing && channel) { /** - * Emitted whenever a channel is created. + * Emitted whenever a guild channel is created. * @event Client#channelCreate - * @param {DMChannel|GuildChannel} channel The channel that was created + * @param {GuildChannel} channel The channel that was created */ client.emit(Events.CHANNEL_CREATE, channel); } diff --git a/src/client/actions/MessageCreate.js b/src/client/actions/MessageCreate.js index 713870750aca..ae17415988e2 100644 --- a/src/client/actions/MessageCreate.js +++ b/src/client/actions/MessageCreate.js @@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants'); class MessageCreateAction extends Action { handle(data) { const client = this.client; - const channel = client.channels.cache.get(data.channel_id); + const channel = this.getChannel(data); if (channel) { const existing = channel.messages.cache.get(data.id); if (existing) return { message: existing }; diff --git a/src/client/actions/PresenceUpdate.js b/src/client/actions/PresenceUpdate.js index f74fbeb5d3e5..69b79eb7835e 100644 --- a/src/client/actions/PresenceUpdate.js +++ b/src/client/actions/PresenceUpdate.js @@ -22,7 +22,6 @@ class PresenceUpdateAction extends Action { if (!member && data.status !== 'offline') { member = guild.members.add({ user, - roles: data.roles, deaf: false, mute: false, }); diff --git a/src/client/websocket/WebSocketShard.js b/src/client/websocket/WebSocketShard.js index 64ceca83ecb6..4fe904e1af38 100644 --- a/src/client/websocket/WebSocketShard.js +++ b/src/client/websocket/WebSocketShard.js @@ -3,6 +3,7 @@ const EventEmitter = require('events'); const WebSocket = require('../../WebSocket'); const { Status, Events, ShardEvents, OPCodes, WSEvents } = require('../../util/Constants'); +const Intents = require('../../util/Intents'); const STATUS_KEYS = Object.keys(Status); const CONNECTION_STATE = Object.keys(WebSocket.WebSocket); @@ -594,6 +595,7 @@ class WebSocketShard extends EventEmitter { // Clone the identify payload and assign the token and shard info const d = { ...client.options.ws, + intents: Intents.resolve(client.options.intents), token: client.token, shard: [this.id, Number(client.options.shardCount)], }; @@ -648,7 +650,7 @@ class WebSocketShard extends EventEmitter { _send(data) { if (!this.connection || this.connection.readyState !== WebSocket.OPEN) { this.debug(`Tried to send packet '${JSON.stringify(data)}' but no WebSocket is available!`); - this.destroy({ close: 4000 }); + this.destroy({ closeCode: 4000 }); return; } diff --git a/src/errors/Messages.js b/src/errors/Messages.js index 4e9d73cacbd2..e1b53de33e54 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -5,6 +5,7 @@ const { register } = require('./DJSError'); const Messages = { CLIENT_INVALID_OPTION: (prop, must) => `The ${prop} option must be ${must}`, CLIENT_INVALID_PROVIDED_SHARDS: 'None of the provided shards were valid.', + CLIENT_MISSING_INTENTS: 'Valid intents must be provided for the Client.', TOKEN_INVALID: 'An invalid token was provided.', TOKEN_MISSING: 'Request to use token, but token was unavailable to the client.', @@ -89,6 +90,7 @@ const Messages = { GUILD_UNCACHED_ME: 'The client user as a member of this guild is uncached.', INVALID_TYPE: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`, + INVALID_ELEMENT: (type, name, elem) => `Supplied ${type} ${name} includes an invalid element: ${elem}`, WEBHOOK_MESSAGE: 'The message was not sent by a webhook.', diff --git a/src/managers/GuildManager.js b/src/managers/GuildManager.js index b04a52c122ce..d5a92b4bf477 100644 --- a/src/managers/GuildManager.js +++ b/src/managers/GuildManager.js @@ -53,7 +53,7 @@ class GuildManager extends BaseManager { * @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number * @property {boolean} [hoist] Whether or not the role should be hoisted * @property {number} [position] The position of the role - * @property {PermissionResolvable|number} [permissions] The permissions of the role + * @property {PermissionResolvable} [permissions] The permissions of the role * @property {boolean} [mentionable] Whether or not the role should be mentionable */ diff --git a/src/managers/RoleManager.js b/src/managers/RoleManager.js index 667085b6beef..04aa47d000c6 100644 --- a/src/managers/RoleManager.js +++ b/src/managers/RoleManager.js @@ -115,7 +115,7 @@ class RoleManager extends BaseManager { create(options = {}) { let { name, color, hoist, permissions, position, mentionable, reason } = options; if (color) color = resolveColor(color); - if (permissions) permissions = Permissions.resolve(permissions); + if (permissions) permissions = Permissions.resolve(permissions).toString(); return this.client.api .guilds(this.guild.id) diff --git a/src/rest/RequestHandler.js b/src/rest/RequestHandler.js index 100035a4bf75..245a285cda4b 100644 --- a/src/rest/RequestHandler.js +++ b/src/rest/RequestHandler.js @@ -105,7 +105,7 @@ class RequestHandler { this.limit = limit ? Number(limit) : Infinity; this.remaining = remaining ? Number(remaining) : 1; this.reset = reset ? calculateReset(reset, serverDate) : Date.now(); - this.retryAfter = retryAfter ? Number(retryAfter) : -1; + this.retryAfter = retryAfter ? Number(retryAfter) * 1000 : -1; // https://github.com/discordapp/discord-api-docs/issues/182 if (request.route.includes('reactions')) { diff --git a/src/structures/ClientPresence.js b/src/structures/ClientPresence.js index 6c0955627318..f32577b47c45 100644 --- a/src/structures/ClientPresence.js +++ b/src/structures/ClientPresence.js @@ -2,7 +2,6 @@ const { Presence } = require('./Presence'); const { TypeError } = require('../errors'); -const Collection = require('../util/Collection'); const { ActivityTypes, OPCodes } = require('../util/Constants'); class ClientPresence extends Presence { @@ -14,8 +13,8 @@ class ClientPresence extends Presence { super(client, Object.assign(data, { status: data.status || 'online', user: { id: null } })); } - async set(presence) { - const packet = await this._parse(presence); + set(presence) { + const packet = this._parse(presence); this.patch(packet); if (typeof presence.shardID === 'undefined') { this.client.ws.broadcast({ op: OPCodes.STATUS_UPDATE, d: packet }); @@ -29,58 +28,33 @@ class ClientPresence extends Presence { return this; } - async _parse({ status, since, afk, activity }) { - const applicationID = activity && (activity.application ? activity.application.id || activity.application : null); - let assets = new Collection(); - if (activity) { - if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', 'name', 'string'); - if (!activity.type) activity.type = 0; - if (activity.assets && applicationID) { - try { - const a = await this.client.api.oauth2.applications(applicationID).assets.get(); - for (const asset of a) assets.set(asset.name, asset.id); - } catch {} // eslint-disable-line no-empty - } - } - - const packet = { - afk: afk != null ? afk : false, // eslint-disable-line eqeqeq - since: since != null ? since : null, // eslint-disable-line eqeqeq + _parse({ status, since, afk, activities }) { + const data = { + activities: [], + afk: typeof afk === 'boolean' ? afk : false, + since: typeof since === 'number' && !Number.isNaN(since) ? since : null, status: status || this.status, - game: activity - ? { - type: activity.type, - name: activity.name, - url: activity.url, - details: activity.details || undefined, - state: activity.state || undefined, - assets: activity.assets - ? { - large_text: activity.assets.largeText || undefined, - small_text: activity.assets.smallText || undefined, - large_image: assets.get(activity.assets.largeImage) || activity.assets.largeImage, - small_image: assets.get(activity.assets.smallImage) || activity.assets.smallImage, - } - : undefined, - timestamps: activity.timestamps || undefined, - party: activity.party || undefined, - application_id: applicationID || undefined, - secrets: activity.secrets || undefined, - instance: activity.instance || undefined, - } - : null, }; - - if ((status || afk || since) && !activity) { - packet.game = this.activities[0] || null; + if (activities === null) { + data.activities = null; + return data; } - - if (packet.game) { - packet.game.type = - typeof packet.game.type === 'number' ? packet.game.type : ActivityTypes.indexOf(packet.game.type); + if (activities && activities.length) { + for (const [i, activity] of activities.entries()) { + if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string'); + if (!activity.type) activity.type = 0; + + data.activities.push({ + type: typeof activity.type === 'number' ? activity.type : ActivityTypes.indexOf(activity.type), + name: activity.name, + url: activity.url, + }); + } + } else if ((status || afk || since) && this.activities.length) { + data.activities.push(...this.activities); } - return packet; + return data; } } diff --git a/src/structures/ClientUser.js b/src/structures/ClientUser.js index 65112b8cc1f0..33b4be56daf9 100644 --- a/src/structures/ClientUser.js +++ b/src/structures/ClientUser.js @@ -46,16 +46,18 @@ class ClientUser extends Structures.get('User') { return this.client.presence; } - edit(data) { - return this.client.api - .users('@me') - .patch({ data }) - .then(newData => { - this.client.token = newData.token; - const { updated } = this.client.actions.UserUpdate.handle(newData); - if (updated) return updated; - return this; - }); + /** + * Edits the logged in client. + * @param {Object} data The new data + * @param {string} [data.username] The new username + * @param {BufferResolvable|Base64Resolvable} [data.avatar] The new avatar + */ + async edit(data) { + const newData = await this.client.api.users('@me').patch({ data }); + this.client.token = newData.token; + const { updated } = this.client.actions.UserUpdate.handle(newData); + if (updated) return updated; + return this; } /** @@ -103,7 +105,7 @@ class ClientUser extends Structures.get('User') { /** * Sets the full presence of the client user. * @param {PresenceData} data Data for the presence - * @returns {Promise} + * @returns {Presence} * @example * // Set the client user's presence * client.user.setPresence({ activity: { name: 'with discord.js' }, status: 'idle' }) @@ -127,7 +129,7 @@ class ClientUser extends Structures.get('User') { * Sets the status of the client user. * @param {PresenceStatusData} status Status to change to * @param {?number|number[]} [shardID] Shard ID(s) to have the activity set on - * @returns {Promise} + * @returns {Presence} * @example * // Set the client user's status * client.user.setStatus('idle') @@ -144,14 +146,14 @@ class ClientUser extends Structures.get('User') { * @type {Object} * @property {string} [url] Twitch / YouTube stream URL * @property {ActivityType|number} [type] Type of the activity - * @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 */ /** * Sets the activity the client user is playing. * @param {string|ActivityOptions} [name] Activity being played, or options for setting the activity * @param {ActivityOptions} [options] Options for setting the activity - * @returns {Promise} + * @returns {Presence} * @example * // Set the client user's activity * client.user.setActivity('discord.js', { type: 'WATCHING' }) @@ -159,19 +161,20 @@ class ClientUser extends Structures.get('User') { * .catch(console.error); */ setActivity(name, options = {}) { - if (!name) return this.setPresence({ activity: null, shardID: options.shardID }); + if (!name) return this.setPresence({ activities: null, shardID: options.shardID }); const activity = Object.assign({}, options, typeof name === 'object' ? name : { name }); - return this.setPresence({ activity, shardID: activity.shardID }); + return this.setPresence({ activities: [activity], shardID: activity.shardID }); } /** * Sets/removes the AFK flag for the client user. * @param {boolean} afk Whether or not the user is AFK - * @returns {Promise} + * @param {number|number[]} [shardID] Shard Id(s) to have the AFK flag set on + * @returns {Presence} */ - setAFK(afk) { - return this.setPresence({ afk }); + setAFK(afk, shardID) { + return this.setPresence({ afk, shardID }); } } diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 055f065d63cc..2f4225f02add 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -217,13 +217,6 @@ class Guild extends Base { */ this.systemChannelID = data.system_channel_id; - /** - * Whether embedded images are enabled on this guild - * @type {boolean} - * @deprecated - */ - this.embedEnabled = data.embed_enabled; - /** * The type of premium tier: * * 0: NONE @@ -263,15 +256,6 @@ class Guild extends Base { this.widgetChannelID = data.widget_channel_id; } - if (typeof data.embed_channel_id !== 'undefined') { - /** - * The embed channel ID, if enabled - * @type {?string} - * @deprecated - */ - this.embedChannelID = data.embed_channel_id; - } - /** * The verification level of the guild * @type {VerificationLevel} @@ -592,16 +576,6 @@ class Guild extends Base { return this.client.channels.cache.get(this.widgetChannelID) || null; } - /** - * Embed channel for this guild - * @type {?TextChannel} - * @readonly - * @deprecated - */ - get embedChannel() { - return this.client.channels.cache.get(this.embedChannelID) || null; - } - /** * Rules channel for this guild * @type {?TextChannel} @@ -651,8 +625,6 @@ class Guild extends Base { /** * Fetches a collection of integrations to this guild. * Resolves with a collection mapping integrations by their ids. - * @param {Object} [options] Options for fetching integrations - * @param {boolean} [options.includeApplications] Whether to include bot and Oauth2 webhook integrations * @returns {Promise>} * @example * // Fetch integrations @@ -660,20 +632,12 @@ class Guild extends Base { * .then(integrations => console.log(`Fetched ${integrations.size} integrations`)) * .catch(console.error); */ - fetchIntegrations({ includeApplications = false } = {}) { - return this.client.api - .guilds(this.id) - .integrations.get({ - query: { - include_applications: includeApplications, - }, - }) - .then(data => - data.reduce( - (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)), - new Collection(), - ), - ); + async fetchIntegrations() { + const data = await this.client.api.guilds(this.id).integrations.get(); + return data.reduce( + (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)), + new Collection(), + ); } /** @@ -858,20 +822,6 @@ class Guild extends Base { * @property {?GuildChannelResolvable} channel The widget channel */ - /** - * Fetches the guild embed. - * @returns {Promise} - * @deprecated - * @example - * // Fetches the guild embed - * guild.fetchEmbed() - * .then(embed => console.log(`The embed is ${embed.enabled ? 'enabled' : 'disabled'}`)) - * .catch(console.error); - */ - fetchEmbed() { - return this.fetchWidget(); - } - /** * Fetches the guild widget. * @returns {Promise} @@ -883,8 +833,8 @@ class Guild extends Base { */ async fetchWidget() { const data = await this.client.api.guilds(this.id).widget.get(); - this.widgetEnabled = this.embedEnabled = data.enabled; - this.widgetChannelID = this.embedChannelID = data.channel_id; + this.widgetEnabled = data.enabled; + this.widgetChannelID = data.channel_id; return { enabled: data.enabled, channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null, @@ -1330,7 +1280,7 @@ class Guild extends Base { * @returns {Promise} * @example * guild.setRolePositions([{ role: roleID, position: updatedRoleIndex }]) - * .then(guild => console.log(`Role permissions updated for ${guild}`)) + * .then(guild => console.log(`Role positions updated for ${guild}`)) * .catch(console.error); */ setRolePositions(rolePositions) { @@ -1355,17 +1305,6 @@ class Guild extends Base { ); } - /** - * Edits the guild's embed. - * @param {GuildWidgetData} embed The embed for the guild - * @param {string} [reason] Reason for changing the guild's embed - * @returns {Promise} - * @deprecated - */ - setEmbed(embed, reason) { - return this.setWidget(embed, reason); - } - /** * Edits the guild's widget. * @param {GuildWidgetData} widget The widget for the guild @@ -1427,7 +1366,7 @@ class Guild extends Base { * @returns {boolean} */ equals(guild) { - let equal = + return ( guild && guild instanceof this.constructor && this.id === guild.id && @@ -1441,20 +1380,10 @@ class Guild extends Base { this.icon === guild.icon && this.ownerID === guild.ownerID && this.verificationLevel === guild.verificationLevel && - this.embedEnabled === guild.embedEnabled && (this.features === guild.features || (this.features.length === guild.features.length && - this.features.every((feat, i) => feat === guild.features[i]))); - - if (equal) { - if (this.embedChannel) { - if (!guild.embedChannel || this.embedChannel.id !== guild.embedChannel.id) equal = false; - } else if (guild.embedChannel) { - equal = false; - } - } - - return equal; + this.features.every((feat, i) => feat === guild.features[i]))) + ); } /** @@ -1485,7 +1414,7 @@ class Guild extends Base { /** * Creates a collection of this guild's roles, sorted by their position and IDs. - * @returns {Collection} + * @returns {Collection} * @private */ _sortedRoles() { @@ -1495,7 +1424,7 @@ class Guild extends Base { /** * Creates a collection of this guild's or a specific category's channels, sorted by their position and IDs. * @param {GuildChannel} [channel] Category to get the channels of - * @returns {Collection} + * @returns {Collection} * @private */ _sortedChannels(channel) { @@ -1512,10 +1441,6 @@ class Guild extends Base { } } -Guild.prototype.setEmbed = deprecate(Guild.prototype.setEmbed, 'Guild#setEmbed: Use setWidget instead'); - -Guild.prototype.fetchEmbed = deprecate(Guild.prototype.fetchEmbed, 'Guild#fetchEmbed: Use fetchWidget instead'); - Guild.prototype.fetchVanityCode = deprecate( Guild.prototype.fetchVanityCode, 'Guild#fetchVanityCode: Use fetchVanityData() instead', diff --git a/src/structures/GuildAuditLogs.js b/src/structures/GuildAuditLogs.js index 394fdebfc368..aab133d4cc3a 100644 --- a/src/structures/GuildAuditLogs.js +++ b/src/structures/GuildAuditLogs.js @@ -3,7 +3,7 @@ const Integration = require('./Integration'); const Webhook = require('./Webhook'); const Collection = require('../util/Collection'); -const { PartialTypes } = require('../util/Constants'); +const { OverwriteTypes, PartialTypes } = require('../util/Constants'); const Permissions = require('../util/Permissions'); const Snowflake = require('../util/Snowflake'); const Util = require('../util/Util'); @@ -384,16 +384,19 @@ class GuildAuditLogsEntry { case Actions.CHANNEL_OVERWRITE_CREATE: case Actions.CHANNEL_OVERWRITE_UPDATE: case Actions.CHANNEL_OVERWRITE_DELETE: - switch (data.options.type) { - case 'member': - this.extra = guild.members.cache.get(data.options.id) || { id: data.options.id, type: 'member' }; - break; - - case 'role': + switch (Number(data.options.type)) { + case OverwriteTypes.role: this.extra = guild.roles.cache.get(data.options.id) || { id: data.options.id, name: data.options.role_name, - type: 'role', + type: OverwriteTypes[OverwriteTypes.role], + }; + break; + + case OverwriteTypes.member: + this.extra = guild.members.cache.get(data.options.id) || { + id: data.options.id, + type: OverwriteTypes[OverwriteTypes.member], }; break; diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 6832b6ff6fc9..1a53fc7f4177 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -7,6 +7,7 @@ const Role = require('./Role'); const { Error, TypeError } = require('../errors'); const Collection = require('../util/Collection'); const { ChannelTypes } = require('../util/Constants'); +const { OverwriteTypes } = require('../util/Constants'); const Permissions = require('../util/Permissions'); const Util = require('../util/Util'); @@ -161,12 +162,12 @@ class GuildChannel extends Channel { const overwrites = this.overwritesFor(member, true, roles); return permissions - .remove(overwrites.everyone ? overwrites.everyone.deny : 0) - .add(overwrites.everyone ? overwrites.everyone.allow : 0) - .remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny) : 0) - .add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow) : 0) - .remove(overwrites.member ? overwrites.member.deny : 0) - .add(overwrites.member ? overwrites.member.allow : 0) + .remove(overwrites.everyone ? overwrites.everyone.deny : 0n) + .add(overwrites.everyone ? overwrites.everyone.allow : 0n) + .remove(overwrites.roles.length > 0n ? overwrites.roles.map(role => role.deny) : 0n) + .add(overwrites.roles.length > 0n ? overwrites.roles.map(role => role.allow) : 0n) + .remove(overwrites.member ? overwrites.member.deny : 0n) + .add(overwrites.member ? overwrites.member.allow : 0n) .freeze(); } @@ -183,10 +184,10 @@ class GuildChannel extends Channel { const roleOverwrites = this.permissionOverwrites.get(role.id); return role.permissions - .remove(everyoneOverwrites ? everyoneOverwrites.deny : 0) - .add(everyoneOverwrites ? everyoneOverwrites.allow : 0) - .remove(roleOverwrites ? roleOverwrites.deny : 0) - .add(roleOverwrites ? roleOverwrites.allow : 0) + .remove(everyoneOverwrites ? everyoneOverwrites.deny : 0n) + .add(everyoneOverwrites ? everyoneOverwrites.allow : 0n) + .remove(roleOverwrites ? roleOverwrites.deny : 0n) + .add(roleOverwrites ? roleOverwrites.allow : 0n) .freeze(); } @@ -204,13 +205,12 @@ class GuildChannel extends Channel { * }, * ], 'Needed to change permissions'); */ - overwritePermissions(overwrites, reason) { + async overwritePermissions(overwrites, reason) { if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) { - return Promise.reject( - new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true), - ); + throw new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true); } - return this.edit({ permissionOverwrites: overwrites, reason }).then(() => this); + await this.edit({ permissionOverwrites: overwrites, reason }); + return this; } /** @@ -227,13 +227,17 @@ class GuildChannel extends Channel { * .then(channel => console.log(channel.permissionOverwrites.get(message.author.id))) * .catch(console.error); */ - updateOverwrite(userOrRole, options, reason) { + async updateOverwrite(userOrRole, options, reason) { userOrRole = this.guild.roles.resolve(userOrRole) || this.client.users.resolve(userOrRole); if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role')); const existing = this.permissionOverwrites.get(userOrRole.id); - if (existing) return existing.update(options, reason).then(() => this); - return this.createOverwrite(userOrRole, options, reason); + if (existing) { + await existing.update(options, reason); + } else { + await this.createOverwrite(userOrRole, options, reason); + } + return this; } /** @@ -254,13 +258,19 @@ class GuildChannel extends Channel { userOrRole = this.guild.roles.resolve(userOrRole) || this.client.users.resolve(userOrRole); if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role')); - const type = userOrRole instanceof Role ? 'role' : 'member'; + const type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member; const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options); return this.client.api .channels(this.id) - .permissions[userOrRole.id].put({ - data: { id: userOrRole.id, type, allow: allow.bitfield, deny: deny.bitfield }, + .permissions(userOrRole.id) + .put({ + data: { + id: userOrRole.id, + type, + allow, + deny, + }, reason, }) .then(() => this); diff --git a/src/structures/PermissionOverwrites.js b/src/structures/PermissionOverwrites.js index bbc7cd13632e..b8990136c2f9 100644 --- a/src/structures/PermissionOverwrites.js +++ b/src/structures/PermissionOverwrites.js @@ -2,8 +2,8 @@ const Role = require('./Role'); const { TypeError } = require('../errors'); +const { OverwriteTypes } = require('../util/Constants'); const Permissions = require('../util/Permissions'); -const Util = require('../util/Util'); /** * Represents a permission overwrite for a role or member in a guild channel. @@ -28,30 +28,23 @@ class PermissionOverwrites { */ this.id = data.id; - /** - * The type of a permission overwrite. It can be one of: - * * member - * * role - * @typedef {string} OverwriteType - */ - /** * The type of this overwrite * @type {OverwriteType} */ - this.type = data.type; + this.type = OverwriteTypes[data.type]; /** * The permissions that are denied for the user or role. * @type {Readonly} */ - this.deny = new Permissions(data.deny).freeze(); + this.deny = new Permissions(BigInt(data.deny)).freeze(); /** * The permissions that are allowed for the user or role. * @type {Readonly} */ - this.allow = new Permissions(data.allow).freeze(); + this.allow = new Permissions(BigInt(data.allow)).freeze(); } /** @@ -67,16 +60,22 @@ class PermissionOverwrites { * .then(channel => console.log(channel.permissionOverwrites.get(message.author.id))) * .catch(console.error); */ - update(options, reason) { + async update(options, reason) { const { allow, deny } = this.constructor.resolveOverwriteOptions(options, this); - return this.channel.client.api + await this.channel.client.api .channels(this.channel.id) - .permissions[this.id].put({ - data: { id: this.id, type: this.type, allow: allow.bitfield, deny: deny.bitfield }, + .permissions(this.id) + .put({ + data: { + id: this.id, + type: OverwriteTypes[this.type], + allow, + deny, + }, reason, - }) - .then(() => this); + }); + return this; } /** @@ -84,12 +83,18 @@ class PermissionOverwrites { * @param {string} [reason] Reason for deleting this overwrite * @returns {Promise} */ - delete(reason) { - return this.channel.client.api.channels[this.channel.id].permissions[this.id].delete({ reason }).then(() => this); + async delete(reason) { + await this.channel.client.api.channels(this.channel.id).permissions(this.id).delete({ reason }); + return this; } toJSON() { - return Util.flatten(this); + return { + id: this.id, + type: OverwriteTypes[this.type], + allow: this.allow, + deny: this.deny, + }; } /** @@ -142,9 +147,9 @@ class PermissionOverwrites { * The raw data for a permission overwrite * @typedef {Object} RawOverwriteData * @property {Snowflake} id The id of the overwrite - * @property {number} allow The permissions to allow - * @property {number} deny The permissions to deny - * @property {OverwriteType} type The type of this OverwriteData + * @property {string} allow The permissions to allow + * @property {string} deny The permissions to deny + * @property {number} type The type of this OverwriteData */ /** @@ -164,24 +169,29 @@ class PermissionOverwrites { /** * Resolves an overwrite into {@link RawOverwriteData}. * @param {OverwriteResolvable} overwrite The overwrite-like data to resolve - * @param {Guild} guild The guild to resolve from + * @param {Guild} [guild] The guild to resolve from * @returns {RawOverwriteData} */ static resolve(overwrite, guild) { if (overwrite instanceof this) return overwrite.toJSON(); - if (typeof overwrite.id === 'string' && ['role', 'member'].includes(overwrite.type)) { - return { ...overwrite, allow: Permissions.resolve(overwrite.allow), deny: Permissions.resolve(overwrite.deny) }; + if (typeof overwrite.id === 'string' && overwrite.type in OverwriteTypes) { + return { + id: overwrite.id, + type: OverwriteTypes[overwrite.type], + allow: Permissions.resolve(overwrite.allow).toString(), + deny: Permissions.resolve(overwrite.deny).toString(), + }; } const userOrRole = guild.roles.resolve(overwrite.id) || guild.client.users.resolve(overwrite.id); if (!userOrRole) throw new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role'); - const type = userOrRole instanceof Role ? 'role' : 'member'; + const type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member; return { id: userOrRole.id, type, - allow: Permissions.resolve(overwrite.allow), - deny: Permissions.resolve(overwrite.deny), + allow: Permissions.resolve(overwrite.allow).toString(), + deny: Permissions.resolve(overwrite.deny).toString(), }; } } diff --git a/src/structures/Role.js b/src/structures/Role.js index 04db107ee694..90fb2383fea1 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -63,7 +63,7 @@ class Role extends Base { * The permissions of the role * @type {Readonly} */ - this.permissions = new Permissions(data.permissions).freeze(); + this.permissions = new Permissions(BigInt(data.permissions)).freeze(); /** * Whether or not the role is managed by an external service @@ -301,7 +301,7 @@ class Role extends Base { * .catch(console.error); * @example * // Remove all permissions from a role - * role.setPermissions(0) + * role.setPermissions(0n) * .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`)) * .catch(console.error); */ diff --git a/src/structures/User.js b/src/structures/User.js index 2811e86222d4..bddb94825264 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -245,7 +245,7 @@ class User extends Base { recipient_id: this.id, }, }); - return this.client.actions.ChannelCreate.handle(data).channel; + return this.client.channels.add(data); } /** @@ -255,8 +255,9 @@ class User extends Base { async deleteDM() { const { dmChannel } = this; if (!dmChannel) throw new Error('USER_NO_DMCHANNEL'); - const data = await this.client.api.channels(dmChannel.id).delete(); - return this.client.actions.ChannelDelete.handle(data).channel; + await this.client.api.channels(dmChannel.id).delete(); + this.client.channels.remove(dmChannel.id); + return dmChannel; } /** diff --git a/src/util/BitField.js b/src/util/BitField.js index 070f28db02fa..fe32332f4fd7 100644 --- a/src/util/BitField.js +++ b/src/util/BitField.js @@ -7,12 +7,12 @@ const { RangeError } = require('../errors'); */ class BitField { /** - * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + * @param {BitFieldResolvable} [bits=this.constructor.defaultBit] Bit(s) to read from */ - constructor(bits) { + constructor(bits = this.constructor.defaultBit) { /** * Bitfield of the packed bits - * @type {number} + * @type {number|bigint} */ this.bitfield = this.constructor.resolve(bits); } @@ -23,7 +23,7 @@ class BitField { * @returns {boolean} */ any(bit) { - return (this.bitfield & this.constructor.resolve(bit)) !== 0; + return (this.bitfield & this.constructor.resolve(bit)) !== this.constructor.defaultBit; } /** @@ -71,7 +71,7 @@ class BitField { * @returns {BitField} These bits or new BitField if the instance is frozen. */ add(...bits) { - let total = 0; + let total = this.constructor.defaultBit; for (const bit of bits) { total |= this.constructor.resolve(bit); } @@ -86,7 +86,7 @@ class BitField { * @returns {BitField} These bits or new BitField if the instance is frozen. */ remove(...bits) { - let total = 0; + let total = this.constructor.defaultBit; for (const bit of bits) { total |= this.constructor.resolve(bit); } @@ -117,7 +117,7 @@ class BitField { } toJSON() { - return this.bitfield; + return typeof this.bitfield === 'number' ? this.bitfield : this.bitfield.toString(); } valueOf() { @@ -133,18 +133,20 @@ class BitField { * * A bit number (this can be a number literal or a value taken from {@link BitField.FLAGS}) * * An instance of BitField * * An Array of BitFieldResolvable - * @typedef {number|BitField|BitFieldResolvable[]} BitFieldResolvable + * @typedef {number|bigint|BitField|BitFieldResolvable[]} BitFieldResolvable */ /** * Resolves bitfields to their numeric form. - * @param {BitFieldResolvable} [bit=0] - bit(s) to resolve - * @returns {number} + * @param {BitFieldResolvable} [bit] - bit(s) to resolve + * @returns {number|bigint} */ - static resolve(bit = 0) { - if (typeof bit === 'number' && bit >= 0) return bit; + static resolve(bit) { + const { defaultBit } = this; + if (typeof bit === 'undefined') return defaultBit; + if (typeof defaultBit === typeof bit && bit >= defaultBit) return bit; if (bit instanceof BitField) return bit.bitfield; - if (Array.isArray(bit)) return bit.map(p => this.resolve(p)).reduce((prev, p) => prev | p, 0); + if (Array.isArray(bit)) return bit.map(p => this.resolve(p)).reduce((prev, p) => prev | p, defaultBit); if (typeof bit === 'string' && typeof this.FLAGS[bit] !== 'undefined') return this.FLAGS[bit]; throw new RangeError('BITFIELD_INVALID', bit); } @@ -158,4 +160,10 @@ class BitField { */ BitField.FLAGS = {}; +/** + * @type {number|bigint} + * @private + */ +BitField.defaultBit = 0; + module.exports = BitField; diff --git a/src/util/Constants.js b/src/util/Constants.js index 308e45ab94e4..3f4d7dcbe438 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -30,7 +30,8 @@ const { Error, RangeError } = require('../errors'); * @property {number} [restSweepInterval=60] How frequently to delete inactive request buckets, in seconds * (or 0 for never) * @property {number} [retryLimit=1] How many times to retry on 5XX errors (Infinity for indefinite amount of retries) - * @property {PresenceData} [presence] Presence data to use upon login + * @property {PresenceData} [presence={}] Presence data to use upon login + * @property {IntentsResolvable} intents Intents to enable for this connection * @property {WebsocketOptions} [ws] Options for the WebSocket * @property {HTTPOptions} [http] HTTP options */ @@ -52,7 +53,6 @@ exports.DefaultOptions = { * @typedef {Object} WebsocketOptions * @property {number} [large_threshold=50] Number of members in a guild after which offline users will no longer be * sent in the initial guild member list, must be between 50 and 250 - * @property {IntentsResolvable} [intents] Intents to enable for this connection */ ws: { large_threshold: 50, @@ -62,7 +62,7 @@ exports.DefaultOptions = { $browser: 'discord.js', $device: 'discord.js', }, - version: 6, + version: 8, }, /** @@ -75,7 +75,7 @@ exports.DefaultOptions = { * @property {string} [template='https://discord.new'] Base url of templates */ http: { - version: 7, + version: 8, api: 'https://discord.com/api', cdn: 'https://cdn.discordapp.com', invite: 'https://discord.gg', @@ -375,6 +375,36 @@ exports.WSEvents = keyMirror([ 'WEBHOOKS_UPDATE', ]); +/** + * A valid scope to request when generating an invite link. + * Scopes that require whitelist are not considered valid for this generator + * * `applications.builds.read`: allows reading build data for a users applications + * * `applications.commands`: allows this bot to create commands in the server + * * `applications.entitlements`: allows reading entitlements for a users applications + * * `applications.store.update`: allows reading and updating of store data for a users applications + * * `connections`: makes the endpoint for getting a users connections available + * * `email`: allows the `/users/@me` endpoint return with an email + * * `identify`: allows the `/users/@me` endpoint without an email + * * `guilds`: makes the `/users/@me/guilds` endpoint available for a user + * * `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 + * * `webhook.incoming`: generates a webhook to a channel + * @typedef {string} InviteScope + */ +exports.InviteScopes = [ + 'applications.builds.read', + 'applications.commands', + 'applications.entitlements', + 'applications.store.update', + 'connections', + 'email', + 'identity', + 'guilds', + 'guilds.join', + 'gdm.join', + 'webhook.incoming', +]; + /** * The type of a message, e.g. `DEFAULT`. Here are the available types: * * DEFAULT @@ -527,6 +557,7 @@ exports.VerificationLevels = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_HIGH']; * * UNKNOWN_GUILD_TEMPLATE * * BOT_PROHIBITED_ENDPOINT * * BOT_ONLY_ENDPOINT + * * ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED * * CHANNEL_HIT_WRITE_RATELIMIT * * MAXIMUM_GUILDS * * MAXIMUM_FRIENDS @@ -563,7 +594,9 @@ exports.VerificationLevels = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_HIGH']; * * CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL * * INVALID_OR_TAKEN_INVITE_CODE * * CANNOT_EXECUTE_ON_SYSTEM_MESSAGE + * * CANNOT_EXECUTE_ON_CHANNEL_TYPE * * INVALID_OAUTH_TOKEN + * * INVALID_RECIPIENTS * * BULK_DELETE_MESSAGE_TOO_OLD * * INVALID_FORM_BODY * * INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT @@ -593,6 +626,7 @@ exports.APIErrors = { UNKNOWN_GUILD_TEMPLATE: 10057, BOT_PROHIBITED_ENDPOINT: 20001, BOT_ONLY_ENDPOINT: 20002, + ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED: 20022, CHANNEL_HIT_WRITE_RATELIMIT: 20028, MAXIMUM_GUILDS: 30001, MAXIMUM_FRIENDS: 30002, @@ -629,7 +663,9 @@ exports.APIErrors = { CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: 50019, INVALID_OR_TAKEN_INVITE_CODE: 50020, CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: 50021, + CANNOT_EXECUTE_ON_CHANNEL_TYPE: 50024, INVALID_OAUTH_TOKEN: 50025, + INVALID_RECIPIENTS: 50033, BULK_DELETE_MESSAGE_TOO_OLD: 50034, INVALID_FORM_BODY: 50035, INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT: 50036, @@ -673,8 +709,26 @@ exports.WebhookTypes = [ 'Channel Follower', ]; +/** + * An overwrite type: + * * role + * * member + * @typedef {string} OverwriteType + */ +exports.OverwriteTypes = createEnum(['role', 'member']); + function keyMirror(arr) { let tmp = Object.create(null); for (const value of arr) tmp[value] = value; return tmp; } + +function createEnum(keys) { + const obj = {}; + for (const [index, key] of keys.entries()) { + if (key === null) continue; + obj[key] = index; + obj[index] = key; + } + return obj; +} diff --git a/src/util/MessageFlags.js b/src/util/MessageFlags.js index 536cbd8815b5..fb8d2abb6e66 100644 --- a/src/util/MessageFlags.js +++ b/src/util/MessageFlags.js @@ -15,6 +15,12 @@ class MessageFlags extends BitField {} * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ +/** + * Bitfield of the packed bits + * @type {number} + * @name MessageFlags#bitfield + */ + /** * Numeric message flags. All available properties: * * `CROSSPOSTED` diff --git a/src/util/Permissions.js b/src/util/Permissions.js index 98a283892a20..efaf1e72daca 100644 --- a/src/util/Permissions.js +++ b/src/util/Permissions.js @@ -10,10 +10,9 @@ const BitField = require('./BitField'); */ class Permissions extends BitField { /** - * @name Permissions - * @kind constructor - * @memberof Permissions - * @param {PermissionResolvable} [bits=0] Bit(s) to read from + * Bitfield of the packed bits + * @type {bigint} + * @name Permissions#bitfield */ /** @@ -22,7 +21,7 @@ class Permissions extends BitField { * * A permission number * * An instance of Permissions * * An Array of PermissionResolvable - * @typedef {string|number|Permissions|PermissionResolvable[]} PermissionResolvable + * @typedef {string|bigint|Permissions|PermissionResolvable[]} PermissionResolvable */ /** @@ -79,53 +78,55 @@ class Permissions extends BitField { * * `MANAGE_ROLES` * * `MANAGE_WEBHOOKS` * * `MANAGE_EMOJIS` - * @type {Object} + * @type {Object} * @see {@link https://discord.com/developers/docs/topics/permissions} */ Permissions.FLAGS = { - CREATE_INSTANT_INVITE: 1 << 0, - KICK_MEMBERS: 1 << 1, - BAN_MEMBERS: 1 << 2, - ADMINISTRATOR: 1 << 3, - MANAGE_CHANNELS: 1 << 4, - MANAGE_GUILD: 1 << 5, - ADD_REACTIONS: 1 << 6, - VIEW_AUDIT_LOG: 1 << 7, - PRIORITY_SPEAKER: 1 << 8, - STREAM: 1 << 9, - VIEW_CHANNEL: 1 << 10, - SEND_MESSAGES: 1 << 11, - SEND_TTS_MESSAGES: 1 << 12, - MANAGE_MESSAGES: 1 << 13, - EMBED_LINKS: 1 << 14, - ATTACH_FILES: 1 << 15, - READ_MESSAGE_HISTORY: 1 << 16, - MENTION_EVERYONE: 1 << 17, - USE_EXTERNAL_EMOJIS: 1 << 18, - VIEW_GUILD_INSIGHTS: 1 << 19, - CONNECT: 1 << 20, - SPEAK: 1 << 21, - MUTE_MEMBERS: 1 << 22, - DEAFEN_MEMBERS: 1 << 23, - MOVE_MEMBERS: 1 << 24, - USE_VAD: 1 << 25, - CHANGE_NICKNAME: 1 << 26, - MANAGE_NICKNAMES: 1 << 27, - MANAGE_ROLES: 1 << 28, - MANAGE_WEBHOOKS: 1 << 29, - MANAGE_EMOJIS: 1 << 30, + CREATE_INSTANT_INVITE: 1n << 0n, + KICK_MEMBERS: 1n << 1n, + BAN_MEMBERS: 1n << 2n, + ADMINISTRATOR: 1n << 3n, + MANAGE_CHANNELS: 1n << 4n, + MANAGE_GUILD: 1n << 5n, + ADD_REACTIONS: 1n << 6n, + VIEW_AUDIT_LOG: 1n << 7n, + PRIORITY_SPEAKER: 1n << 8n, + STREAM: 1n << 9n, + VIEW_CHANNEL: 1n << 10n, + SEND_MESSAGES: 1n << 11n, + SEND_TTS_MESSAGES: 1n << 12n, + MANAGE_MESSAGES: 1n << 13n, + EMBED_LINKS: 1n << 14n, + ATTACH_FILES: 1n << 15n, + READ_MESSAGE_HISTORY: 1n << 16n, + MENTION_EVERYONE: 1n << 17n, + USE_EXTERNAL_EMOJIS: 1n << 18n, + VIEW_GUILD_INSIGHTS: 1n << 19n, + CONNECT: 1n << 20n, + SPEAK: 1n << 21n, + MUTE_MEMBERS: 1n << 22n, + DEAFEN_MEMBERS: 1n << 23n, + MOVE_MEMBERS: 1n << 24n, + USE_VAD: 1n << 25n, + CHANGE_NICKNAME: 1n << 26n, + MANAGE_NICKNAMES: 1n << 27n, + MANAGE_ROLES: 1n << 28n, + MANAGE_WEBHOOKS: 1n << 29n, + MANAGE_EMOJIS: 1n << 30n, }; /** * Bitfield representing every permission combined - * @type {number} + * @type {bigint} */ -Permissions.ALL = Object.values(Permissions.FLAGS).reduce((all, p) => all | p, 0); +Permissions.ALL = Object.values(Permissions.FLAGS).reduce((all, p) => all | p, 0n); /** * Bitfield representing the default permissions for users - * @type {number} + * @type {bigint} */ -Permissions.DEFAULT = 104324673; +Permissions.DEFAULT = BigInt(104324673); + +Permissions.defaultBit = BigInt(0); module.exports = Permissions; diff --git a/src/util/Speaking.js b/src/util/Speaking.js index 5fda560e0a18..e8914250c256 100644 --- a/src/util/Speaking.js +++ b/src/util/Speaking.js @@ -16,6 +16,12 @@ class Speaking extends BitField {} * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ +/** + * Bitfield of the packed bits + * @type {number} + * @name Speaking#bitfield + */ + /** * Numeric speaking flags. All available properties: * * `SPEAKING` diff --git a/src/util/SystemChannelFlags.js b/src/util/SystemChannelFlags.js index 4d08b7609644..b7a3f172ffd3 100644 --- a/src/util/SystemChannelFlags.js +++ b/src/util/SystemChannelFlags.js @@ -17,6 +17,12 @@ class SystemChannelFlags extends BitField {} * @param {SystemChannelFlagsResolvable} [bits=0] Bit(s) to read from */ +/** + * Bitfield of the packed bits + * @type {number} + * @name SystemChannelFlags#bitfield + */ + /** * Data that can be resolved to give a sytem channel flag bitfield. This can be: * * A string (see {@link SystemChannelFlags.FLAGS}) diff --git a/src/util/UserFlags.js b/src/util/UserFlags.js index 871fbb7300af..ec801b0d078e 100644 --- a/src/util/UserFlags.js +++ b/src/util/UserFlags.js @@ -14,6 +14,12 @@ class UserFlags extends BitField {} * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ +/** + * Bitfield of the packed bits + * @type {number} + * @name UserFlags#bitfield + */ + /** * Numeric user flags. All available properties: * * `DISCORD_EMPLOYEE` diff --git a/test/createGuild.js b/test/createGuild.js index ccd10e027390..750987a0ca32 100644 --- a/test/createGuild.js +++ b/test/createGuild.js @@ -2,9 +2,11 @@ const assert = require('assert'); const { token } = require('./auth'); -const { Client } = require('../src'); +const { Client, Intents } = require('../src'); -const client = new Client(); +const client = new Client({ + intents: Intents.NON_PRIVILEGED, +}); client.on('ready', async () => { try { diff --git a/test/random.js b/test/random.js index 4b719f56e03f..d8d51e139baa 100644 --- a/test/random.js +++ b/test/random.js @@ -9,7 +9,9 @@ const Discord = require('../src'); console.time('magic'); -const client = new Discord.Client(); +const client = new Discord.Client({ + intents: Discord.Intents.NON_PRIVILEGED +}); client .login(token) diff --git a/test/sendtest.js b/test/sendtest.js index 691c4e24c5da..d5456d9c5d4a 100644 --- a/test/sendtest.js +++ b/test/sendtest.js @@ -7,7 +7,9 @@ const fetch = require('node-fetch'); const { owner, token } = require('./auth.js'); const Discord = require('../src'); -const client = new Discord.Client(); +const client = new Discord.Client({ + intents: Discord.Intents.NON_PRIVILEGED, +}); const fill = c => Array(4).fill(c.repeat(1000)); const buffer = l => fetch(l).then(res => res.buffer()); diff --git a/test/shard.js b/test/shard.js index 52225370c865..1dd1e89f8ab9 100644 --- a/test/shard.js +++ b/test/shard.js @@ -6,17 +6,13 @@ const Discord = require('../src'); const client = new Discord.Client({ shards: process.argv[2], shardCount: process.argv[3], + intents: Discord.Intents.NON_PRIVILEGED, }); client.on('message', msg => { if (msg.content.startsWith('?eval') && msg.author.id === '66564597481480192') { try { - const com = eval( - msg.content - .split(' ') - .slice(1) - .join(' '), - ); + const com = eval(msg.content.split(' ').slice(1).join(' ')); msg.channel.send(com, { code: true }); } catch (e) { msg.channel.send(e, { code: true }); diff --git a/test/tester1000.js b/test/tester1000.js index 077b996bb6f9..2705a40548ab 100644 --- a/test/tester1000.js +++ b/test/tester1000.js @@ -8,6 +8,7 @@ const log = (...args) => console.log(process.uptime().toFixed(3), ...args); const client = new Discord.Client({ shardCount: 2, + intents: Discord.Intents.NON_PRIVILEGED, }); client.on('debug', log); diff --git a/test/voice.js b/test/voice.js index 0ab2fe4f0a1c..cd7bc67eab3e 100644 --- a/test/voice.js +++ b/test/voice.js @@ -5,7 +5,10 @@ const ytdl = require('ytdl-core'); const auth = require('./auth.js'); const Discord = require('../src'); -const client = new Discord.Client({ partials: [] }); +const client = new Discord.Client({ + partials: [], + intents: Discord.Intents.NON_PRIVILEGED, +}); client .login(auth.token) diff --git a/test/webhooktest.js b/test/webhooktest.js index 3691dd8dd1f6..74cb34a5d20b 100644 --- a/test/webhooktest.js +++ b/test/webhooktest.js @@ -7,7 +7,9 @@ const fetch = require('node-fetch'); const { owner, token, webhookChannel, webhookToken } = require('./auth.js'); const Discord = require('../src'); -const client = new Discord.Client(); +const client = new Discord.Client({ + intents: Discord.Intents.NON_PRIVILEGED, +}); const fill = c => Array(4).fill(c.repeat(1000)); const buffer = l => fetch(l).then(res => res.buffer()); diff --git a/typings/index.d.ts b/typings/index.d.ts index 8d7f854dd97b..1108e243f215 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -9,6 +9,11 @@ declare enum ChannelType { unknown = 7, } +declare enum OverwriteTypes { + role = 0, + member = 1, +} + declare module 'discord.js' { import BaseCollection from '@discordjs/collection'; import { ChildProcess } from 'child_process'; @@ -47,7 +52,7 @@ declare module 'discord.js' { export class ActivityFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class APIMessage { @@ -118,7 +123,7 @@ declare module 'discord.js' { } export class BaseClient extends EventEmitter { - constructor(options?: ClientOptions); + constructor(options?: ClientOptions | WebhookClientOptions); private _timeouts: Set; private _intervals: Set; private _immediates: Set; @@ -127,7 +132,7 @@ declare module 'discord.js' { private decrementMaxListeners(): void; private incrementMaxListeners(): void; - public options: ClientOptions; + public options: ClientOptions | WebhookClientOptions; public clearInterval(interval: NodeJS.Timeout): void; public clearTimeout(timeout: NodeJS.Timeout): void; public clearImmediate(timeout: NodeJS.Immediate): void; @@ -155,23 +160,23 @@ declare module 'discord.js' { public broadcast: VoiceBroadcast; } - export class BitField { - constructor(bits?: BitFieldResolvable); - public bitfield: number; - public add(...bits: BitFieldResolvable[]): BitField; - public any(bit: BitFieldResolvable): boolean; - public equals(bit: BitFieldResolvable): boolean; - public freeze(): Readonly>; - public has(bit: BitFieldResolvable): boolean; - public missing(bits: BitFieldResolvable, ...hasParam: readonly unknown[]): S[]; - public remove(...bits: BitFieldResolvable[]): BitField; + export class BitField { + constructor(bits?: BitFieldResolvable); + public bitfield: N; + public add(...bits: BitFieldResolvable[]): BitField; + public any(bit: BitFieldResolvable): boolean; + public equals(bit: BitFieldResolvable): boolean; + public freeze(): Readonly>; + public has(bit: BitFieldResolvable): boolean; + public missing(bits: BitFieldResolvable, ...hasParam: readonly unknown[]): S[]; + public remove(...bits: BitFieldResolvable[]): BitField; public serialize(...hasParam: readonly unknown[]): Record; public toArray(...hasParam: readonly unknown[]): S[]; public toJSON(): number; public valueOf(): number; public [Symbol.iterator](): IterableIterator; public static FLAGS: object; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number | bigint; } export class CategoryChannel extends GuildChannel { @@ -193,14 +198,15 @@ declare module 'discord.js' { } export class Client extends BaseClient { - constructor(options?: ClientOptions); + constructor(options: ClientOptions); private actions: object; private _eval(script: string): any; - private _validateOptions(options?: ClientOptions): void; + private _validateOptions(options: ClientOptions): void; public channels: ChannelManager; public readonly emojis: BaseGuildEmojiManager; public guilds: GuildManager; + public options: ClientOptions; public readyAt: Date | null; public readonly readyTimestamp: number | null; public shard: ShardClientUtil | null; @@ -258,13 +264,14 @@ declare module 'discord.js' { export class ClientUser extends User { public mfaEnabled: boolean; public verified: boolean; - public setActivity(options?: ActivityOptions): Promise; - public setActivity(name: string, options?: ActivityOptions): Promise; + public edit(data: ClientUserEditData): Promise; + public setActivity(options?: ActivityOptions): Presence; + public setActivity(name: string, options?: ActivityOptions): Presence; public setAFK(afk: boolean): Promise; - public setAvatar(avatar: BufferResolvable | Base64Resolvable): Promise; - public setPresence(data: PresenceData): Promise; - public setStatus(status: PresenceStatusData, shardID?: number | number[]): Promise; - public setUsername(username: string): Promise; + public setAvatar(avatar: BufferResolvable | Base64Resolvable): Promise; + public setPresence(data: PresenceData): Presence; + public setStatus(status: PresenceStatusData, shardID?: number | number[]): Presence; + public setUsername(username: string): Promise; } export class ClientVoiceManager { @@ -513,9 +520,11 @@ declare module 'discord.js' { SMALL: 1; BIG: 2; }; + InviteScopes: InviteScope[]; MessageTypes: MessageType[]; SystemMessageTypes: SystemMessageType[]; ActivityTypes: ActivityType[]; + OverwriteTypes: OverwriteTypes; ExplicitContentFilterLevels: ExplicitContentFilterLevel[]; DefaultMessageNotifications: DefaultMessageNotifications[]; VerificationLevels: VerificationLevel[]; @@ -587,9 +596,6 @@ declare module 'discord.js' { public deleted: boolean; public description: string | null; public discoverySplash: string | null; - public embedChannel: GuildChannel | null; - public embedChannelID: Snowflake | null; - public embedEnabled: boolean; public emojis: GuildEmojiManager; public explicitContentFilter: ExplicitContentFilterLevel; public features: GuildFeatures[]; @@ -645,8 +651,7 @@ declare module 'discord.js' { public fetchAuditLogs(options?: GuildAuditLogsFetchOptions): Promise; public fetchBan(user: UserResolvable): Promise<{ user: User; reason: string }>; public fetchBans(): Promise>; - public fetchEmbed(): Promise; - public fetchIntegrations(options?: FetchIntegrationsOptions): Promise>; + public fetchIntegrations(): Promise>; public fetchInvites(): Promise>; public fetchPreview(): Promise; public fetchTemplates(): Promise>; @@ -666,7 +671,6 @@ declare module 'discord.js' { reason?: string, ): Promise; public setDiscoverySplash(discoverySplash: Base64Resolvable | null, reason?: string): Promise; - public setEmbed(embed: GuildWidgetData, reason?: string): Promise; public setExplicitContentFilter( explicitContentFilter: ExplicitContentFilterLevel | number, reason?: string, @@ -929,7 +933,7 @@ declare module 'discord.js' { public static PRIVILEGED: number; public static ALL: number; public static NON_PRIVILEGED: number; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class Invite extends Base { @@ -1104,7 +1108,7 @@ declare module 'discord.js' { export class MessageFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class MessageMentions { @@ -1198,17 +1202,17 @@ declare module 'discord.js' { public static resolve(overwrite: OverwriteResolvable, guild: Guild): RawOverwriteData; } - export class Permissions extends BitField { + export class Permissions extends BitField { public any(permission: PermissionResolvable, checkAdmin?: boolean): boolean; public has(permission: PermissionResolvable, checkAdmin?: boolean): boolean; - public missing(bits: BitFieldResolvable, checkAdmin?: boolean): PermissionString[]; + public missing(bits: BitFieldResolvable, checkAdmin?: boolean): PermissionString[]; public serialize(checkAdmin?: boolean): Record; public toArray(checkAdmin?: boolean): PermissionString[]; - public static ALL: number; - public static DEFAULT: number; + public static ALL: bigint; + public static DEFAULT: bigint; public static FLAGS: PermissionFlags; - public static resolve(permission?: PermissionResolvable): number; + public static resolve(permission?: PermissionResolvable): bigint; } export class Presence { @@ -1419,7 +1423,7 @@ declare module 'discord.js' { export class Speaking extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class StoreChannel extends GuildChannel { @@ -1477,7 +1481,7 @@ declare module 'discord.js' { export class SystemChannelFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class Team extends Base { @@ -1557,7 +1561,7 @@ declare module 'discord.js' { export class UserFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class Util { @@ -1664,7 +1668,7 @@ declare module 'discord.js' { public voiceManager: ClientVoiceManager; public disconnect(): void; public play(input: VoiceBroadcast | Readable | string, options?: StreamOptions): StreamDispatcher; - public setSpeaking(value: BitFieldResolvable): void; + public setSpeaking(value: BitFieldResolvable): void; public on(event: 'authenticated' | 'closing' | 'newSession' | 'ready' | 'reconnecting', listener: () => void): this; public on(event: 'debug', listener: (message: string) => void): this; @@ -1765,8 +1769,9 @@ declare module 'discord.js' { } export class WebhookClient extends WebhookMixin(BaseClient) { - constructor(id: string, token: string, options?: ClientOptions); + constructor(id: string, token: string, options?: WebhookClientOptions); public client: this; + public options: WebhookClientOptions; public token: string; } @@ -2175,6 +2180,7 @@ declare module 'discord.js' { UNKNOWN_GUILD_TEMPLATE: 10057; BOT_PROHIBITED_ENDPOINT: 20001; BOT_ONLY_ENDPOINT: 20002; + ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED: 20022; CHANNEL_HIT_WRITE_RATELIMIT: 20028; MAXIMUM_GUILDS: 30001; MAXIMUM_FRIENDS: 30002; @@ -2341,17 +2347,17 @@ declare module 'discord.js' { type Base64String = string; - type BitFieldResolvable = - | RecursiveReadonlyArray>> + type BitFieldResolvable = + | RecursiveReadonlyArray>> | T - | number - | Readonly>; + | N + | Readonly>; type BufferResolvable = Buffer | string; interface ChannelCreationOverwrites { - allow?: PermissionResolvable | number; - deny?: PermissionResolvable | number; + allow?: PermissionResolvable; + deny?: PermissionResolvable; id: RoleResolvable | UserResolvable; } @@ -2384,8 +2390,8 @@ declare module 'discord.js' { type ChannelResolvable = Channel | Snowflake; interface ClientEvents { - channelCreate: [channel: Channel]; - channelDelete: [channel: Channel | PartialDMChannel]; + channelCreate: [channel: GuildChannel]; + channelDelete: [channel: DMChannel | GuildChannel]; channelPinsUpdate: [channel: Channel | PartialDMChannel, date: Date]; channelUpdate: [oldChannel: Channel, newChannel: Channel]; debug: [message: string]; @@ -2454,6 +2460,7 @@ declare module 'discord.js' { restSweepInterval?: number; retryLimit?: number; presence?: PresenceData; + intents: BitFieldResolvable; ws?: WebSocketOptions; http?: HTTPOptions; } @@ -2466,6 +2473,11 @@ declare module 'discord.js' { desktop?: ClientPresenceStatus; } + interface ClientUserEditData { + username?: string; + avatar?: BufferResolvable | Base64Resolvable; + } + interface CloseEvent { wasClean: boolean; code: number; @@ -2855,6 +2867,7 @@ declare module 'discord.js' { permissions?: PermissionResolvable; guild?: GuildResolvable; disableGuildSelect?: boolean; + additionalScopes?: InviteScope[]; } interface InviteOptions { @@ -2867,6 +2880,19 @@ declare module 'discord.js' { type InviteResolvable = string; + type InviteScope = + | 'applications.builds.read' + | 'applications.commands' + | 'applications.entitlements' + | 'applications.store.update' + | 'connections' + | 'email' + | 'identity' + | 'guilds' + | 'guilds.join' + | 'gdm.join' + | 'webhook.incoming'; + type GuildTemplateResolvable = string; type MembershipStates = 'INVITED' | 'ACCEPTED'; @@ -2887,7 +2913,7 @@ declare module 'discord.js' { content?: StringResolvable; embed?: MessageEmbed | MessageEmbedOptions | null; code?: string | boolean; - flags?: BitFieldResolvable; + flags?: BitFieldResolvable; allowedMentions?: MessageMentionOptions; } @@ -3015,13 +3041,13 @@ declare module 'discord.js' { type OverwriteType = 'member' | 'role'; - interface PermissionFlags extends Record {} + interface PermissionFlags extends Record {} interface PermissionObject extends Record {} interface PermissionOverwriteOption extends Partial> {} - type PermissionResolvable = BitFieldResolvable; + type PermissionResolvable = BitFieldResolvable; type PermissionString = | 'CREATE_INSTANT_INVITE' @@ -3209,9 +3235,9 @@ declare module 'discord.js' { interface RawOverwriteData { id: Snowflake; - allow: number; - deny: number; - type: OverwriteType; + allow: string; + deny: string; + type: number; } interface ReactionCollectorOptions extends CollectorOptions { @@ -3278,7 +3304,7 @@ declare module 'discord.js' { type SystemChannelFlagsString = 'WELCOME_MESSAGE_DISABLED' | 'BOOST_MESSAGE_DISABLED'; - type SystemChannelFlagsResolvable = BitFieldResolvable; + type SystemChannelFlagsResolvable = BitFieldResolvable; type SystemMessageType = Exclude; @@ -3313,6 +3339,11 @@ declare module 'discord.js' { type VoiceStatus = number; + type WebhookClientOptions = Pick< + ClientOptions, + 'allowedMentions' | 'restTimeOffset' | 'restRequestTimeout' | 'retryLimit' | 'http' + >; + interface WebhookEditData { name?: string; avatar?: BufferResolvable; @@ -3347,7 +3378,6 @@ declare module 'discord.js' { interface WebSocketOptions { large_threshold?: number; compress?: boolean; - intents?: BitFieldResolvable | number; properties?: WebSocketProperties; } diff --git a/typings/index.ts b/typings/index.ts index db7abe7c63a9..75dbc9bebfca 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -1,8 +1,10 @@ /// -import { Client, Message, MessageAttachment, MessageEmbed } from 'discord.js'; +import { Client, Intents, Message, MessageAttachment, MessageEmbed } from 'discord.js'; -const client: Client = new Client(); +const client: Client = new Client({ + intents: Intents.NON_PRIVILEGED, +}); client.on('ready', () => { console.log(`Client is logged in as ${client.user!.tag} and ready!`); From 71a2de1bd8beff1ddc6e75c98fd080a9b72da172 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Thu, 11 Feb 2021 20:35:22 +0100 Subject: [PATCH 34/39] Revert "feat(*): merge v8" This reverts commit 598ba38178ee992de9782bc86ef86466099a0f30. --- src/client/Client.js | 25 +---- src/client/actions/ChannelCreate.js | 4 +- src/client/actions/MessageCreate.js | 2 +- src/client/actions/PresenceUpdate.js | 1 + src/client/websocket/WebSocketShard.js | 4 +- src/errors/Messages.js | 2 - src/managers/GuildManager.js | 2 +- src/managers/RoleManager.js | 2 +- src/rest/RequestHandler.js | 2 +- src/structures/ClientPresence.js | 74 ++++++++----- src/structures/ClientUser.js | 41 ++++--- src/structures/Guild.js | 103 +++++++++++++++--- src/structures/GuildAuditLogs.js | 19 ++-- src/structures/GuildChannel.js | 52 ++++----- src/structures/PermissionOverwrites.js | 68 +++++------- src/structures/Role.js | 4 +- src/structures/User.js | 7 +- src/util/BitField.js | 34 +++--- src/util/Constants.js | 62 +---------- src/util/MessageFlags.js | 6 -- src/util/Permissions.js | 83 +++++++-------- src/util/Speaking.js | 6 -- src/util/SystemChannelFlags.js | 6 -- src/util/UserFlags.js | 6 -- test/createGuild.js | 6 +- test/random.js | 4 +- test/sendtest.js | 4 +- test/shard.js | 8 +- test/tester1000.js | 1 - test/voice.js | 5 +- test/webhooktest.js | 4 +- typings/index.d.ts | 142 ++++++++++--------------- typings/index.ts | 6 +- 33 files changed, 362 insertions(+), 433 deletions(-) diff --git a/src/client/Client.js b/src/client/Client.js index f38a0c0fb4ba..4ac6da82c614 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -17,7 +17,7 @@ const Invite = require('../structures/Invite'); const VoiceRegion = require('../structures/VoiceRegion'); const Webhook = require('../structures/Webhook'); const Collection = require('../util/Collection'); -const { Events, DefaultOptions, InviteScopes } = require('../util/Constants'); +const { Events, DefaultOptions } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); const Intents = require('../util/Intents'); const Permissions = require('../util/Permissions'); @@ -29,9 +29,9 @@ const Structures = require('../util/Structures'); */ class Client extends BaseClient { /** - * @param {ClientOptions} options Options for the client + * @param {ClientOptions} [options] Options for the client */ - constructor(options) { + constructor(options = {}) { super(Object.assign({ _tokenType: 'Bot' }, options)); // Obtain shard details from environment or if present, worker threads @@ -377,7 +377,6 @@ class Client extends BaseClient { * @property {PermissionResolvable} [permissions] Permissions to request * @property {GuildResolvable} [guild] Guild to preselect * @property {boolean} [disableGuildSelect] Whether to disable the guild selection - * @property {InviteScope[]} [additionalScopes] Whether any additional scopes should be requested */ /** @@ -419,18 +418,6 @@ class Client extends BaseClient { query.set('guild_id', guildID); } - if (options.additionalScopes) { - const scopes = options.additionalScopes; - if (!Array.isArray(scopes)) { - throw new TypeError('INVALID_TYPE', 'additionalScopes', 'Array of Invite Scopes', true); - } - const invalidScope = scopes.find(scope => !InviteScopes.includes(scope)); - if (invalidScope) { - throw new TypeError('INVALID_ELEMENT', 'Array', 'additionalScopes', invalidScope); - } - query.set('scope', ['bot', ...scopes].join(' ')); - } - return `${this.options.http.api}${this.api.oauth2.authorize}?${query}`; } @@ -457,10 +444,8 @@ class Client extends BaseClient { * @private */ _validateOptions(options = this.options) { - if (typeof options.intents === 'undefined') { - throw new TypeError('CLIENT_MISSING_INTENTS'); - } else { - options.intents = Intents.resolve(options.intents); + if (typeof options.ws.intents !== 'undefined') { + options.ws.intents = Intents.resolve(options.ws.intents); } if (typeof options.shardCount !== 'number' || isNaN(options.shardCount) || options.shardCount < 1) { throw new TypeError('CLIENT_INVALID_OPTION', 'shardCount', 'a number greater than or equal to 1'); diff --git a/src/client/actions/ChannelCreate.js b/src/client/actions/ChannelCreate.js index d1660aa76d6b..fa60a0b39508 100644 --- a/src/client/actions/ChannelCreate.js +++ b/src/client/actions/ChannelCreate.js @@ -10,9 +10,9 @@ class ChannelCreateAction extends Action { const channel = client.channels.add(data); if (!existing && channel) { /** - * Emitted whenever a guild channel is created. + * Emitted whenever a channel is created. * @event Client#channelCreate - * @param {GuildChannel} channel The channel that was created + * @param {DMChannel|GuildChannel} channel The channel that was created */ client.emit(Events.CHANNEL_CREATE, channel); } diff --git a/src/client/actions/MessageCreate.js b/src/client/actions/MessageCreate.js index ae17415988e2..713870750aca 100644 --- a/src/client/actions/MessageCreate.js +++ b/src/client/actions/MessageCreate.js @@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants'); class MessageCreateAction extends Action { handle(data) { const client = this.client; - const channel = this.getChannel(data); + const channel = client.channels.cache.get(data.channel_id); if (channel) { const existing = channel.messages.cache.get(data.id); if (existing) return { message: existing }; diff --git a/src/client/actions/PresenceUpdate.js b/src/client/actions/PresenceUpdate.js index 69b79eb7835e..f74fbeb5d3e5 100644 --- a/src/client/actions/PresenceUpdate.js +++ b/src/client/actions/PresenceUpdate.js @@ -22,6 +22,7 @@ class PresenceUpdateAction extends Action { if (!member && data.status !== 'offline') { member = guild.members.add({ user, + roles: data.roles, deaf: false, mute: false, }); diff --git a/src/client/websocket/WebSocketShard.js b/src/client/websocket/WebSocketShard.js index 4fe904e1af38..64ceca83ecb6 100644 --- a/src/client/websocket/WebSocketShard.js +++ b/src/client/websocket/WebSocketShard.js @@ -3,7 +3,6 @@ const EventEmitter = require('events'); const WebSocket = require('../../WebSocket'); const { Status, Events, ShardEvents, OPCodes, WSEvents } = require('../../util/Constants'); -const Intents = require('../../util/Intents'); const STATUS_KEYS = Object.keys(Status); const CONNECTION_STATE = Object.keys(WebSocket.WebSocket); @@ -595,7 +594,6 @@ class WebSocketShard extends EventEmitter { // Clone the identify payload and assign the token and shard info const d = { ...client.options.ws, - intents: Intents.resolve(client.options.intents), token: client.token, shard: [this.id, Number(client.options.shardCount)], }; @@ -650,7 +648,7 @@ class WebSocketShard extends EventEmitter { _send(data) { if (!this.connection || this.connection.readyState !== WebSocket.OPEN) { this.debug(`Tried to send packet '${JSON.stringify(data)}' but no WebSocket is available!`); - this.destroy({ closeCode: 4000 }); + this.destroy({ close: 4000 }); return; } diff --git a/src/errors/Messages.js b/src/errors/Messages.js index e1b53de33e54..4e9d73cacbd2 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -5,7 +5,6 @@ const { register } = require('./DJSError'); const Messages = { CLIENT_INVALID_OPTION: (prop, must) => `The ${prop} option must be ${must}`, CLIENT_INVALID_PROVIDED_SHARDS: 'None of the provided shards were valid.', - CLIENT_MISSING_INTENTS: 'Valid intents must be provided for the Client.', TOKEN_INVALID: 'An invalid token was provided.', TOKEN_MISSING: 'Request to use token, but token was unavailable to the client.', @@ -90,7 +89,6 @@ const Messages = { GUILD_UNCACHED_ME: 'The client user as a member of this guild is uncached.', INVALID_TYPE: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`, - INVALID_ELEMENT: (type, name, elem) => `Supplied ${type} ${name} includes an invalid element: ${elem}`, WEBHOOK_MESSAGE: 'The message was not sent by a webhook.', diff --git a/src/managers/GuildManager.js b/src/managers/GuildManager.js index d5a92b4bf477..b04a52c122ce 100644 --- a/src/managers/GuildManager.js +++ b/src/managers/GuildManager.js @@ -53,7 +53,7 @@ class GuildManager extends BaseManager { * @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number * @property {boolean} [hoist] Whether or not the role should be hoisted * @property {number} [position] The position of the role - * @property {PermissionResolvable} [permissions] The permissions of the role + * @property {PermissionResolvable|number} [permissions] The permissions of the role * @property {boolean} [mentionable] Whether or not the role should be mentionable */ diff --git a/src/managers/RoleManager.js b/src/managers/RoleManager.js index 04aa47d000c6..667085b6beef 100644 --- a/src/managers/RoleManager.js +++ b/src/managers/RoleManager.js @@ -115,7 +115,7 @@ class RoleManager extends BaseManager { create(options = {}) { let { name, color, hoist, permissions, position, mentionable, reason } = options; if (color) color = resolveColor(color); - if (permissions) permissions = Permissions.resolve(permissions).toString(); + if (permissions) permissions = Permissions.resolve(permissions); return this.client.api .guilds(this.guild.id) diff --git a/src/rest/RequestHandler.js b/src/rest/RequestHandler.js index 245a285cda4b..100035a4bf75 100644 --- a/src/rest/RequestHandler.js +++ b/src/rest/RequestHandler.js @@ -105,7 +105,7 @@ class RequestHandler { this.limit = limit ? Number(limit) : Infinity; this.remaining = remaining ? Number(remaining) : 1; this.reset = reset ? calculateReset(reset, serverDate) : Date.now(); - this.retryAfter = retryAfter ? Number(retryAfter) * 1000 : -1; + this.retryAfter = retryAfter ? Number(retryAfter) : -1; // https://github.com/discordapp/discord-api-docs/issues/182 if (request.route.includes('reactions')) { diff --git a/src/structures/ClientPresence.js b/src/structures/ClientPresence.js index f32577b47c45..6c0955627318 100644 --- a/src/structures/ClientPresence.js +++ b/src/structures/ClientPresence.js @@ -2,6 +2,7 @@ const { Presence } = require('./Presence'); const { TypeError } = require('../errors'); +const Collection = require('../util/Collection'); const { ActivityTypes, OPCodes } = require('../util/Constants'); class ClientPresence extends Presence { @@ -13,8 +14,8 @@ class ClientPresence extends Presence { super(client, Object.assign(data, { status: data.status || 'online', user: { id: null } })); } - set(presence) { - const packet = this._parse(presence); + async set(presence) { + const packet = await this._parse(presence); this.patch(packet); if (typeof presence.shardID === 'undefined') { this.client.ws.broadcast({ op: OPCodes.STATUS_UPDATE, d: packet }); @@ -28,33 +29,58 @@ class ClientPresence extends Presence { return this; } - _parse({ status, since, afk, activities }) { - const data = { - activities: [], - afk: typeof afk === 'boolean' ? afk : false, - since: typeof since === 'number' && !Number.isNaN(since) ? since : null, + async _parse({ status, since, afk, activity }) { + const applicationID = activity && (activity.application ? activity.application.id || activity.application : null); + let assets = new Collection(); + if (activity) { + if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', 'name', 'string'); + if (!activity.type) activity.type = 0; + if (activity.assets && applicationID) { + try { + const a = await this.client.api.oauth2.applications(applicationID).assets.get(); + for (const asset of a) assets.set(asset.name, asset.id); + } catch {} // eslint-disable-line no-empty + } + } + + const packet = { + afk: afk != null ? afk : false, // eslint-disable-line eqeqeq + since: since != null ? since : null, // eslint-disable-line eqeqeq status: status || this.status, + game: activity + ? { + type: activity.type, + name: activity.name, + url: activity.url, + details: activity.details || undefined, + state: activity.state || undefined, + assets: activity.assets + ? { + large_text: activity.assets.largeText || undefined, + small_text: activity.assets.smallText || undefined, + large_image: assets.get(activity.assets.largeImage) || activity.assets.largeImage, + small_image: assets.get(activity.assets.smallImage) || activity.assets.smallImage, + } + : undefined, + timestamps: activity.timestamps || undefined, + party: activity.party || undefined, + application_id: applicationID || undefined, + secrets: activity.secrets || undefined, + instance: activity.instance || undefined, + } + : null, }; - if (activities === null) { - data.activities = null; - return data; + + if ((status || afk || since) && !activity) { + packet.game = this.activities[0] || null; } - if (activities && activities.length) { - for (const [i, activity] of activities.entries()) { - if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string'); - if (!activity.type) activity.type = 0; - - data.activities.push({ - type: typeof activity.type === 'number' ? activity.type : ActivityTypes.indexOf(activity.type), - name: activity.name, - url: activity.url, - }); - } - } else if ((status || afk || since) && this.activities.length) { - data.activities.push(...this.activities); + + if (packet.game) { + packet.game.type = + typeof packet.game.type === 'number' ? packet.game.type : ActivityTypes.indexOf(packet.game.type); } - return data; + return packet; } } diff --git a/src/structures/ClientUser.js b/src/structures/ClientUser.js index 33b4be56daf9..65112b8cc1f0 100644 --- a/src/structures/ClientUser.js +++ b/src/structures/ClientUser.js @@ -46,18 +46,16 @@ class ClientUser extends Structures.get('User') { return this.client.presence; } - /** - * Edits the logged in client. - * @param {Object} data The new data - * @param {string} [data.username] The new username - * @param {BufferResolvable|Base64Resolvable} [data.avatar] The new avatar - */ - async edit(data) { - const newData = await this.client.api.users('@me').patch({ data }); - this.client.token = newData.token; - const { updated } = this.client.actions.UserUpdate.handle(newData); - if (updated) return updated; - return this; + edit(data) { + return this.client.api + .users('@me') + .patch({ data }) + .then(newData => { + this.client.token = newData.token; + const { updated } = this.client.actions.UserUpdate.handle(newData); + if (updated) return updated; + return this; + }); } /** @@ -105,7 +103,7 @@ class ClientUser extends Structures.get('User') { /** * Sets the full presence of the client user. * @param {PresenceData} data Data for the presence - * @returns {Presence} + * @returns {Promise} * @example * // Set the client user's presence * client.user.setPresence({ activity: { name: 'with discord.js' }, status: 'idle' }) @@ -129,7 +127,7 @@ class ClientUser extends Structures.get('User') { * Sets the status of the client user. * @param {PresenceStatusData} status Status to change to * @param {?number|number[]} [shardID] Shard ID(s) to have the activity set on - * @returns {Presence} + * @returns {Promise} * @example * // Set the client user's status * client.user.setStatus('idle') @@ -146,14 +144,14 @@ class ClientUser extends Structures.get('User') { * @type {Object} * @property {string} [url] Twitch / YouTube stream URL * @property {ActivityType|number} [type] Type of the activity - * @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 */ /** * Sets the activity the client user is playing. * @param {string|ActivityOptions} [name] Activity being played, or options for setting the activity * @param {ActivityOptions} [options] Options for setting the activity - * @returns {Presence} + * @returns {Promise} * @example * // Set the client user's activity * client.user.setActivity('discord.js', { type: 'WATCHING' }) @@ -161,20 +159,19 @@ class ClientUser extends Structures.get('User') { * .catch(console.error); */ setActivity(name, options = {}) { - if (!name) return this.setPresence({ activities: null, shardID: options.shardID }); + if (!name) return this.setPresence({ activity: null, shardID: options.shardID }); const activity = Object.assign({}, options, typeof name === 'object' ? name : { name }); - return this.setPresence({ activities: [activity], shardID: activity.shardID }); + return this.setPresence({ activity, shardID: activity.shardID }); } /** * Sets/removes the AFK flag for the client user. * @param {boolean} afk Whether or not the user is AFK - * @param {number|number[]} [shardID] Shard Id(s) to have the AFK flag set on - * @returns {Presence} + * @returns {Promise} */ - setAFK(afk, shardID) { - return this.setPresence({ afk, shardID }); + setAFK(afk) { + return this.setPresence({ afk }); } } diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 2f4225f02add..055f065d63cc 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -217,6 +217,13 @@ class Guild extends Base { */ this.systemChannelID = data.system_channel_id; + /** + * Whether embedded images are enabled on this guild + * @type {boolean} + * @deprecated + */ + this.embedEnabled = data.embed_enabled; + /** * The type of premium tier: * * 0: NONE @@ -256,6 +263,15 @@ class Guild extends Base { this.widgetChannelID = data.widget_channel_id; } + if (typeof data.embed_channel_id !== 'undefined') { + /** + * The embed channel ID, if enabled + * @type {?string} + * @deprecated + */ + this.embedChannelID = data.embed_channel_id; + } + /** * The verification level of the guild * @type {VerificationLevel} @@ -576,6 +592,16 @@ class Guild extends Base { return this.client.channels.cache.get(this.widgetChannelID) || null; } + /** + * Embed channel for this guild + * @type {?TextChannel} + * @readonly + * @deprecated + */ + get embedChannel() { + return this.client.channels.cache.get(this.embedChannelID) || null; + } + /** * Rules channel for this guild * @type {?TextChannel} @@ -625,6 +651,8 @@ class Guild extends Base { /** * Fetches a collection of integrations to this guild. * Resolves with a collection mapping integrations by their ids. + * @param {Object} [options] Options for fetching integrations + * @param {boolean} [options.includeApplications] Whether to include bot and Oauth2 webhook integrations * @returns {Promise>} * @example * // Fetch integrations @@ -632,12 +660,20 @@ class Guild extends Base { * .then(integrations => console.log(`Fetched ${integrations.size} integrations`)) * .catch(console.error); */ - async fetchIntegrations() { - const data = await this.client.api.guilds(this.id).integrations.get(); - return data.reduce( - (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)), - new Collection(), - ); + fetchIntegrations({ includeApplications = false } = {}) { + return this.client.api + .guilds(this.id) + .integrations.get({ + query: { + include_applications: includeApplications, + }, + }) + .then(data => + data.reduce( + (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)), + new Collection(), + ), + ); } /** @@ -822,6 +858,20 @@ class Guild extends Base { * @property {?GuildChannelResolvable} channel The widget channel */ + /** + * Fetches the guild embed. + * @returns {Promise} + * @deprecated + * @example + * // Fetches the guild embed + * guild.fetchEmbed() + * .then(embed => console.log(`The embed is ${embed.enabled ? 'enabled' : 'disabled'}`)) + * .catch(console.error); + */ + fetchEmbed() { + return this.fetchWidget(); + } + /** * Fetches the guild widget. * @returns {Promise} @@ -833,8 +883,8 @@ class Guild extends Base { */ async fetchWidget() { const data = await this.client.api.guilds(this.id).widget.get(); - this.widgetEnabled = data.enabled; - this.widgetChannelID = data.channel_id; + this.widgetEnabled = this.embedEnabled = data.enabled; + this.widgetChannelID = this.embedChannelID = data.channel_id; return { enabled: data.enabled, channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null, @@ -1280,7 +1330,7 @@ class Guild extends Base { * @returns {Promise} * @example * guild.setRolePositions([{ role: roleID, position: updatedRoleIndex }]) - * .then(guild => console.log(`Role positions updated for ${guild}`)) + * .then(guild => console.log(`Role permissions updated for ${guild}`)) * .catch(console.error); */ setRolePositions(rolePositions) { @@ -1305,6 +1355,17 @@ class Guild extends Base { ); } + /** + * Edits the guild's embed. + * @param {GuildWidgetData} embed The embed for the guild + * @param {string} [reason] Reason for changing the guild's embed + * @returns {Promise} + * @deprecated + */ + setEmbed(embed, reason) { + return this.setWidget(embed, reason); + } + /** * Edits the guild's widget. * @param {GuildWidgetData} widget The widget for the guild @@ -1366,7 +1427,7 @@ class Guild extends Base { * @returns {boolean} */ equals(guild) { - return ( + let equal = guild && guild instanceof this.constructor && this.id === guild.id && @@ -1380,10 +1441,20 @@ class Guild extends Base { this.icon === guild.icon && this.ownerID === guild.ownerID && this.verificationLevel === guild.verificationLevel && + this.embedEnabled === guild.embedEnabled && (this.features === guild.features || (this.features.length === guild.features.length && - this.features.every((feat, i) => feat === guild.features[i]))) - ); + this.features.every((feat, i) => feat === guild.features[i]))); + + if (equal) { + if (this.embedChannel) { + if (!guild.embedChannel || this.embedChannel.id !== guild.embedChannel.id) equal = false; + } else if (guild.embedChannel) { + equal = false; + } + } + + return equal; } /** @@ -1414,7 +1485,7 @@ class Guild extends Base { /** * Creates a collection of this guild's roles, sorted by their position and IDs. - * @returns {Collection} + * @returns {Collection} * @private */ _sortedRoles() { @@ -1424,7 +1495,7 @@ class Guild extends Base { /** * Creates a collection of this guild's or a specific category's channels, sorted by their position and IDs. * @param {GuildChannel} [channel] Category to get the channels of - * @returns {Collection} + * @returns {Collection} * @private */ _sortedChannels(channel) { @@ -1441,6 +1512,10 @@ class Guild extends Base { } } +Guild.prototype.setEmbed = deprecate(Guild.prototype.setEmbed, 'Guild#setEmbed: Use setWidget instead'); + +Guild.prototype.fetchEmbed = deprecate(Guild.prototype.fetchEmbed, 'Guild#fetchEmbed: Use fetchWidget instead'); + Guild.prototype.fetchVanityCode = deprecate( Guild.prototype.fetchVanityCode, 'Guild#fetchVanityCode: Use fetchVanityData() instead', diff --git a/src/structures/GuildAuditLogs.js b/src/structures/GuildAuditLogs.js index aab133d4cc3a..394fdebfc368 100644 --- a/src/structures/GuildAuditLogs.js +++ b/src/structures/GuildAuditLogs.js @@ -3,7 +3,7 @@ const Integration = require('./Integration'); const Webhook = require('./Webhook'); const Collection = require('../util/Collection'); -const { OverwriteTypes, PartialTypes } = require('../util/Constants'); +const { PartialTypes } = require('../util/Constants'); const Permissions = require('../util/Permissions'); const Snowflake = require('../util/Snowflake'); const Util = require('../util/Util'); @@ -384,19 +384,16 @@ class GuildAuditLogsEntry { case Actions.CHANNEL_OVERWRITE_CREATE: case Actions.CHANNEL_OVERWRITE_UPDATE: case Actions.CHANNEL_OVERWRITE_DELETE: - switch (Number(data.options.type)) { - case OverwriteTypes.role: - this.extra = guild.roles.cache.get(data.options.id) || { - id: data.options.id, - name: data.options.role_name, - type: OverwriteTypes[OverwriteTypes.role], - }; + switch (data.options.type) { + case 'member': + this.extra = guild.members.cache.get(data.options.id) || { id: data.options.id, type: 'member' }; break; - case OverwriteTypes.member: - this.extra = guild.members.cache.get(data.options.id) || { + case 'role': + this.extra = guild.roles.cache.get(data.options.id) || { id: data.options.id, - type: OverwriteTypes[OverwriteTypes.member], + name: data.options.role_name, + type: 'role', }; break; diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 1a53fc7f4177..6832b6ff6fc9 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -7,7 +7,6 @@ const Role = require('./Role'); const { Error, TypeError } = require('../errors'); const Collection = require('../util/Collection'); const { ChannelTypes } = require('../util/Constants'); -const { OverwriteTypes } = require('../util/Constants'); const Permissions = require('../util/Permissions'); const Util = require('../util/Util'); @@ -162,12 +161,12 @@ class GuildChannel extends Channel { const overwrites = this.overwritesFor(member, true, roles); return permissions - .remove(overwrites.everyone ? overwrites.everyone.deny : 0n) - .add(overwrites.everyone ? overwrites.everyone.allow : 0n) - .remove(overwrites.roles.length > 0n ? overwrites.roles.map(role => role.deny) : 0n) - .add(overwrites.roles.length > 0n ? overwrites.roles.map(role => role.allow) : 0n) - .remove(overwrites.member ? overwrites.member.deny : 0n) - .add(overwrites.member ? overwrites.member.allow : 0n) + .remove(overwrites.everyone ? overwrites.everyone.deny : 0) + .add(overwrites.everyone ? overwrites.everyone.allow : 0) + .remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny) : 0) + .add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow) : 0) + .remove(overwrites.member ? overwrites.member.deny : 0) + .add(overwrites.member ? overwrites.member.allow : 0) .freeze(); } @@ -184,10 +183,10 @@ class GuildChannel extends Channel { const roleOverwrites = this.permissionOverwrites.get(role.id); return role.permissions - .remove(everyoneOverwrites ? everyoneOverwrites.deny : 0n) - .add(everyoneOverwrites ? everyoneOverwrites.allow : 0n) - .remove(roleOverwrites ? roleOverwrites.deny : 0n) - .add(roleOverwrites ? roleOverwrites.allow : 0n) + .remove(everyoneOverwrites ? everyoneOverwrites.deny : 0) + .add(everyoneOverwrites ? everyoneOverwrites.allow : 0) + .remove(roleOverwrites ? roleOverwrites.deny : 0) + .add(roleOverwrites ? roleOverwrites.allow : 0) .freeze(); } @@ -205,12 +204,13 @@ class GuildChannel extends Channel { * }, * ], 'Needed to change permissions'); */ - async overwritePermissions(overwrites, reason) { + overwritePermissions(overwrites, reason) { if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) { - throw new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true); + return Promise.reject( + new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true), + ); } - await this.edit({ permissionOverwrites: overwrites, reason }); - return this; + return this.edit({ permissionOverwrites: overwrites, reason }).then(() => this); } /** @@ -227,17 +227,13 @@ class GuildChannel extends Channel { * .then(channel => console.log(channel.permissionOverwrites.get(message.author.id))) * .catch(console.error); */ - async updateOverwrite(userOrRole, options, reason) { + updateOverwrite(userOrRole, options, reason) { userOrRole = this.guild.roles.resolve(userOrRole) || this.client.users.resolve(userOrRole); if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role')); const existing = this.permissionOverwrites.get(userOrRole.id); - if (existing) { - await existing.update(options, reason); - } else { - await this.createOverwrite(userOrRole, options, reason); - } - return this; + if (existing) return existing.update(options, reason).then(() => this); + return this.createOverwrite(userOrRole, options, reason); } /** @@ -258,19 +254,13 @@ class GuildChannel extends Channel { userOrRole = this.guild.roles.resolve(userOrRole) || this.client.users.resolve(userOrRole); if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role')); - const type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member; + const type = userOrRole instanceof Role ? 'role' : 'member'; const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options); return this.client.api .channels(this.id) - .permissions(userOrRole.id) - .put({ - data: { - id: userOrRole.id, - type, - allow, - deny, - }, + .permissions[userOrRole.id].put({ + data: { id: userOrRole.id, type, allow: allow.bitfield, deny: deny.bitfield }, reason, }) .then(() => this); diff --git a/src/structures/PermissionOverwrites.js b/src/structures/PermissionOverwrites.js index b8990136c2f9..bbc7cd13632e 100644 --- a/src/structures/PermissionOverwrites.js +++ b/src/structures/PermissionOverwrites.js @@ -2,8 +2,8 @@ const Role = require('./Role'); const { TypeError } = require('../errors'); -const { OverwriteTypes } = require('../util/Constants'); const Permissions = require('../util/Permissions'); +const Util = require('../util/Util'); /** * Represents a permission overwrite for a role or member in a guild channel. @@ -28,23 +28,30 @@ class PermissionOverwrites { */ this.id = data.id; + /** + * The type of a permission overwrite. It can be one of: + * * member + * * role + * @typedef {string} OverwriteType + */ + /** * The type of this overwrite * @type {OverwriteType} */ - this.type = OverwriteTypes[data.type]; + this.type = data.type; /** * The permissions that are denied for the user or role. * @type {Readonly} */ - this.deny = new Permissions(BigInt(data.deny)).freeze(); + this.deny = new Permissions(data.deny).freeze(); /** * The permissions that are allowed for the user or role. * @type {Readonly} */ - this.allow = new Permissions(BigInt(data.allow)).freeze(); + this.allow = new Permissions(data.allow).freeze(); } /** @@ -60,22 +67,16 @@ class PermissionOverwrites { * .then(channel => console.log(channel.permissionOverwrites.get(message.author.id))) * .catch(console.error); */ - async update(options, reason) { + update(options, reason) { const { allow, deny } = this.constructor.resolveOverwriteOptions(options, this); - await this.channel.client.api + return this.channel.client.api .channels(this.channel.id) - .permissions(this.id) - .put({ - data: { - id: this.id, - type: OverwriteTypes[this.type], - allow, - deny, - }, + .permissions[this.id].put({ + data: { id: this.id, type: this.type, allow: allow.bitfield, deny: deny.bitfield }, reason, - }); - return this; + }) + .then(() => this); } /** @@ -83,18 +84,12 @@ class PermissionOverwrites { * @param {string} [reason] Reason for deleting this overwrite * @returns {Promise} */ - async delete(reason) { - await this.channel.client.api.channels(this.channel.id).permissions(this.id).delete({ reason }); - return this; + delete(reason) { + return this.channel.client.api.channels[this.channel.id].permissions[this.id].delete({ reason }).then(() => this); } toJSON() { - return { - id: this.id, - type: OverwriteTypes[this.type], - allow: this.allow, - deny: this.deny, - }; + return Util.flatten(this); } /** @@ -147,9 +142,9 @@ class PermissionOverwrites { * The raw data for a permission overwrite * @typedef {Object} RawOverwriteData * @property {Snowflake} id The id of the overwrite - * @property {string} allow The permissions to allow - * @property {string} deny The permissions to deny - * @property {number} type The type of this OverwriteData + * @property {number} allow The permissions to allow + * @property {number} deny The permissions to deny + * @property {OverwriteType} type The type of this OverwriteData */ /** @@ -169,29 +164,24 @@ class PermissionOverwrites { /** * Resolves an overwrite into {@link RawOverwriteData}. * @param {OverwriteResolvable} overwrite The overwrite-like data to resolve - * @param {Guild} [guild] The guild to resolve from + * @param {Guild} guild The guild to resolve from * @returns {RawOverwriteData} */ static resolve(overwrite, guild) { if (overwrite instanceof this) return overwrite.toJSON(); - if (typeof overwrite.id === 'string' && overwrite.type in OverwriteTypes) { - return { - id: overwrite.id, - type: OverwriteTypes[overwrite.type], - allow: Permissions.resolve(overwrite.allow).toString(), - deny: Permissions.resolve(overwrite.deny).toString(), - }; + if (typeof overwrite.id === 'string' && ['role', 'member'].includes(overwrite.type)) { + return { ...overwrite, allow: Permissions.resolve(overwrite.allow), deny: Permissions.resolve(overwrite.deny) }; } const userOrRole = guild.roles.resolve(overwrite.id) || guild.client.users.resolve(overwrite.id); if (!userOrRole) throw new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role'); - const type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member; + const type = userOrRole instanceof Role ? 'role' : 'member'; return { id: userOrRole.id, type, - allow: Permissions.resolve(overwrite.allow).toString(), - deny: Permissions.resolve(overwrite.deny).toString(), + allow: Permissions.resolve(overwrite.allow), + deny: Permissions.resolve(overwrite.deny), }; } } diff --git a/src/structures/Role.js b/src/structures/Role.js index 90fb2383fea1..04db107ee694 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -63,7 +63,7 @@ class Role extends Base { * The permissions of the role * @type {Readonly} */ - this.permissions = new Permissions(BigInt(data.permissions)).freeze(); + this.permissions = new Permissions(data.permissions).freeze(); /** * Whether or not the role is managed by an external service @@ -301,7 +301,7 @@ class Role extends Base { * .catch(console.error); * @example * // Remove all permissions from a role - * role.setPermissions(0n) + * role.setPermissions(0) * .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`)) * .catch(console.error); */ diff --git a/src/structures/User.js b/src/structures/User.js index bddb94825264..2811e86222d4 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -245,7 +245,7 @@ class User extends Base { recipient_id: this.id, }, }); - return this.client.channels.add(data); + return this.client.actions.ChannelCreate.handle(data).channel; } /** @@ -255,9 +255,8 @@ class User extends Base { async deleteDM() { const { dmChannel } = this; if (!dmChannel) throw new Error('USER_NO_DMCHANNEL'); - await this.client.api.channels(dmChannel.id).delete(); - this.client.channels.remove(dmChannel.id); - return dmChannel; + const data = await this.client.api.channels(dmChannel.id).delete(); + return this.client.actions.ChannelDelete.handle(data).channel; } /** diff --git a/src/util/BitField.js b/src/util/BitField.js index fe32332f4fd7..070f28db02fa 100644 --- a/src/util/BitField.js +++ b/src/util/BitField.js @@ -7,12 +7,12 @@ const { RangeError } = require('../errors'); */ class BitField { /** - * @param {BitFieldResolvable} [bits=this.constructor.defaultBit] Bit(s) to read from + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ - constructor(bits = this.constructor.defaultBit) { + constructor(bits) { /** * Bitfield of the packed bits - * @type {number|bigint} + * @type {number} */ this.bitfield = this.constructor.resolve(bits); } @@ -23,7 +23,7 @@ class BitField { * @returns {boolean} */ any(bit) { - return (this.bitfield & this.constructor.resolve(bit)) !== this.constructor.defaultBit; + return (this.bitfield & this.constructor.resolve(bit)) !== 0; } /** @@ -71,7 +71,7 @@ class BitField { * @returns {BitField} These bits or new BitField if the instance is frozen. */ add(...bits) { - let total = this.constructor.defaultBit; + let total = 0; for (const bit of bits) { total |= this.constructor.resolve(bit); } @@ -86,7 +86,7 @@ class BitField { * @returns {BitField} These bits or new BitField if the instance is frozen. */ remove(...bits) { - let total = this.constructor.defaultBit; + let total = 0; for (const bit of bits) { total |= this.constructor.resolve(bit); } @@ -117,7 +117,7 @@ class BitField { } toJSON() { - return typeof this.bitfield === 'number' ? this.bitfield : this.bitfield.toString(); + return this.bitfield; } valueOf() { @@ -133,20 +133,18 @@ class BitField { * * A bit number (this can be a number literal or a value taken from {@link BitField.FLAGS}) * * An instance of BitField * * An Array of BitFieldResolvable - * @typedef {number|bigint|BitField|BitFieldResolvable[]} BitFieldResolvable + * @typedef {number|BitField|BitFieldResolvable[]} BitFieldResolvable */ /** * Resolves bitfields to their numeric form. - * @param {BitFieldResolvable} [bit] - bit(s) to resolve - * @returns {number|bigint} + * @param {BitFieldResolvable} [bit=0] - bit(s) to resolve + * @returns {number} */ - static resolve(bit) { - const { defaultBit } = this; - if (typeof bit === 'undefined') return defaultBit; - if (typeof defaultBit === typeof bit && bit >= defaultBit) return bit; + static resolve(bit = 0) { + if (typeof bit === 'number' && bit >= 0) return bit; if (bit instanceof BitField) return bit.bitfield; - if (Array.isArray(bit)) return bit.map(p => this.resolve(p)).reduce((prev, p) => prev | p, defaultBit); + if (Array.isArray(bit)) return bit.map(p => this.resolve(p)).reduce((prev, p) => prev | p, 0); if (typeof bit === 'string' && typeof this.FLAGS[bit] !== 'undefined') return this.FLAGS[bit]; throw new RangeError('BITFIELD_INVALID', bit); } @@ -160,10 +158,4 @@ class BitField { */ BitField.FLAGS = {}; -/** - * @type {number|bigint} - * @private - */ -BitField.defaultBit = 0; - module.exports = BitField; diff --git a/src/util/Constants.js b/src/util/Constants.js index 3f4d7dcbe438..308e45ab94e4 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -30,8 +30,7 @@ const { Error, RangeError } = require('../errors'); * @property {number} [restSweepInterval=60] How frequently to delete inactive request buckets, in seconds * (or 0 for never) * @property {number} [retryLimit=1] How many times to retry on 5XX errors (Infinity for indefinite amount of retries) - * @property {PresenceData} [presence={}] Presence data to use upon login - * @property {IntentsResolvable} intents Intents to enable for this connection + * @property {PresenceData} [presence] Presence data to use upon login * @property {WebsocketOptions} [ws] Options for the WebSocket * @property {HTTPOptions} [http] HTTP options */ @@ -53,6 +52,7 @@ exports.DefaultOptions = { * @typedef {Object} WebsocketOptions * @property {number} [large_threshold=50] Number of members in a guild after which offline users will no longer be * sent in the initial guild member list, must be between 50 and 250 + * @property {IntentsResolvable} [intents] Intents to enable for this connection */ ws: { large_threshold: 50, @@ -62,7 +62,7 @@ exports.DefaultOptions = { $browser: 'discord.js', $device: 'discord.js', }, - version: 8, + version: 6, }, /** @@ -75,7 +75,7 @@ exports.DefaultOptions = { * @property {string} [template='https://discord.new'] Base url of templates */ http: { - version: 8, + version: 7, api: 'https://discord.com/api', cdn: 'https://cdn.discordapp.com', invite: 'https://discord.gg', @@ -375,36 +375,6 @@ exports.WSEvents = keyMirror([ 'WEBHOOKS_UPDATE', ]); -/** - * A valid scope to request when generating an invite link. - * Scopes that require whitelist are not considered valid for this generator - * * `applications.builds.read`: allows reading build data for a users applications - * * `applications.commands`: allows this bot to create commands in the server - * * `applications.entitlements`: allows reading entitlements for a users applications - * * `applications.store.update`: allows reading and updating of store data for a users applications - * * `connections`: makes the endpoint for getting a users connections available - * * `email`: allows the `/users/@me` endpoint return with an email - * * `identify`: allows the `/users/@me` endpoint without an email - * * `guilds`: makes the `/users/@me/guilds` endpoint available for a user - * * `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 - * * `webhook.incoming`: generates a webhook to a channel - * @typedef {string} InviteScope - */ -exports.InviteScopes = [ - 'applications.builds.read', - 'applications.commands', - 'applications.entitlements', - 'applications.store.update', - 'connections', - 'email', - 'identity', - 'guilds', - 'guilds.join', - 'gdm.join', - 'webhook.incoming', -]; - /** * The type of a message, e.g. `DEFAULT`. Here are the available types: * * DEFAULT @@ -557,7 +527,6 @@ exports.VerificationLevels = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_HIGH']; * * UNKNOWN_GUILD_TEMPLATE * * BOT_PROHIBITED_ENDPOINT * * BOT_ONLY_ENDPOINT - * * ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED * * CHANNEL_HIT_WRITE_RATELIMIT * * MAXIMUM_GUILDS * * MAXIMUM_FRIENDS @@ -594,9 +563,7 @@ exports.VerificationLevels = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_HIGH']; * * CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL * * INVALID_OR_TAKEN_INVITE_CODE * * CANNOT_EXECUTE_ON_SYSTEM_MESSAGE - * * CANNOT_EXECUTE_ON_CHANNEL_TYPE * * INVALID_OAUTH_TOKEN - * * INVALID_RECIPIENTS * * BULK_DELETE_MESSAGE_TOO_OLD * * INVALID_FORM_BODY * * INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT @@ -626,7 +593,6 @@ exports.APIErrors = { UNKNOWN_GUILD_TEMPLATE: 10057, BOT_PROHIBITED_ENDPOINT: 20001, BOT_ONLY_ENDPOINT: 20002, - ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED: 20022, CHANNEL_HIT_WRITE_RATELIMIT: 20028, MAXIMUM_GUILDS: 30001, MAXIMUM_FRIENDS: 30002, @@ -663,9 +629,7 @@ exports.APIErrors = { CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: 50019, INVALID_OR_TAKEN_INVITE_CODE: 50020, CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: 50021, - CANNOT_EXECUTE_ON_CHANNEL_TYPE: 50024, INVALID_OAUTH_TOKEN: 50025, - INVALID_RECIPIENTS: 50033, BULK_DELETE_MESSAGE_TOO_OLD: 50034, INVALID_FORM_BODY: 50035, INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT: 50036, @@ -709,26 +673,8 @@ exports.WebhookTypes = [ 'Channel Follower', ]; -/** - * An overwrite type: - * * role - * * member - * @typedef {string} OverwriteType - */ -exports.OverwriteTypes = createEnum(['role', 'member']); - function keyMirror(arr) { let tmp = Object.create(null); for (const value of arr) tmp[value] = value; return tmp; } - -function createEnum(keys) { - const obj = {}; - for (const [index, key] of keys.entries()) { - if (key === null) continue; - obj[key] = index; - obj[index] = key; - } - return obj; -} diff --git a/src/util/MessageFlags.js b/src/util/MessageFlags.js index fb8d2abb6e66..536cbd8815b5 100644 --- a/src/util/MessageFlags.js +++ b/src/util/MessageFlags.js @@ -15,12 +15,6 @@ class MessageFlags extends BitField {} * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ -/** - * Bitfield of the packed bits - * @type {number} - * @name MessageFlags#bitfield - */ - /** * Numeric message flags. All available properties: * * `CROSSPOSTED` diff --git a/src/util/Permissions.js b/src/util/Permissions.js index efaf1e72daca..98a283892a20 100644 --- a/src/util/Permissions.js +++ b/src/util/Permissions.js @@ -10,9 +10,10 @@ const BitField = require('./BitField'); */ class Permissions extends BitField { /** - * Bitfield of the packed bits - * @type {bigint} - * @name Permissions#bitfield + * @name Permissions + * @kind constructor + * @memberof Permissions + * @param {PermissionResolvable} [bits=0] Bit(s) to read from */ /** @@ -21,7 +22,7 @@ class Permissions extends BitField { * * A permission number * * An instance of Permissions * * An Array of PermissionResolvable - * @typedef {string|bigint|Permissions|PermissionResolvable[]} PermissionResolvable + * @typedef {string|number|Permissions|PermissionResolvable[]} PermissionResolvable */ /** @@ -78,55 +79,53 @@ class Permissions extends BitField { * * `MANAGE_ROLES` * * `MANAGE_WEBHOOKS` * * `MANAGE_EMOJIS` - * @type {Object} + * @type {Object} * @see {@link https://discord.com/developers/docs/topics/permissions} */ Permissions.FLAGS = { - CREATE_INSTANT_INVITE: 1n << 0n, - KICK_MEMBERS: 1n << 1n, - BAN_MEMBERS: 1n << 2n, - ADMINISTRATOR: 1n << 3n, - MANAGE_CHANNELS: 1n << 4n, - MANAGE_GUILD: 1n << 5n, - ADD_REACTIONS: 1n << 6n, - VIEW_AUDIT_LOG: 1n << 7n, - PRIORITY_SPEAKER: 1n << 8n, - STREAM: 1n << 9n, - VIEW_CHANNEL: 1n << 10n, - SEND_MESSAGES: 1n << 11n, - SEND_TTS_MESSAGES: 1n << 12n, - MANAGE_MESSAGES: 1n << 13n, - EMBED_LINKS: 1n << 14n, - ATTACH_FILES: 1n << 15n, - READ_MESSAGE_HISTORY: 1n << 16n, - MENTION_EVERYONE: 1n << 17n, - USE_EXTERNAL_EMOJIS: 1n << 18n, - VIEW_GUILD_INSIGHTS: 1n << 19n, - CONNECT: 1n << 20n, - SPEAK: 1n << 21n, - MUTE_MEMBERS: 1n << 22n, - DEAFEN_MEMBERS: 1n << 23n, - MOVE_MEMBERS: 1n << 24n, - USE_VAD: 1n << 25n, - CHANGE_NICKNAME: 1n << 26n, - MANAGE_NICKNAMES: 1n << 27n, - MANAGE_ROLES: 1n << 28n, - MANAGE_WEBHOOKS: 1n << 29n, - MANAGE_EMOJIS: 1n << 30n, + CREATE_INSTANT_INVITE: 1 << 0, + KICK_MEMBERS: 1 << 1, + BAN_MEMBERS: 1 << 2, + ADMINISTRATOR: 1 << 3, + MANAGE_CHANNELS: 1 << 4, + MANAGE_GUILD: 1 << 5, + ADD_REACTIONS: 1 << 6, + VIEW_AUDIT_LOG: 1 << 7, + PRIORITY_SPEAKER: 1 << 8, + STREAM: 1 << 9, + VIEW_CHANNEL: 1 << 10, + SEND_MESSAGES: 1 << 11, + SEND_TTS_MESSAGES: 1 << 12, + MANAGE_MESSAGES: 1 << 13, + EMBED_LINKS: 1 << 14, + ATTACH_FILES: 1 << 15, + READ_MESSAGE_HISTORY: 1 << 16, + MENTION_EVERYONE: 1 << 17, + USE_EXTERNAL_EMOJIS: 1 << 18, + VIEW_GUILD_INSIGHTS: 1 << 19, + CONNECT: 1 << 20, + SPEAK: 1 << 21, + MUTE_MEMBERS: 1 << 22, + DEAFEN_MEMBERS: 1 << 23, + MOVE_MEMBERS: 1 << 24, + USE_VAD: 1 << 25, + CHANGE_NICKNAME: 1 << 26, + MANAGE_NICKNAMES: 1 << 27, + MANAGE_ROLES: 1 << 28, + MANAGE_WEBHOOKS: 1 << 29, + MANAGE_EMOJIS: 1 << 30, }; /** * Bitfield representing every permission combined - * @type {bigint} + * @type {number} */ -Permissions.ALL = Object.values(Permissions.FLAGS).reduce((all, p) => all | p, 0n); +Permissions.ALL = Object.values(Permissions.FLAGS).reduce((all, p) => all | p, 0); /** * Bitfield representing the default permissions for users - * @type {bigint} + * @type {number} */ -Permissions.DEFAULT = BigInt(104324673); - -Permissions.defaultBit = BigInt(0); +Permissions.DEFAULT = 104324673; module.exports = Permissions; diff --git a/src/util/Speaking.js b/src/util/Speaking.js index e8914250c256..5fda560e0a18 100644 --- a/src/util/Speaking.js +++ b/src/util/Speaking.js @@ -16,12 +16,6 @@ class Speaking extends BitField {} * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ -/** - * Bitfield of the packed bits - * @type {number} - * @name Speaking#bitfield - */ - /** * Numeric speaking flags. All available properties: * * `SPEAKING` diff --git a/src/util/SystemChannelFlags.js b/src/util/SystemChannelFlags.js index b7a3f172ffd3..4d08b7609644 100644 --- a/src/util/SystemChannelFlags.js +++ b/src/util/SystemChannelFlags.js @@ -17,12 +17,6 @@ class SystemChannelFlags extends BitField {} * @param {SystemChannelFlagsResolvable} [bits=0] Bit(s) to read from */ -/** - * Bitfield of the packed bits - * @type {number} - * @name SystemChannelFlags#bitfield - */ - /** * Data that can be resolved to give a sytem channel flag bitfield. This can be: * * A string (see {@link SystemChannelFlags.FLAGS}) diff --git a/src/util/UserFlags.js b/src/util/UserFlags.js index ec801b0d078e..871fbb7300af 100644 --- a/src/util/UserFlags.js +++ b/src/util/UserFlags.js @@ -14,12 +14,6 @@ class UserFlags extends BitField {} * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ -/** - * Bitfield of the packed bits - * @type {number} - * @name UserFlags#bitfield - */ - /** * Numeric user flags. All available properties: * * `DISCORD_EMPLOYEE` diff --git a/test/createGuild.js b/test/createGuild.js index 750987a0ca32..ccd10e027390 100644 --- a/test/createGuild.js +++ b/test/createGuild.js @@ -2,11 +2,9 @@ const assert = require('assert'); const { token } = require('./auth'); -const { Client, Intents } = require('../src'); +const { Client } = require('../src'); -const client = new Client({ - intents: Intents.NON_PRIVILEGED, -}); +const client = new Client(); client.on('ready', async () => { try { diff --git a/test/random.js b/test/random.js index d8d51e139baa..4b719f56e03f 100644 --- a/test/random.js +++ b/test/random.js @@ -9,9 +9,7 @@ const Discord = require('../src'); console.time('magic'); -const client = new Discord.Client({ - intents: Discord.Intents.NON_PRIVILEGED -}); +const client = new Discord.Client(); client .login(token) diff --git a/test/sendtest.js b/test/sendtest.js index d5456d9c5d4a..691c4e24c5da 100644 --- a/test/sendtest.js +++ b/test/sendtest.js @@ -7,9 +7,7 @@ const fetch = require('node-fetch'); const { owner, token } = require('./auth.js'); const Discord = require('../src'); -const client = new Discord.Client({ - intents: Discord.Intents.NON_PRIVILEGED, -}); +const client = new Discord.Client(); const fill = c => Array(4).fill(c.repeat(1000)); const buffer = l => fetch(l).then(res => res.buffer()); diff --git a/test/shard.js b/test/shard.js index 1dd1e89f8ab9..52225370c865 100644 --- a/test/shard.js +++ b/test/shard.js @@ -6,13 +6,17 @@ const Discord = require('../src'); const client = new Discord.Client({ shards: process.argv[2], shardCount: process.argv[3], - intents: Discord.Intents.NON_PRIVILEGED, }); client.on('message', msg => { if (msg.content.startsWith('?eval') && msg.author.id === '66564597481480192') { try { - const com = eval(msg.content.split(' ').slice(1).join(' ')); + const com = eval( + msg.content + .split(' ') + .slice(1) + .join(' '), + ); msg.channel.send(com, { code: true }); } catch (e) { msg.channel.send(e, { code: true }); diff --git a/test/tester1000.js b/test/tester1000.js index 2705a40548ab..077b996bb6f9 100644 --- a/test/tester1000.js +++ b/test/tester1000.js @@ -8,7 +8,6 @@ const log = (...args) => console.log(process.uptime().toFixed(3), ...args); const client = new Discord.Client({ shardCount: 2, - intents: Discord.Intents.NON_PRIVILEGED, }); client.on('debug', log); diff --git a/test/voice.js b/test/voice.js index cd7bc67eab3e..0ab2fe4f0a1c 100644 --- a/test/voice.js +++ b/test/voice.js @@ -5,10 +5,7 @@ const ytdl = require('ytdl-core'); const auth = require('./auth.js'); const Discord = require('../src'); -const client = new Discord.Client({ - partials: [], - intents: Discord.Intents.NON_PRIVILEGED, -}); +const client = new Discord.Client({ partials: [] }); client .login(auth.token) diff --git a/test/webhooktest.js b/test/webhooktest.js index 74cb34a5d20b..3691dd8dd1f6 100644 --- a/test/webhooktest.js +++ b/test/webhooktest.js @@ -7,9 +7,7 @@ const fetch = require('node-fetch'); const { owner, token, webhookChannel, webhookToken } = require('./auth.js'); const Discord = require('../src'); -const client = new Discord.Client({ - intents: Discord.Intents.NON_PRIVILEGED, -}); +const client = new Discord.Client(); const fill = c => Array(4).fill(c.repeat(1000)); const buffer = l => fetch(l).then(res => res.buffer()); diff --git a/typings/index.d.ts b/typings/index.d.ts index 1108e243f215..8d7f854dd97b 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -9,11 +9,6 @@ declare enum ChannelType { unknown = 7, } -declare enum OverwriteTypes { - role = 0, - member = 1, -} - declare module 'discord.js' { import BaseCollection from '@discordjs/collection'; import { ChildProcess } from 'child_process'; @@ -52,7 +47,7 @@ declare module 'discord.js' { export class ActivityFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class APIMessage { @@ -123,7 +118,7 @@ declare module 'discord.js' { } export class BaseClient extends EventEmitter { - constructor(options?: ClientOptions | WebhookClientOptions); + constructor(options?: ClientOptions); private _timeouts: Set; private _intervals: Set; private _immediates: Set; @@ -132,7 +127,7 @@ declare module 'discord.js' { private decrementMaxListeners(): void; private incrementMaxListeners(): void; - public options: ClientOptions | WebhookClientOptions; + public options: ClientOptions; public clearInterval(interval: NodeJS.Timeout): void; public clearTimeout(timeout: NodeJS.Timeout): void; public clearImmediate(timeout: NodeJS.Immediate): void; @@ -160,23 +155,23 @@ declare module 'discord.js' { public broadcast: VoiceBroadcast; } - export class BitField { - constructor(bits?: BitFieldResolvable); - public bitfield: N; - public add(...bits: BitFieldResolvable[]): BitField; - public any(bit: BitFieldResolvable): boolean; - public equals(bit: BitFieldResolvable): boolean; - public freeze(): Readonly>; - public has(bit: BitFieldResolvable): boolean; - public missing(bits: BitFieldResolvable, ...hasParam: readonly unknown[]): S[]; - public remove(...bits: BitFieldResolvable[]): BitField; + export class BitField { + constructor(bits?: BitFieldResolvable); + public bitfield: number; + public add(...bits: BitFieldResolvable[]): BitField; + public any(bit: BitFieldResolvable): boolean; + public equals(bit: BitFieldResolvable): boolean; + public freeze(): Readonly>; + public has(bit: BitFieldResolvable): boolean; + public missing(bits: BitFieldResolvable, ...hasParam: readonly unknown[]): S[]; + public remove(...bits: BitFieldResolvable[]): BitField; public serialize(...hasParam: readonly unknown[]): Record; public toArray(...hasParam: readonly unknown[]): S[]; public toJSON(): number; public valueOf(): number; public [Symbol.iterator](): IterableIterator; public static FLAGS: object; - public static resolve(bit?: BitFieldResolvable): number | bigint; + public static resolve(bit?: BitFieldResolvable): number; } export class CategoryChannel extends GuildChannel { @@ -198,15 +193,14 @@ declare module 'discord.js' { } export class Client extends BaseClient { - constructor(options: ClientOptions); + constructor(options?: ClientOptions); private actions: object; private _eval(script: string): any; - private _validateOptions(options: ClientOptions): void; + private _validateOptions(options?: ClientOptions): void; public channels: ChannelManager; public readonly emojis: BaseGuildEmojiManager; public guilds: GuildManager; - public options: ClientOptions; public readyAt: Date | null; public readonly readyTimestamp: number | null; public shard: ShardClientUtil | null; @@ -264,14 +258,13 @@ declare module 'discord.js' { export class ClientUser extends User { public mfaEnabled: boolean; public verified: boolean; - public edit(data: ClientUserEditData): Promise; - public setActivity(options?: ActivityOptions): Presence; - public setActivity(name: string, options?: ActivityOptions): Presence; + public setActivity(options?: ActivityOptions): Promise; + public setActivity(name: string, options?: ActivityOptions): Promise; public setAFK(afk: boolean): Promise; - public setAvatar(avatar: BufferResolvable | Base64Resolvable): Promise; - public setPresence(data: PresenceData): Presence; - public setStatus(status: PresenceStatusData, shardID?: number | number[]): Presence; - public setUsername(username: string): Promise; + public setAvatar(avatar: BufferResolvable | Base64Resolvable): Promise; + public setPresence(data: PresenceData): Promise; + public setStatus(status: PresenceStatusData, shardID?: number | number[]): Promise; + public setUsername(username: string): Promise; } export class ClientVoiceManager { @@ -520,11 +513,9 @@ declare module 'discord.js' { SMALL: 1; BIG: 2; }; - InviteScopes: InviteScope[]; MessageTypes: MessageType[]; SystemMessageTypes: SystemMessageType[]; ActivityTypes: ActivityType[]; - OverwriteTypes: OverwriteTypes; ExplicitContentFilterLevels: ExplicitContentFilterLevel[]; DefaultMessageNotifications: DefaultMessageNotifications[]; VerificationLevels: VerificationLevel[]; @@ -596,6 +587,9 @@ declare module 'discord.js' { public deleted: boolean; public description: string | null; public discoverySplash: string | null; + public embedChannel: GuildChannel | null; + public embedChannelID: Snowflake | null; + public embedEnabled: boolean; public emojis: GuildEmojiManager; public explicitContentFilter: ExplicitContentFilterLevel; public features: GuildFeatures[]; @@ -651,7 +645,8 @@ declare module 'discord.js' { public fetchAuditLogs(options?: GuildAuditLogsFetchOptions): Promise; public fetchBan(user: UserResolvable): Promise<{ user: User; reason: string }>; public fetchBans(): Promise>; - public fetchIntegrations(): Promise>; + public fetchEmbed(): Promise; + public fetchIntegrations(options?: FetchIntegrationsOptions): Promise>; public fetchInvites(): Promise>; public fetchPreview(): Promise; public fetchTemplates(): Promise>; @@ -671,6 +666,7 @@ declare module 'discord.js' { reason?: string, ): Promise; public setDiscoverySplash(discoverySplash: Base64Resolvable | null, reason?: string): Promise; + public setEmbed(embed: GuildWidgetData, reason?: string): Promise; public setExplicitContentFilter( explicitContentFilter: ExplicitContentFilterLevel | number, reason?: string, @@ -933,7 +929,7 @@ declare module 'discord.js' { public static PRIVILEGED: number; public static ALL: number; public static NON_PRIVILEGED: number; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class Invite extends Base { @@ -1108,7 +1104,7 @@ declare module 'discord.js' { export class MessageFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class MessageMentions { @@ -1202,17 +1198,17 @@ declare module 'discord.js' { public static resolve(overwrite: OverwriteResolvable, guild: Guild): RawOverwriteData; } - export class Permissions extends BitField { + export class Permissions extends BitField { public any(permission: PermissionResolvable, checkAdmin?: boolean): boolean; public has(permission: PermissionResolvable, checkAdmin?: boolean): boolean; - public missing(bits: BitFieldResolvable, checkAdmin?: boolean): PermissionString[]; + public missing(bits: BitFieldResolvable, checkAdmin?: boolean): PermissionString[]; public serialize(checkAdmin?: boolean): Record; public toArray(checkAdmin?: boolean): PermissionString[]; - public static ALL: bigint; - public static DEFAULT: bigint; + public static ALL: number; + public static DEFAULT: number; public static FLAGS: PermissionFlags; - public static resolve(permission?: PermissionResolvable): bigint; + public static resolve(permission?: PermissionResolvable): number; } export class Presence { @@ -1423,7 +1419,7 @@ declare module 'discord.js' { export class Speaking extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class StoreChannel extends GuildChannel { @@ -1481,7 +1477,7 @@ declare module 'discord.js' { export class SystemChannelFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class Team extends Base { @@ -1561,7 +1557,7 @@ declare module 'discord.js' { export class UserFlags extends BitField { public static FLAGS: Record; - public static resolve(bit?: BitFieldResolvable): number; + public static resolve(bit?: BitFieldResolvable): number; } export class Util { @@ -1668,7 +1664,7 @@ declare module 'discord.js' { public voiceManager: ClientVoiceManager; public disconnect(): void; public play(input: VoiceBroadcast | Readable | string, options?: StreamOptions): StreamDispatcher; - public setSpeaking(value: BitFieldResolvable): void; + public setSpeaking(value: BitFieldResolvable): void; public on(event: 'authenticated' | 'closing' | 'newSession' | 'ready' | 'reconnecting', listener: () => void): this; public on(event: 'debug', listener: (message: string) => void): this; @@ -1769,9 +1765,8 @@ declare module 'discord.js' { } export class WebhookClient extends WebhookMixin(BaseClient) { - constructor(id: string, token: string, options?: WebhookClientOptions); + constructor(id: string, token: string, options?: ClientOptions); public client: this; - public options: WebhookClientOptions; public token: string; } @@ -2180,7 +2175,6 @@ declare module 'discord.js' { UNKNOWN_GUILD_TEMPLATE: 10057; BOT_PROHIBITED_ENDPOINT: 20001; BOT_ONLY_ENDPOINT: 20002; - ANNOUNCEMENT_EDIT_LIMIT_EXCEEDED: 20022; CHANNEL_HIT_WRITE_RATELIMIT: 20028; MAXIMUM_GUILDS: 30001; MAXIMUM_FRIENDS: 30002; @@ -2347,17 +2341,17 @@ declare module 'discord.js' { type Base64String = string; - type BitFieldResolvable = - | RecursiveReadonlyArray>> + type BitFieldResolvable = + | RecursiveReadonlyArray>> | T - | N - | Readonly>; + | number + | Readonly>; type BufferResolvable = Buffer | string; interface ChannelCreationOverwrites { - allow?: PermissionResolvable; - deny?: PermissionResolvable; + allow?: PermissionResolvable | number; + deny?: PermissionResolvable | number; id: RoleResolvable | UserResolvable; } @@ -2390,8 +2384,8 @@ declare module 'discord.js' { type ChannelResolvable = Channel | Snowflake; interface ClientEvents { - channelCreate: [channel: GuildChannel]; - channelDelete: [channel: DMChannel | GuildChannel]; + channelCreate: [channel: Channel]; + channelDelete: [channel: Channel | PartialDMChannel]; channelPinsUpdate: [channel: Channel | PartialDMChannel, date: Date]; channelUpdate: [oldChannel: Channel, newChannel: Channel]; debug: [message: string]; @@ -2460,7 +2454,6 @@ declare module 'discord.js' { restSweepInterval?: number; retryLimit?: number; presence?: PresenceData; - intents: BitFieldResolvable; ws?: WebSocketOptions; http?: HTTPOptions; } @@ -2473,11 +2466,6 @@ declare module 'discord.js' { desktop?: ClientPresenceStatus; } - interface ClientUserEditData { - username?: string; - avatar?: BufferResolvable | Base64Resolvable; - } - interface CloseEvent { wasClean: boolean; code: number; @@ -2867,7 +2855,6 @@ declare module 'discord.js' { permissions?: PermissionResolvable; guild?: GuildResolvable; disableGuildSelect?: boolean; - additionalScopes?: InviteScope[]; } interface InviteOptions { @@ -2880,19 +2867,6 @@ declare module 'discord.js' { type InviteResolvable = string; - type InviteScope = - | 'applications.builds.read' - | 'applications.commands' - | 'applications.entitlements' - | 'applications.store.update' - | 'connections' - | 'email' - | 'identity' - | 'guilds' - | 'guilds.join' - | 'gdm.join' - | 'webhook.incoming'; - type GuildTemplateResolvable = string; type MembershipStates = 'INVITED' | 'ACCEPTED'; @@ -2913,7 +2887,7 @@ declare module 'discord.js' { content?: StringResolvable; embed?: MessageEmbed | MessageEmbedOptions | null; code?: string | boolean; - flags?: BitFieldResolvable; + flags?: BitFieldResolvable; allowedMentions?: MessageMentionOptions; } @@ -3041,13 +3015,13 @@ declare module 'discord.js' { type OverwriteType = 'member' | 'role'; - interface PermissionFlags extends Record {} + interface PermissionFlags extends Record {} interface PermissionObject extends Record {} interface PermissionOverwriteOption extends Partial> {} - type PermissionResolvable = BitFieldResolvable; + type PermissionResolvable = BitFieldResolvable; type PermissionString = | 'CREATE_INSTANT_INVITE' @@ -3235,9 +3209,9 @@ declare module 'discord.js' { interface RawOverwriteData { id: Snowflake; - allow: string; - deny: string; - type: number; + allow: number; + deny: number; + type: OverwriteType; } interface ReactionCollectorOptions extends CollectorOptions { @@ -3304,7 +3278,7 @@ declare module 'discord.js' { type SystemChannelFlagsString = 'WELCOME_MESSAGE_DISABLED' | 'BOOST_MESSAGE_DISABLED'; - type SystemChannelFlagsResolvable = BitFieldResolvable; + type SystemChannelFlagsResolvable = BitFieldResolvable; type SystemMessageType = Exclude; @@ -3339,11 +3313,6 @@ declare module 'discord.js' { type VoiceStatus = number; - type WebhookClientOptions = Pick< - ClientOptions, - 'allowedMentions' | 'restTimeOffset' | 'restRequestTimeout' | 'retryLimit' | 'http' - >; - interface WebhookEditData { name?: string; avatar?: BufferResolvable; @@ -3378,6 +3347,7 @@ declare module 'discord.js' { interface WebSocketOptions { large_threshold?: number; compress?: boolean; + intents?: BitFieldResolvable | number; properties?: WebSocketProperties; } diff --git a/typings/index.ts b/typings/index.ts index 75dbc9bebfca..db7abe7c63a9 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -1,10 +1,8 @@ /// -import { Client, Intents, Message, MessageAttachment, MessageEmbed } from 'discord.js'; +import { Client, Message, MessageAttachment, MessageEmbed } from 'discord.js'; -const client: Client = new Client({ - intents: Intents.NON_PRIVILEGED, -}); +const client: Client = new Client(); client.on('ready', () => { console.log(`Client is logged in as ${client.user!.tag} and ready!`); From e29963ff1ad79cce14eb6267254ff2bd04931079 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Wed, 17 Mar 2021 10:59:55 +0100 Subject: [PATCH 35/39] fix(typings): remove FetchIntegrationsOptions Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> --- typings/index.d.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 1108e243f215..1b0cb2f8fa8f 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -2611,10 +2611,6 @@ declare module 'discord.js' { cache: boolean; } - interface FetchIntegrationsOptions { - includeApplications?: boolean; - } - interface FetchMemberOptions { user: UserResolvable; cache?: boolean; From 1994727c39c00db4058108dfd822b428f23ee173 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Fri, 26 Mar 2021 12:06:14 +0100 Subject: [PATCH 36/39] docs(GuildBanManager): minor change Co-authored-by: Shubham Parihar --- src/managers/GuildBanManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index bbc8f377f83f..4243e62424f1 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -6,7 +6,7 @@ const GuildMember = require('../structures/GuildMember'); const Collection = require('../util/Collection'); /** - * Manages API methods for Guilds bans and stores their cache. + * Manages API methods for GuildBans and stores their cache. * @extends {BaseManager} */ class GuildBanManager extends BaseManager { From 6ac5ae98e45ec0a400ab4d5c20834410921d95bd Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 27 Mar 2021 22:01:50 +0100 Subject: [PATCH 37/39] types(Guild): remove fetchBan(s) methods --- typings/index.d.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 1b0cb2f8fa8f..9bc2b7a91420 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -649,8 +649,6 @@ declare module 'discord.js' { public equals(guild: Guild): boolean; public fetch(): Promise; public fetchAuditLogs(options?: GuildAuditLogsFetchOptions): Promise; - public fetchBan(user: UserResolvable): Promise<{ user: User; reason: string }>; - public fetchBans(): Promise>; public fetchIntegrations(): Promise>; public fetchInvites(): Promise>; public fetchPreview(): Promise; From 2122e6dea50c3899475d9a959c57d29cb81a8351 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sat, 27 Mar 2021 22:09:19 +0100 Subject: [PATCH 38/39] typings(GuildBan): extend Base class --- typings/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 9bc2b7a91420..4377bf5f86da 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -734,7 +734,7 @@ declare module 'discord.js' { public toJSON(): object; } - export class GuildBan { + export class GuildBan extends Base { constructor(client: Client, data: object, guild: Guild); public guild: Guild; public user: User; From 21b8d7c33dec763ae830d7f72b24253e1710d340 Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Sun, 28 Mar 2021 17:05:30 +0200 Subject: [PATCH 39/39] docs(GuildBanManager): add inclusive to days Co-authored-by: Shubham Parihar --- src/managers/GuildBanManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 4243e62424f1..cb2dd6d03712 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -123,7 +123,7 @@ class GuildBanManager extends BaseManager { * Bans a user from the guild. * @param {UserResolvable} user The user to ban * @param {Object} [options] Options for the ban - * @param {number} [options.days=0] Number of days of messages to delete, must be between 0 and 7 + * @param {number} [options.days=0] Number of days of messages to delete, must be between 0 and 7, inclusive * @param {string} [options.reason] Reason for banning * @returns {Promise} Result object will be resolved as specifically as possible. * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot