@balegraf/balegraf
v0.15.1
Published
create Bale bots with a Telegraf-like framework for Bale messenger
Maintainers
Readme
Features
- Telegraf-style API
- Middleware system (
bot.use) - Command handlers (
bot.command) - Text matching (
bot.hears) - Callback query handlers (
bot.action) - Event handlers (
bot.on) - Inline keyboards
- Reply keyboards
- Keyboard removal
- Callback query support
- Callback query answers (
ctx.answerCallbackQuery) - Message editing support
- Message deletion support
- Photo sending support
- File upload support
InputFilehelpers for path, file ID, URL, buffer, and stream- Button helpers:
Markup.button.text,Markup.button.contact,Markup.button.location,Markup.button.url,Markup.button.copy - Type guards:
IsMessage,IsEditedMessage,IsCallbackQuery,IsPreCheckoutQuery - Pre-checkout query support (
bot.on('pre_checkout_query')) - TypeScript support
- Long polling updates
- Lightweight core
Installation
npm install @balegraf/balegrafQuick Start
import { Balegraf, Markup } from "@balegraf/balegraf";
const bot = new Balegraf(process.env.BALE_TOKEN!);
bot.command("start", async (ctx) => {
await ctx.reply(
"Choose an option",
Markup.inlineKeyboard([[Markup.button.callback("Click Me", "click_me")]]),
);
});
bot.action("click_me", async (ctx) => {
await ctx.answerCallbackQuery();
await ctx.reply("Button clicked!");
});
bot.launch();Editing Inline Messages
bot.action("edit", async (ctx) => {
await ctx.editMessageText(
"Message updated",
Markup.inlineKeyboard([[Markup.button.callback("Done", "done")]]),
);
await ctx.answerCallbackQuery();
});Middleware
bot.use(async (ctx, next) => {
console.log(ctx.update);
await next();
});Commands
bot.command("start", async (ctx) => {
await ctx.reply("Welcome!");
});Text Matching
String matching:
bot.hears("hello", async (ctx) => {
await ctx.reply("Hi!");
});Regex matching:
bot.hears(/hello|سلام/i, async (ctx) => {
await ctx.reply("Hi!");
});Actions
Handle callback queries from inline keyboards.
bot.action("like", async (ctx) => {
await ctx.answerCallbackQuery("Liked!");
});
bot.action("delete", async (ctx) => {
await ctx.answerCallbackQuery("Deleted!");
});Regex actions:
bot.action(/^user:\d+$/, async (ctx) => {
console.log(ctx.callbackData);
});Event Handlers
bot.on("message", async (ctx) => {
console.log(ctx.message);
});bot.on("callback_query", async (ctx) => {
await ctx.answerCallbackQuery("You clicked the button!", true);
await ctx.reply(JSON.stringify(ctx.callbackQuery));
});
bot.on('callback_query', ...)now receives aCallbackQueryContext, soctx.answerCallbackQuery()is available directly.
Inline Keyboard
import { Markup } from "@balegraf/balegraf";
await ctx.reply(
"Choose an option",
Markup.inlineKeyboard([
[Markup.button.callback("Click Me", "click_me")],
[Markup.button.text("Just a Button")],
]),
);
Markup.inlineKeyboardnow accepts plain text buttons viaMarkup.button.text().
Button Helpers
Use built-in helper methods to create text, contact, location, URL, and copy buttons for inline keyboards.
await ctx.reply(
"Choose an option",
Markup.inlineKeyboard([
[Markup.button.text("Plain text")],
[Markup.button.url("Open site", "https://example.com")],
[Markup.button.contact("Share contact")],
[Markup.button.location("Share location")],
[Markup.button.copy("Copy text")],
]),
);Reply Keyboard
await ctx.reply(
"Choose an option",
Markup.keyboard([["Profile", "Settings"], ["Help"]]),
);
Markup.keyboardaccepts string buttons directly and converts them to keyboard buttons.
Remove Keyboard
await ctx.reply("Keyboard removed", Markup.removeKeyboard());Sending Photos
Using a local file:
import { InputFile } from "@balegraf/balegraf";
await ctx.replyWithPhoto(InputFile.fromPath("./photo.jpg"));With caption:
await ctx.replyWithPhoto(InputFile.fromPath("./photo.jpg"), {
caption: "Example photo",
});With inline keyboard:
await ctx.replyWithPhoto(InputFile.fromPath("./photo.jpg"), {
caption: "Choose an option",
replyMarkup: Markup.inlineKeyboard([
[Markup.button.callback("Like", "like")],
]),
});InputFile
Create files from different sources.
Local File
InputFile.fromPath("./photo.jpg");File ID
InputFile.fromFileId(fileId);URL
InputFile.fromUrl("https://example.com/photo.jpg");Buffer
InputFile.fromBuffer(buffer, "photo.jpg");Stream
InputFile.fromStream(fs.createReadStream("./photo.jpg"), "photo.jpg");Editing Messages
Edit Text
await ctx.editMessageText("Updated text");With inline keyboard:
await ctx.editMessageText(
"Updated text",
Markup.inlineKeyboard([[Markup.button.callback("Refresh", "refresh")]]),
);Edit Caption
await ctx.editMessageCaption(
"Updated caption",
ctx.callbackQuery.message.reply_markup,
);Edit Reply Markup
await ctx.editMessageReplyMarkup(
Markup.inlineKeyboard([[Markup.button.callback("New Button", "new_button")]]),
);Deleting Messages
await ctx.deleteMessage();Context
Properties
ctx.update;
ctx.updateType;
ctx.message;
ctx.callbackQuery;
ctx.callbackData;
ctx.user;
ctx.chat;Methods
ctx.reply(...)
ctx.replyWithPhoto(...)
ctx.answerCallbackQuery(...)
ctx.answerPreCheckoutQuery(...)
ctx.editMessageText(...)
ctx.editMessageCaption(...)
ctx.editMessageReplyMarkup(...)
ctx.deleteMessage()Type Guards
import { IsMessage, IsPreCheckoutQuery } from "@balegraf/balegraf";
bot.on("message", async (ctx) => {
if (IsMessage(ctx)) {
await ctx.reply("This is a message update");
}
});
bot.on("pre_checkout_query", async (ctx) => {
if (IsPreCheckoutQuery(ctx)) {
await ctx.answerPreCheckoutQuery(true);
}
});Pre-checkout Queries
bot.on("pre_checkout_query", async (ctx) => {
await ctx.answerPreCheckoutQuery(true);
});Update Types
Supported update types:
message;
edited_message;
callback_query;
pre_checkout_query;Note:
editMessageText,editMessageCaption,editMessageReplyMarkup, anddeleteMessageoperate on the current message associated with the incoming update, similar to Telegraf.
Requirements
- Node.js 20+
License
MIT
