5839 lines
188 KiB
JavaScript
5839 lines
188 KiB
JavaScript
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 GIFT_INFO_KEYS = {
|
|
can_be_upgraded: {},
|
|
is_upgrade_separate: {},
|
|
is_private: {}
|
|
};
|
|
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: GIFT_INFO_KEYS,
|
|
gift_upgrade_sent: GIFT_INFO_KEYS,
|
|
unique_gift: {
|
|
transfer_star_count: {}
|
|
},
|
|
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: {},
|
|
chat_owner_left: {
|
|
new_owner: {}
|
|
},
|
|
chat_owner_changd: {},
|
|
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: {
|
|
is_name_implicit: {}
|
|
},
|
|
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);
|
|
}
|
|
replyWithDraft(text, other, signal) {
|
|
const msg = this.msg;
|
|
return this.api.sendMessageDraft(orThrow(this.chatId, "sendMessageDraft"), this.update.update_id, text, {
|
|
...msg?.is_topic_message ? {
|
|
message_thread_id: msg?.message_thread_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) {
|
|
const msg = this.msg;
|
|
return this.api.sendPaidMedia(orThrow(this.chatId, "sendPaidMedia"), star_count, media, {
|
|
business_connection_id: this.businessConnectionId,
|
|
...msg?.is_topic_message ? {
|
|
message_thread_id: msg.message_thread_id
|
|
} : {},
|
|
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,
|
|
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);
|
|
}
|
|
getUserProfileAudios(other, signal) {
|
|
return this.api.getUserProfileAudios(orThrow(this.from, "getUserProfileAudios").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.chatId, "getUserChatBoosts"), orThrow(this.from, "getUserChatBoosts").id, signal);
|
|
}
|
|
getUserGifts(other, signal) {
|
|
return this.api.getUserGifts(orThrow(this.from, "getUserGifts").id, other, signal);
|
|
}
|
|
getChatGifts(other, signal) {
|
|
return this.api.getChatGifts(orThrow(this.chatId, "getChatGifts"), other, 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.setBusinessAccountBio(orThrow(this.businessConnectionId, "setBusinessAccountBio"), bio, signal);
|
|
}
|
|
setBusinessAccountProfilePhoto(photo, other, signal) {
|
|
return this.api.setBusinessAccountProfilePhoto(orThrow(this.businessConnectionId, "setBusinessAccountProfilePhoto"), photo, other, signal);
|
|
}
|
|
removeBusinessAccountProfilePhoto(other, signal) {
|
|
return this.api.removeBusinessAccountProfilePhoto(orThrow(this.businessConnectionId, "removeBusinessAccountProfilePhoto"), other, signal);
|
|
}
|
|
setBusinessAccountGiftSettings(show_gift_button, accepted_gift_types, signal) {
|
|
return this.api.setBusinessAccountGiftSettings(orThrow(this.businessConnectionId, "setBusinessAccountGiftSettings"), show_gift_button, accepted_gift_types, signal);
|
|
}
|
|
getBusinessAccountStarBalance(signal) {
|
|
return this.api.getBusinessAccountStarBalance(orThrow(this.businessConnectionId, "getBusinessAccountStarBalance"), signal);
|
|
}
|
|
transferBusinessAccountStars(star_count, signal) {
|
|
return this.api.transferBusinessAccountStars(orThrow(this.businessConnectionId, "transferBusinessAccountStars"), star_count, signal);
|
|
}
|
|
getBusinessAccountGifts(other, signal) {
|
|
return this.api.getBusinessAccountGifts(orThrow(this.businessConnectionId, "getBusinessAccountGifts"), other, signal);
|
|
}
|
|
convertGiftToStars(owned_gift_id, signal) {
|
|
return this.api.convertGiftToStars(orThrow(this.businessConnectionId, "convertGiftToStars"), owned_gift_id, signal);
|
|
}
|
|
upgradeGift(owned_gift_id, other, signal) {
|
|
return this.api.upgradeGift(orThrow(this.businessConnectionId, "upgradeGift"), owned_gift_id, other, signal);
|
|
}
|
|
transferGift(owned_gift_id, new_owner_chat_id, star_count, signal) {
|
|
return this.api.transferGift(orThrow(this.businessConnectionId, "transferGift"), owned_gift_id, new_owner_chat_id, star_count, signal);
|
|
}
|
|
postStory(content, active_period, other, signal) {
|
|
return this.api.postStory(orThrow(this.businessConnectionId, "postStory"), content, active_period, other, signal);
|
|
}
|
|
repostStory(active_period, other, signal) {
|
|
const story = orThrow(this.msg?.story, "repostStory");
|
|
return this.api.repostStory(orThrow(this.businessConnectionId, "repostStory"), story.chat.id, story.id, active_period, other, signal);
|
|
}
|
|
editStory(story_id, content, other, signal) {
|
|
return this.api.editStory(orThrow(this.businessConnectionId, "editStory"), story_id, content, other, signal);
|
|
}
|
|
deleteStory(story_id, signal) {
|
|
return this.api.deleteStory(orThrow(this.businessConnectionId, "deleteStory"), story_id, signal);
|
|
}
|
|
replyWithSticker(sticker, other, signal) {
|
|
const msg = this.msg;
|
|
return this.api.sendSticker(orThrow(this.chatId, "sendSticker"), sticker, {
|
|
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);
|
|
}
|
|
getCustomEmojiStickers(signal) {
|
|
return this.api.getCustomEmojiStickers((this.msg?.entities ?? []).filter((e)=>e.type === "custom_emoji").map((e)=>e.custom_emoji_id), signal);
|
|
}
|
|
replyWithGift(gift_id, other, signal) {
|
|
return this.api.sendGift(orThrow(this.from, "sendGift").id, gift_id, other, signal);
|
|
}
|
|
giftPremiumSubscription(month_count, star_count, other, signal) {
|
|
return this.api.giftPremiumSubscription(orThrow(this.from, "giftPremiumSubscription").id, month_count, star_count, other, signal);
|
|
}
|
|
replyWithGiftToChannel(gift_id, other, signal) {
|
|
return this.api.sendGiftToChannel(orThrow(this.chat, "sendGift").id, gift_id, other, signal);
|
|
}
|
|
answerInlineQuery(results, other, signal) {
|
|
return this.api.answerInlineQuery(orThrow(this.inlineQuery, "answerInlineQuery").id, results, other, signal);
|
|
}
|
|
savePreparedInlineMessage(result, other, signal) {
|
|
return this.api.savePreparedInlineMessage(orThrow(this.from, "savePreparedInlineMessage").id, result, other, signal);
|
|
}
|
|
replyWithInvoice(title, description, payload, currency, prices, other, signal) {
|
|
const msg = this.msg;
|
|
return this.api.sendInvoice(orThrow(this.chatId, "sendInvoice"), title, description, payload, currency, prices, {
|
|
...msg?.is_topic_message ? {
|
|
message_thread_id: msg.message_thread_id
|
|
} : {},
|
|
direct_messages_topic_id: msg?.direct_messages_topic?.topic_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
answerShippingQuery(ok, other, signal) {
|
|
return this.api.answerShippingQuery(orThrow(this.shippingQuery, "answerShippingQuery").id, ok, other, signal);
|
|
}
|
|
answerPreCheckoutQuery(ok, other, signal) {
|
|
return this.api.answerPreCheckoutQuery(orThrow(this.preCheckoutQuery, "answerPreCheckoutQuery").id, ok, typeof other === "string" ? {
|
|
error_message: other
|
|
} : other, signal);
|
|
}
|
|
refundStarPayment(signal) {
|
|
return this.api.refundStarPayment(orThrow(this.from, "refundStarPayment").id, orThrow(this.msg?.successful_payment, "refundStarPayment").telegram_payment_charge_id, signal);
|
|
}
|
|
editUserStarSubscription(telegram_payment_charge_id, is_canceled, signal) {
|
|
return this.api.editUserStarSubscription(orThrow(this.from, "editUserStarSubscription").id, telegram_payment_charge_id, is_canceled, signal);
|
|
}
|
|
verifyUser(other, signal) {
|
|
return this.api.verifyUser(orThrow(this.from, "verifyUser").id, other, signal);
|
|
}
|
|
verifyChat(other, signal) {
|
|
return this.api.verifyChat(orThrow(this.chatId, "verifyChat"), other, signal);
|
|
}
|
|
removeUserVerification(signal) {
|
|
return this.api.removeUserVerification(orThrow(this.from, "removeUserVerification").id, signal);
|
|
}
|
|
removeChatVerification(signal) {
|
|
return this.api.removeChatVerification(orThrow(this.chatId, "removeChatVerification"), signal);
|
|
}
|
|
readBusinessMessage(signal) {
|
|
return this.api.readBusinessMessage(orThrow(this.businessConnectionId, "readBusinessMessage"), orThrow(this.chatId, "readBusinessMessage"), orThrow(this.msgId, "readBusinessMessage"), signal);
|
|
}
|
|
setPassportDataErrors(errors, signal) {
|
|
return this.api.setPassportDataErrors(orThrow(this.from, "setPassportDataErrors").id, errors, signal);
|
|
}
|
|
replyWithGame(game_short_name, other, signal) {
|
|
const msg = this.msg;
|
|
return this.api.sendGame(orThrow(this.chatId, "sendGame"), game_short_name, {
|
|
business_connection_id: this.businessConnectionId,
|
|
...msg?.is_topic_message ? {
|
|
message_thread_id: msg.message_thread_id
|
|
} : {},
|
|
...other
|
|
}, signal);
|
|
}
|
|
}
|
|
function orThrow(value, method) {
|
|
if (value === undefined) {
|
|
throw new Error(`Missing information for API call to ${method}`);
|
|
}
|
|
return value;
|
|
}
|
|
function triggerFn(trigger) {
|
|
return toArray(trigger).map((t)=>typeof t === "string" ? (txt)=>txt === t ? t : null : (txt)=>txt.match(t));
|
|
}
|
|
function match(ctx, content, triggers) {
|
|
for (const t of triggers){
|
|
const res = t(content);
|
|
if (res) {
|
|
ctx.match = res;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function toArray(e) {
|
|
return Array.isArray(e) ? e : [
|
|
e
|
|
];
|
|
}
|
|
class BotError extends Error {
|
|
error;
|
|
ctx;
|
|
constructor(error, ctx){
|
|
super(generateBotErrorMessage(error));
|
|
this.error = error;
|
|
this.ctx = ctx;
|
|
this.name = "BotError";
|
|
if (error instanceof Error) this.stack = error.stack;
|
|
}
|
|
}
|
|
function generateBotErrorMessage(error) {
|
|
let msg;
|
|
if (error instanceof Error) {
|
|
msg = `${error.name} in middleware: ${error.message}`;
|
|
} else {
|
|
const type = typeof error;
|
|
msg = `Non-error value of type ${type} thrown in middleware`;
|
|
switch(type){
|
|
case "bigint":
|
|
case "boolean":
|
|
case "number":
|
|
case "symbol":
|
|
msg += `: ${error}`;
|
|
break;
|
|
case "string":
|
|
msg += `: ${String(error).substring(0, 50)}`;
|
|
break;
|
|
default:
|
|
msg += "!";
|
|
break;
|
|
}
|
|
}
|
|
return msg;
|
|
}
|
|
function flatten(mw) {
|
|
return typeof mw === "function" ? mw : (ctx, next)=>mw.middleware()(ctx, next);
|
|
}
|
|
function concat1(first, andThen) {
|
|
return async (ctx, next)=>{
|
|
let nextCalled = false;
|
|
await first(ctx, async ()=>{
|
|
if (nextCalled) throw new Error("`next` already called before!");
|
|
else nextCalled = true;
|
|
await andThen(ctx, next);
|
|
});
|
|
};
|
|
}
|
|
function pass(_ctx, next) {
|
|
return next();
|
|
}
|
|
const leaf1 = ()=>Promise.resolve();
|
|
async function run(middleware, ctx) {
|
|
await middleware(ctx, leaf1);
|
|
}
|
|
class Composer {
|
|
handler;
|
|
constructor(...middleware){
|
|
this.handler = middleware.length === 0 ? pass : middleware.map(flatten).reduce(concat1);
|
|
}
|
|
middleware() {
|
|
return this.handler;
|
|
}
|
|
use(...middleware) {
|
|
const composer = new Composer(...middleware);
|
|
this.handler = concat1(this.handler, flatten(composer));
|
|
return composer;
|
|
}
|
|
on(filter, ...middleware) {
|
|
return this.filter(Context.has.filterQuery(filter), ...middleware);
|
|
}
|
|
hears(trigger, ...middleware) {
|
|
return this.filter(Context.has.text(trigger), ...middleware);
|
|
}
|
|
command(command, ...middleware) {
|
|
return this.filter(Context.has.command(command), ...middleware);
|
|
}
|
|
reaction(reaction, ...middleware) {
|
|
return this.filter(Context.has.reaction(reaction), ...middleware);
|
|
}
|
|
chatType(chatType, ...middleware) {
|
|
return this.filter(Context.has.chatType(chatType), ...middleware);
|
|
}
|
|
callbackQuery(trigger, ...middleware) {
|
|
return this.filter(Context.has.callbackQuery(trigger), ...middleware);
|
|
}
|
|
gameQuery(trigger, ...middleware) {
|
|
return this.filter(Context.has.gameQuery(trigger), ...middleware);
|
|
}
|
|
inlineQuery(trigger, ...middleware) {
|
|
return this.filter(Context.has.inlineQuery(trigger), ...middleware);
|
|
}
|
|
chosenInlineResult(resultId, ...middleware) {
|
|
return this.filter(Context.has.chosenInlineResult(resultId), ...middleware);
|
|
}
|
|
preCheckoutQuery(trigger, ...middleware) {
|
|
return this.filter(Context.has.preCheckoutQuery(trigger), ...middleware);
|
|
}
|
|
shippingQuery(trigger, ...middleware) {
|
|
return this.filter(Context.has.shippingQuery(trigger), ...middleware);
|
|
}
|
|
filter(predicate, ...middleware) {
|
|
const composer = new Composer(...middleware);
|
|
this.branch(predicate, composer, pass);
|
|
return composer;
|
|
}
|
|
drop(predicate, ...middleware) {
|
|
return this.filter(async (ctx)=>!await predicate(ctx), ...middleware);
|
|
}
|
|
fork(...middleware) {
|
|
const composer = new Composer(...middleware);
|
|
const fork = flatten(composer);
|
|
this.use((ctx, next)=>Promise.all([
|
|
next(),
|
|
run(fork, ctx)
|
|
]));
|
|
return composer;
|
|
}
|
|
lazy(middlewareFactory) {
|
|
return this.use(async (ctx, next)=>{
|
|
const middleware = await middlewareFactory(ctx);
|
|
const arr = Array.isArray(middleware) ? middleware : [
|
|
middleware
|
|
];
|
|
await flatten(new Composer(...arr))(ctx, next);
|
|
});
|
|
}
|
|
route(router, routeHandlers, fallback = pass) {
|
|
return this.lazy(async (ctx)=>{
|
|
const route = await router(ctx);
|
|
return (route === undefined || !routeHandlers[route] ? fallback : routeHandlers[route]) ?? [];
|
|
});
|
|
}
|
|
branch(predicate, trueMiddleware, falseMiddleware) {
|
|
return this.lazy(async (ctx)=>await predicate(ctx) ? trueMiddleware : falseMiddleware);
|
|
}
|
|
errorBoundary(errorHandler, ...middleware) {
|
|
const composer = new Composer(...middleware);
|
|
const bound = flatten(composer);
|
|
this.use(async (ctx, next)=>{
|
|
let nextCalled = false;
|
|
const cont = ()=>(nextCalled = true, Promise.resolve());
|
|
try {
|
|
await bound(ctx, cont);
|
|
} catch (err) {
|
|
nextCalled = false;
|
|
await errorHandler(new BotError(err, ctx), cont);
|
|
}
|
|
if (nextCalled) await next();
|
|
});
|
|
return composer;
|
|
}
|
|
}
|
|
var s = 1e3;
|
|
var m = s * 60;
|
|
var h = m * 60;
|
|
var d = h * 24;
|
|
var w = d * 7;
|
|
var y = d * 365.25;
|
|
var ms = function(val, options) {
|
|
options = options || {};
|
|
var type = typeof val;
|
|
if (type === "string" && val.length > 0) {
|
|
return parse1(val);
|
|
} else if (type === "number" && isFinite(val)) {
|
|
return options.long ? fmtLong(val) : fmtShort(val);
|
|
}
|
|
throw new Error("val is not a non-empty string or a valid number. val=" + JSON.stringify(val));
|
|
};
|
|
function parse1(str) {
|
|
str = String(str);
|
|
if (str.length > 100) {
|
|
return;
|
|
}
|
|
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);
|
|
if (!match) {
|
|
return;
|
|
}
|
|
var n = parseFloat(match[1]);
|
|
var type = (match[2] || "ms").toLowerCase();
|
|
switch(type){
|
|
case "years":
|
|
case "year":
|
|
case "yrs":
|
|
case "yr":
|
|
case "y":
|
|
return n * y;
|
|
case "weeks":
|
|
case "week":
|
|
case "w":
|
|
return n * w;
|
|
case "days":
|
|
case "day":
|
|
case "d":
|
|
return n * d;
|
|
case "hours":
|
|
case "hour":
|
|
case "hrs":
|
|
case "hr":
|
|
case "h":
|
|
return n * h;
|
|
case "minutes":
|
|
case "minute":
|
|
case "mins":
|
|
case "min":
|
|
case "m":
|
|
return n * m;
|
|
case "seconds":
|
|
case "second":
|
|
case "secs":
|
|
case "sec":
|
|
case "s":
|
|
return n * s;
|
|
case "milliseconds":
|
|
case "millisecond":
|
|
case "msecs":
|
|
case "msec":
|
|
case "ms":
|
|
return n;
|
|
default:
|
|
return void 0;
|
|
}
|
|
}
|
|
function fmtShort(ms2) {
|
|
var msAbs = Math.abs(ms2);
|
|
if (msAbs >= d) {
|
|
return Math.round(ms2 / d) + "d";
|
|
}
|
|
if (msAbs >= h) {
|
|
return Math.round(ms2 / h) + "h";
|
|
}
|
|
if (msAbs >= m) {
|
|
return Math.round(ms2 / m) + "m";
|
|
}
|
|
if (msAbs >= s) {
|
|
return Math.round(ms2 / s) + "s";
|
|
}
|
|
return ms2 + "ms";
|
|
}
|
|
function fmtLong(ms2) {
|
|
var msAbs = Math.abs(ms2);
|
|
if (msAbs >= d) {
|
|
return plural(ms2, msAbs, d, "day");
|
|
}
|
|
if (msAbs >= h) {
|
|
return plural(ms2, msAbs, h, "hour");
|
|
}
|
|
if (msAbs >= m) {
|
|
return plural(ms2, msAbs, m, "minute");
|
|
}
|
|
if (msAbs >= s) {
|
|
return plural(ms2, msAbs, s, "second");
|
|
}
|
|
return ms2 + " ms";
|
|
}
|
|
function plural(ms2, msAbs, n, name) {
|
|
var isPlural = msAbs >= n * 1.5;
|
|
return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
|
|
}
|
|
function defaultSetTimout() {
|
|
throw new Error("setTimeout has not been defined");
|
|
}
|
|
function defaultClearTimeout() {
|
|
throw new Error("clearTimeout has not been defined");
|
|
}
|
|
var cachedSetTimeout = defaultSetTimout;
|
|
var cachedClearTimeout = defaultClearTimeout;
|
|
var globalContext;
|
|
if (typeof window !== "undefined") {
|
|
globalContext = window;
|
|
} else if (typeof self !== "undefined") {
|
|
globalContext = self;
|
|
} else {
|
|
globalContext = {};
|
|
}
|
|
if (typeof globalContext.setTimeout === "function") {
|
|
cachedSetTimeout = setTimeout;
|
|
}
|
|
if (typeof globalContext.clearTimeout === "function") {
|
|
cachedClearTimeout = clearTimeout;
|
|
}
|
|
function runTimeout(fun) {
|
|
if (cachedSetTimeout === setTimeout) {
|
|
return setTimeout(fun, 0);
|
|
}
|
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
|
cachedSetTimeout = setTimeout;
|
|
return setTimeout(fun, 0);
|
|
}
|
|
try {
|
|
return cachedSetTimeout(fun, 0);
|
|
} catch (e) {
|
|
try {
|
|
return cachedSetTimeout.call(null, fun, 0);
|
|
} catch (e2) {
|
|
return cachedSetTimeout.call(this, fun, 0);
|
|
}
|
|
}
|
|
}
|
|
function runClearTimeout(marker) {
|
|
if (cachedClearTimeout === clearTimeout) {
|
|
return clearTimeout(marker);
|
|
}
|
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
|
cachedClearTimeout = clearTimeout;
|
|
return clearTimeout(marker);
|
|
}
|
|
try {
|
|
return cachedClearTimeout(marker);
|
|
} catch (e) {
|
|
try {
|
|
return cachedClearTimeout.call(null, marker);
|
|
} catch (e2) {
|
|
return cachedClearTimeout.call(this, marker);
|
|
}
|
|
}
|
|
}
|
|
var queue = [];
|
|
var draining = false;
|
|
var currentQueue;
|
|
var queueIndex = -1;
|
|
function cleanUpNextTick() {
|
|
if (!draining || !currentQueue) {
|
|
return;
|
|
}
|
|
draining = false;
|
|
if (currentQueue.length) {
|
|
queue = currentQueue.concat(queue);
|
|
} else {
|
|
queueIndex = -1;
|
|
}
|
|
if (queue.length) {
|
|
drainQueue();
|
|
}
|
|
}
|
|
function drainQueue() {
|
|
if (draining) {
|
|
return;
|
|
}
|
|
var timeout = runTimeout(cleanUpNextTick);
|
|
draining = true;
|
|
var len = queue.length;
|
|
while(len){
|
|
currentQueue = queue;
|
|
queue = [];
|
|
while(++queueIndex < len){
|
|
if (currentQueue) {
|
|
currentQueue[queueIndex].run();
|
|
}
|
|
}
|
|
queueIndex = -1;
|
|
len = queue.length;
|
|
}
|
|
currentQueue = null;
|
|
draining = false;
|
|
runClearTimeout(timeout);
|
|
}
|
|
function nextTick(fun) {
|
|
var args = new Array(arguments.length - 1);
|
|
if (arguments.length > 1) {
|
|
for(var i = 1; i < arguments.length; i++){
|
|
args[i - 1] = arguments[i];
|
|
}
|
|
}
|
|
queue.push(new Item(fun, args));
|
|
if (queue.length === 1 && !draining) {
|
|
runTimeout(drainQueue);
|
|
}
|
|
}
|
|
function Item(fun, array) {
|
|
this.fun = fun;
|
|
this.array = array;
|
|
}
|
|
Item.prototype.run = function() {
|
|
this.fun.apply(null, this.array);
|
|
};
|
|
var title = "browser";
|
|
var platform = "browser";
|
|
var browser = true;
|
|
var argv = [];
|
|
var version = "";
|
|
var versions = {};
|
|
var release = {};
|
|
var config = {};
|
|
function noop() {}
|
|
var on = noop;
|
|
var addListener = noop;
|
|
var once = noop;
|
|
var off = noop;
|
|
var removeListener = noop;
|
|
var removeAllListeners = noop;
|
|
var emit = noop;
|
|
function binding(name) {
|
|
throw new Error("process.binding is not supported");
|
|
}
|
|
function cwd() {
|
|
return "/";
|
|
}
|
|
function chdir(dir) {
|
|
throw new Error("process.chdir is not supported");
|
|
}
|
|
function umask() {
|
|
return 0;
|
|
}
|
|
var performance = globalContext.performance || {};
|
|
var performanceNow = performance.now || performance.mozNow || performance.msNow || performance.oNow || performance.webkitNow || function() {
|
|
return new Date().getTime();
|
|
};
|
|
function hrtime(previousTimestamp) {
|
|
var clocktime = performanceNow.call(performance) * 1e-3;
|
|
var seconds = Math.floor(clocktime);
|
|
var nanoseconds = Math.floor(clocktime % 1 * 1e9);
|
|
if (previousTimestamp) {
|
|
seconds = seconds - previousTimestamp[0];
|
|
nanoseconds = nanoseconds - previousTimestamp[1];
|
|
if (nanoseconds < 0) {
|
|
seconds--;
|
|
nanoseconds += 1e9;
|
|
}
|
|
}
|
|
return [
|
|
seconds,
|
|
nanoseconds
|
|
];
|
|
}
|
|
var startTime = new Date();
|
|
function uptime() {
|
|
var currentTime = new Date();
|
|
var dif = currentTime - startTime;
|
|
return dif / 1e3;
|
|
}
|
|
var process = {
|
|
nextTick,
|
|
title,
|
|
browser,
|
|
env: {
|
|
NODE_ENV: "production"
|
|
},
|
|
argv,
|
|
version,
|
|
versions,
|
|
on,
|
|
addListener,
|
|
once,
|
|
off,
|
|
removeListener,
|
|
removeAllListeners,
|
|
emit,
|
|
binding,
|
|
cwd,
|
|
chdir,
|
|
umask,
|
|
hrtime,
|
|
platform,
|
|
release,
|
|
config,
|
|
uptime
|
|
};
|
|
function createCommonjsModule(fn, basedir, module) {
|
|
return module = {
|
|
path: basedir,
|
|
exports: {},
|
|
require: function(path, base) {
|
|
return commonjsRequire(path, base === void 0 || base === null ? module.path : base);
|
|
}
|
|
}, fn(module, module.exports), module.exports;
|
|
}
|
|
function commonjsRequire() {
|
|
throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs");
|
|
}
|
|
function setup(env) {
|
|
createDebug.debug = createDebug;
|
|
createDebug.default = createDebug;
|
|
createDebug.coerce = coerce;
|
|
createDebug.disable = disable;
|
|
createDebug.enable = enable;
|
|
createDebug.enabled = enabled;
|
|
createDebug.humanize = ms;
|
|
createDebug.destroy = destroy2;
|
|
Object.keys(env).forEach((key)=>{
|
|
createDebug[key] = env[key];
|
|
});
|
|
createDebug.names = [];
|
|
createDebug.skips = [];
|
|
createDebug.formatters = {};
|
|
function selectColor(namespace) {
|
|
let hash = 0;
|
|
for(let i = 0; i < namespace.length; i++){
|
|
hash = (hash << 5) - hash + namespace.charCodeAt(i);
|
|
hash |= 0;
|
|
}
|
|
return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
|
|
}
|
|
createDebug.selectColor = selectColor;
|
|
function createDebug(namespace) {
|
|
let prevTime;
|
|
let enableOverride = null;
|
|
let namespacesCache;
|
|
let enabledCache;
|
|
function debug(...args) {
|
|
if (!debug.enabled) {
|
|
return;
|
|
}
|
|
const self2 = debug;
|
|
const curr = Number(new Date());
|
|
const ms2 = curr - (prevTime || curr);
|
|
self2.diff = ms2;
|
|
self2.prev = prevTime;
|
|
self2.curr = curr;
|
|
prevTime = curr;
|
|
args[0] = createDebug.coerce(args[0]);
|
|
if (typeof args[0] !== "string") {
|
|
args.unshift("%O");
|
|
}
|
|
let index = 0;
|
|
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format)=>{
|
|
if (match === "%%") {
|
|
return "%";
|
|
}
|
|
index++;
|
|
const formatter = createDebug.formatters[format];
|
|
if (typeof formatter === "function") {
|
|
const val = args[index];
|
|
match = formatter.call(self2, val);
|
|
args.splice(index, 1);
|
|
index--;
|
|
}
|
|
return match;
|
|
});
|
|
createDebug.formatArgs.call(self2, args);
|
|
const logFn = self2.log || createDebug.log;
|
|
logFn.apply(self2, args);
|
|
}
|
|
debug.namespace = namespace;
|
|
debug.useColors = createDebug.useColors();
|
|
debug.color = createDebug.selectColor(namespace);
|
|
debug.extend = extend;
|
|
debug.destroy = createDebug.destroy;
|
|
Object.defineProperty(debug, "enabled", {
|
|
enumerable: true,
|
|
configurable: false,
|
|
get: ()=>{
|
|
if (enableOverride !== null) {
|
|
return enableOverride;
|
|
}
|
|
if (namespacesCache !== createDebug.namespaces) {
|
|
namespacesCache = createDebug.namespaces;
|
|
enabledCache = createDebug.enabled(namespace);
|
|
}
|
|
return enabledCache;
|
|
},
|
|
set: (v)=>{
|
|
enableOverride = v;
|
|
}
|
|
});
|
|
if (typeof createDebug.init === "function") {
|
|
createDebug.init(debug);
|
|
}
|
|
return debug;
|
|
}
|
|
function extend(namespace, delimiter) {
|
|
const newDebug = createDebug(this.namespace + (typeof delimiter === "undefined" ? ":" : delimiter) + namespace);
|
|
newDebug.log = this.log;
|
|
return newDebug;
|
|
}
|
|
function enable(namespaces) {
|
|
createDebug.save(namespaces);
|
|
createDebug.namespaces = namespaces;
|
|
createDebug.names = [];
|
|
createDebug.skips = [];
|
|
const split = (typeof namespaces === "string" ? namespaces : "").trim().replace(/\s+/g, ",").split(",").filter(Boolean);
|
|
for (const ns of split){
|
|
if (ns[0] === "-") {
|
|
createDebug.skips.push(ns.slice(1));
|
|
} else {
|
|
createDebug.names.push(ns);
|
|
}
|
|
}
|
|
}
|
|
function matchesTemplate(search, template) {
|
|
let searchIndex = 0;
|
|
let templateIndex = 0;
|
|
let starIndex = -1;
|
|
let matchIndex = 0;
|
|
while(searchIndex < search.length){
|
|
if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === "*")) {
|
|
if (template[templateIndex] === "*") {
|
|
starIndex = templateIndex;
|
|
matchIndex = searchIndex;
|
|
templateIndex++;
|
|
} else {
|
|
searchIndex++;
|
|
templateIndex++;
|
|
}
|
|
} else if (starIndex !== -1) {
|
|
templateIndex = starIndex + 1;
|
|
matchIndex++;
|
|
searchIndex = matchIndex;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
while(templateIndex < template.length && template[templateIndex] === "*"){
|
|
templateIndex++;
|
|
}
|
|
return templateIndex === template.length;
|
|
}
|
|
function disable() {
|
|
const namespaces = [
|
|
...createDebug.names,
|
|
...createDebug.skips.map((namespace)=>"-" + namespace)
|
|
].join(",");
|
|
createDebug.enable("");
|
|
return namespaces;
|
|
}
|
|
function enabled(name) {
|
|
for (const skip of createDebug.skips){
|
|
if (matchesTemplate(name, skip)) {
|
|
return false;
|
|
}
|
|
}
|
|
for (const ns of createDebug.names){
|
|
if (matchesTemplate(name, ns)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function coerce(val) {
|
|
if (val instanceof Error) {
|
|
return val.stack || val.message;
|
|
}
|
|
return val;
|
|
}
|
|
function destroy2() {
|
|
console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
}
|
|
createDebug.enable(createDebug.load());
|
|
return createDebug;
|
|
}
|
|
var common = setup;
|
|
var browser$1 = createCommonjsModule(function(module, exports) {
|
|
exports.formatArgs = formatArgs2;
|
|
exports.save = save2;
|
|
exports.load = load2;
|
|
exports.useColors = useColors2;
|
|
exports.storage = localstorage();
|
|
exports.destroy = (()=>{
|
|
let warned = false;
|
|
return ()=>{
|
|
if (!warned) {
|
|
warned = true;
|
|
console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
}
|
|
};
|
|
})();
|
|
exports.colors = [
|
|
"#0000CC",
|
|
"#0000FF",
|
|
"#0033CC",
|
|
"#0033FF",
|
|
"#0066CC",
|
|
"#0066FF",
|
|
"#0099CC",
|
|
"#0099FF",
|
|
"#00CC00",
|
|
"#00CC33",
|
|
"#00CC66",
|
|
"#00CC99",
|
|
"#00CCCC",
|
|
"#00CCFF",
|
|
"#3300CC",
|
|
"#3300FF",
|
|
"#3333CC",
|
|
"#3333FF",
|
|
"#3366CC",
|
|
"#3366FF",
|
|
"#3399CC",
|
|
"#3399FF",
|
|
"#33CC00",
|
|
"#33CC33",
|
|
"#33CC66",
|
|
"#33CC99",
|
|
"#33CCCC",
|
|
"#33CCFF",
|
|
"#6600CC",
|
|
"#6600FF",
|
|
"#6633CC",
|
|
"#6633FF",
|
|
"#66CC00",
|
|
"#66CC33",
|
|
"#9900CC",
|
|
"#9900FF",
|
|
"#9933CC",
|
|
"#9933FF",
|
|
"#99CC00",
|
|
"#99CC33",
|
|
"#CC0000",
|
|
"#CC0033",
|
|
"#CC0066",
|
|
"#CC0099",
|
|
"#CC00CC",
|
|
"#CC00FF",
|
|
"#CC3300",
|
|
"#CC3333",
|
|
"#CC3366",
|
|
"#CC3399",
|
|
"#CC33CC",
|
|
"#CC33FF",
|
|
"#CC6600",
|
|
"#CC6633",
|
|
"#CC9900",
|
|
"#CC9933",
|
|
"#CCCC00",
|
|
"#CCCC33",
|
|
"#FF0000",
|
|
"#FF0033",
|
|
"#FF0066",
|
|
"#FF0099",
|
|
"#FF00CC",
|
|
"#FF00FF",
|
|
"#FF3300",
|
|
"#FF3333",
|
|
"#FF3366",
|
|
"#FF3399",
|
|
"#FF33CC",
|
|
"#FF33FF",
|
|
"#FF6600",
|
|
"#FF6633",
|
|
"#FF9900",
|
|
"#FF9933",
|
|
"#FFCC00",
|
|
"#FFCC33"
|
|
];
|
|
function useColors2() {
|
|
if (typeof window !== "undefined" && window.process && (window.process.type === "renderer" || window.process.__nwjs)) {
|
|
return true;
|
|
}
|
|
if (typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
|
|
return false;
|
|
}
|
|
let m;
|
|
return typeof document !== "undefined" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || typeof window !== "undefined" && window.console && (window.console.firebug || window.console.exception && window.console.table) || typeof navigator !== "undefined" && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31 || typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
|
|
}
|
|
function formatArgs2(args) {
|
|
args[0] = (this.useColors ? "%c" : "") + this.namespace + (this.useColors ? " %c" : " ") + args[0] + (this.useColors ? "%c " : " ") + "+" + module.exports.humanize(this.diff);
|
|
if (!this.useColors) {
|
|
return;
|
|
}
|
|
const c = "color: " + this.color;
|
|
args.splice(1, 0, c, "color: inherit");
|
|
let index = 0;
|
|
let lastC = 0;
|
|
args[0].replace(/%[a-zA-Z%]/g, (match)=>{
|
|
if (match === "%%") {
|
|
return;
|
|
}
|
|
index++;
|
|
if (match === "%c") {
|
|
lastC = index;
|
|
}
|
|
});
|
|
args.splice(lastC, 0, c);
|
|
}
|
|
exports.log = console.debug || console.log || (()=>{});
|
|
function save2(namespaces) {
|
|
try {
|
|
if (namespaces) {
|
|
exports.storage.setItem("debug", namespaces);
|
|
} else {
|
|
exports.storage.removeItem("debug");
|
|
}
|
|
} catch (error) {}
|
|
}
|
|
function load2() {
|
|
let r;
|
|
try {
|
|
r = exports.storage.getItem("debug") || exports.storage.getItem("DEBUG");
|
|
} catch (error) {}
|
|
if (!r && typeof process !== "undefined" && "env" in process) {
|
|
r = process.env.DEBUG;
|
|
}
|
|
return r;
|
|
}
|
|
function localstorage() {
|
|
try {
|
|
return localStorage;
|
|
} catch (error) {}
|
|
}
|
|
module.exports = common(exports);
|
|
const { formatters } = module.exports;
|
|
formatters.j = function(v) {
|
|
try {
|
|
return JSON.stringify(v);
|
|
} catch (error) {
|
|
return "[UnexpectedJSONParseError]: " + error.message;
|
|
}
|
|
};
|
|
});
|
|
browser$1.colors;
|
|
browser$1.destroy;
|
|
browser$1.formatArgs;
|
|
browser$1.load;
|
|
browser$1.log;
|
|
browser$1.save;
|
|
browser$1.storage;
|
|
browser$1.useColors;
|
|
const itrToStream = (itr)=>{
|
|
const it = itr[Symbol.asyncIterator]();
|
|
return new ReadableStream({
|
|
async pull (controller) {
|
|
const chunk = await it.next();
|
|
if (chunk.done) controller.close();
|
|
else controller.enqueue(chunk.value);
|
|
}
|
|
});
|
|
};
|
|
const baseFetchConfig = (_apiRoot)=>({});
|
|
const defaultAdapter = "cloudflare";
|
|
const debug = browser$1("grammy:warn");
|
|
class GrammyError extends Error {
|
|
method;
|
|
payload;
|
|
ok;
|
|
error_code;
|
|
description;
|
|
parameters;
|
|
constructor(message, err, method, payload){
|
|
super(`${message} (${err.error_code}: ${err.description})`);
|
|
this.method = method;
|
|
this.payload = payload;
|
|
this.ok = false;
|
|
this.name = "GrammyError";
|
|
this.error_code = err.error_code;
|
|
this.description = err.description;
|
|
this.parameters = err.parameters ?? {};
|
|
}
|
|
}
|
|
function toGrammyError(err, method, payload) {
|
|
switch(err.error_code){
|
|
case 401:
|
|
debug("Error 401 means that your bot token is wrong, talk to https://t.me/BotFather to check it.");
|
|
break;
|
|
case 409:
|
|
debug("Error 409 means that you are running your bot several times on long polling. Consider revoking the bot token if you believe that no other instance is running.");
|
|
break;
|
|
}
|
|
return new GrammyError(`Call to '${method}' failed!`, err, method, payload);
|
|
}
|
|
class HttpError extends Error {
|
|
error;
|
|
constructor(message, error){
|
|
super(message);
|
|
this.error = error;
|
|
this.name = "HttpError";
|
|
}
|
|
}
|
|
function isTelegramError(err) {
|
|
return typeof err === "object" && err !== null && "status" in err && "statusText" in err;
|
|
}
|
|
function toHttpError(method, sensitiveLogs) {
|
|
return (err)=>{
|
|
let msg = `Network request for '${method}' failed!`;
|
|
if (isTelegramError(err)) msg += ` (${err.status}: ${err.statusText})`;
|
|
if (sensitiveLogs && err instanceof Error) msg += ` ${err.message}`;
|
|
throw new HttpError(msg, err);
|
|
};
|
|
}
|
|
function checkWindows() {
|
|
const global = globalThis;
|
|
const os = global.Deno?.build?.os;
|
|
return typeof os === "string" ? os === "windows" : global.navigator?.platform?.startsWith("Win") ?? global.process?.platform?.startsWith("win") ?? false;
|
|
}
|
|
const isWindows = checkWindows();
|
|
function assertPath(path) {
|
|
if (typeof path !== "string") {
|
|
throw new TypeError(`Path must be a string, received "${JSON.stringify(path)}"`);
|
|
}
|
|
}
|
|
function stripSuffix(name, suffix) {
|
|
if (suffix.length >= name.length) {
|
|
return name;
|
|
}
|
|
const lenDiff = name.length - suffix.length;
|
|
for(let i = suffix.length - 1; i >= 0; --i){
|
|
if (name.charCodeAt(lenDiff + i) !== suffix.charCodeAt(i)) {
|
|
return name;
|
|
}
|
|
}
|
|
return name.slice(0, -suffix.length);
|
|
}
|
|
function lastPathSegment(path, isSep, start = 0) {
|
|
let matchedNonSeparator = false;
|
|
let end = path.length;
|
|
for(let i = path.length - 1; i >= start; --i){
|
|
if (isSep(path.charCodeAt(i))) {
|
|
if (matchedNonSeparator) {
|
|
start = i + 1;
|
|
break;
|
|
}
|
|
} else if (!matchedNonSeparator) {
|
|
matchedNonSeparator = true;
|
|
end = i + 1;
|
|
}
|
|
}
|
|
return path.slice(start, end);
|
|
}
|
|
function assertArgs(path, suffix) {
|
|
assertPath(path);
|
|
if (path.length === 0) return path;
|
|
if (typeof suffix !== "string") {
|
|
throw new TypeError(`Suffix must be a string, received "${JSON.stringify(suffix)}"`);
|
|
}
|
|
}
|
|
function assertArg(url) {
|
|
url = url instanceof URL ? url : new URL(url);
|
|
if (url.protocol !== "file:") {
|
|
throw new TypeError(`URL must be a file URL: received "${url.protocol}"`);
|
|
}
|
|
return url;
|
|
}
|
|
function fromFileUrl(url) {
|
|
url = assertArg(url);
|
|
return decodeURIComponent(url.pathname.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"));
|
|
}
|
|
function stripTrailingSeparators(segment, isSep) {
|
|
if (segment.length <= 1) {
|
|
return segment;
|
|
}
|
|
let end = segment.length;
|
|
for(let i = segment.length - 1; i > 0; i--){
|
|
if (isSep(segment.charCodeAt(i))) {
|
|
end = i;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return segment.slice(0, end);
|
|
}
|
|
function isPosixPathSeparator(code) {
|
|
return code === 47;
|
|
}
|
|
function basename(path, suffix = "") {
|
|
if (path instanceof URL) {
|
|
path = fromFileUrl(path);
|
|
}
|
|
assertArgs(path, suffix);
|
|
const lastSegment = lastPathSegment(path, isPosixPathSeparator);
|
|
const strippedSegment = stripTrailingSeparators(lastSegment, isPosixPathSeparator);
|
|
return suffix ? stripSuffix(strippedSegment, suffix) : strippedSegment;
|
|
}
|
|
function isPathSeparator(code) {
|
|
return code === 47 || code === 92;
|
|
}
|
|
function isWindowsDeviceRoot(code) {
|
|
return code >= 97 && code <= 122 || code >= 65 && code <= 90;
|
|
}
|
|
function fromFileUrl1(url) {
|
|
url = assertArg(url);
|
|
let path = decodeURIComponent(url.pathname.replace(/\//g, "\\").replace(/%(?![0-9A-Fa-f]{2})/g, "%25")).replace(/^\\*([A-Za-z]:)(\\|$)/, "$1\\");
|
|
if (url.hostname !== "") {
|
|
path = `\\\\${url.hostname}${path}`;
|
|
}
|
|
return path;
|
|
}
|
|
function basename1(path, suffix = "") {
|
|
if (path instanceof URL) {
|
|
path = fromFileUrl1(path);
|
|
}
|
|
assertArgs(path, suffix);
|
|
let start = 0;
|
|
if (path.length >= 2) {
|
|
const drive = path.charCodeAt(0);
|
|
if (isWindowsDeviceRoot(drive)) {
|
|
if (path.charCodeAt(1) === 58) start = 2;
|
|
}
|
|
}
|
|
const lastSegment = lastPathSegment(path, isPathSeparator, start);
|
|
const strippedSegment = stripTrailingSeparators(lastSegment, isPathSeparator);
|
|
return suffix ? stripSuffix(strippedSegment, suffix) : strippedSegment;
|
|
}
|
|
function basename2(path, suffix = "") {
|
|
return isWindows ? basename1(path, suffix) : basename(path, suffix);
|
|
}
|
|
class InputFile {
|
|
consumed = false;
|
|
fileData;
|
|
filename;
|
|
constructor(file, filename){
|
|
this.fileData = file;
|
|
filename ??= this.guessFilename(file);
|
|
this.filename = filename;
|
|
}
|
|
guessFilename(file) {
|
|
if (typeof file === "string") return basename2(file);
|
|
if (typeof file !== "object") return undefined;
|
|
if ("url" in file) return basename2(file.url);
|
|
if (!(file instanceof URL)) return undefined;
|
|
return basename2(file.pathname) || basename2(file.hostname);
|
|
}
|
|
toRaw() {
|
|
if (this.consumed) {
|
|
throw new Error("Cannot reuse InputFile data source!");
|
|
}
|
|
const data = this.fileData;
|
|
if (data instanceof Blob) return data.stream();
|
|
if (data instanceof URL) return fetchFile(data);
|
|
if ("url" in data) return fetchFile(data.url);
|
|
if (!(data instanceof Uint8Array)) this.consumed = true;
|
|
return data;
|
|
}
|
|
toJSON() {
|
|
throw new Error("InputFile instances must be sent via grammY");
|
|
}
|
|
}
|
|
async function* fetchFile(url) {
|
|
const { body } = await fetch(url);
|
|
if (body === null) {
|
|
throw new Error(`Download failed, no response body from '${url}'`);
|
|
}
|
|
yield* body;
|
|
}
|
|
function requiresFormDataUpload(payload) {
|
|
return payload instanceof InputFile || typeof payload === "object" && payload !== null && Object.values(payload).some((v)=>Array.isArray(v) ? v.some(requiresFormDataUpload) : v instanceof InputFile || requiresFormDataUpload(v));
|
|
}
|
|
function str(value) {
|
|
return JSON.stringify(value, (_, v)=>v ?? undefined);
|
|
}
|
|
function createJsonPayload(payload) {
|
|
return {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
connection: "keep-alive"
|
|
},
|
|
body: str(payload)
|
|
};
|
|
}
|
|
async function* protectItr(itr, onError) {
|
|
try {
|
|
yield* itr;
|
|
} catch (err) {
|
|
onError(err);
|
|
}
|
|
}
|
|
function createFormDataPayload(payload, onError) {
|
|
const boundary = createBoundary();
|
|
const itr = payloadToMultipartItr(payload, boundary);
|
|
const safeItr = protectItr(itr, onError);
|
|
const stream = itrToStream(safeItr);
|
|
return {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": `multipart/form-data; boundary=${boundary}`,
|
|
connection: "keep-alive"
|
|
},
|
|
body: stream
|
|
};
|
|
}
|
|
function createBoundary() {
|
|
return "----------" + randomId(32);
|
|
}
|
|
function randomId(length = 16) {
|
|
return Array.from(Array(length)).map(()=>Math.random().toString(36)[2] || 0).join("");
|
|
}
|
|
const enc = new TextEncoder();
|
|
async function* payloadToMultipartItr(payload, boundary) {
|
|
const files = collectFiles(payload);
|
|
yield enc.encode(`--${boundary}\r\n`);
|
|
const separator = enc.encode(`\r\n--${boundary}\r\n`);
|
|
let first = true;
|
|
for (const [key, value] of Object.entries(payload)){
|
|
if (value == null) continue;
|
|
if (!first) yield separator;
|
|
yield valuePart(key, value instanceof InputFile ? value.toJSON() : typeof value === "object" ? str(value) : value);
|
|
first = false;
|
|
}
|
|
for (const { id, origin, file } of files){
|
|
if (!first) yield separator;
|
|
yield* filePart(id, origin, file);
|
|
first = false;
|
|
}
|
|
yield enc.encode(`\r\n--${boundary}--\r\n`);
|
|
}
|
|
function collectFiles(value) {
|
|
if (typeof value !== "object" || value === null) return [];
|
|
return Object.entries(value).flatMap(([k, v])=>{
|
|
if (Array.isArray(v)) return v.flatMap((p)=>collectFiles(p));
|
|
else if (v instanceof InputFile) {
|
|
const id = randomId();
|
|
Object.assign(v, {
|
|
toJSON: ()=>`attach://${id}`
|
|
});
|
|
const origin = k === "media" && "type" in value && typeof value.type === "string" ? value.type : k;
|
|
return {
|
|
id,
|
|
origin,
|
|
file: v
|
|
};
|
|
} else return collectFiles(v);
|
|
});
|
|
}
|
|
function valuePart(key, value) {
|
|
return enc.encode(`content-disposition:form-data;name="${key}"\r\n\r\n${value}`);
|
|
}
|
|
async function* filePart(id, origin, input) {
|
|
const filename = input.filename || `${origin}.${getExt(origin)}`;
|
|
if (filename.includes("\r") || filename.includes("\n")) {
|
|
throw new Error(`File paths cannot contain carriage-return (\\r) \
|
|
or newline (\\n) characters! Filename for property '${origin}' was:
|
|
"""
|
|
${filename}
|
|
"""`);
|
|
}
|
|
yield enc.encode(`content-disposition:form-data;name="${id}";filename=${filename}\r\ncontent-type:application/octet-stream\r\n\r\n`);
|
|
const data = await input.toRaw();
|
|
if (data instanceof Uint8Array) yield data;
|
|
else yield* data;
|
|
}
|
|
function getExt(key) {
|
|
switch(key){
|
|
case "certificate":
|
|
return "pem";
|
|
case "photo":
|
|
case "thumbnail":
|
|
return "jpg";
|
|
case "voice":
|
|
return "ogg";
|
|
case "audio":
|
|
return "mp3";
|
|
case "animation":
|
|
case "video":
|
|
case "video_note":
|
|
return "mp4";
|
|
case "sticker":
|
|
return "webp";
|
|
default:
|
|
return "dat";
|
|
}
|
|
}
|
|
const debug1 = browser$1("grammy:core");
|
|
function concatTransformer(prev, trans) {
|
|
return (method, payload, signal)=>trans(prev, method, payload, signal);
|
|
}
|
|
class ApiClient {
|
|
token;
|
|
webhookReplyEnvelope;
|
|
options;
|
|
fetch;
|
|
hasUsedWebhookReply;
|
|
installedTransformers;
|
|
constructor(token, options = {}, webhookReplyEnvelope = {}){
|
|
this.token = token;
|
|
this.webhookReplyEnvelope = webhookReplyEnvelope;
|
|
this.hasUsedWebhookReply = false;
|
|
this.installedTransformers = [];
|
|
this.call = async (method, p, signal)=>{
|
|
const payload = p ?? {};
|
|
debug1(`Calling ${method}`);
|
|
if (signal !== undefined) validateSignal(method, payload, signal);
|
|
const opts = this.options;
|
|
const formDataRequired = requiresFormDataUpload(payload);
|
|
if (this.webhookReplyEnvelope.send !== undefined && !this.hasUsedWebhookReply && !formDataRequired && opts.canUseWebhookReply(method)) {
|
|
this.hasUsedWebhookReply = true;
|
|
const config = createJsonPayload({
|
|
...payload,
|
|
method
|
|
});
|
|
await this.webhookReplyEnvelope.send(config.body);
|
|
return {
|
|
ok: true,
|
|
result: true
|
|
};
|
|
}
|
|
const controller = createAbortControllerFromSignal(signal);
|
|
const timeout = createTimeout(controller, opts.timeoutSeconds, method);
|
|
const streamErr = createStreamError(controller);
|
|
const url = opts.buildUrl(opts.apiRoot, this.token, method, opts.environment);
|
|
const config = formDataRequired ? createFormDataPayload(payload, (err)=>streamErr.catch(err)) : createJsonPayload(payload);
|
|
const sig = controller.signal;
|
|
const options = {
|
|
...opts.baseFetchConfig,
|
|
signal: sig,
|
|
...config
|
|
};
|
|
const successPromise = this.fetch(url instanceof URL ? url.href : url, options).catch(toHttpError(method, opts.sensitiveLogs));
|
|
const operations = [
|
|
successPromise,
|
|
streamErr.promise,
|
|
timeout.promise
|
|
];
|
|
try {
|
|
const res = await Promise.race(operations);
|
|
return await res.json();
|
|
} finally{
|
|
if (timeout.handle !== undefined) clearTimeout(timeout.handle);
|
|
}
|
|
};
|
|
const apiRoot = options.apiRoot ?? "https://api.telegram.org";
|
|
const environment = options.environment ?? "prod";
|
|
const { fetch: customFetch } = options;
|
|
const fetchFn = customFetch ?? fetch;
|
|
this.options = {
|
|
apiRoot,
|
|
environment,
|
|
buildUrl: options.buildUrl ?? defaultBuildUrl,
|
|
timeoutSeconds: options.timeoutSeconds ?? 500,
|
|
baseFetchConfig: {
|
|
...baseFetchConfig(apiRoot),
|
|
...options.baseFetchConfig
|
|
},
|
|
canUseWebhookReply: options.canUseWebhookReply ?? (()=>false),
|
|
sensitiveLogs: options.sensitiveLogs ?? false,
|
|
fetch: (...args)=>fetchFn(...args)
|
|
};
|
|
this.fetch = this.options.fetch;
|
|
if (this.options.apiRoot.endsWith("/")) {
|
|
throw new Error(`Remove the trailing '/' from the 'apiRoot' option (use '${this.options.apiRoot.substring(0, this.options.apiRoot.length - 1)}' instead of '${this.options.apiRoot}')`);
|
|
}
|
|
}
|
|
call;
|
|
use(...transformers) {
|
|
this.call = transformers.reduce(concatTransformer, this.call);
|
|
this.installedTransformers.push(...transformers);
|
|
return this;
|
|
}
|
|
async callApi(method, payload, signal) {
|
|
const data = await this.call(method, payload, signal);
|
|
if (data.ok) return data.result;
|
|
else throw toGrammyError(data, method, payload);
|
|
}
|
|
}
|
|
function createRawApi(token, options, webhookReplyEnvelope) {
|
|
const client = new ApiClient(token, options, webhookReplyEnvelope);
|
|
const proxyHandler = {
|
|
get (_, m) {
|
|
return m === "toJSON" ? "__internal" : m === "getMe" || m === "getWebhookInfo" || m === "getForumTopicIconStickers" || m === "getAvailableGifts" || m === "logOut" || m === "close" || m === "getMyStarBalance" || m === "removeMyProfilePhoto" ? client.callApi.bind(client, m, {}) : client.callApi.bind(client, m);
|
|
},
|
|
...proxyMethods
|
|
};
|
|
const raw = new Proxy({}, proxyHandler);
|
|
const installedTransformers = client.installedTransformers;
|
|
const api = {
|
|
raw,
|
|
installedTransformers,
|
|
use: (...t)=>{
|
|
client.use(...t);
|
|
return api;
|
|
}
|
|
};
|
|
return api;
|
|
}
|
|
const defaultBuildUrl = (root, token, method, env)=>{
|
|
const prefix = env === "test" ? "test/" : "";
|
|
return `${root}/bot${token}/${prefix}${method}`;
|
|
};
|
|
const proxyMethods = {
|
|
set () {
|
|
return false;
|
|
},
|
|
defineProperty () {
|
|
return false;
|
|
},
|
|
deleteProperty () {
|
|
return false;
|
|
},
|
|
ownKeys () {
|
|
return [];
|
|
}
|
|
};
|
|
function createTimeout(controller, seconds, method) {
|
|
let handle = undefined;
|
|
const promise = new Promise((_, reject)=>{
|
|
handle = setTimeout(()=>{
|
|
const msg = `Request to '${method}' timed out after ${seconds} seconds`;
|
|
reject(new Error(msg));
|
|
controller.abort();
|
|
}, 1000 * seconds);
|
|
});
|
|
return {
|
|
promise,
|
|
handle
|
|
};
|
|
}
|
|
function createStreamError(abortController) {
|
|
let onError = (err)=>{
|
|
throw err;
|
|
};
|
|
const promise = new Promise((_, reject)=>{
|
|
onError = (err)=>{
|
|
reject(err);
|
|
abortController.abort();
|
|
};
|
|
});
|
|
return {
|
|
promise,
|
|
catch: onError
|
|
};
|
|
}
|
|
function createAbortControllerFromSignal(signal) {
|
|
const abortController = new AbortController();
|
|
if (signal === undefined) return abortController;
|
|
const sig = signal;
|
|
function abort() {
|
|
abortController.abort();
|
|
sig.removeEventListener("abort", abort);
|
|
}
|
|
if (sig.aborted) abort();
|
|
else sig.addEventListener("abort", abort);
|
|
return {
|
|
abort,
|
|
signal: abortController.signal
|
|
};
|
|
}
|
|
function validateSignal(method, payload, signal) {
|
|
if (typeof signal?.addEventListener === "function") {
|
|
return;
|
|
}
|
|
let payload0 = JSON.stringify(payload);
|
|
if (payload0.length > 20) {
|
|
payload0 = payload0.substring(0, 16) + " ...";
|
|
}
|
|
let payload1 = JSON.stringify(signal);
|
|
if (payload1.length > 20) {
|
|
payload1 = payload1.substring(0, 16) + " ...";
|
|
}
|
|
throw new Error(`Incorrect abort signal instance found! \
|
|
You passed two payloads to '${method}' but you should merge \
|
|
the second one containing '${payload1}' into the first one \
|
|
containing '${payload0}'! If you are using context shortcuts, \
|
|
you may want to use a method on 'ctx.api' instead.
|
|
|
|
If you want to prevent such mistakes in the future, \
|
|
consider using TypeScript. https://www.typescriptlang.org/`);
|
|
}
|
|
class Api {
|
|
token;
|
|
options;
|
|
raw;
|
|
config;
|
|
constructor(token, options, webhookReplyEnvelope){
|
|
this.token = token;
|
|
this.options = options;
|
|
const { raw, use, installedTransformers } = createRawApi(token, options, webhookReplyEnvelope);
|
|
this.raw = raw;
|
|
this.config = {
|
|
use,
|
|
installedTransformers: ()=>installedTransformers.slice()
|
|
};
|
|
}
|
|
getUpdates(other, signal) {
|
|
return this.raw.getUpdates({
|
|
...other
|
|
}, signal);
|
|
}
|
|
setWebhook(url, other, signal) {
|
|
return this.raw.setWebhook({
|
|
url,
|
|
...other
|
|
}, signal);
|
|
}
|
|
deleteWebhook(other, signal) {
|
|
return this.raw.deleteWebhook({
|
|
...other
|
|
}, signal);
|
|
}
|
|
getWebhookInfo(signal) {
|
|
return this.raw.getWebhookInfo(signal);
|
|
}
|
|
getMe(signal) {
|
|
return this.raw.getMe(signal);
|
|
}
|
|
logOut(signal) {
|
|
return this.raw.logOut(signal);
|
|
}
|
|
close(signal) {
|
|
return this.raw.close(signal);
|
|
}
|
|
sendMessage(chat_id, text, other, signal) {
|
|
return this.raw.sendMessage({
|
|
chat_id,
|
|
text,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendMessageDraft(chat_id, draft_id, text, other, signal) {
|
|
return this.raw.sendMessageDraft({
|
|
chat_id,
|
|
draft_id,
|
|
text,
|
|
...other
|
|
}, signal);
|
|
}
|
|
forwardMessage(chat_id, from_chat_id, message_id, other, signal) {
|
|
return this.raw.forwardMessage({
|
|
chat_id,
|
|
from_chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
forwardMessages(chat_id, from_chat_id, message_ids, other, signal) {
|
|
return this.raw.forwardMessages({
|
|
chat_id,
|
|
from_chat_id,
|
|
message_ids,
|
|
...other
|
|
}, signal);
|
|
}
|
|
copyMessage(chat_id, from_chat_id, message_id, other, signal) {
|
|
return this.raw.copyMessage({
|
|
chat_id,
|
|
from_chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
copyMessages(chat_id, from_chat_id, message_ids, other, signal) {
|
|
return this.raw.copyMessages({
|
|
chat_id,
|
|
from_chat_id,
|
|
message_ids,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendPhoto(chat_id, photo, other, signal) {
|
|
return this.raw.sendPhoto({
|
|
chat_id,
|
|
photo,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendAudio(chat_id, audio, other, signal) {
|
|
return this.raw.sendAudio({
|
|
chat_id,
|
|
audio,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendDocument(chat_id, document1, other, signal) {
|
|
return this.raw.sendDocument({
|
|
chat_id,
|
|
document: document1,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendVideo(chat_id, video, other, signal) {
|
|
return this.raw.sendVideo({
|
|
chat_id,
|
|
video,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendAnimation(chat_id, animation, other, signal) {
|
|
return this.raw.sendAnimation({
|
|
chat_id,
|
|
animation,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendVoice(chat_id, voice, other, signal) {
|
|
return this.raw.sendVoice({
|
|
chat_id,
|
|
voice,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendVideoNote(chat_id, video_note, other, signal) {
|
|
return this.raw.sendVideoNote({
|
|
chat_id,
|
|
video_note,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendMediaGroup(chat_id, media, other, signal) {
|
|
return this.raw.sendMediaGroup({
|
|
chat_id,
|
|
media,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendLocation(chat_id, latitude, longitude, other, signal) {
|
|
return this.raw.sendLocation({
|
|
chat_id,
|
|
latitude,
|
|
longitude,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageLiveLocation(chat_id, message_id, latitude, longitude, other, signal) {
|
|
return this.raw.editMessageLiveLocation({
|
|
chat_id,
|
|
message_id,
|
|
latitude,
|
|
longitude,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageLiveLocationInline(inline_message_id, latitude, longitude, other, signal) {
|
|
return this.raw.editMessageLiveLocation({
|
|
inline_message_id,
|
|
latitude,
|
|
longitude,
|
|
...other
|
|
}, signal);
|
|
}
|
|
stopMessageLiveLocation(chat_id, message_id, other, signal) {
|
|
return this.raw.stopMessageLiveLocation({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
stopMessageLiveLocationInline(inline_message_id, other, signal) {
|
|
return this.raw.stopMessageLiveLocation({
|
|
inline_message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendPaidMedia(chat_id, star_count, media, other, signal) {
|
|
return this.raw.sendPaidMedia({
|
|
chat_id,
|
|
star_count,
|
|
media,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendVenue(chat_id, latitude, longitude, title, address, other, signal) {
|
|
return this.raw.sendVenue({
|
|
chat_id,
|
|
latitude,
|
|
longitude,
|
|
title,
|
|
address,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendContact(chat_id, phone_number, first_name, other, signal) {
|
|
return this.raw.sendContact({
|
|
chat_id,
|
|
phone_number,
|
|
first_name,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendPoll(chat_id, question, options, other, signal) {
|
|
const opts = options.map((o)=>typeof o === "string" ? {
|
|
text: o
|
|
} : o);
|
|
return this.raw.sendPoll({
|
|
chat_id,
|
|
question,
|
|
options: opts,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendChecklist(business_connection_id, chat_id, checklist, other, signal) {
|
|
return this.raw.sendChecklist({
|
|
business_connection_id,
|
|
chat_id,
|
|
checklist,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageChecklist(business_connection_id, chat_id, message_id, checklist, other, signal) {
|
|
return this.raw.editMessageChecklist({
|
|
business_connection_id,
|
|
chat_id,
|
|
message_id,
|
|
checklist,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendDice(chat_id, emoji, other, signal) {
|
|
return this.raw.sendDice({
|
|
chat_id,
|
|
emoji,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setMessageReaction(chat_id, message_id, reaction, other, signal) {
|
|
return this.raw.setMessageReaction({
|
|
chat_id,
|
|
message_id,
|
|
reaction,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendChatAction(chat_id, action, other, signal) {
|
|
return this.raw.sendChatAction({
|
|
chat_id,
|
|
action,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getUserProfilePhotos(user_id, other, signal) {
|
|
return this.raw.getUserProfilePhotos({
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getUserProfileAudios(user_id, other, signal) {
|
|
return this.raw.getUserProfileAudios({
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setUserEmojiStatus(user_id, other, signal) {
|
|
return this.raw.setUserEmojiStatus({
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getUserChatBoosts(chat_id, user_id, signal) {
|
|
return this.raw.getUserChatBoosts({
|
|
chat_id,
|
|
user_id
|
|
}, signal);
|
|
}
|
|
getUserGifts(user_id, other, signal) {
|
|
return this.raw.getUserGifts({
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getChatGifts(chat_id, other, signal) {
|
|
return this.raw.getChatGifts({
|
|
chat_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getBusinessConnection(business_connection_id, signal) {
|
|
return this.raw.getBusinessConnection({
|
|
business_connection_id
|
|
}, signal);
|
|
}
|
|
getFile(file_id, signal) {
|
|
return this.raw.getFile({
|
|
file_id
|
|
}, signal);
|
|
}
|
|
kickChatMember(...args) {
|
|
return this.banChatMember(...args);
|
|
}
|
|
banChatMember(chat_id, user_id, other, signal) {
|
|
return this.raw.banChatMember({
|
|
chat_id,
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
unbanChatMember(chat_id, user_id, other, signal) {
|
|
return this.raw.unbanChatMember({
|
|
chat_id,
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
restrictChatMember(chat_id, user_id, permissions, other, signal) {
|
|
return this.raw.restrictChatMember({
|
|
chat_id,
|
|
user_id,
|
|
permissions,
|
|
...other
|
|
}, signal);
|
|
}
|
|
promoteChatMember(chat_id, user_id, other, signal) {
|
|
return this.raw.promoteChatMember({
|
|
chat_id,
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setChatAdministratorCustomTitle(chat_id, user_id, custom_title, signal) {
|
|
return this.raw.setChatAdministratorCustomTitle({
|
|
chat_id,
|
|
user_id,
|
|
custom_title
|
|
}, signal);
|
|
}
|
|
banChatSenderChat(chat_id, sender_chat_id, signal) {
|
|
return this.raw.banChatSenderChat({
|
|
chat_id,
|
|
sender_chat_id
|
|
}, signal);
|
|
}
|
|
unbanChatSenderChat(chat_id, sender_chat_id, signal) {
|
|
return this.raw.unbanChatSenderChat({
|
|
chat_id,
|
|
sender_chat_id
|
|
}, signal);
|
|
}
|
|
setChatPermissions(chat_id, permissions, other, signal) {
|
|
return this.raw.setChatPermissions({
|
|
chat_id,
|
|
permissions,
|
|
...other
|
|
}, signal);
|
|
}
|
|
exportChatInviteLink(chat_id, signal) {
|
|
return this.raw.exportChatInviteLink({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
createChatInviteLink(chat_id, other, signal) {
|
|
return this.raw.createChatInviteLink({
|
|
chat_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editChatInviteLink(chat_id, invite_link, other, signal) {
|
|
return this.raw.editChatInviteLink({
|
|
chat_id,
|
|
invite_link,
|
|
...other
|
|
}, signal);
|
|
}
|
|
createChatSubscriptionInviteLink(chat_id, subscription_period, subscription_price, other, signal) {
|
|
return this.raw.createChatSubscriptionInviteLink({
|
|
chat_id,
|
|
subscription_period,
|
|
subscription_price,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editChatSubscriptionInviteLink(chat_id, invite_link, other, signal) {
|
|
return this.raw.editChatSubscriptionInviteLink({
|
|
chat_id,
|
|
invite_link,
|
|
...other
|
|
}, signal);
|
|
}
|
|
revokeChatInviteLink(chat_id, invite_link, signal) {
|
|
return this.raw.revokeChatInviteLink({
|
|
chat_id,
|
|
invite_link
|
|
}, signal);
|
|
}
|
|
approveChatJoinRequest(chat_id, user_id, signal) {
|
|
return this.raw.approveChatJoinRequest({
|
|
chat_id,
|
|
user_id
|
|
}, signal);
|
|
}
|
|
declineChatJoinRequest(chat_id, user_id, signal) {
|
|
return this.raw.declineChatJoinRequest({
|
|
chat_id,
|
|
user_id
|
|
}, signal);
|
|
}
|
|
approveSuggestedPost(chat_id, message_id, other, signal) {
|
|
return this.raw.approveSuggestedPost({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
declineSuggestedPost(chat_id, message_id, other, signal) {
|
|
return this.raw.declineSuggestedPost({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setChatPhoto(chat_id, photo, signal) {
|
|
return this.raw.setChatPhoto({
|
|
chat_id,
|
|
photo
|
|
}, signal);
|
|
}
|
|
deleteChatPhoto(chat_id, signal) {
|
|
return this.raw.deleteChatPhoto({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
setChatTitle(chat_id, title, signal) {
|
|
return this.raw.setChatTitle({
|
|
chat_id,
|
|
title
|
|
}, signal);
|
|
}
|
|
setChatDescription(chat_id, description, signal) {
|
|
return this.raw.setChatDescription({
|
|
chat_id,
|
|
description
|
|
}, signal);
|
|
}
|
|
pinChatMessage(chat_id, message_id, other, signal) {
|
|
return this.raw.pinChatMessage({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
unpinChatMessage(chat_id, message_id, other, signal) {
|
|
return this.raw.unpinChatMessage({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
unpinAllChatMessages(chat_id, signal) {
|
|
return this.raw.unpinAllChatMessages({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
leaveChat(chat_id, signal) {
|
|
return this.raw.leaveChat({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
getChat(chat_id, signal) {
|
|
return this.raw.getChat({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
getChatAdministrators(chat_id, signal) {
|
|
return this.raw.getChatAdministrators({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
getChatMembersCount(...args) {
|
|
return this.getChatMemberCount(...args);
|
|
}
|
|
getChatMemberCount(chat_id, signal) {
|
|
return this.raw.getChatMemberCount({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
getChatMember(chat_id, user_id, signal) {
|
|
return this.raw.getChatMember({
|
|
chat_id,
|
|
user_id
|
|
}, signal);
|
|
}
|
|
setChatStickerSet(chat_id, sticker_set_name, signal) {
|
|
return this.raw.setChatStickerSet({
|
|
chat_id,
|
|
sticker_set_name
|
|
}, signal);
|
|
}
|
|
deleteChatStickerSet(chat_id, signal) {
|
|
return this.raw.deleteChatStickerSet({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
getForumTopicIconStickers(signal) {
|
|
return this.raw.getForumTopicIconStickers(signal);
|
|
}
|
|
createForumTopic(chat_id, name, other, signal) {
|
|
return this.raw.createForumTopic({
|
|
chat_id,
|
|
name,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editForumTopic(chat_id, message_thread_id, other, signal) {
|
|
return this.raw.editForumTopic({
|
|
chat_id,
|
|
message_thread_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
closeForumTopic(chat_id, message_thread_id, signal) {
|
|
return this.raw.closeForumTopic({
|
|
chat_id,
|
|
message_thread_id
|
|
}, signal);
|
|
}
|
|
reopenForumTopic(chat_id, message_thread_id, signal) {
|
|
return this.raw.reopenForumTopic({
|
|
chat_id,
|
|
message_thread_id
|
|
}, signal);
|
|
}
|
|
deleteForumTopic(chat_id, message_thread_id, signal) {
|
|
return this.raw.deleteForumTopic({
|
|
chat_id,
|
|
message_thread_id
|
|
}, signal);
|
|
}
|
|
unpinAllForumTopicMessages(chat_id, message_thread_id, signal) {
|
|
return this.raw.unpinAllForumTopicMessages({
|
|
chat_id,
|
|
message_thread_id
|
|
}, signal);
|
|
}
|
|
editGeneralForumTopic(chat_id, name, signal) {
|
|
return this.raw.editGeneralForumTopic({
|
|
chat_id,
|
|
name
|
|
}, signal);
|
|
}
|
|
closeGeneralForumTopic(chat_id, signal) {
|
|
return this.raw.closeGeneralForumTopic({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
reopenGeneralForumTopic(chat_id, signal) {
|
|
return this.raw.reopenGeneralForumTopic({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
hideGeneralForumTopic(chat_id, signal) {
|
|
return this.raw.hideGeneralForumTopic({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
unhideGeneralForumTopic(chat_id, signal) {
|
|
return this.raw.unhideGeneralForumTopic({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
unpinAllGeneralForumTopicMessages(chat_id, signal) {
|
|
return this.raw.unpinAllGeneralForumTopicMessages({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
answerCallbackQuery(callback_query_id, other, signal) {
|
|
return this.raw.answerCallbackQuery({
|
|
callback_query_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setMyName(name, other, signal) {
|
|
return this.raw.setMyName({
|
|
name,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getMyName(other, signal) {
|
|
return this.raw.getMyName(other ?? {}, signal);
|
|
}
|
|
setMyCommands(commands, other, signal) {
|
|
return this.raw.setMyCommands({
|
|
commands,
|
|
...other
|
|
}, signal);
|
|
}
|
|
deleteMyCommands(other, signal) {
|
|
return this.raw.deleteMyCommands({
|
|
...other
|
|
}, signal);
|
|
}
|
|
getMyCommands(other, signal) {
|
|
return this.raw.getMyCommands({
|
|
...other
|
|
}, signal);
|
|
}
|
|
setMyDescription(description, other, signal) {
|
|
return this.raw.setMyDescription({
|
|
description,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getMyDescription(other, signal) {
|
|
return this.raw.getMyDescription({
|
|
...other
|
|
}, signal);
|
|
}
|
|
setMyShortDescription(short_description, other, signal) {
|
|
return this.raw.setMyShortDescription({
|
|
short_description,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getMyShortDescription(other, signal) {
|
|
return this.raw.getMyShortDescription({
|
|
...other
|
|
}, signal);
|
|
}
|
|
setMyProfilePhoto(photo, signal) {
|
|
return this.raw.setMyProfilePhoto({
|
|
photo
|
|
}, signal);
|
|
}
|
|
removeMyProfilePhoto(signal) {
|
|
return this.raw.removeMyProfilePhoto(signal);
|
|
}
|
|
setChatMenuButton(other, signal) {
|
|
return this.raw.setChatMenuButton({
|
|
...other
|
|
}, signal);
|
|
}
|
|
getChatMenuButton(other, signal) {
|
|
return this.raw.getChatMenuButton({
|
|
...other
|
|
}, signal);
|
|
}
|
|
setMyDefaultAdministratorRights(other, signal) {
|
|
return this.raw.setMyDefaultAdministratorRights({
|
|
...other
|
|
}, signal);
|
|
}
|
|
getMyDefaultAdministratorRights(other, signal) {
|
|
return this.raw.getMyDefaultAdministratorRights({
|
|
...other
|
|
}, signal);
|
|
}
|
|
getMyStarBalance(signal) {
|
|
return this.raw.getMyStarBalance(signal);
|
|
}
|
|
editMessageText(chat_id, message_id, text, other, signal) {
|
|
return this.raw.editMessageText({
|
|
chat_id,
|
|
message_id,
|
|
text,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageTextInline(inline_message_id, text, other, signal) {
|
|
return this.raw.editMessageText({
|
|
inline_message_id,
|
|
text,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageCaption(chat_id, message_id, other, signal) {
|
|
return this.raw.editMessageCaption({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageCaptionInline(inline_message_id, other, signal) {
|
|
return this.raw.editMessageCaption({
|
|
inline_message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageMedia(chat_id, message_id, media, other, signal) {
|
|
return this.raw.editMessageMedia({
|
|
chat_id,
|
|
message_id,
|
|
media,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageMediaInline(inline_message_id, media, other, signal) {
|
|
return this.raw.editMessageMedia({
|
|
inline_message_id,
|
|
media,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageReplyMarkup(chat_id, message_id, other, signal) {
|
|
return this.raw.editMessageReplyMarkup({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editMessageReplyMarkupInline(inline_message_id, other, signal) {
|
|
return this.raw.editMessageReplyMarkup({
|
|
inline_message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
stopPoll(chat_id, message_id, other, signal) {
|
|
return this.raw.stopPoll({
|
|
chat_id,
|
|
message_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
deleteMessage(chat_id, message_id, signal) {
|
|
return this.raw.deleteMessage({
|
|
chat_id,
|
|
message_id
|
|
}, signal);
|
|
}
|
|
deleteMessages(chat_id, message_ids, signal) {
|
|
return this.raw.deleteMessages({
|
|
chat_id,
|
|
message_ids
|
|
}, signal);
|
|
}
|
|
deleteBusinessMessages(business_connection_id, message_ids, signal) {
|
|
return this.raw.deleteBusinessMessages({
|
|
business_connection_id,
|
|
message_ids
|
|
}, signal);
|
|
}
|
|
setBusinessAccountName(business_connection_id, first_name, other, signal) {
|
|
return this.raw.setBusinessAccountName({
|
|
business_connection_id,
|
|
first_name,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setBusinessAccountUsername(business_connection_id, username, signal) {
|
|
return this.raw.setBusinessAccountUsername({
|
|
business_connection_id,
|
|
username
|
|
}, signal);
|
|
}
|
|
setBusinessAccountBio(business_connection_id, bio, signal) {
|
|
return this.raw.setBusinessAccountBio({
|
|
business_connection_id,
|
|
bio
|
|
}, signal);
|
|
}
|
|
setBusinessAccountProfilePhoto(business_connection_id, photo, other, signal) {
|
|
return this.raw.setBusinessAccountProfilePhoto({
|
|
business_connection_id,
|
|
photo,
|
|
...other
|
|
}, signal);
|
|
}
|
|
removeBusinessAccountProfilePhoto(business_connection_id, other, signal) {
|
|
return this.raw.removeBusinessAccountProfilePhoto({
|
|
business_connection_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setBusinessAccountGiftSettings(business_connection_id, show_gift_button, accepted_gift_types, signal) {
|
|
return this.raw.setBusinessAccountGiftSettings({
|
|
business_connection_id,
|
|
show_gift_button,
|
|
accepted_gift_types
|
|
}, signal);
|
|
}
|
|
getBusinessAccountStarBalance(business_connection_id, signal) {
|
|
return this.raw.getBusinessAccountStarBalance({
|
|
business_connection_id
|
|
}, signal);
|
|
}
|
|
transferBusinessAccountStars(business_connection_id, star_count, signal) {
|
|
return this.raw.transferBusinessAccountStars({
|
|
business_connection_id,
|
|
star_count
|
|
}, signal);
|
|
}
|
|
getBusinessAccountGifts(business_connection_id, other, signal) {
|
|
return this.raw.getBusinessAccountGifts({
|
|
business_connection_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
convertGiftToStars(business_connection_id, owned_gift_id, signal) {
|
|
return this.raw.convertGiftToStars({
|
|
business_connection_id,
|
|
owned_gift_id
|
|
}, signal);
|
|
}
|
|
upgradeGift(business_connection_id, owned_gift_id, other, signal) {
|
|
return this.raw.upgradeGift({
|
|
business_connection_id,
|
|
owned_gift_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
transferGift(business_connection_id, owned_gift_id, new_owner_chat_id, star_count, signal) {
|
|
return this.raw.transferGift({
|
|
business_connection_id,
|
|
owned_gift_id,
|
|
new_owner_chat_id,
|
|
star_count
|
|
}, signal);
|
|
}
|
|
postStory(business_connection_id, content, active_period, other, signal) {
|
|
return this.raw.postStory({
|
|
business_connection_id,
|
|
content,
|
|
active_period,
|
|
...other
|
|
}, signal);
|
|
}
|
|
repostStory(business_connection_id, from_chat_id, from_story_id, active_period, other, signal) {
|
|
return this.raw.repostStory({
|
|
business_connection_id,
|
|
from_chat_id,
|
|
from_story_id,
|
|
active_period,
|
|
...other
|
|
}, signal);
|
|
}
|
|
editStory(business_connection_id, story_id, content, other, signal) {
|
|
return this.raw.editStory({
|
|
business_connection_id,
|
|
story_id,
|
|
content,
|
|
...other
|
|
}, signal);
|
|
}
|
|
deleteStory(business_connection_id, story_id, signal) {
|
|
return this.raw.deleteStory({
|
|
business_connection_id,
|
|
story_id
|
|
}, signal);
|
|
}
|
|
sendSticker(chat_id, sticker, other, signal) {
|
|
return this.raw.sendSticker({
|
|
chat_id,
|
|
sticker,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getStickerSet(name, signal) {
|
|
return this.raw.getStickerSet({
|
|
name
|
|
}, signal);
|
|
}
|
|
getCustomEmojiStickers(custom_emoji_ids, signal) {
|
|
return this.raw.getCustomEmojiStickers({
|
|
custom_emoji_ids
|
|
}, signal);
|
|
}
|
|
uploadStickerFile(user_id, sticker_format, sticker, signal) {
|
|
return this.raw.uploadStickerFile({
|
|
user_id,
|
|
sticker_format,
|
|
sticker
|
|
}, signal);
|
|
}
|
|
createNewStickerSet(user_id, name, title, stickers, other, signal) {
|
|
return this.raw.createNewStickerSet({
|
|
user_id,
|
|
name,
|
|
title,
|
|
stickers,
|
|
...other
|
|
}, signal);
|
|
}
|
|
addStickerToSet(user_id, name, sticker, signal) {
|
|
return this.raw.addStickerToSet({
|
|
user_id,
|
|
name,
|
|
sticker
|
|
}, signal);
|
|
}
|
|
setStickerPositionInSet(sticker, position, signal) {
|
|
return this.raw.setStickerPositionInSet({
|
|
sticker,
|
|
position
|
|
}, signal);
|
|
}
|
|
deleteStickerFromSet(sticker, signal) {
|
|
return this.raw.deleteStickerFromSet({
|
|
sticker
|
|
}, signal);
|
|
}
|
|
replaceStickerInSet(user_id, name, old_sticker, sticker, signal) {
|
|
return this.raw.replaceStickerInSet({
|
|
user_id,
|
|
name,
|
|
old_sticker,
|
|
sticker
|
|
}, signal);
|
|
}
|
|
setStickerEmojiList(sticker, emoji_list, signal) {
|
|
return this.raw.setStickerEmojiList({
|
|
sticker,
|
|
emoji_list
|
|
}, signal);
|
|
}
|
|
setStickerKeywords(sticker, keywords, signal) {
|
|
return this.raw.setStickerKeywords({
|
|
sticker,
|
|
keywords
|
|
}, signal);
|
|
}
|
|
setStickerMaskPosition(sticker, mask_position, signal) {
|
|
return this.raw.setStickerMaskPosition({
|
|
sticker,
|
|
mask_position
|
|
}, signal);
|
|
}
|
|
setStickerSetTitle(name, title, signal) {
|
|
return this.raw.setStickerSetTitle({
|
|
name,
|
|
title
|
|
}, signal);
|
|
}
|
|
deleteStickerSet(name, signal) {
|
|
return this.raw.deleteStickerSet({
|
|
name
|
|
}, signal);
|
|
}
|
|
setStickerSetThumbnail(name, user_id, thumbnail, format, signal) {
|
|
return this.raw.setStickerSetThumbnail({
|
|
name,
|
|
user_id,
|
|
thumbnail,
|
|
format
|
|
}, signal);
|
|
}
|
|
setCustomEmojiStickerSetThumbnail(name, custom_emoji_id, signal) {
|
|
return this.raw.setCustomEmojiStickerSetThumbnail({
|
|
name,
|
|
custom_emoji_id
|
|
}, signal);
|
|
}
|
|
getAvailableGifts(signal) {
|
|
return this.raw.getAvailableGifts(signal);
|
|
}
|
|
sendGift(user_id, gift_id, other, signal) {
|
|
return this.raw.sendGift({
|
|
user_id,
|
|
gift_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
giftPremiumSubscription(user_id, month_count, star_count, other, signal) {
|
|
return this.raw.giftPremiumSubscription({
|
|
user_id,
|
|
month_count,
|
|
star_count,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendGiftToChannel(chat_id, gift_id, other, signal) {
|
|
return this.raw.sendGift({
|
|
chat_id,
|
|
gift_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
answerInlineQuery(inline_query_id, results, other, signal) {
|
|
return this.raw.answerInlineQuery({
|
|
inline_query_id,
|
|
results,
|
|
...other
|
|
}, signal);
|
|
}
|
|
answerWebAppQuery(web_app_query_id, result, signal) {
|
|
return this.raw.answerWebAppQuery({
|
|
web_app_query_id,
|
|
result
|
|
}, signal);
|
|
}
|
|
savePreparedInlineMessage(user_id, result, other, signal) {
|
|
return this.raw.savePreparedInlineMessage({
|
|
user_id,
|
|
result,
|
|
...other
|
|
}, signal);
|
|
}
|
|
sendInvoice(chat_id, title, description, payload, currency, prices, other, signal) {
|
|
return this.raw.sendInvoice({
|
|
chat_id,
|
|
title,
|
|
description,
|
|
payload,
|
|
currency,
|
|
prices,
|
|
...other
|
|
}, signal);
|
|
}
|
|
createInvoiceLink(title, description, payload, provider_token, currency, prices, other, signal) {
|
|
return this.raw.createInvoiceLink({
|
|
title,
|
|
description,
|
|
payload,
|
|
provider_token,
|
|
currency,
|
|
prices,
|
|
...other
|
|
}, signal);
|
|
}
|
|
answerShippingQuery(shipping_query_id, ok, other, signal) {
|
|
return this.raw.answerShippingQuery({
|
|
shipping_query_id,
|
|
ok,
|
|
...other
|
|
}, signal);
|
|
}
|
|
answerPreCheckoutQuery(pre_checkout_query_id, ok, other, signal) {
|
|
return this.raw.answerPreCheckoutQuery({
|
|
pre_checkout_query_id,
|
|
ok,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getStarTransactions(other, signal) {
|
|
return this.raw.getStarTransactions({
|
|
...other
|
|
}, signal);
|
|
}
|
|
refundStarPayment(user_id, telegram_payment_charge_id, signal) {
|
|
return this.raw.refundStarPayment({
|
|
user_id,
|
|
telegram_payment_charge_id
|
|
}, signal);
|
|
}
|
|
editUserStarSubscription(user_id, telegram_payment_charge_id, is_canceled, signal) {
|
|
return this.raw.editUserStarSubscription({
|
|
user_id,
|
|
telegram_payment_charge_id,
|
|
is_canceled
|
|
}, signal);
|
|
}
|
|
verifyUser(user_id, other, signal) {
|
|
return this.raw.verifyUser({
|
|
user_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
verifyChat(chat_id, other, signal) {
|
|
return this.raw.verifyChat({
|
|
chat_id,
|
|
...other
|
|
}, signal);
|
|
}
|
|
removeUserVerification(user_id, signal) {
|
|
return this.raw.removeUserVerification({
|
|
user_id
|
|
}, signal);
|
|
}
|
|
removeChatVerification(chat_id, signal) {
|
|
return this.raw.removeChatVerification({
|
|
chat_id
|
|
}, signal);
|
|
}
|
|
readBusinessMessage(business_connection_id, chat_id, message_id, signal) {
|
|
return this.raw.readBusinessMessage({
|
|
business_connection_id,
|
|
chat_id,
|
|
message_id
|
|
}, signal);
|
|
}
|
|
setPassportDataErrors(user_id, errors, signal) {
|
|
return this.raw.setPassportDataErrors({
|
|
user_id,
|
|
errors
|
|
}, signal);
|
|
}
|
|
sendGame(chat_id, game_short_name, other, signal) {
|
|
return this.raw.sendGame({
|
|
chat_id,
|
|
game_short_name,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setGameScore(chat_id, message_id, user_id, score, other, signal) {
|
|
return this.raw.setGameScore({
|
|
chat_id,
|
|
message_id,
|
|
user_id,
|
|
score,
|
|
...other
|
|
}, signal);
|
|
}
|
|
setGameScoreInline(inline_message_id, user_id, score, other, signal) {
|
|
return this.raw.setGameScore({
|
|
inline_message_id,
|
|
user_id,
|
|
score,
|
|
...other
|
|
}, signal);
|
|
}
|
|
getGameHighScores(chat_id, message_id, user_id, signal) {
|
|
return this.raw.getGameHighScores({
|
|
chat_id,
|
|
message_id,
|
|
user_id
|
|
}, signal);
|
|
}
|
|
getGameHighScoresInline(inline_message_id, user_id, signal) {
|
|
return this.raw.getGameHighScores({
|
|
inline_message_id,
|
|
user_id
|
|
}, signal);
|
|
}
|
|
}
|
|
const debug2 = browser$1("grammy:bot");
|
|
const debugWarn = browser$1("grammy:warn");
|
|
const debugErr = browser$1("grammy:error");
|
|
const DEFAULT_UPDATE_TYPES = [
|
|
"message",
|
|
"edited_message",
|
|
"channel_post",
|
|
"edited_channel_post",
|
|
"business_connection",
|
|
"business_message",
|
|
"edited_business_message",
|
|
"deleted_business_messages",
|
|
"inline_query",
|
|
"chosen_inline_result",
|
|
"callback_query",
|
|
"shipping_query",
|
|
"pre_checkout_query",
|
|
"purchased_paid_media",
|
|
"poll",
|
|
"poll_answer",
|
|
"my_chat_member",
|
|
"chat_join_request",
|
|
"chat_boost",
|
|
"removed_chat_boost"
|
|
];
|
|
class Bot extends Composer {
|
|
token;
|
|
pollingRunning;
|
|
pollingAbortController;
|
|
lastTriedUpdateId;
|
|
api;
|
|
me;
|
|
mePromise;
|
|
clientConfig;
|
|
ContextConstructor;
|
|
observedUpdateTypes;
|
|
errorHandler;
|
|
constructor(token, config){
|
|
super();
|
|
this.token = token;
|
|
this.pollingRunning = false;
|
|
this.lastTriedUpdateId = 0;
|
|
this.observedUpdateTypes = new Set();
|
|
this.errorHandler = async (err)=>{
|
|
console.error("Error in middleware while handling update", err.ctx?.update?.update_id, err.error);
|
|
console.error("No error handler was set!");
|
|
console.error("Set your own error handler with `bot.catch = ...`");
|
|
if (this.pollingRunning) {
|
|
console.error("Stopping bot");
|
|
await this.stop();
|
|
}
|
|
throw err;
|
|
};
|
|
if (!token) throw new Error("Empty token!");
|
|
this.me = config?.botInfo;
|
|
this.clientConfig = config?.client;
|
|
this.ContextConstructor = config?.ContextConstructor ?? Context;
|
|
this.api = new Api(token, this.clientConfig);
|
|
}
|
|
set botInfo(botInfo) {
|
|
this.me = botInfo;
|
|
}
|
|
get botInfo() {
|
|
if (this.me === undefined) {
|
|
throw new Error("Bot information unavailable! Make sure to call `await bot.init()` before accessing `bot.botInfo`!");
|
|
}
|
|
return this.me;
|
|
}
|
|
on(filter, ...middleware) {
|
|
for (const [u] of parse(filter).flatMap(preprocess)){
|
|
this.observedUpdateTypes.add(u);
|
|
}
|
|
return super.on(filter, ...middleware);
|
|
}
|
|
reaction(reaction, ...middleware) {
|
|
this.observedUpdateTypes.add("message_reaction");
|
|
return super.reaction(reaction, ...middleware);
|
|
}
|
|
isInited() {
|
|
return this.me !== undefined;
|
|
}
|
|
async init(signal) {
|
|
if (!this.isInited()) {
|
|
debug2("Initializing bot");
|
|
this.mePromise ??= withRetries(()=>this.api.getMe(signal), signal);
|
|
let me;
|
|
try {
|
|
me = await this.mePromise;
|
|
} finally{
|
|
this.mePromise = undefined;
|
|
}
|
|
if (this.me === undefined) this.me = me;
|
|
else debug2("Bot info was set by now, will not overwrite");
|
|
}
|
|
debug2(`I am ${this.me.username}!`);
|
|
}
|
|
async handleUpdates(updates) {
|
|
for (const update of updates){
|
|
this.lastTriedUpdateId = update.update_id;
|
|
try {
|
|
await this.handleUpdate(update);
|
|
} catch (err) {
|
|
if (err instanceof BotError) {
|
|
await this.errorHandler(err);
|
|
} else {
|
|
console.error("FATAL: grammY unable to handle:", err);
|
|
throw err;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
async handleUpdate(update, webhookReplyEnvelope) {
|
|
if (this.me === undefined) {
|
|
throw new Error("Bot not initialized! Either call `await bot.init()`, \
|
|
or directly set the `botInfo` option in the `Bot` constructor to specify \
|
|
a known bot info object.");
|
|
}
|
|
debug2(`Processing update ${update.update_id}`);
|
|
const api = new Api(this.token, this.clientConfig, webhookReplyEnvelope);
|
|
const t = this.api.config.installedTransformers();
|
|
if (t.length > 0) api.config.use(...t);
|
|
const ctx = new this.ContextConstructor(update, api, this.me);
|
|
try {
|
|
await run(this.middleware(), ctx);
|
|
} catch (err) {
|
|
debugErr(`Error in middleware for update ${update.update_id}`);
|
|
throw new BotError(err, ctx);
|
|
}
|
|
}
|
|
async start(options) {
|
|
const setup = [];
|
|
if (!this.isInited()) {
|
|
setup.push(this.init(this.pollingAbortController?.signal));
|
|
}
|
|
if (this.pollingRunning) {
|
|
await Promise.all(setup);
|
|
debug2("Simple long polling already running!");
|
|
return;
|
|
}
|
|
this.pollingRunning = true;
|
|
this.pollingAbortController = new AbortController();
|
|
try {
|
|
setup.push(withRetries(async ()=>{
|
|
await this.api.deleteWebhook({
|
|
drop_pending_updates: options?.drop_pending_updates
|
|
}, this.pollingAbortController?.signal);
|
|
}, this.pollingAbortController?.signal));
|
|
await Promise.all(setup);
|
|
await options?.onStart?.(this.botInfo);
|
|
} catch (err) {
|
|
this.pollingRunning = false;
|
|
this.pollingAbortController = undefined;
|
|
throw err;
|
|
}
|
|
if (!this.pollingRunning) return;
|
|
validateAllowedUpdates(this.observedUpdateTypes, options?.allowed_updates);
|
|
this.use = noUseFunction;
|
|
debug2("Starting simple long polling");
|
|
await this.loop(options);
|
|
debug2("Middleware is done running");
|
|
}
|
|
async stop() {
|
|
if (this.pollingRunning) {
|
|
debug2("Stopping bot, saving update offset");
|
|
this.pollingRunning = false;
|
|
this.pollingAbortController?.abort();
|
|
const offset = this.lastTriedUpdateId + 1;
|
|
await this.api.getUpdates({
|
|
offset,
|
|
limit: 1
|
|
}).finally(()=>this.pollingAbortController = undefined);
|
|
} else {
|
|
debug2("Bot is not running!");
|
|
}
|
|
}
|
|
isRunning() {
|
|
return this.pollingRunning;
|
|
}
|
|
catch(errorHandler) {
|
|
this.errorHandler = errorHandler;
|
|
}
|
|
async loop(options) {
|
|
const limit = options?.limit;
|
|
const timeout = options?.timeout ?? 30;
|
|
let allowed_updates = options?.allowed_updates ?? [];
|
|
try {
|
|
while(this.pollingRunning){
|
|
const updates = await this.fetchUpdates({
|
|
limit,
|
|
timeout,
|
|
allowed_updates
|
|
});
|
|
if (updates === undefined) break;
|
|
await this.handleUpdates(updates);
|
|
allowed_updates = undefined;
|
|
}
|
|
} finally{
|
|
this.pollingRunning = false;
|
|
}
|
|
}
|
|
async fetchUpdates({ limit, timeout, allowed_updates }) {
|
|
const offset = this.lastTriedUpdateId + 1;
|
|
let updates = undefined;
|
|
do {
|
|
try {
|
|
updates = await this.api.getUpdates({
|
|
offset,
|
|
limit,
|
|
timeout,
|
|
allowed_updates
|
|
}, this.pollingAbortController?.signal);
|
|
} catch (error) {
|
|
await this.handlePollingError(error);
|
|
}
|
|
}while (updates === undefined && this.pollingRunning)
|
|
return updates;
|
|
}
|
|
async handlePollingError(error) {
|
|
if (!this.pollingRunning) {
|
|
debug2("Pending getUpdates request cancelled");
|
|
return;
|
|
}
|
|
let sleepSeconds = 3;
|
|
if (error instanceof GrammyError) {
|
|
debugErr(error.message);
|
|
if (error.error_code === 401 || error.error_code === 409) {
|
|
throw error;
|
|
} else if (error.error_code === 429) {
|
|
debugErr("Bot API server is closing.");
|
|
sleepSeconds = error.parameters.retry_after ?? sleepSeconds;
|
|
}
|
|
} else debugErr(error);
|
|
debugErr(`Call to getUpdates failed, retrying in ${sleepSeconds} seconds ...`);
|
|
await sleep(sleepSeconds);
|
|
}
|
|
}
|
|
async function withRetries(task, signal) {
|
|
const INITIAL_DELAY = 50;
|
|
let lastDelay = 50;
|
|
async function handleError(error) {
|
|
let delay = false;
|
|
let strategy = "rethrow";
|
|
if (error instanceof HttpError) {
|
|
delay = true;
|
|
strategy = "retry";
|
|
} else if (error instanceof GrammyError) {
|
|
if (error.error_code >= 500) {
|
|
delay = true;
|
|
strategy = "retry";
|
|
} else if (error.error_code === 429) {
|
|
const retryAfter = error.parameters.retry_after;
|
|
if (typeof retryAfter === "number") {
|
|
await sleep(retryAfter, signal);
|
|
lastDelay = INITIAL_DELAY;
|
|
} else {
|
|
delay = true;
|
|
}
|
|
strategy = "retry";
|
|
}
|
|
}
|
|
if (delay) {
|
|
if (lastDelay !== 50) {
|
|
await sleep(lastDelay, signal);
|
|
}
|
|
const TWENTY_MINUTES = 20 * 60 * 1000;
|
|
lastDelay = Math.min(TWENTY_MINUTES, 2 * lastDelay);
|
|
}
|
|
return strategy;
|
|
}
|
|
let result = {
|
|
ok: false
|
|
};
|
|
while(!result.ok){
|
|
try {
|
|
result = {
|
|
ok: true,
|
|
value: await task()
|
|
};
|
|
} catch (error) {
|
|
debugErr(error);
|
|
const strategy = await handleError(error);
|
|
switch(strategy){
|
|
case "retry":
|
|
continue;
|
|
case "rethrow":
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
return result.value;
|
|
}
|
|
async function sleep(seconds, signal) {
|
|
let handle;
|
|
let reject;
|
|
function abort() {
|
|
reject?.(new Error("Aborted delay"));
|
|
if (handle !== undefined) clearTimeout(handle);
|
|
}
|
|
try {
|
|
await new Promise((res, rej)=>{
|
|
reject = rej;
|
|
if (signal?.aborted) {
|
|
abort();
|
|
return;
|
|
}
|
|
signal?.addEventListener("abort", abort);
|
|
handle = setTimeout(res, 1000 * seconds);
|
|
});
|
|
} finally{
|
|
signal?.removeEventListener("abort", abort);
|
|
}
|
|
}
|
|
function validateAllowedUpdates(updates, allowed = DEFAULT_UPDATE_TYPES) {
|
|
const impossible = Array.from(updates).filter((u)=>!allowed.includes(u));
|
|
if (impossible.length > 0) {
|
|
debugWarn(`You registered listeners for the following update types, \
|
|
but you did not specify them in \`allowed_updates\` \
|
|
so they may not be received: ${impossible.map((u)=>`'${u}'`).join(", ")}`);
|
|
}
|
|
}
|
|
function noUseFunction() {
|
|
throw new Error(`It looks like you are registering more listeners \
|
|
on your bot from within other listeners! This means that every time your bot \
|
|
handles a message like this one, new listeners will be added. This list grows until \
|
|
your machine crashes, so grammY throws this error to tell you that you should \
|
|
probably do things a bit differently. If you're unsure how to resolve this problem, \
|
|
you can ask in the group chat: https://telegram.me/grammyjs
|
|
|
|
On the other hand, if you actually know what you're doing and you do need to install \
|
|
further middleware while your bot is running, consider installing a composer \
|
|
instance on your bot, and in turn augment the composer after the fact. This way, \
|
|
you can circumvent this protection against memory leaks.`);
|
|
}
|
|
const ALL_UPDATE_TYPES = [
|
|
...DEFAULT_UPDATE_TYPES,
|
|
"chat_member",
|
|
"message_reaction",
|
|
"message_reaction_count"
|
|
];
|
|
const ALL_CHAT_PERMISSIONS = {
|
|
is_anonymous: true,
|
|
can_manage_chat: true,
|
|
can_delete_messages: true,
|
|
can_manage_video_chats: true,
|
|
can_restrict_members: true,
|
|
can_promote_members: true,
|
|
can_change_info: true,
|
|
can_invite_users: true,
|
|
can_post_stories: true,
|
|
can_edit_stories: true,
|
|
can_delete_stories: true,
|
|
can_post_messages: true,
|
|
can_edit_messages: true,
|
|
can_pin_messages: true,
|
|
can_manage_topics: true
|
|
};
|
|
const API_CONSTANTS = {
|
|
DEFAULT_UPDATE_TYPES,
|
|
ALL_UPDATE_TYPES,
|
|
ALL_CHAT_PERMISSIONS
|
|
};
|
|
Object.freeze(API_CONSTANTS);
|
|
export { API_CONSTANTS as API_CONSTANTS };
|
|
function inputMessage(queryTemplate) {
|
|
return {
|
|
...queryTemplate,
|
|
...inputMessageMethods(queryTemplate)
|
|
};
|
|
}
|
|
function inputMessageMethods(queryTemplate) {
|
|
return {
|
|
text (message_text, options = {}) {
|
|
const content = {
|
|
message_text,
|
|
...options
|
|
};
|
|
return {
|
|
...queryTemplate,
|
|
input_message_content: content
|
|
};
|
|
},
|
|
location (latitude, longitude, options = {}) {
|
|
const content = {
|
|
latitude,
|
|
longitude,
|
|
...options
|
|
};
|
|
return {
|
|
...queryTemplate,
|
|
input_message_content: content
|
|
};
|
|
},
|
|
venue (title, latitude, longitude, address, options) {
|
|
const content = {
|
|
title,
|
|
latitude,
|
|
longitude,
|
|
address,
|
|
...options
|
|
};
|
|
return {
|
|
...queryTemplate,
|
|
input_message_content: content
|
|
};
|
|
},
|
|
contact (first_name, phone_number, options = {}) {
|
|
const content = {
|
|
first_name,
|
|
phone_number,
|
|
...options
|
|
};
|
|
return {
|
|
...queryTemplate,
|
|
input_message_content: content
|
|
};
|
|
},
|
|
invoice (title, description, payload, provider_token, currency, prices, options = {}) {
|
|
const content = {
|
|
title,
|
|
description,
|
|
payload,
|
|
provider_token,
|
|
currency,
|
|
prices,
|
|
...options
|
|
};
|
|
return {
|
|
...queryTemplate,
|
|
input_message_content: content
|
|
};
|
|
}
|
|
};
|
|
}
|
|
const InlineQueryResultBuilder = {
|
|
article (id, title, options = {}) {
|
|
return inputMessageMethods({
|
|
type: "article",
|
|
id,
|
|
title,
|
|
...options
|
|
});
|
|
},
|
|
audio (id, title, audio_url, options = {}) {
|
|
return inputMessage({
|
|
type: "audio",
|
|
id,
|
|
title,
|
|
audio_url: typeof audio_url === "string" ? audio_url : audio_url.href,
|
|
...options
|
|
});
|
|
},
|
|
audioCached (id, audio_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "audio",
|
|
id,
|
|
audio_file_id,
|
|
...options
|
|
});
|
|
},
|
|
contact (id, phone_number, first_name, options = {}) {
|
|
return inputMessage({
|
|
type: "contact",
|
|
id,
|
|
phone_number,
|
|
first_name,
|
|
...options
|
|
});
|
|
},
|
|
documentPdf (id, title, document_url, options = {}) {
|
|
return inputMessage({
|
|
type: "document",
|
|
mime_type: "application/pdf",
|
|
id,
|
|
title,
|
|
document_url: typeof document_url === "string" ? document_url : document_url.href,
|
|
...options
|
|
});
|
|
},
|
|
documentZip (id, title, document_url, options = {}) {
|
|
return inputMessage({
|
|
type: "document",
|
|
mime_type: "application/zip",
|
|
id,
|
|
title,
|
|
document_url: typeof document_url === "string" ? document_url : document_url.href,
|
|
...options
|
|
});
|
|
},
|
|
documentCached (id, title, document_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "document",
|
|
id,
|
|
title,
|
|
document_file_id,
|
|
...options
|
|
});
|
|
},
|
|
game (id, game_short_name, options = {}) {
|
|
return {
|
|
type: "game",
|
|
id,
|
|
game_short_name,
|
|
...options
|
|
};
|
|
},
|
|
gif (id, gif_url, thumbnail_url, options = {}) {
|
|
return inputMessage({
|
|
type: "gif",
|
|
id,
|
|
gif_url: typeof gif_url === "string" ? gif_url : gif_url.href,
|
|
thumbnail_url: typeof thumbnail_url === "string" ? thumbnail_url : thumbnail_url.href,
|
|
...options
|
|
});
|
|
},
|
|
gifCached (id, gif_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "gif",
|
|
id,
|
|
gif_file_id,
|
|
...options
|
|
});
|
|
},
|
|
location (id, title, latitude, longitude, options = {}) {
|
|
return inputMessage({
|
|
type: "location",
|
|
id,
|
|
title,
|
|
latitude,
|
|
longitude,
|
|
...options
|
|
});
|
|
},
|
|
mpeg4gif (id, mpeg4_url, thumbnail_url, options = {}) {
|
|
return inputMessage({
|
|
type: "mpeg4_gif",
|
|
id,
|
|
mpeg4_url: typeof mpeg4_url === "string" ? mpeg4_url : mpeg4_url.href,
|
|
thumbnail_url: typeof thumbnail_url === "string" ? thumbnail_url : thumbnail_url.href,
|
|
...options
|
|
});
|
|
},
|
|
mpeg4gifCached (id, mpeg4_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "mpeg4_gif",
|
|
id,
|
|
mpeg4_file_id,
|
|
...options
|
|
});
|
|
},
|
|
photo (id, photo_url, options = {
|
|
thumbnail_url: typeof photo_url === "string" ? photo_url : photo_url.href
|
|
}) {
|
|
return inputMessage({
|
|
type: "photo",
|
|
id,
|
|
photo_url: typeof photo_url === "string" ? photo_url : photo_url.href,
|
|
...options
|
|
});
|
|
},
|
|
photoCached (id, photo_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "photo",
|
|
id,
|
|
photo_file_id,
|
|
...options
|
|
});
|
|
},
|
|
stickerCached (id, sticker_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "sticker",
|
|
id,
|
|
sticker_file_id,
|
|
...options
|
|
});
|
|
},
|
|
venue (id, title, latitude, longitude, address, options = {}) {
|
|
return inputMessage({
|
|
type: "venue",
|
|
id,
|
|
title,
|
|
latitude,
|
|
longitude,
|
|
address,
|
|
...options
|
|
});
|
|
},
|
|
videoHtml (id, title, video_url, thumbnail_url, options = {}) {
|
|
return inputMessageMethods({
|
|
type: "video",
|
|
mime_type: "text/html",
|
|
id,
|
|
title,
|
|
video_url: typeof video_url === "string" ? video_url : video_url.href,
|
|
thumbnail_url: typeof thumbnail_url === "string" ? thumbnail_url : thumbnail_url.href,
|
|
...options
|
|
});
|
|
},
|
|
videoMp4 (id, title, video_url, thumbnail_url, options = {}) {
|
|
return inputMessage({
|
|
type: "video",
|
|
mime_type: "video/mp4",
|
|
id,
|
|
title,
|
|
video_url: typeof video_url === "string" ? video_url : video_url.href,
|
|
thumbnail_url: typeof thumbnail_url === "string" ? thumbnail_url : thumbnail_url.href,
|
|
...options
|
|
});
|
|
},
|
|
videoCached (id, title, video_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "video",
|
|
id,
|
|
title,
|
|
video_file_id,
|
|
...options
|
|
});
|
|
},
|
|
voice (id, title, voice_url, options = {}) {
|
|
return inputMessage({
|
|
type: "voice",
|
|
id,
|
|
title,
|
|
voice_url: typeof voice_url === "string" ? voice_url : voice_url.href,
|
|
...options
|
|
});
|
|
},
|
|
voiceCached (id, title, voice_file_id, options = {}) {
|
|
return inputMessage({
|
|
type: "voice",
|
|
id,
|
|
title,
|
|
voice_file_id,
|
|
...options
|
|
});
|
|
}
|
|
};
|
|
export { InlineQueryResultBuilder as InlineQueryResultBuilder };
|
|
const InputMediaBuilder = {
|
|
photo (media, options = {}) {
|
|
return {
|
|
type: "photo",
|
|
media,
|
|
...options
|
|
};
|
|
},
|
|
video (media, options = {}) {
|
|
return {
|
|
type: "video",
|
|
media,
|
|
...options
|
|
};
|
|
},
|
|
animation (media, options = {}) {
|
|
return {
|
|
type: "animation",
|
|
media,
|
|
...options
|
|
};
|
|
},
|
|
audio (media, options = {}) {
|
|
return {
|
|
type: "audio",
|
|
media,
|
|
...options
|
|
};
|
|
},
|
|
document (media, options = {}) {
|
|
return {
|
|
type: "document",
|
|
media,
|
|
...options
|
|
};
|
|
}
|
|
};
|
|
export { InputMediaBuilder as InputMediaBuilder };
|
|
class Keyboard {
|
|
keyboard;
|
|
is_persistent;
|
|
selective;
|
|
one_time_keyboard;
|
|
resize_keyboard;
|
|
input_field_placeholder;
|
|
constructor(keyboard = [
|
|
[]
|
|
]){
|
|
this.keyboard = keyboard;
|
|
}
|
|
add(...buttons) {
|
|
this.keyboard[this.keyboard.length - 1]?.push(...buttons);
|
|
return this;
|
|
}
|
|
row(...buttons) {
|
|
this.keyboard.push(buttons);
|
|
return this;
|
|
}
|
|
text(text, options) {
|
|
return this.add(Keyboard.text(text, options));
|
|
}
|
|
static text(text, options) {
|
|
return typeof options === "string" ? {
|
|
text,
|
|
style: options
|
|
} : {
|
|
text,
|
|
...options
|
|
};
|
|
}
|
|
requestUsers(text, requestId, options = {}) {
|
|
return this.add(Keyboard.requestUsers(text, requestId, options));
|
|
}
|
|
static requestUsers(text, requestId, options = {}) {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
request_users: {
|
|
request_id: requestId,
|
|
...options
|
|
}
|
|
} : {
|
|
...text,
|
|
request_users: {
|
|
request_id: requestId,
|
|
...options
|
|
}
|
|
};
|
|
}
|
|
requestChat(text, requestId, options = {
|
|
chat_is_channel: false
|
|
}) {
|
|
return this.add(Keyboard.requestChat(text, requestId, options));
|
|
}
|
|
static requestChat(text, requestId, options = {
|
|
chat_is_channel: false
|
|
}) {
|
|
const request_chat = {
|
|
request_id: requestId,
|
|
...options
|
|
};
|
|
return typeof text === "string" ? {
|
|
text,
|
|
request_chat
|
|
} : {
|
|
...text,
|
|
request_chat
|
|
};
|
|
}
|
|
requestContact(text) {
|
|
return this.add(Keyboard.requestContact(text));
|
|
}
|
|
static requestContact(text) {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
request_contact: true
|
|
} : {
|
|
...text,
|
|
request_contact: true
|
|
};
|
|
}
|
|
requestLocation(text) {
|
|
return this.add(Keyboard.requestLocation(text));
|
|
}
|
|
static requestLocation(text) {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
request_location: true
|
|
} : {
|
|
...text,
|
|
request_location: true
|
|
};
|
|
}
|
|
requestPoll(text, type) {
|
|
return this.add(Keyboard.requestPoll(text, type));
|
|
}
|
|
static requestPoll(text, type) {
|
|
const request_poll = {
|
|
type
|
|
};
|
|
return typeof text === "string" ? {
|
|
text,
|
|
request_poll
|
|
} : {
|
|
...text,
|
|
request_poll
|
|
};
|
|
}
|
|
webApp(text, url) {
|
|
return this.add(Keyboard.webApp(text, url));
|
|
}
|
|
static webApp(text, url) {
|
|
const web_app = {
|
|
url
|
|
};
|
|
return typeof text === "string" ? {
|
|
text,
|
|
web_app
|
|
} : {
|
|
...text,
|
|
web_app
|
|
};
|
|
}
|
|
style(style) {
|
|
const rows = this.keyboard.length;
|
|
if (rows === 0) {
|
|
throw new Error("Need to add a button before applying a style!");
|
|
}
|
|
const lastRow = this.keyboard[rows - 1];
|
|
const cols = lastRow.length;
|
|
if (cols === 0) {
|
|
throw new Error("Need to add a button before applying a style!");
|
|
}
|
|
let lastButton = lastRow[cols - 1];
|
|
if (typeof lastButton === "string") {
|
|
lastButton = {
|
|
text: lastButton
|
|
};
|
|
lastRow[cols - 1] = lastButton;
|
|
}
|
|
lastButton.style = style;
|
|
return this;
|
|
}
|
|
danger() {
|
|
return this.style("danger");
|
|
}
|
|
success() {
|
|
return this.style("success");
|
|
}
|
|
primary() {
|
|
return this.style("primary");
|
|
}
|
|
icon(icon) {
|
|
const rows = this.keyboard.length;
|
|
if (rows === 0) {
|
|
throw new Error("Need to add a button before adding an icon!");
|
|
}
|
|
const lastRow = this.keyboard[rows - 1];
|
|
const cols = lastRow.length;
|
|
if (cols === 0) {
|
|
throw new Error("Need to add a button before adding an icon!");
|
|
}
|
|
let lastButton = lastRow[cols - 1];
|
|
if (typeof lastButton === "string") {
|
|
lastButton = {
|
|
text: lastButton
|
|
};
|
|
lastRow[cols - 1] = lastButton;
|
|
}
|
|
lastButton.icon_custom_emoji_id = icon;
|
|
return this;
|
|
}
|
|
persistent(isEnabled = true) {
|
|
this.is_persistent = isEnabled;
|
|
return this;
|
|
}
|
|
selected(isEnabled = true) {
|
|
this.selective = isEnabled;
|
|
return this;
|
|
}
|
|
oneTime(isEnabled = true) {
|
|
this.one_time_keyboard = isEnabled;
|
|
return this;
|
|
}
|
|
resized(isEnabled = true) {
|
|
this.resize_keyboard = isEnabled;
|
|
return this;
|
|
}
|
|
placeholder(value) {
|
|
this.input_field_placeholder = value;
|
|
return this;
|
|
}
|
|
toTransposed() {
|
|
const original = this.keyboard;
|
|
const transposed = transpose(original);
|
|
return this.clone(transposed);
|
|
}
|
|
toFlowed(columns, options = {}) {
|
|
const original = this.keyboard;
|
|
const flowed = reflow(original, columns, options);
|
|
return this.clone(flowed);
|
|
}
|
|
clone(keyboard = this.keyboard) {
|
|
const clone = new Keyboard(keyboard.map((row)=>row.slice()));
|
|
clone.is_persistent = this.is_persistent;
|
|
clone.selective = this.selective;
|
|
clone.one_time_keyboard = this.one_time_keyboard;
|
|
clone.resize_keyboard = this.resize_keyboard;
|
|
clone.input_field_placeholder = this.input_field_placeholder;
|
|
return clone;
|
|
}
|
|
append(...sources) {
|
|
for (const source of sources){
|
|
const keyboard = Keyboard.from(source);
|
|
this.keyboard.push(...keyboard.keyboard.map((row)=>row.slice()));
|
|
}
|
|
return this;
|
|
}
|
|
build() {
|
|
return this.keyboard;
|
|
}
|
|
static from(source) {
|
|
if (source instanceof Keyboard) return source.clone();
|
|
function toButton(btn) {
|
|
return typeof btn === "string" ? Keyboard.text(btn) : btn;
|
|
}
|
|
return new Keyboard(source.map((row)=>row.map(toButton)));
|
|
}
|
|
}
|
|
class InlineKeyboard {
|
|
inline_keyboard;
|
|
constructor(inline_keyboard = [
|
|
[]
|
|
]){
|
|
this.inline_keyboard = inline_keyboard;
|
|
}
|
|
add(...buttons) {
|
|
this.inline_keyboard[this.inline_keyboard.length - 1]?.push(...buttons);
|
|
return this;
|
|
}
|
|
row(...buttons) {
|
|
this.inline_keyboard.push(buttons);
|
|
return this;
|
|
}
|
|
url(text, url) {
|
|
return this.add(InlineKeyboard.url(text, url));
|
|
}
|
|
static url(text, url) {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
url
|
|
} : {
|
|
...text,
|
|
url
|
|
};
|
|
}
|
|
text(text, data = typeof text === "string" ? text : text.text) {
|
|
return this.add(InlineKeyboard.text(text, data));
|
|
}
|
|
static text(text, data = typeof text === "string" ? text : text.text) {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
callback_data: data
|
|
} : {
|
|
...text,
|
|
callback_data: data
|
|
};
|
|
}
|
|
webApp(text, url) {
|
|
return this.add(InlineKeyboard.webApp(text, url));
|
|
}
|
|
static webApp(text, url) {
|
|
const web_app = typeof url === "string" ? {
|
|
url
|
|
} : url;
|
|
return typeof text === "string" ? {
|
|
text,
|
|
web_app
|
|
} : {
|
|
...text,
|
|
web_app
|
|
};
|
|
}
|
|
login(text, loginUrl) {
|
|
return this.add(InlineKeyboard.login(text, loginUrl));
|
|
}
|
|
static login(text, loginUrl) {
|
|
const login_url = typeof loginUrl === "string" ? {
|
|
url: loginUrl
|
|
} : loginUrl;
|
|
return typeof text === "string" ? {
|
|
text,
|
|
login_url
|
|
} : {
|
|
...text,
|
|
login_url
|
|
};
|
|
}
|
|
switchInline(text, query = "") {
|
|
return this.add(InlineKeyboard.switchInline(text, query));
|
|
}
|
|
static switchInline(text, query = "") {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
switch_inline_query: query
|
|
} : {
|
|
...text,
|
|
switch_inline_query: query
|
|
};
|
|
}
|
|
switchInlineCurrent(text, query = "") {
|
|
return this.add(InlineKeyboard.switchInlineCurrent(text, query));
|
|
}
|
|
static switchInlineCurrent(text, query = "") {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
switch_inline_query_current_chat: query
|
|
} : {
|
|
...text,
|
|
switch_inline_query_current_chat: query
|
|
};
|
|
}
|
|
switchInlineChosen(text, query = {}) {
|
|
return this.add(InlineKeyboard.switchInlineChosen(text, query));
|
|
}
|
|
static switchInlineChosen(text, query = {}) {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
switch_inline_query_chosen_chat: query
|
|
} : {
|
|
...text,
|
|
switch_inline_query_chosen_chat: query
|
|
};
|
|
}
|
|
copyText(text, copyText) {
|
|
return this.add(InlineKeyboard.copyText(text, copyText));
|
|
}
|
|
static copyText(text, copyText) {
|
|
const copy_text = typeof copyText === "string" ? {
|
|
text: copyText
|
|
} : copyText;
|
|
return typeof text === "string" ? {
|
|
text,
|
|
copy_text
|
|
} : {
|
|
...text,
|
|
copy_text
|
|
};
|
|
}
|
|
game(text) {
|
|
return this.add(InlineKeyboard.game(text));
|
|
}
|
|
static game(text) {
|
|
const callback_game = {};
|
|
return typeof text === "string" ? {
|
|
text,
|
|
callback_game
|
|
} : {
|
|
...text,
|
|
callback_game
|
|
};
|
|
}
|
|
pay(text) {
|
|
return this.add(InlineKeyboard.pay(text));
|
|
}
|
|
static pay(text) {
|
|
return typeof text === "string" ? {
|
|
text,
|
|
pay: true
|
|
} : {
|
|
...text,
|
|
pay: true
|
|
};
|
|
}
|
|
style(style) {
|
|
const rows = this.inline_keyboard.length;
|
|
if (rows === 0) {
|
|
throw new Error("Need to add a button before applying a style!");
|
|
}
|
|
const lastRow = this.inline_keyboard[rows - 1];
|
|
const cols = lastRow.length;
|
|
if (cols === 0) {
|
|
throw new Error("Need to add a button before applying a style!");
|
|
}
|
|
lastRow[cols - 1].style = style;
|
|
return this;
|
|
}
|
|
danger() {
|
|
return this.style("danger");
|
|
}
|
|
success() {
|
|
return this.style("success");
|
|
}
|
|
primary() {
|
|
return this.style("primary");
|
|
}
|
|
icon(icon) {
|
|
const rows = this.inline_keyboard.length;
|
|
if (rows === 0) {
|
|
throw new Error("Need to add a button before adding an icon!");
|
|
}
|
|
const lastRow = this.inline_keyboard[rows - 1];
|
|
const cols = lastRow.length;
|
|
if (cols === 0) {
|
|
throw new Error("Need to add a button before adding an icon!");
|
|
}
|
|
lastRow[cols - 1].icon_custom_emoji_id = icon;
|
|
return this;
|
|
}
|
|
toTransposed() {
|
|
const original = this.inline_keyboard;
|
|
const transposed = transpose(original);
|
|
return new InlineKeyboard(transposed);
|
|
}
|
|
toFlowed(columns, options = {}) {
|
|
const original = this.inline_keyboard;
|
|
const flowed = reflow(original, columns, options);
|
|
return new InlineKeyboard(flowed);
|
|
}
|
|
clone() {
|
|
return new InlineKeyboard(this.inline_keyboard.map((row)=>row.slice()));
|
|
}
|
|
append(...sources) {
|
|
for (const source of sources){
|
|
const keyboard = InlineKeyboard.from(source);
|
|
this.inline_keyboard.push(...keyboard.inline_keyboard.map((row)=>row.slice()));
|
|
}
|
|
return this;
|
|
}
|
|
static from(source) {
|
|
if (source instanceof InlineKeyboard) return source.clone();
|
|
return new InlineKeyboard(source.map((row)=>row.slice()));
|
|
}
|
|
}
|
|
function transpose(grid) {
|
|
const transposed = [];
|
|
for(let i = 0; i < grid.length; i++){
|
|
const row = grid[i];
|
|
for(let j = 0; j < row.length; j++){
|
|
const button = row[j];
|
|
(transposed[j] ??= []).push(button);
|
|
}
|
|
}
|
|
return transposed;
|
|
}
|
|
function reflow(grid, columns, { fillLastRow = false }) {
|
|
let first = columns;
|
|
if (fillLastRow) {
|
|
const buttonCount = grid.map((row)=>row.length).reduce((a, b)=>a + b, 0);
|
|
first = buttonCount % columns;
|
|
}
|
|
const reflowed = [];
|
|
for (const row of grid){
|
|
for (const button of row){
|
|
const at = Math.max(0, reflowed.length - 1);
|
|
const max = at === 0 ? first : columns;
|
|
let next = reflowed[at] ??= [];
|
|
if (next.length === max) {
|
|
next = [];
|
|
reflowed.push(next);
|
|
}
|
|
next.push(button);
|
|
}
|
|
}
|
|
return reflowed;
|
|
}
|
|
export { Keyboard as Keyboard };
|
|
export { InlineKeyboard as InlineKeyboard };
|
|
const debug3 = browser$1("grammy:session");
|
|
function session(options = {}) {
|
|
return options.type === "multi" ? strictMultiSession(options) : strictSingleSession(options);
|
|
}
|
|
function strictSingleSession(options) {
|
|
const { initial, storage, getSessionKey, custom } = fillDefaults(options);
|
|
return async (ctx, next)=>{
|
|
const propSession = new PropertySession(storage, ctx, "session", initial);
|
|
const key = await getSessionKey(ctx);
|
|
await propSession.init(key, {
|
|
custom,
|
|
lazy: false
|
|
});
|
|
await next();
|
|
await propSession.finish();
|
|
};
|
|
}
|
|
function strictMultiSession(options) {
|
|
const props = Object.keys(options).filter((k)=>k !== "type");
|
|
const defaults = Object.fromEntries(props.map((prop)=>[
|
|
prop,
|
|
fillDefaults(options[prop])
|
|
]));
|
|
return async (ctx, next)=>{
|
|
ctx.session = {};
|
|
const propSessions = await Promise.all(props.map(async (prop)=>{
|
|
const { initial, storage, getSessionKey, custom } = defaults[prop];
|
|
const s = new PropertySession(storage, ctx.session, prop, initial);
|
|
const key = await getSessionKey(ctx);
|
|
await s.init(key, {
|
|
custom,
|
|
lazy: false
|
|
});
|
|
return s;
|
|
}));
|
|
await next();
|
|
if (ctx.session == null) propSessions.forEach((s)=>s.delete());
|
|
await Promise.all(propSessions.map((s)=>s.finish()));
|
|
};
|
|
}
|
|
function lazySession(options = {}) {
|
|
if (options.type !== undefined && options.type !== "single") {
|
|
throw new Error("Cannot use lazy multi sessions!");
|
|
}
|
|
const { initial, storage, getSessionKey, custom } = fillDefaults(options);
|
|
return async (ctx, next)=>{
|
|
const propSession = new PropertySession(storage, ctx, "session", initial);
|
|
const key = await getSessionKey(ctx);
|
|
await propSession.init(key, {
|
|
custom,
|
|
lazy: true
|
|
});
|
|
await next();
|
|
await propSession.finish();
|
|
};
|
|
}
|
|
class PropertySession {
|
|
storage;
|
|
obj;
|
|
prop;
|
|
initial;
|
|
key;
|
|
value;
|
|
promise;
|
|
fetching;
|
|
read;
|
|
wrote;
|
|
constructor(storage, obj, prop, initial){
|
|
this.storage = storage;
|
|
this.obj = obj;
|
|
this.prop = prop;
|
|
this.initial = initial;
|
|
this.fetching = false;
|
|
this.read = false;
|
|
this.wrote = false;
|
|
}
|
|
load() {
|
|
if (this.key === undefined) {
|
|
return;
|
|
}
|
|
if (this.wrote) {
|
|
return;
|
|
}
|
|
if (this.promise === undefined) {
|
|
this.fetching = true;
|
|
this.promise = Promise.resolve(this.storage.read(this.key)).then((val)=>{
|
|
this.fetching = false;
|
|
if (this.wrote) {
|
|
return this.value;
|
|
}
|
|
if (val !== undefined) {
|
|
this.value = val;
|
|
return val;
|
|
}
|
|
val = this.initial?.();
|
|
if (val !== undefined) {
|
|
this.wrote = true;
|
|
this.value = val;
|
|
}
|
|
return val;
|
|
});
|
|
}
|
|
return this.promise;
|
|
}
|
|
async init(key, opts) {
|
|
this.key = key;
|
|
if (!opts.lazy) await this.load();
|
|
Object.defineProperty(this.obj, this.prop, {
|
|
enumerable: true,
|
|
get: ()=>{
|
|
if (key === undefined) {
|
|
const msg = undef("access", opts);
|
|
throw new Error(msg);
|
|
}
|
|
this.read = true;
|
|
if (!opts.lazy || this.wrote) return this.value;
|
|
this.load();
|
|
return this.fetching ? this.promise : this.value;
|
|
},
|
|
set: (v)=>{
|
|
if (key === undefined) {
|
|
const msg = undef("assign", opts);
|
|
throw new Error(msg);
|
|
}
|
|
this.wrote = true;
|
|
this.fetching = false;
|
|
this.value = v;
|
|
}
|
|
});
|
|
}
|
|
delete() {
|
|
Object.assign(this.obj, {
|
|
[this.prop]: undefined
|
|
});
|
|
}
|
|
async finish() {
|
|
if (this.key !== undefined) {
|
|
if (this.read) await this.load();
|
|
if (this.read || this.wrote) {
|
|
const value = await this.value;
|
|
if (value == null) await this.storage.delete(this.key);
|
|
else await this.storage.write(this.key, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function fillDefaults(opts = {}) {
|
|
let { prefix = "", getSessionKey = defaultGetSessionKey, initial, storage } = opts;
|
|
if (storage == null) {
|
|
debug3("Storing session data in memory, all data will be lost when the bot restarts.");
|
|
storage = new MemorySessionStorage();
|
|
}
|
|
const custom = getSessionKey !== defaultGetSessionKey;
|
|
return {
|
|
initial,
|
|
storage,
|
|
getSessionKey: async (ctx)=>{
|
|
const key = await getSessionKey(ctx);
|
|
return key === undefined ? undefined : prefix + key;
|
|
},
|
|
custom
|
|
};
|
|
}
|
|
function defaultGetSessionKey(ctx) {
|
|
return ctx.chatId?.toString();
|
|
}
|
|
function undef(op, opts) {
|
|
const { lazy = false, custom } = opts;
|
|
const reason = custom ? "the custom `getSessionKey` function returned undefined for this update" : "this update does not belong to a chat, so the session key is undefined";
|
|
return `Cannot ${op} ${lazy ? "lazy " : ""}session data because ${reason}!`;
|
|
}
|
|
function isEnhance(value) {
|
|
return value === undefined || typeof value === "object" && value !== null && "__d" in value;
|
|
}
|
|
function enhanceStorage(options) {
|
|
let { storage, millisecondsToLive, migrations } = options;
|
|
storage = compatStorage(storage);
|
|
if (millisecondsToLive !== undefined) {
|
|
storage = timeoutStorage(storage, millisecondsToLive);
|
|
}
|
|
if (migrations !== undefined) {
|
|
storage = migrationStorage(storage, migrations);
|
|
}
|
|
return wrapStorage(storage);
|
|
}
|
|
function compatStorage(storage) {
|
|
return {
|
|
read: async (k)=>{
|
|
const v = await storage.read(k);
|
|
return isEnhance(v) ? v : {
|
|
__d: v
|
|
};
|
|
},
|
|
write: (k, v)=>storage.write(k, v),
|
|
delete: (k)=>storage.delete(k)
|
|
};
|
|
}
|
|
function timeoutStorage(storage, millisecondsToLive) {
|
|
const ttlStorage = {
|
|
read: async (k)=>{
|
|
const value = await storage.read(k);
|
|
if (value === undefined) return undefined;
|
|
if (value.e === undefined) {
|
|
await ttlStorage.write(k, value);
|
|
return value;
|
|
}
|
|
if (value.e < Date.now()) {
|
|
await ttlStorage.delete(k);
|
|
return undefined;
|
|
}
|
|
return value;
|
|
},
|
|
write: async (k, v)=>{
|
|
v.e = addExpiryDate(v, millisecondsToLive).expires;
|
|
await storage.write(k, v);
|
|
},
|
|
delete: (k)=>storage.delete(k)
|
|
};
|
|
return ttlStorage;
|
|
}
|
|
function migrationStorage(storage, migrations) {
|
|
const versions = Object.keys(migrations).map((v)=>parseInt(v)).sort((a, b)=>a - b);
|
|
const count = versions.length;
|
|
if (count === 0) throw new Error("No migrations given!");
|
|
const earliest = versions[0];
|
|
const last = count - 1;
|
|
const latest = versions[last];
|
|
const index = new Map();
|
|
versions.forEach((v, i)=>index.set(v, i));
|
|
function nextAfter(current) {
|
|
let i = last;
|
|
while(current <= versions[i])i--;
|
|
return i;
|
|
}
|
|
return {
|
|
read: async (k)=>{
|
|
const val = await storage.read(k);
|
|
if (val === undefined) return val;
|
|
let { __d: value, v: current = earliest - 1 } = val;
|
|
let i = 1 + (index.get(current) ?? nextAfter(current));
|
|
for(; i < count; i++)value = migrations[versions[i]](value);
|
|
return {
|
|
...val,
|
|
v: latest,
|
|
__d: value
|
|
};
|
|
},
|
|
write: (k, v)=>storage.write(k, {
|
|
v: latest,
|
|
...v
|
|
}),
|
|
delete: (k)=>storage.delete(k)
|
|
};
|
|
}
|
|
function wrapStorage(storage) {
|
|
return {
|
|
read: (k)=>Promise.resolve(storage.read(k)).then((v)=>v?.__d),
|
|
write: (k, v)=>storage.write(k, {
|
|
__d: v
|
|
}),
|
|
delete: (k)=>storage.delete(k)
|
|
};
|
|
}
|
|
class MemorySessionStorage {
|
|
timeToLive;
|
|
storage;
|
|
constructor(timeToLive){
|
|
this.timeToLive = timeToLive;
|
|
this.storage = new Map();
|
|
}
|
|
read(key) {
|
|
const value = this.storage.get(key);
|
|
if (value === undefined) return undefined;
|
|
if (value.expires !== undefined && value.expires < Date.now()) {
|
|
this.delete(key);
|
|
return undefined;
|
|
}
|
|
return value.session;
|
|
}
|
|
readAll() {
|
|
return this.readAllValues();
|
|
}
|
|
readAllKeys() {
|
|
return Array.from(this.storage.keys());
|
|
}
|
|
readAllValues() {
|
|
return Array.from(this.storage.keys()).map((key)=>this.read(key)).filter((value)=>value !== undefined);
|
|
}
|
|
readAllEntries() {
|
|
return Array.from(this.storage.keys()).map((key)=>[
|
|
key,
|
|
this.read(key)
|
|
]).filter((pair)=>pair[1] !== undefined);
|
|
}
|
|
has(key) {
|
|
return this.storage.has(key);
|
|
}
|
|
write(key, value) {
|
|
this.storage.set(key, addExpiryDate(value, this.timeToLive));
|
|
}
|
|
delete(key) {
|
|
this.storage.delete(key);
|
|
}
|
|
}
|
|
function addExpiryDate(value, ttl) {
|
|
if (ttl !== undefined && ttl < Infinity) {
|
|
const now = Date.now();
|
|
return {
|
|
session: value,
|
|
expires: now + ttl
|
|
};
|
|
} else {
|
|
return {
|
|
session: value
|
|
};
|
|
}
|
|
}
|
|
export { session as session };
|
|
export { lazySession as lazySession };
|
|
export { enhanceStorage as enhanceStorage };
|
|
export { MemorySessionStorage as MemorySessionStorage };
|
|
const SECRET_HEADER = "X-Telegram-Bot-Api-Secret-Token";
|
|
const SECRET_HEADER_LOWERCASE = SECRET_HEADER.toLowerCase();
|
|
const WRONG_TOKEN_ERROR = "secret token is wrong";
|
|
const ok = ()=>new Response(null, {
|
|
status: 200
|
|
});
|
|
const okJson = (json)=>new Response(json, {
|
|
status: 200,
|
|
headers: {
|
|
"Content-Type": "application/json"
|
|
}
|
|
});
|
|
const unauthorized = ()=>new Response('"unauthorized"', {
|
|
status: 401,
|
|
statusText: WRONG_TOKEN_ERROR
|
|
});
|
|
const awsLambda = (event, _context, callback)=>({
|
|
get update () {
|
|
return JSON.parse(event.body ?? "{}");
|
|
},
|
|
header: event.headers[SECRET_HEADER],
|
|
end: ()=>callback(null, {
|
|
statusCode: 200
|
|
}),
|
|
respond: (json)=>callback(null, {
|
|
statusCode: 200,
|
|
headers: {
|
|
"Content-Type": "application/json"
|
|
},
|
|
body: json
|
|
}),
|
|
unauthorized: ()=>callback(null, {
|
|
statusCode: 401
|
|
})
|
|
});
|
|
const awsLambdaAsync = (event, _context)=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return JSON.parse(event.body ?? "{}");
|
|
},
|
|
header: event.headers[SECRET_HEADER],
|
|
end: ()=>resolveResponse({
|
|
statusCode: 200
|
|
}),
|
|
respond: (json)=>resolveResponse({
|
|
statusCode: 200,
|
|
headers: {
|
|
"Content-Type": "application/json"
|
|
},
|
|
body: json
|
|
}),
|
|
unauthorized: ()=>resolveResponse({
|
|
statusCode: 401
|
|
}),
|
|
handlerReturn: new Promise((res)=>resolveResponse = res)
|
|
};
|
|
};
|
|
const azure = (context, request)=>({
|
|
get update () {
|
|
return request.body;
|
|
},
|
|
header: context.res?.headers?.[SECRET_HEADER],
|
|
end: ()=>context.res = {
|
|
status: 200,
|
|
body: ""
|
|
},
|
|
respond: (json)=>{
|
|
context.res?.set?.("Content-Type", "application/json");
|
|
context.res?.send?.(json);
|
|
},
|
|
unauthorized: ()=>{
|
|
context.res?.send?.(401, WRONG_TOKEN_ERROR);
|
|
}
|
|
});
|
|
const azureV4 = (request)=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return request.json();
|
|
},
|
|
header: request.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>resolveResponse({
|
|
status: 204
|
|
}),
|
|
respond: (json)=>resolveResponse({
|
|
jsonBody: json
|
|
}),
|
|
unauthorized: ()=>resolveResponse({
|
|
status: 401,
|
|
body: WRONG_TOKEN_ERROR
|
|
}),
|
|
handlerReturn: new Promise((resolve)=>resolveResponse = resolve)
|
|
};
|
|
};
|
|
const bun = (request)=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return request.json();
|
|
},
|
|
header: request.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>{
|
|
resolveResponse(ok());
|
|
},
|
|
respond: (json)=>{
|
|
resolveResponse(okJson(json));
|
|
},
|
|
unauthorized: ()=>{
|
|
resolveResponse(unauthorized());
|
|
},
|
|
handlerReturn: new Promise((res)=>resolveResponse = res)
|
|
};
|
|
};
|
|
const cloudflare = (event)=>{
|
|
let resolveResponse;
|
|
event.respondWith(new Promise((resolve)=>{
|
|
resolveResponse = resolve;
|
|
}));
|
|
return {
|
|
get update () {
|
|
return event.request.json();
|
|
},
|
|
header: event.request.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>{
|
|
resolveResponse(ok());
|
|
},
|
|
respond: (json)=>{
|
|
resolveResponse(okJson(json));
|
|
},
|
|
unauthorized: ()=>{
|
|
resolveResponse(unauthorized());
|
|
}
|
|
};
|
|
};
|
|
const cloudflareModule = (request)=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return request.json();
|
|
},
|
|
header: request.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>{
|
|
resolveResponse(ok());
|
|
},
|
|
respond: (json)=>{
|
|
resolveResponse(okJson(json));
|
|
},
|
|
unauthorized: ()=>{
|
|
resolveResponse(unauthorized());
|
|
},
|
|
handlerReturn: new Promise((res)=>resolveResponse = res)
|
|
};
|
|
};
|
|
const express = (req, res)=>({
|
|
get update () {
|
|
return req.body;
|
|
},
|
|
header: req.header(SECRET_HEADER),
|
|
end: ()=>res.end(),
|
|
respond: (json)=>{
|
|
res.set("Content-Type", "application/json");
|
|
res.send(json);
|
|
},
|
|
unauthorized: ()=>{
|
|
res.status(401).send(WRONG_TOKEN_ERROR);
|
|
}
|
|
});
|
|
const fastify = (request, reply)=>({
|
|
get update () {
|
|
return request.body;
|
|
},
|
|
header: request.headers[SECRET_HEADER_LOWERCASE],
|
|
end: ()=>reply.send(""),
|
|
respond: (json)=>reply.headers({
|
|
"Content-Type": "application/json"
|
|
}).send(json),
|
|
unauthorized: ()=>reply.code(401).send(WRONG_TOKEN_ERROR)
|
|
});
|
|
const hono = (c)=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return c.req.json();
|
|
},
|
|
header: c.req.header(SECRET_HEADER),
|
|
end: ()=>{
|
|
resolveResponse(c.body(""));
|
|
},
|
|
respond: (json)=>{
|
|
resolveResponse(c.json(json));
|
|
},
|
|
unauthorized: ()=>{
|
|
c.status(401);
|
|
resolveResponse(c.body(""));
|
|
},
|
|
handlerReturn: new Promise((res)=>resolveResponse = res)
|
|
};
|
|
};
|
|
const http = (req, res)=>{
|
|
const secretHeaderFromRequest = req.headers[SECRET_HEADER_LOWERCASE];
|
|
return {
|
|
get update () {
|
|
return new Promise((resolve, reject)=>{
|
|
const chunks = [];
|
|
req.on("data", (chunk)=>chunks.push(chunk)).once("end", ()=>{
|
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
resolve(JSON.parse(raw));
|
|
}).once("error", reject);
|
|
});
|
|
},
|
|
header: Array.isArray(secretHeaderFromRequest) ? secretHeaderFromRequest[0] : secretHeaderFromRequest,
|
|
end: ()=>res.end(),
|
|
respond: (json)=>res.writeHead(200, {
|
|
"Content-Type": "application/json"
|
|
}).end(json),
|
|
unauthorized: ()=>res.writeHead(401).end(WRONG_TOKEN_ERROR)
|
|
};
|
|
};
|
|
const koa = (ctx)=>({
|
|
get update () {
|
|
return ctx.request.body;
|
|
},
|
|
header: ctx.get(SECRET_HEADER) || undefined,
|
|
end: ()=>{
|
|
ctx.body = "";
|
|
},
|
|
respond: (json)=>{
|
|
ctx.set("Content-Type", "application/json");
|
|
ctx.response.body = json;
|
|
},
|
|
unauthorized: ()=>{
|
|
ctx.status = 401;
|
|
}
|
|
});
|
|
const nextJs = (request, response)=>({
|
|
get update () {
|
|
return request.body;
|
|
},
|
|
header: request.headers[SECRET_HEADER_LOWERCASE],
|
|
end: ()=>response.end(),
|
|
respond: (json)=>response.status(200).json(json),
|
|
unauthorized: ()=>response.status(401).send(WRONG_TOKEN_ERROR)
|
|
});
|
|
const nhttp = (rev)=>({
|
|
get update () {
|
|
return rev.body;
|
|
},
|
|
header: rev.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>rev.response.sendStatus(200),
|
|
respond: (json)=>rev.response.status(200).send(json),
|
|
unauthorized: ()=>rev.response.status(401).send(WRONG_TOKEN_ERROR)
|
|
});
|
|
const oak = (ctx)=>({
|
|
get update () {
|
|
return ctx.request.body.json();
|
|
},
|
|
header: ctx.request.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>{
|
|
ctx.response.status = 200;
|
|
},
|
|
respond: (json)=>{
|
|
ctx.response.type = "json";
|
|
ctx.response.body = json;
|
|
},
|
|
unauthorized: ()=>{
|
|
ctx.response.status = 401;
|
|
}
|
|
});
|
|
const serveHttp = (requestEvent)=>({
|
|
get update () {
|
|
return requestEvent.request.json();
|
|
},
|
|
header: requestEvent.request.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>requestEvent.respondWith(ok()),
|
|
respond: (json)=>requestEvent.respondWith(okJson(json)),
|
|
unauthorized: ()=>requestEvent.respondWith(unauthorized())
|
|
});
|
|
const stdHttp = (req)=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return req.json();
|
|
},
|
|
header: req.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>{
|
|
if (resolveResponse) resolveResponse(ok());
|
|
},
|
|
respond: (json)=>{
|
|
if (resolveResponse) resolveResponse(okJson(json));
|
|
},
|
|
unauthorized: ()=>{
|
|
if (resolveResponse) resolveResponse(unauthorized());
|
|
},
|
|
handlerReturn: new Promise((res)=>resolveResponse = res)
|
|
};
|
|
};
|
|
const sveltekit = ({ request })=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return request.json();
|
|
},
|
|
header: request.headers.get(SECRET_HEADER) || undefined,
|
|
end: ()=>{
|
|
if (resolveResponse) resolveResponse(ok());
|
|
},
|
|
respond: (json)=>{
|
|
if (resolveResponse) resolveResponse(okJson(json));
|
|
},
|
|
unauthorized: ()=>{
|
|
if (resolveResponse) resolveResponse(unauthorized());
|
|
},
|
|
handlerReturn: new Promise((res)=>resolveResponse = res)
|
|
};
|
|
};
|
|
const worktop = (req, res)=>({
|
|
get update () {
|
|
return req.json();
|
|
},
|
|
header: req.headers.get(SECRET_HEADER) ?? undefined,
|
|
end: ()=>res.end(null),
|
|
respond: (json)=>res.send(200, json),
|
|
unauthorized: ()=>res.send(401, WRONG_TOKEN_ERROR)
|
|
});
|
|
const elysia = (ctx)=>{
|
|
let resolveResponse;
|
|
return {
|
|
get update () {
|
|
return ctx.body;
|
|
},
|
|
header: ctx.headers[SECRET_HEADER_LOWERCASE],
|
|
end () {
|
|
resolveResponse("");
|
|
},
|
|
respond (json) {
|
|
ctx.set.headers["content-type"] = "application/json";
|
|
resolveResponse(json);
|
|
},
|
|
unauthorized () {
|
|
ctx.set.status = 401;
|
|
resolveResponse("");
|
|
},
|
|
handlerReturn: new Promise((res)=>resolveResponse = res)
|
|
};
|
|
};
|
|
const adapters = {
|
|
"aws-lambda": awsLambda,
|
|
"aws-lambda-async": awsLambdaAsync,
|
|
azure,
|
|
"azure-v4": azureV4,
|
|
bun,
|
|
cloudflare,
|
|
"cloudflare-mod": cloudflareModule,
|
|
elysia,
|
|
express,
|
|
fastify,
|
|
hono,
|
|
http,
|
|
https: http,
|
|
koa,
|
|
"next-js": nextJs,
|
|
nhttp,
|
|
oak,
|
|
serveHttp,
|
|
"std/http": stdHttp,
|
|
sveltekit,
|
|
worktop
|
|
};
|
|
const debugErr1 = browser$1("grammy:error");
|
|
const callbackAdapter = (update, callback, header, unauthorized = ()=>callback('"unauthorized"'))=>({
|
|
update: Promise.resolve(update),
|
|
respond: callback,
|
|
header,
|
|
unauthorized
|
|
});
|
|
const adapters1 = {
|
|
...adapters,
|
|
callback: callbackAdapter
|
|
};
|
|
function compareSecretToken(header, token) {
|
|
if (token === undefined) {
|
|
return true;
|
|
}
|
|
if (header === undefined) {
|
|
return false;
|
|
}
|
|
const encoder = new TextEncoder();
|
|
const headerBytes = encoder.encode(header);
|
|
const tokenBytes = encoder.encode(token);
|
|
if (headerBytes.length !== tokenBytes.length) {
|
|
return false;
|
|
}
|
|
let hasDifference = 0;
|
|
for(let i = 0; i < tokenBytes.length; i++){
|
|
const headerByte = i < headerBytes.length ? headerBytes[i] : 0;
|
|
const tokenByte = tokenBytes[i];
|
|
hasDifference |= headerByte ^ tokenByte;
|
|
}
|
|
return hasDifference === 0;
|
|
}
|
|
function webhookCallback(bot, adapter = defaultAdapter, onTimeout, timeoutMilliseconds, secretToken) {
|
|
if (bot.isRunning()) {
|
|
throw new Error("Bot is already running via long polling, the webhook setup won't receive any updates!");
|
|
} else {
|
|
bot.start = ()=>{
|
|
throw new Error("You already started the bot via webhooks, calling `bot.start()` starts the bot with long polling and this will prevent your webhook setup from receiving any updates!");
|
|
};
|
|
}
|
|
const { onTimeout: timeout = "throw", timeoutMilliseconds: ms = 10_000, secretToken: token } = typeof onTimeout === "object" ? onTimeout : {
|
|
onTimeout,
|
|
timeoutMilliseconds,
|
|
secretToken
|
|
};
|
|
let initialized = false;
|
|
const server = typeof adapter === "string" ? adapters1[adapter] : adapter;
|
|
return async (...args)=>{
|
|
const handler = server(...args);
|
|
if (!initialized) {
|
|
await bot.init();
|
|
initialized = true;
|
|
}
|
|
if (!compareSecretToken(handler.header, token)) {
|
|
await handler.unauthorized();
|
|
return handler.handlerReturn;
|
|
}
|
|
let usedWebhookReply = false;
|
|
const webhookReplyEnvelope = {
|
|
async send (json) {
|
|
usedWebhookReply = true;
|
|
await handler.respond(json);
|
|
}
|
|
};
|
|
await timeoutIfNecessary(bot.handleUpdate(await handler.update, webhookReplyEnvelope), typeof timeout === "function" ? ()=>timeout(...args) : timeout, ms);
|
|
if (!usedWebhookReply) handler.end?.();
|
|
return handler.handlerReturn;
|
|
};
|
|
}
|
|
function timeoutIfNecessary(task, onTimeout, timeout) {
|
|
if (timeout === Infinity) return task;
|
|
return new Promise((resolve, reject)=>{
|
|
const handle = setTimeout(()=>{
|
|
debugErr1(`Request timed out after ${timeout} ms`);
|
|
if (onTimeout === "throw") {
|
|
reject(new Error(`Request timed out after ${timeout} ms`));
|
|
} else {
|
|
if (typeof onTimeout === "function") onTimeout();
|
|
resolve();
|
|
}
|
|
const now = Date.now();
|
|
task.finally(()=>{
|
|
const diff = Date.now() - now;
|
|
debugErr1(`Request completed ${diff} ms after timeout!`);
|
|
});
|
|
}, timeout);
|
|
task.then(resolve).catch(reject).finally(()=>clearTimeout(handle));
|
|
});
|
|
}
|
|
export { webhookCallback as webhookCallback };
|
|
export { Bot as Bot, BotError as BotError };
|
|
export { InputFile as InputFile };
|
|
export { Context as Context };
|
|
export { Composer as Composer };
|
|
export { matchFilter as matchFilter };
|
|
export { Api as Api };
|
|
export { GrammyError as GrammyError, HttpError as HttpError };
|