hobots 3.2.2 → 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 +5 -4
- package/dist/chunk-5WIIACWC.js +31 -0
- package/dist/chunk-5WIIACWC.js.map +1 -0
- package/dist/index.cjs +313 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +123 -31
- package/dist/index.d.ts +123 -31
- package/dist/index.js +290 -99
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs +34 -0
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +62 -7
- package/dist/protocol.d.ts +62 -7
- package/dist/protocol.js +6 -0
- package/docs/api-reference.md +7 -6
- package/docs/protocol.md +9 -6
- package/docs/tasks.md +54 -8
- package/package.json +4 -1
package/dist/protocol.cjs
CHANGED
|
@@ -3,6 +3,10 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
6
10
|
var __copyProps = (to, from, except, desc) => {
|
|
7
11
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
12
|
for (let key of __getOwnPropNames(from))
|
|
@@ -15,5 +19,35 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
15
19
|
|
|
16
20
|
// src/protocol.ts
|
|
17
21
|
var protocol_exports = {};
|
|
22
|
+
__export(protocol_exports, {
|
|
23
|
+
WIRE_LIMITS: () => WIRE_LIMITS
|
|
24
|
+
});
|
|
18
25
|
module.exports = __toCommonJS(protocol_exports);
|
|
26
|
+
|
|
27
|
+
// protocol-limits.json
|
|
28
|
+
var protocol_limits_default = {
|
|
29
|
+
MAX_ITEMS_PER_ENVELOPE: 50,
|
|
30
|
+
HEARTBEAT_DEFAULT_INTERVAL_MS: 3e4,
|
|
31
|
+
HEARTBEAT_MIN_INTERVAL_MS: 1e3,
|
|
32
|
+
HEARTBEAT_MAX_INTERVAL_MS: 9e5,
|
|
33
|
+
MAX_CLAIM_PER_POLL: 5,
|
|
34
|
+
MAX_LOG_MESSAGE_CHARS: 1e4,
|
|
35
|
+
MAX_LOGS_PER_PATCH: 100,
|
|
36
|
+
MAX_ERROR_MESSAGE_CHARS: 1e4,
|
|
37
|
+
MAX_ERROR_STACK_CHARS: 2e4,
|
|
38
|
+
MAX_ITEMS_PER_RUN: 1e4,
|
|
39
|
+
MAX_ITEMS_PER_REQUEST: 500,
|
|
40
|
+
MAX_ITEM_MESSAGE_CHARS: 2e3,
|
|
41
|
+
MAX_ITEM_PAYLOAD_BYTES: 16384,
|
|
42
|
+
MAX_ITEM_COLUMNS: 12,
|
|
43
|
+
MAX_ITEM_COLUMN_LABEL_CHARS: 60,
|
|
44
|
+
MAX_ATTACHMENT_BYTES: 5242880,
|
|
45
|
+
MAX_ATTACHMENTS_PER_RUN: 20,
|
|
46
|
+
MAX_ATTACHMENTS_PER_LOG_ENTRY: 4,
|
|
47
|
+
MAX_CAPTION_CHARS: 200,
|
|
48
|
+
MAX_IMAGE_DIMENSION_PX: 2e4
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/wire-limits.ts
|
|
52
|
+
var WIRE_LIMITS = protocol_limits_default;
|
|
19
53
|
//# sourceMappingURL=protocol.cjs.map
|
package/dist/protocol.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format
|
|
1
|
+
{"version":3,"sources":["../src/protocol.ts","../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida\n * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)\n * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único\n * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.\n */\n\nexport { WIRE_LIMITS, type WireLimits } from './wire-limits';\n\nimport type { EnvironmentInput } from './environment-protocol';\nimport type { MachineSnapshot } from './machine-protocol';\n\n// Wire format de tasks (agente ↔ servidor) — reexportado aqui para o app\n// consumir tudo de `hobots/protocol`.\nexport type {\n RunStatus,\n RunUpdateStatus,\n RunLogLevel,\n RunLogEntry,\n InstanceInfo,\n PollRequest,\n RunDescriptor,\n PollResponse,\n RunCreateRequest,\n RunCreateResponse,\n RunError,\n RunProgress,\n RunUpdateRequest,\n RunUpdateResponse,\n RunItemStatus,\n RunItemInput,\n RunItemsCreateRequest,\n RunItemsCreateResponse,\n ItemColumn,\n TaskItemsDeclaration,\n RunAttachmentContentType,\n RunAttachmentCreateRequest,\n RunAttachmentCreateResponse,\n RunAttachmentConfirmRequest,\n RunAttachmentConfirmResponse,\n} from './tasks/protocol';\n\n// Snapshot de recursos da máquina — usado no heartbeat, no poll e em contexts.machine.\nexport type { MachineProcess, MachineSnapshot } from './machine-protocol';\nexport type { Environment, EnvironmentInput } from './environment-protocol';\n\n/**\n * Tipo de um evento — o que ele é, não o quanto ele fala. Só 'fatal', 'error' e\n * 'warning' viram issue; 'success' é ingerido e nunca abre issue.\n * Ruído de log não é evento: para isso existem os logs da execução (RunLogLevel)\n * e as breadcrumbs, que têm níveis próprios com 'debug'/'info'.\n */\nexport type EventType = 'fatal' | 'error' | 'warning' | 'success';\n\n/** Nível de uma breadcrumb — trilha do que aconteceu antes, aqui log é bem-vindo. */\nexport type BreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error' | 'fatal';\n\n/** Frames em ordem innermost-first (mesma ordem impressa pelo V8). */\nexport interface StackFrame {\n function?: string;\n filename?: string;\n lineno?: number;\n colno?: number;\n in_app: boolean;\n}\n\nexport interface Breadcrumb {\n /** ISO 8601 */\n timestamp: string;\n type?: string;\n category?: string;\n message?: string;\n level?: BreadcrumbLevel;\n data?: Record<string, unknown>;\n}\n\nexport interface ExceptionData {\n type: string;\n value: string;\n stacktrace?: { frames: StackFrame[] };\n}\n\nexport interface EventUser {\n id?: string;\n username?: string;\n email?: string;\n}\n\nexport interface EventPayload {\n /** uuid v4 sem hífens (32 hex), gerado pelo SDK */\n event_id: string;\n /** ISO 8601 */\n timestamp: string;\n type: EventType;\n message?: string;\n exception?: ExceptionData;\n /** Override de agrupamento; quando ausente o servidor calcula pelo stack trace */\n fingerprint?: string[];\n breadcrumbs?: Breadcrumb[];\n tags?: Record<string, string>;\n user?: EventUser;\n contexts?: Record<string, Record<string, unknown>>;\n extra?: Record<string, unknown>;\n release?: string;\n environment?: EnvironmentInput;\n}\n\n/** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */\nexport type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled';\n\nexport interface StepData {\n /** 16 hex */\n step_id: string;\n parent_step_id?: string;\n op?: string;\n description?: string;\n status?: StepStatus;\n /** ISO 8601 */\n start_timestamp: string;\n /** ISO 8601 (fim da step) */\n timestamp: string;\n data?: Record<string, unknown>;\n}\n\nexport interface TransactionPayload {\n event_id: string;\n name: string;\n op?: string;\n status: string;\n start_timestamp: string;\n timestamp: string;\n steps: StepData[];\n tags?: Record<string, string>;\n release?: string;\n environment?: EnvironmentInput;\n /** Correlaciona esta transaction a uma execução de task (ctx.tx dentro de um task handler) */\n run_id?: string;\n}\n\nexport interface HeartbeatPayload {\n instance_id: string;\n name?: string;\n interval_ms: number;\n /** ISO 8601 */\n timestamp: string;\n metadata?: Record<string, unknown>;\n release?: string;\n /** Ambiente da instância — é ele que o app exibe e que as regras de alerta filtram */\n environment?: EnvironmentInput;\n /** Recursos da máquina no momento do beat (CPU, memória, disco, processo) */\n machine?: MachineSnapshot;\n}\n\nexport type EnvelopeItem =\n | { type: 'event'; payload: EventPayload }\n | { type: 'transaction'; payload: TransactionPayload }\n | { type: 'heartbeat'; payload: HeartbeatPayload };\n\nexport interface Envelope {\n sdk: { name: string; version: string };\n /** ISO 8601 */\n sent_at: string;\n items: EnvelopeItem[];\n}\n","{\n \"MAX_ITEMS_PER_ENVELOPE\": 50,\n \"HEARTBEAT_DEFAULT_INTERVAL_MS\": 30000,\n \"HEARTBEAT_MIN_INTERVAL_MS\": 1000,\n \"HEARTBEAT_MAX_INTERVAL_MS\": 900000,\n \"MAX_CLAIM_PER_POLL\": 5,\n \"MAX_LOG_MESSAGE_CHARS\": 10000,\n \"MAX_LOGS_PER_PATCH\": 100,\n \"MAX_ERROR_MESSAGE_CHARS\": 10000,\n \"MAX_ERROR_STACK_CHARS\": 20000,\n \"MAX_ITEMS_PER_RUN\": 10000,\n \"MAX_ITEMS_PER_REQUEST\": 500,\n \"MAX_ITEM_MESSAGE_CHARS\": 2000,\n \"MAX_ITEM_PAYLOAD_BYTES\": 16384,\n \"MAX_ITEM_COLUMNS\": 12,\n \"MAX_ITEM_COLUMN_LABEL_CHARS\": 60,\n \"MAX_ATTACHMENT_BYTES\": 5242880,\n \"MAX_ATTACHMENTS_PER_RUN\": 20,\n \"MAX_ATTACHMENTS_PER_LOG_ENTRY\": 4,\n \"MAX_CAPTION_CHARS\": 200,\n \"MAX_IMAGE_DIMENSION_PX\": 20000\n}\n","import limits from '../protocol-limits.json';\n\n/**\n * Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK\n * Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python\n * confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o\n * JSON (e, no Python, a constante espelhada — o teste acusa).\n */\nexport const WIRE_LIMITS = limits as Readonly<typeof limits>;\nexport type WireLimits = typeof WIRE_LIMITS;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA,EACE,wBAA0B;AAAA,EAC1B,+BAAiC;AAAA,EACjC,2BAA6B;AAAA,EAC7B,2BAA6B;AAAA,EAC7B,oBAAsB;AAAA,EACtB,uBAAyB;AAAA,EACzB,oBAAsB;AAAA,EACtB,yBAA2B;AAAA,EAC3B,uBAAyB;AAAA,EACzB,mBAAqB;AAAA,EACrB,uBAAyB;AAAA,EACzB,wBAA0B;AAAA,EAC1B,wBAA0B;AAAA,EAC1B,kBAAoB;AAAA,EACpB,6BAA+B;AAAA,EAC/B,sBAAwB;AAAA,EACxB,yBAA2B;AAAA,EAC3B,+BAAiC;AAAA,EACjC,mBAAqB;AAAA,EACrB,wBAA0B;AAC5B;;;ACbO,IAAM,cAAc;","names":[]}
|
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;
|
|
@@ -262,12 +264,65 @@ interface RunAttachmentConfirmResponse {
|
|
|
262
264
|
ok: true;
|
|
263
265
|
}
|
|
264
266
|
|
|
267
|
+
var MAX_ITEMS_PER_ENVELOPE = 50;
|
|
268
|
+
var HEARTBEAT_DEFAULT_INTERVAL_MS = 30000;
|
|
269
|
+
var HEARTBEAT_MIN_INTERVAL_MS = 1000;
|
|
270
|
+
var HEARTBEAT_MAX_INTERVAL_MS = 900000;
|
|
271
|
+
var MAX_CLAIM_PER_POLL = 5;
|
|
272
|
+
var MAX_LOG_MESSAGE_CHARS = 10000;
|
|
273
|
+
var MAX_LOGS_PER_PATCH = 100;
|
|
274
|
+
var MAX_ERROR_MESSAGE_CHARS = 10000;
|
|
275
|
+
var MAX_ERROR_STACK_CHARS = 20000;
|
|
276
|
+
var MAX_ITEMS_PER_RUN = 10000;
|
|
277
|
+
var MAX_ITEMS_PER_REQUEST = 500;
|
|
278
|
+
var MAX_ITEM_MESSAGE_CHARS = 2000;
|
|
279
|
+
var MAX_ITEM_PAYLOAD_BYTES = 16384;
|
|
280
|
+
var MAX_ITEM_COLUMNS = 12;
|
|
281
|
+
var MAX_ITEM_COLUMN_LABEL_CHARS = 60;
|
|
282
|
+
var MAX_ATTACHMENT_BYTES = 5242880;
|
|
283
|
+
var MAX_ATTACHMENTS_PER_RUN = 20;
|
|
284
|
+
var MAX_ATTACHMENTS_PER_LOG_ENTRY = 4;
|
|
285
|
+
var MAX_CAPTION_CHARS = 200;
|
|
286
|
+
var MAX_IMAGE_DIMENSION_PX = 20000;
|
|
287
|
+
var limits = {
|
|
288
|
+
MAX_ITEMS_PER_ENVELOPE: MAX_ITEMS_PER_ENVELOPE,
|
|
289
|
+
HEARTBEAT_DEFAULT_INTERVAL_MS: HEARTBEAT_DEFAULT_INTERVAL_MS,
|
|
290
|
+
HEARTBEAT_MIN_INTERVAL_MS: HEARTBEAT_MIN_INTERVAL_MS,
|
|
291
|
+
HEARTBEAT_MAX_INTERVAL_MS: HEARTBEAT_MAX_INTERVAL_MS,
|
|
292
|
+
MAX_CLAIM_PER_POLL: MAX_CLAIM_PER_POLL,
|
|
293
|
+
MAX_LOG_MESSAGE_CHARS: MAX_LOG_MESSAGE_CHARS,
|
|
294
|
+
MAX_LOGS_PER_PATCH: MAX_LOGS_PER_PATCH,
|
|
295
|
+
MAX_ERROR_MESSAGE_CHARS: MAX_ERROR_MESSAGE_CHARS,
|
|
296
|
+
MAX_ERROR_STACK_CHARS: MAX_ERROR_STACK_CHARS,
|
|
297
|
+
MAX_ITEMS_PER_RUN: MAX_ITEMS_PER_RUN,
|
|
298
|
+
MAX_ITEMS_PER_REQUEST: MAX_ITEMS_PER_REQUEST,
|
|
299
|
+
MAX_ITEM_MESSAGE_CHARS: MAX_ITEM_MESSAGE_CHARS,
|
|
300
|
+
MAX_ITEM_PAYLOAD_BYTES: MAX_ITEM_PAYLOAD_BYTES,
|
|
301
|
+
MAX_ITEM_COLUMNS: MAX_ITEM_COLUMNS,
|
|
302
|
+
MAX_ITEM_COLUMN_LABEL_CHARS: MAX_ITEM_COLUMN_LABEL_CHARS,
|
|
303
|
+
MAX_ATTACHMENT_BYTES: MAX_ATTACHMENT_BYTES,
|
|
304
|
+
MAX_ATTACHMENTS_PER_RUN: MAX_ATTACHMENTS_PER_RUN,
|
|
305
|
+
MAX_ATTACHMENTS_PER_LOG_ENTRY: MAX_ATTACHMENTS_PER_LOG_ENTRY,
|
|
306
|
+
MAX_CAPTION_CHARS: MAX_CAPTION_CHARS,
|
|
307
|
+
MAX_IMAGE_DIMENSION_PX: MAX_IMAGE_DIMENSION_PX
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK
|
|
312
|
+
* Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python
|
|
313
|
+
* confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o
|
|
314
|
+
* JSON (e, no Python, a constante espelhada — o teste acusa).
|
|
315
|
+
*/
|
|
316
|
+
declare const WIRE_LIMITS: Readonly<typeof limits>;
|
|
317
|
+
type WireLimits = typeof WIRE_LIMITS;
|
|
318
|
+
|
|
265
319
|
/**
|
|
266
320
|
* Tipos do protocolo do Hobots (SDK → servidor).
|
|
267
321
|
*
|
|
268
|
-
* Este arquivo é a fonte de verdade do wire format
|
|
269
|
-
*
|
|
270
|
-
*
|
|
322
|
+
* Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida
|
|
323
|
+
* os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)
|
|
324
|
+
* e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único
|
|
325
|
+
* valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.
|
|
271
326
|
*/
|
|
272
327
|
|
|
273
328
|
/**
|
|
@@ -388,4 +443,4 @@ interface Envelope {
|
|
|
388
443
|
items: EnvelopeItem[];
|
|
389
444
|
}
|
|
390
445
|
|
|
391
|
-
export type
|
|
446
|
+
export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type HeartbeatPayload, type InstanceInfo, type ItemColumn, type MachineProcess, type MachineSnapshot, type PollRequest, type PollResponse, type RunAttachmentConfirmRequest, type RunAttachmentConfirmResponse, type RunAttachmentContentType, type RunAttachmentCreateRequest, type RunAttachmentCreateResponse, type RunCreateRequest, type RunCreateResponse, type RunDescriptor, type RunError, type RunItemInput, type RunItemStatus, type RunItemsCreateRequest, type RunItemsCreateResponse, type RunLogEntry, type RunLogLevel, type RunProgress, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TaskItemsDeclaration, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
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;
|
|
@@ -262,12 +264,65 @@ interface RunAttachmentConfirmResponse {
|
|
|
262
264
|
ok: true;
|
|
263
265
|
}
|
|
264
266
|
|
|
267
|
+
var MAX_ITEMS_PER_ENVELOPE = 50;
|
|
268
|
+
var HEARTBEAT_DEFAULT_INTERVAL_MS = 30000;
|
|
269
|
+
var HEARTBEAT_MIN_INTERVAL_MS = 1000;
|
|
270
|
+
var HEARTBEAT_MAX_INTERVAL_MS = 900000;
|
|
271
|
+
var MAX_CLAIM_PER_POLL = 5;
|
|
272
|
+
var MAX_LOG_MESSAGE_CHARS = 10000;
|
|
273
|
+
var MAX_LOGS_PER_PATCH = 100;
|
|
274
|
+
var MAX_ERROR_MESSAGE_CHARS = 10000;
|
|
275
|
+
var MAX_ERROR_STACK_CHARS = 20000;
|
|
276
|
+
var MAX_ITEMS_PER_RUN = 10000;
|
|
277
|
+
var MAX_ITEMS_PER_REQUEST = 500;
|
|
278
|
+
var MAX_ITEM_MESSAGE_CHARS = 2000;
|
|
279
|
+
var MAX_ITEM_PAYLOAD_BYTES = 16384;
|
|
280
|
+
var MAX_ITEM_COLUMNS = 12;
|
|
281
|
+
var MAX_ITEM_COLUMN_LABEL_CHARS = 60;
|
|
282
|
+
var MAX_ATTACHMENT_BYTES = 5242880;
|
|
283
|
+
var MAX_ATTACHMENTS_PER_RUN = 20;
|
|
284
|
+
var MAX_ATTACHMENTS_PER_LOG_ENTRY = 4;
|
|
285
|
+
var MAX_CAPTION_CHARS = 200;
|
|
286
|
+
var MAX_IMAGE_DIMENSION_PX = 20000;
|
|
287
|
+
var limits = {
|
|
288
|
+
MAX_ITEMS_PER_ENVELOPE: MAX_ITEMS_PER_ENVELOPE,
|
|
289
|
+
HEARTBEAT_DEFAULT_INTERVAL_MS: HEARTBEAT_DEFAULT_INTERVAL_MS,
|
|
290
|
+
HEARTBEAT_MIN_INTERVAL_MS: HEARTBEAT_MIN_INTERVAL_MS,
|
|
291
|
+
HEARTBEAT_MAX_INTERVAL_MS: HEARTBEAT_MAX_INTERVAL_MS,
|
|
292
|
+
MAX_CLAIM_PER_POLL: MAX_CLAIM_PER_POLL,
|
|
293
|
+
MAX_LOG_MESSAGE_CHARS: MAX_LOG_MESSAGE_CHARS,
|
|
294
|
+
MAX_LOGS_PER_PATCH: MAX_LOGS_PER_PATCH,
|
|
295
|
+
MAX_ERROR_MESSAGE_CHARS: MAX_ERROR_MESSAGE_CHARS,
|
|
296
|
+
MAX_ERROR_STACK_CHARS: MAX_ERROR_STACK_CHARS,
|
|
297
|
+
MAX_ITEMS_PER_RUN: MAX_ITEMS_PER_RUN,
|
|
298
|
+
MAX_ITEMS_PER_REQUEST: MAX_ITEMS_PER_REQUEST,
|
|
299
|
+
MAX_ITEM_MESSAGE_CHARS: MAX_ITEM_MESSAGE_CHARS,
|
|
300
|
+
MAX_ITEM_PAYLOAD_BYTES: MAX_ITEM_PAYLOAD_BYTES,
|
|
301
|
+
MAX_ITEM_COLUMNS: MAX_ITEM_COLUMNS,
|
|
302
|
+
MAX_ITEM_COLUMN_LABEL_CHARS: MAX_ITEM_COLUMN_LABEL_CHARS,
|
|
303
|
+
MAX_ATTACHMENT_BYTES: MAX_ATTACHMENT_BYTES,
|
|
304
|
+
MAX_ATTACHMENTS_PER_RUN: MAX_ATTACHMENTS_PER_RUN,
|
|
305
|
+
MAX_ATTACHMENTS_PER_LOG_ENTRY: MAX_ATTACHMENTS_PER_LOG_ENTRY,
|
|
306
|
+
MAX_CAPTION_CHARS: MAX_CAPTION_CHARS,
|
|
307
|
+
MAX_IMAGE_DIMENSION_PX: MAX_IMAGE_DIMENSION_PX
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK
|
|
312
|
+
* Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python
|
|
313
|
+
* confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o
|
|
314
|
+
* JSON (e, no Python, a constante espelhada — o teste acusa).
|
|
315
|
+
*/
|
|
316
|
+
declare const WIRE_LIMITS: Readonly<typeof limits>;
|
|
317
|
+
type WireLimits = typeof WIRE_LIMITS;
|
|
318
|
+
|
|
265
319
|
/**
|
|
266
320
|
* Tipos do protocolo do Hobots (SDK → servidor).
|
|
267
321
|
*
|
|
268
|
-
* Este arquivo é a fonte de verdade do wire format
|
|
269
|
-
*
|
|
270
|
-
*
|
|
322
|
+
* Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida
|
|
323
|
+
* os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)
|
|
324
|
+
* e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único
|
|
325
|
+
* valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.
|
|
271
326
|
*/
|
|
272
327
|
|
|
273
328
|
/**
|
|
@@ -388,4 +443,4 @@ interface Envelope {
|
|
|
388
443
|
items: EnvelopeItem[];
|
|
389
444
|
}
|
|
390
445
|
|
|
391
|
-
export type
|
|
446
|
+
export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type HeartbeatPayload, type InstanceInfo, type ItemColumn, type MachineProcess, type MachineSnapshot, type PollRequest, type PollResponse, type RunAttachmentConfirmRequest, type RunAttachmentConfirmResponse, type RunAttachmentContentType, type RunAttachmentCreateRequest, type RunAttachmentCreateResponse, type RunCreateRequest, type RunCreateResponse, type RunDescriptor, type RunError, type RunItemInput, type RunItemStatus, type RunItemsCreateRequest, type RunItemsCreateResponse, type RunLogEntry, type RunLogLevel, type RunProgress, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TaskItemsDeclaration, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
package/dist/protocol.js
CHANGED
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 | Ponto de parada cooperativo |
|
|
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) |
|
|
@@ -67,10 +67,37 @@ hobots.items.add({ status: 'succeeded', id: '11', payload: { … } });
|
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
- Chamadas síncronas e bufferizadas (lotes de até 500); o SDK drena o buffer antes do reporte final.
|
|
70
|
-
- `id` é a identidade de negócio do item na execução — repetido, o
|
|
70
|
+
- `id` é a identidade de negócio do item na execução — repetido, **vale o último reporte** (o servidor faz upsert: uma conta que falhou numa tentativa e deu certo no retry fica como sucesso; retry de rede é no-op). Sem `id`, cada chamada é um item novo.
|
|
71
71
|
- Limites: 10.000 itens/execução, payload 16 KB, mensagem 2.000 caracteres. Uma execução cancelada ainda aceita os itens já bufferizados (trabalho feito).
|
|
72
72
|
- Cada chamada é um **ponto de parada cooperativo** (lança `RunCanceled` se a execução foi cancelada).
|
|
73
73
|
|
|
74
|
+
### Processar uma lista inteira (`hobots.items.each`)
|
|
75
|
+
|
|
76
|
+
O contrato da plataforma — **todo item previsto termina com um desfecho registrado, e a falha de um não interrompe os outros** — fica garantido pelo SDK quando o loop é dele:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
const resultado = await hobots.items.each(
|
|
80
|
+
contas,
|
|
81
|
+
async (conta, item) => {
|
|
82
|
+
await login(conta); // lançou → item `failed` com a mensagem, step em erro, segue
|
|
83
|
+
const fatura = await baixar(conta);
|
|
84
|
+
if (!fatura) return item.occurrence('sem fatura no mês'); // ocorrência de negócio
|
|
85
|
+
item.succeeded({ fatura: fatura.numero, valor: fatura.valor }); // mescla com o payload base
|
|
86
|
+
// retornou sem registrar nada → `succeeded`
|
|
87
|
+
},
|
|
88
|
+
{ id: c => c.numero_cliente, payload: c => ({ cpf_cnpj: c.cpf_cnpj, nome: c.nome }) }
|
|
89
|
+
);
|
|
90
|
+
// resultado = { total, succeeded, failed, occurrence }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- Cada elemento vira uma **step** no waterfall (`op` 'item', descrição = `id`; `item.step.startChild(...)` mede sub-etapas) e um **item** com o `id` e o payload base.
|
|
94
|
+
- **Exceção no handler** = item `failed` com a mensagem do erro, `step.setError(erro)`, linha de erro no log da run — e o loop **segue para o próximo**. Nada do que o handler já registrou (`item.failed/occurrence`) é sobrescrito.
|
|
95
|
+
- **Progresso automático**: declara o total pelo tamanho da lista (se o bot ainda não declarou um) e avança a cada elemento, inclusive nos que falharam. `progress: false` deixa o progresso por conta do bot.
|
|
96
|
+
- Só **cancelamento, timeout e shutdown** interrompem o loop: o `RunCanceled` sobe, o item em curso não é registrado e o progresso não avança.
|
|
97
|
+
- Aceita `Iterable` ou `AsyncIterable` (sem `length`, nenhum total é declarado).
|
|
98
|
+
|
|
99
|
+
> Se o handler da task termina com o progresso parado antes do total declarado (ex.: 45/76), o SDK deixa um aviso no log da execução — e a Central sinaliza o desencontro entre processados e itens reportados.
|
|
100
|
+
|
|
74
101
|
### Colunas da aba de itens
|
|
75
102
|
|
|
76
103
|
As colunas vêm do código, não do formulário — valem para `register()` (com ou sem formulário) e `start()`:
|
|
@@ -97,20 +124,39 @@ for (const nota of notas) {
|
|
|
97
124
|
|
|
98
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.
|
|
99
126
|
|
|
100
|
-
##
|
|
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):
|
|
101
131
|
|
|
102
132
|
```js
|
|
103
|
-
|
|
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
|
+
});
|
|
104
143
|
|
|
144
|
+
// na step
|
|
145
|
+
const step = hobots.transaction.startChild('emitir', numero);
|
|
105
146
|
try {
|
|
106
|
-
await emitir(
|
|
147
|
+
await emitir(numero);
|
|
107
148
|
} catch (erro) {
|
|
108
|
-
|
|
149
|
+
step.setError(erro, undefined, { image: await page.screenshot() });
|
|
109
150
|
throw erro;
|
|
151
|
+
} finally {
|
|
152
|
+
step.finish();
|
|
110
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' }) });
|
|
111
157
|
```
|
|
112
158
|
|
|
113
|
-
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.
|
|
114
160
|
|
|
115
161
|
## Cancelamento cooperativo
|
|
116
162
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hobots",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
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,
|
|
@@ -33,13 +33,16 @@
|
|
|
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:*",
|
|
45
|
+
"@workspace/utils": "workspace:*",
|
|
43
46
|
"tsup": "^8.4.0",
|
|
44
47
|
"typescript": "5.7.3",
|
|
45
48
|
"vitest": "^4.1.10"
|