@yaebal/throttle
space out outgoing API calls to stay within Telegram's rate limits — calls are delayed, never dropped.
install
pnpm add @yaebal/throttleusage
call throttle(bot.api) once after constructing the bot. it installs a before hook on the API layer that enforces a minimum gap between consecutive
outgoing calls. no middleware registration needed.
import { Bot } from "@yaebal/core";
import { throttle } from "@yaebal/throttle";
const bot = new Bot(process.env.BOT_TOKEN!);
// space outgoing API calls to ≤ 30/sec (Telegram's global cap)
throttle(bot.api);
bot.on("message:text", (ctx) => ctx.reply("hello!"));
bot.start();custom interval
// tighter limit — one call per 100 ms
throttle(bot.api, { minIntervalMs: 100 });api
| export | signature | description |
|---|---|---|
throttle | (api: Api, options?: ThrottleOptions) => void | installs the throttle hook on bot.api |
reserve | (now: number, next: number, interval: number) => \{ at: number; next: number \} | pure slot-reservation function — exported for testing |
ThrottleOptions | interface | options bag passed to throttle() |
ThrottleOptions
| field | type | default | description |
|---|---|---|---|
minIntervalMs | number | 34 | minimum milliseconds between outgoing API calls (~30 calls/sec, Telegram's global cap) |
how slot reservation works
reserve(now, next, interval) returns the earliest slot at or after now that is at least interval ms after the previous slot. if the bot is idle, the
next call fires at now with no artificial delay. if calls arrive faster than the
interval, they queue up by advancing the next-slot pointer.
import { reserve } from "@yaebal/throttle";
// first call at t=1000 — fires immediately, next slot at 1034
reserve(1000, 0, 34);
// => { at: 1000, next: 1034 }
// second call arrives at t=1000 — queued to slot 1034
reserve(1000, 1034, 34);
// => { at: 1034, next: 1068 }
// call arrives after a long gap — fires immediately at t=2000
reserve(2000, 1068, 34);
// => { at: 2000, next: 2034 }calls are delayed, not dropped. every API call will eventually go through —
throttle only adds a wait, it never discards a request. if your bot sends a large burst it
will drain the queue over time rather than losing messages.
this is a global outgoing rate limit. throttle operates on
the default 34 ms corresponds to Telegram's documented global cap of ~30 messages/second. lower values risk 429 errors; the
this is a global outgoing rate limit. throttle operates on
bot.api and applies to every method call regardless of which user triggered it. for per-user
incoming-update limiting, use @yaebal/ratelimiter instead. the default 34 ms corresponds to Telegram's documented global cap of ~30 messages/second. lower values risk 429 errors; the
@yaebal/again plugin
can handle those automatically if they occur.