Migrating
0.3.0 → 0.3.1
Two small breaking changes, both from easytg dropping Node-only APIs so it also runs in browsers.
verifyInitDataSignaturereturns a promise. It checks Telegram's Ed25519 signature with Web Crypto, which is async: addawait.tsconst init = verifyInitDataSignature(initData, botId); // 0.3.0 const init = await verifyInitDataSignature(initData, botId); // 0.3.1TypeScript points you to every call whose result is used directly.
verifyInitData(with the bot token) stays synchronous.Node.js 20 or newer. easytg uses the global
crypto(Web Crypto) for random ids and Ed25519. Bun and Deno are unaffected.
Nothing stored changes: signed buttons, stored button params, deep links and file id cache keys are computed exactly as before, so buttons in old messages keep working.
0.2 → 0.3
0.3 adds a lot (storage adapters, scheduled tasks, queues, i18n, payments, several processes) and makes the API more consistent, which breaks a few things. Most of them are type errors, so TypeScript points you to them.
Durations are milliseconds everywhere
| 0.2 | 0.3 |
|---|---|
session: { ttlSeconds: 3600 } | session: { ttlMs: 3600_000 } |
buttons: { ttlSeconds }, deepLinks: { ttlSeconds } | buttons: { ttlMs }, deepLinks: { ttlMs } |
session.set(key, value, { ttlSeconds: 300 }) | session.set(key, value, { ttlMs: 300_000 }) |
retryAfter(error) (seconds) | retryAfterMs(error) (ms) |
Custom storage adapters: the third argument of set is now a TTL in milliseconds (it was seconds), and may be below one second. Convert it where you pass it to your database (Redis: PX instead of EX), then run verifyStorageAdapter(adapter, { ttlMs: 200 }), which now takes options { keyPrefix?, ttlMs? } instead of a key-prefix string. (The one duration still in seconds is telegramError(…, { retryAfter }) in easytg/testing, because it mirrors Telegram's retry_after field.)
Renamed
| 0.2 | 0.3 |
|---|---|
isBlockedByUser(error) | isChatUnreachable(error) |
examples/storage/sqlite.ts (copy) | SqliteStorage from easytg, taking an open database: new SqliteStorage(new Database('bot.sqlite')). Same table, your data stays readable. |
Changed behaviour
limitUser,releaseUser,isLimitedreturn promises (limits can live in a shared storage):await app.isLimited(id).- A limited user's updates are all dropped, not only the ones that count towards the limit (group chatter, inline queries…). Payments still pass.
exemptusers are never counted, but a manuallimitUsernow applies to them too. The rate-limit window starts with the first interaction (it was sliding). - Updates of one user are handled one at a time (
sequential, on by default, waits at most 8 s). Setsequential: falsefor the 0.2 behaviour. - Button params:
falseleaves the param out (it arrived as the truthy string"false").nav.startDialogue(d, { id: 42 })passes"42", like a button does.nav.redirectandnav.startDialogueno longer accept button options as a third argument (they were ignored). MemoryStoragestores JSON, like SQLite and Redis: aDatein a session comes back as a string, aMapas{}, andset(key, undefined)throws. Tests now catch what production would break on.- Code keeps its backslashes: in
`code`and code blocks only\\and\`are escapes, so`\d+`shows\d+(0.2 removed the backslash). - Defining a handler twice throws:
onText,steps,onFinishandonCancel(likerenderalready did). dialogueCancelreasons:app.cancelDialoguenow reports'app'(was'command'), and dialogues with a timeout report'timeout'. Update exhaustiveswitches overreason.dialogue()without a type argument now infers the answers from the steps. Code that relied onanswersbeinganymay now see precise types (and catch misspellings); steps built in a loop stay untyped. If you annotate theDialoguetype yourself, its first type argument defaults toAutonow.easytg/testing: the fake API answerssendChatActionwithtrue, so chat actions no longer use up message ids; tests that assert exact message ids may shift.app.broadcastsends up to 5 messages at once (concurrency), so recipients aren't served strictly in list order.concurrency: 1restores the 0.2 behaviour.
Built-in texts
If you translate EasyTGTexts in full (like examples/locales/id.ts):
- add
adminOnly(used byrequireChatAdmin),openWebAppandexpectWebApp(thewebAppdialogue step); collectReceivedandcollectLimitreceive the Done button's label:collectReceived: ({ total, done }) => …,collectLimit: ({ max, done }) => …(collectLimittook a number).
Docs
docs/guide.md is split into one page per feature; start at docs/README.md.