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/index.d.cts CHANGED
@@ -256,7 +256,18 @@ declare class Step {
256
256
  endTimestamp?: string;
257
257
  data?: Record<string, unknown>;
258
258
  constructor(transaction: Transaction, parentStepId: string, op?: string | undefined, description?: string | undefined);
259
- setStatus(status: StepStatus): this;
259
+ /**
260
+ * Desfecho da step. `message` (opcional) é o motivo legível — vai em `data.message`
261
+ * e aparece na Central (performance e banner da execução) e no log de FINISH.
262
+ */
263
+ setStatus(status: StepStatus, message?: string): this;
264
+ /**
265
+ * Marca a step como `error` guardando o motivo em `data.error` ({ type, message }).
266
+ * Aceita qualquer valor lançado; `message` sobrescreve a mensagem do erro.
267
+ */
268
+ setError(error: unknown, message?: string): this;
269
+ /** Motivo registrado via setStatus(…, message) ou setError — usado no log de FINISH. */
270
+ private reason;
260
271
  setData(key: string, value: unknown): this;
261
272
  /** Step aninhada (filha desta step). */
262
273
  startChild(op?: string, description?: string): Step;
@@ -292,7 +303,7 @@ declare class Transaction {
292
303
  * logs da run no app), e ecoa no terminal apenas com `debug: true` — o SDK não
293
304
  * escreve no stdout do processo do usuário sem permissão.
294
305
  */
295
- emit(kind: 'transaction' | 'step', phase: 'start' | 'finish', label: string, startTs?: string, endTs?: string, status?: StepStatus | string): void;
306
+ emit(kind: 'transaction' | 'step', phase: 'start' | 'finish', label: string, startTs?: string, endTs?: string, status?: StepStatus | string, reason?: string): void;
296
307
  /** Conecta o espelho de lifecycle (RunReporter) e faz replay do backlog em ordem. */
297
308
  setLifecycleSink(sink: LifecycleSink): void;
298
309
  /**
@@ -328,6 +339,51 @@ interface RunItemOptions {
328
339
  */
329
340
  id?: string;
330
341
  }
342
+ /**
343
+ * O item em processamento dentro de `items.each`: o desfecho (`succeeded`/`failed`/
344
+ * `occurrence`) com o `id` e o payload base já resolvidos, e a step da etapa para quem
345
+ * quiser medir sub-etapas (`item.step.startChild(...)`). Sem chamada explícita, o SDK
346
+ * decide: retornou → `succeeded`; lançou → `failed` com a mensagem do erro.
347
+ */
348
+ interface RunItemHandle {
349
+ /** Posição do elemento na lista (0-based). */
350
+ readonly index: number;
351
+ /** Identidade de negócio resolvida por `options.id` (undefined = o SDK gera uma). */
352
+ readonly id: string | undefined;
353
+ /** Step desta etapa no waterfall de performance; undefined fora de uma execução. */
354
+ readonly step: Step | undefined;
355
+ /** true depois do primeiro desfecho registrado (o SDK não sobrescreve o que o handler decidiu). */
356
+ readonly reported: boolean;
357
+ /** Item processado com sucesso. `payload` é mesclado sobre o payload base de `options.payload`. */
358
+ succeeded(payload?: Record<string, unknown>): void;
359
+ /** Falha sem lançar — o loop segue igual; a step vira `error` com o motivo. */
360
+ failed(message: string, payload?: Record<string, unknown>): void;
361
+ /** Ocorrência de negócio — a step vira `warning` com o motivo. */
362
+ occurrence(message: string, payload?: Record<string, unknown>): void;
363
+ }
364
+ interface RunItemsEachOptions<T> {
365
+ /** Identidade de negócio do item (ex.: nº do cliente). Omitido/null: o SDK gera um id único. */
366
+ id?: (element: T, index: number) => string | number | null | undefined;
367
+ /** Atributos base do item (viram colunas no app) — presentes em qualquer desfecho, inclusive falha. */
368
+ payload?: (element: T, index: number) => Record<string, unknown> | undefined;
369
+ /** `op` da step de cada item no waterfall. Default: 'item'. */
370
+ op?: string;
371
+ /** Descrição da step de cada item. Default: o `id`, senão `#<posição>`. */
372
+ description?: (element: T, index: number) => string;
373
+ /**
374
+ * Progresso automático: declara o total (tamanho da lista, se o bot ainda não declarou um)
375
+ * e avança a cada elemento. `false` deixa o progresso por conta do bot. Default: true.
376
+ */
377
+ progress?: boolean;
378
+ }
379
+ /** Totalizadores do `items.each`, pelo desfecho final de cada elemento. */
380
+ interface RunItemsEachResult {
381
+ total: number;
382
+ succeeded: number;
383
+ failed: number;
384
+ occurrence: number;
385
+ }
386
+ type RunItemsEachHandler<T> = (element: T, item: RunItemHandle, index: number) => unknown;
331
387
  /**
332
388
  * Registro dos itens que a execução processou/gerou (a entrega do bot: notas
333
389
  * fiscais baixadas, boletos emitidos...). Chamadas são síncronas — os itens são
@@ -348,6 +404,15 @@ interface RunItems {
348
404
  failed(message: string, payload?: Record<string, unknown>, options?: RunItemOptions): void;
349
405
  /** Ocorrência de negócio (ex.: "nota nº 10 não encontrada") — não é falha do bot. */
