diff --git a/packages/discord.js/src/structures/CommandInteraction.js b/packages/discord.js/src/structures/CommandInteraction.js index 5e7f8f4f8..4987d09b2 100644 --- a/packages/discord.js/src/structures/CommandInteraction.js +++ b/packages/discord.js/src/structures/CommandInteraction.js @@ -3,6 +3,7 @@ const { Collection } = require('@discordjs/collection'); const Interaction = require('./Interaction'); const InteractionWebhook = require('./InteractionWebhook'); +const MessageAttachment = require('./MessageAttachment'); const InteractionResponses = require('./interfaces/InteractionResponses'); /** @@ -81,6 +82,7 @@ class CommandInteraction extends Interaction { * @property {Collection} [roles] The resolved roles * @property {Collection} [channels] The resolved channels * @property {Collection} [messages] The resolved messages + * @property {Collection} [attachments] The resolved attachments */ /** @@ -89,7 +91,7 @@ class CommandInteraction extends Interaction { * @returns {CommandInteractionResolvedData} * @private */ - transformResolved({ members, users, channels, roles, messages }) { + transformResolved({ members, users, channels, roles, messages, attachments }) { const result = {}; if (members) { @@ -128,6 +130,14 @@ class CommandInteraction extends Interaction { } } + if (attachments) { + result.attachments = new Collection(); + for (const attachment of Object.values(attachments)) { + const patched = new MessageAttachment(attachment.url, attachment.filename, attachment); + result.attachments.set(attachment.id, patched); + } + } + return result; } @@ -146,6 +156,7 @@ class CommandInteraction extends Interaction { * @property {GuildMember|APIGuildMember} [member] The resolved member * @property {GuildChannel|ThreadChannel|APIChannel} [channel] The resolved channel * @property {Role|APIRole} [role] The resolved role + * @property {MessageAttachment} [attachment] The resolved attachment */ /** @@ -176,6 +187,9 @@ class CommandInteraction extends Interaction { const role = resolved.roles?.[option.value]; if (role) result.role = this.guild?.roles._add(role) ?? role; + + const attachment = resolved.attachments?.[option.value]; + if (attachment) result.attachment = new MessageAttachment(attachment.url, attachment.filename, attachment); } return result; diff --git a/packages/discord.js/src/structures/CommandInteractionOptionResolver.js b/packages/discord.js/src/structures/CommandInteractionOptionResolver.js index b70c8e95a..2aa693829 100644 --- a/packages/discord.js/src/structures/CommandInteractionOptionResolver.js +++ b/packages/discord.js/src/structures/CommandInteractionOptionResolver.js @@ -216,6 +216,17 @@ class CommandInteractionOptionResolver { return option?.role ?? null; } + /** + * Gets an attachment option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?MessageAttachment} The value of the option, or null if not set and not required. + */ + getAttachment(name, required = false) { + const option = this._getTypedOption(name, ApplicationCommandOptionType.Attachment, ['attachment'], required); + return option?.attachment ?? null; + } + /** * Gets a mentionable option. * @param {string} name The name of the option. diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 3aaf7949e..da4e1c1c9 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -46,6 +46,7 @@ import { APIPartialEmoji, APIPartialGuild, APIRole, + APIAttachment, APISelectMenuComponent, APITemplateSerializedSourceGuild, APIUser, @@ -334,6 +335,7 @@ export abstract class CommandInteraction e | 'getFocused' | 'getMentionable' | 'getRole' + | 'getAttachment' | 'getNumber' | 'getInteger' | 'getString' @@ -740,6 +742,8 @@ export interface ApplicationCommandInteractionOptionResolver['member']> | null; getRole(name: string, required: true): NonNullable['role']>; getRole(name: string, required?: boolean): NonNullable['role']> | null; + getAttachment(name: string, required: true): NonNullable['attachment']>; + getAttachment(name: string, required?: boolean): NonNullable['attachment']> | null; getMentionable( name: string, required: true, @@ -3276,6 +3280,10 @@ export interface ApplicationCommandChannelOption extends BaseApplicationCommandO channelTypes?: ChannelType[]; } +export interface ApplicationCommandAttachmentOption extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Attachment; +} + export interface ApplicationCommandAutocompleteOption extends Omit { type: | ApplicationCommandOptionType.String @@ -3359,6 +3367,7 @@ export type ApplicationCommandOption = | ApplicationCommandChannelOption | ApplicationCommandChoicesOption | ApplicationCommandNumericOption + | ApplicationCommandAttachmentOption | ApplicationCommandSubCommand; export interface ApplicationCommandOptionChoice { @@ -3711,6 +3720,7 @@ export interface CommandInteractionOption member?: CacheTypeReducer; channel?: CacheTypeReducer; role?: CacheTypeReducer; + attachment?: Collection; message?: GuildCacheMessage; } @@ -3720,6 +3730,7 @@ export interface CommandInteractionResolvedData>; channels?: Collection>; messages?: Collection>; + attachments?: Collection; } export declare const Colors: {