Example
Extends
EventEmitter
Constructors
Constructor
Parameters
Returns
Bot
Overrides
EventEmitter.constructor
Properties
logger
ready
'ready' connection state.
blacklist
'message' event). Ids are matched exactly
against ctx.sender and ctx.from. See AccessList.
whitelist
Methods
on()
Call Signature
listener function to the end of the listeners array for the
event named eventName. No checks are made to see if the listener has
already been added. Multiple calls passing the same combination of eventName
and listener will result in the listener being added, and called, multiple
times.
EventEmitter, so that calls can be chained.
By default, event listeners are invoked in the order they are added. The
emitter.prependListener() method can be used as an alternative to add the
event listener to the beginning of the listeners array.
Type Parameters
Parameters
Returns
this
Since
v0.1.101Overrides
EventEmitter.on
Call Signature
Parameters
Returns
this
Overrides
EventEmitter.on
once()
Call Signature
listener function for the event named eventName. The
next time eventName is triggered, this listener is removed and then invoked.
EventEmitter, so that calls can be chained.
By default, event listeners are invoked in the order they are added. The
emitter.prependOnceListener() method can be used as an alternative to add the
event listener to the beginning of the listeners array.
Type Parameters
Parameters
Returns
this
Since
v0.3.0Overrides
EventEmitter.once
Call Signature
Parameters
Returns
this
Overrides
EventEmitter.once
off()
Call Signature
emitter.removeListener().
Type Parameters
Parameters
Returns
this
Since
v10.0.0Overrides
EventEmitter.off
Call Signature
Parameters
Returns
this
Overrides
EventEmitter.off
emit()
Call Signature
eventName, in the order they were registered, passing the supplied arguments
to each.
Returns true if the event had listeners, false otherwise.
Type Parameters
Parameters
Returns
boolean
Since
v0.1.26Overrides
EventEmitter.emit
Call Signature
Parameters
Returns
boolean
Overrides
EventEmitter.emit
start()
Returns
Promise<void>
stop()
Parameters
Returns
Promise<void>
send()
before('send')/after('send') hook
pipeline; a before('send') hook may mutate payload.content or abort() to skip.
Parameters
Returns
Promise<SentMessage<unknown>>
enqueue()
BotConfig.durability): runs the before('send')
hooks, journals the send and returns its outbox key at once; the background sweeper
delivers it (retries, backoff, dead-letter queue). Enqueueing an idempotencyKey that
already exists is a no-op (status: 'exists') — use it for campaigns and scheduled
jobs that may run twice. A text over the channel’s limit is split after the hooks
(BotConfig.splitLongText) into one record per part: key, key#2, ….
Parameters
Returns
Promise<{
key: string;
status: "exists" | "queued" | "skipped";
}>
Example
sendText()
send(chatId, text).
Parameters
Returns
Promise<SentMessage<unknown>>
Deprecated
Use send:bot.send(chatId, text) (a string is sent as text).
broadcast()
content (a string is sent as text) to many chats: in batches of batchSize
(default 10) with concurrency parallel sends (default 1), pausing delayBetween
between batches. A RateLimitedError pauses the whole broadcast for its
retryAfterMs and retries that chat (up to retries times after the first send, default 3); other errors
are recorded and the broadcast goes on. Abort signal to stop early — never-attempted
chats come back in pending. bot.stop() cancels it the same way (with drain,
stop waits for its in-flight sends), and a broadcast started on a bot that is not
started (never started, or stopped) sends nothing. Duplicate ids are sent once. Each send takes the normal
outbound path (send hooks, ledger, the provider’s rate limiter) but not the
dispatcher’s per-chat queues, so inbound handling is never blocked; still, launch it
with void (not await) from inside a handler so that chat’s queue is not held.
Parameters
Returns
Promise<BroadcastResult>
Example
trigger()
bot.schedule(), webhooks, admin panels. data seeds
c.state. The start goes through the same gates as a message (blacklist /
whitelist, human handoff) and the chat’s FIFO queue; by default a subject that
already has a live or dormant conversation is left alone (ifActive: 'replace'
cancels it). Resolves once the conversation is entered — not when it ends
(listen to 'conversation:ended' for that). Rejects when name is not registered.
Safe to await from a handler or command of the same chat: the trigger then runs
inline in that message’s queue slot instead of queuing behind it (which would
deadlock the chat). Awaiting a trigger for a DIFFERENT chat whose handlers in turn
await a trigger back into this one can still deadlock — launch those with void.
Before-message hooks, matchers and the 'message' event do not run, and nothing
is persisted for the synthetic inbound (ctx.raw is { synthetic: 'trigger', name }).
Parameters
Returns
Promise<TriggerResult>
Example
metrics()
toPrometheus().
Returns
BotMetricsSnapshot
resetMetrics()
Returns
void
handoff()
chatId over to a human agent. Until resume, the Dispatcher skips
every routing stage for that chat (commands, conversations, dormant resume,
matchers, catch-all) except BotConfig.handoff.allowCommands; inbound messages
are still persisted, hooks still run and the 'message' event still fires.
Active conversations in the chat are cancelled silently and its dormant
checkpoints dropped. Emits 'handoff' and persists the state on
StoredChat.handoff (survives restarts with a persistent store).
The state flips synchronously, so not awaiting is safe. Resolves true if the
chat was not already handed off; never rejects for store failures (they go to
the 'error' event). Throws TypeError synchronously on an empty chat id.
Parameters
Returns
Promise<boolean>
resume()
'resume'
fires and the persisted state is cleared. Resolves true if the chat was handed off.
Parameters
Returns
Promise<boolean>
isHandedOff()
chatId currently handed off to a human?
Parameters
Returns
boolean
getHandoff()
since, reason, meta), or undefined.
Parameters
Returns
HandoffState | undefined
listHandoffs()
Returns
HandoffState[]
sendTo()
before/after('send')
hooks, outbound ledger); it is the same call as send, named for handoff
code. Works whether or not the chat is handed off and never resumes the bot by itself.
Parameters
Returns
Promise<SentMessage<unknown>>
Deprecated
Use send:bot.send(chatId, content, options) (the very same call).
exportAccessLists()
Returns
AccessListsSnapshot
loadAccessLists()
snapshot are left untouched.
Parameters
Returns
this
when()
trigger (text, RegExp, function, type trigger such as
IMAGE, WELCOME, or an array) to a handler or a flow. Returns an unsubscriber.
Parameters
Returns
() =>void
conversation()
opts.trigger (default: name) matches.
ctx is the full MessageContext of the triggering message (ctx.tools, media
helpers, react…); c offers ask/waitText/waitMedia/choose, retry(),
idle()/idleClear(), end(farewell?) and goto(name).
Parameters
Returns
() =>void
Example
enterConversation()
Call Signature
ctx.
To start a REGISTERED conversation or flow, use trigger (the by-name form here is
deprecated).
Fire-and-forget by design: it returns immediately, so a handler can start a
conversation and return, releasing the chat’s FIFO queue for the user’s next
message (which the conversation then receives). Any conversation already active
on that key is replaced. Failures (e.g. an unknown name) are reported through
the 'error' event, never as an unhandled rejection.
The returned promise settles (it never rejects) once the conversation has ended
and released its key. Never await it inside a handler: that blocks the chat’s
queue, so the user’s answer could never reach the conversation.
Parameters
Returns
Promise<void>
Example
Call Signature
Parameters
Returns
Promise<void>
Deprecated
Start a registered conversation with trigger:bot.trigger(name, { chatId: ctx.from, userId: ctx.sender, isGroup: ctx.isGroup, ifActive: 'replace' })
(safe to await from a handler of the same chat).
use()
Call Signature
Parameters
Returns
this
Call Signature
Parameters
Returns
this
Deprecated
Plug plugins with plug (bot.plug(plugin)), which also returns the
unsubscriber; use() is for flows.
useFlow()
use(flow), typed for a single flow.
Parameters
Returns
this
Deprecated
Use use (bot.use(flow)), or registerFlow to get the flow id
back and refuse a duplicate id.
command()
/name command (wins over an active conversation). Returns an unsubscriber.
Parameters
Returns
() =>void
onMessage()
bot.on('message', …), the event that observes every
inbound message. Returns an unsubscriber.
Parameters
Returns
() =>void
onType()
when(IMAGE, handler) and the
other type triggers). Returns an unsubscriber.
Parameters
Returns
() =>void
onImage()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('image', handler) or bot.when(IMAGE, handler).
onAudio()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('audio', handler) or bot.when(AUDIO, handler).
onVideo()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('video', handler) or bot.when(VIDEO, handler).
onDocument()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('document', handler) or bot.when(DOCUMENT, handler).
onSticker()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('sticker', handler) or bot.when(STICKER, handler).
onLocation()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('location', handler) or bot.when(LOCATION, handler).
onContact()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('contact', handler) or bot.when(CONTACT, handler).
onPoll()
Parameters
Returns
() =>void
Deprecated
Usebot.onType('poll', handler) or bot.when(POLL, handler).
registerFlow()
use(flow), but refuses a duplicate id).
Returns the flow id. See replaceFlow to hot-swap an existing one.
Parameters
Returns
string
Example
unregisterFlow()
false when unknown.
Parameters
Returns
boolean
replaceFlow()
id (registers it when absent). The new flow keeps
id whatever its own id is; its trigger replaces the old one. Running conversations
keep the old version; persisted checkpoints resume on the new steps (by step index).
Parameters
Returns
void
hasFlow()
id.
Parameters
Returns
boolean
listFlows()
kind: 'flow') and async conversation (kind: 'conversation').
Returns
RegisteredFlowInfo[]
triggerFlow()
id proactively in a chat, without an inbound message (the user’s replies
then flow into it as usual). A thin wrapper over trigger with
ifActive: 'replace' — same access-list and handoff gates, per-chat FIFO slot,
language resolution, messaging seams and metrics — so it replaces a conversation
already running (or dormant) on the same key. Resolves false when the flow is
unknown, the subject is refused by the access lists (blacklist / whitelist) or the
chat is handed off; rejects when the bot is not started.
Parameters
Returns
Promise<boolean>
Deprecated
Use trigger:bot.trigger(id, { chatId, userId, isGroup, data, body, ifActive: 'replace' })
(it resolves a TriggerResult; result.started is this method’s boolean).
listConversations()
key, state, waiting, queued).
Returns
ConversationSnapshot[]
abortConversation()
target (a ConversationTarget, e.g. a ctx,
or a raw runtime key from listConversations). Returns false when none is live.
Parameters
Returns
boolean
resetWelcome()
WELCOME trigger so the subject’s next message is treated as a
first contact again (persisted in the store, so it survives restarts).
resetWelcome(dmChatId)— the user of that DM.resetWelcome(groupId, userId)— one participant of a group.resetWelcome(groupId)— every participant of that group.
slashCommandsPlugin calls it on /reset.
Parameters
Returns
Promise<void>
Example
inspectConversation()
c.state, whether it waits for a reply. undefined when
none is active. Diagnostics only — e.g. botmesh dev’s :state command.
Parameters
Returns
|ConversationSnapshot
| undefined
isBusy()
botmesh dev uses it to wait for slow replies when its
input is piped.
Returns
boolean
before()
before hook (higher priority runs first). Chainable. The context is typed
by the event (HookContextMap: MessageContext for 'message',
SendHookContext for 'send', …) plus abort(); a custom event’s context is
unknown unless the handler annotates it (or TCtx is given).
Type Parameters
Parameters
Returns
this
after()
after hook (higher priority runs first). Chainable. Context typed like before.
Type Parameters
Parameters
Returns
this
onError()
error-phase hook: (ctx, error) with the failing context. priority
orders it like before/after (default 0).
Type Parameters
Parameters
Returns
this
hook()
Call Signature
Type Parameters
Parameters
Returns
this
Call Signature
Type Parameters
Parameters
Returns
this
Call Signature
Type Parameters
Parameters
Returns
this
Call Signature
Parameters
Returns
this
plug()
config). Unlike use, returns an
unsubscriber (not the bot: do not chain) that first calls the plugin’s uninstall()
and then removes, newest first, what it registered through ctx.bot: commands,
matchers, conversations/flow triggers, hooks, nested plugins, runtime flows and
onDispose callbacks. Calling it again is a no-op. It does NOT undo event listeners
(on/once), provide()d tools, locale() messages, schedule/every/delay
jobs, onIdle handlers or a flow replaceFlow() overwrote: undo those in
ctx.onDispose() (e.g. ctx.bot.unprovide(name)).
install() should be synchronous. If it throws, whatever it registered so far is
rolled back and the error is rethrown; if it returns a promise that rejects, the
rejection goes to the 'error' event instead of crashing the process.
spec.requires lists plugin names that must already be plugged (a nested plugin may
require its parent); a missing one throws before install() runs. Flows registered
through ctx.bot.registerFlow() (or created by ctx.bot.replaceFlow()) are
unregistered on unplug.
One instance per plugin name: plugging a name that is already plugged throws (unplug
the first instance before plugging it again), unless every instance sets
spec.multiple: true.
config is typed by the plugin (definePlugin<MyConfig>()), so an unknown option or a
wrong type is a compile error.
Type Parameters
Parameters
Returns
() =>void
Throws
when a plugin named inspec.requires is not plugged, or when a plugin
with the same spec.name is already plugged and spec.multiple is not set.
locale()
Call Signature
code, or — with an options
object — configure i18n (defaultLocale, detect, providerLanguage,
userKey, locales). Either form turns on per-message language resolution:
ctx.user preference → provider-reported language → detect → default,
limited to the locales allow-list when one is set.
Keys nest (ctx.t('menu.title')), {param} placeholders are interpolated
and { one, other, zero? } leaves pick a plural form from params.count.
The built-in core messages live under core.* (es and en ship) and
can be overridden here. Throws TypeError on an invalid code or message tree.
Parameters
Returns
this
Example
Call Signature
code, or — with an options
object — configure i18n (defaultLocale, detect, providerLanguage,
userKey, locales). Either form turns on per-message language resolution:
ctx.user preference → provider-reported language → detect → default,
limited to the locales allow-list when one is set.
Keys nest (ctx.t('menu.title')), {param} placeholders are interpolated
and { one, other, zero? } leaves pick a plural form from params.count.
The built-in core messages live under core.* (es and en ship) and
can be overridden here. Throws TypeError on an invalid code or message tree.
Parameters
Returns
this
Example
t()
lang defaults to the
default locale. Pair it with langOf to use a user’s stored preference.
Parameters
Returns
string
langOf()
userId (ctx.setLang) when a registered locale
serves it, else the default locale — the same language ctx.lang would resolve from
the stored value (always the default while i18n is off). A store read failure
resolves the default (logged at debug level).
Parameters
Returns
Promise<string>
locales()
es/en included.
Returns
string[]
provide()
value as ctx.tools[name] in every handler (replacing a previous value under
the same name). Returns the bot, so calls can be chained. Undo it with unprovide.
Type Parameters
Parameters
Returns
this
unprovide()
name by provide (the inverse of provide, as
unregisterFlow is of registerFlow). Returns true when a tool was removed,
false when none was provided under that name. Unplugging a plugin does not undo its
provide() calls: call this from ctx.onDispose().
Parameters
Returns
boolean
schedule()
Call Signature
fn on a cron expression (e.g. '0 9 * * *').
Parameters
Returns
ScheduledTask
Call Signature
opts.id (see BotConfig.scheduler),
survives restarts with the opts.missed policy, and each occurrence runs on one replica.
Parameters
Returns
ScheduledTask
Call Signature
bot.schedule('0 9 * * 1-5', { timeZone: 'America/Bogota' }, fn)
(see CronTaskOptions for the daylight-saving rules). Add an id to make it durable.
Parameters
Returns
ScheduledTask
every()
Call Signature
fn every interval (a duration such as '10m', or ms).
Parameters
Returns
ScheduledTask
Call Signature
Parameters
Returns
ScheduledTask
delay()
Call Signature
fn once after duration (a duration such as '30s', or ms).
Parameters
Returns
ScheduledTask
Call Signature
opts.id is first stored, so a
restart does not push it back, provided the code registers the id again at boot (only
the schedule is stored, not the handler). See the durable schedule overload.
Parameters
Returns
ScheduledTask
forgetTask()
id (the bot’s store namespace is
applied, as on registration): an orphan logged at start (stored, no longer registered
in code), a one-shot tombstone, or a registered task, which is cancelled as well.
Parameters
Returns
Promise<void>
onIdle()
handler once when a chat stays quiet for duration ('10m', '1h', '1d', ms…) after
its last processed inbound message. Every new inbound message from that chat reschedules it,
and re-arms it after it fired. ctx is that last message’s context, so
ctx.reply('¿Sigues ahí?') answers in the right chat. Handler errors go to the bot
'error' event. Pending timers are cancelled by clearIdle, by the returned
unsubscribe and by stop(). The handler never runs for a chat in human handoff: a
'handoff' event carrying { chatId } cancels that chat’s timers, and its messages do not
re-arm them until a 'resume' event for that chat (the bot’s own isHandedOff() state is
honoured too, when present). duration must be positive and at most 2^31 − 1 ms (about
24.8 days, the longest a Node timer can wait); otherwise it throws RangeError.
Parameters
Returns
() =>void
Example
clearIdle()
chatId (every chat when omitted) — e.g. when a
human agent takes the chat over. They re-arm on that chat’s next processed inbound message.
Parameters
Returns
void
getStore()
Returns
IStore
getProvider()
Returns
IProvider
getConnectionState()
Returns
ConnectionState
getNamespace()
Returns
Readonly<StoreNamespace>
getSessionName()
Returns
string
user()
ctx.user when that subject writes (scheduled jobs, webhooks, admin code).
Requires a store implementing the user-data contract (every built-in one).
Parameters
Returns
UserData
Example
purgeExpiredUserData()
ctx.user entries store-wide and resolve with
how many were removed (0 with native-TTL stores such as Redis). Writes
already trigger this at most once a minute; schedule it for idle bots:
bot.every('1h', () => bot.purgeExpiredUserData()).
Returns
Promise<number>
exportSubject()
Parameters
Returns
Promise<SubjectDataExport>
deleteSubject()
userId and the subject’s live or dormant conversations.
Parameters
Returns
Promise<SubjectDeletionResult>
flowInventory()
describeFlows()/lintFlows().
Returns
FlowInventory
describe()
Call Signature
{ format: 'json' }, as a JSON graph. See describeFlows.
Parameters
Returns
FlowGraph
Example
Call Signature
{ format: 'json' }, as a JSON graph. See describeFlows.
Parameters
Returns
string
Example
Call Signature
{ format: 'json' }, as a JSON graph. See describeFlows.
Parameters
Returns
string | FlowGraph
Example
lint()
Parameters
Returns
LintDiagnostic[]
Example
Accessors
durability
Get Signature
undefined unless BotConfig.durability is set.
Example
Returns
DurabilityControl | undefined
tracing
Get Signature
BotConfig.telemetry): start your own spans under the bot’s, or
check enabled. Plugins (@botmesh/ai) use it to add their spans to the same trace.
Without telemetry it is a disabled no-op (BotTracing.enabled false).
Example
Returns
BotTracing
injectTools
Get Signature
Returns
DefaultTools & Record<string, unknown>