350
406
  occurrence(message: string, payload?: Record<string, unknown>, options?: RunItemOptions): void;
407
+ /**
408
+ * Processa uma lista item a item com o contrato da plataforma garantido pelo SDK: cada
409
+ * elemento vira uma step e um item; uma exceção no handler registra o item como `failed`
410
+ * (com a mensagem do erro), marca a step com `setError` e **segue para o próximo** — a
411
+ * lista inteira é processada, e o progresso avança a cada elemento. Só cancelamento,
412
+ * timeout e shutdown interrompem o loop (o erro sobe como em qualquer ponto de parada).
413
+ * Resolve com os totalizadores por desfecho.
414
+ */
415
+ each<T>(list: Iterable<T> | AsyncIterable<T>, handler: RunItemsEachHandler<T>, options?: RunItemsEachOptions<T>): Promise<RunItemsEachResult>;
351
416
  }
352
417
  /**
353
418
  * Progresso da execução (itens processados / total) — opcional e independente de
@@ -434,4 +499,4 @@ declare const close: (timeoutMs?: number) => Promise<boolean>;
434
499
  declare const captureException: (error: unknown, hint?: CaptureHint) => string | undefined;
435
500
  declare const retry: <T>(fn: (attempt: number) => T | Promise<T>, options?: RetryOptions) => Promise<T>;
436
501
 
437
- export { type AttachFailureReason, type AttachInput, type AttachOptions, type AttachResult, type CaptureAttachment, type CaptureHint, EnvironmentInput, EventPayload, EventType, HeartbeatPayload, type Hobots, type HobotsOptions, type ItemColumnInput, MachineSnapshot, type RegisterOptions, type RetryDelay, type RetryOptions, RunAttachmentContentType, type RunContext, type RunItemOptions, RunItemStatus, type RunItems, RunLogLevel, type RunLogger, RunProgress, type RunProgressReporter, type StartOptions, Step, StepData, StepStatus, type TaskHandler, type TaskItemsOptions, type TaskOptions, Transaction, TransactionPayload, captureException, close, hobots as default, hobots, register, retry, start };
502
+ export { type AttachFailureReason, type AttachInput, type AttachOptions, type AttachResult, type CaptureAttachment, type CaptureHint, EnvironmentInput, EventPayload, EventType, HeartbeatPayload, type Hobots, type HobotsOptions, type ItemColumnInput, MachineSnapshot, type RegisterOptions, type RetryDelay, type RetryOptions, RunAttachmentContentType, type RunContext, type RunItemHandle, type RunItemOptions, RunItemStatus, type RunItems, type RunItemsEachHandler, type RunItemsEachOptions, type RunItemsEachResult, RunLogLevel, type RunLogger, RunProgress, type RunProgressReporter, type StartOptions, Step, StepData, StepStatus, type TaskHandler, type TaskItemsOptions, type TaskOptions, Transaction, TransactionPayload, captureException, close, hobots as default, hobots, register, retry, start };
package/dist/index.d.ts CHANGED
@@ -256,7 +256,18 @@ declare class Step {
256
256
  endTimestamp?: string;
257
257
  data?: Record<string, unknown>;
258
258
  constructor(transaction: Transaction, parentStepId: string, op?: string | undefined, description?: string | undefined);
259
- setStatus(status: StepStatus): this;
259
+ /**
260
+ * Desfecho da step. `message` (opcional) é o motivo legível — vai em `data.message`
261
+ * e aparece na Central (performance e banner da execução) e no log de FINISH.
262
+ */
263
+ setStatus(status: StepStatus, message?: string): this;
264
+ /**
265
+ * Marca a step como `error` guardando o motivo em `data.error` ({ type, message }).
266
+ * Aceita qualquer valor lançado; `message` sobrescreve a mensagem do erro.
267
+ */
268
+ setError(error: unknown, message?: string): this;
269
+ /** Motivo registrado via setStatus(…, message) ou setError — usado no log de FINISH. */
270
+ private reason;
260
271
  setData(key: string, value: unknown): this;
261
272
  /** Step aninhada (filha desta step). */
262
273
  startChild(op?: string, description?: string): Step;
@@ -292,7 +303,7 @@ declare class Transaction {
292
303
  * logs da run no app), e ecoa no terminal apenas com `debug: true` — o SDK não
293
304
  * escreve no stdout do processo do usuário sem permissão.
294
305
  */
295
- emit(kind: 'transaction' | 'step', phase: 'start' | 'finish', label: string, startTs?: string, endTs?: string, status?: StepStatus | string): void;
306
+ emit(kind: 'transaction' | 'step', phase: 'start' | 'finish', label: string, startTs?: string, endTs?: string, status?: StepStatus | string, reason?: string): void;
296
307
  /** Conecta o espelho de lifecycle (RunReporter) e faz replay do backlog em ordem. */
