mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
839 lines
26 KiB
TypeScript
839 lines
26 KiB
TypeScript
import {
|
|
type APIActionRowComponent,
|
|
type APIApplicationCommandAutocompleteInteraction,
|
|
type APIApplicationCommandInteraction,
|
|
type APIBaseInteraction,
|
|
type APIChatInputApplicationCommandInteraction,
|
|
type APIChatInputApplicationCommandInteractionData,
|
|
type APICommandAutocompleteInteractionResponseCallbackData,
|
|
type APIEntryPointCommandInteraction,
|
|
type APIInteraction,
|
|
type APIInteractionResponse,
|
|
type APIInteractionResponseChannelMessageWithSource,
|
|
type APIInteractionResponseDeferredChannelMessageWithSource,
|
|
type APIInteractionResponseDeferredMessageUpdate,
|
|
type APIInteractionResponsePong,
|
|
type APIInteractionResponseUpdateMessage,
|
|
type APIMessageApplicationCommandInteraction,
|
|
type APIMessageApplicationCommandInteractionData,
|
|
type APIMessageButtonInteractionData,
|
|
type APIMessageChannelSelectInteractionData,
|
|
type APIMessageComponentInteraction,
|
|
type APIMessageComponentSelectMenuInteraction,
|
|
type APIMessageMentionableSelectInteractionData,
|
|
type APIMessageRoleSelectInteractionData,
|
|
type APIMessageStringSelectInteractionData,
|
|
type APIMessageUserSelectInteractionData,
|
|
type APIModalSubmission,
|
|
type APIModalSubmitInteraction,
|
|
type APITextInputComponent,
|
|
type APIUserApplicationCommandInteraction,
|
|
type APIUserApplicationCommandInteractionData,
|
|
ApplicationCommandType,
|
|
ComponentType,
|
|
type GatewayInteractionCreateDispatchData,
|
|
type InteractionCallbackData,
|
|
type InteractionCallbackResourceActivity,
|
|
InteractionResponseType,
|
|
InteractionType,
|
|
type MessageFlags,
|
|
type RESTAPIAttachment,
|
|
type RESTPostAPIInteractionCallbackJSONBody,
|
|
type RESTPostAPIInteractionCallbackResult,
|
|
} from '../types';
|
|
|
|
import type { RawFile } from '../api';
|
|
import { ActionRow, Embed, Modal, PollBuilder, resolveAttachment, resolveFiles } from '../builders';
|
|
import {
|
|
type EntitlementStructure,
|
|
type GuildRoleStructure,
|
|
type InteractionGuildMemberStructure,
|
|
type MessageStructure,
|
|
type OptionResolverStructure,
|
|
Transformers,
|
|
type UserStructure,
|
|
type WebhookMessageStructure,
|
|
} from '../client/transformers';
|
|
import type { ContextOptionsResolved, UsingClient } from '../commands';
|
|
import {
|
|
type ComponentInteractionMessageUpdate,
|
|
type InteractionCreateBodyRequest,
|
|
type InteractionMessageUpdateBodyRequest,
|
|
type MessageCreateBodyRequest,
|
|
type MessageUpdateBodyRequest,
|
|
type MessageWebhookCreateBodyRequest,
|
|
type ModalCreateBodyRequest,
|
|
type ObjectToLower,
|
|
type OmitInsert,
|
|
type ToClass,
|
|
type When,
|
|
toCamelCase,
|
|
} from '../common';
|
|
import { mix } from '../deps/mixer';
|
|
import { type AllChannels, channelFrom } from './';
|
|
import { DiscordBase } from './extra/DiscordBase';
|
|
import { PermissionsBitField } from './extra/Permissions';
|
|
|
|
export type ReplyInteractionBody =
|
|
| { type: InteractionResponseType.Modal; data: ModalCreateBodyRequest }
|
|
| {
|
|
type: InteractionResponseType.ChannelMessageWithSource | InteractionResponseType.UpdateMessage;
|
|
data: InteractionCreateBodyRequest | InteractionMessageUpdateBodyRequest | ComponentInteractionMessageUpdate;
|
|
}
|
|
| { type: InteractionResponseType.LaunchActivity }
|
|
| Exclude<RESTPostAPIInteractionCallbackJSONBody, APIInteractionResponsePong>;
|
|
|
|
export type __InternalReplyFunction = (_: { body: APIInteractionResponse; files?: RawFile[] }) => Promise<any>;
|
|
|
|
export interface BaseInteraction
|
|
extends ObjectToLower<
|
|
Omit<
|
|
APIBaseInteraction<InteractionType, any>,
|
|
'user' | 'member' | 'message' | 'channel' | 'type' | 'app_permissions'
|
|
>
|
|
> {}
|
|
|
|
export class BaseInteraction<
|
|
FromGuild extends boolean = boolean,
|
|
Type extends APIInteraction = APIInteraction,
|
|
> extends DiscordBase<Type> {
|
|
user: UserStructure;
|
|
member!: When<FromGuild, InteractionGuildMemberStructure, undefined>;
|
|
channel?: AllChannels;
|
|
message?: MessageStructure;
|
|
replied?: Promise<boolean | RESTPostAPIInteractionCallbackResult | undefined> | boolean;
|
|
appPermissions: PermissionsBitField;
|
|
entitlements: EntitlementStructure[];
|
|
|
|
constructor(
|
|
readonly client: UsingClient,
|
|
interaction: Type,
|
|
protected __reply?: __InternalReplyFunction,
|
|
) {
|
|
super(client, interaction);
|
|
if (interaction.member) {
|
|
this.member = Transformers.InteractionGuildMember(
|
|
client,
|
|
interaction.member,
|
|
interaction.member.user,
|
|
interaction.guild_id!,
|
|
) as never;
|
|
}
|
|
if (interaction.message) {
|
|
this.message = Transformers.Message(client, interaction.message);
|
|
}
|
|
this.appPermissions = new PermissionsBitField(Number(interaction.app_permissions));
|
|
if (interaction.channel) {
|
|
this.channel = channelFrom(interaction.channel, client);
|
|
}
|
|
this.user = this.member?.user ?? Transformers.User(client, interaction.user!);
|
|
|
|
this.entitlements = interaction.entitlements.map(e => Transformers.Entitlement(this.client, e));
|
|
}
|
|
|
|
static transformBodyRequest(
|
|
body: ReplyInteractionBody,
|
|
files: RawFile[] | undefined,
|
|
self: UsingClient,
|
|
): APIInteractionResponse {
|
|
switch (body.type) {
|
|
case InteractionResponseType.ApplicationCommandAutocompleteResult:
|
|
case InteractionResponseType.DeferredMessageUpdate:
|
|
case InteractionResponseType.DeferredChannelMessageWithSource:
|
|
return body;
|
|
case InteractionResponseType.ChannelMessageWithSource:
|
|
case InteractionResponseType.UpdateMessage: {
|
|
//@ts-ignore
|
|
return {
|
|
type: body.type,
|
|
data: BaseInteraction.transformBody(body.data ?? {}, files, self),
|
|
};
|
|
}
|
|
case InteractionResponseType.Modal:
|
|
return {
|
|
type: body.type,
|
|
data:
|
|
body.data instanceof Modal
|
|
? body.data.toJSON()
|
|
: {
|
|
...body.data,
|
|
components: body.data?.components
|
|
? body.data.components.map(x =>
|
|
x instanceof ActionRow
|
|
? (x.toJSON() as unknown as APIActionRowComponent<APITextInputComponent>)
|
|
: x,
|
|
)
|
|
: [],
|
|
},
|
|
};
|
|
case InteractionResponseType.LaunchActivity:
|
|
return body;
|
|
default:
|
|
return body;
|
|
}
|
|
}
|
|
|
|
static transformBody<T>(
|
|
body:
|
|
| InteractionCreateBodyRequest
|
|
| InteractionMessageUpdateBodyRequest
|
|
| MessageUpdateBodyRequest
|
|
| MessageCreateBodyRequest
|
|
| MessageWebhookCreateBodyRequest,
|
|
files: RawFile[] | undefined,
|
|
self: UsingClient,
|
|
) {
|
|
const poll = (body as MessageWebhookCreateBodyRequest).poll;
|
|
|
|
const payload = {
|
|
allowed_mentions: self.options?.allowedMentions,
|
|
...body,
|
|
components: body.components?.map(x => (x instanceof ActionRow ? x.toJSON() : x)),
|
|
embeds: body?.embeds?.map(x => (x instanceof Embed ? x.toJSON() : x)),
|
|
poll: poll ? (poll instanceof PollBuilder ? poll.toJSON() : poll) : undefined,
|
|
};
|
|
|
|
if ('attachments' in body) {
|
|
payload.attachments =
|
|
body.attachments?.map((x, i) => ({
|
|
id: i,
|
|
...resolveAttachment(x),
|
|
})) ?? undefined;
|
|
} else if (files?.length) {
|
|
payload.attachments = files?.map(({ filename }, id) => ({
|
|
id,
|
|
filename,
|
|
})) as RESTAPIAttachment[];
|
|
}
|
|
return payload as T;
|
|
}
|
|
|
|
private async matchReplied(body: ReplyInteractionBody, withResponse = false) {
|
|
if (this.__reply) {
|
|
//@ts-expect-error
|
|
const { files, ...rest } = body.data ?? {};
|
|
//@ts-expect-error
|
|
const data = body.data instanceof Modal ? body.data : rest;
|
|
const parsedFiles = files ? await 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.WebhookMessage(this.client, result.resource.message as any, this.id, this.token)
|
|
: undefined;
|
|
}
|
|
|
|
async reply<WR extends boolean = false>(
|
|
body: ReplyInteractionBody,
|
|
withResponse?: WR,
|
|
): Promise<When<WR, WebhookMessageStructure, undefined>> {
|
|
if (this.replied) {
|
|
throw new Error('Interaction already replied');
|
|
}
|
|
const result = await this.matchReplied(body, withResponse);
|
|
// @ts-expect-error
|
|
if (body.data instanceof Modal) {
|
|
// @ts-expect-error
|
|
if (body.data.__exec) this.client.components.modals.set(this.user.id, (body.data as Modal).__exec);
|
|
else if (this.client.components.modals.has(this.user.id)) this.client.components.modals.delete(this.user.id);
|
|
}
|
|
return result as never;
|
|
}
|
|
|
|
deferReply<WR extends boolean = false>(
|
|
flags?: MessageFlags,
|
|
withResponse?: WR,
|
|
): Promise<When<WR, WebhookMessageStructure, undefined>> {
|
|
return this.reply(
|
|
{
|
|
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
data: {
|
|
flags,
|
|
},
|
|
},
|
|
withResponse,
|
|
) as never;
|
|
}
|
|
|
|
isButton(): this is ButtonInteraction {
|
|
return false;
|
|
}
|
|
|
|
isChannelSelectMenu(): this is ChannelSelectMenuInteraction {
|
|
return false;
|
|
}
|
|
|
|
isRoleSelectMenu(): this is RoleSelectMenuInteraction {
|
|
return false;
|
|
}
|
|
|
|
isMentionableSelectMenu(): this is MentionableSelectMenuInteraction {
|
|
return false;
|
|
}
|
|
|
|
isUserSelectMenu(): this is UserSelectMenuInteraction {
|
|
return false;
|
|
}
|
|
|
|
isStringSelectMenu(): this is StringSelectMenuInteraction {
|
|
return false;
|
|
}
|
|
|
|
isChatInput(): this is ChatInputCommandInteraction {
|
|
return false;
|
|
}
|
|
|
|
isUser(): this is UserCommandInteraction {
|
|
return false;
|
|
}
|
|
|
|
isMessage(): this is MessageCommandInteraction {
|
|
return false;
|
|
}
|
|
|
|
isAutocomplete(): this is AutocompleteInteraction {
|
|
return false;
|
|
}
|
|
|
|
isModal(): this is ModalSubmitInteraction {
|
|
return false;
|
|
}
|
|
|
|
isEntryPoint(): this is EntryPointInteraction {
|
|
return false;
|
|
}
|
|
|
|
static from(client: UsingClient, gateway: GatewayInteractionCreateDispatchData, __reply?: __InternalReplyFunction) {
|
|
switch (gateway.type) {
|
|
case InteractionType.ApplicationCommandAutocomplete:
|
|
return new AutocompleteInteraction(client, gateway, undefined, __reply);
|
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: bad interaction between biome and ts-server
|
|
case InteractionType.ApplicationCommand:
|
|
switch (gateway.data.type) {
|
|
case ApplicationCommandType.ChatInput:
|
|
return new ChatInputCommandInteraction(
|
|
client,
|
|
gateway as APIChatInputApplicationCommandInteraction,
|
|
__reply,
|
|
);
|
|
case ApplicationCommandType.User:
|
|
return new UserCommandInteraction(client, gateway as APIUserApplicationCommandInteraction, __reply);
|
|
case ApplicationCommandType.Message:
|
|
return new MessageCommandInteraction(client, gateway as APIMessageApplicationCommandInteraction, __reply);
|
|
case ApplicationCommandType.PrimaryEntryPoint:
|
|
return new EntryPointInteraction(client, gateway as APIEntryPointCommandInteraction, __reply);
|
|
}
|
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: bad interaction between biome and ts-server
|
|
case InteractionType.MessageComponent:
|
|
switch (gateway.data.component_type) {
|
|
case ComponentType.Button:
|
|
return new ButtonInteraction(client, gateway as APIMessageComponentInteraction, __reply);
|
|
case ComponentType.ChannelSelect:
|
|
return new ChannelSelectMenuInteraction(
|
|
client,
|
|
gateway as APIMessageComponentSelectMenuInteraction,
|
|
__reply,
|
|
);
|
|
case ComponentType.RoleSelect:
|
|
return new RoleSelectMenuInteraction(client, gateway as APIMessageComponentSelectMenuInteraction, __reply);
|
|
case ComponentType.MentionableSelect:
|
|
return new MentionableSelectMenuInteraction(
|
|
client,
|
|
gateway as APIMessageComponentSelectMenuInteraction,
|
|
__reply,
|
|
);
|
|
case ComponentType.UserSelect:
|
|
return new UserSelectMenuInteraction(client, gateway as APIMessageComponentSelectMenuInteraction, __reply);
|
|
case ComponentType.StringSelect:
|
|
return new StringSelectMenuInteraction(
|
|
client,
|
|
gateway as APIMessageComponentSelectMenuInteraction,
|
|
__reply,
|
|
);
|
|
}
|
|
case InteractionType.ModalSubmit:
|
|
return new ModalSubmitInteraction(client, gateway);
|
|
default:
|
|
return new BaseInteraction(client, gateway);
|
|
}
|
|
}
|
|
|
|
async fetchGuild(force = false) {
|
|
return this.guildId ? this.client.guilds.fetch(this.guildId, force) : undefined;
|
|
}
|
|
}
|
|
|
|
export type AllInteractions =
|
|
| AutocompleteInteraction
|
|
| ChatInputCommandInteraction
|
|
| UserCommandInteraction
|
|
| MessageCommandInteraction
|
|
| ComponentInteraction
|
|
| SelectMenuInteraction
|
|
| ModalSubmitInteraction
|
|
| EntryPointInteraction
|
|
| BaseInteraction;
|
|
|
|
export interface AutocompleteInteraction
|
|
extends ObjectToLower<
|
|
Omit<
|
|
APIApplicationCommandAutocompleteInteraction,
|
|
'user' | 'member' | 'type' | 'data' | 'message' | 'channel' | 'app_permissions'
|
|
>
|
|
> {}
|
|
|
|
export class AutocompleteInteraction<FromGuild extends boolean = boolean> extends BaseInteraction<
|
|
FromGuild,
|
|
APIApplicationCommandAutocompleteInteraction
|
|
> {
|
|
declare type: InteractionType.ApplicationCommandAutocomplete;
|
|
declare data: ObjectToLower<APIApplicationCommandAutocompleteInteraction['data']>;
|
|
options: OptionResolverStructure;
|
|
declare entitlements: EntitlementStructure[];
|
|
constructor(
|
|
client: UsingClient,
|
|
interaction: APIApplicationCommandAutocompleteInteraction,
|
|
resolver?: OptionResolverStructure,
|
|
protected __reply?: __InternalReplyFunction,
|
|
) {
|
|
super(client, interaction);
|
|
this.options =
|
|
resolver ??
|
|
Transformers.OptionResolver(
|
|
client,
|
|
interaction.data.options,
|
|
undefined,
|
|
interaction.guild_id,
|
|
interaction.data.resolved as ContextOptionsResolved,
|
|
);
|
|
}
|
|
|
|
getInput() {
|
|
return this.options.getAutocompleteValue() ?? '';
|
|
}
|
|
|
|
respond(choices: APICommandAutocompleteInteractionResponseCallbackData['choices']) {
|
|
return super.reply({ data: { choices }, type: InteractionResponseType.ApplicationCommandAutocompleteResult });
|
|
}
|
|
|
|
isAutocomplete(): this is AutocompleteInteraction {
|
|
return true;
|
|
}
|
|
|
|
/** @intenal */
|
|
async reply(..._args: unknown[]): Promise<any> {
|
|
throw new Error('Cannot use reply in this interaction');
|
|
}
|
|
}
|
|
|
|
export class Interaction<
|
|
FromGuild extends boolean = boolean,
|
|
Type extends APIInteraction = APIInteraction,
|
|
> extends BaseInteraction<FromGuild, Type> {
|
|
fetchMessage(messageId: string): Promise<WebhookMessageStructure> {
|
|
return this.client.interactions.fetchResponse(this.token, messageId);
|
|
}
|
|
|
|
fetchResponse(): Promise<WebhookMessageStructure> {
|
|
return this.fetchMessage('@original');
|
|
}
|
|
|
|
write<FR extends boolean = false>(
|
|
body: InteractionCreateBodyRequest,
|
|
withResponse?: FR,
|
|
): Promise<When<FR, WebhookMessageStructure, void>> {
|
|
return this.reply(
|
|
{
|
|
type: InteractionResponseType.ChannelMessageWithSource,
|
|
data: body,
|
|
},
|
|
withResponse,
|
|
) as never;
|
|
}
|
|
|
|
modal(body: ModalCreateBodyRequest) {
|
|
return this.reply({
|
|
type: InteractionResponseType.Modal,
|
|
data: body,
|
|
});
|
|
}
|
|
|
|
async editOrReply<FR extends boolean = false>(
|
|
body: InteractionCreateBodyRequest,
|
|
fetchReply?: FR,
|
|
): Promise<When<FR, WebhookMessageStructure, void>>;
|
|
async editOrReply<FR extends true = true>(
|
|
body: InteractionMessageUpdateBodyRequest,
|
|
fetchReply?: FR,
|
|
): Promise<WebhookMessageStructure> {
|
|
if (await this.replied) {
|
|
const { content, embeds, allowed_mentions, components, files, attachments, poll } = body;
|
|
return this.editResponse({ content, embeds, allowed_mentions, components, files, attachments, poll });
|
|
}
|
|
return this.write(body as InteractionCreateBodyRequest, fetchReply);
|
|
}
|
|
|
|
editMessage(messageId: string, body: InteractionMessageUpdateBodyRequest): Promise<WebhookMessageStructure> {
|
|
return this.client.interactions.editMessage(this.token, messageId, body);
|
|
}
|
|
|
|
editResponse(body: InteractionMessageUpdateBodyRequest): Promise<WebhookMessageStructure> {
|
|
return this.editMessage('@original', body);
|
|
}
|
|
|
|
deleteResponse() {
|
|
return this.deleteMessage('@original');
|
|
}
|
|
|
|
deleteMessage(messageId: string) {
|
|
return this.client.interactions.deleteResponse(this.token, messageId);
|
|
}
|
|
|
|
followup(body: MessageWebhookCreateBodyRequest): Promise<WebhookMessageStructure> {
|
|
return this.client.interactions.followup(this.token, body);
|
|
}
|
|
}
|
|
|
|
export class ApplicationCommandInteraction<
|
|
FromGuild extends boolean = boolean,
|
|
Type extends APIApplicationCommandInteraction = APIApplicationCommandInteraction,
|
|
> extends Interaction<FromGuild, Type> {
|
|
type!: ApplicationCommandType;
|
|
respond(
|
|
data:
|
|
| APIInteractionResponseChannelMessageWithSource
|
|
| APIInteractionResponseDeferredChannelMessageWithSource
|
|
| APIInteractionResponseDeferredMessageUpdate
|
|
| APIInteractionResponseUpdateMessage,
|
|
) {
|
|
return this.reply(data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Seyfert don't support activities, so this interaction is blank
|
|
*/
|
|
export class EntryPointInteraction<FromGuild extends boolean = boolean> extends ApplicationCommandInteraction<
|
|
FromGuild,
|
|
APIEntryPointCommandInteraction
|
|
> {
|
|
async withReponse(data?: InteractionCreateBodyRequest) {
|
|
let body = { type: InteractionResponseType.LaunchActivity } as const;
|
|
|
|
if (data) {
|
|
let { files, ...rest } = data;
|
|
files = files ? await 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: Partial<EntryPointWithResponseResult> = {
|
|
interaction: toCamelCase(response.interaction),
|
|
};
|
|
|
|
if (response.resource) {
|
|
if (response.resource.type !== InteractionResponseType.LaunchActivity) {
|
|
result.resource = {
|
|
type: response.resource.type,
|
|
message: Transformers.WebhookMessage(this.client, response.resource.message as any, this.id, this.token),
|
|
};
|
|
} else {
|
|
result.resource = {
|
|
type: response.resource.type,
|
|
activityInstance: response.resource.activity_instance!,
|
|
};
|
|
}
|
|
}
|
|
|
|
return result as EntryPointWithResponseResult;
|
|
}
|
|
|
|
isEntryPoint(): this is EntryPointInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export interface EntryPointWithResponseResult {
|
|
interaction: ObjectToLower<InteractionCallbackData>;
|
|
resource?:
|
|
| { type: InteractionResponseType.LaunchActivity; activityInstance: InteractionCallbackResourceActivity }
|
|
| {
|
|
type: Exclude<InteractionResponseType, InteractionResponseType.LaunchActivity>;
|
|
message: WebhookMessageStructure;
|
|
};
|
|
}
|
|
|
|
export interface ComponentInteraction
|
|
extends ObjectToLower<
|
|
Omit<
|
|
APIMessageComponentInteraction,
|
|
'user' | 'member' | 'type' | 'data' | 'message' | 'channel' | 'app_permissions'
|
|
>
|
|
> {}
|
|
|
|
export class ComponentInteraction<
|
|
FromGuild extends boolean = boolean,
|
|
Type extends APIMessageComponentInteraction = APIMessageComponentInteraction,
|
|
> extends Interaction<FromGuild, Type> {
|
|
declare data: ObjectToLower<APIMessageComponentInteraction['data']>;
|
|
declare channelId: string;
|
|
declare channel: AllChannels;
|
|
declare type: InteractionType.MessageComponent;
|
|
declare message: MessageStructure;
|
|
declare entitlements: EntitlementStructure[];
|
|
|
|
update(data: ComponentInteractionMessageUpdate) {
|
|
return this.reply({
|
|
type: InteractionResponseType.UpdateMessage,
|
|
data,
|
|
});
|
|
}
|
|
|
|
deferUpdate() {
|
|
return this.reply({
|
|
type: InteractionResponseType.DeferredMessageUpdate,
|
|
});
|
|
}
|
|
|
|
get customId() {
|
|
return this.data.customId;
|
|
}
|
|
|
|
get componentType() {
|
|
return this.data.componentType;
|
|
}
|
|
}
|
|
|
|
export class ButtonInteraction extends ComponentInteraction {
|
|
declare data: ObjectToLower<APIMessageButtonInteractionData>;
|
|
|
|
isButton(): this is ButtonInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class SelectMenuInteraction extends ComponentInteraction {
|
|
declare data: ObjectToLower<APIMessageComponentSelectMenuInteraction['data']>;
|
|
|
|
constructor(
|
|
client: UsingClient,
|
|
interaction: APIMessageComponentSelectMenuInteraction,
|
|
protected __reply?: __InternalReplyFunction,
|
|
) {
|
|
super(client, interaction);
|
|
}
|
|
|
|
get values() {
|
|
return this.data.values;
|
|
}
|
|
}
|
|
|
|
export class StringSelectMenuInteraction<
|
|
T extends any[] = string[],
|
|
> extends (SelectMenuInteraction as unknown as ToClass<
|
|
Omit<SelectMenuInteraction, 'data' | 'isStringSelectMenu'>,
|
|
StringSelectMenuInteraction
|
|
>) {
|
|
declare data: OmitInsert<ObjectToLower<APIMessageStringSelectInteractionData>, 'values', { values: T }>;
|
|
declare values: T;
|
|
|
|
isStringSelectMenu(): this is StringSelectMenuInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class ChannelSelectMenuInteraction extends SelectMenuInteraction {
|
|
channels: AllChannels[];
|
|
constructor(
|
|
client: UsingClient,
|
|
interaction: APIMessageComponentSelectMenuInteraction,
|
|
protected __reply?: __InternalReplyFunction,
|
|
) {
|
|
super(client, interaction);
|
|
const resolved = (interaction.data as APIMessageChannelSelectInteractionData).resolved;
|
|
this.channels = this.values.map(x => channelFrom(resolved.channels[x], this.client));
|
|
}
|
|
|
|
isChannelSelectMenu(): this is ChannelSelectMenuInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class MentionableSelectMenuInteraction extends SelectMenuInteraction {
|
|
roles: GuildRoleStructure[];
|
|
members: InteractionGuildMemberStructure[];
|
|
users: UserStructure[];
|
|
constructor(
|
|
client: UsingClient,
|
|
interaction: APIMessageComponentSelectMenuInteraction,
|
|
protected __reply?: __InternalReplyFunction,
|
|
) {
|
|
super(client, interaction);
|
|
const resolved = (interaction.data as APIMessageMentionableSelectInteractionData).resolved;
|
|
this.roles = resolved.roles
|
|
? this.values.map(x => Transformers.GuildRole(this.client, resolved.roles![x], this.guildId!))
|
|
: [];
|
|
this.members = resolved.members
|
|
? this.values.map(x =>
|
|
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.User(this.client, resolved.users![x])) : [];
|
|
}
|
|
|
|
isMentionableSelectMenu(): this is MentionableSelectMenuInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class RoleSelectMenuInteraction extends SelectMenuInteraction {
|
|
roles: GuildRoleStructure[];
|
|
constructor(
|
|
client: UsingClient,
|
|
interaction: APIMessageComponentSelectMenuInteraction,
|
|
protected __reply?: __InternalReplyFunction,
|
|
) {
|
|
super(client, interaction);
|
|
const resolved = (interaction.data as APIMessageRoleSelectInteractionData).resolved;
|
|
this.roles = this.values.map(x => Transformers.GuildRole(this.client, resolved.roles[x], this.guildId!));
|
|
}
|
|
|
|
isRoleSelectMenu(): this is RoleSelectMenuInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class UserSelectMenuInteraction extends SelectMenuInteraction {
|
|
members: InteractionGuildMemberStructure[];
|
|
users: UserStructure[];
|
|
constructor(
|
|
client: UsingClient,
|
|
interaction: APIMessageComponentSelectMenuInteraction,
|
|
protected __reply?: __InternalReplyFunction,
|
|
) {
|
|
super(client, interaction);
|
|
const resolved = (interaction.data as APIMessageUserSelectInteractionData).resolved;
|
|
this.users = this.values.map(x => Transformers.User(this.client, resolved.users[x]));
|
|
this.members = resolved.members
|
|
? this.values.map(x =>
|
|
Transformers.InteractionGuildMember(
|
|
this.client,
|
|
resolved.members![x],
|
|
resolved.users[this.values!.find(u => u === x)!]!,
|
|
this.guildId!,
|
|
),
|
|
)
|
|
: [];
|
|
}
|
|
|
|
isUserSelectMenu(): this is UserSelectMenuInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class ChatInputCommandInteraction<FromGuild extends boolean = boolean> extends ApplicationCommandInteraction<
|
|
FromGuild,
|
|
APIChatInputApplicationCommandInteraction
|
|
> {
|
|
declare data: ObjectToLower<APIChatInputApplicationCommandInteractionData>;
|
|
|
|
isChatInput(): this is ChatInputCommandInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class UserCommandInteraction<FromGuild extends boolean = boolean> extends ApplicationCommandInteraction<
|
|
FromGuild,
|
|
APIUserApplicationCommandInteraction
|
|
> {
|
|
declare type: ApplicationCommandType.User;
|
|
declare data: ObjectToLower<APIUserApplicationCommandInteractionData>;
|
|
|
|
isUser(): this is UserCommandInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export class MessageCommandInteraction<FromGuild extends boolean = boolean> extends ApplicationCommandInteraction<
|
|
FromGuild,
|
|
APIMessageApplicationCommandInteraction
|
|
> {
|
|
declare type: ApplicationCommandType.Message;
|
|
declare data: ObjectToLower<APIMessageApplicationCommandInteractionData>;
|
|
|
|
isMessage(): this is MessageCommandInteraction {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export interface ModalSubmitInteraction<FromGuild extends boolean = boolean>
|
|
extends Omit<Interaction<FromGuild, APIModalSubmitInteraction>, 'modal'> {}
|
|
@mix(Interaction)
|
|
export class ModalSubmitInteraction<FromGuild extends boolean = boolean> extends BaseInteraction<FromGuild> {
|
|
declare data: ObjectToLower<APIModalSubmission>;
|
|
|
|
update<WR extends boolean = false>(
|
|
data: ComponentInteractionMessageUpdate,
|
|
withResponse?: WR,
|
|
): Promise<When<WR, WebhookMessageStructure, undefined>> {
|
|
return this.reply<WR>(
|
|
{
|
|
type: InteractionResponseType.UpdateMessage,
|
|
data,
|
|
},
|
|
withResponse,
|
|
);
|
|
}
|
|
|
|
deferUpdate<WR extends boolean = false>(withResponse?: WR): Promise<When<WR, WebhookMessageStructure, undefined>> {
|
|
return this.reply<WR>(
|
|
{
|
|
type: InteractionResponseType.DeferredMessageUpdate,
|
|
},
|
|
withResponse,
|
|
);
|
|
}
|
|
|
|
get customId() {
|
|
return this.data.customId;
|
|
}
|
|
|
|
get components() {
|
|
return this.data.components;
|
|
}
|
|
|
|
getInputValue(customId: string, required: true): string;
|
|
getInputValue(customId: string, required?: false): string | undefined;
|
|
getInputValue(customId: string, required?: boolean): string | undefined {
|
|
let value: string | undefined;
|
|
for (const { components } of this.components) {
|
|
const get = components.find(x => x.customId === customId);
|
|
if (get) {
|
|
value = get.value;
|
|
break;
|
|
}
|
|
}
|
|
if (!value && required) throw new Error(`${customId} component doesn't have a value`);
|
|
return value;
|
|
}
|
|
|
|
isModal(): this is ModalSubmitInteraction {
|
|
return true;
|
|
}
|
|
}
|