@openvertice/bot-sdk 0.0.0-stage → 0.1.1

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 CHANGED
@@ -1,3 +1,199 @@
1
- # Temporary Holding Version
1
+ # `@openvertice/bot-sdk`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
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. Falhas transitórias — servidor fora, rede caindo, sessão que
78
+ não pôde ser renovada — são tentadas **indefinidamente** (espera de 1 s até
79
+ 30 s); desistir só acontece nos casos definitivos abaixo. Token girado, bot
80
+ desativado ou outra conexão assumindo o mesmo bot **não** reconectam:
81
+ `bot.estado` vira `recusado` e o erro fica em `bot.ultimoErro`.
82
+
83
+ ## Mensagem de voz (áudio no chat)
84
+
85
+ ```ts
86
+ import { Bot, wavDeTom } from "@openvertice/bot-sdk";
87
+
88
+ const wav = wavDeTom({ segundos: 1, frequencia: 440 }); // Uint8Array PCM 16 bits
89
+ const mensagem = await bot.enviarVoz("MURAL", wav, { nome: "recado.wav" });
90
+ mensagem.tipo; // "voz"
91
+ mensagem.arquivo?.url; // /chat/arquivos/<id>?exp=…&sig=… (pronta para <audio>)
92
+ ```
93
+
94
+ O corpo vai cru, com o tipo no cabeçalho — não há multipart. Para um arquivo
95
+ que não seja voz, use `enviarArquivo` (sem `X-Vertice-Tipo`). O limite é o do
96
+ chat (`VERTICE_CHAT_MAX_MB`) e a rajada de 30 mensagens por minuto vale igual.
97
+
98
+ ## Ser chamado com `@`
99
+
100
+ ```ts
101
+ bot.on("mention", async (m) => {
102
+ if (m.autorBot) return;
103
+ await bot.enviar(m.sala!, `oi, ${m.autor}!`);
104
+ });
105
+ ```
106
+
107
+ `mention` chega quando alguém escreve `@login` ou `@nome de exibição` (sem
108
+ caixa nem acento) e o bot tem o canal com `escutar`. Ele **atravessa o prefixo**
109
+ do canal — é o que deixa chamar o bot numa sala de comandos (`!`) sem que ele
110
+ leia a conversa toda. Em canal sem prefixo, `mention` vem junto com
111
+ `message.created` (mesmo `id`): trate como aviso, não como segunda mensagem.
112
+
113
+ ## Voz
114
+
115
+ ```ts
116
+ import { Bot, Voz, criarTransporteWrtc, tocarTom } from "@openvertice/bot-sdk";
117
+
118
+ const bot = new Bot({ token, intents: ["MESSAGES"] });
119
+ await bot.start();
120
+
121
+ const transporte = await criarTransporteWrtc();
122
+ // A track sai da fonte que você alimenta; sem `track` a `Voz` cria outra fonte
123
+ // e o bot publica silêncio.
124
+ const fonte = transporte.criarFonteDeAudio();
125
+ const voz = new Voz(bot, { transporte, track: fonte.createTrack() });
126
+ const parar = tocarTom({ fonte, frequencia: 440 });
127
+
128
+ await voz.entrar("PATIO"); // resolve no `voice.joined`
129
+ voz.sair();
130
+ parar();
131
+ ```
132
+
133
+ O bot entra **só quando pede** — `start()` nunca entra na voz. O layout dos
134
+ transceivers é o mesmo dos clientes (`audio[0]` = microfone, `audio[1]` = som da
135
+ transmissão, `video[0]` = tela) e a oferta cruzada é resolvida pelo id, como nos
136
+ dois lados. `aoReceberTrack` recebe o áudio dos outros pares, se você quiser
137
+ monitorar ou gravar.
138
+
139
+ `@roamhq/wrtc` exige blocos de **480 amostras** em 48 kHz (10 ms) no
140
+ `RTCAudioSource` — é o que `tocarTom` faz; lendo arquivo, respeite o mesmo
141
+ tamanho.
142
+
143
+ ## Exemplos
144
+
145
+ ```bash
146
+ npm run build
147
+ cp .env.example .env # e edite o VERTICE_BOT_TOKEN
148
+ npm run eco # repete e responde !ping
149
+ npm run radio # !entrar toca um tom na voz
150
+ npm run recado # !recado manda áudio no chat
151
+ ```
152
+
153
+ Os exemplos carregam o `.env` da raiz do pacote na partida (com o leitor nativo
154
+ do Node — nada de `dotenv`). Variável do ambiente ganha do arquivo, então
155
+ `VERTICE_BOT_TOKEN=vtb_… npm run eco` também funciona — e é o que vale se você
156
+ rodar `node dist/exemplos/eco.js` de outro diretório.
157
+
158
+ ## Testes
159
+
160
+ A reconexão do gateway tem teste próprio, **sem servidor** (usa um `WebSocket`
161
+ falso e o `dist/` compilado):
162
+
163
+ ```bash
164
+ npm run build && node testes/gateway-reconexao.mjs # backoff, recusa, queda e fechar()
165
+ ```
166
+
167
+ Os testes de fumaça sobem o servidor de verdade (precisa do repositório do
168
+ Vértice ao lado):
169
+
170
+ ```bash
171
+ node testes/fumaca.mjs # dois bots: comando, histórico, apagar, eventos
172
+ node testes/voz.mjs # dois bots na voz: ICE + DTLS fechados, track recebida
173
+ node testes/voz-cliente.mjs # bot ↔ cliente do navegador: SDP nos dois nomes e áudio
174
+ # (o fumaca.mjs também manda um recado de voz e baixa o áudio de volta)
175
+ ```
176
+
177
+ ## Limites (do servidor, não do SDK)
178
+
179
+ - 30 mensagens por minuto por bot; 1 sessão por minuto (o SDK só pede outra
180
+ quando a atual está para vencer).
181
+ - O bot só vê os canais marcados no painel e, com prefixo, só o que começa por
182
+ ele.
183
+ - Bot não é conta: não aparece na gestão de membros, não recebe cargo e não
184
+ apaga mensagem de outra pessoa.
185
+
186
+ ## Publicar no npm
187
+
188
+ O pacote vai para o escopo `@openvertice` como **público** (`publishConfig.access`):
189
+
190
+ ```bash
191
+ npm login # conta com acesso à org @openvertice
192
+ npm run build # o `prepack` também compila durante o publish
193
+ npm pack --dry-run # confere exatamente o que entra no tarball
194
+ npm publish # @openvertice/bot-sdk@<versão>
195
+ ```
196
+
197
+ O tarball leva `dist/src` (JS + `.d.ts`), `src` (para os source maps) e este
198
+ README. Testes, exemplos, `.env` e `node_modules` ficam de fora. Para publicar
199
+ 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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"}