297
308
  setLifecycleSink(sink: LifecycleSink): void;
298
309
  /**
@@ -328,6 +339,51 @@ interface RunItemOptions {
328
339
  */
329
340
  id?: string;
330
341
  }
342
+ /**
343
+ * O item em processamento dentro de `items.each`: o desfecho (`succeeded`/`failed`/
344
+ * `occurrence`) com o `id` e o payload base já resolvidos, e a step da etapa para quem
345
+ * quiser medir sub-etapas (`item.step.startChild(...)`). Sem chamada explícita, o SDK
346
+ * decide: retornou → `succeeded`; lançou → `failed` com a mensagem do erro.
347
+ */
348
+ interface RunItemHandle {
349
+ /** Posição do elemento na lista (0-based). */
350
+ readonly index: number;
351
+ /** Identidade de negócio resolvida por `options.id` (undefined = o SDK gera uma). */
352
+ readonly id: string | undefined;
353
+ /** Step desta etapa no waterfall de performance; undefined fora de uma execução. */
354
+ readonly step: Step | undefined;
355
+ /** true depois do primeiro desfecho registrado (o SDK não sobrescreve o que o handler decidiu). */
356
+ readonly reported: boolean;
357
+ /** Item processado com sucesso. `payload` é mesclado sobre o payload base de `options.payload`. */
358
+ succeeded(payload?: Record<string, unknown>): void;
359
+ /** Falha sem lançar — o loop segue igual; a step vira `error` com o motivo. */
360
+ failed(message: string, payload?: Record<string, unknown>): void;
361
+ /** Ocorrência de negócio — a step vira `warning` com o motivo. */
362
+ occurrence(message: string, payload?: Record<string, unknown>): void;
363
+ }
364
+ interface RunItemsEachOptions<T> {
365
+ /** Identidade de negócio do item (ex.: nº do cliente). Omitido/null: o SDK gera um id único. */
366
+ id?: (element: T, index: number) => string | number | null | undefined;
367
+ /** Atributos base do item (viram colunas no app) — presentes em qualquer desfecho, inclusive falha. */
368
+ payload?: (element: T, index: number) => Record<string, unknown> | undefined;
369
+ /** `op` da step de cada item no waterfall. Default: 'item'. */
370
+ op?: string;
371
+ /** Descrição da step de cada item. Default: o `id`, senão `#<posição>`. */
372
+ description?: (element: T, index: number) => string;
373
+ /**
374
+ * Progresso automático: declara o total (tamanho da lista, se o bot ainda não declarou um)
375
+ * e avança a cada elemento. `false` deixa o progresso por conta do bot. Default: true.
376
+ */
377
+ progress?: boolean;
378
+ }
379
+ /** Totalizadores do `items.each`, pelo desfecho final de cada elemento. */
380
+ interface RunItemsEachResult {
381
+ total: number;
382
+ succeeded: number;
383
+ failed: number;
384
+ occurrence: number;
385
+ }
386
+ type RunItemsEachHandler<T> = (element: T, item: RunItemHandle, index: number) => unknown;
331
387
  /**
332
388
  * Registro dos itens que a execução processou/gerou (a entrega do bot: notas
333
389
  * fiscais baixadas, boletos emitidos...). Chamadas são síncronas — os itens são
@@ -348,6 +404,15 @@ interface RunItems {
348
404
  failed(message: string, payload?: Record<string, unknown>, options?: RunItemOptions): void;
349
405
  /** Ocorrência de negócio (ex.: "nota nº 10 não encontrada") — não é falha do bot. */
350
406
  occurrence(message: string, payload?: Record<string, unknown>, options?: RunItemOptions): void;
407
+ /**
408
+ * Processa uma lista item a item com o contrato da plataforma garantido pelo SDK: cada
409
+ * elemento vira uma step e um item; uma exceção no handler registra o item como `failed`
410
+ * (com a mensagem do erro), marca a step com `setError` e **segue para o próximo** — a
411
+ * lista inteira é processada, e o progresso avança a cada elemento. Só cancelamento,
412
+ * timeout e shutdown interrompem o loop (o erro sobe como em qualquer ponto de parada).
413
+ * Resolve com os totalizadores por desfecho.
414
+ */
415
+ each<T>(list: Iterable<T> | AsyncIterable<T>, handler: RunItemsEachHandler<T>, options?: RunItemsEachOptions<T>): Promise<RunItemsEachResult>;
351
416
  }
