hobots 3.2.1 → 3.3.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/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
@@ -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 e só pode reexportar tipos:\n * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>`\n * contra estes tipos (importados de `hobots/protocol`).\n */\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"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
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":[]}
@@ -222,9 +222,9 @@ interface RunItemsCreateRequest {
222
222
  items: RunItemInput[];
223
223
  }
224
224
  interface RunItemsCreateResponse {
225
- /** Itens inseridos */
225
+ /** Itens gravados — inseridos ou atualizados (id repetido na run: vale o último reporte) */
226
226
  accepted: number;
227
- /** Ignorados por id repetido na run (retry de rede é idempotente) */
227
+ /** Colapsados por id repetido dentro do mesmo lote (vale o de maior seq) */
228
228
  duplicates: number;
229
229
  }
230
230
  /** Formatos aceitos para anexo. O S3 valida o content-type contra a assinatura. */
@@ -262,12 +262,65 @@ interface RunAttachmentConfirmResponse {
262
262
  ok: true;
263
263
  }
264
264
 
265
+ var MAX_ITEMS_PER_ENVELOPE = 50;
266
+ var HEARTBEAT_DEFAULT_INTERVAL_MS = 30000;
267
+ var HEARTBEAT_MIN_INTERVAL_MS = 1000;
268
+ var HEARTBEAT_MAX_INTERVAL_MS = 900000;
269
+ var MAX_CLAIM_PER_POLL = 5;
270
+ var MAX_LOG_MESSAGE_CHARS = 10000;
271
+ var MAX_LOGS_PER_PATCH = 100;
272
+ var MAX_ERROR_MESSAGE_CHARS = 10000;
273
+ var MAX_ERROR_STACK_CHARS = 20000;
274
+ var MAX_ITEMS_PER_RUN = 10000;
275
+ var MAX_ITEMS_PER_REQUEST = 500;
276
+ var MAX_ITEM_MESSAGE_CHARS = 2000;
277
+ var MAX_ITEM_PAYLOAD_BYTES = 16384;
278
+ var MAX_ITEM_COLUMNS = 12;
279
+ var MAX_ITEM_COLUMN_LABEL_CHARS = 60;
280
+ var MAX_ATTACHMENT_BYTES = 5242880;
281
+ var MAX_ATTACHMENTS_PER_RUN = 20;
282
+ var MAX_ATTACHMENTS_PER_LOG_ENTRY = 4;
283
+ var MAX_CAPTION_CHARS = 200;
284
+ var MAX_IMAGE_DIMENSION_PX = 20000;
285
+ var limits = {
286
+ MAX_ITEMS_PER_ENVELOPE: MAX_ITEMS_PER_ENVELOPE,
287
+ HEARTBEAT_DEFAULT_INTERVAL_MS: HEARTBEAT_DEFAULT_INTERVAL_MS,
288
+ HEARTBEAT_MIN_INTERVAL_MS: HEARTBEAT_MIN_INTERVAL_MS,
289
+ HEARTBEAT_MAX_INTERVAL_MS: HEARTBEAT_MAX_INTERVAL_MS,
290
+ MAX_CLAIM_PER_POLL: MAX_CLAIM_PER_POLL,
291
+ MAX_LOG_MESSAGE_CHARS: MAX_LOG_MESSAGE_CHARS,
292
+ MAX_LOGS_PER_PATCH: MAX_LOGS_PER_PATCH,
293
+ MAX_ERROR_MESSAGE_CHARS: MAX_ERROR_MESSAGE_CHARS,
294
+ MAX_ERROR_STACK_CHARS: MAX_ERROR_STACK_CHARS,
295
+ MAX_ITEMS_PER_RUN: MAX_ITEMS_PER_RUN,
296
+ MAX_ITEMS_PER_REQUEST: MAX_ITEMS_PER_REQUEST,
297
+ MAX_ITEM_MESSAGE_CHARS: MAX_ITEM_MESSAGE_CHARS,
298
+ MAX_ITEM_PAYLOAD_BYTES: MAX_ITEM_PAYLOAD_BYTES,
299
+ MAX_ITEM_COLUMNS: MAX_ITEM_COLUMNS,
300
+ MAX_ITEM_COLUMN_LABEL_CHARS: MAX_ITEM_COLUMN_LABEL_CHARS,
301
+ MAX_ATTACHMENT_BYTES: MAX_ATTACHMENT_BYTES,
302
+ MAX_ATTACHMENTS_PER_RUN: MAX_ATTACHMENTS_PER_RUN,
303
+ MAX_ATTACHMENTS_PER_LOG_ENTRY: MAX_ATTACHMENTS_PER_LOG_ENTRY,
304
+ MAX_CAPTION_CHARS: MAX_CAPTION_CHARS,
305
+ MAX_IMAGE_DIMENSION_PX: MAX_IMAGE_DIMENSION_PX
306
+ };
307
+
308
+ /**
309
+ * Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK
310
+ * Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python
311
+ * confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o
312
+ * JSON (e, no Python, a constante espelhada — o teste acusa).
313
+ */
314
+ declare const WIRE_LIMITS: Readonly<typeof limits>;
315
+ type WireLimits = typeof WIRE_LIMITS;
316
+
265
317
  /**
266
318
  * Tipos do protocolo do Hobots (SDK → servidor).
267
319
  *
268
- * Este arquivo é a fonte de verdade do wire format e só pode reexportar tipos:
269
- * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>`
270
- * contra estes tipos (importados de `hobots/protocol`).
320
+ * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida
321
+ * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)
322
+ * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único
323
+ * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.
271
324
  */
