hobots 1.9.0 → 1.9.2

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.
@@ -128,6 +128,19 @@ O teto da fila do transport (200 itens; ao encher, o **mais antigo** é descarta
128
128
  | `tags` | `Record<string,string>` | tags só deste evento |
129
129
  | `extra` | `Record<string,unknown>` | dados extras |
130
130
  | `fingerprint` | `string[]` | agrupamento manual |
131
+ | `attachment` | `AttachInput \| CaptureAttachment` | print enviado junto da captura — dentro de uma execução de task, vira anexo da linha de log da run que espelha o evento; fora de uma execução é descartado com aviso. Guia: [Anexos](./tasks.md#anexos-screenshots) |
132
+
133
+ ### CaptureAttachment
134
+
135
+ `AttachInput = Uint8Array | ArrayBuffer | string` (bytes ou um caminho de arquivo, só em Node). Para legenda ou content-type, passe o objeto:
136
+
137
+ | Campo | Tipo | Default | O que faz |
138
+ | --- | --- | --- | --- |
139
+ | `image` | `AttachInput` | — | a imagem em si |
140
+ | `caption` | `string` | — | legenda exibida sob a imagem ampliada; truncada em 200 caracteres e passada pelo scrub de segredos |
141
+ | `contentType` | `'image/png' \| 'image/jpeg' \| 'image/webp'` | detectado pelos *magic bytes* | só usado quando a detecção falha; a detecção sempre tem precedência |
142
+
143
+ O texto da linha de log é a mensagem capturada; o nível vem do `level` da captura (`'fatal'` vira `'error'`). O upload roda em segundo plano e **nunca bloqueia nem faz a captura lançar**. Limites (todos aplicados também no servidor): PNG/JPEG/WEBP, **5 MB** por imagem, **20** anexos por execução, **4** por linha de log.
131
144
 
132
145
  `Severity = 'fatal' | 'error' | 'warning' | 'info' | 'debug' | 'success'`. O que cada nível significa (e por que `'success'` existe) em [Level](./concepts.md#level-severity).
133
146
 
@@ -159,7 +172,6 @@ interface RunContext {
159
172
  signal: AbortSignal;
160
173
  throwIfCanceled(): void; // lança RunCanceled se o signal já disparou
161
174
  sleep(ms: number): Promise<void>; // espera cancelável — rejeita com RunCanceled no abort
162
- attach(image: Uint8Array | ArrayBuffer | string, options?: AttachOptions): Promise<AttachResult>;
163
175
  }
164
176
  ```
165
177
 
@@ -169,26 +181,8 @@ interface RunContext {
169
181
  - **`signal`** — `AbortSignal` que dispara em cancelamento no app, timeout ou shutdown.
170
182
  - **`throwIfCanceled()`** — o ponto de parada de uma linha: lança `RunCanceled` se o `signal` já disparou.
171
183
  - **`sleep(ms)`** — espera que respeita o `signal` (rejeita com `RunCanceled` em vez de dormir até o fim). Use no lugar do seu `sleep` em esperas longas.
172
- - **`attach(image, options?)`** — anexa um print à linha de log. Aceita bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo (só em Node). A linha de log entra na hora; o upload é em segundo plano e **nunca lança**. Guia: [Anexos](./tasks.md#anexos-screenshots).
173
-
174
- ### AttachOptions
175
-
176
- | Campo | Tipo | Default | O que faz |
177
- | --- | --- | --- | --- |
178
- | `caption` | `string` | — | legenda exibida sob a imagem ampliada; truncada em 200 caracteres e passada pelo scrub de segredos |
179
- | `level` | `RunLogLevel` | `'info'` | nível da linha de log que carrega o anexo |
180
- | `message` | `string` | `caption` ou `'captura de tela'` | texto da linha de log |
181
- | `contentType` | `'image/png' \| 'image/jpeg' \| 'image/webp'` | detectado pelos *magic bytes* | só usado quando a detecção falha; a detecção sempre tem precedência |
182
-
183
- ### AttachResult
184
-
185
- | Campo | Tipo | O que é |
186
- | --- | --- | --- |
187
- | `id` | `string` | id do anexo — o mesmo referenciado na linha de log |
188
- | `ok` | `boolean` | `true` quando o binário chegou ao S3 |
189
- | `reason` | `AttachFailureReason?` | `'too-large' \| 'quota' \| 'unsupported-format' \| 'read-failed' \| 'unsupported' \| 'upload-failed' \| 'canceled'` |
190
184
 
191
- Limites (todos aplicados também no servidor): PNG/JPEG/WEBP, **5 MB** por imagem, **20** anexos por execução, **4** por linha de log.
185
+ Para anexar um print a uma linha de log da run, use o campo `attachment` do [`CaptureHint`](#capturehint) em `captureException`/`captureMessage` dentro do handler. Guia: [Anexos](./tasks.md#anexos-screenshots).
192
186
 
193
187
  ---
194
188
 
package/docs/concepts.md CHANGED
@@ -369,7 +369,7 @@ Cada run carrega os **`params`** (o JSON validado do formulário) e chega ao seu
369
369
 
370
370
  Um **anexo** é uma imagem — na prática, um print da tela — vinculada a uma linha de log de uma [run](#run). Serve para responder "como estava a tela quando isso aconteceu?", pergunta que texto de log sozinho não responde. No app, aparece como miniatura logo abaixo da linha de log correspondente, na aba "logs do agente" da execução.
371
371
 
372
- Quem captura é o seu código; o SDK só recebe a imagem pronta via [`ctx.attach()`](./tasks.md#anexos-screenshots).
372
+ Quem captura é o seu código; o SDK só recebe a imagem pronta, via o campo [`attachment`](./tasks.md#anexos-screenshots) de `captureException`/`captureMessage`.
373
373
 
374
374
  **O binário não passa pela API do Hobots.** O agente pede uma URL presignada, sobe direto no S3 e depois confirma. Isso mantém a API livre de tráfego pesado e permite imagens bem maiores do que o limite de corpo de um PATCH. O ciclo de vida de um anexo é:
375
375
 
@@ -88,7 +88,7 @@ Hobots.init({
88
88
 
89
89
  Hobots.register('processar-nfe', async (params, ctx) => {
90
90
  ctx.log.info(`processando lote ${params.lote}…`);
91
- // await ctx.attach(await page.screenshot(), { caption: 'portal após o login' }); // print junto do log
91
+ // Hobots.captureMessage('portal após o login', 'info', { attachment: await page.screenshot() }); // print junto do log
92
92
  ctx.log.info('12 notas processadas'); // o retorno do handler é ignorado — reporte por log
93
93
  });
94
94
  Hobots.start(); // mantém o processo vivo até stop()/close()
package/docs/tasks.md CHANGED
@@ -52,7 +52,6 @@ interface RunContext {
52
52
  signal: AbortSignal;
53
53
  throwIfCanceled(): void;
54
54
  sleep(ms: number): Promise<void>;
55
- attach(image, options?): Promise<AttachResult>; // anexa um print a uma linha de log
56
55
  }
57
56
  ```
58
57
 
@@ -62,7 +61,6 @@ interface RunContext {
62
61
  - **`ctx.signal`** — `AbortSignal` que dispara quando a run é **cancelada no app**, em **timeout** ou no **shutdown**. Cancelamento é cooperativo (veja abaixo).
63
62
  - **`ctx.throwIfCanceled()`** — lança `RunCanceled` se o `signal` já disparou. O ponto de parada de 1 linha para chamar entre as etapas do trabalho.
64
63
  - **`ctx.sleep(ms)`** — sleep que respeita o `signal`: rejeita com `RunCanceled` no cancelamento em vez de esperar até o fim. Use no lugar do seu `sleep` em esperas longas.
65
- - **`ctx.attach(image, options?)`** — anexa um print da tela a uma linha de log (veja [Anexos](#anexos-screenshots) abaixo).
66
64
  - **Retorno** — **ignorado**. O SDK não captura nem envia o valor retornado pelo handler ao servidor — resultados de execução podem conter dados sensíveis e não são coletados.
67
65
  - **Erro lançado** — a run é reportada como `failed` com tipo/mensagem/stack (mensagem cap 10k, stack 20k).
68
66
 
@@ -72,18 +70,22 @@ Você pode tipar os params: `Hobots.register<{ lote: number }>(...)`.
72
70
 
73
71
  ## Anexos (screenshots)
74
72
 
75
- Texto de log conta o que o robô fez; um print conta **como estava a tela**. `ctx.attach()` anexa uma imagem a uma linha de log, e ela aparece como miniatura logo abaixo dela na aba "logs do agente" da execução — clicável para ampliar.
73
+ Texto de log conta o que o robô fez; um print conta **como estava a tela**. Os métodos de captura — `Hobots.captureException(error, hint)` e `Hobots.captureMessage(message, level, hint)` — aceitam um **`attachment`** no hint. Dentro de uma execução de task, a imagem vira anexo da linha de log da run que espelha a captura, e aparece como miniatura logo abaixo dela na aba "logs do agente" da execução — clicável para ampliar.
76
74
 
77
75
  ```js
78
76
  Hobots.register('processar-nfe', async (params, ctx) => {
79
77
  await entrar();
80
- await ctx.attach(await page.screenshot(), { caption: 'portal após o login' });
78
+ Hobots.captureMessage('portal após o login', 'info', {
79
+ attachment: await page.screenshot(),
80
+ });
81
81
 
82
82
  try {
83
83
  await emitir(params);
84
84
  } catch (erro) {
85
85
  // numa falha é justamente quando o print importa
86
- await ctx.attach(await page.screenshot(), { caption: 'tela no momento do erro', level: 'error' });
86
+ Hobots.captureException(erro, {
87
+ attachment: { image: await page.screenshot(), caption: 'tela no momento do erro' },
88
+ });
87
89
  throw erro;
88
90
  }
89
91
  });
@@ -93,20 +95,22 @@ Hobots.register('processar-nfe', async (params, ctx) => {
93
95
 
94
96
  ### O que aceita
95
97
 
98
+ O `attachment` pode ser a imagem direto, ou um objeto com metadados:
99
+
96
100
  | Entrada | Exemplo |
97
101
  | --- | --- |
98
102
  | bytes | `Uint8Array`, `ArrayBuffer` ou `Buffer` — `await page.screenshot()` |
99
103
  | caminho de arquivo | `'C:\\prints\\tela.png'` (só em Node) |
104
+ | objeto | `{ image, caption?, contentType? }` |
100
105
 
101
- ### Opções
102
-
103
- | Opção | Tipo | Default | O que faz |
106
+ | Campo do objeto | Tipo | Default | O que faz |
104
107
  | --- | --- | --- | --- |
108
+ | `image` | bytes ou caminho | — | a imagem em si |
105
109
  | `caption` | `string` | — | legenda curta exibida sob a imagem ampliada (máx. 200 caracteres) |
106
- | `level` | `RunLogLevel` | `'info'` | nível da linha de log que carrega o anexo |
107
- | `message` | `string` | a legenda, ou `'captura de tela'` | texto da linha de log |
108
110
  | `contentType` | `'image/png' \| 'image/jpeg' \| 'image/webp'` | detectado | só é usado quando os *magic bytes* não bastam |
109
111
 
112
+ O texto da linha de log é a própria mensagem capturada (`message` do `captureMessage`, ou `Nome: mensagem` do erro no `captureException`); o nível vem do `level` da captura (`'fatal'` vira `'error'` no log da run).
113
+
110
114
  ### Limites
111
115
 
112
116
  | Limite | Valor |
@@ -121,9 +125,9 @@ Hobots.register('processar-nfe', async (params, ctx) => {
121
125
 
122
126
  A linha de log é registrada **na hora**, com o id do anexo; o upload roda em segundo plano. O binário vai direto para o S3 por uma URL presignada — não passa pela API do Hobots. Enquanto o upload não termina, o app mostra a miniatura como "enviando imagem…".
123
127
 
124
- `attach()` **nunca lança**. Todo insucesso vira `{ ok: false, reason }` e um aviso no log da run:
128
+ O anexo **nunca faz a captura lançar**. Todo insucesso vira um aviso no log da run:
125
129
 
126
- | `reason` | Quando |
130
+ | Motivo | Quando |
127
131
  | --- | --- |
128
132
  | `too-large` | acima de 5 MB |
129
133
  | `quota` | passou de 20 anexos na execução |
@@ -133,7 +137,9 @@ A linha de log é registrada **na hora**, com o id do anexo; o upload roda em se
133
137
  | `upload-failed` | falha de rede depois dos retries |
134
138
  | `canceled` | a run foi cancelada ou encerrada durante o upload |
135
139
 
136
- Você pode `await` para saber o desfecho, ou disparar sem esperar (`void ctx.attach(...)`) — antes de reportar o desfecho da run, o SDK aguarda os uploads pendentes por até 15 s, para a execução não terminar com miniaturas em "enviando…".
140
+ O upload é sempre fire-and-forget — a captura retorna na hora. Antes de reportar o desfecho da run, o SDK aguarda os uploads pendentes por até 15 s, para a execução não terminar com miniaturas em "enviando…".
141
+
142
+ > **Fora de uma execução:** `attachment` só funciona dentro de um handler de task — fora dele não existe log de run para pendurar a imagem, e o SDK descarta o anexo com um aviso no console (o evento em si é capturado normalmente).
137
143
 
138
144
  > **Dados sensíveis:** o print é enviado ao servidor **exatamente como está** — o SDK não borra nem recorta nada. Uma tela de portal costuma conter CPF, nome, saldo, número de documento. Capture apenas o necessário e evite prints de telas com dados de terceiros. Solicitantes (papel `requester`) só veem os anexos quando o projeto está com "mostrar logs para solicitantes" ligado, o mesmo gate dos logs.
139
145
 
@@ -178,6 +184,8 @@ Hobots.register('processar-nfe', async (params, ctx) => {
178
184
 
179
185
  Quando o cancelamento veio do app, a run já está `cancelada` no servidor — o erro `RunCanceled` lançado pelo handler é suprimido, nada é reportado por cima. Para lógica de limpeza antes de parar (fechar navegador, desfazer estado), use `try/finally` ou escute `ctx.signal` diretamente.
180
186
 
187
+ Se o handler **nunca** checar `ctx.signal` (loop sem `throwIfCanceled()`, `sleep()` genérico em vez de `ctx.sleep()`), o SDK ainda assim não trava o agente: depois de `cancelGraceMs` (default `10_000`) a partir do disparo de `ctx.signal`, o agente desiste de esperar aquele handler e libera o slot de concorrência para novas runs — logando um aviso. Isso não mata o handler (ele pode continuar rodando em segundo plano, sem efeito no app já que a run está cancelada), só evita que uma run "zumbi" trave o agente inteiro num `concurrency` baixo.
188
+
181
189
  ## Encerramento inesperado
182
190
 
183
191
  Se o processo do agente **morre no meio de uma run**, a solicitação vira **falha** no app com erro `AgentTerminated` ("execução encerrada inesperadamente") — sem re-execução automática. Dois caminhos garantem isso:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hobots",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "description": "SDK JavaScript da Hobots — telemetria (erros, transactions e heartbeats) e execução remota de tarefas sob demanda (tasks) para RPAs e integrações. Um único import e um único init().",
5
5
  "type": "module",
6
6
  "sideEffects": false,