diff --git a/packages/builders/src/interactions/contextMenuCommands/Assertions.ts b/packages/builders/src/interactions/contextMenuCommands/Assertions.ts index 90543d627..d719b4f79 100644 --- a/packages/builders/src/interactions/contextMenuCommands/Assertions.ts +++ b/packages/builders/src/interactions/contextMenuCommands/Assertions.ts @@ -30,3 +30,19 @@ export function validateRequiredParameters(name: string, type: number) { // Assert type is valid validateType(type); } + +const dmPermissionPredicate = s.boolean.nullish; + +export function validateDMPermission(value: unknown): asserts value is boolean | null | undefined { + dmPermissionPredicate.parse(value); +} + +const memberPermissionPredicate = s.union( + s.bigint.transform((value) => value.toString()), + s.number.safeInt.transform((value) => value.toString()), + s.string.regex(/^\d+$/), +).nullish; + +export function validateDefaultMemberPermissions(permissions: unknown) { + return memberPermissionPredicate.parse(permissions); +} diff --git a/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts b/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts index 0567c7a69..d07c014e6 100644 --- a/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts +++ b/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts @@ -2,9 +2,17 @@ import type { ApplicationCommandType, LocaleString, LocalizationMap, + Permissions, RESTPostAPIApplicationCommandsJSONBody, } from 'discord-api-types/v10'; -import { validateRequiredParameters, validateName, validateType, validateDefaultPermission } from './Assertions'; +import { + validateRequiredParameters, + validateName, + validateType, + validateDefaultPermission, + validateDefaultMemberPermissions, + validateDMPermission, +} from './Assertions'; import { validateLocale, validateLocalizationMap } from '../slashCommands/Assertions'; export class ContextMenuCommandBuilder { @@ -26,9 +34,21 @@ export class ContextMenuCommandBuilder { /** * Whether the command is enabled by default when the app is added to a guild * - * @default true + * @deprecated This property is deprecated and will be removed in the future. + * You should use `setDefaultMemberPermissions` or `setDMPermission` instead. */ - public readonly defaultPermission: boolean | undefined = undefined; + public readonly default_permission: boolean | undefined = undefined; + + /** + * Set of permissions represented as a bit set for the command + */ + public readonly default_member_permissions: Permissions | null | undefined = undefined; + + /** + * Indicates whether the command is available in DMs with the application, only for globally-scoped commands. + * By default, commands are visible. + */ + public readonly dm_permission: boolean | null | undefined = undefined; /** * Sets the name @@ -66,12 +86,48 @@ export class ContextMenuCommandBuilder { * @param value Whether or not to enable this command by default * * @see https://discord.com/developers/docs/interactions/application-commands#permissions + * @deprecated Use `setDefaultMemberPermissions` or `setDMPermission` instead. */ public setDefaultPermission(value: boolean) { // Assert the value matches the conditions validateDefaultPermission(value); - Reflect.set(this, 'defaultPermission', value); + Reflect.set(this, 'default_permission', value); + + return this; + } + + /** + * Sets the default permissions a member should have in order to run the command. + * + * **Note:** You can set this to `'0'` to disable the command by default. + * + * @param permissions The permissions bit field to set + * + * @see https://discord.com/developers/docs/interactions/application-commands#permissions + */ + public setDefaultMemberPermissions(permissions: Permissions | null | undefined) { + // Assert the value and parse it + const permissionValue = validateDefaultMemberPermissions(permissions); + + Reflect.set(this, 'default_member_permissions', permissionValue); + + return this; + } + + /** + * Sets if the command is available in DMs with the application, only for globally-scoped commands. + * By default, commands are visible. + * + * @param enabled If the command should be enabled in DMs + * + * @see https://discord.com/developers/docs/interactions/application-commands#permissions + */ + public setDMPermission(enabled: boolean | null | undefined) { + // Assert the value matches the conditions + validateDMPermission(enabled); + + Reflect.set(this, 'dm_permission', enabled); return this; } @@ -129,12 +185,7 @@ export class ContextMenuCommandBuilder { validateLocalizationMap(this.name_localizations); - return { - name: this.name, - name_localizations: this.name_localizations, - type: this.type, - default_permission: this.defaultPermission, - }; + return { ...this }; } } diff --git a/packages/builders/src/interactions/slashCommands/Assertions.ts b/packages/builders/src/interactions/slashCommands/Assertions.ts index 6e1a9bc04..4a5f75a96 100644 --- a/packages/builders/src/interactions/slashCommands/Assertions.ts +++ b/packages/builders/src/interactions/slashCommands/Assertions.ts @@ -95,3 +95,19 @@ export const localizationMapPredicate = s.object( export function validateLocalizationMap(value: unknown): asserts value is LocalizationMap { localizationMapPredicate.parse(value); } + +const dmPermissionPredicate = s.boolean.nullish; + +export function validateDMPermission(value: unknown): asserts value is boolean | null | undefined { + dmPermissionPredicate.parse(value); +} + +const memberPermissionPredicate = s.union( + s.bigint.transform((value) => value.toString()), + s.number.safeInt.transform((value) => value.toString()), + s.string.regex(/^\d+$/), +).nullish; + +export function validateDefaultMemberPermissions(permissions: unknown) { + return memberPermissionPredicate.parse(permissions); +} diff --git a/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts b/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts index 163ae1319..6343b0b7d 100644 --- a/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts +++ b/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts @@ -6,8 +6,10 @@ import type { import { mix } from 'ts-mixer'; import { assertReturnOfBuilder, + validateDefaultMemberPermissions, validateDefaultPermission, validateLocalizationMap, + validateDMPermission, validateMaxOptionsLength, validateRequiredParameters, } from './Assertions'; @@ -45,9 +47,21 @@ export class SlashCommandBuilder { /** * Whether the command is enabled by default when the app is added to a guild * - * @default true + * @deprecated This property is deprecated and will be removed in the future. + * You should use `setDefaultMemberPermissions` or `setDMPermission` instead. */ - public readonly defaultPermission: boolean | undefined = undefined; + public readonly default_permission: boolean | undefined = undefined; + + /** + * Set of permissions represented as a bit set for the command + */ + public readonly default_member_permissions: Permissions | null | undefined = undefined; + + /** + * Indicates whether the command is available in DMs with the application, only for globally-scoped commands. + * By default, commands are visible. + */ + public readonly dm_permission: boolean | null | undefined = undefined; /** * Returns the final data that should be sent to Discord. @@ -61,12 +75,8 @@ export class SlashCommandBuilder { validateLocalizationMap(this.description_localizations); return { - name: this.name, - name_localizations: this.name_localizations, - description: this.description, - description_localizations: this.description_localizations, + ...this, options: this.options.map((option) => option.toJSON()), - default_permission: this.defaultPermission, }; } @@ -78,12 +88,48 @@ export class SlashCommandBuilder { * @param value Whether or not to enable this command by default * * @see https://discord.com/developers/docs/interactions/application-commands#permissions + * @deprecated Use `setDefaultMemberPermissions` or `setDMPermission` instead. */ public setDefaultPermission(value: boolean) { // Assert the value matches the conditions validateDefaultPermission(value); - Reflect.set(this, 'defaultPermission', value); + Reflect.set(this, 'default_permission', value); + + return this; + } + + /** + * Sets the default permissions a member should have in order to run the command. + * + * **Note:** You can set this to `'0'` to disable the command by default. + * + * @param permissions The permissions bit field to set + * + * @see https://discord.com/developers/docs/interactions/application-commands#permissions + */ + public setDefaultMemberPermissions(permissions: Permissions | null | undefined) { + // Assert the value and parse it + const permissionValue = validateDefaultMemberPermissions(permissions); + + Reflect.set(this, 'default_member_permissions', permissionValue); + + return this; + } + + /** + * Sets if the command is available in DMs with the application, only for globally-scoped commands. + * By default, commands are visible. + * + * @param enabled If the command should be enabled in DMs + * + * @see https://discord.com/developers/docs/interactions/application-commands#permissions + */ + public setDMPermission(enabled: boolean | null | undefined) { + // Assert the value matches the conditions + validateDMPermission(enabled); + + Reflect.set(this, 'dm_permission', enabled); return this; }