Los 3 tipos
before — antes de procesar
after — después de procesar
onError — cuando algo falla
bot.hook(event, phase, handler, priority?) genérico si
necesitas registrar una fase dinámicamente en lugar de llamar directamente a
before/after/onError.
El error de un handler se emite siempre en bot.on('error', ({ error, ctx }) => ...),
haya o no un hook onError('message') registrado.
Casos de uso
Logging
logIds.
Rate limiting
Filtrar grupos
groupMode, que filtra antes incluso de que corran los hooks.
Bloquear usuarios
bot.blacklist / bot.whitelist:
descartan el mensaje antes incluso de persistirlo y también cubren botones y
llamadas. Ver Handoff y listas de acceso.
Transformar o bloquear mensajes salientes
'send' se dispara en cada envío saliente, ya sea que venga de
ctx.reply/ctx.photo/… o de bot.send. El payload es
{ chatId, content, options } — content es el OutboundContent neutral
de transporte ({ kind: 'text', text }, { kind: 'image', media, caption }, …); mútalo para transformar un mensaje, o aborta para
saltarte el envío por completo:
{ skipped: true } en lugar de rechazar (una
difusión lo cuenta como skipped).
Ediciones y salida en streaming
Algunos payloads llevan una marca para que un hook los distinga de un envío normal:
Un hook puede reescribir
payload.content o hacer abort() en cualquiera de ellos.
Una edición abortada resuelve skipped y no envía un mensaje nuevo en su lugar.
Una edición degradada (el provider no puede editar) sale como un envío normal, sin edit.
abort() — detener el pipeline
abort() detiene los hooks before restantes y el propio evento. Volver sin
next() tiene el mismo efecto; abort() sirve además desde código que no
tiene next a mano (un helper que solo recibe ctx).
Prioridad
Contextos tipados
El contexto que recibe un hook se tipa por el nombre del evento (HookContextMap): 'message' da un MessageContext, 'send' un
SendHookContext ({ chatId, content, options?, stream?, edit? }), 'call'
un CallEvent, 'reaction' un InboundReaction, etc.; los hooks before
reciben además abort(). No hace falta anotar nada:
unknown salvo que anotes el handler, pases el argumento de tipo o amplíes
HookContextMap (declaration merging):
HookHandler<TCtx = unknown> y HookErrorHandler<TCtx = unknown> nombran el
tipo de un handler; un handler tipado para un evento (HookHandler<MessageContext>)
no se puede registrar en otro ('send').
Eventos disponibles
Los eventos de conexión a nivel de provider (
qr, ready, connection,
…) son listeners bot.on(...) normales, no fases de hooks — ver
Conceptos básicos. Lo mismo vale para
'conversation:started' / 'conversation:ended'
(ver Operación).
Siguientes pasos
- Plugins — empaquetar hooks para reutilizar
- Ejemplo: rate limiter — plugin completo