@yaebal/toml
declarative toml routes for yaebal bots. describe simple commands, text routes, message filters, callback queries and replies in toml, then keep real logic in typescript handlers.
install
pnpm add @yaebal/tomlbot.toml
all route arrays are optional. an empty config is valid and registers nothing. every route must
define at least reply or handler.
[bot]
name = "demo"
[[commands]]
name = "start"
description = "start command"
reply = "привет! я бот из toml."
[[commands]]
name = "ping"
handler = "ping"
[[hears]]
text = "ping"
reply = "pong"
[[messages]]
on = "message:text"
contains = "yaebal"
reply = "yaebal мощь"
[[callbacks]]
data = "profile"
handler = "profileCallback"usage
call installToml once before bot.start(). it accepts a file path,
a raw toml string, or an already parsed object, and returns the same bot or composer instance.
import { Bot } from "@yaebal/core";
import { installToml } from "@yaebal/toml";
const bot = new Bot(process.env.BOT_TOKEN!);
await installToml(bot, "./bot.toml", {
handlers: {
ping: async (ctx) => {
await ctx.reply("pong from typescript");
},
profileCallback: async (ctx) => {
await ctx.reply("profile");
},
},
});
await bot.start();handler registry
handler = "name" looks up options.handlers.name. if the handler is
missing, installation fails with a readable startup error instead of silently skipping the route.
| toml | registered as |
|---|---|
[[commands]] name = "start" reply = "hi" | bot.command("start", ctx => ctx.reply("hi")) |
[[hears]] text = "ping" reply = "pong" | bot.hears("ping", ...) |
[[messages]] on = "message:text" contains = "x" | bot.on("message:text", ...) plus a text filter |
[[callbacks]] data = "profile" handler = "profile" | bot.callbackQuery("profile", handlers.profile) |
handler and reply are present, the handler wins. the reply is
only used when no handler is configured. example errors:
Missing handler "ping" referenced in commands[1], commands[0] must define either reply or handler, messages[0].on is required.plugin usage
createTomlPlugin returns a normal yaebal plugin, so it can be installed through bot.install() or composed with other feature modules.
import { createTomlPlugin } from "@yaebal/toml";
bot.install(createTomlPlugin("./bot.toml", { handlers }));api
| export | signature | description |
|---|---|---|
installToml | (bot, configPathOrObject, options?) => bot | parse, validate and register routes on an existing bot or composer |
createTomlPlugin | (configPathOrObject, options?) => Plugin | create a yaebal-compatible plugin that installs the toml routes |
parseTomlConfig | (input) => TomlBotConfig | parse from file path, raw toml string or parsed object, then validate |
validateTomlConfig | (input) => TomlBotConfig | runtime validation through zod with human-readable error paths |
raw strings and objects
file paths are the common case, but tests and generated configs can pass raw toml or an object.
import { parseTomlConfig, validateTomlConfig } from "@yaebal/toml";
const config = parseTomlConfig(`[[commands]]
name = "start"
reply = "hi"
`);
validateTomlConfig(config);limits
toml is not a replacement for typescript. use it for routes and simple replies; use the handler registry for database calls, external services, branching flows, permissions and anything that needs compile-time types.