migrate from grammy
grammy and yaebal both use middleware and filter queries. the main difference is that yaebal's composer chain carries context additions forward without manual context flavors.
initialization
// grammy
import { Bot } from "grammy";
const bot = new Bot(process.env.BOT_TOKEN!);
// yaebal
import { createBot } from "yaebal";
const bot = createBot(process.env.BOT_TOKEN!);handlers and filters
// grammy
bot.command("start", (ctx) => ctx.reply("hello"));
bot.on("message:text", (ctx) => ctx.reply(ctx.message.text));
// yaebal
bot.command("start", (ctx) => ctx.reply("hello"));
bot.on("message:text", (ctx) => ctx.reply(ctx.text));context flavors to derive/decorate
in yaebal, add fields with derive, decorate, or typed plugins instead of
module augmentation or manually passing flavored context types everywhere.
// grammy flavor-style state
type MyContext = Context & { user: User };
// yaebal chain state
const bot = createBot(token)
.derive(async (ctx) => ({ user: await loadUser(ctx.from?.id) }))
.on("message:text", (ctx) => ctx.user);sessions
// grammy
bot.use(session({ initial: () => ({ count: 0 }) }));
// yaebal
bot.install(session({ initial: () => ({ count: 0 }) }));api params
yaebal uses named bot api params, matching the generated bot api reference.
// grammy
await ctx.api.sendMessage(chatId, "hello");
// yaebal
await ctx.api.sendMessage({ chat_id: chatId, text: "hello" });middleware
// yaebal raw middleware is koa-style
bot.use(async (ctx, next) => {
const started = Date.now();
try {
await next();
} finally {
console.log(ctx.updateType, Date.now() - started);
}
});migration checklist
- replace flavored context types with
derive,decorate, and plugins. - keep filter queries like
message:text; they map well to yaebal. - convert positional api calls to named params.
- use
@yaebal/againand api hooks instead of transformer-style retry code. - move conversation/session choices to the matching yaebal plugins.