diff --git a/src/managers/GuildEmojiManager.js b/src/managers/GuildEmojiManager.js index 74661f280..919579139 100644 --- a/src/managers/GuildEmojiManager.js +++ b/src/managers/GuildEmojiManager.js @@ -156,7 +156,7 @@ class GuildEmojiManager extends BaseGuildEmojiManager { throw new Error('EMOJI_MANAGED'); } - const { me } = this.guild; + const { me } = this.guild.members; if (!me) throw new Error('GUILD_UNCACHED_ME'); if (!me.permissions.has(Permissions.FLAGS.MANAGE_EMOJIS_AND_STICKERS)) { throw new Error('MISSING_MANAGE_EMOJIS_AND_STICKERS_PERMISSION', this.guild); diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index 4a20d38f3..110bd8591 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -9,6 +9,7 @@ const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel'); const { GuildMember } = require('../structures/GuildMember'); const { Role } = require('../structures/Role'); const { Events, Opcodes } = require('../util/Constants'); +const { PartialTypes } = require('../util/Constants'); const SnowflakeUtil = require('../util/SnowflakeUtil'); /** @@ -118,6 +119,20 @@ class GuildMemberManager extends CachedManager { return data instanceof Buffer ? (options.fetchWhenExisting === false ? null : this.fetch(userId)) : this._add(data); } + /** + * The client user as a GuildMember of this guild + * @type {?GuildMember} + * @readonly + */ + get me() { + return ( + this.resolve(this.client.user.id) ?? + (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) + ? this._add({ user: { id: this.client.user.id } }, true) + : null) + ); + } + /** * Options used to fetch a single member from a guild. * @typedef {BaseFetchOptions} FetchMemberOptions @@ -189,6 +204,15 @@ class GuildMemberManager extends CachedManager { return this._fetchMany(options); } + /** + * Fetches the client user as a GuildMember of the guild. + * @param {BaseFetchOptions} [options] The options for fetching the member + * @returns {Promise} + */ + fetchMe(options) { + return this.fetch({ ...options, user: this.client.user.id }); + } + /** * Options used for searching guild members. * @typedef {Object} GuildSearchMembersOptions diff --git a/src/managers/ThreadMemberManager.js b/src/managers/ThreadMemberManager.js index ce6988e5c..db9e0c5c2 100644 --- a/src/managers/ThreadMemberManager.js +++ b/src/managers/ThreadMemberManager.js @@ -36,6 +36,24 @@ class ThreadMemberManager extends CachedManager { return member; } + /** + * Fetches the client user as a ThreadMember of the thread. + * @param {BaseFetchOptions} [options] The options for fetching the member + * @returns {Promise} + */ + fetchMe(options) { + return this.fetch(this.client.user.id, options); + } + + /** + * The client user as a ThreadMember of this ThreadChannel + * @type {?ThreadMember} + * @readonly + */ + get me() { + return this.resolve(this.client.user.id); + } + /** * Data that resolves to give a ThreadMember object. This can be: * * A ThreadMember object diff --git a/src/structures/BaseGuildVoiceChannel.js b/src/structures/BaseGuildVoiceChannel.js index 8fe65a167..7caa79d9b 100644 --- a/src/structures/BaseGuildVoiceChannel.js +++ b/src/structures/BaseGuildVoiceChannel.js @@ -75,7 +75,7 @@ class BaseGuildVoiceChannel extends GuildChannel { if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true; return ( - this.guild.me.communicationDisabledUntilTimestamp < Date.now() && + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() && permissions.has(Permissions.FLAGS.CONNECT, false) ); } diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 091150a20..963b81034 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -25,7 +25,6 @@ const VoiceStateManager = require('../managers/VoiceStateManager'); const { ChannelTypes, DefaultMessageNotificationLevels, - PartialTypes, VerificationLevels, ExplicitContentFilterLevels, Status, @@ -39,6 +38,7 @@ const Util = require('../util/Util'); let deprecationEmittedForSetChannelPositions = false; let deprecationEmittedForSetRolePositions = false; let deprecationEmittedForDeleted = false; +let deprecationEmittedForMe = false; /** * @type {WeakSet} @@ -590,15 +590,16 @@ class Guild extends AnonymousGuild { /** * The client user as a GuildMember of this guild * @type {?GuildMember} + * @deprecated Use {@link GuildMemberManager#me} instead. * @readonly */ get me() { - return ( - this.members.resolve(this.client.user.id) ?? - (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) - ? this.members._add({ user: { id: this.client.user.id } }, true) - : null) - ); + if (!deprecationEmittedForMe) { + process.emitWarning('Guild#me is deprecated. Use Guild#members#me instead.', 'DeprecationWarning'); + deprecationEmittedForMe = true; + } + + return this.members.me; } /** diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 2a796094e..481d3cfaf 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -415,7 +415,7 @@ class GuildChannel extends Channel { // This flag allows managing even if timed out if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true; - if (this.guild.me.communicationDisabledUntilTimestamp > Date.now()) return false; + if (this.guild.members.me.communicationDisabledUntilTimestamp > Date.now()) return false; const bitfield = VoiceBasedChannelTypes.includes(this.type) ? Permissions.FLAGS.MANAGE_CHANNELS | Permissions.FLAGS.CONNECT diff --git a/src/structures/GuildEmoji.js b/src/structures/GuildEmoji.js index abe263330..456b89321 100644 --- a/src/structures/GuildEmoji.js +++ b/src/structures/GuildEmoji.js @@ -55,8 +55,8 @@ class GuildEmoji extends BaseGuildEmoji { * @readonly */ get deletable() { - if (!this.guild.me) throw new Error('GUILD_UNCACHED_ME'); - return !this.managed && this.guild.me.permissions.has(Permissions.FLAGS.MANAGE_EMOJIS_AND_STICKERS); + if (!this.guild.members.me) throw new Error('GUILD_UNCACHED_ME'); + return !this.managed && this.guild.members.me.permissions.has(Permissions.FLAGS.MANAGE_EMOJIS_AND_STICKERS); } /** diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 0a2c82c27..b568f44b4 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -272,8 +272,8 @@ class GuildMember extends Base { if (this.user.id === this.guild.ownerId) return false; if (this.user.id === this.client.user.id) return false; if (this.client.user.id === this.guild.ownerId) return true; - if (!this.guild.me) throw new Error('GUILD_UNCACHED_ME'); - return this.guild.me.roles.highest.comparePositionTo(this.roles.highest) > 0; + if (!this.guild.members.me) throw new Error('GUILD_UNCACHED_ME'); + return this.guild.members.me.roles.highest.comparePositionTo(this.roles.highest) > 0; } /** @@ -282,7 +282,7 @@ class GuildMember extends Base { * @readonly */ get kickable() { - return this.manageable && this.guild.me.permissions.has(Permissions.FLAGS.KICK_MEMBERS); + return this.manageable && this.guild.members.me.permissions.has(Permissions.FLAGS.KICK_MEMBERS); } /** @@ -291,7 +291,7 @@ class GuildMember extends Base { * @readonly */ get bannable() { - return this.manageable && this.guild.me.permissions.has(Permissions.FLAGS.BAN_MEMBERS); + return this.manageable && this.guild.members.me.permissions.has(Permissions.FLAGS.BAN_MEMBERS); } /** @@ -303,7 +303,7 @@ class GuildMember extends Base { return ( !this.permissions.has(Permissions.FLAGS.ADMINISTRATOR) && this.manageable && - (this.guild.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false) + (this.guild.members.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false) ); } diff --git a/src/structures/Invite.js b/src/structures/Invite.js index ee84b8b58..6e5b9c5fe 100644 --- a/src/structures/Invite.js +++ b/src/structures/Invite.js @@ -241,10 +241,10 @@ class Invite extends Base { get deletable() { const guild = this.guild; if (!guild || !this.client.guilds.cache.has(guild.id)) return false; - if (!guild.me) throw new Error('GUILD_UNCACHED_ME'); + if (!guild.members.me) throw new Error('GUILD_UNCACHED_ME'); return ( this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS, false) || - guild.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD) + guild.members.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD) ); } diff --git a/src/structures/Message.js b/src/structures/Message.js index 2fb213bd2..45501935f 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -632,7 +632,7 @@ class Message extends Base { return Boolean( this.author.id === this.client.user.id || (permissions.has(Permissions.FLAGS.MANAGE_MESSAGES, false) && - this.guild.me.communicationDisabledUntilTimestamp < Date.now()), + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()), ); } diff --git a/src/structures/ThreadChannel.js b/src/structures/ThreadChannel.js index 8bb5b8f29..7e41cece5 100644 --- a/src/structures/ThreadChannel.js +++ b/src/structures/ThreadChannel.js @@ -521,7 +521,7 @@ class ThreadChannel extends Channel { if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true; return ( - this.guild.me.communicationDisabledUntilTimestamp < Date.now() && + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() && permissions.has(Permissions.FLAGS.MANAGE_THREADS, false) ); } @@ -553,7 +553,7 @@ class ThreadChannel extends Channel { !(this.archived && this.locked && !this.manageable) && (this.type !== 'GUILD_PRIVATE_THREAD' || this.joined || this.manageable) && permissions.has(Permissions.FLAGS.SEND_MESSAGES_IN_THREADS, false) && - this.guild.me.communicationDisabledUntilTimestamp < Date.now() + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() ); } diff --git a/src/structures/VoiceChannel.js b/src/structures/VoiceChannel.js index c09fc81de..bdb1f56bf 100644 --- a/src/structures/VoiceChannel.js +++ b/src/structures/VoiceChannel.js @@ -113,7 +113,8 @@ class VoiceChannel extends BaseGuildVoiceChannel { if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true; return ( - this.guild.me.communicationDisabledUntilTimestamp < Date.now() && permissions.has(Permissions.FLAGS.SPEAK, false) + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() && + permissions.has(Permissions.FLAGS.SPEAK, false) ); } diff --git a/src/structures/VoiceState.js b/src/structures/VoiceState.js index da1c2d07a..18ab16f90 100644 --- a/src/structures/VoiceState.js +++ b/src/structures/VoiceState.js @@ -208,10 +208,10 @@ class VoiceState extends Base { * @param {boolean} [request=true] Whether or not the client is requesting to become a speaker. * @example * // Making the client request to speak in a stage channel (raise its hand) - * guild.me.voice.setRequestToSpeak(true); + * guild.members.me.voice.setRequestToSpeak(true); * @example * // Making the client cancel a request to speak - * guild.me.voice.setRequestToSpeak(false); + * guild.members.me.voice.setRequestToSpeak(false); * @returns {Promise} */ async setRequestToSpeak(request = true) { @@ -232,10 +232,10 @@ class VoiceState extends Base { * @param {boolean} [suppressed=true] Whether or not the user should be suppressed. * @example * // Making the client a speaker - * guild.me.voice.setSuppressed(false); + * guild.members.me.voice.setSuppressed(false); * @example * // Making the client an audience member - * guild.me.voice.setSuppressed(true); + * guild.members.me.voice.setSuppressed(true); * @example * // Inviting another user to speak * voiceState.setSuppressed(false); diff --git a/typings/index.d.ts b/typings/index.d.ts index aa15af7b9..bb66ed70c 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -705,9 +705,7 @@ export interface CollectorEventTypes { end: [collected: Collection, reason: string]; } -export type ChannelFlagsString = - | 'PINNED' - | 'REQUIRE_TAG'; +export type ChannelFlagsString = 'PINNED' | 'REQUIRE_TAG'; export class ChannelFlags extends BitField { public static FLAGS: Record; public static resolve(bit?: BitFieldResolvable): number; @@ -966,6 +964,7 @@ export class Guild extends AnonymousGuild { public large: boolean; public maximumMembers: number | null; public maximumPresences: number | null; + /** @deprecated Use {@link GuildMemberManager.me} instead. */ public readonly me: GuildMember | null; public memberCount: number; public members: GuildMemberManager; @@ -3371,6 +3370,7 @@ export class GuildManager extends CachedManager { private constructor(guild: Guild, iterable?: Iterable); public guild: Guild; + public get me(): GuildMember | null; public add( user: UserResolvable, options: AddGuildMemberOptions & { fetchWhenExisting: false }, @@ -3382,6 +3382,7 @@ export class GuildMemberManager extends CachedManager; public fetch(options?: FetchMembersOptions): Promise>; + public fetchMe(options?: BaseFetchOptions): Promise; public kick(user: UserResolvable, reason?: string): Promise; public list(options?: GuildListMembersOptions): Promise>; public prune(options: GuildPruneMembersOptions & { dry?: false; count: false }): Promise; @@ -3579,10 +3580,12 @@ export class GuildForumThreadManager extends ThreadManager { export class ThreadMemberManager extends CachedManager { private constructor(thread: ThreadChannel, iterable?: Iterable); public thread: ThreadChannel; + public get me(): ThreadMember | null; public add(member: UserResolvable | '@me', reason?: string): Promise; public fetch(member?: UserResolvable, options?: BaseFetchOptions): Promise; /** @deprecated Use `fetch(member, options)` instead. */ public fetch(cache?: boolean): Promise>; + public fetchMe(options?: BaseFetchOptions): Promise; public remove(id: Snowflake | '@me', reason?: string): Promise; } @@ -5476,8 +5479,7 @@ export type MessageComponentType = keyof typeof MessageComponentTypes; export type MessageComponentTypeResolvable = MessageComponentType | MessageComponentTypes; -export type GuildForumThreadMessageCreateOptions = MessageOptions & - Pick; +export type GuildForumThreadMessageCreateOptions = MessageOptions & Pick; export interface MessageEditOptions { attachments?: MessageAttachment[];