examples
33 runnable bots in the monorepo under examples/. each one is a private workspace package wired to local source, so it
doubles as a live public api smoke test. the table below is generated straight from examples/README.md — it can't drift out of sync with the repo.
# from a clone of the monorepo
pnpm install
# copy an env template, then add BOT_TOKEN
cp examples/commerce-suite/.env.example examples/commerce-suite/.env
# run with reload
pnpm --filter @yaebal/example-commerce-suite devfor the full plugin coverage matrix, see examples/readme.md.
for a standalone project, use create-yaebal.
playground quick tours
these snippets run in-browser with mock telegram updates, then can switch to live mode with a token.
import { InlineKeyboard, callbackData, createBot } from "yaebal";
const choice = callbackData("choice", { value: String });
const bot = createBot(process.env.BOT_TOKEN!);
bot.command("start", (ctx) =>
ctx.reply("pick a path", {
reply_markup: new InlineKeyboard()
.text("ship it", choice.pack({ value: "ship" }))
.text("wait", choice.pack({ value: "wait" }))
.build(),
}),
);
bot.callbackQuery(choice.pattern, async (ctx) => {
const data = choice.unpack(ctx.callbackQuery.data ?? "");
await ctx.answer(data?.value === "ship" ? "shipping" : "holding");
await ctx.editText(`status: ${data?.value ?? "unknown"}`);
});
bot.start();import { createBot, html, md } from "yaebal";
const bot = createBot(process.env.BOT_TOKEN!);
bot.command("start", (ctx) =>
ctx.reply(html`<b>hello</b>, ${ctx.from?.first_name ?? "friend"}
<code>no parse_mode needed</code>`),
);
bot.command("md", (ctx) =>
ctx.reply(md`**bold**, *italic*, __underline__ and ~~strike~~
> a quoted line`),
);
bot.start();import { createBot } from "yaebal";
const bot = createBot(process.env.BOT_TOKEN!);
bot.command("launch", async (ctx) => {
await ctx.sendPhoto("https://picsum.photos/seed/yaebal/640/360", {
caption: "release image by url",
});
await ctx.sendPoll("ship today?", ["yes", "hold"]);
});
bot.start();example catalog
roughly ordered simple → advanced: a bare-core echo bot first, single-plugin demos in the middle, multi-plugin product bots last.
| example | package | focus | run | try it |
|---|---|---|---|---|
| core-echo | @yaebal/example-core-echo | bare @yaebal/core: middleware, filter narrowing, format, raw typed api.call | pnpm --filter @yaebal/example-core-echo dev | — |
| basic | @yaebal/example-basic | whole-stack tour on yaebal: session, keyboard, callback-data, morda, i18n, scenes, prompt, filters, fmt, retry, throttle, cache | pnpm --filter @yaebal/example-basic dev | — |
| again | @yaebal/example-again | awaited retry, retry_after, transient failures, retry metrics | pnpm --filter @yaebal/example-again dev | — |
| ai-chat | @yaebal/example-ai-chat | @yaebal/ai: streamed replies (drafts in private, edits in groups), conversation memory, AiLimitError handling | pnpm --filter @yaebal/example-ai-chat dev | — |
| throttle | @yaebal/example-throttle | outbound buckets, priorities, cancellation, scheduler metrics | pnpm --filter @yaebal/example-throttle dev | — |
| broadcast | @yaebal/example-broadcast | typed broadcast jobs, pause, resume, cancel, retry, progress | pnpm --filter @yaebal/example-broadcast dev | broadcast-queue |
| cron | @yaebal/example-cron | intervals, cron expressions with per-job tz, retries + backoff, timeoutMs, overlap: "wait", catch-up via a persisted store, ctx.cron, cronAdmin ops commands | pnpm --filter @yaebal/example-cron dev | cron-admin,cron-digest |
| keyboard | @yaebal/example-keyboard | inline and reply keyboard builders, every button type, request user/chat/managed bot | pnpm --filter @yaebal/example-keyboard dev | keyboard-callback,reply-keyboard |
| auto-answer | @yaebal/example-auto-answer | "deadline" default racing a handler's own alert, fallback ack on a forgotten handler, skipAutoAnswer(), filter() | pnpm --filter @yaebal/example-auto-answer dev | auto-answer-deadline,auto-answer-skip |
| guards | @yaebal/example-guards | safe guard+getChatMember pattern, membership() caching, guardOr answering a denial, bot's own permission check, anonymous admin/owner | pnpm --filter @yaebal/example-guards dev | guards-private |
| commands | @yaebal/example-commands | typed command registry: localized menus, scopes, aliases, hidden commands, diff-based sync | pnpm --filter @yaebal/example-commands dev | — |
| ephemeral | @yaebal/example-ephemeral | ephemeral menu commands (is_ephemeral), ctx.replyEphemeral() in groups, handle edits/deletes, wrapEphemeralMessage from a callback, private-chat fallback | pnpm --filter @yaebal/example-ephemeral dev | — |
| pagination | @yaebal/example-pagination | lazy sources (count + limit+1 probing), item buttons with onSelect, typed payload, button() menu morphing and back-navigation, ownership filter | pnpm --filter @yaebal/example-pagination dev | pagination-list,pagination-select |
| session | @yaebal/example-session | session v2: dirty-checked saves, file storage, two independent sessions (key + keyBy.user), ttl() fields, clearSession, migrations | pnpm --filter @yaebal/example-session dev | session-counter,session-v2 |
| simple | @yaebal/example-simple | toml route config plus typescript handlers | pnpm --filter @yaebal/example-simple dev | — |
| onboarding | @yaebal/example-onboarding | first-run product tour, force restart, dismiss, opt-out | pnpm --filter @yaebal/example-onboarding dev | — |
| feature-flags | @yaebal/example-feature-flags | percentage rollout, kill-switch rule, chat-type targeting, multivariate (A/B/n) flag, per-bucket + global overrides with ttl, envProvider, whenFlag branch, flagsAdmin ops commands | pnpm --filter @yaebal/example-feature-flags dev | feature-flags-override,feature-flags-variants |
| audit-log | @yaebal/example-audit-log | correlated, redacted-by-default structured logging, applyRedaction, memorySink, chatSink, auditAdmin ops commands | pnpm --filter @yaebal/example-audit-log dev | audit-log-basic |
| analytics | @yaebal/example-analytics | typed event catalog, autoTrack (commands/callbacks/messages), ctx.identify, context() enricher, multiple adapters, analyticsAdmin ops commands | pnpm --filter @yaebal/example-analytics dev | analytics-admin,analytics-auto-capture,analytics-track |
| rich-messages | @yaebal/example-rich-messages | rich blocks, markdown/html builders, fake streaming draft, rich message readback | pnpm --filter @yaebal/example-rich-messages dev | rich-ai |
| panel | @yaebal/example-panel | operator dashboard, media viewer, callbacks, outgoing replies, realtime events | pnpm --filter @yaebal/example-panel dev | — |
| commerce-suite | @yaebal/example-commerce-suite | shop bot with session cart, i18n, pagination, commands, callback-data, ratelimiter | pnpm --filter @yaebal/example-commerce-suite dev | — |
| dialog-quest | @yaebal/example-dialog-quest | morda cockpit, scene wizard, prompt, conversation, session profile | pnpm --filter @yaebal/example-dialog-quest dev | wizard-form,conversation-prompt,conversation-wizard,scenes-buttons,scenes-wizard |
| state-machine | @yaebal/example-state-machine | typed events driving transitions, a guard you can trip interactively, per-state onEnter hooks, reset() | pnpm --filter @yaebal/example-state-machine dev | state-machine-order |
| morda-jsx | @yaebal/example-morda-jsx | jsx screens with hooks: persisted useState/useEffect, useDialogData, widgets (Toggle/Select/Counter/Pagination), onText input | pnpm --filter @yaebal/example-morda-jsx dev | — |
| media-studio | @yaebal/example-media-studio | albums, file metadata + links, file_id introspection, media cache, svg previews, entity-aware long message splitting + caption strategy | pnpm --filter @yaebal/example-media-studio dev | — |
| modular-router | @yaebal/example-modular-router | typed define*() file-based routes (commands/on/hears/use), a nested _guard.ts, syncCommands, watchRoutes hot-reload | pnpm --filter @yaebal/example-modular-router dev | — |
| webhook-edge | @yaebal/example-webhook-edge | serve() on node, sequentialize + dedupe, setWebhook / getWebhookInfo, secret token, path routing | pnpm --filter @yaebal/example-webhook-edge dev | webhook-ready |
| runner-workers | @yaebal/example-runner-workers | concurrent polling and worker thread offload | pnpm --filter @yaebal/example-runner-workers dev | — |
| testing-lab | @yaebal/example-testing-lab | bot factory plus actor-driven tests | pnpm --filter @yaebal/example-testing-lab test | — |
| inline-search | @yaebal/example-inline-search | core + @yaebal/contexts layering: contextFor, inline.answer(), pagination offset, chosen-result analytics | pnpm --filter @yaebal/example-inline-search dev | inline-mode |
| payments-stars | @yaebal/example-payments-stars | telegram stars invoices, pre-checkout approval, successful payment, refund | pnpm --filter @yaebal/example-payments-stars dev | payments-stars |
| mini-app | @yaebal/example-mini-app | HMAC + Ed25519 initData validation, Authorization: tma backend, answerWebAppQuery, web_app_data, direct/attachment-menu links | pnpm --filter @yaebal/example-mini-app dev | — |
patterns to copy
| pattern | copy from |
|---|---|
| bare core, no plugins | core-echo |
| core + contexts by hand | inline-search |
| single-file product demo | basic |
| plugin in isolation | again, throttle, keyboard, auto-answer, guards, commands, ephemeral, onboarding, rich-messages, state-machine |
| production operator tooling | broadcast, panel, webhook-edge, runner-workers |
| business workflow | commerce-suite, payments-stars, inline-search |
| multi-step ux | dialog-quest, testing-lab |
| media-heavy workflow | media-studio |
| large codebase routing | modular-router, simple |
tests
every example has a test script. most examples typecheck as no-network smoke tests; testing-lab runs real actor-driven tests with @yaebal/test.
# smoke-test every example workspace
pnpm -r --filter "./examples/*" run test
# run the actor-driven test example only
pnpm --filter @yaebal/example-testing-lab testplugin packages keep focused tests under
packages/*/src/*.test.ts; examples prove the
public imports still compose in real bot shapes.