yaebal
Yet Another tElegram Bot Api Library.
the context type accumulates through the chain — handlers see what plugins added,
with zero casting.
pnpm add yaebalimport { InlineKeyboard, callbackData, createBot, html, session } from "yaebal";
const vibe = callbackData("vibe", { score: Number });
const bot = createBot(process.env.BOT_TOKEN!)
.install(session({ initial: () => ({ fire: 0 }) }))
.derive((ctx) => ({ who: ctx.from?.first_name ?? "friend" }));
bot.command("start", (ctx) =>
ctx.reply(html`<b>hey ${ctx.who}</b> — pick the vibe`, {
reply_markup: new InlineKeyboard()
.text("🔥 ship it", vibe.pack({ score: 1 }))
.text("🚀 10x", vibe.pack({ score: 10 }))
.build(),
}),
);
bot.on("message:text", async (ctx) => {
await ctx.react("🔥"); // generated MessageContext shortcut
return ctx.reply(html`<code>${ctx.text}</code> landed in a typed handler`);
});
bot.callbackQuery(vibe.pattern, (ctx) => {
const data = vibe.unpack(ctx.callbackQuery.data ?? "");
ctx.session.fire += data?.score ?? 0;
return ctx.answer(`vibe score: ${ctx.session.fire}`);
});
bot.start();batteries, not a shopping list
retries, the callback-query spinner, message handles, the typing indicator, file downloads,
4096-char splitting — first-party, typed, and already in the yaebal package.
every install widens the context type, so a missing one is a compile error.
import { createBot, autoRetry, autoAnswer, hydrate, typing } from "yaebal";
// the six lines every production bot writes anyway — one import, no wiring
const bot = createBot(process.env.BOT_TOKEN!)
.install(autoRetry()) // 429 flood-waits and transient 5xx retry themselves
.install(autoAnswer()) // no callback query left spinning
.install(hydrate()) // msg.editText(...) / msg.delete() on what you just sent
.install(typing()); // ctx.typing(fn) holds "typing…" for as long as fn runs
bot.command("ask", (ctx) =>
ctx.typing(async () => {
const msg = ctx.hydrate(await ctx.reply("thinking…"));
await msg.editText("here you go");
}),
);🛟 type-safe
strict mode, no any in public types. the context type flows through the whole chain.
⛓️ chainable
Bot extends Composer. derive / decorate / guard each return an augmented context type.
🚘 auto-gen contexts
every per-update context and its shortcut methods are generated from the Bot API schema.
🥇 plugin-first
a deep set of first-party plugins — filters, conversation, runner, and more. dependencies are explicit and type-checked, never implicit order.