feat: accept high-level objects as inputs to methods
This commit is contained in:
parent
a03d73503a
commit
e01c876690
45 changed files with 734 additions and 1233 deletions
File diff suppressed because it is too large
Load diff
|
@ -42,6 +42,7 @@ import {
|
|||
InputFileLike,
|
||||
InputInlineResult,
|
||||
InputMediaLike,
|
||||
InputMessageId,
|
||||
InputPeerLike,
|
||||
InputPrivacyRule,
|
||||
InputReaction,
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import { BaseTelegramClient, Long } from '@mtcute/core'
|
||||
|
||||
import { CallbackQuery } from '../../types/bots/callback-query'
|
||||
|
||||
/**
|
||||
* Send an answer to a callback query.
|
||||
*
|
||||
* @param queryId ID of the callback query
|
||||
* @param queryId ID of the callback query, or the query itself
|
||||
* @param params Parameters of the answer
|
||||
*/
|
||||
export async function answerCallbackQuery(
|
||||
client: BaseTelegramClient,
|
||||
queryId: Long,
|
||||
queryId: Long | CallbackQuery,
|
||||
params?: {
|
||||
/**
|
||||
* Maximum amount of time in seconds for which
|
||||
|
@ -49,7 +51,7 @@ export async function answerCallbackQuery(
|
|||
|
||||
await client.call({
|
||||
_: 'messages.setBotCallbackAnswer',
|
||||
queryId,
|
||||
queryId: Long.isLong(queryId) ? queryId : queryId.id,
|
||||
cacheTime,
|
||||
alert,
|
||||
message: text,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
import { BaseTelegramClient, Long, tl } from '@mtcute/core'
|
||||
|
||||
import { BotInline, InputInlineResult } from '../../types'
|
||||
import { BotInline, InlineQuery, InputInlineResult } from '../../types/bots'
|
||||
|
||||
/**
|
||||
* Answer an inline query.
|
||||
|
@ -11,7 +11,7 @@ import { BotInline, InputInlineResult } from '../../types'
|
|||
*/
|
||||
export async function answerInlineQuery(
|
||||
client: BaseTelegramClient,
|
||||
queryId: tl.Long,
|
||||
queryId: tl.Long | InlineQuery,
|
||||
results: InputInlineResult[],
|
||||
params?: {
|
||||
/**
|
||||
|
@ -99,7 +99,7 @@ export async function answerInlineQuery(
|
|||
|
||||
await client.call({
|
||||
_: 'messages.setInlineBotResults',
|
||||
queryId,
|
||||
queryId: Long.isLong(queryId) ? queryId : queryId.id,
|
||||
results: tlResults,
|
||||
cacheTime,
|
||||
gallery: gallery ?? defaultGallery,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
import { BaseTelegramClient, Long, tl } from '@mtcute/core'
|
||||
|
||||
import { PreCheckoutQuery } from '../../types/updates'
|
||||
|
||||
/**
|
||||
* Answer a pre-checkout query.
|
||||
|
@ -7,7 +9,7 @@ import { BaseTelegramClient, tl } from '@mtcute/core'
|
|||
*/
|
||||
export async function answerPreCheckoutQuery(
|
||||
client: BaseTelegramClient,
|
||||
queryId: tl.Long,
|
||||
queryId: tl.Long | PreCheckoutQuery,
|
||||
params?: {
|
||||
/** If pre-checkout is rejected, error message to show to the user */
|
||||
error?: string
|
||||
|
@ -17,7 +19,7 @@ export async function answerPreCheckoutQuery(
|
|||
|
||||
await client.call({
|
||||
_: 'messages.setBotPrecheckoutResults',
|
||||
queryId,
|
||||
queryId: Long.isLong(queryId) ? queryId : queryId.queryId,
|
||||
success: !error,
|
||||
error,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
|
||||
import { GameHighScore, InputPeerLike, PeersIndex } from '../../types'
|
||||
import { GameHighScore, InputMessageId, InputPeerLike, normalizeInputMessageId, PeersIndex } from '../../types'
|
||||
import { normalizeInlineId } from '../../utils/inline-utils'
|
||||
import { normalizeToInputUser } from '../../utils/peer-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
@ -10,18 +10,13 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
*/
|
||||
export async function getGameHighScores(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** ID of the chat where the game was found */
|
||||
chatId: InputPeerLike
|
||||
|
||||
/** ID of the message containing the game */
|
||||
message: number
|
||||
|
||||
params: InputMessageId & {
|
||||
/** ID of the user to find high scores for */
|
||||
userId?: InputPeerLike
|
||||
},
|
||||
): Promise<GameHighScore[]> {
|
||||
const { chatId, message, userId } = params
|
||||
const { userId } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const chat = await resolvePeer(client, chatId)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike, Message } from '../../types'
|
||||
import { InputMessageId, InputPeerLike, Message, normalizeInputMessageId } from '../../types'
|
||||
import { normalizeInlineId } from '../../utils/inline-utils'
|
||||
import { normalizeToInputUser } from '../../utils/peer-utils'
|
||||
import { _findMessageInUpdate } from '../messages/find-in-update'
|
||||
|
@ -14,13 +14,7 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
*/
|
||||
export async function setGameScore(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Chat where the game was found */
|
||||
chatId: InputPeerLike
|
||||
|
||||
/** ID of the message where the game was found */
|
||||
message: number
|
||||
|
||||
params: InputMessageId & {
|
||||
/** ID of the user who has scored */
|
||||
userId: InputPeerLike
|
||||
|
||||
|
@ -40,7 +34,8 @@ export async function setGameScore(
|
|||
force?: boolean
|
||||
},
|
||||
): Promise<Message> {
|
||||
const { chatId, message, userId, score, noEdit, force } = params
|
||||
const { userId, score, noEdit, force } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const user = normalizeToInputUser(await resolvePeer(client, userId), userId)
|
||||
const chat = await resolvePeer(client, chatId)
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from '../../utils/peer-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
// @available=both
|
||||
/**
|
||||
* Get basic information about a chat.
|
||||
*
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from '../../utils/peer-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
// @available=both
|
||||
/**
|
||||
* Get full information about a chat.
|
||||
*
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
import { assertTypeIsNot } from '@mtcute/core/utils'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import type { ForumTopic, InputPeerLike } from '../../types'
|
||||
import { normalizeToInputChannel } from '../../utils/peer-utils'
|
||||
import { createDummyUpdate } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
@ -15,7 +15,7 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
export async function deleteForumTopicHistory(
|
||||
client: BaseTelegramClient,
|
||||
chat: InputPeerLike,
|
||||
topicId: number,
|
||||
topicId: number | ForumTopic,
|
||||
): Promise<void> {
|
||||
const channel = normalizeToInputChannel(await resolvePeer(client, chat), chat)
|
||||
assertTypeIsNot('deleteForumTopicHistory', channel, 'inputChannelEmpty')
|
||||
|
@ -23,7 +23,7 @@ export async function deleteForumTopicHistory(
|
|||
const res = await client.call({
|
||||
_: 'channels.deleteTopicHistory',
|
||||
channel,
|
||||
topMsgId: topicId,
|
||||
topMsgId: typeof topicId === 'number' ? topicId : topicId.id,
|
||||
})
|
||||
|
||||
client.network.handleUpdate(createDummyUpdate(res.pts, res.ptsCount, channel.channelId))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient, Long, tl } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike, Message } from '../../types'
|
||||
import type { ForumTopic, InputPeerLike, Message } from '../../types'
|
||||
import { normalizeToInputChannel } from '../../utils/peer-utils'
|
||||
import { _findMessageInUpdate } from '../messages/find-in-update'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
@ -19,9 +19,10 @@ export async function editForumTopic(
|
|||
params: {
|
||||
/** Chat ID or username */
|
||||
chatId: InputPeerLike
|
||||
/** ID of the topic (i.e. its top message ID) */
|
||||
|
||||
topicId: number
|
||||
/** ID of the topic (i.e. its top message ID) */
|
||||
topicId: number | ForumTopic
|
||||
|
||||
/**
|
||||
* New topic title
|
||||
*/
|
||||
|
@ -41,7 +42,7 @@ export async function editForumTopic(
|
|||
const res = await client.call({
|
||||
_: 'channels.editForumTopic',
|
||||
channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
|
||||
topicId,
|
||||
topicId: typeof topicId === 'number' ? topicId : topicId.id,
|
||||
title,
|
||||
iconEmojiId: icon ? icon ?? Long.ZERO : undefined,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import type { ForumTopic, InputPeerLike } from '../../types'
|
||||
import { normalizeToInputChannel } from '../../utils/peer-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
|
@ -18,7 +18,7 @@ export async function reorderPinnedForumTopics(
|
|||
/**
|
||||
* Order of the pinned topics
|
||||
*/
|
||||
order: number[]
|
||||
order: (number | ForumTopic)[]
|
||||
|
||||
/**
|
||||
* Whether to un-pin topics not present in the order
|
||||
|
@ -30,7 +30,7 @@ export async function reorderPinnedForumTopics(
|
|||
await client.call({
|
||||
_: 'channels.reorderPinnedForumTopics',
|
||||
channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
|
||||
order,
|
||||
order: order.map((it) => (typeof it === 'number' ? it : it.id)),
|
||||
force,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike, Message } from '../../types'
|
||||
import type { ForumTopic, InputPeerLike, Message } from '../../types'
|
||||
import { normalizeToInputChannel } from '../../utils/peer-utils'
|
||||
import { _findMessageInUpdate } from '../messages/find-in-update'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
@ -19,7 +19,7 @@ export async function toggleForumTopicClosed(
|
|||
chatId: InputPeerLike
|
||||
|
||||
/** ID of the topic (i.e. its top message ID) */
|
||||
topicId: number
|
||||
topicId: number | ForumTopic
|
||||
|
||||
/** Whether the topic should be closed */
|
||||
closed: boolean
|
||||
|
@ -30,7 +30,7 @@ export async function toggleForumTopicClosed(
|
|||
const res = await client.call({
|
||||
_: 'channels.editForumTopic',
|
||||
channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
|
||||
topicId,
|
||||
topicId: typeof topicId === 'number' ? topicId : topicId.id,
|
||||
closed,
|
||||
})
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import { ForumTopic, InputPeerLike } from '../../types'
|
||||
import { normalizeToInputChannel } from '../../utils/peer-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
|
@ -15,7 +15,7 @@ export async function toggleForumTopicPinned(
|
|||
/** Chat ID or username */
|
||||
chatId: InputPeerLike
|
||||
/** ID of the topic (i.e. its top message ID) */
|
||||
topicId: number
|
||||
topicId: number | ForumTopic
|
||||
/** Whether the topic should be pinned */
|
||||
pinned: boolean
|
||||
},
|
||||
|
@ -25,7 +25,7 @@ export async function toggleForumTopicPinned(
|
|||
await client.call({
|
||||
_: 'channels.updatePinnedForumTopic',
|
||||
channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
|
||||
topicId,
|
||||
topicId: typeof topicId === 'number' ? topicId : topicId.id,
|
||||
pinned,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export async function editInviteLink(
|
|||
/** Chat ID */
|
||||
chatId: InputPeerLike
|
||||
/** Invite link to edit */
|
||||
link: string
|
||||
link: string | ChatInviteLink
|
||||
/**
|
||||
* Date when this link will expire.
|
||||
* If `number` is passed, UNIX time in ms is expected.
|
||||
|
@ -48,7 +48,7 @@ export async function editInviteLink(
|
|||
const res = await client.call({
|
||||
_: 'messages.editExportedChatInvite',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
link,
|
||||
link: typeof link === 'string' ? link : link.link,
|
||||
expireDate: normalizeDate(expires),
|
||||
usageLimit,
|
||||
requestNeeded: withApproval,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
|
||||
import { ArrayPaginated, ChatInviteLinkMember, InputPeerLike, PeersIndex } from '../../types'
|
||||
import { ArrayPaginated, ChatInviteLink, ChatInviteLinkMember, InputPeerLike, PeersIndex } from '../../types'
|
||||
import { makeArrayPaginated, normalizeDate, normalizeToInputUser } from '../../utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
|
@ -18,7 +18,7 @@ export async function getInviteLinkMembers(
|
|||
/**
|
||||
* Invite link for which to get members
|
||||
*/
|
||||
link?: string
|
||||
link?: string | ChatInviteLink
|
||||
|
||||
/**
|
||||
* Maximum number of users to return
|
||||
|
@ -65,7 +65,7 @@ export async function getInviteLinkMembers(
|
|||
_: 'messages.getChatInviteImporters',
|
||||
limit,
|
||||
peer,
|
||||
link,
|
||||
link: typeof link === 'string' ? link : link?.link,
|
||||
requested,
|
||||
q: requestedSearch,
|
||||
offsetDate,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import type { ChatInviteLink, InputPeerLike } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,7 @@ export async function hideAllJoinRequests(
|
|||
action: 'approve' | 'deny'
|
||||
|
||||
/** Invite link to target */
|
||||
link?: string
|
||||
link?: string | ChatInviteLink
|
||||
},
|
||||
): Promise<void> {
|
||||
const { chatId, action, link } = params
|
||||
|
@ -25,6 +25,6 @@ export async function hideAllJoinRequests(
|
|||
_: 'messages.hideAllChatJoinRequests',
|
||||
approved: action === 'approve',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
link,
|
||||
link: typeof link === 'string' ? link : link?.link,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
export async function revokeInviteLink(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
link: string,
|
||||
link: string | ChatInviteLink,
|
||||
): Promise<ChatInviteLink> {
|
||||
const res = await client.call({
|
||||
_: 'messages.editExportedChatInvite',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
link,
|
||||
link: typeof link === 'string' ? link : link.link,
|
||||
revoked: true,
|
||||
})
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseTelegramClient, Long, MtTypeAssertionError } from '@mtcute/core'
|
||||
import { assertTypeIs } from '@mtcute/core/utils'
|
||||
|
||||
import { InputPeerLike, PeersIndex, Poll } from '../../types'
|
||||
import { InputMessageId, normalizeInputMessageId, PeersIndex, Poll } from '../../types'
|
||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
|
@ -11,16 +11,8 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
* Once closed, poll can't be re-opened, and nobody
|
||||
* will be able to vote in it
|
||||
*/
|
||||
export async function closePoll(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Chat ID where this poll was found */
|
||||
chatId: InputPeerLike
|
||||
/** Message ID where this poll was found */
|
||||
message: number
|
||||
},
|
||||
): Promise<Poll> {
|
||||
const { chatId, message } = params
|
||||
export async function closePoll(client: BaseTelegramClient, params: InputMessageId): Promise<Poll> {
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.editMessage',
|
||||
|
|
|
@ -1,34 +1,36 @@
|
|||
import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
|
||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import { InputPeerLike, Message } from '../../types'
|
||||
import { isInputPeerChannel, normalizeToInputChannel } from '../../utils/peer-utils'
|
||||
import { createDummyUpdate } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
import { deleteScheduledMessages } from './delete-scheduled-messages'
|
||||
|
||||
// @exported
|
||||
export interface DeleteMessagesParams {
|
||||
/**
|
||||
* Whether to "revoke" (i.e. delete for both sides).
|
||||
* Only used for chats and private chats.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
revoke?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete messages, including service messages.
|
||||
* Delete messages by their IDs
|
||||
*
|
||||
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`.
|
||||
* @param ids Message(s) ID(s) to delete.
|
||||
*/
|
||||
export async function deleteMessages(
|
||||
export async function deleteMessagesById(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
ids: MaybeArray<number>,
|
||||
params?: {
|
||||
/**
|
||||
* Whether to "revoke" (i.e. delete for both sides).
|
||||
* Only used for chats and private chats.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
revoke?: boolean
|
||||
},
|
||||
ids: number[],
|
||||
params?: DeleteMessagesParams,
|
||||
): Promise<void> {
|
||||
const { revoke = true } = params ?? {}
|
||||
|
||||
if (!Array.isArray(ids)) ids = [ids]
|
||||
|
||||
const peer = await resolvePeer(client, chatId)
|
||||
|
||||
let upd
|
||||
|
@ -52,3 +54,38 @@ export async function deleteMessages(
|
|||
|
||||
client.network.handleUpdate(upd)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one or more {@link Message}
|
||||
*
|
||||
* @param messages Message(s) to delete
|
||||
*/
|
||||
export async function deleteMessages(
|
||||
client: BaseTelegramClient,
|
||||
messages: Message[],
|
||||
params?: DeleteMessagesParams,
|
||||
): Promise<void> {
|
||||
if (messages.length === 1) {
|
||||
return deleteMessagesById(client, messages[0].chat.inputPeer, [messages[0].id], params)
|
||||
}
|
||||
|
||||
const byChat = new Map<number, [tl.TypeInputPeer, number[]]>()
|
||||
const byChatScheduled = new Map<number, [tl.TypeInputPeer, number[]]>()
|
||||
|
||||
for (const msg of messages) {
|
||||
const map = msg.isScheduled ? byChatScheduled : byChat
|
||||
|
||||
if (!map.has(msg.chat.id)) {
|
||||
map.set(msg.chat.id, [msg.chat.inputPeer, []])
|
||||
}
|
||||
map.get(msg.chat.id)![1].push(msg.id)
|
||||
}
|
||||
|
||||
for (const [peer, ids] of byChat.values()) {
|
||||
await deleteMessagesById(client, peer, ids, params)
|
||||
}
|
||||
|
||||
for (const [peer, ids] of byChatScheduled.values()) {
|
||||
await deleteScheduledMessages(client, peer, ids)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
|
||||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Delete scheduled messages.
|
||||
* Delete scheduled messages by their IDs.
|
||||
*
|
||||
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`.
|
||||
* @param ids Message(s) ID(s) to delete.
|
||||
|
@ -12,10 +12,8 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
export async function deleteScheduledMessages(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
ids: MaybeArray<number>,
|
||||
ids: number[],
|
||||
): Promise<void> {
|
||||
if (!Array.isArray(ids)) ids = [ids]
|
||||
|
||||
const peer = await resolvePeer(client, chatId)
|
||||
|
||||
const res = await client.call({
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
|
||||
import { BotKeyboard, FormattedString, InputMediaLike, InputPeerLike, Message, ReplyMarkup } from '../../types'
|
||||
import {
|
||||
BotKeyboard,
|
||||
FormattedString,
|
||||
InputMediaLike,
|
||||
InputMessageId,
|
||||
Message,
|
||||
normalizeInputMessageId,
|
||||
ReplyMarkup,
|
||||
} from '../../types'
|
||||
import { _normalizeInputMedia } from '../files/normalize-input-media'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
import { _findMessageInUpdate } from './find-in-update'
|
||||
|
@ -15,12 +23,7 @@ import { _parseEntities } from './parse-entities'
|
|||
*/
|
||||
export async function editMessage(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Chat ID */
|
||||
chatId: InputPeerLike
|
||||
/** Message to edit */
|
||||
message: number | Message
|
||||
|
||||
params: InputMessageId & {
|
||||
/**
|
||||
* New message text
|
||||
*
|
||||
|
@ -77,7 +80,7 @@ export async function editMessage(
|
|||
progressCallback?: (uploaded: number, total: number) => void
|
||||
},
|
||||
): Promise<Message> {
|
||||
const { chatId, message } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
let content: string | undefined = undefined
|
||||
let entities: tl.TypeMessageEntity[] | undefined
|
||||
let media: tl.TypeInputMedia | undefined = undefined
|
||||
|
@ -103,7 +106,7 @@ export async function editMessage(
|
|||
|
||||
const res = await client.call({
|
||||
_: 'messages.editMessage',
|
||||
id: typeof message === 'number' ? message : message.id,
|
||||
id: message,
|
||||
peer: await resolvePeer(client, chatId),
|
||||
noWebpage: params.disableWebPreview,
|
||||
replyMarkup: BotKeyboard._convertToTl(params.replyMarkup),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BaseTelegramClient, MaybeArray, MtArgumentError, tl } from '@mtcute/core'
|
||||
import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
|
||||
import { randomLong } from '@mtcute/core/utils'
|
||||
|
||||
import { FormattedString, InputMediaLike, InputPeerLike, Message, PeersIndex } from '../../types'
|
||||
|
@ -6,103 +6,93 @@ import { normalizeDate } from '../../utils/misc-utils'
|
|||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Forward a single message.
|
||||
*
|
||||
* To forward with a caption, use another overload that takes an array of IDs.
|
||||
*
|
||||
* @param message Message ID
|
||||
* @param params Additional sending parameters
|
||||
* @returns Newly sent, forwarded messages in the destination chat
|
||||
*/
|
||||
export async function forwardMessages(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Source chat ID, username, phone, `"me"` or `"self"` */
|
||||
fromChatId: InputPeerLike
|
||||
/** Destination chat ID, username, phone, `"me"` or `"self"` */
|
||||
toChatId: InputPeerLike
|
||||
/** Message ID */
|
||||
messages: number
|
||||
// @exported
|
||||
export interface ForwardMessageOptions {
|
||||
/** Destination chat ID, username, phone, `"me"` or `"self"` */
|
||||
toChatId: InputPeerLike
|
||||
|
||||
/**
|
||||
* Optionally, a caption for your forwarded message(s).
|
||||
* It will be sent as a separate message before the forwarded messages.
|
||||
*
|
||||
* You can either pass `caption` or `captionMedia`, passing both will
|
||||
* result in an error
|
||||
*/
|
||||
caption?: string | FormattedString<string>
|
||||
/**
|
||||
* Optionally, a caption for your forwarded message(s).
|
||||
* It will be sent as a separate message before the forwarded messages.
|
||||
*
|
||||
* You can either pass `caption` or `captionMedia`, passing both will
|
||||
* result in an error
|
||||
*/
|
||||
caption?: string | FormattedString<string>
|
||||
|
||||
/**
|
||||
* Optionally, a media caption for your forwarded message(s).
|
||||
* It will be sent as a separate message before the forwarded messages.
|
||||
*
|
||||
* You can either pass `caption` or `captionMedia`, passing both will
|
||||
* result in an error
|
||||
*/
|
||||
captionMedia?: InputMediaLike
|
||||
/**
|
||||
* Optionally, a media caption for your forwarded message(s).
|
||||
* It will be sent as a separate message before the forwarded messages.
|
||||
*
|
||||
* You can either pass `caption` or `captionMedia`, passing both will
|
||||
* result in an error
|
||||
*/
|
||||
captionMedia?: InputMediaLike
|
||||
|
||||
/**
|
||||
* Parse mode to use to parse entities in caption.
|
||||
* Defaults to current default parse mode (if any).
|
||||
*
|
||||
* Passing `null` will explicitly disable formatting.
|
||||
*/
|
||||
parseMode?: string | null
|
||||
/**
|
||||
* Parse mode to use to parse entities in caption.
|
||||
* Defaults to current default parse mode (if any).
|
||||
*
|
||||
* Passing `null` will explicitly disable formatting.
|
||||
*/
|
||||
parseMode?: string | null
|
||||
|
||||
/**
|
||||
* List of formatting entities in caption to use instead
|
||||
* of parsing via a parse mode.
|
||||
*
|
||||
* **Note:** Passing this makes the method ignore {@link parseMode}
|
||||
*/
|
||||
entities?: tl.TypeMessageEntity[]
|
||||
/**
|
||||
* List of formatting entities in caption to use instead
|
||||
* of parsing via a parse mode.
|
||||
*
|
||||
* **Note:** Passing this makes the method ignore {@link parseMode}
|
||||
*/
|
||||
entities?: tl.TypeMessageEntity[]
|
||||
|
||||
/**
|
||||
* Whether to forward silently (also applies to caption message).
|
||||
*/
|
||||
silent?: boolean
|
||||
/**
|
||||
* Whether to forward silently (also applies to caption message).
|
||||
*/
|
||||
silent?: boolean
|
||||
|
||||
/**
|
||||
* If set, the forwarding will be scheduled to this date
|
||||
* (also applies to caption message).
|
||||
* When passing a number, a UNIX time in ms is expected.
|
||||
*
|
||||
* You can also pass `0x7FFFFFFE`, this will send the message
|
||||
* once the peer is online
|
||||
*/
|
||||
schedule?: Date | number
|
||||
/**
|
||||
* If set, the forwarding will be scheduled to this date
|
||||
* (also applies to caption message).
|
||||
* When passing a number, a UNIX time in ms is expected.
|
||||
*
|
||||
* You can also pass `0x7FFFFFFE`, this will send the message
|
||||
* once the peer is online
|
||||
*/
|
||||
schedule?: Date | number
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message (only used for caption)
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
/**
|
||||
* Whether to clear draft after sending this message (only used for caption)
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
|
||||
/**
|
||||
* Whether to forward without author
|
||||
*/
|
||||
noAuthor?: boolean
|
||||
/**
|
||||
* Whether to forward without author
|
||||
*/
|
||||
noAuthor?: boolean
|
||||
|
||||
/**
|
||||
* Whether to forward without caption (implies {@link noAuthor})
|
||||
*/
|
||||
noCaption?: boolean
|
||||
/**
|
||||
* Whether to forward without caption (implies {@link noAuthor})
|
||||
*/
|
||||
noCaption?: boolean
|
||||
|
||||
/**
|
||||
* Whether to disallow further forwards of this message.
|
||||
*
|
||||
* Only for bots, works even if the target chat does not
|
||||
* have content protection.
|
||||
*/
|
||||
forbidForwards?: boolean
|
||||
},
|
||||
): Promise<Message>
|
||||
/**
|
||||
* Whether to disallow further forwards of this message.
|
||||
*
|
||||
* Only for bots, works even if the target chat does not
|
||||
* have content protection.
|
||||
*/
|
||||
forbidForwards?: boolean
|
||||
|
||||
/**
|
||||
* Peer to use when sending the message.
|
||||
*/
|
||||
sendAs?: InputPeerLike
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward one or more messages, optionally including a caption message.
|
||||
* Forward one or more messages by their IDs.
|
||||
* You can forward no more than 100 messages at once.
|
||||
*
|
||||
* If a caption message was sent, it will be the first message in the resulting array.
|
||||
|
@ -111,123 +101,18 @@ export async function forwardMessages(
|
|||
* @param fromChatId Source chat ID, username, phone, `"me"` or `"self"`
|
||||
* @param messages Message IDs
|
||||
* @param params Additional sending parameters
|
||||
* @returns
|
||||
* Newly sent, forwarded messages in the destination chat.
|
||||
* If a caption message was provided, it will be the first message in the array.
|
||||
* @returns Newly sent, forwarded messages in the destination chat.
|
||||
*/
|
||||
export async function forwardMessages(
|
||||
export async function forwardMessagesById(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
params: ForwardMessageOptions & {
|
||||
/** Source chat ID, username, phone, `"me"` or `"self"` */
|
||||
fromChatId: InputPeerLike
|
||||
/** Destination chat ID, username, phone, `"me"` or `"self"` */
|
||||
toChatId: InputPeerLike
|
||||
/** Message IDs */
|
||||
/** Message IDs to forward */
|
||||
messages: number[]
|
||||
|
||||
/**
|
||||
* Optionally, a caption for your forwarded message(s).
|
||||
* It will be sent as a separate message before the forwarded messages.
|
||||
*
|
||||
* You can either pass `caption` or `captionMedia`, passing both will
|
||||
* result in an error
|
||||
*/
|
||||
caption?: string | FormattedString<string>
|
||||
|
||||
/**
|
||||
* Optionally, a media caption for your forwarded message(s).
|
||||
* It will be sent as a separate message before the forwarded messages.
|
||||
*
|
||||
* You can either pass `caption` or `captionMedia`, passing both will
|
||||
* result in an error
|
||||
*/
|
||||
captionMedia?: InputMediaLike
|
||||
|
||||
/**
|
||||
* Parse mode to use to parse entities in caption.
|
||||
* Defaults to current default parse mode (if any).
|
||||
*
|
||||
* Passing `null` will explicitly disable formatting.
|
||||
*/
|
||||
parseMode?: string | null
|
||||
|
||||
/**
|
||||
* List of formatting entities in caption to use instead
|
||||
* of parsing via a parse mode.
|
||||
*
|
||||
* **Note:** Passing this makes the method ignore {@link parseMode}
|
||||
*/
|
||||
entities?: tl.TypeMessageEntity[]
|
||||
|
||||
/**
|
||||
* Whether to forward silently (also applies to caption message).
|
||||
*/
|
||||
silent?: boolean
|
||||
|
||||
/**
|
||||
* If set, the forwarding will be scheduled to this date
|
||||
* (also applies to caption message).
|
||||
* When passing a number, a UNIX time in ms is expected.
|
||||
*
|
||||
* You can also pass `0x7FFFFFFE`, this will send the message
|
||||
* once the peer is online
|
||||
*/
|
||||
schedule?: Date | number
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message (only used for caption)
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
|
||||
/**
|
||||
* Whether to forward without author
|
||||
*/
|
||||
noAuthor?: boolean
|
||||
|
||||
/**
|
||||
* Whether to forward without caption (implies {@link noAuthor})
|
||||
*/
|
||||
noCaption?: boolean
|
||||
|
||||
/**
|
||||
* Whether to disallow further forwards of this message.
|
||||
*
|
||||
* Only for bots, works even if the target chat does not
|
||||
* have content protection.
|
||||
*/
|
||||
forbidForwards?: boolean
|
||||
},
|
||||
): Promise<MaybeArray<Message>>
|
||||
|
||||
/** @internal */
|
||||
export async function forwardMessages(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
toChatId: InputPeerLike
|
||||
fromChatId: InputPeerLike
|
||||
messages: MaybeArray<number>
|
||||
parseMode?: string | null
|
||||
entities?: tl.TypeMessageEntity[]
|
||||
silent?: boolean
|
||||
schedule?: Date | number
|
||||
clearDraft?: boolean
|
||||
noAuthor?: boolean
|
||||
noCaption?: boolean
|
||||
forbidForwards?: boolean
|
||||
sendAs?: InputPeerLike
|
||||
},
|
||||
): Promise<MaybeArray<Message>> {
|
||||
const { toChatId, fromChatId, silent, schedule, forbidForwards, sendAs, noAuthor, noCaption } = params
|
||||
let { messages } = params
|
||||
|
||||
let isSingle = false
|
||||
|
||||
if (!Array.isArray(messages)) {
|
||||
isSingle = true
|
||||
messages = [messages]
|
||||
}
|
||||
): Promise<Message[]> {
|
||||
const { messages, toChatId, fromChatId, silent, schedule, forbidForwards, sendAs, noAuthor, noCaption } = params
|
||||
|
||||
// sending more than 100 will not result in a server-sent
|
||||
// error, instead only first 100 IDs will be forwarded,
|
||||
|
@ -269,7 +154,25 @@ export async function forwardMessages(
|
|||
}
|
||||
})
|
||||
|
||||
if (isSingle) return forwarded[0]
|
||||
|
||||
return forwarded
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward one or more {@link Message}s to another chat.
|
||||
*
|
||||
* > **Note**: all messages must be from the same chat.
|
||||
*/
|
||||
export async function forwardMessages(
|
||||
client: BaseTelegramClient,
|
||||
params: ForwardMessageOptions & {
|
||||
messages: Message[]
|
||||
},
|
||||
): Promise<Message[]> {
|
||||
const { messages, ...rest } = params
|
||||
|
||||
return forwardMessagesById(client, {
|
||||
...rest,
|
||||
fromChatId: messages[0].chat.inputPeer,
|
||||
messages: messages.map((it) => it.id),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
||||
|
||||
import { Message } from '../../types/messages'
|
||||
import { InputMessageId, Message, normalizeInputMessageId } from '../../types/messages'
|
||||
import { InputPeerLike, PeersIndex } from '../../types/peers'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
|
@ -54,10 +54,11 @@ export async function _getDiscussionMessage(
|
|||
*/
|
||||
export async function getDiscussionMessage(
|
||||
client: BaseTelegramClient,
|
||||
peer: InputPeerLike,
|
||||
message: number,
|
||||
params: InputMessageId,
|
||||
): Promise<Message | null> {
|
||||
const inputPeer = await resolvePeer(client, peer)
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const inputPeer = await resolvePeer(client, chatId)
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.getDiscussionMessage',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseTelegramClient, MtArgumentError } from '@mtcute/core'
|
||||
import { isPresent } from '@mtcute/core/utils'
|
||||
|
||||
import { InputPeerLike, Message } from '../../types'
|
||||
import { InputMessageId, Message, normalizeInputMessageId } from '../../types'
|
||||
import { isInputPeerChannel } from '../../utils/peer-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
import { getMessages } from './get-messages'
|
||||
|
@ -12,11 +12,9 @@ import { getMessages } from './get-messages'
|
|||
* @param chatId Chat ID
|
||||
* @param message ID of one of the messages in the group
|
||||
*/
|
||||
export async function getMessageGroup(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
message: number,
|
||||
): Promise<Message[]> {
|
||||
export async function getMessageGroup(client: BaseTelegramClient, params: InputMessageId): Promise<Message[]> {
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
// awesome hack stolen from pyrogram
|
||||
// groups have no more than 10 items
|
||||
// however, since for non-channels message ids are shared,
|
||||
|
|
|
@ -1,29 +1,12 @@
|
|||
import { BaseTelegramClient, getMarkedPeerId, MaybeArray } from '@mtcute/core'
|
||||
import { BaseTelegramClient, getMarkedPeerId } from '@mtcute/core'
|
||||
import { assertTypeIs } from '@mtcute/core/utils'
|
||||
|
||||
import { InputPeerLike, MessageReactions, PeersIndex } from '../../types'
|
||||
import { InputPeerLike, Message, MessageReactions, PeersIndex } from '../../types'
|
||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Get reactions to a message.
|
||||
*
|
||||
* > Apps should short-poll reactions for visible messages
|
||||
* > (that weren't sent by the user) once every 15-30 seconds,
|
||||
* > but only if `message.reactions` is set
|
||||
*
|
||||
* @param chatId ID of the chat with the message
|
||||
* @param messages Message ID
|
||||
* @returns Reactions to the corresponding message, or `null` if there are none
|
||||
*/
|
||||
export async function getMessageReactions(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messages: number,
|
||||
): Promise<MessageReactions | null>
|
||||
|
||||
/**
|
||||
* Get reactions to messages.
|
||||
* Get reactions to messages by their IDs.
|
||||
*
|
||||
* > Apps should short-poll reactions for visible messages
|
||||
* > (that weren't sent by the user) once every 15-30 seconds,
|
||||
|
@ -33,26 +16,11 @@ export async function getMessageReactions(
|
|||
* @param messages Message IDs
|
||||
* @returns Reactions to corresponding messages, or `null` if there are none
|
||||
*/
|
||||
export async function getMessageReactions(
|
||||
export async function getMessageReactionsById(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messages: number[],
|
||||
): Promise<(MessageReactions | null)[]>
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export async function getMessageReactions(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messages: MaybeArray<number>,
|
||||
): Promise<MaybeArray<MessageReactions | null>> {
|
||||
const single = !Array.isArray(messages)
|
||||
|
||||
if (!Array.isArray(messages)) {
|
||||
messages = [messages]
|
||||
}
|
||||
|
||||
): Promise<(MessageReactions | null)[]> {
|
||||
const res = await client.call({
|
||||
_: 'messages.getMessagesReactions',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
|
@ -77,9 +45,29 @@ export async function getMessageReactions(
|
|||
index[update.msgId] = new MessageReactions(update.msgId, getMarkedPeerId(update.peer), update.reactions, peers)
|
||||
}
|
||||
|
||||
if (single) {
|
||||
return index[messages[0]] ?? null
|
||||
}
|
||||
|
||||
return messages.map((messageId) => index[messageId] ?? null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reactions to {@link Message}s.
|
||||
*
|
||||
* > **Note**: messages must all be from the same chat.
|
||||
*
|
||||
* > Apps should short-poll reactions for visible messages
|
||||
* > (that weren't sent by the user) once every 15-30 seconds,
|
||||
* > but only if `message.reactions` is set
|
||||
*
|
||||
* @param chatId ID of the chat with messages
|
||||
* @param messages Message IDs
|
||||
* @returns Reactions to corresponding messages, or `null` if there are none
|
||||
*/
|
||||
export async function getMessageReactions(
|
||||
client: BaseTelegramClient,
|
||||
messages: Message[],
|
||||
): Promise<(MessageReactions | null)[]> {
|
||||
return getMessageReactionsById(
|
||||
client,
|
||||
messages[0].chat.inputPeer,
|
||||
messages.map((it) => it.id),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,23 +3,6 @@ import { assertTypeIsNot } from '@mtcute/core/utils'
|
|||
|
||||
import { Message, PeersIndex } from '../../types'
|
||||
|
||||
/**
|
||||
* Get a single message from PM or legacy group by its ID.
|
||||
* For channels, use {@link getMessages}.
|
||||
*
|
||||
* Unlike {@link getMessages}, this method does not
|
||||
* check if the message belongs to some chat.
|
||||
*
|
||||
* @param messageId Messages ID
|
||||
* @param [fromReply=false]
|
||||
* Whether the reply to a given message should be fetched
|
||||
* (i.e. `getMessages(msg.chat.id, msg.id, true).id === msg.replyToMessageId`)
|
||||
*/
|
||||
export async function getMessagesUnsafe(
|
||||
client: BaseTelegramClient,
|
||||
messageId: number,
|
||||
fromReply?: boolean,
|
||||
): Promise<Message | null>
|
||||
/**
|
||||
* Get messages from PM or legacy group by their IDs.
|
||||
* For channels, use {@link getMessages}.
|
||||
|
@ -35,23 +18,15 @@ export async function getMessagesUnsafe(
|
|||
* Whether the reply to a given message should be fetched
|
||||
* (i.e. `getMessages(msg.chat.id, msg.id, true).id === msg.replyToMessageId`)
|
||||
*/
|
||||
export async function getMessagesUnsafe(
|
||||
client: BaseTelegramClient,
|
||||
messageIds: number[],
|
||||
fromReply?: boolean,
|
||||
): Promise<(Message | null)[]>
|
||||
|
||||
/** @internal */
|
||||
export async function getMessagesUnsafe(
|
||||
client: BaseTelegramClient,
|
||||
messageIds: MaybeArray<number>,
|
||||
fromReply = false,
|
||||
): Promise<MaybeArray<Message | null>> {
|
||||
const isSingle = !Array.isArray(messageIds)
|
||||
if (isSingle) messageIds = [messageIds as number]
|
||||
): Promise<(Message | null)[]> {
|
||||
if (!Array.isArray(messageIds)) messageIds = [messageIds]
|
||||
|
||||
const type = fromReply ? 'inputMessageReplyTo' : 'inputMessageID'
|
||||
const ids: tl.TypeInputMessage[] = (messageIds as number[]).map((it) => ({
|
||||
const ids: tl.TypeInputMessage[] = messageIds.map((it) => ({
|
||||
_: type,
|
||||
id: it,
|
||||
}))
|
||||
|
@ -65,11 +40,9 @@ export async function getMessagesUnsafe(
|
|||
|
||||
const peers = PeersIndex.from(res)
|
||||
|
||||
const ret = res.messages.map((msg) => {
|
||||
return res.messages.map((msg) => {
|
||||
if (msg._ === 'messageEmpty') return null
|
||||
|
||||
return new Message(msg, peers)
|
||||
})
|
||||
|
||||
return isSingle ? ret[0] : ret
|
||||
}
|
||||
|
|
|
@ -7,21 +7,7 @@ import { isInputPeerChannel, normalizeToInputChannel } from '../../utils/peer-ut
|
|||
import { getAuthState } from '../auth/_state'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Get a single message in chat by its ID
|
||||
*
|
||||
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`
|
||||
* @param messageId Messages ID
|
||||
* @param [fromReply=false]
|
||||
* Whether the reply to a given message should be fetched
|
||||
* (i.e. `getMessages(msg.chat.id, msg.id, true).id === msg.replyToMessageId`)
|
||||
*/
|
||||
export async function getMessages(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageId: number,
|
||||
fromReply?: boolean,
|
||||
): Promise<Message | null>
|
||||
// @available=both
|
||||
/**
|
||||
* Get messages in chat by their IDs
|
||||
*
|
||||
|
@ -34,28 +20,17 @@ export async function getMessages(
|
|||
* Whether the reply to a given message should be fetched
|
||||
* (i.e. `getMessages(msg.chat.id, msg.id, true).id === msg.replyToMessageId`)
|
||||
*/
|
||||
export async function getMessages(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageIds: number[],
|
||||
fromReply?: boolean,
|
||||
): Promise<(Message | null)[]>
|
||||
|
||||
// @available=both
|
||||
/** @internal */
|
||||
export async function getMessages(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageIds: MaybeArray<number>,
|
||||
fromReply = false,
|
||||
): Promise<MaybeArray<Message | null>> {
|
||||
): Promise<(Message | null)[]> {
|
||||
const peer = await resolvePeer(client, chatId)
|
||||
|
||||
const isSingle = !Array.isArray(messageIds)
|
||||
if (isSingle) messageIds = [messageIds as number]
|
||||
if (!Array.isArray(messageIds)) messageIds = [messageIds]
|
||||
|
||||
const type = fromReply ? 'inputMessageReplyTo' : 'inputMessageID'
|
||||
const ids: tl.TypeInputMessage[] = (messageIds as number[]).map((it) => ({
|
||||
const ids: tl.TypeInputMessage[] = messageIds.map((it) => ({
|
||||
_: type,
|
||||
id: it,
|
||||
}))
|
||||
|
@ -80,7 +55,8 @@ export async function getMessages(
|
|||
const peers = PeersIndex.from(res)
|
||||
|
||||
let selfId: number | null | undefined = undefined
|
||||
const ret = res.messages.map((msg) => {
|
||||
|
||||
return res.messages.map((msg) => {
|
||||
if (msg._ === 'messageEmpty') return null
|
||||
|
||||
if (!isChannel) {
|
||||
|
@ -110,6 +86,4 @@ export async function getMessages(
|
|||
|
||||
return new Message(msg, peers)
|
||||
})
|
||||
|
||||
return isSingle ? ret[0] : ret
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@ import { BaseTelegramClient } from '@mtcute/core'
|
|||
|
||||
import {
|
||||
ArrayPaginated,
|
||||
InputPeerLike,
|
||||
InputMessageId,
|
||||
InputReaction,
|
||||
normalizeInputMessageId,
|
||||
normalizeInputReaction,
|
||||
PeerReaction,
|
||||
PeersIndex,
|
||||
|
@ -17,15 +18,11 @@ export type GetReactionUsersOffset = string
|
|||
/**
|
||||
* Get users who have reacted to the message.
|
||||
*
|
||||
* @param chatId Chat ID
|
||||
* @param messageId Message ID
|
||||
* @param params
|
||||
*/
|
||||
export async function getReactionUsers(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageId: number,
|
||||
params?: {
|
||||
params: InputMessageId & {
|
||||
/**
|
||||
* Get only reactions with the specified emoji
|
||||
*/
|
||||
|
@ -44,9 +41,8 @@ export async function getReactionUsers(
|
|||
offset?: GetReactionUsersOffset
|
||||
},
|
||||
): Promise<ArrayPaginated<PeerReaction, GetReactionUsersOffset>> {
|
||||
if (!params) params = {}
|
||||
|
||||
const { limit = 100, offset, emoji } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const peer = await resolvePeer(client, chatId)
|
||||
|
||||
|
@ -55,7 +51,7 @@ export async function getReactionUsers(
|
|||
const res = await client.call({
|
||||
_: 'messages.getMessageReactionsList',
|
||||
peer,
|
||||
id: messageId,
|
||||
id: message,
|
||||
reaction,
|
||||
limit,
|
||||
offset,
|
||||
|
|
|
@ -4,17 +4,6 @@ import { assertTypeIsNot } from '@mtcute/core/utils'
|
|||
import { InputPeerLike, Message, PeersIndex } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Get a single scheduled message in chat by its ID
|
||||
*
|
||||
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`
|
||||
* @param messageId Scheduled message ID
|
||||
*/
|
||||
export async function getScheduledMessages(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageId: number,
|
||||
): Promise<Message | null>
|
||||
/**
|
||||
* Get scheduled messages in chat by their IDs
|
||||
*
|
||||
|
@ -24,27 +13,18 @@ export async function getScheduledMessages(
|
|||
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`
|
||||
* @param messageIds Scheduled messages IDs
|
||||
*/
|
||||
export async function getScheduledMessages(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageIds: number[],
|
||||
): Promise<(Message | null)[]>
|
||||
|
||||
/** @internal */
|
||||
export async function getScheduledMessages(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageIds: MaybeArray<number>,
|
||||
): Promise<MaybeArray<Message | null>> {
|
||||
): Promise<(Message | null)[]> {
|
||||
const peer = await resolvePeer(client, chatId)
|
||||
|
||||
const isSingle = !Array.isArray(messageIds)
|
||||
if (isSingle) messageIds = [messageIds as number]
|
||||
if (!Array.isArray(messageIds)) messageIds = [messageIds]
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.getScheduledMessages',
|
||||
peer,
|
||||
id: messageIds as number[],
|
||||
id: messageIds,
|
||||
})
|
||||
|
||||
assertTypeIsNot('getScheduledMessages', res, 'messages.messagesNotModified')
|
||||
|
@ -57,5 +37,5 @@ export async function getScheduledMessages(
|
|||
return new Message(msg, peers, true)
|
||||
})
|
||||
|
||||
return isSingle ? ret[0] : ret
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike, normalizeInputReaction, PeerReaction } from '../../types'
|
||||
import { normalizeInputMessageId, normalizeInputReaction, PeerReaction } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
import { getReactionUsers } from './get-reaction-users'
|
||||
|
||||
|
@ -15,9 +15,7 @@ import { getReactionUsers } from './get-reaction-users'
|
|||
*/
|
||||
export async function* iterReactionUsers(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageId: number,
|
||||
params?: Parameters<typeof getReactionUsers>[3] & {
|
||||
params: Parameters<typeof getReactionUsers>[1] & {
|
||||
/**
|
||||
* Limit the number of events returned.
|
||||
*
|
||||
|
@ -33,8 +31,7 @@ export async function* iterReactionUsers(
|
|||
chunkSize?: number
|
||||
},
|
||||
): AsyncIterableIterator<PeerReaction> {
|
||||
if (!params) params = {}
|
||||
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
const peer = await resolvePeer(client, chatId)
|
||||
|
||||
const { limit = Infinity, chunkSize = 100 } = params
|
||||
|
@ -45,7 +42,9 @@ export async function* iterReactionUsers(
|
|||
const reaction = normalizeInputReaction(params.emoji)
|
||||
|
||||
for (;;) {
|
||||
const res = await getReactionUsers(client, peer, messageId, {
|
||||
const res = await getReactionUsers(client, {
|
||||
chatId: peer,
|
||||
message,
|
||||
emoji: reaction,
|
||||
limit: Math.min(chunkSize, limit - current),
|
||||
offset,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import { InputMessageId, normalizeInputMessageId } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
|
@ -8,15 +8,10 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
*
|
||||
* For supergroups/channels, you must have appropriate permissions,
|
||||
* either as an admin, or as default permissions
|
||||
*
|
||||
* @param chatId Chat ID, username, phone number, `"self"` or `"me"`
|
||||
* @param messageId Message ID
|
||||
*/
|
||||
export async function pinMessage(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageId: number,
|
||||
params?: {
|
||||
params: InputMessageId & {
|
||||
/** Whether to send a notification (only for legacy groups and supergroups) */
|
||||
notify?: boolean
|
||||
/** Whether to pin for both sides (only for private chats) */
|
||||
|
@ -24,11 +19,12 @@ export async function pinMessage(
|
|||
},
|
||||
): Promise<void> {
|
||||
const { notify, bothSides } = params ?? {}
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.updatePinnedMessage',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
id: messageId,
|
||||
id: message,
|
||||
silent: !notify,
|
||||
pmOneside: !bothSides,
|
||||
})
|
||||
|
|
|
@ -6,9 +6,82 @@ import { getMessages } from './get-messages'
|
|||
import { sendMedia } from './send-media'
|
||||
import { sendText } from './send-text'
|
||||
|
||||
// @exported
|
||||
export interface SendCopyParams {
|
||||
/** Target chat ID */
|
||||
toChatId: InputPeerLike
|
||||
|
||||
/**
|
||||
* Whether to send this message silently.
|
||||
*/
|
||||
silent?: boolean
|
||||
|
||||
/**
|
||||
* If set, the message will be scheduled to this date.
|
||||
* When passing a number, a UNIX time in ms is expected.
|
||||
*
|
||||
* You can also pass `0x7FFFFFFE`, this will send the message
|
||||
* once the peer is online
|
||||
*/
|
||||
schedule?: Date | number
|
||||
|
||||
/**
|
||||
* New message caption (only used for media)
|
||||
*/
|
||||
caption?: string | FormattedString<string>
|
||||
|
||||
/**
|
||||
* Parse mode to use to parse `text` entities before sending
|
||||
* the message. Defaults to current default parse mode (if any).
|
||||
*
|
||||
* Passing `null` will explicitly disable formatting.
|
||||
*/
|
||||
parseMode?: string | null
|
||||
|
||||
/**
|
||||
* Message to reply to. Either a message object or message ID.
|
||||
*
|
||||
* For forums - can also be an ID of the topic (i.e. its top message ID)
|
||||
*/
|
||||
replyTo?: number | Message
|
||||
|
||||
/**
|
||||
* Whether to throw an error if {@link replyTo}
|
||||
* message does not exist.
|
||||
*
|
||||
* If that message was not found, `NotFoundError` is thrown,
|
||||
* with `text` set to `MESSAGE_NOT_FOUND`.
|
||||
*
|
||||
* Incurs an additional request, so only use when really needed.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
mustReply?: boolean
|
||||
|
||||
/**
|
||||
* List of formatting entities to use instead of parsing via a
|
||||
* parse mode.
|
||||
*
|
||||
* **Note:** Passing this makes the method ignore {@link parseMode}
|
||||
*/
|
||||
entities?: tl.TypeMessageEntity[]
|
||||
|
||||
/**
|
||||
* For bots: inline or reply markup or an instruction
|
||||
* to hide a reply keyboard or to force a reply.
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a message (i.e. send the same message,
|
||||
* but do not forward it).
|
||||
* Copy a message (i.e. send the same message, but do not forward it).
|
||||
*
|
||||
* Note that if the message contains a webpage,
|
||||
* it will be copied simply as a text message,
|
||||
|
@ -19,90 +92,31 @@ import { sendText } from './send-text'
|
|||
*/
|
||||
export async function sendCopy(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Source chat ID */
|
||||
fromChatId: InputPeerLike
|
||||
/** Target chat ID */
|
||||
toChatId: InputPeerLike
|
||||
/** Message ID to forward */
|
||||
message: number
|
||||
/**
|
||||
* Whether to send this message silently.
|
||||
*/
|
||||
silent?: boolean
|
||||
|
||||
/**
|
||||
* If set, the message will be scheduled to this date.
|
||||
* When passing a number, a UNIX time in ms is expected.
|
||||
*
|
||||
* You can also pass `0x7FFFFFFE`, this will send the message
|
||||
* once the peer is online
|
||||
*/
|
||||
schedule?: Date | number
|
||||
|
||||
/**
|
||||
* New message caption (only used for media)
|
||||
*/
|
||||
caption?: string | FormattedString<string>
|
||||
|
||||
/**
|
||||
* Parse mode to use to parse `text` entities before sending
|
||||
* the message. Defaults to current default parse mode (if any).
|
||||
*
|
||||
* Passing `null` will explicitly disable formatting.
|
||||
*/
|
||||
parseMode?: string | null
|
||||
|
||||
/**
|
||||
* Message to reply to. Either a message object or message ID.
|
||||
*
|
||||
* For forums - can also be an ID of the topic (i.e. its top message ID)
|
||||
*/
|
||||
replyTo?: number | Message
|
||||
|
||||
/**
|
||||
* Whether to throw an error if {@link replyTo}
|
||||
* message does not exist.
|
||||
*
|
||||
* If that message was not found, `NotFoundError` is thrown,
|
||||
* with `text` set to `MESSAGE_NOT_FOUND`.
|
||||
*
|
||||
* Incurs an additional request, so only use when really needed.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
mustReply?: boolean
|
||||
|
||||
/**
|
||||
* List of formatting entities to use instead of parsing via a
|
||||
* parse mode.
|
||||
*
|
||||
* **Note:** Passing this makes the method ignore {@link parseMode}
|
||||
*/
|
||||
entities?: tl.TypeMessageEntity[]
|
||||
|
||||
/**
|
||||
* For bots: inline or reply markup or an instruction
|
||||
* to hide a reply keyboard or to force a reply.
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
},
|
||||
params: SendCopyParams &
|
||||
(
|
||||
| {
|
||||
/** Source chat ID */
|
||||
fromChatId: InputPeerLike
|
||||
/** Message ID to forward */
|
||||
message: number
|
||||
}
|
||||
| { message: Message }
|
||||
),
|
||||
): Promise<Message> {
|
||||
const { fromChatId, toChatId, message, ...rest } = params
|
||||
const { toChatId, ...rest } = params
|
||||
|
||||
const fromPeer = await resolvePeer(client, fromChatId)
|
||||
let msg
|
||||
|
||||
const msg = await getMessages(client, fromPeer, message)
|
||||
if ('fromChatId' in params) {
|
||||
const fromPeer = await resolvePeer(client, params.fromChatId)
|
||||
|
||||
if (!msg) {
|
||||
throw new MtMessageNotFoundError(getMarkedPeerId(fromPeer), message, 'to copy')
|
||||
;[msg] = await getMessages(client, fromPeer, params.message)
|
||||
|
||||
if (!msg) {
|
||||
throw new MtMessageNotFoundError(getMarkedPeerId(fromPeer), params.message, 'to copy')
|
||||
}
|
||||
} else {
|
||||
msg = params.message
|
||||
}
|
||||
|
||||
if (msg.raw._ === 'messageService') {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike, InputReaction, Message, normalizeInputReaction } from '../../types'
|
||||
import { InputMessageId, InputReaction, Message, normalizeInputMessageId, normalizeInputReaction } from '../../types'
|
||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
import { _findMessageInUpdate } from './find-in-update'
|
||||
|
@ -12,18 +12,15 @@ import { _findMessageInUpdate } from './find-in-update'
|
|||
*/
|
||||
export async function sendReaction(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Chat ID with the message to react to */
|
||||
chatId: InputPeerLike
|
||||
/** Message ID to react to */
|
||||
message: number
|
||||
params: InputMessageId & {
|
||||
/** Reaction emoji (or `null` to remove reaction) */
|
||||
emoji?: InputReaction | null
|
||||
/** Whether to use a big reaction */
|
||||
big?: boolean
|
||||
},
|
||||
): Promise<Message> {
|
||||
const { chatId, message, emoji, big } = params
|
||||
const { emoji, big } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const reaction = normalizeInputReaction(emoji)
|
||||
|
||||
|
|
|
@ -4,18 +4,6 @@ import { InputPeerLike, Message, PeersIndex } from '../../types'
|
|||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Send s previously scheduled message.
|
||||
*
|
||||
* Note that if the message belongs to a media group,
|
||||
* the entire group will be sent, but only
|
||||
* the first message will be returned (in this overload).
|
||||
*
|
||||
* @param peer Chat where the messages were scheduled
|
||||
* @param id ID of the message
|
||||
*/
|
||||
export async function sendScheduled(client: BaseTelegramClient, peer: InputPeerLike, id: number): Promise<Message>
|
||||
|
||||
/**
|
||||
* Send previously scheduled message(s)
|
||||
*
|
||||
|
@ -26,21 +14,17 @@ export async function sendScheduled(client: BaseTelegramClient, peer: InputPeerL
|
|||
* @param peer Chat where the messages were scheduled
|
||||
* @param ids ID(s) of the messages
|
||||
*/
|
||||
export async function sendScheduled(client: BaseTelegramClient, peer: InputPeerLike, ids: number[]): Promise<Message[]>
|
||||
|
||||
/** @internal */
|
||||
export async function sendScheduled(
|
||||
client: BaseTelegramClient,
|
||||
peer: InputPeerLike,
|
||||
ids: MaybeArray<number>,
|
||||
): Promise<MaybeArray<Message>> {
|
||||
const isSingle = !Array.isArray(ids)
|
||||
if (isSingle) ids = [ids as number]
|
||||
): Promise<Message[]> {
|
||||
if (!Array.isArray(ids)) ids = [ids]
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.sendScheduledMessages',
|
||||
peer: await resolvePeer(client, peer),
|
||||
id: ids as number[],
|
||||
id: ids,
|
||||
})
|
||||
|
||||
assertIsUpdatesGroup('sendScheduled', res)
|
||||
|
@ -55,5 +39,5 @@ export async function sendScheduled(
|
|||
)
|
||||
.map((u) => new Message(u.message, peers))
|
||||
|
||||
return isSingle ? msgs[0] : msgs
|
||||
return msgs
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseTelegramClient, getMarkedPeerId, MaybeArray, MtArgumentError, MtTypeAssertionError } from '@mtcute/core'
|
||||
import { assertTypeIs } from '@mtcute/core/utils'
|
||||
|
||||
import { InputPeerLike, MtMessageNotFoundError, PeersIndex, Poll } from '../../types'
|
||||
import { InputMessageId, MtMessageNotFoundError, normalizeInputMessageId, PeersIndex, Poll } from '../../types'
|
||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
import { getMessages } from './get-messages'
|
||||
|
@ -11,11 +11,7 @@ import { getMessages } from './get-messages'
|
|||
*/
|
||||
export async function sendVote(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Chat ID where this poll was found */
|
||||
chatId: InputPeerLike
|
||||
/** Message ID where this poll was found */
|
||||
message: number
|
||||
params: InputMessageId & {
|
||||
/**
|
||||
* Selected options, or `null` to retract.
|
||||
* You can pass indexes of the answers or the `Buffer`s
|
||||
|
@ -25,7 +21,7 @@ export async function sendVote(
|
|||
options: null | MaybeArray<number | Buffer>
|
||||
},
|
||||
): Promise<Poll> {
|
||||
const { chatId, message } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
let { options } = params
|
||||
|
||||
if (options === null) options = []
|
||||
|
@ -36,7 +32,7 @@ export async function sendVote(
|
|||
let poll: Poll | undefined = undefined
|
||||
|
||||
if (options.some((it) => typeof it === 'number')) {
|
||||
const msg = await getMessages(client, peer, message)
|
||||
const [msg] = await getMessages(client, peer, message)
|
||||
|
||||
if (!msg) {
|
||||
throw new MtMessageNotFoundError(getMarkedPeerId(peer), message, 'to vote in')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike, MessageEntity } from '../../types'
|
||||
import { InputMessageId, MessageEntity, normalizeInputMessageId } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
|
@ -10,21 +10,18 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
*/
|
||||
export async function translateMessage(
|
||||
client: BaseTelegramClient,
|
||||
params: {
|
||||
/** Chat or user ID */
|
||||
chatId: InputPeerLike
|
||||
/** Identifier of the message to translate */
|
||||
messageId: number
|
||||
params: InputMessageId & {
|
||||
/** Target language (two-letter ISO 639-1 language code) */
|
||||
toLanguage: string
|
||||
},
|
||||
): Promise<[string, MessageEntity[]] | null> {
|
||||
const { chatId, messageId, toLanguage } = params
|
||||
const { toLanguage } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.translateText',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
id: [messageId],
|
||||
id: [message],
|
||||
toLang: toLanguage,
|
||||
})
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike } from '../../types'
|
||||
import { InputMessageId, normalizeInputMessageId } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
|
@ -12,15 +12,13 @@ import { resolvePeer } from '../users/resolve-peer'
|
|||
* @param chatId Chat ID, username, phone number, `"self"` or `"me"`
|
||||
* @param messageId Message ID
|
||||
*/
|
||||
export async function unpinMessage(
|
||||
client: BaseTelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
messageId: number,
|
||||
): Promise<void> {
|
||||
export async function unpinMessage(client: BaseTelegramClient, params: InputMessageId): Promise<void> {
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.updatePinnedMessage',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
id: messageId,
|
||||
id: message,
|
||||
unpin: true,
|
||||
})
|
||||
|
||||
|
|
|
@ -5,40 +5,22 @@ import { InputPeerLike, PeersIndex, Story } from '../../types'
|
|||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Get a single story by its ID
|
||||
*
|
||||
* @param peerId Peer ID whose stories to fetch
|
||||
* @param storyId Story ID
|
||||
*/
|
||||
export async function getStoriesById(client: BaseTelegramClient, peerId: InputPeerLike, storyId: number): Promise<Story>
|
||||
|
||||
/**
|
||||
* Get multiple stories by their IDs
|
||||
* Get one or more stories by their IDs
|
||||
*
|
||||
* @param peerId Peer ID whose stories to fetch
|
||||
* @param storyIds Story IDs
|
||||
*/
|
||||
export async function getStoriesById(
|
||||
client: BaseTelegramClient,
|
||||
peerId: InputPeerLike,
|
||||
storyIds: number[],
|
||||
): Promise<Story[]>
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export async function getStoriesById(
|
||||
client: BaseTelegramClient,
|
||||
peerId: InputPeerLike,
|
||||
storyIds: MaybeArray<number>,
|
||||
): Promise<MaybeArray<Story>> {
|
||||
const single = !Array.isArray(storyIds)
|
||||
if (single) storyIds = [storyIds as number]
|
||||
): Promise<Story[]> {
|
||||
if (!Array.isArray(storyIds)) storyIds = [storyIds]
|
||||
|
||||
const res = await client.call({
|
||||
_: 'stories.getStoriesByID',
|
||||
peer: await resolvePeer(client, peerId),
|
||||
id: storyIds as number[],
|
||||
id: storyIds,
|
||||
})
|
||||
|
||||
const peers = PeersIndex.from(res)
|
||||
|
@ -49,5 +31,5 @@ export async function getStoriesById(
|
|||
return new Story(it, peers)
|
||||
})
|
||||
|
||||
return single ? stories[0] : stories
|
||||
return stories
|
||||
}
|
||||
|
|
|
@ -3,46 +3,27 @@ import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
|
|||
import { InputPeerLike, PeersIndex, StoryInteractions } from '../../types'
|
||||
import { resolvePeer } from '../users/resolve-peer'
|
||||
|
||||
/**
|
||||
* Get brief information about story interactions.
|
||||
*/
|
||||
export async function getStoriesInteractions(
|
||||
client: BaseTelegramClient,
|
||||
peerId: InputPeerLike,
|
||||
storyId: number,
|
||||
): Promise<StoryInteractions>
|
||||
|
||||
/**
|
||||
* Get brief information about stories interactions.
|
||||
*
|
||||
* The result will be in the same order as the input IDs
|
||||
*/
|
||||
export async function getStoriesInteractions(
|
||||
client: BaseTelegramClient,
|
||||
peerId: InputPeerLike,
|
||||
storyIds: number[],
|
||||
): Promise<StoryInteractions[]>
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export async function getStoriesInteractions(
|
||||
client: BaseTelegramClient,
|
||||
peerId: InputPeerLike,
|
||||
storyIds: MaybeArray<number>,
|
||||
): Promise<MaybeArray<StoryInteractions>> {
|
||||
const isSingle = !Array.isArray(storyIds)
|
||||
if (isSingle) storyIds = [storyIds as number]
|
||||
): Promise<StoryInteractions[]> {
|
||||
if (!Array.isArray(storyIds)) storyIds = [storyIds]
|
||||
|
||||
const res = await client.call({
|
||||
_: 'stories.getStoriesViews',
|
||||
peer: await resolvePeer(client, peerId),
|
||||
id: storyIds as number[],
|
||||
id: storyIds,
|
||||
})
|
||||
|
||||
const peers = PeersIndex.from(res)
|
||||
|
||||
const infos = res.views.map((it) => new StoryInteractions(it, peers))
|
||||
|
||||
return isSingle ? infos[0] : infos
|
||||
return infos
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
tl,
|
||||
toggleChannelIdMark,
|
||||
} from '@mtcute/core'
|
||||
import { assertTypeIs } from '@mtcute/core/utils'
|
||||
|
||||
import { MtPeerNotFoundError } from '../../types/errors'
|
||||
import { InputPeerLike } from '../../types/peers'
|
||||
|
@ -26,10 +25,13 @@ export async function resolvePeer(
|
|||
peerId: InputPeerLike,
|
||||
force = false,
|
||||
): Promise<tl.TypeInputPeer> {
|
||||
// for convenience we also accept tl objects directly
|
||||
// for convenience we also accept tl and User/Chat objects directly
|
||||
if (typeof peerId === 'object') {
|
||||
if (tl.isAnyPeer(peerId)) {
|
||||
peerId = getMarkedPeerId(peerId)
|
||||
} else if ('type' in peerId) {
|
||||
// User | Chat
|
||||
return peerId.inputPeer
|
||||
} else {
|
||||
return normalizeToInputPeer(peerId)
|
||||
}
|
||||
|
@ -45,29 +47,17 @@ export async function resolvePeer(
|
|||
|
||||
peerId = peerId.replace(/[@+\s()]/g, '')
|
||||
|
||||
let res
|
||||
|
||||
if (peerId.match(/^\d+$/)) {
|
||||
// phone number
|
||||
const fromStorage = await client.storage.getPeerByPhone(peerId)
|
||||
if (fromStorage) return fromStorage
|
||||
|
||||
const res = await client.call({
|
||||
_: 'contacts.getContacts',
|
||||
hash: Long.ZERO,
|
||||
res = await client.call({
|
||||
_: 'contacts.resolvePhone',
|
||||
phone: peerId,
|
||||
})
|
||||
|
||||
assertTypeIs('contacts.getContacts', res, 'contacts.contacts')
|
||||
|
||||
const found = res.users.find((it) => (it as tl.RawUser).phone === peerId)
|
||||
|
||||
if (found && found._ === 'user') {
|
||||
return {
|
||||
_: 'inputPeerUser',
|
||||
userId: found.id,
|
||||
accessHash: found.accessHash!,
|
||||
}
|
||||
}
|
||||
|
||||
throw new MtPeerNotFoundError(`Could not find a peer by phone ${peerId}`)
|
||||
} else {
|
||||
// username
|
||||
if (!force) {
|
||||
|
@ -75,64 +65,62 @@ export async function resolvePeer(
|
|||
if (fromStorage) return fromStorage
|
||||
}
|
||||
|
||||
const res = await client.call({
|
||||
res = await client.call({
|
||||
_: 'contacts.resolveUsername',
|
||||
username: peerId,
|
||||
})
|
||||
|
||||
if (res.peer._ === 'peerUser') {
|
||||
const id = res.peer.userId
|
||||
|
||||
const found = res.users.find((it) => it.id === id)
|
||||
|
||||
if (found && found._ === 'user') {
|
||||
if (!found.accessHash) {
|
||||
// no access hash, we can't use it
|
||||
// this may happen when bot resolves a username
|
||||
// of a user who hasn't started a conversation with it
|
||||
throw new MtPeerNotFoundError(
|
||||
`Peer (user) with username ${peerId} was found, but it has no access hash`,
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputPeerUser',
|
||||
userId: found.id,
|
||||
accessHash: found.accessHash,
|
||||
}
|
||||
}
|
||||
} else if (res.peer._ === 'peerChannel') {
|
||||
const id = res.peer.channelId
|
||||
const found = res.chats.find((it) => it.id === id)
|
||||
|
||||
if (found) {
|
||||
if (!(found._ === 'channel' || found._ === 'channelForbidden')) {
|
||||
// chats can't have usernames
|
||||
// furthermore, our id is a channel id, so it must be a channel
|
||||
// this should never happen, unless Telegram goes crazy
|
||||
throw new MtTypeAssertionError('contacts.resolveUsername#chats', 'channel', found._)
|
||||
}
|
||||
|
||||
if (!found.accessHash) {
|
||||
// shouldn't happen? but just in case
|
||||
throw new MtPeerNotFoundError(
|
||||
`Peer (channel) with username ${peerId} was found, but it has no access hash`,
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputPeerChannel',
|
||||
channelId: found.id,
|
||||
accessHash: found.accessHash,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// chats can't have usernames
|
||||
throw new MtTypeAssertionError('contacts.resolveUsername', 'user or channel', res.peer._)
|
||||
}
|
||||
|
||||
throw new MtPeerNotFoundError(`Could not find a peer by username ${peerId}`)
|
||||
}
|
||||
|
||||
if (res.peer._ === 'peerUser') {
|
||||
const id = res.peer.userId
|
||||
|
||||
const found = res.users.find((it) => it.id === id)
|
||||
|
||||
if (found && found._ === 'user') {
|
||||
if (!found.accessHash) {
|
||||
// no access hash, we can't use it
|
||||
// this may happen when bot resolves a username
|
||||
// of a user who hasn't started a conversation with it
|
||||
throw new MtPeerNotFoundError(
|
||||
`Peer (user) with username ${peerId} was found, but it has no access hash`,
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputPeerUser',
|
||||
userId: found.id,
|
||||
accessHash: found.accessHash,
|
||||
}
|
||||
}
|
||||
} else if (res.peer._ === 'peerChannel') {
|
||||
const id = res.peer.channelId
|
||||
const found = res.chats.find((it) => it.id === id)
|
||||
|
||||
if (found) {
|
||||
if (!(found._ === 'channel' || found._ === 'channelForbidden')) {
|
||||
// chats can't have usernames
|
||||
// furthermore, our id is a channel id, so it must be a channel
|
||||
// this should never happen, unless Telegram goes crazy
|
||||
throw new MtTypeAssertionError('contacts.resolveUsername#chats', 'channel', found._)
|
||||
}
|
||||
|
||||
if (!found.accessHash) {
|
||||
// shouldn't happen? but just in case
|
||||
throw new MtPeerNotFoundError(`Peer (channel) with ${peerId} was found, but it has no access hash`)
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputPeerChannel',
|
||||
channelId: found.id,
|
||||
accessHash: found.accessHash,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// chats can't have usernames
|
||||
throw new MtTypeAssertionError('contacts.resolveUsername', 'user or channel', res.peer._)
|
||||
}
|
||||
|
||||
throw new MtPeerNotFoundError(`Could not find a peer by ${peerId}`)
|
||||
}
|
||||
|
||||
const peerType = getBasicPeerType(peerId)
|
||||
|
@ -171,25 +159,10 @@ export async function resolvePeer(
|
|||
break
|
||||
}
|
||||
case 'chat': {
|
||||
// do we really need to make a call?
|
||||
// const id = -peerId
|
||||
// const res = await client.call({
|
||||
// _: 'messages.getChats',
|
||||
// id: [id],
|
||||
// })
|
||||
//
|
||||
// const found = res.chats.find((it) => it.id === id)
|
||||
// if (found && (found._ === 'chat' || found._ === 'chatForbidden'))
|
||||
// return {
|
||||
// _: 'inputPeerChat',
|
||||
// chatId: found.id
|
||||
// }
|
||||
|
||||
return {
|
||||
_: 'inputPeerChat',
|
||||
chatId: -peerId,
|
||||
}
|
||||
// break
|
||||
}
|
||||
case 'channel': {
|
||||
const id = toggleChannelIdMark(peerId)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export * from './dialog'
|
||||
export * from './draft-message'
|
||||
export * from './input-message-id'
|
||||
export * from './message'
|
||||
export * from './message-action'
|
||||
export * from './message-entity'
|
||||
|
|
16
packages/client/src/types/messages/input-message-id.ts
Normal file
16
packages/client/src/types/messages/input-message-id.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import type { InputPeerLike } from '../peers'
|
||||
import type { Message } from './message'
|
||||
|
||||
/**
|
||||
* Parameters for methods that accept a message
|
||||
*
|
||||
* Either a message object (in `message` field), or a chat ID and a message ID
|
||||
*/
|
||||
export type InputMessageId = { chatId: InputPeerLike; message: number } | { message: Message }
|
||||
|
||||
/** @internal */
|
||||
export function normalizeInputMessageId(id: InputMessageId) {
|
||||
if ('chatId' in id) return id
|
||||
|
||||
return { chatId: id.message.chat.inputPeer, message: id.message.id }
|
||||
}
|
|
@ -12,6 +12,7 @@ import { parseDocument } from '../media/document-utils'
|
|||
* Can be one of:
|
||||
* - Raw TL object
|
||||
* - Sticker set short name
|
||||
* - {@link StickerSet} object
|
||||
* - `{ dice: "<emoji>" }` (e.g. `{ dice: "🎲" }`) - Used for fetching animated dice stickers
|
||||
* - `{ system: string }` - for system stickersets:
|
||||
* - `"animated"` - Animated emojis stickerset
|
||||
|
@ -35,6 +36,7 @@ export type InputStickerSet =
|
|||
| 'default_statuses'
|
||||
| 'default_topic_icons'
|
||||
}
|
||||
| StickerSet
|
||||
| string
|
||||
|
||||
export function normalizeInputStickerSet(input: InputStickerSet): tl.TypeInputStickerSet {
|
||||
|
@ -45,6 +47,7 @@ export function normalizeInputStickerSet(input: InputStickerSet): tl.TypeInputSt
|
|||
}
|
||||
}
|
||||
if ('_' in input) return input
|
||||
if (input instanceof StickerSet) return input.inputStickerSet
|
||||
|
||||
if ('dice' in input) {
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { tl } from '@mtcute/core'
|
||||
|
||||
import { Chat } from './chat'
|
||||
import { User } from './user'
|
||||
|
||||
export * from './chat'
|
||||
export * from './chat-event'
|
||||
export * from './chat-invite-link'
|
||||
|
@ -21,15 +24,23 @@ export * from './user'
|
|||
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:
|
||||
* 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 (w/out preceding `@`)
|
||||
* - `string`, representing user's phone number (only for contacts)
|
||||
* - `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
|
||||
* - `Chat` or `User` object
|
||||
* - Raw TL object
|
||||
*
|
||||
* > Telegram has moved to int64 IDs. Though, Levin [has confirmed](https://t.me/tdlibchat/25075)
|
||||
* > * 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
|
||||
export type InputPeerLike =
|
||||
| string
|
||||
| number
|
||||
| tl.TypePeer
|
||||
| tl.TypeInputPeer
|
||||
| tl.TypeInputUser
|
||||
| tl.TypeInputChannel
|
||||
| Chat
|
||||
| User
|
||||
|
|
Loading…
Reference in a new issue