From 036bb035c9d6ddf780bab5af4884861d08f04d24 Mon Sep 17 00:00:00 2001 From: monbrey Date: Sun, 20 Jun 2021 04:18:10 +1000 Subject: [PATCH] feat(Interactions): components and component interactions (#132) Co-authored-by: nearlySplat Co-authored-by: Advaith Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Vlad Frangu --- deno/gateway/v8.ts | 3 +- deno/gateway/v9.ts | 3 +- deno/payloads/v8/channel.ts | 149 +++++++++++++++++++++++++++++++ deno/payloads/v8/interactions.ts | 50 ++++++++++- deno/payloads/v9/channel.ts | 149 +++++++++++++++++++++++++++++++ deno/payloads/v9/interactions.ts | 50 ++++++++++- gateway/v8.ts | 3 +- gateway/v9.ts | 3 +- payloads/v8/channel.ts | 149 +++++++++++++++++++++++++++++++ payloads/v8/interactions.ts | 50 ++++++++++- payloads/v9/channel.ts | 149 +++++++++++++++++++++++++++++++ payloads/v9/interactions.ts | 50 ++++++++++- 12 files changed, 792 insertions(+), 16 deletions(-) diff --git a/deno/gateway/v8.ts b/deno/gateway/v8.ts index 8a4971c1..2a81d3bb 100644 --- a/deno/gateway/v8.ts +++ b/deno/gateway/v8.ts @@ -13,6 +13,7 @@ import type { APIGuildIntegration, APIGuildMember, APIMessage, + APIMessageComponentInteraction, APIRole, APIUnavailableGuild, APIUser, @@ -889,7 +890,7 @@ export type GatewayInteractionCreateDispatch = DataPayload< /** * https://discord.com/developers/docs/topics/gateway#interaction-create */ -export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction; +export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction | APIMessageComponentInteraction; /** * https://discord.com/developers/docs/topics/gateway#invite-create diff --git a/deno/gateway/v9.ts b/deno/gateway/v9.ts index 720dcda8..49062285 100644 --- a/deno/gateway/v9.ts +++ b/deno/gateway/v9.ts @@ -13,6 +13,7 @@ import type { APIGuildIntegration, APIGuildMember, APIMessage, + APIMessageComponentInteraction, APIRole, APIThreadMember, APIUnavailableGuild, @@ -902,7 +903,7 @@ export type GatewayInteractionCreateDispatch = DataPayload< /** * https://discord.com/developers/docs/topics/gateway#interaction-create */ -export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction; +export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction | APIMessageComponentInteraction; /** * https://discord.com/developers/docs/topics/gateway#invite-create diff --git a/deno/payloads/v8/channel.ts b/deno/payloads/v8/channel.ts index 27311a17..95864e47 100644 --- a/deno/payloads/v8/channel.ts +++ b/deno/payloads/v8/channel.ts @@ -342,6 +342,10 @@ export interface APIMessage { * Sent if the message is a response to an Interaction */ interaction?: APIMessageInteraction; + /** + * Sent if the message contains components like buttons, action rows, or other interactive components + */ + components?: APIActionRowComponent[]; } /** @@ -930,3 +934,148 @@ export interface APIAllowedMentions { */ replied_user?: boolean; } + +/** + * https://discord.com/developers/docs/interactions/message-components + */ +export interface APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-types + */ +export enum ComponentType { + /** + * ActionRow component + */ + ActionRow = 1, + /** + * Button component + */ + Button, + /** + * Select Menu component + */ + SelectMenu, +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APIActionRowComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.ActionRow; + /** + * The components in the ActionRow + */ + components: Exclude[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-object + */ +export interface APIButtonComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.Button; + /** + * The label to be displayed on the button + */ + label?: string; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id?: string; + /** + * The style of the button + */ + style: ButtonStyle; + /** + * The emoji to display to the left of the text + */ + emoji?: APIPartialEmoji; + /** + * The URL to direct users to when clicked for Link buttons + */ + url?: string; + /** + * The status of the button + */ + disabled?: boolean; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectMenuComponent { + /** + * The type of the component + */ + type: ComponentType.SelectMenu; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id: string; + /** + * Custom placeholder text if nothing is selected + */ + placeholder?: string; + /** + * The minimum number of items that must be chosen + */ + min_values?: number; + /** + * The maximum number of items that can be chosen + */ + max_values?: number; + /** + * Choices to display in the select menu + */ + options: APISelectOption[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectOption { + /** + * The user-facing name of the option (max 25 chars) + */ + label: string; + /** + * The dev-defined value of the option (max 100 chars) + */ + value: string; + /** + * An additional description of the option (max 50 chars) + */ + description?: string; + /** + * The emoji to display to the left of the option + */ + emoji?: APIPartialEmoji; + /** + * Whether this option should be already-selected by default + */ + default: boolean; +} + +export type APIMessageComponent = APIActionRowComponent | APIButtonComponent | APISelectMenuComponent; + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-styles + */ +export enum ButtonStyle { + Primary = 1, + Secondary, + Success, + Danger, + Link, +} diff --git a/deno/payloads/v8/interactions.ts b/deno/payloads/v8/interactions.ts index 91351361..8c3ed6ff 100644 --- a/deno/payloads/v8/interactions.ts +++ b/deno/payloads/v8/interactions.ts @@ -1,5 +1,6 @@ import type { Permissions, Snowflake } from '../../globals.ts'; import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../rest/v8/mod.ts'; +import { APIMessage, ComponentType } from './channel.ts'; import type { APIGuildMember, APIPartialChannel, APIRole, APIUser, MessageFlags } from './mod.ts'; /** @@ -118,7 +119,7 @@ export interface APIBaseInteraction { /** * The command data payload */ - data?: APIApplicationCommandInteractionData; + data?: APIApplicationCommandInteractionData | APIMessageComponentInteractionData; /** * The channel it was sent from */ @@ -169,10 +170,20 @@ export interface APIDMInteraction extends APIBaseInteraction { channel_id: Snowflake; } +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-interaction + */ +export interface APIMessageComponentInteraction extends APIBaseInteraction { + /** + * Message object to which the button was attached + */ + message: APIMessage; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction */ -export type APIInteraction = APIGuildInteraction | APIDMInteraction; +export type APIInteraction = APIGuildInteraction | APIDMInteraction | APIMessageComponentInteraction; /** * Like APIGuildInteraction, only with the `data` property always present @@ -203,6 +214,7 @@ export type APIApplicationCommandInteraction = export enum InteractionType { Ping = 1, ApplicationCommand, + MessageComponent, } /** @@ -346,13 +358,28 @@ export type ApplicationCommandInteractionDataOptionBoolean = InteractionDataOpti boolean >; +export interface APIMessageButtonInteractionData { + custom_id: string; + component_type: ComponentType.Button; +} + +export interface APIMessageSelectMenuInteractionData { + custom_id: string; + component_type: ComponentType.SelectMenu; + values: string[]; +} + +export type APIMessageComponentInteractionData = APIMessageButtonInteractionData | APIMessageSelectMenuInteractionData; + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response */ export type APIInteractionResponse = | APIInteractionResponsePong | APIInteractionResponseChannelMessageWithSource - | APIInteractionResponseDeferredChannelMessageWithSource; + | APIInteractionResponseDeferredChannelMessageWithSource + | APIInteractionResponseDeferredMessageUpdate + | APIInteractionResponseUpdateMessage; export interface APIInteractionResponsePong { type: InteractionResponseType.Pong; @@ -368,6 +395,15 @@ export interface APIInteractionResponseDeferredChannelMessageWithSource { data?: Pick; } +export interface APIInteractionResponseDeferredMessageUpdate { + type: InteractionResponseType.DeferredMessageUpdate; +} + +export interface APIInteractionResponseUpdateMessage { + type: InteractionResponseType.UpdateMessage; + data?: APIInteractionApplicationCommandCallbackData; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype */ @@ -384,6 +420,14 @@ export enum InteractionResponseType { * ACK an interaction and edit to a response later, the user sees a loading state */ DeferredChannelMessageWithSource, + /** + * ACK a button interaction and update it to a loading state + */ + DeferredMessageUpdate, + /** + * ACK a button interaction and edit the message to which the button was attached + */ + UpdateMessage, } /** diff --git a/deno/payloads/v9/channel.ts b/deno/payloads/v9/channel.ts index b869f285..8af9ce45 100644 --- a/deno/payloads/v9/channel.ts +++ b/deno/payloads/v9/channel.ts @@ -378,6 +378,10 @@ export interface APIMessage { * Sent if the message is a response to an Interaction */ interaction?: APIMessageInteraction; + /** + * Sent if the message contains components like buttons, action rows, or other interactive components + */ + components?: APIActionRowComponent[]; /** * Sent if a thread was started from this message */ @@ -1046,3 +1050,148 @@ export interface APIAllowedMentions { */ replied_user?: boolean; } + +/** + * https://discord.com/developers/docs/interactions/message-components + */ +export interface APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-types + */ +export enum ComponentType { + /** + * ActionRow component + */ + ActionRow = 1, + /** + * Button component + */ + Button, + /** + * Select Menu component + */ + SelectMenu, +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APIActionRowComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.ActionRow; + /** + * The components in the ActionRow + */ + components: Exclude[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-object + */ +export interface APIButtonComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.Button; + /** + * The label to be displayed on the button + */ + label?: string; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id?: string; + /** + * The style of the button + */ + style: ButtonStyle; + /** + * The emoji to display to the left of the text + */ + emoji?: APIPartialEmoji; + /** + * The URL to direct users to when clicked for Link buttons + */ + url?: string; + /** + * The status of the button + */ + disabled?: boolean; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectMenuComponent { + /** + * The type of the component + */ + type: ComponentType.SelectMenu; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id: string; + /** + * Custom placeholder text if nothing is selected + */ + placeholder?: string; + /** + * The minimum number of items that must be chosen + */ + min_values?: number; + /** + * The maximum number of items that can be chosen + */ + max_values?: number; + /** + * Choices to display in the select menu + */ + options: APISelectOption[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectOption { + /** + * The user-facing name of the option (max 25 chars) + */ + label: string; + /** + * The dev-defined value of the option (max 100 chars) + */ + value: string; + /** + * An additional description of the option (max 50 chars) + */ + description?: string; + /** + * The emoji to display to the left of the option + */ + emoji?: APIPartialEmoji; + /** + * Whether this option should be already-selected by default + */ + default: boolean; +} + +export type APIMessageComponent = APIActionRowComponent | APIButtonComponent | APISelectMenuComponent; + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-styles + */ +export enum ButtonStyle { + Primary = 1, + Secondary, + Success, + Danger, + Link, +} diff --git a/deno/payloads/v9/interactions.ts b/deno/payloads/v9/interactions.ts index 96daf49e..c6f77f2a 100644 --- a/deno/payloads/v9/interactions.ts +++ b/deno/payloads/v9/interactions.ts @@ -1,5 +1,6 @@ import type { Permissions, Snowflake } from '../../globals.ts'; import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../rest/v9/mod.ts'; +import { APIMessage, ComponentType } from './channel.ts'; import type { APIGuildMember, APIPartialChannel, APIRole, APIUser, MessageFlags } from './mod.ts'; /** @@ -118,7 +119,7 @@ export interface APIBaseInteraction { /** * The command data payload */ - data?: APIApplicationCommandInteractionData; + data?: APIApplicationCommandInteractionData | APIMessageComponentInteractionData; /** * The channel it was sent from */ @@ -169,10 +170,20 @@ export interface APIDMInteraction extends APIBaseInteraction { channel_id: Snowflake; } +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-interaction + */ +export interface APIMessageComponentInteraction extends APIBaseInteraction { + /** + * Message object to which the button was attached + */ + message: APIMessage; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction */ -export type APIInteraction = APIGuildInteraction | APIDMInteraction; +export type APIInteraction = APIGuildInteraction | APIDMInteraction | APIMessageComponentInteraction; /** * Like APIGuildInteraction, only with the `data` property always present @@ -203,6 +214,7 @@ export type APIApplicationCommandInteraction = export enum InteractionType { Ping = 1, ApplicationCommand, + MessageComponent, } /** @@ -346,13 +358,28 @@ export type ApplicationCommandInteractionDataOptionBoolean = InteractionDataOpti boolean >; +export interface APIMessageButtonInteractionData { + custom_id: string; + component_type: ComponentType.Button; +} + +export interface APIMessageSelectMenuInteractionData { + custom_id: string; + component_type: ComponentType.SelectMenu; + values: string[]; +} + +export type APIMessageComponentInteractionData = APIMessageButtonInteractionData | APIMessageSelectMenuInteractionData; + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response */ export type APIInteractionResponse = | APIInteractionResponsePong | APIInteractionResponseChannelMessageWithSource - | APIInteractionResponseDeferredChannelMessageWithSource; + | APIInteractionResponseDeferredChannelMessageWithSource + | APIInteractionResponseDeferredMessageUpdate + | APIInteractionResponseUpdateMessage; export interface APIInteractionResponsePong { type: InteractionResponseType.Pong; @@ -368,6 +395,15 @@ export interface APIInteractionResponseDeferredChannelMessageWithSource { data?: Pick; } +export interface APIInteractionResponseDeferredMessageUpdate { + type: InteractionResponseType.DeferredMessageUpdate; +} + +export interface APIInteractionResponseUpdateMessage { + type: InteractionResponseType.UpdateMessage; + data?: APIInteractionApplicationCommandCallbackData; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype */ @@ -384,6 +420,14 @@ export enum InteractionResponseType { * ACK an interaction and edit to a response later, the user sees a loading state */ DeferredChannelMessageWithSource, + /** + * ACK a button interaction and update it to a loading state + */ + DeferredMessageUpdate, + /** + * ACK a button interaction and edit the message to which the button was attached + */ + UpdateMessage, } /** diff --git a/gateway/v8.ts b/gateway/v8.ts index ed53bec4..9dae44c7 100644 --- a/gateway/v8.ts +++ b/gateway/v8.ts @@ -13,6 +13,7 @@ import type { APIGuildIntegration, APIGuildMember, APIMessage, + APIMessageComponentInteraction, APIRole, APIUnavailableGuild, APIUser, @@ -889,7 +890,7 @@ export type GatewayInteractionCreateDispatch = DataPayload< /** * https://discord.com/developers/docs/topics/gateway#interaction-create */ -export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction; +export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction | APIMessageComponentInteraction; /** * https://discord.com/developers/docs/topics/gateway#invite-create diff --git a/gateway/v9.ts b/gateway/v9.ts index dd7eb5b8..f74de589 100644 --- a/gateway/v9.ts +++ b/gateway/v9.ts @@ -13,6 +13,7 @@ import type { APIGuildIntegration, APIGuildMember, APIMessage, + APIMessageComponentInteraction, APIRole, APIThreadMember, APIUnavailableGuild, @@ -902,7 +903,7 @@ export type GatewayInteractionCreateDispatch = DataPayload< /** * https://discord.com/developers/docs/topics/gateway#interaction-create */ -export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction; +export type GatewayInteractionCreateDispatchData = APIApplicationCommandInteraction | APIMessageComponentInteraction; /** * https://discord.com/developers/docs/topics/gateway#invite-create diff --git a/payloads/v8/channel.ts b/payloads/v8/channel.ts index 1c8f03e5..c7581eef 100644 --- a/payloads/v8/channel.ts +++ b/payloads/v8/channel.ts @@ -342,6 +342,10 @@ export interface APIMessage { * Sent if the message is a response to an Interaction */ interaction?: APIMessageInteraction; + /** + * Sent if the message contains components like buttons, action rows, or other interactive components + */ + components?: APIActionRowComponent[]; } /** @@ -930,3 +934,148 @@ export interface APIAllowedMentions { */ replied_user?: boolean; } + +/** + * https://discord.com/developers/docs/interactions/message-components + */ +export interface APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-types + */ +export const enum ComponentType { + /** + * ActionRow component + */ + ActionRow = 1, + /** + * Button component + */ + Button, + /** + * Select Menu component + */ + SelectMenu, +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APIActionRowComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.ActionRow; + /** + * The components in the ActionRow + */ + components: Exclude[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-object + */ +export interface APIButtonComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.Button; + /** + * The label to be displayed on the button + */ + label?: string; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id?: string; + /** + * The style of the button + */ + style: ButtonStyle; + /** + * The emoji to display to the left of the text + */ + emoji?: APIPartialEmoji; + /** + * The URL to direct users to when clicked for Link buttons + */ + url?: string; + /** + * The status of the button + */ + disabled?: boolean; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectMenuComponent { + /** + * The type of the component + */ + type: ComponentType.SelectMenu; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id: string; + /** + * Custom placeholder text if nothing is selected + */ + placeholder?: string; + /** + * The minimum number of items that must be chosen + */ + min_values?: number; + /** + * The maximum number of items that can be chosen + */ + max_values?: number; + /** + * Choices to display in the select menu + */ + options: APISelectOption[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectOption { + /** + * The user-facing name of the option (max 25 chars) + */ + label: string; + /** + * The dev-defined value of the option (max 100 chars) + */ + value: string; + /** + * An additional description of the option (max 50 chars) + */ + description?: string; + /** + * The emoji to display to the left of the option + */ + emoji?: APIPartialEmoji; + /** + * Whether this option should be already-selected by default + */ + default: boolean; +} + +export type APIMessageComponent = APIActionRowComponent | APIButtonComponent | APISelectMenuComponent; + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-styles + */ +export const enum ButtonStyle { + Primary = 1, + Secondary, + Success, + Danger, + Link, +} diff --git a/payloads/v8/interactions.ts b/payloads/v8/interactions.ts index e8e05286..ad7b14a8 100644 --- a/payloads/v8/interactions.ts +++ b/payloads/v8/interactions.ts @@ -1,5 +1,6 @@ import type { Permissions, Snowflake } from '../../globals'; import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../rest/v8/index'; +import { APIMessage, ComponentType } from './channel'; import type { APIGuildMember, APIPartialChannel, APIRole, APIUser, MessageFlags } from './index'; /** @@ -118,7 +119,7 @@ export interface APIBaseInteraction { /** * The command data payload */ - data?: APIApplicationCommandInteractionData; + data?: APIApplicationCommandInteractionData | APIMessageComponentInteractionData; /** * The channel it was sent from */ @@ -169,10 +170,20 @@ export interface APIDMInteraction extends APIBaseInteraction { channel_id: Snowflake; } +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-interaction + */ +export interface APIMessageComponentInteraction extends APIBaseInteraction { + /** + * Message object to which the button was attached + */ + message: APIMessage; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction */ -export type APIInteraction = APIGuildInteraction | APIDMInteraction; +export type APIInteraction = APIGuildInteraction | APIDMInteraction | APIMessageComponentInteraction; /** * Like APIGuildInteraction, only with the `data` property always present @@ -203,6 +214,7 @@ export type APIApplicationCommandInteraction = export const enum InteractionType { Ping = 1, ApplicationCommand, + MessageComponent, } /** @@ -346,13 +358,28 @@ export type ApplicationCommandInteractionDataOptionBoolean = InteractionDataOpti boolean >; +export interface APIMessageButtonInteractionData { + custom_id: string; + component_type: ComponentType.Button; +} + +export interface APIMessageSelectMenuInteractionData { + custom_id: string; + component_type: ComponentType.SelectMenu; + values: string[]; +} + +export type APIMessageComponentInteractionData = APIMessageButtonInteractionData | APIMessageSelectMenuInteractionData; + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response */ export type APIInteractionResponse = | APIInteractionResponsePong | APIInteractionResponseChannelMessageWithSource - | APIInteractionResponseDeferredChannelMessageWithSource; + | APIInteractionResponseDeferredChannelMessageWithSource + | APIInteractionResponseDeferredMessageUpdate + | APIInteractionResponseUpdateMessage; export interface APIInteractionResponsePong { type: InteractionResponseType.Pong; @@ -368,6 +395,15 @@ export interface APIInteractionResponseDeferredChannelMessageWithSource { data?: Pick; } +export interface APIInteractionResponseDeferredMessageUpdate { + type: InteractionResponseType.DeferredMessageUpdate; +} + +export interface APIInteractionResponseUpdateMessage { + type: InteractionResponseType.UpdateMessage; + data?: APIInteractionApplicationCommandCallbackData; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype */ @@ -384,6 +420,14 @@ export const enum InteractionResponseType { * ACK an interaction and edit to a response later, the user sees a loading state */ DeferredChannelMessageWithSource, + /** + * ACK a button interaction and update it to a loading state + */ + DeferredMessageUpdate, + /** + * ACK a button interaction and edit the message to which the button was attached + */ + UpdateMessage, } /** diff --git a/payloads/v9/channel.ts b/payloads/v9/channel.ts index 13b39de4..800f5aa7 100644 --- a/payloads/v9/channel.ts +++ b/payloads/v9/channel.ts @@ -378,6 +378,10 @@ export interface APIMessage { * Sent if the message is a response to an Interaction */ interaction?: APIMessageInteraction; + /** + * Sent if the message contains components like buttons, action rows, or other interactive components + */ + components?: APIActionRowComponent[]; /** * Sent if a thread was started from this message */ @@ -1046,3 +1050,148 @@ export interface APIAllowedMentions { */ replied_user?: boolean; } + +/** + * https://discord.com/developers/docs/interactions/message-components + */ +export interface APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-types + */ +export const enum ComponentType { + /** + * ActionRow component + */ + ActionRow = 1, + /** + * Button component + */ + Button, + /** + * Select Menu component + */ + SelectMenu, +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APIActionRowComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.ActionRow; + /** + * The components in the ActionRow + */ + components: Exclude[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-object + */ +export interface APIButtonComponent extends APIBaseComponent { + /** + * The type of the component + */ + type: ComponentType.Button; + /** + * The label to be displayed on the button + */ + label?: string; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id?: string; + /** + * The style of the button + */ + style: ButtonStyle; + /** + * The emoji to display to the left of the text + */ + emoji?: APIPartialEmoji; + /** + * The URL to direct users to when clicked for Link buttons + */ + url?: string; + /** + * The status of the button + */ + disabled?: boolean; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectMenuComponent { + /** + * The type of the component + */ + type: ComponentType.SelectMenu; + /** + * The custom_id to be sent in the interaction when clicked + */ + custom_id: string; + /** + * Custom placeholder text if nothing is selected + */ + placeholder?: string; + /** + * The minimum number of items that must be chosen + */ + min_values?: number; + /** + * The maximum number of items that can be chosen + */ + max_values?: number; + /** + * Choices to display in the select menu + */ + options: APISelectOption[]; +} + +/** + * https://discord.com/developers/docs/interactions/message-components#component-object + */ +export interface APISelectOption { + /** + * The user-facing name of the option (max 25 chars) + */ + label: string; + /** + * The dev-defined value of the option (max 100 chars) + */ + value: string; + /** + * An additional description of the option (max 50 chars) + */ + description?: string; + /** + * The emoji to display to the left of the option + */ + emoji?: APIPartialEmoji; + /** + * Whether this option should be already-selected by default + */ + default: boolean; +} + +export type APIMessageComponent = APIActionRowComponent | APIButtonComponent | APISelectMenuComponent; + +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-styles + */ +export const enum ButtonStyle { + Primary = 1, + Secondary, + Success, + Danger, + Link, +} diff --git a/payloads/v9/interactions.ts b/payloads/v9/interactions.ts index 70c3bcd3..16084358 100644 --- a/payloads/v9/interactions.ts +++ b/payloads/v9/interactions.ts @@ -1,5 +1,6 @@ import type { Permissions, Snowflake } from '../../globals'; import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../rest/v9/index'; +import { APIMessage, ComponentType } from './channel'; import type { APIGuildMember, APIPartialChannel, APIRole, APIUser, MessageFlags } from './index'; /** @@ -118,7 +119,7 @@ export interface APIBaseInteraction { /** * The command data payload */ - data?: APIApplicationCommandInteractionData; + data?: APIApplicationCommandInteractionData | APIMessageComponentInteractionData; /** * The channel it was sent from */ @@ -169,10 +170,20 @@ export interface APIDMInteraction extends APIBaseInteraction { channel_id: Snowflake; } +/** + * https://discord.com/developers/docs/interactions/message-components#buttons-button-interaction + */ +export interface APIMessageComponentInteraction extends APIBaseInteraction { + /** + * Message object to which the button was attached + */ + message: APIMessage; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction */ -export type APIInteraction = APIGuildInteraction | APIDMInteraction; +export type APIInteraction = APIGuildInteraction | APIDMInteraction | APIMessageComponentInteraction; /** * Like APIGuildInteraction, only with the `data` property always present @@ -203,6 +214,7 @@ export type APIApplicationCommandInteraction = export const enum InteractionType { Ping = 1, ApplicationCommand, + MessageComponent, } /** @@ -346,13 +358,28 @@ export type ApplicationCommandInteractionDataOptionBoolean = InteractionDataOpti boolean >; +export interface APIMessageButtonInteractionData { + custom_id: string; + component_type: ComponentType.Button; +} + +export interface APIMessageSelectMenuInteractionData { + custom_id: string; + component_type: ComponentType.SelectMenu; + values: string[]; +} + +export type APIMessageComponentInteractionData = APIMessageButtonInteractionData | APIMessageSelectMenuInteractionData; + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response */ export type APIInteractionResponse = | APIInteractionResponsePong | APIInteractionResponseChannelMessageWithSource - | APIInteractionResponseDeferredChannelMessageWithSource; + | APIInteractionResponseDeferredChannelMessageWithSource + | APIInteractionResponseDeferredMessageUpdate + | APIInteractionResponseUpdateMessage; export interface APIInteractionResponsePong { type: InteractionResponseType.Pong; @@ -368,6 +395,15 @@ export interface APIInteractionResponseDeferredChannelMessageWithSource { data?: Pick; } +export interface APIInteractionResponseDeferredMessageUpdate { + type: InteractionResponseType.DeferredMessageUpdate; +} + +export interface APIInteractionResponseUpdateMessage { + type: InteractionResponseType.UpdateMessage; + data?: APIInteractionApplicationCommandCallbackData; +} + /** * https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype */ @@ -384,6 +420,14 @@ export const enum InteractionResponseType { * ACK an interaction and edit to a response later, the user sees a loading state */ DeferredChannelMessageWithSource, + /** + * ACK a button interaction and update it to a loading state + */ + DeferredMessageUpdate, + /** + * ACK a button interaction and edit the message to which the button was attached + */ + UpdateMessage, } /**