diff --git a/packages/core/scripts/update-types.txt b/packages/core/scripts/update-types.txt index 9e6b0123..fb833e40 100644 --- a/packages/core/scripts/update-types.txt +++ b/packages/core/scripts/update-types.txt @@ -8,6 +8,7 @@ inline_query = InlineQuery in InlineQueryContext chosen_inline_result = ChosenInlineResult in ChosenInlineResultContext callback_query = CallbackQuery + State in CallbackQueryContext inline_callback_query = InlineCallbackQuery + State in InlineCallbackQueryContext +business_callback_query = BusinessCallbackQuery + State in BusinessCallbackQueryContext poll: PollUpdate = PollUpdate poll_vote = PollVoteUpdate user_status: UserStatusUpdate = UserStatusUpdate diff --git a/packages/core/src/highlevel/methods/messages/find-in-update.ts b/packages/core/src/highlevel/methods/messages/find-in-update.ts index 7d3d414b..38a6b2d4 100644 --- a/packages/core/src/highlevel/methods/messages/find-in-update.ts +++ b/packages/core/src/highlevel/methods/messages/find-in-update.ts @@ -59,9 +59,12 @@ export function _findMessageInUpdate( if (isEdit) { if ( !( - u._ === 'updateEditMessage' || - u._ === 'updateEditChannelMessage' || - u._ === 'updateBotEditBusinessMessage' + ( + u._ === 'updateEditMessage' || + u._ === 'updateEditChannelMessage' || + u._ === 'updateBotEditBusinessMessage' || + u._ === 'updateBotNewBusinessMessage' + ) // for whatever reason ) ) { continue diff --git a/packages/core/src/highlevel/types/updates/callback-query.ts b/packages/core/src/highlevel/types/updates/callback-query.ts index adb45ac2..c88577ac 100644 --- a/packages/core/src/highlevel/types/updates/callback-query.ts +++ b/packages/core/src/highlevel/types/updates/callback-query.ts @@ -5,6 +5,7 @@ import { MtArgumentError } from '../../../types/errors.js' import { makeInspectable } from '../../utils/index.js' import { encodeInlineMessageId } from '../../utils/inline-utils.js' import { memoizeGetters } from '../../utils/memoize.js' +import { Message } from '../messages/message.js' import { Chat } from '../peers/chat.js' import { PeersIndex } from '../peers/peers-index.js' import { User } from '../peers/user.js' @@ -12,7 +13,10 @@ import { User } from '../peers/user.js' /** Base class for callback queries */ class BaseCallbackQuery { constructor( - readonly raw: tl.RawUpdateBotCallbackQuery | tl.RawUpdateInlineBotCallbackQuery, + readonly raw: + | tl.RawUpdateBotCallbackQuery + | tl.RawUpdateInlineBotCallbackQuery + | tl.RawUpdateBusinessBotCallbackQuery, readonly _peers: PeersIndex, ) {} @@ -67,6 +71,8 @@ class BaseCallbackQuery { * short name of the game that should be returned. */ get game(): string | null { + if (this.raw._ === 'updateBusinessBotCallbackQuery') return null + return this.raw.gameShortName ?? null } } @@ -138,3 +144,35 @@ export class InlineCallbackQuery extends BaseCallbackQuery { memoizeGetters(InlineCallbackQuery, ['user', 'dataStr', 'inlineMessageIdStr']) makeInspectable(InlineCallbackQuery) + +/** + * A callback query originating from a message sent by the bot via a business connection + */ +export class BusinessCallbackQuery extends BaseCallbackQuery { + constructor( + readonly raw: tl.RawUpdateBusinessBotCallbackQuery, + _peers: PeersIndex, + ) { + super(raw, _peers) + } + + /** ID of the business connection */ + get connectionId(): string { + return this.raw.connectionId + } + + /** Message containing the button */ + get message(): Message { + return new Message(this.raw.message, this._peers) + } + + /** Message that {@link message} is a reply to (if any) */ + get replyToMessage(): Message | null { + if (!this.raw.replyToMessage) return null + + return new Message(this.raw.replyToMessage, this._peers) + } +} + +memoizeGetters(BusinessCallbackQuery, ['user', 'dataStr', 'message', 'replyToMessage']) +makeInspectable(BusinessCallbackQuery) diff --git a/packages/core/src/highlevel/types/updates/index.ts b/packages/core/src/highlevel/types/updates/index.ts index ad772c0d..dfd630ac 100644 --- a/packages/core/src/highlevel/types/updates/index.ts +++ b/packages/core/src/highlevel/types/updates/index.ts @@ -1,7 +1,7 @@ import type { BusinessConnection, Message } from '../../types/index.js' import { BotChatJoinRequestUpdate } from './bot-chat-join-request.js' import { BotStoppedUpdate } from './bot-stopped.js' -import { CallbackQuery, InlineCallbackQuery } from './callback-query.js' +import { BusinessCallbackQuery, CallbackQuery, InlineCallbackQuery } from './callback-query.js' import { ChatJoinRequestUpdate } from './chat-join-request.js' import { ChatMemberUpdate } from './chat-member-update.js' import { InlineQuery } from './inline-query.js' @@ -25,6 +25,7 @@ export { BotReactionCountUpdate, BotReactionUpdate, BotStoppedUpdate, + BusinessCallbackQuery, BusinessMessage, CallbackQuery, ChatJoinRequestUpdate, @@ -55,6 +56,7 @@ export type ParsedUpdate = | { name: 'chosen_inline_result'; data: ChosenInlineResult } | { name: 'callback_query'; data: CallbackQuery } | { name: 'inline_callback_query'; data: InlineCallbackQuery } + | { name: 'business_callback_query'; data: BusinessCallbackQuery } | { name: 'poll'; data: PollUpdate } | { name: 'poll_vote'; data: PollVoteUpdate } | { name: 'user_status'; data: UserStatusUpdate } diff --git a/packages/core/src/highlevel/types/updates/parse-update.ts b/packages/core/src/highlevel/types/updates/parse-update.ts index c0a662f3..5baa26db 100644 --- a/packages/core/src/highlevel/types/updates/parse-update.ts +++ b/packages/core/src/highlevel/types/updates/parse-update.ts @@ -6,6 +6,7 @@ import { BotReactionCountUpdate, BotReactionUpdate, BotStoppedUpdate, + BusinessCallbackQuery, BusinessConnection, BusinessMessage, CallbackQuery, @@ -105,6 +106,8 @@ export function _parseUpdate(update: tl.TypeUpdate, peers: PeersIndex): ParsedUp return { name: 'edit_business_message', data: new BusinessMessage(update, peers) } case 'updateBotDeleteBusinessMessage': return { name: 'delete_business_message', data: new DeleteBusinessMessageUpdate(update, peers) } + case 'updateBusinessBotCallbackQuery': + return { name: 'business_callback_query', data: new BusinessCallbackQuery(update, peers) } default: return null } diff --git a/packages/dispatcher/src/context/callback-query.ts b/packages/dispatcher/src/context/callback-query.ts index 2018a00a..385befa1 100644 --- a/packages/dispatcher/src/context/callback-query.ts +++ b/packages/dispatcher/src/context/callback-query.ts @@ -1,4 +1,4 @@ -import { CallbackQuery, InlineCallbackQuery, MaybePromise, Message } from '@mtcute/core' +import { BusinessCallbackQuery, CallbackQuery, InlineCallbackQuery, MaybePromise, Message } from '@mtcute/core' import { TelegramClient } from '@mtcute/core/client.js' import { UpdateContext } from './base.js' @@ -88,3 +88,37 @@ export class InlineCallbackQueryContext extends InlineCallbackQuery implements U }) } } + +/** + * Context of an callback query update originated from a business connection message + * + * This is a subclass of {@link BusinessCallbackQuery}, so all its fields are also available. + */ +export class BusinessCallbackQueryContext + extends BusinessCallbackQuery + implements UpdateContext { + readonly _name = 'business_callback_query' + + constructor( + readonly client: TelegramClient, + query: BusinessCallbackQuery, + ) { + super(query.raw, query._peers) + } + + /** Answer to this callback query */ + answer(params: Parameters[1]) { + return this.client.answerCallbackQuery(this.id, params) + } + + /** + * Edit the message that contained the callback button that was clicked. + */ + async editMessage(params: Omit[0], 'messageId'>) { + return this.client.editMessage({ + message: this.message, + businessConnectionId: this.connectionId, + ...params, + }) + } +} diff --git a/packages/dispatcher/src/context/index.ts b/packages/dispatcher/src/context/index.ts index aeafdf77..385735e8 100644 --- a/packages/dispatcher/src/context/index.ts +++ b/packages/dispatcher/src/context/index.ts @@ -1,4 +1,5 @@ export * from './base.js' +export * from './business-message.js' export * from './callback-query.js' export * from './chat-join-request.js' export * from './chosen-inline-result.js' diff --git a/packages/dispatcher/src/context/parse.ts b/packages/dispatcher/src/context/parse.ts index 7a4cd102..acf8ef40 100644 --- a/packages/dispatcher/src/context/parse.ts +++ b/packages/dispatcher/src/context/parse.ts @@ -3,7 +3,7 @@ import { TelegramClient } from '@mtcute/core/client.js' import { UpdateContextDistributed } from './base.js' import { BusinessMessageContext } from './business-message.js' -import { CallbackQueryContext, InlineCallbackQueryContext } from './callback-query.js' +import { BusinessCallbackQueryContext, CallbackQueryContext, InlineCallbackQueryContext } from './callback-query.js' import { ChatJoinRequestUpdateContext } from './chat-join-request.js' import { ChosenInlineResultContext } from './chosen-inline-result.js' import { InlineQueryContext } from './inline-query.js' @@ -25,6 +25,8 @@ export function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpd return new CallbackQueryContext(client, update.data) case 'inline_callback_query': return new InlineCallbackQueryContext(client, update.data) + case 'business_callback_query': + return new BusinessCallbackQueryContext(client, update.data) case 'bot_chat_join_request': return new ChatJoinRequestUpdateContext(client, update.data) case 'pre_checkout_query': diff --git a/packages/dispatcher/src/dispatcher.ts b/packages/dispatcher/src/dispatcher.ts index 66ecd9e3..ee97e938 100644 --- a/packages/dispatcher/src/dispatcher.ts +++ b/packages/dispatcher/src/dispatcher.ts @@ -30,6 +30,7 @@ import { TelegramClient } from '@mtcute/core/client.js' import { UpdateContext } from './context/base.js' import { BusinessMessageContext } from './context/business-message.js' import { + BusinessCallbackQueryContext, CallbackQueryContext, ChatJoinRequestUpdateContext, ChosenInlineResultContext, @@ -47,6 +48,7 @@ import { BotReactionCountUpdateHandler, BotReactionUpdateHandler, BotStoppedHandler, + BusinessCallbackQueryHandler, BusinessConnectionUpdateHandler, BusinessMessageGroupHandler, CallbackQueryHandler, @@ -1141,7 +1143,7 @@ export class Dispatcher { */ onAnyCallbackQuery( handler: CallbackQueryHandler< - CallbackQueryContext | InlineCallbackQueryContext, + CallbackQueryContext | InlineCallbackQueryContext | BusinessCallbackQueryContext, State extends never ? never : UpdateState >['callback'], group?: number, @@ -1155,9 +1157,13 @@ export class Dispatcher { * @param group Handler group index */ onAnyCallbackQuery( - filter: UpdateFilter, + filter: UpdateFilter< + CallbackQueryContext | InlineCallbackQueryContext | BusinessCallbackQueryContext, + Mod, + State + >, handler: CallbackQueryHandler< - filters.Modify, + filters.Modify, State extends never ? never : UpdateState >['callback'], group?: number, @@ -1171,9 +1177,9 @@ export class Dispatcher { * @param group Handler group index */ onAnyCallbackQuery( - filter: UpdateFilter, + filter: UpdateFilter, handler: CallbackQueryHandler< - filters.Modify, + filters.Modify, State extends never ? never : UpdateState >['callback'], group?: number, @@ -1183,6 +1189,7 @@ export class Dispatcher { onAnyCallbackQuery(filter: any, handler?: any, group?: number): void { this._addKnownHandler('callback_query', filter, handler, group) this._addKnownHandler('inline_callback_query', filter, handler, group) + this._addKnownHandler('business_callback_query', filter, handler, group) } // begin-codegen @@ -1537,6 +1544,57 @@ export class Dispatcher { this._addKnownHandler('inline_callback_query', filter, handler, group) } + /** + * Register a business callback query handler without any filters + * + * @param handler Business callback query handler + * @param group Handler group index + */ + onBusinessCallbackQuery( + handler: BusinessCallbackQueryHandler< + BusinessCallbackQueryContext, + State extends never ? never : UpdateState + >['callback'], + group?: number, + ): void + + /** + * Register a business callback query handler with a filter + * + * @param filter Update filter + * @param handler Business callback query handler + * @param group Handler group index + */ + onBusinessCallbackQuery( + filter: UpdateFilter, + handler: BusinessCallbackQueryHandler< + filters.Modify, + State extends never ? never : UpdateState + >['callback'], + group?: number, + ): void + + /** + * Register a business callback query handler with a filter + * + * @param filter Update filter + * @param handler Business callback query handler + * @param group Handler group index + */ + onBusinessCallbackQuery( + filter: UpdateFilter, + handler: BusinessCallbackQueryHandler< + filters.Modify, + State extends never ? never : UpdateState + >['callback'], + group?: number, + ): void + + /** @internal */ + onBusinessCallbackQuery(filter: any, handler?: any, group?: number): void { + this._addKnownHandler('business_callback_query', filter, handler, group) + } + /** * Register a poll update handler without any filters * diff --git a/packages/dispatcher/src/filters/chat.ts b/packages/dispatcher/src/filters/chat.ts index f00789f3..6a170660 100644 --- a/packages/dispatcher/src/filters/chat.ts +++ b/packages/dispatcher/src/filters/chat.ts @@ -1,5 +1,6 @@ import { BotChatJoinRequestUpdate, + BusinessMessage, Chat, ChatMemberUpdate, ChatType, @@ -48,12 +49,14 @@ export const chat = export const chatId: { (id: MaybeArray): UpdateFilter> (id: MaybeArray): UpdateFilter function extractText(obj: UpdatesWithText): string | null { switch (obj._name) { case 'new_message': + case 'new_business_message': return obj.text case 'inline_query': return obj.query @@ -17,6 +32,7 @@ function extractText(obj: UpdatesWithText): string | null { return obj.id case 'callback_query': case 'inline_callback_query': + case 'business_callback_query': if (obj.raw.data) return obj.dataStr } @@ -28,7 +44,7 @@ function extractText(obj: UpdatesWithText): string | null { * - for `Message`, `Message.text` is used * - for `InlineQuery`, `InlineQuery.query` is used * - for {@link ChosenInlineResult}, {@link ChosenInlineResult#id} is used - * - for `CallbackQuery`, `CallbackQuery.dataStr` is used + * - for callback queries, `dataStr` is used * * When a regex matches, the match array is stored in a * type-safe extension field `.match` of the object @@ -57,7 +73,7 @@ export const regex = * - for `Message`, `Message.text` is used * - for `InlineQuery`, `InlineQuery.query` is used * - for {@link ChosenInlineResult}, {@link ChosenInlineResult.id} is used - * - for `CallbackQuery`, `CallbackQuery.dataStr` is used + * - for callback queries, `dataStr` is used * * @param str String to be matched * @param ignoreCase Whether string case should be ignored @@ -77,7 +93,7 @@ export const equals = (str: string, ignoreCase = false): UpdateFilter = (msg) => msg.sender. export const userId: { (id: MaybeArray): UpdateFilter> (id: MaybeArray): UpdateFilter> diff --git a/packages/dispatcher/src/handler.ts b/packages/dispatcher/src/handler.ts index 01e2c707..3ac77bed 100644 --- a/packages/dispatcher/src/handler.ts +++ b/packages/dispatcher/src/handler.ts @@ -21,8 +21,9 @@ import { import { TelegramClient } from '@mtcute/core/client.js' import { UpdateContext } from './context/base.js' -import { BusinessMessageContext } from './context/business-message.js' import { + BusinessCallbackQueryContext, + BusinessMessageContext, CallbackQueryContext, ChatJoinRequestUpdateContext, ChosenInlineResultContext, @@ -70,6 +71,11 @@ export type InlineCallbackQueryHandler +export type BusinessCallbackQueryHandler = ParsedUpdateHandler< + 'business_callback_query', + T, + S +> export type PollUpdateHandler> = ParsedUpdateHandler<'poll', T> export type PollVoteHandler> = ParsedUpdateHandler<'poll_vote', T> export type UserStatusUpdateHandler> = ParsedUpdateHandler<'user_status', T> @@ -127,6 +133,7 @@ export type UpdateHandler = | ChosenInlineResultHandler | CallbackQueryHandler | InlineCallbackQueryHandler + | BusinessCallbackQueryHandler | PollUpdateHandler | PollVoteHandler | UserStatusUpdateHandler