352
417
  /**
353
418
  * Progresso da execução (itens processados / total) — opcional e independente de
@@ -434,4 +499,4 @@ declare const close: (timeoutMs?: number) => Promise<boolean>;
434
499
  declare const captureException: (error: unknown, hint?: CaptureHint) => string | undefined;
435
500
  declare const retry: <T>(fn: (attempt: number) => T | Promise<T>, options?: RetryOptions) => Promise<T>;
436
501
 
437
- export { type AttachFailureReason, type AttachInput, type AttachOptions, type AttachResult, type CaptureAttachment, type CaptureHint, EnvironmentInput, EventPayload, EventType, HeartbeatPayload, type Hobots, type HobotsOptions, type ItemColumnInput, MachineSnapshot, type RegisterOptions, type RetryDelay, type RetryOptions, RunAttachmentContentType, type RunContext, type RunItemOptions, RunItemStatus, type RunItems, RunLogLevel, type RunLogger, RunProgress, type RunProgressReporter, type StartOptions, Step, StepData, StepStatus, type TaskHandler, type TaskItemsOptions, type TaskOptions, Transaction, TransactionPayload, captureException, close, hobots as default, hobots, register, retry, start };
502
+ export { type AttachFailureReason, type AttachInput, type AttachOptions, type AttachResult, type CaptureAttachment, type CaptureHint, EnvironmentInput, EventPayload, EventType, HeartbeatPayload, type Hobots, type HobotsOptions, type ItemColumnInput, MachineSnapshot, type RegisterOptions, type RetryDelay, type RetryOptions, RunAttachmentContentType, type RunContext, type RunItemHandle, type RunItemOptions, RunItemStatus, type RunItems, type RunItemsEachHandler, type RunItemsEachOptions, type RunItemsEachResult, RunLogLevel, type RunLogger, RunProgress, type RunProgressReporter, type StartOptions, Step, StepData, StepStatus, type TaskHandler, type TaskItemsOptions, type TaskOptions, Transaction, TransactionPayload, captureException, close, hobots as default, hobots, register, retry, start };
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ import {
2
+ WIRE_LIMITS
3
+ } from "./chunk-5WIIACWC.js";
4
+
1
5
  // src/stacktrace.ts
2
6
  var MAX_FRAMES = 50;
3
7
  var MAX_FILENAME_CHARS = 1024;
@@ -53,7 +57,7 @@ function scrubSecrets(text) {
53
57
 
54
58
  // src/utils.ts
55
59
  var SDK_NAME = "hobots";
56
- var SDK_VERSION = true ? "3.2.0" : "0.0.0-dev";
60
+ var SDK_VERSION = true ? "3.3.0" : "0.0.0-dev";
57
61
  function isNode() {
58
62
  return typeof process !== "undefined" && typeof process.versions?.node === "string";
59
63
  }
@@ -232,7 +236,7 @@ var REQUEST_TIMEOUT_MS = 1e4;
232
236
  var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
233
237
  var DEFAULT_MAX_BATCH_SIZE = 10;
234
238
  var DEFAULT_MAX_QUEUE_SIZE = 200;
235
- var MAX_ITEMS_PER_ENVELOPE = 50;
239
+ var MAX_ITEMS_PER_ENVELOPE = WIRE_LIMITS.MAX_ITEMS_PER_ENVELOPE;
236
240
  var Transport = class {
237
241
  endpoint;
238
242
  key;
@@ -556,9 +560,9 @@ async function fallbackInstanceId() {
556
560
  }
557
561
 
558
562
  // src/heartbeat.ts
559
- var DEFAULT_INTERVAL_MS = 3e4;
560
- var MIN_REPORTED_INTERVAL_MS = 1e3;
561
- var MAX_REPORTED_INTERVAL_MS = 9e5;
563
+ var DEFAULT_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_DEFAULT_INTERVAL_MS;
564
+ var MIN_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MIN_INTERVAL_MS;
565
+ var MAX_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MAX_INTERVAL_MS;
562
566
  var Heartbeat = class {
563
567
  constructor(client, options = {}, instanceId, sampler) {
564
568
  this.client = client;
@@ -569,6 +573,8 @@ var Heartbeat = class {
569
573
  this.metadata = options.metadata;
570
574
  this.keepAlive = options.keepAlive ?? false;
571
575
  }
576
+ client;
577
+ sampler;
572
578
  intervalMs;
573
579
  instanceId;
574
580
  name;
@@ -705,6 +711,8 @@ var MachineSampler = class {
705
711
  this.instanceId = instanceId;
706
712
  this.logger = logger;
707
713
  }
714
+ instanceId;
715
+ logger;
708
716
  os;
709
717
  fs;
710
718
  ready = false;
@@ -832,6 +840,7 @@ var TasksApiError = class extends Error {
832
840
  this.status = status;
833
841
  this.name = "TasksApiError";
834
842
  }
843
+ status;
835
844
  };
836
845
  async function withRequestTimeout(timeoutMs, external, send) {
837
846
  const { signal, cleanup } = withTimeoutSignal(timeoutMs, external);
@@ -1072,6 +1081,9 @@ var Backoff = class {
1072
1081
  this.label = label;
1073
1082
  this.floorMs = floorMs;
1074
1083
  }
1084
+ logger;
1085
+ label;
1086
+ floorMs;
1075
1087
  failures = 0;
1076
1088
  authFailures = 0;
1077
1089
  reset() {
@@ -1110,6 +1122,88 @@ function isTerminalError(error) {
1110
1122
  return error instanceof Error && TERMINAL_ERROR_NAMES.has(error.name);
1111
1123
  }
1112
1124
 
1125
+ // src/tasks/each.ts
1126
+ function thrownMessage(error) {
1127
+ if (error instanceof Error) return error.message || error.name;
1128
+ return safeString(error);
1129
+ }
1130
+ var ItemHandle = class {
1131
+ constructor(index, id, step, basePayload, sink) {
1132
+ this.index = index;
1133
+ this.id = id;
1134
+ this.step = step;
1135
+ this.basePayload = basePayload;
1136
+ this.sink = sink;
1137
+ }
1138
+ index;
1139
+ id;
1140
+ step;
1141
+ basePayload;
1142
+ sink;
1143
+ reported = false;
1144
+ status;
1145
+ succeeded(payload) {
1146
+ this.record("succeeded", void 0, payload);
1147
+ }
1148
+ failed(message, payload) {
1149
+ this.record("failed", message, payload);
1150
+ if (this.step && this.step.status !== "error") this.step.setStatus("error", message);
1151
+ }
1152
+ occurrence(message, payload) {
1153
+ this.record("occurrence", message, payload);
1154
+ if (this.step && this.step.status === "ok") this.step.setStatus("warning", message);
1155
+ }
1156
+ record(status, message, payload) {
1157
+ this.reported = true;
1158
+ this.status = status;
1159
+ const merged = { ...this.basePayload ?? {}, ...payload ?? {} };
1160
+ this.sink.report(status, message, Object.keys(merged).length > 0 ? merged : void 0, this.id);
1161
+ }
1162
+ };
1163
+ function resolveId(options, element, index) {
1164
+ const raw = options.id?.(element, index);
1165
+ if (raw === null || raw === void 0) return void 0;
1166
+ const text = safeString(raw);
1167
+ return text.length > 0 ? text : void 0;
1168
+ }
1169
+ function knownLength(list) {
1170
+ const length = list?.length;
1171
+ return typeof length === "number" && Number.isInteger(length) && length >= 1 ? length : void 0;
1172
+ }
1173
+ async function eachItem(list, handler, options, sink) {
1174
+ const result = { total: 0, succeeded: 0, failed: 0, occurrence: 0 };
1175
+ const length = options.progress === false ? void 0 : knownLength(list);
1176
+ if (length !== void 0) sink.declareTotal(length);
1177
+ let index = 0;
1178
+ for await (const element of list) {
1179
+ sink.checkCanceled();
1180
+ const id = resolveId(options, element, index);
1181
+ const description = options.description?.(element, index) ?? id ?? `#${index + 1}`;
1182
+ const step = sink.startStep(options.op ?? "item", description);
1183
+ const handle = new ItemHandle(index, id, step, options.payload?.(element, index), sink);
1184
+ try {
1185
+ await handler(element, handle, index);
1186
+ if (!handle.reported) handle.succeeded();
1187
+ } catch (error) {
1188
+ if (isTerminalError(error) || sink.isAborted()) {
1189
+ step?.setStatus("cancelled");
1190
+ step?.finish();
1191
+ throw error;
1192
+ }
1193
+ const message = thrownMessage(error);
1194
+ if (!handle.reported) handle.failed(message);
1195
+ step?.setError(error);
1196
+ sink.logError(`item ${description} falhou: ${message}`);
1197
+ }
1198
+ step?.finish();
1199
+ if (options.progress !== false) sink.advance();
1200
+ result.total += 1;
1201
+ result[handle.status ?? "succeeded"] += 1;
1202
+ index += 1;
1203
+ }
1204
+ return result;
1205
+ }
1206
+
1113
1207
  // src/retry.ts
1114
1208
  var DEFAULT_RETRIES = 3;
1115
1209
  var DEFAULT_DELAY_MS = 1e3;
@@ -1137,10 +1231,11 @@ async function retryWithBackoff(fn, options = {}) {
1137
1231
  }
1138
1232
 
1139
1233
  // src/tasks/attachments.ts
1140
- var MAX_ATTACHMENT_BYTES = 5242880;
1141
- var MAX_ATTACHMENTS_PER_RUN = 20;
1234
+ var MAX_ATTACHMENT_BYTES = WIRE_LIMITS.MAX_ATTACHMENT_BYTES;
1235
+ var MAX_ATTACHMENTS_PER_RUN = WIRE_LIMITS.MAX_ATTACHMENTS_PER_RUN;
1236
+ var MAX_ATTACHMENTS_PER_LOG_ENTRY = WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY;
1142
1237
  var MAX_CONCURRENT_UPLOADS = 3;
1143
- var MAX_CAPTION_CHARS = 200;
1238
+ var MAX_CAPTION_CHARS = WIRE_LIMITS.MAX_CAPTION_CHARS;
1144
1239
  var ATTACHMENT_DRAIN_MS = 15e3;
1145
1240
  async function readImageFile(path) {
1146
1241
  if (!isNode()) {
@@ -1154,7 +1249,7 @@ function startsWith(bytes, signature, offset = 0) {
1154
1249
  return signature.every((byte, index) => bytes[offset + index] === byte);
1155
1250
  }
1156
1251
  var PNG_MAGIC = [137, 80, 78, 71, 13, 10, 26, 10];
1157
- var MAX_PNG_DIMENSION = 2e4;
1252
+ var MAX_PNG_DIMENSION = WIRE_LIMITS.MAX_IMAGE_DIMENSION_PX;
1158
1253
  var JPEG_MAGIC = [255, 216, 255];
1159
1254
  var RIFF_MAGIC = [82, 73, 70, 70];
1160
1255
  var WEBP_MAGIC = [87, 69, 66, 80];
@@ -1217,13 +1312,13 @@ var DEFAULT_LOG_FLUSH_INTERVAL_MS = 2e3;
1217
1312
  var DEFAULT_CANCEL_CHECK_INTERVAL_MS = 5e3;
1218
1313
  var MIN_CANCEL_CHECK_INTERVAL_MS = 1e3;
1219
1314
  var MAX_CANCEL_CHECK_INTERVAL_MS = 15e3;
1220
- var MAX_LOG_MESSAGE_CHARS = 1e4;
1221
- var MAX_LOGS_PER_PATCH = 100;
1315
+ var MAX_LOG_MESSAGE_CHARS = WIRE_LIMITS.MAX_LOG_MESSAGE_CHARS;
1316
+ var MAX_LOGS_PER_PATCH = WIRE_LIMITS.MAX_LOGS_PER_PATCH;
1222
1317
  var FLUSH_AT_BUFFERED = 20;
1223
- var MAX_ITEMS_PER_RUN = 1e4;
1224
- var MAX_ITEMS_PER_REQUEST = 500;
1225
- var MAX_ITEM_MESSAGE_CHARS = 2e3;
1226
- var MAX_ITEM_PAYLOAD_BYTES = 16384;
1318
+ var MAX_ITEMS_PER_RUN = WIRE_LIMITS.MAX_ITEMS_PER_RUN;
1319
+ var MAX_ITEMS_PER_REQUEST = WIRE_LIMITS.MAX_ITEMS_PER_REQUEST;
1320
+ var MAX_ITEM_MESSAGE_CHARS = WIRE_LIMITS.MAX_ITEM_MESSAGE_CHARS;
1321
+ var MAX_ITEM_PAYLOAD_BYTES = WIRE_LIMITS.MAX_ITEM_PAYLOAD_BYTES;
1227
1322
  var ITEMS_FLUSH_AT_BUFFERED = 100;
1228
1323
  var ITEMS_DRAIN_MS = 15e3;
1229
1324
  var PROGRESS_FLUSH_MS = 1e3;
@@ -1257,6 +1352,17 @@ var RunReporter = class {
1257
1352
  tx.setLifecycleSink((level, message) => this.push(level, message));
1258
1353
  const checkCanceled = () => this.checkCanceled();
1259
1354
  tx.setStepGuard(checkCanceled);
1355
+ const eachSink = {
1356
+ report: (status, message, payload, id) => this.addItem(status, message, payload, id),
1357
+ startStep: (op, description) => tx.startChild(op, description),
1358
+ declareTotal: (total) => {
1359
+ if (this.progressTotal == null) this.setProgress(this.progressCurrent, total);
1360
+ },
1361
+ advance: () => this.setProgress(this.progressCurrent + 1, this.progressTotal),
1362
+ checkCanceled,
1363
+ isAborted: () => this.abortController.signal.aborted,
1364
+ logError: (message) => this.log("error", message)
1365
+ };
1260
1366
  const items = {
1261
1367
  add: (item) => {
1262
1368
  checkCanceled();
@@ -1273,7 +1379,8 @@ var RunReporter = class {
1273
1379
  occurrence: (message, payload, options) => {
1274
1380
  checkCanceled();
1275
1381
  this.addItem("occurrence", message, payload, options?.id);
1276
- }
1382
+ },
1383
+ each: (list, handler, options = {}) => eachItem(list, handler, options, eachSink)
1277
1384
  };
1278
1385
  const progress = Object.defineProperties(
1279
1386
  {
@@ -1316,6 +1423,9 @@ var RunReporter = class {
1316
1423
  retry: (fn, options) => retryWithBackoff(fn, { ...options, signal, wait: sleep2 })
1317
1424
  };
1318
1425
  }
1426
+ api;
1427
+ runId;
1428
+ logger;
1319
1429
  context;
1320
1430
  buffer = [];
1321
1431
  dead = false;
@@ -1415,7 +1525,7 @@ var RunReporter = class {
1415
1525
  ts,
1416
1526
  level,
1417
1527
  message: truncate(scrubbed, MAX_LOG_MESSAGE_CHARS),
1418
- ...attachments && attachments.length > 0 ? { attachments } : {}
1528
+ ...attachments && attachments.length > 0 ? { attachments: attachments.slice(0, WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY) } : {}
1419
1529
  });
1420
1530
  if (this.buffer.length >= FLUSH_AT_BUFFERED) {
1421
1531
  this.flushLogs();
@@ -1640,6 +1750,7 @@ var RunReporter = class {
1640
1750
  }
1641
1751
  if (error instanceof TasksApiError) {
1642
1752
  this.logger.error(`lote de ${batch.length} item(ns) rejeitado pelo servidor:`, error);
1753
+ this.log("warning", `${batch.length} item(ns) descartado(s): envio rejeitado pelo servidor (HTTP ${error.status})`);
1643
1754
  return;
1644
1755
  }
1645
1756
  this.itemsBuffer.unshift(...batch);
@@ -1866,6 +1977,10 @@ function currentRunReporter() {
1866
1977
  }
1867
1978
 
1868
1979
  // src/transaction.ts
1980
+ var MAX_STEP_MESSAGE_CHARS = 2e3;
1981
+ function stepMessage(text) {
1982
+ return truncate(scrubSecrets(text), MAX_STEP_MESSAGE_CHARS);
1983
+ }
1869
1984
  function stepId() {
1870
1985
  return uuid4().slice(0, 16);
1871
1986
  }
@@ -1903,15 +2018,41 @@ var Step = class {
1903
2018
  this.op = op;
1904
2019
  this.description = description;
1905
2020
  }
2021
+ transaction;
2022
+ parentStepId;
2023
+ op;
2024
+ description;
1906
2025
  stepId = stepId();
1907
2026
  startTimestamp = nowISO();
1908
2027
  status = "ok";
1909
2028
  endTimestamp;
1910
2029
  data;
1911
- setStatus(status) {
2030
+ /**
2031
+ * Desfecho da step. `message` (opcional) é o motivo legível — vai em `data.message`
2032
+ * e aparece na Central (performance e banner da execução) e no log de FINISH.
2033
+ */
2034
+ setStatus(status, message) {
1912
2035
  this.status = status;
2036
+ if (message) this.setData("message", stepMessage(message));
2037
+ return this;
2038
+ }
2039
+ /**
2040
+ * Marca a step como `error` guardando o motivo em `data.error` ({ type, message }).
2041
+ * Aceita qualquer valor lançado; `message` sobrescreve a mensagem do erro.
2042
+ */
2043
+ setError(error, message) {
2044
+ this.status = "error";
2045
+ const type = error instanceof Error ? error.name : typeof error === "object" && error !== null ? "Error" : void 0;
2046
+ const raw = message ?? (error instanceof Error ? error.message || error.name : String(error));
2047
+ this.setData("error", { ...type ? { type } : {}, message: stepMessage(raw) });
1913
2048
  return this;
1914
2049
  }
