feat: support callback queries
This commit is contained in:
parent
95f6515340
commit
1fb7057866
8 changed files with 375 additions and 2 deletions
|
@ -15,6 +15,7 @@ import { signIn } from './methods/auth/sign-in'
|
||||||
import { signUp } from './methods/auth/sign-up'
|
import { signUp } from './methods/auth/sign-up'
|
||||||
import { startTest } from './methods/auth/start-test'
|
import { startTest } from './methods/auth/start-test'
|
||||||
import { start } from './methods/auth/start'
|
import { start } from './methods/auth/start'
|
||||||
|
import { answerCallbackQuery } from './methods/bots/answer-callback-query'
|
||||||
import { answerInlineQuery } from './methods/bots/answer-inline-query'
|
import { answerInlineQuery } from './methods/bots/answer-inline-query'
|
||||||
import { addChatMembers } from './methods/chats/add-chat-members'
|
import { addChatMembers } from './methods/chats/add-chat-members'
|
||||||
import { archiveChats } from './methods/chats/archive-chats'
|
import { archiveChats } from './methods/chats/archive-chats'
|
||||||
|
@ -396,6 +397,50 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*/
|
*/
|
||||||
catchUp?: boolean
|
catchUp?: boolean
|
||||||
}): Promise<User>
|
}): Promise<User>
|
||||||
|
/**
|
||||||
|
* Send an answer to a callback query.
|
||||||
|
*
|
||||||
|
* @param queryId ID of the callback query
|
||||||
|
* @param params Parameters of the answer
|
||||||
|
*/
|
||||||
|
answerCallbackQuery(
|
||||||
|
queryId: tl.Long,
|
||||||
|
params?: {
|
||||||
|
/**
|
||||||
|
* Maximum amount of time in seconds for which
|
||||||
|
* this result can be cached by the client (not server!).
|
||||||
|
*
|
||||||
|
* Defaults to `0`
|
||||||
|
*/
|
||||||
|
cacheTime?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text of the notification (0-200 chars).
|
||||||
|
*
|
||||||
|
* If not set, nothing will be displayed
|
||||||
|
*/
|
||||||
|
text?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show an alert in the middle of the screen
|
||||||
|
* instead of a notification at the top of the screen.
|
||||||
|
*
|
||||||
|
* Defaults to `false`.
|
||||||
|
*/
|
||||||
|
alert?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL that the client should open.
|
||||||
|
*
|
||||||
|
* If this was a button containing a game,
|
||||||
|
* you can provide arbitrary link to your game.
|
||||||
|
* Otherwise, you can only use links in the format
|
||||||
|
* `t.me/your_bot?start=...` that open your bot
|
||||||
|
* with a deep-link parameter.
|
||||||
|
*/
|
||||||
|
url?: string
|
||||||
|
}
|
||||||
|
): Promise<void>
|
||||||
/**
|
/**
|
||||||
* Answer an inline query.
|
* Answer an inline query.
|
||||||
*
|
*
|
||||||
|
@ -2060,6 +2105,7 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
signUp = signUp
|
signUp = signUp
|
||||||
startTest = startTest
|
startTest = startTest
|
||||||
start = start
|
start = start
|
||||||
|
answerCallbackQuery = answerCallbackQuery
|
||||||
answerInlineQuery = answerInlineQuery
|
answerInlineQuery = answerInlineQuery
|
||||||
addChatMembers = addChatMembers
|
addChatMembers = addChatMembers
|
||||||
archiveChats = archiveChats
|
archiveChats = archiveChats
|
||||||
|
|
60
packages/client/src/methods/bots/answer-callback-query.ts
Normal file
60
packages/client/src/methods/bots/answer-callback-query.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an answer to a callback query.
|
||||||
|
*
|
||||||
|
* @param queryId ID of the callback query
|
||||||
|
* @param params Parameters of the answer
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function answerCallbackQuery(
|
||||||
|
this: TelegramClient,
|
||||||
|
queryId: tl.Long,
|
||||||
|
params?: {
|
||||||
|
/**
|
||||||
|
* Maximum amount of time in seconds for which
|
||||||
|
* this result can be cached by the client (not server!).
|
||||||
|
*
|
||||||
|
* Defaults to `0`
|
||||||
|
*/
|
||||||
|
cacheTime?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text of the notification (0-200 chars).
|
||||||
|
*
|
||||||
|
* If not set, nothing will be displayed
|
||||||
|
*/
|
||||||
|
text?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show an alert in the middle of the screen
|
||||||
|
* instead of a notification at the top of the screen.
|
||||||
|
*
|
||||||
|
* Defaults to `false`.
|
||||||
|
*/
|
||||||
|
alert?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL that the client should open.
|
||||||
|
*
|
||||||
|
* If this was a button containing a game,
|
||||||
|
* you can provide arbitrary link to your game.
|
||||||
|
* Otherwise, you can only use links in the format
|
||||||
|
* `t.me/your_bot?start=...` that open your bot
|
||||||
|
* with a deep-link parameter.
|
||||||
|
*/
|
||||||
|
url?: string
|
||||||
|
}
|
||||||
|
): Promise<void> {
|
||||||
|
if (!params) params = {}
|
||||||
|
|
||||||
|
await this.call({
|
||||||
|
_: 'messages.setBotCallbackAnswer',
|
||||||
|
queryId,
|
||||||
|
cacheTime: params.cacheTime ?? 0,
|
||||||
|
alert: params.alert,
|
||||||
|
message: params.text,
|
||||||
|
url: params.url
|
||||||
|
})
|
||||||
|
}
|
187
packages/client/src/types/bots/callback-query.ts
Normal file
187
packages/client/src/types/bots/callback-query.ts
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
import { makeInspectable } from '../utils'
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
import { Message } from '../messages'
|
||||||
|
import { MtCuteArgumentError } from '../errors'
|
||||||
|
import { getMarkedPeerId } from '@mtcute/core'
|
||||||
|
import { encodeInlineMessageId } from '../../utils/inline-utils'
|
||||||
|
import { User } from '../peers'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An incoming callback query, originated from a callback button
|
||||||
|
* of an inline keyboard.
|
||||||
|
*/
|
||||||
|
export class CallbackQuery {
|
||||||
|
readonly client: TelegramClient
|
||||||
|
readonly raw:
|
||||||
|
| tl.RawUpdateBotCallbackQuery
|
||||||
|
| tl.RawUpdateInlineBotCallbackQuery
|
||||||
|
|
||||||
|
readonly _users: Record<number, tl.TypeUser>
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
client: TelegramClient,
|
||||||
|
raw: tl.RawUpdateBotCallbackQuery | tl.RawUpdateInlineBotCallbackQuery,
|
||||||
|
users: Record<number, tl.TypeUser>
|
||||||
|
) {
|
||||||
|
this.client = client
|
||||||
|
this.raw = raw
|
||||||
|
this._users = users
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of this callback query
|
||||||
|
*/
|
||||||
|
get id(): tl.Long {
|
||||||
|
return this.raw.queryId
|
||||||
|
}
|
||||||
|
|
||||||
|
private _user?: User
|
||||||
|
/**
|
||||||
|
* User who has pressed the button
|
||||||
|
*/
|
||||||
|
get user(): User {
|
||||||
|
if (!this._user) {
|
||||||
|
this._user = new User(this.client, this._users[this.raw.userId])
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._user
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique ID, that represents the chat to which the inline
|
||||||
|
* message was sent. Does *not* contain actual chat ID.
|
||||||
|
*
|
||||||
|
* Useful for high scores in games
|
||||||
|
*/
|
||||||
|
get uniqueChatId(): tl.Long {
|
||||||
|
return this.raw.chatInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this callback query originates from
|
||||||
|
* a button that was attached to a message sent
|
||||||
|
* *via* the bot (i.e. using inline mode).
|
||||||
|
*
|
||||||
|
* If `true`, `messageId` is available and `getMessage` can be used,
|
||||||
|
* otherwise `inlineMessageId` and `inlineMessageIdStr` are available
|
||||||
|
*/
|
||||||
|
get isInline(): boolean {
|
||||||
|
return this.raw._ === 'updateInlineBotCallbackQuery'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier of the previously sent inline message,
|
||||||
|
* that contained the button which was clicked.
|
||||||
|
* This ID can be used in `TelegramClient.editInlineMessage`
|
||||||
|
*
|
||||||
|
* Is only available in case `isInline = true`
|
||||||
|
*/
|
||||||
|
get inlineMessageId(): tl.TypeInputBotInlineMessageID {
|
||||||
|
if (this.raw._ !== 'updateInlineBotCallbackQuery')
|
||||||
|
throw new MtCuteArgumentError(
|
||||||
|
'Cannot get inline message id for non-inline callback'
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.raw.msgId
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier of the previously sent inline message,
|
||||||
|
* that contained the button which was clicked,
|
||||||
|
* as a TDLib and Bot API compatible string.
|
||||||
|
* Can be used instead of {@link inlineMessageId} in
|
||||||
|
* case you want to store it in some storage.
|
||||||
|
*
|
||||||
|
* Is only available in case `isInline = true`
|
||||||
|
*/
|
||||||
|
get inlineMessageIdStr(): string {
|
||||||
|
if (this.raw._ !== 'updateInlineBotCallbackQuery')
|
||||||
|
throw new MtCuteArgumentError(
|
||||||
|
'Cannot get inline message id for non-inline callback'
|
||||||
|
)
|
||||||
|
|
||||||
|
return encodeInlineMessageId(this.raw.msgId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier of the message sent by the bot
|
||||||
|
* that contained the button which was clicked.
|
||||||
|
*
|
||||||
|
* Is only available in case `isInline = false`
|
||||||
|
*/
|
||||||
|
get messageId(): number {
|
||||||
|
if (this.raw._ !== 'updateBotCallbackQuery')
|
||||||
|
throw new MtCuteArgumentError(
|
||||||
|
'Cannot get message id for inline callback'
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.raw.msgId
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that was contained in the callback button, if any
|
||||||
|
*
|
||||||
|
* Note that this field is defined by the client, and a bad
|
||||||
|
* client can send arbitrary data in this field.
|
||||||
|
*/
|
||||||
|
get data(): Buffer | null {
|
||||||
|
return this.raw.data ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this message was from {@link InputInlineResultGame},
|
||||||
|
* or the button was {@link BotKeyboard.game},
|
||||||
|
* short name of the game that should be returned.
|
||||||
|
*/
|
||||||
|
get game(): string | null {
|
||||||
|
return this.raw.gameShortName ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message that contained the callback button that was clicked.
|
||||||
|
*
|
||||||
|
* Can only be used if `isInline = false`
|
||||||
|
*/
|
||||||
|
async getMessage(): Promise<Message> {
|
||||||
|
if (this.raw._ !== 'updateBotCallbackQuery')
|
||||||
|
throw new MtCuteArgumentError(
|
||||||
|
'Cannot get a message for inline callback'
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.client.getMessages(
|
||||||
|
getMarkedPeerId(this.raw.peer),
|
||||||
|
this.raw.msgId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answer this query
|
||||||
|
*/
|
||||||
|
async answer(
|
||||||
|
params: Parameters<TelegramClient['answerCallbackQuery']>[1]
|
||||||
|
): Promise<void> {
|
||||||
|
return this.client.answerCallbackQuery(this.raw.queryId, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit the message that originated this callback query
|
||||||
|
*/
|
||||||
|
async editMessage(
|
||||||
|
params: Parameters<TelegramClient['editInlineMessage']>[1]
|
||||||
|
): Promise<void> {
|
||||||
|
// we can use editInlineMessage as a parameter since they share most of the parameters,
|
||||||
|
// except the ones that won't apply to already sent message anyways.
|
||||||
|
if (this.raw._ === 'updateInlineBotCallbackQuery') {
|
||||||
|
return this.client.editInlineMessage(this.raw.msgId, params)
|
||||||
|
} else {
|
||||||
|
await this.client.editMessage(
|
||||||
|
getMarkedPeerId(this.raw.peer),
|
||||||
|
this.raw.msgId,
|
||||||
|
params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(CallbackQuery)
|
|
@ -1,3 +1,5 @@
|
||||||
|
export * from './input'
|
||||||
|
|
||||||
export * from './keyboards'
|
export * from './keyboards'
|
||||||
export * from './inline-query'
|
export * from './inline-query'
|
||||||
export * from './input'
|
export * from './callback-query'
|
||||||
|
|
|
@ -6,3 +6,4 @@ edit_message = Message
|
||||||
chat_member: ChatMemberUpdate = ChatMemberUpdate
|
chat_member: ChatMemberUpdate = ChatMemberUpdate
|
||||||
inline_query = InlineQuery
|
inline_query = InlineQuery
|
||||||
chosen_inline_result = ChosenInlineResult
|
chosen_inline_result = ChosenInlineResult
|
||||||
|
callback_query = CallbackQuery
|
||||||
|
|
|
@ -7,10 +7,11 @@ import {
|
||||||
ChatMemberUpdateHandler,
|
ChatMemberUpdateHandler,
|
||||||
InlineQueryHandler,
|
InlineQueryHandler,
|
||||||
ChosenInlineResultHandler,
|
ChosenInlineResultHandler,
|
||||||
|
CallbackQueryHandler,
|
||||||
} from './handler'
|
} from './handler'
|
||||||
// end-codegen-imports
|
// end-codegen-imports
|
||||||
import { filters, UpdateFilter } from './filters'
|
import { filters, UpdateFilter } from './filters'
|
||||||
import { InlineQuery, Message } from '@mtcute/client'
|
import { CallbackQuery, InlineQuery, Message } from '@mtcute/client'
|
||||||
import { ChatMemberUpdate } from './updates'
|
import { ChatMemberUpdate } from './updates'
|
||||||
import { ChosenInlineResult } from './updates/chosen-inline-result'
|
import { ChosenInlineResult } from './updates/chosen-inline-result'
|
||||||
|
|
||||||
|
@ -204,5 +205,35 @@ export namespace handlers {
|
||||||
return _create('chosen_inline_result', filter, handler)
|
return _create('chosen_inline_result', filter, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a callback query handler
|
||||||
|
*
|
||||||
|
* @param handler Callback query handler
|
||||||
|
*/
|
||||||
|
export function callbackQuery(
|
||||||
|
handler: CallbackQueryHandler['callback']
|
||||||
|
): CallbackQueryHandler
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a callback query handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Callback query handler
|
||||||
|
*/
|
||||||
|
export function callbackQuery<Mod>(
|
||||||
|
filter: UpdateFilter<CallbackQuery, Mod>,
|
||||||
|
handler: CallbackQueryHandler<
|
||||||
|
filters.Modify<CallbackQuery, Mod>
|
||||||
|
>['callback']
|
||||||
|
): CallbackQueryHandler
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export function callbackQuery(
|
||||||
|
filter: any,
|
||||||
|
handler?: any
|
||||||
|
): CallbackQueryHandler {
|
||||||
|
return _create('callback_query', filter, handler)
|
||||||
|
}
|
||||||
|
|
||||||
// end-codegen
|
// end-codegen
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {
|
import {
|
||||||
|
CallbackQuery,
|
||||||
InlineQuery,
|
InlineQuery,
|
||||||
Message,
|
Message,
|
||||||
MtCuteArgumentError,
|
MtCuteArgumentError,
|
||||||
|
@ -20,6 +21,7 @@ import {
|
||||||
ChatMemberUpdateHandler,
|
ChatMemberUpdateHandler,
|
||||||
InlineQueryHandler,
|
InlineQueryHandler,
|
||||||
ChosenInlineResultHandler,
|
ChosenInlineResultHandler,
|
||||||
|
CallbackQueryHandler,
|
||||||
} from './handler'
|
} from './handler'
|
||||||
// end-codegen-imports
|
// end-codegen-imports
|
||||||
import { filters, UpdateFilter } from './filters'
|
import { filters, UpdateFilter } from './filters'
|
||||||
|
@ -57,6 +59,10 @@ const chatMemberParser: UpdateParser = [
|
||||||
(client, upd, users, chats) =>
|
(client, upd, users, chats) =>
|
||||||
new ChatMemberUpdate(client, upd as any, users, chats),
|
new ChatMemberUpdate(client, upd as any, users, chats),
|
||||||
]
|
]
|
||||||
|
const callbackQueryParser: UpdateParser = [
|
||||||
|
'callback_query',
|
||||||
|
(client, upd, users) => new CallbackQuery(client, upd as any, users),
|
||||||
|
]
|
||||||
|
|
||||||
const PARSERS: Partial<
|
const PARSERS: Partial<
|
||||||
Record<(tl.TypeUpdate | tl.TypeMessage)['_'], UpdateParser>
|
Record<(tl.TypeUpdate | tl.TypeMessage)['_'], UpdateParser>
|
||||||
|
@ -80,6 +86,8 @@ const PARSERS: Partial<
|
||||||
(client, upd, users) =>
|
(client, upd, users) =>
|
||||||
new ChosenInlineResult(client, upd as any, users),
|
new ChosenInlineResult(client, upd as any, users),
|
||||||
],
|
],
|
||||||
|
updateBotCallbackQuery: callbackQueryParser,
|
||||||
|
updateInlineBotCallbackQuery: callbackQueryParser,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -559,5 +567,37 @@ export class Dispatcher {
|
||||||
this._addKnownHandler('chosenInlineResult', filter, handler, group)
|
this._addKnownHandler('chosenInlineResult', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback query handler without any filters
|
||||||
|
*
|
||||||
|
* @param handler Callback query handler
|
||||||
|
* @param group Handler group index
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
onCallbackQuery(
|
||||||
|
handler: CallbackQueryHandler['callback'],
|
||||||
|
group?: number
|
||||||
|
): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback query handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Callback query handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onCallbackQuery<Mod>(
|
||||||
|
filter: UpdateFilter<CallbackQuery, Mod>,
|
||||||
|
handler: CallbackQueryHandler<
|
||||||
|
filters.Modify<CallbackQuery, Mod>
|
||||||
|
>['callback'],
|
||||||
|
group?: number
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
onCallbackQuery(filter: any, handler?: any, group?: number): void {
|
||||||
|
this._addKnownHandler('callbackQuery', filter, handler, group)
|
||||||
|
}
|
||||||
|
|
||||||
// end-codegen
|
// end-codegen
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
Message,
|
Message,
|
||||||
TelegramClient,
|
TelegramClient,
|
||||||
InlineQuery,
|
InlineQuery,
|
||||||
|
CallbackQuery,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { PropagationSymbol } from './propagation'
|
import { PropagationSymbol } from './propagation'
|
||||||
|
@ -61,6 +62,10 @@ export type InlineQueryHandler<T = InlineQuery> = ParsedUpdateHandler<
|
||||||
export type ChosenInlineResultHandler<
|
export type ChosenInlineResultHandler<
|
||||||
T = ChosenInlineResult
|
T = ChosenInlineResult
|
||||||
> = ParsedUpdateHandler<'chosen_inline_result', T>
|
> = ParsedUpdateHandler<'chosen_inline_result', T>
|
||||||
|
export type CallbackQueryHandler<T = CallbackQuery> = ParsedUpdateHandler<
|
||||||
|
'callback_query',
|
||||||
|
T
|
||||||
|
>
|
||||||
|
|
||||||
export type UpdateHandler =
|
export type UpdateHandler =
|
||||||
| RawUpdateHandler
|
| RawUpdateHandler
|
||||||
|
@ -69,5 +74,6 @@ export type UpdateHandler =
|
||||||
| ChatMemberUpdateHandler
|
| ChatMemberUpdateHandler
|
||||||
| InlineQueryHandler
|
| InlineQueryHandler
|
||||||
| ChosenInlineResultHandler
|
| ChosenInlineResultHandler
|
||||||
|
| CallbackQueryHandler
|
||||||
|
|
||||||
// end-codegen
|
// end-codegen
|
||||||
|
|
Loading…
Reference in a new issue