feat(client): reactions for bots
This commit is contained in:
parent
9459748d0d
commit
0474ab918a
12 changed files with 273 additions and 36 deletions
|
@ -18,4 +18,6 @@ bot_chat_join_request = BotChatJoinRequestUpdate in ChatJoinRequestUpdateContext
|
|||
chat_join_request = ChatJoinRequestUpdate
|
||||
pre_checkout_query = PreCheckoutQuery in PreCheckoutQueryContext
|
||||
story: StoryUpdate = StoryUpdate
|
||||
delete_story = DeleteStoryUpdate
|
||||
delete_story = DeleteStoryUpdate
|
||||
bot_reaction: BotReactionUpdate = BotReactionUpdate
|
||||
bot_reaction_count: BotReactionCountUpdate = BotReactionCountUpdate
|
|
@ -260,6 +260,8 @@ import {
|
|||
BoostStats,
|
||||
BotChatJoinRequestUpdate,
|
||||
BotCommands,
|
||||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
|
@ -532,6 +534,20 @@ export interface TelegramClient extends BaseTelegramClient {
|
|||
* @param handler Delete story handler
|
||||
*/
|
||||
on(name: 'delete_story', handler: (upd: DeleteStoryUpdate) => void): this
|
||||
/**
|
||||
* Register a bot reaction update handler
|
||||
*
|
||||
* @param name Event name
|
||||
* @param handler Bot reaction update handler
|
||||
*/
|
||||
on(name: 'bot_reaction', handler: (upd: BotReactionUpdate) => void): this
|
||||
/**
|
||||
* Register a bot reaction count update handler
|
||||
*
|
||||
* @param name Event name
|
||||
* @param handler Bot reaction count update handler
|
||||
*/
|
||||
on(name: 'bot_reaction_count', handler: (upd: BotReactionCountUpdate) => void): this
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
on(name: string, handler: (...args: any[]) => void): this
|
||||
|
@ -3907,12 +3923,14 @@ export interface TelegramClient extends BaseTelegramClient {
|
|||
*
|
||||
* **Available**: 👤 users only
|
||||
*
|
||||
* @returns Message to which the reaction was sent
|
||||
* @returns
|
||||
* Message to which the reaction was sent, if available.
|
||||
* The message is normally available for users, but may not be available for bots in PMs.
|
||||
*/
|
||||
sendReaction(
|
||||
params: InputMessageId & {
|
||||
/** Reaction emoji (or `null` to remove reaction) */
|
||||
emoji?: InputReaction | null
|
||||
emoji?: MaybeArray<InputReaction> | null
|
||||
/** Whether to use a big reaction */
|
||||
big?: boolean
|
||||
|
||||
|
@ -3922,7 +3940,7 @@ export interface TelegramClient extends BaseTelegramClient {
|
|||
*/
|
||||
shouldDispatch?: true
|
||||
},
|
||||
): Promise<Message>
|
||||
): Promise<Message | null>
|
||||
/** Send a text in reply to a given message */
|
||||
replyText(message: Message, ...params: ParametersSkip2<typeof sendText>): ReturnType<typeof sendText>
|
||||
/** Send a media in reply to a given message */
|
||||
|
|
|
@ -24,6 +24,8 @@ import {
|
|||
BoostStats,
|
||||
BotChatJoinRequestUpdate,
|
||||
BotCommands,
|
||||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BaseTelegramClient, MtTypeAssertionError } from '@mtcute/core'
|
||||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputPeerLike, Message, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||
import { isInputPeerChannel, isInputPeerChat, toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
||||
|
@ -56,14 +56,5 @@ export async function banChatMember(
|
|||
})
|
||||
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
|
||||
|
||||
try {
|
||||
return _findMessageInUpdate(client, res, false, !shouldDispatch)
|
||||
} catch (e) {
|
||||
if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') {
|
||||
// no service message
|
||||
return null
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
return _findMessageInUpdate(client, res, false, !shouldDispatch, true)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,44 @@
|
|||
/* eslint-disable max-params */
|
||||
import { BaseTelegramClient, MtTypeAssertionError, tl } from '@mtcute/core'
|
||||
|
||||
import { Message } from '../../types/messages/index.js'
|
||||
import { PeersIndex } from '../../types/peers/index.js'
|
||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
||||
|
||||
/** @internal */
|
||||
/**
|
||||
* @internal
|
||||
* @noemit
|
||||
*/
|
||||
export function _findMessageInUpdate(
|
||||
client: BaseTelegramClient,
|
||||
res: tl.TypeUpdates,
|
||||
isEdit?: boolean,
|
||||
noDispatch?: boolean,
|
||||
allowNull?: false,
|
||||
): Message
|
||||
/**
|
||||
* @internal
|
||||
* @noemit
|
||||
*/
|
||||
export function _findMessageInUpdate(
|
||||
client: BaseTelegramClient,
|
||||
res: tl.TypeUpdates,
|
||||
isEdit?: boolean,
|
||||
noDispatch?: boolean,
|
||||
allowNull?: true,
|
||||
): Message | null
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @noemit
|
||||
*/
|
||||
export function _findMessageInUpdate(
|
||||
client: BaseTelegramClient,
|
||||
res: tl.TypeUpdates,
|
||||
isEdit = false,
|
||||
noDispatch = true,
|
||||
): Message {
|
||||
allowNull = false,
|
||||
): Message | null {
|
||||
assertIsUpdatesGroup('_findMessageInUpdate', res)
|
||||
|
||||
client.network.handleUpdate(res, noDispatch)
|
||||
|
@ -29,6 +57,8 @@ export function _findMessageInUpdate(
|
|||
}
|
||||
}
|
||||
|
||||
if (allowNull) return null
|
||||
|
||||
throw new MtTypeAssertionError(
|
||||
'_findInUpdate (@ .updates[*])',
|
||||
'updateNewMessage | updateNewChannelMessage | updateNewScheduledMessage',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BaseTelegramClient, MtTypeAssertionError } from '@mtcute/core'
|
||||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
|
||||
import { InputMessageId, Message, normalizeInputMessageId } from '../../types/index.js'
|
||||
import { resolvePeer } from '../users/resolve-peer.js'
|
||||
|
@ -38,14 +38,5 @@ export async function pinMessage(
|
|||
pmOneside: !bothSides,
|
||||
})
|
||||
|
||||
try {
|
||||
return _findMessageInUpdate(client, res, false, !shouldDispatch)
|
||||
} catch (e) {
|
||||
if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') {
|
||||
// no service message
|
||||
return null
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
return _findMessageInUpdate(client, res, false, !shouldDispatch, true)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
|
||||
|
||||
import { InputMessageId, InputReaction, Message, normalizeInputMessageId, normalizeInputReaction } from '../../types/index.js'
|
||||
import {
|
||||
InputMessageId,
|
||||
InputReaction,
|
||||
Message,
|
||||
normalizeInputMessageId,
|
||||
normalizeInputReaction,
|
||||
} from '../../types/index.js'
|
||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
||||
import { resolvePeer } from '../users/resolve-peer.js'
|
||||
import { _findMessageInUpdate } from './find-in-update.js'
|
||||
|
@ -8,13 +14,15 @@ import { _findMessageInUpdate } from './find-in-update.js'
|
|||
/**
|
||||
* Send or remove a reaction.
|
||||
*
|
||||
* @returns Message to which the reaction was sent
|
||||
* @returns
|
||||
* Message to which the reaction was sent, if available.
|
||||
* The message is normally available for users, but may not be available for bots in PMs.
|
||||
*/
|
||||
export async function sendReaction(
|
||||
client: BaseTelegramClient,
|
||||
params: InputMessageId & {
|
||||
/** Reaction emoji (or `null` to remove reaction) */
|
||||
emoji?: InputReaction | null
|
||||
emoji?: MaybeArray<InputReaction> | null
|
||||
/** Whether to use a big reaction */
|
||||
big?: boolean
|
||||
|
||||
|
@ -24,17 +32,18 @@ export async function sendReaction(
|
|||
*/
|
||||
shouldDispatch?: true
|
||||
},
|
||||
): Promise<Message> {
|
||||
): Promise<Message | null> {
|
||||
const { emoji, big } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
|
||||
const reaction = normalizeInputReaction(emoji)
|
||||
const emojis = Array.isArray(emoji) ? emoji : [emoji]
|
||||
const reactions = emojis.map(normalizeInputReaction)
|
||||
|
||||
const res = await client.call({
|
||||
_: 'messages.sendReaction',
|
||||
peer: await resolvePeer(client, chatId),
|
||||
msgId: message,
|
||||
reaction: [reaction],
|
||||
reaction: reactions,
|
||||
big,
|
||||
})
|
||||
|
||||
|
@ -45,6 +54,9 @@ export async function sendReaction(
|
|||
// updateMessageReactions
|
||||
// idk why, they contain literally the same data
|
||||
// so we can just return the message from the first one
|
||||
//
|
||||
// for whatever reason, sendReaction for bots returns empty updates
|
||||
// group in pms, so we should handle that too
|
||||
|
||||
return _findMessageInUpdate(client, res, true, !params.shouldDispatch)
|
||||
return _findMessageInUpdate(client, res, true, !params.shouldDispatch, true)
|
||||
}
|
||||
|
|
115
packages/client/src/types/updates/bot-reaction.ts
Normal file
115
packages/client/src/types/updates/bot-reaction.ts
Normal file
|
@ -0,0 +1,115 @@
|
|||
import { tl } from '@mtcute/core'
|
||||
|
||||
import { makeInspectable } from '../../utils/inspectable.js'
|
||||
import { memoizeGetters } from '../../utils/memoize.js'
|
||||
import { Chat } from '../peers/chat.js'
|
||||
import { parsePeer, Peer } from '../peers/peer.js'
|
||||
import { PeersIndex } from '../peers/peers-index.js'
|
||||
import { ReactionCount } from '../reactions/reaction-count.js'
|
||||
import { InputReaction, toReactionEmoji } from '../reactions/types.js'
|
||||
|
||||
/**
|
||||
* A reaction to a message was changed by a user.
|
||||
*
|
||||
* These updates are only received for bots - for PMs and in chats
|
||||
* where the bot is an administrator.
|
||||
*
|
||||
* Reactions sent by other bots are not received.
|
||||
*/
|
||||
export class BotReactionUpdate {
|
||||
constructor(
|
||||
readonly raw: tl.RawUpdateBotMessageReaction,
|
||||
readonly _peers: PeersIndex,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Chat where the reaction has been changed
|
||||
*/
|
||||
get chat(): Chat {
|
||||
return Chat._parseFromPeer(this.raw.peer, this._peers)
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the message where the reaction has been changed
|
||||
*/
|
||||
get messageId(): number {
|
||||
return this.raw.msgId
|
||||
}
|
||||
|
||||
/**
|
||||
* Date when the reaction has been changed
|
||||
*/
|
||||
get date(): Date {
|
||||
return new Date(this.raw.date * 1000)
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the user who has set/removed the reaction
|
||||
*/
|
||||
get actor(): Peer {
|
||||
return parsePeer(this.raw.actor, this._peers)
|
||||
}
|
||||
|
||||
/**
|
||||
* List of reactions before the change
|
||||
*/
|
||||
get before(): InputReaction[] {
|
||||
return this.raw.oldReactions.map((it) => toReactionEmoji(it))
|
||||
}
|
||||
|
||||
/**
|
||||
* List of reactions after the change
|
||||
*/
|
||||
get after(): InputReaction[] {
|
||||
return this.raw.newReactions.map((it) => toReactionEmoji(it))
|
||||
}
|
||||
}
|
||||
|
||||
memoizeGetters(BotReactionUpdate, ['chat', 'actor', 'before', 'after'])
|
||||
makeInspectable(BotReactionUpdate)
|
||||
|
||||
/**
|
||||
* The count of reactions to a message has been updated.
|
||||
*
|
||||
* These updates are only received for bots in chats where
|
||||
* the bot is an administrator. Unlike {@link BotReactionUpdate},
|
||||
* this update is used for chats where the list of users who
|
||||
* reacted to a message is not visible (e.g. channels).
|
||||
*/
|
||||
export class BotReactionCountUpdate {
|
||||
constructor(
|
||||
readonly raw: tl.RawUpdateBotMessageReactions,
|
||||
readonly _peers: PeersIndex,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Chat where the reaction has been changed
|
||||
*/
|
||||
get chat(): Chat {
|
||||
return Chat._parseFromPeer(this.raw.peer, this._peers)
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the message where the reaction has been changed
|
||||
*/
|
||||
get messageId(): number {
|
||||
return this.raw.msgId
|
||||
}
|
||||
|
||||
/**
|
||||
* Date when the reaction has been changed
|
||||
*/
|
||||
get date(): Date {
|
||||
return new Date(this.raw.date * 1000)
|
||||
}
|
||||
|
||||
/**
|
||||
* The new list of reactions to the message
|
||||
*/
|
||||
get reactions(): ReactionCount[] {
|
||||
return this.raw.reactions.map((it) => new ReactionCount(it))
|
||||
}
|
||||
}
|
||||
|
||||
memoizeGetters(BotReactionCountUpdate, ['chat'])
|
||||
makeInspectable(BotReactionCountUpdate)
|
|
@ -6,6 +6,7 @@ import { ChatJoinRequestUpdate } from './chat-join-request.js'
|
|||
import { ChatMemberUpdate } from './chat-member-update.js'
|
||||
import { InlineQuery } from './inline-query.js'
|
||||
export type { ChatMemberUpdateType } from './chat-member-update.js'
|
||||
import { BotReactionCountUpdate, BotReactionUpdate } from './bot-reaction.js'
|
||||
import { ChosenInlineResult } from './chosen-inline-result.js'
|
||||
import { DeleteMessageUpdate } from './delete-message-update.js'
|
||||
import { DeleteStoryUpdate } from './delete-story-update.js'
|
||||
|
@ -19,6 +20,8 @@ import { UserTypingUpdate } from './user-typing-update.js'
|
|||
|
||||
export {
|
||||
BotChatJoinRequestUpdate,
|
||||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
CallbackQuery,
|
||||
ChatJoinRequestUpdate,
|
||||
|
@ -59,5 +62,7 @@ export type ParsedUpdate =
|
|||
| { name: 'pre_checkout_query'; data: PreCheckoutQuery }
|
||||
| { name: 'story'; data: StoryUpdate }
|
||||
| { name: 'delete_story'; data: DeleteStoryUpdate }
|
||||
| { name: 'bot_reaction'; data: BotReactionUpdate }
|
||||
| { name: 'bot_reaction_count'; data: BotReactionCountUpdate }
|
||||
|
||||
// end-codegen
|
||||
|
|
|
@ -3,6 +3,8 @@ import { tl } from '@mtcute/core'
|
|||
|
||||
import {
|
||||
BotChatJoinRequestUpdate,
|
||||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
CallbackQuery,
|
||||
ChatJoinRequestUpdate,
|
||||
|
@ -88,6 +90,10 @@ export function _parseUpdate(update: tl.TypeUpdate, peers: PeersIndex): ParsedUp
|
|||
data: new StoryUpdate(update, peers),
|
||||
}
|
||||
}
|
||||
case 'updateBotMessageReaction':
|
||||
return { name: 'bot_reaction', data: new BotReactionUpdate(update, peers) }
|
||||
case 'updateBotMessageReactions':
|
||||
return { name: 'bot_reaction_count', data: new BotReactionCountUpdate(update, peers) }
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
// ^^ will be looked into in MTQ-29
|
||||
|
||||
import {
|
||||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
ChatJoinRequestUpdate,
|
||||
ChatMemberUpdate,
|
||||
|
@ -38,6 +40,8 @@ import { filters, UpdateFilter } from './filters/index.js'
|
|||
// begin-codegen-imports
|
||||
import {
|
||||
BotChatJoinRequestHandler,
|
||||
BotReactionCountUpdateHandler,
|
||||
BotReactionUpdateHandler,
|
||||
BotStoppedHandler,
|
||||
CallbackQueryHandler,
|
||||
ChatJoinRequestHandler,
|
||||
|
@ -1698,5 +1702,57 @@ export class Dispatcher<State extends object = never> {
|
|||
this._addKnownHandler('delete_story', filter, handler, group)
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a bot reaction update handler without any filters
|
||||
*
|
||||
* @param handler Bot reaction update handler
|
||||
* @param group Handler group index
|
||||
*/
|
||||
onBotReactionUpdate(handler: BotReactionUpdateHandler['callback'], group?: number): void
|
||||
|
||||
/**
|
||||
* Register a bot reaction update handler with a filter
|
||||
*
|
||||
* @param filter Update filter
|
||||
* @param handler Bot reaction update handler
|
||||
* @param group Handler group index
|
||||
*/
|
||||
onBotReactionUpdate<Mod>(
|
||||
filter: UpdateFilter<UpdateContext<BotReactionUpdate>, Mod>,
|
||||
handler: BotReactionUpdateHandler<filters.Modify<UpdateContext<BotReactionUpdate>, Mod>>['callback'],
|
||||
group?: number,
|
||||
): void
|
||||
|
||||
/** @internal */
|
||||
onBotReactionUpdate(filter: any, handler?: any, group?: number): void {
|
||||
this._addKnownHandler('bot_reaction', filter, handler, group)
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a bot reaction count update handler without any filters
|
||||
*
|
||||
* @param handler Bot reaction count update handler
|
||||
* @param group Handler group index
|
||||
*/
|
||||
onBotReactionCountUpdate(handler: BotReactionCountUpdateHandler['callback'], group?: number): void
|
||||
|
||||
/**
|
||||
* Register a bot reaction count update handler with a filter
|
||||
*
|
||||
* @param filter Update filter
|
||||
* @param handler Bot reaction count update handler
|
||||
* @param group Handler group index
|
||||
*/
|
||||
onBotReactionCountUpdate<Mod>(
|
||||
filter: UpdateFilter<UpdateContext<BotReactionCountUpdate>, Mod>,
|
||||
handler: BotReactionCountUpdateHandler<filters.Modify<UpdateContext<BotReactionCountUpdate>, Mod>>['callback'],
|
||||
group?: number,
|
||||
): void
|
||||
|
||||
/** @internal */
|
||||
onBotReactionCountUpdate(filter: any, handler?: any, group?: number): void {
|
||||
this._addKnownHandler('bot_reaction_count', filter, handler, group)
|
||||
}
|
||||
|
||||
// end-codegen
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import {
|
||||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
ChatJoinRequestUpdate,
|
||||
ChatMemberUpdate,
|
||||
|
@ -82,6 +84,11 @@ export type ChatJoinRequestHandler<T = UpdateContext<ChatJoinRequestUpdate>> = P
|
|||
export type PreCheckoutQueryHandler<T = PreCheckoutQueryContext> = ParsedUpdateHandler<'pre_checkout_query', T>
|
||||
export type StoryUpdateHandler<T = UpdateContext<StoryUpdate>> = ParsedUpdateHandler<'story', T>
|
||||
export type DeleteStoryHandler<T = UpdateContext<DeleteStoryUpdate>> = ParsedUpdateHandler<'delete_story', T>
|
||||
export type BotReactionUpdateHandler<T = UpdateContext<BotReactionUpdate>> = ParsedUpdateHandler<'bot_reaction', T>
|
||||
export type BotReactionCountUpdateHandler<T = UpdateContext<BotReactionCountUpdate>> = ParsedUpdateHandler<
|
||||
'bot_reaction_count',
|
||||
T
|
||||
>
|
||||
|
||||
export type UpdateHandler =
|
||||
| RawUpdateHandler
|
||||
|
@ -105,5 +112,7 @@ export type UpdateHandler =
|
|||
| PreCheckoutQueryHandler
|
||||
| StoryUpdateHandler
|
||||
| DeleteStoryHandler
|
||||
| BotReactionUpdateHandler
|
||||
| BotReactionCountUpdateHandler
|
||||
|
||||
// end-codegen
|
||||
|
|
Loading…
Reference in a new issue