diff --git a/packages/core/src/api/interactions.ts b/packages/core/src/api/interactions.ts index 797e71caa6ea..9fe693d47471 100644 --- a/packages/core/src/api/interactions.ts +++ b/packages/core/src/api/interactions.ts @@ -1,6 +1,6 @@ /* eslint-disable jsdoc/check-param-names */ -import type { RawFile, RequestData, REST } from '@discordjs/rest'; +import { makeURLSearchParams, type RawFile, type RequestData, type REST } from '@discordjs/rest'; import { InteractionResponseType, Routes, @@ -10,6 +10,8 @@ import { type APIModalInteractionResponseCallbackData, type APIPremiumRequiredInteractionResponse, type RESTGetAPIWebhookWithTokenMessageResult, + type RESTPostAPIInteractionCallbackQuery, + type RESTPostAPIInteractionCallbackWithResponseResult, type Snowflake, } from 'discord-api-types/v10'; import type { WebhooksAPI } from './webhook.js'; @@ -20,6 +22,23 @@ export class InteractionsAPI { private readonly webhooks: WebhooksAPI, ) {} + /** + * Replies to an interaction and returns an interaction callback object + * + * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} + * @param interactionId - The id of the interaction + * @param interactionToken - The token of the interaction + * @param body - The callback data for replying + * @param options - The options for replying + */ + public async reply( + interactionId: Snowflake, + interactionToken: string, + body: APIInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { files?: RawFile[]; with_response: true }, + options?: Pick, + ): Promise; + /** * Replies to an interaction * @@ -32,10 +51,23 @@ export class InteractionsAPI { public async reply( interactionId: Snowflake, interactionToken: string, - { files, ...data }: APIInteractionResponseCallbackData & { files?: RawFile[] }, + body: APIInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { files?: RawFile[]; with_response?: false }, + options?: Pick, + ): Promise; + + public async reply( + interactionId: Snowflake, + interactionToken: string, + { + files, + with_response, + ...data + }: APIInteractionResponseCallbackData & RESTPostAPIInteractionCallbackQuery & { files?: RawFile[] }, { signal }: Pick = {}, ) { - await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + const response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + query: makeURLSearchParams({ with_response }), files, auth: false, body: { @@ -44,24 +76,55 @@ export class InteractionsAPI { }, signal, }); + + return with_response ? response : undefined; } + /** + * Defers the reply to an interaction and returns an interaction callback object + * + * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} + * @param interactionId - The id of the interaction + * @param interactionToken - The token of the interaction + * @param body - The callback data for deferring the reply + * @param options - The options for deferring + */ + public async defer( + interactionId: Snowflake, + interactionToken: string, + body: APIInteractionResponseDeferredChannelMessageWithSource['data'] & + RESTPostAPIInteractionCallbackQuery & { with_response: true }, + options?: Pick, + ): Promise; + /** * Defers the reply to an interaction * * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} * @param interactionId - The id of the interaction * @param interactionToken - The token of the interaction - * @param data - The data for deferring the reply + * @param body - The callback data for deferring the reply * @param options - The options for deferring */ public async defer( interactionId: Snowflake, interactionToken: string, - data?: APIInteractionResponseDeferredChannelMessageWithSource['data'], + body?: APIInteractionResponseDeferredChannelMessageWithSource['data'] & + RESTPostAPIInteractionCallbackQuery & { with_response?: false }, + options?: Pick, + ): Promise; + + public async defer( + interactionId: Snowflake, + interactionToken: string, + { + with_response, + ...data + }: APIInteractionResponseDeferredChannelMessageWithSource['data'] & RESTPostAPIInteractionCallbackQuery = {}, { signal }: Pick = {}, ) { - await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + const response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + query: makeURLSearchParams({ with_response }), auth: false, body: { type: InteractionResponseType.DeferredChannelMessageWithSource, @@ -69,28 +132,58 @@ export class InteractionsAPI { }, signal, }); + + return with_response ? response : undefined; } + /** + * Defers an update from a message component interaction and returns an interaction callback object + * + * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} + * @param interactionId - The id of the interaction + * @param interactionToken - The token of the interaction + * @param body - The callback data for deferring the update + * @param options - The options for deferring + */ + public async deferMessageUpdate( + interactionId: Snowflake, + interactionToken: string, + body: RESTPostAPIInteractionCallbackQuery & { with_response: true }, + options?: Pick, + ): Promise; + /** * Defers an update from a message component interaction * * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} * @param interactionId - The id of the interaction * @param interactionToken - The token of the interaction + * @param body - The callback data for deferring the update * @param options - The options for deferring */ public async deferMessageUpdate( interactionId: Snowflake, interactionToken: string, + body?: RESTPostAPIInteractionCallbackQuery & { with_response?: false }, + options?: Pick, + ): Promise; + + public async deferMessageUpdate( + interactionId: Snowflake, + interactionToken: string, + { with_response }: RESTPostAPIInteractionCallbackQuery = {}, { signal }: Pick = {}, ) { - await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + const response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + query: makeURLSearchParams({ with_response }), auth: false, body: { type: InteractionResponseType.DeferredMessageUpdate, }, signal, }); + + return with_response ? response : undefined; } /** @@ -175,6 +268,23 @@ export class InteractionsAPI { await this.webhooks.deleteMessage(applicationId, interactionToken, messageId ?? '@original', {}, { signal }); } + /** + * Updates the message the component interaction was triggered on and returns an interaction callback object + * + * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} + * @param interactionId - The id of the interaction + * @param interactionToken - The token of the interaction + * @param callbackData - The callback data for updating the interaction + * @param options - The options for updating the interaction + */ + public async updateMessage( + interactionId: Snowflake, + interactionToken: string, + callbackData: APIInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { files?: RawFile[]; with_response: true }, + options: Pick, + ): Promise; + /** * Updates the message the component interaction was triggered on * @@ -187,10 +297,22 @@ export class InteractionsAPI { public async updateMessage( interactionId: Snowflake, interactionToken: string, - { files, ...data }: APIInteractionResponseCallbackData & { files?: RawFile[] }, + callbackData: APIInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { files?: RawFile[]; with_response?: false }, + options: Pick, + ): Promise; + + public async updateMessage( + interactionId: Snowflake, + interactionToken: string, + { + files, + with_response, + ...data + }: APIInteractionResponseCallbackData & RESTPostAPIInteractionCallbackQuery & { files?: RawFile[] }, { signal }: Pick = {}, ) { - await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + const response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { files, auth: false, body: { @@ -199,8 +321,27 @@ export class InteractionsAPI { }, signal, }); + + return with_response ? response : undefined; } + /** + * Sends an autocomplete response to an interaction and returns an interaction callback object + * + * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} + * @param interactionId - The id of the interaction + * @param interactionToken - The token of the interaction + * @param callbackData - The callback data for the autocomplete response + * @param options - The options for sending the autocomplete response + */ + public async createAutocompleteResponse( + interactionId: Snowflake, + interactionToken: string, + callbackData: APICommandAutocompleteInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { with_response: true }, + options?: Pick, + ): Promise; + /** * Sends an autocomplete response to an interaction * @@ -213,19 +354,49 @@ export class InteractionsAPI { public async createAutocompleteResponse( interactionId: Snowflake, interactionToken: string, - callbackData: APICommandAutocompleteInteractionResponseCallbackData, + callbackData: APICommandAutocompleteInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { with_response?: false }, + options: Pick, + ): Promise; + + public async createAutocompleteResponse( + interactionId: Snowflake, + interactionToken: string, + { + with_response, + ...data + }: APICommandAutocompleteInteractionResponseCallbackData & RESTPostAPIInteractionCallbackQuery, { signal }: Pick = {}, ) { - await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + const response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { auth: false, body: { type: InteractionResponseType.ApplicationCommandAutocompleteResult, - data: callbackData, + data, }, signal, }); + + return with_response ? response : undefined; } + /** + * Sends a modal response to an interaction and returns an interaction callback object + * + * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response} + * @param interactionId - The id of the interaction + * @param interactionToken - The token of the interaction + * @param callbackData - The modal callback data to send + * @param options - The options for sending the modal + */ + public async createModal( + interactionId: Snowflake, + interactionToken: string, + callbackData: APIModalInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { with_response: true }, + options?: Pick, + ): Promise; + /** * Sends a modal response to an interaction * @@ -238,17 +409,27 @@ export class InteractionsAPI { public async createModal( interactionId: Snowflake, interactionToken: string, - callbackData: APIModalInteractionResponseCallbackData, + callbackData: APIModalInteractionResponseCallbackData & + RESTPostAPIInteractionCallbackQuery & { with_response?: false }, + options?: Pick, + ): Promise; + + public async createModal( + interactionId: Snowflake, + interactionToken: string, + { with_response, ...data }: APIModalInteractionResponseCallbackData & RESTPostAPIInteractionCallbackQuery, { signal }: Pick = {}, ) { - await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { + const response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), { auth: false, body: { type: InteractionResponseType.Modal, - data: callbackData, + data, }, signal, }); + + return with_response ? response : undefined; } /**