diff --git a/esm.mjs b/esm.mjs index e1e0b194b..7dbf78c74 100644 --- a/esm.mjs +++ b/esm.mjs @@ -5,6 +5,7 @@ export default function(token, options) { } export const { + ApplicationCommand, AutocompleteInteraction, Base, Bucket, @@ -53,7 +54,6 @@ export const { ThreadChannel, ThreadMember, UnavailableGuild, - UnknownInteraction, User, VERSION, VoiceChannel, diff --git a/examples/applicationCommands.js b/examples/applicationCommands.js index d54021be4..2a6d1fb7b 100644 --- a/examples/applicationCommands.js +++ b/examples/applicationCommands.js @@ -10,8 +10,6 @@ const bot = new Eris("BOT TOKEN", { bot.on("ready", async () => { // When the bot is ready console.log("Ready!"); // Log "Ready!" - //Note: You should use guild commands to test, as they update instantly. Global commands can take up to an hour to update. - const commands = await bot.getCommands(); if(!commands.length) { diff --git a/index.d.ts b/index.d.ts index efd4c9c2c..c8b6b380c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -15,35 +15,41 @@ declare namespace Eris { // TYPES - // Application Commands - type AnyApplicationCommand = ChatInputApplicationCommand | MessageApplicationCommand | UserApplicationCommand; - type ApplicationCommandStructure = ChatInputApplicationCommandStructure | MessageApplicationCommandStructure | UserApplicationCommandStructure; - type ChatInputApplicationCommand = ApplicationCommand; - type ChatInputApplicationCommandStructure = Omit; - type MessageApplicationCommand = Omit, "description" | "options">; - type MessageApplicationCommandStructure = Omit; - type UserApplicationCommand = Omit, "description" | "options">; - type UserApplicationCommandStructure = Omit; - type ApplicationCommandOptions = ApplicationCommandOptionsSubCommand | ApplicationCommandOptionsSubCommandGroup | ApplicationCommandOptionsWithValue; - type ApplicationCommandOptionsBoolean = ApplicationCommandOption; - type ApplicationCommandOptionsChannel = ApplicationCommandOption; - type ApplicationCommandOptionsInteger = ApplicationCommandOptionsIntegerWithAutocomplete | ApplicationCommandOptionsIntegerWithoutAutocomplete | ApplicationCommandOptionsIntegerWithMinMax; - type ApplicationCommandOptionsIntegerWithAutocomplete = Omit, "choices" | "min_value" | "max_value"> & AutocompleteEnabled; - type ApplicationCommandOptionsIntegerWithoutAutocomplete = Omit, "autocomplete" | "min_value" | "max_value"> & AutocompleteDisabledInteger; - type ApplicationCommandOptionsIntegerWithMinMax = Omit, "choices" | "autocomplete"> & AutocompleteDisabledIntegerMinMax; - type ApplicationCommandOptionsMentionable = ApplicationCommandOption; - type ApplicationCommandOptionsNumber = ApplicationCommandOptionsNumberWithAutocomplete | ApplicationCommandOptionsNumberWithoutAutocomplete | ApplicationCommandOptionsNumberWithMinMax; - type ApplicationCommandOptionsNumberWithAutocomplete = Omit, "choices" | "min_value" | "max_value"> & AutocompleteEnabled; - type ApplicationCommandOptionsNumberWithoutAutocomplete = Omit, "autocomplete" | "min_value" | "max_value"> & AutocompleteDisabledInteger; - type ApplicationCommandOptionsNumberWithMinMax = Omit, "choices" | "autocomplete"> & AutocompleteDisabledIntegerMinMax; - type ApplicationCommandOptionsRole = ApplicationCommandOption; - type ApplicationCommandOptionsString = ApplicationCommandOptionsStringWithAutocomplete | ApplicationCommandOptionsStringWithoutAutocomplete; - type ApplicationCommandOptionsStringWithAutocomplete = Omit, "choices"> & AutocompleteEnabled; - type ApplicationCommandOptionsStringWithoutAutocomplete = Omit, "autocomplete"> & AutocompleteDisabled; - type ApplicationCommandOptionsUser = ApplicationCommandOption; + // Application Command + type AnyApplicationCommand = ChatInputApplicationCommand | MessageApplicationCommand | UserApplicationCommand; + type ApplicationCommandOptions = ApplicationCommandOptionsWithOptions | ApplicationCommandOptionsWithValue; + type ApplicationCommandOptionsTypes = Constants["ApplicationCommandOptionTypes"][keyof Constants["ApplicationCommandOptionTypes"]]; + type ApplicationCommandOptionsTypesWithAutocomplete = Constants["ApplicationCommandOptionTypes"][keyof Pick]; + type ApplicationCommandOptionsTypesWithChoices = Constants["ApplicationCommandOptionTypes"][keyof Pick]; + type ApplicationCommandOption = ApplicationCommandOptionBase; + type ApplicationCommandOptionAutocomplete = (ApplicationCommandOption & ApplicationCommandOptionsAutocomplete); + type ApplicationCommandOptionChannelTypes = (ApplicationCommandOption & ApplicationCommandOptionsChannelTypes); + type ApplicationCommandOptionChoices = (ApplicationCommandOption & ApplicationCommandOptionsChoices); + type ApplicationCommandOptionMinMaxValue = (ApplicationCommandOption & ApplicationCommandOptionsMinMaxValue); + type ApplicationCommandOptionMinMaxLength = (ApplicationCommandOption & ApplicationCommandOptionsMinMaxLength); + + type ApplicationCommandOptionsBoolean = ApplicationCommandOption<"BOOLEAN">; + type ApplicationCommandOptionsChannel = ApplicationCommandOptionChannelTypes<"CHANNEL">; + type ApplicationCommandOptionsInteger = ApplicationCommandOptionAutocomplete<"INTEGER"> | ApplicationCommandOptionChoices<"INTEGER"> | ApplicationCommandOptionMinMaxValue<"INTEGER">; + type ApplicationCommandOptionsMentionable = ApplicationCommandOption<"MENTIONABLE">; + type ApplicationCommandOptionsNumber = ApplicationCommandOptionAutocomplete<"NUMBER"> | ApplicationCommandOptionChoices<"NUMBER"> | ApplicationCommandOptionMinMaxValue<"NUMBER">; + type ApplicationCommandOptionsRole = ApplicationCommandOption<"ROLE">; + type ApplicationCommandOptionsString = ApplicationCommandOptionAutocomplete<"STRING"> | ApplicationCommandOptionChoices<"STRING"> | ApplicationCommandOptionMinMaxLength<"STRING">; + type ApplicationCommandOptionsUser = ApplicationCommandOption<"USER">; + + type ApplicationCommandOptionsWithOptions = ApplicationCommandOptionsSubCommand | ApplicationCommandOptionsSubCommandGroup; type ApplicationCommandOptionsWithValue = ApplicationCommandOptionsString | ApplicationCommandOptionsInteger | ApplicationCommandOptionsBoolean | ApplicationCommandOptionsUser | ApplicationCommandOptionsChannel | ApplicationCommandOptionsRole | ApplicationCommandOptionsMentionable | ApplicationCommandOptionsNumber; - type ApplicationCommandPermissionTypes = Constants["ApplicationCommandPermissionTypes"][keyof Constants["ApplicationCommandPermissionTypes"]]; + type ApplicationCommandStructure = ChatInputApplicationCommandStructure | MessageApplicationCommandStructure | UserApplicationCommandStructure; + type ApplicationCommandStructureConversion = T extends ChatInputApplicationCommandStructure ? + ChatInputApplicationCommand : T extends MessageApplicationCommandStructure ? + MessageApplicationCommand : T extends UserApplicationCommandStructure ? + UserApplicationCommand : never; type ApplicationCommandTypes = Constants["ApplicationCommandTypes"][keyof Constants["ApplicationCommandTypes"]]; + type ChatInputApplicationCommand = ApplicationCommand<"CHAT_INPUT", W>; + type MessageApplicationCommand = ApplicationCommand<"MESSAGE", W>; + type MessageApplicationCommandStructure = ApplicationCommandStructureBase<"MESSAGE">; + type UserApplicationCommand = ApplicationCommand<"USER", W>; + type UserApplicationCommandStructure = ApplicationCommandStructureBase<"USER">; // Cache interface Uncached { id: string } @@ -96,21 +102,23 @@ declare namespace Eris { type GuildIntegrationExpireBehavior = Constants["GuildIntegrationExpireBehavior"][keyof Constants["GuildIntegrationExpireBehavior"]]; // Interaction - type AnyInteraction = PingInteraction | CommandInteraction | ComponentInteraction | AutocompleteInteraction; - type InteractionCallbackData = InteractionAutocomplete | InteractionContent; + type AnyInteraction = AnyInteractionGateway | PingInteraction; + type AnyInteractionGateway = AutocompleteInteraction | CommandInteraction | ComponentInteraction; type InteractionContent = Pick; - type InteractionContentEdit = Pick; - type InteractionDataOptions = InteractionDataOptionsSubCommand | InteractionDataOptionsSubCommandGroup | InteractionDataOptionsWithValue; - type InteractionDataOptionsBoolean = InteractionDataOptionWithValue; - type InteractionDataOptionsChannel = InteractionDataOptionWithValue; - type InteractionDataOptionsInteger = InteractionDataOptionWithValue; - type InteractionDataOptionsMentionable = InteractionDataOptionWithValue; - type InteractionDataOptionsNumber = InteractionDataOptionWithValue; - type InteractionDataOptionsRole = InteractionDataOptionWithValue; - type InteractionDataOptionsString = InteractionDataOptionWithValue; - type InteractionDataOptionsUser = InteractionDataOptionWithValue; + type InteractionContentEdit = Omit; + type InteractionDataOption, V = boolean | number | string> = InteractionDataOptionsBase; + type InteractionDataOptions = InteractionDataOptionsWithOptions | InteractionDataOptionsWithValue; + type InteractionDataOptionsBoolean = InteractionDataOption<"BOOLEAN", boolean>; + type InteractionDataOptionsChannel = InteractionDataOption<"CHANNEL", string>; + type InteractionDataOptionsInteger = InteractionDataOption<"INTEGER", number>; + type InteractionDataOptionsMentionable = InteractionDataOption<"MENTIONABLE", string>; + type InteractionDataOptionsNumber = InteractionDataOption<"NUMBER", number>; + type InteractionDataOptionsRole = InteractionDataOption<"ROLE", string>; + type InteractionDataOptionsString = InteractionDataOption<"STRING", string>; + type InteractionDataOptionsUser = InteractionDataOption<"USER", string>; + type InteractionDataOptionsWithOptions = InteractionDataOptionsSubCommand | InteractionDataOptionsSubCommandGroup; type InteractionDataOptionsWithValue = InteractionDataOptionsString | InteractionDataOptionsInteger | InteractionDataOptionsBoolean | InteractionDataOptionsUser | InteractionDataOptionsChannel | InteractionDataOptionsRole | InteractionDataOptionsMentionable | InteractionDataOptionsNumber; - type InteractionResponseTypes = Constants["InteractionResponseTypes"][keyof Constants["InteractionResponseTypes"]]; + type InteractionResponse = InteractionResponseAutocomplete | InteractionResponseDeferred | InteractionResponseMessage; type InteractionTypes = Constants["InteractionTypes"][keyof Constants["InteractionTypes"]]; // Invite @@ -120,7 +128,10 @@ declare namespace Eris { type ActionRowComponents = Button | SelectMenu; type Button = InteractionButton | URLButton; type ButtonStyles = Constants["ButtonStyles"][keyof Constants["ButtonStyles"]]; + type ButtonStyleNormal = Exclude; + type ButtonStyleLink = Constants["ButtonStyles"]["LINK"]; type Component = ActionRow | ActionRowComponents; + type ComponentTypes = Constants["ComponentTypes"][keyof Constants["ComponentTypes"]]; type ImageFormat = Constants["ImageFormats"][number]; type MessageActivityFlags = Constants["MessageActivityFlags"][keyof Constants["MessageActivityFlags"]]; type MessageContent = string | AdvancedMessageContent; @@ -172,87 +183,66 @@ declare namespace Eris { toJSON(props?: string[]): JSONCache; } - // Application Commands - interface ApplicationCommand { - application_id: string; - defaultPermission?: boolean; - description: T extends Constants["ApplicationCommandTypes"]["CHAT_INPUT"] ? string : never; - guild_id?: string; - id: string; - name: string; - options?: ApplicationCommandOptions[]; - type: T; - } - interface ApplicationCommandOptionsSubCommand { - description: string; + // Application Command + interface ApplicationCommandStructureBase { + defaultMemberPermissions?: string; + dmPermission?: boolean; name: string; - options?: ApplicationCommandOptionsWithValue[]; - type: Constants["ApplicationCommandOptionTypes"]["SUB_COMMAND"]; + nameLocalizations?: Record; + type: Constants["ApplicationCommandTypes"][T]; } - interface ApplicationCommandOptionsSubCommandGroup { + interface ApplicationCommandOptionBase { description: string; + description_localizations?: Record; name: string; - options?: (ApplicationCommandOptionsSubCommand | ApplicationCommandOptionsWithValue)[]; - type: Constants["ApplicationCommandOptionTypes"]["SUB_COMMAND_GROUP"]; + name_localizations?: Record; + required?: T extends Constants["ApplicationCommandOptionTypes"]["SUB_COMMAND" | "SUB_COMMAND_GROUP"] ? never : boolean; + type: T; } - interface ApplicationCommandOptionChoice] | unknown = unknown> { - name: string; - value: T extends Constants["ApplicationCommandOptionTypes"]["STRING"] - ? string - : T extends Constants["ApplicationCommandOptionTypes"]["NUMBER"] - ? number - : T extends Constants["ApplicationCommandOptionTypes"]["INTEGER"] - ? number - : number | string; - } - interface ApplicationCommandOptionWithChoices] = Constants["ApplicationCommandOptionTypes"][keyof Pick]> { + interface ApplicationCommandOptionsAutocomplete { autocomplete?: boolean; - choices?: ApplicationCommandOptionChoice[]; - description: string; + } + interface ApplicationCommandOptionsChoice { name: string; - required?: boolean; - type: T; + value: + T extends Constants["ApplicationCommandOptionTypes"]["STRING"] ? string : + T extends Constants["ApplicationCommandOptionTypes"]["INTEGER" | "NUMBER"] ? number : + unknown; } - interface ApplicationCommandOptionWithMinMax] = Constants["ApplicationCommandOptionTypes"][keyof Pick]> { - autocomplete?: boolean; - choices?: ApplicationCommandOptionChoice[]; - description: string; + + interface ApplicationCommandOptionsChannelTypes { + channel_types?: GuildChannelTypes[]; + } + interface ApplicationCommandOptionsChoices { choices?: ApplicationCommandOptionsChoice[] } + interface ApplicationCommandOptionsMinMaxValue { max_value?: number; min_value?: number; - name: string; - required?: boolean; - type: T; } - interface ApplicationCommandOption]> { - channel_types: T extends Constants["ApplicationCommandOptionTypes"]["CHANNEL"] ? ChannelTypes | undefined : never; - description: string; - name: string; - required?: boolean; - type: T; + interface ApplicationCommandOptionsMinMaxLength { + max_length?: number; + min_length?: number; + } + interface ApplicationCommandOptionsSubCommand extends ApplicationCommandOptionBase { + options?: ApplicationCommandOptionsWithValue[]; + } + interface ApplicationCommandOptionsSubCommandGroup extends ApplicationCommandOptionBase { + options?: (ApplicationCommandOptionsSubCommand | ApplicationCommandOptionsWithValue)[]; } interface ApplicationCommandPermissions { id: string; permission: boolean; - type: ApplicationCommandPermissionTypes; - } - interface AutocompleteEnabled { - autocomplete: true; - } - interface AutocompleteDisabled { - autocomplete?: false; + type: Constants["ApplicationCommandPermissionTypes"][keyof Constants["ApplicationCommandPermissionTypes"]]; } - interface AutocompleteDisabledInteger extends AutocompleteDisabled { - min_value?: null; - max_value?: null; - } - interface AutocompleteDisabledIntegerMinMax extends AutocompleteDisabled { - choices?: null; + interface ChatInputApplicationCommandStructure extends ApplicationCommandStructureBase<"CHAT_INPUT"> { + description: string; + descriptionLocalizations?: Record; + options?: ApplicationCommandOptions[]; } interface GuildApplicationCommandPermissions { application_id: string; guild_id: string; id: string; - permissions?: ApplicationCommandPermissions[]; + permissions: ApplicationCommandPermissions[]; } // Channel @@ -728,7 +718,7 @@ declare namespace Eris { guildUnavailable: [guild: UnavailableGuild]; guildUpdate: [guild: Guild, oldGuild: OldGuild]; hello: [trace: string[], id: number]; - interactionCreate: [interaction: PingInteraction | CommandInteraction | ComponentInteraction | AutocompleteInteraction | UnknownInteraction]; + interactionCreate: [interaction: AnyInteractionGateway]; inviteCreate: [guild: Guild, invite: Invite]; inviteDelete: [guild: Guild, invite: Invite]; messageCreate: [message: Message]; @@ -1000,28 +990,66 @@ declare namespace Eris { } // Interaction - interface InteractionAutocomplete { - choices: ApplicationCommandOptionChoice[]; + interface AutocompleteInteractionData { + id: string; + name: string; + type: Constants["ApplicationCommandTypes"]["CHAT_INPUT"]; + target_id?: string; + options: InteractionDataOptions[]; } - interface InteractionDataOptionsSubCommand { + interface CommandInteractionData { + id: string; name: string; + type: ApplicationCommandTypes; + target_id?: string; + resolved?: CommandInteractionResolvedData; options?: InteractionDataOptions[]; - type: Constants["ApplicationCommandOptionTypes"]["SUB_COMMAND"]; } - interface InteractionDataOptionsSubCommandGroup { - name: string; - options: InteractionDataOptions[]; - type: Constants["ApplicationCommandOptionTypes"]["SUB_COMMAND_GROUP"]; + interface CommandInteractionResolvedData { + channels?: Collection; + members?: Collection; + messages?: Collection; + roles?: Collection; + users?: Collection; + } + interface InteractionComponentButtonData { + component_type: Constants["ComponentTypes"]["BUTTON"]; + custom_id: string; + } + interface InteractionComponentSelectMenuData { + component_type: Constants["ComponentTypes"]["SELECT_MENU"]; + custom_id: string; + values: string[]; } - interface InteractionDataOptionWithValue] = Constants["ApplicationCommandOptionTypes"][Exclude], V = unknown> { - focused?: boolean; + interface InteractionDataOptionsBase { + focused?: T extends ApplicationCommandOptionsTypesWithAutocomplete ? boolean : never; name: string; type: T; - value: V; + value: T extends Constants["ApplicationCommandOptionTypes"]["SUB_COMMAND" | "SUB_COMMAND_GROUP"] ? never : V; + } + interface InteractionDataOptionsSubCommand extends InteractionDataOptionsBase { + options?: InteractionDataOptionsWithValue[]; + } + interface InteractionDataOptionsSubCommandGroup extends InteractionDataOptionsBase { + // technically these can have zero options, but it will then not show in the client so it's effectively not possible + options: (InteractionDataOptionsSubCommand | InteractionDataOptionsWithValue)[]; + } + interface InteractionResponseAutocomplete { + data: ApplicationCommandOptionsChoice[]; + type: Constants["InteractionResponseTypes"]["APPLICATION_COMMAND_AUTOCOMPLETE_RESULT"]; + } + interface InteractionResponseDeferred { + data?: { + flags?: number; + }; + type: Constants["InteractionResponseTypes"]["DEFERRED_UPDATE_MESSAGE" | "DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE"]; + } + interface InteractionResponseMessage { + data: InteractionContent; + type: Constants["InteractionResponseTypes"]["CHANNEL_MESSAGE_WITH_SOURCE" | "UPDATE_MESSAGE"]; } - interface InteractionOptions { - data?: InteractionCallbackData; - type: InteractionResponseTypes; + interface InteractionResponsePong { + type: Constants["InteractionResponseTypes"]["PONG"]; } // Invite @@ -1141,7 +1169,7 @@ declare namespace Eris { } interface ButtonBase { disabled?: boolean; - emoji?: Partial; + emoji?: PartialEmoji; label?: string; type: Constants["ComponentTypes"]["BUTTON"]; } @@ -1178,7 +1206,7 @@ declare namespace Eris { interface InteractionButton extends ButtonBase { custom_id: string; - style: Exclude; + style: ButtonStyleNormal; } interface MessageActivity { party_id?: string; @@ -2142,8 +2170,8 @@ declare namespace Eris { addSelfPremiumSubscription(token: string, plan: string): Promise; banGuildMember(guildID: string, userID: string, deleteMessageDays?: number, reason?: string): Promise; bulkEditCommandPermissions(guildID: string, permissions: { id: string; permissions: ApplicationCommandPermissions[] }[]): Promise; - bulkEditCommands(commands: ApplicationCommandStructure[]): Promise; - bulkEditGuildCommands(guildID: string, commands: ApplicationCommandStructure[]): Promise; + bulkEditCommands(commands: ApplicationCommandStructure[]): Promise[]>; + bulkEditGuildCommands(guildID: string, commands: ApplicationCommandStructure[]): Promise[]>; closeVoiceConnection(guildID: string): void; connect(): Promise; createChannel(guildID: string, name: string): Promise; @@ -2255,15 +2283,15 @@ declare namespace Eris { options: { name: string; avatar?: string | null }, reason?: string ): Promise; - createCommand(command: ApplicationCommandStructure): Promise; + createCommand(command: T): Promise>; createGroupChannel(userIDs: string[]): Promise; createGuild(name: string, options?: CreateGuildOptions): Promise; - createGuildCommand(guildID: string, command: ApplicationCommandStructure): Promise; + createGuildCommand(guildID: string, command: T): Promise>; createGuildEmoji(guildID: string, options: EmojiOptions, reason?: string): Promise; createGuildFromTemplate(code: string, name: string, icon?: string): Promise; createGuildSticker(guildID: string, options: CreateStickerOptions, reason?: string): Promise; createGuildTemplate(guildID: string, name: string, description?: string | null): Promise; - createInteractionResponse(interactionID: string, interactionToken: string, options: InteractionOptions, file?: FileContent | FileContent[]): Promise; + createInteractionResponse(interactionID: string, interactionToken: string, options: InteractionResponse, file?: FileContent | FileContent[]): Promise; createMessage(channelID: string, content: MessageContent, file?: FileContent | FileContent[]): Promise; createRole(guildID: string, options?: RoleOptions, reason?: string): Promise; createRole(guildID: string, options?: Role, reason?: string): Promise; @@ -2309,10 +2337,10 @@ declare namespace Eris { ): Promise; editChannelPosition(channelID: string, position: number, options?: EditChannelPositionOptions): Promise; editChannelPositions(guildID: string, channelPositions: ChannelPosition[]): Promise; - editCommand(commandID: string, command: ApplicationCommandStructure): Promise; + editCommand(commandID: string, command: Omit): Promise>; editCommandPermissions(guildID: string, commandID: string, permissions: ApplicationCommandPermissions[]): Promise; editGuild(guildID: string, options: GuildOptions, reason?: string): Promise; - editGuildCommand(guildID: string, commandID: string, command: ApplicationCommandStructure): Promise; + editGuildCommand(guildID: string, commandID: string, command: Omit): Promise>; editGuildDiscovery(guildID: string, options?: DiscoveryOptions): Promise; editGuildEmoji( guildID: string, @@ -2376,9 +2404,9 @@ declare namespace Eris { getChannel(channelID: string): AnyChannel; getChannelInvites(channelID: string): Promise; getChannelWebhooks(channelID: string): Promise; - getCommand(commandID: string): Promise; + getCommand = AnyApplicationCommand>(commandID: string, withLocalizations?: W): Promise; getCommandPermissions(guildID: string, commandID: string): Promise; - getCommands(): Promise; + getCommands(withLocalizations?: W): Promise[]>; getDiscoveryCategories(): Promise; getDMChannel(userID: string): Promise; getEmojiGuild(emojiID: string): Promise; @@ -2388,9 +2416,9 @@ declare namespace Eris { getGuildAuditLogs(guildID: string, limit?: number, before?: string, actionType?: number, userID?: string): Promise; getGuildBan(guildID: string, userID: string): Promise; getGuildBans(guildID: string, options?: GetGuildBansOptions): Promise; - getGuildCommand(guildID: string, commandID: string): Promise; + getGuildCommand = AnyApplicationCommand>(guildID: string, commandID: string, withLocalizations?: W): Promise; getGuildCommandPermissions(guildID: string): Promise; - getGuildCommands(guildID: string): Promise; + getGuildCommands(guildID: string, withLocalizations?: W): Promise[]>; getGuildDiscovery(guildID: string): Promise; /** @deprecated */ getGuildEmbed(guildID: string): Promise; @@ -2701,7 +2729,7 @@ declare namespace Eris { addDiscoverySubcategory(categoryID: string, reason?: string): Promise; addMemberRole(memberID: string, roleID: string, reason?: string): Promise; banMember(userID: string, deleteMessageDays?: number, reason?: string): Promise; - bulkEditCommands(commands: ApplicationCommandStructure[]): Promise; + bulkEditCommands(commands: ApplicationCommandStructure[]): Promise; createChannel(name: string): Promise; createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_TEXT"], options?: CreateChannelOptions): Promise; createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_VOICE"], options?: CreateChannelOptions): Promise; @@ -2724,7 +2752,7 @@ declare namespace Eris { createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_STAGE"], reason?: string, options?: CreateChannelOptions | string): Promise; /** @deprecated */ createChannel(name: string, type?: number, reason?: string, options?: CreateChannelOptions | string): Promise; - createCommand(command: ApplicationCommandStructure): Promise; + createCommand(command: T): Promise>; createEmoji(options: { image: string; name: string; roles?: string[] }, reason?: string): Promise; createRole(options: RoleOptions, reason?: string): Promise; createRole(options: Role, reason?: string): Promise; @@ -2744,7 +2772,7 @@ declare namespace Eris { dynamicSplashURL(format?: ImageFormat, size?: number): string | null; edit(options: GuildOptions, reason?: string): Promise; editChannelPositions(channelPositions: ChannelPosition[]): Promise; - editCommand(commandID: string, command: ApplicationCommandStructure): Promise; + editCommand(commandID: string, command: Omit): Promise>; editCommandPermissions(permissions: ApplicationCommandPermissions[]): Promise; editDiscovery(options?: DiscoveryOptions): Promise; editEmoji(emojiID: string, options: { name: string; roles?: string[] }, reason?: string): Promise; @@ -2767,9 +2795,9 @@ declare namespace Eris { getAuditLogs(limit?: number, before?: string, actionType?: number, userID?: string): Promise; getBan(userID: string): Promise; getBans(options?: GetGuildBansOptions): Promise; - getCommand(commandID: string): Promise; + getCommand = AnyApplicationCommand>(commandID: string, withLocalizations?: W): Promise; getCommandPermissions(): Promise; - getCommands(): Promise; + getCommands(): Promise[]>; getDiscovery(): Promise; /** @deprecated */ getEmbed(): Promise; @@ -2912,73 +2940,50 @@ declare namespace Eris { toJSON(props?: string[]): JSONCache; } - export class TextVoiceChannel extends VoiceChannel implements GuildTextable { - lastMessageID: string; - messages: Collection>; - rateLimitPerUser: number; - addMessageReaction(messageID: string, reaction: string): Promise; - /** @deprecated */ - addMessageReaction(messageID: string, reaction: string, userID: string): Promise; - createMessage(content: MessageContent, file?: FileContent | FileContent[]): Promise>; - createWebhook(options: { name: string; avatar?: string | null }, reason?: string): Promise; - deleteMessage(messageID: string, reason?: string): Promise; - deleteMessages(messageIDs: string[], reason?: string): Promise; - editMessage(messageID: string, content: MessageContentEdit): Promise>; - getMessage(messageID: string): Promise>; - getMessageReaction(messageID: string, reaction: string, options?: GetMessageReactionOptions): Promise; - /** @deprecated */ - getMessageReaction(messageID: string, reaction: string, limit?: number, before?: string, after?: string): Promise; - getMessages(options?: GetMessagesOptions): Promise[]>; - /** @deprecated */ - getMessages(limit?: number, before?: string, after?: string, around?: string): Promise; - getWebhooks(): Promise; - purge(options: PurgeChannelOptions): Promise; - removeMessageReaction(messageID: string, reaction: string, userID?: string): Promise; - removeMessageReactionEmoji(messageID: string, reaction: string): Promise; - removeMessageReactions(messageID: string): Promise; - sendTyping(): Promise; - unsendMessage(messageID: string): Promise; - } - export class Interaction extends Base { - acknowledged: boolean; + export class ApplicationCommand extends Base { applicationID: string; + defaultMemberPermissions?: string | null; + description: T extends "CHAT_INPUT" ? string : ""; + // despite descriptions not being allowed for user & message, localizations are allowed + descriptionLocalizations: W extends true ? Record | null : Record | null | undefined; + dmPermission?: boolean; id: string; - token: string; - type: number; - version: number; - static from(data: BaseData): AnyInteraction; + name: string; + nameLocalizations: W extends true ? Record | null : Record | null | undefined; + options?: ApplicationCommandOptions[]; + type: Constants["ApplicationCommandTypes"][T]; + version: string; + delete(): Promise; + edit(options: Omit): Promise; } - export class PingInteraction extends Interaction { - type: Constants["InteractionTypes"]["PING"]; - acknowledge(): Promise; - pong(): Promise; + export class AutocompleteInteraction extends Interaction { + appPermissions?: Permission; + channel: T; + data: AutocompleteInteractionData; + guildID?: string; + guildLocale?: string; + locale: string; + member?: Member; + type: Constants["InteractionTypes"]["APPLICATION_COMMAND_AUTOCOMPLETE"]; + user: User; + acknowledge(choices: ApplicationCommandOptionsChoice[]): Promise; + result(choices: ApplicationCommandOptionsChoice[]): Promise; } export class CommandInteraction extends Interaction { appPermissions?: Permission; channel: T; - data: { - id: string; - name: string; - type: ApplicationCommandTypes; - target_id?: string; - resolved?: { - users?: Collection; - members?: Collection>; - roles?: Collection; - channels?: Collection; - messages?: Collection; - }; - options?: InteractionDataOptions[]; - }; + data: CommandInteractionData; guildID?: string; + guildLocale?: string; + locale: string; member?: Member; type: Constants["InteractionTypes"]["APPLICATION_COMMAND"]; - user?: User; + user: User; acknowledge(flags?: number): Promise; createFollowup(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise; - createMessage(content: string | InteractionContent , file?: FileContent | FileContent[]): Promise; + createMessage(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise; defer(flags?: number): Promise; deleteMessage(messageID: string): Promise; deleteOriginalMessage(): Promise; @@ -2987,26 +2992,17 @@ declare namespace Eris { getOriginalMessage(): Promise } - interface ComponentInteractionButtonData { - component_type: Constants["ComponentTypes"]["BUTTON"]; - custom_id: string; - } - - interface ComponentInteractionSelectMenuData { - component_type: Constants["ComponentTypes"]["SELECT_MENU"]; - custom_id: string; - values: string[]; - } - export class ComponentInteraction extends Interaction { appPermissions?: Permission; channel: T; - data: ComponentInteractionButtonData | ComponentInteractionSelectMenuData; + data: InteractionComponentButtonData | InteractionComponentSelectMenuData; guildID?: string; + guildLocale?: string; + locale: string; member?: Member; message: Message; type: Constants["InteractionTypes"]["MESSAGE_COMPONENT"]; - user?: User; + user: User; acknowledge(): Promise; createFollowup(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise; createMessage(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise; @@ -3016,48 +3012,29 @@ declare namespace Eris { deleteOriginalMessage(): Promise; editMessage(messageID: string, content: string | InteractionContentEdit, file?: FileContent | FileContent[]): Promise; editOriginalMessage(content: string | InteractionContentEdit, file?: FileContent | FileContent[]): Promise; - editParent(content: InteractionContentEdit, file?: FileContent | FileContent[]): Promise; + editParent(content: string | InteractionContentEdit, file?: FileContent | FileContent[]): Promise; getOriginalMessage(): Promise } - export class AutocompleteInteraction extends Interaction { - appPermissions?: Permission; - channel: T; - data: { - id: string; - name: string; - type: Constants["ApplicationCommandTypes"]["CHAT_INPUT"]; - target_id?: string; - options: InteractionDataOptions[]; - }; - guildID?: string; + export class Interaction extends Base { + acknowledged: boolean; + applicationID: string; + guildLocale?: string; + id: string; + locale?: string; member?: Member; - type: Constants["InteractionTypes"]["APPLICATION_COMMAND_AUTOCOMPLETE"]; + token: string; + type: InteractionTypes; user?: User; - acknowledge(choices: ApplicationCommandOptionChoice[]): Promise; - result(choices: ApplicationCommandOptionChoice[]): Promise; + version: number; + static from(data: BaseData): AnyInteraction; } - export class UnknownInteraction extends Interaction { - appPermissions?: Permission; - channel?: T; - data?: unknown; - guildID?: string; - member?: Member; - message?: Message; - type: number; - user?: User; - acknowledge(data: InteractionOptions): Promise; - createFollowup(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise; - createMessage(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise; - defer(flags?: number): Promise; - deferUpdate(): Promise; - deleteMessage(messageID: string): Promise; - deleteOriginalMessage(): Promise; - editMessage(messageID: string, content: string | InteractionContentEdit, file?: FileContent | FileContent[]): Promise; - editOriginalMessage(content: string | InteractionContentEdit, file?: FileContent | FileContent[]): Promise; - editParent(content: InteractionContentEdit, file?: FileContent | FileContent[]): Promise; - getOriginalMessage(): Promise + + export class PingInteraction extends Interaction { + guildLocale: never; + locale: never; + type: Constants["InteractionTypes"]["PING"]; + acknowledge(): Promise; pong(): Promise; - result(choices: ApplicationCommandOptionChoice[]): Promise; } // If CT (count) is "withMetadata", it will not have count properties @@ -3520,6 +3497,34 @@ declare namespace Eris { unsendMessage(messageID: string): Promise; } + export class TextVoiceChannel extends VoiceChannel implements GuildTextable { + lastMessageID: string; + messages: Collection>; + rateLimitPerUser: number; + addMessageReaction(messageID: string, reaction: string): Promise; + /** @deprecated */ + addMessageReaction(messageID: string, reaction: string, userID: string): Promise; + createMessage(content: MessageContent, file?: FileContent | FileContent[]): Promise>; + createWebhook(options: { name: string; avatar?: string | null }, reason?: string): Promise; + deleteMessage(messageID: string, reason?: string): Promise; + deleteMessages(messageIDs: string[], reason?: string): Promise; + editMessage(messageID: string, content: MessageContentEdit): Promise>; + getMessage(messageID: string): Promise>; + getMessageReaction(messageID: string, reaction: string, options?: GetMessageReactionOptions): Promise; + /** @deprecated */ + getMessageReaction(messageID: string, reaction: string, limit?: number, before?: string, after?: string): Promise; + getMessages(options?: GetMessagesOptions): Promise[]>; + /** @deprecated */ + getMessages(limit?: number, before?: string, after?: string, around?: string): Promise; + getWebhooks(): Promise; + purge(options: PurgeChannelOptions): Promise; + removeMessageReaction(messageID: string, reaction: string, userID?: string): Promise; + removeMessageReactionEmoji(messageID: string, reaction: string): Promise; + removeMessageReactions(messageID: string): Promise; + sendTyping(): Promise; + unsendMessage(messageID: string): Promise; + } + export class ThreadChannel extends GuildChannel implements ThreadTextable { lastMessageID: string; lastPinTimestamp?: number; diff --git a/index.js b/index.js index b016f9cc6..7cc117953 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ function Eris(token, options) { return new Client(token, options); } +Eris.ApplicationCommand = require("./lib/structures/ApplicationCommand"); Eris.AutocompleteInteraction = require("./lib/structures/AutocompleteInteraction"); Eris.Base = require("./lib/structures/Base"); Eris.Bucket = require("./lib/util/Bucket"); @@ -54,7 +55,6 @@ Eris.TextVoiceChannel = require("./lib/structures/TextVoiceChannel"); Eris.ThreadChannel = require("./lib/structures/ThreadChannel"); Eris.ThreadMember = require("./lib/structures/ThreadMember"); Eris.UnavailableGuild = require("./lib/structures/UnavailableGuild"); -Eris.UnknownInteraction = require("./lib/structures/UnknownInteraction"); Eris.User = require("./lib/structures/User"); Eris.VERSION = require("./package.json").version; Eris.VoiceChannel = require("./lib/structures/VoiceChannel"); diff --git a/lib/Client.js b/lib/Client.js index 7c609bd23..12adcedfc 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -1,5 +1,6 @@ "use strict"; +const ApplicationCommand = require("./structures/ApplicationCommand"); const Base = require("./structures/Base"); const Channel = require("./structures/Channel"); const Collection = require("./util/Collection"); @@ -361,50 +362,43 @@ class Client extends EventEmitter { * @returns {Promise>} Returns an array of [GuildApplicationCommandPermissions](https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure) objects. */ bulkEditCommandPermissions(guildID, permissions) { - if(!guildID) { - throw new Error("You must provide an id of the guild whose permissions you want to edit."); - } - return this.requestHandler.request("PUT", Endpoints.GUILD_COMMAND_PERMISSIONS(this.application.id, guildID), true, permissions); } /** * Bulk create/edit global application commands * @arg {Array} commands An array of [Command objects](https://discord.com/developers/docs/interactions/application-commands#application-command-object) - * @returns {Promise} Resolves with an array of commands objects + * @returns {Promise} */ bulkEditCommands(commands) { for(const command of commands) { - if(command.name !== undefined){ - if(command.type === 1 || command.type === undefined) { - command.name = command.name.toLowerCase(); - if(!command.name.match(/^[\w-]{1,32}$/)) { - throw new Error("Slash Command names must match the regular expression \"^[\\w-]{1,32}$\""); - } - } + if(command.name !== undefined && command.type === 1) { + command.name = command.name.toLowerCase(); } + command.default_member_permissions = command.defaultMemberPermissions; + command.dm_permission = command.dmPermission; + command.description_localizations = command.descriptionLocalizations; + command.name_localizations = command.nameLocalizations; } - return this.requestHandler.request("PUT", Endpoints.COMMANDS(this.application.id), true, commands); + return this.requestHandler.request("PUT", Endpoints.COMMANDS(this.application.id), true, commands).then((applicationCommands) => applicationCommands.map((applicationCommand) => new ApplicationCommand(applicationCommand, this))); } /** * Bulk create/edit guild application commands * @arg {String} guildID Guild id to create the commands in * @arg {Array} commands An array of [Command objects](https://discord.com/developers/docs/interactions/application-commands#application-command-object) - * @returns {Promise} Resolves with an array of commands objects + * @returns {ApplicationCommand[]} Resolves with an array of commands objects */ bulkEditGuildCommands(guildID, commands) { for(const command of commands) { - if(command.name !== undefined){ - if(command.type === 1 || command.type === undefined) { - command.name = command.name.toLowerCase(); - if(!command.name.match(/^[\w-]{1,32}$/)) { - throw new Error("Slash Command names must match the regular expression \"^[\\w-]{1,32}$\""); - } - } + if(command.name !== undefined && command.type === 1) { + command.name = command.name.toLowerCase(); } + command.default_member_permissions = command.defaultMemberPermissions; + command.description_localizations = command.descriptionLocalizations; + command.name_localizations = command.nameLocalizations; } - return this.requestHandler.request("PUT", Endpoints.GUILD_COMMANDS(this.application.id, guildID), true, commands); + return this.requestHandler.request("PUT", Endpoints.GUILD_COMMANDS(this.application.id, guildID), true, commands).then((applicationCommands) => applicationCommands.map((applicationCommand) => new ApplicationCommand(applicationCommand, this))); } /** @@ -567,23 +561,24 @@ class Client extends EventEmitter { * Create a global application command * @arg {Object} command A command object * @arg {String} command.name The command name - * @arg {String} [command.description] The command description (Slash Commands Only) + * @arg {Number} command.type The [type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types) of command + * @arg {Object} [command.nameLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @arg {String} [command.description] The command description (chat input commands only) + * @arg {Object} [command.descriptionLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale * @arg {Array} [command.options] An array of [command options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) - * @arg {Number} [type=1] The type of application command, 1 for slash command, 2 for user, and 3 for message - * @arg {Boolean} [command.defaultPermission=true] Whether the command is enabled by default when the app is added to a guild - * @returns {Promise} Resolves with a commands object + * @arg {String} [command.defaultMemberPermissions] The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @arg {Boolean} [command.dmPermission=true] If this command can be used in direct messages + * @returns {Promise} */ createCommand(command) { - if(command.name !== undefined){ - if(command.type === 1 || command.type === undefined) { - command.name = command.name.toLowerCase(); - if(!command.name.match(/^[\w-]{1,32}$/)) { - throw new Error("Slash Command names must match the regular expression \"^[\\w-]{1,32}$\""); - } - } + if(command.name !== undefined && command.type === 1) { + command.name = command.name.toLowerCase(); } - command.default_permission = command.defaultPermission; - return this.requestHandler.request("POST", Endpoints.COMMANDS(this.application.id), true, command); + command.default_member_permissions = command.defaultMemberPermissions; + command.dm_permission = command.dmPermission; + command.description_localizations = command.descriptionLocalizations; + command.name_localizations = command.nameLocalizations; + return this.requestHandler.request("POST", Endpoints.COMMANDS(this.application.id), true, command).then((applicationCommand) => new ApplicationCommand(applicationCommand, this)); } /** @@ -637,23 +632,22 @@ class Client extends EventEmitter { * @arg {String} guildID The ID of the guild to create the command in * @arg {Object} command A command object * @arg {String} command.name The command name - * @arg {String} [command.description] The command description (Slash Commands Only) + * @arg {Number} command.type The [type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types) of command + * @arg {Object} [command.nameLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @arg {String} [command.description] The command description (chat input commands only) + * @arg {Object} [command.descriptionLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale * @arg {Array} [command.options] An array of [command options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) - * @arg {Number} [type=1] The type of application command, 1 for slash command, 2 for user, and 3 for message - * @arg {Boolean} [command.defaultPermission] Whether the command is enabled by default when the app is added to a guild - * @returns {Promise} Resolves with a commands object + * @arg {String} [command.defaultMemberPermissions] The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @returns {Promise} */ createGuildCommand(guildID, command) { - if(command.name !== undefined){ - if(command.type === 1 || command.type === undefined) { - command.name = command.name.toLowerCase(); - if(!command.name.match(/^[\w-]{1,32}$/)) { - throw new Error("Slash Command names must match the regular expression \"^[\\w-]{1,32}$\""); - } - } + if(command.name !== undefined && command.type === 1) { + command.name = command.name.toLowerCase(); } - command.default_permission = command.defaultPermission; - return this.requestHandler.request("POST", Endpoints.GUILD_COMMANDS(this.application.id, guildID), true, command); + command.default_member_permissions = command.defaultMemberPermissions; + command.description_localizations = command.descriptionLocalizations; + command.name_localizations = command.nameLocalizations; + return this.requestHandler.request("POST", Endpoints.GUILD_COMMANDS(this.application.id, guildID), true, command).then((applicationCommand) => new ApplicationCommand(applicationCommand, this)); } /** @@ -732,27 +726,11 @@ class Client extends EventEmitter { * @arg {Boolean} [options.data.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. * @arg {Boolean | Array} [options.data.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [options.data.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [options.data.components] An array of component objects - * @arg {String} [options.data.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [options.data.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [options.data.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [options.data.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [options.data.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [options.data.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [options.data.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [options.data.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [options.data.components[].options[].description] The description for this option - * @arg {Object} [options.data.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} options.data.components[].options[].label The label for this option - * @arg {Number | String} options.data.components[].options[].value The value for this option - * @arg {String} [options.data.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [options.data.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} options.data.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [options.data.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [options.data.content] A content string - * @arg {Object} [options.data.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [options.data.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [options.data.flags] 64 for Ephemeral (applies to Application Commands and Message Components) + * @arg {Object} [options.data.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [options.data.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Boolean} [options.data.flags] A number representing the flags to apply to the response. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @arg {Boolean} [options.data.tts] Set the message TTS flag * @arg {Number} options.type The response type to send [Check Discord docs for valid responses](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type). * @arg {Object | Array} [file] A file object (or an Array of them) @@ -780,26 +758,10 @@ class Client extends EventEmitter { * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object} [content.messageReference] The message reference, used when replying to messages * @arg {String} [content.messageReference.channelID] The channel ID of the referenced message * @arg {Boolean} [content.messageReference.failIfNotExists=true] Whether to throw an error if the message reference doesn't exist. If false, and the referenced message doesn't exist, the message is created without a referenced message @@ -984,9 +946,6 @@ class Client extends EventEmitter { * @returns {Promise} */ deleteCommand(commandID) { - if(!commandID) { - throw new Error("You must provide an id of the command to delete."); - } return this.requestHandler.request("DELETE", Endpoints.COMMAND(this.application.id, commandID), true); } @@ -1006,12 +965,6 @@ class Client extends EventEmitter { * @returns {Promise} */ deleteGuildCommand(guildID, commandID) { - if(!guildID) { - throw new Error("You must provide an id of the guild which the command is in."); - } - if(!commandID) { - throw new Error("You must provide an id of the command to delete."); - } return this.requestHandler.request("DELETE", Endpoints.GUILD_COMMAND(this.application.id, guildID, commandID), true); } @@ -1377,26 +1330,24 @@ class Client extends EventEmitter { * Edit a global application command * @arg {String} commandID The command id * @arg {Object} command A command object - * @arg {String} command.name The command name - * @arg {String} [command.description] The command description (Slash Commands Only) + * @arg {String} [command.name] The command name + * @arg {Object} [command.nameLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @arg {String} [command.description] The command description (chat input commands only) + * @arg {Object} [command.descriptionLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale * @arg {Array} [command.options] An array of [command options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) - * @arg {Boolean} [command.defaultPermission] Whether the command is enabled by default when the app is added to a guild - * @returns {Promise} Resolves with a commands object + * @arg {String} [command.defaultMemberPermissions] The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @arg {Boolean} [command.dmPermission] If this command can be used in direct messages + * @returns {Promise} */ editCommand(commandID, command) { - if(!commandID) { - throw new Error("You must provide an id of the command to edit."); - } - if(command.name !== undefined){ - if(command.type === 1 || command.type === undefined) { - command.name = command.name.toLowerCase(); - if(!command.name.match(/^[\w-]{1,32}$/)) { - throw new Error("Slash Command names must match the regular expression \"^[\\w-]{1,32}$\""); - } - } + if(command.name !== undefined && command.type === 1) { + command.name = command.name.toLowerCase(); } - command.default_permission = command.defaultPermission; - return this.requestHandler.request("PATCH", Endpoints.COMMAND(this.application.id, commandID), true, command); + command.default_member_permissions = command.defaultMemberPermissions; + command.dm_permission = command.dmPermission; + command.description_localizations = command.descriptionLocalizations; + command.name_localizations = command.nameLocalizations; + return this.requestHandler.request("PATCH", Endpoints.COMMAND(this.application.id, commandID), true, command).then((applicationCommand) => new ApplicationCommand(applicationCommand, this)); } /** @@ -1408,12 +1359,6 @@ class Client extends EventEmitter { * @returns {Promise} Resolves with a [GuildApplicationCommandPermissions](https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure) object. */ editCommandPermissions(guildID, commandID, permissions) { - if(!guildID) { - throw new Error("You must provide an id of the guild whose permissions you want to edit."); - } - if(!commandID) { - throw new Error("You must provide an id of the command whose permissions you want to edit."); - } return this.requestHandler.request("PUT", Endpoints.COMMAND_PERMISSIONS(this.application.id, guildID, commandID), true, {permissions}); } @@ -1470,26 +1415,22 @@ class Client extends EventEmitter { * Edit a guild application command * @arg {String} guildID The guild id * @arg {Object} command A command object - * @arg {String} command.name The command name - * @arg {String} [command.description] The command description (Slash Commands Only) + * @arg {String} [command.name] The command name + * @arg {Object} [command.nameLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @arg {String} [command.description] The command description (chat input commands only) + * @arg {Object} [command.descriptionLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale * @arg {Array} [command.options] An array of [command options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) - * @arg {Boolean} [command.defaultPermission] Whether the command is enabled by default when the app is added to a guild - * @returns {Promise} Resolves with a commands object + * @arg {String} [command.defaultMemberPermissions] The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @returns {Promise} */ editGuildCommand(guildID, commandID, command) { - if(!commandID) { - throw new Error("You must provide an id of the command to edit."); - } - if(command.name !== undefined){ - if(command.type === 1 || command.type === undefined) { - command.name = command.name.toLowerCase(); - if(!command.name.match(/^[\w-]{1,32}$/)) { - throw new Error("Slash Command names must match the regular expression \"^[\\w-]{1,32}$\""); - } - } + if(command.name !== undefined && command.type === 1) { + command.name = command.name.toLowerCase(); } - command.default_permission = command.defaultPermission; - return this.requestHandler.request("PATCH", Endpoints.GUILD_COMMAND(this.application.id, guildID, commandID), true, command); + command.default_member_permissions = command.defaultMemberPermissions; + command.description_localizations = command.descriptionLocalizations; + command.name_localizations = command.nameLocalizations; + return this.requestHandler.request("PATCH", Endpoints.GUILD_COMMAND(this.application.id, guildID, commandID), true, command).then((applicationCommand) => new ApplicationCommand(applicationCommand, this)); } /** @@ -1674,30 +1615,14 @@ class Client extends EventEmitter { * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [content.file] A file object (or an Array of them) * @arg {Buffer} content.file[].file A buffer containing file data * @arg {String} content.file[].name What to name the file - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @returns {Promise} */ editMessage(channelID, messageID, content) { @@ -1965,26 +1890,10 @@ class Client extends EventEmitter { * @arg {Boolean} [options.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. * @arg {Boolean | Array} [options.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [options.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [options.components] An array of component objects - * @arg {String} [options.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [options.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [options.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [options.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [options.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [options.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [options.components[].options[].description] The description for this option - * @arg {Object} [options.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} options.components[].options[].label The label for this option - * @arg {Number | String} options.components[].options[].value The value for this option - * @arg {String} [options.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [options.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} options.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [options.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [options.content] A content string - * @arg {Object} [options.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [options.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [options.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [options.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [options.file] A file object (or an Array of them) * @arg {Buffer} options.file[].file A buffer containing file data * @arg {String} options.file[].name What to name the file @@ -2058,30 +1967,14 @@ class Client extends EventEmitter { * @arg {Boolean | Array} [options.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. * @arg {Boolean} [options.auth=false] Whether or not to authenticate with the bot token. * @arg {String} [options.avatarURL] A URL for a custom avatar, defaults to webhook default avatar if not specified - * @arg {Array} [options.components] An array of component objects - * @arg {String} [options.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [options.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [options.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [options.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [options.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [options.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [options.components[].options[].description] The description for this option - * @arg {Object} [options.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} options.components[].options[].label The label for this option - * @arg {Number | String} options.components[].options[].value The value for this option - * @arg {String} [options.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [options.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} options.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [options.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [options.content] A content string - * @arg {Object} [options.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [options.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [options.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [options.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [options.file] A file object (or an Array of them) * @arg {Buffer} options.file.file A buffer containing file data * @arg {String} options.file.name What to name the file - * @arg {Number} [options.flags] Flags to execute the webhook with, 64 for ephemeral (Interaction webhooks only) + * @arg {Number} [options.flags] A number representing the flags to apply to the message. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @arg {String} [options.threadID] The ID of the thread channel in the webhook's channel to send the message to * @arg {Boolean} [options.tts=false] Whether the message should be a TTS message or not * @arg {String} [options.username] A custom username, defaults to webhook default username if not specified @@ -2223,13 +2116,15 @@ class Client extends EventEmitter { /** * Get a global application command * @arg {String} commandID The command id - * @returns {Promise} Resolves with an application command object. + * @arg {Boolean} [withLocalizations] Include [localizations](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands) in the response + * @returns {Promise} */ - getCommand(commandID) { - if(!commandID) { - throw new Error("You must provide an id of the command to get."); + getCommand(commandID, withLocalizations) { + let qs = ""; + if(withLocalizations) { + qs += "&with_localizations=true"; } - return this.requestHandler.request("GET", Endpoints.COMMAND(this.application.id, commandID), true); + return this.requestHandler.request("GET", Endpoints.COMMAND(this.application.id, commandID) + (qs ? "?" + qs : ""), true).then((applicationCommand) => new ApplicationCommand(applicationCommand, this)); } /** @@ -2239,21 +2134,20 @@ class Client extends EventEmitter { * @returns {Promise} Resolves with a guild application command permissions object. */ getCommandPermissions(guildID, commandID) { - if(!guildID) { - throw new Error("You must provide an id of the guild whose permissions you want to get."); - } - if(!commandID) { - throw new Error("You must provide an id of the command whose permissions you want to get."); - } return this.requestHandler.request("GET", Endpoints.COMMAND_PERMISSIONS(this.application.id, guildID, commandID), true); } /** * Get the global application commands - * @returns {Promise>} Resolves with an array of application command objects. + * @arg {Boolean} [withLocalizations] Include [localizations](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands) in the response + * @returns {Promise} */ - getCommands() { - return this.requestHandler.request("GET", Endpoints.COMMANDS(this.application.id), true); + getCommands(withLocalizations) { + let qs = ""; + if(withLocalizations) { + qs += "&with_localizations=true"; + } + return this.requestHandler.request("GET", Endpoints.COMMANDS(this.application.id) + (qs ? "?" + qs : ""), true).then((applicationCommands) => applicationCommands.map((applicationCommand) => new ApplicationCommand(applicationCommand, this))); } /** @@ -2411,13 +2305,15 @@ class Client extends EventEmitter { * Get a guild application command * @arg {String} guildID The guild id * @arg {String} commandID The command id - * @returns {Promise} Resolves with an command object. + * @arg {Boolean} [withLocalizations] Include [localizations](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands) in the response + * @returns {Promise} Resolves with an command object. */ - getGuildCommand(guildID, commandID) { - if(!commandID) { - throw new Error("You must provide an id of the command to get."); + getGuildCommand(guildID, commandID, withLocalizations) { + let qs = ""; + if(withLocalizations) { + qs += "&with_localizations=true"; } - return this.requestHandler.request("GET", Endpoints.GUILD_COMMAND(this.application.id, guildID, commandID), true); + return this.requestHandler.request("GET", Endpoints.GUILD_COMMAND(this.application.id, guildID, commandID) + (qs ? "?" + qs : ""), true).then((applicationCommand) => new ApplicationCommand(applicationCommand, this)); } /** @@ -2426,19 +2322,21 @@ class Client extends EventEmitter { * @returns {Promise>} Resolves with an array of guild application command permissions objects. */ getGuildCommandPermissions(guildID) { - if(!guildID) { - throw new Error("You must provide an id of the guild whose permissions you want to get."); - } return this.requestHandler.request("GET", Endpoints.GUILD_COMMAND_PERMISSIONS(this.application.id, guildID), true); } /** * Get a guild's application commands * @arg {String} guildID The guild id - * @returns {Promise>} Resolves with an array of command objects. + * @arg {Boolean} [withLocalizations] Include [localizations](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands) in the response + * @returns {Promise} Resolves with an array of command objects. */ - getGuildCommands(guildID) { - return this.requestHandler.request("GET", Endpoints.GUILD_COMMANDS(this.application.id, guildID), true); + getGuildCommands(guildID, withLocalizations) { + let qs = ""; + if(withLocalizations) { + qs += "&with_localizations=true"; + } + return this.requestHandler.request("GET", Endpoints.GUILD_COMMANDS(this.application.id, guildID) + (qs ? "?" + qs : ""), true).then((applicationCommands) => applicationCommands.map((applicationCommand) => new ApplicationCommand(applicationCommand, this))); } /** @@ -2692,7 +2590,7 @@ class Client extends EventEmitter { /** * Get data on an OAuth2 application * @arg {String} [appID="@me"] The client ID of the application to get data for (user accounts only). "@me" refers to the logged in user's own application - * @returns {Promise} The bot's application data. Refer to [the official Discord API documentation entry](https://discord.com/developers/docs/topics/oauth2#get-current-application-information) for object structure + * @returns {Promise} The bot's application data. Refer to [Discord's Documentation](https://discord.com/developers/docs/topics/oauth2#get-current-application-information) for object structure */ getOAuthApplication(appID) { return this.requestHandler.request("GET", Endpoints.OAUTH2_APPLICATION(appID || "@me"), true); diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index 86a31af7d..f33427ebd 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -2338,7 +2338,7 @@ class Shard extends EventEmitter { /** * Fired when an interaction is created * @event Client#interactionCreate - * @prop {PingInteraction | CommandInteraction | ComponentInteraction | AutocompleteInteraction | UnknownInteraction} Interaction The Interaction that was created + * @prop {CommandInteraction | ComponentInteraction | AutocompleteInteraction} Interaction The Interaction that was created */ this.emit("interactionCreate", Interaction.from(packet.d, this.client)); break; diff --git a/lib/structures/ApplicationCommand.js b/lib/structures/ApplicationCommand.js new file mode 100644 index 000000000..bdf213216 --- /dev/null +++ b/lib/structures/ApplicationCommand.js @@ -0,0 +1,95 @@ +const Base = require("./Base"); + +/** + * Represents an application command + * @prop {String} applicationID The ID of the application that this command belongs to + * @prop {String?} defaultMemberPermissions The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @prop {String} description The description of the command (empty for user & message commands) + * @prop {Object?} descriptionLocalizations A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale + * @prop {Boolean?} dmPermission If this command can be used in direct messages (global commands only) + * @prop {String?} guildID The ID of the guild associated with this command (guild commands only) + * @prop {String} id The ID of the application command + * @prop {String} name The name of the command + * @prop {Object?} nameLocalizations A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @prop {Object[]?} options The [options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) associated with this command + * @prop {Number} type The [command type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types) + * @prop {String} version The id of the version of this command + */ +class ApplicationCommand extends Base { + constructor(data, client) { + super(data.id); + this._client = client; + this.applicationID = data.application_id; + this.name = data.name; + this.description = data.description; + this.type = data.type; + this.version = data.version; + + if(data.guild_id !== undefined) { + this.guildID = data.guild_id; + } + + if(data.name_localizations !== undefined) { + this.nameLocalizations = data.name_localizations; + } + + if(data.description_localizations !== undefined) { + this.descriptionLocalizations = data.description_localizations; + } + + if(data.options !== undefined) { + this.options = data.options; + } + + if(data.default_member_permissions !== undefined) { + this.defaultMemberPermissions = data.default_member_permissions; + } + + if(data.dm_permission !== undefined) { + this.dmPermission = data.dm_permission; + } + } + + /** + * Delete This command + * @returns {Promise} + */ + delete() { + return this.guildID === undefined ? this._client.deleteCommand.call(this._client, this.id) : this._client.deleteGuildCommand.call(this._client, this.guildID, this.id); + } + + /** + * Edit this application command + * @arg {Object} options The properties to edit + * @arg {String} [options.name] The command name + * @arg {Object} [options.nameLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @arg {String} [options.description] The command description (chat input commands only) + * @arg {Object} [options.descriptionLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale + * @arg {Array} [options.options] An array of [command options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) + * @arg {String} [options.defaultMemberPermissions] The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @arg {Boolean} [options.dmPermission] If this command can be used in direct messages (global commands only) + * @returns {Promise} + */ + edit(options) { + return this.guildID === undefined ? this._client.editCommand.call(this._client, this.id, options) : this._client.editGuildCommand.call(this._client, this.id, this.guildID, options); + } + + toJSON(props = []) { + return super.toJSON([ + "applicationID", + "defaultMemberPermissions", + "description", + "descriptionLocalizations", + "dmPermission", + "guildID", + "name", + "nameLocalizations", + "options", + "type", + "version", + ...props + ]); + } +} + +module.exports = ApplicationCommand; diff --git a/lib/structures/AutocompleteInteraction.js b/lib/structures/AutocompleteInteraction.js index a3f4a703e..fbf2993e8 100644 --- a/lib/structures/AutocompleteInteraction.js +++ b/lib/structures/AutocompleteInteraction.js @@ -1,15 +1,11 @@ "use strict"; const Interaction = require("./Interaction"); -const Member = require("./Member"); -const Permission = require("./Permission"); const {InteractionResponseTypes} = require("../Constants"); /** * Represents an application command autocomplete interaction. See Interaction for more properties. * @extends Interaction -* @prop {Permission?} appPermissions The permissions the app or bot has within the channel the interaction was sent from -* @prop {PrivateChannel | TextChannel | NewsChannel} channel The channel the interaction was created in. Can be partial with only the id if the channel is not cached. * @prop {Object} data The data attached to the interaction * @prop {String} data.id The ID of the Application Command * @prop {String} data.name The command name @@ -17,46 +13,12 @@ const {InteractionResponseTypes} = require("../Constants"); * @prop {String?} data.target_id The id the of user or message targetted by a context menu command * @prop {Array?} data.options The run Application Command options * @prop {String} data.options[].name The name of the Application Command option -* @prop {Number} data.options[].type Command option type, 1-10 -* @prop {(String | Number | Boolean)?} data.options[].value The value of the run Application Command (Mutually exclusive with options) -* @prop {Boolean?} data.options[].focused Whether or not the option is focused -* @prop {Array?} data.options[].options The run Application Command options (Mutually exclusive with value) -* @prop {String?} guildID The ID of the guild in which the interaction was created -* @prop {Member?} member The member who triggered the interaction (This is only sent when the interaction is invoked within a guild) -* @prop {User?} user The user who triggered the interaction (This is only sent when the interaction is invoked within a dm) +* @prop {Number} data.options[].type The [option type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type) +* @prop {(String | Number | Boolean)?} data.options[].value The option value (Mutually exclusive with options) +* @prop {Boolean?} data.options[].focused If the option is focused +* @prop {Array?} data.options[].options Sub-options (Mutually exclusive with value, subcommand/subcommandgroup) */ class AutocompleteInteraction extends Interaction { - constructor(info, client) { - super(info, client); - - this.channel = this._client.getChannel(info.channel_id) || { - id: info.channel_id - }; - - this.data = info.data; - - if(info.guild_id !== undefined) { - this.guildID = info.guild_id; - } - - if(info.member !== undefined) { - if(this.channel.guild) { - info.member.id = info.member.user.id; - this.member = this.channel.guild.members.update(info.member, this.channel.guild); - } else { - const guild = this._client.guilds.get(info.guild_id); - this.member = new Member(info.member, guild, this._client); - } - } - - if(info.user !== undefined) { - this.user = this._client.users.update(info.user, client); - } - - if(info.app_permissions !== undefined) { - this.appPermissions = new Permission(info.app_permissions); - } - } /** * Acknowledges the autocomplete interaction with a result of choices. @@ -66,7 +28,7 @@ class AutocompleteInteraction extends Interaction { * @arg {String} choices[].value The choice value to return to the bot * @returns {Promise} */ - async acknowledge(choices) { + acknowledge(choices) { return this.result(choices); } @@ -78,7 +40,7 @@ class AutocompleteInteraction extends Interaction { * @arg {String} choices[].value The choice value to return to the bot * @returns {Promise} */ - async result(choices) { + result(choices) { if(this.acknowledged === true) { throw new Error("You have already acknowledged this interaction."); } @@ -87,7 +49,6 @@ class AutocompleteInteraction extends Interaction { data: {choices} }).then(() => this.update()); } - } module.exports = AutocompleteInteraction; diff --git a/lib/structures/CommandInteraction.js b/lib/structures/CommandInteraction.js index 8a44fb046..169bc6d16 100644 --- a/lib/structures/CommandInteraction.js +++ b/lib/structures/CommandInteraction.js @@ -7,15 +7,12 @@ const Role = require("./Role"); const Channel = require("./Channel"); const Message = require("./Message"); const Collection = require("../util/Collection"); -const Permission = require("./Permission"); const {InteractionResponseTypes} = require("../Constants"); /** * Represents an application command interaction. See Interaction for more properties. * @extends Interaction -* @prop {Permission?} appPermissions The permissions the app or bot has within the channel the interaction was sent from -* @prop {PrivateChannel | TextChannel | NewsChannel} channel The channel the interaction was created in. Can be partial with only the id if the channel is not cached. * @prop {Object} data The data attached to the interaction * @prop {String} data.id The ID of the Application Command * @prop {String} data.name The command name @@ -23,47 +20,39 @@ const {InteractionResponseTypes} = require("../Constants"); * @prop {String?} data.target_id The id the of user or message targetted by a context menu command * @prop {Array?} data.options The run Application Command options * @prop {String} data.options[].name The name of the Application Command option -* @prop {Number} data.options[].type Command option type, 1-10 -* @prop {(String | Number | Boolean)?} data.options[].value The value of the run Application Command (Mutually exclusive with options) -* @prop {Array?} data.options[].options The run Application Command options (Mutually exclusive with value) -* @prop {Object?} data.resolved converted users + roles + channels -* @prop {Collection?} data.resolved.users converted users -* @prop {Collection?} data.resolved.members converted members -* @prop {Collection?} data.resolved.roles converted roles -* @prop {Collection?} data.resolved.channels converted channels -* @prop {String?} guildID The ID of the guild in which the interaction was created -* @prop {Member?} member The member who triggered the interaction (This is only sent when the interaction is invoked within a guild) -* @prop {User?} user The user who triggered the interaction (This is only sent when the interaction is invoked within a dm) +* @prop {Number} data.options[].type The [option type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type) +* @prop {(String | Number | Boolean)?} data.options[].value The option value (Mutually exclusive with options) +* @prop {Array?} data.options[].options Sub-options (Mutually exclusive with value, subcommand/subcommandgroup) +* @prop {Object?} data.resolved resolved objects within the interaction (e.x. the user for a user option) +* @prop {Collection?} data.resolved.channels resolved channels +* @prop {Collection?} data.resolved.members resolved members +* @prop {Collection?} data.resolved.messages resolved messages +* @prop {Collection?} data.resolved.roles resolved roles +* @prop {Collection?} data.resolved.users resolved users */ class CommandInteraction extends Interaction { - constructor(info, client) { - super(info, client); + constructor(data, client) { + super(data, client); - this.channel = this._client.getChannel(info.channel_id) || { - id: info.channel_id - }; - - this.data = JSON.parse(JSON.stringify(info.data)); - - if(info.data.resolved !== undefined) { + if(data.data.resolved !== undefined) { //Users - if(info.data.resolved.users !== undefined) { + if(data.data.resolved.users !== undefined) { const usermap = new Collection(User); - Object.entries(info.data.resolved.users).forEach(([id, user]) => { + Object.entries(data.data.resolved.users).forEach(([id, user]) => { usermap.set(id, this._client.users.update(user, client)); }); this.data.resolved.users = usermap; } //Members - if(info.data.resolved.members !== undefined) { + if(data.data.resolved.members !== undefined) { const membermap = new Collection(Member); - Object.entries(info.data.resolved.members).forEach(([id, member]) => { + Object.entries(data.data.resolved.members).forEach(([id, member]) => { member.id = id; member.user = {id}; if(this.channel.guild) { membermap.set(id, this.channel.guild.members.update(member, this.channel.guild)); } else { - const guild = this._client.guilds.get(info.guild_id); + const guild = this._client.guilds.get(data.guild_id); if(guild) { membermap.set(id, guild.members.update(member, guild)); } else { @@ -74,61 +63,39 @@ class CommandInteraction extends Interaction { this.data.resolved.members = membermap; } //Roles - if(info.data.resolved.roles !== undefined) { + if(data.data.resolved.roles !== undefined) { const rolemap = new Collection(Role); - Object.entries(info.data.resolved.roles).forEach(([id, role]) => { - rolemap.set(id, new Role(role, this._client)); + Object.entries(data.data.resolved.roles).forEach(([id, role]) => { + rolemap.set(id, new Role(role, this.channel.guild)); }); this.data.resolved.roles = rolemap; } //Channels - if(info.data.resolved.channels !== undefined) { + if(data.data.resolved.channels !== undefined) { const channelmap = new Collection(Channel); - Object.entries(info.data.resolved.channels).forEach(([id, channel]) => { - channelmap.set(id, new Channel(channel, this._client)); + Object.entries(data.data.resolved.channels).forEach(([id, channel]) => { + channelmap.set(id, Channel.from(channel, this._client) || new Channel(channel, this._client)); }); this.data.resolved.channels = channelmap; } //Messages - if(info.data.resolved.messages !== undefined) { + if(data.data.resolved.messages !== undefined) { const messagemap = new Collection(Message); - Object.entries(info.data.resolved.messages).forEach(([id, message]) => { + Object.entries(data.data.resolved.messages).forEach(([id, message]) => { messagemap.set(id, new Message(message, this._client)); }); this.data.resolved.messages = messagemap; } } - - if(info.guild_id !== undefined) { - this.guildID = info.guild_id; - } - - if(info.member !== undefined) { - if(this.channel.guild) { - info.member.id = info.member.user.id; - this.member = this.channel.guild.members.update(info.member, this.channel.guild); - } else { - const guild = this._client.guilds.get(info.guild_id); - this.member = new Member(info.member, guild, this._client); - } - } - - if(info.user !== undefined) { - this.user = this._client.users.update(info.user, client); - } - - if(info.app_permissions !== undefined) { - this.appPermissions = new Permission(info.app_permissions); - } } /** * Acknowledges the interaction with a defer response * Note: You can **not** use more than 1 initial interaction response per interaction. - * @arg {Number} [flags] 64 for Ephemeral + * @arg {Number} [flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @returns {Promise} */ - async acknowledge(flags) { + acknowledge(flags) { return this.defer(flags); } @@ -139,34 +106,18 @@ class CommandInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [options.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Number} [content.flags] 64 for Ephemeral + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [options.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async createFollowup(content, file) { + createFollowup(content, file) { if(this.acknowledged === false) { throw new Error("createFollowup cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first."); } @@ -193,34 +144,18 @@ class CommandInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [content.flags] 64 for Ephemeral + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async createMessage(content, file) { + createMessage(content, file) { if(this.acknowledged === true) { return this.createFollowup(content, file); } @@ -245,10 +180,10 @@ class CommandInteraction extends Interaction { /** * Acknowledges the interaction with a defer response * Note: You can **not** use more than 1 initial interaction response per interaction. - * @arg {Number} [flags] 64 for Ephemeral + * @arg {Number} [flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @returns {Promise} */ - async defer(flags) { + defer(flags) { if(this.acknowledged === true) { throw new Error("You have already acknowledged this interaction."); } @@ -265,7 +200,7 @@ class CommandInteraction extends Interaction { * @arg {String} messageID the id of the message to delete, or "@original" for the original response. * @returns {Promise} */ - async deleteMessage(messageID) { + deleteMessage(messageID) { if(this.acknowledged === false) { throw new Error("deleteMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first."); } @@ -277,7 +212,7 @@ class CommandInteraction extends Interaction { * Warning: Will error with ephemeral messages. * @returns {Promise} */ - async deleteOriginalMessage() { + deleteOriginalMessage() { if(this.acknowledged === false) { throw new Error("deleteOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first."); } @@ -293,32 +228,16 @@ class CommandInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async editMessage(messageID, content, file) { + editMessage(messageID, content, file) { if(this.acknowledged === false) { throw new Error("editMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first."); } @@ -345,32 +264,16 @@ class CommandInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async editOriginalMessage(content, file) { + editOriginalMessage(content, file) { if(this.acknowledged === false) { throw new Error("editOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first."); } @@ -394,7 +297,7 @@ class CommandInteraction extends Interaction { * Warning: Will error with ephemeral messages. * @returns {Promise} */ - async getOriginalMessage() { + getOriginalMessage() { if(this.acknowledged === false) { throw new Error("getOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first."); } diff --git a/lib/structures/ComponentInteraction.js b/lib/structures/ComponentInteraction.js index cd9a7df77..ca4e657d4 100644 --- a/lib/structures/ComponentInteraction.js +++ b/lib/structures/ComponentInteraction.js @@ -3,57 +3,33 @@ const Interaction = require("./Interaction"); const Message = require("./Message"); const Member = require("./Member"); -const Permission = require("./Permission"); const {InteractionResponseTypes} = require("../Constants"); /** * Represents a message component interaction. See Interaction for more properties. * @extends Interaction -* @prop {Permission?} appPermissions The permissions the app or bot has within the channel the interaction was sent from -* @prop {PrivateChannel | TextChannel | NewsChannel} channel The channel the interaction was created in. Can be partial with only the id if the channel is not cached. * @prop {Object} data The data attached to the interaction * @prop {Number} data.component_type The type of Message Component * @prop {String} data.custom_id The ID of the Message Component * @prop {Array?} data.values The value of the run selected options (Select Menus Only) -* @prop {String?} guildID The ID of the guild in which the interaction was created -* @prop {Member?} member The member who triggered the interaction (This is only sent when the interaction is invoked within a guild) * @prop {Message?} message The message the interaction came from. -* @prop {User?} user The user who triggered the interaction (This is only sent when the interaction is invoked within a dm) */ class ComponentInteraction extends Interaction { - constructor(info, client) { - super(info, client); + constructor(data, client) { + super(data, client); - this.channel = this._client.getChannel(info.channel_id) || { - id: info.channel_id - }; - - this.data = info.data; - - if(info.guild_id !== undefined) { - this.guildID = info.guild_id; - } - - if(info.member !== undefined) { + if(data.member !== undefined) { if(this.channel.guild) { - info.member.id = info.member.user.id; - this.member = this.channel.guild.members.update(info.member, this.channel.guild); + data.member.id = data.member.user.id; + this.member = this.channel.guild.members.update(data.member, this.channel.guild); } else { - const guild = this._client.guilds.get(info.guild_id); - this.member = new Member(info.member, guild, this._client); + const guild = this._client.guilds.get(data.guild_id); + this.member = new Member(data.member, guild, this._client); } } - if(info.message !== undefined) { - this.message = new Message(info.message, this._client); - } - - if(info.user !== undefined) { - this.user = this._client.users.update(info.user, client); - } - - if(info.app_permissions !== undefined) { - this.appPermissions = new Permission(info.app_permissions); + if(data.message !== undefined) { + this.message = new Message(data.message, this._client); } } @@ -61,7 +37,7 @@ class ComponentInteraction extends Interaction { * Acknowledges the interaction with a defer message update response * @returns {Promise} */ - async acknowledge() { + acknowledge() { return this.deferUpdate(); } @@ -72,34 +48,18 @@ class ComponentInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [options.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Number} [content.flags] 64 for Ephemeral + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [options.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async createFollowup(content, file) { + createFollowup(content, file) { if(this.acknowledged === false) { throw new Error("createFollowup cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first."); } @@ -126,34 +86,18 @@ class ComponentInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [content.flags] 64 for Ephemeral + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async createMessage(content, file) { + createMessage(content, file) { if(this.acknowledged === true) { return this.createFollowup(content, file); } @@ -178,10 +122,10 @@ class ComponentInteraction extends Interaction { /** * Acknowledges the interaction with a defer response * Note: You can **not** use more than 1 initial interaction response per interaction. - * @arg {Number} [flags] 64 for Ephemeral + * @arg {Number} [flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @returns {Promise} */ - async defer(flags) { + defer(flags) { if(this.acknowledged === true) { throw new Error("You have already acknowledged this interaction."); } @@ -198,7 +142,7 @@ class ComponentInteraction extends Interaction { * Note: You can **not** use more than 1 initial interaction response per interaction. * @returns {Promise} */ - async deferUpdate() { + deferUpdate() { if(this.acknowledged === true) { throw new Error("You have already acknowledged this interaction."); } @@ -212,7 +156,7 @@ class ComponentInteraction extends Interaction { * @arg {String} messageID the id of the message to delete, or "@original" for the original response. * @returns {Promise} */ - async deleteMessage(messageID) { + deleteMessage(messageID) { if(this.acknowledged === false) { throw new Error("deleteMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first."); } @@ -224,7 +168,7 @@ class ComponentInteraction extends Interaction { * Warning: Will error with ephemeral messages. * @returns {Promise} */ - async deleteOriginalMessage() { + deleteOriginalMessage() { if(this.acknowledged === false) { throw new Error("deleteOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first."); } @@ -240,32 +184,16 @@ class ComponentInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async editMessage(messageID, content, file) { + editMessage(messageID, content, file) { if(this.acknowledged === false) { throw new Error("editMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first."); } @@ -292,32 +220,16 @@ class ComponentInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async editOriginalMessage(content, file) { + editOriginalMessage(content, file) { if(this.acknowledged === false) { throw new Error("editOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first."); } @@ -346,34 +258,18 @@ class ComponentInteraction extends Interaction { * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [content.flags] 64 for Ephemeral + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @arg {Boolean} [content.tts] Set the message TTS flag * @arg {Object | Array} [file] A file object (or an Array of them) * @arg {Buffer} file.file A buffer containing file data * @arg {String} file.name What to name the file * @returns {Promise} */ - async editParent(content, file) { + editParent(content, file) { if(this.acknowledged === true) { return this.editOriginalMessage(content); } @@ -400,7 +296,7 @@ class ComponentInteraction extends Interaction { * Warning: Will error with ephemeral messages. * @returns {Promise} */ - async getOriginalMessage() { + getOriginalMessage() { if(this.acknowledged === false) { throw new Error("getOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first."); } diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index ed3d5bd62..e52220ca8 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -408,11 +408,13 @@ class Guild extends Base { * Create a guild application command * @arg {Object} command A command object * @arg {String} command.name The command name - * @arg {String} [command.description] The command description (Slash Commands Only) + * @arg {Number} command.type The [type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types) of command + * @arg {Object} [command.nameLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @arg {String} [command.description] The command description (chat input commands only) + * @arg {Object} [command.descriptionLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale * @arg {Array} [command.options] An array of [command options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) - * @arg {Number} [type=1] The type of application command, 1 for slash command, 2 for user, and 3 for message - * @arg {Boolean} [command.defaultPermission] Whether the command is enabled by default when the app is added to a guild - * @returns {Promise} Resolves with a command object + * @arg {String} [command.defaultMemberPermissions] The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @returns {Promise} */ createCommand(command) { return this._client.createGuildCommand.call(this._client, this.id, command); @@ -485,7 +487,7 @@ class Guild extends Base { /** * Delete a guild application command * @arg {String} commandID The command id - * @returns {Promise} Resolves with a promise object + * @returns {Promise} */ deleteCommand(commandID) { return this._client.deleteGuildCommand.call(this._client, this.id, commandID); @@ -634,14 +636,16 @@ class Guild extends Base { * Edit a guild application command * @arg {String} commandID The command id * @arg {Object} command A command object - * @arg {String} command.name The command name - * @arg {String} [command.description] The command description (Slash Commands Only) + * @arg {String} [command.name] The command name + * @arg {Object} [command.nameLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to names for that locale + * @arg {String} [command.description] The command description (chat input commands only) + * @arg {Object} [command.descriptionLocalizations] A map of [locales](https://discord.com/developers/docs/reference#locales) to descriptions for that locale * @arg {Array} [command.options] An array of [command options](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure) - * @arg {Boolean} [command.defaultPermission] Whether the command is enabled by default when the app is added to a guild - * @returns {Promise} Resolves with a command object + * @arg {String} [command.defaultMemberPermissions] The [permissions](https://discord.com/developers/docs/topics/permissions) required by default for this command to be usable + * @returns {Promise} */ - editCommand(commandID, commands) { - return this._client.editGuildCommand.call(this._client, this.id, commandID, commands); + editCommand(commandID, command) { + return this._client.editGuildCommand.call(this._client, this.id, commandID, command); } /** @@ -893,10 +897,11 @@ class Guild extends Base { /** * Get a guild application command * @arg {String} commandID The command id + * @arg {Boolean} withLocalizations Include [localizations](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands) in the response * @returns {Promise} Resolves with a command object */ - getCommand(commandID) { - return this._client.getGuildCommand.call(this._client, this.id, commandID); + getCommand(commandID, withLocalizations) { + return this._client.getGuildCommand.call(this._client, this.id, commandID, withLocalizations); } /** @@ -910,12 +915,14 @@ class Guild extends Base { /** * Get the guild's application commands + * @arg {Boolean} withLocalizations Include [localizations](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands) in the response * @returns {Promise>} Resolves with an array of command objects */ - getCommands() { - return this._client.getGuildCommands.call(this._client, this.id); + getCommands(withLocalizations) { + return this._client.getGuildCommands.call(this._client, this.id, withLocalizations); } + /** * Get the guild's discovery object * @returns {Promise} diff --git a/lib/structures/Interaction.js b/lib/structures/Interaction.js index 9529878c1..dbe325d6f 100644 --- a/lib/structures/Interaction.js +++ b/lib/structures/Interaction.js @@ -2,14 +2,24 @@ const Base = require("./Base"); const {InteractionTypes} = require("../Constants"); +const Member = require("./Member"); +const Permission = require("./Permission"); /** -* Represents an interaction. You also probably want to look at PingInteraction, CommandInteraction, ComponentInteraction, AutocompleteInteraction, and UnknownInteraction. +* Represents an interaction. You also probably want to look at AutocompleteInteraction, CommandInteraction, and ComponentInteraction. * @prop {Boolean} acknowledged Whether or not the interaction has been acknowledged * @prop {String} applicationID The ID of the interaction's application +* @prop {Permission?} appPermissions The permissions the app or bot has within the channel the interaction was sent from +* @prop {(PrivateChannel | TextChannel | NewsChannel)?} channel The channel the interaction was created in. Can be partial with only the id if the channel is not cached. +* @prop {Object} data The data attached to the interaction. See AutocompleteInteraction, CommandInteraction, and ComponentInteraction for specific details +* @prop {String?} guildID The ID of the guild in which the interaction was created +* @prop {String?} guildLocale The selected language of the guild the command was invoked from (e.g. "en-US") * @prop {String} id The ID of the interaction +* @prop {String?} locale The selected language of the invoking user (e.g. "en-US") +* @prop {Member?} member The member who triggered the interaction (This is only sent when the interaction is invoked within a guild) * @prop {String} token The interaction token (Interaction tokens are valid for 15 minutes after initial response and can be used to send followup messages but you must send an initial response within 3 seconds of receiving the event. If the 3 second deadline is exceeded, the token will be invalidated.) -* @prop {Number} type 1 is a Ping, 2 is an Application Command, 3 is a Message Component +* @prop {Number} type The [interaction type](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type) +* @prop {User} user The user who triggered the interaction * @prop {Number} version The interaction version */ class Interaction extends Base { @@ -22,16 +32,55 @@ class Interaction extends Base { this.type = data.type; this.version = data.version; this.acknowledged = false; + + if(data.channel_id !== undefined) { + this.channel = this._client.getChannel(data.channel_id) || { + id: data.channel_id + }; + } + + if(data.data !== undefined) { + this.data = JSON.parse(JSON.stringify(data.data)); + } + + if(data.guild_id !== undefined) { + this.guildID = data.guild_id; + } + + if(data.member !== undefined) { + if(this.channel.guild) { + data.member.id = data.member.user.id; + this.member = this.channel.guild.members.update(data.member, this.channel.guild); + } else { + const guild = this._client.guilds.get(data.guild_id); + this.member = new Member(data.member, guild, this._client); + } + this.user = this.member.user; + } + + if(data.user !== undefined) { + this.user = this._client.users.update(data.user, client); + } + + if(data.locale !== undefined) { + this.locale = data.locale; + } + + if(data.guild_locale !== undefined) { + this.guildLocale = data.guild_locale; + } + + if(data.app_permissions !== undefined) { + this.appPermissions = new Permission(data.app_permissions); + } } + update() { this.acknowledged = true; } static from(data, client) { switch(data.type) { - case InteractionTypes.PING: { - return new PingInteraction(data, client); - } case InteractionTypes.APPLICATION_COMMAND: { return new CommandInteraction(data, client); } @@ -43,16 +92,28 @@ class Interaction extends Base { } } - client.emit("warn", new Error(`Unknown interaction type: ${data.type}\n${JSON.stringify(data)}`)); - return new UnknownInteraction(data, client); + client.emit("warn", new Error(`Unknown interaction type: ${data.type}\n${JSON.stringify(data, null, 2)}`)); + } + + toJSON(props = []) { + return super.toJSON([ + "acknowledged", + "applicationID", + "channel", + "data", + "guildLocale", + "locale", + "token", + "type", + "version", + ...props + ]); } } module.exports = Interaction; // Circular import -const PingInteraction = require("./PingInteraction"); const CommandInteraction = require("./CommandInteraction"); const ComponentInteraction = require("./ComponentInteraction"); const AutocompleteInteraction = require("./AutocompleteInteraction"); -const UnknownInteraction = require("./UnknownInteraction"); diff --git a/lib/structures/Message.js b/lib/structures/Message.js index 76a400344..9f51cd25b 100644 --- a/lib/structures/Message.js +++ b/lib/structures/Message.js @@ -22,7 +22,7 @@ const User = require("./User"); * @prop {Number} createdAt Timestamp of message creation * @prop {Number?} editedTimestamp Timestamp of latest message edit * @prop {Array} embeds Array of embeds -* @prop {Number} flags Message flags (see constants) +* @prop {Number} flags Message flags. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @prop {String} [guildID] The ID of the guild this message is in (undefined if in DMs) * @prop {String} id The ID of the message * @prop {String} jumpLink The url used by Discord clients to jump to this message @@ -472,7 +472,7 @@ class Message extends Base { * @arg {Object | Array} [content.file] A file object (or an Array of them) * @arg {Buffer} content.file[].file A buffer containing file data * @arg {String} content.file[].name What to name the file - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list * @returns {Promise} */ edit(content) { diff --git a/lib/structures/PingInteraction.js b/lib/structures/PingInteraction.js index e901c1dbf..3a4ea9ca9 100644 --- a/lib/structures/PingInteraction.js +++ b/lib/structures/PingInteraction.js @@ -8,16 +8,13 @@ const {InteractionResponseTypes} = require("../Constants"); * @extends Interaction */ class PingInteraction extends Interaction { - constructor(info, client) { - super(info, client); - } /** * Acknowledges the ping interaction with a pong response. * Note: You can **not** use more than 1 initial interaction response per interaction. * @returns {Promise} */ - async acknowledge() { + acknowledge() { return this.pong(); } @@ -26,7 +23,7 @@ class PingInteraction extends Interaction { * Note: You can **not** use more than 1 initial interaction response per interaction. * @returns {Promise} */ - async pong() { + pong() { if(this.acknowledged === true) { throw new Error("You have already acknowledged this interaction."); } diff --git a/lib/structures/PrivateChannel.js b/lib/structures/PrivateChannel.js index f3dff09c8..c4ecdf300 100644 --- a/lib/structures/PrivateChannel.js +++ b/lib/structures/PrivateChannel.js @@ -45,26 +45,10 @@ class PrivateChannel extends Channel { * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object} [content.messageReference] The message reference, used when replying to messages * @arg {String} [content.messageReference.channelID] The channel ID of the referenced message * @arg {Boolean} [content.messageReference.failIfNotExists=true] Whether to throw an error if the message reference doesn't exist. If false, and the referenced message doesn't exist, the message is created without a referenced message @@ -100,30 +84,14 @@ class PrivateChannel extends Channel { * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [content.file] A file object (or an Array of them) * @arg {Buffer} content.file[].file A buffer containing file data * @arg {String} content.file[].name What to name the file - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference * @returns {Promise} */ editMessage(messageID, content) { diff --git a/lib/structures/TextChannel.js b/lib/structures/TextChannel.js index 01e3c8a68..5c14238e2 100644 --- a/lib/structures/TextChannel.js +++ b/lib/structures/TextChannel.js @@ -70,26 +70,10 @@ class TextChannel extends GuildChannel { * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object} [content.messageReference] The message reference, used when replying to messages * @arg {String} [content.messageReference.channelID] The channel ID of the referenced message * @arg {Boolean} [content.messageReference.failIfNotExists=true] Whether to throw an error if the message reference doesn't exist. If false, and the referenced message doesn't exist, the message is created without a referenced message @@ -172,30 +156,14 @@ class TextChannel extends GuildChannel { * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) + * @arg {Array} [content.components] An array of components. See [Discord's Documentation](https://discord.com/developers/docs/interactions/message-components#what-is-a-component) for object structure * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Object} [content.embed] An embed object. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure + * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Object | Array} [content.file] A file object (or an Array of them) * @arg {Buffer} content.file[].file A buffer containing file data * @arg {String} content.file[].name What to name the file - * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference + * @arg {Number} [content.flags] A number representing the flags to apply to the message. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference * @returns {Promise} */ editMessage(messageID, content) { diff --git a/lib/structures/UnknownInteraction.js b/lib/structures/UnknownInteraction.js deleted file mode 100644 index f8be86c5c..000000000 --- a/lib/structures/UnknownInteraction.js +++ /dev/null @@ -1,453 +0,0 @@ -"use strict"; - -const Interaction = require("./Interaction"); -const Message = require("./Message"); -const Member = require("./Member"); -const Permission = require("./Permission"); -const {InteractionResponseTypes} = require("../Constants"); - -/** -* Represents an unknown interaction. See Interaction for more properties. -* Note: Methods are not guaranteed to work properly, they are all added just in case you know which to use. -* @extends Interaction -* @prop {Permission?} appPermissions The permissions the app or bot has within the channel the interaction was sent from -* @prop {(PrivateChannel | TextChannel | NewsChannel)?} channel The channel the interaction was created in. Can be partial with only the id if the channel is not cached. -* @prop {Object?} data The data attached to the interaction -* @prop {String?} guildID The ID of the guild in which the interaction was created -* @prop {Member?} member The member who triggered the interaction (This is only sent when the interaction is invoked within a guild) -* @prop {Message?} message The message the interaction came from (Message Component only). If the message is ephemeral, this will be an object with `id` and `flags` keys. -* @prop {User?} user The user who triggered the interaction (This is only sent when the interaction is invoked within a dm) -*/ -class UnknownInteraction extends Interaction { - constructor(info, client) { - super(info, client); - - if(info.channel_id !== undefined) { - this.channel = this._client.getChannel(info.channel_id) || { - id: info.channel_id - }; - } - - if(info.data !== undefined) { - this.data = info.data; - } - - if(info.guild_id !== undefined) { - this.guildID = info.guild_id; - } - - if(info.member !== undefined) { - if(this.channel.guild) { - info.member.id = info.member.user.id; - this.member = this.channel.guild.members.update(info.member, this.channel.guild); - } else { - const guild = this._client.guilds.get(info.guild_id); - this.member = new Member(info.member, guild, this._client); - } - } - - if(info.message !== undefined) { - this.message = new Message(info.message, this._client); - } - - if(info.user !== undefined) { - this.user = this._client.users.update(info.user, client); - } - - if(info.app_permissions !== undefined) { - this.appPermissions = new Permission(info.app_permissions); - } - } - - /** - * Acknowledges the autocomplete interaction with a result of choices. - * Note: You can **not** use more than 1 initial interaction response per interaction. - * @arg {Object} data The data object - * @arg {Number} data.type The type of [interaction response](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type) to send - * @arg {Object} data.data The data to return to discord - * @returns {Promise} - */ - async acknowledge(data) { - if(this.acknowledged === true) { - throw new Error("You have already acknowledged this interaction."); - } - return this._client.createInteractionResponse.call(this._client, this.id, this.token, data).then(() => this.update()); - } - - /** - * Respond to the interaction with a followup message - * @arg {String | Object} content A string or object. If an object is passed: - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) - * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [options.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Number} [content.flags] 64 for Ephemeral - * @arg {Boolean} [content.tts] Set the message TTS flag - * @arg {Object | Array} [file] A file object (or an Array of them) - * @arg {Buffer} file.file A buffer containing file data - * @arg {String} file.name What to name the file - * @returns {Promise} - */ - async createFollowup(content, file) { - if(this.acknowledged === false) { - throw new Error("createFollowup cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, pong, or result first."); - } - if(content !== undefined) { - if(typeof content !== "object" || content === null) { - content = { - content: "" + content - }; - } else if(content.content !== undefined && typeof content.content !== "string") { - content.content = "" + content.content; - } - } - if(file) { - content.file = file; - } - return this._client.executeWebhook.call(this._client, this.applicationID, this.token, Object.assign({wait: true}, content)); - } - - /** - * Acknowledges the interaction with a message. If already acknowledged runs createFollowup - * Note: You can **not** use more than 1 initial interaction response per interaction, use createFollowup if you have already responded with a different interaction response. - * @arg {String | Object} content A string or object. If an object is passed: - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) - * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [content.flags] 64 for Ephemeral - * @arg {Boolean} [content.tts] Set the message TTS flag - * @arg {Object | Array} [file] A file object (or an Array of them) - * @arg {Buffer} file.file A buffer containing file data - * @arg {String} file.name What to name the file - * @returns {Promise} - */ - async createMessage(content, file) { - if(this.acknowledged === true) { - return this.createFollowup(content, file); - } - if(content !== undefined) { - if(typeof content !== "object" || content === null) { - content = { - content: "" + content - }; - } else if(content.content !== undefined && typeof content.content !== "string") { - content.content = "" + content.content; - } - if(content.content !== undefined || content.embeds || content.allowedMentions) { - content.allowed_mentions = this._client._formatAllowedMentions(content.allowedMentions); - } - } - return this._client.createInteractionResponse.call(this._client, this.id, this.token, { - type: InteractionResponseTypes.CHANNEL_MESSAGE_WITH_SOURCE, - data: content - }, file).then(() => this.update()); - } - - /** - * Acknowledges the interaction with a defer response - * Note: You can **not** use more than 1 initial interaction response per interaction. - * @arg {Number} [flags] 64 for Ephemeral - * @returns {Promise} - */ - async defer(flags) { - if(this.acknowledged === true) { - throw new Error("You have already acknowledged this interaction."); - } - return this._client.createInteractionResponse.call(this._client, this.id, this.token, { - type: InteractionResponseTypes.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE, - data: { - flags: flags || 0 - } - }).then(() => this.update()); - } - - /** - * Acknowledges the interaction with a defer message update response (Message Component only) - * Note: You can **not** use more than 1 initial interaction response per interaction. - * @returns {Promise} - */ - async deferUpdate() { - if(this.acknowledged === true) { - throw new Error("You have already acknowledged this interaction."); - } - return this._client.createInteractionResponse.call(this._client, this.id, this.token, { - type: InteractionResponseTypes.DEFERRED_UPDATE_MESSAGE - }).then(() => this.update()); - } - - /** - * Delete a message - * @arg {String} messageID the id of the message to delete, or "@original" for the original response. - * @returns {Promise} - */ - async deleteMessage(messageID) { - if(this.acknowledged === false) { - throw new Error("deleteMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); - } - return this._client.deleteWebhookMessage.call(this._client, this.applicationID, this.token, messageID); - } - - /** - * Delete the Original message (or the parent message for components) - * Warning: Will error with ephemeral messages. - * @returns {Promise} - */ - async deleteOriginalMessage() { - if(this.acknowledged === false) { - throw new Error("deleteOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); - } - return this._client.deleteWebhookMessage.call(this._client, this.applicationID, this.token, "@original"); - } - - /** - * Edit a message - * @arg {String} messageID the id of the message to edit, or "@original" for the original response. - * @arg {Object} content Interaction message edit options - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) - * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Object | Array} [file] A file object (or an Array of them) - * @arg {Buffer} file.file A buffer containing file data - * @arg {String} file.name What to name the file - * @returns {Promise} - */ - async editMessage(messageID, content, file) { - if(this.acknowledged === false) { - throw new Error("editMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, pong, or result first."); - } - if(content !== undefined) { - if(typeof content !== "object" || content === null) { - content = { - content: "" + content - }; - } else if(content.content !== undefined && typeof content.content !== "string") { - content.content = "" + content.content; - } - } - if(file) { - content.file = file; - } - return this._client.editWebhookMessage.call(this._client, this.applicationID, this.token, messageID, content); - } - - /** - * Edit the Original response message - * @arg {Object} content Interaction message edit options (or the parent message for components) - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) - * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Object | Array} [file] A file object (or an Array of them) - * @arg {Buffer} file.file A buffer containing file data - * @arg {String} file.name What to name the file - * @returns {Promise} - */ - async editOriginalMessage(content, file) { - if(this.acknowledged === false) { - throw new Error("editOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, pong, or result first."); - } - if(content !== undefined) { - if(typeof content !== "object" || content === null) { - content = { - content: "" + content - }; - } else if(content.content !== undefined && typeof content.content !== "string") { - content.content = "" + content.content; - } - } - if(file) { - content.file = file; - } - return this._client.editWebhookMessage.call(this._client, this.applicationID, this.token, "@original", content); - } - - /** - * Acknowledges the interaction by editing the parent message. If already acknowledged runs editOriginalMessage (Message Component only) - * Note: You can **not** use more than 1 initial interaction response per interaction, use edit if you have already responded with a different interaction response. - * Warning: Will error with ephemeral messages. - * @arg {String | Object} content What to edit the message with - * @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default) - * @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here. - * @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to. - * @arg {Boolean | Array} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. - * @arg {Boolean | Array} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow. - * @arg {Array} [content.components] An array of component objects - * @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only) - * @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only) - * @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2) - * @arg {String} [content.components[].label] The label to be displayed in the component (type 2) - * @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1) - * @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1) - * @arg {Array} [content.components[].options] The options for this component (type 3 only) - * @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected - * @arg {String} [content.components[].options[].description] The description for this option - * @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option - * @arg {String} content.components[].options[].label The label for this option - * @arg {Number | String} content.components[].options[].value The value for this option - * @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only) - * @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required - * @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu - * @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only) - * @arg {String} [content.content] A content string - * @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure - * @arg {Boolean} [content.flags] 64 for Ephemeral - * @arg {Boolean} [content.tts] Set the message TTS flag - * @arg {Object | Array} [file] A file object (or an Array of them) - * @arg {Buffer} file.file A buffer containing file data - * @arg {String} file.name What to name the file - * @returns {Promise} - */ - async editParent(content, file) { - if(this.acknowledged === true) { - return this.editOriginalMessage(content); - } - if(content !== undefined) { - if(typeof content !== "object" || content === null) { - content = { - content: "" + content - }; - } else if(content.content !== undefined && typeof content.content !== "string") { - content.content = "" + content.content; - } - if(content.content !== undefined || content.embeds || content.allowedMentions) { - content.allowed_mentions = this._client._formatAllowedMentions(content.allowedMentions); - } - } - return this._client.createInteractionResponse.call(this._client, this.id, this.token, { - type: InteractionResponseTypes.UPDATE_MESSAGE, - data: content - }, file).then(() => this.update()); - } - - /** - * Get the Original response message (or the parent message for components) - * Warning: Will error with ephemeral messages. - * @returns {Promise} - */ - async getOriginalMessage() { - if(this.acknowledged === false) { - throw new Error("getOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first."); - } - return this._client.getWebhookMessage.call(this._client, this.applicationID, this.token, "@original"); - } - - /** - * Acknowledges the ping interaction with a pong response (Ping Only) - * Note: You can **not** use more than 1 initial interaction response per interaction. - * @returns {Promise} - */ - async pong() { - if(this.acknowledged === true) { - throw new Error("You have already acknowledged this interaction."); - } - return this._client.createInteractionResponse.call(this._client, this.id, this.token, { - type: InteractionResponseTypes.PONG - }).then(() => this.update()); - } - - /** - * Acknowledges the autocomplete interaction with a result of choices. - * Note: You can **not** use more than 1 initial interaction response per interaction. - * @arg {Array} choices The autocomplete choices to return to the user - * @arg {String | Number} choices[].name The choice display name - * @arg {String} choices[].value The choice value to return to the bot - * @returns {Promise} - */ - async result(choices) { - if(this.acknowledged === true) { - throw new Error("You have already acknowledged this interaction."); - } - return this._client.createInteractionResponse.call(this._client, this.id, this.token, { - type: InteractionResponseTypes.APPLICATION_COMMAND_AUTOCOMPLETE_RESULT, - data: {choices} - }).then(() => this.update()); - } - -} - -module.exports = UnknownInteraction;