diff --git a/src/managers/ApplicationCommandManager.js b/src/managers/ApplicationCommandManager.js index e1aacfc..c15edcc 100644 --- a/src/managers/ApplicationCommandManager.js +++ b/src/managers/ApplicationCommandManager.js @@ -6,6 +6,7 @@ const CachedManager = require('./CachedManager'); const { TypeError } = require('../errors'); const ApplicationCommand = require('../structures/ApplicationCommand'); const { ApplicationCommandTypes } = require('../util/Constants'); +const Permissions = require('../util/Permissions'); /** * Manages API methods for application commands and stores their cache. @@ -167,7 +168,7 @@ class ApplicationCommandManager extends CachedManager { /** * Edits an application command. * @param {ApplicationCommandResolvable} command The command to edit - * @param {ApplicationCommandData|APIApplicationCommand} data The data to update the command with + * @param {Partial} data The data to update the command with * @param {Snowflake} [guildId] The guild's id where the command registered, * ignored when using a {@link GuildApplicationCommandManager} * @returns {Promise} @@ -221,6 +222,19 @@ class ApplicationCommandManager extends CachedManager { * @private */ static transformCommand(command) { + let default_member_permissions; + + if ('default_member_permissions' in command) { + default_member_permissions = command.default_member_permissions + ? new Permissions(BigInt(command.default_member_permissions)).bitfield.toString() + : command.default_member_permissions; + } + + if ('defaultMemberPermissions' in command) { + default_member_permissions = command.defaultMemberPermissions + ? new Permissions(command.defaultMemberPermissions).bitfield.toString() + : command.defaultMemberPermissions; + } return { name: command.name, name_localizations: command.nameLocalizations ?? command.name_localizations, @@ -229,6 +243,8 @@ class ApplicationCommandManager extends CachedManager { type: typeof command.type === 'number' ? command.type : ApplicationCommandTypes[command.type], options: command.options?.map(o => ApplicationCommand.transformOption(o)), default_permission: command.defaultPermission ?? command.default_permission, + default_member_permissions, + dm_permission: command.dmPermission ?? command.dm_permission, }; } } diff --git a/src/structures/ApplicationCommand.js b/src/structures/ApplicationCommand.js index 5b97a73..8ae903a 100644 --- a/src/structures/ApplicationCommand.js +++ b/src/structures/ApplicationCommand.js @@ -5,6 +5,7 @@ const ApplicationCommandPermissionsManager = require('../managers/ApplicationCom const MessageAttachment = require('../structures/MessageAttachment'); const { ApplicationCommandOptionTypes, ApplicationCommandTypes, ChannelTypes } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); +const Permissions = require('../util/Permissions'); const SnowflakeUtil = require('../util/SnowflakeUtil'); const { lazy } = require('../util/Util'); const Message = lazy(() => require('../structures/Message').Message); @@ -125,14 +126,41 @@ class ApplicationCommand extends Base { this.options ??= []; } + /* eslint-disable max-len */ if ('default_permission' in data) { /** * Whether the command is enabled by default when the app is added to a guild * @type {boolean} + * @deprecated Use {@link ApplicationCommand.defaultMemberPermissions} and {@link ApplicationCommand.dmPermission} instead. */ this.defaultPermission = data.default_permission; } + /* eslint-disable max-len */ + + if ('default_member_permissions' in data) { + /** + * The default bitfield used to determine whether this command be used in a guild + * @type {?Readonly} + */ + this.defaultMemberPermissions = data.default_member_permissions + ? new Permissions(BigInt(data.default_member_permissions)).freeze() + : null; + } else { + this.defaultMemberPermissions ??= null; + } + + if ('dm_permission' in data) { + /** + * Whether the command can be used in DMs + * This property is always `null` on guild commands + * @type {?boolean} + */ + this.dmPermission = data.dm_permission; + } else { + this.dmPermission ??= null; + } + if ('version' in data) { /** * Autoincrementing version identifier updated during substantial record changes @@ -179,6 +207,9 @@ class ApplicationCommand extends Base { * @property {ApplicationCommandType} [type] The type of the command * @property {ApplicationCommandOptionData[]} [options] Options for the command * @property {boolean} [defaultPermission] Whether the command is enabled by default when the app is added to a guild + * @property {?PermissionResolvable} [defaultMemberPermissions] The bitfield used to determine the default permissions + * a member needs in order to run the command + * @property {boolean} [dmPermission] Whether the command is enabled in DMs */ /** @@ -212,7 +243,7 @@ class ApplicationCommand extends Base { /** * Edits this application command. - * @param {ApplicationCommandData} data The data to update the command with + * @param {Partial} data The data to update the command with * @returns {Promise} * @example * // Edit the description of this command @@ -278,15 +309,37 @@ class ApplicationCommand extends Base { return this.edit({ descriptionLocalizations }); } + /* eslint-disable max-len */ /** * Edits the default permission of this ApplicationCommand * @param {boolean} [defaultPermission=true] The default permission for this command * @returns {Promise} + * @deprecated Use {@link ApplicationCommand#setDefaultMemberPermissions} and {@link ApplicationCommand#setDMPermission} instead. */ setDefaultPermission(defaultPermission = true) { return this.edit({ defaultPermission }); } + /* eslint-enable max-len */ + + /** + * Edits the default member permissions of this ApplicationCommand + * @param {?PermissionResolvable} defaultMemberPermissions The default member permissions required to run this command + * @returns {Promise} + */ + setDefaultMemberPermissions(defaultMemberPermissions) { + return this.edit({ defaultMemberPermissions }); + } + + /** + * Edits the DM permission of this ApplicationCommand + * @param {boolean} [dmPermission=true] Whether the command can be used in DMs + * @returns {Promise} + */ + setDMPermission(dmPermission = true) { + return this.edit({ dmPermission }); + } + /** * Edits the options of this ApplicationCommand * @param {ApplicationCommandOptionData[]} options The options to set for this command @@ -321,7 +374,20 @@ class ApplicationCommand extends Base { equals(command, enforceOptionOrder = false) { // If given an id, check if the id matches if (command.id && this.id !== command.id) return false; + let defaultMemberPermissions = null; + let dmPermission = command.dmPermission ?? command.dm_permission; + if ('default_member_permissions' in command) { + defaultMemberPermissions = command.default_member_permissions + ? new Permissions(BigInt(command.default_member_permissions)).bitfield + : null; + } + + if ('defaultMemberPermissions' in command) { + defaultMemberPermissions = command.defaultMemberPermissions + ? new Permissions(command.defaultMemberPermissions).bitfield + : null; + } // Check top level parameters const commandType = typeof command.type === 'string' ? command.type : ApplicationCommandTypes[command.type]; if ( @@ -330,6 +396,8 @@ class ApplicationCommand extends Base { ('version' in command && command.version !== this.version) || ('autocomplete' in command && command.autocomplete !== this.autocomplete) || (commandType && commandType !== this.type) || + defaultMemberPermissions !== (this.defaultMemberPermissions?.bitfield ?? null) || + (typeof dmPermission !== 'undefined' && dmPermission !== this.dmPermission) || // Future proof for options being nullable // TODO: remove ?? 0 on each when nullable (command.options?.length ?? 0) !== (this.options?.length ?? 0) || diff --git a/typings/index.d.ts b/typings/index.d.ts index 47877aa..67d435c 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -230,6 +230,7 @@ export class ApplicationCommand extends Base { public applicationId: Snowflake; public readonly createdAt: Date; public readonly createdTimestamp: number; + /** @deprecated Use {@link defaultMemberPermissions} and {@link dmPermission} instead. */ public defaultPermission: boolean; public description: string; public descriptionLocalizations: LocalizationMap | null; @@ -252,14 +253,19 @@ export class ApplicationCommand extends Base { public type: ApplicationCommandType; public version: Snowflake; public delete(): Promise>; - public edit(data: ApplicationCommandData): Promise>; + public edit(data: Partial): Promise>; public setName(name: string): Promise>; public setNameLocalizations(nameLocalizations: LocalizationMap): Promise>; public setDescription(description: string): Promise>; public setDescriptionLocalizations( descriptionLocalizations: LocalizationMap, ): Promise>; + /** @deprecated Use {@link setDefaultMemberPermissions} and {@link setDMPermission} instead. */ public setDefaultPermission(defaultPermission?: boolean): Promise>; + public setDefaultMemberPermissions( + defaultMemberPermissions: PermissionResolvable | null, + ): Promise>; + public setDMPermission(dmPermission?: boolean): Promise>; public setOptions(options: ApplicationCommandOptionData[]): Promise>; public equals( command: ApplicationCommand | ApplicationCommandData | RawApplicationCommandData, @@ -3215,11 +3221,11 @@ export class ApplicationCommandManager< public delete(command: ApplicationCommandResolvable, guildId?: Snowflake): Promise; public edit( command: ApplicationCommandResolvable, - data: ApplicationCommandDataResolvable, + data: Partial, ): Promise; public edit( command: ApplicationCommandResolvable, - data: ApplicationCommandDataResolvable, + data: Partial, guildId: Snowflake, ): Promise; public fetch( @@ -4282,7 +4288,10 @@ export interface ClientOptions { export interface BaseApplicationCommandData { name: string; nameLocalizations?: LocalizationMap; + /** @deprecated Use {@link defaultMemberPermissions} and {@link dmPermission} instead. */ defaultPermission?: boolean; + defaultMemberPermissions?: PermissionResolvable | null; + dmPermission?: boolean; } export type CommandOptionDataTypeResolvable = ApplicationCommandOptionType | ApplicationCommandOptionTypes;