diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index d5e4d5fe3..bbfa45805 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -22,7 +22,8 @@ class GuildForumThreadManager extends ThreadManager { * @typedef {BaseMessageOptions} GuildForumThreadMessageCreateOptions * @property {StickerResolvable} [stickers] The stickers to send with the message * @property {BitFieldResolvable} [flags] The flags to send with the message - * Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set. + * Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications}, and + * {@link MessageFlags.IsVoiceMessage} can be set. */ /** diff --git a/packages/discord.js/src/structures/Attachment.js b/packages/discord.js/src/structures/Attachment.js index 0e502a064..74ff8389d 100644 --- a/packages/discord.js/src/structures/Attachment.js +++ b/packages/discord.js/src/structures/Attachment.js @@ -5,9 +5,12 @@ const { basename, flatten } = require('../util/Util.js'); /** * @typedef {Object} AttachmentPayload - * @property {?string} name The name of the attachment * @property {Stream|BufferResolvable} attachment The attachment in this payload - * @property {?string} description The description of the attachment + * @property {string} [name] The name of the attachment + * @property {string} [description] The description of the attachment + * @property {title} [title] The title of the attachment + * @property {string} [waveform] The base64 encoded byte array representing a sampled waveform (from voice message attachments) + * @property {number} [duration] The duration of the attachment in seconds (from voice message attachments) */ /** @@ -115,7 +118,7 @@ class Attachment { if ('duration_secs' in data) { /** * The duration of this attachment in seconds - * This will only be available if the attachment is an audio file. + * This will only be available if the attachment is the audio file from a voice message. * * @type {?number} */ @@ -127,7 +130,7 @@ class Attachment { if ('waveform' in data) { /** * The base64 encoded byte array representing a sampled waveform - * This will only be available if the attachment is an audio file. + * This will only be available if this attachment is the audio file from a voice message. * * @type {?string} */ diff --git a/packages/discord.js/src/structures/AttachmentBuilder.js b/packages/discord.js/src/structures/AttachmentBuilder.js index f5489c7f0..3dd8d1e86 100644 --- a/packages/discord.js/src/structures/AttachmentBuilder.js +++ b/packages/discord.js/src/structures/AttachmentBuilder.js @@ -17,18 +17,43 @@ class AttachmentBuilder { * @type {BufferResolvable|Stream} */ this.attachment = attachment; + /** * The name of this attachment * * @type {?string} */ this.name = data.name; + /** * The description of the attachment * * @type {?string} */ this.description = data.description; + + /** + * The title of the attachment + * + * @type {?string} + */ + this.title = data.title; + + /** + * The base64 encoded byte array representing a sampled waveform + * This is only for voice message attachments. + * + * @type {?string} + */ + this.waveform = data.waveform; + + /** + * The duration of the attachment in seconds + * This is only for voice message attachments. + * + * @type {?number} + */ + this.duration = data.duration; } /** @@ -64,6 +89,41 @@ class AttachmentBuilder { return this; } + /** + * Sets the title of this attachment. + * + * @param {string} title The title of the file + * @returns {AttachmentBuilder} This attachment + */ + setTitle(title) { + this.title = title; + return this; + } + + /** + * Sets the waveform of this attachment. + * This is only for voice message attachments. + * + * @param {string} waveform The base64 encoded byte array representing a sampled waveform + * @returns {AttachmentBuilder} This attachment + */ + setWaveform(waveform) { + this.waveform = waveform; + return this; + } + + /** + * Sets the duration of this attachment. + * This is only for voice message attachments. + * + * @param {number} duration The duration of the attachment in seconds + * @returns {AttachmentBuilder} This attachment + */ + setDuration(duration) { + this.duration = duration; + return this; + } + /** * Sets whether this attachment is a spoiler * @@ -119,4 +179,7 @@ exports.AttachmentBuilder = AttachmentBuilder; * @typedef {Object} AttachmentData * @property {string} [name] The name of the attachment * @property {string} [description] The description of the attachment + * @property {string} [title] The title of the attachment + * @property {string} [waveform] The base64 encoded byte array representing a sampled waveform (for voice message attachments) + * @property {number} [duration] The duration of the attachment in seconds (for voice message attachments) */ diff --git a/packages/discord.js/src/structures/MessagePayload.js b/packages/discord.js/src/structures/MessagePayload.js index ff3b994b4..58d62c92f 100644 --- a/packages/discord.js/src/structures/MessagePayload.js +++ b/packages/discord.js/src/structures/MessagePayload.js @@ -192,6 +192,9 @@ class MessagePayload { const attachments = this.options.files?.map((file, index) => ({ id: index.toString(), description: file.description, + title: file.title, + waveform: file.waveform, + duration_secs: file.duration, })); if (Array.isArray(this.options.attachments)) { this.options.attachments.push(...(attachments ?? [])); diff --git a/packages/discord.js/src/structures/Webhook.js b/packages/discord.js/src/structures/Webhook.js index 3c9e41889..2edfb94c1 100644 --- a/packages/discord.js/src/structures/Webhook.js +++ b/packages/discord.js/src/structures/Webhook.js @@ -142,7 +142,7 @@ class Webhook { * @typedef {BaseMessageOptionsWithPoll} WebhookMessageCreateOptions * @property {boolean} [tts=false] Whether the message should be spoken aloud * @property {MessageFlags} [flags] Which flags to set for the message. - * Only the {@link MessageFlags.SuppressEmbeds} flag can be set. + * Only {@link MessageFlags.SuppressEmbeds} and {@link MessageFlags.IsVoiceMessage} can be set. * @property {string} [username=this.name] Username override for the message * @property {string} [avatarURL] Avatar URL override for the message * @property {Snowflake} [threadId] The id of the thread in the channel to send to. diff --git a/packages/discord.js/src/structures/interfaces/InteractionResponses.js b/packages/discord.js/src/structures/interfaces/InteractionResponses.js index db55f2010..d0e0afca0 100644 --- a/packages/discord.js/src/structures/interfaces/InteractionResponses.js +++ b/packages/discord.js/src/structures/interfaces/InteractionResponses.js @@ -45,8 +45,8 @@ class InteractionResponses { * @property {boolean} [tts=false] Whether the message should be spoken aloud * @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response * @property {MessageFlagsResolvable} [flags] Which flags to set for the message. - * Only `MessageFlags.Ephemeral`, `MessageFlags.SuppressEmbeds`, and `MessageFlags.SuppressNotifications` - * can be set. + * Only {@link MessageFlags.Ephemeral}, {@link MessageFlags.SuppressEmbeds}, + * {@link MessageFlags.SuppressNotifications}, and {@link MessageFlags.IsVoiceMessage} can be set. */ /** diff --git a/packages/discord.js/src/structures/interfaces/TextBasedChannel.js b/packages/discord.js/src/structures/interfaces/TextBasedChannel.js index 04467bf54..473c96467 100644 --- a/packages/discord.js/src/structures/interfaces/TextBasedChannel.js +++ b/packages/discord.js/src/structures/interfaces/TextBasedChannel.js @@ -114,8 +114,8 @@ class TextBasedChannel { * that message will be returned and no new message will be created * @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message * @property {MessageFlags} [flags] Which flags to set for the message. - * Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications} and - * {@link MessageFlags.IsComponentsV2} can be set. + * Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications}, + * {@link MessageFlags.IsComponentsV2}, and {@link MessageFlags.IsVoiceMessage} can be set. * {@link MessageFlags.IsComponentsV2} is required if passing components that aren't action rows */ diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 0d59e50db..2c6fc92ce 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2249,10 +2249,16 @@ export class AttachmentBuilder { public attachment: BufferResolvable | Stream; public description: string | null; public name: string | null; + public title: string | null; + public waveform: string | null; + public duration: number | null; public get spoiler(): boolean; public setDescription(description: string): this; public setFile(attachment: BufferResolvable | Stream, name?: string): this; public setName(name: string): this; + public setTitle(title: string): this; + public setWaveform(waveform: string): this; + public setDuration(duration: number): this; public setSpoiler(spoiler?: boolean): this; public toJSON(): unknown; public static from(other: JSONEncodable): AttachmentBuilder; @@ -4828,7 +4834,10 @@ export interface BaseApplicationCommandData { export interface AttachmentData { description?: string; + duration?: number; name?: string; + title?: string; + waveform?: string; } export type CommandOptionDataTypeResolvable = ApplicationCommandOptionType; @@ -5878,7 +5887,10 @@ export interface FetchThreadsOptions { export interface AttachmentPayload { attachment: BufferResolvable | Stream; description?: string; + duration?: number; name?: string; + title?: string; + waveform?: string; } export type GlobalSweepFilter = () => @@ -6398,9 +6410,13 @@ export interface InteractionDeferUpdateOptions { export interface InteractionReplyOptions extends BaseMessageOptions, MessageOptionsPoll { flags?: | BitFieldResolvable< - Extract, + Extract< + MessageFlagsString, + 'Ephemeral' | 'IsComponentsV2' | 'IsVoiceMessage' | 'SuppressEmbeds' | 'SuppressNotifications' + >, | MessageFlags.Ephemeral | MessageFlags.IsComponentsV2 + | MessageFlags.IsVoiceMessage | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications > @@ -6577,8 +6593,11 @@ export interface MessageOptionsPoll { export interface MessageOptionsFlags { flags?: | BitFieldResolvable< - Extract, - MessageFlags.IsComponentsV2 | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications + Extract, + | MessageFlags.IsComponentsV2 + | MessageFlags.IsVoiceMessage + | MessageFlags.SuppressEmbeds + | MessageFlags.SuppressNotifications > | undefined; } diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 58de5134e..7c64653a7 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -3000,3 +3000,23 @@ await guildScheduledEventManager.edit(snowflake, { recurrenceRule: null }); byMonth: [GuildScheduledEventRecurrenceRuleMonth.May], }); } + +await textChannel.send({ + files: [ + new AttachmentBuilder('https://example.com/voice-message.ogg') + .setDuration(2) + .setWaveform('AFUqPDw3Eg2hh4+gopOYj4xthU4='), + ], + flags: MessageFlags.IsVoiceMessage, +}); + +await textChannel.send({ + files: [ + { + attachment: 'https://example.com/voice-message.ogg', + duration: 2, + waveform: 'AFUqPDw3Eg2hh4+gopOYj4xthU4=', + }, + ], + flags: MessageFlags.IsVoiceMessage, +});