chore(client)!: better parsed peer handling

breaking: anonymous sender is now represented with `AnonymousSender` interface and not `string`
This commit is contained in:
alina 🌸 2023-12-02 17:48:01 +03:00
parent 9db9411c27
commit 893a15d111
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
14 changed files with 120 additions and 145 deletions

View file

@ -3,8 +3,8 @@ import { MtTypeAssertionError, tl } from '@mtcute/core'
import { makeInspectable } from '../../utils/inspectable.js'
import { memoizeGetters } from '../../utils/memoize.js'
import { Chat } from '../peers/chat.js'
import { parsePeer, PeerSender } from '../peers/peer.js'
import { PeersIndex } from '../peers/peers-index.js'
import { User } from '../peers/user.js'
import { _messageMediaFromTl } from './message-media.js'
/**
@ -27,20 +27,16 @@ export class MessageForwardInfo {
* Sender of the original message (either user or a channel)
* or their name (for users with private forwards)
*/
get sender(): User | Chat | string {
get sender(): PeerSender {
if (this.raw.fromName) {
return this.raw.fromName
return {
type: 'anonymous',
displayName: this.raw.fromName,
}
}
if (this.raw.fromId) {
switch (this.raw.fromId._) {
case 'peerChannel':
return new Chat(this._peers.chat(this.raw.fromId.channelId))
case 'peerUser':
return new User(this._peers.user(this.raw.fromId.userId))
default:
throw new MtTypeAssertionError('raw.fwdFrom.fromId', 'peerUser | peerChannel', this.raw.fromId._)
}
return parsePeer(this.raw.fromId, this._peers)
}
throw new MtTypeAssertionError('MessageForwardInfo', 'to have fromId or fromName', 'neither')
@ -50,7 +46,7 @@ export class MessageForwardInfo {
* For "saved" messages (i.e. messages forwarded to yourself,
* "Saved Messages"), the peer where the message was originally sent
*/
fromChat(): User | Chat | null {
fromChat(): Chat | null {
if (!this.raw.savedFromPeer) return null
return Chat._parseFromPeer(this.raw.savedFromPeer, this._peers)

View file

@ -2,9 +2,8 @@ import { getMarkedPeerId, tl } from '@mtcute/core'
import { makeInspectable } from '../../utils/inspectable.js'
import { memoizeGetters } from '../../utils/memoize.js'
import { Chat } from '../peers/chat.js'
import { parsePeer, Peer } from '../peers/peer.js'
import { PeersIndex } from '../peers/peers-index.js'
import { User } from '../peers/user.js'
/**
* Information about replies to a message
@ -65,19 +64,8 @@ export class MessageRepliesInfo {
/**
* Last few commenters to the post (usually 3)
*/
get repliers(): (User | Chat)[] {
return (
this.raw.recentRepliers?.map((it) => {
switch (it._) {
case 'peerUser':
return new User(this._peers.user(it.userId))
case 'peerChannel':
return new Chat(this._peers.chat(it.channelId))
default:
throw new Error('Unexpected peer type: ' + it._)
}
}) ?? []
)
get repliers(): Peer[] {
return this.raw.recentRepliers?.map((it) => parsePeer(it, this._peers)) ?? []
}
}

View file

@ -1,11 +1,4 @@
import {
assertNever,
getMarkedPeerId,
MtArgumentError,
MtTypeAssertionError,
tl,
toggleChannelIdMark,
} from '@mtcute/core'
import { assertNever, getMarkedPeerId, MtArgumentError, tl, toggleChannelIdMark } from '@mtcute/core'
import { assertTypeIsNot } from '@mtcute/core/utils.js'
import { makeInspectable } from '../../utils/index.js'
@ -13,6 +6,7 @@ import { memoizeGetters } from '../../utils/memoize.js'
import { BotKeyboard, ReplyMarkup } from '../bots/keyboards.js'
import { TextWithEntities } from '../misc/index.js'
import { Chat } from '../peers/chat.js'
import { parsePeer, Peer } from '../peers/peer.js'
import { PeersIndex } from '../peers/peers-index.js'
import { User } from '../peers/user.js'
import { _messageActionFromTl, MessageAction } from './message-action.js'
@ -114,7 +108,7 @@ export class Message {
* If the message is a forwarded channel post,
* sender is the channel itself.
*/
get sender(): User | Chat {
get sender(): Peer {
const from = this.raw.fromId
if (!from) {
@ -125,14 +119,8 @@ export class Message {
// anon admin, return the chat
return this.chat
}
switch (from._) {
case 'peerChannel': // forwarded channel post or anon
return new Chat(this._peers.chat(from.channelId))
case 'peerUser':
return new User(this._peers.user(from.userId))
default:
throw new MtTypeAssertionError('raw.fromId', 'peerUser | peerChannel', from._)
}
return parsePeer(from, this._peers)
}
/**

View file

@ -3,6 +3,7 @@ import { MtTypeAssertionError, tl } from '@mtcute/core'
import { makeInspectable } from '../../utils/inspectable.js'
import { memoizeGetters } from '../../utils/memoize.js'
import { Chat } from '../peers/chat.js'
import { PeerSender } from '../peers/peer.js'
import { PeersIndex } from '../peers/peers-index.js'
import { User } from '../peers/user.js'
import { MessageEntity } from './message-entity.js'
@ -27,12 +28,12 @@ export interface _RepliedMessageAssertionsByOrigin {
other_chat: {
id: number
chat: Chat
sender: User | Chat | string
sender: PeerSender
}
private: {
id: null
chat: null
sender: User | Chat | string
sender: PeerSender
}
}
@ -90,7 +91,7 @@ export class RepliedMessageInfo {
}
}
return true
return false
}
/**
@ -128,12 +129,15 @@ export class RepliedMessageInfo {
*
* `null` if the sender is not available (for `same_chat` origin)
*/
get sender(): User | Chat | string | null {
get sender(): PeerSender | null {
const { replyFrom, replyToPeerId } = this.raw
if (!replyFrom && !replyToPeerId) return null
if (replyFrom?.fromName) {
return replyFrom.fromName
return {
type: 'anonymous',
displayName: replyFrom.fromName,
}
}
const peer = replyFrom?.fromId ?? replyToPeerId

View file

@ -1,12 +1,11 @@
import { MtTypeAssertionError, tl } from '@mtcute/core'
import { tl } from '@mtcute/core'
import { hasValueAtKey, makeInspectable } from '../../utils/index.js'
import { memoizeGetters } from '../../utils/memoize.js'
import { MtMessageNotFoundError } from '../errors.js'
import { DraftMessage, Message } from '../messages/index.js'
import { Chat } from './chat.js'
import { parsePeer, Peer } from './peer.js'
import { PeersIndex } from './peers-index.js'
import { User } from './user.js'
export class ForumTopic {
static COLOR_BLUE = 0x6fb9f0
@ -108,15 +107,8 @@ export class ForumTopic {
/**
* Creator of the topic
*/
get creator(): User | Chat {
switch (this.raw.fromId._) {
case 'peerUser':
return new User(this._peers.user(this.raw.fromId.userId))
case 'peerChat':
return new Chat(this._peers.chat(this.raw.fromId.chatId))
default:
throw new MtTypeAssertionError('ForumTopic#creator', 'peerUser | peerChat', this.raw.fromId._)
}
get creator(): Peer {
return parsePeer(this.raw.fromId, this._peers)
}
/**

View file

@ -1,5 +1,3 @@
import { tl } from '@mtcute/core'
export * from './chat.js'
export * from './chat-event/index.js'
export * from './chat-invite-link.js'
@ -10,33 +8,7 @@ export * from './chat-permissions.js'
export * from './chat-photo.js'
export * from './chat-preview.js'
export * from './forum-topic.js'
export * from './peer.js'
export * from './peers-index.js'
export * from './typing-status.js'
export * from './user.js'
/**
* More extensive peer types, that differentiate between
* users and bots, channels and supergroups.
*/
export type PeerType = 'user' | 'bot' | 'group' | 'channel' | 'supergroup'
/**
* Type that can be used as an input peer to most of the high-level methods. Can be:
* - `number`, representing peer's marked ID*
* - `string`, representing peer's username (without preceding `@`)
* - `string`, representing user's phone number
* - `"me"` and `"self"` which will be replaced with the current user/bot
* - Any object with `inputPeer: tl.TypeInputPeer` property
* - Raw TL object
*
* > * Telegram has moved to int64 IDs. Though, Levin [has confirmed](https://t.me/tdlibchat/25071)
* > that new IDs *will* still fit into int53, meaning JS integers are fine.
*/
export type InputPeerLike =
| string
| number
| tl.TypePeer
| tl.TypeInputPeer
| tl.TypeInputUser
| tl.TypeInputChannel
| { inputPeer: tl.TypeInputPeer }

View file

@ -0,0 +1,71 @@
import { tl } from '@mtcute/core'
import { Chat } from './chat.js'
import { PeersIndex } from './peers-index.js'
import { User } from './user.js'
/**
* More extensive peer types, that differentiate between
* users and bots, channels and supergroups.
*/
export type PeerType = 'user' | 'bot' | 'group' | 'channel' | 'supergroup'
/**
* Type that can be used as an input peer to most of the high-level methods. Can be:
* - `number`, representing peer's marked ID*
* - `string`, representing peer's username (without preceding `@`)
* - `string`, representing user's phone number
* - `"me"` and `"self"` which will be replaced with the current user/bot
* - Any object with `inputPeer: tl.TypeInputPeer` property
* - Raw TL object
*
* > * Telegram has moved to int64 IDs. Though, Levin [has confirmed](https://t.me/tdlibchat/25071)
* > that new IDs *will* still fit into int53, meaning JS integers are fine.
*/
export type InputPeerLike =
| string
| number
| tl.TypePeer
| tl.TypeInputPeer
| tl.TypeInputUser
| tl.TypeInputChannel
| { inputPeer: tl.TypeInputPeer }
/**
* Peer (a user or a chat)
*
* Type of the peer can be determined by the `.type` property
*/
export type Peer = User | Chat
/**
* An object representing an anonymous sender (e.g. for users that have forwards hidden)
*/
export interface AnonymousSender {
readonly type: 'anonymous'
/**
* Name of the anonymous sender that should be displayed
*/
readonly displayName: string
}
/**
* Object representing a sender of a forwarded message,
* which can be either a {@link Peer} or an {@link AnonymousSender}
*/
export type PeerSender = Peer | AnonymousSender
/**
* Given a `tl.TypePeer`, return a {@link Peer} object ({@link User} or {@link Chat})
*/
export function parsePeer(peer: tl.TypePeer, index: PeersIndex): Peer {
switch (peer._) {
case 'peerUser':
return new User(index.user(peer.userId))
case 'peerChat':
return new Chat(index.chat(peer.chatId))
case 'peerChannel':
return new Chat(index.chat(peer.channelId))
}
}

View file

@ -2,7 +2,7 @@ import { tl } from '@mtcute/core'
import { assertTypeIs, makeInspectable } from '../../utils/index.js'
import { memoizeGetters } from '../../utils/memoize.js'
import { Chat, PeersIndex, User } from '../peers/index.js'
import { parsePeer, Peer, PeersIndex } from '../peers/index.js'
import { Story } from './story.js'
export class PeerStories {
@ -14,15 +14,8 @@ export class PeerStories {
/**
* Peer that owns these stories.
*/
get peer(): User | Chat {
switch (this.raw.peer._) {
case 'peerUser':
return new User(this._peers.user(this.raw.peer.userId))
case 'peerChat':
return new Chat(this._peers.chat(this.raw.peer.chatId))
case 'peerChannel':
return new Chat(this._peers.chat(this.raw.peer.channelId))
}
get peer(): Peer {
return parsePeer(this.raw.peer, this._peers)
}
/**

View file

@ -1,6 +1,6 @@
import { tl } from '@mtcute/core'
import { Chat, PeersIndex, User } from '../../types/peers/index.js'
import { parsePeer, Peer, PeersIndex } from '../../types/peers/index.js'
import { makeInspectable } from '../../utils/index.js'
import { memoizeGetters } from '../../utils/memoize.js'
@ -16,15 +16,8 @@ export class DeleteStoryUpdate {
/**
* Peer that owns these stories.
*/
get peer(): User | Chat {
switch (this.raw.peer._) {
case 'peerUser':
return new User(this._peers.user(this.raw.peer.userId))
case 'peerChat':
return new Chat(this._peers.chat(this.raw.peer.chatId))
case 'peerChannel':
return new Chat(this._peers.chat(this.raw.peer.channelId))
}
get peer(): Peer {
return parsePeer(this.raw.peer, this._peers)
}
/**

View file

@ -1,9 +1,8 @@
import { MtUnsupportedError, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils.js'
import { makeInspectable } from '../../utils/index.js'
import { memoizeGetters } from '../../utils/memoize.js'
import { Chat, PeersIndex, User } from '../peers/index.js'
import { parsePeer, Peer, PeersIndex } from '../peers/index.js'
/**
* Some user has voted in a public poll.
@ -27,14 +26,8 @@ export class PollVoteUpdate {
/**
* Peer who has voted
*/
get peer(): User | Chat {
if (this.raw.peer._ === 'peerUser') {
return new User(this._peers.user(this.raw.peer.userId))
}
assertTypeIs('PollVoteUpdate.peer', this.raw.peer, 'peerChannel')
return new Chat(this._peers.chat(this.raw.peer.channelId))
get peer(): Peer {
return parsePeer(this.raw.peer, this._peers)
}
/**

View file

@ -1,6 +1,6 @@
import { tl } from '@mtcute/core'
import { Chat, PeersIndex, User } from '../../types/peers/index.js'
import { parsePeer, Peer, PeersIndex } from '../../types/peers/index.js'
import { Story } from '../../types/stories/index.js'
import { assertTypeIs, makeInspectable } from '../../utils/index.js'
import { memoizeGetters } from '../../utils/memoize.js'
@ -20,15 +20,8 @@ export class StoryUpdate {
/**
* Peer that owns these stories.
*/
get peer(): User | Chat {
switch (this.raw.peer._) {
case 'peerUser':
return new User(this._peers.user(this.raw.peer.userId))
case 'peerChat':
return new Chat(this._peers.chat(this.raw.peer.chatId))
case 'peerChannel':
return new Chat(this._peers.chat(this.raw.peer.channelId))
}
get peer(): Peer {
return parsePeer(this.raw.peer, this._peers)
}
/**

View file

@ -1,12 +1,4 @@
import {
Chat,
Message,
MtPeerNotFoundError,
OmitInputMessageId,
ParametersSkip1,
TelegramClient,
User,
} from '@mtcute/client'
import { Message, MtPeerNotFoundError, OmitInputMessageId, ParametersSkip1, Peer, TelegramClient } from '@mtcute/client'
import { DeleteMessagesParams } from '@mtcute/client/src/methods/messages/delete-messages.js'
import { ForwardMessageOptions } from '@mtcute/client/src/methods/messages/forward-messages.js'
import { SendCopyParams } from '@mtcute/client/src/methods/messages/send-copy.js'
@ -53,7 +45,7 @@ export class MessageContext extends Message implements UpdateContext<Message> {
*
* Learn more: [Incomplete peers](https://mtcute.dev/guide/topics/peers.html#incomplete-peers)
*/
async getSender(): Promise<User | Chat> {
async getCompleteSender(): Promise<Peer> {
if (!this.sender.isMin) return this.sender
let res

View file

@ -2,11 +2,11 @@
// ^^ will be looked into in MTQ-29
import {
_RepliedMessageAssertionsByOrigin,
Chat,
MaybeArray,
Message,
MessageAction,
MessageMediaType,
Peer,
RawDocument,
RawLocation,
RepliedMessageInfo,
@ -208,7 +208,7 @@ export const action = <T extends Exclude<MessageAction, null>['type']>(
action: Extract<MessageAction, { type: T }>
sender: T extends 'user_joined_link' | 'user_removed' | 'history_cleared' | 'contact_joined' | 'bot_allowed'
? User
: User | Chat
: Peer
}
> => {
if (Array.isArray(type)) {
@ -261,7 +261,7 @@ export const withCompleteSender =
): UpdateFilter<MessageContext, Mod, State> =>
async (msg, state) => {
try {
await msg.getSender()
await msg.getCompleteSender()
} catch (e) {
return false
}

View file

@ -1,4 +1,4 @@
import { assertNever, Chat, MaybeAsync, User } from '@mtcute/client'
import { assertNever, MaybeAsync, Peer } from '@mtcute/client'
import { CallbackQueryContext, MessageContext } from '../context/index.js'
@ -10,7 +10,7 @@ import { CallbackQueryContext, MessageContext } from '../context/index.js'
* @param msg Message or callback from which to derive the key
* @param scene Current scene UID, or `null` if none
*/
export type StateKeyDelegate = (upd: MessageContext | CallbackQueryContext | User | Chat) => MaybeAsync<string | null>
export type StateKeyDelegate = (upd: MessageContext | CallbackQueryContext | Peer) => MaybeAsync<string | null>
/**
* Default state key delegate.