Skip to content
79 changes: 67 additions & 12 deletions packages/discord.js/src/structures/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,18 +139,22 @@ class User extends Base {
* @property {Snowflake} skuId The id of the avatar decoration's SKU
*/

if (data.avatar_decoration_data) {
/**
* The user avatar decoration's data
*
* @type {?AvatarDecorationData}
*/
this.avatarDecorationData = {
asset: data.avatar_decoration_data.asset,
skuId: data.avatar_decoration_data.sku_id,
};
if ('avatar_decoration_data' in data) {
if (data.avatar_decoration_data) {
/**
* The user avatar decoration's data
*
* @type {?AvatarDecorationData}
*/
this.avatarDecorationData = {
asset: data.avatar_decoration_data.asset,
skuId: data.avatar_decoration_data.sku_id,
};
} else {
this.avatarDecorationData = null;
}
} else {
this.avatarDecorationData = null;
this.avatarDecorationData ??= null;
}

/**
Expand All @@ -176,6 +180,34 @@ class User extends Base {
} else {
this.collectibles = null;
}

/**
* @typedef {Object} UserPrimaryGuild
* @property {?Snowflake} identityGuildId The id of the user's primary guild
* @property {?boolean} identityEnabled Whether the user is displaying the primary guild's tag
* @property {?string} tag The user's guild tag. Limited to 4 characters
* @property {?string} badge The guild tag badge hash
*/

if ('primary_guild' in data) {
if (data.primary_guild) {
/**
* The primary guild of the user
*
* @type {?UserPrimaryGuild}
*/
this.primaryGuild = {
identityGuildId: data.primary_guild.identity_guild_id,
identityEnabled: data.primary_guild.identity_enabled,
tag: data.primary_guild.tag,
badge: data.primary_guild.badge,
};
} else {
this.primaryGuild = null;
}
} else {
this.primaryGuild ??= null;
}
}

/**
Expand Down Expand Up @@ -271,6 +303,18 @@ class User extends Base {
return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);
}

/**
* A link to the user's guild tag badge.
*
* @param {ImageURLOptions} [options={}] Options for the image URL
* @returns {?string}
*/
guildTagBadgeURL(options = {}) {
return this.primaryGuild?.badge
? this.client.rest.cdn.guildTagBadge(this.primaryGuild.identityGuildId, this.primaryGuild.badge, options)
: null;
}

/**
* The tag of this user
* <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
Expand Down Expand Up @@ -367,7 +411,11 @@ class User extends Base {
this.collectibles?.nameplate?.skuId === user.collectibles?.nameplate?.skuId &&
this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&
this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette &&
this.primaryGuild?.identityGuildId === user.primaryGuild?.identityGuildId &&
this.primaryGuild?.identityEnabled === user.primaryGuild?.identityEnabled &&
this.primaryGuild?.tag === user.primaryGuild?.tag &&
this.primaryGuild?.badge === user.primaryGuild?.badge
);
}

Expand Down Expand Up @@ -398,6 +446,12 @@ class User extends Base {
this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&
this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette
: true) &&
('primary_guild' in user
? this.primaryGuild?.identityGuildId === user.primary_guild?.identity_guild_id &&
this.primaryGuild?.identityEnabled === user.primary_guild?.identity_enabled &&
this.primaryGuild?.tag === user.primary_guild?.tag &&
this.primaryGuild?.badge === user.primary_guild?.badge
: true)
);
}
Expand Down Expand Up @@ -437,6 +491,7 @@ class User extends Base {
json.avatarURL = this.avatarURL();
json.displayAvatarURL = this.displayAvatarURL();
json.bannerURL = this.banner ? this.bannerURL() : this.banner;
json.guildTagBadgeURL = this.guildTagBadgeURL();
return json;
}
}
Expand Down
20 changes: 13 additions & 7 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ import {
APIComponentInModalActionRow,
APIContainerComponent,
APIEmbed,
APIEmbedAuthor,
APIEmbedField,
APIEmbedFooter,
APIEmbedImage,
APIEmbedProvider,
APIEmoji,
APIEntitlement,
Expand Down Expand Up @@ -3510,17 +3507,24 @@ export interface AvatarDecorationData {
skuId: Snowflake;
}

export interface Collectibles {
nameplate: NameplateData | null;
}

export interface UserPrimaryGuild {
badge: string | null;
identityEnabled: boolean | null;
identityGuildId: Snowflake | null;
tag: string | null;
}

export interface NameplateData {
asset: string;
label: string;
palette: NameplatePalette;
skuId: Snowflake;
}

export interface Collectibles {
nameplate: NameplateData | null;
}

export interface UnfurledMediaItemData {
url: string;
}
Expand Down Expand Up @@ -3553,12 +3557,14 @@ export class User extends Base {
public get hexAccentColor(): HexColorString | null | undefined;
public id: Snowflake;
public get partial(): false;
public primaryGuild: UserPrimaryGuild | null;
public system: boolean;
public get tag(): string;
public username: string;
public avatarURL(options?: ImageURLOptions): string | null;
public avatarDecorationURL(): string | null;
public bannerURL(options?: ImageURLOptions): string | null | undefined;
public guildTagBadgeURL(options?: ImageURLOptions): string | null;
public createDM(force?: boolean): Promise<DMChannel>;
public deleteDM(): Promise<DMChannel>;
public displayAvatarURL(options?: ImageURLOptions): string;
Expand Down
5 changes: 4 additions & 1 deletion packages/rest/__tests__/CDN.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,11 @@ test('soundboardSound', () => {
expect(cdn.soundboardSound(id)).toEqual(`${baseCDN}/soundboard-sounds/${id}`);
});

test('guildTagBadge', () => {
expect(cdn.guildTagBadge(id, hash)).toEqual(`${baseCDN}/guild-tag-badges/${id}/${hash}.webp`);
});

test('makeURL throws on invalid size', () => {
// @ts-expect-error: Invalid size
expect(() => cdn.avatar(id, animatedHash, { size: 5 })).toThrow(RangeError);
});

Expand Down
11 changes: 11 additions & 0 deletions packages/rest/src/lib/CDN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,17 @@ export class CDN {
return `${this.cdn}${CDNRoutes.soundboardSound(soundId)}`;
}

/**
* Generates a URL for a guild tag badge.
*
* @param guildId - The guild id
* @param badgeHash - The hash of the badge
* @param options - Optional options for the badge
*/
public guildTagBadge(guildId: string, badgeHash: string, options?: Readonly<BaseImageURLOptions>): string {
return this.makeURL(`/guild-tag-badges/${guildId}/${badgeHash}`, options);
}

/**
* Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.
*
Expand Down