hobots 3.3.0 → 3.4.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 +4 -4
- package/dist/index.cjs +155 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -36
- package/dist/index.d.ts +74 -36
- package/dist/index.js +155 -86
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.cts +5 -3
- package/dist/protocol.d.ts +5 -3
- package/docs/api-reference.md +7 -6
- package/docs/protocol.md +9 -6
- package/docs/tasks.md +26 -7
- package/package.json +4 -2
package/dist/protocol.d.cts
CHANGED
|
@@ -204,7 +204,7 @@ type RunItemStatus = 'succeeded' | 'failed' | 'occurrence';
|
|
|
204
204
|
interface RunItemInput {
|
|
205
205
|
/**
|
|
206
206
|
* Identidade do item dentro da run — id de negócio do dev (ex.: nº da nota)
|
|
207
|
-
* ou uuid4-hex gerado pelo SDK. Repetido na mesma run =
|
|
207
|
+
* ou uuid4-hex gerado pelo SDK. Repetido na mesma run = upsert (vale o último reporte).
|
|
208
208
|
*/
|
|
209
209
|
id: string;
|
|
210
210
|
/** Ordem de emissão no agente (contador monotônico por run) */
|
|
@@ -216,6 +216,8 @@ interface RunItemInput {
|
|
|
216
216
|
payload?: Record<string, unknown>;
|
|
217
217
|
/** ISO 8601 — relógio do agente, apenas para exibição */
|
|
218
218
|
ts?: string;
|
|
219
|
+
/** Ids de anexo (print do item) — opcional; mesmo teto por entrada das linhas de log */
|
|
220
|
+
attachments?: string[];
|
|
219
221
|
}
|
|
220
222
|
/** POST /v1/tasks/runs/{id}/items — aceito mesmo com a run cancelada/terminal */
|
|
221
223
|
interface RunItemsCreateRequest {
|
|
@@ -231,13 +233,13 @@ interface RunItemsCreateResponse {
|
|
|
231
233
|
type RunAttachmentContentType = 'image/png' | 'image/jpeg' | 'image/webp';
|
|
232
234
|
/** POST /v1/tasks/runs/{id}/attachments */
|
|
233
235
|
interface RunAttachmentCreateRequest {
|
|
234
|
-
/** Id do anexo gerado pelo agente (32 hex) — já referenciado
|
|
236
|
+
/** Id do anexo gerado pelo agente (32 hex) — já referenciado no log/item/step que o carrega */
|
|
235
237
|
id: string;
|
|
236
238
|
content_type: RunAttachmentContentType;
|
|
237
239
|
/** Tamanho exato do binário; o PUT presignado é assinado com este Content-Length */
|
|
238
240
|
size_bytes: number;
|
|
239
241
|
caption?: string;
|
|
240
|
-
/** ISO 8601 — ts
|
|
242
|
+
/** ISO 8601 — ts do evento (log/item/step) que referencia o anexo */
|
|
241
243
|
log_ts?: string;
|
|
242
244
|
width?: number;
|
|
243
245
|
height?: number;
|
package/dist/protocol.d.ts
CHANGED
|
@@ -204,7 +204,7 @@ type RunItemStatus = 'succeeded' | 'failed' | 'occurrence';
|
|
|
204
204
|
interface RunItemInput {
|
|
205
205
|
/**
|
|
206
206
|
* Identidade do item dentro da run — id de negócio do dev (ex.: nº da nota)
|
|
207
|
-
* ou uuid4-hex gerado pelo SDK. Repetido na mesma run =
|
|
207
|
+
* ou uuid4-hex gerado pelo SDK. Repetido na mesma run = upsert (vale o último reporte).
|
|
208
208
|
*/
|
|
209
209
|
id: string;
|
|
210
210
|
/** Ordem de emissão no agente (contador monotônico por run) */
|
|
@@ -216,6 +216,8 @@ interface RunItemInput {
|
|
|
216
216
|
payload?: Record<string, unknown>;
|
|
217
217
|
/** ISO 8601 — relógio do agente, apenas para exibição */
|
|
218
218
|
ts?: string;
|
|
219
|
+
/** Ids de anexo (print do item) — opcional; mesmo teto por entrada das linhas de log */
|
|
220
|
+
attachments?: string[];
|
|
219
221
|
}
|
|
220
222
|
/** POST /v1/tasks/runs/{id}/items — aceito mesmo com a run cancelada/terminal */
|
|
221
223
|
interface RunItemsCreateRequest {
|
|
@@ -231,13 +233,13 @@ interface RunItemsCreateResponse {
|
|
|
231
233
|
type RunAttachmentContentType = 'image/png' | 'image/jpeg' | 'image/webp';
|
|
232
234
|
/** POST /v1/tasks/runs/{id}/attachments */
|
|
233
235
|
interface RunAttachmentCreateRequest {
|
|
234
|
-
/** Id do anexo gerado pelo agente (32 hex) — já referenciado
|
|
236
|
+
/** Id do anexo gerado pelo agente (32 hex) — já referenciado no log/item/step que o carrega */
|
|
235
237
|
id: string;
|
|
236
238
|
content_type: RunAttachmentContentType;
|
|
237
239
|
/** Tamanho exato do binário; o PUT presignado é assinado com este Content-Length */
|
|
238
240
|
size_bytes: number;
|
|
239
241
|
caption?: string;
|
|
240
|
-
/** ISO 8601 — ts
|
|
242
|
+
/** ISO 8601 — ts do evento (log/item/step) que referencia o anexo */
|
|
241
243
|
log_ts?: string;
|
|
242
244
|
width?: number;
|
|
243
245
|
height?: number;
|
package/docs/api-reference.md
CHANGED
|
@@ -25,17 +25,18 @@ ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois da
|
|
|
25
25
|
| --- | --- | --- |
|
|
26
26
|
| `runId`, `task` | `string` | Identidade da execução (`''` fora de uma execução) |
|
|
27
27
|
| `params` | `Record<string, unknown>` | Params da solicitação; `{}` no modo start |
|
|
28
|
-
| `log` | `RunLogger` — `debug/info/warn/error/success(message, ...rest)` | Nunca lança. Vários argumentos viram texto unidos por espaço (como `console.log`) |
|
|
29
|
-
| `items` | `RunItems` — `add(item)`, `succeeded(payload?, opts?)`, `failed(message, payload?, opts?)`, `occurrence(message, payload?, opts?)`; `opts.id` = identidade de negócio. `each(list, (element, item, index) => …, { id?, payload?, op?, description?, progress? }) => Promise<{ total, succeeded, failed, occurrence }>` processa a lista inteira: exceção no handler vira item `failed` + step em erro e o loop segue; `item: RunItemHandle` = `succeeded/failed/occurrence`, `id`, `index`, `step`, `reported` | Ponto de parada cooperativo (o `each` para só em cancelamento/timeout) |
|
|
28
|
+
| `log` | `RunLogger` — `debug/info/warn/error/success(message, ...rest)` | Nunca lança. Vários argumentos viram texto unidos por espaço (como `console.log`); um `hobots.image(...)` no **último** argumento vira o print da linha |
|
|
29
|
+
| `items` | `RunItems` — `add(item)`, `succeeded(payload?, opts?)`, `failed(message, payload?, opts?)`, `occurrence(message, payload?, opts?)`; `opts.id` = identidade de negócio, `opts.image` = print do item. `each(list, (element, item, index) => …, { id?, payload?, op?, description?, progress? }) => Promise<{ total, succeeded, failed, occurrence }>` processa a lista inteira: exceção no handler vira item `failed` + step em erro e o loop segue; `item: RunItemHandle` = `succeeded(payload?, { image }?)/failed(msg, payload?, { image }?)/occurrence(…)`, `id`, `index`, `step`, `reported` | Ponto de parada cooperativo (o `each` para só em cancelamento/timeout) |
|
|
30
30
|
| `progress` | `RunProgressReporter` — `total(n)`, `advance(count = 1)`, `set(current, total?)`, `current`, `snapshot` | `total/advance/set` são pontos de parada |
|
|
31
|
-
| `transaction` | `Transaction` — `startChild(op?, description?)`, `setTag`, `setStatus`, `setName`; `Step` — `startChild`, `setStatus('ok' \| 'warning' \| 'error', message?)`, `setError(err, message?)` (motivo em `data.error`,
|
|
31
|
+
| `transaction` | `Transaction` — `startChild(op?, description?)`, `setTag`, `setStatus`, `setName`; `Step` — `startChild`, `setStatus('ok' \| 'warning' \| 'error', message?, { image }?)`, `setError(err, message?, { image }?)` (motivo em `data.error`, print em `data.attachments`, exibidos na Central), `setData(k, v)`, `finish()` | Finalizada pelo SDK; `startChild` é ponto de parada |
|
|
32
32
|
| `signal` | `AbortSignal` | Cancelamento (app, timeout, shutdown) |
|
|
33
33
|
| `throwIfCanceled()` | `() => void` | Lança `RunCanceled` se o signal disparou |
|
|
34
34
|
| `sleep(ms)` | `(ms: number) => Promise<void>` | Rejeita com `RunCanceled` no cancelamento |
|
|
35
|
-
| `attach(image, options?)` | `(image: AttachInput, options?: AttachOptions) => Promise<AttachResult>` | `AttachInput = Uint8Array \| ArrayBuffer \| string` (caminho); `AttachOptions = { caption?, level?, message?, contentType? }`; `AttachResult = { id, ok, reason? }`. Nunca lança |
|
|
36
35
|
| `retry(fn, options?)` | como `hobots.retry` | |
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
`hobots.image(input, options?)` — `(input: AttachInput, options?: ImageOptions) => ImageAttachment`; `AttachInput = Uint8Array \| ArrayBuffer \| string` (caminho); `ImageOptions = { caption?, contentType? }`; `ImageInput = AttachInput \| ImageAttachment` é o que `log.*` (só o embrulho), `items.*` e `step.setStatus/setError` aceitam. Puro, nunca lança; o upload (segundo plano, nunca bloqueia) acontece quando o evento é registrado.
|
|
38
|
+
|
|
39
|
+
Fora de uma execução, `hobots.*` cai em fallbacks seguros com aviso único por membro (log ecoa no terminal, imagem descartada; items/progress no-op; `signal` nunca aborta).
|
|
39
40
|
|
|
40
41
|
## Tabelas de opções
|
|
41
42
|
|
|
@@ -88,7 +89,7 @@ Fora de uma execução, `hobots.*` cai em fallbacks seguros com aviso único por
|
|
|
88
89
|
| --- | --- | --- |
|
|
89
90
|
| `type` | `'fatal' \| 'error' \| 'warning' \| 'success'` | default `'error'` |
|
|
90
91
|
| `tags`, `extra`, `fingerprint` | | metadados do evento (`fingerprint` sobrescreve o agrupamento) |
|
|
91
|
-
| `attachment` | `
|
|
92
|
+
| `attachment` | `ImageInput \| { image, caption?, contentType? }` | print anexado à linha de log da execução atual |
|
|
92
93
|
|
|
93
94
|
### `TaskHandler`
|
|
94
95
|
|
package/docs/protocol.md
CHANGED
|
@@ -117,7 +117,7 @@ Corpo `RunUpdateRequest`:
|
|
|
117
117
|
"logs": [
|
|
118
118
|
{ "ts": "…", "level": "info", "message": "…" }, // delta; o servidor concatena
|
|
119
119
|
{ "ts": "…", "level": "info", "message": "portal após o login",
|
|
120
|
-
"attachments": ["<32 hex>"] } // opcional; ids de anexo (máx. 4)
|
|
120
|
+
"attachments": ["<32 hex>"] } // opcional; ids de anexo (máx. 4) — hobots.image() no log
|
|
121
121
|
],
|
|
122
122
|
"error": { "type": "Error", "message": "…", "stack": "…" }, // só com 'failed'
|
|
123
123
|
"progress": { "current": 10, "total": 100 } // opcional: snapshot de hobots.progress
|
|
@@ -149,13 +149,16 @@ Corpo `RunItemsCreateRequest`:
|
|
|
149
149
|
"status": "succeeded", // 'succeeded' | 'failed' | 'occurrence'
|
|
150
150
|
"message": "…", // opcional — motivo (failed/occurrence), máx. 2100
|
|
151
151
|
"payload": { "numero_nota": "12345", "cnpj_prestador": "…" }, // opcional, máx. 16 KB
|
|
152
|
-
"ts": "2026-08-10T12:00:00.000Z"
|
|
152
|
+
"ts": "2026-08-10T12:00:00.000Z", // opcional — relógio do agente, só exibição
|
|
153
|
+
"attachments": ["<32 hex>"] // opcional — ids de anexo (máx. 4): print do item
|
|
153
154
|
}
|
|
154
155
|
]
|
|
155
156
|
}
|
|
156
157
|
```
|
|
157
158
|
|
|
158
|
-
Resposta `200` `RunItemsCreateResponse`: `{ "accepted": 1, "duplicates": 0 }` — `duplicates` conta os
|
|
159
|
+
Resposta `200` `RunItemsCreateResponse`: `{ "accepted": 1, "duplicates": 0 }` — `duplicates` conta os colapsados por `(run, id)` repetido no mesmo lote (vale o último reporte; no banco é upsert).
|
|
160
|
+
|
|
161
|
+
- `attachments` é **opcional** e aditivo (uma API anterior ao recurso descarta o campo). As steps carregam o print do mesmo jeito, em `data.attachments` do `StepData` que vai no `POST /v1/ingest` da transaction — sem campo novo no wire.
|
|
159
162
|
|
|
160
163
|
- **Run cancelada/terminal aceita itens** (200): item é fato de trabalho já feito — mesmo racional do log tardio. Esta rota não tem 409.
|
|
161
164
|
- O insert e os **contadores materializados** da run (`items_total/succeeded/failed/occurrence`, que alimentam os totalizadores no app) saem num único statement atômico no servidor.
|
|
@@ -177,11 +180,11 @@ Corpo `RunAttachmentCreateRequest`:
|
|
|
177
180
|
|
|
178
181
|
```jsonc
|
|
179
182
|
{
|
|
180
|
-
"id": "<32 hex>", // gerado pelo agente, já referenciado
|
|
183
|
+
"id": "<32 hex>", // gerado pelo agente, já referenciado no log/item/step
|
|
181
184
|
"content_type": "image/png", // 'image/png' | 'image/jpeg' | 'image/webp'
|
|
182
185
|
"size_bytes": 184320, // exato — entra na assinatura da URL
|
|
183
186
|
"caption": "portal após o login", // opcional, máx. 500
|
|
184
|
-
"log_ts": "…", // opcional, ISO 8601 — ts
|
|
187
|
+
"log_ts": "…", // opcional, ISO 8601 — ts do evento (log/item/step)
|
|
185
188
|
"width": 1920, "height": 1080 // opcionais
|
|
186
189
|
}
|
|
187
190
|
```
|
|
@@ -216,7 +219,7 @@ Confirma o upload. Corpo `RunAttachmentConfirmRequest`: `{ "status": "uploaded"
|
|
|
216
219
|
|
|
217
220
|
É **conforto de UX**, não correção: enquanto não confirmado, o app mostra a miniatura como "enviando imagem…". O agente engole falhas desta chamada.
|
|
218
221
|
|
|
219
|
-
Limites de anexo (aplicados no SDK **e** no servidor): PNG/JPEG/WEBP, 5 MB por imagem, 20 por execução, 4 por linha de log.
|
|
222
|
+
Limites de anexo (aplicados no SDK **e** no servidor): PNG/JPEG/WEBP, 5 MB por imagem, 20 por execução, 4 por evento (linha de log, item ou step).
|
|
220
223
|
|
|
221
224
|
## Onde vive o claim atômico
|
|
222
225
|
|
package/docs/tasks.md
CHANGED
|
@@ -40,11 +40,11 @@ Isso funciona com `concurrency > 1` porque cada execução roda no seu contexto
|
|
|
40
40
|
|
|
41
41
|
| Membro | Notas |
|
|
42
42
|
| --- | --- |
|
|
43
|
-
| `hobots.log.<debug\|info\|warn\|error\|success>(msg)` | Enviado incrementalmente (PATCHes com throttle) e ecoado no terminal. Nunca lança. |
|
|
43
|
+
| `hobots.log.<debug\|info\|warn\|error\|success>(msg, ...rest)` | Enviado incrementalmente (PATCHes com throttle) e ecoado no terminal. Nunca lança. `hobots.image(...)` no último argumento = print da linha. |
|
|
44
44
|
| `hobots.items` | Ver [Itens](#itens-de-execução-hobotsitems) |
|
|
45
45
|
| `hobots.progress` | Ver [Progresso](#progresso-hobotsprogress) |
|
|
46
46
|
| `hobots.transaction` | Transaction da execução, já correlacionada e finalizada pelo SDK. `startChild(op, descrição)` = uma step no waterfall. |
|
|
47
|
-
| `hobots.
|
|
47
|
+
| `hobots.image(imagem, opts?)` | Ver [Imagens](#imagens-screenshots) |
|
|
48
48
|
| `hobots.captureException(erro, hint?)` | Issue no módulo Issues; `hint.attachment` anexa um print à linha de log |
|
|
49
49
|
| `hobots.retry(fn, opts?)` | Ver [Retry](#retry) |
|
|
50
50
|
| `hobots.sleep(ms)` · `hobots.signal` · `hobots.throwIfCanceled()` | Ver [Cancelamento](#cancelamento-cooperativo) |
|
|
@@ -124,20 +124,39 @@ for (const nota of notas) {
|
|
|
124
124
|
|
|
125
125
|
Opcional e independente de `items`. Sem `total()` nada é enviado. Snapshot absoluto que pega carona nos PATCHes de log (no pior caso 1/s); o PATCH terminal leva o valor final. `set(atual, total?)`, `current` e `snapshot` completam a API. `total/advance/set` são pontos de parada cooperativos; `current`/`snapshot` nunca lançam.
|
|
126
126
|
|
|
127
|
-
##
|
|
127
|
+
## Imagens (screenshots)
|
|
128
|
+
|
|
129
|
+
Um print vai **junto do evento** que ele ilustra — a linha de log, o item ou a step — para o
|
|
130
|
+
usuário ver o estado do robô no momento em que aquilo aconteceu (botão de imagem no app):
|
|
128
131
|
|
|
129
132
|
```js
|
|
130
|
-
|
|
133
|
+
// na linha de log: hobots.image(...) como ÚLTIMO argumento
|
|
134
|
+
hobots.log.info('portal após o login', hobots.image(await page.screenshot()));
|
|
135
|
+
hobots.log.error('login falhou', hobots.image(await page.screenshot(), { caption: 'tela do erro' }));
|
|
136
|
+
|
|
137
|
+
// no item
|
|
138
|
+
hobots.items.failed('nota rejeitada', { numero }, { image: await page.screenshot() });
|
|
139
|
+
await hobots.items.each(notas, async (nota, item) => {
|
|
140
|
+
…
|
|
141
|
+
item.occurrence('sem fatura no mês', undefined, { image: await page.screenshot() });
|
|
142
|
+
});
|
|
131
143
|
|
|
144
|
+
// na step
|
|
145
|
+
const step = hobots.transaction.startChild('emitir', numero);
|
|
132
146
|
try {
|
|
133
|
-
await emitir(
|
|
147
|
+
await emitir(numero);
|
|
134
148
|
} catch (erro) {
|
|
135
|
-
|
|
149
|
+
step.setError(erro, undefined, { image: await page.screenshot() });
|
|
136
150
|
throw erro;
|
|
151
|
+
} finally {
|
|
152
|
+
step.finish();
|
|
137
153
|
}
|
|
154
|
+
|
|
155
|
+
// numa issue (módulo Issues) — o print vai na linha de log que espelha o erro
|
|
156
|
+
hobots.captureException(erro, { attachment: hobots.image(await page.screenshot(), { caption: 'tela no momento do erro' }) });
|
|
138
157
|
```
|
|
139
158
|
|
|
140
|
-
O SDK não tira o print: aceita bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo.
|
|
159
|
+
O SDK não tira o print: aceita bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo, crus ou embrulhados por `hobots.image(bytes, { caption?, contentType? })` (só o embrulho leva legenda; em `log.*` ele é obrigatório para distinguir a imagem de um argumento comum). O evento entra na hora com o id do anexo; o upload sobe em segundo plano direto para o S3 (URL presignada) e **nunca lança nem bloqueia** — falhas viram um aviso no log da execução. Limites: PNG/JPEG/WEBP, 5 MB, 20 por execução, 4 por evento. Fora de uma execução não há onde pendurar a imagem (descartada com aviso). O `hobots.attach` das versões anteriores foi removido nesta API.
|
|
141
160
|
|
|
142
161
|
## Cancelamento cooperativo
|
|
143
162
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hobots",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "SDK JavaScript da Hobots
|
|
3
|
+
"version": "3.4.0",
|
|
4
|
+
"description": "SDK JavaScript da Hobots — tudo é uma task: register() atende solicitações da plataforma, start() roda sempre e reporta logs, itens e progresso. Credenciais por env, heartbeat sempre ligado, objeto global `hobots`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"license": "MIT",
|
|
@@ -33,11 +33,13 @@
|
|
|
33
33
|
"dev": "tsup --watch",
|
|
34
34
|
"lint": "eslint . --max-warnings 0",
|
|
35
35
|
"test": "vitest run",
|
|
36
|
+
"test:coverage": "vitest run --coverage",
|
|
36
37
|
"test:watch": "vitest",
|
|
37
38
|
"typecheck": "tsc --noEmit"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@types/node": "^20",
|
|
42
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
41
43
|
"@workspace/eslint-config": "workspace:*",
|
|
42
44
|
"@workspace/typescript-config": "workspace:*",
|
|
43
45
|
"@workspace/utils": "workspace:*",
|