From c21f0af7db1578d203fbfab7d029bebf92f31bf1 Mon Sep 17 00:00:00 2001 From: Almeida Date: Sun, 19 Jul 2026 17:20:25 +0100 Subject: [PATCH] feat(BaseChannel): add `permissions` and `appPermissions` (#11577) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../discord.js/src/structures/BaseChannel.js | 26 +++++++++++++++++++ packages/discord.js/typings/index.d.ts | 2 ++ packages/discord.js/typings/index.test-d.ts | 4 +++ 3 files changed, 32 insertions(+) diff --git a/packages/discord.js/src/structures/BaseChannel.js b/packages/discord.js/src/structures/BaseChannel.js index 416d2c434..8d6de7764 100644 --- a/packages/discord.js/src/structures/BaseChannel.js +++ b/packages/discord.js/src/structures/BaseChannel.js @@ -5,6 +5,7 @@ const { DiscordSnowflake } = require('@sapphire/snowflake'); const { ChannelType, Routes } = require('discord-api-types/v10'); const { ChannelFlagsBitField } = require('../util/ChannelFlagsBitField.js'); const { ThreadChannelTypes } = require('../util/Constants.js'); +const { PermissionsBitField } = require('../util/PermissionsBitField.js'); const { Base } = require('./Base.js'); /** @@ -46,6 +47,31 @@ class BaseChannel extends Base { * @type {Snowflake} */ this.id = data.id; + + if ('permissions' in data) { + /** + * The computed permissions of the user who invoked the interaction in this channel, including overwrites. + * This is only present on channels received through an interaction's resolved data. + * + * @type {?Readonly} + */ + this.permissions = new PermissionsBitField(data.permissions).freeze(); + } else { + this.permissions ??= null; + } + + if ('app_permissions' in data) { + /** + * The computed permissions of the application in this channel, including overwrites. + * This is only present on channels received through an interaction's resolved data, and only when the + * application's bot user is in the guild. + * + * @type {?Readonly} + */ + this.appPermissions = new PermissionsBitField(data.app_permissions).freeze(); + } else { + this.appPermissions ??= null; + } } /** diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 6ef607587..1ca5ebe90 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -900,6 +900,8 @@ export abstract class BaseChannel extends Base { public get createdTimestamp(): number | null; public id: Snowflake; public flags: Readonly | null; + public permissions: Readonly | null; + public appPermissions: Readonly | null; public get partial(): false; public type: ChannelType; public get url(): string; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index f06db5b36..a3602b2ec 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -2270,6 +2270,10 @@ client.on('interactionCreate', async interaction => { interaction.options.getChannel('test', false, [ChannelType.GuildForum, ChannelType.GuildVoice]), ); expectType(interaction.options.getChannel('test', true, [ChannelType.GuildMedia])); + + const resolvedChannel = interaction.options.getChannel('test', true); + expectType | null>(resolvedChannel.permissions); + expectType | null>(resolvedChannel.appPermissions); } else { expectType(interaction); expectType>(interaction.reply({ withResponse: true }));