diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js
index f830b98f1a7e..3ce08fdb6069 100644
--- a/packages/discord.js/src/managers/GuildForumThreadManager.js
+++ b/packages/discord.js/src/managers/GuildForumThreadManager.js
@@ -20,7 +20,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 `MessageFlags.SuppressEmbeds`, `MessageFlags.SuppressNotifications`, and `MessageFlags.IsVoiceMessage`
+ * can be set.
*/
/**
diff --git a/packages/discord.js/src/structures/Attachment.js b/packages/discord.js/src/structures/Attachment.js
index e175e5b60751..365d81f25f65 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');
/**
* @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
+ * @property {number} [duration] The duration of the attachment in seconds
*/
/**
diff --git a/packages/discord.js/src/structures/AttachmentBuilder.js b/packages/discord.js/src/structures/AttachmentBuilder.js
index 707234524871..f84b2781ffba 100644
--- a/packages/discord.js/src/structures/AttachmentBuilder.js
+++ b/packages/discord.js/src/structures/AttachmentBuilder.js
@@ -16,16 +16,45 @@ 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
+ * @type {?string}
+ */
+ this.waveform = data.waveform;
+
+ /**
+ * The duration of the attachment in seconds
+ * @type {?number}
+ */
+ this.duration = data.duration;
+ }
+
+ /**
+ * Whether this attachment has been marked as a spoiler
+ * @type {boolean}
+ * @readonly
+ */
+ get spoiler() {
+ return basename(this.name).startsWith('SPOILER_');
}
/**
@@ -58,6 +87,36 @@ 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.
+ * @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.
+ * @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
* @param {boolean} [spoiler=true] Whether the attachment should be marked as a spoiler
@@ -76,15 +135,6 @@ class AttachmentBuilder {
return this;
}
- /**
- * Whether or not this attachment has been marked as a spoiler
- * @type {boolean}
- * @readonly
- */
- get spoiler() {
- return basename(this.name).startsWith('SPOILER_');
- }
-
toJSON() {
return flatten(this);
}
@@ -108,4 +158,7 @@ module.exports = 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
+ * @property {number} [duration] The duration of the attachment in seconds
*/
diff --git a/packages/discord.js/src/structures/MessagePayload.js b/packages/discord.js/src/structures/MessagePayload.js
index dad8ffedb026..827b90f425bc 100644
--- a/packages/discord.js/src/structures/MessagePayload.js
+++ b/packages/discord.js/src/structures/MessagePayload.js
@@ -204,6 +204,9 @@ class MessagePayload {
const attachments = this.options.files?.map((file, index) => ({
id: index.toString(),
description: file.description,
+ title: file.name,
+ 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/interfaces/InteractionResponses.js b/packages/discord.js/src/structures/interfaces/InteractionResponses.js
index 9f711b517b49..1c104c66bd6d 100644
--- a/packages/discord.js/src/structures/interfaces/InteractionResponses.js
+++ b/packages/discord.js/src/structures/interfaces/InteractionResponses.js
@@ -41,8 +41,8 @@ class InteractionResponses {
* @property {boolean} [ephemeral] Whether the reply should be ephemeral
* @property {boolean} [fetchReply] Whether to fetch the reply
* @property {MessageFlags} [flags] Which flags to set for the message.
- * Only `MessageFlags.Ephemeral`, `MessageFlags.SuppressEmbeds`, and `MessageFlags.SuppressNotifications`
- * can be set.
+ * Only `MessageFlags.Ephemeral`, `MessageFlags.SuppressEmbeds`, `MessageFlags.SuppressNotifications`,
+ * and `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 f3f2bf8d6a0b..d8809ff38562 100644
--- a/packages/discord.js/src/structures/interfaces/TextBasedChannel.js
+++ b/packages/discord.js/src/structures/interfaces/TextBasedChannel.js
@@ -102,7 +102,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 `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.
+ * Only `MessageFlags.SuppressEmbeds`, `MessageFlags.SuppressNotifications`, and `MessageFlags.IsVoiceMessage`
+ * can be set.
*/
/**
diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts
index a7b00f808e01..282967bf6847 100644
--- a/packages/discord.js/typings/index.d.ts
+++ b/packages/discord.js/typings/index.d.ts
@@ -2204,10 +2204,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;
@@ -4752,6 +4758,9 @@ export interface BaseApplicationCommandData {
export interface AttachmentData {
name?: string;
description?: string;
+ title?: string;
+ waveform?: string;
+ duration?: number;
}
export type CommandOptionDataTypeResolvable = ApplicationCommandOptionType;
@@ -5773,6 +5782,9 @@ export interface AttachmentPayload {
attachment: BufferResolvable | Stream;
name?: string;
description?: string;
+ title?: string;
+ waveform?: string;
+ duration?: number;
}
export type GlobalSweepFilter = () =>
@@ -6240,8 +6252,11 @@ export interface InteractionReplyOptions extends BaseMessageOptions {
ephemeral?: boolean;
fetchReply?: boolean;
flags?: BitFieldResolvable<
- Extract,
- MessageFlags.Ephemeral | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
+ Extract,
+ | MessageFlags.Ephemeral
+ | MessageFlags.SuppressEmbeds
+ | MessageFlags.SuppressNotifications
+ | MessageFlags.IsVoiceMessage
>;
}
@@ -6402,8 +6417,8 @@ export interface MessageCreateOptions extends BaseMessageOptions {
reply?: ReplyOptions;
stickers?: readonly StickerResolvable[];
flags?: BitFieldResolvable<
- Extract,
- MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
+ Extract,
+ MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications | MessageFlags.IsVoiceMessage
>;
}
diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts
index 78093fc55654..a149d0287267 100644
--- a/packages/discord.js/typings/index.test-d.ts
+++ b/packages/discord.js/typings/index.test-d.ts
@@ -33,6 +33,7 @@ import {
APIMentionableSelectComponent,
APIModalInteractionResponseCallbackData,
WebhookType,
+ MessageFlags,
} from 'discord-api-types/v10';
import {
ApplicationCommand,
@@ -2592,3 +2593,23 @@ declare const poll: Poll;
expectType>(await client.fetchStickerPacks());
expectType>(await client.fetchStickerPacks({}));
expectType(await client.fetchStickerPacks({ packId: snowflake }));
+
+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,
+});