UNPKG

grammy

Version:

The Telegram Bot Framework.

1,261 lines 183 kB
const filterQueryCache = new Map(); function matchFilter(filter) { const queries = Array.isArray(filter) ? filter : [ filter ]; const key = queries.join(","); const predicate = filterQueryCache.get(key) ?? (()=>{ const parsed = parse(queries); const pred = compile(parsed); filterQueryCache.set(key, pred); return pred; })(); return (ctx)=>predicate(ctx); } function parse(filter) { return Array.isArray(filter) ? filter.map((q)=>q.split(":")) : [ filter.split(":") ]; } function compile(parsed) { const preprocessed = parsed.flatMap((q)=>check(q, preprocess(q))); const ltree = treeify(preprocessed); const predicate = arborist(ltree); return (ctx)=>!!predicate(ctx.update, ctx); } function preprocess(filter) { const valid = UPDATE_KEYS; const expanded = [ filter ].flatMap((q)=>{ const [l1, l2, l3] = q; if (!(l1 in L1_SHORTCUTS)) return [ q ]; if (!l1 && !l2 && !l3) return [ q ]; const targets = L1_SHORTCUTS[l1]; const expanded = targets.map((s)=>[ s, l2, l3 ]); if (l2 === undefined) return expanded; if (l2 in L2_SHORTCUTS && (l2 || l3)) return expanded; return expanded.filter(([s])=>!!valid[s]?.[l2]); }).flatMap((q)=>{ const [l1, l2, l3] = q; if (!(l2 in L2_SHORTCUTS)) return [ q ]; if (!l2 && !l3) return [ q ]; const targets = L2_SHORTCUTS[l2]; const expanded = targets.map((s)=>[ l1, s, l3 ]); if (l3 === undefined) return expanded; return expanded.filter(([, s])=>!!valid[l1]?.[s]?.[l3]); }); if (expanded.length === 0) { throw new Error(`Shortcuts in '${filter.join(":")}' do not expand to any valid filter query`); } return expanded; } function check(original, preprocessed) { if (preprocessed.length === 0) throw new Error("Empty filter query given"); const errors = preprocessed.map(checkOne).filter((r)=>r !== true); if (errors.length === 0) return preprocessed; else if (errors.length === 1) throw new Error(errors[0]); else { throw new Error(`Invalid filter query '${original.join(":")}'. There are ${errors.length} errors after expanding the contained shortcuts: ${errors.join("; ")}`); } } function checkOne(filter) { const [l1, l2, l3, ...n] = filter; if (l1 === undefined) return "Empty filter query given"; if (!(l1 in UPDATE_KEYS)) { const permitted = Object.keys(UPDATE_KEYS); return `Invalid L1 filter '${l1}' given in '${filter.join(":")}'. \ Permitted values are: ${permitted.map((k)=>`'${k}'`).join(", ")}.`; } if (l2 === undefined) return true; const l1Obj = UPDATE_KEYS[l1]; if (!(l2 in l1Obj)) { const permitted = Object.keys(l1Obj); return `Invalid L2 filter '${l2}' given in '${filter.join(":")}'. \ Permitted values are: ${permitted.map((k)=>`'${k}'`).join(", ")}.`; } if (l3 === undefined) return true; const l2Obj = l1Obj[l2]; if (!(l3 in l2Obj)) { const permitted = Object.keys(l2Obj); return `Invalid L3 filter '${l3}' given in '${filter.join(":")}'. ${permitted.length === 0 ? `No further filtering is possible after '${l1}:${l2}'.` : `Permitted values are: ${permitted.map((k)=>`'${k}'`).join(", ")}.`}`; } if (n.length === 0) return true; return `Cannot filter further than three levels, ':${n.join(":")}' is invalid!`; } function treeify(paths) { const tree = {}; for (const [l1, l2, l3] of paths){ const subtree = tree[l1] ??= {}; if (l2 !== undefined) { const set = subtree[l2] ??= new Set(); if (l3 !== undefined) set.add(l3); } } return tree; } function or(left, right) { return (obj, ctx)=>left(obj, ctx) || right(obj, ctx); } function concat(get, test) { return (obj, ctx)=>{ const nextObj = get(obj, ctx); return nextObj && test(nextObj, ctx); }; } function leaf(pred) { return (obj, ctx)=>pred(obj, ctx) != null; } function arborist(tree) { const l1Predicates = Object.entries(tree).map(([l1, subtree])=>{ const l1Pred = (obj)=>obj[l1]; const l2Predicates = Object.entries(subtree).map(([l2, set])=>{ const l2Pred = (obj)=>obj[l2]; const l3Predicates = Array.from(set).map((l3)=>{ const l3Pred = l3 === "me" ? (obj, ctx)=>{ const me = ctx.me.id; return testMaybeArray(obj, (u)=>u.id === me); } : (obj)=>testMaybeArray(obj, (e)=>e[l3] || e.type === l3); return l3Pred; }); return l3Predicates.length === 0 ? leaf(l2Pred) : concat(l2Pred, l3Predicates.reduce(or)); }); return l2Predicates.length === 0 ? leaf(l1Pred) : concat(l1Pred, l2Predicates.reduce(or)); }); if (l1Predicates.length === 0) { throw new Error("Cannot create filter function for empty query"); } return l1Predicates.reduce(or); } function testMaybeArray(t, pred) { const p = (x)=>x != null && pred(x); return Array.isArray(t) ? t.some(p) : p(t); } const ENTITY_KEYS = { mention: {}, hashtag: {}, cashtag: {}, bot_command: {}, url: {}, email: {}, phone_number: {}, bold: {}, italic: {}, underline: {}, strikethrough: {}, spoiler: {}, blockquote: {}, expandable_blockquote: {}, code: {}, pre: {}, text_link: {}, text_mention: {}, custom_emoji: {} }; const USER_KEYS = { me: {}, is_bot: {}, is_premium: {}, added_to_attachment_menu: {} }; const FORWARD_ORIGIN_KEYS = { user: {}, hidden_user: {}, chat: {}, channel: {} }; const STICKER_KEYS = { is_video: {}, is_animated: {}, premium_animation: {} }; const REACTION_KEYS = { emoji: {}, custom_emoji: {}, paid: {} }; const COMMON_MESSAGE_KEYS = { forward_origin: FORWARD_ORIGIN_KEYS, is_topic_message: {}, is_automatic_forward: {}, business_connection_id: {}, text: {}, animation: {}, audio: {}, document: {}, paid_media: {}, photo: {}, sticker: STICKER_KEYS, story: {}, video: {}, video_note: {}, voice: {}, contact: {}, dice: {}, game: {}, poll: {}, venue: {}, location: {}, entities: ENTITY_KEYS, caption_entities: ENTITY_KEYS, caption: {}, link_preview_options: { url: {}, prefer_small_media: {}, prefer_large_media: {}, show_above_text: {} }, effect_id: {}, paid_star_count: {}, has_media_spoiler: {}, new_chat_title: {}, new_chat_photo: {}, delete_chat_photo: {}, message_auto_delete_timer_changed: {}, pinned_message: {}, invoice: {}, proximity_alert_triggered: {}, chat_background_set: {}, giveaway_created: {}, giveaway: { only_new_members: {}, has_public_winners: {} }, giveaway_winners: { only_new_members: {}, was_refunded: {} }, giveaway_completed: {}, gift: {}, unique_gift: {}, paid_message_price_changed: {}, video_chat_scheduled: {}, video_chat_started: {}, video_chat_ended: {}, video_chat_participants_invited: {}, web_app_data: {} }; const MESSAGE_KEYS = { ...COMMON_MESSAGE_KEYS, direct_messages_topic: {}, new_chat_members: USER_KEYS, left_chat_member: USER_KEYS, group_chat_created: {}, supergroup_chat_created: {}, migrate_to_chat_id: {}, migrate_from_chat_id: {}, successful_payment: {}, refunded_payment: {}, users_shared: {}, chat_shared: {}, connected_website: {}, write_access_allowed: {}, passport_data: {}, boost_added: {}, forum_topic_created: {}, forum_topic_edited: { name: {}, icon_custom_emoji_id: {} }, forum_topic_closed: {}, forum_topic_reopened: {}, general_forum_topic_hidden: {}, general_forum_topic_unhidden: {}, checklist: { others_can_add_tasks: {}, others_can_mark_tasks_as_done: {} }, checklist_tasks_done: {}, checklist_tasks_added: {}, suggested_post_info: {}, suggested_post_approved: {}, suggested_post_approval_failed: {}, suggested_post_declined: {}, suggested_post_paid: {}, suggested_post_refunded: {}, sender_boost_count: {} }; const CHANNEL_POST_KEYS = { ...COMMON_MESSAGE_KEYS, channel_chat_created: {}, direct_message_price_changed: {}, is_paid_post: {} }; const BUSINESS_CONNECTION_KEYS = { can_reply: {}, is_enabled: {} }; const MESSAGE_REACTION_KEYS = { old_reaction: REACTION_KEYS, new_reaction: REACTION_KEYS }; const MESSAGE_REACTION_COUNT_UPDATED_KEYS = { reactions: REACTION_KEYS }; const CALLBACK_QUERY_KEYS = { data: {}, game_short_name: {} }; const CHAT_MEMBER_UPDATED_KEYS = { from: USER_KEYS }; const UPDATE_KEYS = { message: MESSAGE_KEYS, edited_message: MESSAGE_KEYS, channel_post: CHANNEL_POST_KEYS, edited_channel_post: CHANNEL_POST_KEYS, business_connection: BUSINESS_CONNECTION_KEYS, business_message: MESSAGE_KEYS, edited_business_message: MESSAGE_KEYS, deleted_business_messages: {}, inline_query: {}, chosen_inline_result: {}, callback_query: CALLBACK_QUERY_KEYS, shipping_query: {}, pre_checkout_query: {}, poll: {}, poll_answer: {}, my_chat_member: CHAT_MEMBER_UPDATED_KEYS, chat_member: CHAT_MEMBER_UPDATED_KEYS, chat_join_request: {}, message_reaction: MESSAGE_REACTION_KEYS, message_reaction_count: MESSAGE_REACTION_COUNT_UPDATED_KEYS, chat_boost: {}, removed_chat_boost: {}, purchased_paid_media: {} }; const L1_SHORTCUTS = { "": [ "message", "channel_post" ], msg: [ "message", "channel_post" ], edit: [ "edited_message", "edited_channel_post" ] }; const L2_SHORTCUTS = { "": [ "entities", "caption_entities" ], media: [ "photo", "video" ], file: [ "photo", "animation", "audio", "document", "video", "video_note", "voice", "sticker" ] }; const checker = { filterQuery (filter) { const pred = matchFilter(filter); return (ctx)=>pred(ctx); }, text (trigger) { const hasText = checker.filterQuery([ ":text", ":caption" ]); const trg = triggerFn(trigger); return (ctx)=>{ if (!hasText(ctx)) return false; const msg = ctx.message ?? ctx.channelPost; const txt = msg.text ?? 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)=>{ if (!hasEntities(ctx)) return false; const msg = ctx.message ?? ctx.channelPost; const txt = msg.text ?? 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; for (const reaction of new_reaction){ 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 {} if (isOld) continue; 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 { return true; } } return false; }; }, chatType (chatType) { const set = new Set(toArray(chatType)); return (ctx)=>ctx.chat?.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); } }; class Context { update; api; me; match; constructor(update, api, me){ this.update = update; this.api = api; this.me = me; } get message() { return this.update.message; } get editedMessage() { return this.update.edited_message; } get channelPost() { return this.update.channel_post; } get editedChannelPost() { return this.update.edited_channel_post; } get businessConnection() { return this.update.business_connection; } get businessMessage() { return this.update.business_message; } get editedBusinessMessage() { return this.update.edited_business_message; } get deletedBusinessMessages() { return this.update.deleted_business_messages; } get messageReaction() { return this.update.message_reaction; } get messageReactionCount() { return this.update.message_reaction_count; } get inlineQuery() { return this.update.inline_query; } get chosenInlineResult() { return this.update.chosen_inline_result; } get callbackQuery() { return this.update.callback_query; } get shippingQuery() { return this.update.shipping_query; } get preCheckoutQuery() { return this.update.pre_checkout_query; } get poll() { return this.update.poll; } get pollAnswer() { return this.update.poll_answer; } get myChatMember() { return this.update.my_chat_member; } get chatMember() { return this.update.chat_member; } get chatJoinRequest() { return this.update.chat_join_request; } get chatBoost() { return this.update.chat_boost; } get removedChatBoost() { return this.update.removed_chat_boost; } get purchasedPaidMedia() { return this.update.purchased_paid_media; } get msg() { return this.message ?? this.editedMessage ?? this.channelPost ?? this.editedChannelPost ?? this.businessMessage ?? this.editedBusinessMessage ?? this.callbackQuery?.message; } get chat() { return (this.msg ?? this.deletedBusinessMessages ?? this.messageReaction ?? this.messageReactionCount ?? this.myChatMember ?? this.chatMember ?? this.chatJoinRequest ?? this.chatBoost ?? this.removedChatBoost)?.chat; } get senderChat() { return this.msg?.sender_chat; } get from() { return (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 msgId() { return this.msg?.message_id ?? this.messageReaction?.message_id ?? this.messageReactionCount?.message_id; } get chatId() { return this.chat?.id ?? this.businessConnection?.user_chat_id; } get inlineMessageId() { return this.callbackQuery?.inline_message_id ?? this.chosenInlineResult?.inline_message_id; } get businessConnectionId() { return this.msg?.business_connection_id ?? this.businessConnection?.id ?? this.deletedBusinessMessages?.business_connection_id; } entities(types) { const message = this.msg; if (message === undefined) return []; const text = message.text ?? message.caption; if (text === undefined) return []; let entities = message.entities ?? 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) })); } 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; 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; } } 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; } } emojiAdded.push(...emoji); customEmojiAdded.push(...customEmoji); 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; } } } 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 }; } static has = checker; has(filter) { return Context.has.filterQuery(filter)(this); } hasText(trigger) { return Context.has.text(trigger)(this); } hasCommand(command) { return Context.has.command(command)(this); } hasReaction(reaction) { return Context.has.reaction(reaction)(this); } hasChatType(chatType) { return Context.has.chatType(chatType)(this); } hasCallbackQuery(trigger) { return Context.has.callbackQuery(trigger)(this); } hasGameQuery(trigger) { return Context.has.gameQuery(trigger)(this); } hasInlineQuery(trigger) { return Context.has.inlineQuery(trigger)(this); } hasChosenInlineResult(trigger) { return Context.has.chosenInlineResult(trigger)(this); } hasPreCheckoutQuery(trigger) { return Context.has.preCheckoutQuery(trigger)(this); } hasShippingQuery(trigger) { return Context.has.shippingQuery(trigger)(this); } reply(text, other, signal) { const msg = this.msg; return this.api.sendMessage(orThrow(this.chatId, "sendMessage"), text, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } forwardMessage(chat_id, other, signal) { const msg = this.msg; return this.api.forwardMessage(chat_id, orThrow(this.chatId, "forwardMessage"), orThrow(this.msgId, "forwardMessage"), { direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } forwardMessages(chat_id, message_ids, other, signal) { const msg = this.msg; return this.api.forwardMessages(chat_id, orThrow(this.chatId, "forwardMessages"), message_ids, { direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } copyMessage(chat_id, other, signal) { const msg = this.msg; return this.api.copyMessage(chat_id, orThrow(this.chatId, "copyMessage"), orThrow(this.msgId, "copyMessage"), { direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } copyMessages(chat_id, message_ids, other, signal) { const msg = this.msg; return this.api.copyMessages(chat_id, orThrow(this.chatId, "copyMessages"), message_ids, { direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithPhoto(photo, other, signal) { const msg = this.msg; return this.api.sendPhoto(orThrow(this.chatId, "sendPhoto"), photo, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithAudio(audio, other, signal) { const msg = this.msg; return this.api.sendAudio(orThrow(this.chatId, "sendAudio"), audio, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithDocument(document1, other, signal) { const msg = this.msg; return this.api.sendDocument(orThrow(this.chatId, "sendDocument"), document1, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithVideo(video, other, signal) { const msg = this.msg; return this.api.sendVideo(orThrow(this.chatId, "sendVideo"), video, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithAnimation(animation, other, signal) { const msg = this.msg; return this.api.sendAnimation(orThrow(this.chatId, "sendAnimation"), animation, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithVoice(voice, other, signal) { const msg = this.msg; return this.api.sendVoice(orThrow(this.chatId, "sendVoice"), voice, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithVideoNote(video_note, other, signal) { const msg = this.msg; return this.api.sendVideoNote(orThrow(this.chatId, "sendVideoNote"), video_note, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithMediaGroup(media, other, signal) { const msg = this.msg; return this.api.sendMediaGroup(orThrow(this.chatId, "sendMediaGroup"), media, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithLocation(latitude, longitude, other, signal) { const msg = this.msg; return this.api.sendLocation(orThrow(this.chatId, "sendLocation"), latitude, longitude, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } 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); } stopMessageLiveLocation(other, signal) { const inlineId = this.inlineMessageId; return inlineId !== undefined ? this.api.stopMessageLiveLocationInline(inlineId, { business_connection_id: this.businessConnectionId, ...other }, signal) : this.api.stopMessageLiveLocation(orThrow(this.chatId, "stopMessageLiveLocation"), orThrow(this.msgId, "stopMessageLiveLocation"), { business_connection_id: this.businessConnectionId, ...other }, signal); } sendPaidMedia(star_count, media, other, signal) { return this.api.sendPaidMedia(orThrow(this.chatId, "sendPaidMedia"), star_count, media, { business_connection_id: this.businessConnectionId, direct_messages_topic_id: this.msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithVenue(latitude, longitude, title, address, other, signal) { const msg = this.msg; return this.api.sendVenue(orThrow(this.chatId, "sendVenue"), latitude, longitude, title, address, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithContact(phone_number, first_name, other, signal) { const msg = this.msg; return this.api.sendContact(orThrow(this.chatId, "sendContact"), phone_number, first_name, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithPoll(question, options, other, signal) { const msg = this.msg; return this.api.sendPoll(orThrow(this.chatId, "sendPoll"), question, options, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, ...other }, signal); } replyWithChecklist(checklist, other, signal) { return this.api.sendChecklist(orThrow(this.businessConnectionId, "sendChecklist"), orThrow(this.chatId, "sendChecklist"), checklist, other, signal); } editMessageChecklist(checklist, other, signal) { const msg = orThrow(this.msg, "editMessageChecklist"); const target = msg.checklist_tasks_done?.checklist_message ?? msg.checklist_tasks_added?.checklist_message ?? msg; return this.api.editMessageChecklist(orThrow(this.businessConnectionId, "editMessageChecklist"), orThrow(target.chat.id, "editMessageChecklist"), orThrow(target.message_id, "editMessageChecklist"), checklist, other, signal); } replyWithDice(emoji, other, signal) { const msg = this.msg; return this.api.sendDice(orThrow(this.chatId, "sendDice"), emoji, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, direct_messages_topic_id: msg?.direct_messages_topic?.topic_id, ...other }, signal); } replyWithChatAction(action, other, signal) { const msg = this.msg; return this.api.sendChatAction(orThrow(this.chatId, "sendChatAction"), action, { business_connection_id: this.businessConnectionId, ...msg?.is_topic_message ? { message_thread_id: msg?.message_thread_id } : {}, ...other }, signal); } react(reaction, other, signal) { return this.api.setMessageReaction(orThrow(this.chatId, "setMessageReaction"), orThrow(this.msgId, "setMessageReaction"), typeof reaction === "string" ? [ { type: "emoji", emoji: reaction } ] : (Array.isArray(reaction) ? reaction : [ reaction ]).map((emoji)=>typeof emoji === "string" ? { type: "emoji", emoji } : emoji), other, signal); } getUserProfilePhotos(other, signal) { return this.api.getUserProfilePhotos(orThrow(this.from, "getUserProfilePhotos").id, other, signal); } setUserEmojiStatus(other, signal) { return this.api.setUserEmojiStatus(orThrow(this.from, "setUserEmojiStatus").id, other, signal); } getUserChatBoosts(chat_id, signal) { return this.api.getUserChatBoosts(chat_id, orThrow(this.from, "getUserChatBoosts").id, signal); } getBusinessConnection(signal) { return this.api.getBusinessConnection(orThrow(this.businessConnectionId, "getBusinessConnection"), signal); } getFile(signal) { const m = orThrow(this.msg, "getFile"); const file = m.photo !== undefined ? m.photo[m.photo.length - 1] : m.animation ?? m.audio ?? m.document ?? m.video ?? m.video_note ?? m.voice ?? m.sticker; return this.api.getFile(orThrow(file, "getFile").file_id, signal); } kickAuthor(...args) { return this.banAuthor(...args); } banAuthor(other, signal) { return this.api.banChatMember(orThrow(this.chatId, "banAuthor"), orThrow(this.from, "banAuthor").id, other, signal); } kickChatMember(...args) { return this.banChatMember(...args); } banChatMember(user_id, other, signal) { return this.api.banChatMember(orThrow(this.chatId, "banChatMember"), user_id, other, signal); } unbanChatMember(user_id, other, signal) { return this.api.unbanChatMember(orThrow(this.chatId, "unbanChatMember"), user_id, other, signal); } restrictAuthor(permissions, other, signal) { return this.api.restrictChatMember(orThrow(this.chatId, "restrictAuthor"), orThrow(this.from, "restrictAuthor").id, permissions, other, signal); } restrictChatMember(user_id, permissions, other, signal) { return this.api.restrictChatMember(orThrow(this.chatId, "restrictChatMember"), user_id, permissions, other, signal); } promoteAuthor(other, signal) { return this.api.promoteChatMember(orThrow(this.chatId, "promoteAuthor"), orThrow(this.from, "promoteAuthor").id, other, signal); } promoteChatMember(user_id, other, signal) { return this.api.promoteChatMember(orThrow(this.chatId, "promoteChatMember"), user_id, other, signal); } setChatAdministratorAuthorCustomTitle(custom_title, signal) { return this.api.setChatAdministratorCustomTitle(orThrow(this.chatId, "setChatAdministratorAuthorCustomTitle"), orThrow(this.from, "setChatAdministratorAuthorCustomTitle").id, custom_title, signal); } setChatAdministratorCustomTitle(user_id, custom_title, signal) { return this.api.setChatAdministratorCustomTitle(orThrow(this.chatId, "setChatAdministratorCustomTitle"), user_id, custom_title, signal); } banChatSenderChat(sender_chat_id, signal) { return this.api.banChatSenderChat(orThrow(this.chatId, "banChatSenderChat"), sender_chat_id, signal); } unbanChatSenderChat(sender_chat_id, signal) { return this.api.unbanChatSenderChat(orThrow(this.chatId, "unbanChatSenderChat"), sender_chat_id, signal); } setChatPermissions(permissions, other, signal) { return this.api.setChatPermissions(orThrow(this.chatId, "setChatPermissions"), permissions, other, signal); } exportChatInviteLink(signal) { return this.api.exportChatInviteLink(orThrow(this.chatId, "exportChatInviteLink"), signal); } createChatInviteLink(other, signal) { return this.api.createChatInviteLink(orThrow(this.chatId, "createChatInviteLink"), other, signal); } editChatInviteLink(invite_link, other, signal) { return this.api.editChatInviteLink(orThrow(this.chatId, "editChatInviteLink"), invite_link, other, signal); } createChatSubscriptionInviteLink(subscription_period, subscription_price, other, signal) { return this.api.createChatSubscriptionInviteLink(orThrow(this.chatId, "createChatSubscriptionInviteLink"), subscription_period, subscription_price, other, signal); } editChatSubscriptionInviteLink(invite_link, other, signal) { return this.api.editChatSubscriptionInviteLink(orThrow(this.chatId, "editChatSubscriptionInviteLink"), invite_link, other, signal); } revokeChatInviteLink(invite_link, signal) { return this.api.revokeChatInviteLink(orThrow(this.chatId, "editChatInviteLink"), invite_link, signal); } approveChatJoinRequest(user_id, signal) { return this.api.approveChatJoinRequest(orThrow(this.chatId, "approveChatJoinRequest"), user_id, signal); } declineChatJoinRequest(user_id, signal) { return this.api.declineChatJoinRequest(orThrow(this.chatId, "declineChatJoinRequest"), user_id, signal); } approveSuggestedPost(other, signal) { return this.api.approveSuggestedPost(orThrow(this.chatId, "approveSuggestedPost"), orThrow(this.msgId, "approveSuggestedPost"), other, signal); } declineSuggestedPost(other, signal) { return this.api.declineSuggestedPost(orThrow(this.chatId, "declineSuggestedPost"), orThrow(this.msgId, "declineSuggestedPost"), other, signal); } setChatPhoto(photo, signal) { return this.api.setChatPhoto(orThrow(this.chatId, "setChatPhoto"), photo, signal); } deleteChatPhoto(signal) { return this.api.deleteChatPhoto(orThrow(this.chatId, "deleteChatPhoto"), signal); } setChatTitle(title, signal) { return this.api.setChatTitle(orThrow(this.chatId, "setChatTitle"), title, signal); } setChatDescription(description, signal) { return this.api.setChatDescription(orThrow(this.chatId, "setChatDescription"), description, signal); } pinChatMessage(message_id, other, signal) { return this.api.pinChatMessage(orThrow(this.chatId, "pinChatMessage"), message_id, { business_connection_id: this.businessConnectionId, ...other }, signal); } unpinChatMessage(message_id, other, signal) { return this.api.unpinChatMessage(orThrow(this.chatId, "unpinChatMessage"), message_id, { business_connection_id: this.businessConnectionId, ...other }, signal); } unpinAllChatMessages(signal) { return this.api.unpinAllChatMessages(orThrow(this.chatId, "unpinAllChatMessages"), signal); } leaveChat(signal) { return this.api.leaveChat(orThrow(this.chatId, "leaveChat"), signal); } getChat(signal) { return this.api.getChat(orThrow(this.chatId, "getChat"), signal); } getChatAdministrators(signal) { return this.api.getChatAdministrators(orThrow(this.chatId, "getChatAdministrators"), signal); } getChatMembersCount(...args) { return this.getChatMemberCount(...args); } getChatMemberCount(signal) { return this.api.getChatMemberCount(orThrow(this.chatId, "getChatMemberCount"), signal); } getAuthor(signal) { return this.api.getChatMember(orThrow(this.chatId, "getAuthor"), orThrow(this.from, "getAuthor").id, signal); } getChatMember(user_id, signal) { return this.api.getChatMember(orThrow(this.chatId, "getChatMember"), user_id, signal); } setChatStickerSet(sticker_set_name, signal) { return this.api.setChatStickerSet(orThrow(this.chatId, "setChatStickerSet"), sticker_set_name, signal); } deleteChatStickerSet(signal) { return this.api.deleteChatStickerSet(orThrow(this.chatId, "deleteChatStickerSet"), signal); } createForumTopic(name, other, signal) { return this.api.createForumTopic(orThrow(this.chatId, "createForumTopic"), name, other, signal); } editForumTopic(other, signal) { const message = orThrow(this.msg, "editForumTopic"); const thread = orThrow(message.message_thread_id, "editForumTopic"); return this.api.editForumTopic(message.chat.id, thread, other, signal); } closeForumTopic(signal) { const message = orThrow(this.msg, "closeForumTopic"); const thread = orThrow(message.message_thread_id, "closeForumTopic"); return this.api.closeForumTopic(message.chat.id, thread, signal); } reopenForumTopic(signal) { const message = orThrow(this.msg, "reopenForumTopic"); const thread = orThrow(message.message_thread_id, "reopenForumTopic"); return this.api.reopenForumTopic(message.chat.id, thread, signal); } deleteForumTopic(signal) { const message = orThrow(this.msg, "deleteForumTopic"); const thread = orThrow(message.message_thread_id, "deleteForumTopic"); return this.api.deleteForumTopic(message.chat.id, thread, signal); } unpinAllForumTopicMessages(signal) { const message = orThrow(this.msg, "unpinAllForumTopicMessages"); const thread = orThrow(message.message_thread_id, "unpinAllForumTopicMessages"); return this.api.unpinAllForumTopicMessages(message.chat.id, thread, signal); } editGeneralForumTopic(name, signal) { return this.api.editGeneralForumTopic(orThrow(this.chatId, "editGeneralForumTopic"), name, signal); } closeGeneralForumTopic(signal) { return this.api.closeGeneralForumTopic(orThrow(this.chatId, "closeGeneralForumTopic"), signal); } reopenGeneralForumTopic(signal) { return this.api.reopenGeneralForumTopic(orThrow(this.chatId, "reopenGeneralForumTopic"), signal); } hideGeneralForumTopic(signal) { return this.api.hideGeneralForumTopic(orThrow(this.chatId, "hideGeneralForumTopic"), signal); } unhideGeneralForumTopic(signal) { return this.api.unhideGeneralForumTopic(orThrow(this.chatId, "unhideGeneralForumTopic"), signal); } unpinAllGeneralForumTopicMessages(signal) { return this.api.unpinAllGeneralForumTopicMessages(orThrow(this.chatId, "unpinAllGeneralForumTopicMessages"), signal); } answerCallbackQuery(other, signal) { return this.api.answerCallbackQuery(orThrow(this.callbackQuery, "answerCallbackQuery").id, typeof other === "string" ? { text: other } : other, signal); } setChatMenuButton(other, signal) { return this.api.setChatMenuButton(other, signal); } getChatMenuButton(other, signal) { return this.api.getChatMenuButton(other, signal); } setMyDefaultAdministratorRights(other, signal) { return this.api.setMyDefaultAdministratorRights(other, signal); } getMyDefaultAdministratorRights(other, signal) { return this.api.getMyDefaultAdministratorRights(other, signal); } editMessageText(text, other, signal) { const inlineId = this.inlineMessageId; return inlineId !== undefined ? this.api.editMessageTextInline(inlineId, text, { business_connection_id: this.businessConnectionId, ...other }, signal) : this.api.editMessageText(orThrow(this.chatId, "editMessageText"), orThrow(this.msg?.message_id ?? this.messageReaction?.message_id ?? this.messageReactionCount?.message_id, "editMessageText"), text, { business_connection_id: this.businessConnectionId, ...other }, signal); } editMessageCaption(other, signal) { const inlineId = this.inlineMessageId; return inlineId !== undefined ? this.api.editMessageCaptionInline(inlineId, { business_connection_id: this.businessConnectionId, ...other }, signal) : this.api.editMessageCaption(orThrow(this.chatId, "editMessageCaption"), orThrow(this.msg?.message_id ?? this.messageReaction?.message_id ?? this.messageReactionCount?.message_id, "editMessageCaption"), { business_connection_id: this.businessConnectionId, ...other }, signal); } editMessageMedia(media, other, signal) { const inlineId = this.inlineMessageId; return inlineId !== undefined ? this.api.editMessageMediaInline(inlineId, media, { business_connection_id: this.businessConnectionId, ...other }, signal) : this.api.editMessageMedia(orThrow(this.chatId, "editMessageMedia"), orThrow(this.msg?.message_id ?? this.messageReaction?.message_id ?? this.messageReactionCount?.message_id, "editMessageMedia"), media, { business_connection_id: this.businessConnectionId, ...other }, signal); } editMessageReplyMarkup(other, signal) { const inlineId = this.inlineMessageId; return inlineId !== undefined ? this.api.editMessageReplyMarkupInline(inlineId, { business_connection_id: this.businessConnectionId, ...other }, signal) : this.api.editMessageReplyMarkup(orThrow(this.chatId, "editMessageReplyMarkup"), orThrow(this.msg?.message_id ?? this.messageReaction?.message_id ?? this.messageReactionCount?.message_id, "editMessageReplyMarkup"), { business_connection_id: this.businessConnectionId, ...other }, signal); } stopPoll(other, signal) { return this.api.stopPoll(orThrow(this.chatId, "stopPoll"), orThrow(this.msg?.message_id ?? this.messageReaction?.message_id ?? this.messageReactionCount?.message_id, "stopPoll"), { business_connection_id: this.businessConnectionId, ...other }, signal); } deleteMessage(signal) { return this.api.deleteMessage(orThrow(this.chatId, "deleteMessage"), orThrow(this.msg?.message_id ?? this.messageReaction?.message_id ?? this.messageReactionCount?.message_id, "deleteMessage"), signal); } deleteMessages(message_ids, signal) { return this.api.deleteMessages(orThrow(this.chatId, "deleteMessages"), message_ids, signal); } deleteBusinessMessages(message_ids, signal) { return this.api.deleteBusinessMessages(orThrow(this.businessConnectionId, "deleteBusinessMessages"), message_ids, signal); } setBusinessAccountName(first_name, other, signal) { return this.api.setBusinessAccountName(orThrow(this.businessConnectionId, "setBusinessAccountName"), first_name, other, signal); } setBusinessAccountUsername(username, signal) { return this.api.setBusinessAccountUsername(orThrow(this.businessConnectionId, "setBusinessAccountUsername"), username, signal); } setBusinessAccountBio(bio, signal) { return this.api.se