fix: Components V2 & docs link

This commit is contained in:
Elysia
2025-07-08 19:48:32 +07:00
parent 74ffe0e3fe
commit eb639d45d7
20 changed files with 162 additions and 68 deletions

View File

@@ -265,7 +265,7 @@ class BaseDispatcher extends Writable {
/** /**
* Creates a one-byte extension header & a single extension of type playout-delay * Creates a one-byte extension header & a single extension of type playout-delay
* @see https://docs.discord.sex/topics/voice-connections#sending-and-receiving-voice * @see https://docs.discord.food/topics/voice-connections#sending-and-receiving-voice
* Discord expects a playout delay RTP extension header on every video packet. * Discord expects a playout delay RTP extension header on every video packet.
* @see https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/playout-delay * @see https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/playout-delay
* @returns {Buffer} playout-delay extension <Buffer 51 00 00 00> * @returns {Buffer} playout-delay extension <Buffer 51 00 00 00>
@@ -354,7 +354,7 @@ class BaseDispatcher extends Writable {
return null; return null;
} }
// Header // Header
// https://docs.discord.sex/topics/voice-connections#rtp-packet-structure // https://docs.discord.food/topics/voice-connections#rtp-packet-structure
let rtpHeader = buffer.slice(0, 12); // RTP_HEADER_SIZE let rtpHeader = buffer.slice(0, 12); // RTP_HEADER_SIZE
rtpHeader[0] = 0x80; // Version + Flags (1 byte) rtpHeader[0] = 0x80; // Version + Flags (1 byte)
rtpHeader[1] = this.payloadType; // Payload Type (1 byte) rtpHeader[1] = this.payloadType; // Payload Type (1 byte)

View File

@@ -60,7 +60,7 @@ class PresenceManager extends CachedManager {
*/ */
async fetch() { async fetch() {
const data = await this.client.api.presences.get(); const data = await this.client.api.presences.get();
// https://docs.discord.sex/resources/presence#endpoints // https://docs.discord.food/resources/presence#endpoints
data.presences.forEach(presence => { data.presences.forEach(presence => {
this._add(presence, true); this._add(presence, true);
}); });

View File

@@ -43,17 +43,32 @@ class BaseMessageComponent {
/** /**
* @param {BaseMessageComponent|BaseMessageComponentOptions} [data={}] The options for this component * @param {BaseMessageComponent|BaseMessageComponentOptions} [data={}] The options for this component
* @param {MessageComponentOptions} [componentData={}] The raw data for component
*/ */
constructor(data, componentData = {}) { constructor(data) {
/** /**
* The type of this component * The type of this component
* @type {?MessageComponentType} * @type {?MessageComponentType}
*/ */
this.rawData = componentData;
this.type = 'type' in data ? BaseMessageComponent.resolveType(data.type) : null; this.type = 'type' in data ? BaseMessageComponent.resolveType(data.type) : null;
} }
setup(data) {
/**
* The data for this component
* @type {MessageComponentOptions}
*/
this.data = data;
}
/**
* The id of this component
* @type {number}
* @readonly
*/
get id() {
return this.data.id;
}
/** /**
* Constructs a component based on the type of the incoming data * Constructs a component based on the type of the incoming data
* @param {MessageComponentOptions} data Data for a MessageComponent * @param {MessageComponentOptions} data Data for a MessageComponent

View File

@@ -15,7 +15,13 @@ class ContainerComponent extends BaseMessageComponent {
* @param {ContainerComponent | APIContainerComponent} [data={}] The data * @param {ContainerComponent | APIContainerComponent} [data={}] The data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'CONTAINER' }, data); super({ type: 'CONTAINER' });
this.setup(data);
}
setup(data) {
super.setup(data);
/** /**
* Components of the type action row, text display, section, media gallery, separator, or file * Components of the type action row, text display, section, media gallery, separator, or file
* @type {ContainerComponents[]} * @type {ContainerComponents[]}
@@ -26,7 +32,7 @@ class ContainerComponent extends BaseMessageComponent {
* Color for the accent on the container as RGB from 0x000000 to 0xFFFFFF * Color for the accent on the container as RGB from 0x000000 to 0xFFFFFF
* @type {Number} * @type {Number}
*/ */
this.accent_color = data.accent_color ?? null; this.accentColor = data.accent_color ?? null;
/** /**
* Whether the container should be a spoiler (or blurred out). Defaults to false. * Whether the container should be a spoiler (or blurred out). Defaults to false.
@@ -35,6 +41,17 @@ class ContainerComponent extends BaseMessageComponent {
this.spoiler = data.spoiler ?? false; this.spoiler = data.spoiler ?? false;
} }
/**
* The hex accent color of this container
* @type {?string}
* @readonly
*/
get hexAccentColor() {
return typeof this.accentColor === 'number'
? `#${this.accentColor.toString(16).padStart(6, '0')}`
: this.accentColor ?? null;
}
/** /**
* @returns {APIContainerComponent} * @returns {APIContainerComponent}
*/ */

View File

@@ -14,8 +14,13 @@ class FileComponent extends BaseMessageComponent {
* @param {FileComponent | APIFileComponent} [data={}] The data * @param {FileComponent | APIFileComponent} [data={}] The data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'FILE' }, data); super({ type: 'FILE' });
this.setup(data);
}
setup(data) {
super.setup(data);
/** /**
* This unfurled media item is unique in that it only supports attachment references using the attachment://<filename> syntax * This unfurled media item is unique in that it only supports attachment references using the attachment://<filename> syntax
* @type {UnfurledMediaItem} * @type {UnfurledMediaItem}

View File

@@ -178,7 +178,7 @@ class Invite extends Base {
* * 1: GROUP_DM * * 1: GROUP_DM
* * 2: FRIEND * * 2: FRIEND
* @typedef {number} InviteType * @typedef {number} InviteType
* @see {@link https://docs.discord.sex/resources/invite#invite-type} * @see {@link https://docs.discord.food/resources/invite#invite-type}
*/ */
if ('type' in data) { if ('type' in data) {
/** /**

View File

@@ -13,8 +13,13 @@ class MediaGalleryComponent extends BaseMessageComponent {
* @param {MediaGalleryComponent | APIMediaGalleryComponent} [data={}] The data * @param {MediaGalleryComponent | APIMediaGalleryComponent} [data={}] The data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'MEDIA_GALLERY' }, data); super({ type: 'MEDIA_GALLERY' });
this.setup(data);
}
setup(data) {
super.setup(data);
/** /**
* 1 to 10 media gallery items * 1 to 10 media gallery items
* @type {MediaGalleryItem[]} * @type {MediaGalleryItem[]}

View File

@@ -160,10 +160,14 @@ class Message extends Base {
this.embeds = this.embeds?.slice() ?? []; this.embeds = this.embeds?.slice() ?? [];
} }
/**
* @typedef {MessageActionRow|ContainerComponent|FileComponent|MediaGalleryComponent|SectionComponent|SeparatorComponent|TextDisplayComponent} TopLevelComponent
*/
if ('components' in data) { if ('components' in data) {
/** /**
* A list of components in the message * An array of components in the message
* @type {MessageActionRow[] | ContainerComponent[]} * @type {TopLevelComponent[]}
*/ */
this.components = data.components.map(c => BaseMessageComponent.create(c, this.client)); this.components = data.components.map(c => BaseMessageComponent.create(c, this.client));
} else { } else {

View File

@@ -42,13 +42,15 @@ class MessageActionRow extends BaseMessageComponent {
* @param {Client} [client] The client constructing this MessageActionRow, if provided * @param {Client} [client] The client constructing this MessageActionRow, if provided
*/ */
constructor(data = {}, client = null) { constructor(data = {}, client = null) {
super({ type: 'ACTION_ROW' }, data); super({ type: 'ACTION_ROW' });
/** /**
* The components in this action row * The components in this action row
* @type {MessageActionRowComponent[]} * @type {MessageActionRowComponent[]}
*/ */
this.components = data.components?.map(c => BaseMessageComponent.create(c, client)) ?? []; this.components = data.components?.map(c => BaseMessageComponent.create(c, client)) ?? [];
super.setup(data);
} }
/** /**

View File

@@ -24,12 +24,13 @@ class MessageButton extends BaseMessageComponent {
* @param {MessageButton|MessageButtonOptions} [data={}] MessageButton to clone or raw data * @param {MessageButton|MessageButtonOptions} [data={}] MessageButton to clone or raw data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'BUTTON' }, data); super({ type: 'BUTTON' });
this.setup(data); this.setup(data);
} }
setup(data) { setup(data) {
super.setup(data);
/** /**
* The text to be displayed on this button * The text to be displayed on this button
* @type {?string} * @type {?string}

View File

@@ -42,12 +42,13 @@ class MessageSelectMenu extends BaseMessageComponent {
* @param {MessageSelectMenu|MessageSelectMenuOptions} [data={}] MessageSelectMenu to clone or raw data * @param {MessageSelectMenu|MessageSelectMenuOptions} [data={}] MessageSelectMenu to clone or raw data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: BaseMessageComponent.resolveType(data.type) ?? 'STRING_SELECT' }, data); super({ type: BaseMessageComponent.resolveType(data.type) ?? 'STRING_SELECT' });
this.setup(data); this.setup(data);
} }
setup(data) { setup(data) {
super.setup(data);
/** /**
* A unique string to be sent in the interaction when clicked * A unique string to be sent in the interaction when clicked
* @type {?string} * @type {?string}

View File

@@ -13,8 +13,13 @@ class SectionComponent extends BaseMessageComponent {
* @param {SectionComponent | APISectionComponent} [data={}] The data * @param {SectionComponent | APISectionComponent} [data={}] The data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'SECTION' }, data); super({ type: 'SECTION' });
this.setup(data);
}
setup(data) {
super.setup(data);
/** /**
* One to three text components * One to three text components
* @type {TextDisplayComponent[]} * @type {TextDisplayComponent[]}

View File

@@ -13,8 +13,13 @@ class SeparatorComponent extends BaseMessageComponent {
* @param {SeparatorComponent | APISeparatorComponent} [data={}] The data * @param {SeparatorComponent | APISeparatorComponent} [data={}] The data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'SEPARATOR' }, data); super({ type: 'SEPARATOR' });
this.setup(data);
}
setup(data) {
super.setup(data);
/** /**
* Size of separator padding — SeparatorSpacingSizes.SMALL for small padding, SeparatorSpacingSizes.LARGE for large padding. Defaults to SeparatorSpacingSizes.SMALL * Size of separator padding — SeparatorSpacingSizes.SMALL for small padding, SeparatorSpacingSizes.LARGE for large padding. Defaults to SeparatorSpacingSizes.SMALL
* @type {SeparatorSpacingSizes} * @type {SeparatorSpacingSizes}

View File

@@ -12,8 +12,13 @@ class TextDisplayComponent extends BaseMessageComponent {
* @param {TextDisplayComponent | APITextDisplayComponent} [data={}] The data * @param {TextDisplayComponent | APITextDisplayComponent} [data={}] The data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'TEXT_DISPLAY' }, data); super({ type: 'TEXT_DISPLAY' });
this.setup(data);
}
setup(data) {
super.setup(data);
/** /**
* Text that will be displayed similar to a message * Text that will be displayed similar to a message
* @type {String} * @type {String}

View File

@@ -27,12 +27,13 @@ class TextInputComponent extends BaseMessageComponent {
* @param {TextInputComponent|TextInputComponentOptions} [data={}] TextInputComponent to clone or raw data * @param {TextInputComponent|TextInputComponentOptions} [data={}] TextInputComponent to clone or raw data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'TEXT_INPUT' }, data); super({ type: 'TEXT_INPUT' });
this.setup(data); this.setup(data);
} }
setup(data) { setup(data) {
super.setup(data);
/** /**
* A unique string to be sent in the interaction when submitted * A unique string to be sent in the interaction when submitted
* @type {?string} * @type {?string}

View File

@@ -15,8 +15,13 @@ class ThumbnailComponent extends BaseMessageComponent {
* @param {ThumbnailComponent | APIThumbnailComponent} [data={}] The data * @param {ThumbnailComponent | APIThumbnailComponent} [data={}] The data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'THUMBNAIL' }, data); super({ type: 'THUMBNAIL' });
this.setup(data);
}
setup(data) {
super.setup(data);
/** /**
* A url or attachment * A url or attachment
* @type {UnfurledMediaItem} * @type {UnfurledMediaItem}

View File

@@ -737,7 +737,7 @@ exports.IntegrationExpireBehaviors = createEnum(['REMOVE_ROLE', 'KICK']);
* * NITRO_NOTIFICATION * * NITRO_NOTIFICATION
* @typedef {string} MessageType * @typedef {string} MessageType
* @see {@link https://discord.com/developers/docs/resources/channel#message-object-message-types} * @see {@link https://discord.com/developers/docs/resources/channel#message-object-message-types}
* @see {@link https://docs.discord.sex/resources/message#message-type} * @see {@link https://docs.discord.food/resources/message#message-type}
*/ */
exports.MessageTypes = [ exports.MessageTypes = [
'DEFAULT', // 0 'DEFAULT', // 0
@@ -1780,7 +1780,7 @@ exports.ForumLayoutTypes = createEnum(['NOT_SET', 'LIST_VIEW', 'GALLERY_VIEW']);
* * DEFAULT * * DEFAULT
* * IMAGE_ONLY_ANSWERS * * IMAGE_ONLY_ANSWERS
* @typedef {string} PollLayoutType * @typedef {string} PollLayoutType
* @see {@link https://docs.discord.sex/resources/message#poll-layout-type} * @see {@link https://docs.discord.food/resources/message#poll-layout-type}
*/ */
exports.PollLayoutTypes = createEnum([null, 'DEFAULT', 'IMAGE_ONLY_ANSWERS']); exports.PollLayoutTypes = createEnum([null, 'DEFAULT', 'IMAGE_ONLY_ANSWERS']);
@@ -1866,7 +1866,7 @@ function createEnum(keys) {
* @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object. * @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object.
* @property {InviteScope[]} InviteScopes The scopes of an invite. * @property {InviteScope[]} InviteScopes The scopes of an invite.
* @property {Object<RelationshipType, number>} RelationshipTypes Relationship Enums * @property {Object<RelationshipType, number>} RelationshipTypes Relationship Enums
* * @property {Object<SeparatorSpacingSize, number>} SeparatorSpacingSize Relationship Enums * @property {Object<SeparatorSpacingSize, number>} SeparatorSpacingSize Size of separator padding (Enums)
* @property {Object<MembershipState, number>} MembershipStates The value set for a team members membership state. * @property {Object<MembershipState, number>} MembershipStates The value set for a team members membership state.
* @property {Object<MessageButtonStyle, number>} MessageButtonStyles The style of a message button. * @property {Object<MessageButtonStyle, number>} MessageButtonStyles The style of a message button.
* @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component. * @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component.

View File

@@ -37,10 +37,10 @@ class MessageFlags extends BitField {}
* * `SUPPRESS_NOTIFICATIONS` * * `SUPPRESS_NOTIFICATIONS`
* * `IS_VOICE_MESSAGE` * * `IS_VOICE_MESSAGE`
* * `HAS_SNAPSHOT` * * `HAS_SNAPSHOT`
* * `IS_UIKIT_COMPONENTS` * * `IS_COMPONENTS_V2`
* @type {Object} * @type {Object}
* @see {@link https://discord.com/developers/docs/resources/channel#message-object-message-flags} * @see {@link https://discord.com/developers/docs/resources/channel#message-object-message-flags}
* @see {@link https://docs.discord.sex/resources/message#message-flags} * @see {@link https://docs.discord.food/resources/message#message-flags}
*/ */
MessageFlags.FLAGS = { MessageFlags.FLAGS = {
CROSSPOSTED: 1 << 0, CROSSPOSTED: 1 << 0,

57
typings/index.d.ts vendored
View File

@@ -651,6 +651,8 @@ export class BaseGuildVoiceChannel extends TextBasedChannelMixin(GuildChannel, [
export class BaseMessageComponent { export class BaseMessageComponent {
protected constructor(data?: BaseMessageComponent | BaseMessageComponentOptions); protected constructor(data?: BaseMessageComponent | BaseMessageComponentOptions);
public type: MessageComponentType | null; public type: MessageComponentType | null;
public readonly id: number;
public data: MessageComponentOptions;
private static create(data: MessageComponentOptions, client?: Client | WebhookClient): MessageComponent | undefined; private static create(data: MessageComponentOptions, client?: Client | WebhookClient): MessageComponent | undefined;
private static resolveType(type: MessageComponentTypeResolvable): MessageComponentType; private static resolveType(type: MessageComponentTypeResolvable): MessageComponentType;
} }
@@ -2099,21 +2101,21 @@ export class LimitedCollection<K, V> extends Collection<K, V> {
} }
export type MessageCollectorOptionsParams< export type MessageCollectorOptionsParams<
T extends MessageComponentTypeResolvable, T extends MessageComponentInteractableResolvable,
Cached extends boolean = boolean, Cached extends boolean = boolean,
> = { > = {
componentType?: T; componentType?: T;
} & MessageComponentCollectorOptions<MappedInteractionTypes<Cached>[T]>; } & MessageComponentCollectorOptions<MappedInteractionTypes<Cached>[T]>;
export type MessageChannelCollectorOptionsParams< export type MessageChannelCollectorOptionsParams<
T extends MessageComponentTypeResolvable, T extends MessageComponentInteractableResolvable,
Cached extends boolean = boolean, Cached extends boolean = boolean,
> = { > = {
componentType?: T; componentType?: T;
} & MessageChannelComponentCollectorOptions<MappedInteractionTypes<Cached>[T]>; } & MessageChannelComponentCollectorOptions<MappedInteractionTypes<Cached>[T]>;
export type AwaitMessageCollectorOptionsParams< export type AwaitMessageCollectorOptionsParams<
T extends MessageComponentTypeResolvable, T extends MessageComponentInteractableResolvable,
Cached extends boolean = boolean, Cached extends boolean = boolean,
> = { componentType?: T } & Pick< > = { componentType?: T } & Pick<
InteractionCollectorOptions<MappedInteractionTypes<Cached>[T]>, InteractionCollectorOptions<MappedInteractionTypes<Cached>[T]>,
@@ -2159,7 +2161,7 @@ export class Message<Cached extends boolean = boolean> extends Base {
public readonly channel: If<Cached, GuildTextBasedChannel, TextBasedChannel>; public readonly channel: If<Cached, GuildTextBasedChannel, TextBasedChannel>;
public channelId: Snowflake; public channelId: Snowflake;
public readonly cleanContent: string; public readonly cleanContent: string;
public components: MessageActionRow[]; public components: TopLevelComponent[];
public content: string; public content: string;
public readonly createdAt: Date; public readonly createdAt: Date;
public createdTimestamp: number; public createdTimestamp: number;
@@ -2357,26 +2359,28 @@ export class ThumbnailComponent extends BaseMessageComponent {
public spoiler: boolean; public spoiler: boolean;
} }
export class SectionComponent<T extends ThumbnailComponent | MessageButton> extends BaseMessageComponent { export class SectionComponent<
public constructor(data?: SectionComponent<T> | APISectionComponent); AccessoryType extends MessageButton | ThumbnailComponent = MessageButton | ThumbnailComponent,
> extends BaseMessageComponent {
public constructor(data?: SectionComponent<AccessoryType> | APISectionComponent);
public components: TextDisplayComponent[]; public components: TextDisplayComponent[];
public accessory: T[]; public accessory: AccessoryType[];
public toJSON(): APISectionComponent; public toJSON(): APISectionComponent;
} }
export class ContainerComponent< export type ComponentInContainer =
U extends ThumbnailComponent | MessageButton,
T extends
| MessageActionRow | MessageActionRow
| TextDisplayComponent | FileComponent
| SectionComponent<U>
| MediaGalleryComponent | MediaGalleryComponent
| SectionComponent
| SeparatorComponent | SeparatorComponent
| FileComponent, | TextDisplayComponent;
> extends BaseMessageComponent {
public constructor(data?: ContainerComponent<U, T> | APIContainerComponent); export class ContainerComponent extends BaseMessageComponent {
public components: T[]; public constructor(data?: ComponentInContainer | APIContainerComponent);
public accent_color: number | null; public components: ComponentInContainer[];
public accentColor: number | null;
public readonly hexAccentColor: HexColorString | null;
public spoiler: boolean; public spoiler: boolean;
public toJSON(): APIContainerComponent; public toJSON(): APIContainerComponent;
} }
@@ -7161,13 +7165,26 @@ export type MessageComponentOptions =
| MessageButtonOptions | MessageButtonOptions
| MessageSelectMenuOptions; | MessageSelectMenuOptions;
export type MessageComponentType = keyof typeof MessageComponentInteractables; export type MessageComponentType = keyof typeof MessageComponentTypes;
export type MessageComponentTypeResolvable = MessageComponentType | MessageComponentInteractables; export type MessageComponentInteractableType = keyof typeof MessageComponentInteractables;
export type MessageComponentTypeResolvable = MessageComponentType | MessageComponentTypes;
export type MessageComponentInteractableResolvable = MessageComponentInteractableType | MessageComponentInteractables;
export type GuildForumThreadMessageCreateOptions = Omit<MessageOptions, 'poll'> & export type GuildForumThreadMessageCreateOptions = Omit<MessageOptions, 'poll'> &
Pick<MessageOptions, 'flags' | 'stickers'>; Pick<MessageOptions, 'flags' | 'stickers'>;
export type TopLevelComponent =
| MessageActionRow
| ContainerComponent
| FileComponent
| MediaGalleryComponent
| SectionComponent
| SeparatorComponent
| TextDisplayComponent;
export interface MessageEditOptions { export interface MessageEditOptions {
attachments?: MessageAttachment[]; attachments?: MessageAttachment[];
content?: string | null; content?: string | null;
@@ -7252,7 +7269,7 @@ export type MessageFlagsString =
| 'SUPPRESS_NOTIFICATIONS' | 'SUPPRESS_NOTIFICATIONS'
| 'IS_VOICE_MESSAGE' | 'IS_VOICE_MESSAGE'
| 'HAS_SNAPSHOT' | 'HAS_SNAPSHOT'
| 'IS_UIKIT_COMPONENTS'; | 'IS_COMPONENTS_V2';
export interface MessageInteraction { export interface MessageInteraction {
id: Snowflake; id: Snowflake;

View File

@@ -386,10 +386,16 @@ export interface APIMediaGalleryComponent extends APIBaseComponent<MessageCompon
export interface APISectionComponent extends APIBaseComponent<MessageComponentTypes.SECTION> { export interface APISectionComponent extends APIBaseComponent<MessageComponentTypes.SECTION> {
components: APITextDisplayComponent[]; components: APITextDisplayComponent[];
accessory: APIThumbnailComponent | APIMessageButtonInteractionData accessory: APIThumbnailComponent | APIMessageButtonInteractionData;
} }
export type APIContainerComponents = APIActionRowComponent<APIActionRowComponentTypes> | APITextDisplayComponent | APISectionComponent | APIMediaGalleryComponent | APISeparatorComponent | APIFileComponent; export type APIContainerComponents =
| APIActionRowComponent<APIActionRowComponentTypes>
| APITextDisplayComponent
| APISectionComponent
| APIMediaGalleryComponent
| APISeparatorComponent
| APIFileComponent;
export interface APIContainerComponent extends APIBaseComponent<MessageComponentTypes.CONTAINER> { export interface APIContainerComponent extends APIBaseComponent<MessageComponentTypes.CONTAINER> {
components: APIContainerComponents[]; components: APIContainerComponents[];
accent_color: number; accent_color: number;