hobots 3.2.2 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/chunk-5WIIACWC.js +31 -0
- package/dist/chunk-5WIIACWC.js.map +1 -0
- package/dist/index.cjs +313 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +123 -31
- package/dist/index.d.ts +123 -31
- package/dist/index.js +290 -99
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs +34 -0
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +62 -7
- package/dist/protocol.d.ts +62 -7
- package/dist/protocol.js +6 -0
- package/docs/api-reference.md +7 -6
- package/docs/protocol.md +9 -6
- package/docs/tasks.md +54 -8
- package/package.json +4 -1
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(src_exports, {
|
|
|
34
34
|
close: () => close2,
|
|
35
35
|
default: () => src_default,
|
|
36
36
|
hobots: () => hobots,
|
|
37
|
+
image: () => image2,
|
|
37
38
|
register: () => register2,
|
|
38
39
|
retry: () => retry,
|
|
39
40
|
start: () => start2
|
|
@@ -95,7 +96,7 @@ function scrubSecrets(text) {
|
|
|
95
96
|
|
|
96
97
|
// src/utils.ts
|
|
97
98
|
var SDK_NAME = "hobots";
|
|
98
|
-
var SDK_VERSION = true ? "3.
|
|
99
|
+
var SDK_VERSION = true ? "3.4.0" : "0.0.0-dev";
|
|
99
100
|
function isNode() {
|
|
100
101
|
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
101
102
|
}
|
|
@@ -269,12 +270,39 @@ function eventFromException(error, type = "error") {
|
|
|
269
270
|
};
|
|
270
271
|
}
|
|
271
272
|
|
|
273
|
+
// protocol-limits.json
|
|
274
|
+
var protocol_limits_default = {
|
|
275
|
+
MAX_ITEMS_PER_ENVELOPE: 50,
|
|
276
|
+
HEARTBEAT_DEFAULT_INTERVAL_MS: 3e4,
|
|
277
|
+
HEARTBEAT_MIN_INTERVAL_MS: 1e3,
|
|
278
|
+
HEARTBEAT_MAX_INTERVAL_MS: 9e5,
|
|
279
|
+
MAX_CLAIM_PER_POLL: 5,
|
|
280
|
+
MAX_LOG_MESSAGE_CHARS: 1e4,
|
|
281
|
+
MAX_LOGS_PER_PATCH: 100,
|
|
282
|
+
MAX_ERROR_MESSAGE_CHARS: 1e4,
|
|
283
|
+
MAX_ERROR_STACK_CHARS: 2e4,
|
|
284
|
+
MAX_ITEMS_PER_RUN: 1e4,
|
|
285
|
+
MAX_ITEMS_PER_REQUEST: 500,
|
|
286
|
+
MAX_ITEM_MESSAGE_CHARS: 2e3,
|
|
287
|
+
MAX_ITEM_PAYLOAD_BYTES: 16384,
|
|
288
|
+
MAX_ITEM_COLUMNS: 12,
|
|
289
|
+
MAX_ITEM_COLUMN_LABEL_CHARS: 60,
|
|
290
|
+
MAX_ATTACHMENT_BYTES: 5242880,
|
|
291
|
+
MAX_ATTACHMENTS_PER_RUN: 20,
|
|
292
|
+
MAX_ATTACHMENTS_PER_LOG_ENTRY: 4,
|
|
293
|
+
MAX_CAPTION_CHARS: 200,
|
|
294
|
+
MAX_IMAGE_DIMENSION_PX: 2e4
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// src/wire-limits.ts
|
|
298
|
+
var WIRE_LIMITS = protocol_limits_default;
|
|
299
|
+
|
|
272
300
|
// src/transport.ts
|
|
273
301
|
var REQUEST_TIMEOUT_MS = 1e4;
|
|
274
302
|
var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
|
|
275
303
|
var DEFAULT_MAX_BATCH_SIZE = 10;
|
|
276
304
|
var DEFAULT_MAX_QUEUE_SIZE = 200;
|
|
277
|
-
var MAX_ITEMS_PER_ENVELOPE =
|
|
305
|
+
var MAX_ITEMS_PER_ENVELOPE = WIRE_LIMITS.MAX_ITEMS_PER_ENVELOPE;
|
|
278
306
|
var Transport = class {
|
|
279
307
|
endpoint;
|
|
280
308
|
key;
|
|
@@ -350,6 +378,7 @@ var Transport = class {
|
|
|
350
378
|
try {
|
|
351
379
|
response = await fetchWithRetry(
|
|
352
380
|
() => fetch(this.endpoint, {
|
|
381
|
+
redirect: "error",
|
|
353
382
|
method: "POST",
|
|
354
383
|
headers: { "content-type": "application/json", authorization: `Bearer ${this.key}` },
|
|
355
384
|
body: JSON.stringify(envelope),
|
|
@@ -527,7 +556,6 @@ function envBaseUrl() {
|
|
|
527
556
|
function isLoopbackHost(hostname2) {
|
|
528
557
|
return hostname2 === "localhost" || hostname2.endsWith(".localhost") || hostname2.startsWith("127.") || hostname2 === "[::1]" || hostname2 === "::1" || hostname2 === "0.0.0.0";
|
|
529
558
|
}
|
|
530
|
-
var warnedInsecureBaseUrl = false;
|
|
531
559
|
function validateBaseUrl(raw, prefix) {
|
|
532
560
|
let url;
|
|
533
561
|
try {
|
|
@@ -541,11 +569,8 @@ function validateBaseUrl(raw, prefix) {
|
|
|
541
569
|
if (url.username || url.password) {
|
|
542
570
|
throw new Error(`${prefix} HOBOTS_API_URL n\xE3o pode conter credenciais na URL \u2014 a autentica\xE7\xE3o \xE9 s\xF3 pelo Client Secret`);
|
|
543
571
|
}
|
|
544
|
-
if (url.protocol === "http:" && !isLoopbackHost(url.hostname)
|
|
545
|
-
|
|
546
|
-
console.warn(
|
|
547
|
-
`${prefix} HOBOTS_API_URL usa http para o host remoto "${url.hostname}" \u2014 o Client Secret trafega sem TLS`
|
|
548
|
-
);
|
|
572
|
+
if (url.protocol === "http:" && !isLoopbackHost(url.hostname)) {
|
|
573
|
+
throw new Error(`${prefix} HOBOTS_API_URL usa http para o host remoto "${url.hostname}" \u2014 o Client Secret trafegaria sem TLS; use https`);
|
|
549
574
|
}
|
|
550
575
|
return raw.replace(/\/+$/, "");
|
|
551
576
|
}
|
|
@@ -598,9 +623,9 @@ async function fallbackInstanceId() {
|
|
|
598
623
|
}
|
|
599
624
|
|
|
600
625
|
// src/heartbeat.ts
|
|
601
|
-
var DEFAULT_INTERVAL_MS =
|
|
602
|
-
var MIN_REPORTED_INTERVAL_MS =
|
|
603
|
-
var MAX_REPORTED_INTERVAL_MS =
|
|
626
|
+
var DEFAULT_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_DEFAULT_INTERVAL_MS;
|
|
627
|
+
var MIN_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MIN_INTERVAL_MS;
|
|
628
|
+
var MAX_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MAX_INTERVAL_MS;
|
|
604
629
|
var Heartbeat = class {
|
|
605
630
|
constructor(client, options = {}, instanceId, sampler) {
|
|
606
631
|
this.client = client;
|
|
@@ -909,6 +934,7 @@ var TasksApi = class {
|
|
|
909
934
|
let response;
|
|
910
935
|
try {
|
|
911
936
|
response = await fetch(`${this.baseUrl}/poll`, {
|
|
937
|
+
redirect: "error",
|
|
912
938
|
method: "POST",
|
|
913
939
|
headers: this.headers(),
|
|
914
940
|
body: JSON.stringify(request),
|
|
@@ -932,6 +958,7 @@ var TasksApi = class {
|
|
|
932
958
|
let response;
|
|
933
959
|
try {
|
|
934
960
|
response = await fetch(`${this.baseUrl}/runs`, {
|
|
961
|
+
redirect: "error",
|
|
935
962
|
method: "POST",
|
|
936
963
|
headers: this.headers(),
|
|
937
964
|
body: JSON.stringify(request),
|
|
@@ -982,6 +1009,7 @@ var TasksApi = class {
|
|
|
982
1009
|
try {
|
|
983
1010
|
response = await fetchWithRetry(
|
|
984
1011
|
() => fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}`, {
|
|
1012
|
+
redirect: "error",
|
|
985
1013
|
method: "PATCH",
|
|
986
1014
|
headers: this.headers(),
|
|
987
1015
|
body: JSON.stringify(update),
|
|
@@ -1003,6 +1031,7 @@ var TasksApi = class {
|
|
|
1003
1031
|
*/
|
|
1004
1032
|
async updateRunOnce(runId, update, timeoutMs = 2e3) {
|
|
1005
1033
|
await fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}`, {
|
|
1034
|
+
redirect: "error",
|
|
1006
1035
|
method: "PATCH",
|
|
1007
1036
|
headers: this.headers(),
|
|
1008
1037
|
body: JSON.stringify(update),
|
|
@@ -1019,6 +1048,7 @@ var TasksApi = class {
|
|
|
1019
1048
|
try {
|
|
1020
1049
|
response = await fetchWithRetry(
|
|
1021
1050
|
() => fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}/items`, {
|
|
1051
|
+
redirect: "error",
|
|
1022
1052
|
method: "POST",
|
|
1023
1053
|
headers: this.headers(),
|
|
1024
1054
|
body: JSON.stringify(request),
|
|
@@ -1048,6 +1078,7 @@ var TasksApi = class {
|
|
|
1048
1078
|
UPDATE_TIMEOUT_MS,
|
|
1049
1079
|
signal,
|
|
1050
1080
|
(timeoutSignal) => fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}/attachments`, {
|
|
1081
|
+
redirect: "error",
|
|
1051
1082
|
method: "POST",
|
|
1052
1083
|
headers: this.headers(),
|
|
1053
1084
|
body: JSON.stringify(request),
|
|
@@ -1080,6 +1111,7 @@ var TasksApi = class {
|
|
|
1080
1111
|
UPLOAD_TIMEOUT_MS,
|
|
1081
1112
|
signal,
|
|
1082
1113
|
(timeoutSignal) => fetch(url, {
|
|
1114
|
+
redirect: "error",
|
|
1083
1115
|
method: "PUT",
|
|
1084
1116
|
headers,
|
|
1085
1117
|
// BodyInit não aceita Uint8Array<ArrayBufferLike> em todos os lib.dom; o buffer é o mesmo
|
|
@@ -1098,6 +1130,7 @@ var TasksApi = class {
|
|
|
1098
1130
|
const response = await fetch(
|
|
1099
1131
|
`${this.baseUrl}/runs/${encodeURIComponent(runId)}/attachments/${encodeURIComponent(attachmentId)}`,
|
|
1100
1132
|
{
|
|
1133
|
+
redirect: "error",
|
|
1101
1134
|
method: "PATCH",
|
|
1102
1135
|
headers: this.headers(),
|
|
1103
1136
|
body: JSON.stringify(request),
|
|
@@ -1160,6 +1193,88 @@ function isTerminalError(error) {
|
|
|
1160
1193
|
return error instanceof Error && TERMINAL_ERROR_NAMES.has(error.name);
|
|
1161
1194
|
}
|
|
1162
1195
|
|
|
1196
|
+
// src/tasks/each.ts
|
|
1197
|
+
function thrownMessage(error) {
|
|
1198
|
+
if (error instanceof Error) return error.message || error.name;
|
|
1199
|
+
return safeString(error);
|
|
1200
|
+
}
|
|
1201
|
+
var ItemHandle = class {
|
|
1202
|
+
constructor(index, id, step, basePayload, sink) {
|
|
1203
|
+
this.index = index;
|
|
1204
|
+
this.id = id;
|
|
1205
|
+
this.step = step;
|
|
1206
|
+
this.basePayload = basePayload;
|
|
1207
|
+
this.sink = sink;
|
|
1208
|
+
}
|
|
1209
|
+
index;
|
|
1210
|
+
id;
|
|
1211
|
+
step;
|
|
1212
|
+
basePayload;
|
|
1213
|
+
sink;
|
|
1214
|
+
reported = false;
|
|
1215
|
+
status;
|
|
1216
|
+
succeeded(payload, options) {
|
|
1217
|
+
this.record("succeeded", void 0, payload, options?.image);
|
|
1218
|
+
}
|
|
1219
|
+
failed(message, payload, options) {
|
|
1220
|
+
this.record("failed", message, payload, options?.image);
|
|
1221
|
+
if (this.step && this.step.status !== "error") this.step.setStatus("error", message);
|
|
1222
|
+
}
|
|
1223
|
+
occurrence(message, payload, options) {
|
|
1224
|
+
this.record("occurrence", message, payload, options?.image);
|
|
1225
|
+
if (this.step && this.step.status === "ok") this.step.setStatus("warning", message);
|
|
1226
|
+
}
|
|
1227
|
+
record(status, message, payload, image3) {
|
|
1228
|
+
this.reported = true;
|
|
1229
|
+
this.status = status;
|
|
1230
|
+
const merged = { ...this.basePayload ?? {}, ...payload ?? {} };
|
|
1231
|
+
this.sink.report(status, message, Object.keys(merged).length > 0 ? merged : void 0, this.id, image3);
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1234
|
+
function resolveId(options, element, index) {
|
|
1235
|
+
const raw = options.id?.(element, index);
|
|
1236
|
+
if (raw === null || raw === void 0) return void 0;
|
|
1237
|
+
const text = safeString(raw);
|
|
1238
|
+
return text.length > 0 ? text : void 0;
|
|
1239
|
+
}
|
|
1240
|
+
function knownLength(list) {
|
|
1241
|
+
const length = list?.length;
|
|
1242
|
+
return typeof length === "number" && Number.isInteger(length) && length >= 1 ? length : void 0;
|
|
1243
|
+
}
|
|
1244
|
+
async function eachItem(list, handler, options, sink) {
|
|
1245
|
+
const result = { total: 0, succeeded: 0, failed: 0, occurrence: 0 };
|
|
1246
|
+
const length = options.progress === false ? void 0 : knownLength(list);
|
|
1247
|
+
if (length !== void 0) sink.declareTotal(length);
|
|
1248
|
+
let index = 0;
|
|
1249
|
+
for await (const element of list) {
|
|
1250
|
+
sink.checkCanceled();
|
|
1251
|
+
const id = resolveId(options, element, index);
|
|
1252
|
+
const description = options.description?.(element, index) ?? id ?? `#${index + 1}`;
|
|
1253
|
+
const step = sink.startStep(options.op ?? "item", description);
|
|
1254
|
+
const handle = new ItemHandle(index, id, step, options.payload?.(element, index), sink);
|
|
1255
|
+
try {
|
|
1256
|
+
await handler(element, handle, index);
|
|
1257
|
+
if (!handle.reported) handle.succeeded();
|
|
1258
|
+
} catch (error) {
|
|
1259
|
+
if (isTerminalError(error) || sink.isAborted()) {
|
|
1260
|
+
step?.setStatus("cancelled");
|
|
1261
|
+
step?.finish();
|
|
1262
|
+
throw error;
|
|
1263
|
+
}
|
|
1264
|
+
const message = thrownMessage(error);
|
|
1265
|
+
if (!handle.reported) handle.failed(message);
|
|
1266
|
+
step?.setError(error);
|
|
1267
|
+
sink.logError(`item ${description} falhou: ${message}`);
|
|
1268
|
+
}
|
|
1269
|
+
step?.finish();
|
|
1270
|
+
if (options.progress !== false) sink.advance();
|
|
1271
|
+
result.total += 1;
|
|
1272
|
+
result[handle.status ?? "succeeded"] += 1;
|
|
1273
|
+
index += 1;
|
|
1274
|
+
}
|
|
1275
|
+
return result;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1163
1278
|
// src/retry.ts
|
|
1164
1279
|
var DEFAULT_RETRIES = 3;
|
|
1165
1280
|
var DEFAULT_DELAY_MS = 1e3;
|
|
@@ -1187,11 +1302,33 @@ async function retryWithBackoff(fn, options = {}) {
|
|
|
1187
1302
|
}
|
|
1188
1303
|
|
|
1189
1304
|
// src/tasks/attachments.ts
|
|
1190
|
-
var MAX_ATTACHMENT_BYTES =
|
|
1191
|
-
var MAX_ATTACHMENTS_PER_RUN =
|
|
1305
|
+
var MAX_ATTACHMENT_BYTES = WIRE_LIMITS.MAX_ATTACHMENT_BYTES;
|
|
1306
|
+
var MAX_ATTACHMENTS_PER_RUN = WIRE_LIMITS.MAX_ATTACHMENTS_PER_RUN;
|
|
1307
|
+
var MAX_ATTACHMENTS_PER_LOG_ENTRY = WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY;
|
|
1192
1308
|
var MAX_CONCURRENT_UPLOADS = 3;
|
|
1193
|
-
var MAX_CAPTION_CHARS =
|
|
1309
|
+
var MAX_CAPTION_CHARS = WIRE_LIMITS.MAX_CAPTION_CHARS;
|
|
1194
1310
|
var ATTACHMENT_DRAIN_MS = 15e3;
|
|
1311
|
+
var IMAGE_BRAND = /* @__PURE__ */ Symbol.for("hobots.image");
|
|
1312
|
+
var ImageAttachment = class {
|
|
1313
|
+
constructor(input, caption, contentType) {
|
|
1314
|
+
this.input = input;
|
|
1315
|
+
this.caption = caption;
|
|
1316
|
+
this.contentType = contentType;
|
|
1317
|
+
}
|
|
1318
|
+
input;
|
|
1319
|
+
caption;
|
|
1320
|
+
contentType;
|
|
1321
|
+
[IMAGE_BRAND] = true;
|
|
1322
|
+
};
|
|
1323
|
+
function image(input, options = {}) {
|
|
1324
|
+
return new ImageAttachment(input, options.caption, options.contentType);
|
|
1325
|
+
}
|
|
1326
|
+
function isImageAttachment(value) {
|
|
1327
|
+
return typeof value === "object" && value !== null && value[IMAGE_BRAND] === true;
|
|
1328
|
+
}
|
|
1329
|
+
function toImageAttachment(value) {
|
|
1330
|
+
return isImageAttachment(value) ? value : new ImageAttachment(value);
|
|
1331
|
+
}
|
|
1195
1332
|
async function readImageFile(path) {
|
|
1196
1333
|
if (!isNode()) {
|
|
1197
1334
|
throw new Error("caminho de arquivo s\xF3 \xE9 suportado em Node");
|
|
@@ -1204,7 +1341,7 @@ function startsWith(bytes, signature, offset = 0) {
|
|
|
1204
1341
|
return signature.every((byte, index) => bytes[offset + index] === byte);
|
|
1205
1342
|
}
|
|
1206
1343
|
var PNG_MAGIC = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
1207
|
-
var MAX_PNG_DIMENSION =
|
|
1344
|
+
var MAX_PNG_DIMENSION = WIRE_LIMITS.MAX_IMAGE_DIMENSION_PX;
|
|
1208
1345
|
var JPEG_MAGIC = [255, 216, 255];
|
|
1209
1346
|
var RIFF_MAGIC = [82, 73, 70, 70];
|
|
1210
1347
|
var WEBP_MAGIC = [87, 69, 66, 80];
|
|
@@ -1241,6 +1378,14 @@ function joinLogArgs(message, rest) {
|
|
|
1241
1378
|
if (rest.length === 0) return safeString(message);
|
|
1242
1379
|
return [message, ...rest].map(safeString).join(" ");
|
|
1243
1380
|
}
|
|
1381
|
+
function splitLogArgs(message, rest) {
|
|
1382
|
+
const args = [message, ...rest];
|
|
1383
|
+
const last = args[args.length - 1];
|
|
1384
|
+
if (!isImageAttachment(last)) return { text: joinLogArgs(message, rest) };
|
|
1385
|
+
const text = args.slice(0, -1);
|
|
1386
|
+
if (text.length === 0) return { text: last.caption !== void 0 ? safeString(last.caption) : "captura de tela", image: last };
|
|
1387
|
+
return { text: joinLogArgs(text[0], text.slice(1)), image: last };
|
|
1388
|
+
}
|
|
1244
1389
|
function printRunLog(task, level, message) {
|
|
1245
1390
|
const line = colorize(`[hobots:${task}] ${level.toUpperCase()}`, LOG_LEVEL_COLOR[level]);
|
|
1246
1391
|
const method2 = level === "warning" ? "warn" : level === "success" ? "info" : level;
|
|
@@ -1267,13 +1412,13 @@ var DEFAULT_LOG_FLUSH_INTERVAL_MS = 2e3;
|
|
|
1267
1412
|
var DEFAULT_CANCEL_CHECK_INTERVAL_MS = 5e3;
|
|
1268
1413
|
var MIN_CANCEL_CHECK_INTERVAL_MS = 1e3;
|
|
1269
1414
|
var MAX_CANCEL_CHECK_INTERVAL_MS = 15e3;
|
|
1270
|
-
var MAX_LOG_MESSAGE_CHARS =
|
|
1271
|
-
var MAX_LOGS_PER_PATCH =
|
|
1415
|
+
var MAX_LOG_MESSAGE_CHARS = WIRE_LIMITS.MAX_LOG_MESSAGE_CHARS;
|
|
1416
|
+
var MAX_LOGS_PER_PATCH = WIRE_LIMITS.MAX_LOGS_PER_PATCH;
|
|
1272
1417
|
var FLUSH_AT_BUFFERED = 20;
|
|
1273
|
-
var MAX_ITEMS_PER_RUN =
|
|
1274
|
-
var MAX_ITEMS_PER_REQUEST =
|
|
1275
|
-
var MAX_ITEM_MESSAGE_CHARS =
|
|
1276
|
-
var MAX_ITEM_PAYLOAD_BYTES =
|
|
1418
|
+
var MAX_ITEMS_PER_RUN = WIRE_LIMITS.MAX_ITEMS_PER_RUN;
|
|
1419
|
+
var MAX_ITEMS_PER_REQUEST = WIRE_LIMITS.MAX_ITEMS_PER_REQUEST;
|
|
1420
|
+
var MAX_ITEM_MESSAGE_CHARS = WIRE_LIMITS.MAX_ITEM_MESSAGE_CHARS;
|
|
1421
|
+
var MAX_ITEM_PAYLOAD_BYTES = WIRE_LIMITS.MAX_ITEM_PAYLOAD_BYTES;
|
|
1277
1422
|
var ITEMS_FLUSH_AT_BUFFERED = 100;
|
|
1278
1423
|
var ITEMS_DRAIN_MS = 15e3;
|
|
1279
1424
|
var PROGRESS_FLUSH_MS = 1e3;
|
|
@@ -1297,33 +1442,50 @@ var RunReporter = class {
|
|
|
1297
1442
|
MAX_CANCEL_CHECK_INTERVAL_MS,
|
|
1298
1443
|
Math.max(MIN_CANCEL_CHECK_INTERVAL_MS, cancelCheckIntervalMs ?? DEFAULT_CANCEL_CHECK_INTERVAL_MS)
|
|
1299
1444
|
);
|
|
1445
|
+
const logAt = (level) => (message, ...rest) => {
|
|
1446
|
+
const { text, image: image3 } = splitLogArgs(message, rest);
|
|
1447
|
+
this.log(level, text, image3);
|
|
1448
|
+
};
|
|
1300
1449
|
const log = {
|
|
1301
|
-
debug: (
|
|
1302
|
-
info: (
|
|
1303
|
-
warn: (
|
|
1304
|
-
error: (
|
|
1305
|
-
success: (
|
|
1450
|
+
debug: logAt("debug"),
|
|
1451
|
+
info: logAt("info"),
|
|
1452
|
+
warn: logAt("warning"),
|
|
1453
|
+
error: logAt("error"),
|
|
1454
|
+
success: logAt("success")
|
|
1306
1455
|
};
|
|
1307
1456
|
tx.setLifecycleSink((level, message) => this.push(level, message));
|
|
1457
|
+
tx.setAttachmentSink((image3, ts) => this.queueAttachment(image3, ts));
|
|
1308
1458
|
const checkCanceled = () => this.checkCanceled();
|
|
1309
1459
|
tx.setStepGuard(checkCanceled);
|
|
1460
|
+
const eachSink = {
|
|
1461
|
+
report: (status, message, payload, id, image3) => this.addItem(status, message, payload, id, image3),
|
|
1462
|
+
startStep: (op, description) => tx.startChild(op, description),
|
|
1463
|
+
declareTotal: (total) => {
|
|
1464
|
+
if (this.progressTotal == null) this.setProgress(this.progressCurrent, total);
|
|
1465
|
+
},
|
|
1466
|
+
advance: () => this.setProgress(this.progressCurrent + 1, this.progressTotal),
|
|
1467
|
+
checkCanceled,
|
|
1468
|
+
isAborted: () => this.abortController.signal.aborted,
|
|
1469
|
+
logError: (message) => this.log("error", message)
|
|
1470
|
+
};
|
|
1310
1471
|
const items = {
|
|
1311
1472
|
add: (item) => {
|
|
1312
1473
|
checkCanceled();
|
|
1313
|
-
this.addItem(item.status, item.message, item.payload, item.id);
|
|
1474
|
+
this.addItem(item.status, item.message, item.payload, item.id, item.image);
|
|
1314
1475
|
},
|
|
1315
1476
|
succeeded: (payload, options) => {
|
|
1316
1477
|
checkCanceled();
|
|
1317
|
-
this.addItem("succeeded", void 0, payload, options?.id);
|
|
1478
|
+
this.addItem("succeeded", void 0, payload, options?.id, options?.image);
|
|
1318
1479
|
},
|
|
1319
1480
|
failed: (message, payload, options) => {
|
|
1320
1481
|
checkCanceled();
|
|
1321
|
-
this.addItem("failed", message, payload, options?.id);
|
|
1482
|
+
this.addItem("failed", message, payload, options?.id, options?.image);
|
|
1322
1483
|
},
|
|
1323
1484
|
occurrence: (message, payload, options) => {
|
|
1324
1485
|
checkCanceled();
|
|
1325
|
-
this.addItem("occurrence", message, payload, options?.id);
|
|
1326
|
-
}
|
|
1486
|
+
this.addItem("occurrence", message, payload, options?.id, options?.image);
|
|
1487
|
+
},
|
|
1488
|
+
each: (list, handler, options = {}) => eachItem(list, handler, options, eachSink)
|
|
1327
1489
|
};
|
|
1328
1490
|
const progress = Object.defineProperties(
|
|
1329
1491
|
{
|
|
@@ -1362,7 +1524,6 @@ var RunReporter = class {
|
|
|
1362
1524
|
signal,
|
|
1363
1525
|
throwIfCanceled: checkCanceled,
|
|
1364
1526
|
sleep: sleep2,
|
|
1365
|
-
attach: (image, options) => this.attach(image, options),
|
|
1366
1527
|
retry: (fn, options) => retryWithBackoff(fn, { ...options, signal, wait: sleep2 })
|
|
1367
1528
|
};
|
|
1368
1529
|
}
|
|
@@ -1453,22 +1614,28 @@ var RunReporter = class {
|
|
|
1453
1614
|
this.clearFlushTimer();
|
|
1454
1615
|
return this.takeLogs().slice(-MAX_LOGS_PER_PATCH);
|
|
1455
1616
|
}
|
|
1456
|
-
|
|
1617
|
+
/**
|
|
1618
|
+
* Linha de log da run com eco no terminal. `image` (opcional) vira o anexo da linha:
|
|
1619
|
+
* o id entra na entrada ANTES de qualquer I/O — é isso que mantém a ordem dos logs
|
|
1620
|
+
* intacta e o handler livre da latência do upload.
|
|
1621
|
+
*/
|
|
1622
|
+
log(level, message, image3) {
|
|
1457
1623
|
if (this.dead) return;
|
|
1458
1624
|
const scrubbed = scrubSecrets(safeString(message));
|
|
1459
|
-
|
|
1460
|
-
this.
|
|
1625
|
+
const ts = nowISO();
|
|
1626
|
+
const attachmentId = image3 === void 0 ? void 0 : this.queueAttachment(image3, ts);
|
|
1627
|
+
printRunLog(this.context.task, level, attachmentId ? `${scrubbed} [imagem]` : scrubbed);
|
|
1628
|
+
this.push(level, scrubbed, true, attachmentId ? [attachmentId] : void 0, ts);
|
|
1461
1629
|
}
|
|
1462
1630
|
/** Bufferiza uma entrada de log sem eco no terminal (cap, truncate, flush). */
|
|
1463
|
-
push(level, message, alreadyScrubbed = false, attachments) {
|
|
1464
|
-
const ts = nowISO();
|
|
1631
|
+
push(level, message, alreadyScrubbed = false, attachments, ts = nowISO()) {
|
|
1465
1632
|
if (this.dead) return ts;
|
|
1466
1633
|
const scrubbed = alreadyScrubbed ? message : scrubSecrets(message);
|
|
1467
1634
|
this.buffer.push({
|
|
1468
1635
|
ts,
|
|
1469
1636
|
level,
|
|
1470
1637
|
message: truncate(scrubbed, MAX_LOG_MESSAGE_CHARS),
|
|
1471
|
-
...attachments && attachments.length > 0 ? { attachments } : {}
|
|
1638
|
+
...attachments && attachments.length > 0 ? { attachments: attachments.slice(0, WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY) } : {}
|
|
1472
1639
|
});
|
|
1473
1640
|
if (this.buffer.length >= FLUSH_AT_BUFFERED) {
|
|
1474
1641
|
this.flushLogs();
|
|
@@ -1611,7 +1778,7 @@ var RunReporter = class {
|
|
|
1611
1778
|
* de status, o servidor aceita itens mesmo com a run cancelada (trabalho já feito),
|
|
1612
1779
|
* então um reporter morto não descarta: só um kill() de exit path descarta.
|
|
1613
1780
|
*/
|
|
1614
|
-
addItem(status, message, payload, id) {
|
|
1781
|
+
addItem(status, message, payload, id, image3) {
|
|
1615
1782
|
if (this.itemsClosed || this.itemsUnsupported) return;
|
|
1616
1783
|
if (this.itemCount >= MAX_ITEMS_PER_RUN) {
|
|
1617
1784
|
if (!this.itemsQuotaExceeded) {
|
|
@@ -1636,13 +1803,16 @@ var RunReporter = class {
|
|
|
1636
1803
|
scrubbedPayload = void 0;
|
|
1637
1804
|
}
|
|
1638
1805
|
}
|
|
1806
|
+
const ts = nowISO();
|
|
1807
|
+
const attachmentId = image3 === void 0 ? void 0 : this.queueAttachment(image3, ts);
|
|
1639
1808
|
this.itemsBuffer.push({
|
|
1640
1809
|
id: id ? truncate(String(id), 255) : uuid4(),
|
|
1641
1810
|
seq: this.itemSeq++,
|
|
1642
1811
|
status,
|
|
1643
1812
|
...message ? { message: truncate(scrubSecrets(safeString(message)), MAX_ITEM_MESSAGE_CHARS) } : {},
|
|
1644
1813
|
...scrubbedPayload ? { payload: scrubbedPayload } : {},
|
|
1645
|
-
ts
|
|
1814
|
+
ts,
|
|
1815
|
+
...attachmentId ? { attachments: [attachmentId] } : {}
|
|
1646
1816
|
});
|
|
1647
1817
|
if (this.itemsBuffer.length >= ITEMS_FLUSH_AT_BUFFERED) {
|
|
1648
1818
|
this.flushItems();
|
|
@@ -1722,59 +1892,51 @@ var RunReporter = class {
|
|
|
1722
1892
|
}
|
|
1723
1893
|
// ── Anexos ───────────────────────────────────────────────────────────────────
|
|
1724
1894
|
/**
|
|
1725
|
-
*
|
|
1726
|
-
*
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
1895
|
+
* Pendura uma imagem num evento da run (log, item ou step): faz as checagens que não
|
|
1896
|
+
* dependem de I/O (reporter morto, instalação sem anexos, cota), reserva o id e dispara
|
|
1897
|
+
* o upload em segundo plano. Devolve o id — já referenciável pelo evento — ou undefined
|
|
1898
|
+
* quando a imagem foi descartada (sempre com aviso no log da run). Nunca lança: todo
|
|
1899
|
+
* caminho de erro do upload vira aviso. O hint `attachment` de `hobots.captureException`
|
|
1900
|
+
* também cai aqui via `log()`.
|
|
1729
1901
|
*/
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
const
|
|
1733
|
-
|
|
1734
|
-
const rawMessage = options.message !== void 0 ? safeString(options.message) : void 0;
|
|
1735
|
-
const caption = rawCaption ? truncate(scrubSecrets(rawCaption), MAX_CAPTION_CHARS) : void 0;
|
|
1736
|
-
const message = rawMessage ?? rawCaption ?? "captura de tela";
|
|
1737
|
-
if (this.dead) return { id, ok: false, reason: "canceled" };
|
|
1738
|
-
if (this.attachmentsUnsupported) {
|
|
1739
|
-
this.log(level, message);
|
|
1740
|
-
return { id, ok: false, reason: "unsupported" };
|
|
1741
|
-
}
|
|
1902
|
+
queueAttachment(imageIn, ts) {
|
|
1903
|
+
if (this.dead) return void 0;
|
|
1904
|
+
const image3 = toImageAttachment(imageIn);
|
|
1905
|
+
if (this.attachmentsUnsupported) return void 0;
|
|
1742
1906
|
if (this.attachmentCount >= MAX_ATTACHMENTS_PER_RUN) {
|
|
1743
|
-
this.
|
|
1744
|
-
|
|
1745
|
-
|
|
1907
|
+
if (this.attachmentCount === MAX_ATTACHMENTS_PER_RUN) {
|
|
1908
|
+
this.attachmentCount++;
|
|
1909
|
+
this.log("warning", `imagem descartada: limite de ${MAX_ATTACHMENTS_PER_RUN} por execu\xE7\xE3o atingido`);
|
|
1910
|
+
}
|
|
1911
|
+
return void 0;
|
|
1746
1912
|
}
|
|
1747
1913
|
this.attachmentCount++;
|
|
1748
|
-
const
|
|
1749
|
-
|
|
1750
|
-
const
|
|
1751
|
-
|
|
1752
|
-
const result = new Promise((resolve2) => {
|
|
1753
|
-
settle = resolve2;
|
|
1754
|
-
});
|
|
1755
|
-
const work = this.uploadAttachment(id, image, { caption, logTs, contentType: options.contentType }).then((reason) => settle(reason ? { id, ok: false, reason } : { id, ok: true })).catch(() => settle({ id, ok: false, reason: "upload-failed" }));
|
|
1914
|
+
const id = uuid4();
|
|
1915
|
+
const rawCaption = image3.caption !== void 0 ? safeString(image3.caption) : void 0;
|
|
1916
|
+
const caption = rawCaption ? truncate(scrubSecrets(rawCaption), MAX_CAPTION_CHARS) : void 0;
|
|
1917
|
+
const work = this.uploadAttachment(id, image3.input, { caption, logTs: ts, contentType: image3.contentType }).then(() => void 0).catch(() => void 0);
|
|
1756
1918
|
this.pendingAttachments.add(work);
|
|
1757
1919
|
void work.finally(() => this.pendingAttachments.delete(work));
|
|
1758
|
-
return
|
|
1920
|
+
return id;
|
|
1759
1921
|
}
|
|
1760
1922
|
/** Retorna o motivo da falha, ou undefined em sucesso. */
|
|
1761
|
-
async uploadAttachment(id,
|
|
1923
|
+
async uploadAttachment(id, image3, meta) {
|
|
1762
1924
|
let bytes;
|
|
1763
1925
|
try {
|
|
1764
|
-
bytes = await toBytes(
|
|
1926
|
+
bytes = await toBytes(image3);
|
|
1765
1927
|
} catch (error) {
|
|
1766
|
-
this.log("warning", `
|
|
1928
|
+
this.log("warning", `imagem n\xE3o p\xF4de ser lida: ${String(error)}`);
|
|
1767
1929
|
return "read-failed";
|
|
1768
1930
|
}
|
|
1769
1931
|
const contentType = sniffContentType(bytes) ?? meta.contentType;
|
|
1770
1932
|
if (!contentType) {
|
|
1771
|
-
this.log("warning", "
|
|
1933
|
+
this.log("warning", "imagem descartada: formato n\xE3o reconhecido (aceitos: PNG, JPEG, WEBP)");
|
|
1772
1934
|
return "unsupported-format";
|
|
1773
1935
|
}
|
|
1774
1936
|
if (bytes.byteLength > MAX_ATTACHMENT_BYTES) {
|
|
1775
1937
|
this.log(
|
|
1776
1938
|
"warning",
|
|
1777
|
-
`
|
|
1939
|
+
`imagem descartada: ${Math.round(bytes.byteLength / 1024)} KB excede o limite de ${MAX_ATTACHMENT_BYTES / 1024 / 1024} MB`
|
|
1778
1940
|
);
|
|
1779
1941
|
return "too-large";
|
|
1780
1942
|
}
|
|
@@ -1805,11 +1967,11 @@ var RunReporter = class {
|
|
|
1805
1967
|
return "unsupported";
|
|
1806
1968
|
}
|
|
1807
1969
|
if (error instanceof TasksApiError && error.status === 429) {
|
|
1808
|
-
this.log("warning", "
|
|
1970
|
+
this.log("warning", "imagem descartada: limite de anexos por execu\xE7\xE3o atingido no servidor");
|
|
1809
1971
|
return "quota";
|
|
1810
1972
|
}
|
|
1811
1973
|
if (this.abortController.signal.aborted) return "canceled";
|
|
1812
|
-
this.log("warning", `falha ao enviar
|
|
1974
|
+
this.log("warning", `falha ao enviar a imagem: ${String(error)}`);
|
|
1813
1975
|
void this.api.confirmAttachment(this.runId, id, { status: "failed" }).catch(() => {
|
|
1814
1976
|
});
|
|
1815
1977
|
return "upload-failed";
|
|
@@ -1973,23 +2135,39 @@ var Step = class {
|
|
|
1973
2135
|
/**
|
|
1974
2136
|
* Desfecho da step. `message` (opcional) é o motivo legível — vai em `data.message`
|
|
1975
2137
|
* e aparece na Central (performance e banner da execução) e no log de FINISH.
|
|
2138
|
+
* `options.image` pendura um print do estado da tela em `data.attachments`.
|
|
1976
2139
|
*/
|
|
1977
|
-
setStatus(status, message) {
|
|
2140
|
+
setStatus(status, message, options) {
|
|
1978
2141
|
this.status = status;
|
|
1979
2142
|
if (message) this.setData("message", stepMessage(message));
|
|
2143
|
+
if (options?.image !== void 0) this.attachImage(options.image);
|
|
1980
2144
|
return this;
|
|
1981
2145
|
}
|
|
1982
2146
|
/**
|
|
1983
2147
|
* Marca a step como `error` guardando o motivo em `data.error` ({ type, message }).
|
|
1984
2148
|
* Aceita qualquer valor lançado; `message` sobrescreve a mensagem do erro.
|
|
2149
|
+
* `options.image` pendura um print do estado da tela em `data.attachments`.
|
|
1985
2150
|
*/
|
|
1986
|
-
setError(error, message) {
|
|
2151
|
+
setError(error, message, options) {
|
|
1987
2152
|
this.status = "error";
|
|
1988
2153
|
const type = error instanceof Error ? error.name : typeof error === "object" && error !== null ? "Error" : void 0;
|
|
1989
2154
|
const raw = message ?? (error instanceof Error ? error.message || error.name : String(error));
|
|
1990
2155
|
this.setData("error", { ...type ? { type } : {}, message: stepMessage(raw) });
|
|
2156
|
+
if (options?.image !== void 0) this.attachImage(options.image);
|
|
1991
2157
|
return this;
|
|
1992
2158
|
}
|
|
2159
|
+
/**
|
|
2160
|
+
* Dispara o upload pela run (sink do RunReporter) e referencia o anexo em
|
|
2161
|
+
* `data.attachments` (chave reservada; teto igual ao das linhas de log). Fora de uma
|
|
2162
|
+
* run não há onde pendurar a imagem — descarta com aviso único.
|
|
2163
|
+
*/
|
|
2164
|
+
attachImage(image3) {
|
|
2165
|
+
const current = Array.isArray(this.data?.attachments) ? this.data.attachments : [];
|
|
2166
|
+
if (current.length >= MAX_ATTACHMENTS_PER_LOG_ENTRY) return;
|
|
2167
|
+
const id = this.transaction.attachImage(image3);
|
|
2168
|
+
if (!id) return;
|
|
2169
|
+
this.setData("attachments", [...current, id]);
|
|
2170
|
+
}
|
|
1993
2171
|
/** Motivo registrado via setStatus(…, message) ou setError — usado no log de FINISH. */
|
|
1994
2172
|
reason() {
|
|
1995
2173
|
const error = this.data?.error;
|
|
@@ -2050,6 +2228,8 @@ var Transaction = class {
|
|
|
2050
2228
|
tags = {};
|
|
2051
2229
|
finished = false;
|
|
2052
2230
|
lifecycleSink;
|
|
2231
|
+
attachmentSink;
|
|
2232
|
+
warnedNoAttachmentSink = false;
|
|
2053
2233
|
// instalado pelo RunReporter: abrir uma step é um ponto de parada cooperativo (lança RunCanceled)
|
|
2054
2234
|
stepGuard;
|
|
2055
2235
|
// eventos emitidos antes do sink existir (o START da transaction sai no construtor,
|
|
@@ -2080,6 +2260,19 @@ var Transaction = class {
|
|
|
2080
2260
|
this.lifecycleBacklog = [];
|
|
2081
2261
|
for (const [level, message] of backlog) sink(level, message);
|
|
2082
2262
|
}
|
|
2263
|
+
/** Conecta o pipeline de anexos da run — é o que dá imagem às steps. */
|
|
2264
|
+
setAttachmentSink(sink) {
|
|
2265
|
+
this.attachmentSink = sink;
|
|
2266
|
+
}
|
|
2267
|
+
/** Imagem de uma step → id do anexo pela run; sem run, descarta com aviso único. */
|
|
2268
|
+
attachImage(image3) {
|
|
2269
|
+
if (this.attachmentSink) return this.attachmentSink(image3, nowISO());
|
|
2270
|
+
if (!this.warnedNoAttachmentSink) {
|
|
2271
|
+
this.warnedNoAttachmentSink = true;
|
|
2272
|
+
console.warn("[hobots] imagem de step descartada \u2014 s\xF3 \xE9 suportada dentro de uma execu\xE7\xE3o de task");
|
|
2273
|
+
}
|
|
2274
|
+
return void 0;
|
|
2275
|
+
}
|
|
2083
2276
|
/**
|
|
2084
2277
|
* Conecta a checagem de cancelamento chamada antes de cada step nova — é assim que
|
|
2085
2278
|
* `hobots.transaction.startChild()` (e `step.startChild()`) param uma run cancelada.
|
|
@@ -2169,6 +2362,7 @@ async function executeRun(input) {
|
|
|
2169
2362
|
await runWithRunContext({ reporter }, () => invokeWithRetry(task, run, reporter, logger));
|
|
2170
2363
|
await reporter.finalizeAttachments();
|
|
2171
2364
|
await reporter.finalizeItems();
|
|
2365
|
+
warnIncompleteProgress(reporter);
|
|
2172
2366
|
tx.setStatus("ok");
|
|
2173
2367
|
tx.finish();
|
|
2174
2368
|
reporter.reportSuccess();
|
|
@@ -2186,6 +2380,13 @@ async function executeRun(input) {
|
|
|
2186
2380
|
tracker.remove(reporter);
|
|
2187
2381
|
}
|
|
2188
2382
|
}
|
|
2383
|
+
function warnIncompleteProgress(reporter) {
|
|
2384
|
+
const snapshot = reporter.context.progress.snapshot;
|
|
2385
|
+
if (!snapshot || snapshot.current >= snapshot.total) return;
|
|
2386
|
+
reporter.context.log.warn(
|
|
2387
|
+
`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`
|
|
2388
|
+
);
|
|
2389
|
+
}
|
|
2189
2390
|
function invokeWithRetry(task, run, reporter, logger) {
|
|
2190
2391
|
const { retries, retryDelayMs } = task.options;
|
|
2191
2392
|
const total = retries + 1;
|
|
@@ -2240,8 +2441,8 @@ function waitForCancelGrace(signal, graceMs) {
|
|
|
2240
2441
|
signal.addEventListener("abort", () => setTimeout(resolve2, graceMs), { once: true });
|
|
2241
2442
|
});
|
|
2242
2443
|
}
|
|
2243
|
-
var MAX_ERROR_MESSAGE_CHARS =
|
|
2244
|
-
var MAX_ERROR_STACK_CHARS =
|
|
2444
|
+
var MAX_ERROR_MESSAGE_CHARS = WIRE_LIMITS.MAX_ERROR_MESSAGE_CHARS;
|
|
2445
|
+
var MAX_ERROR_STACK_CHARS = WIRE_LIMITS.MAX_ERROR_STACK_CHARS;
|
|
2245
2446
|
function toRunError(error) {
|
|
2246
2447
|
if (error instanceof Error) {
|
|
2247
2448
|
return {
|
|
@@ -2256,7 +2457,7 @@ function toRunError(error) {
|
|
|
2256
2457
|
// src/tasks/agent.ts
|
|
2257
2458
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
2258
2459
|
var MIN_POLL_INTERVAL_MS = 1e3;
|
|
2259
|
-
var MAX_CLAIM_PER_POLL =
|
|
2460
|
+
var MAX_CLAIM_PER_POLL = WIRE_LIMITS.MAX_CLAIM_PER_POLL;
|
|
2260
2461
|
var TaskAgent = class {
|
|
2261
2462
|
constructor(options) {
|
|
2262
2463
|
this.options = options;
|
|
@@ -2391,8 +2592,8 @@ var TaskAgent = class {
|
|
|
2391
2592
|
|
|
2392
2593
|
// src/tasks/item-columns.ts
|
|
2393
2594
|
var KEY_RE = /^[a-zA-Z0-9_.-]{1,100}$/;
|
|
2394
|
-
var MAX_COLUMNS =
|
|
2395
|
-
var MAX_LABEL_CHARS =
|
|
2595
|
+
var MAX_COLUMNS = WIRE_LIMITS.MAX_ITEM_COLUMNS;
|
|
2596
|
+
var MAX_LABEL_CHARS = WIRE_LIMITS.MAX_ITEM_COLUMN_LABEL_CHARS;
|
|
2396
2597
|
function normalizeItemColumns(slug, input, logger) {
|
|
2397
2598
|
if (input === void 0 || input === null) return void 0;
|
|
2398
2599
|
const columns = input.columns;
|
|
@@ -2839,13 +3040,8 @@ function forwardAttachment(rt, attachment, message, type) {
|
|
|
2839
3040
|
rt.logger.warn("attachment descartado \u2014 s\xF3 \xE9 suportado dentro de uma execu\xE7\xE3o de task");
|
|
2840
3041
|
return;
|
|
2841
3042
|
}
|
|
2842
|
-
const withMeta = typeof attachment === "object" && "image" in attachment ? attachment :
|
|
2843
|
-
|
|
2844
|
-
message,
|
|
2845
|
-
level: toRunLogLevel(type),
|
|
2846
|
-
caption: withMeta.caption,
|
|
2847
|
-
contentType: withMeta.contentType
|
|
2848
|
-
});
|
|
3043
|
+
const withMeta = typeof attachment === "object" && !isImageAttachment(attachment) && "image" in attachment ? image(attachment.image, { caption: attachment.caption, contentType: attachment.contentType }) : attachment;
|
|
3044
|
+
reporter.log(toRunLogLevel(type), message, withMeta);
|
|
2849
3045
|
}
|
|
2850
3046
|
function captureException(error, hint) {
|
|
2851
3047
|
const rt = runtime;
|
|
@@ -2892,15 +3088,34 @@ function warnOutsideRun(member) {
|
|
|
2892
3088
|
else console.warn(`[hobots] ${message}`);
|
|
2893
3089
|
}
|
|
2894
3090
|
var FALLBACK_TASK = "hobots";
|
|
3091
|
+
var fallbackLogAt = (level) => (message, ...rest) => {
|
|
3092
|
+
const { text, image: dropped } = splitLogArgs(message, rest);
|
|
3093
|
+
printRunLog(FALLBACK_TASK, level, dropped ? `${text} [imagem descartada]` : text);
|
|
3094
|
+
};
|
|
2895
3095
|
var fallbackLog = {
|
|
2896
|
-
debug: (
|
|
2897
|
-
info: (
|
|
2898
|
-
warn: (
|
|
2899
|
-
error: (
|
|
2900
|
-
success: (
|
|
3096
|
+
debug: fallbackLogAt("debug"),
|
|
3097
|
+
info: fallbackLogAt("info"),
|
|
3098
|
+
warn: fallbackLogAt("warning"),
|
|
3099
|
+
error: fallbackLogAt("error"),
|
|
3100
|
+
success: fallbackLogAt("success")
|
|
2901
3101
|
};
|
|
2902
3102
|
var noop = () => void 0;
|
|
2903
|
-
var
|
|
3103
|
+
var fallbackEachSink = {
|
|
3104
|
+
report: noop,
|
|
3105
|
+
startStep: () => void 0,
|
|
3106
|
+
declareTotal: noop,
|
|
3107
|
+
advance: noop,
|
|
3108
|
+
checkCanceled: noop,
|
|
3109
|
+
isAborted: () => false,
|
|
3110
|
+
logError: (message) => printRunLog(FALLBACK_TASK, "error", message)
|
|
3111
|
+
};
|
|
3112
|
+
var fallbackItems = {
|
|
3113
|
+
add: noop,
|
|
3114
|
+
succeeded: noop,
|
|
3115
|
+
failed: noop,
|
|
3116
|
+
occurrence: noop,
|
|
3117
|
+
each: (list, handler, options = {}) => eachItem(list, handler, options, fallbackEachSink)
|
|
3118
|
+
};
|
|
2904
3119
|
var fallbackProgress = { total: noop, advance: noop, set: noop, current: 0, snapshot: null };
|
|
2905
3120
|
var neverAborts = new AbortController().signal;
|
|
2906
3121
|
var detachedTransaction;
|
|
@@ -2928,9 +3143,6 @@ var hobots = Object.defineProperties({}, {
|
|
|
2928
3143
|
signal: getter("signal", () => neverAborts),
|
|
2929
3144
|
throwIfCanceled: method(() => resolve("throwIfCanceled")?.throwIfCanceled()),
|
|
2930
3145
|
sleep: method((ms) => resolve("sleep")?.sleep(ms) ?? sleep(ms)),
|
|
2931
|
-
attach: method(
|
|
2932
|
-
(image, options) => resolve("attach")?.attach(image, options) ?? Promise.resolve({ id: "", ok: false, reason: "canceled" })
|
|
2933
|
-
),
|
|
2934
3146
|
retry: method((fn, options) => {
|
|
2935
3147
|
const reporter = currentReporter();
|
|
2936
3148
|
return reporter ? reporter.context.retry(fn, options) : retryWithBackoff(fn, options);
|
|
@@ -2945,7 +3157,8 @@ var hobots = Object.defineProperties({}, {
|
|
|
2945
3157
|
installGlobalHobots();
|
|
2946
3158
|
}),
|
|
2947
3159
|
close: method((timeoutMs) => close(timeoutMs)),
|
|
2948
|
-
captureException: method((error, hint) => captureException(error, hint))
|
|
3160
|
+
captureException: method((error, hint) => captureException(error, hint)),
|
|
3161
|
+
image: method(image)
|
|
2949
3162
|
});
|
|
2950
3163
|
function installGlobalHobots() {
|
|
2951
3164
|
if (globalThis.hobots === hobots) return;
|
|
@@ -2956,6 +3169,7 @@ var start2 = hobots.start;
|
|
|
2956
3169
|
var close2 = hobots.close;
|
|
2957
3170
|
var captureException2 = hobots.captureException;
|
|
2958
3171
|
var retry = hobots.retry;
|
|
3172
|
+
var image2 = hobots.image;
|
|
2959
3173
|
|
|
2960
3174
|
// src/index.ts
|
|
2961
3175
|
var src_default = hobots;
|