2050
+ /** Motivo registrado via setStatus(…, message) ou setError — usado no log de FINISH. */
2051
+ reason() {
2052
+ const error = this.data?.error;
2053
+ const text = typeof error?.message === "string" ? error.message : this.data?.message;
2054
+ return typeof text === "string" && text ? text : void 0;
2055
+ }
1915
2056
  setData(key, value) {
1916
2057
  this.data = { ...this.data, [key]: value };
1917
2058
  return this;
@@ -1929,7 +2070,8 @@ var Step = class {
1929
2070
  stepLabel(this.op, this.description),
1930
2071
  this.startTimestamp,
1931
2072
  this.endTimestamp,
1932
- this.status
2073
+ this.status,
2074
+ this.reason()
1933
2075
  );
1934
2076
  }
1935
2077
  toJSON() {
@@ -1953,6 +2095,10 @@ var Transaction = class {
1953
2095
  this.runId = runId;
1954
2096
  this.emit("transaction", "start", op ? `${name} (${op})` : name);
1955
2097
  }
2098
+ client;
2099
+ name;
2100
+ op;
2101
+ runId;
1956
2102
  eventId = uuid4();
1957
2103
  stepId = stepId();
1958
2104
  startTimestamp = nowISO();
@@ -1972,9 +2118,9 @@ var Transaction = class {
1972
2118
  * logs da run no app), e ecoa no terminal apenas com `debug: true` — o SDK não
1973
2119
  * escreve no stdout do processo do usuário sem permissão.
1974
2120
  */
1975
- emit(kind, phase, label, startTs, endTs, status) {
2121
+ emit(kind, phase, label, startTs, endTs, status, reason) {
1976
2122
  const durationMs = startTs && endTs ? new Date(endTs).getTime() - new Date(startTs).getTime() : void 0;
1977
- const suffix = durationMs != null ? ` (${durationMs}ms)` : "";
2123
+ const suffix = (durationMs != null ? ` (${durationMs}ms)` : "") + (reason ? `: ${reason}` : "");
1978
2124
  if (this.client?.debug) {
1979
2125
  const tag = colorize(`[hobots:${kind}] ${phase.toUpperCase()}`, phase === "finish" ? colorForStatus(status ?? "ok") : "cyan");
1980
2126
  console.log(`${tag} ${label}${suffix}`);
@@ -2080,6 +2226,7 @@ async function executeRun(input) {
2080
2226
  await runWithRunContext({ reporter }, () => invokeWithRetry(task, run, reporter, logger));
2081
2227
  await reporter.finalizeAttachments();
2082
2228
  await reporter.finalizeItems();
2229
+ warnIncompleteProgress(reporter);
2083
2230
  tx.setStatus("ok");
2084
2231
  tx.finish();
2085
2232
  reporter.reportSuccess();
@@ -2097,6 +2244,13 @@ async function executeRun(input) {
2097
2244
  tracker.remove(reporter);
2098
2245
  }
2099
2246
  }
2247
+ function warnIncompleteProgress(reporter) {
2248
+ const snapshot = reporter.context.progress.snapshot;
2249
+ if (!snapshot || snapshot.current >= snapshot.total) return;
2250
+ reporter.context.log.warn(
2251
+ `execu\xE7\xE3o conclu\xEDda com progresso incompleto: ${snapshot.current}/${snapshot.total} \u2014 o handler terminou sem processar (ou sem avan\xE7ar) todos os itens previstos`
2252
+ );
2253
+ }
2100
2254
  function invokeWithRetry(task, run, reporter, logger) {
2101
2255
  const { retries, retryDelayMs } = task.options;
2102
2256
  const total = retries + 1;
@@ -2151,8 +2305,8 @@ function waitForCancelGrace(signal, graceMs) {
2151
2305
  signal.addEventListener("abort", () => setTimeout(resolve2, graceMs), { once: true });
2152
2306
  });
2153
2307
  }
2154
- var MAX_ERROR_MESSAGE_CHARS = 1e4;
2155
- var MAX_ERROR_STACK_CHARS = 2e4;
2308
+ var MAX_ERROR_MESSAGE_CHARS = WIRE_LIMITS.MAX_ERROR_MESSAGE_CHARS;
2309
+ var MAX_ERROR_STACK_CHARS = WIRE_LIMITS.MAX_ERROR_STACK_CHARS;
2156
2310
  function toRunError(error) {
2157
2311
  if (error instanceof Error) {
2158
2312
  return {
@@ -2167,7 +2321,7 @@ function toRunError(error) {
2167
2321
  // src/tasks/agent.ts
2168
2322
  var DEFAULT_POLL_INTERVAL_MS = 2e3;
2169
2323
  var MIN_POLL_INTERVAL_MS = 1e3;
2170
- var MAX_CLAIM_PER_POLL = 5;
2324
+ var MAX_CLAIM_PER_POLL = WIRE_LIMITS.MAX_CLAIM_PER_POLL;
2171
2325
  var TaskAgent = class {
2172
2326
  constructor(options) {
2173
2327
  this.options = options;
@@ -2179,6 +2333,7 @@ var TaskAgent = class {
2179
2333
  this.pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
2180
2334
  this.backoff = new Backoff(this.logger, "poll", this.pollIntervalMs);
2181
2335
  }
2336
+ options;
2182
2337
  logger;
2183
2338
  pollIntervalMs;
2184
2339
  api;
@@ -2301,8 +2456,8 @@ var TaskAgent = class {
2301
2456
 
2302
2457
  // src/tasks/item-columns.ts
2303
2458
  var KEY_RE = /^[a-zA-Z0-9_.-]{1,100}$/;
2304
- var MAX_COLUMNS = 12;
2305
- var MAX_LABEL_CHARS = 60;
2459
+ var MAX_COLUMNS = WIRE_LIMITS.MAX_ITEM_COLUMNS;
2460
+ var MAX_LABEL_CHARS = WIRE_LIMITS.MAX_ITEM_COLUMN_LABEL_CHARS;
2306
2461
  function normalizeItemColumns(slug, input, logger) {
2307
2462
  if (input === void 0 || input === null) return void 0;
2308
2463
  const columns = input.columns;
@@ -2345,6 +2500,8 @@ var LocalRunner = class {
2345
2500
  this.resolveDone = resolve2;
2346
2501
  });
2347
2502
  }
2503
+ task;
2504
+ deps;
2348
2505
  abort = new AbortController();
2349
2506
  backoff;
2350
2507
  /** Resolve quando a run terminou (ou o runner foi parado antes de abri-la). */
@@ -2430,6 +2587,7 @@ var RunTracker = class {
2430
2587
  constructor(api) {
2431
2588
  this.api = api;
2432
2589
  }
2590
+ api;
2433
2591
  reporters = /* @__PURE__ */ new Set();
2434
2592
  waiters = /* @__PURE__ */ new Set();
2435
2593
  add(reporter) {
@@ -2807,7 +2965,22 @@ var fallbackLog = {
2807
2965
  success: (message, ...rest) => printRunLog(FALLBACK_TASK, "success", joinLogArgs(message, rest))
2808
2966
  };
2809
2967
  var noop = () => void 0;
2810
- var fallbackItems = { add: noop, succeeded: noop, failed: noop, occurrence: noop };
2968
+ var fallbackEachSink = {
2969
+ report: noop,
2970
+ startStep: () => void 0,
2971
+ declareTotal: noop,
2972
+ advance: noop,
2973
+ checkCanceled: noop,
2974
+ isAborted: () => false,
2975
+ logError: (message) => printRunLog(FALLBACK_TASK, "error", message)
2976
+ };
2977
+ var fallbackItems = {
2978
+ add: noop,
2979
+ succeeded: noop,
2980
+ failed: noop,
2981
+ occurrence: noop,
2982
+ each: (list, handler, options = {}) => eachItem(list, handler, options, fallbackEachSink)
2983
+ };
2811
2984
  var fallbackProgress = { total: noop, advance: noop, set: noop, current: 0, snapshot: null };
2812
2985
  var neverAborts = new AbortController().signal;
2813
2986
  var detachedTransaction;