import type { Model } from "../Base.ts"; import type { Session } from "../../Session.ts"; import type { DiscordInteraction, DiscordMessage, DiscordMessageComponents, } from "../../../discordeno/mod.ts"; import type CommandInteraction from "./CommandInteraction.ts"; import type PingInteraction from "./PingInteraction.ts"; import type ComponentInteraction from "./ComponentInteraction.ts"; import type ModalSubmitInteraction from "./ModalSubmitInteraction.ts"; import type AutoCompleteInteraction from "./AutoCompleteInteraction.ts"; import type { CreateMessage } from "../Message.ts"; import type { MessageFlags } from "../../Util.ts"; import type { EditWebhookMessage } from "../Webhook.ts"; import { InteractionTypes, InteractionResponseTypes } from "../../../discordeno/mod.ts"; import { Snowflake } from "../../Snowflake.ts"; import User from "../User.ts"; import Member from "../Member.ts"; import Message from "../Message.ts"; import Permsisions from "../Permissions.ts"; import Webhook from "../Webhook.ts"; import * as Routes from "../../Routes.ts"; /** * @link https://discord.com/developers/docs/interactions/slash-commands#interaction-response */ export interface InteractionResponse { type: InteractionResponseTypes; data?: InteractionApplicationCommandCallbackData; } /** * @link https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionapplicationcommandcallbackdata */ export interface InteractionApplicationCommandCallbackData extends Pick { customId?: string; title?: string; components?: DiscordMessageComponents; flags?: MessageFlags; choices?: ApplicationCommandOptionChoice[]; } /** * @link https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoptionchoice */ export interface ApplicationCommandOptionChoice { name: string; value: string | number; } export abstract class BaseInteraction implements Model { constructor(session: Session, data: DiscordInteraction) { this.session = session; this.id = data.id; this.token = data.token; this.type = data.type; this.guildId = data.guild_id; this.channelId = data.channel_id; this.applicationId = data.application_id; this.version = data.version; // @ts-expect-error: vendor error const perms = data.app_permissions as string; if (perms) { this.appPermissions = new Permsisions(BigInt(perms)); } if (!data.guild_id) { this.user = new User(session, data.user!); } else { this.member = new Member(session, data.member!, data.guild_id); } } readonly session: Session; readonly id: Snowflake; readonly token: string; type: InteractionTypes; guildId?: Snowflake; channelId?: Snowflake; applicationId?: Snowflake; user?: User; member?: Member; appPermissions?: Permsisions; readonly version: 1; responded = false; get createdTimestamp(): number { return Snowflake.snowflakeToTimestamp(this.id); } get createdAt(): Date { return new Date(this.createdTimestamp); } isCommand(): this is CommandInteraction { return this.type === InteractionTypes.ApplicationCommand; } isAutoComplete(): this is AutoCompleteInteraction { return this.type === InteractionTypes.ApplicationCommandAutocomplete; } isComponent(): this is ComponentInteraction { return this.type === InteractionTypes.MessageComponent; } isPing(): this is PingInteraction { return this.type === InteractionTypes.Ping; } isModalSubmit(): this is ModalSubmitInteraction { return this.type === InteractionTypes.ModalSubmit; } inGuild(): this is this & { guildId: Snowflake } { return !!this.guildId; } // webhooks methods: async editReply(options: EditWebhookMessage & { messageId?: Snowflake }): Promise { const message = await this.session.rest.runMethod( this.session.rest, "PATCH", options.messageId ? Routes.WEBHOOK_MESSAGE(this.id, this.token, options.messageId) : Routes.WEBHOOK_MESSAGE_ORIGINAL(this.id, this.token), { content: options.content, embeds: options.embeds, file: options.files, components: options.components, allowed_mentions: options.allowedMentions || { parse: options.allowedMentions!.parse, replied_user: options.allowedMentions!.repliedUser, users: options.allowedMentions!.users, roles: options.allowedMentions!.roles, }, attachments: options.attachments?.map((attachment) => { return { id: attachment.id, filename: attachment.name, content_type: attachment.contentType, size: attachment.size, url: attachment.attachment, proxy_url: attachment.proxyUrl, height: attachment.height, width: attachment.width, }; }), message_id: options.messageId, } ); if (!message || !options.messageId) { return message as undefined; } return new Message(this.session, message); } async sendFollowUp(options: InteractionApplicationCommandCallbackData): Promise { const message = await Webhook.prototype.execute.call({ id: this.applicationId!, token: this.token, session: this.session, }, options); return message!; } async editFollowUp(messageId: Snowflake, options?: { threadId: Snowflake }): Promise { const message = await Webhook.prototype.editMessage.call( { id: this.session.applicationId, token: this.token, }, messageId, options ); return message; } async deleteFollowUp(messageId: Snowflake, options?: { threadId?: Snowflake }): Promise { await Webhook.prototype.deleteMessage.call( { id: this.session.applicationId, token: this.token }, messageId, options ); } async fetchFollowUp(messageId: Snowflake, options?: { threadId?: Snowflake }): Promise { const message = await Webhook.prototype.fetchMessage.call( { id: this.session.applicationId, token: this.token, }, messageId, options ); return message; } // end webhook methods // deno-fmt-ignore async respond(resp: InteractionResponse): Promise; async respond(resp: { with: InteractionApplicationCommandCallbackData }): Promise; async respond(resp: InteractionResponse | { with: InteractionApplicationCommandCallbackData }): Promise { const options = "with" in resp ? resp.with : resp.data; const type = "type" in resp ? resp.type : InteractionResponseTypes.ChannelMessageWithSource; const data = { content: options?.content, custom_id: options?.customId, file: options?.files, allowed_mentions: options?.allowedMentions, flags: options?.flags, chocies: options?.choices, embeds: options?.embeds, title: options?.title, components: options?.components, }; if (!this.responded) { await this.session.rest.sendRequest(this.session.rest, { url: Routes.INTERACTION_ID_TOKEN(this.id, this.token), method: "POST", payload: this.session.rest.createRequestBody(this.session.rest, { method: "POST", body: { type, data, file: options?.files }, headers: { "Authorization": "" }, }), }); this.responded = true; return; } return this.sendFollowUp(data); } // start custom methods async respondWith(resp: InteractionApplicationCommandCallbackData): Promise { const m = await this.respond({ with: resp }); return m; } async defer() { await this.respond({ type: InteractionResponseTypes.DeferredChannelMessageWithSource }); } async autocomplete() { await this.respond({ type: InteractionResponseTypes.ApplicationCommandAutocompleteResult }); } // end custom methods } export default BaseInteraction;