feat(examples): add emulated variant of telegram-chat reference bot - #411
feat(examples): add emulated variant of telegram-chat reference bot#411serejke wants to merge 1 commit into
Conversation
Introduce a parallel entry point, src/index.emulated.ts, that runs the
same reference bot against a local emulate.dev Telegram emulator instead
of the real Bot API. Lets contributors exercise the Chat SDK end-to-end
(polling, menu cards, callback_query dispatch, MarkdownV2 rendering,
demo runners) without a BotFather token, a phone, or a Telegram client.
Extract src/bot.ts to share the wiring between the two entries. All
handler registration, demo lookup construction, mention and action
dispatch, and chat.initialize() now live in a single startBot() helper
parameterised by { botToken, userName, apiBaseUrl?, logger? }. The real
entry (src/index.ts) shrinks from 183 lines to ~30 — it only reads env
vars, calls startBot(), and installs SIGINT.
The emulated entry:
1. Spins up a Telegram emulator via createEmulator({service: "telegram"}).
2. Mints a bot, user, and private chat through the test control plane
(createTelegramTestClient → createBot / createUser / createPrivateChat).
These four values — bot token, bot username, user id, chat id —
replace everything a human normally does in BotFather and the
Telegram app.
3. Hands the minted bot to the shared startBot() with apiBaseUrl
pointed at the emulator URL. This is the whole trick: the adapter
already supports a custom API base, so switching from production to
emulated is a single-field change.
4. Drives a scripted interaction from the test client — simulate a DM
("hi bot"), click the "Text & Markdown" menu button, run the first
demo — and dumps each bot-sent message with its inline keyboard via
getSentMessages() so you can see the round-trip in the console.
Why this is useful beyond "look, it works":
- Exercises real code paths on both sides. The Chat SDK runs exactly the
production flow (long-polling getUpdates, update → Message conversion,
thread locking, JSX → MarkdownV2 + inline_keyboard via FormatConverter,
callback-data encode/decode, thread.post → sendMessage). The emulator
stores state, so getSentMessages() is a real oracle, not a mock — if
the bot constructs a malformed message the emulator rejects it,
surfacing a concrete failure instead of a silently-passing mock.
- Closes the loop. Most harnesses stop at "did the SDK issue the right
outgoing call?"; this script feeds the response back in as the next
user action, so bugs in round-trip encoding (callback_data, update_id
offsets, keyboard shape) show up as observable behaviour differences.
- Deterministic and offline. No rate limits, no flaky network, no
BotFather ceremony — runs anywhere with Node ≥ 20 and works in CI.
Adds a start:emulated script to package.json and declares emulate and
@emulators/telegram as dependencies. Known gaps (webhook mode,
real-MarkdownV2 escape-edge fidelity, media chunking, human visual
verification) are out of scope here and would be covered either against
a real bot or via fault injection (tg.injectFault) in follow-ups.
|
@serejke is attempting to deploy a commit to the Vercel Team on Vercel. A member of the Team first needs to authorize it. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Converting to draft — blocked on vercel-labs/emulate#75. Quick note on the Socket scan above: it picked up Once the upstream PR merges and the next |
|
@bensabic I see, the problem is the blocked PR vercel-labs/emulate#75 that I pinged the maintainers to review and push several times (on Twitter too). I'll be ready to fix the comments, if any. Then this PR will be unblocked. If you could prioritize the vercel-labs/emulate#75 that would be great. |
Follow-up to #407. Adds a second entry point for the
telegram-chatexample that runs against a local emulate.dev Telegram emulator — same bot wiring, differentapiBaseUrl.Extracts
src/bot.tswithstartBot({ botToken, userName, apiBaseUrl?, logger? })soindex.ts(real bot) and the newindex.emulated.tsshare all handler registration, demo lookup, andchat.initialize().index.tsdrops from 183 → 29 lines; the emulated entry adds the three-step scripted drive (simulated DM → menu click → demo click) and asserts viagetSentMessages().The Telegram adapter already accepts
apiBaseUrl, so nothing in@chat-adapter/telegramchanges.Dependency
Blocked on vercel-labs/emulate#75, which adds the Telegram emulator and publishes
emulate+@emulators/telegramto npm.pnpm-lock.yamlis intentionally not committed — integrity hashes will be generated against the real tarballs on firstpnpm installpost-release.Test plan
Once upstream is released:
pnpm installpnpm --filter example-telegram-chat typecheckpnpm --filter example-telegram-chat start:emulated— bot sends exactly 3 messages: main menu (msg_id=2, 3 nav buttons), Text & Markdown sub-menu (msg_id=3, 12 buttons),"Hello, this is plain text. No formatting."(msg_id=4)TELEGRAM_BOT_TOKEN=... pnpm --filter example-telegram-chat start