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/README.md +1 -0
- package/dist/chunk-5WIIACWC.js +31 -0
- package/dist/chunk-5WIIACWC.js.map +1 -0
- package/dist/index.cjs +223 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -3
- package/dist/index.d.ts +68 -3
- package/dist/index.js +200 -27
- 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 +59 -6
- package/dist/protocol.d.ts +59 -6
- package/dist/protocol.js +6 -0
- package/docs/api-reference.md +1 -1
- package/docs/tasks.md +28 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -95,6 +95,7 @@ Os dois podem coexistir no mesmo processo: um monitor sempre ligado + tasks sob
|
|
|
95
95
|
| --- | --- |
|
|
96
96
|
| `hobots.log.debug/info/warn/error/success(msg, ...rest)` | Log da execução, enviado incrementalmente ao app (e ecoado no terminal). Aceita vários argumentos como `console.log` — `hobots.log.info('nota', numero, 'ok')` — cada um vira texto, unidos por espaço. **Nunca lança** — pode ir em `finally`. |
|
|
97
97
|
| `hobots.items.succeeded(payload?, { id }?)` · `.failed(msg, payload?, …)` · `.occurrence(msg, payload?, …)` · `.add({...})` | **A entrega do robô**: cada item processado, com status e atributos (viram colunas no app — declare-as com a opção `items: { columns: [...] }` do `register`/`start`). Bufferizado, em lotes. |
|
|
98
|
+
| `hobots.items.each(lista, async (el, item) => …, { id, payload }?)` | **Loop com o contrato garantido**: cada elemento vira step + item; exceção no handler = item `failed` com a mensagem e o loop **segue** até o fim; progresso automático. Só cancelamento/timeout interrompem. |
|
|
98
99
|
| `hobots.progress.total(n)` · `.advance(k = 1)` · `.set(atual, total?)` · `.current` · `.snapshot` | Barra, percentual e tempo restante na solicitação. Sem `total()` nada é enviado. |
|
|
99
100
|
| `hobots.transaction.startChild(op, descrição)` | Uma **step** no waterfall de performance da execução. A transaction da execução já existe e é finalizada pelo SDK. |
|
|
100
101
|
| `hobots.attach(imagem, { caption?, level? })` | Pendura um **print** (PNG/JPEG/WEBP, até 5 MB, 20 por execução) na linha de log. Nunca lança nem bloqueia. |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// protocol-limits.json
|
|
2
|
+
var protocol_limits_default = {
|
|
3
|
+
MAX_ITEMS_PER_ENVELOPE: 50,
|
|
4
|
+
HEARTBEAT_DEFAULT_INTERVAL_MS: 3e4,
|
|
5
|
+
HEARTBEAT_MIN_INTERVAL_MS: 1e3,
|
|
6
|
+
HEARTBEAT_MAX_INTERVAL_MS: 9e5,
|
|
7
|
+
MAX_CLAIM_PER_POLL: 5,
|
|
8
|
+
MAX_LOG_MESSAGE_CHARS: 1e4,
|
|
9
|
+
MAX_LOGS_PER_PATCH: 100,
|
|
10
|
+
MAX_ERROR_MESSAGE_CHARS: 1e4,
|
|
11
|
+
MAX_ERROR_STACK_CHARS: 2e4,
|
|
12
|
+
MAX_ITEMS_PER_RUN: 1e4,
|
|
13
|
+
MAX_ITEMS_PER_REQUEST: 500,
|
|
14
|
+
MAX_ITEM_MESSAGE_CHARS: 2e3,
|
|
15
|
+
MAX_ITEM_PAYLOAD_BYTES: 16384,
|
|
16
|
+
MAX_ITEM_COLUMNS: 12,
|
|
17
|
+
MAX_ITEM_COLUMN_LABEL_CHARS: 60,
|
|
18
|
+
MAX_ATTACHMENT_BYTES: 5242880,
|
|
19
|
+
MAX_ATTACHMENTS_PER_RUN: 20,
|
|
20
|
+
MAX_ATTACHMENTS_PER_LOG_ENTRY: 4,
|
|
21
|
+
MAX_CAPTION_CHARS: 200,
|
|
22
|
+
MAX_IMAGE_DIMENSION_PX: 2e4
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/wire-limits.ts
|
|
26
|
+
var WIRE_LIMITS = protocol_limits_default;
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
WIRE_LIMITS
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=chunk-5WIIACWC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["{\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,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/index.cjs
CHANGED
|
@@ -95,7 +95,7 @@ function scrubSecrets(text) {
|
|
|
95
95
|
|
|
96
96
|
// src/utils.ts
|
|
97
97
|
var SDK_NAME = "hobots";
|
|
98
|
-
var SDK_VERSION = true ? "3.
|
|
98
|
+
var SDK_VERSION = true ? "3.3.0" : "0.0.0-dev";
|
|
99
99
|
function isNode() {
|
|
100
100
|
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
101
101
|
}
|
|
@@ -269,12 +269,39 @@ function eventFromException(error, type = "error") {
|
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
// protocol-limits.json
|
|
273
|
+
var protocol_limits_default = {
|
|
274
|
+
MAX_ITEMS_PER_ENVELOPE: 50,
|
|
275
|
+
HEARTBEAT_DEFAULT_INTERVAL_MS: 3e4,
|
|
276
|
+
HEARTBEAT_MIN_INTERVAL_MS: 1e3,
|
|
277
|
+
HEARTBEAT_MAX_INTERVAL_MS: 9e5,
|
|
278
|
+
MAX_CLAIM_PER_POLL: 5,
|
|
279
|
+
MAX_LOG_MESSAGE_CHARS: 1e4,
|
|
280
|
+
MAX_LOGS_PER_PATCH: 100,
|
|
281
|
+
MAX_ERROR_MESSAGE_CHARS: 1e4,
|
|
282
|
+
MAX_ERROR_STACK_CHARS: 2e4,
|
|
283
|
+
MAX_ITEMS_PER_RUN: 1e4,
|
|
284
|
+
MAX_ITEMS_PER_REQUEST: 500,
|
|
285
|
+
MAX_ITEM_MESSAGE_CHARS: 2e3,
|
|
286
|
+
MAX_ITEM_PAYLOAD_BYTES: 16384,
|
|
287
|
+
MAX_ITEM_COLUMNS: 12,
|
|
288
|
+
MAX_ITEM_COLUMN_LABEL_CHARS: 60,
|
|
289
|
+
MAX_ATTACHMENT_BYTES: 5242880,
|
|
290
|
+
MAX_ATTACHMENTS_PER_RUN: 20,
|
|
291
|
+
MAX_ATTACHMENTS_PER_LOG_ENTRY: 4,
|
|
292
|
+
MAX_CAPTION_CHARS: 200,
|
|
293
|
+
MAX_IMAGE_DIMENSION_PX: 2e4
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// src/wire-limits.ts
|
|
297
|
+
var WIRE_LIMITS = protocol_limits_default;
|
|
298
|
+
|
|
272
299
|
// src/transport.ts
|
|
273
300
|
var REQUEST_TIMEOUT_MS = 1e4;
|
|
274
301
|
var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
|
|
275
302
|
var DEFAULT_MAX_BATCH_SIZE = 10;
|
|
276
303
|
var DEFAULT_MAX_QUEUE_SIZE = 200;
|
|
277
|
-
var MAX_ITEMS_PER_ENVELOPE =
|
|
304
|
+
var MAX_ITEMS_PER_ENVELOPE = WIRE_LIMITS.MAX_ITEMS_PER_ENVELOPE;
|
|
278
305
|
var Transport = class {
|
|
279
306
|
endpoint;
|
|
280
307
|
key;
|
|
@@ -598,9 +625,9 @@ async function fallbackInstanceId() {
|
|
|
598
625
|
}
|
|
599
626
|
|
|
600
627
|
// src/heartbeat.ts
|
|
601
|
-
var DEFAULT_INTERVAL_MS =
|
|
602
|
-
var MIN_REPORTED_INTERVAL_MS =
|
|
603
|
-
var MAX_REPORTED_INTERVAL_MS =
|
|
628
|
+
var DEFAULT_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_DEFAULT_INTERVAL_MS;
|
|
629
|
+
var MIN_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MIN_INTERVAL_MS;
|
|
630
|
+
var MAX_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MAX_INTERVAL_MS;
|
|
604
631
|
var Heartbeat = class {
|
|
605
632
|
constructor(client, options = {}, instanceId, sampler) {
|
|
606
633
|
this.client = client;
|
|
@@ -611,6 +638,8 @@ var Heartbeat = class {
|
|
|
611
638
|
this.metadata = options.metadata;
|
|
612
639
|
this.keepAlive = options.keepAlive ?? false;
|
|
613
640
|
}
|
|
641
|
+
client;
|
|
642
|
+
sampler;
|
|
614
643
|
intervalMs;
|
|
615
644
|
instanceId;
|
|
616
645
|
name;
|
|
@@ -747,6 +776,8 @@ var MachineSampler = class {
|
|
|
747
776
|
this.instanceId = instanceId;
|
|
748
777
|
this.logger = logger;
|
|
749
778
|
}
|
|
779
|
+
instanceId;
|
|
780
|
+
logger;
|
|
750
781
|
os;
|
|
751
782
|
fs;
|
|
752
783
|
ready = false;
|
|
@@ -874,6 +905,7 @@ var TasksApiError = class extends Error {
|
|
|
874
905
|
this.status = status;
|
|
875
906
|
this.name = "TasksApiError";
|
|
876
907
|
}
|
|
908
|
+
status;
|
|
877
909
|
};
|
|
878
910
|
async function withRequestTimeout(timeoutMs, external, send) {
|
|
879
911
|
const { signal, cleanup } = withTimeoutSignal(timeoutMs, external);
|
|
@@ -1114,6 +1146,9 @@ var Backoff = class {
|
|
|
1114
1146
|
this.label = label;
|
|
1115
1147
|
this.floorMs = floorMs;
|
|
1116
1148
|
}
|
|
1149
|
+
logger;
|
|
1150
|
+
label;
|
|
1151
|
+
floorMs;
|
|
1117
1152
|
failures = 0;
|
|
1118
1153
|
authFailures = 0;
|
|
1119
1154
|
reset() {
|
|
@@ -1152,6 +1187,88 @@ function isTerminalError(error) {
|
|
|
1152
1187
|
return error instanceof Error && TERMINAL_ERROR_NAMES.has(error.name);
|
|
1153
1188
|
}
|
|
1154
1189
|
|
|
1190
|
+
// src/tasks/each.ts
|
|
1191
|
+
function thrownMessage(error) {
|
|
1192
|
+
if (error instanceof Error) return error.message || error.name;
|
|
1193
|
+
return safeString(error);
|
|
1194
|
+
}
|
|
1195
|
+
var ItemHandle = class {
|
|
1196
|
+
constructor(index, id, step, basePayload, sink) {
|
|
1197
|
+
this.index = index;
|
|
1198
|
+
this.id = id;
|
|
1199
|
+
this.step = step;
|
|
1200
|
+
this.basePayload = basePayload;
|
|
1201
|
+
this.sink = sink;
|
|
1202
|
+
}
|
|
1203
|
+
index;
|
|
1204
|
+
id;
|
|
1205
|
+
step;
|
|
1206
|
+
basePayload;
|
|
1207
|
+
sink;
|
|
1208
|
+
reported = false;
|
|
1209
|
+
status;
|
|
1210
|
+
succeeded(payload) {
|
|
1211
|
+
this.record("succeeded", void 0, payload);
|
|
1212
|
+
}
|
|
1213
|
+
failed(message, payload) {
|
|
1214
|
+
this.record("failed", message, payload);
|
|
1215
|
+
if (this.step && this.step.status !== "error") this.step.setStatus("error", message);
|
|
1216
|
+
}
|
|
1217
|
+
occurrence(message, payload) {
|
|
1218
|
+
this.record("occurrence", message, payload);
|
|
1219
|
+
if (this.step && this.step.status === "ok") this.step.setStatus("warning", message);
|
|
1220
|
+
}
|
|
1221
|
+
record(status, message, payload) {
|
|
1222
|
+
this.reported = true;
|
|
1223
|
+
this.status = status;
|
|
1224
|
+
const merged = { ...this.basePayload ?? {}, ...payload ?? {} };
|
|
1225
|
+
this.sink.report(status, message, Object.keys(merged).length > 0 ? merged : void 0, this.id);
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1228
|
+
function resolveId(options, element, index) {
|
|
1229
|
+
const raw = options.id?.(element, index);
|
|
1230
|
+
if (raw === null || raw === void 0) return void 0;
|
|
1231
|
+
const text = safeString(raw);
|
|
1232
|
+
return text.length > 0 ? text : void 0;
|
|
1233
|
+
}
|
|
1234
|
+
function knownLength(list) {
|
|
1235
|
+
const length = list?.length;
|
|
1236
|
+
return typeof length === "number" && Number.isInteger(length) && length >= 1 ? length : void 0;
|
|
1237
|
+
}
|
|
1238
|
+
async function eachItem(list, handler, options, sink) {
|
|
1239
|
+
const result = { total: 0, succeeded: 0, failed: 0, occurrence: 0 };
|
|
1240
|
+
const length = options.progress === false ? void 0 : knownLength(list);
|
|
1241
|
+
if (length !== void 0) sink.declareTotal(length);
|
|
1242
|
+
let index = 0;
|
|
1243
|
+
for await (const element of list) {
|
|
1244
|
+
sink.checkCanceled();
|
|
1245
|
+
const id = resolveId(options, element, index);
|
|
1246
|
+
const description = options.description?.(element, index) ?? id ?? `#${index + 1}`;
|
|
1247
|
+
const step = sink.startStep(options.op ?? "item", description);
|
|
1248
|
+
const handle = new ItemHandle(index, id, step, options.payload?.(element, index), sink);
|
|
1249
|
+
try {
|
|
1250
|
+
await handler(element, handle, index);
|
|
1251
|
+
if (!handle.reported) handle.succeeded();
|
|
1252
|
+
} catch (error) {
|
|
1253
|
+
if (isTerminalError(error) || sink.isAborted()) {
|
|
1254
|
+
step?.setStatus("cancelled");
|
|
1255
|
+
step?.finish();
|
|
1256
|
+
throw error;
|
|
1257
|
+
}
|
|
1258
|
+
const message = thrownMessage(error);
|
|
1259
|
+
if (!handle.reported) handle.failed(message);
|
|
1260
|
+
step?.setError(error);
|
|
1261
|
+
sink.logError(`item ${description} falhou: ${message}`);
|
|
1262
|
+
}
|
|
1263
|
+
step?.finish();
|
|
1264
|
+
if (options.progress !== false) sink.advance();
|
|
1265
|
+
result.total += 1;
|
|
1266
|
+
result[handle.status ?? "succeeded"] += 1;
|
|
1267
|
+
index += 1;
|
|
1268
|
+
}
|
|
1269
|
+
return result;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1155
1272
|
// src/retry.ts
|
|
1156
1273
|
var DEFAULT_RETRIES = 3;
|
|
1157
1274
|
var DEFAULT_DELAY_MS = 1e3;
|
|
@@ -1179,10 +1296,11 @@ async function retryWithBackoff(fn, options = {}) {
|
|
|
1179
1296
|
}
|
|
1180
1297
|
|
|
1181
1298
|
// src/tasks/attachments.ts
|
|
1182
|
-
var MAX_ATTACHMENT_BYTES =
|
|
1183
|
-
var MAX_ATTACHMENTS_PER_RUN =
|
|
1299
|
+
var MAX_ATTACHMENT_BYTES = WIRE_LIMITS.MAX_ATTACHMENT_BYTES;
|
|
1300
|
+
var MAX_ATTACHMENTS_PER_RUN = WIRE_LIMITS.MAX_ATTACHMENTS_PER_RUN;
|
|
1301
|
+
var MAX_ATTACHMENTS_PER_LOG_ENTRY = WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY;
|
|
1184
1302
|
var MAX_CONCURRENT_UPLOADS = 3;
|
|
1185
|
-
var MAX_CAPTION_CHARS =
|
|
1303
|
+
var MAX_CAPTION_CHARS = WIRE_LIMITS.MAX_CAPTION_CHARS;
|
|
1186
1304
|
var ATTACHMENT_DRAIN_MS = 15e3;
|
|
1187
1305
|
async function readImageFile(path) {
|
|
1188
1306
|
if (!isNode()) {
|
|
@@ -1196,7 +1314,7 @@ function startsWith(bytes, signature, offset = 0) {
|
|
|
1196
1314
|
return signature.every((byte, index) => bytes[offset + index] === byte);
|
|
1197
1315
|
}
|
|
1198
1316
|
var PNG_MAGIC = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
1199
|
-
var MAX_PNG_DIMENSION =
|
|
1317
|
+
var MAX_PNG_DIMENSION = WIRE_LIMITS.MAX_IMAGE_DIMENSION_PX;
|
|
1200
1318
|
var JPEG_MAGIC = [255, 216, 255];
|
|
1201
1319
|
var RIFF_MAGIC = [82, 73, 70, 70];
|
|
1202
1320
|
var WEBP_MAGIC = [87, 69, 66, 80];
|
|
@@ -1259,13 +1377,13 @@ var DEFAULT_LOG_FLUSH_INTERVAL_MS = 2e3;
|
|
|
1259
1377
|
var DEFAULT_CANCEL_CHECK_INTERVAL_MS = 5e3;
|
|
1260
1378
|
var MIN_CANCEL_CHECK_INTERVAL_MS = 1e3;
|
|
1261
1379
|
var MAX_CANCEL_CHECK_INTERVAL_MS = 15e3;
|
|
1262
|
-
var MAX_LOG_MESSAGE_CHARS =
|
|
1263
|
-
var MAX_LOGS_PER_PATCH =
|
|
1380
|
+
var MAX_LOG_MESSAGE_CHARS = WIRE_LIMITS.MAX_LOG_MESSAGE_CHARS;
|
|
1381
|
+
var MAX_LOGS_PER_PATCH = WIRE_LIMITS.MAX_LOGS_PER_PATCH;
|
|
1264
1382
|
var FLUSH_AT_BUFFERED = 20;
|
|
1265
|
-
var MAX_ITEMS_PER_RUN =
|
|
1266
|
-
var MAX_ITEMS_PER_REQUEST =
|
|
1267
|
-
var MAX_ITEM_MESSAGE_CHARS =
|
|
1268
|
-
var MAX_ITEM_PAYLOAD_BYTES =
|
|
1383
|
+
var MAX_ITEMS_PER_RUN = WIRE_LIMITS.MAX_ITEMS_PER_RUN;
|
|
1384
|
+
var MAX_ITEMS_PER_REQUEST = WIRE_LIMITS.MAX_ITEMS_PER_REQUEST;
|
|
1385
|
+
var MAX_ITEM_MESSAGE_CHARS = WIRE_LIMITS.MAX_ITEM_MESSAGE_CHARS;
|
|
1386
|
+
var MAX_ITEM_PAYLOAD_BYTES = WIRE_LIMITS.MAX_ITEM_PAYLOAD_BYTES;
|
|
1269
1387
|
var ITEMS_FLUSH_AT_BUFFERED = 100;
|
|
1270
1388
|
var ITEMS_DRAIN_MS = 15e3;
|
|
1271
1389
|
var PROGRESS_FLUSH_MS = 1e3;
|
|
@@ -1299,6 +1417,17 @@ var RunReporter = class {
|
|
|
1299
1417
|
tx.setLifecycleSink((level, message) => this.push(level, message));
|
|
1300
1418
|
const checkCanceled = () => this.checkCanceled();
|
|
1301
1419
|
tx.setStepGuard(checkCanceled);
|
|
1420
|
+
const eachSink = {
|
|
1421
|
+
report: (status, message, payload, id) => this.addItem(status, message, payload, id),
|
|
1422
|
+
startStep: (op, description) => tx.startChild(op, description),
|
|
1423
|
+
declareTotal: (total) => {
|
|
1424
|
+
if (this.progressTotal == null) this.setProgress(this.progressCurrent, total);
|
|
1425
|
+
},
|
|
1426
|
+
advance: () => this.setProgress(this.progressCurrent + 1, this.progressTotal),
|
|
1427
|
+
checkCanceled,
|
|
1428
|
+
isAborted: () => this.abortController.signal.aborted,
|
|
1429
|
+
logError: (message) => this.log("error", message)
|
|
1430
|
+
};
|
|
1302
1431
|
const items = {
|
|
1303
1432
|
add: (item) => {
|
|
1304
1433
|
checkCanceled();
|
|
@@ -1315,7 +1444,8 @@ var RunReporter = class {
|
|
|
1315
1444
|
occurrence: (message, payload, options) => {
|
|
1316
1445
|
checkCanceled();
|
|
1317
1446
|
this.addItem("occurrence", message, payload, options?.id);
|
|
1318
|
-
}
|
|
1447
|
+
},
|
|
1448
|
+
each: (list, handler, options = {}) => eachItem(list, handler, options, eachSink)
|
|
1319
1449
|
};
|
|
1320
1450
|
const progress = Object.defineProperties(
|
|
1321
1451
|
{
|
|
@@ -1358,6 +1488,9 @@ var RunReporter = class {
|
|
|
1358
1488
|
retry: (fn, options) => retryWithBackoff(fn, { ...options, signal, wait: sleep2 })
|
|
1359
1489
|
};
|
|
1360
1490
|
}
|
|
1491
|
+
api;
|
|
1492
|
+
runId;
|
|
1493
|
+
logger;
|
|
1361
1494
|
context;
|
|
1362
1495
|
buffer = [];
|
|
1363
1496
|
dead = false;
|
|
@@ -1457,7 +1590,7 @@ var RunReporter = class {
|
|
|
1457
1590
|
ts,
|
|
1458
1591
|
level,
|
|
1459
1592
|
message: truncate(scrubbed, MAX_LOG_MESSAGE_CHARS),
|
|
1460
|
-
...attachments && attachments.length > 0 ? { attachments } : {}
|
|
1593
|
+
...attachments && attachments.length > 0 ? { attachments: attachments.slice(0, WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY) } : {}
|
|
1461
1594
|
});
|
|
1462
1595
|
if (this.buffer.length >= FLUSH_AT_BUFFERED) {
|
|
1463
1596
|
this.flushLogs();
|
|
@@ -1682,6 +1815,7 @@ var RunReporter = class {
|
|
|
1682
1815
|
}
|
|
1683
1816
|
if (error instanceof TasksApiError) {
|
|
1684
1817
|
this.logger.error(`lote de ${batch.length} item(ns) rejeitado pelo servidor:`, error);
|
|
1818
|
+
this.log("warning", `${batch.length} item(ns) descartado(s): envio rejeitado pelo servidor (HTTP ${error.status})`);
|
|
1685
1819
|
return;
|
|
1686
1820
|
}
|
|
1687
1821
|
this.itemsBuffer.unshift(...batch);
|
|
@@ -1908,6 +2042,10 @@ function currentRunReporter() {
|
|
|
1908
2042
|
}
|
|
1909
2043
|
|
|
1910
2044
|
// src/transaction.ts
|
|
2045
|
+
var MAX_STEP_MESSAGE_CHARS = 2e3;
|
|
2046
|
+
function stepMessage(text) {
|
|
2047
|
+
return truncate(scrubSecrets(text), MAX_STEP_MESSAGE_CHARS);
|
|
2048
|
+
}
|
|
1911
2049
|
function stepId() {
|
|
1912
2050
|
return uuid4().slice(0, 16);
|
|
1913
2051
|
}
|
|
@@ -1945,15 +2083,41 @@ var Step = class {
|
|
|
1945
2083
|
this.op = op;
|
|
1946
2084
|
this.description = description;
|
|
1947
2085
|
}
|
|
2086
|
+
transaction;
|
|
2087
|
+
parentStepId;
|
|
2088
|
+
op;
|
|
2089
|
+
description;
|
|
1948
2090
|
stepId = stepId();
|
|
1949
2091
|
startTimestamp = nowISO();
|
|
1950
2092
|
status = "ok";
|
|
1951
2093
|
endTimestamp;
|
|
1952
2094
|
data;
|
|
1953
|
-
|
|
2095
|
+
/**
|
|
2096
|
+
* Desfecho da step. `message` (opcional) é o motivo legível — vai em `data.message`
|
|
2097
|
+
* e aparece na Central (performance e banner da execução) e no log de FINISH.
|
|
2098
|
+
*/
|
|
2099
|
+
setStatus(status, message) {
|
|
1954
2100
|
this.status = status;
|
|
2101
|
+
if (message) this.setData("message", stepMessage(message));
|
|
2102
|
+
return this;
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Marca a step como `error` guardando o motivo em `data.error` ({ type, message }).
|
|
2106
|
+
* Aceita qualquer valor lançado; `message` sobrescreve a mensagem do erro.
|
|
2107
|
+
*/
|
|
2108
|
+
setError(error, message) {
|
|
2109
|
+
this.status = "error";
|
|
2110
|
+
const type = error instanceof Error ? error.name : typeof error === "object" && error !== null ? "Error" : void 0;
|
|
2111
|
+
const raw = message ?? (error instanceof Error ? error.message || error.name : String(error));
|
|
2112
|
+
this.setData("error", { ...type ? { type } : {}, message: stepMessage(raw) });
|
|
1955
2113
|
return this;
|
|
1956
2114
|
}
|
|
2115
|
+
/** Motivo registrado via setStatus(…, message) ou setError — usado no log de FINISH. */
|
|
2116
|
+
reason() {
|
|
2117
|
+
const error = this.data?.error;
|
|
2118
|
+
const text = typeof error?.message === "string" ? error.message : this.data?.message;
|
|
2119
|
+
return typeof text === "string" && text ? text : void 0;
|
|
2120
|
+
}
|
|
1957
2121
|
setData(key, value) {
|
|
1958
2122
|
this.data = { ...this.data, [key]: value };
|
|
1959
2123
|
return this;
|
|
@@ -1971,7 +2135,8 @@ var Step = class {
|
|
|
1971
2135
|
stepLabel(this.op, this.description),
|
|
1972
2136
|
this.startTimestamp,
|
|
1973
2137
|
this.endTimestamp,
|
|
1974
|
-
this.status
|
|
2138
|
+
this.status,
|
|
2139
|
+
this.reason()
|
|
1975
2140
|
);
|
|
1976
2141
|
}
|
|
1977
2142
|
toJSON() {
|
|
@@ -1995,6 +2160,10 @@ var Transaction = class {
|
|
|
1995
2160
|
this.runId = runId;
|
|
1996
2161
|
this.emit("transaction", "start", op ? `${name} (${op})` : name);
|
|
1997
2162
|
}
|
|
2163
|
+
client;
|
|
2164
|
+
name;
|
|
2165
|
+
op;
|
|
2166
|
+
runId;
|
|
1998
2167
|
eventId = uuid4();
|
|
1999
2168
|
stepId = stepId();
|
|
2000
2169
|
startTimestamp = nowISO();
|
|
@@ -2014,9 +2183,9 @@ var Transaction = class {
|
|
|
2014
2183
|
* logs da run no app), e ecoa no terminal apenas com `debug: true` — o SDK não
|
|
2015
2184
|
* escreve no stdout do processo do usuário sem permissão.
|
|
2016
2185
|
*/
|
|
2017
|
-
emit(kind, phase, label, startTs, endTs, status) {
|
|
2186
|
+
emit(kind, phase, label, startTs, endTs, status, reason) {
|
|
2018
2187
|
const durationMs = startTs && endTs ? new Date(endTs).getTime() - new Date(startTs).getTime() : void 0;
|
|
2019
|
-
const suffix = durationMs != null ? ` (${durationMs}ms)` : "";
|
|
2188
|
+
const suffix = (durationMs != null ? ` (${durationMs}ms)` : "") + (reason ? `: ${reason}` : "");
|
|
2020
2189
|
if (this.client?.debug) {
|
|
2021
2190
|
const tag = colorize(`[hobots:${kind}] ${phase.toUpperCase()}`, phase === "finish" ? colorForStatus(status ?? "ok") : "cyan");
|
|
2022
2191
|
console.log(`${tag} ${label}${suffix}`);
|
|
@@ -2122,6 +2291,7 @@ async function executeRun(input) {
|
|
|
2122
2291
|
await runWithRunContext({ reporter }, () => invokeWithRetry(task, run, reporter, logger));
|
|
2123
2292
|
await reporter.finalizeAttachments();
|
|
2124
2293
|
await reporter.finalizeItems();
|
|
2294
|
+
warnIncompleteProgress(reporter);
|
|
2125
2295
|
tx.setStatus("ok");
|
|
2126
2296
|
tx.finish();
|
|
2127
2297
|
reporter.reportSuccess();
|
|
@@ -2139,6 +2309,13 @@ async function executeRun(input) {
|
|
|
2139
2309
|
tracker.remove(reporter);
|
|
2140
2310
|
}
|
|
2141
2311
|
}
|
|
2312
|
+
function warnIncompleteProgress(reporter) {
|
|
2313
|
+
const snapshot = reporter.context.progress.snapshot;
|
|
2314
|
+
if (!snapshot || snapshot.current >= snapshot.total) return;
|
|
2315
|
+
reporter.context.log.warn(
|
|
2316
|
+
`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`
|
|
2317
|
+
);
|
|
2318
|
+
}
|
|
2142
2319
|
function invokeWithRetry(task, run, reporter, logger) {
|
|
2143
2320
|
const { retries, retryDelayMs } = task.options;
|
|
2144
2321
|
const total = retries + 1;
|
|
@@ -2193,8 +2370,8 @@ function waitForCancelGrace(signal, graceMs) {
|
|
|
2193
2370
|
signal.addEventListener("abort", () => setTimeout(resolve2, graceMs), { once: true });
|
|
2194
2371
|
});
|
|
2195
2372
|
}
|
|
2196
|
-
var MAX_ERROR_MESSAGE_CHARS =
|
|
2197
|
-
var MAX_ERROR_STACK_CHARS =
|
|
2373
|
+
var MAX_ERROR_MESSAGE_CHARS = WIRE_LIMITS.MAX_ERROR_MESSAGE_CHARS;
|
|
2374
|
+
var MAX_ERROR_STACK_CHARS = WIRE_LIMITS.MAX_ERROR_STACK_CHARS;
|
|
2198
2375
|
function toRunError(error) {
|
|
2199
2376
|
if (error instanceof Error) {
|
|
2200
2377
|
return {
|
|
@@ -2209,7 +2386,7 @@ function toRunError(error) {
|
|
|
2209
2386
|
// src/tasks/agent.ts
|
|
2210
2387
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
2211
2388
|
var MIN_POLL_INTERVAL_MS = 1e3;
|
|
2212
|
-
var MAX_CLAIM_PER_POLL =
|
|
2389
|
+
var MAX_CLAIM_PER_POLL = WIRE_LIMITS.MAX_CLAIM_PER_POLL;
|
|
2213
2390
|
var TaskAgent = class {
|
|
2214
2391
|
constructor(options) {
|
|
2215
2392
|
this.options = options;
|
|
@@ -2221,6 +2398,7 @@ var TaskAgent = class {
|
|
|
2221
2398
|
this.pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
2222
2399
|
this.backoff = new Backoff(this.logger, "poll", this.pollIntervalMs);
|
|
2223
2400
|
}
|
|
2401
|
+
options;
|
|
2224
2402
|
logger;
|
|
2225
2403
|
pollIntervalMs;
|
|
2226
2404
|
api;
|
|
@@ -2343,8 +2521,8 @@ var TaskAgent = class {
|
|
|
2343
2521
|
|
|
2344
2522
|
// src/tasks/item-columns.ts
|
|
2345
2523
|
var KEY_RE = /^[a-zA-Z0-9_.-]{1,100}$/;
|
|
2346
|
-
var MAX_COLUMNS =
|
|
2347
|
-
var MAX_LABEL_CHARS =
|
|
2524
|
+
var MAX_COLUMNS = WIRE_LIMITS.MAX_ITEM_COLUMNS;
|
|
2525
|
+
var MAX_LABEL_CHARS = WIRE_LIMITS.MAX_ITEM_COLUMN_LABEL_CHARS;
|
|
2348
2526
|
function normalizeItemColumns(slug, input, logger) {
|
|
2349
2527
|
if (input === void 0 || input === null) return void 0;
|
|
2350
2528
|
const columns = input.columns;
|
|
@@ -2387,6 +2565,8 @@ var LocalRunner = class {
|
|
|
2387
2565
|
this.resolveDone = resolve2;
|
|
2388
2566
|
});
|
|
2389
2567
|
}
|
|
2568
|
+
task;
|
|
2569
|
+
deps;
|
|
2390
2570
|
abort = new AbortController();
|
|
2391
2571
|
backoff;
|
|
2392
2572
|
/** Resolve quando a run terminou (ou o runner foi parado antes de abri-la). */
|
|
@@ -2472,6 +2652,7 @@ var RunTracker = class {
|
|
|
2472
2652
|
constructor(api) {
|
|
2473
2653
|
this.api = api;
|
|
2474
2654
|
}
|
|
2655
|
+
api;
|
|
2475
2656
|
reporters = /* @__PURE__ */ new Set();
|
|
2476
2657
|
waiters = /* @__PURE__ */ new Set();
|
|
2477
2658
|
add(reporter) {
|
|
@@ -2849,7 +3030,22 @@ var fallbackLog = {
|
|
|
2849
3030
|
success: (message, ...rest) => printRunLog(FALLBACK_TASK, "success", joinLogArgs(message, rest))
|
|
2850
3031
|
};
|
|
2851
3032
|
var noop = () => void 0;
|
|
2852
|
-
var
|
|
3033
|
+
var fallbackEachSink = {
|
|
3034
|
+
report: noop,
|
|
3035
|
+
startStep: () => void 0,
|
|
3036
|
+
declareTotal: noop,
|
|
3037
|
+
advance: noop,
|
|
3038
|
+
checkCanceled: noop,
|
|
3039
|
+
isAborted: () => false,
|
|
3040
|
+
logError: (message) => printRunLog(FALLBACK_TASK, "error", message)
|
|
3041
|
+
};
|
|
3042
|
+
var fallbackItems = {
|
|
3043
|
+
add: noop,
|
|
3044
|
+
succeeded: noop,
|
|
3045
|
+
failed: noop,
|
|
3046
|
+
occurrence: noop,
|
|
3047
|
+
each: (list, handler, options = {}) => eachItem(list, handler, options, fallbackEachSink)
|
|
3048
|
+
};
|
|
2853
3049
|
var fallbackProgress = { total: noop, advance: noop, set: noop, current: 0, snapshot: null };
|
|
2854
3050
|
var neverAborts = new AbortController().signal;
|
|
2855
3051
|
var detachedTransaction;
|