From de8033e6d2f69daa89f2676c4a8fff4160955730 Mon Sep 17 00:00:00 2001 From: alina sireneva Date: Sat, 4 May 2024 06:00:35 +0300 Subject: [PATCH] chore(core)!: moved full-specific fields to `FullChat` breaking: `Chat` constructor signature changed. also removed some fields from`Chat`, but any code depending on them would be incorrect anyway --- packages/core/src/highlevel/client.ts | 3 +- .../core/src/highlevel/methods/_imports.ts | 1 + .../highlevel/methods/chats/get-full-chat.ts | 6 +- .../core/src/highlevel/types/peers/chat.ts | 218 +----------------- .../src/highlevel/types/peers/full-chat.ts | 208 +++++++++++++++++ .../core/src/highlevel/types/peers/index.ts | 1 + 6 files changed, 217 insertions(+), 220 deletions(-) create mode 100644 packages/core/src/highlevel/types/peers/full-chat.ts diff --git a/packages/core/src/highlevel/client.ts b/packages/core/src/highlevel/client.ts index e7107817..9445d442 100644 --- a/packages/core/src/highlevel/client.ts +++ b/packages/core/src/highlevel/client.ts @@ -261,6 +261,7 @@ import { FileDownloadLocation, FileDownloadParameters, ForumTopic, + FullChat, GameHighScore, HistoryReadUpdate, InlineCallbackQuery, @@ -1562,7 +1563,7 @@ export interface TelegramClient extends ITelegramClient { * In case you are trying to get info about private chat that you haven't joined. * Use {@link getChatPreview} instead. */ - getFullChat(chatId: InputPeerLike): Promise + getFullChat(chatId: InputPeerLike): Promise /** * Get nearby chats * diff --git a/packages/core/src/highlevel/methods/_imports.ts b/packages/core/src/highlevel/methods/_imports.ts index 2f2029c0..ce798592 100644 --- a/packages/core/src/highlevel/methods/_imports.ts +++ b/packages/core/src/highlevel/methods/_imports.ts @@ -42,6 +42,7 @@ import { FileDownloadLocation, FileDownloadParameters, ForumTopic, + FullChat, GameHighScore, HistoryReadUpdate, InlineCallbackQuery, diff --git a/packages/core/src/highlevel/methods/chats/get-full-chat.ts b/packages/core/src/highlevel/methods/chats/get-full-chat.ts index 57401d17..9c6e9a02 100644 --- a/packages/core/src/highlevel/methods/chats/get-full-chat.ts +++ b/packages/core/src/highlevel/methods/chats/get-full-chat.ts @@ -2,7 +2,7 @@ import { tl } from '@mtcute/tl' import { MtArgumentError } from '../../../types/errors.js' import { ITelegramClient } from '../../client.types.js' -import { Chat, InputPeerLike } from '../../types/index.js' +import { FullChat, InputPeerLike } from '../../types/index.js' import { INVITE_LINK_REGEX, isInputPeerChannel, @@ -22,7 +22,7 @@ import { resolvePeer } from '../users/resolve-peer.js' * In case you are trying to get info about private chat that you haven't joined. * Use {@link getChatPreview} instead. */ -export async function getFullChat(client: ITelegramClient, chatId: InputPeerLike): Promise { +export async function getFullChat(client: ITelegramClient, chatId: InputPeerLike): Promise { if (typeof chatId === 'string') { const m = chatId.match(INVITE_LINK_REGEX) @@ -61,5 +61,5 @@ export async function getFullChat(client: ITelegramClient, chatId: InputPeerLike }) } else throw new Error('should not happen') - return Chat._parseFull(res) + return FullChat._parse(res) } diff --git a/packages/core/src/highlevel/types/peers/chat.ts b/packages/core/src/highlevel/types/peers/chat.ts index 2396b727..82d4cc21 100644 --- a/packages/core/src/highlevel/types/peers/chat.ts +++ b/packages/core/src/highlevel/types/peers/chat.ts @@ -4,11 +4,9 @@ import { MtArgumentError, MtTypeAssertionError } from '../../../types/errors.js' import { getMarkedPeerId } from '../../../utils/peer-utils.js' import { makeInspectable } from '../../utils/index.js' import { memoizeGetters } from '../../utils/memoize.js' -import { Photo } from '../media/photo.js' import { MessageEntity } from '../messages/message-entity.js' import { EmojiStatus } from '../reactions/emoji-status.js' import { ChatColors } from './chat-colors.js' -import { ChatLocation } from './chat-location.js' import { ChatPermissions } from './chat-permissions.js' import { ChatPhoto } from './chat-photo.js' import { PeersIndex } from './peers-index.js' @@ -36,10 +34,7 @@ export class Chat { */ readonly peer: tl.RawUser | tl.RawChat | tl.RawChannel | tl.RawChatForbidden | tl.RawChannelForbidden - constructor( - peer: tl.TypeUser | tl.TypeChat, - readonly fullPeer?: tl.TypeUserFull | tl.TypeChatFull, - ) { + constructor(peer: tl.TypeUser | tl.TypeChat) { if (!peer) throw new MtArgumentError('peer is not available') switch (peer._) { @@ -283,15 +278,6 @@ export class Chat { return (this.peer._ === 'channel' || this.peer._ === 'chat') && this.peer.noforwards! } - /** - * Whether this chat (user) has restricted sending them voice/video messages. - * - * Returned only in {@link TelegramClient.getFullChat} - */ - get hasBlockedVoices(): boolean { - return this.fullPeer?._ === 'userFull' && this.fullPeer.voiceMessagesForbidden! - } - /** * Title, for supergroups, channels and groups */ @@ -357,7 +343,7 @@ export class Chat { * Chat photo, if any. * Suitable for downloads only. * - * If full chat information is available, prefer {@link fullPhoto} instead. + * If full chat information is available, prefer {@link FullChat#fullPhoto} instead. */ get photo(): ChatPhoto | null { if ( @@ -371,89 +357,6 @@ export class Chat { return new ChatPhoto(this.inputPeer, this.peer.photo) } - /** - * Full information about this chat's photo, if any. - * - * Unlike {@link Chat.photo}, this field contains additional information - * about the photo, such as its date, more sizes, and is the only - * way to get the animated profile photo. - * - * This field takes into account any personal/fallback photo - * that the user may have set - * - * Only available in {@link TelegramClient.getFullChat} - */ - get fullPhoto(): Photo | null { - if (!this.fullPeer) return null - - let photo: tl.TypePhoto | undefined = undefined - - switch (this.fullPeer._) { - case 'userFull': - photo = this.fullPeer.personalPhoto ?? this.fullPeer.profilePhoto ?? this.fullPeer.fallbackPhoto - break - case 'chatFull': - case 'channelFull': - photo = this.fullPeer.chatPhoto - } - - if (photo?._ !== 'photo') return null - - return new Photo(photo) - } - - /** - * A custom photo (set by the current user) that should be displayed - * instead of the actual chat photo. - * - * Currently only available for users. - * Returned only in {@link TelegramClient.getFullChat} - */ - get personalPhoto(): Photo | null { - if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null - if (this.fullPeer.personalPhoto?._ !== 'photo') return null - - return new Photo(this.fullPeer.personalPhoto) - } - - /** - * Actual profile photo of the user, bypassing the custom one. - * - * Returned only in {@link TelegramClient.getFullChat} - */ - get realPhoto(): Photo | null { - if (!this.fullPeer) return null - if (this.fullPeer._ !== 'userFull') return this.fullPhoto - if (this.fullPeer.personalPhoto?._ !== 'photo') return null - - return new Photo(this.fullPeer.personalPhoto) - } - - /** - * A photo that the user has set to be shown - * in case their actual profile photo is not available - * due to privacy settings. - * - * Currently only available for users. - * Returned only in {@link TelegramClient.getFullChat} - */ - get publicPhoto(): Photo | null { - if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null - if (this.fullPeer.fallbackPhoto?._ !== 'photo') return null - - return new Photo(this.fullPeer.fallbackPhoto) - } - - /** - * Bio of the other party in a private chat, or description of a - * group, supergroup or channel. - * - * Returned only in {@link TelegramClient.getFullChat} - */ - get bio(): string | null { - return this.fullPeer?.about ?? null - } - /** * User's or bot's assigned DC (data center). * Available only in case the user has set a public profile photo. @@ -472,55 +375,6 @@ export class Chat { ) } - /** - * Chat's permanent invite link, for groups, supergroups and channels. - * Returned only in {@link TelegramClient.getFullChat} - */ - get inviteLink(): string | null { - if (this.fullPeer && this.fullPeer._ !== 'userFull') { - switch (this.fullPeer.exportedInvite?._) { - case 'chatInvitePublicJoinRequests': - return null - case 'chatInviteExported': - return this.fullPeer.exportedInvite.link - } - } - - return null - } - - /** - * For supergroups, name of the group sticker set. - * Returned only in {@link TelegramClient.getFullChat} - */ - get stickerSetName(): string | null { - return this.fullPeer && this.fullPeer._ === 'channelFull' ? this.fullPeer.stickerset?.shortName ?? null : null - } - - /** - * Whether the group sticker set can be changed by you. - * Returned only in {@link TelegramClient.getFullChat} - */ - get canSetStickerSet(): boolean | null { - return this.fullPeer && this.fullPeer._ === 'channelFull' ? this.fullPeer.canSetStickers ?? null : null - } - - /** - * Chat members count, for groups, supergroups and channels only. - * Returned only in {@link TelegramClient.getFullChat} - */ - get membersCount(): number | null { - if (this.fullPeer && this.fullPeer._ !== 'userFull') { - if (this.fullPeer._ === 'chatFull' && this.fullPeer.participants._ === 'chatParticipants') { - return this.fullPeer.participants.participants.length - } else if (this.fullPeer._ === 'channelFull') { - return this.fullPeer.participantsCount ?? null - } - } - - return null - } - /** * The list of reasons why this chat might be unavailable to some users. * This field is available only in case {@link isRestricted} is `true` @@ -565,38 +419,6 @@ export class Chat { */ readonly distance?: number - /** - * Location of the chat. - * Returned only in {@link TelegramClient.getFullChat} - */ - get location(): ChatLocation | null { - if (!this.fullPeer || this.fullPeer._ !== 'channelFull' || this.fullPeer.location?._ !== 'channelLocation') { - return null - } - - return new ChatLocation(this.fullPeer.location) - } - - private _linkedChat?: Chat - /** - * The linked discussion group (in case of channels) - * or the linked channel (in case of supergroups). - * - * Returned only in {@link TelegramClient.getFullChat} - */ - get linkedChat(): Chat | null { - return this._linkedChat ?? null - } - - /** - * TTL of all messages in this chat, in seconds - * - * Returned only in {@link TelegramClient.getFullChat} - */ - get ttlPeriod(): number | null { - return this.fullPeer?.ttlPeriod ?? null - } - /** * Maximum ID of stories this chat has (or 0 if none) */ @@ -676,37 +498,6 @@ export class Chat { return new Chat(peers.chat(peer.channelId)) } - /** @internal */ - static _parseFull(full: tl.messages.RawChatFull | tl.users.TypeUserFull): Chat { - if (full._ === 'users.userFull') { - const user = full.users.find((it) => it.id === full.fullUser.id) - - if (!user || user._ === 'userEmpty') { - throw new MtTypeAssertionError('Chat._parseFull', 'user', user?._ ?? 'undefined') - } - - return new Chat(user, full.fullUser) - } - - const fullChat = full.fullChat - let chat: tl.TypeChat | undefined = undefined - let linked: tl.TypeChat | undefined = undefined - - for (const c of full.chats) { - if (fullChat.id === c.id) { - chat = c - } - if (fullChat._ === 'channelFull' && fullChat.linkedChatId === c.id) { - linked = c - } - } - - const ret = new Chat(chat!, fullChat) - ret._linkedChat = linked ? new Chat(linked) : undefined - - return ret - } - /** * Create a mention for the chat. * @@ -758,13 +549,8 @@ memoizeGetters(Chat, [ 'chatType', 'usernames', 'photo', - 'fullPhoto', - 'personalPhoto', - 'realPhoto', - 'publicPhoto', 'permissions', 'defaultPermissions', - 'location', 'user', 'color', ]) diff --git a/packages/core/src/highlevel/types/peers/full-chat.ts b/packages/core/src/highlevel/types/peers/full-chat.ts new file mode 100644 index 00000000..20ae49aa --- /dev/null +++ b/packages/core/src/highlevel/types/peers/full-chat.ts @@ -0,0 +1,208 @@ +import { tl } from '@mtcute/tl' + +import { MtTypeAssertionError } from '../../../types/errors.js' +import { makeInspectable } from '../../utils/inspectable.js' +import { memoizeGetters } from '../../utils/memoize.js' +import { Photo } from '../media/photo.js' +import { Chat } from './chat.js' +import { ChatLocation } from './chat-location.js' + +/** + * Complete information about a particular chat. + */ +export class FullChat extends Chat { + constructor( + peer: tl.TypeUser | tl.TypeChat, + readonly fullPeer: tl.TypeUserFull | tl.TypeChatFull, + ) { + super(peer) + } + + /** @internal */ + static _parse(full: tl.messages.RawChatFull | tl.users.TypeUserFull): FullChat { + if (full._ === 'users.userFull') { + const user = full.users.find((it) => it.id === full.fullUser.id) + + if (!user || user._ === 'userEmpty') { + throw new MtTypeAssertionError('Chat._parseFull', 'user', user?._ ?? 'undefined') + } + + return new FullChat(user, full.fullUser) + } + + const fullChat = full.fullChat + let chat: tl.TypeChat | undefined = undefined + let linked: tl.TypeChat | undefined = undefined + + for (const c of full.chats) { + if (fullChat.id === c.id) { + chat = c + } + if (fullChat._ === 'channelFull' && fullChat.linkedChatId === c.id) { + linked = c + } + } + + const ret = new FullChat(chat!, fullChat) + ret._linkedChat = linked ? new Chat(linked) : undefined + + return ret + } + + /** + * Whether this chat (user) has restricted sending them voice/video messages. + */ + get hasBlockedVoices(): boolean { + return this.fullPeer?._ === 'userFull' && this.fullPeer.voiceMessagesForbidden! + } + + /** + * Full information about this chat's photo, if any. + * + * Unlike {@link Chat.photo}, this field contains additional information + * about the photo, such as its date, more sizes, and is the only + * way to get the animated profile photo. + * + * This field takes into account any personal/fallback photo + * that the user may have set + */ + get fullPhoto(): Photo | null { + if (!this.fullPeer) return null + + let photo: tl.TypePhoto | undefined = undefined + + switch (this.fullPeer._) { + case 'userFull': + photo = this.fullPeer.personalPhoto ?? this.fullPeer.profilePhoto ?? this.fullPeer.fallbackPhoto + break + case 'chatFull': + case 'channelFull': + photo = this.fullPeer.chatPhoto + } + + if (photo?._ !== 'photo') return null + + return new Photo(photo) + } + + /** + * A custom photo (set by the current user) that should be displayed + * instead of the actual chat photo. + * + * Currently only available for users. + */ + get personalPhoto(): Photo | null { + if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null + if (this.fullPeer.personalPhoto?._ !== 'photo') return null + + return new Photo(this.fullPeer.personalPhoto) + } + + /** + * Actual profile photo of the user, bypassing the custom one. + */ + get realPhoto(): Photo | null { + if (!this.fullPeer) return null + if (this.fullPeer._ !== 'userFull') return this.fullPhoto + if (this.fullPeer.personalPhoto?._ !== 'photo') return null + + return new Photo(this.fullPeer.personalPhoto) + } + + /** + * A photo that the user has set to be shown + * in case their actual profile photo is not available + * due to privacy settings. + * + * Currently only available for users. + */ + get publicPhoto(): Photo | null { + if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null + if (this.fullPeer.fallbackPhoto?._ !== 'photo') return null + + return new Photo(this.fullPeer.fallbackPhoto) + } + + /** + * Bio of the other party in a private chat, or description of a + * group, supergroup or channel. + */ + get bio(): string | null { + return this.fullPeer?.about ?? null + } + + /** + * Chat's permanent invite link, for groups, supergroups and channels. + */ + get inviteLink(): string | null { + if (this.fullPeer && this.fullPeer._ !== 'userFull') { + switch (this.fullPeer.exportedInvite?._) { + case 'chatInvitePublicJoinRequests': + return null + case 'chatInviteExported': + return this.fullPeer.exportedInvite.link + } + } + + return null + } + + /** + * For supergroups, name of the group sticker set. + */ + get stickerSetName(): string | null { + return this.fullPeer && this.fullPeer._ === 'channelFull' ? this.fullPeer.stickerset?.shortName ?? null : null + } + + /** + * Whether the group sticker set can be changed by you. + */ + get canSetStickerSet(): boolean | null { + return this.fullPeer && this.fullPeer._ === 'channelFull' ? this.fullPeer.canSetStickers ?? null : null + } + + /** + * Chat members count, for groups, supergroups and channels only. + */ + get membersCount(): number | null { + if (this.fullPeer && this.fullPeer._ !== 'userFull') { + if (this.fullPeer._ === 'chatFull' && this.fullPeer.participants._ === 'chatParticipants') { + return this.fullPeer.participants.participants.length + } else if (this.fullPeer._ === 'channelFull') { + return this.fullPeer.participantsCount ?? null + } + } + + return null + } + + /** + * Location of the chat. + */ + get location(): ChatLocation | null { + if (!this.fullPeer || this.fullPeer._ !== 'channelFull' || this.fullPeer.location?._ !== 'channelLocation') { + return null + } + + return new ChatLocation(this.fullPeer.location) + } + + private _linkedChat?: Chat + /** + * The linked discussion group (in case of channels) + * or the linked channel (in case of supergroups). + */ + get linkedChat(): Chat | null { + return this._linkedChat ?? null + } + + /** + * TTL of all messages in this chat, in seconds + */ + get ttlPeriod(): number | null { + return this.fullPeer?.ttlPeriod ?? null + } +} + +memoizeGetters(FullChat, ['fullPhoto', 'personalPhoto', 'realPhoto', 'publicPhoto', 'location']) +makeInspectable(FullChat) diff --git a/packages/core/src/highlevel/types/peers/index.ts b/packages/core/src/highlevel/types/peers/index.ts index c86d7ab2..cbf59756 100644 --- a/packages/core/src/highlevel/types/peers/index.ts +++ b/packages/core/src/highlevel/types/peers/index.ts @@ -8,6 +8,7 @@ export * from './chat-permissions.js' export * from './chat-photo.js' export * from './chat-preview.js' export * from './forum-topic.js' +export * from './full-chat.js' export * from './peer.js' export * from './peers-index.js' export * from './typing-status.js'