mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-14 18:43:31 +01:00
feat: support new username system (#9512)
* feat: support new username system * docs(GuildMember#displayName): update * fix(User#hasNewUsername): use User#discriminator * feat(User#tag): add new username * docs(User#tag): update * docs(User#hasNewUsername): update * docs: update * feat(User#defaultAvatarURL): update * feat: remove some newly added properties * docs(User#discriminator): update * docs(User#globalName): bad Copilot * feat(User#displayName): return display name * types(User#displayName): not a partial structure * feat: add `calculateUserDefaultAvatarId` function * docs(CND#defaultAvatar): update * docs(CDN#defaultAvatar): update * feat: change default avatar id to type * feat: deprecate `User#tag` * docs(CDN#defaultAvatar): update Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * docs(User): update Co-authored-by: Rodrigo Leitão <38259440+ImRodry@users.noreply.github.com> * feat: update * typing: update Co-authored-by: Jan <66554238+vaporoxx@users.noreply.github.com> * feat: change the param type to `Snowflake` --------- Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: Rodrigo Leitão <38259440+ImRodry@users.noreply.github.com> Co-authored-by: Jan <66554238+vaporoxx@users.noreply.github.com>
This commit is contained in:
@@ -238,12 +238,12 @@ class GuildMember extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The nickname of this member, or their username if they don't have one
|
* The nickname of this member, or their user display name if they don't have one
|
||||||
* @type {?string}
|
* @type {?string}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get displayName() {
|
get displayName() {
|
||||||
return this.nickname ?? this.user.username;
|
return this.nickname ?? this.user.displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const process = require('node:process');
|
||||||
const { userMention } = require('@discordjs/builders');
|
const { userMention } = require('@discordjs/builders');
|
||||||
|
const { calculateUserDefaultAvatarIndex } = require('@discordjs/rest');
|
||||||
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
||||||
const Base = require('./Base');
|
const Base = require('./Base');
|
||||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||||
const UserFlagsBitField = require('../util/UserFlagsBitField');
|
const UserFlagsBitField = require('../util/UserFlagsBitField');
|
||||||
|
|
||||||
|
let tagDeprecationEmitted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a user on Discord.
|
* Represents a user on Discord.
|
||||||
* @implements {TextBasedChannel}
|
* @implements {TextBasedChannel}
|
||||||
@@ -41,6 +45,16 @@ class User extends Base {
|
|||||||
this.username ??= null;
|
this.username ??= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('global_name' in data) {
|
||||||
|
/**
|
||||||
|
* The global name of this user
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.globalName = data.global_name;
|
||||||
|
} else {
|
||||||
|
this.globalName ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
if ('bot' in data) {
|
if ('bot' in data) {
|
||||||
/**
|
/**
|
||||||
* Whether or not the user is a bot
|
* Whether or not the user is a bot
|
||||||
@@ -53,7 +67,8 @@ class User extends Base {
|
|||||||
|
|
||||||
if ('discriminator' in data) {
|
if ('discriminator' in data) {
|
||||||
/**
|
/**
|
||||||
* A discriminator based on username for the user
|
* The discriminator of this user
|
||||||
|
* <info>`'0'`, or a 4-digit stringified number if they're using the legacy username system</info>
|
||||||
* @type {?string}
|
* @type {?string}
|
||||||
*/
|
*/
|
||||||
this.discriminator = data.discriminator;
|
this.discriminator = data.discriminator;
|
||||||
@@ -154,7 +169,8 @@ class User extends Base {
|
|||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get defaultAvatarURL() {
|
get defaultAvatarURL() {
|
||||||
return this.client.rest.cdn.defaultAvatar(this.discriminator % 5);
|
const index = this.discriminator === '0' ? calculateUserDefaultAvatarIndex(this.id) : this.discriminator % 5;
|
||||||
|
return this.client.rest.cdn.defaultAvatar(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,12 +204,33 @@ class User extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Discord "tag" (e.g. `hydrabolt#0001`) for this user
|
* The tag of this user
|
||||||
|
* <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
|
||||||
|
* if they're using the legacy username system</info>
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
* @deprecated Use {@link User#username} instead.
|
||||||
|
*/
|
||||||
|
get tag() {
|
||||||
|
if (!tagDeprecationEmitted) {
|
||||||
|
process.emitWarning('User#tag is deprecated. Use User#username instead.', 'DeprecationWarning');
|
||||||
|
tagDeprecationEmitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeof this.username === 'string'
|
||||||
|
? this.discriminator === '0'
|
||||||
|
? this.username
|
||||||
|
: `${this.username}#${this.discriminator}`
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The global name of this user, or their username if they don't have one
|
||||||
* @type {?string}
|
* @type {?string}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get tag() {
|
get displayName() {
|
||||||
return typeof this.username === 'string' ? `${this.username}#${this.discriminator}` : null;
|
return this.globalName ?? this.username;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
3
packages/discord.js/typings/index.d.ts
vendored
3
packages/discord.js/typings/index.d.ts
vendored
@@ -3060,13 +3060,16 @@ export class User extends PartialTextBasedChannel(Base) {
|
|||||||
public get createdAt(): Date;
|
public get createdAt(): Date;
|
||||||
public get createdTimestamp(): number;
|
public get createdTimestamp(): number;
|
||||||
public discriminator: string;
|
public discriminator: string;
|
||||||
|
public get displayName(): string;
|
||||||
public get defaultAvatarURL(): string;
|
public get defaultAvatarURL(): string;
|
||||||
public get dmChannel(): DMChannel | null;
|
public get dmChannel(): DMChannel | null;
|
||||||
public flags: Readonly<UserFlagsBitField> | null;
|
public flags: Readonly<UserFlagsBitField> | null;
|
||||||
|
public globalName: string | null;
|
||||||
public get hexAccentColor(): HexColorString | null | undefined;
|
public get hexAccentColor(): HexColorString | null | undefined;
|
||||||
public id: Snowflake;
|
public id: Snowflake;
|
||||||
public get partial(): false;
|
public get partial(): false;
|
||||||
public system: boolean;
|
public system: boolean;
|
||||||
|
/** @deprecated Use {@link User#username} instead. */
|
||||||
public get tag(): string;
|
public get tag(): string;
|
||||||
public username: string;
|
public username: string;
|
||||||
public avatarURL(options?: ImageURLOptions): string | null;
|
public avatarURL(options?: ImageURLOptions): string | null;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export * from './lib/errors/RateLimitError.js';
|
|||||||
export * from './lib/RequestManager.js';
|
export * from './lib/RequestManager.js';
|
||||||
export * from './lib/REST.js';
|
export * from './lib/REST.js';
|
||||||
export * from './lib/utils/constants.js';
|
export * from './lib/utils/constants.js';
|
||||||
export { makeURLSearchParams, parseResponse } from './lib/utils/utils.js';
|
export { calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse } from './lib/utils/utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version
|
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version
|
||||||
|
|||||||
@@ -119,12 +119,15 @@ export class CDN {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the default avatar URL for a discriminator.
|
* Generates a default avatar URL
|
||||||
*
|
*
|
||||||
* @param discriminator - The discriminator modulo 5
|
* @param index - The default avatar index
|
||||||
|
* @remarks
|
||||||
|
* To calculate the index for a user do `(userId >> 22) % 6`,
|
||||||
|
* or `discriminator % 5` if they're using the legacy username system.
|
||||||
*/
|
*/
|
||||||
public defaultAvatar(discriminator: number): string {
|
public defaultAvatar(index: number): string {
|
||||||
return this.makeURL(`/embed/avatars/${discriminator}`, { extension: 'png' });
|
return this.makeURL(`/embed/avatars/${index}`, { extension: 'png' });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { URLSearchParams } from 'node:url';
|
import { URLSearchParams } from 'node:url';
|
||||||
import type { RESTPatchAPIChannelJSONBody } from 'discord-api-types/v10';
|
import type { RESTPatchAPIChannelJSONBody, Snowflake } from 'discord-api-types/v10';
|
||||||
import type { RateLimitData, ResponseLike } from '../REST.js';
|
import type { RateLimitData, ResponseLike } from '../REST.js';
|
||||||
import { type RequestManager, RequestMethod } from '../RequestManager.js';
|
import { type RequestManager, RequestMethod } from '../RequestManager.js';
|
||||||
import { RateLimitError } from '../errors/RateLimitError.js';
|
import { RateLimitError } from '../errors/RateLimitError.js';
|
||||||
@@ -112,3 +112,12 @@ export async function onRateLimit(manager: RequestManager, rateLimitData: RateLi
|
|||||||
throw new RateLimitError(rateLimitData);
|
throw new RateLimitError(rateLimitData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the default avatar index for a given user id.
|
||||||
|
*
|
||||||
|
* @param userId - The user id to calculate the default avatar index for
|
||||||
|
*/
|
||||||
|
export function calculateUserDefaultAvatarIndex(userId: Snowflake) {
|
||||||
|
return Number(BigInt(userId) >> 22n) % 6;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user