From 7e19c81504e8d6bf34211dfa12fb833e8bb6c12b Mon Sep 17 00:00:00 2001 From: Catboy Date: Mon, 30 Aug 2021 10:34:23 -0500 Subject: [PATCH] Undo last commit --- esm.mjs | 2 +- index.d.ts | 25 +- index.js | 2 +- lib/gateway/Shard.js | 2 +- lib/structures/Interaction.js | 34 +-- lib/structures/UnknownInteraction.js | 402 +++++++++++++++++++++++++++ 6 files changed, 442 insertions(+), 25 deletions(-) create mode 100644 lib/structures/UnknownInteraction.js diff --git a/esm.mjs b/esm.mjs index f56b48bbb..5984c2ff6 100644 --- a/esm.mjs +++ b/esm.mjs @@ -26,7 +26,6 @@ export const { GuildIntegration, GuildPreview, GuildTemplate, - Interaction, Invite, Member, Message, @@ -44,6 +43,7 @@ export const { StoreChannel, TextChannel, UnavailableGuild, + UnknownInteraction, User, VERSION, VoiceChannel, diff --git a/index.d.ts b/index.d.ts index dc9026d99..efa88d50d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -644,7 +644,7 @@ declare namespace Eris { guildUnavailable: [guild: UnavailableGuild]; guildUpdate: [guild: Guild, oldGuild: OldGuild]; hello: [trace: string[], id: number]; - interactionCreate: [interaction: PingInteraction | CommandInteraction | ComponentInteraction | Interaction]; + interactionCreate: [interaction: PingInteraction | CommandInteraction | ComponentInteraction | UnknownInteraction]; inviteCreate: [guild: Guild, invite: Invite]; inviteDelete: [guild: Guild, invite: Invite]; messageCreate: [message: Message]; @@ -2449,7 +2449,6 @@ declare namespace Eris { export class Interaction extends Base { acknowledged: boolean; applicationID: string; - data?: unknown; id: string; token: string; type: number; @@ -2457,7 +2456,6 @@ declare namespace Eris { } export class PingInteraction extends Interaction { - data: undefined; type: Constants["InteractionTypes"]["PING"]; acknowledge(): Promise; pong(): Promise; @@ -2526,6 +2524,27 @@ declare namespace Eris { getOriginalMessage(): Promise } + export class UnknownInteraction extends Interaction { + channel?: T; + data?: unknown; + guildID?: string; + member?: Member; + message?: Message; + type: number; + user?: User; + createFollowup(content: string | InteractionWebhookContent): Promise; + createMessage(content: string | InteractionContent | InteractionWebhookContent): Promise; + defer(flags?: number): Promise; + deferUpdate(): Promise; + deleteMessage(messageID: string): Promise; + deleteOriginalMessage(): Promise; + editMessage(messageID: string, content: string | MessageWebhookContent): Promise; + editOriginalMessage(content: string | MessageWebhookContent): Promise; + editParent(content: MessageWebhookContent): Promise; + getOriginalMessage(): Promise + pong(): Promise; + } + // If CT (count) is "withMetadata", it will not have count properties export class Invite extends Base { channel: CH; diff --git a/index.js b/index.js index 3e7dceee3..4ddb09ca1 100644 --- a/index.js +++ b/index.js @@ -44,7 +44,7 @@ Eris.SharedStream = require("./lib/voice/SharedStream"); Eris.StoreChannel = require("./lib/structures/StoreChannel"); Eris.TextChannel = require("./lib/structures/TextChannel"); Eris.UnavailableGuild = require("./lib/structures/UnavailableGuild"); -Eris.Interaction = require("./lib/structures/Interaction"); +Eris.UnknownInteraction = require("./lib/structures/UnknownInteraction"); Eris.User = require("./lib/structures/User"); Eris.VERSION = require("./package.json").version; Eris.VoiceChannel = require("./lib/structures/VoiceChannel"); diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index f3543b1c0..508b110c9 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -2082,7 +2082,7 @@ class Shard extends EventEmitter { /** * Fired when an interaction is created * @event Client#interactionCreate - * @prop {PingInteraction | CommandInteraction | ComponentInteraction | Interaction} Interaction Interaction that was created + * @prop {PingInteraction | CommandInteraction | ComponentInteraction | UnknownInteraction} Interaction Interaction that was created */ this.emit("interactionCreate", Interaction.from(packet.d, this.client)); break; diff --git a/lib/structures/Interaction.js b/lib/structures/Interaction.js index 094ebc1d9..ff213eac5 100644 --- a/lib/structures/Interaction.js +++ b/lib/structures/Interaction.js @@ -4,49 +4,44 @@ const Base = require("./Base"); const {InteractionTypes} = require("../Constants"); /** -* Represents an interaction. You also probably want to look at PingInteraction, CommandInteraction, and ComponentInteraction. +* Represents an interaction. You also probably want to look at PingInteraction, CommandInteraction, ComponentInteraction, and UnknownInteraction. * @prop {Boolean} acknowledged Whether or not the interaction has been acknowledged * @prop {String} applicationID The ID of the interaction's application -* @prop {Object?} data The data attached to the interaction. Check CommandInteraction and ComponentInteraction for specifics * @prop {String} id The ID of the interaction * @prop {String} token The interaction token (Interaction tokens are valid for 15 minutes after initial response and can be used to send followup messages but you must send an initial response within 3 seconds of receiving the event. If the 3 second deadline is exceeded, the token will be invalidated.) * @prop {Number} type 1 is a Ping, 2 is an Application Command, 3 is a Message Component * @prop {Number} version The interaction version */ class Interaction extends Base { - constructor(info, client) { - super(info.id); + constructor(data, client) { + super(data.id); this._client = client; - this.applicationID = info.application_id; - this.token = info.token; - this.type = info.type; - this.version = info.version; + this.applicationID = data.application_id; + this.token = data.token; + this.type = data.type; + this.version = data.version; this.acknowledged = false; - - if(info.data !== undefined) { - this.data = info.data; - } } update() { this.acknowledged = true; } - static from(info, client) { - switch(info.type) { + static from(data, client) { + switch(data.type) { case InteractionTypes.PING: { - return new PingInteraction(info, client); + return new PingInteraction(data, client); } case InteractionTypes.APPLICATION_COMMAND: { - return new CommandInteraction(info, client); + return new CommandInteraction(data, client); } case InteractionTypes.MESSAGE_COMPONENT: { - return new ComponentInteraction(info, client); + return new ComponentInteraction(data, client); } } - this._client.emit("warn", new Error(`Unknown interaction type: ${info.type}\n${JSON.stringify(info)}`)); - return new Interaction(info, client); + this._client.emit("warn", new Error(`Unknown interaction type: ${data.type}\n${JSON.stringify(data)}`)); + return new UnknownInteraction(data, client); } } @@ -56,3 +51,4 @@ module.exports = Interaction; const PingInteraction = require("./PingInteraction"); const CommandInteraction = require("./CommandInteraction"); const ComponentInteraction = require("./ComponentInteraction"); +const UnknownInteraction = require("./UnknownInteraction"); diff --git a/lib/structures/UnknownInteraction.js b/lib/structures/UnknownInteraction.js new file mode 100644 index 000000000..afb5fcbc2 --- /dev/null +++ b/lib/structures/UnknownInteraction.js @@ -0,0 +1,402 @@ +"use strict"; + +const Interaction = require("./Interaction"); +const Message = require("./Message"); +const Member = require("./Member"); +const {InteractionResponseTypes} = require("../Constants"); + +/** +* Represents an unknown interaction. See Interaction for more properties. +* @extends Interaction +* @prop {PrivateChannel? | TextChannel? | NewsChannel?} channel The channel the interaction was created in. Can be partial with only the id if the channel is not cached. +* @prop {Object?} data The data attached to the interaction +* @prop {String?} guildID The ID of the guild in which the interaction was created +* @prop {Member?} member The member who triggered the interaction (This is only sent when the interaction is invoked within a guild) +* @prop {Message?} message The message the interaction came from (Message Component only). If the message is ephemeral, this will be an object with `id` and `flags` keys. +* @prop {User?} user The user who triggered the interaction (This is only sent when the interaction is invoked within a dm) +*/ +class UnknownInteraction extends Interaction { + constructor(info, client) { + super(info, client); + + if(info.channel_id !== undefined) { + this.channel = this._client.getChannel(info.channel_id) || { + id: info.channel_id + }; + } + + if(info.data !== undefined) { + this.data = info.data; + } + + if(info.guild_id !== undefined) { + this.guildID = info.guild_id; + } + + if(info.member !== undefined) { + if(this.channel.guild) { + info.member.id = info.member.user.id; + this.member = this.channel.guild.members.update(info.member, this.channel.guild); + } else { + const guild = this._client.guilds.get(info.guild_id); + this.member = new Member(info.member, guild, this._client); + } + } + + if(info.message !== undefined) { + this.message = new Message(info.message, this._client); + } + + if(info.user !== undefined) { + this.user = this._client.users.update(info.user, client); + } + + } + + /** + * Respond to the interaction with a followup message + * @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 {Array} [content.components] An array of component objects + * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) + * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) + * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) + * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) + * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) + * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) + * @arg {Array} [content.components[].options] The options for this component (type 3 only) + * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected + * @arg {String} [content.components[].options[].description] The description for this option + * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option + * @arg {String} content.components[].options[].label The label for this option + * @arg {Number | String} content.components[].options[].value The value for this option + * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) + * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required + * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu + * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {String} content.content A content string + * @arg {Object} [content.embeds] An array of up to 10 embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] 64 for Ephemeral + * @arg {Object | Array} [content.file] A file object (or an Array of them) + * @arg {Buffer} content.file.file A buffer containing file data + * @arg {String} content.file.name What to name the file + * @arg {Boolean} [content.tts] Set the message TTS flag + * @returns {Promise} + */ + async createFollowup(content) { + if(this.acknowledged === false) { + throw new Error("createFollowup cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); + } + 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; + } + } + return this._client.executeWebhook.call(this._client, this.applicationID, this.token, Object.assign({wait: true}, content)); + } + + /** + * Acknowledges the interaction with a message. If already acknowledged runs createFollowup + * Note: You can **not** use more than 1 initial interaction response per interaction, use createFollowup if you have already responded with a different interaction response. + * @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 {Array} [content.components] An array of component objects + * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) + * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) + * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) + * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) + * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) + * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) + * @arg {Array} [content.components[].options] The options for this component (type 3 only) + * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected + * @arg {String} [content.components[].options[].description] The description for this option + * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option + * @arg {String} content.components[].options[].label The label for this option + * @arg {Number | String} content.components[].options[].value The value for this option + * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) + * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required + * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu + * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {String} content.content A content string + * @arg {Object} [content.embeds] An array of up to 10 embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] 64 for Ephemeral + * @arg {Object | Array} [content.file] (Only applies after the interaction is acknowledged.) A file object (or an Array of them) + * @arg {Buffer} content.file.file A buffer containing file data + * @arg {String} content.file.name What to name the file + * @arg {Boolean} [content.tts] Set the message TTS flag + * @returns {Promise} + */ + async createMessage(content) { + if(this.acknowledged === true) { + return this.createFollowup(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.embeds) { + return Promise.reject(new Error("No content or embeds")); + } + if(content.content !== undefined || content.embeds || content.allowedMentions) { + content.allowed_mentions = this._client._formatAllowedMentions(content.allowedMentions); + } + } + return this._client.createInteractionResponse.call(this._client, this.id, this.token, { + type: InteractionResponseTypes.CHANNEL_MESSAGE_WITH_SOURCE, + data: content + }); + } + + /** + * Acknowledges the interaction with a defer response + * Note: You can **not** use more than 1 initial interaction response per interaction. + * @arg {Number} [flags] 64 for Ephemeral + * @returns {Promise} + */ + async defer(flags) { + if(this.acknowledged === true) { + throw new Error("You have already acknowledged this interaction."); + } + return this._client.createInteractionResponse.call(this._client, this.id, this.token, { + type: InteractionResponseTypes.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE, + data: { + flags: flags || 0 + } + }); + } + + /** + * Acknowledges the interaction with a defer message update response (Message Component only) + * Note: You can **not** use more than 1 initial interaction response per interaction. + * @returns {Promise} + */ + async deferUpdate() { + if(this.acknowledged === true) { + throw new Error("You have already acknowledged this interaction."); + } + return this._client.createInteractionResponse.call(this._client, this.id, this.token, { + type: InteractionResponseTypes.DEFERRED_UPDATE_MESSAGE + }); + } + + /** + * Delete a message + * @arg {String} messageID the id of the message to delete, or "@original" for the original response. + * @returns {Promise} + */ + async deleteMessage(messageID) { + if(this.acknowledged === false) { + throw new Error("deleteMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); + } + return this._client.deleteWebhookMessage.call(this._client, this.applicationID, this.token, messageID); + } + + /** + * Delete the Original message (or the parent message for components) + * Warning: Will error with ephemeral messages. + * @returns {Promise} + */ + async deleteOriginalMessage() { + if(this.acknowledged === false) { + throw new Error("deleteOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); + } + return this._client.deleteWebhookMessage.call(this._client, this.applicationID, this.token, "@original"); + } + + /** + * Edit a message + * @arg {String} messageID the id of the message to edit, or "@original" for the original response. + * @arg {Object} options Interaction message edit 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.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. + * @arg {Array} [content.components] An array of component objects + * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) + * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) + * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) + * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) + * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) + * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) + * @arg {Array} [content.components[].options] The options for this component (type 3 only) + * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected + * @arg {String} [content.components[].options[].description] The description for this option + * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option + * @arg {String} content.components[].options[].label The label for this option + * @arg {Number | String} content.components[].options[].value The value for this option + * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) + * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required + * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu + * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {String} [options.content=""] A content string + * @arg {Object} [content.embeds] An array of up to 10 embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object | Array} [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 + * @returns {Promise} + */ + async editMessage(messageID, content) { + if(this.acknowledged === false) { + throw new Error("editMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); + } + 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; + } + } + return this._client.editWebhookMessage.call(this._client, this.applicationID, this.token, messageID, content); + } + + /** + * Edit the Original response message (or the parent message for components) + * @arg {Object} options Interaction message edit 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.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. + * @arg {Array} [content.components] An array of component objects + * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) + * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) + * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) + * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) + * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) + * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) + * @arg {Array} [content.components[].options] The options for this component (type 3 only) + * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected + * @arg {String} [content.components[].options[].description] The description for this option + * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option + * @arg {String} content.components[].options[].label The label for this option + * @arg {Number | String} content.components[].options[].value The value for this option + * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) + * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required + * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu + * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {String} [options.content=""] A content string + * @arg {Object} [content.embeds] An array of up to 10 embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object | Array} [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 + * @returns {Promise} + */ + async editOriginalMessage(content) { + if(this.acknowledged === false) { + throw new Error("editOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); + } + 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; + } + } + return this._client.editWebhookMessage.call(this._client, this.applicationID, this.token, "@original", content); + } + + /** + * Acknowledges the interaction by editing the parent message. If already acknowledged runs editOriginalMessage (Message Component only) + * Note: You can **not** use more than 1 initial interaction response per interaction, use edit if you have already responded with a different interaction response. + * Warning: Will error with ephemeral messages. + * @arg {String | Object} content What to edit the message with + * @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 {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. + * @arg {Array} [content.components] An array of component objects + * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) + * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) + * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) + * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) + * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) + * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) + * @arg {Array} [content.components[].options] The options for this component (type 3 only) + * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected + * @arg {String} [content.components[].options[].description] The description for this option + * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option + * @arg {String} content.components[].options[].label The label for this option + * @arg {Number | String} content.components[].options[].value The value for this option + * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) + * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required + * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu + * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {String} [content.content=""] A content string + * @arg {Object} [content.embeds] An array of up to 10 embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object | Array} [content.file] A file object (or an Array of them) + * @arg {Buffer} content.file.file A buffer containing file data + * @arg {String} content.file.name What to name the file + * @returns {Promise} + */ + async editParent(content) { + if(this.acknowledged === true) { + return this.editOriginalMessage(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.embeds === undefined && content.components === undefined) { + return Promise.reject(new Error("No content, embeds, or components")); + } + if(content.content !== undefined || content.embeds || content.allowedMentions) { + content.allowed_mentions = this._client._formatAllowedMentions(content.allowedMentions); + } + } + return this._client.createInteractionResponse.call(this._client, this.id, this.token, { + type: InteractionResponseTypes.UPDATE_MESSAGE, + data: content + }); + } + + /** + * Get the Original response message (or the parent message for components) + * Warning: Will error with ephemeral messages. + * @returns {Promise} + */ + async getOriginalMessage() { + if(this.acknowledged === false) { + throw new Error("getOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); + } + return this._client.getWebhookMessage.call(this._client, this.applicationID, this.token, "@original"); + } + + /** + * Acknowledges the ping interaction with a pong response (Ping Only) + * Note: You can **not** use more than 1 initial interaction response per interaction. + * @returns {Promise} + */ + async pong() { + if(this.acknowledged === true) { + throw new Error("You have already acknowledged this interaction."); + } + return this._client.createInteractionResponse.call(this._client, this.id, this.token, { + type: InteractionResponseTypes.PONG + }); + } + +} + +module.exports = UnknownInteraction;