feat: handle file upload component for v14 (#11179)

* feat: handle file upload component

* chore: fix import

* chore: typings

* fix: `Snowflake`

---------

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
This commit is contained in:
Naiyar
2025-10-24 18:19:37 +06:00
committed by GitHub
parent 0ff239a602
commit 104ad754f3
5 changed files with 60 additions and 7 deletions

View File

@@ -85,6 +85,7 @@ class CommandInteraction extends BaseInteraction {
* @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved guild members
* @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles
* @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels
* @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
*/
/**
@@ -92,7 +93,6 @@ class CommandInteraction extends BaseInteraction {
*
* @typedef {BaseInteractionResolvedData} CommandInteractionResolvedData
* @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages
* @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
*/
/**

View File

@@ -216,6 +216,17 @@ class ModalSubmitFields {
return null;
}
/**
* Gets file upload component
*
* @param {string} customId The custom id of the component
* @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty
* @returns {?Collection<Snowflake, Attachment>} The uploaded files, or null if none were uploaded and not required
*/
getUploadedFiles(customId, required = false) {
return this._getTypedComponent(customId, [ComponentType.FileUpload], ['attachments'], required).attachments ?? null;
}
}
module.exports = ModalSubmitFields;

View File

@@ -9,6 +9,7 @@ const InteractionResponses = require('./interfaces/InteractionResponses');
const { transformResolved } = require('../util/Util');
const getMessage = lazy(() => require('./Message').Message);
const getAttachment = lazy(() => require('./Attachment'));
/**
* @typedef {Object} BaseModalData
@@ -16,6 +17,13 @@ const getMessage = lazy(() => require('./Message').Message);
* @property {number} id The id of the field
*/
/**
* @typedef {BaseModalData} FileUploadModalData
* @property {string} customId The custom id of the file upload
* @property {string[]} values The values of the file upload
* @property {Collection<string, Attachment>} [attachments] The resolved attachments
*/
/**
* @typedef {BaseModalData} TextInputModalData
* @property {string} customId The custom id of the field
@@ -37,7 +45,7 @@ const getMessage = lazy(() => require('./Message').Message);
*/
/**
* @typedef {SelectMenuModalData|TextInputModalData} ModalData
* @typedef {SelectMenuModalData|TextInputModalData|FileUploadModalData} ModalData
*/
/**
@@ -161,7 +169,7 @@ class ModalSubmitInteraction extends BaseInteraction {
/* eslint-disable max-depth */
if (resolved) {
const { members, users, channels, roles } = resolved;
const { members, users, channels, roles, attachments } = resolved;
const valueSet = new Set(rawComponent.values);
if (users) {
@@ -204,6 +212,15 @@ class ModalSubmitInteraction extends BaseInteraction {
}
}
}
if (attachments) {
data.attachments = new Collection();
for (const [id, attachment] of Object.entries(attachments)) {
if (valueSet.has(id)) {
data.attachments.set(id, new (getAttachment())(attachment));
}
}
}
}
/* eslint-enable max-depth */

View File

@@ -23,7 +23,8 @@ const { ComponentType } = require('discord-api-types/v10');
/**
* @typedef {StringSelectMenuComponentData|TextInputComponentData|UserSelectMenuComponentData|
* RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData} ComponentInLabelData
* RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData|
* FileUploadComponentData} ComponentInLabelData
*/
/**
@@ -43,6 +44,14 @@ const { ComponentType } = require('discord-api-types/v10');
* @property {string} [url] The URL of the button
*/
/**
* @typedef {BaseComponentData} FileUploadComponentData
* @property {string} customId The custom id of the file upload
* @property {number} [minValues] The minimum number of files that can be uploaded (0-10)
* @property {number} [maxValues] The maximum number of files that can be uploaded (1-10)
* @property {boolean} [required] Whether this component is required in modals
*/
/**
* @typedef {BaseComponentData} BaseSelectMenuComponentData
* @property {string} customId The custom id of the select menu

View File

@@ -367,7 +367,8 @@ export type ComponentInLabelData =
| UserSelectMenuComponentData
| ChannelSelectMenuComponentData
| RoleSelectMenuComponentData
| MentionableSelectMenuComponentData;
| MentionableSelectMenuComponentData
| FileUploadComponentData;
export interface LabelComponentData extends BaseComponentData {
type: ComponentType.Label;
@@ -2823,7 +2824,12 @@ export interface SelectMenuModalData<Cached extends CacheType = CacheType>
values: readonly string[];
}
export type ModalData = SelectMenuModalData | TextInputModalData;
export interface FileUploadModalData extends BaseModalData<ComponentType.FileUpload> {
customId: string;
files: readonly Attachment[];
}
export type ModalData = FileUploadModalData | SelectMenuModalData | TextInputModalData;
export interface LabelModalData extends BaseModalData<ComponentType.Label> {
component: readonly ModalData[];
@@ -2900,6 +2906,8 @@ export class ModalSubmitFields<Cached extends CacheType = CacheType> {
public getSelectedMentionables(customId: string, required: true): ModalSelectedMentionables<Cached>;
public getSelectedMentionables(customId: string, required?: boolean): ModalSelectedMentionables<Cached> | null;
public getUploadedFiles(customId: string, required: true): ReadonlyCollection<Snowflake, Attachment>;
public getUploadedFiles(customId: string, required?: boolean): ReadonlyCollection<Snowflake, Attachment> | null;
}
export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType>
@@ -6184,6 +6192,7 @@ export interface CommandInteractionOption<Cached extends CacheType = CacheType>
}
export interface BaseInteractionResolvedData<Cached extends CacheType = CacheType> {
attachments?: ReadonlyCollection<Snowflake, Attachment>;
channels?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;
members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
@@ -6192,7 +6201,6 @@ export interface BaseInteractionResolvedData<Cached extends CacheType = CacheTyp
export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType>
extends BaseInteractionResolvedData<Cached> {
attachments?: ReadonlyCollection<Snowflake, Attachment>;
messages?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;
}
@@ -7430,6 +7438,14 @@ export interface TextInputComponentData extends BaseComponentData {
placeholder?: string;
}
export interface FileUploadComponentData extends BaseComponentData {
customId: string;
maxValues?: number;
minValues?: number;
required?: number;
type: ComponentType.FileUpload;
}
export type MessageTarget =
| Interaction
| InteractionWebhook