Pular para o conteúdo principal
O sistema de plugins permite estender o WaClient sem fazer fork dele. Um plugin pode conectar-se ao pipeline de stanzas de entrada, expor seu próprio coordinator em client[exposeAs], contribuir com eventos tipados em client.on e fazer limpeza no disconnect — tudo com inferência completa de TypeScript, sem augmentation global de módulo. @zapo-js/voip é a implementação de referência; veja o guia de VoIP para o que parece um plugin finalizado.

O que é um plugin

Cada plugin é um valor WaClientPluginDefinition passado pela opção plugins:
Há dois sabores:
  • Plugins de comportamento rodam efeitos colaterais (registram handlers de stanza, ouvem eventos, agendam trabalho) e não expõem nada no client.
  • Plugins de exposição também publicam um valor em client[exposeAs] — tipicamente um objeto coordinator, como client.voip.
Ambos os sabores podem contribuir com eventos tipados que aparecem em client.on / client.once / client.off apenas quando o plugin está no array plugins. A inferência é derivada do valor: se o plugin não estiver instalado, o nome do evento não existe no tipo do client.

Autoria de um plugin

Use defineWaClientPlugin para autoria com tipos seguros. Ele tem duas sobrecargas.

Plugin de comportamento

Plugin de exposição

A sobrecarga de exposição recebe três parâmetros de tipo: a chave exposeAs como literal string, o tipo do valor retornado por setup e o mapa de eventos. A inferência flui do valor de volta para client.on e client[exposeAs]:
Depois de conectar metricsPlugin() em plugins, client.metrics é tipado como Metrics e client.on('metrics_tick', ...) é verificado contra MetricsEvents.
O parâmetro exposeAs é restrito a K extends keyof WaClient ? never : K. Tentar expor um nome que já existe no client — 'message', 'group', 'voip' se voip também estiver instalado — é um erro de TypeScript no call site.

Contexto do plugin

setup recebe um WaClientPluginContext:
ctx.deps é uma API avançada para autores de plugin — novos coordinators podem aparecer em releases minor. Alguns coordinators aninhados acessam material de chaves, então não logue nem persista deps de forma indiscriminada.

Handlers de entrada

registerIncomingHandler({ tag, prepend, handler }) permite interceptar uma tag específica de stanza ('message', 'iq', 'call', 'ack', 'receipt', …). Retorne true de handler para sinalizar que você cuidou da stanza (o core client não vai dar ack novamente); retorne false para deixar o resto do pipeline rodar.
registerIncomingStanzaFilter roda ainda mais cedo e pode descartar stanzas inteiramente.

Extensão de eventos tipados

Plugins encadeiam seus eventos no host client por meio de um marcador fantasma __pluginEvents carregado pelo valor de retorno de defineWaClientPlugin. O terceiro parâmetro genérico é o mapa de eventos:
O tipo de evento do WaClient é derivado da tupla plugins via WaClientPluginEventsFromPlugins. O efeito prático: um evento voip_* existe em client.on apenas quando voipPlugin() está em plugins.
Não há augmentation global de módulo — instalar um WaClient diferente no mesmo projeto não herda eventos de plugins estranhos.

Ciclo de vida

Plugins instalam durante new WaClient(...):
  1. O client é construído e seus coordinators são conectados.
  2. installWaClientPlugins itera o array plugins em ordem. Para cada plugin:
    • O id é verificado contra ids vistos anteriormente.
    • Se exposeAs estiver definido, o nome é verificado contra outros plugins e contra membros existentes do WaClient.
    • setup(ctx) roda. O valor de retorno (para plugins de exposição) é publicado como um getter não-configurável e não-gravável no client.
  3. No client.disconnect(), depois que os handlers de entrada drenam, os callbacks de dispose registrados rodam em ordem reversa (LIFO). Um dispose que lança é logado e o resto ainda roda.
  4. No próximo client.connect(), os plugins são reinstalados do zero — o disconnect() anterior os disposeou, então o connect() roda setup(ctx) novamente. Os accessors client[exposeAs] continuam funcionando entre reconexões (eles resolvem contra a instância de coordinator recém-instalada), e setup vê um contexto limpo a cada vez.

Condições de erro

installWaClientPlugins lança sincronamente durante a construção do client nestes casos:
  • id duplicado"duplicate wa client plugin id: <id>". Cada plugin precisa ter um id único no array plugins.
  • exposeAs duplicado"duplicate wa client plugin exposeAs: <name>". Dois plugins de exposição não podem publicar o mesmo nome.
  • Colisão com um built-in"wa client plugin exposeAs \"<name>\" collides with a reserved client member". Tentar exposeAs: 'message', 'group', 'on', etc. falha em runtime (e em compile time via a guarda keyof WaClient).

Veja também

Guia de VoIP

Faça e receba chamadas do WhatsApp via @zapo-js/voip, o plugin de referência.

Configuração

Onde plugins fica em WaClientOptions.
Última modificação em 12 de julho de 2026