@openvertice/bot-sdk 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -2
- package/dist/src/audio.d.ts +32 -0
- package/dist/src/audio.d.ts.map +1 -0
- package/dist/src/audio.js +47 -0
- package/dist/src/audio.js.map +1 -0
- package/dist/src/cliente.d.ts +213 -0
- package/dist/src/cliente.d.ts.map +1 -0
- package/dist/src/cliente.js +381 -0
- package/dist/src/cliente.js.map +1 -0
- package/dist/src/gateway.d.ts +76 -0
- package/dist/src/gateway.d.ts.map +1 -0
- package/dist/src/gateway.js +299 -0
- package/dist/src/gateway.js.map +1 -0
- package/dist/src/http.d.ts +119 -0
- package/dist/src/http.d.ts.map +1 -0
- package/dist/src/http.js +189 -0
- package/dist/src/http.js.map +1 -0
- package/dist/src/index.d.ts +19 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +16 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/tipos.d.ts +243 -0
- package/dist/src/tipos.d.ts.map +1 -0
- package/dist/src/tipos.js +5 -0
- package/dist/src/tipos.js.map +1 -0
- package/dist/src/voz-wrtc.d.ts +20 -0
- package/dist/src/voz-wrtc.d.ts.map +1 -0
- package/dist/src/voz-wrtc.js +68 -0
- package/dist/src/voz-wrtc.js.map +1 -0
- package/dist/src/voz.d.ts +150 -0
- package/dist/src/voz.d.ts.map +1 -0
- package/dist/src/voz.js +311 -0
- package/dist/src/voz.js.map +1 -0
- package/dist/src/wav.d.ts +29 -0
- package/dist/src/wav.d.ts.map +1 -0
- package/dist/src/wav.js +54 -0
- package/dist/src/wav.js.map +1 -0
- package/package.json +58 -3
- package/src/audio.ts +88 -0
- package/src/cliente.ts +472 -0
- package/src/gateway.ts +354 -0
- package/src/http.ts +249 -0
- package/src/index.ts +41 -0
- package/src/tipos.ts +220 -0
- package/src/voz-wrtc.ts +100 -0
- package/src/voz.ts +407 -0
- package/src/wav.ts +71 -0
- package/src/wrtc.d.ts +4 -0
package/README.md
CHANGED
|
@@ -1,3 +1,190 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@openvertice/bot-sdk`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Escreva um bot para o Vértice: ele entra num canal de texto, responde a
|
|
4
|
+
comandos e — quando você quiser — entra na sala de voz como mais um par da
|
|
5
|
+
malha, publicando áudio de verdade.
|
|
6
|
+
|
|
7
|
+
O contrato do servidor (versão `2026-10`) vive em `server/bots/README.md`, no
|
|
8
|
+
repositório do Vértice. Este pacote é um cliente desse contrato, não uma segunda
|
|
9
|
+
verdade: se os dois discordarem, o servidor está certo.
|
|
10
|
+
|
|
11
|
+
## Instalar
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @openvertice/bot-sdk # texto
|
|
15
|
+
npm i @openvertice/bot-sdk @roamhq/wrtc # texto + voz
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Node **22 ou mais novo**. Para texto, o SDK não tem dependência nenhuma: usa o
|
|
19
|
+
`WebSocket` e o `fetch` do próprio Node. `@roamhq/wrtc` é opcional e só é
|
|
20
|
+
carregado quando alguém usa voz (no Node 24 ele vem com binário pronto —
|
|
21
|
+
verificado: ABI 137, sem compilar nada).
|
|
22
|
+
|
|
23
|
+
## Criar o bot
|
|
24
|
+
|
|
25
|
+
1. Abra o painel administrativo (`VERTICE_ADMIN_PORT` + `VERTICE_ADMIN_SENHA`).
|
|
26
|
+
2. Aba **Bots** → dê um nome, marque os canais de texto (com `escutar`/`falar`)
|
|
27
|
+
e os de voz.
|
|
28
|
+
3. Copie o token `vtb_…` **na hora**: ele aparece uma única vez.
|
|
29
|
+
4. Guarde no `.env` da raiz do pacote (`cp .env.example .env`) — os exemplos
|
|
30
|
+
leem de lá. Rodar `npm run eco` com o token só no arquivo funciona.
|
|
31
|
+
|
|
32
|
+
Se você não quer manter um processo rodando, o painel também gera um **webhook**
|
|
33
|
+
(`POST /api/bots/webhook/<segredo>?canal=CODE`, corpo = texto): serve para
|
|
34
|
+
publicar em nome do bot a partir de outro sistema. É credencial separada do
|
|
35
|
+
token.
|
|
36
|
+
|
|
37
|
+
## Texto
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { Bot } from "@openvertice/bot-sdk";
|
|
41
|
+
|
|
42
|
+
const bot = new Bot({
|
|
43
|
+
token: process.env.VERTICE_BOT_TOKEN!,
|
|
44
|
+
baseUrl: "http://localhost:8080",
|
|
45
|
+
intents: ["MESSAGES"],
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
bot.on("message.created", (m) => {
|
|
49
|
+
if (m.autorBot) return; // sem isso o bot conversa consigo mesmo
|
|
50
|
+
console.log(`${m.autor}: ${m.texto}`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
bot.command("ping", { descricao: "responde pong" }, async ({ responder }) => {
|
|
54
|
+
await responder("pong");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
await bot.start();
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- `bot.on(evento, fn)` — `ready`, `message.created`, `message.deleted`,
|
|
61
|
+
`mention`, `voice.joined`, `voice.left`, `voice.signal`,
|
|
62
|
+
`voice.peer.joined`, `voice.peer.left`, `error`.
|
|
63
|
+
- `bot.command(nome, fn)` / `bot.command(nome, { descricao, canais }, fn)` — o
|
|
64
|
+
prefixo (`!`) é do canal, não do comando. O bot **não** executa os próprios
|
|
65
|
+
comandos.
|
|
66
|
+
- Os comandos registrados são anunciados no `identify`: o cliente completa
|
|
67
|
+
`!to` → `!tocar` no compositor, com a descrição ao lado. Registrar depois de
|
|
68
|
+
`start()` também aparece — sem reconectar (`bot.comandos` é a lista viva).
|
|
69
|
+
- `await bot.enviar("MURAL", "oi")` — devolve o item criado (id, horário).
|
|
70
|
+
- `await bot.enviarVoz("MURAL", wav)` — manda áudio como **mensagem de voz**;
|
|
71
|
+
`enviarArquivo(canal, bytes, { nome, mime })` faz o mesmo como anexo comum.
|
|
72
|
+
- `await bot.historico("MURAL", antesDe?)` e `bot.apagar("MURAL", id)`.
|
|
73
|
+
- `bot.agir(tipo, dados)` — ação crua no gateway (a voz usa por baixo).
|
|
74
|
+
|
|
75
|
+
O SDK cuida do que ninguém quer escrever duas vezes: troca o token por sessão,
|
|
76
|
+
renova antes de vencer, manda batimento, retoma com `resume` e reconecta com
|
|
77
|
+
espera crescente. Token girado, bot desativado ou outra conexão assumindo o
|
|
78
|
+
mesmo bot **não** reconectam: `bot.estado` vira `recusado` e o erro fica em
|
|
79
|
+
`bot.ultimoErro`.
|
|
80
|
+
|
|
81
|
+
## Mensagem de voz (áudio no chat)
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { Bot, wavDeTom } from "@openvertice/bot-sdk";
|
|
85
|
+
|
|
86
|
+
const wav = wavDeTom({ segundos: 1, frequencia: 440 }); // Uint8Array PCM 16 bits
|
|
87
|
+
const mensagem = await bot.enviarVoz("MURAL", wav, { nome: "recado.wav" });
|
|
88
|
+
mensagem.tipo; // "voz"
|
|
89
|
+
mensagem.arquivo?.url; // /chat/arquivos/<id>?exp=…&sig=… (pronta para <audio>)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
O corpo vai cru, com o tipo no cabeçalho — não há multipart. Para um arquivo
|
|
93
|
+
que não seja voz, use `enviarArquivo` (sem `X-Vertice-Tipo`). O limite é o do
|
|
94
|
+
chat (`VERTICE_CHAT_MAX_MB`) e a rajada de 30 mensagens por minuto vale igual.
|
|
95
|
+
|
|
96
|
+
## Ser chamado com `@`
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
bot.on("mention", async (m) => {
|
|
100
|
+
if (m.autorBot) return;
|
|
101
|
+
await bot.enviar(m.sala!, `oi, ${m.autor}!`);
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`mention` chega quando alguém escreve `@login` ou `@nome de exibição` (sem
|
|
106
|
+
caixa nem acento) e o bot tem o canal com `escutar`. Ele **atravessa o prefixo**
|
|
107
|
+
do canal — é o que deixa chamar o bot numa sala de comandos (`!`) sem que ele
|
|
108
|
+
leia a conversa toda. Em canal sem prefixo, `mention` vem junto com
|
|
109
|
+
`message.created` (mesmo `id`): trate como aviso, não como segunda mensagem.
|
|
110
|
+
|
|
111
|
+
## Voz
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { Bot, Voz, criarTransporteWrtc, tocarTom } from "@openvertice/bot-sdk";
|
|
115
|
+
|
|
116
|
+
const bot = new Bot({ token, intents: ["MESSAGES"] });
|
|
117
|
+
await bot.start();
|
|
118
|
+
|
|
119
|
+
const transporte = await criarTransporteWrtc();
|
|
120
|
+
// A track sai da fonte que você alimenta; sem `track` a `Voz` cria outra fonte
|
|
121
|
+
// e o bot publica silêncio.
|
|
122
|
+
const fonte = transporte.criarFonteDeAudio();
|
|
123
|
+
const voz = new Voz(bot, { transporte, track: fonte.createTrack() });
|
|
124
|
+
const parar = tocarTom({ fonte, frequencia: 440 });
|
|
125
|
+
|
|
126
|
+
await voz.entrar("PATIO"); // resolve no `voice.joined`
|
|
127
|
+
voz.sair();
|
|
128
|
+
parar();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
O bot entra **só quando pede** — `start()` nunca entra na voz. O layout dos
|
|
132
|
+
transceivers é o mesmo dos clientes (`audio[0]` = microfone, `audio[1]` = som da
|
|
133
|
+
transmissão, `video[0]` = tela) e a oferta cruzada é resolvida pelo id, como nos
|
|
134
|
+
dois lados. `aoReceberTrack` recebe o áudio dos outros pares, se você quiser
|
|
135
|
+
monitorar ou gravar.
|
|
136
|
+
|
|
137
|
+
`@roamhq/wrtc` exige blocos de **480 amostras** em 48 kHz (10 ms) no
|
|
138
|
+
`RTCAudioSource` — é o que `tocarTom` faz; lendo arquivo, respeite o mesmo
|
|
139
|
+
tamanho.
|
|
140
|
+
|
|
141
|
+
## Exemplos
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm run build
|
|
145
|
+
cp .env.example .env # e edite o VERTICE_BOT_TOKEN
|
|
146
|
+
npm run eco # repete e responde !ping
|
|
147
|
+
npm run radio # !entrar toca um tom na voz
|
|
148
|
+
npm run recado # !recado manda áudio no chat
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Os exemplos carregam o `.env` da raiz do pacote na partida (com o leitor nativo
|
|
152
|
+
do Node — nada de `dotenv`). Variável do ambiente ganha do arquivo, então
|
|
153
|
+
`VERTICE_BOT_TOKEN=vtb_… npm run eco` também funciona — e é o que vale se você
|
|
154
|
+
rodar `node dist/exemplos/eco.js` de outro diretório.
|
|
155
|
+
|
|
156
|
+
## Testes
|
|
157
|
+
|
|
158
|
+
Os testes de fumaça sobem o servidor de verdade (precisa do repositório do
|
|
159
|
+
Vértice ao lado):
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
node testes/fumaca.mjs # dois bots: comando, histórico, apagar, eventos
|
|
163
|
+
node testes/voz.mjs # dois bots na voz: ICE + DTLS fechados, track recebida
|
|
164
|
+
node testes/voz-cliente.mjs # bot ↔ cliente do navegador: SDP nos dois nomes e áudio
|
|
165
|
+
# (o fumaca.mjs também manda um recado de voz e baixa o áudio de volta)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Limites (do servidor, não do SDK)
|
|
169
|
+
|
|
170
|
+
- 30 mensagens por minuto por bot; 1 sessão por minuto (o SDK só pede outra
|
|
171
|
+
quando a atual está para vencer).
|
|
172
|
+
- O bot só vê os canais marcados no painel e, com prefixo, só o que começa por
|
|
173
|
+
ele.
|
|
174
|
+
- Bot não é conta: não aparece na gestão de membros, não recebe cargo e não
|
|
175
|
+
apaga mensagem de outra pessoa.
|
|
176
|
+
|
|
177
|
+
## Publicar no npm
|
|
178
|
+
|
|
179
|
+
O pacote vai para o escopo `@openvertice` como **público** (`publishConfig.access`):
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm login # conta com acesso à org @openvertice
|
|
183
|
+
npm run build # o `prepack` também compila durante o publish
|
|
184
|
+
npm pack --dry-run # confere exatamente o que entra no tarball
|
|
185
|
+
npm publish # @openvertice/bot-sdk@<versão>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
O tarball leva `dist/src` (JS + `.d.ts`), `src` (para os source maps) e este
|
|
189
|
+
README. Testes, exemplos, `.env` e `node_modules` ficam de fora. Para publicar
|
|
190
|
+
uma versão nova: `npm version patch|minor|major` e `npm publish`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FonteDeAudio } from "./voz.js";
|
|
2
|
+
/** Everything `tocarTom` needs in order to publish a sine wave. */
|
|
3
|
+
export interface OpcoesDoTom {
|
|
4
|
+
/** The transport source (`transporte.criarFonteDeAudio()`). */
|
|
5
|
+
fonte: FonteDeAudio;
|
|
6
|
+
/** Frequency in Hz. 440 is concert A. */
|
|
7
|
+
frequencia?: number;
|
|
8
|
+
/** 0…1. Anything above 0.5 starts to clip and distort. */
|
|
9
|
+
amplitude?: number;
|
|
10
|
+
/** 48 kHz: wrtc requires blocks of 480 samples. */
|
|
11
|
+
sampleRate?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Starts playing the tone on the given source.
|
|
15
|
+
*
|
|
16
|
+
* Keep the returned stop function for as long as the bot stays in the room:
|
|
17
|
+
* stopping mid-flight leaves the peer with silence, not with an error — which
|
|
18
|
+
* is exactly what a bot that stops speaking should do.
|
|
19
|
+
*
|
|
20
|
+
* @param options Tone parameters; every field has a sensible default.
|
|
21
|
+
* @returns A function that stops the tone and clears its timer.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const fonte = transporte.criarFonteDeAudio();
|
|
26
|
+
* const parar = tocarTom({ fonte, frequencia: 440, amplitude: 0.15 });
|
|
27
|
+
* // …later, on shutdown:
|
|
28
|
+
* parar();
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function tocarTom({ fonte, frequencia, amplitude, sampleRate, }: OpcoesDoTom): () => void;
|
|
32
|
+
//# sourceMappingURL=audio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../src/audio.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAmB7C,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,KAAK,EAAE,YAAY,CAAC;IACpB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,UAAgB,EAChB,SAAe,EACf,UAAmB,GACpB,EAAE,WAAW,GAAG,MAAM,IAAI,CA2B1B"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Starts playing the tone on the given source.
|
|
3
|
+
*
|
|
4
|
+
* Keep the returned stop function for as long as the bot stays in the room:
|
|
5
|
+
* stopping mid-flight leaves the peer with silence, not with an error — which
|
|
6
|
+
* is exactly what a bot that stops speaking should do.
|
|
7
|
+
*
|
|
8
|
+
* @param options Tone parameters; every field has a sensible default.
|
|
9
|
+
* @returns A function that stops the tone and clears its timer.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const fonte = transporte.criarFonteDeAudio();
|
|
14
|
+
* const parar = tocarTom({ fonte, frequencia: 440, amplitude: 0.15 });
|
|
15
|
+
* // …later, on shutdown:
|
|
16
|
+
* parar();
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function tocarTom({ fonte, frequencia = 440, amplitude = 0.2, sampleRate = 48_000, }) {
|
|
20
|
+
const comDados = fonte;
|
|
21
|
+
// 10 ms per block: it is the frame size of wrtc's RTCAudioSource.
|
|
22
|
+
const quadros = Math.round(sampleRate / 100);
|
|
23
|
+
const passo = (2 * Math.PI * frequencia) / sampleRate;
|
|
24
|
+
const limite = Math.max(0, Math.min(1, amplitude)) * 0x7fff;
|
|
25
|
+
let fase = 0;
|
|
26
|
+
const timer = setInterval(() => {
|
|
27
|
+
const amostras = new Int16Array(quadros);
|
|
28
|
+
for (let i = 0; i < quadros; i += 1) {
|
|
29
|
+
amostras[i] = Math.round(Math.sin(fase) * limite);
|
|
30
|
+
fase += passo;
|
|
31
|
+
if (fase > 2 * Math.PI)
|
|
32
|
+
fase -= 2 * Math.PI;
|
|
33
|
+
}
|
|
34
|
+
comDados.onData({
|
|
35
|
+
samples: amostras,
|
|
36
|
+
sampleRate,
|
|
37
|
+
bitsPerSample: 16,
|
|
38
|
+
channelCount: 1,
|
|
39
|
+
numberOfFrames: quadros,
|
|
40
|
+
});
|
|
41
|
+
}, 10);
|
|
42
|
+
// Without `unref` the process would not exit while the tone plays — and the
|
|
43
|
+
// bot must be able to leave the room and still shut down cleanly.
|
|
44
|
+
timer.unref?.();
|
|
45
|
+
return () => clearInterval(timer);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../../src/audio.ts"],"names":[],"mappings":"AAqCA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,EACL,UAAU,GAAG,GAAG,EAChB,SAAS,GAAG,GAAG,EACf,UAAU,GAAG,MAAM,GACP;IACZ,MAAM,QAAQ,GAAG,KAAsB,CAAC;IACxC,kEAAkE;IAClE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC;IAC5D,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;QACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;YAClD,IAAI,IAAI,KAAK,CAAC;YACd,IAAI,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE;gBAAE,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;QAC9C,CAAC;QACD,QAAQ,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,QAAQ;YACjB,UAAU;YACV,aAAa,EAAE,EAAE;YACjB,YAAY,EAAE,CAAC;YACf,cAAc,EAAE,OAAO;SACxB,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,4EAA4E;IAC5E,kEAAkE;IAClE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAChB,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { ErroDaApi } from "./http.js";
|
|
2
|
+
import { type EstadoDoGateway } from "./gateway.js";
|
|
3
|
+
import type { CanalDeTexto, Descoberta, ServidorIce, Eventos, Intencao, Mensagem } from "./tipos.js";
|
|
4
|
+
/** Everything needed to build a {@link Bot}. */
|
|
5
|
+
export interface OpcoesDoBot {
|
|
6
|
+
/** Bot token (`vtb_…`), copied from the admin panel (Bots tab). */
|
|
7
|
+
token: string;
|
|
8
|
+
/** Server base URL. Default: `http://localhost:8080`. */
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
/** Intents this process wants; the server refuses whatever the panel did not grant. */
|
|
11
|
+
intents?: Intencao[];
|
|
12
|
+
/** Diagnostics: one line per state change. */
|
|
13
|
+
log?: (mensagem: string) => void;
|
|
14
|
+
}
|
|
15
|
+
/** What a command handler receives on every invocation. */
|
|
16
|
+
export interface ContextoDoComando {
|
|
17
|
+
/** The message that triggered the command. */
|
|
18
|
+
mensagem: Mensagem;
|
|
19
|
+
/** The channel where the command was typed, with its settings. */
|
|
20
|
+
canal: CanalDeTexto;
|
|
21
|
+
/** `!tocar a.mp3` → `["a.mp3"]` (already split on whitespace). */
|
|
22
|
+
args: string[];
|
|
23
|
+
/** Everything typed after the command name, as-is. */
|
|
24
|
+
resto: string;
|
|
25
|
+
/** Replies in the same channel. */
|
|
26
|
+
responder(texto: string): Promise<Mensagem>;
|
|
27
|
+
/** Deletes the triggering message — only works when the bot wrote it. */
|
|
28
|
+
apagar(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/** Handler signature for one gateway event. */
|
|
31
|
+
type Ouvinte<K extends keyof Eventos> = (dados: Eventos[K]) => void | Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* A Vértice bot.
|
|
34
|
+
*
|
|
35
|
+
* Create one, register listeners with {@link on} and commands with
|
|
36
|
+
* {@link command}, then call {@link start}. Sessions, heartbeats, `resume` and
|
|
37
|
+
* reconnection are handled internally, so the author only has to react to
|
|
38
|
+
* events.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const bot = new Bot({ token: process.env.VERTICE_BOT_TOKEN! });
|
|
43
|
+
*
|
|
44
|
+
* bot.command("ping", { descricao: "responde pong" }, async ({ responder }) => {
|
|
45
|
+
* await responder("pong");
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* await bot.start();
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class Bot {
|
|
52
|
+
#private;
|
|
53
|
+
/** @param opcoes Token, base URL and the intents this process wants. */
|
|
54
|
+
constructor(opcoes: OpcoesDoBot);
|
|
55
|
+
/** Identity the server assigned, or `null` before {@link start}. */
|
|
56
|
+
get bot(): Descoberta["bot"] | null;
|
|
57
|
+
/** Channels granted to the bot, or `null` before {@link start}. */
|
|
58
|
+
get canais(): Descoberta["canais"] | null;
|
|
59
|
+
/** ICE servers from discovery (the bot's voice uses the same ones). */
|
|
60
|
+
get iceServers(): ServidorIce[];
|
|
61
|
+
/** Current gateway state, or `"parado"` before {@link start} and after {@link stop}. */
|
|
62
|
+
get estado(): EstadoDoGateway | "parado";
|
|
63
|
+
/**
|
|
64
|
+
* Registers a listener for every gateway state change.
|
|
65
|
+
*
|
|
66
|
+
* Voice uses it to leave the room when the connection drops: `resume` brings
|
|
67
|
+
* the events back, but not the seat in the voice room.
|
|
68
|
+
*
|
|
69
|
+
* @param ouvinte Called with the new state.
|
|
70
|
+
* @returns This bot, for chaining.
|
|
71
|
+
*/
|
|
72
|
+
aoMudarEstado(ouvinte: (estado: EstadoDoGateway) => void): this;
|
|
73
|
+
/** Last connection error, for callers that want to show it in a `/status` command. */
|
|
74
|
+
get ultimoErro(): Error | null;
|
|
75
|
+
/**
|
|
76
|
+
* Discovers what the bot may do, opens a session and connects the gateway.
|
|
77
|
+
*
|
|
78
|
+
* @returns This bot, once the gateway reports `ready`.
|
|
79
|
+
* @throws {ErroDaApi} When discovery or session creation fails.
|
|
80
|
+
* @throws {Error} When the server refuses the bot.
|
|
81
|
+
*/
|
|
82
|
+
start(): Promise<this>;
|
|
83
|
+
/**
|
|
84
|
+
* Sends a raw gateway action (voice uses it to join, leave and signal).
|
|
85
|
+
*
|
|
86
|
+
* @param tipo Action name understood by the server.
|
|
87
|
+
* @param dados Action payload.
|
|
88
|
+
* @throws {Error} When `start()` has not been called yet.
|
|
89
|
+
*/
|
|
90
|
+
agir(tipo: string, dados?: Record<string, unknown>): void;
|
|
91
|
+
/** Closes the gateway for good and forgets the session. */
|
|
92
|
+
stop(): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Subscribes to a gateway event (`message.created`, `voice.joined`, …).
|
|
95
|
+
*
|
|
96
|
+
* @param nome Event name.
|
|
97
|
+
* @param ouvinte Handler; it may be async. Failures are logged, never thrown.
|
|
98
|
+
* @returns This bot, for chaining.
|
|
99
|
+
*/
|
|
100
|
+
on<K extends keyof Eventos>(nome: K, ouvinte: Ouvinte<K>): this;
|
|
101
|
+
/**
|
|
102
|
+
* Removes a listener previously registered with {@link on}.
|
|
103
|
+
*
|
|
104
|
+
* @param nome Event name.
|
|
105
|
+
* @param ouvinte The exact handler reference that was registered.
|
|
106
|
+
* @returns This bot, for chaining.
|
|
107
|
+
*/
|
|
108
|
+
off<K extends keyof Eventos>(nome: K, ouvinte: Ouvinte<K>): this;
|
|
109
|
+
/**
|
|
110
|
+
* Registers a command.
|
|
111
|
+
*
|
|
112
|
+
* The channel prefix (`!`) belongs to the server: here the name is just
|
|
113
|
+
* `tocar`. Without `canais`, the command works in every channel where the bot
|
|
114
|
+
* may speak. Every registered command is announced to the client's
|
|
115
|
+
* autocomplete, including ones registered after `start()`.
|
|
116
|
+
*
|
|
117
|
+
* @param nome Command name; a leading `!` or `/` is stripped.
|
|
118
|
+
* @param opcoesOuFn Either the options object or the handler itself.
|
|
119
|
+
* @param talvezFn Handler, when the second argument carries the options.
|
|
120
|
+
* @returns This bot, for chaining.
|
|
121
|
+
* @throws {Error} When no handler is provided.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* bot.command("ping", async ({ responder }) => {
|
|
126
|
+
* await responder("pong");
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* bot.command("eco", { descricao: "repete o texto" }, async ({ resto, responder }) => {
|
|
130
|
+
* await responder(resto);
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
command(nome: string, opcoesOuFn: {
|
|
135
|
+
descricao?: string;
|
|
136
|
+
canais?: string[];
|
|
137
|
+
} | ((contexto: ContextoDoComando) => void | Promise<void>), talvezFn?: (contexto: ContextoDoComando) => void | Promise<void>): this;
|
|
138
|
+
/** Registered commands, in registration order (handy in a `!help` command). */
|
|
139
|
+
get comandos(): {
|
|
140
|
+
nome: string;
|
|
141
|
+
descricao?: string;
|
|
142
|
+
}[];
|
|
143
|
+
/**
|
|
144
|
+
* Sends a text message.
|
|
145
|
+
*
|
|
146
|
+
* It goes over HTTP on purpose: the response carries the created item (id,
|
|
147
|
+
* timestamp), and the gateway delivers `message.created` to everyone anyway.
|
|
148
|
+
*
|
|
149
|
+
* @param canal Channel code (case-insensitive; uppercased before sending).
|
|
150
|
+
* @param texto Message content.
|
|
151
|
+
* @returns The message the server created.
|
|
152
|
+
* @throws {ErroDaApi} When the bot cannot post in the channel.
|
|
153
|
+
*/
|
|
154
|
+
enviar(canal: string, texto: string): Promise<Mensagem>;
|
|
155
|
+
/**
|
|
156
|
+
* Sends audio as a **voice message** — the item the client renders as a
|
|
157
|
+
* "voice message" and plays inline.
|
|
158
|
+
*
|
|
159
|
+
* @param canal Channel code.
|
|
160
|
+
* @param audio The audio bytes (WAV by default; see `wavDeTom`).
|
|
161
|
+
* @param opcoes File name and MIME type; defaults to `recado.wav` / `audio/wav`.
|
|
162
|
+
* @returns The message the server created.
|
|
163
|
+
* @throws {ErroDaApi} When the upload fails.
|
|
164
|
+
*/
|
|
165
|
+
enviarVoz(canal: string, audio: Uint8Array, opcoes?: {
|
|
166
|
+
nome?: string;
|
|
167
|
+
mime?: string;
|
|
168
|
+
}): Promise<Mensagem>;
|
|
169
|
+
/**
|
|
170
|
+
* Sends any other file (image, PDF, audio as a regular attachment).
|
|
171
|
+
*
|
|
172
|
+
* @param canal Channel code.
|
|
173
|
+
* @param conteudo File bytes.
|
|
174
|
+
* @param opcoes File name and MIME type; defaults to `arquivo` /
|
|
175
|
+
* `application/octet-stream`.
|
|
176
|
+
* @returns The message the server created.
|
|
177
|
+
* @throws {ErroDaApi} When the upload fails.
|
|
178
|
+
*/
|
|
179
|
+
enviarArquivo(canal: string, conteudo: Uint8Array, opcoes?: {
|
|
180
|
+
nome?: string;
|
|
181
|
+
mime?: string;
|
|
182
|
+
}): Promise<Mensagem>;
|
|
183
|
+
/**
|
|
184
|
+
* Reads a page of history (100 items; `antesDe` pages backwards).
|
|
185
|
+
*
|
|
186
|
+
* @param canal Channel code.
|
|
187
|
+
* @param antesDe Timestamp cursor: returns messages older than this one.
|
|
188
|
+
* @returns The page, plus `temMais` telling whether another page exists.
|
|
189
|
+
* @throws {ErroDaApi} When the bot cannot read the channel.
|
|
190
|
+
*/
|
|
191
|
+
historico(canal: string, antesDe?: number): Promise<{
|
|
192
|
+
sala: string;
|
|
193
|
+
mensagens: Mensagem[];
|
|
194
|
+
temMais: boolean;
|
|
195
|
+
}>;
|
|
196
|
+
/**
|
|
197
|
+
* Deletes a message the bot wrote.
|
|
198
|
+
*
|
|
199
|
+
* @param canal Channel code.
|
|
200
|
+
* @param id Message id.
|
|
201
|
+
* @throws {ErroDaApi} When the message is not the bot's or is already gone.
|
|
202
|
+
*/
|
|
203
|
+
apagar(canal: string, id: string): Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* Re-runs only the discovery step (e.g. after changing channels in the panel).
|
|
206
|
+
*
|
|
207
|
+
* @returns The fresh discovery document.
|
|
208
|
+
* @throws {ErroDaApi} When the token is rejected.
|
|
209
|
+
*/
|
|
210
|
+
recarregar(): Promise<Descoberta>;
|
|
211
|
+
}
|
|
212
|
+
export { ErroDaApi };
|
|
213
|
+
//# sourceMappingURL=cliente.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliente.d.ts","sourceRoot":"","sources":["../../src/cliente.ts"],"names":[],"mappings":"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"}
|