diff --git a/packages/discord.js/src/errors/ErrorCodes.js b/packages/discord.js/src/errors/ErrorCodes.js index b160068e7..8e5b82bd8 100644 --- a/packages/discord.js/src/errors/ErrorCodes.js +++ b/packages/discord.js/src/errors/ErrorCodes.js @@ -129,6 +129,9 @@ * @property {'BulkBanUsersOptionEmpty'} BulkBanUsersOptionEmpty * @property {'PollAlreadyExpired'} PollAlreadyExpired + + * @property {'PermissionOverwritesTypeMandatory'} PermissionOverwritesTypeMandatory + * @property {'PermissionOverwritesTypeMismatch'} PermissionOverwritesTypeMismatch */ const keys = [ @@ -258,6 +261,9 @@ const keys = [ 'BulkBanUsersOptionEmpty', 'PollAlreadyExpired', + + 'PermissionOverwritesTypeMandatory', + 'PermissionOverwritesTypeMismatch', ]; // JSDoc for IntelliSense purposes diff --git a/packages/discord.js/src/errors/Messages.js b/packages/discord.js/src/errors/Messages.js index 133c4d0ce..69f12ce04 100644 --- a/packages/discord.js/src/errors/Messages.js +++ b/packages/discord.js/src/errors/Messages.js @@ -144,6 +144,11 @@ const Messages = { [DjsErrorCodes.BulkBanUsersOptionEmpty]: 'Option "users" array or collection is empty', [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 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 f8d81c87f..396062ef5 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,31 @@ 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; + 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 (overwrite.type === undefined) { + throw new DiscordjsTypeError(ErrorCodes.PermissionOverwritesTypeMandatory); + } + type = overwrite.type; + } else { + type = overwrite.id instanceof Role ? OverwriteType.Role : OverwriteType.Member; + if (overwrite.type !== undefined && type !== overwrite.type) { + throw new DiscordjsTypeError(ErrorCodes.PermissionOverwritesTypeMismatch, OverwriteType[type]); + } + } return { - id: userOrRole.id, + id, type, allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(), deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(), diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index ba0da0eea..7da648484 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;