hobots 0.3.1 → 1.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/LICENSE +21 -0
- package/README.md +389 -0
- package/dist/index.cjs +1203 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +312 -0
- package/dist/index.d.ts +312 -0
- package/dist/index.js +1180 -0
- package/dist/index.js.map +1 -0
- package/dist/manager/protocol.cjs +19 -0
- package/dist/manager/protocol.cjs.map +1 -0
- package/dist/manager/protocol.d.cts +72 -0
- package/dist/manager/protocol.d.ts +72 -0
- package/dist/manager/protocol.js +1 -0
- package/dist/manager/protocol.js.map +1 -0
- package/dist/protocol.cjs +19 -0
- package/dist/protocol.cjs.map +1 -0
- package/dist/protocol.d.cts +129 -0
- package/dist/protocol.d.ts +129 -0
- package/dist/protocol.js +1 -0
- package/dist/protocol.js.map +1 -0
- package/docs/README.md +41 -0
- package/docs/api-reference.md +153 -0
- package/docs/getting-started.md +103 -0
- package/docs/manager.md +95 -0
- package/docs/monitor.md +138 -0
- package/docs/protocol.md +101 -0
- package/package.json +46 -3
- package/auth/index.d.ts +0 -10
- package/csv/index.d.ts +0 -9
- package/datasets/index.d.ts +0 -2
- package/db/drizzle.config.d.ts +0 -8
- package/db/index.d.ts +0 -9
- package/db/migrate.d.ts +0 -3
- package/db/schema.d.ts +0 -215
- package/db/storages/base.d.ts +0 -23
- package/db/storages/index.d.ts +0 -3
- package/db/storages/job.d.ts +0 -233
- package/exceptions/break.d.ts +0 -6
- package/exceptions/ignore.d.ts +0 -6
- package/exceptions/index.d.ts +0 -4
- package/exceptions/warning.d.ts +0 -6
- package/foreach/foreach.d.ts +0 -7
- package/foreach/index.d.ts +0 -5
- package/foreach/item.d.ts +0 -13
- package/hobots/samples/bot.d.ts +0 -2
- package/hobots/samples/index.d.ts +0 -2
- package/hobots/src/auth/index.d.ts +0 -10
- package/hobots/src/csv/index.d.ts +0 -9
- package/hobots/src/datasets/index.d.ts +0 -2
- package/hobots/src/db/drizzle.config.d.ts +0 -8
- package/hobots/src/db/index.d.ts +0 -9
- package/hobots/src/db/migrate.d.ts +0 -3
- package/hobots/src/db/schema.d.ts +0 -215
- package/hobots/src/db/storages/base.d.ts +0 -23
- package/hobots/src/db/storages/index.d.ts +0 -3
- package/hobots/src/db/storages/job.d.ts +0 -233
- package/hobots/src/exceptions/break.d.ts +0 -6
- package/hobots/src/exceptions/ignore.d.ts +0 -6
- package/hobots/src/exceptions/index.d.ts +0 -4
- package/hobots/src/exceptions/warning.d.ts +0 -6
- package/hobots/src/foreach/foreach.d.ts +0 -7
- package/hobots/src/foreach/index.d.ts +0 -5
- package/hobots/src/foreach/item.d.ts +0 -13
- package/hobots/src/index.d.ts +0 -9
- package/hobots/src/reports/data-report.d.ts +0 -9
- package/hobots/src/reports/index.d.ts +0 -3
- package/hobots/src/reports/job-report.d.ts +0 -22
- package/hobots/src/setup.d.ts +0 -20
- package/hobots/src/sheets/index.d.ts +0 -13
- package/hobots/src/types/hobots-types.d.ts +0 -20
- package/hobots/src/utils/date.d.ts +0 -117
- package/hobots/src/utils/dist.d.ts +0 -8
- package/hobots/src/utils/garbage.d.ts +0 -2
- package/hobots/src/utils/index.d.ts +0 -10
- package/hobots/src/utils/logger.d.ts +0 -21
- package/hobots/src/utils/manifest.d.ts +0 -2
- package/hobots/src/utils/path.d.ts +0 -13
- package/hobots/src/utils/publish.d.ts +0 -2
- package/hobots/src/utils/retry.d.ts +0 -5
- package/hobots/src/utils/text.d.ts +0 -74
- package/hobots/src/utils/timer.d.ts +0 -3
- package/index.d.ts +0 -9
- package/index.js +0 -131866
- package/index.js.map +0 -1
- package/reports/data-report.d.ts +0 -9
- package/reports/index.d.ts +0 -3
- package/reports/job-report.d.ts +0 -22
- package/setup.d.ts +0 -20
- package/sheets/index.d.ts +0 -13
- package/types/hobots-types.d.ts +0 -20
- package/utils/date.d.ts +0 -117
- package/utils/dist.d.ts +0 -8
- package/utils/garbage.d.ts +0 -2
- package/utils/index.d.ts +0 -10
- package/utils/logger.d.ts +0 -21
- package/utils/manifest.d.ts +0 -2
- package/utils/path.d.ts +0 -13
- package/utils/publish.d.ts +0 -2
- package/utils/retry.d.ts +0 -5
- package/utils/src/path.d.ts +0 -14
- package/utils/text.d.ts +0 -74
- package/utils/timer.d.ts +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hobots
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# hobots
|
|
2
|
+
|
|
3
|
+
SDK JavaScript/TypeScript da **Hobots** para instrumentar funcionários digitais (RPAs) e integrações.
|
|
4
|
+
|
|
5
|
+
- **Monitor** — telemetria que o programa **emite** sozinho: erros com stack trace, performance (transactions/spans), check-ins de cron e heartbeats de uptime.
|
|
6
|
+
- **Manager** — execução **sob demanda**: o agente faz polling no app da Hobots, executa handlers registrados e reporta status e logs.
|
|
7
|
+
|
|
8
|
+
**Um único import e um único `init()`** cobrem as duas capabilities. Cliente HTTP puro, **sem dependências de runtime**. Requer **Node 18+** (usa o `fetch` global); o Monitor também roda no browser para captura de erros.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Instalação
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install hobots
|
|
16
|
+
# ou: pnpm add hobots · yarn add hobots
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import * as Hobots from 'hobots'; // um import só — Monitor e Manager
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Também funciona em CommonJS: `const Hobots = require('hobots')`.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Um SDK, duas capabilities, um `init()`
|
|
28
|
+
|
|
29
|
+
O SDK expõe **duas capabilities** autenticadas pela **mesma DSN única do projeto**, configuradas em um único `init()`:
|
|
30
|
+
|
|
31
|
+
| Capability | Como habilita | Para quê | Ciclo de vida |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| **Monitor** | sempre ativo no `init()` | Telemetria emitida pelo próprio programa: erros, transactions/spans, crons, heartbeat. | Timers `unref`'d — **não** segura o processo. Chame `close()` no fim. |
|
|
34
|
+
| **Manager** | `manager: true` (ou opções) no `init()` | Execução remota sob demanda via polling. | `start()` **segura o processo vivo** até `stop()`/`close()`. |
|
|
35
|
+
|
|
36
|
+
Você usa **uma, outra ou as duas**:
|
|
37
|
+
|
|
38
|
+
- Só saber se o robô quebrou, quanto demora e se está vivo? → `init({ dsn, heartbeat: true })`.
|
|
39
|
+
- Disparar o robô sob demanda a partir de um formulário no app? → `init({ dsn, manager: true })` + `register()` + `start()`.
|
|
40
|
+
- Ambos? Passe `heartbeat` e `manager` no mesmo `init()` — o `instanceId` é a identidade única, e os dois canais convergem em **um agente** no painel.
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
Hobots.init({
|
|
44
|
+
dsn: 'https://<secretKey>@<host>/<projectSlug>',
|
|
45
|
+
instanceId: 'vm-cliente-01',
|
|
46
|
+
heartbeat: true, // Monitor: "estou vivo" a cada 30s
|
|
47
|
+
manager: { pollIntervalMs: 5_000 }, // Manager: execução sob demanda
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
Hobots.register('processar-nfe', async (params, ctx) => {
|
|
51
|
+
ctx.log('info', 'começando…');
|
|
52
|
+
return { processadas: 12 };
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
Hobots.start(); // inicia o polling do Manager (segura o processo vivo)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## O DSN
|
|
61
|
+
|
|
62
|
+
Cada projeto tem **uma única DSN** — a mesma credencial autentica o Monitor **e** o Manager:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
https://<secretKey>@<host>/<projectSlug>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
A `secretKey` (64 hex) é **secreta**: vai embutida na DSN só por conveniência — nas requisições viaja sempre no header `Authorization: Bearer`, nunca na URL. O `projectSlug` do path é informativo; a identidade do projeto vem da chave. Copie a DSN pronta no app, em **Configurações → Agentes** — os snippets de integração já vêm prontos.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Monitor
|
|
73
|
+
|
|
74
|
+
Todas as funções abaixo são **no-op seguras** se `Hobots.init()` não foi chamado (com aviso no console).
|
|
75
|
+
|
|
76
|
+
### `init(options)`
|
|
77
|
+
|
|
78
|
+
Inicialize **uma vez**, o mais cedo possível no processo. Cria o cliente, instala handlers globais de erro (a menos que `captureUnhandled: false`) e inicia o heartbeat se configurado.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
Hobots.init({
|
|
82
|
+
dsn: 'https://<secretKey>@<host>/<projectSlug>',
|
|
83
|
+
environment: 'production',
|
|
84
|
+
release: 'robo-nfe@1.4.2',
|
|
85
|
+
instanceId: 'vm-cliente-01',
|
|
86
|
+
tags: { squad: 'automacoes' },
|
|
87
|
+
heartbeat: true, // "estou vivo" a cada 30s
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
| Opção | Tipo | Default | Descrição |
|
|
92
|
+
| --- | --- | --- | --- |
|
|
93
|
+
| `dsn` | `string` | **obrigatório** | a DSN única do projeto: `https://<secretKey>@host/<projectSlug>` |
|
|
94
|
+
| `environment` | `string` | `'production'` | ambiente lógico |
|
|
95
|
+
| `release` | `string` | — | versão do programa, ex. `robo-nfe@1.4.2` |
|
|
96
|
+
| `instanceId` | `string` | **obrigatório** | identidade única da instância — heartbeat do Monitor e agente do Manager convergem nela |
|
|
97
|
+
| `tags` | `Record<string,string>` | — | tags aplicadas a todos os eventos |
|
|
98
|
+
| `sampleRate` | `number` | `1` | amostragem de erros (0..1) |
|
|
99
|
+
| `tracesSampleRate` | `number` | `1` | amostragem de transactions (0..1) |
|
|
100
|
+
| `maxBreadcrumbs` | `number` | `100` | tamanho do buffer de breadcrumbs |
|
|
101
|
+
| `captureUnhandled` | `boolean` | `true` | handlers globais de erro (`uncaughtException`/`unhandledRejection`) |
|
|
102
|
+
| `heartbeat` | `boolean \| HeartbeatOptions` | `false` | heartbeat periódico (`true` usa defaults) |
|
|
103
|
+
| `manager` | `boolean \| ManagerOptions` | `false` | habilita o agente Manager (`true` usa defaults) — veja [Manager](#manager) |
|
|
104
|
+
| `beforeSend` | `(event) => event \| null` | — | edita/descarta evento (retorne `null` para descartar) |
|
|
105
|
+
| `debug` | `boolean` | `false` | loga atividade do SDK |
|
|
106
|
+
| `flushIntervalMs` | `number` | `2000` | intervalo do flush automático do transport |
|
|
107
|
+
| `maxBatchSize` | `number` | `10` | itens por envelope antes do flush imediato |
|
|
108
|
+
|
|
109
|
+
### Captura de erros e mensagens
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
try {
|
|
113
|
+
await processarNota(nota);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
Hobots.captureException(error, {
|
|
116
|
+
level: 'error',
|
|
117
|
+
tags: { cliente: 'acme' },
|
|
118
|
+
fingerprint: ['sefaz-timeout'], // agrupa manualmente; sem isso o servidor agrupa pelo stack
|
|
119
|
+
});
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
Hobots.captureMessage('Lote processado com sucesso', 'info');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Ambas retornam o `event_id` (ou `undefined` se não inicializado). O hint aceita `level`, `tags`, `extra` e `fingerprint`. Erros **não tratados** são capturados e flushados automaticamente antes do processo sair — desligue com `captureUnhandled: false`.
|
|
127
|
+
|
|
128
|
+
`Severity = 'fatal' | 'error' | 'warning' | 'info' | 'debug'`.
|
|
129
|
+
|
|
130
|
+
### Breadcrumbs
|
|
131
|
+
|
|
132
|
+
Trilha do que aconteceu antes do erro; enviada junto do próximo evento (buffer limitado por `maxBreadcrumbs`, mais antigos descartados).
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
Hobots.addBreadcrumb({ category: 'nfe', message: 'Baixou XML da nota 123', level: 'info' });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Escopo: tags, usuário, contexto, extras
|
|
139
|
+
|
|
140
|
+
Dados anexados a **todos** os eventos seguintes:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
Hobots.setTag('regiao', 'nordeste');
|
|
144
|
+
Hobots.setTags({ squad: 'automacoes', cliente: 'acme' });
|
|
145
|
+
Hobots.setUser({ id: 'op-42', email: 'op@acme.com' });
|
|
146
|
+
Hobots.setContext('vm', { cpu: 4, ram: '8GB' });
|
|
147
|
+
Hobots.setExtra('ultimoLote', 128);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Para um escopo **isolado** (sem vazar para o global), use `withScope`:
|
|
151
|
+
|
|
152
|
+
```js
|
|
153
|
+
Hobots.withScope((scope) => {
|
|
154
|
+
scope.setTag('lote', '128').setFingerprint(['reprocessamento']);
|
|
155
|
+
Hobots.captureMessage('Reprocessando lote 128');
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Performance: transactions e spans
|
|
160
|
+
|
|
161
|
+
```js
|
|
162
|
+
const tx = Hobots.startTransaction('processar-lote', 'rpa.job');
|
|
163
|
+
|
|
164
|
+
const span = tx.startChild('http.client', 'GET /api/notas');
|
|
165
|
+
await api.buscarNotas();
|
|
166
|
+
span.setData('notas', 42).finish();
|
|
167
|
+
|
|
168
|
+
const filho = span.startChild('db.query', 'INSERT INTO notas'); // spans aninham
|
|
169
|
+
await gravar();
|
|
170
|
+
filho.finish();
|
|
171
|
+
|
|
172
|
+
tx.setStatus('ok'); // ou 'error'
|
|
173
|
+
tx.finish(); // só aqui a transaction é enviada (respeitando tracesSampleRate)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- `startChild(op?, description?)` existe em `Transaction` **e** `Span` (aninhamento arbitrário).
|
|
177
|
+
- Métodos encadeáveis: `setStatus`, `setData` (span), `setTag`/`setName` (transaction).
|
|
178
|
+
- `finish()` na transaction fecha os spans abertos e envia o payload; nada é enviado se ela não foi amostrada.
|
|
179
|
+
|
|
180
|
+
### Crons (check-ins)
|
|
181
|
+
|
|
182
|
+
Monitora jobs agendados: check-in `in_progress` na entrada, `ok`/`error` na saída, com duração medida. O jeito recomendado é `withMonitor`, que faz o par e captura exceções:
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
await Hobots.withMonitor(
|
|
186
|
+
'sync-notas',
|
|
187
|
+
() => executarSync(),
|
|
188
|
+
{ schedule: '0 */2 * * *', timezone: 'America/Fortaleza' }
|
|
189
|
+
);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
O `schedule` (expressão cron) faz o servidor **criar/atualizar o monitor automaticamente** (upsert) e habilita a detecção de **execução perdida**. Para controle manual:
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
const id = Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'in_progress' });
|
|
196
|
+
// … trabalho …
|
|
197
|
+
Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'ok', checkInId: id, durationMs: 1234 });
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Heartbeat (uptime)
|
|
201
|
+
|
|
202
|
+
Bate "estou vivo" periodicamente; o servidor acusa o robô **offline** quando os batimentos param.
|
|
203
|
+
|
|
204
|
+
```js
|
|
205
|
+
Hobots.init({
|
|
206
|
+
dsn,
|
|
207
|
+
heartbeat: { intervalMs: 30_000, name: 'Robô NFe — VM 01' },
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`heartbeat: true` usa os defaults. A identidade é o `instanceId` do `init()`. Campos: `intervalMs` (30000), `name` (default: o `instanceId`), `metadata`.
|
|
212
|
+
|
|
213
|
+
### Flush e close
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
await Hobots.flush(2000); // envia o buffer, mantém o SDK vivo
|
|
217
|
+
await Hobots.close(2000); // flush final + para o heartbeat + fecha o transport
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Chame `close` antes do processo sair. Os timers do Monitor são `unref`'d — ele **não** segura o processo vivo sozinho.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Manager
|
|
225
|
+
|
|
226
|
+
Capability de **execução remota sob demanda**, habilitada com `manager: true` (ou opções) no `init()`. O agente faz polling no app, executa os handlers registrados quando aparece trabalho e reporta status e logs incrementais. Mesma DSN, mesmo `debug` e o `instanceId` como identidade — nenhum handler global extra é instalado.
|
|
227
|
+
|
|
228
|
+
### Ciclo de vida
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
Hobots.init({
|
|
232
|
+
dsn: 'https://<secretKey>@<host>/<projectSlug>',
|
|
233
|
+
instanceId: 'vm-cliente-01',
|
|
234
|
+
manager: true, // ou { pollIntervalMs, concurrency, ... }
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
Hobots.register('processar-nfe', async (params, ctx) => {
|
|
238
|
+
ctx.log('info', `processando lote ${params.lote}…`);
|
|
239
|
+
if (ctx.signal.aborted) return; // cancelamento cooperativo
|
|
240
|
+
ctx.log('info', '12 notas processadas');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
Hobots.start(); // começa o polling e MANTÉM O PROCESSO VIVO
|
|
244
|
+
|
|
245
|
+
process.on('SIGINT', () => {
|
|
246
|
+
void Hobots.close(15_000).then(() => process.exit(0));
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
- `init({ manager })` — cria o agente. Chamar `init()` de novo para o agente anterior e o substitui (o registry de handlers é preservado).
|
|
251
|
+
- `register(task, handler)` — `task` é o `task_slug` configurado no formulário do app. Registre **antes** de `start()`. Funciona até antes do `init()`; com o Manager desabilitado, avisa no console.
|
|
252
|
+
- `start()` — começa o polling. Lança se o `init()` não configurou `manager` ou se nenhuma task foi registrada.
|
|
253
|
+
- `stop(timeoutMs?)` — para **só o Manager**: encerra o polling e aguarda as runs ativas (default 30s); a telemetria continua. Retorna `false` se estourou o timeout.
|
|
254
|
+
- `close(timeoutMs?)` — encerra **tudo**: agente (aguardando runs em voo) → heartbeat → flush final do transport.
|
|
255
|
+
|
|
256
|
+
| Opção (`ManagerOptions`) | Tipo | Default | Descrição |
|
|
257
|
+
| --- | --- | --- | --- |
|
|
258
|
+
| `pollIntervalMs` | `number` | `5000` | intervalo entre polls sem trabalho (mínimo `1000`) |
|
|
259
|
+
| `concurrency` | `number` | `1` | runs simultâneas (clamp 1..5) |
|
|
260
|
+
| `taskTimeoutMs` | `number` | — | timeout client-side por run (não mata o handler; servidor é o backstop) |
|
|
261
|
+
| `logFlushIntervalMs` | `number` | `2000` | intervalo do envio incremental de logs |
|
|
262
|
+
|
|
263
|
+
A DSN, o `debug` e a identidade do agente (`instanceId`) vêm do `init()` — o heartbeat do Monitor e o agente do Manager convergem em **um agente** no painel automaticamente.
|
|
264
|
+
|
|
265
|
+
### O handler e o `RunContext`
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
type ManagerTaskHandler<P = Record<string, unknown>> =
|
|
269
|
+
(params: P, ctx: RunContext) => void | Promise<void>;
|
|
270
|
+
|
|
271
|
+
interface RunContext {
|
|
272
|
+
runId: string;
|
|
273
|
+
task: string;
|
|
274
|
+
log(level: 'debug' | 'info' | 'warning' | 'error', message: string): void;
|
|
275
|
+
signal: AbortSignal;
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
- **`params`** — os dados do formulário configurado no app (JSON validado). Tipável: `Hobots.register<{ lote: number }>(...)`.
|
|
280
|
+
- **`ctx.log(level, message)`** — logs enviados **incrementalmente** ao app (PATCHes com throttle), visíveis na run quase em tempo real.
|
|
281
|
+
- **`ctx.signal`** — `AbortSignal` que dispara quando a run é **cancelada no app**, em **timeout** ou no **shutdown**.
|
|
282
|
+
- **Retorno** — **ignorado**: o SDK não captura nem envia o valor retornado pelo handler (resultados podem conter dados sensíveis e não são coletados).
|
|
283
|
+
- **Erro lançado** — a run é reportada como `failed` (mensagem cap 10k, stack 20k).
|
|
284
|
+
|
|
285
|
+
> **Dados sensíveis:** `ctx.log()` e mensagens/stack de erros **são enviados ao servidor** e ficam visíveis no app. Não inclua senhas, tokens, dados pessoais ou qualquer informação sensível em logs e mensagens de erro.
|
|
286
|
+
|
|
287
|
+
### Cancelamento cooperativo
|
|
288
|
+
|
|
289
|
+
Uma run cancelada no app **não mata** o handler — o SDK apenas dispara `ctx.signal`. **Verifique `ctx.signal.aborted`** em loops longos:
|
|
290
|
+
|
|
291
|
+
```js
|
|
292
|
+
Hobots.register('processar-nfe', async (params, ctx) => {
|
|
293
|
+
for (const nota of params.notas) {
|
|
294
|
+
if (ctx.signal.aborted) {
|
|
295
|
+
ctx.log('warning', 'cancelamento detectado — parando');
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
await processar(nota);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Concorrência
|
|
304
|
+
|
|
305
|
+
`concurrency` (default 1, máx 5) controla quantas runs o agente executa em paralelo. Com 1, as runs são sequenciais. O agente só reivindica o que consegue rodar (`max = concurrency - runs ativas`) e entra em **drain mode**: re-pesquisa imediatamente enquanto vem trabalho; quando não vem, espera `pollIntervalMs`.
|
|
306
|
+
|
|
307
|
+
### Timeout por run
|
|
308
|
+
|
|
309
|
+
`taskTimeoutMs` é **client-side**. No estouro o SDK **não mata** o handler — dispara `ctx.signal`, libera o slot e reporta a run como falha (`TaskTimeout`). Respeite o `signal` para parar de verdade. Sem ele, o backstop é o servidor.
|
|
310
|
+
|
|
311
|
+
### Idempotência (at-least-once)
|
|
312
|
+
|
|
313
|
+
A entrega é **at-least-once**: se o agente morre logo após capturar uma run (antes de reportar a conclusão), ela é re-entregue quando o agente voltar. Escreva handlers **idempotentes** (use uma chave de deduplicação sua, como o número da nota).
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Encerramento gracioso
|
|
318
|
+
|
|
319
|
+
`close(timeoutMs?)` encerra tudo na ordem certa: para o Manager (aguardando a run atual), para o heartbeat e faz o flush final do transport.
|
|
320
|
+
|
|
321
|
+
```js
|
|
322
|
+
// só Monitor: não segura o processo, mas faça o flush final para não perder eventos
|
|
323
|
+
await Hobots.close(2_000);
|
|
324
|
+
|
|
325
|
+
// com Manager: segura o processo por design — aguarde a run atual
|
|
326
|
+
process.on('SIGINT', () => {
|
|
327
|
+
void Hobots.close(15_000).then(() => process.exit(0));
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Para parar de aceitar execuções **sem** derrubar a telemetria, use `stop(timeoutMs?)`.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Entry points / exports
|
|
336
|
+
|
|
337
|
+
| Import | Conteúdo |
|
|
338
|
+
| --- | --- |
|
|
339
|
+
| `hobots` | Tudo: `init`, Monitor (captura, transactions, crons, heartbeat), Manager (`register`/`start`/`stop`), `close`, classes e tipos. |
|
|
340
|
+
| `hobots/protocol` | Tipos do wire format (Monitor e Manager). |
|
|
341
|
+
|
|
342
|
+
Empacotado em **ESM e CommonJS** com **definições de tipos** (`.d.ts`) para todas as entradas. (`hobots/manager/protocol` segue existindo como alias transitório de tipos.)
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Migração 1.x → 2.x
|
|
347
|
+
|
|
348
|
+
A 2.0 unifica o Manager no import raiz — `hobots/manager` **foi removido**:
|
|
349
|
+
|
|
350
|
+
```diff
|
|
351
|
+
-import * as Monitor from 'hobots';
|
|
352
|
+
-import * as Manager from 'hobots/manager';
|
|
353
|
+
+import * as Hobots from 'hobots';
|
|
354
|
+
|
|
355
|
+
-Monitor.init({ dsn, serverName: 'vm-01', heartbeat: true });
|
|
356
|
+
-Manager.init({ dsn, agentName: 'vm-01' });
|
|
357
|
+
+Hobots.init({ dsn, instanceId: 'vm-01', heartbeat: true, manager: true });
|
|
358
|
+
|
|
359
|
+
-Manager.register('minha-task', handler);
|
|
360
|
+
-Manager.start();
|
|
361
|
+
+Hobots.register('minha-task', handler);
|
|
362
|
+
+Hobots.start();
|
|
363
|
+
|
|
364
|
+
-await Manager.stop(15_000);
|
|
365
|
+
-await Monitor.close(3_000);
|
|
366
|
+
+await Hobots.close(15_000);
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
- `agentName` e `serverName` não existem mais — a identidade do agente é o `instanceId` (obrigatório, sem fallback).
|
|
370
|
+
- As opções do Manager (`pollIntervalMs`, `concurrency`, `taskTimeoutMs`, `logFlushIntervalMs`) vão no campo `manager` do `init()`; `dsn` e `debug` não se repetem.
|
|
371
|
+
- Tipos (`ManagerTaskHandler`, `RunContext`, `ManagerOptions`) e classes (`ManagerAgent`, `ManagerApi`) agora vêm de `hobots`; o wire format vem de `hobots/protocol`.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Documentação completa
|
|
376
|
+
|
|
377
|
+
Guias detalhados acompanham o pacote em [`docs/`](./docs/README.md):
|
|
378
|
+
|
|
379
|
+
- [Getting started](./docs/getting-started.md) — instalação, DSN, primeiro `init`, Monitor vs Hobots.
|
|
380
|
+
- [Monitor](./docs/monitor.md) — erros, breadcrumbs, escopo, transactions/spans, crons, heartbeat.
|
|
381
|
+
- [Manager](./docs/manager.md) — handlers, `RunContext`, cancelamento, concorrência, idempotência.
|
|
382
|
+
- [Referência de API](./docs/api-reference.md) — todas as funções e tabelas de opções com defaults.
|
|
383
|
+
- [Protocolo & transporte](./docs/protocol.md) — a DSN única, endpoints, envelope, retries.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Licença
|
|
388
|
+
|
|
389
|
+
[MIT](./LICENSE) © Hobots
|