API reference
Everything easytg exports, and every method of the app. Options are listed in Options. All durations are in milliseconds.
Building blocks
| export | |
|---|---|
page<P>(id) | a page: .use(...), .params(parse | schema), .allowDeepLink(), .loading(...), .render(fn), .onText(fn, options) — Pages |
dialogue<A, P>(id) | a multi-step form: .use(...), .steps(...), .onFinish(...), .onCancel(...), .timeout(ms), .loading(...), .allowBack(), .allowDeepLink() — Dialogues |
task<P>(id) | a scheduled job: .run(fn, { maxAttempts, retryDelayMs }) — Scheduled tasks |
withContext<C>() | { page, dialogue, task } bound to your context type |
replyMenu(rows, options) | a main menu on the reply keyboard — Main menu |
md, html, escapeMarkdown, escapeHTML, escapeMarkdownV2 | Text formatting |
escapeRichMarkdown, RichInput | rich content — Rich messages |
defaultTexts | the built-in English texts — Languages |
paginate(args, { total, perPage }) | page numbers for list pages |
requireChatAdmin(options) | middleware: chat admins only — Groups |
isProactive(ctx) | whether a render comes from sendTo & co |
MemoryStorage, SqliteStorage, RedisStorage, withPrefix | Storage |
autoRetry(options) | API transformer for 429s — Error helpers |
verifyInitData, verifyInitDataSignature, miniAppLink, WebAppAuthError | Mini Apps |
mermaidLiveUrl(chart) | a link that opens a diagram in Mermaid Live — Flow map |
Auto | "infer the answers from the steps": dialogue<Auto, Params>(id) — Dialogues |
isChatUnreachable, isMessageNotFound, isTransient, retryAfterMs | Error helpers |
EasyTGError, InvalidParamsError, QueueFullError, QueueTimeoutError | errors easytg throws |
easytg/testing | createTestBot, telegramError, verifyStorageAdapter, verifyTaskStore — Testing |
easytg/simulator | TelegramSimulator, parseHtml, parseMarkdownV2, messageText, richPlainText, richButtons, richHtml — Simulator |
easytg/simulator/load | loadBot, interceptBotApi, trackBots: your bot file against a simulator (Bun, Node) — Preview and recorded tests |
easytg preview <file> (CLI) | your bot file in a simulated Telegram, in the browser — Preview |
easytg/simulator/element | mountChat, EasyTGChatElement (<easytg-chat>), defineChatElement — Simulator |
app methods
Setup
| method | |
|---|---|
new EasyTG(options) | Options |
app.register(...items) | pages, dialogues and tasks |
app.command(names, target, { description, chats, params, ephemeral }) | a /command that opens a page or starts a dialogue — Commands |
app.syncCommands(bot) | Telegram's command menu from the commands with a description |
app.flowchart({ direction, observed }) | the bot's pages, dialogues, commands and the buttons seen, as a Mermaid diagram — Flow map |
bot.use(app) | handle updates; register before your own handlers |
app.on(event, listener) | returns an unsubscribe function — Events |
Showing pages
| method | |
|---|---|
app.open(ctx, page, params?, { mode }) | show a page for an update; returns the sent Message, true for an edited inline message, or undefined |
app.sendTo(bot, target, page, params?) | send a page without an update — Sending without an update |
app.edit(bot, { chatId, messageId }, page, params?) | re-render a page into an existing message; undefined if it can't be edited |
app.broadcast(bot, targets, page, options) | paced sends to many chats |
app.broadcastLater(targets, page, options) | the same, as scheduled tasks that survive restarts; returns { id, batches } |
app.inlineResult(ctx, page, options) | a page as an inline-mode result — Inline mode |
app.answerWebAppQuery(bot, queryId, page, options) | a Mini App puts a page into the chat — Mini Apps |
app.prepareShare(bot, userId, page, options) | a page the user shares from a Mini App — Mini Apps |
app.showMenu(ctx, text) / app.hideMenu(ctx, text) | show or remove the main menu |
app.relay.start(ctx | bot, userA, userB, options) / app.relay.end(…, userId) / app.relay.peer(…, userId) | two users talking through the bot — Relays |
app.answer(ctx, toast?) | answer a button press now (e.g. before slow work) |
app.stream(ctx, source, { finish, stoppable, intervalMs, rich }) | text shown while it is generated (a draft in private chats, a growing message in groups), then sent as a message — Streaming |
app.withLoading(ctx, job, options) | run slow work with "typing…", a placeholder or a toast — Pages |
app.throttle(options) | API transformer keeping sends within Telegram's limits — Scaling |
app.nav(ctx) | a nav outside renders |
app.deepLink(bot, target, params?, { store }) | a t.me/…?start= link |
app.hasPage(id) | whether a page is registered |
Dialogues
| method | |
|---|---|
app.startDialogue(ctx, dialogue, params?) | start one (middlewares run first) |
app.cancelDialogue(ctx) | cancel the active one (reason: 'app'); false if none |
State and language
| method | |
|---|---|
app.session(ctx) | the user's session in this chat — Sessions |
app.userSession(ctx) | the user's session across all chats |
app.chatSession(ctx) | the chat's shared session |
app.flush(ctx) | save now (otherwise done at the end of the update) |
app.withUser(bot, target, fn) | work as a user outside an update (Mini App server, webhooks), saved like an update |
app.t(ctx | locale) | your messages in the user's (or a given) language — Languages |
app.setLocale(ctx, locale) | set the user's language (undefined: automatic) |
app.localeOf(ctx) | the user's language |
app.textsFor(ctx) | easytg's built-in texts in the user's language |
Limits, queues and tasks
| method | |
|---|---|
app.limitUser(userId, ms, botId?) / app.releaseUser(userId, botId?) / app.isLimited(userId, botId?) | manual mutes — Anti-spam |
app.queue(name, job, { ctx }) / app.enterQueue(ctx, name) | concurrency limits — Queues |
app.schedule(task, payload, options) / app.cancelTask(id) | Scheduled tasks |
app.deleteLater(target, messageIds, { delayMs }) | delete messages later |
app.sendLater(target, page, { params, delayMs }) | send a page later |
app.startScheduler(...bots) | run due tasks; returns stop() |
app.runDueTasks(...bots) | run what's due now, once (cron, tests) |