From 2c1fbda621fc1c1ea227295c578e6d8486dbc4f2 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:58:02 -0500 Subject: [PATCH] types: Add tagged `type` unions for channel types (#200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: All of the channel types are now split based on their type. As such, you will need to assert the type (either by checking it with the enum or by casting the data as the correct channel) before accessing data. *If you encounter any missing properties due to this, please open an issue! This is a big change, and we hope nothing is missing* Co-authored-by: Vlad Frangu Co-authored-by: Antonio Román --- .gitignore | 3 + deno/payloads/v8/channel.ts | 146 ++++++++++++++++++++-------- deno/payloads/v9/channel.ts | 188 +++++++++++++++++++++++++++--------- deno/rest/v8/guild.ts | 9 +- deno/rest/v9/guild.ts | 9 +- deno/utils/internals.ts | 2 + payloads/v8/channel.ts | 146 ++++++++++++++++++++-------- payloads/v9/channel.ts | 188 +++++++++++++++++++++++++++--------- rest/v8/guild.ts | 9 +- rest/v9/guild.ts | 9 +- utils/internals.ts | 2 + 11 files changed, 529 insertions(+), 182 deletions(-) diff --git a/.gitignore b/.gitignore index 61aa2ebc..cc966e89 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ voice/**/*.js voice/**/*.map voice/**/*.d.ts voice/**/*.mjs + +# macOS files +.DS_store diff --git a/deno/payloads/v8/channel.ts b/deno/payloads/v8/channel.ts index 23bcf6fa..621c1510 100644 --- a/deno/payloads/v8/channel.ts +++ b/deno/payloads/v8/channel.ts @@ -32,17 +32,37 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = ChannelType.DM | ChannelType.GroupDM | ChannelType.GuildNews | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ guild_id?: Snowflake; - /** - * Sorting position of the channel - */ - position?: number; /** * Explicit permission overwrites for members and roles * @@ -50,17 +70,48 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * The channel topic (0-1024 characters) */ - last_message_id?: Snowflake | null; + topic?: string | null; + /** + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + */ + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { + /** + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + */ + rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** * The bitrate (in bits) of the voice channel */ @@ -69,38 +120,6 @@ export interface APIChannel extends APIPartialChannel { * The user limit of the voice channel */ user_limit?: number; - /** - * Amount of seconds a user has to wait before sending another message (0-21600); - * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected - */ - rate_limit_per_user?: number; - /** - * The recipients of the DM - * - * See https://discord.com/developers/docs/resources/user#user-object - */ - recipients?: APIUser[]; - /** - * Icon hash - */ - icon?: string | null; - /** - * ID of the DM creator - */ - owner_id?: Snowflake; - /** - * Application id of the group DM creator if it is bot-created - */ - application_id?: Snowflake; - /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - */ - parent_id?: Snowflake | null; - /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned - */ - last_pin_timestamp?: string | null; /** * Voice region id for the voice or stage channel, automatic when set to `null` * @@ -115,6 +134,49 @@ export interface APIChannel extends APIPartialChannel { video_quality_mode?: VideoQualityMode; } +interface APIDMChannelBase extends APITextBasedChannel { + /** + * The recipients of the DM + * + * See https://discord.com/developers/docs/resources/user#user-object + */ + recipients?: APIUser[]; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { + /** + * Application id of the group DM creator if it is bot-created + */ + application_id?: Snowflake; + /** + * Icon hash + */ + icon?: string | null; + /** + * ID of the DM creator + */ + owner_id?: Snowflake; + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/deno/payloads/v9/channel.ts b/deno/payloads/v9/channel.ts index 548d60a9..24f35480 100644 --- a/deno/payloads/v9/channel.ts +++ b/deno/payloads/v9/channel.ts @@ -32,17 +32,44 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = + | ChannelType.DM + | ChannelType.GroupDM + | ChannelType.GuildNews + | ChannelType.GuildPublicThread + | ChannelType.GuildPrivateThread + | ChannelType.GuildNewsThread + | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ guild_id?: Snowflake; - /** - * Sorting position of the channel - */ - position?: number; /** * Explicit permission overwrites for members and roles * @@ -50,25 +77,44 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + * + * OR + * + * ID of the parent channel for a thread + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity */ - last_message_id?: Snowflake | null; + default_auto_archive_duration?: ThreadAutoArchiveDuration; /** - * The bitrate (in bits) of the voice channel + * The channel topic (0-1024 characters) */ - bitrate?: number; + topic?: string | null; /** - * The user limit of the voice channel + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned */ - user_limit?: number; + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { /** * Amount of seconds a user has to wait before sending another message (0-21600); * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected @@ -79,37 +125,21 @@ export interface APIChannel extends APIPartialChannel { * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** - * The recipients of the DM - * - * See https://discord.com/developers/docs/resources/user#user-object + * The bitrate (in bits) of the voice channel */ - recipients?: APIUser[]; + bitrate?: number; /** - * Icon hash + * The user limit of the voice channel */ - icon?: string | null; - /** - * ID of the DM creator or thread creator - */ - owner_id?: Snowflake; - /** - * Application id of the group DM creator if it is bot-created - */ - application_id?: Snowflake; - /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - * - * OR - * - * ID of the parent channel for a thread - */ - parent_id?: Snowflake | null; - /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned - */ - last_pin_timestamp?: string | null; + user_limit?: number; /** * Voice region id for the voice or stage channel, automatic when set to `null` * @@ -122,6 +152,50 @@ export interface APIChannel extends APIPartialChannel { * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes */ video_quality_mode?: VideoQualityMode; +} + +interface APIDMChannelBase extends APITextBasedChannel { + /** + * The recipients of the DM + * + * See https://discord.com/developers/docs/resources/user#user-object + */ + recipients?: APIUser[]; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { + /** + * Application id of the group DM creator if it is bot-created + */ + application_id?: Snowflake; + /** + * Icon hash + */ + icon?: string | null; + /** + * ID of the DM creator + */ + owner_id?: Snowflake; + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +export interface APIThreadChannel + extends APIGuildChannel< + ChannelType.GuildPublicThread | ChannelType.GuildPrivateThread | ChannelType.GuildNewsThread + > { + /** + * The client users member for the thread, only included in select endpoints + */ + member?: APIThreadMember; + /** + * The metadata for a thread channel not shared by other channels + */ + thread_metadata?: APIThreadMetadata; /** * The approximate message count of the thread, does not count above 50 even if there are more messages */ @@ -131,19 +205,39 @@ export interface APIChannel extends APIPartialChannel { */ member_count?: number; /** - * The metadata for a thread channel not shared by other channels + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + * + * `rate_limit_per_user` also applies to thread creation. Users can send one message and create one thread during each `rate_limit_per_user` interval. + * + * For thread channels, `rate_limit_per_user` is only returned if the field is set to a non-zero and non-null value. + * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ - thread_metadata?: APIThreadMetadata; + rate_limit_per_user?: number; /** - * The client users member for the thread, only included in select endpoints + * ID of the thread creator */ - member?: APIThreadMember; + owner_id?: Snowflake; /** - * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity + * The id of the last message sent in this thread (may not point to an existing or valid message) */ - default_auto_archive_duration?: ThreadAutoArchiveDuration; + last_message_id?: Snowflake | null; } +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APIThreadChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/deno/rest/v8/guild.ts b/deno/rest/v8/guild.ts index 83d577f8..abbd8625 100644 --- a/deno/rest/v8/guild.ts +++ b/deno/rest/v8/guild.ts @@ -2,7 +2,9 @@ import type { Permissions, Snowflake } from '../../globals.ts'; import type { APIBan, APIChannel, + APIDMChannel, APIExtendedInvite, + APIGroupDMChannel, APIGuild, APIGuildIntegration, APIGuildMember, @@ -25,6 +27,7 @@ import type { Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals.ts'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel.ts'; @@ -32,8 +35,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/deno/rest/v9/guild.ts b/deno/rest/v9/guild.ts index 81645aea..79b6a3e0 100644 --- a/deno/rest/v9/guild.ts +++ b/deno/rest/v9/guild.ts @@ -20,12 +20,15 @@ import type { GuildSystemChannelFlags, GuildVerificationLevel, GuildWidgetStyle, + APIDMChannel, + APIGroupDMChannel, } from '../../payloads/v9/mod.ts'; import type { AddUndefinedToPossiblyUndefinedPropertiesOfInterface, Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals.ts'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel.ts'; @@ -33,8 +36,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/deno/utils/internals.ts b/deno/utils/internals.ts index 305ded2e..fea21fab 100644 --- a/deno/utils/internals.ts +++ b/deno/utils/internals.ts @@ -13,3 +13,5 @@ export type AddUndefinedToPossiblyUndefinedPropertiesOfInterface = { export type StrictPartial = AddUndefinedToPossiblyUndefinedPropertiesOfInterface>; export type StrictRequired = Required<{ [K in keyof Base]: Exclude }>; + +export type UnionToIntersection = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never; diff --git a/payloads/v8/channel.ts b/payloads/v8/channel.ts index afda486d..7aab50f8 100644 --- a/payloads/v8/channel.ts +++ b/payloads/v8/channel.ts @@ -32,17 +32,37 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = ChannelType.DM | ChannelType.GroupDM | ChannelType.GuildNews | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ guild_id?: Snowflake; - /** - * Sorting position of the channel - */ - position?: number; /** * Explicit permission overwrites for members and roles * @@ -50,17 +70,48 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * The channel topic (0-1024 characters) */ - last_message_id?: Snowflake | null; + topic?: string | null; + /** + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + */ + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { + /** + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + */ + rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** * The bitrate (in bits) of the voice channel */ @@ -69,38 +120,6 @@ export interface APIChannel extends APIPartialChannel { * The user limit of the voice channel */ user_limit?: number; - /** - * Amount of seconds a user has to wait before sending another message (0-21600); - * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected - */ - rate_limit_per_user?: number; - /** - * The recipients of the DM - * - * See https://discord.com/developers/docs/resources/user#user-object - */ - recipients?: APIUser[]; - /** - * Icon hash - */ - icon?: string | null; - /** - * ID of the DM creator - */ - owner_id?: Snowflake; - /** - * Application id of the group DM creator if it is bot-created - */ - application_id?: Snowflake; - /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - */ - parent_id?: Snowflake | null; - /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned - */ - last_pin_timestamp?: string | null; /** * Voice region id for the voice or stage channel, automatic when set to `null` * @@ -115,6 +134,49 @@ export interface APIChannel extends APIPartialChannel { video_quality_mode?: VideoQualityMode; } +interface APIDMChannelBase extends APITextBasedChannel { + /** + * The recipients of the DM + * + * See https://discord.com/developers/docs/resources/user#user-object + */ + recipients?: APIUser[]; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { + /** + * Application id of the group DM creator if it is bot-created + */ + application_id?: Snowflake; + /** + * Icon hash + */ + icon?: string | null; + /** + * ID of the DM creator + */ + owner_id?: Snowflake; + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/payloads/v9/channel.ts b/payloads/v9/channel.ts index 5ee9dc2a..8c1108a6 100644 --- a/payloads/v9/channel.ts +++ b/payloads/v9/channel.ts @@ -32,17 +32,44 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = + | ChannelType.DM + | ChannelType.GroupDM + | ChannelType.GuildNews + | ChannelType.GuildPublicThread + | ChannelType.GuildPrivateThread + | ChannelType.GuildNewsThread + | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ guild_id?: Snowflake; - /** - * Sorting position of the channel - */ - position?: number; /** * Explicit permission overwrites for members and roles * @@ -50,25 +77,44 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + * + * OR + * + * ID of the parent channel for a thread + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity */ - last_message_id?: Snowflake | null; + default_auto_archive_duration?: ThreadAutoArchiveDuration; /** - * The bitrate (in bits) of the voice channel + * The channel topic (0-1024 characters) */ - bitrate?: number; + topic?: string | null; /** - * The user limit of the voice channel + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned */ - user_limit?: number; + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { /** * Amount of seconds a user has to wait before sending another message (0-21600); * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected @@ -79,37 +125,21 @@ export interface APIChannel extends APIPartialChannel { * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** - * The recipients of the DM - * - * See https://discord.com/developers/docs/resources/user#user-object + * The bitrate (in bits) of the voice channel */ - recipients?: APIUser[]; + bitrate?: number; /** - * Icon hash + * The user limit of the voice channel */ - icon?: string | null; - /** - * ID of the DM creator or thread creator - */ - owner_id?: Snowflake; - /** - * Application id of the group DM creator if it is bot-created - */ - application_id?: Snowflake; - /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - * - * OR - * - * ID of the parent channel for a thread - */ - parent_id?: Snowflake | null; - /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned - */ - last_pin_timestamp?: string | null; + user_limit?: number; /** * Voice region id for the voice or stage channel, automatic when set to `null` * @@ -122,6 +152,50 @@ export interface APIChannel extends APIPartialChannel { * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes */ video_quality_mode?: VideoQualityMode; +} + +interface APIDMChannelBase extends APITextBasedChannel { + /** + * The recipients of the DM + * + * See https://discord.com/developers/docs/resources/user#user-object + */ + recipients?: APIUser[]; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { + /** + * Application id of the group DM creator if it is bot-created + */ + application_id?: Snowflake; + /** + * Icon hash + */ + icon?: string | null; + /** + * ID of the DM creator + */ + owner_id?: Snowflake; + /** + * The id of the last message sent in this channel (may not point to an existing or valid message) + */ + last_message_id?: Snowflake | null; +} + +export interface APIThreadChannel + extends APIGuildChannel< + ChannelType.GuildPublicThread | ChannelType.GuildPrivateThread | ChannelType.GuildNewsThread + > { + /** + * The client users member for the thread, only included in select endpoints + */ + member?: APIThreadMember; + /** + * The metadata for a thread channel not shared by other channels + */ + thread_metadata?: APIThreadMetadata; /** * The approximate message count of the thread, does not count above 50 even if there are more messages */ @@ -131,19 +205,39 @@ export interface APIChannel extends APIPartialChannel { */ member_count?: number; /** - * The metadata for a thread channel not shared by other channels + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + * + * `rate_limit_per_user` also applies to thread creation. Users can send one message and create one thread during each `rate_limit_per_user` interval. + * + * For thread channels, `rate_limit_per_user` is only returned if the field is set to a non-zero and non-null value. + * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ - thread_metadata?: APIThreadMetadata; + rate_limit_per_user?: number; /** - * The client users member for the thread, only included in select endpoints + * ID of the thread creator */ - member?: APIThreadMember; + owner_id?: Snowflake; /** - * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity + * The id of the last message sent in this thread (may not point to an existing or valid message) */ - default_auto_archive_duration?: ThreadAutoArchiveDuration; + last_message_id?: Snowflake | null; } +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APIThreadChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/rest/v8/guild.ts b/rest/v8/guild.ts index fdf8f381..88e790f8 100644 --- a/rest/v8/guild.ts +++ b/rest/v8/guild.ts @@ -2,7 +2,9 @@ import type { Permissions, Snowflake } from '../../globals'; import type { APIBan, APIChannel, + APIDMChannel, APIExtendedInvite, + APIGroupDMChannel, APIGuild, APIGuildIntegration, APIGuildMember, @@ -25,6 +27,7 @@ import type { Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel'; @@ -32,8 +35,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/rest/v9/guild.ts b/rest/v9/guild.ts index e95ef2eb..82b3a34d 100644 --- a/rest/v9/guild.ts +++ b/rest/v9/guild.ts @@ -20,12 +20,15 @@ import type { GuildSystemChannelFlags, GuildVerificationLevel, GuildWidgetStyle, + APIDMChannel, + APIGroupDMChannel, } from '../../payloads/v9/index'; import type { AddUndefinedToPossiblyUndefinedPropertiesOfInterface, Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel'; @@ -33,8 +36,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/utils/internals.ts b/utils/internals.ts index 305ded2e..fea21fab 100644 --- a/utils/internals.ts +++ b/utils/internals.ts @@ -13,3 +13,5 @@ export type AddUndefinedToPossiblyUndefinedPropertiesOfInterface = { export type StrictPartial = AddUndefinedToPossiblyUndefinedPropertiesOfInterface>; export type StrictRequired = Required<{ [K in keyof Base]: Exclude }>; + +export type UnionToIntersection = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;