272
325
 
273
326
  /**
@@ -388,4 +441,4 @@ interface Envelope {
388
441
  items: EnvelopeItem[];
389
442
  }
390
443
 
391
- export type { Breadcrumb, BreadcrumbLevel, Envelope, EnvelopeItem, Environment, EnvironmentInput, EventPayload, EventType, EventUser, ExceptionData, HeartbeatPayload, InstanceInfo, ItemColumn, MachineProcess, MachineSnapshot, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentContentType, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunCreateRequest, RunCreateResponse, RunDescriptor, RunError, RunItemInput, RunItemStatus, RunItemsCreateRequest, RunItemsCreateResponse, RunLogEntry, RunLogLevel, RunProgress, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame, StepData, StepStatus, TaskItemsDeclaration, TransactionPayload };
444
+ 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 };
@@ -222,9 +222,9 @@ interface RunItemsCreateRequest {
222
222
  items: RunItemInput[];
223
223
  }
224
224
  interface RunItemsCreateResponse {
225
- /** Itens inseridos */
225
+ /** Itens gravados — inseridos ou atualizados (id repetido na run: vale o último reporte) */
226
226
  accepted: number;
227
- /** Ignorados por id repetido na run (retry de rede é idempotente) */
227
+ /** Colapsados por id repetido dentro do mesmo lote (vale o de maior seq) */
228
228
  duplicates: number;
229
229
  }
230
230
  /** Formatos aceitos para anexo. O S3 valida o content-type contra a assinatura. */
@@ -262,12 +262,65 @@ interface RunAttachmentConfirmResponse {
262
262
  ok: true;
263
263
  }
264
264
 
265
+ var MAX_ITEMS_PER_ENVELOPE = 50;
266
+ var HEARTBEAT_DEFAULT_INTERVAL_MS = 30000;
267
+ var HEARTBEAT_MIN_INTERVAL_MS = 1000;
268
+ var HEARTBEAT_MAX_INTERVAL_MS = 900000;
269
+ var MAX_CLAIM_PER_POLL = 5;
270
+ var MAX_LOG_MESSAGE_CHARS = 10000;
271
+ var MAX_LOGS_PER_PATCH = 100;
272
+ var MAX_ERROR_MESSAGE_CHARS = 10000;
273
+ var MAX_ERROR_STACK_CHARS = 20000;
274
+ var MAX_ITEMS_PER_RUN = 10000;
275
+ var MAX_ITEMS_PER_REQUEST = 500;
276
+ var MAX_ITEM_MESSAGE_CHARS = 2000;
277
+ var MAX_ITEM_PAYLOAD_BYTES = 16384;
278
+ var MAX_ITEM_COLUMNS = 12;
279
+ var MAX_ITEM_COLUMN_LABEL_CHARS = 60;
280
+ var MAX_ATTACHMENT_BYTES = 5242880;
281
+ var MAX_ATTACHMENTS_PER_RUN = 20;
282
+ var MAX_ATTACHMENTS_PER_LOG_ENTRY = 4;
283
+ var MAX_CAPTION_CHARS = 200;
284
+ var MAX_IMAGE_DIMENSION_PX = 20000;
285
+ var limits = {
286
+ MAX_ITEMS_PER_ENVELOPE: MAX_ITEMS_PER_ENVELOPE,
287
+ HEARTBEAT_DEFAULT_INTERVAL_MS: HEARTBEAT_DEFAULT_INTERVAL_MS,
288
+ HEARTBEAT_MIN_INTERVAL_MS: HEARTBEAT_MIN_INTERVAL_MS,
289
+ HEARTBEAT_MAX_INTERVAL_MS: HEARTBEAT_MAX_INTERVAL_MS,
290
+ MAX_CLAIM_PER_POLL: MAX_CLAIM_PER_POLL,
291
+ MAX_LOG_MESSAGE_CHARS: MAX_LOG_MESSAGE_CHARS,
292
+ MAX_LOGS_PER_PATCH: MAX_LOGS_PER_PATCH,
293
+ MAX_ERROR_MESSAGE_CHARS: MAX_ERROR_MESSAGE_CHARS,
294
+ MAX_ERROR_STACK_CHARS: MAX_ERROR_STACK_CHARS,
295
+ MAX_ITEMS_PER_RUN: MAX_ITEMS_PER_RUN,
296
+ MAX_ITEMS_PER_REQUEST: MAX_ITEMS_PER_REQUEST,
297
+ MAX_ITEM_MESSAGE_CHARS: MAX_ITEM_MESSAGE_CHARS,
298
+ MAX_ITEM_PAYLOAD_BYTES: MAX_ITEM_PAYLOAD_BYTES,
299
+ MAX_ITEM_COLUMNS: MAX_ITEM_COLUMNS,
300
+ MAX_ITEM_COLUMN_LABEL_CHARS: MAX_ITEM_COLUMN_LABEL_CHARS,
301
+ MAX_ATTACHMENT_BYTES: MAX_ATTACHMENT_BYTES,
302
+ MAX_ATTACHMENTS_PER_RUN: MAX_ATTACHMENTS_PER_RUN,
303
+ MAX_ATTACHMENTS_PER_LOG_ENTRY: MAX_ATTACHMENTS_PER_LOG_ENTRY,
304
+ MAX_CAPTION_CHARS: MAX_CAPTION_CHARS,
305
+ MAX_IMAGE_DIMENSION_PX: MAX_IMAGE_DIMENSION_PX
306
+ };
307
+
308
+ /**
309
+ * Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK
310
+ * Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python
311
+ * confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o
312
+ * JSON (e, no Python, a constante espelhada — o teste acusa).
313
+ */
314
+ declare const WIRE_LIMITS: Readonly<typeof limits>;
315
+ type WireLimits = typeof WIRE_LIMITS;
316
+
265
317
  /**
266
318
  * Tipos do protocolo do Hobots (SDK → servidor).
267
319
  *
268
- * Este arquivo é a fonte de verdade do wire format e só pode reexportar tipos:
269
- * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>`
270
- * contra estes tipos (importados de `hobots/protocol`).
320
+ * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida
321
+ * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)
322
+ * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único
323
+ * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.
271
324
  */
