ti-hooks
v1.3.3
Published
ti-hooks: proxy de webhooks com túnel WebSocket — recebe eventos em URL pública e entrega em apps locais, com fila, ack e histórico
Maintainers
Readme
ti-hooks
Receba webhooks de produção/sandbox (Asaas etc.) na sua máquina local, sem ngrok e sem mexer no painel da origem a cada dev.
Funciona como pub/sub: cada hook tem uma URL pública única (cadastrada uma vez na origem) e N assinantes. Todo evento é entregue a todos os assinantes (fan-out), cada um com fila, retry e histórico independentes — a entrega em localhost atravessa um túnel WebSocket que o CLI abre da sua máquina.
Origem (Asaas etc.) ──▶ https://<proxy>/webhook/<hook>/<token>
│ fan-out
┌───────────────┼────────────────┐
túnel do joão túnel da maria fila do CI (offline)
▼ ▼
localhost:4000 localhost:3300 entrega quando abrirSe o seu túnel estiver fechado, os eventos ficam na fila e descem quando você conectar. Se a sua app recusar (500, caiu), o proxy re-tenta com backoff até 10 vezes e depois guarda como failed — reprocessável com um comando.
Começar (dev)
O admin vai te passar três coisas: a URL do proxy da equipe (ex.: wss://hooks.ti.dev.br), o nome do hook (ex.: asaas) e o joinCode (código de convite). Com elas em mãos, na pasta em que for trabalhar:
npm i -g ti-hooks # requer Node 20.17+ — recomendado 22 LTS (Mac, Windows ou Linux)
ti-hooks # primeiro uso: o assistente pergunta as 3 coisas + seu nome
# e a URL da sua app local, grava o .env e já abre o túnelPrefere sem assistente? O mesmo, em uma linha:
PROXY_URL=wss://hooks.ti.dev.br ti-hooks subscribe asaas <joinCode> seu-nome http://localhost:4000/webhooksNos dois casos tudo fica salvo no .env da pasta — daqui em diante os comandos não pedem mais nada. Dia a dia:
Navegação do menu: ⏎ seleciona · esc volta · ctrl+c sai — em qualquer tela.
ti-hooks # menu interativo (túnel, log, eventos, teste)
ti-hooks tunnel-bg # abre o túnel em segundo plano
ti-hooks logs -f # acompanha as entregas ao vivo
ti-hooks events <hook> # histórico do seu hook: ✓ entregues · ● fila · ✗ falhos
ti-hooks resend <hook> <id> # reprocessa um evento seu
ti-hooks test <hook> # dispara um evento de teste
ti-hooks stop # fecha o túnel
ti-hooks unsubscribe <hook> <seu-nome> # cancela sua assinaturaSem ADMIN_TOKEN no .env, o CLI opera em modo dev: o token da sua assinatura autentica você nos comandos do seu hook; assinaturas de outros devs e administração ficam bloqueadas. Estado do túnel: ~/.ti-hooks/.
Administrar (admin)
Com ADMIN_TOKEN no .env (o mesmo do servidor), o CLI libera tudo. Para promover alguém a admin, envie o token por canal seguro e a pessoa roda:
ti-hooks admin <ADMIN_TOKEN> # valida no servidor e grava no .env da pasta⚠️ O token é único e dá poder total (criar/remover hooks, ver tokens de todos). Revogar alguém = trocar o ADMIN_TOKEN no servidor e reenviar aos demais admins.
ti-hooks add <hook> [targetUrl] # cria hook → retorna webhookUrl (p/ origem) e joinCode (p/ devs)
ti-hooks list # hooks, assinantes, joinCodes, filas
ti-hooks list-con # só os túneis conectados
ti-hooks events <hook> # histórico com o status POR assinante
ti-hooks resend <hook> <id> [assinante]
ti-hooks unsubscribe <hook> <nome> # remove assinatura de qualquer dev
ti-hooks delete <hook> # remove o hook inteiro
ti-hooks tunnel-bg # seu túnel (usa sua assinatura "default", criada com o hook)Regra do targetUrl: a entrega usa sempre o destino do assinante; o do hook (raiz) é só o padrão herdado por quem assina sem informar o seu.
API
| Método | Rota | Auth | Descrição |
|---|---|---|---|
| POST | /registrations | x-admin-token | Cria hook; gera inboundToken e joinCode |
| GET | /registrations | x-admin-token | Lista hooks e assinantes |
| POST | /hooks/:slug/join-info | joinCode no body | Valida o código e revela o destino padrão do hook |
| POST | /hooks/:slug/subscribe | joinCode no body | Cria assinatura; retorna o token do assinante |
| DELETE | /hooks/:slug/subscribers/:name | admin ou o próprio | Remove assinatura (descarta a fila dela) |
| POST | /registrations/:slug/test | admin ou x-tunnel-token | Evento de teste pelo caminho real |
| GET | /registrations/:slug/events | admin ou x-tunnel-token | Histórico (admin: por assinante; dev: só o seu) |
| POST | /registrations/:slug/events/:id/resend | admin ou x-tunnel-token | Reprocessa (?subscriber= p/ um só) |
| DELETE | /registrations/:slug | x-admin-token | Remove o hook inteiro |
| POST/PUT/PATCH | /webhook/:slug/:inboundToken | token na URL | Recebe o webhook e faz o fan-out |
| GET | /health | — | { ok, agents: ["hook/assinante", ...] } |
slug é o identificador técnico do hook na API. O proxy repassa todos os headers intactos — validação fim-a-fim (ex.: asaas-access-token) é da aplicação destino.
Garantia de entrega
At-least-once por assinante: o proxy só marca delivered com confirmação 2xx (ack do agent pelo túnel). Falha ou 30s sem ack → volta pra fila com backoff, até 10 tentativas → failed (dead letter), reprocessável via resend. Fila aguardando túnel fechado não gasta tentativas.
Rodar o seu próprio proxy
O pacote inclui o servidor: npm run server (ou pm2 via npm run deploy). Persistência em JSON no data/ (registrations, filas por assinante e histórico com retenção de 200 eventos/30 dias por hook).
Variáveis do servidor (.env): PORT (3207), HOST, ADMIN_TOKEN (obrigatória), DATA_DIR e as opcionais MAX_ATTEMPTS (10), ACK_TIMEOUT_MS (30000), RETRY_SWEEP_MS (30000), HISTORY_RETENTION_DAYS (30). Na máquina local: PROXY_URL, ADMIN_TOKEN (admin) ou TUNNELS=hook:token[,...] (dev — o subscribe preenche sozinho).
Guia completo de operação (infra, deploy, troubleshooting) e collection do Bruno: no repositório, em docs/.
Licença
MIT
