From 4eccbea89f35968f791ca0953ca697f9acf10a7d Mon Sep 17 00:00:00 2001 From: Fleny Date: Tue, 27 Jan 2026 18:46:19 +0100 Subject: [PATCH] fix(rest)!: Remove calculateBits from changeToDiscordFormat (#4557) * fix(rest)!: Remove calculateBits from changeToDiscordFormat The rest manager currently has to assume that request bodies that have "permissions", "allow", "deny", "defaultMemberPermissions" fields are always meant as a permissions. If these are not, for user error or future discord changes, this will break. Also Discord expects these as strings, and discordeno does not abstract too much from the discord api, so it doesn't really makes sense for us to accept PermissionStrings[], the user should call calculateBits themselves, there is an argument to be made about accepting bigints since these are bitfields but that's another discussion. * Channel.permissionOverwrites use PermissionStrings For the transformed type we can keep the fact that it uses PermissionStrings * Fix e2e test * remove comment --- packages/bot/src/transformers/types.ts | 14 ++++++++++++-- packages/rest/src/manager.ts | 10 ---------- packages/rest/tests/e2e/role.spec.ts | 2 +- packages/types/src/discordeno/channel.ts | 11 ++++------- packages/types/src/discordeno/guild.ts | 5 ++--- packages/types/src/discordeno/interactions.ts | 3 +-- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/packages/bot/src/transformers/types.ts b/packages/bot/src/transformers/types.ts index fab2f3afe..b5b5e9a91 100644 --- a/packages/bot/src/transformers/types.ts +++ b/packages/bot/src/transformers/types.ts @@ -50,7 +50,8 @@ import type { MessageTypes, MfaLevels, OAuth2Scope, - Overwrite, + OverwriteTypes, + PermissionStrings, PremiumTiers, PremiumTypes, PresenceStatus, @@ -510,7 +511,16 @@ export interface Channel { /** for group DM channels: whether the channel is managed by an application via the `gdm.join` OAuth2 scope */ managed: boolean; /** Explicit permission overwrites for members and roles. */ - permissionOverwrites: Overwrite[]; + permissionOverwrites: { + /** Role or user id */ + id: bigint; + /** Either 0 (role) or 1 (member) */ + type: OverwriteTypes; + /** Permission bit set */ + allow: PermissionStrings[]; + /** Permission bit set */ + deny: PermissionStrings[]; + }[]; } export interface ForumTag { diff --git a/packages/rest/src/manager.ts b/packages/rest/src/manager.ts index 16a4c5da7..e463463e4 100644 --- a/packages/rest/src/manager.ts +++ b/packages/rest/src/manager.ts @@ -59,7 +59,6 @@ import type { ModifyGuildTemplate, } from '@discordeno/types'; import { - calculateBits, camelize, camelToSnakeCase, DISCORDENO_VERSION, @@ -236,17 +235,8 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage continue; } - // Some falsy values should be allowed like null or 0 if (value !== undefined) { switch (key) { - case 'permissions': - case 'allow': - case 'deny': - newObj[key] = typeof value === 'string' ? value : calculateBits(value); - continue; - case 'defaultMemberPermissions': - newObj.default_member_permissions = typeof value === 'string' ? value : calculateBits(value); - continue; case 'nameLocalizations': newObj.name_localizations = value; continue; diff --git a/packages/rest/tests/e2e/role.spec.ts b/packages/rest/tests/e2e/role.spec.ts index 8eaa5da9b..41a9cd12a 100644 --- a/packages/rest/tests/e2e/role.spec.ts +++ b/packages/rest/tests/e2e/role.spec.ts @@ -46,7 +46,7 @@ describe('Role tests', () => { color: 0x0000ff, hoist: true, mentionable: true, - permissions: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + permissions: calculateBits(['SEND_MESSAGES', 'VIEW_CHANNEL']), }); expect(edited.name).to.equal('test role 4'); diff --git a/packages/types/src/discordeno/channel.ts b/packages/types/src/discordeno/channel.ts index 6e2e79252..aa21ff127 100644 --- a/packages/types/src/discordeno/channel.ts +++ b/packages/types/src/discordeno/channel.ts @@ -3,7 +3,6 @@ import type { ChannelFlags, ChannelTypes, ForumLayout, OverwriteTypes, SortOrderTypes, VideoQualityModes } from '../discord/channel.js'; import type { TargetTypes } from '../discord/invite.js'; import type { DiscordAttachment, DiscordEmbed, MessageFlags } from '../discord/message.js'; -import type { PermissionStrings } from '../discord/permissions.js'; import type { BigString, Camelize } from '../shared.js'; import type { MessageComponents } from './components.js'; import type { AllowedMentions } from './message.js'; @@ -17,12 +16,11 @@ export interface Overwrite { type: OverwriteTypes; // NOTE: - // - We allow PermissionStrings[] because in the rest manager we convert these value to the actual string discord wants // - Discord says that these are always present, we keep them as optional (and allow for null) because when it is sent it can be null / not present, https://discord.com/developers/docs/resources/guild#create-guild-channel-json-params, specificly the ** /** Permission bit set */ - allow?: PermissionStrings[] | string | null; + allow?: string | null; /** Permission bit set */ - deny?: PermissionStrings[] | string | null; + deny?: string | null; } // This needs the prefix Discordeno to avoid conflicts with the @discordeno/bot types. @@ -280,11 +278,10 @@ export interface EditChannelPermissionOverridesOptions { /** Either 0 (role) or 1 (member) */ type: OverwriteTypes; - // We allow PermissionStrings[] because in the rest manager we convert these value to the actual string discord wants /** The bitwise value of all allowed permissions */ - allow?: PermissionStrings[] | string | null; + allow?: string | null; /** The bitwise value of all disallowed permissions */ - deny?: PermissionStrings[] | string | null; + deny?: string | null; } /** https://discord.com/developers/docs/resources/channel#create-channel-invite-json-params */ diff --git a/packages/types/src/discordeno/guild.ts b/packages/types/src/discordeno/guild.ts index b84768a2e..0f5d3e69b 100644 --- a/packages/types/src/discordeno/guild.ts +++ b/packages/types/src/discordeno/guild.ts @@ -12,7 +12,6 @@ import type { SystemChannelFlags, VerificationLevels, } from '../discord/guild.js'; -import type { PermissionStrings } from '../discord/permissions.js'; import type { BigString, Camelize } from '../shared.js'; import type { DiscordenoDefaultReactionEmoji, DiscordenoForumTag, Overwrite } from './channel.js'; import type { GuildRoleColors } from './permissions.js'; @@ -216,7 +215,7 @@ export interface CreateGuildRole { /** Name of the role, max 100 characters, default: "new role" */ name?: string; /** Bitwise value of the enabled/disabled permissions, default: everyone permissions in guild */ - permissions?: PermissionStrings[] | string; + permissions?: string; /** * RGB color value, default: 0 * @deprecated the {@link colors} field is recommended for use instead of this field @@ -247,7 +246,7 @@ export interface EditGuildRole { /** Name of the role, max 100 characters, default: "new role" */ name?: string | null; /** Bitwise value of the enabled/disabled permissions, default: everyone permissions in guild */ - permissions?: PermissionStrings[] | string | null; + permissions?: string | null; /** * RGB color value, default: 0 * @deprecated the {@link colors} field is recommended for use instead of this field diff --git a/packages/types/src/discordeno/interactions.ts b/packages/types/src/discordeno/interactions.ts index b6667ea56..e43d6dcee 100644 --- a/packages/types/src/discordeno/interactions.ts +++ b/packages/types/src/discordeno/interactions.ts @@ -14,7 +14,6 @@ import type { InteractionResponseTypes, } from '../discord/interactions.js'; import type { DiscordAttachment, DiscordEmbed, MessageFlags } from '../discord/message.js'; -import type { PermissionStrings } from '../discord/permissions.js'; import type { Localization } from '../discord/reference.js'; import type { BigString, Camelize } from '../shared.js'; import type { MessageComponents } from './components.js'; @@ -128,7 +127,7 @@ export interface CreateApplicationCommand { */ options?: Camelize; /** Set of permissions represented as a bit set */ - defaultMemberPermissions?: PermissionStrings[] | string | null; + defaultMemberPermissions?: string | null; /** * Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. *