From 69d6fbeb15b041bfa3b3e6036a67604c83e89c6f Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 19:48:06 -0400 Subject: [PATCH 01/35] Alphabetize oldPresence, oldState, oldMessage, oldRole, and emoji also added oldMessage.pinned to typings. idk if it is supposed to be null or undefined though. --- index.d.ts | 1 + lib/gateway/Shard.js | 60 +++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/index.d.ts b/index.d.ts index c7d9b0f0c..273cba885 100644 --- a/index.d.ts +++ b/index.d.ts @@ -356,6 +356,7 @@ declare namespace Eris { embeds: Embed[]; mentionedBy?: any; mentions: string[]; + pinned: boolean; roleMentions: string[]; tts: boolean; } diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index f5b7999ff..f42b02775 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -286,16 +286,16 @@ class Shard extends EventEmitter { * @event Client#presenceUpdate * @prop {Member | Relationship} other The updated member or relationship * @prop {Object?} oldPresence The old presence data. If the user was offline when the bot started and the client option getAllUsers is not true, this will be null - * @prop {String} oldPresence.status The other user's old status. Either "online", "idle", or "offline" - * @prop {Object?} oldPresence.game The old game the other user was playing - * @prop {String} oldPresence.game.name The name of the active game - * @prop {Number} oldPresence.game.type The type of the active game (0 is default, 1 is Twitch, 2 is YouTube) - * @prop {String} oldPresence.game.url The url of the active game + * @prop {Object[]?} oldPresence.activities The member's current activities * @prop {Object?} oldPresence.clientStatus The member's per-client status * @prop {String} oldPresence.clientStatus.web The member's status on web. Either "online", "idle", "dnd", or "offline". Will be "online" for bots * @prop {String} oldPresence.clientStatus.desktop The member's status on desktop. Either "online", "idle", "dnd", or "offline". Will be "offline" for bots * @prop {String} oldPresence.clientStatus.mobile The member's status on mobile. Either "online", "idle", "dnd", or "offline". Will be "offline" for bots - * @prop {Object[]?} oldPresence.activities The member's current activities + * @prop {Object?} oldPresence.game The old game the other user was playing + * @prop {String} oldPresence.game.name The name of the active game + * @prop {Number} oldPresence.game.type The type of the active game (0 is default, 1 is Twitch, 2 is YouTube) + * @prop {String} oldPresence.game.url The url of the active game + * @prop {String} oldPresence.status The other user's old status. Either "online", "idle", or "offline" */ this.emit("presenceUpdate", this.client.relationships.update(packet.d), oldPresence); break; @@ -309,10 +309,10 @@ class Shard extends EventEmitter { let oldPresence = null; if(member) { oldPresence = { - game: member.game, - status: member.status, + activities: member.activities, clientStatus: member.clientStatus, - activities: member.activities + game: member.game, + status: member.status }; } if((!member && packet.d.user.username) || oldPresence) { @@ -377,10 +377,10 @@ class Shard extends EventEmitter { } } const oldState = { - mute: member.voiceState.mute, deaf: member.voiceState.deaf, - selfMute: member.voiceState.selfMute, + mute: member.voiceState.mute, selfDeaf: member.voiceState.selfDeaf, + selfMute: member.voiceState.selfMute, selfStream: member.voiceState.selfStream }; const oldChannelID = member.voiceState.channelID; @@ -433,10 +433,10 @@ class Shard extends EventEmitter { * @event Client#voiceStateUpdate * @prop {Member} member The member * @prop {Object} oldState The old voice state - * @prop {Boolean} oldState.mute The previous server mute status * @prop {Boolean} oldState.deaf The previous server deaf status - * @prop {Boolean} oldState.selfMute The previous self mute status + * @prop {Boolean} oldState.mute The previous server mute status * @prop {Boolean} oldState.selfDeaf The previous self deaf status + * @prop {Boolean} oldState.selfMute The previous self mute status * @prop {Boolean} oldState.selfStream The previous self stream status */ this.emit("voiceStateUpdate", member, oldState); @@ -480,15 +480,15 @@ class Shard extends EventEmitter { if(message) { oldMessage = { attachments: message.attachments, + channelMentions: message.channelMentions, content: message.content, - embeds: message.embeds, editedTimestamp: message.editedTimestamp, + embeds: message.embeds, mentionedBy: message.mentionedBy, mentions: message.mentions, + pinned: message.pinned, roleMentions: message.roleMentions, - channelMentions: message.channelMentions, - tts: message.tts, - pinned: message.pinned + tts: message.tts }; } else if(!packet.d.timestamp) { packet.d.channel = channel; @@ -501,15 +501,15 @@ class Shard extends EventEmitter { * @prop {Message} message The updated message. If oldMessage is null, it is recommended to discard this event, since the message data will be very incomplete (only `id` and `channel` are guaranteed) * @prop {Object?} oldMessage The old message data. If the message was cached, this will return the full old message. Otherwise, it will be null * @prop {Object[]} oldMessage.attachments Array of attachments - * @prop {Object[]} oldMessage.embeds Array of embeds + * @prop {String[]} oldMessage.channelMentions Array of mentions channels' ids. * @prop {String} oldMessage.content Message content * @prop {Number} oldMessage.editedTimestamp Timestamp of latest message edit + * @prop {Object[]} oldMessage.embeds Array of embeds * @prop {Object} oldMessage.mentionedBy Object of if different things mention the bot user - * @prop {Boolean} oldMessage.pinned Whether the message was pinned or not - * @prop {Boolean} oldMessage.tts Whether to play the message using TTS or not * @prop {String[]} oldMessage.mentions Array of mentioned users' ids + * @prop {Boolean} oldMessage.pinned Whether the message was pinned or not * @prop {String[]} oldMessage.roleMentions Array of mentioned roles' ids. - * @prop {String[]} oldMessage.channelMentions Array of mentions channels' ids. + * @prop {Boolean} oldMessage.tts Whether to play the message using TTS or not */ this.emit("messageUpdate", channel.messages.update(packet.d, this.client), oldMessage); break; @@ -659,7 +659,9 @@ class Shard extends EventEmitter { * Fired when someone removes all reactions from a message for a single emoji * @event Client#messageReactionRemoveEmoji * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id` and `channel` keys. If the channel is not cached, channel key will be an object with only an id. No other property is guaranteed - * @prop {Object} emoji The emoji object with a `name` prop. If the emoji is a custom emoji it will also have an `id` prop. + * @prop {Object} emoji The reaction emoji object + * @prop {String?} emoji.id The ID of the emoji (null for non-custom emojis) + * @prop {String} emoji.name The emoji name */ this.emit("messageReactionRemoveEmoji", message || { id: packet.d.message_id, @@ -927,10 +929,10 @@ class Shard extends EventEmitter { color: role.color, hoist: role.hoist, managed: role.managed, + mentionable: role.mentionable, name: role.name, permissions: role.permissions, - position: role.position, - mentionable: role.mentionable + position: role.position }; /** * Fired when a guild role is updated @@ -938,13 +940,13 @@ class Shard extends EventEmitter { * @prop {Guild} guild The guild * @prop {Role} role The updated role * @prop {Object} oldRole The old role data - * @prop {String} oldRole.name The name of the role - * @prop {Boolean} oldRole.mentionable Whether the role is mentionable or not - * @prop {Boolean} oldRole.managed Whether a guild integration manages this role or not - * @prop {Boolean} oldRole.hoist Whether users with this role are hoisted in the user list or not * @prop {Number} oldRole.color The hex color of the role in base 10 - * @prop {Number} oldRole.position The position of the role + * @prop {Boolean} oldRole.hoist Whether users with this role are hoisted in the user list or not + * @prop {Boolean} oldRole.managed Whether a guild integration manages this role or not + * @prop {Boolean} oldRole.mentionable Whether the role is mentionable or not + * @prop {String} oldRole.name The name of the role * @prop {Permission} oldRole.permissions The permissions number of the role + * @prop {Number} oldRole.position The position of the role */ this.emit("guildRoleUpdate", guild, guild.roles.update(packet.d.role, guild), oldRole); break; From 7326cafae08835d28abe8eef7feaea098267f697 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 19:55:28 -0400 Subject: [PATCH 02/35] Alphabetize oldCall and and relationship in friendSuggestionCreate --- lib/gateway/Shard.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index f42b02775..d9049179b 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -1206,10 +1206,10 @@ class Shard extends EventEmitter { throw new Error("CALL_UPDATE but channel has no call"); } const oldCall = { + endedTimestamp: channel.call.endedTimestamp, participants: channel.call.participants, - ringing: channel.call.ringing, region: channel.call.region, - endedTimestamp: channel.call.endedTimestamp, + ringing: channel.call.ringing, unavailable: channel.call.unavailable }; /** @@ -1217,10 +1217,10 @@ class Shard extends EventEmitter { * @event Client#callUpdate * @prop {Call} call The updated call * @prop {Object} oldCall The old call data - * @prop {String[]} oldCall.participants The IDs of the call participants * @prop {Number?} oldCall.endedTimestamp The timestamp of the call end - * @prop {String[]?} oldCall.ringing The IDs of people that were being rung + * @prop {String[]} oldCall.participants The IDs of the call participants * @prop {String?} oldCall.region The region of the call server + * @prop {String[]?} oldCall.ringing The IDs of people that were being rung * @prop {Boolean} oldCall.unavailable Whether the call was unavailable or not */ this.emit("callUpdate", channel.call.update(packet.d), oldCall); @@ -1269,9 +1269,9 @@ class Shard extends EventEmitter { * @event Client#friendSuggestionCreate * @prop {User} user The suggested user * @prop {String[]} reasons Array of reasons why this suggestion was made - * @prop {Number} reasons.type Type of reason? - * @prop {String} reasons.platform_type Platform you share with the user * @prop {String} reasons.name Username of suggested user on that platform + * @prop {String} reasons.platform_type Platform you share with the user + * @prop {Number} reasons.type Type of reason? */ this.emit("friendSuggestionCreate", new User(packet.d.suggested_user, this.client), packet.d.reasons); break; From 559f472309b92ac1d806cedfbc22cea142af2bcf Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 20:19:22 -0400 Subject: [PATCH 03/35] Alphabetize props for Call, CategoryChannel, and Channel --- lib/structures/Call.js | 4 ++-- lib/structures/CategoryChannel.js | 12 +++++++----- lib/structures/Channel.js | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/structures/Call.js b/lib/structures/Call.js index 7700d4d77..47ecdfa28 100644 --- a/lib/structures/Call.js +++ b/lib/structures/Call.js @@ -6,10 +6,10 @@ const VoiceState = require("./VoiceState"); /** * Represents a call -* @prop {String} id The ID of the call -* @prop {Number} createdAt Timestamp of the call's creation * @prop {GroupChannel} channel The call channel +* @prop {Number} createdAt Timestamp of the call's creation * @prop {Number?} endedTimestamp The timestamp of the call end +* @prop {String} id The ID of the call * @prop {String[]} participants The IDs of the call participants * @prop {String?} region The region of the call server * @prop {String[]?} ringing The IDs of people that still have not responded to the call request diff --git a/lib/structures/CategoryChannel.js b/lib/structures/CategoryChannel.js index 7f819333b..4d99d0223 100644 --- a/lib/structures/CategoryChannel.js +++ b/lib/structures/CategoryChannel.js @@ -6,16 +6,18 @@ const GuildChannel = require("./GuildChannel"); /** * Represents a guild category channel * @extends GuildChannel +* @prop {Collection} channels A collection of guild channels that are part of this category +* @prop {Client} client The client that initialized the channel +* @prop {Number} createdAt Timestamp of the channel's creation +* @prop {Guild} guild The guild that owns the channel * @prop {String} id The ID of the channel * @prop {String} mention A string that mentions the channel -* @prop {Number} type The type of the channel -* @prop {Guild} guild The guild that owns the channel -* @prop {String?} parentID The ID of the category this channel belongs to * @prop {String} name The name of the channel -* @prop {Number} position The position of the channel * @prop {Boolean} nsfw Whether the channel is an NSFW channel or not +* @prop {String?} parentID The ID of the category this channel belongs to * @prop {Collection} permissionOverwrites Collection of PermissionOverwrites in this channel -* @prop {Collection} channels A collection of guild channels that are part of this category +* @prop {Number} position The position of the channel +* @prop {Number} type The type of the channel */ class CategoryChannel extends GuildChannel { get channels() { diff --git a/lib/structures/Channel.js b/lib/structures/Channel.js index 61eba5925..d0a9e69c4 100644 --- a/lib/structures/Channel.js +++ b/lib/structures/Channel.js @@ -5,9 +5,9 @@ const {ChannelTypes} = require("../Constants"); /** * Represents a channel. You also probably want to look at CategoryChannel, GroupChannel, NewsChannel, PrivateChannel, TextChannel, and VoiceChannel. -* @prop {String} id The ID of the channel * @prop {Client} client The client that initialized the channel * @prop {Number} createdAt Timestamp of the channel's creation +* @prop {String} id The ID of the channel * @prop {String} mention A string that mentions the channel * @prop {Number} type The type of the channel */ From bdd78fb57a35bc3cb70b8733431f24f4889d6422 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 20:38:18 -0400 Subject: [PATCH 04/35] Alphabetize Guild --- lib/structures/Guild.js | 628 ++++++++++++++++++++-------------------- 1 file changed, 314 insertions(+), 314 deletions(-) diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index bcb0a6aab..f9fac5e9d 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -11,49 +11,49 @@ const VoiceState = require("./VoiceState"); /** * Represents a guild -* @prop {String} id The ID of the guild -* @prop {Number} createdAt Timestamp of the guild's creation -* @prop {String} name The name of the guild -* @prop {Number} verificationLevel The guild verification level -* @prop {String} region The region of the guild -* @prop {String?} icon The hash of the guild icon, or null if no icon * @prop {String?} afkChannelID The ID of the AFK voice channel * @prop {Number} afkTimeout The AFK timeout in seconds +* @prop {Number?} approximateMemberCount The approximate number of members in the guild (REST only) +* @prop {Number?} approximatePresenceCount The approximate number of presences in the guild (REST only) +* @prop {String?} banner The hash of the guild banner image, or null if no banner (VIP only) +* @prop {String?} bannerURL The URL of the guild's banner image +* @prop {Collection} channels Collection of Channels in the guild +* @prop {Number} createdAt Timestamp of the guild's creation * @prop {Number} defaultNotifications The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions" -* @prop {Number} mfaLevel The admin 2FA level for the guild. 0 is not required, 1 is required +* @prop {String?} description The description for the guild (VIP only) +* @prop {Object[]} emojis An array of guild emoji objects +* @prop {Number} explicitContentFilter The explicit content filter level for the guild. 0 is off, 1 is on for people without roles, 2 is on for all +* @prop {String[]} features An array of guild feature strings +* @prop {String?} icon The hash of the guild icon, or null if no icon +* @prop {String?} iconURL The URL of the guild's icon +* @prop {String} id The ID of the guild * @prop {Number} joinedAt Timestamp of when the bot account joined the guild -* @prop {String} ownerID The ID of the user that is the guild owner -* @prop {String?} systemChannelID The ID of the default channel for system messages (built-in join messages and boost messages) -* @prop {String?} splash The hash of the guild splash image, or null if no splash (VIP only) -* @prop {String?} banner The hash of the guild banner image, or null if no banner (VIP only) -* @prop {Boolean} unavailable Whether the guild is unavailable or not * @prop {Boolean} large Whether the guild is "large" by "some Discord standard" +* @prop {Number} mfaLevel The admin 2FA level for the guild. 0 is not required, 1 is required +* @prop {Number} maxMembers The maximum amount of members for the guild * @prop {Number} maxPresences The maximum number of people that can be online in a guild at once (returned from REST API only) -* @prop {Collection} voiceStates Collection of voice states in the guild -* @prop {Collection} channels Collection of Channels in the guild -* @prop {Collection} members Collection of Members in the guild +* @prop {Number?} maxVideoChannelUsers The max number of users allowed in a video channel * @prop {Number} memberCount Number of members in the guild +* @prop {Collection} members Collection of Members in the guild +* @prop {String} name The name of the guild +* @prop {String} ownerID The ID of the user that is the guild owner +* @prop {String} preferredLocale Preferred "PUBLIC" guild language used in server discovery and notices from Discord +* @prop {Number?} premiumSubscriptionCount The total number of users currently boosting this guild +* @prop {Number} premiumTier Nitro boost level of the guild +* @prop {String?} publicUpdatesChannelID ID of the guild's updates channel if the guild has "PUBLIC" features +* @prop {String} region The region of the guild * @prop {Collection} roles Collection of Roles in the guild +* @prop {String?} rulesChannelID The channel where "PUBLIC" guilds display rules and/or guidelines * @prop {Shard} shard The Shard that owns the guild -* @prop {String[]} features An array of guild feature strings -* @prop {Object[]} emojis An array of guild emoji objects -* @prop {String?} iconURL The URL of the guild's icon -* @prop {String?} bannerURL The URL of the guild's banner image +* @prop {String?} splash The hash of the guild splash image, or null if no splash (VIP only) * @prop {String?} splashURL The URL of the guild's splash image -* @prop {Number} explicitContentFilter The explicit content filter level for the guild. 0 is off, 1 is on for people without roles, 2 is on for all -* @prop {Number} premiumTier Nitro boost level of the guild -* @prop {Number?} premiumSubscriptionCount The total number of users currently boosting this guild +* @prop {String?} systemChannelID The ID of the default channel for system messages (built-in join messages and boost messages) +* @prop {Boolean} unavailable Whether the guild is unavailable or not * @prop {String?} vanityURL The vanity URL of the guild (VIP only) -* @prop {String} preferredLocale Preferred "PUBLIC" guild language used in server discovery and notices from Discord -* @prop {String?} description The description for the guild (VIP only) -* @prop {Number} maxMembers The maximum amount of members for the guild -* @prop {String?} publicUpdatesChannelID ID of the guild's updates channel if the guild has "PUBLIC" features -* @prop {String?} rulesChannelID The channel where "PUBLIC" guilds display rules and/or guidelines -* @prop {Number?} maxVideoChannelUsers The max number of users allowed in a video channel -* @prop {Boolean?} widgetEnabled Whether the guild widget is enabled. REST only. +* @prop {Number} verificationLevel The guild verification level +* @prop {Collection} voiceStates Collection of voice states in the guild * @prop {Number?} widgetChannelID The channel id that the widget will generate an invite to. REST only. -* @prop {Number?} approximateMemberCount The approximate number of members in the guild (REST only) -* @prop {Number?} approximatePresenceCount The approximate number of presences in the guild (REST only) +* @prop {Boolean?} widgetEnabled Whether the guild widget is enabled. REST only. */ class Guild extends Base { constructor(data, client) { @@ -226,67 +226,25 @@ class Guild extends Base { } /** - * Request all guild members from Discord - * @arg {Number} [timeout] The number of milliseconds to wait before resolving early. Defaults to the `requestTimeout` client option - * @returns {Promise} Resolves with the total number of fetched members. - */ - fetchAllMembers(timeout) { - return this.fetchMembers({ - timeout - }).then((m) => m.length); - } - - /** - * Request specific guild members through the gateway connection - * @arg {Object} [options] Options for fetching the members - * @arg {String} [options.query] The query used for looking up the members. When using intents, `GUILD_MEMBERS` is required to fetch all members. - * @arg {String[]} [options.userIDs] The IDs of members to fetch - * @arg {Number} [options.limit] The maximum number of members to fetch - * @arg {Number} [options.timeout] The number of milliseconds to wait before resolving early. Defaults to the `requestTimeout` client option - * @arg {Boolean} [options.presences] Whether to request member presences or not. When using intents, the `GUILD_PRESENCES` intent is required. - * @returns {Promise} Resolves with the fetched members. - */ - fetchMembers(options) { - return this.shard.requestGuildMembers(this.id, options); - } - - get iconURL() { - return this.icon ? this._client._formatImage(Endpoints.GUILD_ICON(this.id, this.icon)) : null; - } - - /** - * Get the guild's icon with the given format and size - * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") - * @arg {Number} [size] The size of the icon (any power of two between 16 and 4096) - */ - dynamicIconURL(format, size) { - return this.icon ? this._client._formatImage(Endpoints.GUILD_ICON(this.id, this.icon), format, size) : null; - } - - get splashURL() { - return this.splash ? this._client._formatImage(Endpoints.GUILD_SPLASH(this.id, this.splash)) : null; - } - - get bannerURL() { - return this.banner ? this._client._formatImage(Endpoints.GUILD_BANNER(this.id, this.banner)) : null; - } - - /** - * Get the guild's splash with the given format and size - * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") - * @param {Number} [size] The size of the icon (any power of two between 16 and 4096) + * Add a role to a guild member + * @arg {String} memberID The ID of the member + * @arg {String} roleID The ID of the role + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - dynamicSplashURL(format, size) { - return this.splash ? this._client._formatImage(Endpoints.GUILD_SPLASH(this.id, this.splash), format, size) : null; + addMemberRole(memberID, roleID, reason) { + return this._client.addGuildMemberRole.call(this._client, this.id, memberID, roleID, reason); } /** - * Get the guild's banner with the given format and size - * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") - * @param {Number} [size] The size of the icon (any power of two between 16 and 4096) + * Ban a user from the guild + * @arg {String} userID The ID of the member + * @arg {Number} [deleteMessageDays=0] Number of days to delete messages for + * @arg {String} [reason] Reason for the ban + * @returns {Promise} */ - dynamicBannerURL(format, size) { - return this.banner ? this._client._formatImage(Endpoints.GUILD_BANNER(this.id, this.banner), format, size) : null; + banMember(userID, deleteMessageDays, reason) { + return this._client.banGuildMember.call(this._client, this.id, userID, deleteMessageDays, reason); } /** @@ -294,13 +252,13 @@ class Guild extends Base { * @arg {String} name The name of the channel * @arg {Number} [type=0] The type of the channel, either 0 (text), 2 (voice), or 4 (category) * @arg {Object | String} [options] The properties the channel should have. If `options` is a string, it will be treated as `options.parentID` (see below). Passing a string is deprecated and will not be supported in future versions. - * @arg {String} [options.topic] The topic of the channel (text channels only) - * @arg {Boolean} [options.nsfw] The nsfw status of the channel * @arg {Number} [options.bitrate] The bitrate of the channel (voice channels only) + * @arg {Boolean} [options.nsfw] The nsfw status of the channel * @arg {String?} [options.parentID] The ID of the parent category channel for this channel * @arg {Array} [options.permissionOverwrites] An array containing permission overwrite objects * @arg {Number} [options.rateLimitPerUser] The time in seconds a user has to wait before sending another message (does not affect bots or users with manageMessages/manageChannel permissions) (text channels only) * @arg {String} [options.reason] The reason to be displayed in audit logs + * @arg {String} [options.topic] The topic of the channel (text channels only) * @arg {Number} [options.userLimit] The channel user limit (voice channels only) * @returns {Promise} */ @@ -311,8 +269,8 @@ class Guild extends Base { /** * Create a emoji in the guild * @arg {Object} options Emoji options - * @arg {String} options.name The name of emoji * @arg {String} options.image The base 64 encoded string + * @arg {String} options.name The name of emoji * @arg {Array} [options.roles] An array containing authorized role IDs * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} A guild emoji object @@ -321,37 +279,14 @@ class Guild extends Base { return this._client.createGuildEmoji.call(this._client, this.id, options, reason); } - /** - * Edit a emoji in the guild - * @arg {String} emojiID The ID of the emoji you want to modify - * @arg {Object} options Emoji options - * @arg {String} [options.name] The name of emoji - * @arg {Array} [options.roles] An array containing authorized role IDs - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} A guild emoji object - */ - editEmoji(emojiID, options, reason) { - return this._client.editGuildEmoji.call(this._client, this.id, emojiID, options, reason); - } - - /** - * Delete a emoji in the guild - * @arg {String} emojiID The ID of the emoji - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} - */ - deleteEmoji(emojiID, reason) { - return this._client.deleteGuildEmoji.call(this._client, this.id, emojiID, reason); - } - /** * Create a guild role * @arg {Object|Role} [options] An object or Role containing the properties to set - * @arg {String} [options.name] The name of the role - * @arg {Number} [options.permissions] The role permissions number * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3d15b3 or 4040115) * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not + * @arg {String} [options.name] The name of the role + * @arg {Number} [options.permissions] The role permissions number * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ @@ -360,129 +295,155 @@ class Guild extends Base { } /** - * Get the prune count for the guild - * @arg {Number} [options] The options to use to get number of prune members - * @arg {Number} [options.days=7] The number of days of inactivity to prune for - * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning - * @returns {Promise} Resolves with the number of members that would be pruned - */ - getPruneCount(options) { - return this._client.getPruneCount.call(this._client, this.id, options); - } - - /** - * Begin pruning the guild - * @arg {Number} [options] The options to pass to prune members - * @arg {Number} [options.days=7] The number of days of inactivity to prune for - * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning - * @arg {String} [options.reason] The reason to be displayed in audit logs - * @returns {Promise} Resolves with the number of pruned members - */ - pruneMembers(options) { - return this._client.pruneMembers.call(this._client, this.id, options); - } - - /** - * Get a guild's channels via the REST API. REST mode is required to use this endpoint. - * @returns {Promise<(CategoryChannel[] | TextChannel[] | VoiceChannel[])>} + * Delete the guild (bot user must be owner) + * @returns {Promise} */ - getRESTChannels() { - return this._client.getRESTGuildChannels.call(this._client, this.id); + delete() { + return this._client.deleteGuild.call(this._client, this.id); } /** - * Get a guild's emojis via the REST API. REST mode is required to use this endpoint. - * @returns {Promise} An array of guild emoji objects + * Delete a emoji in the guild + * @arg {String} emojiID The ID of the emoji + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getRESTEmojis() { - return this._client.getRESTGuildEmojis.call(this._client, this.id); + deleteEmoji(emojiID, reason) { + return this._client.deleteGuildEmoji.call(this._client, this.id, emojiID, reason); } /** - * Get a guild emoji via the REST API. REST mode is required to use this endpoint. - * @arg {String} emojiID The ID of the emoji - * @returns {Promise} An emoji object + * Delete a role + * @arg {String} roleID The ID of the role + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getRESTEmoji(emojiID) { - return this._client.getRESTGuildEmoji.call(this._client, this.id, emojiID); + deleteRole(roleID, reason) { + return this._client.deleteRole.call(this._client, this.id, roleID, reason); } /** - * Get a guild's members via the REST API. REST mode is required to use this endpoint. - * @arg {Number} [limit=1] The max number of members to get (1 to 1000) - * @arg {String} [after] The highest user ID of the previous page - * @returns {Promise} + * Delete a guild integration + * @arg {String} integrationID The ID of the integration + * @returns {Promise} */ - getRESTMembers(limit, after) { - return this._client.getRESTGuildMembers.call(this._client, this.id, limit, after); + deleteIntegration(integrationID) { + return this._client.deleteGuildIntegration.call(this._client, this.id, integrationID); } /** - * Get a guild's members via the REST API. REST mode is required to use this endpoint. - * @arg {String} memberID The ID of the member - * @returns {Promise} + * Get the guild's banner with the given format and size + * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") + * @param {Number} [size] The size of the icon (any power of two between 16 and 4096) */ - getRESTMember(memberID) { - return this._client.getRESTGuildMember.call(this._client, this.id, memberID); + dynamicBannerURL(format, size) { + return this.banner ? this._client._formatImage(Endpoints.GUILD_BANNER(this.id, this.banner), format, size) : null; } /** - * Get a guild's roles via the REST API. REST mode is required to use this endpoint. - * @returns {Promise} + * Get the guild's icon with the given format and size + * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") + * @arg {Number} [size] The size of the icon (any power of two between 16 and 4096) */ - getRESTRoles() { - return this._client.getRESTGuildRoles.call(this._client, this.id); + dynamicIconURL(format, size) { + return this.icon ? this._client._formatImage(Endpoints.GUILD_ICON(this.id, this.icon), format, size) : null; } /** - * [DEPRECATED] Get a guild's embed object - * @returns {Promise} A guild embed object + * Get the guild's splash with the given format and size + * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") + * @param {Number} [size] The size of the icon (any power of two between 16 and 4096) */ - getEmbed() { - return this._client.getGuildEmbed.call(this._client, this.id); + dynamicSplashURL(format, size) { + return this.splash ? this._client._formatImage(Endpoints.GUILD_SPLASH(this.id, this.splash), format, size) : null; } /** - * Get a guild's widget object - * @returns {Promise} A guild widget object + * Edit the guild + * @arg {Object} options The properties to edit + * @arg {String} [options.afkChannelID] The ID of the AFK voice channel + * @arg {Number} [options.afkTimeout] The AFK timeout in seconds + * @arg {String} [options.banner] The guild banner image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings + * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". + * @arg {String} [options.description] The description for the guild (VIP only) + * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. + * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.name] The ID of the guild + * @arg {String} [options.ownerID] The ID of the member to transfer guild ownership to (bot user must be owner) + * @arg {String} [options.preferredLocale] Preferred "PUBLIC" guild language used in server discovery and notices from Discord + * @arg {String} [options.publicUpdatesChannelID] The id of the channel where admins and moderators of "PUBLIC" guilds receive notices from Discord + * @arg {String} [options.region] The region of the guild + * @arg {String} [options.rulesChannelID] The id of the channel where "PUBLIC" guilds display rules and/or guidelines + * @arg {String} [options.splash] The guild splash image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.systemChannelID] The ID of the system channel + * @arg {Number} [options.verificationLevel] The guild verification level + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getWidget() { - return this._client.getGuildWidget.call(this._client, this.id); + edit(options, reason) { + return this._client.editGuild.call(this._client, this.id, options, reason); } /** - * Modify a guild's widget - * @arg {Object} options The widget object to modify (https://discord.com/developers/docs/resources/guild#modify-guild-widget) - * @returns {Promise} A guild widget object + * Edit a emoji in the guild + * @arg {String} emojiID The ID of the emoji you want to modify + * @arg {Object} options Emoji options + * @arg {String} [options.name] The name of emoji + * @arg {Array} [options.roles] An array containing authorized role IDs + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} A guild emoji object */ - editWidget(options) { - return this._client.getGuildWidget.call(this._client, this.id, options); + editEmoji(emojiID, options, reason) { + return this._client.editGuildEmoji.call(this._client, this.id, emojiID, options, reason); } /** - * Get possible voice regions for a guild - * @returns {Promise} Resolves with an array of voice region objects + * Edit a guild integration + * @arg {String} integrationID The ID of the integration + * @arg {Object} options The properties to edit + * @arg {String} [options.enableEmoticons] Whether to enable integration emoticons or not + * @arg {String} [options.expireBehavior] What to do when a user's subscription runs out + * @arg {String} [options.expireGracePeriod] How long before the integration's role is removed from an unsubscribed user + * @returns {Promise} */ - getVoiceRegions() { - return this._client.getVoiceRegions.call(this._client, this.id); + editIntegration(integrationID, options) { + return this._client.editGuildIntegration.call(this._client, this.id, integrationID, options); } /** - * Leaves the voice channel in this guild + * Edit a guild member + * @arg {String} memberID The ID of the member + * @arg {Object} options The properties to edit + * @arg {String} [options.channelID] The ID of the voice channel to move the member to (must be in voice) + * @arg {Boolean} [options.deaf] Server deafen the member + * @arg {Boolean} [options.mute] Server mute the member + * @arg {String} [options.nick] Set the member's guild nickname, "" to remove + * @arg {String[]} [options.roles] The array of role IDs the member should have + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - leaveVoiceChannel() { - this._client.closeVoiceConnection.call(this._client, this.id); + editMember(memberID, options, reason) { + return this._client.editGuildMember.call(this._client, this.id, memberID, options, reason); + } + + /** + * Edit the bot's nickname in the guild + * @arg {String} nick The nickname + * @returns {Promise} + */ + editNickname(nick) { + return this._client.editNickname.call(this._client, this.id, nick); } /** * Edit the guild role * @arg {String} roleID The ID of the role * @arg {Object} options The properties to edit - * @arg {String} [options.name] The name of the role - * @arg {Number} [options.permissions] The role permissions number * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3da5b3 or 4040115) * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not + * @arg {String} [options.name] The name of the role + * @arg {Number} [options.permissions] The role permissions number * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ @@ -491,13 +452,37 @@ class Guild extends Base { } /** - * Delete a role - * @arg {String} roleID The ID of the role - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Modify a guild's widget + * @arg {Object} options The widget object to modify (https://discord.com/developers/docs/resources/guild#modify-guild-widget) + * @returns {Promise} A guild widget object */ - deleteRole(roleID, reason) { - return this._client.deleteRole.call(this._client, this.id, roleID, reason); + editWidget(options) { + return this._client.getGuildWidget.call(this._client, this.id, options); + } + + /** + * Request all guild members from Discord + * @arg {Number} [timeout] The number of milliseconds to wait before resolving early. Defaults to the `requestTimeout` client option + * @returns {Promise} Resolves with the total number of fetched members. + */ + fetchAllMembers(timeout) { + return this.fetchMembers({ + timeout + }).then((m) => m.length); + } + + /** + * Request specific guild members through the gateway connection + * @arg {Object} [options] Options for fetching the members + * @arg {Number} [options.limit] The maximum number of members to fetch + * @arg {Boolean} [options.presences] Whether to request member presences or not. When using intents, the `GUILD_PRESENCES` intent is required. + * @arg {String} [options.query] The query used for looking up the members. When using intents, `GUILD_MEMBERS` is required to fetch all members. + * @arg {Number} [options.timeout] The number of milliseconds to wait before resolving early. Defaults to the `requestTimeout` client option + * @arg {String[]} [options.userIDs] The IDs of members to fetch + * @returns {Promise} Resolves with the fetched members. + */ + fetchMembers(options) { + return this.shard.requestGuildMembers(this.id, options); } /** @@ -512,42 +497,28 @@ class Guild extends Base { } /** - * Get a list of integrations for the guild - * @returns {Promise} - */ - getIntegrations() { - return this._client.getGuildIntegrations.call(this._client, this.id); - } - - /** - * Edit a guild integration - * @arg {String} integrationID The ID of the integration - * @arg {Object} options The properties to edit - * @arg {String} [options.expireBehavior] What to do when a user's subscription runs out - * @arg {String} [options.expireGracePeriod] How long before the integration's role is removed from an unsubscribed user - * @arg {String} [options.enableEmoticons] Whether to enable integration emoticons or not - * @returns {Promise} + * Get a ban from the ban list of a guild + * @arg {String} userID The ID of the banned user + * @returns {Promise} Resolves with {reason: String, user: User} */ - editIntegration(integrationID, options) { - return this._client.editGuildIntegration.call(this._client, this.id, integrationID, options); + getBan(userID) { + return this._client.getGuildBan.call(this._client, this.id, userID); } /** - * Force a guild integration to sync - * @arg {String} integrationID The ID of the integration - * @returns {Promise} + * Get the ban list of the guild + * @returns {Promise} Resolves with an array of {reason: String, user: User} */ - syncIntegration(integrationID) { - return this._client.syncGuildIntegration.call(this._client, this.id, integrationID); + getBans() { + return this._client.getGuildBans.call(this._client, this.id); } /** - * Delete a guild integration - * @arg {String} integrationID The ID of the integration - * @returns {Promise} + * [DEPRECATED] Get a guild's embed object + * @returns {Promise} A guild embed object */ - deleteIntegration(integrationID) { - return this._client.deleteGuildIntegration.call(this._client, this.id, integrationID); + getEmbed() { + return this._client.getGuildEmbed.call(this._client, this.id); } /** @@ -559,114 +530,116 @@ class Guild extends Base { } /** - * Returns the vanity url of the guild - * @returns {Promise} + * Get a list of integrations for the guild + * @returns {Promise} */ - getVanity() { - return this._client.getGuildVanity.call(this._client, this.id); + getIntegrations() { + return this._client.getGuildIntegrations.call(this._client, this.id); } /** - * Edit a guild member - * @arg {String} memberID The ID of the member - * @arg {Object} options The properties to edit - * @arg {String[]} [options.roles] The array of role IDs the member should have - * @arg {String} [options.nick] Set the member's guild nickname, "" to remove - * @arg {Boolean} [options.mute] Server mute the member - * @arg {Boolean} [options.deaf] Server deafen the member - * @arg {String} [options.channelID] The ID of the voice channel to move the member to (must be in voice) - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get the prune count for the guild + * @arg {Number} [options] The options to use to get number of prune members + * @arg {Number} [options.days=7] The number of days of inactivity to prune for + * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning + * @returns {Promise} Resolves with the number of members that would be pruned */ - editMember(memberID, options, reason) { - return this._client.editGuildMember.call(this._client, this.id, memberID, options, reason); + getPruneCount(options) { + return this._client.getPruneCount.call(this._client, this.id, options); } /** - * Add a role to a guild member - * @arg {String} memberID The ID of the member - * @arg {String} roleID The ID of the role - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get a guild's channels via the REST API. REST mode is required to use this endpoint. + * @returns {Promise<(CategoryChannel[] | TextChannel[] | VoiceChannel[])>} */ - addMemberRole(memberID, roleID, reason) { - return this._client.addGuildMemberRole.call(this._client, this.id, memberID, roleID, reason); + getRESTChannels() { + return this._client.getRESTGuildChannels.call(this._client, this.id); } /** - * Remove a role from a guild member + * Get a guild emoji via the REST API. REST mode is required to use this endpoint. + * @arg {String} emojiID The ID of the emoji + * @returns {Promise} An emoji object + */ + getRESTEmoji(emojiID) { + return this._client.getRESTGuildEmoji.call(this._client, this.id, emojiID); + } + + /** + * Get a guild's emojis via the REST API. REST mode is required to use this endpoint. + * @returns {Promise} An array of guild emoji objects + */ + getRESTEmojis() { + return this._client.getRESTGuildEmojis.call(this._client, this.id); + } + + /** + * Get a guild's members via the REST API. REST mode is required to use this endpoint. * @arg {String} memberID The ID of the member - * @arg {String} roleID The ID of the role - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {Promise} */ - removeMemberRole(memberID, roleID, reason) { - return this._client.removeGuildMemberRole.call(this._client, this.id, memberID, roleID, reason); + getRESTMember(memberID) { + return this._client.getRESTGuildMember.call(this._client, this.id, memberID); } /** - * Kick a member from the guild - * @arg {String} userID The ID of the member - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get a guild's members via the REST API. REST mode is required to use this endpoint. + * @arg {Number} [limit=1] The max number of members to get (1 to 1000) + * @arg {String} [after] The highest user ID of the previous page + * @returns {Promise} */ - kickMember(userID, reason) { - return this._client.kickGuildMember.call(this._client, this.id, userID, reason); + getRESTMembers(limit, after) { + return this._client.getRESTGuildMembers.call(this._client, this.id, limit, after); } /** - * Ban a user from the guild - * @arg {String} userID The ID of the member - * @arg {Number} [deleteMessageDays=0] Number of days to delete messages for - * @arg {String} [reason] Reason for the ban - * @returns {Promise} + * Get a guild's roles via the REST API. REST mode is required to use this endpoint. + * @returns {Promise} */ - banMember(userID, deleteMessageDays, reason) { - return this._client.banGuildMember.call(this._client, this.id, userID, deleteMessageDays, reason); + getRESTRoles() { + return this._client.getRESTGuildRoles.call(this._client, this.id); } /** - * Unban a user from the guild - * @arg {String} userID The ID of the member - * @arg {String} [reason] The reason to be displayed in audit logs + * Returns the vanity url of the guild * @returns {Promise} */ - unbanMember(userID, reason) { - return this._client.unbanGuildMember.call(this._client, this.id, userID, reason); + getVanity() { + return this._client.getGuildVanity.call(this._client, this.id); } /** - * Edit the guild - * @arg {Object} options The properties to edit - * @arg {String} [options.name] The ID of the guild - * @arg {String} [options.region] The region of the guild - * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings - * @arg {Number} [options.verificationLevel] The guild verification level - * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". - * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. - * @arg {String} [options.systemChannelID] The ID of the system channel - * @arg {String} [options.rulesChannelID] The id of the channel where "PUBLIC" guilds display rules and/or guidelines - * @arg {String} [options.publicUpdatesChannelID] The id of the channel where admins and moderators of "PUBLIC" guilds receive notices from Discord - * @arg {String} [options.preferredLocale] Preferred "PUBLIC" guild language used in server discovery and notices from Discord - * @arg {String} [options.afkChannelID] The ID of the AFK voice channel - * @arg {Number} [options.afkTimeout] The AFK timeout in seconds - * @arg {String} [options.ownerID] The ID of the member to transfer guild ownership to (bot user must be owner) - * @arg {String} [options.splash] The guild splash image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings - * @arg {String} [options.banner] The guild banner image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings - * @arg {String} [options.description] The description for the guild (VIP only) - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get possible voice regions for a guild + * @returns {Promise} Resolves with an array of voice region objects */ - edit(options, reason) { - return this._client.editGuild.call(this._client, this.id, options, reason); + getVoiceRegions() { + return this._client.getVoiceRegions.call(this._client, this.id); } /** - * Delete the guild (bot user must be owner) + * Get all the webhooks in the guild + * @returns {Promise} Resolves with an array of webhook objects + */ + getWebhooks() { + return this._client.getGuildWebhooks.call(this._client, this.id); + } + + /** + * Get a guild's widget object + * @returns {Promise} A guild widget object + */ + getWidget() { + return this._client.getGuildWidget.call(this._client, this.id); + } + + /** + * Kick a member from the guild + * @arg {String} userID The ID of the member + * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - delete() { - return this._client.deleteGuild.call(this._client, this.id); + kickMember(userID, reason) { + return this._client.kickGuildMember.call(this._client, this.id, userID, reason); } /** @@ -678,37 +651,33 @@ class Guild extends Base { } /** - * Get the ban list of the guild - * @returns {Promise} Resolves with an array of {reason: String, user: User} + * Leaves the voice channel in this guild */ - getBans() { - return this._client.getGuildBans.call(this._client, this.id); + leaveVoiceChannel() { + this._client.closeVoiceConnection.call(this._client, this.id); } /** - * Get a ban from the ban list of a guild - * @arg {String} userID The ID of the banned user - * @returns {Promise} Resolves with {reason: String, user: User} + * Begin pruning the guild + * @arg {Number} [options] The options to pass to prune members + * @arg {Number} [options.days=7] The number of days of inactivity to prune for + * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning + * @arg {String} [options.reason] The reason to be displayed in audit logs + * @returns {Promise} Resolves with the number of pruned members */ - getBan(userID) { - return this._client.getGuildBan.call(this._client, this.id, userID); + pruneMembers(options) { + return this._client.pruneMembers.call(this._client, this.id, options); } /** - * Edit the bot's nickname in the guild - * @arg {String} nick The nickname + * Remove a role from a guild member + * @arg {String} memberID The ID of the member + * @arg {String} roleID The ID of the role + * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - editNickname(nick) { - return this._client.editNickname.call(this._client, this.id, nick); - } - - /** - * Get all the webhooks in the guild - * @returns {Promise} Resolves with an array of webhook objects - */ - getWebhooks() { - return this._client.getGuildWebhooks.call(this._client, this.id); + removeMemberRole(memberID, roleID, reason) { + return this._client.removeGuildMemberRole.call(this._client, this.id, memberID, roleID, reason); } /** @@ -721,6 +690,37 @@ class Guild extends Base { return this._client.searchGuildMembers.call(this._client, this.id, query, limit); } + /** + * Force a guild integration to sync + * @arg {String} integrationID The ID of the integration + * @returns {Promise} + */ + syncIntegration(integrationID) { + return this._client.syncGuildIntegration.call(this._client, this.id, integrationID); + } + + /** + * Unban a user from the guild + * @arg {String} userID The ID of the member + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + unbanMember(userID, reason) { + return this._client.unbanGuildMember.call(this._client, this.id, userID, reason); + } + + get bannerURL() { + return this.banner ? this._client._formatImage(Endpoints.GUILD_BANNER(this.id, this.banner)) : null; + } + + get iconURL() { + return this.icon ? this._client._formatImage(Endpoints.GUILD_ICON(this.id, this.icon)) : null; + } + + get splashURL() { + return this.splash ? this._client._formatImage(Endpoints.GUILD_SPLASH(this.id, this.splash)) : null; + } + toJSON(props = []) { return super.toJSON([ "afkChannelID", From e4adff3f975b2ee313f332b44b631e6fcc8298e5 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 20:41:22 -0400 Subject: [PATCH 05/35] Alphabetize GuildAuditLogEntry --- lib/structures/GuildAuditLogEntry.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/structures/GuildAuditLogEntry.js b/lib/structures/GuildAuditLogEntry.js index 03c329c93..98096a4b5 100644 --- a/lib/structures/GuildAuditLogEntry.js +++ b/lib/structures/GuildAuditLogEntry.js @@ -6,12 +6,20 @@ const {AuditLogActions} = require("../Constants"); /** * Represents a guild audit log entry describing a moderation action -* @prop {String} id The ID of the entry -* @prop {Guild} guild The guild containing the entry * @prop {Number} actionType The action type of the entry. See Constants.AuditLogActions for more details +* @prop {Object?} after The properties of the targeted object after the action was taken +* For example, if a channel was renamed from #general to #potato, this would be `{name: "potato"}`` +* @prop {Object?} before The properties of the targeted object before the action was taken +* For example, if a channel was renamed from #general to #potato, this would be `{name: "general"}`` +* @prop {(CategoryChannel | TextChannel | VoiceChannel)?} channel The channel containing the deleted messages, action type 72 (MESSAGE_DELETE) only +* @prop {Number?} count The number of messages deleted, action type 72 (MESSAGE_DELETE) only +* @prop {Number?} deleteMemberDays The number of days of inactivity to prune for, action type 21 (MEMBER_PRUNE) only +* @prop {Guild} guild The guild containing the entry +* @prop {String} id The ID of the entry +* @prop {(Member | Object)?} member The member described by the permission overwrite, action types 13-15 (CHANNEL\_OVERWRITE\_CREATE/UPDATE/DELETE) only. If the member is not cached, this could be {id: String} +* @prop {Number?} membersRemoved The number of members pruned from the server, action type 21 (MEMBER_PRUNE) only * @prop {String?} reason The reason for the action -* @prop {User} user The user that performed the action -* @prop {String} targetID The ID of the action target +* @prop {(Role | Object)?} role The role described by the permission overwrite, action types 13-15 (CHANNEL\_OVERWRITE\_CREATE/UPDATE/DELETE) only. If the role is not cached, this could be {id: String, name: String} * @prop {(CategoryChannel | Guild | Member | Invite | Role | Object | TextChannel | VoiceChannel | NewsChannel)?} target The object of the action target * If the item is not cached, this property will be null * If the action targets a guild, this could be a Guild object @@ -22,16 +30,8 @@ const {AuditLogActions} = require("../Constants"); * If the action targets a webhook, this is null * If the action targets a emoji, this could be an emoji Object * If the action targets a message, this is a User object -* @prop {Object?} before The properties of the targeted object before the action was taken -* For example, if a channel was renamed from #general to #potato, this would be `{name: "general"}`` -* @prop {Object?} after The properties of the targeted object after the action was taken -* For example, if a channel was renamed from #general to #potato, this would be `{name: "potato"}`` -* @prop {Number?} count The number of messages deleted, action type 72 (MESSAGE_DELETE) only -* @prop {(CategoryChannel | TextChannel | VoiceChannel)?} channel The channel containing the deleted messages, action type 72 (MESSAGE_DELETE) only -* @prop {Number?} deleteMemberDays The number of days of inactivity to prune for, action type 21 (MEMBER_PRUNE) only -* @prop {Number?} membersRemoved The number of members pruned from the server, action type 21 (MEMBER_PRUNE) only -* @prop {(Member | Object)?} member The member described by the permission overwrite, action types 13-15 (CHANNEL\_OVERWRITE\_CREATE/UPDATE/DELETE) only. If the member is not cached, this could be {id: String} -* @prop {(Role | Object)?} role The role described by the permission overwrite, action types 13-15 (CHANNEL\_OVERWRITE\_CREATE/UPDATE/DELETE) only. If the role is not cached, this could be {id: String, name: String} +* @prop {String} targetID The ID of the action target +* @prop {User} user The user that performed the action */ class GuildAuditLogEntry extends Base { constructor(data, guild) { From 05c990facfbd7b78d6a0787340d21ce5fc60a057 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 20:47:34 -0400 Subject: [PATCH 06/35] Alphabetize GuildIntegration --- lib/structures/GuildIntegration.js | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/structures/GuildIntegration.js b/lib/structures/GuildIntegration.js index a8b0003fc..563b730ec 100644 --- a/lib/structures/GuildIntegration.js +++ b/lib/structures/GuildIntegration.js @@ -4,22 +4,22 @@ const Base = require("./Base"); /** * Represents a guild integration -* @prop {String} id The ID of the integration -* @prop {Number} createdAt Timestamp of the guild integration's creation -* @prop {String} name The name of the integration -* @prop {String} type The type of the integration -* @prop {String} roleID The ID of the role connected to the integration -* @prop {User} user The user connected to the integration * @prop {Object} account Info on the integration account * @prop {String} account.id The ID of the integration account * @prop {String} account.name The name of the integration account +* @prop {Number} createdAt Timestamp of the guild integration's creation * @prop {Boolean} enabled Whether the integration is enabled or not -* @prop {Boolean} syncing Whether the integration is syncing or not +* @prop {Boolean} enableEmoticons Whether integration emoticons are enabled or not * @prop {Number} expireBehavior behavior of expired subscriptions * @prop {Number} expireGracePeriod grace period for expired subscriptions -* @prop {Boolean} enableEmoticons Whether integration emoticons are enabled or not +* @prop {String} id The ID of the integration +* @prop {String} name The name of the integration +* @prop {String} roleID The ID of the role connected to the integration * @prop {Number} subscriberCount number of subscribers * @prop {Number} syncedAt Unix timestamp of last integration sync +* @prop {Boolean} syncing Whether the integration is syncing or not +* @prop {String} type The type of the integration +* @prop {User} user The user connected to the integration */ class GuildIntegration extends Base { constructor(data, guild) { @@ -43,6 +43,14 @@ class GuildIntegration extends Base { this.syncedAt = data.synced_at; } + /** + * Delete the guild integration + * @returns {Promise} + */ + delete() { + return this.guild.shard.client.deleteGuildIntegration.call(this.guild.shard.client, this.guild.id, this.id); + } + /** * Edit the guild integration * @arg {Object} options The properties to edit @@ -55,14 +63,6 @@ class GuildIntegration extends Base { return this.guild.shard.client.editGuildIntegration.call(this.guild.shard.client, this.guild.id, this.id, options); } - /** - * Delete the guild integration - * @returns {Promise} - */ - delete() { - return this.guild.shard.client.deleteGuildIntegration.call(this.guild.shard.client, this.guild.id, this.id); - } - /** * Force the guild integration to sync * @returns {Promise} From 90f0eec2ef9536c12dc651cb94bf6d3193135898 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 20:50:43 -0400 Subject: [PATCH 07/35] Alphabetize GuildPreview --- index.d.ts | 4 ++-- lib/structures/GuildPreview.js | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/index.d.ts b/index.d.ts index 273cba885..dec2ce1ae 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1673,8 +1673,6 @@ declare namespace Eris { approximatePresenceCount: number; description: string | null; discoverySplash: string | null; - dynamicIconURL(format?: string, size?: number): string; - dynamicSplashURL(format?: string, size?: number): string; emojis: Emoji[]; features: string[]; icon: string | null; @@ -1684,6 +1682,8 @@ declare namespace Eris { splash: string | null; splashURL: string | null; constructor(data: BaseData, client: Client); + dynamicIconURL(format?: string, size?: number): string; + dynamicSplashURL(format?: string, size?: number): string; } export class Invite extends Base { diff --git a/lib/structures/GuildPreview.js b/lib/structures/GuildPreview.js index b7eb918b1..04bd289a0 100644 --- a/lib/structures/GuildPreview.js +++ b/lib/structures/GuildPreview.js @@ -6,18 +6,18 @@ const Endpoints = require("../rest/Endpoints.js"); /** * Represents a GuildPreview structure * @extends Base -* @prop {String} id The ID of the guild -* @prop {String} name The name of the guild - -* @prop {String?} icon The hash of the guild icon, or null if no icon -* @prop {String?} description The description for the guild (VIP only) -* @prop {String?} splash The hash of the guild splash image, or null if no splash (VIP only) -* @prop {String?} discoverySplash The description for the guild (VIP only) -* @prop {String[]} features An array of guild feature strings * @prop {Number} approximateMemberCount The **approximate** number of members in the guild * @prop {Number} approximatePresenceCount The **approximate** number of presences in the guild +* @prop {String?} description The description for the guild (VIP only) +* @prop {String?} discoverySplash The description for the guild (VIP only) * @prop {Object[]} emojis An array of guild emoji objects +* @prop {String[]} features An array of guild feature strings +* @prop {String?} icon The hash of the guild icon, or null if no icon * @prop {String?} iconURL The URL of the guild's icon +* @prop {String} id The ID of the guild +* @prop {String} name The name of the guild +* @prop {String?} splash The hash of the guild splash image, or null if no splash (VIP only) +* @prop {String?} splashURL The URL of the guild's splash image */ class GuildPreview extends Base { constructor(data, client) { From b0a729d12aaf78a9960472a1f9733ea0f943ed50 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 20:52:04 -0400 Subject: [PATCH 08/35] Alphabetize Invite --- lib/structures/Invite.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/structures/Invite.js b/lib/structures/Invite.js index b4a6c0bd8..6f1552bc7 100644 --- a/lib/structures/Invite.js +++ b/lib/structures/Invite.js @@ -5,21 +5,21 @@ const Guild = require("./Guild"); /** * Represents an invite. Some properties are only available when fetching invites from channels, which requires the Manage Channel permission. -* @prop {String} code The invite code * @prop {TextChannel | NewsChannel | VoiceChannel | GroupChannel | Object} channel Info on the invite channel * @prop {String} channel.id The ID of the invite's channel * @prop {String?} channel.name The name of the invite's channel * @prop {Number} channel.type The type of the invite's channel * @prop {String?} channel.icon The icon of a channel (group dm) +* @prop {String} code The invite code +* @prop {Number?} createdAt Timestamp of invite creation * @prop {Guild?} guild Info on the invite guild * @prop {User?} inviter The invite creator -* @prop {Number?} uses The number of invite uses -* @prop {Number?} maxUses The max number of invite uses * @prop {Number?} maxAge How long the invite lasts in seconds -* @prop {Boolean?} temporary Whether the invite grants temporary membership or not -* @prop {Number?} createdAt Timestamp of invite creation -* @prop {Number?} presenceCount The **approximate** presence count for the guild +* @prop {Number?} maxUses The max number of invite uses * @prop {Number?} memberCount The **approximate** member count for the guild +* @prop {Number?} presenceCount The **approximate** presence count for the guild +* @prop {Boolean?} temporary Whether the invite grants temporary membership or not +* @prop {Number?} uses The number of invite uses */ class Invite extends Base { constructor(data, client) { From f83f281e809d2c18bbef28f0aa8d091aa8bc1cb8 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:00:20 -0400 Subject: [PATCH 09/35] Alphabetize Member --- lib/structures/Member.js | 156 +++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/lib/structures/Member.js b/lib/structures/Member.js index 30edb98f8..46627c413 100644 --- a/lib/structures/Member.js +++ b/lib/structures/Member.js @@ -8,35 +8,35 @@ const VoiceState = require("./VoiceState"); /** * Represents a server member -* @prop {String} id The ID of the member -* @prop {String} mention A string that mentions the member -* @prop {Guild} guild The guild the member is in -* @prop {Number} joinedAt Timestamp of when the member joined the guild -* @prop {String} status The member's status. Either "online", "idle", "dnd", or "offline" +* @prop {Object[]?} activities The member's current activities +* @prop {String?} avatar The hash of the user's avatar, or null if no avatar +* @prop {String} avatarURL The URL of the user's avatar which can be either a JPG or GIF +* @prop {Boolean} bot Whether the user is an OAuth bot or not * @prop {Object?} clientStatus The member's per-client status * @prop {String} clientStatus.web The member's status on web. Either "online", "idle", "dnd", or "offline". Will be "online" for bots * @prop {String} clientStatus.desktop The member's status on desktop. Either "online", "idle", "dnd", or "offline". Will be "offline" for bots * @prop {String} clientStatus.mobile The member's status on mobile. Either "online", "idle", "dnd", or "offline". Will be "offline" for bots -* @prop {Object[]?} activities The member's current activities +* @prop {Number} createdAt Timestamp of user creation +* @prop {String} defaultAvatar The hash for the default avatar of a user if there is no avatar set +* @prop {String} defaultAvatarURL The URL of the user's default avatar +* @prop {String} discriminator The discriminator of the user * @prop {Object?} game The active game the member is playing * @prop {String} game.name The name of the active game * @prop {Number} game.type The type of the active game (0 is default, 1 is Twitch, 2 is YouTube) * @prop {String?} game.url The url of the active game -* @prop {VoiceState} voiceState The voice state of the member +* @prop {Guild} guild The guild the member is in +* @prop {String} id The ID of the member +* @prop {Number} joinedAt Timestamp of when the member joined the guild +* @prop {String} mention A string that mentions the member * @prop {String?} nick The server nickname of the member +* @prop {Permission} permission The guild-wide permissions of the member +* @prop {Number} premiumSince Timestamp of when the member boosted the guild * @prop {String[]} roles An array of role IDs this member is a part of +* @prop {String} staticAvatarURL The URL of the user's avatar (always a JPG) +* @prop {String} status The member's status. Either "online", "idle", "dnd", or "offline" * @prop {User} user The user object of the member -* @prop {Permission} permission The guild-wide permissions of the member -* @prop {String} defaultAvatar The hash for the default avatar of a user if there is no avatar set -* @prop {Number} createdAt Timestamp of user creation -* @prop {Boolean} bot Whether the user is an OAuth bot or not * @prop {String} username The username of the user -* @prop {String} discriminator The discriminator of the user -* @prop {String?} avatar The hash of the user's avatar, or null if no avatar -* @prop {String} defaultAvatarURL The URL of the user's default avatar -* @prop {String} avatarURL The URL of the user's avatar which can be either a JPG or GIF -* @prop {String} staticAvatarURL The URL of the user's avatar (always a JPG) -* @prop {Number} premiumSince Timestamp of when the member boosted the guild +* @prop {VoiceState} voiceState The voice state of the member */ class Member extends Base { constructor(data, guild, client) { @@ -100,14 +100,36 @@ class Member extends Base { } } - get voiceState() { - if(this.guild && this.guild.voiceStates.has(this.id)) { - return this.guild.voiceStates.get(this.id); - } else { - return new VoiceState({ - id: this.id - }); - } + get avatar() { + return this.user.avatar; + } + + get avatarURL() { + return this.user.avatarURL; + } + + get bot() { + return this.user.bot; + } + + get createdAt() { + return this.user.createdAt; + } + + get defaultAvatar() { + return this.user.defaultAvatar; + } + + get defaultAvatarURL() { + return this.user.defaultAvatarURL; + } + + get discriminator() { + return this.user.discriminator; + } + + get mention() { + return `<@!${this.id}>`; } get permission() { @@ -133,79 +155,57 @@ class Member extends Base { } } - get username() { - return this.user.username; - } - - get discriminator() { - return this.user.discriminator; - } - - get avatar() { - return this.user.avatar; - } - - get bot() { - return this.user.bot; - } - - get createdAt() { - return this.user.createdAt; - } - - get defaultAvatar() { - return this.user.defaultAvatar; - } - - get defaultAvatarURL() { - return this.user.defaultAvatarURL; - } - get staticAvatarURL(){ return this.user.staticAvatarURL; } - get avatarURL() { - return this.user.avatarURL; + get username() { + return this.user.username; } - get mention() { - return `<@!${this.id}>`; + get voiceState() { + if(this.guild && this.guild.voiceStates.has(this.id)) { + return this.guild.voiceStates.get(this.id); + } else { + return new VoiceState({ + id: this.id + }); + } } /** - * Edit the guild member - * @arg {Object} options The properties to edit - * @arg {String[]} [options.roles] The array of role IDs the user should have - * @arg {String} [options.nick] Set the user's server nickname, "" to remove - * @arg {Boolean} [options.mute] Server mute the user - * @arg {Boolean} [options.deaf] Server deafen the user - * @arg {String} [options.channelID] The ID of the voice channel to move the user to (must be in voice) + * Add a role to the guild member + * @arg {String} roleID The ID of the role * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - edit(options, reason) { - return this.guild.shard.client.editGuildMember.call(this.guild.shard.client, this.guild.id, this.id, options, reason); + addRole(roleID, reason) { + return this.guild.shard.client.addGuildMemberRole.call(this.guild.shard.client, this.guild.id, this.id, roleID, reason); } /** - * Add a role to the guild member - * @arg {String} roleID The ID of the role + * Edit the guild member + * @arg {Object} options The properties to edit + * @arg {String} [options.channelID] The ID of the voice channel to move the user to (must be in voice) + * @arg {Boolean} [options.deaf] Server deafen the user + * @arg {Boolean} [options.mute] Server mute the user + * @arg {String} [options.nick] Set the user's server nickname, "" to remove + * @arg {String[]} [options.roles] The array of role IDs the user should have * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - addRole(roleID, reason) { - return this.guild.shard.client.addGuildMemberRole.call(this.guild.shard.client, this.guild.id, this.id, roleID, reason); + edit(options, reason) { + return this.guild.shard.client.editGuildMember.call(this.guild.shard.client, this.guild.id, this.id, options, reason); } /** - * Remove a role from the guild member - * @arg {String} roleID The ID of the role + * Ban the user from the guild + * @arg {Number} [deleteMessageDays=0] Number of days to delete messages for * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - removeRole(roleID, reason) { - return this.guild.shard.client.removeGuildMemberRole.call(this.guild.shard.client, this.guild.id, this.id, roleID, reason); + ban(deleteMessageDays, reason) { + return this.guild.shard.client.banGuildMember.call(this.guild.shard.client, this.guild.id, this.id, deleteMessageDays, reason); } /** @@ -218,13 +218,13 @@ class Member extends Base { } /** - * Ban the user from the guild - * @arg {Number} [deleteMessageDays=0] Number of days to delete messages for + * Remove a role from the guild member + * @arg {String} roleID The ID of the role * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - ban(deleteMessageDays, reason) { - return this.guild.shard.client.banGuildMember.call(this.guild.shard.client, this.guild.id, this.id, deleteMessageDays, reason); + removeRole(roleID, reason) { + return this.guild.shard.client.removeGuildMemberRole.call(this.guild.shard.client, this.guild.id, this.id, roleID, reason); } /** From a3113255597949e315754a90b3ee61d47a3af953 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:08:39 -0400 Subject: [PATCH 10/35] Alphabetize Message --- index.d.ts | 6 +- lib/structures/Message.js | 127 +++++++++++++++++++------------------- 2 files changed, 70 insertions(+), 63 deletions(-) diff --git a/index.d.ts b/index.d.ts index dec2ce1ae..494fd5a51 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1737,6 +1737,8 @@ declare namespace Eris { } export class Message extends Base { + // Note: add activity + // Note: add application attachments: Attachment[]; author: User; channel: T; @@ -1747,11 +1749,13 @@ declare namespace Eris { createdAt: number; editedTimestamp?: number; embeds: Embed[]; + // note: add flags guildID?: string; id: string; member: Member | null; mentionEveryone: boolean; mentions: User[]; + // Note: add messageReference pinned: boolean; prefix?: string; reactions: { [s: string]: any; count: number; me: boolean }; @@ -1767,8 +1771,8 @@ declare namespace Eris { edit(content: MessageContent): Promise>; getReaction(reaction: string, limit?: number, before?: string, after?: string): Promise; pin(): Promise; - removeReactionEmoji(reaction: string): Promise; removeReaction(reaction: string, userID?: string): Promise; + removeReactionEmoji(reaction: string): Promise; removeReactions(): Promise; unpin(): Promise; } diff --git a/lib/structures/Message.js b/lib/structures/Message.js index c093b1734..57b21d056 100644 --- a/lib/structures/Message.js +++ b/lib/structures/Message.js @@ -7,36 +7,39 @@ const User = require("./User"); /** * Represents a message -* @prop {String} id The ID of the message -* @prop {PrivateChannel | TextChannel | NewsChannel} channel The channel the message is in -* @prop {String} [guildID] The ID of the guild this message is in (undefined if in DMs) -* @prop {Number} timestamp Timestamp of message creation -* @prop {Number} type The type of the message +* @prop {Object?} activity The activity specified in the message +* @prop {Object?} application The application of the activity in the message +* @prop {Object[]} attachments Array of attachments * @prop {User} author The message author -* @prop {Member?} member The message author with server-specific data -* @prop {User[]} mentions Array of mentioned users -* @prop {String} content Message content -* @prop {String?} cleanContent Message content with mentions replaced by names, and @everyone/@here escaped -* @prop {String[]} roleMentions Array of mentioned roles' ids +* @prop {PrivateChannel | TextChannel | NewsChannel} channel The channel the message is in * @prop {String[]} channelMentions Array of mentions channels' ids +* @prop {String?} cleanContent Message content with mentions replaced by names, and @everyone/@here escaped +* @prop {Command?} command The Command used in the Message, if any (CommandClient only) +* @prop {String} content Message content +* @prop {Number} createdAt Timestamp of message creation * @prop {Number?} editedTimestamp Timestamp of latest message edit -* @prop {Boolean} tts Whether to play the message using TTS or not +* @prop {Object[]} embeds Array of embeds +* @prop {Number} flags Message flags (see constants) +* @prop {String} [guildID] The ID of the guild this message is in (undefined if in DMs) +* @prop {String} id The ID of the message +* @prop {Member?} member The message author with server-specific data * @prop {Boolean} mentionEveryone Whether the message mentions everyone/here or not +* @prop {User[]} mentions Array of mentioned users * @prop {Object?} messageReference An object containing the reference to the original message if it is a crossposted message * @prop {String} messageReference.messageID The id of the original message this message was crossposted from * @prop {String} messageReference.channelID The id of the channel this message was crossposted from * @prop {String} messageReference.guildID The id of the guild this message was crossposted from -* @prop {Number} flags Message flags (see constants) -* @prop {Object[]} attachments Array of attachments -* @prop {Object[]} embeds Array of embeds -* @prop {Object?} activity The activity specified in the message -* @prop {Object?} application The application of the activity in the message +* @prop {Boolean} pinned Whether the message is pinned or not +// Note add prefix? * @prop {Object} reactions An object containing the reactions on the message -* @prop {Number} reactions.count The number of times the reaction was used * @prop {Boolean} reactions.me Whether or not the bot user did the reaction +* @prop {Number} reactions.count The number of times the reaction was used +* @prop {String[]} roleMentions Array of mentioned roles' ids +* @prop {Number} timestamp Timestamp of message creation +* @prop {Boolean} tts Whether to play the message using TTS or not +* @prop {Number} type The type of the message * @prop {String?} webhookID ID of the webhook that sent the message -* @prop {Boolean} pinned Whether the message is pinned or not -* @prop {Command?} command The Command used in the Message, if any (CommandClient only) + */ class Message extends Base { constructor(data, client) { @@ -226,6 +229,14 @@ class Message extends Base { } } + get channelMentions() { + if(this._channelMentions) { + return this._channelMentions; + } + + return (this._channelMentions = (this.content.match(/<#[0-9]+>/g) || []).map((mention) => mention.substring(2, mention.length - 1))); + } + get cleanContent() { let cleanContent = this.content.replace(/<(:\w+:)[0-9]+>/g, "$1"); @@ -268,12 +279,31 @@ class Message extends Base { return cleanContent.replace(/@everyone/g, "@\u200beveryone").replace(/@here/g, "@\u200bhere"); } - get channelMentions() { - if(this._channelMentions) { - return this._channelMentions; - } + /** + * Add a reaction to a message + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @arg {String} [userID="@me"] The ID of the user to react as + * @returns {Promise} + */ + addReaction(reaction, userID) { + return this._client.addMessageReaction.call(this._client, this.channel.id, this.id, reaction, userID); + } - return (this._channelMentions = (this.content.match(/<#[0-9]+>/g) || []).map((mention) => mention.substring(2, mention.length - 1))); + /** + * Crosspost (publish) a message to subscribed channels (NewsChannel only) + * @returns {Promise} + */ + crosspost() { + return this._client.crosspostMessage.call(this._client, this.channel.id, this.id); + } + + /** + * Delete the message + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + delete(reason) { + return this._client.deleteMessage.call(this._client, this.channel.id, this.id, reason); } /** @@ -293,22 +323,6 @@ class Message extends Base { return this._client.editMessage.call(this._client, this.channel.id, this.id, content); } - /** - * Pin the message - * @returns {Promise} - */ - pin() { - return this._client.pinMessage.call(this._client, this.channel.id, this.id); - } - - /** - * Unpin the message - * @returns {Promise} - */ - unpin() { - return this._client.unpinMessage.call(this._client, this.channel.id, this.id); - } - /** * Get a list of users who reacted with a specific reaction * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) @@ -322,13 +336,11 @@ class Message extends Base { } /** - * Add a reaction to a message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {String} [userID="@me"] The ID of the user to react as + * Pin the message * @returns {Promise} */ - addReaction(reaction, userID) { - return this._client.addMessageReaction.call(this._client, this.channel.id, this.id, reaction, userID); + pin() { + return this._client.pinMessage.call(this._client, this.channel.id, this.id); } /** @@ -341,14 +353,6 @@ class Message extends Base { return this._client.removeMessageReaction.call(this._client, this.channel.id, this.id, reaction, userID); } - /** - * Remove all reactions from a message - * @returns {Promise} - */ - removeReactions() { - return this._client.removeMessageReactions.call(this._client, this.channel.id, this.id); - } - /** * Remove all reactions from a message for a single emoji * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) @@ -359,20 +363,19 @@ class Message extends Base { } /** - * Delete the message - * @arg {String} [reason] The reason to be displayed in audit logs + * Remove all reactions from a message * @returns {Promise} */ - delete(reason) { - return this._client.deleteMessage.call(this._client, this.channel.id, this.id, reason); + removeReactions() { + return this._client.removeMessageReactions.call(this._client, this.channel.id, this.id); } /** - * Crosspost (publish) a message to subscribed channels (NewsChannel only) - * @returns {Promise} - */ - crosspost() { - return this._client.crosspostMessage.call(this._client, this.channel.id, this.id); + * Unpin the message + * @returns {Promise} + */ + unpin() { + return this._client.unpinMessage.call(this._client, this.channel.id, this.id); } toJSON(props = []) { From 0aea83508dcfcbb47cf00731b3768329a1435d67 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:11:04 -0400 Subject: [PATCH 11/35] Fix PermissionOverwrite typing Please correct if wrong, i don't write typings usually --- index.d.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 494fd5a51..bce1d0832 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1803,10 +1803,9 @@ declare namespace Eris { } export class PermissionOverwrite extends Permission { - createdAt: number; id: string; type: string; - constructor(data: { allow: number; deny: number }); + constructor(data: { allow: number; deny: number , id: string, type: "member" | "role"}); } export class PrivateChannel extends Channel implements Textable { From 32a63fdc40e9372a2b8b27b6b5cc7697a6d32bcc Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:14:06 -0400 Subject: [PATCH 12/35] Alphabetize Role --- lib/structures/Role.js | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/structures/Role.js b/lib/structures/Role.js index 5087fc0c5..2fa28d1a6 100644 --- a/lib/structures/Role.js +++ b/lib/structures/Role.js @@ -5,18 +5,17 @@ const Permission = require("./Permission"); /** * Represents a role -* @prop {String} id The ID of the role +* @prop {Number} color The hex color of the role in base 10 * @prop {Number} createdAt Timestamp of the role's creation +* @prop {Boolean} hoist Whether users with this role are hoisted in the user list or not +* @prop {String} id The ID of the role * @prop {Guild} guild The guild that owns the role +* @prop {Boolean} managed Whether a guild integration manages this role or not * @prop {String} mention A string that mentions the role -* @prop {Number} createdAt Timestamp of role creation -* @prop {String} name The name of the role * @prop {Boolean} mentionable Whether the role is mentionable or not -* @prop {Boolean} managed Whether a guild integration manages this role or not -* @prop {Boolean} hoist Whether users with this role are hoisted in the user list or not -* @prop {Number} color The hex color of the role in base 10 -* @prop {Number} position The position of the role +* @prop {String} name The name of the role * @prop {Permission} permissions The permissions representation of the role +* @prop {Number} position The position of the role */ class Role extends Base { constructor(data, guild) { @@ -49,6 +48,10 @@ class Role extends Base { } } + get mention() { + return `<@&${this.id}>`; + } + /** * Generates a JSON representation of the role permissions * @returns {Object} @@ -57,18 +60,23 @@ class Role extends Base { return this.permissions.json; } - get mention() { - return `<@&${this.id}>`; + /** + * Delete the role + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + delete(reason) { + return this.guild.shard.client.deleteRole.call(this.guild.shard.client, this.guild.id, this.id, reason); } /** * Edit the guild role * @arg {Object} options The properties to edit - * @arg {String} [options.name] The name of the role - * @arg {Number} [options.permissions] The role permissions number * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3da5b3 or 4040115) * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not + * @arg {String} [options.name] The name of the role + * @arg {Number} [options.permissions] The role permissions number * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ @@ -85,15 +93,6 @@ class Role extends Base { return this.guild.shard.client.editRolePosition.call(this.guild.shard.client, this.guild.id, this.id, position); } - /** - * Delete the role - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} - */ - delete(reason) { - return this.guild.shard.client.deleteRole.call(this.guild.shard.client, this.guild.id, this.id, reason); - } - toJSON(props = []) { return super.toJSON([ "color", From be7ecb0a05c258ab127b104942ff7943c5cb3bc8 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:16:54 -0400 Subject: [PATCH 13/35] Alphabetize User --- lib/structures/User.js | 85 +++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/lib/structures/User.js b/lib/structures/User.js index 9d070e866..421053ced 100644 --- a/lib/structures/User.js +++ b/lib/structures/User.js @@ -5,20 +5,19 @@ const Endpoints = require("../rest/Endpoints"); /** * Represents a user -* @prop {String} id The ID of the user +* @prop {String?} avatar The hash of the user's avatar, or null if no avatar +* @prop {String} avatarURL The URL of the user's avatar which can be either a JPG or GIF +* @prop {Boolean} bot Whether the user is an OAuth bot or not * @prop {Number} createdAt Timestamp of the user's creation -* @prop {String} mention A string that mentions the user * @prop {String} defaultAvatar The hash for the default avatar of a user if there is no avatar set -* @prop {Number} createdAt Timestamp of user creation -* @prop {Boolean} bot Whether the user is an OAuth bot or not -* @prop {String} username The username of the user -* @prop {String} discriminator The discriminator of the user -* @prop {String?} avatar The hash of the user's avatar, or null if no avatar * @prop {String} defaultAvatarURL The URL of the user's default avatar -* @prop {String} avatarURL The URL of the user's avatar which can be either a JPG or GIF +* @prop {String} discriminator The discriminator of the user +* @prop {String} id The ID of the user +* @prop {String} mention A string that mentions the user +* @prop {Number?} publicFlags Publicly vicible flags for this user * @prop {String} staticAvatarURL The URL of the user's avatar (always a JPG) * @prop {Boolean} system Whether the user is an official Discord system user (e.g. urgent messages) -* @prop {Number?} publicFlags Publicly vicible flags for this user +* @prop {String} username The username of the user */ class User extends Base { constructor(data, client) { @@ -47,8 +46,11 @@ class User extends Base { } } - get mention() { - return `<@${this.id}>`; + get avatarURL() { + if(this._missingClientError) { + throw this._missingClientError; + } + return this.avatar ? this._client._formatImage(Endpoints.USER_AVATAR(this.id, this.avatar)) : this.defaultAvatarURL; } get defaultAvatar() { @@ -59,52 +61,49 @@ class User extends Base { return `${Endpoints.CDN_URL}${Endpoints.DEFAULT_USER_AVATAR(this.defaultAvatar)}.png`; } - get staticAvatarURL() { - if(this._missingClientError) { - throw this._missingClientError; - } - return this.avatar ? this._client._formatImage(Endpoints.USER_AVATAR(this.id, this.avatar), "jpg") : this.defaultAvatarURL; + get mention() { + return `<@${this.id}>`; } - get avatarURL() { + get staticAvatarURL() { if(this._missingClientError) { throw this._missingClientError; } - return this.avatar ? this._client._formatImage(Endpoints.USER_AVATAR(this.id, this.avatar)) : this.defaultAvatarURL; + return this.avatar ? this._client._formatImage(Endpoints.USER_AVATAR(this.id, this.avatar), "jpg") : this.defaultAvatarURL; } /** - * Get the user's avatar with the given format and size - * @arg {String} [format] The filetype of the avatar ("jpg", "jpeg", "png", "gif", or "webp") - * @arg {Number} [size] The size of the avatar (any power of two between 16 and 4096) + * [USER ACCOUNT] Create a relationship with the user + * @arg {Boolean} [block=false] If true, block the user. Otherwise, add the user as a friend + * @returns {Promise} */ - dynamicAvatarURL(format, size) { - return this.avatar ? this._client._formatImage(Endpoints.USER_AVATAR(this.id, this.avatar), format, size) : this.defaultAvatarURL; + addRelationship(block) { + return this._client.addRelationship.call(this._client, this.id, block); } /** - * Get a DM channel with the user, or create one if it does not exist - * @returns {Promise} + * [USER ACCOUNT] Delete the current user's note for another user */ - getDMChannel() { - return this._client.getDMChannel.call(this._client, this.id); + deleteNote() { + return this._client.deleteUserNote.call(this._client, this.id); } /** - * [USER ACCOUNT] Create a relationship with the user - * @arg {Boolean} [block=false] If true, block the user. Otherwise, add the user as a friend - * @returns {Promise} + * Get the user's avatar with the given format and size + * @arg {String} [format] The filetype of the avatar ("jpg", "jpeg", "png", "gif", or "webp") + * @arg {Number} [size] The size of the avatar (any power of two between 16 and 4096) */ - addRelationship(block) { - return this._client.addRelationship.call(this._client, this.id, block); + dynamicAvatarURL(format, size) { + return this.avatar ? this._client._formatImage(Endpoints.USER_AVATAR(this.id, this.avatar), format, size) : this.defaultAvatarURL; } /** - * [USER ACCOUNT] Remove a relationship with the user + * [USER ACCOUNT] Edit the current user's note for the user + * @arg {String} note The note * @returns {Promise} */ - removeRelationship() { - return this._client.removeRelationship.call(this._client, this.id); + editNote(note) { + return this._client.editUserNote.call(this._client, this.id, note); } /** @@ -116,19 +115,19 @@ class User extends Base { } /** - * [USER ACCOUNT] Edit the current user's note for the user - * @arg {String} note The note - * @returns {Promise} + * Get a DM channel with the user, or create one if it does not exist + * @returns {Promise} */ - editNote(note) { - return this._client.editUserNote.call(this._client, this.id, note); + getDMChannel() { + return this._client.getDMChannel.call(this._client, this.id); } /** - * [USER ACCOUNT] Delete the current user's note for another user + * [USER ACCOUNT] Remove a relationship with the user + * @returns {Promise} */ - deleteNote() { - return this._client.deleteUserNote.call(this._client, this.id); + removeRelationship() { + return this._client.removeRelationship.call(this._client, this.id); } toJSON(props = []) { From 5f85a8abf2a1053e0011aed50f7fd213ef7fa8a6 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:18:44 -0400 Subject: [PATCH 14/35] Alphabetize VoiceState --- lib/structures/VoiceState.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/structures/VoiceState.js b/lib/structures/VoiceState.js index e862e1bf9..a63b84537 100644 --- a/lib/structures/VoiceState.js +++ b/lib/structures/VoiceState.js @@ -4,15 +4,15 @@ const Base = require("./Base"); /** * Represents a member's voice state in a call/guild -* @prop {String} id The ID of the member -* @prop {String?} sessionID The ID of the member's current voice session * @prop {String?} channelID The ID of the member's current voice channel -* @prop {Boolean} mute Whether the member is server muted or not * @prop {Boolean} deaf Whether the member is server deafened or not -* @prop {Boolean} suppress Whether the member is suppressed or not -* @prop {Boolean} selfMute Whether the member is self muted or not +* @prop {String} id The ID of the member +* @prop {Boolean} mute Whether the member is server muted or not * @prop {Boolean} selfDeaf Whether the member is self deafened or not +* @prop {Boolean} selfMute Whether the member is self muted or not * @prop {Boolean} selfStream Whether the member is streaming using "Go Live" +* @prop {Boolean} suppress Whether the member is suppressed or not +* @prop {String?} sessionID The ID of the member's current voice session */ class VoiceState extends Base { constructor(data) { From 5cc202baa2bfcc06a9edd6a0f24a27807a49b3a1 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:25:43 -0400 Subject: [PATCH 15/35] Alphabetize GuildChannel and fix typings for GuildChannel --- index.d.ts | 1 - lib/structures/GuildChannel.js | 94 +++++++++++++++++----------------- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/index.d.ts b/index.d.ts index bce1d0832..37e6a40b2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1631,7 +1631,6 @@ declare namespace Eris { position: number; type: Exclude; constructor(data: BaseData, guild: Guild); - createInvite(options?: CreateInviteOptions, reason?: string): Promise>; delete(reason?: string): Promise; deletePermission(overwriteID: string, reason?: string): Promise; edit(options: Omit, reason?: string): Promise; diff --git a/lib/structures/GuildChannel.js b/lib/structures/GuildChannel.js index f2ce38cdc..8514c2043 100644 --- a/lib/structures/GuildChannel.js +++ b/lib/structures/GuildChannel.js @@ -9,15 +9,15 @@ const PermissionOverwrite = require("./PermissionOverwrite"); /** * Represents a guild channel. You also probably want to look at CategoryChannel, NewsChannel, StoreChannel, TextChannel, and VoiceChannel. * @extends Channel -* @prop {String} id The ID of the channel -* @prop {String} mention A string that mentions the channel -* @prop {Number} type The type of the channel * @prop {Guild} guild The guild that owns the channel -* @prop {String?} parentID The ID of the category this channel belongs to * @prop {String} name The name of the channel -* @prop {Number} position The position of the channel * @prop {Boolean} nsfw Whether the channel is an NSFW channel or not +* @prop {String?} parentID The ID of the category this channel belongs to * @prop {Collection} permissionOverwrites Collection of PermissionOverwrites in this channel +* @prop {Number} position The position of the channel +* @prop {Number} type The type of the channel +* @prop {String} id The ID of the channel +* @prop {String} mention A string that mentions the channel */ class GuildChannel extends Channel { constructor(data, client) { @@ -52,34 +52,22 @@ class GuildChannel extends Channel { } /** - * Get the channel-specific permissions of a member - * @arg {String} memberID The ID of the member - * @returns {Permission} + * Delete the channel + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - permissionsOf(memberID) { - const member = this.guild.members.get(memberID); - let permission = member.permission.allow; - if(permission & Permissions.administrator) { - return new Permission(Permissions.all); - } - let overwrite = this.permissionOverwrites.get(this.guild.id); - if(overwrite) { - permission = (permission & ~overwrite.deny) | overwrite.allow; - } - let deny = 0; - let allow = 0; - for(const roleID of member.roles) { - if((overwrite = this.permissionOverwrites.get(roleID))) { - deny |= overwrite.deny; - allow |= overwrite.allow; - } - } - permission = (permission & ~deny) | allow; - overwrite = this.permissionOverwrites.get(memberID); - if(overwrite) { - permission = (permission & ~overwrite.deny) | overwrite.allow; - } - return new Permission(permission); + delete(reason) { + return this.client.deleteChannel.call(this.client, this.id, reason); + } + + /** + * Delete a channel permission overwrite + * @arg {String} overwriteID The ID of the overwritten user or role + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + deletePermission(overwriteID, reason) { + return this.client.deleteChannelPermission.call(this.client, this.id, overwriteID, reason); } /** @@ -108,15 +96,6 @@ class GuildChannel extends Channel { return this.client.editChannelPosition.call(this.client, this.id, position); } - /** - * Delete the channel - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} - */ - delete(reason) { - return this.client.deleteChannel.call(this.client, this.id, reason); - } - /** * Create a channel permission overwrite * @arg {String} overwriteID The ID of the overwritten user or role @@ -131,13 +110,34 @@ class GuildChannel extends Channel { } /** - * Delete a channel permission overwrite - * @arg {String} overwriteID The ID of the overwritten user or role - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get the channel-specific permissions of a member + * @arg {String} memberID The ID of the member + * @returns {Permission} */ - deletePermission(overwriteID, reason) { - return this.client.deleteChannelPermission.call(this.client, this.id, overwriteID, reason); + permissionsOf(memberID) { + const member = this.guild.members.get(memberID); + let permission = member.permission.allow; + if(permission & Permissions.administrator) { + return new Permission(Permissions.all); + } + let overwrite = this.permissionOverwrites.get(this.guild.id); + if(overwrite) { + permission = (permission & ~overwrite.deny) | overwrite.allow; + } + let deny = 0; + let allow = 0; + for(const roleID of member.roles) { + if((overwrite = this.permissionOverwrites.get(roleID))) { + deny |= overwrite.deny; + allow |= overwrite.allow; + } + } + permission = (permission & ~deny) | allow; + overwrite = this.permissionOverwrites.get(memberID); + if(overwrite) { + permission = (permission & ~overwrite.deny) | overwrite.allow; + } + return new Permission(permission); } toJSON(props = []) { From 0798e93de98a8755a09e052f91122c236fb6df60 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:30:39 -0400 Subject: [PATCH 16/35] Alphabetize NewsChannel --- lib/structures/NewsChannel.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/structures/NewsChannel.js b/lib/structures/NewsChannel.js index b049c23ab..76ca82974 100644 --- a/lib/structures/NewsChannel.js +++ b/lib/structures/NewsChannel.js @@ -3,22 +3,22 @@ const TextChannel = require("./TextChannel"); /** -* Represents a guild news channel +* Represents a guild news channel. * @extends TextChannel +* @prop {Guild} guild The guild that owns the channel * @prop {String} id The ID of the channel +* @prop {String} lastMessageID The ID of the last message in this channel +* @prop {Number} lastPinTimestamp The timestamp of the last pinned message * @prop {String} mention A string that mentions the channel -* @prop {Number} type The type of the channel -* @prop {Guild} guild The guild that owns the channel -* @prop {String?} parentID The ID of the category this channel belongs to +* @prop {Collection} messages Collection of Messages in this channel * @prop {String} name The name of the channel -* @prop {Number} position The position of the channel * @prop {Boolean} nsfw Whether the channel is an NSFW channel or not +* @prop {String?} parentID The ID of the category this channel belongs to * @prop {Collection} permissionOverwrites Collection of PermissionOverwrites in this channel -* @prop {Collection} messages Collection of Messages in this channel -* @prop {String} lastMessageID The ID of the last message in this channel -* @prop {Number} lastPinTimestamp The timestamp of the last pinned message -* @prop {String?} topic The topic of the channel +* @prop {Number} position The position of the channel * @prop {Number} rateLimitPerUser The ratelimit of the channel, in seconds. 0 means no ratelimit is enabled. Always 0 in NewsChannel +* @prop {String?} topic The topic of the channel +* @prop {Number} type The type of the channel */ class NewsChannel extends TextChannel { constructor(data, guild, messageLimit) { From 5fd96926063adaae395f0f74367ff8ff07e07414 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:36:30 -0400 Subject: [PATCH 17/35] Alphabetize PrivateChannel --- lib/structures/PrivateChannel.js | 169 ++++++++++++++++--------------- 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/lib/structures/PrivateChannel.js b/lib/structures/PrivateChannel.js index e7cb86e30..8a58ac63d 100644 --- a/lib/structures/PrivateChannel.js +++ b/lib/structures/PrivateChannel.js @@ -11,11 +11,11 @@ const User = require("./User"); * Represents a private channel * @extends Channel * @prop {String} id The ID of the channel -* @prop {String} mention A string that mentions the channel -* @prop {Number} type The type of the channel * @prop {String} lastMessageID The ID of the last message in this channel -* @prop {User} recipient The recipient in this private channel (private channels only) * @prop {Collection} messages Collection of Messages in this channel +* @prop {String} mention A string that mentions the channel +* @prop {User} recipient The recipient in this private channel (private channels only) +* @prop {Number} type The type of the channel */ class PrivateChannel extends Channel { constructor(data, client) { @@ -30,67 +30,14 @@ class PrivateChannel extends Channel { } /** - * [USER ACCOUNT] Ring fellow group channel recipient(s) - * @arg {String[]} recipients The IDs of the recipients to ring - */ - ring(recipients) { - this.client.requestHandler.request("POST", Endpoints.CHANNEL_CALL_RING(this.id), true, { - recipients - }); - } - - /** - * Check if the channel has an existing call - */ - syncCall() { - this.client.shards.values().next().value.sendWS(GatewayOPCodes.SYNC_CALL, { - channel_id: this.id - }); - } - - /** - * Leave the channel - * @returns {Promise} - */ - leave() { - return this.client.deleteChannel.call(this.client, this.id); - } - - /** - * Send typing status in a text channel - * @returns {Promise} - */ - sendTyping() { - return this.client.sendChannelTyping.call(this.client, this.id); - } - - /** - * Get a previous message in a text channel + * Add a reaction to a message * @arg {String} messageID The ID of the message - * @returns {Promise} - */ - getMessage(messageID) { - return this.client.getMessage.call(this.client, this.id, messageID); - } - - /** - * Get a previous message in a text channel - * @arg {Number} [limit=50] The max number of messages to get - * @arg {String} [before] Get messages before this message ID - * @arg {String} [after] Get messages after this message ID - * @arg {String} [around] Get messages around this message ID (does not work with limit > 100) - * @returns {Promise} - */ - getMessages(limit, before, after, around) { - return this.client.getMessages.call(this.client, this.id, limit, before, after, around); - } - - /** - * Get all the pins in a text channel - * @returns {Promise} + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @arg {String} [userID="@me"] The ID of the user to react as + * @returns {Promise} */ - getPins() { - return this.client.getPins.call(this.client, this.id); + addMessageReaction(messageID, reaction, userID) { + return this.client.addMessageReaction.call(this.client, this.id, messageID, reaction, userID); } /** @@ -113,6 +60,16 @@ class PrivateChannel extends Channel { return this.client.createMessage.call(this.client, this.id, content, file); } + /** + * Delete a message + * @arg {String} messageID The ID of the message + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + deleteMessage(messageID, reason) { + return this.client.deleteMessage.call(this.client, this.id, messageID, reason); + } + /** * Edit a message * @arg {String} messageID The ID of the message @@ -132,21 +89,12 @@ class PrivateChannel extends Channel { } /** - * Pin a message - * @arg {String} messageID The ID of the message - * @returns {Promise} - */ - pinMessage(messageID) { - return this.client.pinMessage.call(this.client, this.id, messageID); - } - - /** - * Unpin a message + * Get a previous message in a text channel * @arg {String} messageID The ID of the message - * @returns {Promise} + * @returns {Promise} */ - unpinMessage(messageID) { - return this.client.unpinMessage.call(this.client, this.id, messageID); + getMessage(messageID) { + return this.client.getMessage.call(this.client, this.id, messageID); } /** @@ -163,14 +111,40 @@ class PrivateChannel extends Channel { } /** - * Add a reaction to a message + * Get a previous message in a text channel + * @arg {Number} [limit=50] The max number of messages to get + * @arg {String} [before] Get messages before this message ID + * @arg {String} [after] Get messages after this message ID + * @arg {String} [around] Get messages around this message ID (does not work with limit > 100) + * @returns {Promise} + */ + getMessages(limit, before, after, around) { + return this.client.getMessages.call(this.client, this.id, limit, before, after, around); + } + + /** + * Get all the pins in a text channel + * @returns {Promise} + */ + getPins() { + return this.client.getPins.call(this.client, this.id); + } + + /** + * Leave the channel + * @returns {Promise} + */ + leave() { + return this.client.deleteChannel.call(this.client, this.id); + } + + /** + * Pin a message * @arg {String} messageID The ID of the message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {String} [userID="@me"] The ID of the user to react as * @returns {Promise} */ - addMessageReaction(messageID, reaction, userID) { - return this.client.addMessageReaction.call(this.client, this.id, messageID, reaction, userID); + pinMessage(messageID) { + return this.client.pinMessage.call(this.client, this.id, messageID); } /** @@ -184,14 +158,41 @@ class PrivateChannel extends Channel { return this.client.removeMessageReaction.call(this.client, this.id, messageID, reaction, userID); } + /** - * Delete a message + * [USER ACCOUNT] Ring fellow group channel recipient(s) + * @arg {String[]} recipients The IDs of the recipients to ring + */ + ring(recipients) { + this.client.requestHandler.request("POST", Endpoints.CHANNEL_CALL_RING(this.id), true, { + recipients + }); + } + + /** + * Send typing status in a text channel + * @returns {Promise} + */ + sendTyping() { + return this.client.sendChannelTyping.call(this.client, this.id); + } + + /** + * Check if the channel has an existing call + */ + syncCall() { + this.client.shards.values().next().value.sendWS(GatewayOPCodes.SYNC_CALL, { + channel_id: this.id + }); + } + + /** + * Unpin a message * @arg {String} messageID The ID of the message - * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - deleteMessage(messageID, reason) { - return this.client.deleteMessage.call(this.client, this.id, messageID, reason); + unpinMessage(messageID) { + return this.client.unpinMessage.call(this.client, this.id, messageID); } /** From 8d28bd4633b03fcc1966d7c1990c7fe9af2ac6f2 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:38:09 -0400 Subject: [PATCH 18/35] Alphabetize StoreChannel --- lib/structures/StoreChannel.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/structures/StoreChannel.js b/lib/structures/StoreChannel.js index bb719be2b..c5d4ce1b6 100644 --- a/lib/structures/StoreChannel.js +++ b/lib/structures/StoreChannel.js @@ -5,15 +5,15 @@ const GuildChannel = require("./GuildChannel"); /** * Represents a store channel * @extends GuildChannel +* @prop {Guild} guild The guild that owns the channel * @prop {String} id The ID of the channel * @prop {String} mention A string that mentions the channel -* @prop {Number} type The type of the channel -* @prop {Guild} guild The guild that owns the channel -* @prop {String?} parentID The ID of the category this channel belongs to * @prop {String} name The name of the channel -* @prop {Number} position The position of the channel * @prop {Boolean} nsfw Whether the channel is an NSFW channel or not +* @prop {String?} parentID The ID of the category this channel belongs to +* @prop {Number} position The position of the channel * @prop {Collection} permissionOverwrites Collection of PermissionOverwrites in this channel +* @prop {Number} type The type of the channel */ class StoreChannel extends GuildChannel { } From bca0552b75e4c2603aab4e98a3e2e5626773c75e Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:42:36 -0400 Subject: [PATCH 19/35] Alphabetize PrivateChannel method args --- lib/structures/PrivateChannel.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/structures/PrivateChannel.js b/lib/structures/PrivateChannel.js index 8a58ac63d..294e2ffe4 100644 --- a/lib/structures/PrivateChannel.js +++ b/lib/structures/PrivateChannel.js @@ -44,13 +44,13 @@ class PrivateChannel extends Channel { * Create a message in a text channel * Note: If you want to DM someone, the user ID is **not** the DM channel ID. use Client.getDMChannel() to get the DM channel ID for a user * @arg {String | Object} content A string or object. If an object is passed: - * @arg {String} content.content A content string - * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object} [file] A file object * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file @@ -74,14 +74,14 @@ class PrivateChannel extends Channel { * Edit a message * @arg {String} messageID The ID of the message * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: - * @arg {String} content.content A content string - * @arg {Boolean} [content.disableEveryone] Whether to filter @everyone/@here or not (overrides default) - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string + * @arg {Boolean} [content.disableEveryone] Whether to filter @everyone/@here or not (overrides default) + * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference * @returns {Promise} */ editMessage(messageID, content) { From 0bf68e643a0745a1b7d4c78c0c0818134cc2c7d2 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:48:33 -0400 Subject: [PATCH 20/35] Alphabetize TextChannel --- lib/structures/TextChannel.js | 198 +++++++++++++++++----------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/lib/structures/TextChannel.js b/lib/structures/TextChannel.js index d68253afa..b3425ac67 100644 --- a/lib/structures/TextChannel.js +++ b/lib/structures/TextChannel.js @@ -7,20 +7,20 @@ const Message = require("./Message"); /** * Represents a guild text channel * @extends GuildChannel +* @prop {Guild} guild The guild that owns the channel * @prop {String} id The ID of the channel +* @prop {String} lastMessageID The ID of the last message in this channel +* @prop {Number} lastPinTimestamp The timestamp of the last pinned message * @prop {String} mention A string that mentions the channel -* @prop {Number} type The type of the channel -* @prop {Guild} guild The guild that owns the channel -* @prop {String?} parentID The ID of the category this channel belongs to +* @prop {Collection} messages Collection of Messages in this channel * @prop {String} name The name of the channel -* @prop {Number} position The position of the channel * @prop {Boolean} nsfw Whether the channel is an NSFW channel or not +* @prop {Number} type The type of the channel +* @prop {String?} parentID The ID of the category this channel belongs to * @prop {Collection} permissionOverwrites Collection of PermissionOverwrites in this channel -* @prop {Collection} messages Collection of Messages in this channel -* @prop {String} lastMessageID The ID of the last message in this channel -* @prop {Number} lastPinTimestamp The timestamp of the last pinned message -* @prop {String?} topic The topic of the channel +* @prop {Number} position The position of the channel * @prop {Number} rateLimitPerUser The ratelimit of the channel, in seconds. 0 means no ratelimit is enabled +* @prop {String?} topic The topic of the channel */ class TextChannel extends GuildChannel { constructor(data, client, messageLimit) { @@ -43,11 +43,14 @@ class TextChannel extends GuildChannel { } /** - * Get all invites in the channel - * @returns {Promise} + * Add a reaction to a message + * @arg {String} messageID The ID of the message + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @arg {String} [userID="@me"] The ID of the user to react as + * @returns {Promise} */ - getInvites() { - return this.client.getChannelInvites.call(this.client, this.id); + addMessageReaction(messageID, reaction, userID) { + return this.client.addMessageReaction.call(this.client, this.id, messageID, reaction, userID); } /** @@ -65,18 +68,30 @@ class TextChannel extends GuildChannel { } /** - * Get all the webhooks in the channel - * @returns {Promise} Resolves with an array of webhook objects + * Create a message in the channel + * Note: If you want to DM someone, the user ID is **not** the DM channel ID. use Client.getDMChannel() to get the DM channel ID for a user + * @arg {String | Object} content A string or object. If an object is passed: + * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) + * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. + * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. + * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string + * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Boolean} [content.tts] Set the message TTS flag + * @arg {Object} [file] A file object + * @arg {Buffer} file.file A buffer containing file data + * @arg {String} file.name What to name the file + * @returns {Promise} */ - getWebhooks() { - return this.client.getChannelWebhooks.call(this.client, this.id); + createMessage(content, file) { + return this.client.createMessage.call(this.client, this.id, content, file); } /** * Create a channel webhook * @arg {Object} options Webhook options - * @arg {String} options.name The default name * @arg {String} options.avatar The default avatar as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} options.name The default name * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} Resolves with a webhook object */ @@ -84,6 +99,16 @@ class TextChannel extends GuildChannel { return this.client.createChannelWebhook.call(this.client, this.id, options, reason); } + /** + * Delete a message + * @arg {String} messageID The ID of the message + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + deleteMessage(messageID, reason) { + return this.client.deleteMessage.call(this.client, this.id, messageID, reason); + } + /** * Bulk delete messages (bot accounts only) * @arg {String[]} messageIDs Array of message IDs to delete @@ -95,24 +120,29 @@ class TextChannel extends GuildChannel { } /** - * Purge previous messages in the channel with an optional filter (bot accounts only) - * @arg {Number} limit The max number of messages to search through, -1 for no limit - * @arg {function} [filter] Optional filter function that returns a boolean when passed a Message object - * @arg {String} [before] Get messages before this message ID - * @arg {String} [after] Get messages after this message ID - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} Resolves with the number of messages deleted + * Edit a message + * @arg {String} messageID The ID of the message + * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: + * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) + * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. + * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. + * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string + * @arg {Boolean} [content.disableEveryone] Whether to filter @everyone/@here or not (overrides default) + * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference + * @returns {Promise} */ - purge(limit, filter, before, after, reason) { - return this.client.purgeChannel.call(this.client, this.id, limit, filter, before, after, reason); + editMessage(messageID, content) { + return this.client.editMessage.call(this.client, this.id, messageID, content); } /** - * Send typing status in the channel - * @returns {Promise} + * Get all invites in the channel + * @returns {Promise} */ - sendTyping() { - return this.client.sendChannelTyping.call(this.client, this.id); + getInvites() { + return this.client.getChannelInvites.call(this.client, this.id); } /** @@ -124,6 +154,19 @@ class TextChannel extends GuildChannel { return this.client.getMessage.call(this.client, this.id, messageID); } + /** + * Get a list of users who reacted with a specific reaction + * @arg {String} messageID The ID of the message + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @arg {Number} [limit=100] The maximum number of users to get + * @arg {String} [before] Get users before this user ID + * @arg {String} [after] Get users after this user ID + * @returns {Promise} + */ + getMessageReaction(messageID, reaction, limit, before, after) { + return this.client.getMessageReaction.call(this.client, this.id, messageID, reaction, limit, before, after); + } + /** * Get previous messages in the channel * @arg {Number} [limit=50] The max number of messages to get @@ -145,41 +188,11 @@ class TextChannel extends GuildChannel { } /** - * Create a message in the channel - * Note: If you want to DM someone, the user ID is **not** the DM channel ID. use Client.getDMChannel() to get the DM channel ID for a user - * @arg {String | Object} content A string or object. If an object is passed: - * @arg {String} content.content A content string - * @arg {Boolean} [content.tts] Set the message TTS flag - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Object} [file] A file object - * @arg {Buffer} file.file A buffer containing file data - * @arg {String} file.name What to name the file - * @returns {Promise} - */ - createMessage(content, file) { - return this.client.createMessage.call(this.client, this.id, content, file); - } - - /** - * Edit a message - * @arg {String} messageID The ID of the message - * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: - * @arg {String} content.content A content string - * @arg {Boolean} [content.disableEveryone] Whether to filter @everyone/@here or not (overrides default) - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @returns {Promise} + * Get all the webhooks in the channel + * @returns {Promise} Resolves with an array of webhook objects */ - editMessage(messageID, content) { - return this.client.editMessage.call(this.client, this.id, messageID, content); + getWebhooks() { + return this.client.getChannelWebhooks.call(this.client, this.id); } /** @@ -192,47 +205,37 @@ class TextChannel extends GuildChannel { } /** - * Unpin a message - * @arg {String} messageID The ID of the message - * @returns {Promise} - */ - unpinMessage(messageID) { - return this.client.unpinMessage.call(this.client, this.id, messageID); - } - - /** - * Get a list of users who reacted with a specific reaction - * @arg {String} messageID The ID of the message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {Number} [limit=100] The maximum number of users to get - * @arg {String} [before] Get users before this user ID - * @arg {String} [after] Get users after this user ID - * @returns {Promise} + * Purge previous messages in the channel with an optional filter (bot accounts only) + * @arg {Number} limit The max number of messages to search through, -1 for no limit + * @arg {function} [filter] Optional filter function that returns a boolean when passed a Message object + * @arg {String} [before] Get messages before this message ID + * @arg {String} [after] Get messages after this message ID + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} Resolves with the number of messages deleted */ - getMessageReaction(messageID, reaction, limit, before, after) { - return this.client.getMessageReaction.call(this.client, this.id, messageID, reaction, limit, before, after); + purge(limit, filter, before, after, reason) { + return this.client.purgeChannel.call(this.client, this.id, limit, filter, before, after, reason); } /** - * Add a reaction to a message + * Remove a reaction from a message * @arg {String} messageID The ID of the message * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {String} [userID="@me"] The ID of the user to react as + * @arg {String} [userID="@me"] The ID of the user to remove the reaction for * @returns {Promise} */ - addMessageReaction(messageID, reaction, userID) { - return this.client.addMessageReaction.call(this.client, this.id, messageID, reaction, userID); + removeMessageReaction(messageID, reaction, userID) { + return this.client.removeMessageReaction.call(this.client, this.id, messageID, reaction, userID); } /** - * Remove a reaction from a message + * Remove all reactions from a message for a single emoji * @arg {String} messageID The ID of the message * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {String} [userID="@me"] The ID of the user to remove the reaction for * @returns {Promise} */ - removeMessageReaction(messageID, reaction, userID) { - return this.client.removeMessageReaction.call(this.client, this.id, messageID, reaction, userID); + removeMessageReactionEmoji(messageID, reaction) { + return this.client.removeMessageReactionEmoji.call(this.client, this.id, messageID, reaction); } /** @@ -245,23 +248,20 @@ class TextChannel extends GuildChannel { } /** - * Remove all reactions from a message for a single emoji - * @arg {String} messageID The ID of the message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * Send typing status in the channel * @returns {Promise} */ - removeMessageReactionEmoji(messageID, reaction) { - return this.client.removeMessageReactionEmoji.call(this.client, this.id, messageID, reaction); + sendTyping() { + return this.client.sendChannelTyping.call(this.client, this.id); } /** - * Delete a message + * Unpin a message * @arg {String} messageID The ID of the message - * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - deleteMessage(messageID, reason) { - return this.client.deleteMessage.call(this.client, this.id, messageID, reason); + unpinMessage(messageID) { + return this.client.unpinMessage.call(this.client, this.id, messageID); } /** From 775cb5469de29424403d300569f4b392be7bf20e Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:52:22 -0400 Subject: [PATCH 21/35] Alphabetize VoiceChannel please check if the typings are correct here --- index.d.ts | 4 ++-- lib/structures/VoiceChannel.js | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/index.d.ts b/index.d.ts index 37e6a40b2..726e7dd2d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2039,9 +2039,9 @@ declare namespace Eris { type: 2; userLimit?: number; voiceMembers: Collection; - getInvites(): Promise<(Invite & InviteWithMetadata)[]>; createInvite(options?: CreateInviteOptions, reason?: string): Promise>; - join(options: VoiceResourceOptions): Promise; + getInvites(): Promise<(Invite & InviteWithMetadata)[]>; + join(options: { opusOnly?: boolean; shared?: boolean }): Promise; leave(): void; } diff --git a/lib/structures/VoiceChannel.js b/lib/structures/VoiceChannel.js index 7555ed6c0..11f6ea456 100644 --- a/lib/structures/VoiceChannel.js +++ b/lib/structures/VoiceChannel.js @@ -7,16 +7,16 @@ const Member = require("./Member"); /** * Represents a guild voice channel * @extends GuildChannel +* @prop {Number?} bitrate The bitrate of the channel +* @prop {Guild} guild The guild that owns the channel * @prop {String} id The ID of the channel * @prop {String} mention A string that mentions the channel -* @prop {Number} type The type of the channel -* @prop {Guild} guild The guild that owns the channel -* @prop {String?} parentID The ID of the category this channel belongs to * @prop {String} name The name of the channel -* @prop {Number} position The position of the channel * @prop {Boolean} nsfw Whether the channel is an NSFW channel or not +* @prop {String?} parentID The ID of the category this channel belongs to * @prop {Collection} permissionOverwrites Collection of PermissionOverwrites in this channel -* @prop {Number?} bitrate The bitrate of the channel +* @prop {Number} position The position of the channel +* @prop {Number} type The type of the channel * @prop {Number?} userLimit The max number of users that can join the channel * @prop {Collection} voiceMembers Collection of Members in this channel */ @@ -38,14 +38,6 @@ class VoiceChannel extends GuildChannel { } } - /** - * Get all invites in the channel - * @returns {Promise} - */ - getInvites() { - return this.client.getChannelInvites.call(this.client, this.id); - } - /** * Create an invite for the channel * @arg {Object} [options] Invite generation options @@ -60,11 +52,19 @@ class VoiceChannel extends GuildChannel { return this.client.createChannelInvite.call(this.client, this.id, options, reason); } + /** + * Get all invites in the channel + * @returns {Promise} + */ + getInvites() { + return this.client.getChannelInvites.call(this.client, this.id); + } + /** * Joins the channel. * @arg {Object} [options] VoiceConnection constructor options - * @arg {Object} [options.shared] Whether the VoiceConnection will be part of a SharedStream or not * @arg {Object} [options.opusOnly] Skip opus encoder initialization. You should not enable this unless you know what you are doing + * @arg {Object} [options.shared] Whether the VoiceConnection will be part of a SharedStream or not * @returns {Promise} Resolves with a VoiceConnection */ join(options) { From 53a582da698b3fae1d2fea212da1a3f409fa5e69 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 22:57:22 -0400 Subject: [PATCH 22/35] Alphabetize Client --- index.d.ts | 8 ++ lib/Client.js | 224 +++++++++++++++++++++++++------------------------- 2 files changed, 121 insertions(+), 111 deletions(-) diff --git a/index.d.ts b/index.d.ts index 726e7dd2d..cbe7183d7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -152,9 +152,14 @@ declare namespace Eris { largeThreshold?: number; lastShardID?: number; latencyThreshold?: number; + // Note: add maxReconnectAttmpets + // Note: add maxResumeAttemps maxShards?: number | "auto"; messageLimit?: number; opusOnly?: boolean; + // Note: add rateLimiterOffset + // Note add requestTimout + // Note: remove reconnectAttemps reconnectAttempts?: number; reconnectDelay?: ReconnectDelayFunction; restMode?: boolean; @@ -504,6 +509,7 @@ declare namespace Eris { icon?: string; region?: string; roles?: PartialRole[]; + systemChannelID: string; verificationLevel?: number; } interface GetPruneOptions { @@ -1213,6 +1219,7 @@ declare namespace Eris { ): Promise; createGroupChannel(userIDs: string[]): Promise; createGuild(name: string, options?: CreateGuildOptions): Promise; + // EmojiOptions has options.icon. Supposed to be options.image createGuildEmoji(guildID: string, options: EmojiOptions, reason?: string): Promise; createMessage(channelID: string, content: MessageContent, file?: MessageFile | MessageFile[]): Promise; createRole(guildID: string, options?: RoleOptions | Role, reason?: string): Promise; @@ -1374,6 +1381,7 @@ declare namespace Eris { leaveGuild(guildID: string): Promise; leaveVoiceChannel(channelID: string): void; pinMessage(channelID: string, messageID: string): Promise; + // Note: PruneMemberOptions is missing `computerPruneCount` pruneMembers(guildID: string, options?: PruneMemberOptions): Promise; purgeChannel( channelID: string, diff --git a/lib/Client.js b/lib/Client.js index a9f548235..9b5f2fdce 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -49,77 +49,80 @@ const sleep = (ms) => new Promise((res) => setTimeout(res, ms)); /** * Represents the main Eris client * @extends EventEmitter -* @prop {String} token The bot user token * @prop {Boolean?} bot Whether the bot user belongs to an OAuth2 application -* @prop {Object} options Eris options * @prop {Object} channelGuildMap Object mapping channel IDs to guild IDs -* @prop {Collection} shards Collection of shards Eris is using +// Gateway URL? +* @prop {Collection} groupChannels Collection of group channels the bot is in (user accounts only) * @prop {Collection} guilds Collection of guilds the bot is in +* @prop {Object} guildShardMap Object mapping guild IDs to shard IDs +* @prop {Object} notes Object mapping user IDs to user notes (user accounts only) +* @prop {Object} options Eris options * @prop {Object} privateChannelMap Object mapping user IDs to private channel IDs * @prop {Collection} privateChannels Collection of private channels the bot is in -* @prop {Collection} groupChannels Collection of group channels the bot is in (user accounts only) -* @prop {Collection} voiceConnections Extended collection of active VoiceConnections the bot has -* @prop {Object} guildShardMap Object mapping guild IDs to shard IDs +* @prop {Collection} relationships Collection of relationships the bot user has (user accounts only) +// Request handler? +* @prop {Collection} shards Collection of shards Eris is using * @prop {Number} startTime Timestamp of bot ready event +* @prop {String} token The bot user token * @prop {Collection} unavailableGuilds Collection of unavailable guilds the bot is in * @prop {Number} uptime How long in milliseconds the bot has been up for * @prop {ExtendedUser} user The bot user -* @prop {Collection} users Collection of users the bot sees -* @prop {Collection} relationships Collection of relationships the bot user has (user accounts only) * @prop {Object} userGuildSettings Object mapping guild IDs to individual guild settings for the bot user (user accounts only) +* @prop {Collection} users Collection of users the bot sees * @prop {Object} userSettings Object containing the user account settings (user accounts only) -* @prop {Object} notes Object mapping user IDs to user notes (user accounts only) +* @prop {Collection} voiceConnections Extended collection of active VoiceConnections the bot has */ class Client extends EventEmitter { /** * Create a Client * @arg {String} token bot token * @arg {Object} [options] Eris options (all options are optional) - * @arg {Boolean} [options.autoreconnect=true] Have Eris autoreconnect when connection is lost - * @arg {Boolean} [options.compress=false] Whether to request WebSocket data to be compressed or not - * @arg {Number} [options.connectionTimeout=30000] How long in milliseconds to wait for the connection to handshake with the server - * @arg {Object} [options.disableEvents] If disableEvents[eventName] is true, the WS event will not be processed. This can cause significant performance increase on large bots. [A full list of the WS event names can be found on the docs reference page](/Eris/docs/reference#ws-event-names) + * @arg {Object} [options.agent] A HTTP Agent used to proxy requests * @arg {Object} [options.allowedMentions] A list of mentions to allow by default in createMessage/editMessage * @arg {Boolean} [options.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [options.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [options.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {Boolean} [options.autoreconnect=true] Have Eris autoreconnect when connection is lost + * @arg {Boolean} [options.compress=false] Whether to request WebSocket data to be compressed or not + * @arg {Number} [options.connectionTimeout=30000] How long in milliseconds to wait for the connection to handshake with the server + * @arg {String} [options.defaultImageFormat="jpg"] The default format to provide user avatars, guild icons, and group icons in. Can be "jpg", "png", "gif", or "webp" + * @arg {Number} [options.defaultImageSize=128] The default size to return user avatars, guild icons, banners, splashes, and group icons. Can be any power of two between 16 and 2048. If the height and width are different, the width will be the value specified, and the height relative to that + * @arg {Object} [options.disableEvents] If disableEvents[eventName] is true, the WS event will not be processed. This can cause significant performance increase on large bots. [A full list of the WS event names can be found on the docs reference page](/Eris/docs/reference#ws-event-names) * @arg {Number} [options.firstShardID=0] The ID of the first shard to run for this client * @arg {Boolean} [options.getAllUsers=false] Get all the users in every guild. Ready time will be severely delayed * @arg {Number} [options.guildCreateTimeout=2000] How long in milliseconds to wait for a GUILD_CREATE before "ready" is fired. Increase this value if you notice missing guilds * @arg {Boolean} [options.guildSubscriptions=true] If false, disables some guild subscription events, including typing and presence events. This will reduce processing load, but will also result in inconsistent member caching + * @arg {Number | String[]} [options.intents] A list of intents, or raw bitmask value describing the intents to subscribe to. "presence" intent must be enabled on your application's page to be used. * @arg {Number} [options.largeThreshold=250] The maximum number of offline users per guild during initial guild data transmission - * @arg {Number} [options.latencyThreshold=30000] The average request latency at which Eris will start emitting latency errors * @arg {Number} [options.lastShardID=options.maxShards - 1] The ID of the last shard to run for this client + * @arg {Number} [options.latencyThreshold=30000] The average request latency at which Eris will start emitting latency errors + * @arg {Number} [options.maxReconnectAttempts=Infinity] The maximum amount of times that the client is allowed to try to reconnect to Discord. + * @arg {Number} [options.maxResumeAttempts=10] The maximum amount of times a shard can attempt to resume a session before considering that session invalid. * @arg {Number | String} [options.maxShards=1] The total number of shards you want to run. If "auto" Eris will use Discord's recommended shard count. * @arg {Number} [options.messageLimit=100] The maximum size of a channel message cache * @arg {Boolean} [options.opusOnly=false] Whether to suppress the node-opus not found error or not * @arg {Number} [options.ratelimiterOffset=0] A number of milliseconds to offset the ratelimit timing calculations by * @arg {Number} [options.requestTimeout=15000] A number of milliseconds before requests are considered timed out + * @arg {Function} [options.reconnectDelay] A function which returns how long the bot should wait until reconnecting to Discord. * @arg {Boolean} [options.restMode=false] Whether to enable getting objects over REST. This should only be enabled if you are not connecting to the gateway. Bot tokens must be prefixed manually in REST mode * @arg {Boolean} [options.seedVoiceConnections=false] Whether to populate bot.voiceConnections with existing connections the bot account has during startup. Note that this will disconnect connections from other bot sessions - * @arg {String} [options.defaultImageFormat="jpg"] The default format to provide user avatars, guild icons, and group icons in. Can be "jpg", "png", "gif", or "webp" - * @arg {Number} [options.defaultImageSize=128] The default size to return user avatars, guild icons, banners, splashes, and group icons. Can be any power of two between 16 and 2048. If the height and width are different, the width will be the value specified, and the height relative to that * @arg {Object} [options.ws] An object of WebSocket options to pass to the shard WebSocket constructors - * @arg {Object} [options.agent] A HTTP Agent used to proxy requests - * @arg {Number} [options.maxReconnectAttempts=Infinity] The maximum amount of times that the client is allowed to try to reconnect to Discord. - * @arg {Number} [options.maxResumeAttempts=10] The maximum amount of times a shard can attempt to resume a session before considering that session invalid. - * @arg {Function} [options.reconnectDelay] A function which returns how long the bot should wait until reconnecting to Discord. - * @arg {Number | String[]} [options.intents] A list of intents, or raw bitmask value describing the intents to subscribe to. "presence" intent must be enabled on your application's page to be used. */ constructor(token, options) { super(); this.options = Object.assign({ + agent: null, + allowedMentions: { + users: true, + roles: true + }, autoreconnect: true, compress: false, connectionTimeout: 30000, defaultImageFormat: "jpg", defaultImageSize: 128, disableEvents: {}, - allowedMentions: { - users: true, - roles: true - }, firstShardID: 0, getAllUsers: false, guildCreateTimeout: 2000, @@ -136,7 +139,6 @@ class Client extends EventEmitter { restMode: false, seedVoiceConnections: false, ws: {}, - agent: null, reconnectDelay: (lastDelay, attempts) => Math.pow(attempts + 1, 0.7) * 20000 }, options); this.options.allowedMentions = this._formatAllowedMentions(this.options.allowedMentions); @@ -296,8 +298,8 @@ class Client extends EventEmitter { * Join a voice channel. If joining a group call, the voice connection ID will be stored in voiceConnections as "call". Otherwise, it will be the guild ID * @arg {String} channelID The ID of the voice channel * @arg {Object} [options] VoiceConnection constructor options - * @arg {Object} [options.shared] Whether the VoiceConnection will be part of a SharedStream or not * @arg {Object} [options.opusOnly] Skip opus encoder initialization. You should not enable this unless you know what you are doing + * @arg {Object} [options.shared] Whether the VoiceConnection will be part of a SharedStream or not * @returns {Promise} Resolves with a VoiceConnection */ joinVoiceChannel(channelID, options = {}) { @@ -404,13 +406,13 @@ class Client extends EventEmitter { * @arg {String} name The name of the channel * @arg {String} [type=0] The type of the channel, either 0 (text), 2 (voice), or 4 (category) * @arg {Object | String} [options] The properties the channel should have. If `options` is a string, it will be treated as `options.parentID` (see below). Passing a string is deprecated and will not be supported in future versions. - * @arg {String} [options.topic] The topic of the channel (text channels only) - * @arg {Boolean} [options.nsfw] The nsfw status of the channel * @arg {Number} [options.bitrate] The bitrate of the channel (voice channels only) + * @arg {Boolean} [options.nsfw] The nsfw status of the channel * @arg {String?} [options.parentID] The ID of the parent category channel for this channel * @arg {Array} [options.permissionOverwrites] An array containing permission overwrite objects * @arg {Number} [options.rateLimitPerUser] The time in seconds a user has to wait before sending another message (does not affect bots or users with manageMessages/manageChannel permissions) (text channels only) * @arg {String} [options.reason] The reason to be displayed in audit logs + * @arg {String} [options.topic] The topic of the channel (text channels only) * @arg {Number} [options.userLimit] The channel user limit (voice channels only) * @returns {Promise} */ @@ -432,14 +434,14 @@ class Client extends EventEmitter { return this.requestHandler.request("POST", Endpoints.GUILD_CHANNELS(guildID), true, { name: name, type: type, - reason: options.reason, - topic: options.topic, - nsfw: options.nsfw, bitrate: options.bitrate, - user_limit: options.userLimit, - rate_limit_per_user: options.rateLimitPerUser, + nsfw: options.nsfw, parent_id: options.parentID, - permission_overwrites: options.permissionOverwrites + permission_overwrites: options.permissionOverwrites, + rate_limit_per_user: options.rateLimitPerUser, + reason: options.reason, + topic: options.topic, + user_limit: options.userLimit }).then((channel) => Channel.from(channel, this)); } @@ -447,29 +449,29 @@ class Client extends EventEmitter { * Edit a channel's properties * @arg {String} channelID The ID of the channel * @arg {Object} options The properties to edit - * @arg {String} [options.name] The name of the channel + * @arg {Number} [options.bitrate] The bitrate of the channel (guild voice channels only) * @arg {String} [options.icon] The icon of the channel as a base64 data URI (group channels only). Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.name] The name of the channel + * @arg {Boolean} [options.nsfw] The nsfw status of the channel (guild channels only) * @arg {String} [options.ownerID] The ID of the channel owner (group channels only) + * @arg {String?} [options.parentID] The ID of the parent channel category for this channel (guild text/voice channels only) + * @arg {Number} [options.rateLimitPerUser] The time in seconds a user has to wait before sending another message (does not affect bots or users with manageMessages/manageChannel permissions) (guild text channels only) * @arg {String} [options.topic] The topic of the channel (guild text channels only) - * @arg {Boolean} [options.nsfw] The nsfw status of the channel (guild channels only) - * @arg {Number} [options.bitrate] The bitrate of the channel (guild voice channels only) * @arg {Number} [options.userLimit] The channel user limit (guild voice channels only) - * @arg {Number} [options.rateLimitPerUser] The time in seconds a user has to wait before sending another message (does not affect bots or users with manageMessages/manageChannel permissions) (guild text channels only) - * @arg {String?} [options.parentID] The ID of the parent channel category for this channel (guild text/voice channels only) * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ editChannel(channelID, options, reason) { return this.requestHandler.request("PATCH", Endpoints.CHANNEL(channelID), true, { - name: options.name, + bitrate: options.bitrate, icon: options.icon, + name: options.name, + nsfw: options.nsfw, owner_id: options.ownerID, + parent_id: options.parentID, + rate_limit_per_user: options.rateLimitPerUser, topic: options.topic, - nsfw: options.nsfw, - bitrate: options.bitrate, user_limit: options.userLimit, - rate_limit_per_user: options.rateLimitPerUser, - parent_id: options.parentID, reason: reason }).then((channel) => Channel.from(channel, this)); } @@ -644,20 +646,20 @@ class Client extends EventEmitter { * @arg {String} webhookID The ID of the webhook * @arg {String} token The token of the webhook * @arg {Object} options Webhook execution options + * @arg {Object} [options.allowedMentions] A list of mentions to allow (overrides default) + * @arg {Boolean} [options.allowedMentions.everyone] Whether or not to allow @everyone/@here. + * @arg {Boolean | Array} [options.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. + * @arg {Boolean | Array} [options.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. * @arg {Boolean} [options.auth=false] Whether or not to authorize the request with the bot token (allowing custom emotes from other guilds) + * @arg {String} [options.avatarURL] A URL for a custom avatar, defaults to webhook default avatar if not specified * @arg {String} [options.content=""] A content string + * @arg {Object[]} [options.embeds] An array of Discord embeds * @arg {Object | Object[]} [options.file] A file object (or an Array of them) * @arg {Buffer} options.file.file A buffer containing file data * @arg {String} options.file.name What to name the file - * @arg {Object[]} [options.embeds] An array of Discord embeds - * @arg {String} [options.username] A custom username, defaults to webhook default username if not specified - * @arg {String} [options.avatarURL] A URL for a custom avatar, defaults to webhook default avatar if not specified * @arg {Boolean} [options.tts=false] Whether the message should be a TTS message or not + * @arg {String} [options.username] A custom username, defaults to webhook default username if not specified * @arg {Boolean} [options.wait=false] Whether to wait for the server to confirm the message create or not - * @arg {Object} [options.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [options.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [options.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [options.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. * @returns {Promise} */ executeWebhook(webhookID, token, options) { @@ -679,8 +681,8 @@ class Client extends EventEmitter { * @arg {String} webhookID The ID of the webhook * @arg {String} token The token of the webhook * @arg {Object} options Slack webhook options - * @arg {Boolean} [options.wait=false] Whether to wait for the server to confirm the message create or not * @arg {Boolean} [options.auth=false] Whether or not to authorize the request with the bot token (allowing custom emotes from other guilds) + * @arg {Boolean} [options.wait=false] Whether to wait for the server to confirm the message create or not * @returns {Promise} */ executeSlackWebhook(webhookID, token, options) { @@ -739,8 +741,8 @@ class Client extends EventEmitter { * Create a guild emoji object * @arg {String} guildID The ID of the guild to create the emoji in * @arg {Object} options Emoji options - * @arg {String} options.name The name of emoji * @arg {String} options.image The base 64 encoded string + * @arg {String} options.name The name of emoji * @arg {Array} [options.roles] An array containing authorized role IDs * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} A guild emoji object @@ -782,11 +784,11 @@ class Client extends EventEmitter { * Create a guild role * @arg {String} guildID The ID of the guild to create the role in * @arg {Object|Role} [options] An object or Role containing the properties to set - * @arg {String} [options.name] The name of the role - * @arg {Number} [options.permissions] The role permissions number * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3d15b3 or 4040115) * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not + * @arg {String} [options.name] The name of the role + * @arg {Number} [options.permissions] The role permissions number * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ @@ -813,11 +815,11 @@ class Client extends EventEmitter { * @arg {String} guildID The ID of the guild the role is in * @arg {String} roleID The ID of the role * @arg {Object} options The properties to edit - * @arg {String} [options.name] The name of the role - * @arg {Number} [options.permissions] The role permissions number * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3da5b3 or 4040115) * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not + * @arg {String} [options.name] The name of the role + * @arg {Number} [options.permissions] The role permissions number * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ @@ -891,8 +893,8 @@ class Client extends EventEmitter { * Begin pruning a guild * @arg {String} guildID The ID of the guild * @arg {Number} [options] The options to pass to prune members - * @arg {Number} [options.days=7] The number of days of inactivity to prune for * @arg {Boolean} [options.computePruneCount=true] Whether or not the number of pruned members should be returned. Discord discourages setting this to true for larger guilds + * @arg {Number} [options.days=7] The number of days of inactivity to prune for * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning * @arg {String} [options.reason] The reason to be displayed in audit logs * @returns {Promise} If computePruneCount was true, resolves with the number of pruned members @@ -1065,13 +1067,13 @@ class Client extends EventEmitter { * Note: If you want to DM someone, the user ID is **not** the DM channel ID. use Client.getDMChannel() to get the DM channel for a user * @arg {String} channelID The ID of the channel * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: - * @arg {String} content.content A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string + * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object | Object[]} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file @@ -1100,13 +1102,13 @@ class Client extends EventEmitter { * @arg {String} channelID The ID of the channel * @arg {String} messageID The ID of the message * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: - * @arg {String} content.content A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string + * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference * @returns {Promise} */ editMessage(channelID, messageID, content) { @@ -1406,9 +1408,9 @@ class Client extends EventEmitter { * @arg {String} guildID The ID of the guild * @arg {String} integrationID The ID of the integration * @arg {Object} options The properties to edit + * @arg {String} [options.enableEmoticons] Whether to enable integration emoticons or not * @arg {String} [options.expireBehavior] What to do when a user's subscription runs out * @arg {String} [options.expireGracePeriod] How long before the integration's role is removed from an unsubscribed user - * @arg {String} [options.enableEmoticons] Whether to enable integration emoticons or not * @returns {Promise} */ editGuildIntegration(guildID, integrationID, options) { @@ -1492,16 +1494,16 @@ class Client extends EventEmitter { * Create a guild * @arg {String} name The name of the guild * @arg {Object} options The properties of the guild - * @arg {String} [options.region] The region of the guild - * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings - * @arg {Number} [options.verificationLevel] The guild verification level - * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". - * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. - * @arg {String} [options.systemChannelID] The ID of the system channel * @arg {String} [options.afkChannelID] The ID of the AFK voice channel * @arg {Number} [options.afkTimeout] The AFK timeout in seconds - * @arg {Array} [options.roles] The new roles of the guild, the first one is the @everyone role. IDs are placeholders which allow channel overwrites. * @arg {Array} [options.channels] The new channels of the guild. IDs are placeholders which allow use of category channels. + * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". + * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. + * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.region] The region of the guild + * @arg {Array} [options.roles] The new roles of the guild, the first one is the @everyone role. IDs are placeholders which allow channel overwrites. + * @arg {String} [options.systemChannelID] The ID of the system channel + * @arg {Number} [options.verificationLevel] The guild verification level * @returns {Promise} */ createGuild(name, options) { @@ -1528,22 +1530,22 @@ class Client extends EventEmitter { * Edit a guild * @arg {String} guildID The ID of the guild * @arg {Object} options The properties to edit - * @arg {String} [options.name] The ID of the guild - * @arg {String} [options.region] The region of the guild - * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings - * @arg {Number} [options.verificationLevel] The guild verification level - * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". - * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. - * @arg {String} [options.systemChannelID] The ID of the system channel - * @arg {String} [options.rulesChannelID] The id of the channel where "PUBLIC" guilds display rules and/or guidelines - * @arg {String} [options.publicUpdatesChannelID] The id of the channel where admins and moderators of "PUBLIC" guilds receive notices from Discord - * @arg {String} [options.preferredLocale] Preferred "PUBLIC" guild language used in server discovery and notices from Discord * @arg {String} [options.afkChannelID] The ID of the AFK voice channel * @arg {Number} [options.afkTimeout] The AFK timeout in seconds - * @arg {String} [options.ownerID] The ID of the user to transfer server ownership to (bot user must be owner) - * @arg {String} [options.splash] The guild splash image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings * @arg {String} [options.banner] The guild banner image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings + * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". * @arg {String} [options.description] The description for the guild (VIP only) + * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. + * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.name] The ID of the guild + * @arg {String} [options.ownerID] The ID of the user to transfer server ownership to (bot user must be owner) + * @arg {String} [options.preferredLocale] Preferred "PUBLIC" guild language used in server discovery and notices from Discord + * @arg {String} [options.publicUpdatesChannelID] The id of the channel where admins and moderators of "PUBLIC" guilds receive notices from Discord + * @arg {String} [options.region] The region of the guild + * @arg {String} [options.rulesChannelID] The id of the channel where "PUBLIC" guilds display rules and/or guidelines + * @arg {String} [options.splash] The guild splash image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.systemChannelID] The ID of the system channel + * @arg {Number} [options.verificationLevel] The guild verification level * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ @@ -1601,11 +1603,11 @@ class Client extends EventEmitter { * @arg {String} guildID The ID of the guild * @arg {String} memberID The ID of the member * @arg {Object} options The properties to edit - * @arg {String[]} [options.roles] The array of role IDs the member should have - * @arg {String} [options.nick] Set the member's server nickname, "" to remove - * @arg {Boolean} [options.mute] Server mute the member - * @arg {Boolean} [options.deaf] Server deafen the member * @arg {String} [options.channelID] The ID of the voice channel to move the member to (must be in voice) + * @arg {Boolean} [options.deaf] Server deafen the member + * @arg {Boolean} [options.mute] Server mute the member + * @arg {String} [options.nick] Set the member's server nickname, "" to remove + * @arg {String[]} [options.roles] The array of role IDs the member should have * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ @@ -2115,21 +2117,21 @@ class Client extends EventEmitter { * [USER ACCOUNT] Search a channel's messages * @arg {String} channelID The ID of the channel * @arg {Object} query Search parameters - * @arg {String} [query.sortBy="timestamp"] What to sort by, either "timestamp" or "relevance" - * @arg {String} [query.sortOrder="desc"] What order to sort by, either "asc" or "desc" - * @arg {String} [query.content] Filter results by a content string + * @arg {String} [query.attachmentExtensions] Filter results by attachment extension + * @arg {String} [query.attachmentFilename] Filter results by attachment filename * @arg {String} [query.authorID] Filter results by an author ID - * @arg {String} [query.minID] The minimum message ID to return results for - * @arg {String} [query.maxID] The maximum message ID to return results for - * @arg {Number} [query.limit=25] How many messages to return, 1 <= limit <= 25 - * @arg {Number} [query.offset=0] The query index of the first message to be returned, 0 <= offset <= 5000 + * @arg {String} [query.content] Filter results by a content string * @arg {Number} [query.contextSize=2] How many context messages around each result to return. - * For example, if you searched for `6` and contextSize was 2, `[4, 5, 6, 7, 8]` would be returned - * @arg {String} [query.has] Only return messages with an "attachment", "embed", or "link" * @arg {String} [query.embedProviders] Filter results by embed provider * @arg {String} [query.embedTypes] Filter results by embed type - * @arg {String} [query.attachmentExtensions] Filter results by attachment extension - * @arg {String} [query.attachmentFilename] Filter results by attachment filename + * @arg {String} [query.has] Only return messages with an "attachment", "embed", or "link" + * @arg {Number} [query.limit=25] How many messages to return, 1 <= limit <= 25 + * @arg {String} [query.maxID] The maximum message ID to return results for + * @arg {String} [query.minID] The minimum message ID to return results for + * @arg {Number} [query.offset=0] The query index of the first message to be returned, 0 <= offset <= 5000 + * @arg {String} [query.sortBy="timestamp"] What to sort by, either "timestamp" or "relevance" + * @arg {String} [query.sortOrder="desc"] What order to sort by, either "asc" or "desc" + * For example, if you searched for `6` and contextSize was 2, `[4, 5, 6, 7, 8]` would be returned * @returns {Promise} A search result object. The object will have a `totalResults` key and `results` key. * Each entry in the result array is an array of Message objects. * In each array, the message where `Message.hit === true` is the matched message, while the other messages are context messages. @@ -2169,22 +2171,22 @@ class Client extends EventEmitter { * [USER ACCOUNT] Search a guild's messages * @arg {String} guildID The ID of the guild * @arg {Object} query Search parameters - * @arg {String} [query.sortBy="timestamp"] What to sort by, either "timestamp" or "relevance" - * @arg {String} [query.sortOrder="desc"] What order to sort by, either "asc" or "desc" - * @arg {String} [query.content] Filter results by a content string + * @arg {String} [query.attachmentExtensions] Filter results by attachment extension + * @arg {String} [query.attachmentFilename] Filter results by attachment filename * @arg {String} [query.authorID] Filter results by an author ID + * @arg {String[]} [query.channelIDs] Filter results by channel ID + * @arg {String} [query.content] Filter results by a content string + * @arg {Number} [query.contextSize=2] How many context messages around each result to return. + * @arg {String} [query.embedProviders] Filter results by embed provider + * @arg {String} [query.embedTypes] Filter results by embed type + * @arg {String} [query.has] Only return messages with an "attachment", "embed", or "link" + * @arg {Number} [query.limit=25] How many messages to return, 1 <= limit <= 25 * @arg {String} [query.minID] The minimum message ID to return results for * @arg {String} [query.maxID] The maximum message ID to return results for - * @arg {Number} [query.limit=25] How many messages to return, 1 <= limit <= 25 * @arg {Number} [query.offset=0] The query index of the first message to be returned, 0 <= offset <= 5000 - * @arg {Number} [query.contextSize=2] How many context messages around each result to return. + * @arg {String} [query.sortBy="timestamp"] What to sort by, either "timestamp" or "relevance" + * @arg {String} [query.sortOrder="desc"] What order to sort by, either "asc" or "desc" * For example, if you searched for `6` and contextSize was 2, `[4, 5, 6, 7, 8]` would be returned - * @arg {String} [query.has] Only return messages with an "attachment", "embed", or "link" - * @arg {String} [query.embedProviders] Filter results by embed provider - * @arg {String} [query.embedTypes] Filter results by embed type - * @arg {String} [query.attachmentExtensions] Filter results by attachment extension - * @arg {String} [query.attachmentFilename] Filter results by attachment filename - * @arg {String[]} [query.channelIDs] Filter results by channel ID * @returns {Promise} A search result object. The object will have a `totalResults` key and `results` key. * Each entry in the result array is an array of Message objects. * In each array, the message where `Message.hit === true` is the matched message, while the other messages are context messages. From d52571dd2334421e22f7fcce4acae8758e36df34 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Wed, 19 Aug 2020 23:03:32 -0400 Subject: [PATCH 23/35] Put Guild getters at the top --- lib/structures/Guild.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index f9fac5e9d..b00a74f73 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -225,6 +225,18 @@ class Guild extends Base { } } + get bannerURL() { + return this.banner ? this._client._formatImage(Endpoints.GUILD_BANNER(this.id, this.banner)) : null; + } + + get iconURL() { + return this.icon ? this._client._formatImage(Endpoints.GUILD_ICON(this.id, this.icon)) : null; + } + + get splashURL() { + return this.splash ? this._client._formatImage(Endpoints.GUILD_SPLASH(this.id, this.splash)) : null; + } + /** * Add a role to a guild member * @arg {String} memberID The ID of the member @@ -709,18 +721,6 @@ class Guild extends Base { return this._client.unbanGuildMember.call(this._client, this.id, userID, reason); } - get bannerURL() { - return this.banner ? this._client._formatImage(Endpoints.GUILD_BANNER(this.id, this.banner)) : null; - } - - get iconURL() { - return this.icon ? this._client._formatImage(Endpoints.GUILD_ICON(this.id, this.icon)) : null; - } - - get splashURL() { - return this.splash ? this._client._formatImage(Endpoints.GUILD_SPLASH(this.id, this.splash)) : null; - } - toJSON(props = []) { return super.toJSON([ "afkChannelID", From 85b25e5670a2f47ca1c0624a613e819292665077 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:40:50 -0400 Subject: [PATCH 24/35] Add messageReference and more client options --- index.d.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index cbe7183d7..f042ad1a6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -152,15 +152,13 @@ declare namespace Eris { largeThreshold?: number; lastShardID?: number; latencyThreshold?: number; - // Note: add maxReconnectAttmpets - // Note: add maxResumeAttemps + maxReconnectAttempts?: number + maxResumeAttempts?: number maxShards?: number | "auto"; messageLimit?: number; opusOnly?: boolean; - // Note: add rateLimiterOffset - // Note add requestTimout - // Note: remove reconnectAttemps - reconnectAttempts?: number; + rateLimiterOffset?: number + requestTimeout?: number reconnectDelay?: ReconnectDelayFunction; restMode?: boolean; seedVoiceConnections?: boolean; @@ -1756,13 +1754,13 @@ declare namespace Eris { createdAt: number; editedTimestamp?: number; embeds: Embed[]; - // note: add flags + // Note: add flags guildID?: string; id: string; member: Member | null; mentionEveryone: boolean; mentions: User[]; - // Note: add messageReference + messageReference: { messageID: string, channelID: string, guildID: string} | null pinned: boolean; prefix?: string; reactions: { [s: string]: any; count: number; me: boolean }; From b48b1391bd42f3745c46fae03bdc771c388f9250 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:41:58 -0400 Subject: [PATCH 25/35] Add semicolons --- index.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index f042ad1a6..fdb275895 100644 --- a/index.d.ts +++ b/index.d.ts @@ -152,13 +152,13 @@ declare namespace Eris { largeThreshold?: number; lastShardID?: number; latencyThreshold?: number; - maxReconnectAttempts?: number - maxResumeAttempts?: number + maxReconnectAttempts?: number; + maxResumeAttempts?: number; maxShards?: number | "auto"; messageLimit?: number; opusOnly?: boolean; - rateLimiterOffset?: number - requestTimeout?: number + rateLimiterOffset?: number; + requestTimeout?: number; reconnectDelay?: ReconnectDelayFunction; restMode?: boolean; seedVoiceConnections?: boolean; From 18e140fffc406b02afcf61b2430032eaa7c264a9 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:30:02 -0400 Subject: [PATCH 26/35] Alphabetize Client methods --- index.d.ts | 2 + lib/Client.js | 2560 ++++++++++++++++++++++++------------------------- 2 files changed, 1282 insertions(+), 1280 deletions(-) diff --git a/index.d.ts b/index.d.ts index fdb275895..e424b3d81 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1261,6 +1261,7 @@ declare namespace Eris { ): Promise; editGuildIntegration(guildID: string, integrationID: string, options: IntegrationOptions): Promise; editGuildMember(guildID: string, memberID: string, options: MemberOptions, reason?: string): Promise; + editGuildWidget(guildID: string, options: Widget) : Promise editMessage(channelID: string, messageID: string, content: MessageContent): Promise; editNickname(guildID: string, nick: string, reason?: string): Promise; editRole(guildID: string, roleID: string, options: RoleOptions, reason?: string): Promise; // TODO not all options are available? @@ -1303,6 +1304,7 @@ declare namespace Eris { getGuildPreview(guildID: string): Promise; getGuildVanity(guildID: string): Promise<{ code?: string; uses?: number }>; getGuildWebhooks(guildID: string): Promise; + getGuildWidget(guildID: string) : Promise; getInvite(inviteID: string, withCounts?: false): Promise>; getInvite(inviteID: string, withCounts: true): Promise>; getMessage(channelID: string, messageID: string): Promise; diff --git a/lib/Client.js b/lib/Client.js index 9b5f2fdce..4c5e2de39 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -262,25 +262,6 @@ class Client extends EventEmitter { } } - /** - * Get info on connecting to the Discord gateway - * @returns {Promise} Resolves with an object containing gateway connection info - */ - getGateway() { - return this.requestHandler.request("GET", Endpoints.GATEWAY); - } - - /** - * Get general and bot-specific info on connecting to the Discord gateway (e.g. connection ratelimit) - * @returns {Promise} Resolves with an object containing gateway connection info - */ - getBotGateway() { - if(!this.token.startsWith("Bot ")) { - this.token = "Bot " + this.token; - } - return this.requestHandler.request("GET", Endpoints.GATEWAY_BOT, true); - } - /** * Disconnects all shards * @arg {Object?} [options] Shard disconnect options @@ -295,109 +276,110 @@ class Client extends EventEmitter { } /** - * Join a voice channel. If joining a group call, the voice connection ID will be stored in voiceConnections as "call". Otherwise, it will be the guild ID - * @arg {String} channelID The ID of the voice channel - * @arg {Object} [options] VoiceConnection constructor options - * @arg {Object} [options.opusOnly] Skip opus encoder initialization. You should not enable this unless you know what you are doing - * @arg {Object} [options.shared] Whether the VoiceConnection will be part of a SharedStream or not - * @returns {Promise} Resolves with a VoiceConnection + * [USER ACCOUNT] Accept an invite + * @arg {String} inviteID The ID of the invite + * @returns {Promise} */ - joinVoiceChannel(channelID, options = {}) { - const channel = this.getChannel(channelID); - if(!channel) { - return Promise.reject(new Error("Channel not found")); - } - if(channel.guild && !(channel.permissionsOf(this.user.id).allow & Constants.Permissions.voiceConnect)) { - return Promise.reject(new Error("Insufficient permission to connect to voice channel")); - } - this.shards.get(this.guildShardMap[this.channelGuildMap[channelID]] || 0).sendWS(Constants.GatewayOPCodes.VOICE_STATE_UPDATE, { - guild_id: this.channelGuildMap[channelID] || null, - channel_id: channelID || null, - self_mute: false, - self_deaf: false - }); - if(options.opusOnly === undefined) { - options.opusOnly = this.options.opusOnly; - } - return this.voiceConnections.join(this.channelGuildMap[channelID] || "call", channelID, options); + acceptInvite(inviteID) { + return this.requestHandler.request("POST", Endpoints.INVITE(inviteID), true).then((invite) => new Invite(invite, this)); } /** - * Leaves a voice channel - * @arg {String} channelID The ID of the voice channel + * [USER ACCOUNT] Add a user to a group + * @arg {String} groupID The ID of the target group + * @arg {String} userID The ID of the target user + * @returns {Promise} */ - leaveVoiceChannel(channelID) { - if(!channelID || !this.channelGuildMap[channelID]) { - return; - } - this.closeVoiceConnection(this.channelGuildMap[channelID]); + addGroupRecipient(groupID, userID) { + return this.requestHandler.request("PUT", Endpoints.CHANNEL_RECIPIENT(groupID, userID), true); } /** - * Closes a voice connection with a guild ID + * Add a role to a guild member * @arg {String} guildID The ID of the guild + * @arg {String} memberID The ID of the member + * @arg {String} roleID The ID of the role + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - closeVoiceConnection(guildID) { - this.shards.get(this.guildShardMap[guildID] || 0).sendWS(Constants.GatewayOPCodes.VOICE_STATE_UPDATE, { - guild_id: guildID || null, - channel_id: null, - self_mute: false, - self_deaf: false + addGuildMemberRole(guildID, memberID, roleID, reason) { + return this.requestHandler.request("PUT", Endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID), true, { + reason }); - this.voiceConnections.leave(guildID || "call"); } /** - * Update the bot's AFK status. Setting this to true will enable push notifications for userbots. - * @arg {Boolean} afk Whether the bot user is AFK or not + * Add a reaction to a message + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @arg {String} [userID="@me"] The ID of the user to react as + * @returns {Promise} */ - editAFK(afk) { - this.presence.afk = !!afk; + addMessageReaction(channelID, messageID, reaction, userID) { + if(reaction === decodeURI(reaction)) { + reaction = encodeURIComponent(reaction); + } + return this.requestHandler.request("PUT", Endpoints.CHANNEL_MESSAGE_REACTION_USER(channelID, messageID, reaction, userID || "@me"), true); + } - this.shards.forEach((shard) => { - shard.editAFK(afk); + /** + * [USER ACCOUNT] Create a relationship with a user + * @arg {String} userID The ID of the target user + * @arg {Boolean} [block=false] If true, block the user. Otherwise, add the user as a friend + * @returns {Promise} + */ + addRelationship(userID, block) { + return this.requestHandler.request("PUT", Endpoints.USER_RELATIONSHIP("@me", userID), true, { + type: block ? 2 : undefined }); } /** - * Update the bot's status on all guilds - * @arg {String} [status] Sets the bot's status, either "online", "idle", "dnd", or "invisible" - * @arg {Object} [game] Sets the bot's active game, null to clear - * @arg {String} game.name Sets the name of the bot's active game - * @arg {Number} [game.type] The type of game. 0 is playing, 1 is streaming (Twitch only), 2 is listening, 3 is watching - * @arg {String} [game.url] Sets the url of the shard's active game + * [USER ACCOUNT] Purchase a premium subscription (Nitro) for the current user + * You must get a Stripe card token from the Stripe API for this to work + * @arg {String} token The Stripe credit card token + * @arg {String} plan The plan to purchase, either "premium_month" or "premium_year" + * @returns {Promise} */ - editStatus(status, game) { - if(game === undefined && typeof status === "object") { - game = status; - status = undefined; - } - if(status) { - this.presence.status = status; - } - if(game !== undefined) { - this.presence.game = game; - } - - this.shards.forEach((shard) => { - shard.editStatus(status, game); + addSelfPremiumSubscription(token, plan) { + return this.requestHandler.request("PUT", Endpoints.USER_BILLING_PREMIUM_SUBSCRIPTION("@me"), true, { + token: token, + payment_gateway: "stripe", + plan: plan }); } /** - * Get a Channel object from a channel ID - * @arg {String} channelID The ID of the channel - * @returns {CategoryChannel | GroupChannel | PrivateChannel | TextChannel | VoiceChannel | NewsChannel} + * Ban a user from a guild + * @arg {String} guildID The ID of the guild + * @arg {String} userID The ID of the user + * @arg {Number} [deleteMessageDays=0] Number of days to delete messages for, between 0-7 inclusive + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getChannel(channelID) { - if(!channelID) { - throw new Error(`Invalid channel ID: ${channelID}`); + banGuildMember(guildID, userID, deleteMessageDays, reason) { + if(!isNaN(deleteMessageDays) && (deleteMessageDays < 0 || deleteMessageDays > 7)) { + return Promise.reject(new Error(`Invalid deleteMessageDays value (${deleteMessageDays}), should be a number between 0-7 inclusive`)); } + return this.requestHandler.request("PUT", Endpoints.GUILD_BAN(guildID, userID), true, { + delete_message_days: deleteMessageDays || 0, + reason: reason + }); + } - if(this.channelGuildMap[channelID] && this.guilds.get(this.channelGuildMap[channelID])) { - return this.guilds.get(this.channelGuildMap[channelID]).channels.get(channelID); - } - return this.privateChannels.get(channelID) || this.groupChannels.get(channelID); + /** + * Closes a voice connection with a guild ID + * @arg {String} guildID The ID of the guild + */ + closeVoiceConnection(guildID) { + this.shards.get(this.guildShardMap[guildID] || 0).sendWS(Constants.GatewayOPCodes.VOICE_STATE_UPDATE, { + guild_id: guildID || null, + channel_id: null, + self_mute: false, + self_deaf: false + }); + this.voiceConnections.leave(guildID || "call"); } /** @@ -446,106 +428,186 @@ class Client extends EventEmitter { } /** - * Edit a channel's properties + * Create an invite for a channel * @arg {String} channelID The ID of the channel - * @arg {Object} options The properties to edit - * @arg {Number} [options.bitrate] The bitrate of the channel (guild voice channels only) - * @arg {String} [options.icon] The icon of the channel as a base64 data URI (group channels only). Note: base64 strings alone are not base64 data URI strings - * @arg {String} [options.name] The name of the channel - * @arg {Boolean} [options.nsfw] The nsfw status of the channel (guild channels only) - * @arg {String} [options.ownerID] The ID of the channel owner (group channels only) - * @arg {String?} [options.parentID] The ID of the parent channel category for this channel (guild text/voice channels only) - * @arg {Number} [options.rateLimitPerUser] The time in seconds a user has to wait before sending another message (does not affect bots or users with manageMessages/manageChannel permissions) (guild text channels only) - * @arg {String} [options.topic] The topic of the channel (guild text channels only) - * @arg {Number} [options.userLimit] The channel user limit (guild voice channels only) + * @arg {Object} [options] Invite generation options + * @arg {Number} [options.maxAge] How long the invite should last in seconds + * @arg {Number} [options.maxUses] How many uses the invite should last for + * @arg {Boolean} [options.temporary] Whether the invite grants temporary membership or not + * @arg {Boolean} [options.unique] Whether the invite is unique or not * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {Promise} */ - editChannel(channelID, options, reason) { - return this.requestHandler.request("PATCH", Endpoints.CHANNEL(channelID), true, { - bitrate: options.bitrate, - icon: options.icon, - name: options.name, - nsfw: options.nsfw, - owner_id: options.ownerID, - parent_id: options.parentID, - rate_limit_per_user: options.rateLimitPerUser, - topic: options.topic, - user_limit: options.userLimit, + createChannelInvite(channelID, options = {}, reason) { + return this.requestHandler.request("POST", Endpoints.CHANNEL_INVITES(channelID), true, { + max_age: options.maxAge, + max_uses: options.maxUses, + temporary: options.temporary, + unique: options.unique, reason: reason - }).then((channel) => Channel.from(channel, this)); + }).then((invite) => new Invite(invite, this)); } /** - * Edit a guild channel's position. Note that channel position numbers are lowest on top and highest at the bottom. - * @arg {String} channelID The ID of the channel - * @arg {Number} position The new position of the channel - * @returns {Promise} + * Create a channel webhook + * @arg {String} channelID The ID of the channel to create the webhook in + * @arg {Object} options Webhook options + * @arg {String} options.name The default name + * @arg {String} options.avatar The default avatar as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} Resolves with a webhook object */ - editChannelPosition(channelID, position) { - let channels = this.guilds.get(this.channelGuildMap[channelID]).channels; - const channel = channels.get(channelID); - if(!channel) { - return Promise.reject(new Error(`Channel ${channelID} not found`)); - } - if(channel.position === position) { - return Promise.resolve(); - } - const min = Math.min(position, channel.position); - const max = Math.max(position, channel.position); - channels = channels.filter((chan) => { - return chan.type === channel.type - && min <= chan.position - && chan.position <= max - && chan.id !== channelID; - }).sort((a, b) => a.position - b.position); - if(position > channel.position) { - channels.push(channel); - } else { - channels.unshift(channel); - } - return this.requestHandler.request("PATCH", Endpoints.GUILD_CHANNELS(this.channelGuildMap[channelID]), true, channels.map((channel, index) => ({ - id: channel.id, - position: index + min - }))); + createChannelWebhook(channelID, options, reason) { + options.reason = reason; + return this.requestHandler.request("POST", Endpoints.CHANNEL_WEBHOOKS(channelID), true, options); } /** - * Delete a guild channel, or leave a private or group channel - * @arg {String} channelID The ID of the channel - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * [USER ACCOUNT] Create a group channel with other users + * @arg {String[]} userIDs The IDs of the other users + * @returns {Promise} */ - deleteChannel(channelID, reason) { - return this.requestHandler.request("DELETE", Endpoints.CHANNEL(channelID), true, { - reason - }); + createGroupChannel(userIDs) { + return this.requestHandler.request("POST", Endpoints.USER_CHANNELS("@me"), true, { + recipients: userIDs, + type: 3 + }).then((privateChannel) => new GroupChannel(privateChannel, this)); } /** - * Send typing status in a channel + * Create a guild + * @arg {String} name The name of the guild + * @arg {Object} options The properties of the guild + * @arg {String} [options.afkChannelID] The ID of the AFK voice channel + * @arg {Number} [options.afkTimeout] The AFK timeout in seconds + * @arg {Array} [options.channels] The new channels of the guild. IDs are placeholders which allow use of category channels. + * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". + * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. + * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.region] The region of the guild + * @arg {Array} [options.roles] The new roles of the guild, the first one is the @everyone role. IDs are placeholders which allow channel overwrites. + * @arg {String} [options.systemChannelID] The ID of the system channel + * @arg {Number} [options.verificationLevel] The guild verification level + * @returns {Promise} + */ + createGuild(name, options) { + if(this.guilds.size > 9) { + throw new Error("This method can't be used when in 10 or more guilds."); + } + + return this.requestHandler.request("POST", Endpoints.GUILDS, true, { + name: name, + region: options.region, + icon: options.icon, + verification_level: options.verificationLevel, + default_message_notifications: options.defaultNotifications, + explicit_content_filter: options.explicitContentFilter, + system_channel_id: options.systemChannelID, + afk_channel_id: options.afkChannelID, + afk_timeout: options.afkTimeout, + roles: options.roles, + channels: options.channels + }).then((guild) => new Guild(guild, this)); + } + + /** + * Create a guild emoji object + * @arg {String} guildID The ID of the guild to create the emoji in + * @arg {Object} options Emoji options + * @arg {String} options.image The base 64 encoded string + * @arg {String} options.name The name of emoji + * @arg {Array} [options.roles] An array containing authorized role IDs + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} A guild emoji object + */ + createGuildEmoji(guildID, options, reason) { + options.reason = reason; + return this.requestHandler.request("POST", Endpoints.GUILD_EMOJIS(guildID), true, options); + } + + /** + * Create a message in a channel + * Note: If you want to DM someone, the user ID is **not** the DM channel ID. use Client.getDMChannel() to get the DM channel for a user * @arg {String} channelID The ID of the channel - * @returns {Promise} + * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: + * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) + * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. + * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. + * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string + * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Boolean} [content.tts] Set the message TTS flag + * @arg {Object | Object[]} [file] A file object (or an Array of them) + * @arg {Buffer} file.file A buffer containing file data + * @arg {String} file.name What to name the file + * @returns {Promise} */ - sendChannelTyping(channelID) { - return this.requestHandler.request("POST", Endpoints.CHANNEL_TYPING(channelID), true); + createMessage(channelID, content, file) { + if(content !== undefined) { + if(typeof content !== "object" || content === null) { + content = { + content: "" + content + }; + } else if(content.content !== undefined && typeof content.content !== "string") { + content.content = "" + content.content; + } else if(content.content === undefined && !content.embed && !file) { + return Promise.reject(new Error("No content, file, or embed")); + } + content.allowed_mentions = this._formatAllowedMentions(content.allowedMentions); + } else if(!file) { + return Promise.reject(new Error("No content, file, or embed")); + } + return this.requestHandler.request("POST", Endpoints.CHANNEL_MESSAGES(channelID), true, content, file).then((message) => new Message(message, this)); } /** - * Create a channel permission overwrite - * @arg {String} channelID The ID of channel - * @arg {String} overwriteID The ID of the overwritten user or role (everyone role ID = guild ID) - * @arg {Number} allow The permissions number for allowed permissions - * @arg {Number} deny The permissions number for denied permissions - * @arg {String} type The object type of the overwrite, either "member" or "role" + * Create a guild role + * @arg {String} guildID The ID of the guild to create the role in + * @arg {Object|Role} [options] An object or Role containing the properties to set + * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3d15b3 or 4040115) + * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not + * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not + * @arg {String} [options.name] The name of the role + * @arg {Number} [options.permissions] The role permissions number + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + createRole(guildID, options, reason) { + return this.requestHandler.request("POST", Endpoints.GUILD_ROLES(guildID), true, { + name: options.name, + permissions: options.permissions instanceof Permission ? options.permissions.allow : options.permissions, + color: options.color, + hoist: options.hoist, + mentionable: options.mentionable, + reason: reason + }).then((role) => { + const guild = this.guilds.get(guildID); + if(guild) { + return guild.roles.add(role, guild); + } else { + return new Role(role); + } + }); + } + + /** + * Crosspost (publish) a message to subscribed channels + * @arg {String} channelID The ID of the NewsChannel + * @arg {String} messageID The ID of the message + * @returns {Promise} + */ + crosspostMessage(channelID, messageID) { + return this.requestHandler.request("POST", Endpoints.CHANNEL_CROSSPOST(channelID, messageID), true).then((message) => new Message(message, this)); + } + + /** + * Delete a guild channel, or leave a private or group channel + * @arg {String} channelID The ID of the channel * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - editChannelPermission(channelID, overwriteID, allow, deny, type, reason) { - return this.requestHandler.request("PUT", Endpoints.CHANNEL_PERMISSION(channelID, overwriteID), true, { - allow, - deny, - type, + deleteChannel(channelID, reason) { + return this.requestHandler.request("DELETE", Endpoints.CHANNEL(channelID), true, { reason }); } @@ -564,398 +626,463 @@ class Client extends EventEmitter { } /** - * Get all invites in a channel - * @arg {String} channelID The ID of the channel - * @returns {Promise} + * Delete a guild (bot user must be owner) + * @arg {String} guildID The ID of the guild + * @returns {Promise} */ - getChannelInvites(channelID) { - return this.requestHandler.request("GET", Endpoints.CHANNEL_INVITES(channelID), true).then((invites) => invites.map((invite) => new Invite(invite, this))); + deleteGuild(guildID) { + return this.requestHandler.request("DELETE", Endpoints.GUILD(guildID), true); } /** - * Create an invite for a channel - * @arg {String} channelID The ID of the channel - * @arg {Object} [options] Invite generation options - * @arg {Number} [options.maxAge] How long the invite should last in seconds - * @arg {Number} [options.maxUses] How many uses the invite should last for - * @arg {Boolean} [options.temporary] Whether the invite grants temporary membership or not - * @arg {Boolean} [options.unique] Whether the invite is unique or not + * Delete a guild emoji object + * @arg {String} guildID The ID of the guild to delete the emoji in + * @arg {String} emojiID The ID of the emoji * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {Promise} */ - createChannelInvite(channelID, options = {}, reason) { - return this.requestHandler.request("POST", Endpoints.CHANNEL_INVITES(channelID), true, { - max_age: options.maxAge, - max_uses: options.maxUses, - temporary: options.temporary, - unique: options.unique, - reason: reason - }).then((invite) => new Invite(invite, this)); + deleteGuildEmoji(guildID, emojiID, reason) { + return this.requestHandler.request("DELETE", Endpoints.GUILD_EMOJI(guildID, emojiID), true, { + reason + }); } /** - * Get all the webhooks in a channel - * @arg {String} channelID The ID of the channel to get webhooks for - * @returns {Promise} Resolves with an array of webhook objects + * Delete a guild integration + * @arg {String} guildID The ID of the guild + * @arg {String} integrationID The ID of the integration + * @returns {Promise} */ - getChannelWebhooks(channelID) { - return this.requestHandler.request("GET", Endpoints.CHANNEL_WEBHOOKS(channelID), true); + deleteGuildIntegration(guildID, integrationID) { + return this.requestHandler.request("DELETE", Endpoints.GUILD_INTEGRATION(guildID, integrationID), true); } /** - * Get a webhook - * @arg {String} webhookID The ID of the webhook - * @arg {String} [token] The token of the webhook, used instead of the Bot Authorization token - * @returns {Promise} Resolves with a webhook object + * Delete an invite + * @arg {String} inviteID The ID of the invite + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getWebhook(webhookID, token) { - return this.requestHandler.request("GET", token ? Endpoints.WEBHOOK_TOKEN(webhookID, token) : Endpoints.WEBHOOK(webhookID), !token); + deleteInvite(inviteID, reason) { + return this.requestHandler.request("DELETE", Endpoints.INVITE(inviteID), true, { + reason + }); } /** - * Create a channel webhook - * @arg {String} channelID The ID of the channel to create the webhook in - * @arg {Object} options Webhook options - * @arg {String} options.name The default name - * @arg {String} options.avatar The default avatar as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * Delete a message + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} Resolves with a webhook object + * @returns {Promise} */ - createChannelWebhook(channelID, options, reason) { - options.reason = reason; - return this.requestHandler.request("POST", Endpoints.CHANNEL_WEBHOOKS(channelID), true, options); + deleteMessage(channelID, messageID, reason) { + return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE(channelID, messageID), true, { + reason + }); } /** - * Edit a webhook - * @arg {String} webhookID The ID of the webhook - * @arg {Object} options Webhook options - * @arg {String} [options.name] The new default name - * @arg {String} [options.avatar] The new default avatar as a base64 data URI. Note: base64 strings alone are not base64 data URI strings - * @arg {String} [token] The token of the webhook, used instead of the Bot Authorization token + * Bulk delete messages (bot accounts only) + * @arg {String} channelID The ID of the channel + * @arg {String[]} messageIDs Array of message IDs to delete * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} Resolves with a webhook object + * @returns {Promise} */ - editWebhook(webhookID, options, token, reason) { - options.reason = reason; - return this.requestHandler.request("PATCH", token ? Endpoints.WEBHOOK_TOKEN(webhookID, token) : Endpoints.WEBHOOK(webhookID), !token, options); - } + deleteMessages(channelID, messageIDs, reason) { + if(messageIDs.length === 0) { + return Promise.resolve(); + } + if(messageIDs.length === 1) { + return this.deleteMessage(channelID, messageIDs[0]); + } - /** - * Execute a webhook - * @arg {String} webhookID The ID of the webhook - * @arg {String} token The token of the webhook - * @arg {Object} options Webhook execution options - * @arg {Object} [options.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [options.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [options.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [options.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Boolean} [options.auth=false] Whether or not to authorize the request with the bot token (allowing custom emotes from other guilds) - * @arg {String} [options.avatarURL] A URL for a custom avatar, defaults to webhook default avatar if not specified - * @arg {String} [options.content=""] A content string - * @arg {Object[]} [options.embeds] An array of Discord embeds - * @arg {Object | Object[]} [options.file] A file object (or an Array of them) - * @arg {Buffer} options.file.file A buffer containing file data - * @arg {String} options.file.name What to name the file - * @arg {Boolean} [options.tts=false] Whether the message should be a TTS message or not - * @arg {String} [options.username] A custom username, defaults to webhook default username if not specified - * @arg {Boolean} [options.wait=false] Whether to wait for the server to confirm the message create or not - * @returns {Promise} - */ - executeWebhook(webhookID, token, options) { - if(!options.content && !options.file && !options.embeds) { - return Promise.reject(new Error("No content, file, or embeds")); + const oldestAllowedSnowflake = (Date.now() - 1421280000000) * 4194304; + const invalidMessage = messageIDs.find((messageID) => messageID < oldestAllowedSnowflake); + if(invalidMessage) { + return Promise.reject(new Error(`Message ${invalidMessage} is more than 2 weeks old.`)); } - return this.requestHandler.request("POST", Endpoints.WEBHOOK_TOKEN(webhookID, token) + (options.wait ? "?wait=true" : ""), !!options.auth, { - content: options.content, - embeds: options.embeds, - username: options.username, - avatar_url: options.avatarURL, - tts: options.tts, - allowed_mentions: this._formatAllowedMentions(options.allowedMentions) - }, options.file).then((response) => options.wait ? new Message(response, this) : undefined); + + if(messageIDs.length > 100) { + return this.requestHandler.request("POST", Endpoints.CHANNEL_BULK_DELETE(channelID), true, { + messages: messageIDs.splice(0, 100), + reason: reason + }).then(() => this.deleteMessages(channelID, messageIDs)); + } + return this.requestHandler.request("POST", Endpoints.CHANNEL_BULK_DELETE(channelID), true, { + messages: messageIDs, + reason: reason + }); } /** - * Execute a slack-style webhook - * @arg {String} webhookID The ID of the webhook - * @arg {String} token The token of the webhook - * @arg {Object} options Slack webhook options - * @arg {Boolean} [options.auth=false] Whether or not to authorize the request with the bot token (allowing custom emotes from other guilds) - * @arg {Boolean} [options.wait=false] Whether to wait for the server to confirm the message create or not + * Delete a guild role + * @arg {String} guildID The ID of the guild to create the role in + * @arg {String} roleID The ID of the role + * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - executeSlackWebhook(webhookID, token, options) { - const wait = !!options.wait; - options.wait = undefined; - const auth = !!options.auth; - options.auth = undefined; - return this.requestHandler.request("POST", Endpoints.WEBHOOK_TOKEN_SLACK(webhookID, token) + (wait ? "?wait=true" : ""), auth, options); + deleteRole(guildID, roleID, reason) { + return this.requestHandler.request("DELETE", Endpoints.GUILD_ROLE(guildID, roleID), true, { + reason + }); } /** - * Delete a webhook - * @arg {String} webhookID The ID of the webhook - * @arg {String} [token] The token of the webhook, used instead of the Bot Authorization token - * @arg {String} [reason] The reason to be displayed in audit logs + * [USER ACCOUNT] Delete a connection for the current user + * @arg {String} platform The connection platform (e.g. "twitch", "reddit") + * @arg {String} id The connection ID * @returns {Promise} */ - deleteWebhook(webhookID, token, reason) { - return this.requestHandler.request("DELETE", token ? Endpoints.WEBHOOK_TOKEN(webhookID, token) : Endpoints.WEBHOOK(webhookID), !token, { - reason - }); + deleteSelfConnection(platform, id) { + return this.requestHandler.request("DELETE", Endpoints.USER_CONNECTION_PLATFORM("@me", platform, id), true); } /** - * Get all the webhooks in a guild - * @arg {String} guildID The ID of the guild to get webhooks for - * @returns {Promise} Resolves with an array of webhook objects + * [USER ACCOUNT] Cancel the premium subscription (Nitro) for the current user + * @returns {Promise} */ - getGuildWebhooks(guildID) { - return this.requestHandler.request("GET", Endpoints.GUILD_WEBHOOKS(guildID), true); + deleteSelfPremiumSubscription() { + return this.requestHandler.request("DELETE", Endpoints.USER_BILLING_PREMIUM_SUBSCRIPTION("@me"), true); } /** - * Get the audit logs for a guild - * @arg {String} guildID The ID of the guild to get audit logs for - * @arg {Number} [limit=50] The maximum number of entries to return - * @arg {String} [before] Get entries before this entry ID - * @arg {Number} [actionType] Filter entries by action type - * @returns {Promise} Resolves with {users: Users[], entries: GuildAuditLogEntry[]} + * [USER ACCOUNT] Delete the current user's note for another user + * @returns {Promise} */ - getGuildAuditLogs(guildID, limit, before, actionType) { - return this.requestHandler.request("GET", Endpoints.GUILD_AUDIT_LOGS(guildID), true, { - limit: limit || 50, - before: before, - action_type: actionType - }).then((data) => { - const guild = this.guilds.get(guildID); - return { - users: data.users.map((user) => this.users.add(user, this)), - entries: data.audit_log_entries.map((entry) => new GuildAuditLogEntry(entry, guild)) - }; - }); + deleteUserNote(userID) { + return this.requestHandler.request("DELETE", Endpoints.USER_NOTE("@me", userID), true); } /** - * Create a guild emoji object - * @arg {String} guildID The ID of the guild to create the emoji in - * @arg {Object} options Emoji options - * @arg {String} options.image The base 64 encoded string - * @arg {String} options.name The name of emoji - * @arg {Array} [options.roles] An array containing authorized role IDs + * Delete a webhook + * @arg {String} webhookID The ID of the webhook + * @arg {String} [token] The token of the webhook, used instead of the Bot Authorization token * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} A guild emoji object + * @returns {Promise} */ - createGuildEmoji(guildID, options, reason) { - options.reason = reason; - return this.requestHandler.request("POST", Endpoints.GUILD_EMOJIS(guildID), true, options); + deleteWebhook(webhookID, token, reason) { + return this.requestHandler.request("DELETE", token ? Endpoints.WEBHOOK_TOKEN(webhookID, token) : Endpoints.WEBHOOK(webhookID), !token, { + reason + }); } /** - * Edit a guild emoji object - * @arg {String} guildID The ID of the guild to edit the emoji in - * @arg {String} emojiID The ID of the emoji you want to modify - * @arg {Object} options Emoji options - * @arg {String} [options.name] The name of emoji - * @arg {Array} [options.roles] An array containing authorized role IDs - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} A guild emoji object + * [USER ACCOUNT] Disable TOTP authentication for the current user + * @arg {String} code The timed auth code for the current user + * @returns {Promise} An object containing the user's new authorization token */ - editGuildEmoji(guildID, emojiID, options, reason) { - options.reason = reason; - return this.requestHandler.request("PATCH", Endpoints.GUILD_EMOJI(guildID, emojiID), true, options); + disableSelfMFATOTP(code) { + return this.requestHandler.request("POST", Endpoints.USER_MFA_TOTP_DISABLE("@me"), true, { + code + }).then((data) => { + if(data.token) { + this.token = data.token; + } + }); } /** - * Delete a guild emoji object - * @arg {String} guildID The ID of the guild to delete the emoji in - * @arg {String} emojiID The ID of the emoji - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Update the bot's AFK status. Setting this to true will enable push notifications for userbots. + * @arg {Boolean} afk Whether the bot user is AFK or not */ - deleteGuildEmoji(guildID, emojiID, reason) { - return this.requestHandler.request("DELETE", Endpoints.GUILD_EMOJI(guildID, emojiID), true, { - reason + editAFK(afk) { + this.presence.afk = !!afk; + + this.shards.forEach((shard) => { + shard.editAFK(afk); }); } /** - * Create a guild role - * @arg {String} guildID The ID of the guild to create the role in - * @arg {Object|Role} [options] An object or Role containing the properties to set - * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3d15b3 or 4040115) - * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not - * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not - * @arg {String} [options.name] The name of the role - * @arg {Number} [options.permissions] The role permissions number + * Edit a channel's properties + * @arg {String} channelID The ID of the channel + * @arg {Object} options The properties to edit + * @arg {Number} [options.bitrate] The bitrate of the channel (guild voice channels only) + * @arg {String} [options.icon] The icon of the channel as a base64 data URI (group channels only). Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.name] The name of the channel + * @arg {Boolean} [options.nsfw] The nsfw status of the channel (guild channels only) + * @arg {String} [options.ownerID] The ID of the channel owner (group channels only) + * @arg {String?} [options.parentID] The ID of the parent channel category for this channel (guild text/voice channels only) + * @arg {Number} [options.rateLimitPerUser] The time in seconds a user has to wait before sending another message (does not affect bots or users with manageMessages/manageChannel permissions) (guild text channels only) + * @arg {String} [options.topic] The topic of the channel (guild text channels only) + * @arg {Number} [options.userLimit] The channel user limit (guild voice channels only) * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {Promise} */ - createRole(guildID, options, reason) { - return this.requestHandler.request("POST", Endpoints.GUILD_ROLES(guildID), true, { + editChannel(channelID, options, reason) { + return this.requestHandler.request("PATCH", Endpoints.CHANNEL(channelID), true, { + bitrate: options.bitrate, + icon: options.icon, name: options.name, - permissions: options.permissions instanceof Permission ? options.permissions.allow : options.permissions, - color: options.color, - hoist: options.hoist, - mentionable: options.mentionable, + nsfw: options.nsfw, + owner_id: options.ownerID, + parent_id: options.parentID, + rate_limit_per_user: options.rateLimitPerUser, + topic: options.topic, + user_limit: options.userLimit, reason: reason - }).then((role) => { - const guild = this.guilds.get(guildID); - if(guild) { - return guild.roles.add(role, guild); - } else { - return new Role(role); - } - }); + }).then((channel) => Channel.from(channel, this)); } /** - * Edit a guild role - * @arg {String} guildID The ID of the guild the role is in - * @arg {String} roleID The ID of the role - * @arg {Object} options The properties to edit - * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3da5b3 or 4040115) - * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not - * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not - * @arg {String} [options.name] The name of the role - * @arg {Number} [options.permissions] The role permissions number + * Create a channel permission overwrite + * @arg {String} channelID The ID of channel + * @arg {String} overwriteID The ID of the overwritten user or role (everyone role ID = guild ID) + * @arg {Number} allow The permissions number for allowed permissions + * @arg {Number} deny The permissions number for denied permissions + * @arg {String} type The object type of the overwrite, either "member" or "role" * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {Promise} */ - editRole(guildID, roleID, options, reason) { - options.reason = reason; - return this.requestHandler.request("PATCH", Endpoints.GUILD_ROLE(guildID, roleID), true, options).then((role) => new Role(role, this.guilds.get(guildID))); + editChannelPermission(channelID, overwriteID, allow, deny, type, reason) { + return this.requestHandler.request("PUT", Endpoints.CHANNEL_PERMISSION(channelID, overwriteID), true, { + allow, + deny, + type, + reason + }); } /** - * Edit a guild role's position. Note that role position numbers are highest on top and lowest at the bottom. - * @arg {String} guildID The ID of the guild the role is in - * @arg {String} roleID The ID of the role - * @arg {Number} position The new position of the role + * Edit a guild channel's position. Note that channel position numbers are lowest on top and highest at the bottom. + * @arg {String} channelID The ID of the channel + * @arg {Number} position The new position of the channel * @returns {Promise} */ - editRolePosition(guildID, roleID, position) { - if(guildID === roleID) { - return Promise.reject(new Error("Cannot move default role")); - } - let roles = this.guilds.get(guildID).roles; - const role = roles.get(roleID); - if(!role) { - return Promise.reject(new Error(`Role ${roleID} not found`)); + editChannelPosition(channelID, position) { + let channels = this.guilds.get(this.channelGuildMap[channelID]).channels; + const channel = channels.get(channelID); + if(!channel) { + return Promise.reject(new Error(`Channel ${channelID} not found`)); } - if(role.position === position) { + if(channel.position === position) { return Promise.resolve(); } - const min = Math.min(position, role.position); - const max = Math.max(position, role.position); - roles = roles.filter((role) => min <= role.position && role.position <= max && role.id !== roleID).sort((a, b) => a.position - b.position); - if(position > role.position) { - roles.push(role); + const min = Math.min(position, channel.position); + const max = Math.max(position, channel.position); + channels = channels.filter((chan) => { + return chan.type === channel.type + && min <= chan.position + && chan.position <= max + && chan.id !== channelID; + }).sort((a, b) => a.position - b.position); + if(position > channel.position) { + channels.push(channel); } else { - roles.unshift(role); + channels.unshift(channel); } - return this.requestHandler.request("PATCH", Endpoints.GUILD_ROLES(guildID), true, roles.map((role, index) => ({ - id: role.id, + return this.requestHandler.request("PATCH", Endpoints.GUILD_CHANNELS(this.channelGuildMap[channelID]), true, channels.map((channel, index) => ({ + id: channel.id, position: index + min }))); } /** - * Delete a guild role - * @arg {String} guildID The ID of the guild to create the role in - * @arg {String} roleID The ID of the role + * Edit a guild + * @arg {String} guildID The ID of the guild + * @arg {Object} options The properties to edit + * @arg {String} [options.afkChannelID] The ID of the AFK voice channel + * @arg {Number} [options.afkTimeout] The AFK timeout in seconds + * @arg {String} [options.banner] The guild banner image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings + * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". + * @arg {String} [options.description] The description for the guild (VIP only) + * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. + * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.name] The ID of the guild + * @arg {String} [options.ownerID] The ID of the user to transfer server ownership to (bot user must be owner) + * @arg {String} [options.preferredLocale] Preferred "PUBLIC" guild language used in server discovery and notices from Discord + * @arg {String} [options.publicUpdatesChannelID] The id of the channel where admins and moderators of "PUBLIC" guilds receive notices from Discord + * @arg {String} [options.region] The region of the guild + * @arg {String} [options.rulesChannelID] The id of the channel where "PUBLIC" guilds display rules and/or guidelines + * @arg {String} [options.splash] The guild splash image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.systemChannelID] The ID of the system channel + * @arg {Number} [options.verificationLevel] The guild verification level * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {Promise} */ - deleteRole(guildID, roleID, reason) { - return this.requestHandler.request("DELETE", Endpoints.GUILD_ROLE(guildID, roleID), true, { - reason - }); + editGuild(guildID, options, reason) { + return this.requestHandler.request("PATCH", Endpoints.GUILD(guildID), true, { + name: options.name, + region: options.region, + icon: options.icon, + verification_level: options.verificationLevel, + default_message_notifications: options.defaultNotifications, + explicit_content_filter: options.explicitContentFilter, + system_channel_id: options.systemChannelID, + rules_channel_id: options.rulesChannelID, + public_updates_channel_id: options.publicUpdatesChannelID, + preferred_locale: options.preferredLocale, + afk_channel_id: options.afkChannelID, + afk_timeout: options.afkTimeout, + owner_id: options.ownerID, + splash: options.splash, + banner: options.banner, + description: options.description, + reason: reason + }).then((guild) => new Guild(guild, this)); } /** - * Get the prune count for a guild - * @arg {String} guildID The ID of the guild - * @arg {Number} [options] The options to use to get number of prune members - * @arg {Number} [options.days=7] The number of days of inactivity to prune for - * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning - * @returns {Promise} Resolves with the number of members that would be pruned + * Edit a guild emoji object + * @arg {String} guildID The ID of the guild to edit the emoji in + * @arg {String} emojiID The ID of the emoji you want to modify + * @arg {Object} options Emoji options + * @arg {String} [options.name] The name of emoji + * @arg {Array} [options.roles] An array containing authorized role IDs + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} A guild emoji object */ - getPruneCount(guildID, options = {}) { - return this.requestHandler.request("GET", Endpoints.GUILD_PRUNE(guildID), true, { - days: options.days, - include_roles: options.includeRoles - }).then((data) => data.pruned); + editGuildEmoji(guildID, emojiID, options, reason) { + options.reason = reason; + return this.requestHandler.request("PATCH", Endpoints.GUILD_EMOJI(guildID, emojiID), true, options); } /** - * Begin pruning a guild + * Edit a guild integration * @arg {String} guildID The ID of the guild - * @arg {Number} [options] The options to pass to prune members - * @arg {Boolean} [options.computePruneCount=true] Whether or not the number of pruned members should be returned. Discord discourages setting this to true for larger guilds - * @arg {Number} [options.days=7] The number of days of inactivity to prune for - * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning - * @arg {String} [options.reason] The reason to be displayed in audit logs - * @returns {Promise} If computePruneCount was true, resolves with the number of pruned members + * @arg {String} integrationID The ID of the integration + * @arg {Object} options The properties to edit + * @arg {String} [options.enableEmoticons] Whether to enable integration emoticons or not + * @arg {String} [options.expireBehavior] What to do when a user's subscription runs out + * @arg {String} [options.expireGracePeriod] How long before the integration's role is removed from an unsubscribed user + * @returns {Promise} */ - pruneMembers(guildID, options = {}) { - return this.requestHandler.request("POST", Endpoints.GUILD_PRUNE(guildID), true, { - days: options.days, - compute_prune_count: options.computePruneCount, - include_roles: options.includeRoles, - reason: options.reason - }).then((data) => data.pruned); + editGuildIntegration(guildID, integrationID, options) { + return this.requestHandler.request("PATCH", Endpoints.GUILD_INTEGRATION(guildID, integrationID), true, { + expire_behavior: options.expireBehavior, + expire_grace_period: options.expireGracePeriod, + enable_emoticons: options.enableEmoticons + }); } /** - * Get a list of general/guild-specific voice regions - * @arg {String} [guildID] The ID of the guild - * @returns {Promise} Resolves with an array of voice region objects + * Edit a guild member + * @arg {String} guildID The ID of the guild + * @arg {String} memberID The ID of the member + * @arg {Object} options The properties to edit + * @arg {String} [options.channelID] The ID of the voice channel to move the member to (must be in voice) + * @arg {Boolean} [options.deaf] Server deafen the member + * @arg {Boolean} [options.mute] Server mute the member + * @arg {String} [options.nick] Set the member's server nickname, "" to remove + * @arg {String[]} [options.roles] The array of role IDs the member should have + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getVoiceRegions(guildID) { - return guildID ? this.requestHandler.request("GET", Endpoints.GUILD_VOICE_REGIONS(guildID), true) : this.requestHandler.request("GET", Endpoints.VOICE_REGIONS, true); + editGuildMember(guildID, memberID, options, reason) { + return this.requestHandler.request("PATCH", Endpoints.GUILD_MEMBER(guildID, memberID), true, { + roles: options.roles && options.roles.filter((roleID, index) => options.roles.indexOf(roleID) === index), + nick: options.nick, + mute: options.mute, + deaf: options.deaf, + channel_id: options.channelID, + reason: reason + }); } /** - * Get info on an invite - * @arg {String} inviteID The ID of the invite - * @arg {Boolean} [withCounts] Whether to fetch additional invite info or not (approximate member counts, approximate presences, channel counts, etc.) - * @returns {Promise} + * Modify a guild's widget + * @arg {String} guildID The ID of the guild + * @arg {Object} options The widget object to modify (https://discord.com/developers/docs/resources/guild#modify-guild-widget) + * @returns {Promise} A guild widget object */ - getInvite(inviteID, withCounts) { - return this.requestHandler.request("GET", Endpoints.INVITE(inviteID), true, { - with_counts: withCounts - }).then((invite) => new Invite(invite, this)); + editGuildWidget(guildID, options) { + return this.requestHandler.request("PATCH", Endpoints.GUILD_WIDGET(guildID), true, options); } /** - * [USER ACCOUNT] Accept an invite - * @arg {String} inviteID The ID of the invite - * @returns {Promise} + * Edit a message + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: + * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) + * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. + * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. + * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {String} content.content A content string + * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference + * @returns {Promise} */ - acceptInvite(inviteID) { - return this.requestHandler.request("POST", Endpoints.INVITE(inviteID), true).then((invite) => new Invite(invite, this)); + editMessage(channelID, messageID, content) { + if(content !== undefined) { + if(typeof content !== "object" || content === null) { + content = { + content: "" + content + }; + } else if(content.content !== undefined && typeof content.content !== "string") { + content.content = "" + content.content; + } else if(content.content === undefined && !content.embed && content.flags === undefined) { + return Promise.reject(new Error("No content, embed or flags")); + } + content.allowed_mentions = this._formatAllowedMentions(content.allowedMentions); + } + return this.requestHandler.request("PATCH", Endpoints.CHANNEL_MESSAGE(channelID, messageID), true, content).then((message) => new Message(message, this)); } /** - * Delete an invite - * @arg {String} inviteID The ID of the invite + * Edit the bot's nickname in a guild + * @arg {String} guildID The ID of the guild + * @arg {String} nick The nickname * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - deleteInvite(inviteID, reason) { - return this.requestHandler.request("DELETE", Endpoints.INVITE(inviteID), true, { + editNickname(guildID, nick, reason) { + return this.requestHandler.request("PATCH", Endpoints.GUILD_MEMBER_NICK(guildID, "@me"), true, { + nick, reason }); } /** - * Get properties of the bot user - * @returns {Promise} + * Edit a guild role + * @arg {String} guildID The ID of the guild the role is in + * @arg {String} roleID The ID of the role + * @arg {Object} options The properties to edit + * @arg {Number} [options.color] The hex color of the role, in number form (ex: 0x3da5b3 or 4040115) + * @arg {Boolean} [options.hoist] Whether to hoist the role in the user list or not + * @arg {Boolean} [options.mentionable] Whether the role is mentionable or not + * @arg {String} [options.name] The name of the role + * @arg {Number} [options.permissions] The role permissions number + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getSelf() { - return this.requestHandler.request("GET", Endpoints.USER("@me"), true).then((data) => new ExtendedUser(data, this)); + editRole(guildID, roleID, options, reason) { + options.reason = reason; + return this.requestHandler.request("PATCH", Endpoints.GUILD_ROLE(guildID, roleID), true, options).then((role) => new Role(role, this.guilds.get(guildID))); + } + + /** + * Edit a guild role's position. Note that role position numbers are highest on top and lowest at the bottom. + * @arg {String} guildID The ID of the guild the role is in + * @arg {String} roleID The ID of the role + * @arg {Number} position The new position of the role + * @returns {Promise} + */ + editRolePosition(guildID, roleID, position) { + if(guildID === roleID) { + return Promise.reject(new Error("Cannot move default role")); + } + let roles = this.guilds.get(guildID).roles; + const role = roles.get(roleID); + if(!role) { + return Promise.reject(new Error(`Role ${roleID} not found`)); + } + if(role.position === position) { + return Promise.resolve(); + } + const min = Math.min(position, role.position); + const max = Math.max(position, role.position); + roles = roles.filter((role) => min <= role.position && role.position <= max && role.id !== roleID).sort((a, b) => a.position - b.position); + if(position > role.position) { + roles.push(role); + } else { + roles.unshift(role); + } + return this.requestHandler.request("PATCH", Endpoints.GUILD_ROLES(guildID), true, roles.map((role, index) => ({ + id: role.id, + position: index + min + }))); } /** @@ -970,475 +1097,344 @@ class Client extends EventEmitter { } /** - * Get a DM channel with a user, or create one if it does not exist - * @arg {String} userID The ID of the user - * @returns {Promise} + * [USER ACCOUNT] Edit a connection for the current user + * @arg {String} platform The connection platform (e.g. "twitch", "reddit") + * @arg {String} id The connection ID + * @arg {Object} data The connection data + * @arg {Boolean} [data.friendSync] Whether to sync friends from the connection or not + * @arg {Number} [data.visibility] The visibility level for the connection. 0 = hidden, 1 = shown on profile + * @returns {Promise} The updated connection data */ - getDMChannel(userID) { - if(this.privateChannelMap[userID]) { - return Promise.resolve(this.privateChannels.get(this.privateChannelMap[userID])); - } - return this.requestHandler.request("POST", Endpoints.USER_CHANNELS("@me"), true, { - recipients: [userID], - type: 1 - }).then((privateChannel) => new PrivateChannel(privateChannel, this)); - } - - /** - * [USER ACCOUNT] Create a group channel with other users - * @arg {String[]} userIDs The IDs of the other users - * @returns {Promise} - */ - createGroupChannel(userIDs) { - return this.requestHandler.request("POST", Endpoints.USER_CHANNELS("@me"), true, { - recipients: userIDs, - type: 3 - }).then((privateChannel) => new GroupChannel(privateChannel, this)); - } - - /** - * Get a previous message in a channel - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @returns {Promise} - */ - getMessage(channelID, messageID) { - return this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGE(channelID, messageID), true).then((message) => new Message(message, this)); - } - - /** - * Get previous messages in a channel - * @arg {String} channelID The ID of the channel - * @arg {Number} [limit=50] The max number of messages to get - * @arg {String} [before] Get messages before this message ID - * @arg {String} [after] Get messages after this message ID - * @arg {String} [around] Get messages around this message ID (does not work with limit > 100) - * @returns {Promise} - */ - async getMessages(channelID, limit = 50, before, after, around) { - if(limit && limit > 100) { - let logs = []; - const get = async (_before, _after) => { - const messages = await this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGES(channelID), true, { - limit: 100, - before: _before || undefined, - after: _after || undefined - }); - if(limit <= messages.length) { - return (_after ? messages.slice(messages.length - limit, messages.length).map((message) => new Message(message, this)).concat(logs) : logs.concat(messages.slice(0, limit).map((message) => new Message(message, this)))); - } - limit -= messages.length; - logs = (_after ? messages.map((message) => new Message(message, this)).concat(logs) : logs.concat(messages.map((message) => new Message(message, this)))); - if(messages.length < 100) { - return logs; - } - this.emit("debug", `Getting ${limit} more messages during getMessages for ${channelID}: ${_before} ${_after}`, -1); - return get((_before || !_after) && messages[messages.length - 1].id, _after && messages[0].id); - }; - return get(before, after); - } - const messages = await this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGES(channelID), true, { - limit, - before, - after, - around - }); - return messages.map((message) => { - try { - return new Message(message, this); - } catch(err) { - this.emit("error", `Error creating message from channel messages\n${err.stack}\n${JSON.stringify(messages)}`); - return null; - } + editSelfConnection(platform, id, data) { + return this.requestHandler.request("PATCH", Endpoints.USER_CONNECTION_PLATFORM("@me", platform, id), true, { + visibility: data.visibility, + friend_sync: data.friendSync }); } /** - * Get all the pins in a channel - * @arg {String} channelID The ID of the channel - * @returns {Promise} - */ - getPins(channelID) { - return this.requestHandler.request("GET", Endpoints.CHANNEL_PINS(channelID), true).then((messages) => messages.map((message) => new Message(message, this))); - } - - /** - * Create a message in a channel - * Note: If you want to DM someone, the user ID is **not** the DM channel ID. use Client.getDMChannel() to get the DM channel for a user - * @arg {String} channelID The ID of the channel - * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {String} content.content A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [content.tts] Set the message TTS flag - * @arg {Object | Object[]} [file] A file object (or an Array of them) - * @arg {Buffer} file.file A buffer containing file data - * @arg {String} file.name What to name the file - * @returns {Promise} + * [USER ACCOUNT] Edit settings for the current user + * @arg {Object} data The user settings data + * @arg {Boolean} [data.convertEmoticons] Whether to convert emoticons or not (e.g. :D => 😄) + * @arg {Boolean} [data.detectPlatformAccounts] Whether to automatically detect accounts from other platforms or not (Blizzard, Skype, etc.) + * @arg {Boolean} [data.developerMode] Whether to enable developer mode or not + * @arg {Boolean} [data.enableTTSCommand] Whether to respect usage of the TTS command or not + * @arg {Object} [data.friendSourceFlags] An object representing allowed friend request sources + * @arg {Boolean} [data.friendSourceFlags.all] Whether to allow friends requests from anywhere or not + * @arg {Boolean} [data.friendSourceFlags.mutualFriends] Whether to allow friend requests from people with mutual friends or not + * @arg {Boolean} [data.friendSourceFlags.mutualGuilds] Whether to allow friend requests from people in mutual guilds or not + * @arg {Array} [data.guildPositions] An ordered array of guild IDs representing the guild list order in the Discord client + * @arg {Boolean} [data.inlineAttachmentMedia] Whether to show attachment previews or not + * @arg {Boolean} [data.inlineEmbedMedia] Whether to show embed images or not + * @arg {String} [data.locale] The locale to use for the Discord UI + * @arg {Boolean} [data.messageDisplayCompact] Whether to use compact mode or not + * @arg {Boolean} [data.renderEmbeds] Whether to show embeds or not + * @arg {Boolean} [data.renderReactions] Whether to show reactions or not + * @arg {Array} [data.restrictedGuilds] An array of guild IDs where direct messages from guild members are disallowed + * @arg {Boolean} [data.showCurrentGame] Whether to set the user's status to the current game or not + * @arg {String} [data.status] The status of the user, either "invisible", "dnd", "away", or "online" + * @arg {String} [data.theme] The theme to use for the Discord UI, either "dark" or "light" + * @returns {Promise} The user's settings data. */ - createMessage(channelID, content, file) { - if(content !== undefined) { - if(typeof content !== "object" || content === null) { - content = { - content: "" + content - }; - } else if(content.content !== undefined && typeof content.content !== "string") { - content.content = "" + content.content; - } else if(content.content === undefined && !content.embed && !file) { - return Promise.reject(new Error("No content, file, or embed")); + editSelfSettings(data) { + let friendSourceFlags = undefined; + if(data.friendSourceFlags) { + friendSourceFlags = {}; + if(data.friendSourceFlags.all) { + friendSourceFlags.all = true; + } + if(data.friendSourceFlags.mutualFriends) { + friendSourceFlags.mutual_friends = true; + } + if(data.friendSourceFlags.mutualGuilds) { + friendSourceFlags.mutual_guilds = true; } - content.allowed_mentions = this._formatAllowedMentions(content.allowedMentions); - } else if(!file) { - return Promise.reject(new Error("No content, file, or embed")); } - return this.requestHandler.request("POST", Endpoints.CHANNEL_MESSAGES(channelID), true, content, file).then((message) => new Message(message, this)); + return this.requestHandler.request("PATCH", Endpoints.USER_SETTINGS("@me"), true, { + convert_emoticons: data.convertEmoticons, + detect_platform_accounts: data.detectPlatformAccounts, + developer_mode: data.developerMode, + enable_tts_command: data.enableTTSCommand, + friend_source_flags: friendSourceFlags, + guild_positions: data.guildPositions, + inline_attachment_media: data.inlineAttachmentMedia, + inline_embed_media: data.inlineEmbedMedia, + locale: data.locale, + message_display_compact: data.messageDisplayCompact, + render_embeds: data.renderEmbeds, + render_reactions: data.renderReactions, + restricted_guilds: data.restrictedGuilds, + show_current_game: data.showCurrentGame, + status: data.status, + theme: data.theme + }); } /** - * Edit a message - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed: - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {String} content.content A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discordapp.com/developers/docs/resources/channel#message-object-message-flags) for flags reference - * @returns {Promise} + * Update the bot's status on all guilds + * @arg {String} [status] Sets the bot's status, either "online", "idle", "dnd", or "invisible" + * @arg {Object} [game] Sets the bot's active game, null to clear + * @arg {String} game.name Sets the name of the bot's active game + * @arg {Number} [game.type] The type of game. 0 is playing, 1 is streaming (Twitch only), 2 is listening, 3 is watching + * @arg {String} [game.url] Sets the url of the shard's active game */ - editMessage(channelID, messageID, content) { - if(content !== undefined) { - if(typeof content !== "object" || content === null) { - content = { - content: "" + content - }; - } else if(content.content !== undefined && typeof content.content !== "string") { - content.content = "" + content.content; - } else if(content.content === undefined && !content.embed && content.flags === undefined) { - return Promise.reject(new Error("No content, embed or flags")); - } - content.allowed_mentions = this._formatAllowedMentions(content.allowedMentions); + editStatus(status, game) { + if(game === undefined && typeof status === "object") { + game = status; + status = undefined; } - return this.requestHandler.request("PATCH", Endpoints.CHANNEL_MESSAGE(channelID, messageID), true, content).then((message) => new Message(message, this)); + if(status) { + this.presence.status = status; + } + if(game !== undefined) { + this.presence.game = game; + } + + this.shards.forEach((shard) => { + shard.editStatus(status, game); + }); } /** - * Pin a message - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message + * [USER ACCOUNT] Edit the current user's note for another user + * @arg {String} userID The ID of the target user + * @arg {String} note The note * @returns {Promise} */ - pinMessage(channelID, messageID) { - return this.requestHandler.request("PUT", Endpoints.CHANNEL_PIN(channelID, messageID), true); + editUserNote(userID, note) { + return this.requestHandler.request("PUT", Endpoints.USER_NOTE("@me", userID), true, { + note + }); } /** - * Unpin a message - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @returns {Promise} + * Edit a webhook + * @arg {String} webhookID The ID of the webhook + * @arg {Object} options Webhook options + * @arg {String} [options.name] The new default name + * @arg {String} [options.avatar] The new default avatar as a base64 data URI. Note: base64 strings alone are not base64 data URI strings + * @arg {String} [token] The token of the webhook, used instead of the Bot Authorization token + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} Resolves with a webhook object */ - unpinMessage(channelID, messageID) { - return this.requestHandler.request("DELETE", Endpoints.CHANNEL_PIN(channelID, messageID), true); + editWebhook(webhookID, options, token, reason) { + options.reason = reason; + return this.requestHandler.request("PATCH", token ? Endpoints.WEBHOOK_TOKEN(webhookID, token) : Endpoints.WEBHOOK(webhookID), !token, options); } /** - * Get a list of users who reacted with a specific reaction - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {Number} [limit=100] The maximum number of users to get - * @arg {String} [before] Get users before this user ID - * @arg {String} [after] Get users after this user ID - * @returns {Promise} + * [USER ACCOUNT] Enable TOTP authentication for the current user + * @arg {String} secret The TOTP secret used to generate the auth code + * @arg {String} code The timed auth code for the current user + * @returns {Promise} An object containing the user's new authorization token and backup codes */ - getMessageReaction(channelID, messageID, reaction, limit, before, after) { - if(reaction === decodeURI(reaction)) { - reaction = encodeURIComponent(reaction); - } - return this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGE_REACTION(channelID, messageID, reaction), true, { - limit: limit || 100, - before: before, - after: after - }).then((users) => users.map((user) => new User(user, this))); + enableSelfMFATOTP(secret, code) { + return this.requestHandler.request("POST", Endpoints.USER_MFA_TOTP_ENABLE("@me"), true, { + secret, + code + }).then((data) => { + if(data.token) { + this.token = data.token; + } + }); } /** - * Add a reaction to a message - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {String} [userID="@me"] The ID of the user to react as + * Execute a slack-style webhook + * @arg {String} webhookID The ID of the webhook + * @arg {String} token The token of the webhook + * @arg {Object} options Slack webhook options + * @arg {Boolean} [options.auth=false] Whether or not to authorize the request with the bot token (allowing custom emotes from other guilds) + * @arg {Boolean} [options.wait=false] Whether to wait for the server to confirm the message create or not * @returns {Promise} */ - addMessageReaction(channelID, messageID, reaction, userID) { - if(reaction === decodeURI(reaction)) { - reaction = encodeURIComponent(reaction); - } - return this.requestHandler.request("PUT", Endpoints.CHANNEL_MESSAGE_REACTION_USER(channelID, messageID, reaction, userID || "@me"), true); + executeSlackWebhook(webhookID, token, options) { + const wait = !!options.wait; + options.wait = undefined; + const auth = !!options.auth; + options.auth = undefined; + return this.requestHandler.request("POST", Endpoints.WEBHOOK_TOKEN_SLACK(webhookID, token) + (wait ? "?wait=true" : ""), auth, options); } /** - * Remove a reaction from a message - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @arg {String} [userID="@me"] The ID of the user to remove the reaction for - * @returns {Promise} + * Execute a webhook + * @arg {String} webhookID The ID of the webhook + * @arg {String} token The token of the webhook + * @arg {Object} options Webhook execution options + * @arg {Object} [options.allowedMentions] A list of mentions to allow (overrides default) + * @arg {Boolean} [options.allowedMentions.everyone] Whether or not to allow @everyone/@here. + * @arg {Boolean | Array} [options.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. + * @arg {Boolean | Array} [options.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. + * @arg {Boolean} [options.auth=false] Whether or not to authorize the request with the bot token (allowing custom emotes from other guilds) + * @arg {String} [options.avatarURL] A URL for a custom avatar, defaults to webhook default avatar if not specified + * @arg {String} [options.content=""] A content string + * @arg {Object[]} [options.embeds] An array of Discord embeds + * @arg {Object | Object[]} [options.file] A file object (or an Array of them) + * @arg {Buffer} options.file.file A buffer containing file data + * @arg {String} options.file.name What to name the file + * @arg {Boolean} [options.tts=false] Whether the message should be a TTS message or not + * @arg {String} [options.username] A custom username, defaults to webhook default username if not specified + * @arg {Boolean} [options.wait=false] Whether to wait for the server to confirm the message create or not + * @returns {Promise} */ - removeMessageReaction(channelID, messageID, reaction, userID) { - if(reaction === decodeURI(reaction)) { - reaction = encodeURIComponent(reaction); + executeWebhook(webhookID, token, options) { + if(!options.content && !options.file && !options.embeds) { + return Promise.reject(new Error("No content, file, or embeds")); } - return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE_REACTION_USER(channelID, messageID, reaction, userID || "@me"), true); + return this.requestHandler.request("POST", Endpoints.WEBHOOK_TOKEN(webhookID, token) + (options.wait ? "?wait=true" : ""), !!options.auth, { + content: options.content, + embeds: options.embeds, + username: options.username, + avatar_url: options.avatarURL, + tts: options.tts, + allowed_mentions: this._formatAllowedMentions(options.allowedMentions) + }, options.file).then((response) => options.wait ? new Message(response, this) : undefined); } /** - * Remove all reactions from a message - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @returns {Promise} - */ - removeMessageReactions(channelID, messageID) { - return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE_REACTIONS(channelID, messageID), true); + * Follow a NewsChannel in another channel. This creates a webhook in the target channel + * @param {String} channelID The ID of the NewsChannel + * @arg {String} webhookChannelID The ID of the target channel + * @returns {Object} An object containing the NewsChannel's ID and the new webhook's ID + */ + followChannel(channelID, webhookChannelID) { + return this.requestHandler.request("POST", Endpoints.CHANNEL_FOLLOW(channelID), true, {webhook_channel_id: webhookChannelID}); } /** - * Remove all reactions from a message for a single emoji. - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) - * @returns {Promise} + * Get general and bot-specific info on connecting to the Discord gateway (e.g. connection ratelimit) + * @returns {Promise} Resolves with an object containing gateway connection info */ - removeMessageReactionEmoji(channelID, messageID, reaction) { - if(reaction === decodeURI(reaction)) { - reaction = encodeURIComponent(reaction); + getBotGateway() { + if(!this.token.startsWith("Bot ")) { + this.token = "Bot " + this.token; } - return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE_REACTION(channelID, messageID, reaction), true); - } - - /** - * Delete a message - * @arg {String} channelID The ID of the channel - * @arg {String} messageID The ID of the message - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} - */ - deleteMessage(channelID, messageID, reason) { - return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE(channelID, messageID), true, { - reason - }); + return this.requestHandler.request("GET", Endpoints.GATEWAY_BOT, true); } /** - * Bulk delete messages (bot accounts only) + * Get a Channel object from a channel ID * @arg {String} channelID The ID of the channel - * @arg {String[]} messageIDs Array of message IDs to delete - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {CategoryChannel | GroupChannel | PrivateChannel | TextChannel | VoiceChannel | NewsChannel} */ - deleteMessages(channelID, messageIDs, reason) { - if(messageIDs.length === 0) { - return Promise.resolve(); - } - if(messageIDs.length === 1) { - return this.deleteMessage(channelID, messageIDs[0]); - } - - const oldestAllowedSnowflake = (Date.now() - 1421280000000) * 4194304; - const invalidMessage = messageIDs.find((messageID) => messageID < oldestAllowedSnowflake); - if(invalidMessage) { - return Promise.reject(new Error(`Message ${invalidMessage} is more than 2 weeks old.`)); + getChannel(channelID) { + if(!channelID) { + throw new Error(`Invalid channel ID: ${channelID}`); } - if(messageIDs.length > 100) { - return this.requestHandler.request("POST", Endpoints.CHANNEL_BULK_DELETE(channelID), true, { - messages: messageIDs.splice(0, 100), - reason: reason - }).then(() => this.deleteMessages(channelID, messageIDs)); + if(this.channelGuildMap[channelID] && this.guilds.get(this.channelGuildMap[channelID])) { + return this.guilds.get(this.channelGuildMap[channelID]).channels.get(channelID); } - return this.requestHandler.request("POST", Endpoints.CHANNEL_BULK_DELETE(channelID), true, { - messages: messageIDs, - reason: reason - }); - } - - /** - * Crosspost (publish) a message to subscribed channels - * @arg {String} channelID The ID of the NewsChannel - * @arg {String} messageID The ID of the message - * @returns {Promise} - */ - crosspostMessage(channelID, messageID) { - return this.requestHandler.request("POST", Endpoints.CHANNEL_CROSSPOST(channelID, messageID), true).then((message) => new Message(message, this)); - } - - /** - * Follow a NewsChannel in another channel. This creates a webhook in the target channel - * @param {String} channelID The ID of the NewsChannel - * @arg {String} webhookChannelID The ID of the target channel - * @returns {Object} An object containing the NewsChannel's ID and the new webhook's ID - */ - followChannel(channelID, webhookChannelID) { - return this.requestHandler.request("POST", Endpoints.CHANNEL_FOLLOW(channelID), true, {webhook_channel_id: webhookChannelID}); + return this.privateChannels.get(channelID) || this.groupChannels.get(channelID); } /** - * Purge previous messages in a channel with an optional filter (bot accounts only) + * Get all invites in a channel * @arg {String} channelID The ID of the channel - * @arg {Number} limit The max number of messages to search through, -1 for no limit - * @arg {function} [filter] Optional filter function that returns a boolean when passed a Message object - * @arg {String} [before] Get messages before this message ID - * @arg {String} [after] Get messages after this message ID - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} Resolves with the number of messages deleted + * @returns {Promise} */ - async purgeChannel(channelID, limit, filter, before, after, reason) { - if(typeof filter === "string") { - filter = (msg) => msg.content.includes(filter); - } - if(limit !== -1 && limit <= 0) { - return 0; - } - const toDelete = []; - let deleted = 0; - let done = false; - const checkToDelete = async () => { - const messageIDs = (done && toDelete) || (toDelete.length >= 100 && toDelete.splice(0, 100)); - if(messageIDs) { - deleted += messageIDs.length; - await this.deleteMessages(channelID, messageIDs, reason); - if(done) { - return deleted; - } - await sleep(1000); - return checkToDelete(); - } else if(done) { - return deleted; - } else { - await sleep(250); - return checkToDelete(); - } - }; - const del = async (_before, _after) => { - const messages = await this.getMessages(channelID, 100, _before, _after); - if(limit !== -1 && limit <= 0) { - done = true; - return; - } - for(const message of messages) { - if(limit !== -1 && limit <= 0) { - break; - } - if(message.timestamp < Date.now() - 1209600000) { // 14d * 24h * 60m * 60s * 1000ms - done = true; - return; - } - if(!filter || filter(message)) { - toDelete.push(message.id); - } - if(limit !== -1) { - limit--; - } - } - if((limit !== -1 && limit <= 0) || messages.length < 100) { - done = true; - return; - } - await del((_before || !_after) && messages[messages.length - 1].id, _after && messages[0].id); - }; - await del(before, after); - return checkToDelete(); + getChannelInvites(channelID) { + return this.requestHandler.request("GET", Endpoints.CHANNEL_INVITES(channelID), true).then((invites) => invites.map((invite) => new Invite(invite, this))); } /** - * [DEPRECATED] Get a guild's embed object - * @arg {String} guildID The ID of the guild - * @returns {Promise} A guild embed object + * Get all the webhooks in a channel + * @arg {String} channelID The ID of the channel to get webhooks for + * @returns {Promise} Resolves with an array of webhook objects */ - getGuildEmbed(guildID) { - return this.requestHandler.request("GET", Endpoints.GUILD_EMBED(guildID), true); + getChannelWebhooks(channelID) { + return this.requestHandler.request("GET", Endpoints.CHANNEL_WEBHOOKS(channelID), true); } /** - * Get a guild's widget object - * @arg {String} guildID The ID of the guild - * @returns {Promise} A guild widget object + * Get a DM channel with a user, or create one if it does not exist + * @arg {String} userID The ID of the user + * @returns {Promise} */ - getGuildWidget(guildID) { - return this.requestHandler.request("GET", Endpoints.GUILD_WIDGET(guildID), true); + getDMChannel(userID) { + if(this.privateChannelMap[userID]) { + return Promise.resolve(this.privateChannels.get(this.privateChannelMap[userID])); + } + return this.requestHandler.request("POST", Endpoints.USER_CHANNELS("@me"), true, { + recipients: [userID], + type: 1 + }).then((privateChannel) => new PrivateChannel(privateChannel, this)); } /** - * Modify a guild's widget - * @arg {String} guildID The ID of the guild - * @arg {Object} options The widget object to modify (https://discord.com/developers/docs/resources/guild#modify-guild-widget) - * @returns {Promise} A guild widget object + * Get info on connecting to the Discord gateway + * @returns {Promise} Resolves with an object containing gateway connection info */ - editGuildWidget(guildID, options) { - return this.requestHandler.request("PATCH", Endpoints.GUILD_WIDGET(guildID), true, options); + getGateway() { + return this.requestHandler.request("GET", Endpoints.GATEWAY); } /** - * Get a guild preview for a guild. Only available for public guilds. - * @arg {String} guildID The ID of the guild - * @returns {Promise} + * Get the audit logs for a guild + * @arg {String} guildID The ID of the guild to get audit logs for + * @arg {Number} [limit=50] The maximum number of entries to return + * @arg {String} [before] Get entries before this entry ID + * @arg {Number} [actionType] Filter entries by action type + * @returns {Promise} Resolves with {users: Users[], entries: GuildAuditLogEntry[]} */ - getGuildPreview(guildID) { - return this.requestHandler.request("GET", Endpoints.GUILD_PREVIEW(guildID), true).then((data) => new GuildPreview(data, this)); + getGuildAuditLogs(guildID, limit, before, actionType) { + return this.requestHandler.request("GET", Endpoints.GUILD_AUDIT_LOGS(guildID), true, { + limit: limit || 50, + before: before, + action_type: actionType + }).then((data) => { + const guild = this.guilds.get(guildID); + return { + users: data.users.map((user) => this.users.add(user, this)), + entries: data.audit_log_entries.map((entry) => new GuildAuditLogEntry(entry, guild)) + }; + }); } /** - * Get a list of integrations for a guild + * Get a ban from the ban list of a guild * @arg {String} guildID The ID of the guild - * @returns {Promise} + * @arg {String} userID The ID of the banned user + * @returns {Promise} Resolves with {reason: String, user: User} */ - getGuildIntegrations(guildID) { - const guild = this.guilds.get(guildID); - return this.requestHandler.request("GET", Endpoints.GUILD_INTEGRATIONS(guildID), true).then((integrations) => integrations.map((integration) => new GuildIntegration(integration, guild))); + getGuildBan(guildID, userID) { + return this.requestHandler.request("GET", Endpoints.GUILD_BAN(guildID, userID), true).then((ban) => { + ban.user = new User(ban.user, this); + return ban; + }); } /** - * Edit a guild integration + * Get the ban list of a guild * @arg {String} guildID The ID of the guild - * @arg {String} integrationID The ID of the integration - * @arg {Object} options The properties to edit - * @arg {String} [options.enableEmoticons] Whether to enable integration emoticons or not - * @arg {String} [options.expireBehavior] What to do when a user's subscription runs out - * @arg {String} [options.expireGracePeriod] How long before the integration's role is removed from an unsubscribed user - * @returns {Promise} + * @returns {Promise} Resolves with an array of {reason: String, user: User} */ - editGuildIntegration(guildID, integrationID, options) { - return this.requestHandler.request("PATCH", Endpoints.GUILD_INTEGRATION(guildID, integrationID), true, { - expire_behavior: options.expireBehavior, - expire_grace_period: options.expireGracePeriod, - enable_emoticons: options.enableEmoticons + getGuildBans(guildID) { + return this.requestHandler.request("GET", Endpoints.GUILD_BANS(guildID), true).then((bans) => { + bans.forEach((ban) => { + ban.user = new User(ban.user, this); + }); + return bans; }); } /** - * Delete a guild integration + * [DEPRECATED] Get a guild's embed object * @arg {String} guildID The ID of the guild - * @arg {String} integrationID The ID of the integration - * @returns {Promise} + * @returns {Promise} A guild embed object */ - deleteGuildIntegration(guildID, integrationID) { - return this.requestHandler.request("DELETE", Endpoints.GUILD_INTEGRATION(guildID, integrationID), true); + getGuildEmbed(guildID) { + return this.requestHandler.request("GET", Endpoints.GUILD_EMBED(guildID), true); } /** - * Force a guild integration to sync + * Get a list of integrations for a guild * @arg {String} guildID The ID of the guild - * @arg {String} integrationID The ID of the integration - * @returns {Promise} + * @returns {Promise} */ - syncGuildIntegration(guildID, integrationID) { - return this.requestHandler.request("POST", Endpoints.GUILD_INTEGRATION_SYNC(guildID, integrationID), true); + getGuildIntegrations(guildID) { + const guild = this.guilds.get(guildID); + return this.requestHandler.request("GET", Endpoints.GUILD_INTEGRATIONS(guildID), true).then((integrations) => integrations.map((integration) => new GuildIntegration(integration, guild))); } /** @@ -1450,6 +1446,15 @@ class Client extends EventEmitter { return this.requestHandler.request("GET", Endpoints.GUILD_INVITES(guildID), true).then((invites) => invites.map((invite) => new Invite(invite, this))); } + /** + * Get a guild preview for a guild. Only available for public guilds. + * @arg {String} guildID The ID of the guild + * @returns {Promise} + */ + getGuildPreview(guildID) { + return this.requestHandler.request("GET", Endpoints.GUILD_PREVIEW(guildID), true).then((data) => new GuildPreview(data, this)); + } + /** * Returns the vanity url of the guild * @arg {String} guildID The ID of the guild @@ -1460,318 +1465,298 @@ class Client extends EventEmitter { } /** - * Ban a user from a guild - * @arg {String} guildID The ID of the guild - * @arg {String} userID The ID of the user - * @arg {Number} [deleteMessageDays=0] Number of days to delete messages for, between 0-7 inclusive - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get all the webhooks in a guild + * @arg {String} guildID The ID of the guild to get webhooks for + * @returns {Promise} Resolves with an array of webhook objects */ - banGuildMember(guildID, userID, deleteMessageDays, reason) { - if(!isNaN(deleteMessageDays) && (deleteMessageDays < 0 || deleteMessageDays > 7)) { - return Promise.reject(new Error(`Invalid deleteMessageDays value (${deleteMessageDays}), should be a number between 0-7 inclusive`)); - } - return this.requestHandler.request("PUT", Endpoints.GUILD_BAN(guildID, userID), true, { - delete_message_days: deleteMessageDays || 0, - reason: reason - }); + getGuildWebhooks(guildID) { + return this.requestHandler.request("GET", Endpoints.GUILD_WEBHOOKS(guildID), true); } /** - * Unban a user from a guild + * Get a guild's widget object * @arg {String} guildID The ID of the guild - * @arg {String} userID The ID of the user - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @returns {Promise} A guild widget object */ - unbanGuildMember(guildID, userID, reason) { - return this.requestHandler.request("DELETE", Endpoints.GUILD_BAN(guildID, userID), true, { - reason - }); + getGuildWidget(guildID) { + return this.requestHandler.request("GET", Endpoints.GUILD_WIDGET(guildID), true); } /** - * Create a guild - * @arg {String} name The name of the guild - * @arg {Object} options The properties of the guild - * @arg {String} [options.afkChannelID] The ID of the AFK voice channel - * @arg {Number} [options.afkTimeout] The AFK timeout in seconds - * @arg {Array} [options.channels] The new channels of the guild. IDs are placeholders which allow use of category channels. - * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". - * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. - * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings - * @arg {String} [options.region] The region of the guild - * @arg {Array} [options.roles] The new roles of the guild, the first one is the @everyone role. IDs are placeholders which allow channel overwrites. - * @arg {String} [options.systemChannelID] The ID of the system channel - * @arg {Number} [options.verificationLevel] The guild verification level - * @returns {Promise} + * Get info on an invite + * @arg {String} inviteID The ID of the invite + * @arg {Boolean} [withCounts] Whether to fetch additional invite info or not (approximate member counts, approximate presences, channel counts, etc.) + * @returns {Promise} */ - createGuild(name, options) { - if(this.guilds.size > 9) { - throw new Error("This method can't be used when in 10 or more guilds."); - } - - return this.requestHandler.request("POST", Endpoints.GUILDS, true, { - name: name, - region: options.region, - icon: options.icon, - verification_level: options.verificationLevel, - default_message_notifications: options.defaultNotifications, - explicit_content_filter: options.explicitContentFilter, - system_channel_id: options.systemChannelID, - afk_channel_id: options.afkChannelID, - afk_timeout: options.afkTimeout, - roles: options.roles, - channels: options.channels - }).then((guild) => new Guild(guild, this)); + getInvite(inviteID, withCounts) { + return this.requestHandler.request("GET", Endpoints.INVITE(inviteID), true, { + with_counts: withCounts + }).then((invite) => new Invite(invite, this)); } /** - * Edit a guild - * @arg {String} guildID The ID of the guild - * @arg {Object} options The properties to edit - * @arg {String} [options.afkChannelID] The ID of the AFK voice channel - * @arg {Number} [options.afkTimeout] The AFK timeout in seconds - * @arg {String} [options.banner] The guild banner image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings - * @arg {Number} [options.defaultNotifications] The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions". - * @arg {String} [options.description] The description for the guild (VIP only) - * @arg {Number} [options.explicitContentFilter] The level of the explicit content filter for messages/images in the guild. 0 disables message scanning, 1 enables scanning the messages of members without roles, 2 enables scanning for all messages. - * @arg {String} [options.icon] The guild icon as a base64 data URI. Note: base64 strings alone are not base64 data URI strings - * @arg {String} [options.name] The ID of the guild - * @arg {String} [options.ownerID] The ID of the user to transfer server ownership to (bot user must be owner) - * @arg {String} [options.preferredLocale] Preferred "PUBLIC" guild language used in server discovery and notices from Discord - * @arg {String} [options.publicUpdatesChannelID] The id of the channel where admins and moderators of "PUBLIC" guilds receive notices from Discord - * @arg {String} [options.region] The region of the guild - * @arg {String} [options.rulesChannelID] The id of the channel where "PUBLIC" guilds display rules and/or guidelines - * @arg {String} [options.splash] The guild splash image as a base64 data URI (VIP only). Note: base64 strings alone are not base64 data URI strings - * @arg {String} [options.systemChannelID] The ID of the system channel - * @arg {Number} [options.verificationLevel] The guild verification level - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get a previous message in a channel + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @returns {Promise} */ - editGuild(guildID, options, reason) { - return this.requestHandler.request("PATCH", Endpoints.GUILD(guildID), true, { - name: options.name, - region: options.region, - icon: options.icon, - verification_level: options.verificationLevel, - default_message_notifications: options.defaultNotifications, - explicit_content_filter: options.explicitContentFilter, - system_channel_id: options.systemChannelID, - rules_channel_id: options.rulesChannelID, - public_updates_channel_id: options.publicUpdatesChannelID, - preferred_locale: options.preferredLocale, - afk_channel_id: options.afkChannelID, - afk_timeout: options.afkTimeout, - owner_id: options.ownerID, - splash: options.splash, - banner: options.banner, - description: options.description, - reason: reason - }).then((guild) => new Guild(guild, this)); + getMessage(channelID, messageID) { + return this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGE(channelID, messageID), true).then((message) => new Message(message, this)); } /** - * Get the ban list of a guild - * @arg {String} guildID The ID of the guild - * @returns {Promise} Resolves with an array of {reason: String, user: User} + * Get a list of users who reacted with a specific reaction + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @arg {Number} [limit=100] The maximum number of users to get + * @arg {String} [before] Get users before this user ID + * @arg {String} [after] Get users after this user ID + * @returns {Promise} */ - getGuildBans(guildID) { - return this.requestHandler.request("GET", Endpoints.GUILD_BANS(guildID), true).then((bans) => { - bans.forEach((ban) => { - ban.user = new User(ban.user, this); - }); - return bans; - }); + getMessageReaction(channelID, messageID, reaction, limit, before, after) { + if(reaction === decodeURI(reaction)) { + reaction = encodeURIComponent(reaction); + } + return this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGE_REACTION(channelID, messageID, reaction), true, { + limit: limit || 100, + before: before, + after: after + }).then((users) => users.map((user) => new User(user, this))); } - - /** - * Get a ban from the ban list of a guild - * @arg {String} guildID The ID of the guild - * @arg {String} userID The ID of the banned user - * @returns {Promise} Resolves with {reason: String, user: User} + + /** + * Get previous messages in a channel + * @arg {String} channelID The ID of the channel + * @arg {Number} [limit=50] The max number of messages to get + * @arg {String} [before] Get messages before this message ID + * @arg {String} [after] Get messages after this message ID + * @arg {String} [around] Get messages around this message ID (does not work with limit > 100) + * @returns {Promise} */ - getGuildBan(guildID, userID) { - return this.requestHandler.request("GET", Endpoints.GUILD_BAN(guildID, userID), true).then((ban) => { - ban.user = new User(ban.user, this); - return ban; + async getMessages(channelID, limit = 50, before, after, around) { + if(limit && limit > 100) { + let logs = []; + const get = async (_before, _after) => { + const messages = await this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGES(channelID), true, { + limit: 100, + before: _before || undefined, + after: _after || undefined + }); + if(limit <= messages.length) { + return (_after ? messages.slice(messages.length - limit, messages.length).map((message) => new Message(message, this)).concat(logs) : logs.concat(messages.slice(0, limit).map((message) => new Message(message, this)))); + } + limit -= messages.length; + logs = (_after ? messages.map((message) => new Message(message, this)).concat(logs) : logs.concat(messages.map((message) => new Message(message, this)))); + if(messages.length < 100) { + return logs; + } + this.emit("debug", `Getting ${limit} more messages during getMessages for ${channelID}: ${_before} ${_after}`, -1); + return get((_before || !_after) && messages[messages.length - 1].id, _after && messages[0].id); + }; + return get(before, after); + } + const messages = await this.requestHandler.request("GET", Endpoints.CHANNEL_MESSAGES(channelID), true, { + limit, + before, + after, + around + }); + return messages.map((message) => { + try { + return new Message(message, this); + } catch(err) { + this.emit("error", `Error creating message from channel messages\n${err.stack}\n${JSON.stringify(messages)}`); + return null; + } }); } /** - * Edit a guild member - * @arg {String} guildID The ID of the guild - * @arg {String} memberID The ID of the member - * @arg {Object} options The properties to edit - * @arg {String} [options.channelID] The ID of the voice channel to move the member to (must be in voice) - * @arg {Boolean} [options.deaf] Server deafen the member - * @arg {Boolean} [options.mute] Server mute the member - * @arg {String} [options.nick] Set the member's server nickname, "" to remove - * @arg {String[]} [options.roles] The array of role IDs the member should have - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get data on an OAuth2 application + * @arg {String} [appID="@me"] The client ID of the application to get data for (user accounts only). "@me" refers to the logged in user's own application + * @returns {Promise} The bot's application data. Refer to [the official Discord API documentation entry](https://discordapp.com/developers/docs/topics/oauth2#get-current-application-information) for object structure */ - editGuildMember(guildID, memberID, options, reason) { - return this.requestHandler.request("PATCH", Endpoints.GUILD_MEMBER(guildID, memberID), true, { - roles: options.roles && options.roles.filter((roleID, index) => options.roles.indexOf(roleID) === index), - nick: options.nick, - mute: options.mute, - deaf: options.deaf, - channel_id: options.channelID, - reason: reason - }); + getOAuthApplication(appID) { + return this.requestHandler.request("GET", Endpoints.OAUTH2_APPLICATION(appID || "@me"), true); } /** - * Add a role to a guild member - * @arg {String} guildID The ID of the guild - * @arg {String} memberID The ID of the member - * @arg {String} roleID The ID of the role - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get all the pins in a channel + * @arg {String} channelID The ID of the channel + * @returns {Promise} */ - addGuildMemberRole(guildID, memberID, roleID, reason) { - return this.requestHandler.request("PUT", Endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID), true, { - reason - }); + getPins(channelID) { + return this.requestHandler.request("GET", Endpoints.CHANNEL_PINS(channelID), true).then((messages) => messages.map((message) => new Message(message, this))); } /** - * Remove a role from a guild member + * Get the prune count for a guild * @arg {String} guildID The ID of the guild - * @arg {String} memberID The ID of the member - * @arg {String} roleID The ID of the role - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @arg {Number} [options] The options to use to get number of prune members + * @arg {Number} [options.days=7] The number of days of inactivity to prune for + * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning + * @returns {Promise} Resolves with the number of members that would be pruned */ - removeGuildMemberRole(guildID, memberID, roleID, reason) { - return this.requestHandler.request("DELETE", Endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID), true, { - reason - }); + getPruneCount(guildID, options = {}) { + return this.requestHandler.request("GET", Endpoints.GUILD_PRUNE(guildID), true, { + days: options.days, + include_roles: options.includeRoles + }).then((data) => data.pruned); } /** - * Edit the bot's nickname in a guild - * @arg {String} guildID The ID of the guild - * @arg {String} nick The nickname - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * Get a channel's data via the REST API. REST mode is required to use this endpoint. + * @arg {String} channelID The ID of the channel + * @returns {Promise} */ - editNickname(guildID, nick, reason) { - return this.requestHandler.request("PATCH", Endpoints.GUILD_MEMBER_NICK(guildID, "@me"), true, { - nick, - reason - }); + getRESTChannel(channelID) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.CHANNEL(channelID), true) + .then((channel) => Channel.from(channel, this)); } /** - * Kick a user from a guild + * Get a guild's data via the REST API. REST mode is required to use this endpoint. * @arg {String} guildID The ID of the guild - * @arg {String} userID The ID of the user - * @arg {String} [reason] The reason to be displayed in audit logs - * @returns {Promise} + * @arg {Boolean} [withCounts=false] Whether the guild object will have approximateMemberCount and approximatePresenceCount + * @returns {Promise} */ - kickGuildMember(guildID, userID, reason) { - return this.requestHandler.request("DELETE", Endpoints.GUILD_MEMBER(guildID, userID), true, { - reason - }); + getRESTGuild(guildID, withCounts = false) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.GUILD(guildID), true, { + with_counts: withCounts + }).then((guild) => new Guild(guild, this)); } /** - * Delete a guild (bot user must be owner) + * Get a guild's channels via the REST API. REST mode is required to use this endpoint. * @arg {String} guildID The ID of the guild - * @returns {Promise} + * @returns {Promise<(CategoryChannel[] | TextChannel[] | VoiceChannel[] | NewsChannel[])>} */ - deleteGuild(guildID) { - return this.requestHandler.request("DELETE", Endpoints.GUILD(guildID), true); + getRESTGuildChannels(guildID) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.GUILD_CHANNELS(guildID), true) + .then((channels) => channels.map((channel) => Channel.from(channel, this))); } /** - * Leave a guild + * Get a guild emoji via the REST API. REST mode is required to use this endpoint. * @arg {String} guildID The ID of the guild - * @returns {Promise} + * @arg {String} emojiID The ID of the emoji + * @returns {Promise} An emoji object */ - leaveGuild(guildID) { - return this.requestHandler.request("DELETE", Endpoints.USER_GUILD("@me", guildID), true); + getRESTGuildEmoji(guildID, emojiID) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.GUILD_EMOJI(guildID, emojiID), true); } /** - * Get data on an OAuth2 application - * @arg {String} [appID="@me"] The client ID of the application to get data for (user accounts only). "@me" refers to the logged in user's own application - * @returns {Promise} The bot's application data. Refer to [the official Discord API documentation entry](https://discordapp.com/developers/docs/topics/oauth2#get-current-application-information) for object structure + * Get a guild's emojis via the REST API. REST mode is required to use this endpoint. + * @arg {String} guildID The ID of the guild + * @returns {Promise} An array of guild emoji objects */ - getOAuthApplication(appID) { - return this.requestHandler.request("GET", Endpoints.OAUTH2_APPLICATION(appID || "@me"), true); + getRESTGuildEmojis(guildID) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.GUILD_EMOJIS(guildID), true); } /** - * [USER ACCOUNT] Create a relationship with a user - * @arg {String} userID The ID of the target user - * @arg {Boolean} [block=false] If true, block the user. Otherwise, add the user as a friend - * @returns {Promise} + * Get a guild's members via the REST API. REST mode is required to use this endpoint. + * @arg {String} guildID The ID of the guild + * @arg {String} memberID The ID of the member + * @returns {Promise} */ - addRelationship(userID, block) { - return this.requestHandler.request("PUT", Endpoints.USER_RELATIONSHIP("@me", userID), true, { - type: block ? 2 : undefined - }); + getRESTGuildMember(guildID, memberID) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.GUILD_MEMBER(guildID, memberID), true).then((member) => new Member(member, this.guilds.get(guildID), this)); } /** - * [USER ACCOUNT] Remove a relationship with a user - * @arg {String} userID The ID of the target user - * @returns {Promise} + * Get a guild's members via the REST API. REST mode is required to use this endpoint. + * @arg {String} guildID The ID of the guild + * @arg {Number} [limit=1] The max number of members to get (1 to 1000) + * @arg {String} [after] The highest user ID of the previous page + * @returns {Promise} */ - removeRelationship(userID) { - return this.requestHandler.request("DELETE", Endpoints.USER_RELATIONSHIP("@me", userID), true); + getRESTGuildMembers(guildID, limit, after) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.GUILD_MEMBERS(guildID), true, { + limit, + after + }).then((members) => members.map((member) => new Member(member, this.guilds.get(guildID), this))); } /** - * [USER ACCOUNT] Add a user to a group - * @arg {String} groupID The ID of the target group - * @arg {String} userID The ID of the target user - * @returns {Promise} + * Get a guild's roles via the REST API. REST mode is required to use this endpoint. + * @arg {String} guildID The ID of the guild + * @returns {Promise} */ - addGroupRecipient(groupID, userID) { - return this.requestHandler.request("PUT", Endpoints.CHANNEL_RECIPIENT(groupID, userID), true); + getRESTGuildRoles(guildID) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.GUILD_ROLES(guildID), true).then((roles) => roles.map((role) => new Role(role, null))); } /** - * [USER ACCOUNT] Remove a user from a group - * @arg {String} groupID The ID of the target group - * @arg {String} userID The ID of the target user - * @returns {Promise} + * Get a list of the user's guilds via the REST API. REST mode is required to use this endpoint. + * @arg {Number} [limit=100] The max number of guilds to get (1 to 1000) + * @arg {String} [before] The lowest guild ID of the next page + * @arg {String} [after] The highest guild ID of the previous page + * @returns {Promise} */ - removeGroupRecipient(groupID, userID) { - return this.requestHandler.request("DELETE", Endpoints.CHANNEL_RECIPIENT(groupID, userID), true); + getRESTGuilds(limit, before, after) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.USER_GUILDS("@me"), true, { + limit, + before, + after + }).then((guilds) => guilds.map((guild) => new Guild(guild, this))); } /** - * [USER ACCOUNT] Get profile data for a user - * @arg {String} userID The ID of the target user - * @returns {Promise} The user's profile data. + * Get a user's data via the REST API. REST mode is required to use this endpoint. + * @arg {String} userID The ID of the user + * @returns {Promise} */ - getUserProfile(userID) { - return this.requestHandler.request("GET", Endpoints.USER_PROFILE(userID), true); + getRESTUser(userID) { + if(!this.options.restMode) { + return Promise.reject(new Error("Eris REST mode is not enabled")); + } + return this.requestHandler.request("GET", Endpoints.USER(userID), true).then((user) => new User(user, this)); } /** - * [USER ACCOUNT] Edit the current user's note for another user - * @arg {String} userID The ID of the target user - * @arg {String} note The note - * @returns {Promise} + * Get properties of the bot user + * @returns {Promise} */ - editUserNote(userID, note) { - return this.requestHandler.request("PUT", Endpoints.USER_NOTE("@me", userID), true, { - note - }); + getSelf() { + return this.requestHandler.request("GET", Endpoints.USER("@me"), true).then((data) => new ExtendedUser(data, this)); } /** - * [USER ACCOUNT] Delete the current user's note for another user - * @returns {Promise} + * [USER ACCOUNT] Get the billing info for the current user + * @returns {Promise} The user's billing info */ - deleteUserNote(userID) { - return this.requestHandler.request("DELETE", Endpoints.USER_NOTE("@me", userID), true); + getSelfBilling() { + return this.requestHandler.request("GET", Endpoints.USER_BILLING("@me"), true); } /** @@ -1782,32 +1767,6 @@ class Client extends EventEmitter { return this.requestHandler.request("GET", Endpoints.USER_CONNECTIONS("@me"), true); } - /** - * [USER ACCOUNT] Edit a connection for the current user - * @arg {String} platform The connection platform (e.g. "twitch", "reddit") - * @arg {String} id The connection ID - * @arg {Object} data The connection data - * @arg {Boolean} [data.friendSync] Whether to sync friends from the connection or not - * @arg {Number} [data.visibility] The visibility level for the connection. 0 = hidden, 1 = shown on profile - * @returns {Promise} The updated connection data - */ - editSelfConnection(platform, id, data) { - return this.requestHandler.request("PATCH", Endpoints.USER_CONNECTION_PLATFORM("@me", platform, id), true, { - visibility: data.visibility, - friend_sync: data.friendSync - }); - } - - /** - * [USER ACCOUNT] Delete a connection for the current user - * @arg {String} platform The connection platform (e.g. "twitch", "reddit") - * @arg {String} id The connection ID - * @returns {Promise} - */ - deleteSelfConnection(platform, id) { - return this.requestHandler.request("DELETE", Endpoints.USER_CONNECTION_PLATFORM("@me", platform, id), true); - } - /** * [USER ACCOUNT] Get settings for the current user * @returns {Promise} The user's settings data. @@ -1816,64 +1775,6 @@ class Client extends EventEmitter { return this.requestHandler.request("GET", Endpoints.USER_SETTINGS("@me"), true); } - /** - * [USER ACCOUNT] Edit settings for the current user - * @arg {Object} data The user settings data - * @arg {Boolean} [data.convertEmoticons] Whether to convert emoticons or not (e.g. :D => 😄) - * @arg {Boolean} [data.detectPlatformAccounts] Whether to automatically detect accounts from other platforms or not (Blizzard, Skype, etc.) - * @arg {Boolean} [data.developerMode] Whether to enable developer mode or not - * @arg {Boolean} [data.enableTTSCommand] Whether to respect usage of the TTS command or not - * @arg {Object} [data.friendSourceFlags] An object representing allowed friend request sources - * @arg {Boolean} [data.friendSourceFlags.all] Whether to allow friends requests from anywhere or not - * @arg {Boolean} [data.friendSourceFlags.mutualFriends] Whether to allow friend requests from people with mutual friends or not - * @arg {Boolean} [data.friendSourceFlags.mutualGuilds] Whether to allow friend requests from people in mutual guilds or not - * @arg {Array} [data.guildPositions] An ordered array of guild IDs representing the guild list order in the Discord client - * @arg {Boolean} [data.inlineAttachmentMedia] Whether to show attachment previews or not - * @arg {Boolean} [data.inlineEmbedMedia] Whether to show embed images or not - * @arg {String} [data.locale] The locale to use for the Discord UI - * @arg {Boolean} [data.messageDisplayCompact] Whether to use compact mode or not - * @arg {Boolean} [data.renderEmbeds] Whether to show embeds or not - * @arg {Boolean} [data.renderReactions] Whether to show reactions or not - * @arg {Array} [data.restrictedGuilds] An array of guild IDs where direct messages from guild members are disallowed - * @arg {Boolean} [data.showCurrentGame] Whether to set the user's status to the current game or not - * @arg {String} [data.status] The status of the user, either "invisible", "dnd", "away", or "online" - * @arg {String} [data.theme] The theme to use for the Discord UI, either "dark" or "light" - * @returns {Promise} The user's settings data. - */ - editSelfSettings(data) { - let friendSourceFlags = undefined; - if(data.friendSourceFlags) { - friendSourceFlags = {}; - if(data.friendSourceFlags.all) { - friendSourceFlags.all = true; - } - if(data.friendSourceFlags.mutualFriends) { - friendSourceFlags.mutual_friends = true; - } - if(data.friendSourceFlags.mutualGuilds) { - friendSourceFlags.mutual_guilds = true; - } - } - return this.requestHandler.request("PATCH", Endpoints.USER_SETTINGS("@me"), true, { - convert_emoticons: data.convertEmoticons, - detect_platform_accounts: data.detectPlatformAccounts, - developer_mode: data.developerMode, - enable_tts_command: data.enableTTSCommand, - friend_source_flags: friendSourceFlags, - guild_positions: data.guildPositions, - inline_attachment_media: data.inlineAttachmentMedia, - inline_embed_media: data.inlineEmbedMedia, - locale: data.locale, - message_display_compact: data.messageDisplayCompact, - render_embeds: data.renderEmbeds, - render_reactions: data.renderReactions, - restricted_guilds: data.restrictedGuilds, - show_current_game: data.showCurrentGame, - status: data.status, - theme: data.theme - }); - } - /** * [USER ACCOUNT] Get the MFA backup codes for the current user * @arg {String} password The password for the current user @@ -1888,229 +1789,269 @@ class Client extends EventEmitter { } /** - * [USER ACCOUNT] Enable TOTP authentication for the current user - * @arg {String} secret The TOTP secret used to generate the auth code - * @arg {String} code The timed auth code for the current user - * @returns {Promise} An object containing the user's new authorization token and backup codes + * [USER ACCOUNT] Get the payment history for the current user + * @returns {Promise} The user's payment history */ - enableSelfMFATOTP(secret, code) { - return this.requestHandler.request("POST", Endpoints.USER_MFA_TOTP_ENABLE("@me"), true, { - secret, - code - }).then((data) => { - if(data.token) { - this.token = data.token; - } - }); + getSelfPayments() { + return this.requestHandler.request("GET", Endpoints.USER_BILLING_PAYMENTS("@me"), true); } /** - * [USER ACCOUNT] Disable TOTP authentication for the current user - * @arg {String} code The timed auth code for the current user - * @returns {Promise} An object containing the user's new authorization token + * [USER ACCOUNT] Get profile data for a user + * @arg {String} userID The ID of the target user + * @returns {Promise} The user's profile data. */ - disableSelfMFATOTP(code) { - return this.requestHandler.request("POST", Endpoints.USER_MFA_TOTP_DISABLE("@me"), true, { - code - }).then((data) => { - if(data.token) { - this.token = data.token; - } - }); + getUserProfile(userID) { + return this.requestHandler.request("GET", Endpoints.USER_PROFILE(userID), true); } /** - * [USER ACCOUNT] Get the billing info for the current user - * @returns {Promise} The user's billing info + * Get a list of general/guild-specific voice regions + * @arg {String} [guildID] The ID of the guild + * @returns {Promise} Resolves with an array of voice region objects */ - getSelfBilling() { - return this.requestHandler.request("GET", Endpoints.USER_BILLING("@me"), true); + getVoiceRegions(guildID) { + return guildID ? this.requestHandler.request("GET", Endpoints.GUILD_VOICE_REGIONS(guildID), true) : this.requestHandler.request("GET", Endpoints.VOICE_REGIONS, true); } /** - * [USER ACCOUNT] Get the payment history for the current user - * @returns {Promise} The user's payment history + * Get a webhook + * @arg {String} webhookID The ID of the webhook + * @arg {String} [token] The token of the webhook, used instead of the Bot Authorization token + * @returns {Promise} Resolves with a webhook object */ - getSelfPayments() { - return this.requestHandler.request("GET", Endpoints.USER_BILLING_PAYMENTS("@me"), true); + getWebhook(webhookID, token) { + return this.requestHandler.request("GET", token ? Endpoints.WEBHOOK_TOKEN(webhookID, token) : Endpoints.WEBHOOK(webhookID), !token); } /** - * [USER ACCOUNT] Purchase a premium subscription (Nitro) for the current user - * You must get a Stripe card token from the Stripe API for this to work - * @arg {String} token The Stripe credit card token - * @arg {String} plan The plan to purchase, either "premium_month" or "premium_year" - * @returns {Promise} + * Join a voice channel. If joining a group call, the voice connection ID will be stored in voiceConnections as "call". Otherwise, it will be the guild ID + * @arg {String} channelID The ID of the voice channel + * @arg {Object} [options] VoiceConnection constructor options + * @arg {Object} [options.opusOnly] Skip opus encoder initialization. You should not enable this unless you know what you are doing + * @arg {Object} [options.shared] Whether the VoiceConnection will be part of a SharedStream or not + * @returns {Promise} Resolves with a VoiceConnection */ - addSelfPremiumSubscription(token, plan) { - return this.requestHandler.request("PUT", Endpoints.USER_BILLING_PREMIUM_SUBSCRIPTION("@me"), true, { - token: token, - payment_gateway: "stripe", - plan: plan + joinVoiceChannel(channelID, options = {}) { + const channel = this.getChannel(channelID); + if(!channel) { + return Promise.reject(new Error("Channel not found")); + } + if(channel.guild && !(channel.permissionsOf(this.user.id).allow & Constants.Permissions.voiceConnect)) { + return Promise.reject(new Error("Insufficient permission to connect to voice channel")); + } + this.shards.get(this.guildShardMap[this.channelGuildMap[channelID]] || 0).sendWS(Constants.GatewayOPCodes.VOICE_STATE_UPDATE, { + guild_id: this.channelGuildMap[channelID] || null, + channel_id: channelID || null, + self_mute: false, + self_deaf: false }); + if(options.opusOnly === undefined) { + options.opusOnly = this.options.opusOnly; + } + return this.voiceConnections.join(this.channelGuildMap[channelID] || "call", channelID, options); } /** - * [USER ACCOUNT] Cancel the premium subscription (Nitro) for the current user + * Kick a user from a guild + * @arg {String} guildID The ID of the guild + * @arg {String} userID The ID of the user + * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} */ - deleteSelfPremiumSubscription() { - return this.requestHandler.request("DELETE", Endpoints.USER_BILLING_PREMIUM_SUBSCRIPTION("@me"), true); + kickGuildMember(guildID, userID, reason) { + return this.requestHandler.request("DELETE", Endpoints.GUILD_MEMBER(guildID, userID), true, { + reason + }); } /** - * Get a channel's data via the REST API. REST mode is required to use this endpoint. - * @arg {String} channelID The ID of the channel - * @returns {Promise} + * Leave a guild + * @arg {String} guildID The ID of the guild + * @returns {Promise} */ - getRESTChannel(channelID) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); - } - return this.requestHandler.request("GET", Endpoints.CHANNEL(channelID), true) - .then((channel) => Channel.from(channel, this)); + leaveGuild(guildID) { + return this.requestHandler.request("DELETE", Endpoints.USER_GUILD("@me", guildID), true); } /** - * Get a guild's data via the REST API. REST mode is required to use this endpoint. - * @arg {String} guildID The ID of the guild - * @arg {Boolean} [withCounts=false] Whether the guild object will have approximateMemberCount and approximatePresenceCount - * @returns {Promise} + * Leaves a voice channel + * @arg {String} channelID The ID of the voice channel */ - getRESTGuild(guildID, withCounts = false) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); + leaveVoiceChannel(channelID) { + if(!channelID || !this.channelGuildMap[channelID]) { + return; } - return this.requestHandler.request("GET", Endpoints.GUILD(guildID), true, { - with_counts: withCounts - }).then((guild) => new Guild(guild, this)); + this.closeVoiceConnection(this.channelGuildMap[channelID]); } /** - * Get a list of the user's guilds via the REST API. REST mode is required to use this endpoint. - * @arg {Number} [limit=100] The max number of guilds to get (1 to 1000) - * @arg {String} [before] The lowest guild ID of the next page - * @arg {String} [after] The highest guild ID of the previous page - * @returns {Promise} - */ - getRESTGuilds(limit, before, after) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); - } - return this.requestHandler.request("GET", Endpoints.USER_GUILDS("@me"), true, { - limit, - before, - after - }).then((guilds) => guilds.map((guild) => new Guild(guild, this))); + * Pin a message + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @returns {Promise} + */ + pinMessage(channelID, messageID) { + return this.requestHandler.request("PUT", Endpoints.CHANNEL_PIN(channelID, messageID), true); } /** - * Get a guild's channels via the REST API. REST mode is required to use this endpoint. + * Begin pruning a guild * @arg {String} guildID The ID of the guild - * @returns {Promise<(CategoryChannel[] | TextChannel[] | VoiceChannel[] | NewsChannel[])>} + * @arg {Number} [options] The options to pass to prune members + * @arg {Boolean} [options.computePruneCount=true] Whether or not the number of pruned members should be returned. Discord discourages setting this to true for larger guilds + * @arg {Number} [options.days=7] The number of days of inactivity to prune for + * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning + * @arg {String} [options.reason] The reason to be displayed in audit logs + * @returns {Promise} If computePruneCount was true, resolves with the number of pruned members */ - getRESTGuildChannels(guildID) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); - } - return this.requestHandler.request("GET", Endpoints.GUILD_CHANNELS(guildID), true) - .then((channels) => channels.map((channel) => Channel.from(channel, this))); + pruneMembers(guildID, options = {}) { + return this.requestHandler.request("POST", Endpoints.GUILD_PRUNE(guildID), true, { + days: options.days, + compute_prune_count: options.computePruneCount, + include_roles: options.includeRoles, + reason: options.reason + }).then((data) => data.pruned); } /** - * Get a guild's emojis via the REST API. REST mode is required to use this endpoint. - * @arg {String} guildID The ID of the guild - * @returns {Promise} An array of guild emoji objects + * Purge previous messages in a channel with an optional filter (bot accounts only) + * @arg {String} channelID The ID of the channel + * @arg {Number} limit The max number of messages to search through, -1 for no limit + * @arg {function} [filter] Optional filter function that returns a boolean when passed a Message object + * @arg {String} [before] Get messages before this message ID + * @arg {String} [after] Get messages after this message ID + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} Resolves with the number of messages deleted */ - getRESTGuildEmojis(guildID) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); + async purgeChannel(channelID, limit, filter, before, after, reason) { + if(typeof filter === "string") { + filter = (msg) => msg.content.includes(filter); } - return this.requestHandler.request("GET", Endpoints.GUILD_EMOJIS(guildID), true); + if(limit !== -1 && limit <= 0) { + return 0; + } + const toDelete = []; + let deleted = 0; + let done = false; + const checkToDelete = async () => { + const messageIDs = (done && toDelete) || (toDelete.length >= 100 && toDelete.splice(0, 100)); + if(messageIDs) { + deleted += messageIDs.length; + await this.deleteMessages(channelID, messageIDs, reason); + if(done) { + return deleted; + } + await sleep(1000); + return checkToDelete(); + } else if(done) { + return deleted; + } else { + await sleep(250); + return checkToDelete(); + } + }; + const del = async (_before, _after) => { + const messages = await this.getMessages(channelID, 100, _before, _after); + if(limit !== -1 && limit <= 0) { + done = true; + return; + } + for(const message of messages) { + if(limit !== -1 && limit <= 0) { + break; + } + if(message.timestamp < Date.now() - 1209600000) { // 14d * 24h * 60m * 60s * 1000ms + done = true; + return; + } + if(!filter || filter(message)) { + toDelete.push(message.id); + } + if(limit !== -1) { + limit--; + } + } + if((limit !== -1 && limit <= 0) || messages.length < 100) { + done = true; + return; + } + await del((_before || !_after) && messages[messages.length - 1].id, _after && messages[0].id); + }; + await del(before, after); + return checkToDelete(); } /** - * Get a guild emoji via the REST API. REST mode is required to use this endpoint. - * @arg {String} guildID The ID of the guild - * @arg {String} emojiID The ID of the emoji - * @returns {Promise} An emoji object + * [USER ACCOUNT] Remove a user from a group + * @arg {String} groupID The ID of the target group + * @arg {String} userID The ID of the target user + * @returns {Promise} */ - getRESTGuildEmoji(guildID, emojiID) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); - } - return this.requestHandler.request("GET", Endpoints.GUILD_EMOJI(guildID, emojiID), true); + removeGroupRecipient(groupID, userID) { + return this.requestHandler.request("DELETE", Endpoints.CHANNEL_RECIPIENT(groupID, userID), true); } /** - * Get a guild's members via the REST API. REST mode is required to use this endpoint. + * Remove a role from a guild member * @arg {String} guildID The ID of the guild - * @arg {Number} [limit=1] The max number of members to get (1 to 1000) - * @arg {String} [after] The highest user ID of the previous page - * @returns {Promise} + * @arg {String} memberID The ID of the member + * @arg {String} roleID The ID of the role + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} */ - getRESTGuildMembers(guildID, limit, after) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); - } - return this.requestHandler.request("GET", Endpoints.GUILD_MEMBERS(guildID), true, { - limit, - after - }).then((members) => members.map((member) => new Member(member, this.guilds.get(guildID), this))); + removeGuildMemberRole(guildID, memberID, roleID, reason) { + return this.requestHandler.request("DELETE", Endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID), true, { + reason + }); } /** - * Get a guild's members via the REST API. REST mode is required to use this endpoint. - * @arg {String} guildID The ID of the guild - * @arg {String} memberID The ID of the member - * @returns {Promise} + * Remove a reaction from a message + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @arg {String} [userID="@me"] The ID of the user to remove the reaction for + * @returns {Promise} */ - getRESTGuildMember(guildID, memberID) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); + removeMessageReaction(channelID, messageID, reaction, userID) { + if(reaction === decodeURI(reaction)) { + reaction = encodeURIComponent(reaction); } - return this.requestHandler.request("GET", Endpoints.GUILD_MEMBER(guildID, memberID), true).then((member) => new Member(member, this.guilds.get(guildID), this)); + return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE_REACTION_USER(channelID, messageID, reaction, userID || "@me"), true); } /** - * Get a guild's roles via the REST API. REST mode is required to use this endpoint. - * @arg {String} guildID The ID of the guild - * @returns {Promise} + * Remove all reactions from a message for a single emoji. + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) + * @returns {Promise} */ - getRESTGuildRoles(guildID) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); + removeMessageReactionEmoji(channelID, messageID, reaction) { + if(reaction === decodeURI(reaction)) { + reaction = encodeURIComponent(reaction); } - return this.requestHandler.request("GET", Endpoints.GUILD_ROLES(guildID), true).then((roles) => roles.map((role) => new Role(role, null))); + return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE_REACTION(channelID, messageID, reaction), true); } /** - * Get a user's data via the REST API. REST mode is required to use this endpoint. - * @arg {String} userID The ID of the user - * @returns {Promise} + * Remove all reactions from a message + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @returns {Promise} */ - getRESTUser(userID) { - if(!this.options.restMode) { - return Promise.reject(new Error("Eris REST mode is not enabled")); - } - return this.requestHandler.request("GET", Endpoints.USER(userID), true).then((user) => new User(user, this)); + removeMessageReactions(channelID, messageID) { + return this.requestHandler.request("DELETE", Endpoints.CHANNEL_MESSAGE_REACTIONS(channelID, messageID), true); } /** - * Search for guild members by partial nickname/username - * @arg {String} guildID The ID of the guild - * @arg {String} query The query string to match username(s) and nickname(s) against - * @arg {Number} [limit=1] The maximum number of members you want returned, capped at 100 - * @returns {Promise} + * [USER ACCOUNT] Remove a relationship with a user + * @arg {String} userID The ID of the target user + * @returns {Promise} */ - searchGuildMembers(guildID, query, limit) { - return this.requestHandler.request("GET", Endpoints.GUILD_MEMBERS_SEARCH(guildID), true, { - query, - limit - }).then((members) => { - const guild = this.guilds.get(guildID); - return members.map((member) => new Member(member, guild, this)); - }); + removeRelationship(userID) { + return this.requestHandler.request("DELETE", Endpoints.USER_RELATIONSHIP("@me", userID), true); } /** @@ -2167,6 +2108,23 @@ class Client extends EventEmitter { })); } + /** + * Search for guild members by partial nickname/username + * @arg {String} guildID The ID of the guild + * @arg {String} query The query string to match username(s) and nickname(s) against + * @arg {Number} [limit=1] The maximum number of members you want returned, capped at 100 + * @returns {Promise} + */ + searchGuildMembers(guildID, query, limit) { + return this.requestHandler.request("GET", Endpoints.GUILD_MEMBERS_SEARCH(guildID), true, { + query, + limit + }).then((members) => { + const guild = this.guilds.get(guildID); + return members.map((member) => new Member(member, guild, this)); + }); + } + /** * [USER ACCOUNT] Search a guild's messages * @arg {String} guildID The ID of the guild @@ -2223,6 +2181,48 @@ class Client extends EventEmitter { })); } + /** + * Send typing status in a channel + * @arg {String} channelID The ID of the channel + * @returns {Promise} + */ + sendChannelTyping(channelID) { + return this.requestHandler.request("POST", Endpoints.CHANNEL_TYPING(channelID), true); + } + + /** + * Force a guild integration to sync + * @arg {String} guildID The ID of the guild + * @arg {String} integrationID The ID of the integration + * @returns {Promise} + */ + syncGuildIntegration(guildID, integrationID) { + return this.requestHandler.request("POST", Endpoints.GUILD_INTEGRATION_SYNC(guildID, integrationID), true); + } + + /** + * Unban a user from a guild + * @arg {String} guildID The ID of the guild + * @arg {String} userID The ID of the user + * @arg {String} [reason] The reason to be displayed in audit logs + * @returns {Promise} + */ + unbanGuildMember(guildID, userID, reason) { + return this.requestHandler.request("DELETE", Endpoints.GUILD_BAN(guildID, userID), true, { + reason + }); + } + + /** + * Unpin a message + * @arg {String} channelID The ID of the channel + * @arg {String} messageID The ID of the message + * @returns {Promise} + */ + unpinMessage(channelID, messageID) { + return this.requestHandler.request("DELETE", Endpoints.CHANNEL_PIN(channelID, messageID), true); + } + _formatAllowedMentions(allowed) { if(!allowed) { return this.options.allowedMentions; From 3536bd0e88143c1455a7dd3ae36bbce60705323a Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:02:09 -0400 Subject: [PATCH 27/35] Add bsian's commits --- index.d.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index e424b3d81..b86619b4e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1217,7 +1217,6 @@ declare namespace Eris { ): Promise; createGroupChannel(userIDs: string[]): Promise; createGuild(name: string, options?: CreateGuildOptions): Promise; - // EmojiOptions has options.icon. Supposed to be options.image createGuildEmoji(guildID: string, options: EmojiOptions, reason?: string): Promise; createMessage(channelID: string, content: MessageContent, file?: MessageFile | MessageFile[]): Promise; createRole(guildID: string, options?: RoleOptions | Role, reason?: string): Promise; @@ -1381,7 +1380,6 @@ declare namespace Eris { leaveGuild(guildID: string): Promise; leaveVoiceChannel(channelID: string): void; pinMessage(channelID: string, messageID: string): Promise; - // Note: PruneMemberOptions is missing `computerPruneCount` pruneMembers(guildID: string, options?: PruneMemberOptions): Promise; purgeChannel( channelID: string, @@ -1689,8 +1687,8 @@ declare namespace Eris { splash: string | null; splashURL: string | null; constructor(data: BaseData, client: Client); - dynamicIconURL(format?: string, size?: number): string; - dynamicSplashURL(format?: string, size?: number): string; + dynamicIconURL(format?: ImageFormat, size?: number): string; + dynamicSplashURL(format?: ImageFormat, size?: number): string; } export class Invite extends Base { From df4cd5413b2d92a58809f86924402c5a40702496 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:05:05 -0400 Subject: [PATCH 28/35] Add compute prune count --- lib/structures/Guild.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index b00a74f73..f4e45114a 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -672,6 +672,7 @@ class Guild extends Base { /** * Begin pruning the guild * @arg {Number} [options] The options to pass to prune members + * @arg {Boolean} [options.computePruneCount=true] Whether or not the number of pruned members should be returned. Discord discourages setting this to true for larger guilds * @arg {Number} [options.days=7] The number of days of inactivity to prune for * @arg {Array} [options.includeRoles] An array of role IDs that members must have to be considered for pruning * @arg {String} [options.reason] The reason to be displayed in audit logs From 298459266917f87108f08f007dec8945463ae906 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:31:22 -0400 Subject: [PATCH 29/35] Alphabetize oldGuild and oldChannel --- lib/gateway/Shard.js | 78 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index b6979e63a..aff7c9867 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -842,54 +842,54 @@ class Shard extends EventEmitter { break; } const oldGuild = { - name: guild.name, - region: guild.region, - icon: guild.icon, - verificationLevel: guild.verificationLevel, - defaultNotifications: guild.defaultNotifications, - explicitContentFilter: guild.explicitContentFilter, - systemChannelID: guild.systemChannelID, - rulesChannelID: guild.rulesChannelID, - publicUpdatesChannelID: guild.publicUpdatesChannelID, - preferredLocale: guild.preferredLocale, afkChannelID: guild.afkChannelID, afkTimeout: guild.afkTimeout, - ownerID: guild.ownerID, - splash: guild.splash, banner: guild.banner, + defaultNotifications: guild.defaultNotifications, description: guild.description, - features: guild.features, emojis: guild.emojis, - mfaLevel: guild.mfaLevel, + explicitContentFilter: guild.explicitContentFilter, + features: guild.features, + icon: guild.icon, large: guild.large, - maxPresences: guild.maxPresences + maxPresences: guild.maxPresences, + mfaLevel: guild.mfaLevel, + name: guild.name, + ownerID: guild.ownerID, + preferredLocale: guild.preferredLocale, + publicUpdatesChannelID: guild.publicUpdatesChannelID, + region: guild.region, + rulesChannelID: guild.rulesChannelID, + splash: guild.splash, + systemChannelID: guild.systemChannelID, + verificationLevel: guild.verificationLevel }; /** * Fired when a guild is updated * @event Client#guildUpdate * @prop {Guild} guild The guild * @prop {Object} oldGuild The old guild data - * @prop {String} oldGuild.name The name of the guild - * @prop {String} oldGuild.region The region of the guild - * @prop {String?} oldGuild.icon The hash of the guild icon, or null if no icon - * @prop {Number} oldGuild.verificationLevel The guild verification level - * @prop {Number} oldGuild.defaultNotifications The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions" - * @prop {Number} oldGuild.explicitContentFilter The explicit content filter level for the guild. 0 is off, 1 is on for people without roles, 2 is on for all - * @prop {String?} oldGuild.systemChannelID The ID of the default channel for system messages (built-in join messages and boost messages) - * @prop {String?} oldGuild.rulesChannelID The channel where "PUBLIC" guilds display rules and/or guidelines - * @prop {String?} oldGuild.publicUpdatesChannelID ID of the guild's updates channel if the guild has "PUBLIC" features - * @prop {String} oldGuild.preferredLocale Preferred "PUBLIC" guild language used in server discovery and notices from Discord * @prop {String} oldGuild.afkChannelID The ID of the AFK voice channel * @prop {Number} oldGuild.afkTimeout The AFK timeout in seconds - * @prop {String} oldGuild.ownerID The ID of the user that is the guild owner - * @prop {String?} oldGuild.splash The hash of the guild splash image, or null if no splash (VIP only) * @prop {String?} oldGuild.banner The hash of the guild banner image, or null if no splash (VIP only) + * @prop {Number} oldGuild.defaultNotifications The default notification settings for the guild. 0 is "All Messages", 1 is "Only @mentions" * @prop {String?} oldGuild.description The description for the guild (VIP only) - * @prop {Object[]} oldGuild.features An array of guild features * @prop {Object[]} oldGuild.emojis An array of guild emojis - * @prop {Number} oldGuild.mfaLevel The admin 2FA level for the guild. 0 is not required, 1 is required + * @prop {Number} oldGuild.explicitContentFilter The explicit content filter level for the guild. 0 is off, 1 is on for people without roles, 2 is on for all + * @prop {Object[]} oldGuild.features An array of guild features + * @prop {String?} oldGuild.icon The hash of the guild icon, or null if no icon * @prop {Boolean} oldGuild.large Whether the guild is "large" by "some Discord standard" * @prop {Number} oldGuild.maxPresences The maximum number of people that can be online in a guild at once (returned from REST API only) + * @prop {Number} oldGuild.mfaLevel The admin 2FA level for the guild. 0 is not required, 1 is required + * @prop {String} oldGuild.name The name of the guild + * @prop {String} oldGuild.ownerID The ID of the user that is the guild owner + * @prop {String} oldGuild.preferredLocale Preferred "PUBLIC" guild language used in server discovery and notices from Discord + * @prop {String?} oldGuild.publicUpdatesChannelID ID of the guild's updates channel if the guild has "PUBLIC" features + * @prop {String} oldGuild.region The region of the guild + * @prop {String?} oldGuild.rulesChannelID The channel where "PUBLIC" guilds display rules and/or guidelines + * @prop {String?} oldGuild.splash The hash of the guild splash image, or null if no splash (VIP only) + * @prop {String?} oldGuild.systemChannelID The ID of the default channel for system messages (built-in join messages and boost messages) + * @prop {Number} oldGuild.verificationLevel The guild verification level */ this.emit("guildUpdate", this.client.guilds.update(packet.d, this.client), oldGuild); break; @@ -1120,15 +1120,15 @@ class Shard extends EventEmitter { }; } else if(channel instanceof GuildChannel) { oldChannel = { - name: channel.name, - topic: channel.topic, - type: channel.type, - position: channel.position, bitrate: channel.bitrate, + name: channel.name, nsfw: channel.nsfw, - permissionOverwrites: channel.permissionOverwrites, parentID: channel.parentID, + permissionOverwrites: channel.permissionOverwrites, + position: channel.position, rateLimitPerUser: channel.rateLimitPerUser, + topic: channel.topic, + type: channel.type, userLimit: channel.userLimit }; } else { @@ -1168,15 +1168,15 @@ class Shard extends EventEmitter { * @event Client#channelUpdate * @prop {TextChannel | VoiceChannel | CategoryChannel | StoreChannel | NewsChannel | GuildChannel | PrivateChannel} channel The updated channel * @prop {Object} oldChannel The old channel data + * @prop {Number?} oldChannel.bitrate The bitrate of the channel (voice channels only) * @prop {String} oldChannel.name The name of the channel - * @prop {Number} oldChannel.position The position of the channel * @prop {Boolean} oldChannel.nsfw Whether the channel is NSFW or not - * @prop {String?} oldChannel.topic The topic of the channel (text channels only) - * @prop {Number} oldChannel.type The type of the old channel - * @prop {Number?} oldChannel.bitrate The bitrate of the channel (voice channels only) - * @prop {Collection} oldChannel.permissionOverwrites Collection of PermissionOverwrites in this channel * @prop {String?} oldChannel.parentID The ID of the category this channel belongs to + * @prop {Collection} oldChannel.permissionOverwrites Collection of PermissionOverwrites in this channel + * @prop {Number} oldChannel.position The position of the channel * @prop {Number} oldChannel.rateLimitPerUser The ratelimit of the channel, in seconds. 0 means no ratelimit is enabled (text channels only) + * @prop {String?} oldChannel.topic The topic of the channel (text channels only) + * @prop {Number} oldChannel.type The type of the old channel * @prop {Number} oldChannel.userLimit The max number of users that can join the channel (voice channels only) */ this.emit("channelUpdate", channel, oldChannel); From 8e0b81f7989c523ada635fa55a7deb618688c3f4 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:36:35 -0400 Subject: [PATCH 30/35] Add back in createdAt --- index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/index.d.ts b/index.d.ts index 251525bcf..e7b454980 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1863,6 +1863,7 @@ declare namespace Eris { } export class PermissionOverwrite extends Permission { + createdAt: number; id: string; type: PermissionType; constructor(data: { allow: number; deny: number }); From 3e6c17d53274f2c961f726ca63f52558036a3bba Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:41:17 -0400 Subject: [PATCH 31/35] Add new docs --- lib/Client.js | 4 ++-- lib/structures/Message.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Client.js b/lib/Client.js index 4c5e2de39..20022f037 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -51,7 +51,7 @@ const sleep = (ms) => new Promise((res) => setTimeout(res, ms)); * @extends EventEmitter * @prop {Boolean?} bot Whether the bot user belongs to an OAuth2 application * @prop {Object} channelGuildMap Object mapping channel IDs to guild IDs -// Gateway URL? +* @prop {String} gatewayURL The URL for the discord gateway * @prop {Collection} groupChannels Collection of group channels the bot is in (user accounts only) * @prop {Collection} guilds Collection of guilds the bot is in * @prop {Object} guildShardMap Object mapping guild IDs to shard IDs @@ -60,7 +60,7 @@ const sleep = (ms) => new Promise((res) => setTimeout(res, ms)); * @prop {Object} privateChannelMap Object mapping user IDs to private channel IDs * @prop {Collection} privateChannels Collection of private channels the bot is in * @prop {Collection} relationships Collection of relationships the bot user has (user accounts only) -// Request handler? +* @prop {RequestHandler} requestHandler The request handler the client will use * @prop {Collection} shards Collection of shards Eris is using * @prop {Number} startTime Timestamp of bot ready event * @prop {String} token The bot user token diff --git a/lib/structures/Message.js b/lib/structures/Message.js index 2dc1e42e4..fc5b272a3 100644 --- a/lib/structures/Message.js +++ b/lib/structures/Message.js @@ -32,7 +32,7 @@ const User = require("./User"); * @prop {String} messageReference.channelID The id of the channel this message was crossposted from * @prop {String} messageReference.guildID The id of the guild this message was crossposted from * @prop {Boolean} pinned Whether the message is pinned or not -// Note add prefix? +* @prop {String?} prefix The prefix used in the Message, if any (CommandClient only) * @prop {Object} reactions An object containing the reactions on the message * @prop {Boolean} reactions.me Whether or not the bot user did the reaction * @prop {Number} reactions.count The number of times the reaction was used From 04fc6e8e037ad42d79936275d2d17e4f8146753e Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:45:27 -0400 Subject: [PATCH 32/35] Alphabetize GroupChannel --- lib/structures/GroupChannel.js | 54 +++++++++++++++++----------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/structures/GroupChannel.js b/lib/structures/GroupChannel.js index 49173cce2..6a9216c82 100644 --- a/lib/structures/GroupChannel.js +++ b/lib/structures/GroupChannel.js @@ -8,15 +8,15 @@ const User = require("./User"); /** * [USER ACCOUNT] Represents a group channel. See PrivateChannel docs for additional properties. * @extends PrivateChannel -* @prop {String} id The ID of the channel -* @prop {String} mention A string that mentions the channel * @prop {Call?} call The current group call, if any -* @prop {Call?} lastCall The previous group call, if any -* @prop {Collection} recipients The recipients in this private channel -* @prop {String} name The name of the group channel * @prop {String?} icon The hash of the group channel icon * @prop {String?} iconURL The URL of the group channel icon +* @prop {String} id The ID of the channel +* @prop {Call?} lastCall The previous group call, if any +* @prop {String} mention A string that mentions the channel +* @prop {String} name The name of the group channel * @prop {String} ownerID The ID of the user that is the group owner +* @prop {Collection} recipients The recipients in this private channel */ class GroupChannel extends PrivateChannel { // (╯°□°)╯︵ ┻━┻ constructor(data, client) { @@ -40,16 +40,8 @@ class GroupChannel extends PrivateChannel { // (╯°□°)╯︵ ┻━┻ } } - /** - * [USER ACCOUNT] Edit the channel's properties - * @arg {Object} options The properties to edit - * @arg {String} [options.name] The name of the channel - * @arg {String} [options.icon] The icon of the channel as a base64 data URI (group channels only). Note: base64 strings alone are not base64 data URI strings - * @arg {String} [options.ownerID] The ID of the channel owner (group channels only) - * @returns {Promise} - */ - edit(options) { - return this.client.editChannel.call(this.client, this.id, options); + get iconURL() { + return this.icon ? this.client._formatImage(Endpoints.CHANNEL_ICON(this.id, this.icon)) : null; } /** @@ -62,25 +54,33 @@ class GroupChannel extends PrivateChannel { // (╯°□°)╯︵ ┻━┻ } /** - * [USER ACCOUNT] Remove a user from the group - * @arg {String} userID The ID of the target user - * @returns {Promise} + * Get the group's icon with the given format and size + * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") + * @arg {Number} [size] The size of the icon (any power of two between 16 and 4096) */ - removeRecipient(userID) { - return this.client.removeGroupRecipient.call(this.client, this.id, userID); + dynamicIconURL(format, size) { + return this.icon ? this.client._formatImage(Endpoints.CHANNEL_ICON(this.id, this.icon), format, size) : null; } - get iconURL() { - return this.icon ? this.client._formatImage(Endpoints.CHANNEL_ICON(this.id, this.icon)) : null; + /** + * [USER ACCOUNT] Edit the channel's properties + * @arg {Object} options The properties to edit + * @arg {String} [options.name] The name of the channel + * @arg {String} [options.icon] The icon of the channel as a base64 data URI (group channels only). Note: base64 strings alone are not base64 data URI strings + * @arg {String} [options.ownerID] The ID of the channel owner (group channels only) + * @returns {Promise} + */ + edit(options) { + return this.client.editChannel.call(this.client, this.id, options); } /** - * Get the group's icon with the given format and size - * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") - * @arg {Number} [size] The size of the icon (any power of two between 16 and 4096) + * [USER ACCOUNT] Remove a user from the group + * @arg {String} userID The ID of the target user + * @returns {Promise} */ - dynamicIconURL(format, size) { - return this.icon ? this.client._formatImage(Endpoints.CHANNEL_ICON(this.id, this.icon), format, size) : null; + removeRecipient(userID) { + return this.client.removeGroupRecipient.call(this.client, this.id, userID); } toJSON(props = []) { From 4e52165cbf06131207fd986dd1ffbab9dc6ed0fb Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:47:12 -0400 Subject: [PATCH 33/35] Fix conflicts in Guild --- lib/structures/Guild.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index 5fda0f2a6..4341f57cc 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -240,34 +240,22 @@ class Guild extends Base { } /** -<<<<<<< HEAD * Add a role to a guild member * @arg {String} memberID The ID of the member * @arg {String} roleID The ID of the role * @arg {String} [reason] The reason to be displayed in audit logs * @returns {Promise} -======= - * Get the guild's splash with the given format and size - * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") - * @arg {Number} [size] The size of the icon (any power of two between 16 and 4096) ->>>>>>> typings */ addMemberRole(memberID, roleID, reason) { return this._client.addGuildMemberRole.call(this._client, this.id, memberID, roleID, reason); } /** -<<<<<<< HEAD * Ban a user from the guild * @arg {String} userID The ID of the member * @arg {Number} [deleteMessageDays=0] Number of days to delete messages for * @arg {String} [reason] Reason for the ban * @returns {Promise} -======= - * Get the guild's banner with the given format and size - * @arg {String} [format] The filetype of the icon ("jpg", "jpeg", "png", "gif", or "webp") - * @arg {Number} [size] The size of the icon (any power of two between 16 and 4096) ->>>>>>> typings */ banMember(userID, deleteMessageDays, reason) { return this._client.banGuildMember.call(this._client, this.id, userID, deleteMessageDays, reason); From d67ef600082775bf62ef4de136c90f1b61f31353 Mon Sep 17 00:00:00 2001 From: Justin <27078349+jtsshieh@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:49:58 -0400 Subject: [PATCH 34/35] Move permissionOf to correct location --- lib/structures/GuildChannel.js | 62 +++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/structures/GuildChannel.js b/lib/structures/GuildChannel.js index edbb2a845..be8a190ea 100644 --- a/lib/structures/GuildChannel.js +++ b/lib/structures/GuildChannel.js @@ -71,37 +71,6 @@ class GuildChannel extends Channel { return this.client.deleteChannelPermission.call(this.client, this.id, overwriteID, reason); } - /** - * Get the channel-specific permissions of a member - * @arg {String | Member} memberID The ID of the member or a Member instance - * @returns {Permission} - */ - permissionsOf(memberID) { - const member = memberID instanceof Member ? memberID : this.guild.members.get(memberID); - let permission = this.guild.permissionsOf(member).allow; - if(permission & Permissions.administrator) { - return new Permission(Permissions.all); - } - let overwrite = this.permissionOverwrites.get(this.guild.id); - if(overwrite) { - permission = (permission & ~overwrite.deny) | overwrite.allow; - } - let deny = 0; - let allow = 0; - for(const roleID of member.roles) { - if((overwrite = this.permissionOverwrites.get(roleID))) { - deny |= overwrite.deny; - allow |= overwrite.allow; - } - } - permission = (permission & ~deny) | allow; - overwrite = this.permissionOverwrites.get(member.id); - if(overwrite) { - permission = (permission & ~overwrite.deny) | overwrite.allow; - } - return new Permission(permission); - } - /** * Edit the channel's properties * @arg {Object} options The properties to edit @@ -141,6 +110,37 @@ class GuildChannel extends Channel { return this.client.editChannelPermission.call(this.client, this.id, overwriteID, allow, deny, type, reason); } + /** + * Get the channel-specific permissions of a member + * @arg {String | Member} memberID The ID of the member or a Member instance + * @returns {Permission} + */ + permissionsOf(memberID) { + const member = memberID instanceof Member ? memberID : this.guild.members.get(memberID); + let permission = this.guild.permissionsOf(member).allow; + if(permission & Permissions.administrator) { + return new Permission(Permissions.all); + } + let overwrite = this.permissionOverwrites.get(this.guild.id); + if(overwrite) { + permission = (permission & ~overwrite.deny) | overwrite.allow; + } + let deny = 0; + let allow = 0; + for(const roleID of member.roles) { + if((overwrite = this.permissionOverwrites.get(roleID))) { + deny |= overwrite.deny; + allow |= overwrite.allow; + } + } + permission = (permission & ~deny) | allow; + overwrite = this.permissionOverwrites.get(member.id); + if(overwrite) { + permission = (permission & ~overwrite.deny) | overwrite.allow; + } + return new Permission(permission); + } + toJSON(props = []) { return super.toJSON([ "name", From 5d14b9a88a240b092aa96270041e98bf9d5be15b Mon Sep 17 00:00:00 2001 From: bsian03 Date: Thu, 20 Aug 2020 22:54:36 +0100 Subject: [PATCH 35/35] Remove extra space --- index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index e7b454980..6f805f9e9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1311,7 +1311,7 @@ declare namespace Eris { ): Promise; editGuildIntegration(guildID: string, integrationID: string, options: IntegrationOptions): Promise; editGuildMember(guildID: string, memberID: string, options: MemberOptions, reason?: string): Promise; - editGuildWidget(guildID: string, options: Widget) : Promise + editGuildWidget(guildID: string, options: Widget): Promise editMessage(channelID: string, messageID: string, content: MessageContent): Promise; editNickname(guildID: string, nick: string, reason?: string): Promise; editRole(guildID: string, roleID: string, options: RoleOptions, reason?: string): Promise; // TODO not all options are available? @@ -1354,7 +1354,7 @@ declare namespace Eris { getGuildPreview(guildID: string): Promise; getGuildVanity(guildID: string): Promise<{ code?: string; uses?: number }>; getGuildWebhooks(guildID: string): Promise; - getGuildWidget(guildID: string) : Promise; + getGuildWidget(guildID: string): Promise; getInvite(inviteID: string, withCounts?: false): Promise>; getInvite(inviteID: string, withCounts: true): Promise>; getMessage(channelID: string, messageID: string): Promise;