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
This commit is contained in:
alina 🌸 2024-05-04 06:00:35 +03:00
parent 80ddf85083
commit de8033e6d2
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
6 changed files with 217 additions and 220 deletions

View file

@ -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<Chat>
getFullChat(chatId: InputPeerLike): Promise<FullChat>
/**
* Get nearby chats
*

View file

@ -42,6 +42,7 @@ import {
FileDownloadLocation,
FileDownloadParameters,
ForumTopic,
FullChat,
GameHighScore,
HistoryReadUpdate,
InlineCallbackQuery,

View file

@ -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<Chat> {
export async function getFullChat(client: ITelegramClient, chatId: InputPeerLike): Promise<FullChat> {
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)
}

View file

@ -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',
])

View file

@ -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)

View file

@ -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'