hobots 1.5.1 → 1.6.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/docs/concepts.md CHANGED
@@ -8,30 +8,30 @@ Os defaults numéricos **não** estão aqui — eles vivem em [Tempos e interval
8
8
 
9
9
  ## Mapa rápido
10
10
 
11
- | Conceito | Em uma frase | Quando você usa |
12
- | --- | --- | --- |
13
- | [Evento](#evento) | Uma foto de algo que aconteceu — um erro ou uma mensagem | `captureException` / `captureMessage` |
14
- | [Level](#level-severity) | A gravidade do evento | Para separar o que acorda alguém do que é só registro |
15
- | [Fingerprint](#fingerprint) | A chave de agrupamento dos eventos em issues | Quando o agrupamento automático erra |
16
- | [Scope](#scope) | A mochila de contexto que viaja com todo evento | Você raramente mexe direto; mexe pelos `set*` |
17
- | [withScope](#withscope) | Um scope temporário e isolado | Contexto que **não** deve vazar para o resto do programa |
18
- | [Tag](#tag) | Rótulo curto e indexável (`string` → `string`) | Você vai **filtrar** ou **agrupar** por isso |
19
- | [Context](#context) | Grupo nomeado de dados estruturados | Você vai **ler** isso ao abrir o evento |
20
- | [Extra](#extra) | Depósito livre, sem estrutura | Não é filtro nem grupo coerente — é anexo |
21
- | [Breadcrumb](#breadcrumb) | Migalha da trilha que levou até o erro | Marcar cada passo relevante do robô |
22
- | [Transaction](#transaction) | Unidade de trabalho nomeada, com duração | Medir quanto uma rotina inteira demorou |
23
- | [Span](#span) | Uma etapa medida dentro da transaction | Descobrir **onde** o tempo foi gasto |
24
- | [ctx.tx](#transaction-de-run-ctxtx) | A transaction que o SDK já abriu para a run | Medir as etapas de um handler do Manager |
25
- | [Amostragem](#amostragem-samplerate-e-tracessamplerate) | Enviar só uma fração do que acontece | Volume alto demais para enviar tudo |
26
- | [Check-in](#check-in) | Par de avisos "comecei" / "terminei" de um job agendado | Cron que precisa ser vigiado |
27
- | [Heartbeat](#heartbeat) | Batimento "estou vivo" | Saber que o robô está de pé, mesmo parado |
28
- | [instanceId](#instanceid) | A identidade da instância do robô | Sempre — é obrigatório no `init()` |
29
- | [Release e environment](#release-e-environment) | Qual versão, em qual ambiente | Separar produção de homologação; achar a versão que quebrou |
30
- | [Run](#run) | Uma execução solicitada no app | O Manager inteiro gira em volta disso |
31
- | [Claim](#claim) | O ato de um agente pegar uma run para si | Entender por que dois agentes nunca colidem |
32
- | [Drain mode](#drain-mode) | O agente acelera o poll enquanto tem trabalho | Entender o ritmo do polling |
33
- | [Fila, flush e close](#fila-flush-e-close) | Nada é enviado na hora — vai para uma fila | Encerrar o processo sem perder telemetria |
34
- | [beforeSend](#beforesend) | O último gancho antes do envio | Censurar ou descartar eventos |
11
+ | Conceito | Em uma frase | Quando você usa |
12
+ | ------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------- |
13
+ | [Evento](#evento) | Uma foto de algo que aconteceu — um erro ou uma mensagem | `captureException` / `captureMessage` |
14
+ | [Level](#level-severity) | A gravidade do evento | Para separar o que acorda alguém do que é só registro |
15
+ | [Fingerprint](#fingerprint) | A chave de agrupamento dos eventos em issues | Quando o agrupamento automático erra |
16
+ | [Scope](#scope) | A mochila de contexto que viaja com todo evento | Você raramente mexe direto; mexe pelos `set*` |
17
+ | [withScope](#withscope) | Um scope temporário e isolado | Contexto que **não** deve vazar para o resto do programa |
18
+ | [Tag](#tag) | Rótulo curto e indexável (`string` → `string`) | Você vai **filtrar** ou **agrupar** por isso |
19
+ | [Context](#context) | Grupo nomeado de dados estruturados | Você vai **ler** isso ao abrir o evento |
20
+ | [Extra](#extra) | Depósito livre, sem estrutura | Não é filtro nem grupo coerente — é anexo |
21
+ | [Breadcrumb](#breadcrumb) | Migalha da trilha que levou até o erro | Marcar cada passo relevante do robô |
22
+ | [Transaction](#transaction) | Unidade de trabalho nomeada, com duração | Medir quanto uma rotina inteira demorou |
23
+ | [Span](#span) | Uma etapa medida dentro da transaction | Descobrir **onde** o tempo foi gasto |
24
+ | [ctx.tx](#transaction-de-run-ctxtx) | A transaction que o SDK já abriu para a run | Medir as etapas de um handler do Manager |
25
+ | [Amostragem](#amostragem-samplerate-e-tracessamplerate) | Enviar só uma fração do que acontece | Volume alto demais para enviar tudo |
26
+ | [Check-in](#check-in) | Par de avisos "comecei" / "terminei" de um job agendado | Cron que precisa ser vigiado |
27
+ | [Heartbeat](#heartbeat) | Batimento "estou vivo" | Saber que o robô está de pé, mesmo parado |
28
+ | [instanceId](#instanceid) | A identidade da instância do robô | Sempre — é obrigatório no `init()` |
29
+ | [Release e environment](#release-e-environment) | Qual versão, em qual ambiente | Separar produção de homologação; achar a versão que quebrou |
30
+ | [Run](#run) | Uma execução solicitada no app | O Manager inteiro gira em volta disso |
31
+ | [Claim](#claim) | O ato de um agente pegar uma run para si | Entender por que dois agentes nunca colidem |
32
+ | [Drain mode](#drain-mode) | O agente acelera o poll enquanto tem trabalho | Entender o ritmo do polling |
33
+ | [Fila, flush e close](#fila-flush-e-close) | Nada é enviado na hora — vai para uma fila | Encerrar o processo sem perder telemetria |
34
+ | [beforeSend](#beforesend) | O último gancho antes do envio | Censurar ou descartar eventos |
35
35
 
36
36
  > **Nota de manutenção:** esta página é a fonte canônica das explicações de conceito. As outras páginas da doc, o `README.md` do pacote e os tooltips do app parafraseiam daqui — quando um conceito muda, muda aqui primeiro.
37
37
 
@@ -112,7 +112,7 @@ Dois pontos importantes:
112
112
  `withScope` executa um callback com uma **cópia isolada** do scope. O que você escrever lá dentro vale para os eventos capturados dentro do callback e **não vaza** para fora.
113
113
 
114
114
  ```js
115
- Hobots.withScope((scope) => {
115
+ Hobots.withScope(scope => {
116
116
  scope.setTag('lote', '128').setFingerprint(['reprocessamento']);
117
117
  Hobots.captureMessage('Reprocessando lote 128');
118
118
  });
@@ -172,11 +172,11 @@ Hobots.setExtra('tentativas', [1, 2, 3]);
172
172
 
173
173
  É deliberadamente o menos estruturado dos três, e por isso o critério de escolha é simples:
174
174
 
175
- | Você vai… | Use |
176
- | --- | --- |
177
- | filtrar, agrupar, contar por isso | [tag](#tag) |
178
- | ler isso como um conjunto coerente | [context](#context) |
179
- | nenhum dos dois — é só um dado a mais | **extra** |
175
+ | Você vai… | Use |
176
+ | ------------------------------------- | ------------------- |
177
+ | filtrar, agrupar, contar por isso | [tag](#tag) |
178
+ | ler isso como um conjunto coerente | [context](#context) |
179
+ | nenhum dos dois — é só um dado a mais | **extra** |
180
180
 
181
181
  Extra não é indexado: não dá para filtrar por ele nem construir gráfico com ele. Se você se pegar querendo isso, o campo era uma tag.
182
182
 
@@ -207,7 +207,7 @@ Tamanho do buffer: [`maxBreadcrumbs`](./api-reference.md#initoptions).
207
207
 
208
208
  Uma **transaction** é uma unidade de trabalho **nomeada** e **medida**: ela começa, termina, e o que fica registrado é quanto tempo levou. É a resposta para "quanto demora minha rotina de emissão?" — e, quando você adiciona [spans](#span), para "onde foram esses minutos?".
209
209
 
210
- Enquanto o [evento](#evento) responde *o que quebrou*, a transaction responde *quanto tempo levou*. São os dois eixos do Monitor.
210
+ Enquanto o [evento](#evento) responde _o que quebrou_, a transaction responde _quanto tempo levou_. São os dois eixos do Monitor.
211
211
 
212
212
  ```js
213
213
  const tx = Hobots.startTransaction('processar-lote', 'rpa.job');
@@ -272,7 +272,7 @@ Sem nenhum `startChild` a transaction ainda existe e ainda mede o tempo total da
272
272
 
273
273
  - **Não chame `Hobots.startTransaction()` dentro de um handler.** Você criaria uma segunda transaction, **sem** correlação com a run, e ela não apareceria na execução.
274
274
  - `ctx.tx` **não respeita o `tracesSampleRate`** — toda run gera uma transaction. A amostragem vale para as transactions que **você** abre com `startTransaction()`.
275
- - O nome é `run:<task>` e o `op` é `manager.run`, preenchidos pelo SDK.
275
+ - O nome é `run:<task>` e o `op` é `hobots.task`, preenchidos pelo SDK.
276
276
 
277
277
  ## Amostragem (sampleRate e tracesSampleRate)
278
278
 
@@ -280,9 +280,9 @@ Sem nenhum `startChild` a transaction ainda existe e ainda mede o tempo total da
280
280
 
281
281
  São dois controles independentes, os dois de `0` a `1`:
282
282
 
283
- | Opção | Afeta | `0.1` significa |
284
- | --- | --- | --- |
285
- | `sampleRate` | [eventos](#evento) (`captureException`, `captureMessage`) | ~10% dos erros são enviados |
283
+ | Opção | Afeta | `0.1` significa |
284
+ | ------------------ | ------------------------------------------------------------- | ---------------------------------- |
285
+ | `sampleRate` | [eventos](#evento) (`captureException`, `captureMessage`) | ~10% dos erros são enviados |
286
286
  | `tracesSampleRate` | [transactions](#transaction) abertas por `startTransaction()` | ~10% das transactions são enviadas |
287
287
 
288
288
  O sorteio é por item, no momento em que ele é criado — nunca "1 a cada 10", e sim 10% de chance cada.
@@ -319,7 +319,7 @@ Detalhes que importam:
319
319
 
320
320
  O **heartbeat** é um batimento periódico dizendo "estou vivo". O servidor conhece a cadência esperada e marca a instância como **offline** quando os batimentos param.
321
321
 
322
- É o complemento do [check-in](#check-in): check-in vigia *execuções agendadas*, heartbeat vigia *o processo*. Um robô que fica de plantão esperando trabalho não tem cron para monitorar — mas você ainda quer saber quando a VM dele caiu.
322
+ É o complemento do [check-in](#check-in): check-in vigia _execuções agendadas_, heartbeat vigia _o processo_. Um robô que fica de plantão esperando trabalho não tem cron para monitorar — mas você ainda quer saber quando a VM dele caiu.
323
323
 
324
324
  ```js
325
325
  Hobots.init({
@@ -350,8 +350,8 @@ O que o torna especial é que ele é a identidade dos **dois** canais ao mesmo t
350
350
 
351
351
  Servem a duas perguntas concretas:
352
352
 
353
- - *"quebrou desde quando?"* — com `release`, você compara o antes e o depois de um deploy e sabe qual versão introduziu o erro.
354
- - *"isso é real ou é teste?"* — com `environment`, o ruído da homologação não polui os alertas de produção.
353
+ - _"quebrou desde quando?"_ — com `release`, você compara o antes e o depois de um deploy e sabe qual versão introduziu o erro.
354
+ - _"isso é real ou é teste?"_ — com `environment`, o ruído da homologação não polui os alertas de produção.
355
355
 
356
356
  `environment` default é `production`. Se você roda homologação sem definir isso, os dois ambientes se misturam na mesma issue — vale configurar no primeiro dia.
357
357
 
@@ -424,9 +424,9 @@ Defaults e tempos dos dois: [Tempos e intervalos](./api-reference.md#tempos-e-in
424
424
  Hobots.init({
425
425
  clientSecret,
426
426
  instanceId: 'vm-cliente-01',
427
- beforeSend: (event) => {
427
+ beforeSend: event => {
428
428
  if (event.exception?.type === 'AbortError') return null; // não me interessa
429
- delete event.extra?.senha; // censura
429
+ delete event.extra?.senha; // censura
430
430
  return event;
431
431
  },
432
432
  });
@@ -29,7 +29,7 @@ Cada projeto tem **um único Client Secret** — a mesma credencial autentica o
29
29
  hb_<64 hex>
30
30
  ```
31
31
 
32
- (Chaves antigas, 64 hex puros, continuam válidas no servidor.) A credencial é **secreta** e viaja sempre no header `Authorization: Bearer` — nunca na URL. Copie o Client Secret no app, em **Configurações → Projetos** — os snippets de integração já vêm prontos.
32
+ A credencial é **secreta** e viaja sempre no header `Authorization: Bearer` — nunca na URL. Copie o Client Secret no app, em **Configurações → Projetos** — os snippets de integração já vêm prontos.
33
33
 
34
34
  O SDK fala com a API oficial `https://api2.hobots.app` automaticamente — não há configuração de host no `init()`. Em desenvolvimento, aponte para outro host com a env `HOBOTS_API_URL`:
35
35
 
package/docs/protocol.md CHANGED
@@ -17,9 +17,7 @@ hb_<64 hex>
17
17
  | Monitor (ingestão) | `POST <baseUrl>/v1/ingest` | `Authorization: Bearer <clientSecret>` |
18
18
  | Manager (execução) | `<baseUrl>/v1/manager/*` | `Authorization: Bearer <clientSecret>` |
19
19
 
20
- `resolveConfig({ clientSecret }) → { key, baseUrl, ingestEndpoint, managerBaseUrl }` (em `src/config.ts`, com a constante `DEFAULT_BASE_URL = 'https://api2.hobots.app'`; em desenvolvimento a env `HOBOTS_API_URL` sobrescreve a URL base). A credencial é **secreta** (formato `hb_<64 hex>`; chaves antigas de 64 hex puros continuam válidas no servidor) e viaja **só no header** `Authorization: Bearer` — nunca na URL da requisição.
21
-
22
- > As DSNs foram **descontinuadas** em favor do Client Secret — tanto a antiga do Monitor (public key na URL, `POST /v1/ingest/<key>`, que responde **410** e o transport descarta sem retry) quanto a de key-na-URL (`https://<secretKey>@host/<slug>`). Copie o Client Secret em **Configurações → Projetos** no app.
20
+ `resolveConfig({ clientSecret }) → { key, baseUrl, ingestEndpoint, managerBaseUrl }` (em `src/config.ts`, com a constante `DEFAULT_BASE_URL = 'https://api2.hobots.app'`; em desenvolvimento a env `HOBOTS_API_URL` sobrescreve a URL base — apenas `http(s)`, e `http` para host fora de loopback gera aviso porque o secret trafega sem TLS). A credencial é **secreta** (formato `hb_<64 hex>`) e viaja **só no header** `Authorization: Bearer` — nunca na URL da requisição.
23
21
 
24
22
  ## Monitor — ingestão
25
23
 
@@ -88,7 +86,7 @@ Corpo `ManagerRunUpdateRequest`:
88
86
  - Ordem garantida `running → logs → terminal` (PATCHes serializados numa cadeia de promise).
89
87
  - Retry `[1s, 4s, 16s]`; 4xx exceto 429 é terminal (**409** = run cancelada / transição inválida → marca a run como morta e dispara `ctx.signal`).
90
88
  - Todo PATCH atualiza `last_report_at` no servidor (relógio do servidor) — é o **sinal de vida da run**. O heartbeat de cancelamento (PATCH `running` vazio a cada `cancelCheckIntervalMs`, máx 15s) garante reporte contínuo; um sweep server-side marca como `failed` com erro `AgentTerminated` ("execução encerrada inesperadamente") toda run `running` sem reporte há **60s**, sem re-entrega. No exit path (sinal/erro fatal com runs ativas), o SDK envia um único PATCH `failed`/`AgentTerminated` com timeout curto (~2s), sem retry — o sweep é o backstop.
91
- - O protocolo **não transporta resultado** de execução: o retorno do handler é ignorado pelo SDK e o servidor descarta qualquer campo `result` de SDKs antigos (dados de negócio podem ser sensíveis e não são coletados).
89
+ - O protocolo **não transporta resultado** de execução: o retorno do handler é ignorado pelo SDK e o servidor descarta qualquer campo `result` (dados de negócio podem ser sensíveis e não são coletados).
92
90
 
93
91
  Ciclo de vida completo da run no servidor: `pending → claimed → running → succeeded | failed | canceled`. O agente só transiciona para `running`/`succeeded`/`failed`.
94
92
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hobots",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "SDK JavaScript da Hobots — captura de erros, transactions, check-ins de cron e heartbeats (Monitor) e execução remota de tarefas sob demanda (Manager) para RPAs e integrações. Um único import e um único init().",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -36,6 +36,7 @@
36
36
  "build": "tsup",
37
37
  "dev": "tsup --watch",
38
38
  "lint": "eslint . --max-warnings 0",
39
+ "test": "node --test \"test/**/*.test.mjs\"",
39
40
  "typecheck": "tsc --noEmit"
40
41
  },
41
42
  "devDependencies": {