UNPKG

seyfert

Version:

The most advanced framework for discord bots

659 lines (658 loc) 27 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ModalSubmitInteraction = exports.MessageCommandInteraction = exports.UserCommandInteraction = exports.ChatInputCommandInteraction = exports.UserSelectMenuInteraction = exports.RoleSelectMenuInteraction = exports.MentionableSelectMenuInteraction = exports.ChannelSelectMenuInteraction = exports.StringSelectMenuInteraction = exports.SelectMenuInteraction = exports.ButtonInteraction = exports.ComponentInteraction = exports.EntryPointInteraction = exports.ApplicationCommandInteraction = exports.Interaction = exports.AutocompleteInteraction = exports.BaseInteraction = void 0; const builders_1 = require("../builders"); const Label_1 = require("../builders/Label"); const transformers_1 = require("../client/transformers"); const common_1 = require("../common"); const mixer_1 = require("../deps/mixer"); const types_1 = require("../types"); const _1 = require("./"); const DiscordBase_1 = require("./extra/DiscordBase"); const Permissions_1 = require("./extra/Permissions"); class BaseInteraction extends DiscordBase_1.DiscordBase { client; __reply; user; member; channel; message; replied; deferred; appPermissions; entitlements; constructor(client, interaction, __reply) { super(client, interaction); this.client = client; this.__reply = __reply; if (interaction.member) { this.member = transformers_1.Transformers.InteractionGuildMember(client, interaction.member, interaction.member.user, interaction.guild_id); } if (interaction.message) { this.message = transformers_1.Transformers.Message(client, interaction.message); } this.appPermissions = new Permissions_1.PermissionsBitField(BigInt(interaction.app_permissions)); if ('channel' in interaction) { this.channel = (0, _1.channelFrom)(interaction.channel, client); } this.user = this.member?.user ?? transformers_1.Transformers.User(client, interaction.user); this.entitlements = interaction.entitlements.map(e => transformers_1.Transformers.Entitlement(this.client, e)); } static transformBodyRequest(body, files, self) { switch (body.type) { case types_1.InteractionResponseType.ApplicationCommandAutocompleteResult: case types_1.InteractionResponseType.DeferredMessageUpdate: case types_1.InteractionResponseType.DeferredChannelMessageWithSource: return body; case types_1.InteractionResponseType.ChannelMessageWithSource: case types_1.InteractionResponseType.UpdateMessage: { //@ts-ignore return { type: body.type, // @ts-expect-error data: BaseInteraction.transformBody(body.data ?? {}, files, self), }; } case types_1.InteractionResponseType.Modal: return { type: body.type, data: body.data instanceof builders_1.Modal ? body.data.toJSON() : { ...body.data, components: body.data?.components ? body.data.components.map(x => (x instanceof Label_1.Label ? x.toJSON() : x)) : [], }, }; case types_1.InteractionResponseType.LaunchActivity: return body; default: return body; } } static transformBody(body, files, self) { const poll = body.poll; const payload = { allowed_mentions: self.options?.allowedMentions, ...body, components: body.components?.map(x => (x instanceof builders_1.ActionRow ? x.toJSON() : x)), embeds: body?.embeds?.map(x => (x instanceof builders_1.Embed ? x.toJSON() : x)), poll: poll ? (poll instanceof builders_1.PollBuilder ? poll.toJSON() : poll) : undefined, }; if (Array.isArray(body.attachments)) { payload.attachments = body.attachments.map((x, i) => { if (x instanceof builders_1.Attachment) { return { id: x.id ?? i.toString(), title: x.title, description: x.description, filename: x.filename, }; } return { id: x.id ?? i.toString(), ...(0, builders_1.resolveAttachment)(x), }; }); } else if (files?.length) { payload.attachments = files?.map(({ filename }, i) => ({ id: i.toString(), filename, })); } return payload; } async matchReplied(body, withResponse = false) { if (this.__reply) { //@ts-expect-error const { files, ...rest } = body.data ?? {}; //@ts-expect-error const data = body.data instanceof builders_1.Modal ? body.data : rest; const parsedFiles = files ? await (0, builders_1.resolveFiles)(files) : undefined; await (this.replied = this.__reply({ body: BaseInteraction.transformBodyRequest({ data, type: body.type }, parsedFiles, this.client), files: parsedFiles, }).then(() => (this.replied = true))); return; } const result = await (this.replied = this.client.interactions.reply(this.id, this.token, body, withResponse)); this.replied = true; return result?.resource?.message ? transformers_1.Transformers.WebhookMessage(this.client, result.resource.message, this.id, this.token) : undefined; } async reply(body, withResponse) { if (this.replied) { throw new common_1.SeyfertError('INTERACTION_ALREADY_REPLIED', { metadata: { detail: 'Interaction already replied' } }); } const result = await this.matchReplied(body, withResponse); // @ts-expect-error if (body.data instanceof builders_1.Modal) { // @ts-expect-error if (body.data.__exec) this.client.components.modals.set(this.user.id, body.data.__exec); else if (this.client.components.modals.has(this.user.id)) this.client.components.modals.delete(this.user.id); } return result; } deferReply(flags, withResponse) { this.deferred = true; return this.reply({ type: types_1.InteractionResponseType.DeferredChannelMessageWithSource, data: { flags, }, }, withResponse); } isButton() { return false; } isChannelSelectMenu() { return false; } isRoleSelectMenu() { return false; } isMentionableSelectMenu() { return false; } isUserSelectMenu() { return false; } isStringSelectMenu() { return false; } isChatInput() { return false; } isUser() { return false; } isMessage() { return false; } isAutocomplete() { return false; } isModal() { return false; } isEntryPoint() { return false; } static from(client, gateway, __reply) { switch (gateway.type) { case types_1.InteractionType.ApplicationCommandAutocomplete: return new AutocompleteInteraction(client, gateway, undefined, __reply); case types_1.InteractionType.ApplicationCommand: switch (gateway.data.type) { case types_1.ApplicationCommandType.ChatInput: return new ChatInputCommandInteraction(client, gateway, __reply); case types_1.ApplicationCommandType.User: return new UserCommandInteraction(client, gateway, __reply); case types_1.ApplicationCommandType.Message: return new MessageCommandInteraction(client, gateway, __reply); case types_1.ApplicationCommandType.PrimaryEntryPoint: return new EntryPointInteraction(client, gateway, __reply); } case types_1.InteractionType.MessageComponent: switch (gateway.data.component_type) { case types_1.ComponentType.Button: return new ButtonInteraction(client, gateway, __reply); case types_1.ComponentType.ChannelSelect: return new ChannelSelectMenuInteraction(client, gateway, __reply); case types_1.ComponentType.RoleSelect: return new RoleSelectMenuInteraction(client, gateway, __reply); case types_1.ComponentType.MentionableSelect: return new MentionableSelectMenuInteraction(client, gateway, __reply); case types_1.ComponentType.UserSelect: return new UserSelectMenuInteraction(client, gateway, __reply); case types_1.ComponentType.StringSelect: return new StringSelectMenuInteraction(client, gateway, __reply); default: return; } case types_1.InteractionType.ModalSubmit: return new ModalSubmitInteraction(client, gateway); default: return new BaseInteraction(client, gateway); } } fetchGuild(mode = 'flow') { if (!this.guildId) return mode === 'cache' ? (this.client.cache.adapter.isAsync ? Promise.resolve() : undefined) : Promise.resolve(); switch (mode) { case 'cache': return (this.client.cache.guilds?.get(this.guildId) || (this.client.cache.adapter.isAsync ? Promise.resolve() : undefined)); default: return this.client.guilds.fetch(this.guildId, mode === 'rest'); } } } exports.BaseInteraction = BaseInteraction; class AutocompleteInteraction extends BaseInteraction { __reply; options; constructor(client, interaction, resolver, __reply) { super(client, interaction); this.__reply = __reply; this.options = resolver ?? transformers_1.Transformers.OptionResolver(client, interaction.data.options, undefined, interaction.guild_id, interaction.data.resolved); } getInput() { return this.options.getAutocompleteValue() ?? ''; } respond(choices) { return super.reply({ data: { choices }, type: types_1.InteractionResponseType.ApplicationCommandAutocompleteResult }); } isAutocomplete() { return true; } /** @intenal */ async reply(..._args) { throw new common_1.SeyfertError('CANNOT_USE_REPLY', { metadata: { detail: 'Cannot use reply in this interaction' }, }); } } exports.AutocompleteInteraction = AutocompleteInteraction; class Interaction extends BaseInteraction { fetchMessage(messageId) { return this.client.interactions.fetchResponse(this.token, messageId); } fetchResponse() { return this.fetchMessage('@original'); } write(body, withResponse) { return this.reply({ type: types_1.InteractionResponseType.ChannelMessageWithSource, data: body, }, withResponse); } async modal(body, options) { if (options !== undefined && !(body instanceof builders_1.Modal)) { body = new builders_1.Modal(body); } if (options === undefined) return this.reply({ type: types_1.InteractionResponseType.Modal, data: body, }); const promise = new Promise(res => { let nodeTimeout; // body is always a modal here, so we can safely cast it body.__exec = (interaction) => { res(interaction); clearTimeout(nodeTimeout); }; if (options?.waitFor && options?.waitFor > 0) { nodeTimeout = setTimeout(() => { res(null); }, options.waitFor); } }); await this.reply({ type: types_1.InteractionResponseType.Modal, data: body, }); return promise; } async editOrReply(body, fetchReply) { if (await this.replied) { const { content, embeds, allowed_mentions, components, files, attachments, poll, flags } = body; return this.editResponse({ content, embeds, allowed_mentions, components, files, attachments, poll, flags }); } return this.write(body, fetchReply); } editMessage(messageId, body) { return this.client.interactions.editMessage(this.token, messageId, body); } editResponse(body) { return this.editMessage('@original', body); } deleteResponse() { return this.deleteMessage('@original'); } deleteMessage(messageId) { return this.client.interactions.deleteResponse(this.token, messageId); } followup(body) { return this.client.interactions.followup(this.token, body); } } exports.Interaction = Interaction; class ApplicationCommandInteraction extends Interaction { type; respond(data) { return this.reply(data); } } exports.ApplicationCommandInteraction = ApplicationCommandInteraction; /** * Seyfert don't support activities, so this interaction is blank */ class EntryPointInteraction extends ApplicationCommandInteraction { async withReponse(data) { let body = { type: types_1.InteractionResponseType.LaunchActivity }; if (data) { let { files, ...rest } = data; files = files ? await (0, builders_1.resolveFiles)(files) : undefined; body = BaseInteraction.transformBody(rest, files, this.client); } const response = await this.client.proxy .interactions(this.id)(this.token) .callback.post({ body, query: { with_response: true }, }); const result = { interaction: (0, common_1.toCamelCase)(response.interaction), }; if (response.resource) { if (response.resource.type !== types_1.InteractionResponseType.LaunchActivity) { result.resource = { type: response.resource.type, message: transformers_1.Transformers.WebhookMessage(this.client, response.resource.message, this.id, this.token), }; } else { result.resource = { type: response.resource.type, activityInstance: response.resource.activity_instance, }; } } return result; } isEntryPoint() { return true; } } exports.EntryPointInteraction = EntryPointInteraction; class ComponentInteraction extends Interaction { update(data) { return this.reply({ type: types_1.InteractionResponseType.UpdateMessage, data, }); } deferUpdate() { return this.reply({ type: types_1.InteractionResponseType.DeferredMessageUpdate, }); } get customId() { return this.data.customId; } get componentType() { return this.data.componentType; } } exports.ComponentInteraction = ComponentInteraction; class ButtonInteraction extends ComponentInteraction { isButton() { return true; } } exports.ButtonInteraction = ButtonInteraction; class SelectMenuInteraction extends ComponentInteraction { __reply; constructor(client, interaction, __reply) { super(client, interaction); this.__reply = __reply; } get values() { return this.data.values; } } exports.SelectMenuInteraction = SelectMenuInteraction; class StringSelectMenuInteraction extends SelectMenuInteraction { isStringSelectMenu() { return true; } } exports.StringSelectMenuInteraction = StringSelectMenuInteraction; class ChannelSelectMenuInteraction extends SelectMenuInteraction { __reply; channels; constructor(client, interaction, __reply) { super(client, interaction); this.__reply = __reply; const resolved = interaction.data.resolved; this.channels = this.values.map(x => (0, _1.channelFrom)(resolved.channels[x], this.client)); } isChannelSelectMenu() { return true; } } exports.ChannelSelectMenuInteraction = ChannelSelectMenuInteraction; class MentionableSelectMenuInteraction extends SelectMenuInteraction { __reply; roles; members; users; constructor(client, interaction, __reply) { super(client, interaction); this.__reply = __reply; const resolved = interaction.data.resolved; this.roles = resolved.roles ? this.values.map(x => transformers_1.Transformers.GuildRole(this.client, resolved.roles[x], this.guildId)) : []; this.members = resolved.members ? this.values.map(x => transformers_1.Transformers.InteractionGuildMember(this.client, resolved.members[x], resolved.users[this.values.find(u => u === x)], this.guildId)) : []; this.users = resolved.users ? this.values.map(x => transformers_1.Transformers.User(this.client, resolved.users[x])) : []; } isMentionableSelectMenu() { return true; } } exports.MentionableSelectMenuInteraction = MentionableSelectMenuInteraction; class RoleSelectMenuInteraction extends SelectMenuInteraction { __reply; roles; constructor(client, interaction, __reply) { super(client, interaction); this.__reply = __reply; const resolved = interaction.data.resolved; this.roles = this.values.map(x => transformers_1.Transformers.GuildRole(this.client, resolved.roles[x], this.guildId)); } isRoleSelectMenu() { return true; } } exports.RoleSelectMenuInteraction = RoleSelectMenuInteraction; class UserSelectMenuInteraction extends SelectMenuInteraction { __reply; members; users; constructor(client, interaction, __reply) { super(client, interaction); this.__reply = __reply; const resolved = interaction.data.resolved; this.users = this.values.map(x => transformers_1.Transformers.User(this.client, resolved.users[x])); this.members = resolved.members ? this.values.map(x => transformers_1.Transformers.InteractionGuildMember(this.client, resolved.members[x], resolved.users[this.values.find(u => u === x)], this.guildId)) : []; } isUserSelectMenu() { return true; } } exports.UserSelectMenuInteraction = UserSelectMenuInteraction; class ChatInputCommandInteraction extends ApplicationCommandInteraction { isChatInput() { return true; } } exports.ChatInputCommandInteraction = ChatInputCommandInteraction; class UserCommandInteraction extends ApplicationCommandInteraction { isUser() { return true; } } exports.UserCommandInteraction = UserCommandInteraction; class MessageCommandInteraction extends ApplicationCommandInteraction { isMessage() { return true; } } exports.MessageCommandInteraction = MessageCommandInteraction; let ModalSubmitInteraction = class ModalSubmitInteraction extends BaseInteraction { update(data, withResponse) { return this.reply({ type: types_1.InteractionResponseType.UpdateMessage, data, }, withResponse); } deferUpdate(withResponse) { return this.reply({ type: types_1.InteractionResponseType.DeferredMessageUpdate, }, withResponse); } get customId() { return this.data.customId; } get components() { return this.data.components; } getComponent(customId, type) { return this.components .filter(c => c.type === types_1.ComponentType.Label && c.component && (!type?.length || type.includes(c.component.type))) .find(c => c.component.customId === customId)?.component; } getChannels(customId, required) { const component = this.getComponent(customId, [types_1.ComponentType.ChannelSelect]); if (!component && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component not found or is not a channel select menu` }, }); if (component && 'values' in component) { const resolved = this.data.resolved?.channels; return component.values.filter(x => resolved?.[x]).map(x => (0, _1.channelFrom)(resolved[x], this.client)); } } getRoles(customId, required) { const component = this.getComponent(customId, [types_1.ComponentType.RoleSelect]); if (!component && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component not found or is not a role select menu` }, }); if (component && 'values' in component) { const resolved = this.data.resolved?.roles; return component.values .filter(x => resolved?.[x]) .map(x => transformers_1.Transformers.GuildRole(this.client, resolved[x], this.guildId)); } } getUsers(customId, required) { const component = this.getComponent(customId, [types_1.ComponentType.UserSelect]); if (!component && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component not found or is not a user select menu` }, }); if (component && 'values' in component) { const resolved = this.data.resolved?.users; return component.values.filter(x => resolved?.[x]).map(x => transformers_1.Transformers.User(this.client, resolved[x])); } } getMentionables(customId, required) { const component = this.getComponent(customId, [types_1.ComponentType.MentionableSelect]); if (!component && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component not found or is not a mentionable select menu` }, }); if (component && 'values' in component) { const resolved = this.data.resolved; return component.values.map(x => { if (resolved?.users?.[x]) return transformers_1.Transformers.User(this.client, resolved.users[x]); if (resolved?.roles?.[x]) return transformers_1.Transformers.GuildRole(this.client, resolved.roles[x], this.guildId); if (resolved?.members?.[x]) return transformers_1.Transformers.InteractionGuildMember(this.client, resolved.members[x], resolved.users[x], this.guildId); throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `Mentionable ${x} not found in resolved data` }, }); }); } } getRadioValues(customId, required) { const component = this.getComponent(customId, [types_1.ComponentType.RadioGroup]); if (!component && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component not found or is not a radio group` }, }); if (component && 'value' in component) { return component.value; } } getCheckboxValues(customId, required) { const component = this.getComponent(customId, [types_1.ComponentType.CheckboxGroup]); if (!component && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component not found or is not a checkbox group` }, }); if (component && 'values' in component) { return component.values; } } getCheckbox(customId, required) { const component = this.getComponent(customId, [types_1.ComponentType.Checkbox]); if (!component && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component not found or is not a checkbox` }, }); if (component && 'value' in component) { return !!component.value; } } getInputValue(customId, required) { let value; const get = this.getComponent(customId); if (get) { if ('value' in get) value = get.value; if ('values' in get) value = get.values; } if ((!value || value.length === 0) && required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component doesn't have a value` } }); return value; } getFiles(customId, required) { const value = this.getComponent(customId, [types_1.ComponentType.FileUpload]); if (value) { const attachments = this.data.resolved?.attachments; if (attachments) { return Object.values(attachments).map(x => new builders_1.Attachment(this.client, { ...x, proxy_url: x.url, })); } if (required) throw new common_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `${customId} component doesn't have any files` }, }); } return undefined; } isModal() { return true; } }; exports.ModalSubmitInteraction = ModalSubmitInteraction; exports.ModalSubmitInteraction = ModalSubmitInteraction = __decorate([ (0, mixer_1.mix)(Interaction) ], ModalSubmitInteraction);