272
325
 
273
326
  /**
@@ -388,4 +441,4 @@ interface Envelope {
388
441
  items: EnvelopeItem[];
389
442
  }
390
443
 
391
- export type { Breadcrumb, BreadcrumbLevel, Envelope, EnvelopeItem, Environment, EnvironmentInput, EventPayload, EventType, EventUser, ExceptionData, HeartbeatPayload, InstanceInfo, ItemColumn, MachineProcess, MachineSnapshot, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentContentType, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunCreateRequest, RunCreateResponse, RunDescriptor, RunError, RunItemInput, RunItemStatus, RunItemsCreateRequest, RunItemsCreateResponse, RunLogEntry, RunLogLevel, RunProgress, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame, StepData, StepStatus, TaskItemsDeclaration, TransactionPayload };
444
+ 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
@@ -1 +1,7 @@
1
+ import {
2
+ WIRE_LIMITS
3
+ } from "./chunk-5WIIACWC.js";
4
+ export {
5
+ WIRE_LIMITS
6
+ };
1
7
  //# sourceMappingURL=protocol.js.map
@@ -26,7 +26,7 @@ ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois da
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
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 |
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) |
30
30
  | `progress` | `RunProgressReporter` — `total(n)`, `advance(count = 1)`, `set(current, total?)`, `current`, `snapshot` | `total/advance/set` são pontos de parada |
31
31
  | `transaction` | `Transaction` — `startChild(op?, description?)`, `setTag`, `setStatus`, `setName`; `Step` — `startChild`, `setStatus('ok' \| 'warning' \| 'error', message?)`, `setError(err, message?)` (motivo em `data.error`, exibido na Central), `setData(k, v)`, `finish()` | Finalizada pelo SDK; `startChild` é ponto de parada |
32
32
  | `signal` | `AbortSignal` | Cancelamento (app, timeout, shutdown) |
package/docs/tasks.md CHANGED
@@ -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 servidor ignora (retry de rede e retry do handler idempotentes). Sem `id`, cada chamada é um item novo.
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()`:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hobots",
3
- "version": "3.2.1",
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`.",
3
+ "version": "3.3.0",
4
+ "description": "SDK JavaScript da Hobots \u2014 tudo \u00e9 uma task: register() atende solicita\u00e7\u00f5es 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",
@@ -29,6 +29,7 @@
29
29
  },
30
30
  "scripts": {
31
31
  "build": "tsup",
32
+ "prepublishOnly": "tsup",
32
33
  "dev": "tsup --watch",
33
34
  "lint": "eslint . --max-warnings 0",
34
35
  "test": "vitest run",
@@ -39,6 +40,7 @@
39
40
  "@types/node": "^20",
40
41
  "@workspace/eslint-config": "workspace:*",
41
42
  "@workspace/typescript-config": "workspace:*",
43
+ "@workspace/utils": "workspace:*",
42
44
  "tsup": "^8.4.0",
43
45
  "typescript": "5.7.3",
44
46
  "vitest": "^4.1.10"