diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index d7ae0c36..93ce6511 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -1050,6 +1050,12 @@ export interface TelegramClient extends BaseTelegramClient { * This can be useful when fixing mistakes or banning cheaters */ force?: boolean + + /** + * Whether to dispatch the edit message event + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise /** @@ -1161,8 +1167,15 @@ export interface TelegramClient extends BaseTelegramClient { banChatMember(params: { /** Chat ID */ chatId: InputPeerLike + /** ID of the user/channel to ban */ participantId: InputPeerLike + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }): Promise /** * Create a new broadcast channel @@ -2314,6 +2327,12 @@ export interface TelegramClient extends BaseTelegramClient { * Send as a specific channel */ sendAs?: InputPeerLike + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }): Promise /** * Delete a forum topic and all its history @@ -2354,6 +2373,12 @@ export interface TelegramClient extends BaseTelegramClient { * and use static color instead */ icon?: tl.Long | null + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }): Promise /** * Get a single forum topic by its ID @@ -2457,6 +2482,12 @@ export interface TelegramClient extends BaseTelegramClient { /** Whether the topic should be closed */ closed: boolean + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }): Promise /** * Toggle whether a topic in a forum is pinned @@ -2491,11 +2522,20 @@ export interface TelegramClient extends BaseTelegramClient { * * **Available**: ✅ both users and bots * - * @param chatId Chat ID or username - * @param hidden Whether the topic should be hidden * @returns Service message about the modification */ - toggleGeneralTopicHidden(chatId: InputPeerLike, hidden: boolean): Promise + toggleGeneralTopicHidden(params: { + /** Chat ID or username */ + chatId: InputPeerLike + /** Whether the topic should be hidden */ + hidden: boolean + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true + }): Promise /** * Create an additional invite link for the chat. * @@ -2794,7 +2834,15 @@ export interface TelegramClient extends BaseTelegramClient { * **Available**: ✅ both users and bots * */ - closePoll(params: InputMessageId): Promise + closePoll( + params: InputMessageId & { + /** + * Whether to dispatch the edit message event + * to the client's update handler. + */ + shouldDispatch?: true + }, + ): Promise /** * Delete messages by their IDs * @@ -2952,10 +3000,16 @@ export interface TelegramClient extends BaseTelegramClient { * @param total Total file size in bytes */ progressCallback?: (uploaded: number, total: number) => void + + /** + * Whether to dispatch the edit message event + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise - _findMessageInUpdate(res: tl.TypeUpdates, isEdit?: boolean): Message + _findMessageInUpdate(res: tl.TypeUpdates, isEdit?: boolean, noDispatch?: boolean): Message /** * Forward one or more messages by their IDs. * You can forward no more than 100 messages at once. @@ -3310,8 +3364,10 @@ export interface TelegramClient extends BaseTelegramClient { * * For supergroups/channels, you must have appropriate permissions, * either as an admin, or as default permissions + * * **Available**: ✅ both users and bots * + * @returns Service message about pinned message, if one was generated. */ pinMessage( params: InputMessageId & { @@ -3319,8 +3375,14 @@ export interface TelegramClient extends BaseTelegramClient { notify?: boolean /** Whether to pin for both sides (only for private chats) */ bothSides?: boolean + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }, - ): Promise + ): Promise /** * Mark chat history as read. * @@ -3741,6 +3803,12 @@ export interface TelegramClient extends BaseTelegramClient { * Peer to use when sending the message. */ sendAs?: InputPeerLike + + /** + * Whether to dispatch the returned message + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise /** @@ -3756,6 +3824,12 @@ export interface TelegramClient extends BaseTelegramClient { emoji?: InputReaction | null /** Whether to use a big reaction */ big?: boolean + + /** + * Whether to dispatch the returned edit message event + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise /** @@ -3871,6 +3945,12 @@ export interface TelegramClient extends BaseTelegramClient { * Peer to use when sending the message. */ sendAs?: InputPeerLike + + /** + * Whether to dispatch the returned message + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise /** diff --git a/packages/client/src/methods/bots/set-game-score.ts b/packages/client/src/methods/bots/set-game-score.ts index bccc0d0c..9545adf2 100644 --- a/packages/client/src/methods/bots/set-game-score.ts +++ b/packages/client/src/methods/bots/set-game-score.ts @@ -32,9 +32,15 @@ export async function setGameScore( * This can be useful when fixing mistakes or banning cheaters */ force?: boolean + + /** + * Whether to dispatch the edit message event + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { - const { userId, score, noEdit, force } = params + const { userId, score, noEdit, force, shouldDispatch } = params const { chatId, message } = normalizeInputMessageId(params) const user = normalizeToInputUser(await resolvePeer(client, userId), userId) @@ -50,7 +56,7 @@ export async function setGameScore( force, }) - return _findMessageInUpdate(client, res, true) + return _findMessageInUpdate(client, res, true, !shouldDispatch) } /** diff --git a/packages/client/src/methods/chats/ban-chat-member.ts b/packages/client/src/methods/chats/ban-chat-member.ts index bc619409..17df1a47 100644 --- a/packages/client/src/methods/chats/ban-chat-member.ts +++ b/packages/client/src/methods/chats/ban-chat-member.ts @@ -25,12 +25,20 @@ export async function banChatMember( params: { /** Chat ID */ chatId: InputPeerLike + /** ID of the user/channel to ban */ participantId: InputPeerLike + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { - const chat = await resolvePeer(client, params.chatId) - const peer = await resolvePeer(client, params.participantId) + const { chatId, participantId, shouldDispatch } = params + const chat = await resolvePeer(client, chatId) + const peer = await resolvePeer(client, participantId) let res if (isInputPeerChannel(chat)) { @@ -51,10 +59,10 @@ export async function banChatMember( chatId: chat.chatId, userId: normalizeToInputUser(peer), }) - } else throw new MtInvalidPeerTypeError(params.chatId, 'chat or channel') + } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel') try { - return _findMessageInUpdate(client, res) + return _findMessageInUpdate(client, res, false, !shouldDispatch) } catch (e) { if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') { // no service message diff --git a/packages/client/src/methods/forums/create-forum-topic.ts b/packages/client/src/methods/forums/create-forum-topic.ts index ae3e3093..0933496f 100644 --- a/packages/client/src/methods/forums/create-forum-topic.ts +++ b/packages/client/src/methods/forums/create-forum-topic.ts @@ -38,9 +38,15 @@ export async function createForumTopic( * Send as a specific channel */ sendAs?: InputPeerLike + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { - const { chatId, title, icon, sendAs } = params + const { chatId, title, icon, sendAs, shouldDispatch } = params const res = await client.call({ _: 'channels.createForumTopic', @@ -52,5 +58,5 @@ export async function createForumTopic( randomId: randomLong(), }) - return _findMessageInUpdate(client, res) + return _findMessageInUpdate(client, res, false, !shouldDispatch) } diff --git a/packages/client/src/methods/forums/edit-forum-topic.ts b/packages/client/src/methods/forums/edit-forum-topic.ts index e44fb9f6..f00c71c9 100644 --- a/packages/client/src/methods/forums/edit-forum-topic.ts +++ b/packages/client/src/methods/forums/edit-forum-topic.ts @@ -35,9 +35,15 @@ export async function editForumTopic( * and use static color instead */ icon?: tl.Long | null + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { - const { chatId, topicId, title, icon } = params + const { chatId, topicId, title, icon, shouldDispatch } = params const res = await client.call({ _: 'channels.editForumTopic', @@ -47,5 +53,5 @@ export async function editForumTopic( iconEmojiId: icon ? icon ?? Long.ZERO : undefined, }) - return _findMessageInUpdate(client, res) + return _findMessageInUpdate(client, res, false, shouldDispatch) } diff --git a/packages/client/src/methods/forums/toggle-forum-topic-closed.ts b/packages/client/src/methods/forums/toggle-forum-topic-closed.ts index b97760d6..76969a3c 100644 --- a/packages/client/src/methods/forums/toggle-forum-topic-closed.ts +++ b/packages/client/src/methods/forums/toggle-forum-topic-closed.ts @@ -23,9 +23,15 @@ export async function toggleForumTopicClosed( /** Whether the topic should be closed */ closed: boolean + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { - const { chatId, topicId, closed } = parmas + const { chatId, topicId, closed, shouldDispatch } = parmas const res = await client.call({ _: 'channels.editForumTopic', @@ -34,5 +40,5 @@ export async function toggleForumTopicClosed( closed, }) - return _findMessageInUpdate(client, res) + return _findMessageInUpdate(client, res, false, shouldDispatch) } diff --git a/packages/client/src/methods/forums/toggle-general-topic-hidden.ts b/packages/client/src/methods/forums/toggle-general-topic-hidden.ts index 237b643b..493e285b 100644 --- a/packages/client/src/methods/forums/toggle-general-topic-hidden.ts +++ b/packages/client/src/methods/forums/toggle-general-topic-hidden.ts @@ -10,15 +10,24 @@ import { resolvePeer } from '../users/resolve-peer' * * Only admins with `manageTopics` permission can do this. * - * @param chatId Chat ID or username - * @param hidden Whether the topic should be hidden * @returns Service message about the modification */ export async function toggleGeneralTopicHidden( client: BaseTelegramClient, - chatId: InputPeerLike, - hidden: boolean, + params: { + /** Chat ID or username */ + chatId: InputPeerLike + /** Whether the topic should be hidden */ + hidden: boolean + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true + }, ): Promise { + const { chatId, hidden, shouldDispatch } = params const res = await client.call({ _: 'channels.editForumTopic', channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId), @@ -26,5 +35,5 @@ export async function toggleGeneralTopicHidden( hidden, }) - return _findMessageInUpdate(client, res) + return _findMessageInUpdate(client, res, false, shouldDispatch) } diff --git a/packages/client/src/methods/messages/close-poll.ts b/packages/client/src/methods/messages/close-poll.ts index 508aa86e..3ceeab4c 100644 --- a/packages/client/src/methods/messages/close-poll.ts +++ b/packages/client/src/methods/messages/close-poll.ts @@ -11,7 +11,16 @@ 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: InputMessageId): Promise { +export async function closePoll( + client: BaseTelegramClient, + params: InputMessageId & { + /** + * Whether to dispatch the edit message event + * to the client's update handler. + */ + shouldDispatch?: true + }, +): Promise { const { chatId, message } = normalizeInputMessageId(params) const res = await client.call({ @@ -32,7 +41,7 @@ export async function closePoll(client: BaseTelegramClient, params: InputMessage assertIsUpdatesGroup('messages.editMessage', res) - client.network.handleUpdate(res, true) + client.network.handleUpdate(res, !params.shouldDispatch) const upd = res.updates[0] assertTypeIs('messages.editMessage (@ .updates[0])', upd, 'updateMessagePoll') diff --git a/packages/client/src/methods/messages/edit-message.ts b/packages/client/src/methods/messages/edit-message.ts index a1c2dc08..2a106a40 100644 --- a/packages/client/src/methods/messages/edit-message.ts +++ b/packages/client/src/methods/messages/edit-message.ts @@ -78,6 +78,12 @@ export async function editMessage( * @param total Total file size in bytes */ progressCallback?: (uploaded: number, total: number) => void + + /** + * Whether to dispatch the edit message event + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { const { chatId, message } = normalizeInputMessageId(params) @@ -115,5 +121,5 @@ export async function editMessage( media, }) - return _findMessageInUpdate(client, res, true) + return _findMessageInUpdate(client, res, true, !params.shouldDispatch) } diff --git a/packages/client/src/methods/messages/find-in-update.ts b/packages/client/src/methods/messages/find-in-update.ts index 026b6675..830a867a 100644 --- a/packages/client/src/methods/messages/find-in-update.ts +++ b/packages/client/src/methods/messages/find-in-update.ts @@ -5,10 +5,15 @@ import { PeersIndex } from '../../types/peers' import { assertIsUpdatesGroup } from '../../utils/updates-utils' /** @internal */ -export function _findMessageInUpdate(client: BaseTelegramClient, res: tl.TypeUpdates, isEdit = false): Message { +export function _findMessageInUpdate( + client: BaseTelegramClient, + res: tl.TypeUpdates, + isEdit = false, + noDispatch = true, +): Message { assertIsUpdatesGroup('_findMessageInUpdate', res) - client.network.handleUpdate(res, true) + client.network.handleUpdate(res, noDispatch) for (const u of res.updates) { if ( diff --git a/packages/client/src/methods/messages/forward-messages.ts b/packages/client/src/methods/messages/forward-messages.ts index c179c947..580c0635 100644 --- a/packages/client/src/methods/messages/forward-messages.ts +++ b/packages/client/src/methods/messages/forward-messages.ts @@ -89,6 +89,12 @@ export interface ForwardMessageOptions { * Peer to use when sending the message. */ sendAs?: InputPeerLike + + /** + * Whether to dispatch the forwarded messages + * to the client's update handler. + */ + shouldDispatch?: true } /** @@ -139,7 +145,7 @@ export async function forwardMessagesById( assertIsUpdatesGroup('messages.forwardMessages', res) - client.network.handleUpdate(res, true) + client.network.handleUpdate(res, !params.shouldDispatch) const peers = PeersIndex.from(res) diff --git a/packages/client/src/methods/messages/pin-message.ts b/packages/client/src/methods/messages/pin-message.ts index b2d78e64..eaa57a35 100644 --- a/packages/client/src/methods/messages/pin-message.ts +++ b/packages/client/src/methods/messages/pin-message.ts @@ -1,13 +1,16 @@ -import { BaseTelegramClient } from '@mtcute/core' +import { BaseTelegramClient, MtTypeAssertionError } from '@mtcute/core' -import { InputMessageId, normalizeInputMessageId } from '../../types' +import { InputMessageId, Message, normalizeInputMessageId } from '../../types' import { resolvePeer } from '../users/resolve-peer' +import { _findMessageInUpdate } from './find-in-update' /** * Pin a message in a group, supergroup, channel or PM. * * For supergroups/channels, you must have appropriate permissions, * either as an admin, or as default permissions + * + * @returns Service message about pinned message, if one was generated. */ export async function pinMessage( client: BaseTelegramClient, @@ -16,9 +19,15 @@ export async function pinMessage( notify?: boolean /** Whether to pin for both sides (only for private chats) */ bothSides?: boolean + + /** + * Whether to dispatch the returned service message (if any) + * to the client's update handler. + */ + shouldDispatch?: true }, -): Promise { - const { notify, bothSides } = params ?? {} +): Promise { + const { notify, bothSides, shouldDispatch } = params ?? {} const { chatId, message } = normalizeInputMessageId(params) const res = await client.call({ @@ -29,5 +38,14 @@ export async function pinMessage( pmOneside: !bothSides, }) - client.network.handleUpdate(res) + try { + return _findMessageInUpdate(client, res, false, !shouldDispatch) + } catch (e) { + if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') { + // no service message + return null + } + + throw e + } } diff --git a/packages/client/src/methods/messages/send-media-group.ts b/packages/client/src/methods/messages/send-media-group.ts index 27060085..5777ccf4 100644 --- a/packages/client/src/methods/messages/send-media-group.ts +++ b/packages/client/src/methods/messages/send-media-group.ts @@ -193,7 +193,7 @@ export async function sendMediaGroup( sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined, }) - assertIsUpdatesGroup('_findMessageInUpdate', res) + assertIsUpdatesGroup('sendMediaGroup', res) client.network.handleUpdate(res, true) const peers = PeersIndex.from(res) diff --git a/packages/client/src/methods/messages/send-media.ts b/packages/client/src/methods/messages/send-media.ts index a092da62..8a733d9f 100644 --- a/packages/client/src/methods/messages/send-media.ts +++ b/packages/client/src/methods/messages/send-media.ts @@ -131,6 +131,12 @@ export async function sendMedia( * Peer to use when sending the message. */ sendAs?: InputPeerLike + + /** + * Whether to dispatch the returned message + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { if (!params) params = {} @@ -196,7 +202,7 @@ export async function sendMedia( sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined, }) - const msg = _findMessageInUpdate(client, res) + const msg = _findMessageInUpdate(client, res, false, !params.shouldDispatch) return msg } diff --git a/packages/client/src/methods/messages/send-reaction.ts b/packages/client/src/methods/messages/send-reaction.ts index 51ede864..a9c381d9 100644 --- a/packages/client/src/methods/messages/send-reaction.ts +++ b/packages/client/src/methods/messages/send-reaction.ts @@ -17,6 +17,12 @@ export async function sendReaction( emoji?: InputReaction | null /** Whether to use a big reaction */ big?: boolean + + /** + * Whether to dispatch the returned edit message event + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { const { emoji, big } = params @@ -40,5 +46,5 @@ export async function sendReaction( // idk why, they contain literally the same data // so we can just return the message from the first one - return _findMessageInUpdate(client, res, true) + return _findMessageInUpdate(client, res, true, !params.shouldDispatch) } diff --git a/packages/client/src/methods/messages/send-text.ts b/packages/client/src/methods/messages/send-text.ts index 9985e987..ece3d394 100644 --- a/packages/client/src/methods/messages/send-text.ts +++ b/packages/client/src/methods/messages/send-text.ts @@ -115,6 +115,12 @@ export async function sendText( * Peer to use when sending the message. */ sendAs?: InputPeerLike + + /** + * Whether to dispatch the returned message + * to the client's update handler. + */ + shouldDispatch?: true }, ): Promise { if (!params) params = {} @@ -238,7 +244,7 @@ export async function sendText( return ret } - const msg = _findMessageInUpdate(client, res) + const msg = _findMessageInUpdate(client, res, false, !params.shouldDispatch) return msg } diff --git a/packages/client/src/methods/updates/types.ts b/packages/client/src/methods/updates/types.ts index a09d8341..b0c2f833 100644 --- a/packages/client/src/methods/updates/types.ts +++ b/packages/client/src/methods/updates/types.ts @@ -21,7 +21,7 @@ export interface UpdatesManagerParams { /** * **ADVANCED** * - * Whether to disable no-dispatch mechanism. + * Whether to globally disable no-dispatch mechanism. * * No-dispatch is a mechanism that allows you to call methods * that return updates and correctly handle them, without @@ -39,6 +39,9 @@ export interface UpdatesManagerParams { * * Disabling it may also improve performance, but it's not guaranteed. * + * > **Note**: you can disable this on per-request basis by passing + * > `shouldDispatch: true` to the method call that accepts it. + * * @default false */ disableNoDispatch?: boolean