From 42f0d55a3ef06703639a65a0110bd86e77034542 Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Fri, 6 Sep 2024 12:35:12 +0100 Subject: [PATCH 1/3] refactor(PermissionOverwrites): cache-independent resolve --- packages/discord.js/src/errors/ErrorCodes.js | 4 +++ packages/discord.js/src/errors/Messages.js | 4 +++ .../src/structures/PermissionOverwrites.js | 32 ++++++++++++------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/packages/discord.js/src/errors/ErrorCodes.js b/packages/discord.js/src/errors/ErrorCodes.js index b160068e7669..f9b3f5c4bd5f 100644 --- a/packages/discord.js/src/errors/ErrorCodes.js +++ b/packages/discord.js/src/errors/ErrorCodes.js @@ -129,6 +129,8 @@ * @property {'BulkBanUsersOptionEmpty'} BulkBanUsersOptionEmpty * @property {'PollAlreadyExpired'} PollAlreadyExpired + + * @property {'PermissionOverwritesTypeMismatch'} PermissionOverwritesTypeMismatch */ const keys = [ @@ -258,6 +260,8 @@ const keys = [ 'BulkBanUsersOptionEmpty', 'PollAlreadyExpired', + + 'PermissionOverwritesTypeMismatch', ]; // JSDoc for IntelliSense purposes diff --git a/packages/discord.js/src/errors/Messages.js b/packages/discord.js/src/errors/Messages.js index 133c4d0cee50..f4cde8146275 100644 --- a/packages/discord.js/src/errors/Messages.js +++ b/packages/discord.js/src/errors/Messages.js @@ -144,6 +144,10 @@ const Messages = { [DjsErrorCodes.BulkBanUsersOptionEmpty]: 'Option "users" array or collection is empty', [DjsErrorCodes.PollAlreadyExpired]: 'This poll has already expired.', + + [DjsErrorCodes.PermissionOverwritesTypeMismatch]: expected => + `"overwrite.id" is a ${expected.toLowerCase()} object, ` + + `but "overwrite.type" is not equal to OverwriteType.${expected}.`, }; module.exports = Messages; diff --git a/packages/discord.js/src/structures/PermissionOverwrites.js b/packages/discord.js/src/structures/PermissionOverwrites.js index f8d81c87f5e5..45b3561ef5b6 100644 --- a/packages/discord.js/src/structures/PermissionOverwrites.js +++ b/packages/discord.js/src/structures/PermissionOverwrites.js @@ -160,7 +160,7 @@ class PermissionOverwrites extends Base { * @property {GuildMemberResolvable|RoleResolvable} id Member or role this overwrite is for * @property {PermissionResolvable} [allow] The permissions to allow * @property {PermissionResolvable} [deny] The permissions to deny - * @property {OverwriteType} [type] The type of this OverwriteData + * @property {OverwriteType} [type] The type of this OverwriteData (mandatory if `id` is a Snowflake) */ /** @@ -171,21 +171,29 @@ class PermissionOverwrites extends Base { */ static resolve(overwrite, guild) { if (overwrite instanceof this) return overwrite.toJSON(); - if (typeof overwrite.id === 'string' && overwrite.type in OverwriteType) { - return { - id: overwrite.id, - type: overwrite.type, - allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(), - deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(), - }; + + const id = guild.roles.resolveId(overwrite.id) ?? guild.client.users.resolveId(overwrite.id); + if (!id) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'overwrite.id', 'GuildMemberResolvable or RoleResolvable'); } - const userOrRole = guild.roles.cache.get(overwrite.id) ?? guild.client.users.cache.get(overwrite.id); - if (!userOrRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role'); - const type = userOrRole instanceof Role ? OverwriteType.Role : OverwriteType.Member; + let type; + if (typeof overwrite.id === 'string') { + if (typeof overwrite.type === 'number' && overwrite.type in OverwriteType) { + type = overwrite.type; + } else { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'overwrite.type', 'OverwriteType', true); + } + } else { + type = overwrite.id instanceof Role ? OverwriteType.Role : OverwriteType.Member; + // eslint-disable-next-line eqeqeq + if (overwrite.type != null && type !== overwrite.type) { + throw new DiscordjsTypeError(ErrorCodes.PermissionOverwriteTypeMismatch, OverwriteType[type]); + } + } return { - id: userOrRole.id, + id, type, allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(), deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(), From 8b6e29f15165c725ff1f9672ed3e4511f2137a4d Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Tue, 1 Oct 2024 23:23:07 +0100 Subject: [PATCH 2/3] refactor: improve errors --- packages/discord.js/src/errors/ErrorCodes.js | 2 ++ packages/discord.js/src/errors/Messages.js | 3 ++- .../src/structures/PermissionOverwrites.js | 16 +++++++++------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/discord.js/src/errors/ErrorCodes.js b/packages/discord.js/src/errors/ErrorCodes.js index f9b3f5c4bd5f..8e5b82bd80fd 100644 --- a/packages/discord.js/src/errors/ErrorCodes.js +++ b/packages/discord.js/src/errors/ErrorCodes.js @@ -130,6 +130,7 @@ * @property {'PollAlreadyExpired'} PollAlreadyExpired + * @property {'PermissionOverwritesTypeMandatory'} PermissionOverwritesTypeMandatory * @property {'PermissionOverwritesTypeMismatch'} PermissionOverwritesTypeMismatch */ @@ -261,6 +262,7 @@ const keys = [ 'PollAlreadyExpired', + 'PermissionOverwritesTypeMandatory', 'PermissionOverwritesTypeMismatch', ]; diff --git a/packages/discord.js/src/errors/Messages.js b/packages/discord.js/src/errors/Messages.js index f4cde8146275..69f12ce04b35 100644 --- a/packages/discord.js/src/errors/Messages.js +++ b/packages/discord.js/src/errors/Messages.js @@ -145,9 +145,10 @@ const Messages = { [DjsErrorCodes.PollAlreadyExpired]: 'This poll has already expired.', + [DjsErrorCodes.PermissionOverwritesTypeMandatory]: '"overwrite.type" is mandatory if "overwrite.id" is a Snowflake', [DjsErrorCodes.PermissionOverwritesTypeMismatch]: expected => `"overwrite.id" is a ${expected.toLowerCase()} object, ` + - `but "overwrite.type" is not equal to OverwriteType.${expected}.`, + `but "overwrite.type" is defined and not equal to OverwriteType.${expected}`, }; module.exports = Messages; diff --git a/packages/discord.js/src/structures/PermissionOverwrites.js b/packages/discord.js/src/structures/PermissionOverwrites.js index 45b3561ef5b6..396062ef51f3 100644 --- a/packages/discord.js/src/structures/PermissionOverwrites.js +++ b/packages/discord.js/src/structures/PermissionOverwrites.js @@ -177,18 +177,20 @@ class PermissionOverwrites extends Base { throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'overwrite.id', 'GuildMemberResolvable or RoleResolvable'); } + if (overwrite.type !== undefined && (typeof overwrite.type !== 'number' || !(overwrite.type in OverwriteType))) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'overwrite.type', 'OverwriteType', true); + } + let type; if (typeof overwrite.id === 'string') { - if (typeof overwrite.type === 'number' && overwrite.type in OverwriteType) { - type = overwrite.type; - } else { - throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'overwrite.type', 'OverwriteType', true); + if (overwrite.type === undefined) { + throw new DiscordjsTypeError(ErrorCodes.PermissionOverwritesTypeMandatory); } + type = overwrite.type; } else { type = overwrite.id instanceof Role ? OverwriteType.Role : OverwriteType.Member; - // eslint-disable-next-line eqeqeq - if (overwrite.type != null && type !== overwrite.type) { - throw new DiscordjsTypeError(ErrorCodes.PermissionOverwriteTypeMismatch, OverwriteType[type]); + if (overwrite.type !== undefined && type !== overwrite.type) { + throw new DiscordjsTypeError(ErrorCodes.PermissionOverwritesTypeMismatch, OverwriteType[type]); } } From 5987fb0472208c7d5a470a0e83d8992fd19e3580 Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Tue, 1 Oct 2024 23:23:42 +0100 Subject: [PATCH 3/3] types: enforce type when id may be a Snowflake --- packages/discord.js/typings/index.d.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index ba0da0eea83c..7da648484524 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -6519,13 +6519,23 @@ export interface MultipleShardSpawnOptions { timeout?: number; } -export interface OverwriteData { +export interface BaseOverwriteData { allow?: PermissionResolvable; deny?: PermissionResolvable; id: GuildMemberResolvable | RoleResolvable; type?: OverwriteType; } +export interface OverwriteDataWithMandatoryType extends BaseOverwriteData { + type: OverwriteType; +} + +export interface OverwriteDataWithOptionalType extends BaseOverwriteData { + id: Exclude; +} + +export type OverwriteData = OverwriteDataWithMandatoryType | OverwriteDataWithOptionalType; + export type OverwriteResolvable = PermissionOverwrites | OverwriteData; export type PermissionFlags = Record;