grammy
Version:
The Telegram Bot Framework.
968 lines (967 loc) β’ 146 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Context = void 0;
const filter_js_1 = require("./filter.js");
const checker = {
filterQuery(filter) {
const pred = (0, filter_js_1.matchFilter)(filter);
return (ctx) => pred(ctx);
},
text(trigger) {
const hasText = checker.filterQuery([":text", ":caption"]);
const trg = triggerFn(trigger);
return (ctx) => {
var _a, _b;
if (!hasText(ctx))
return false;
const msg = (_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost;
const txt = (_b = msg.text) !== null && _b !== void 0 ? _b : msg.caption;
return match(ctx, txt, trg);
};
},
command(command) {
const hasEntities = checker.filterQuery(":entities:bot_command");
const atCommands = new Set();
const noAtCommands = new Set();
toArray(command).forEach((cmd) => {
if (cmd.startsWith("/")) {
throw new Error(`Do not include '/' when registering command handlers (use '${cmd.substring(1)}' not '${cmd}')`);
}
const set = cmd.includes("@") ? atCommands : noAtCommands;
set.add(cmd);
});
return (ctx) => {
var _a, _b;
if (!hasEntities(ctx))
return false;
const msg = (_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost;
const txt = (_b = msg.text) !== null && _b !== void 0 ? _b : msg.caption;
return msg.entities.some((e) => {
if (e.type !== "bot_command")
return false;
if (e.offset !== 0)
return false;
const cmd = txt.substring(1, e.length);
if (noAtCommands.has(cmd) || atCommands.has(cmd)) {
ctx.match = txt.substring(cmd.length + 1).trimStart();
return true;
}
const index = cmd.indexOf("@");
if (index === -1)
return false;
const atTarget = cmd.substring(index + 1).toLowerCase();
const username = ctx.me.username.toLowerCase();
if (atTarget !== username)
return false;
const atCommand = cmd.substring(0, index);
if (noAtCommands.has(atCommand)) {
ctx.match = txt.substring(cmd.length + 1).trimStart();
return true;
}
return false;
});
};
},
reaction(reaction) {
const hasMessageReaction = checker.filterQuery("message_reaction");
const normalized = typeof reaction === "string"
? [{ type: "emoji", emoji: reaction }]
: (Array.isArray(reaction) ? reaction : [reaction]).map((emoji) => typeof emoji === "string" ? { type: "emoji", emoji } : emoji);
const emoji = new Set(normalized.filter((r) => r.type === "emoji")
.map((r) => r.emoji));
const customEmoji = new Set(normalized.filter((r) => r.type === "custom_emoji")
.map((r) => r.custom_emoji_id));
const paid = normalized.some((r) => r.type === "paid");
return (ctx) => {
if (!hasMessageReaction(ctx))
return false;
const { old_reaction, new_reaction } = ctx.messageReaction;
// try to find a wanted reaction that is new and not old
for (const reaction of new_reaction) {
// first check if the reaction existed previously
let isOld = false;
if (reaction.type === "emoji") {
for (const old of old_reaction) {
if (old.type !== "emoji")
continue;
if (old.emoji === reaction.emoji) {
isOld = true;
break;
}
}
}
else if (reaction.type === "custom_emoji") {
for (const old of old_reaction) {
if (old.type !== "custom_emoji")
continue;
if (old.custom_emoji_id === reaction.custom_emoji_id) {
isOld = true;
break;
}
}
}
else if (reaction.type === "paid") {
for (const old of old_reaction) {
if (old.type !== "paid")
continue;
isOld = true;
break;
}
}
else {
// always regard unsupported emoji types as new
}
// disregard reaction if it is not new
if (isOld)
continue;
// check if the new reaction is wanted and short-circuit
if (reaction.type === "emoji") {
if (emoji.has(reaction.emoji))
return true;
}
else if (reaction.type === "custom_emoji") {
if (customEmoji.has(reaction.custom_emoji_id))
return true;
}
else if (reaction.type === "paid") {
if (paid)
return true;
}
else {
// always regard unsupported emoji types as new
return true;
}
// new reaction not wanted, check next one
}
return false;
};
},
chatType(chatType) {
const set = new Set(toArray(chatType));
return (ctx) => { var _a; return ((_a = ctx.chat) === null || _a === void 0 ? void 0 : _a.type) !== undefined && set.has(ctx.chat.type); };
},
callbackQuery(trigger) {
const hasCallbackQuery = checker.filterQuery("callback_query:data");
const trg = triggerFn(trigger);
return (ctx) => hasCallbackQuery(ctx) && match(ctx, ctx.callbackQuery.data, trg);
},
gameQuery(trigger) {
const hasGameQuery = checker.filterQuery("callback_query:game_short_name");
const trg = triggerFn(trigger);
return (ctx) => hasGameQuery(ctx) &&
match(ctx, ctx.callbackQuery.game_short_name, trg);
},
inlineQuery(trigger) {
const hasInlineQuery = checker.filterQuery("inline_query");
const trg = triggerFn(trigger);
return (ctx) => hasInlineQuery(ctx) && match(ctx, ctx.inlineQuery.query, trg);
},
chosenInlineResult(trigger) {
const hasChosenInlineResult = checker.filterQuery("chosen_inline_result");
const trg = triggerFn(trigger);
return (ctx) => hasChosenInlineResult(ctx) &&
match(ctx, ctx.chosenInlineResult.result_id, trg);
},
preCheckoutQuery(trigger) {
const hasPreCheckoutQuery = checker.filterQuery("pre_checkout_query");
const trg = triggerFn(trigger);
return (ctx) => hasPreCheckoutQuery(ctx) &&
match(ctx, ctx.preCheckoutQuery.invoice_payload, trg);
},
shippingQuery(trigger) {
const hasShippingQuery = checker.filterQuery("shipping_query");
const trg = triggerFn(trigger);
return (ctx) => hasShippingQuery(ctx) &&
match(ctx, ctx.shippingQuery.invoice_payload, trg);
},
};
// === Context class
/**
* When your bot receives a message, Telegram sends an update object to your
* bot. The update contains information about the chat, the user, and of course
* the message itself. There are numerous other updates, too:
* https://core.telegram.org/bots/api#update
*
* When grammY receives an update, it wraps this update into a context object
* for you. Context objects are commonly named `ctx`. A context object does two
* things:
* 1. **`ctx.update`** holds the update object that you can use to process the
* message. This includes providing useful shortcuts for the update, for
* instance, `ctx.msg` is a shortcut that gives you the message object from
* the updateβno matter whether it is contained in `ctx.update.message`, or
* `ctx.update.edited_message`, or `ctx.update.channel_post`, or
* `ctx.update.edited_channel_post`.
* 2. **`ctx.api`** gives you access to the full Telegram Bot API so that you
* can directly call any method, such as responding via
* `ctx.api.sendMessage`. Also here, the context objects has some useful
* shortcuts for you. For instance, if you want to send a message to the same
* chat that a message comes from (i.e. just respond to a user) you can call
* `ctx.reply`. This is nothing but a wrapper for `ctx.api.sendMessage` with
* the right `chat_id` pre-filled for you. Almost all methods of the Telegram
* Bot API have their own shortcut directly on the context object, so you
* probably never really have to use `ctx.api` at all.
*
* This context object is then passed to all of the listeners (called
* middleware) that you register on your bot. Because this is so useful, the
* context object is often used to hold more information. One example are
* sessions (a chat-specific data storage that is stored in a database), and
* another example is `ctx.match` that is used by `bot.command` and other
* methods to keep information about how a regular expression was matched.
*
* Read up about middleware on the
* [website](https://grammy.dev/guide/context) if you want to know more
* about the powerful opportunities that lie in context objects, and about how
* grammY implements them.
*/
class Context {
constructor(
/**
* The update object that is contained in the context.
*/
update,
/**
* An API instance that allows you to call any method of the Telegram
* Bot API.
*/
api,
/**
* Information about the bot itself.
*/
me) {
this.update = update;
this.api = api;
this.me = me;
}
// UPDATE SHORTCUTS
// Keep in sync with types in `filter.ts`.
/** Alias for `ctx.update.message` */
get message() {
return this.update.message;
}
/** Alias for `ctx.update.edited_message` */
get editedMessage() {
return this.update.edited_message;
}
/** Alias for `ctx.update.channel_post` */
get channelPost() {
return this.update.channel_post;
}
/** Alias for `ctx.update.edited_channel_post` */
get editedChannelPost() {
return this.update.edited_channel_post;
}
/** Alias for `ctx.update.business_connection` */
get businessConnection() {
return this.update.business_connection;
}
/** Alias for `ctx.update.business_message` */
get businessMessage() {
return this.update.business_message;
}
/** Alias for `ctx.update.edited_business_message` */
get editedBusinessMessage() {
return this.update.edited_business_message;
}
/** Alias for `ctx.update.deleted_business_messages` */
get deletedBusinessMessages() {
return this.update.deleted_business_messages;
}
/** Alias for `ctx.update.message_reaction` */
get messageReaction() {
return this.update.message_reaction;
}
/** Alias for `ctx.update.message_reaction_count` */
get messageReactionCount() {
return this.update.message_reaction_count;
}
/** Alias for `ctx.update.inline_query` */
get inlineQuery() {
return this.update.inline_query;
}
/** Alias for `ctx.update.chosen_inline_result` */
get chosenInlineResult() {
return this.update.chosen_inline_result;
}
/** Alias for `ctx.update.callback_query` */
get callbackQuery() {
return this.update.callback_query;
}
/** Alias for `ctx.update.shipping_query` */
get shippingQuery() {
return this.update.shipping_query;
}
/** Alias for `ctx.update.pre_checkout_query` */
get preCheckoutQuery() {
return this.update.pre_checkout_query;
}
/** Alias for `ctx.update.poll` */
get poll() {
return this.update.poll;
}
/** Alias for `ctx.update.poll_answer` */
get pollAnswer() {
return this.update.poll_answer;
}
/** Alias for `ctx.update.my_chat_member` */
get myChatMember() {
return this.update.my_chat_member;
}
/** Alias for `ctx.update.chat_member` */
get chatMember() {
return this.update.chat_member;
}
/** Alias for `ctx.update.chat_join_request` */
get chatJoinRequest() {
return this.update.chat_join_request;
}
/** Alias for `ctx.update.chat_boost` */
get chatBoost() {
return this.update.chat_boost;
}
/** Alias for `ctx.update.removed_chat_boost` */
get removedChatBoost() {
return this.update.removed_chat_boost;
}
/** Alias for `ctx.update.purchased_paid_media` */
get purchasedPaidMedia() {
return this.update.purchased_paid_media;
}
// AGGREGATION SHORTCUTS
/**
* Get the message object from wherever possible. Alias for `this.message ??
* this.editedMessage ?? this.channelPost ?? this.editedChannelPost ??
* this.businessMessage ?? this.editedBusinessMessage ??
* this.callbackQuery?.message`.
*/
get msg() {
var _a, _b, _c, _d, _e, _f, _g;
// Keep in sync with types in `filter.ts`.
return ((_f = (_e = (_d = (_c = (_b = (_a = this.message) !== null && _a !== void 0 ? _a : this.editedMessage) !== null && _b !== void 0 ? _b : this.channelPost) !== null && _c !== void 0 ? _c : this.editedChannelPost) !== null && _d !== void 0 ? _d : this.businessMessage) !== null && _e !== void 0 ? _e : this.editedBusinessMessage) !== null && _f !== void 0 ? _f : (_g = this.callbackQuery) === null || _g === void 0 ? void 0 : _g.message);
}
/**
* Get the chat object from wherever possible. Alias for `(this.msg ??
* this.deletedBusinessMessages ?? this.messageReaction ??
* this.messageReactionCount ?? this.myChatMember ?? this.chatMember ??
* this.chatJoinRequest ?? this.chatBoost ?? this.removedChatBoost)?.chat`.
*/
get chat() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
// Keep in sync with types in `filter.ts`.
return (_j = ((_h = (_g = (_f = (_e = (_d = (_c = (_b = (_a = this.msg) !== null && _a !== void 0 ? _a : this.deletedBusinessMessages) !== null && _b !== void 0 ? _b : this.messageReaction) !== null && _c !== void 0 ? _c : this.messageReactionCount) !== null && _d !== void 0 ? _d : this.myChatMember) !== null && _e !== void 0 ? _e : this.chatMember) !== null && _f !== void 0 ? _f : this.chatJoinRequest) !== null && _g !== void 0 ? _g : this.chatBoost) !== null && _h !== void 0 ? _h : this.removedChatBoost)) === null || _j === void 0 ? void 0 : _j.chat;
}
/**
* Get the sender chat object from wherever possible. Alias for
* `ctx.msg?.sender_chat`.
*/
get senderChat() {
var _a;
// Keep in sync with types in `filter.ts`.
return (_a = this.msg) === null || _a === void 0 ? void 0 : _a.sender_chat;
}
/**
* Get the user object from wherever possible. Alias for
* `(this.businessConnection ?? this.messageReaction ??
* (this.chatBoost?.boost ?? this.removedChatBoost)?.source)?.user ??
* (this.callbackQuery ?? this.msg ?? this.inlineQuery ??
* this.chosenInlineResult ?? this.shippingQuery ?? this.preCheckoutQuery ??
* this.myChatMember ?? this.chatMember ?? this.chatJoinRequest ??
* this.purchasedPaidMedia)?.from`.
*/
get from() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
// Keep in sync with types in `filter.ts`.
return (_g = (_f = ((_b = (_a = this.businessConnection) !== null && _a !== void 0 ? _a : this.messageReaction) !== null && _b !== void 0 ? _b : (_e = ((_d = (_c = this.chatBoost) === null || _c === void 0 ? void 0 : _c.boost) !== null && _d !== void 0 ? _d : this.removedChatBoost)) === null || _e === void 0 ? void 0 : _e.source)) === null || _f === void 0 ? void 0 : _f.user) !== null && _g !== void 0 ? _g : (_s = ((_r = (_q = (_p = (_o = (_m = (_l = (_k = (_j = (_h = this.callbackQuery) !== null && _h !== void 0 ? _h : this.msg) !== null && _j !== void 0 ? _j : this.inlineQuery) !== null && _k !== void 0 ? _k : this.chosenInlineResult) !== null && _l !== void 0 ? _l : this.shippingQuery) !== null && _m !== void 0 ? _m : this.preCheckoutQuery) !== null && _o !== void 0 ? _o : this.myChatMember) !== null && _p !== void 0 ? _p : this.chatMember) !== null && _q !== void 0 ? _q : this.chatJoinRequest) !== null && _r !== void 0 ? _r : this.purchasedPaidMedia)) === null || _s === void 0 ? void 0 : _s.from;
}
/**
* Get the message identifier from wherever possible. Alias for
* `this.msg?.message_id ?? this.messageReaction?.message_id ??
* this.messageReactionCount?.message_id`.
*/
get msgId() {
var _a, _b, _c, _d, _e;
// Keep in sync with types in `filter.ts`.
return (_d = (_b = (_a = this.msg) === null || _a === void 0 ? void 0 : _a.message_id) !== null && _b !== void 0 ? _b : (_c = this.messageReaction) === null || _c === void 0 ? void 0 : _c.message_id) !== null && _d !== void 0 ? _d : (_e = this.messageReactionCount) === null || _e === void 0 ? void 0 : _e.message_id;
}
/**
* Gets the chat identifier from wherever possible. Alias for `this.chat?.id
* ?? this.businessConnection?.user_chat_id`.
*/
get chatId() {
var _a, _b, _c;
// Keep in sync with types in `filter.ts`.
return (_b = (_a = this.chat) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : (_c = this.businessConnection) === null || _c === void 0 ? void 0 : _c.user_chat_id;
}
/**
* Get the inline message identifier from wherever possible. Alias for
* `(ctx.callbackQuery ?? ctx.chosenInlineResult)?.inline_message_id`.
*/
get inlineMessageId() {
var _a, _b, _c;
return ((_b = (_a = this.callbackQuery) === null || _a === void 0 ? void 0 : _a.inline_message_id) !== null && _b !== void 0 ? _b : (_c = this.chosenInlineResult) === null || _c === void 0 ? void 0 : _c.inline_message_id);
}
/**
* Get the business connection identifier from wherever possible. Alias for
* `this.msg?.business_connection_id ?? this.businessConnection?.id ??
* this.deletedBusinessMessages?.business_connection_id`.
*/
get businessConnectionId() {
var _a, _b, _c, _d, _e;
return (_d = (_b = (_a = this.msg) === null || _a === void 0 ? void 0 : _a.business_connection_id) !== null && _b !== void 0 ? _b : (_c = this.businessConnection) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : (_e = this.deletedBusinessMessages) === null || _e === void 0 ? void 0 : _e.business_connection_id;
}
entities(types) {
var _a, _b;
const message = this.msg;
if (message === undefined)
return [];
const text = (_a = message.text) !== null && _a !== void 0 ? _a : message.caption;
if (text === undefined)
return [];
let entities = (_b = message.entities) !== null && _b !== void 0 ? _b : message.caption_entities;
if (entities === undefined)
return [];
if (types !== undefined) {
const filters = new Set(toArray(types));
entities = entities.filter((entity) => filters.has(entity.type));
}
return entities.map((entity) => ({
...entity,
text: text.substring(entity.offset, entity.offset + entity.length),
}));
}
/**
* Find out which reactions were added and removed in a `message_reaction`
* update. This method looks at `ctx.messageReaction` and computes the
* difference between the old reaction and the new reaction. It also groups
* the reactions by emoji reactions and custom emoji reactions. For example,
* the resulting object could look like this:
* ```ts
* {
* emoji: ['π', 'π']
* emojiAdded: ['π'],
* emojiKept: ['π'],
* emojiRemoved: [],
* customEmoji: [],
* customEmojiAdded: [],
* customEmojiKept: [],
* customEmojiRemoved: ['id0123'],
* paid: true,
* paidAdded: false,
* paidRemoved: false,
* }
* ```
* In the above example, a tada reaction was added by the user, and a custom
* emoji reaction with the custom emoji 'id0123' was removed in the same
* update. The user had already reacted with a thumbs up reaction and a paid
* star reaction, which they left both unchanged. As a result, the current
* reaction by the user is thumbs up, tada, and a paid reaction. Note that
* the current reaction (all emoji reactions regardless of type in one list)
* can also be obtained from `ctx.messageReaction.new_reaction`.
*
* Remember that reaction updates only include information about the
* reaction of a specific user. The respective message may have many more
* reactions by other people which will not be included in this update.
*
* @returns An object containing information about the reaction update
*/
reactions() {
const emoji = [];
const emojiAdded = [];
const emojiKept = [];
const emojiRemoved = [];
const customEmoji = [];
const customEmojiAdded = [];
const customEmojiKept = [];
const customEmojiRemoved = [];
let paid = false;
let paidAdded = false;
const r = this.messageReaction;
if (r !== undefined) {
const { old_reaction, new_reaction } = r;
// group all current emoji in `emoji` and `customEmoji`
for (const reaction of new_reaction) {
if (reaction.type === "emoji") {
emoji.push(reaction.emoji);
}
else if (reaction.type === "custom_emoji") {
customEmoji.push(reaction.custom_emoji_id);
}
else if (reaction.type === "paid") {
paid = paidAdded = true;
}
}
// temporarily move all old emoji to the *Removed arrays
for (const reaction of old_reaction) {
if (reaction.type === "emoji") {
emojiRemoved.push(reaction.emoji);
}
else if (reaction.type === "custom_emoji") {
customEmojiRemoved.push(reaction.custom_emoji_id);
}
else if (reaction.type === "paid") {
paidAdded = false;
}
}
// temporarily move all new emoji to the *Added arrays
emojiAdded.push(...emoji);
customEmojiAdded.push(...customEmoji);
// drop common emoji from both lists and add them to `emojiKept`
for (let i = 0; i < emojiRemoved.length; i++) {
const len = emojiAdded.length;
if (len === 0)
break;
const rem = emojiRemoved[i];
for (let j = 0; j < len; j++) {
if (rem === emojiAdded[j]) {
emojiKept.push(rem);
emojiRemoved.splice(i, 1);
emojiAdded.splice(j, 1);
i--;
break;
}
}
}
// drop common custom emoji from both lists and add them to `customEmojiKept`
for (let i = 0; i < customEmojiRemoved.length; i++) {
const len = customEmojiAdded.length;
if (len === 0)
break;
const rem = customEmojiRemoved[i];
for (let j = 0; j < len; j++) {
if (rem === customEmojiAdded[j]) {
customEmojiKept.push(rem);
customEmojiRemoved.splice(i, 1);
customEmojiAdded.splice(j, 1);
i--;
break;
}
}
}
}
return {
emoji,
emojiAdded,
emojiKept,
emojiRemoved,
customEmoji,
customEmojiAdded,
customEmojiKept,
customEmojiRemoved,
paid,
paidAdded,
};
}
/**
* Returns `true` if this context object matches the given filter query, and
* `false` otherwise. This uses the same logic as `bot.on`.
*
* @param filter The filter query to check
*/
has(filter) {
return Context.has.filterQuery(filter)(this);
}
/**
* Returns `true` if this context object contains the given text, or if it
* contains text that matches the given regular expression. It returns
* `false` otherwise. This uses the same logic as `bot.hears`.
*
* @param trigger The string or regex to match
*/
hasText(trigger) {
return Context.has.text(trigger)(this);
}
/**
* Returns `true` if this context object contains the given command, and
* `false` otherwise. This uses the same logic as `bot.command`.
*
* @param command The command to match
*/
hasCommand(command) {
return Context.has.command(command)(this);
}
hasReaction(reaction) {
return Context.has.reaction(reaction)(this);
}
/**
* Returns `true` if this context object belongs to a chat with the given
* chat type, and `false` otherwise. This uses the same logic as
* `bot.chatType`.
*
* @param chatType The chat type to match
*/
hasChatType(chatType) {
return Context.has.chatType(chatType)(this);
}
/**
* Returns `true` if this context object contains the given callback query,
* or if the contained callback query data matches the given regular
* expression. It returns `false` otherwise. This uses the same logic as
* `bot.callbackQuery`.
*
* @param trigger The string or regex to match
*/
hasCallbackQuery(trigger) {
return Context.has.callbackQuery(trigger)(this);
}
/**
* Returns `true` if this context object contains the given game query, or
* if the contained game query matches the given regular expression. It
* returns `false` otherwise. This uses the same logic as `bot.gameQuery`.
*
* @param trigger The string or regex to match
*/
hasGameQuery(trigger) {
return Context.has.gameQuery(trigger)(this);
}
/**
* Returns `true` if this context object contains the given inline query, or
* if the contained inline query matches the given regular expression. It
* returns `false` otherwise. This uses the same logic as `bot.inlineQuery`.
*
* @param trigger The string or regex to match
*/
hasInlineQuery(trigger) {
return Context.has.inlineQuery(trigger)(this);
}
/**
* Returns `true` if this context object contains the chosen inline result,
* or if the contained chosen inline result matches the given regular
* expression. It returns `false` otherwise. This uses the same logic as
* `bot.chosenInlineResult`.
*
* @param trigger The string or regex to match
*/
hasChosenInlineResult(trigger) {
return Context.has.chosenInlineResult(trigger)(this);
}
/**
* Returns `true` if this context object contains the given pre-checkout
* query, or if the contained pre-checkout query matches the given regular
* expression. It returns `false` otherwise. This uses the same logic as
* `bot.preCheckoutQuery`.
*
* @param trigger The string or regex to match
*/
hasPreCheckoutQuery(trigger) {
return Context.has.preCheckoutQuery(trigger)(this);
}
/**
* Returns `true` if this context object contains the given shipping query,
* or if the contained shipping query matches the given regular expression.
* It returns `false` otherwise. This uses the same logic as
* `bot.shippingQuery`.
*
* @param trigger The string or regex to match
*/
hasShippingQuery(trigger) {
return Context.has.shippingQuery(trigger)(this);
}
// API
/**
* Context-aware alias for `api.sendMessage`. Use this method to send text messages. On success, the sent Message is returned.
*
* @param text Text of the message to be sent, 1-4096 characters after entities parsing
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendmessage
*/
reply(text, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendMessage(orThrow(this.chatId, "sendMessage"), text, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.forwardMessage`. Use this method to forward messages of any kind. Service messages and messages with protected content can't be forwarded. On success, the sent Message is returned.
*
* @param chat_id Unique identifier for the target chat or username of the target channel (in the format @channelusername)
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#forwardmessage
*/
forwardMessage(chat_id, other, signal) {
var _a;
const msg = this.msg;
return this.api.forwardMessage(chat_id, orThrow(this.chatId, "forwardMessage"), orThrow(this.msgId, "forwardMessage"), {
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.forwardMessages`. Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an array of MessageId of the sent messages is returned.
*
* @param chat_id Unique identifier for the target chat or username of the target channel (in the format @channelusername)
* @param message_ids A list of 1-100 identifiers of messages in the current chat to forward. The identifiers must be specified in a strictly increasing order.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#forwardmessages
*/
forwardMessages(chat_id, message_ids, other, signal) {
var _a;
const msg = this.msg;
return this.api.forwardMessages(chat_id, orThrow(this.chatId, "forwardMessages"), message_ids, {
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.copyMessage`. Use this method to copy messages of any kind. Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessage, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success.
*
* @param chat_id Unique identifier for the target chat or username of the target channel (in the format @channelusername)
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#copymessage
*/
copyMessage(chat_id, other, signal) {
var _a;
const msg = this.msg;
return this.api.copyMessage(chat_id, orThrow(this.chatId, "copyMessage"), orThrow(this.msgId, "copyMessage"), {
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.copyMessages`. Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array of MessageId of the sent messages is returned.
*
* @param chat_id Unique identifier for the target chat or username of the target channel (in the format @channelusername)
* @param message_ids A list of 1-100 identifiers of messages in the current chat to copy. The identifiers must be specified in a strictly increasing order.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#copymessages
*/
copyMessages(chat_id, message_ids, other, signal) {
var _a;
const msg = this.msg;
return this.api.copyMessages(chat_id, orThrow(this.chatId, "copyMessages"), message_ids, {
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendPhoto`. Use this method to send photos. On success, the sent Message is returned.
*
* @param photo Photo to send. Pass a file_id as String to send a photo that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a photo from the Internet, or upload a new photo using multipart/form-data. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendphoto
*/
replyWithPhoto(photo, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendPhoto(orThrow(this.chatId, "sendPhoto"), photo, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendAudio`. Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
*
* For sending voice messages, use the sendVoice method instead.
*
* @param audio Audio file to send. Pass a file_id as String to send an audio file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an audio file from the Internet, or upload a new one using multipart/form-data.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendaudio
*/
replyWithAudio(audio, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendAudio(orThrow(this.chatId, "sendAudio"), audio, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendDocument`. Use this method to send general files. On success, the sent Message is returned. Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
*
* @param document File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#senddocument
*/
replyWithDocument(document, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendDocument(orThrow(this.chatId, "sendDocument"), document, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendVideo`. Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). On success, the sent Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.
*
* @param video Video to send. Pass a file_id as String to send a video that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a video from the Internet, or upload a new video using multipart/form-data.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendvideo
*/
replyWithVideo(video, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendVideo(orThrow(this.chatId, "sendVideo"), video, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendAnimation`. Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
*
* @param animation Animation to send. Pass a file_id as String to send an animation that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation from the Internet, or upload a new animation using multipart/form-data.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendanimation
*/
replyWithAnimation(animation, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendAnimation(orThrow(this.chatId, "sendAnimation"), animation, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendVoice`. Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .OGG file encoded with OPUS (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
*
* @param voice Audio file to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data.
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendvoice
*/
replyWithVoice(voice, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendVoice(orThrow(this.chatId, "sendVoice"), voice, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendVideoNote`. Use this method to send video messages. On success, the sent Message is returned.
* As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long.
*
* @param video_note Video note to send. Pass a file_id as String to send a video note that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data.. Sending video notes by a URL is currently unsupported
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendvideonote
*/
replyWithVideoNote(video_note, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendVideoNote(orThrow(this.chatId, "sendVideoNote"), video_note, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendMediaGroup`. Use this method to send a group of photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an array of Messages that were sent is returned.
*
* @param media An array describing messages to be sent, must include 2-10 items
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendmediagroup
*/
replyWithMediaGroup(media, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendMediaGroup(orThrow(this.chatId, "sendMediaGroup"), media, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.sendLocation`. Use this method to send point on the map. On success, the sent Message is returned.
*
* @param latitude Latitude of the location
* @param longitude Longitude of the location
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#sendlocation
*/
replyWithLocation(latitude, longitude, other, signal) {
var _a;
const msg = this.msg;
return this.api.sendLocation(orThrow(this.chatId, "sendLocation"), latitude, longitude, {
business_connection_id: this.businessConnectionId,
...((msg === null || msg === void 0 ? void 0 : msg.is_topic_message)
? { message_thread_id: msg === null || msg === void 0 ? void 0 : msg.message_thread_id }
: {}),
direct_messages_topic_id: (_a = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a === void 0 ? void 0 : _a.topic_id,
...other,
}, signal);
}
/**
* Context-aware alias for `api.editMessageLiveLocation`. Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned.
*
* @param latitude Latitude of new location
* @param longitude Longitude of new location
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#editmessagelivelocation
*/
editMessageLiveLocation(latitude, longitude, other, signal) {
const inlineId = this.inlineMessageId;
return inlineId !== undefined
? this.api.editMessageLiveLocationInline(inlineId, latitude, longitude, { business_connection_id: this.businessConnectionId, ...other }, signal)
: this.api.editMessageLiveLocation(orThrow(this.chatId, "editMessageLiveLocation"), orThrow(this.msgId, "editMessageLiveLocation"), latitude, longitude, { business_connection_id: this.businessConnectionId, ...other }, signal);
}
/**
* Context-aware alias for `api.stopMessageLiveLocation`. Use this method to stop updating a live location message before live_period expires. On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned.
*
* @param other Optional remaining parameters, confer the official reference below
* @param signal Optional `AbortSignal` to cancel the request
*
* **Official reference:** https://core.telegram.org/bots/api#stopmessagelivelocation
*/
stopMessageLiveLocation(other, signal) {