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.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.
|
|
60
|
+
var SDK_VERSION = true ? "3.4.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 =
|
|
239
|
+
var MAX_ITEMS_PER_ENVELOPE = WIRE_LIMITS.MAX_ITEMS_PER_ENVELOPE;
|
|
236
240
|
var Transport = class {
|
|
237
241
|
endpoint;
|
|
238
242
|
key;
|
|
@@ -308,6 +312,7 @@ var Transport = class {
|
|
|
308
312
|
try {
|
|
309
313
|
response = await fetchWithRetry(
|
|
310
314
|
() => fetch(this.endpoint, {
|
|
315
|
+
redirect: "error",
|
|
311
316
|
method: "POST",
|
|
312
317
|
headers: { "content-type": "application/json", authorization: `Bearer ${this.key}` },
|
|
313
318
|
body: JSON.stringify(envelope),
|
|
@@ -485,7 +490,6 @@ function envBaseUrl() {
|
|
|
485
490
|
function isLoopbackHost(hostname2) {
|
|
486
491
|
return hostname2 === "localhost" || hostname2.endsWith(".localhost") || hostname2.startsWith("127.") || hostname2 === "[::1]" || hostname2 === "::1" || hostname2 === "0.0.0.0";
|
|
487
492
|
}
|
|
488
|
-
var warnedInsecureBaseUrl = false;
|
|
489
493
|
function validateBaseUrl(raw, prefix) {
|
|
490
494
|
let url;
|
|
491
495
|
try {
|
|
@@ -499,11 +503,8 @@ function validateBaseUrl(raw, prefix) {
|
|
|
499
503
|
if (url.username || url.password) {
|
|
500
504
|
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`);
|
|
501
505
|
}
|
|
502
|
-
if (url.protocol === "http:" && !isLoopbackHost(url.hostname)
|
|
503
|
-
|
|
504
|
-
console.warn(
|
|
505
|
-
`${prefix} HOBOTS_API_URL usa http para o host remoto "${url.hostname}" \u2014 o Client Secret trafega sem TLS`
|
|
506
|
-
);
|
|
506
|
+
if (url.protocol === "http:" && !isLoopbackHost(url.hostname)) {
|
|
507
|
+
throw new Error(`${prefix} HOBOTS_API_URL usa http para o host remoto "${url.hostname}" \u2014 o Client Secret trafegaria sem TLS; use https`);
|
|
507
508
|
}
|
|
508
509
|
return raw.replace(/\/+$/, "");
|
|
509
510
|
}
|
|
@@ -556,9 +557,9 @@ async function fallbackInstanceId() {
|
|
|
556
557
|
}
|
|
557
558
|
|
|
558
559
|
// src/heartbeat.ts
|
|
559
|
-
var DEFAULT_INTERVAL_MS =
|
|
560
|
-
var MIN_REPORTED_INTERVAL_MS =
|
|
561
|
-
var MAX_REPORTED_INTERVAL_MS =
|
|
560
|
+
var DEFAULT_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_DEFAULT_INTERVAL_MS;
|
|
561
|
+
var MIN_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MIN_INTERVAL_MS;
|
|
562
|
+
var MAX_REPORTED_INTERVAL_MS = WIRE_LIMITS.HEARTBEAT_MAX_INTERVAL_MS;
|
|
562
563
|
var Heartbeat = class {
|
|
563
564
|
constructor(client, options = {}, instanceId, sampler) {
|
|
564
565
|
this.client = client;
|
|
@@ -867,6 +868,7 @@ var TasksApi = class {
|
|
|
867
868
|
let response;
|
|
868
869
|
try {
|
|
869
870
|
response = await fetch(`${this.baseUrl}/poll`, {
|
|
871
|
+
redirect: "error",
|
|
870
872
|
method: "POST",
|
|
871
873
|
headers: this.headers(),
|
|
872
874
|
body: JSON.stringify(request),
|
|
@@ -890,6 +892,7 @@ var TasksApi = class {
|
|
|
890
892
|
let response;
|
|
891
893
|
try {
|
|
892
894
|
response = await fetch(`${this.baseUrl}/runs`, {
|
|
895
|
+
redirect: "error",
|
|
893
896
|
method: "POST",
|
|
894
897
|
headers: this.headers(),
|
|
895
898
|
body: JSON.stringify(request),
|
|
@@ -940,6 +943,7 @@ var TasksApi = class {
|
|
|
940
943
|
try {
|
|
941
944
|
response = await fetchWithRetry(
|
|
942
945
|
() => fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}`, {
|
|
946
|
+
redirect: "error",
|
|
943
947
|
method: "PATCH",
|
|
944
948
|
headers: this.headers(),
|
|
945
949
|
body: JSON.stringify(update),
|
|
@@ -961,6 +965,7 @@ var TasksApi = class {
|
|
|
961
965
|
*/
|
|
962
966
|
async updateRunOnce(runId, update, timeoutMs = 2e3) {
|
|
963
967
|
await fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}`, {
|
|
968
|
+
redirect: "error",
|
|
964
969
|
method: "PATCH",
|
|
965
970
|
headers: this.headers(),
|
|
966
971
|
body: JSON.stringify(update),
|
|
@@ -977,6 +982,7 @@ var TasksApi = class {
|
|
|
977
982
|
try {
|
|
978
983
|
response = await fetchWithRetry(
|
|
979
984
|
() => fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}/items`, {
|
|
985
|
+
redirect: "error",
|
|
980
986
|
method: "POST",
|
|
981
987
|
headers: this.headers(),
|
|
982
988
|
body: JSON.stringify(request),
|
|
@@ -1006,6 +1012,7 @@ var TasksApi = class {
|
|
|
1006
1012
|
UPDATE_TIMEOUT_MS,
|
|
1007
1013
|
signal,
|
|
1008
1014
|
(timeoutSignal) => fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}/attachments`, {
|
|
1015
|
+
redirect: "error",
|
|
1009
1016
|
method: "POST",
|
|
1010
1017
|
headers: this.headers(),
|
|
1011
1018
|
body: JSON.stringify(request),
|
|
@@ -1038,6 +1045,7 @@ var TasksApi = class {
|
|
|
1038
1045
|
UPLOAD_TIMEOUT_MS,
|
|
1039
1046
|
signal,
|
|
1040
1047
|
(timeoutSignal) => fetch(url, {
|
|
1048
|
+
redirect: "error",
|
|
1041
1049
|
method: "PUT",
|
|
1042
1050
|
headers,
|
|
1043
1051
|
// BodyInit não aceita Uint8Array<ArrayBufferLike> em todos os lib.dom; o buffer é o mesmo
|
|
@@ -1056,6 +1064,7 @@ var TasksApi = class {
|
|
|
1056
1064
|
const response = await fetch(
|
|
1057
1065
|
`${this.baseUrl}/runs/${encodeURIComponent(runId)}/attachments/${encodeURIComponent(attachmentId)}`,
|
|
1058
1066
|
{
|
|
1067
|
+
redirect: "error",
|
|
1059
1068
|
method: "PATCH",
|
|
1060
1069
|
headers: this.headers(),
|
|
1061
1070
|
body: JSON.stringify(request),
|
|
@@ -1118,6 +1127,88 @@ function isTerminalError(error) {
|
|
|
1118
1127
|
return error instanceof Error && TERMINAL_ERROR_NAMES.has(error.name);
|
|
1119
1128
|
}
|
|
1120
1129
|
|
|
1130
|
+
// src/tasks/each.ts
|
|
1131
|
+
function thrownMessage(error) {
|
|
1132
|
+
if (error instanceof Error) return error.message || error.name;
|
|
1133
|
+
return safeString(error);
|
|
1134
|
+
}
|
|
1135
|
+
var ItemHandle = class {
|
|
1136
|
+
constructor(index, id, step, basePayload, sink) {
|
|
1137
|
+
this.index = index;
|
|
1138
|
+
this.id = id;
|
|
1139
|
+
this.step = step;
|
|
1140
|
+
this.basePayload = basePayload;
|
|
1141
|
+
this.sink = sink;
|
|
1142
|
+
}
|
|
1143
|
+
index;
|
|
1144
|
+
id;
|
|
1145
|
+
step;
|
|
1146
|
+
basePayload;
|
|
1147
|
+
sink;
|
|
1148
|
+
reported = false;
|
|
1149
|
+
status;
|
|
1150
|
+
succeeded(payload, options) {
|
|
1151
|
+
this.record("succeeded", void 0, payload, options?.image);
|
|
1152
|
+
}
|
|
1153
|
+
failed(message, payload, options) {
|
|
1154
|
+
this.record("failed", message, payload, options?.image);
|
|
1155
|
+
if (this.step && this.step.status !== "error") this.step.setStatus("error", message);
|
|
1156
|
+
}
|
|
1157
|
+
occurrence(message, payload, options) {
|
|
1158
|
+
this.record("occurrence", message, payload, options?.image);
|
|
1159
|
+
if (this.step && this.step.status === "ok") this.step.setStatus("warning", message);
|
|
1160
|
+
}
|
|
1161
|
+
record(status, message, payload, image3) {
|
|
1162
|
+
this.reported = true;
|
|
1163
|
+
this.status = status;
|
|
1164
|
+
const merged = { ...this.basePayload ?? {}, ...payload ?? {} };
|
|
1165
|
+
this.sink.report(status, message, Object.keys(merged).length > 0 ? merged : void 0, this.id, image3);
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
function resolveId(options, element, index) {
|
|
1169
|
+
const raw = options.id?.(element, index);
|
|
1170
|
+
if (raw === null || raw === void 0) return void 0;
|
|
1171
|
+
const text = safeString(raw);
|
|
1172
|
+
return text.length > 0 ? text : void 0;
|
|
1173
|
+
}
|
|
1174
|
+
function knownLength(list) {
|
|
1175
|
+
const length = list?.length;
|
|
1176
|
+
return typeof length === "number" && Number.isInteger(length) && length >= 1 ? length : void 0;
|
|
1177
|
+
}
|
|
1178
|
+
async function eachItem(list, handler, options, sink) {
|
|
1179
|
+
const result = { total: 0, succeeded: 0, failed: 0, occurrence: 0 };
|
|
1180
|
+
const length = options.progress === false ? void 0 : knownLength(list);
|
|
1181
|
+
if (length !== void 0) sink.declareTotal(length);
|
|
1182
|
+
let index = 0;
|
|
1183
|
+
for await (const element of list) {
|
|
1184
|
+
sink.checkCanceled();
|
|
1185
|
+
const id = resolveId(options, element, index);
|
|
1186
|
+
const description = options.description?.(element, index) ?? id ?? `#${index + 1}`;
|
|
1187
|
+
const step = sink.startStep(options.op ?? "item", description);
|
|
1188
|
+
const handle = new ItemHandle(index, id, step, options.payload?.(element, index), sink);
|
|
1189
|
+
try {
|
|
1190
|
+
await handler(element, handle, index);
|
|
1191
|
+
if (!handle.reported) handle.succeeded();
|
|
1192
|
+
} catch (error) {
|
|
1193
|
+
if (isTerminalError(error) || sink.isAborted()) {
|
|
1194
|
+
step?.setStatus("cancelled");
|
|
1195
|
+
step?.finish();
|
|
1196
|
+
throw error;
|
|
1197
|
+
}
|
|
1198
|
+
const message = thrownMessage(error);
|
|
1199
|
+
if (!handle.reported) handle.failed(message);
|
|
1200
|
+
step?.setError(error);
|
|
1201
|
+
sink.logError(`item ${description} falhou: ${message}`);
|
|
1202
|
+
}
|
|
1203
|
+
step?.finish();
|
|
1204
|
+
if (options.progress !== false) sink.advance();
|
|
1205
|
+
result.total += 1;
|
|
1206
|
+
result[handle.status ?? "succeeded"] += 1;
|
|
1207
|
+
index += 1;
|
|
1208
|
+
}
|
|
1209
|
+
return result;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1121
1212
|
// src/retry.ts
|
|
1122
1213
|
var DEFAULT_RETRIES = 3;
|
|
1123
1214
|
var DEFAULT_DELAY_MS = 1e3;
|
|
@@ -1145,11 +1236,33 @@ async function retryWithBackoff(fn, options = {}) {
|
|
|
1145
1236
|
}
|
|
1146
1237
|
|
|
1147
1238
|
// src/tasks/attachments.ts
|
|
1148
|
-
var MAX_ATTACHMENT_BYTES =
|
|
1149
|
-
var MAX_ATTACHMENTS_PER_RUN =
|
|
1239
|
+
var MAX_ATTACHMENT_BYTES = WIRE_LIMITS.MAX_ATTACHMENT_BYTES;
|
|
1240
|
+
var MAX_ATTACHMENTS_PER_RUN = WIRE_LIMITS.MAX_ATTACHMENTS_PER_RUN;
|
|
1241
|
+
var MAX_ATTACHMENTS_PER_LOG_ENTRY = WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY;
|
|
1150
1242
|
var MAX_CONCURRENT_UPLOADS = 3;
|
|
1151
|
-
var MAX_CAPTION_CHARS =
|
|
1243
|
+
var MAX_CAPTION_CHARS = WIRE_LIMITS.MAX_CAPTION_CHARS;
|
|
1152
1244
|
var ATTACHMENT_DRAIN_MS = 15e3;
|
|
1245
|
+
var IMAGE_BRAND = /* @__PURE__ */ Symbol.for("hobots.image");
|
|
1246
|
+
var ImageAttachment = class {
|
|
1247
|
+
constructor(input, caption, contentType) {
|
|
1248
|
+
this.input = input;
|
|
1249
|
+
this.caption = caption;
|
|
1250
|
+
this.contentType = contentType;
|
|
1251
|
+
}
|
|
1252
|
+
input;
|
|
1253
|
+
caption;
|
|
1254
|
+
contentType;
|
|
1255
|
+
[IMAGE_BRAND] = true;
|
|
1256
|
+
};
|
|
1257
|
+
function image(input, options = {}) {
|
|
1258
|
+
return new ImageAttachment(input, options.caption, options.contentType);
|
|
1259
|
+
}
|
|
1260
|
+
function isImageAttachment(value) {
|
|
1261
|
+
return typeof value === "object" && value !== null && value[IMAGE_BRAND] === true;
|
|
1262
|
+
}
|
|
1263
|
+
function toImageAttachment(value) {
|
|
1264
|
+
return isImageAttachment(value) ? value : new ImageAttachment(value);
|
|
1265
|
+
}
|
|
1153
1266
|
async function readImageFile(path) {
|
|
1154
1267
|
if (!isNode()) {
|
|
1155
1268
|
throw new Error("caminho de arquivo s\xF3 \xE9 suportado em Node");
|
|
@@ -1162,7 +1275,7 @@ function startsWith(bytes, signature, offset = 0) {
|
|
|
1162
1275
|
return signature.every((byte, index) => bytes[offset + index] === byte);
|
|
1163
1276
|
}
|
|
1164
1277
|
var PNG_MAGIC = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
1165
|
-
var MAX_PNG_DIMENSION =
|
|
1278
|
+
var MAX_PNG_DIMENSION = WIRE_LIMITS.MAX_IMAGE_DIMENSION_PX;
|
|
1166
1279
|
var JPEG_MAGIC = [255, 216, 255];
|
|
1167
1280
|
var RIFF_MAGIC = [82, 73, 70, 70];
|
|
1168
1281
|
var WEBP_MAGIC = [87, 69, 66, 80];
|
|
@@ -1199,6 +1312,14 @@ function joinLogArgs(message, rest) {
|
|
|
1199
1312
|
if (rest.length === 0) return safeString(message);
|
|
1200
1313
|
return [message, ...rest].map(safeString).join(" ");
|
|
1201
1314
|
}
|
|
1315
|
+
function splitLogArgs(message, rest) {
|
|
1316
|
+
const args = [message, ...rest];
|
|
1317
|
+
const last = args[args.length - 1];
|
|
1318
|
+
if (!isImageAttachment(last)) return { text: joinLogArgs(message, rest) };
|
|
1319
|
+
const text = args.slice(0, -1);
|
|
1320
|
+
if (text.length === 0) return { text: last.caption !== void 0 ? safeString(last.caption) : "captura de tela", image: last };
|
|
1321
|
+
return { text: joinLogArgs(text[0], text.slice(1)), image: last };
|
|
1322
|
+
}
|
|
1202
1323
|
function printRunLog(task, level, message) {
|
|
1203
1324
|
const line = colorize(`[hobots:${task}] ${level.toUpperCase()}`, LOG_LEVEL_COLOR[level]);
|
|
1204
1325
|
const method2 = level === "warning" ? "warn" : level === "success" ? "info" : level;
|
|
@@ -1225,13 +1346,13 @@ var DEFAULT_LOG_FLUSH_INTERVAL_MS = 2e3;
|
|
|
1225
1346
|
var DEFAULT_CANCEL_CHECK_INTERVAL_MS = 5e3;
|
|
1226
1347
|
var MIN_CANCEL_CHECK_INTERVAL_MS = 1e3;
|
|
1227
1348
|
var MAX_CANCEL_CHECK_INTERVAL_MS = 15e3;
|
|
1228
|
-
var MAX_LOG_MESSAGE_CHARS =
|
|
1229
|
-
var MAX_LOGS_PER_PATCH =
|
|
1349
|
+
var MAX_LOG_MESSAGE_CHARS = WIRE_LIMITS.MAX_LOG_MESSAGE_CHARS;
|
|
1350
|
+
var MAX_LOGS_PER_PATCH = WIRE_LIMITS.MAX_LOGS_PER_PATCH;
|
|
1230
1351
|
var FLUSH_AT_BUFFERED = 20;
|
|
1231
|
-
var MAX_ITEMS_PER_RUN =
|
|
1232
|
-
var MAX_ITEMS_PER_REQUEST =
|
|
1233
|
-
var MAX_ITEM_MESSAGE_CHARS =
|
|
1234
|
-
var MAX_ITEM_PAYLOAD_BYTES =
|
|
1352
|
+
var MAX_ITEMS_PER_RUN = WIRE_LIMITS.MAX_ITEMS_PER_RUN;
|
|
1353
|
+
var MAX_ITEMS_PER_REQUEST = WIRE_LIMITS.MAX_ITEMS_PER_REQUEST;
|
|
1354
|
+
var MAX_ITEM_MESSAGE_CHARS = WIRE_LIMITS.MAX_ITEM_MESSAGE_CHARS;
|
|
1355
|
+
var MAX_ITEM_PAYLOAD_BYTES = WIRE_LIMITS.MAX_ITEM_PAYLOAD_BYTES;
|
|
1235
1356
|
var ITEMS_FLUSH_AT_BUFFERED = 100;
|
|
1236
1357
|
var ITEMS_DRAIN_MS = 15e3;
|
|
1237
1358
|
var PROGRESS_FLUSH_MS = 1e3;
|
|
@@ -1255,33 +1376,50 @@ var RunReporter = class {
|
|
|
1255
1376
|
MAX_CANCEL_CHECK_INTERVAL_MS,
|
|
1256
1377
|
Math.max(MIN_CANCEL_CHECK_INTERVAL_MS, cancelCheckIntervalMs ?? DEFAULT_CANCEL_CHECK_INTERVAL_MS)
|
|
1257
1378
|
);
|
|
1379
|
+
const logAt = (level) => (message, ...rest) => {
|
|
1380
|
+
const { text, image: image3 } = splitLogArgs(message, rest);
|
|
1381
|
+
this.log(level, text, image3);
|
|
1382
|
+
};
|
|
1258
1383
|
const log = {
|
|
1259
|
-
debug: (
|
|
1260
|
-
info: (
|
|
1261
|
-
warn: (
|
|
1262
|
-
error: (
|
|
1263
|
-
success: (
|
|
1384
|
+
debug: logAt("debug"),
|
|
1385
|
+
info: logAt("info"),
|
|
1386
|
+
warn: logAt("warning"),
|
|
1387
|
+
error: logAt("error"),
|
|
1388
|
+
success: logAt("success")
|
|
1264
1389
|
};
|
|
1265
1390
|
tx.setLifecycleSink((level, message) => this.push(level, message));
|
|
1391
|
+
tx.setAttachmentSink((image3, ts) => this.queueAttachment(image3, ts));
|
|
1266
1392
|
const checkCanceled = () => this.checkCanceled();
|
|
1267
1393
|
tx.setStepGuard(checkCanceled);
|
|
1394
|
+
const eachSink = {
|
|
1395
|
+
report: (status, message, payload, id, image3) => this.addItem(status, message, payload, id, image3),
|
|
1396
|
+
startStep: (op, description) => tx.startChild(op, description),
|
|
1397
|
+
declareTotal: (total) => {
|
|
1398
|
+
if (this.progressTotal == null) this.setProgress(this.progressCurrent, total);
|
|
1399
|
+
},
|
|
1400
|
+
advance: () => this.setProgress(this.progressCurrent + 1, this.progressTotal),
|
|
1401
|
+
checkCanceled,
|
|
1402
|
+
isAborted: () => this.abortController.signal.aborted,
|
|
1403
|
+
logError: (message) => this.log("error", message)
|
|
1404
|
+
};
|
|
1268
1405
|
const items = {
|
|
1269
1406
|
add: (item) => {
|
|
1270
1407
|
checkCanceled();
|
|
1271
|
-
this.addItem(item.status, item.message, item.payload, item.id);
|
|
1408
|
+
this.addItem(item.status, item.message, item.payload, item.id, item.image);
|
|
1272
1409
|
},
|
|
1273
1410
|
succeeded: (payload, options) => {
|
|
1274
1411
|
checkCanceled();
|
|
1275
|
-
this.addItem("succeeded", void 0, payload, options?.id);
|
|
1412
|
+
this.addItem("succeeded", void 0, payload, options?.id, options?.image);
|
|
1276
1413
|
},
|
|
1277
1414
|
failed: (message, payload, options) => {
|
|
1278
1415
|
checkCanceled();
|
|
1279
|
-
this.addItem("failed", message, payload, options?.id);
|
|
1416
|
+
this.addItem("failed", message, payload, options?.id, options?.image);
|
|
1280
1417
|
},
|
|
1281
1418
|
occurrence: (message, payload, options) => {
|
|
1282
1419
|
checkCanceled();
|
|
1283
|
-
this.addItem("occurrence", message, payload, options?.id);
|
|
1284
|
-
}
|
|
1420
|
+
this.addItem("occurrence", message, payload, options?.id, options?.image);
|
|
1421
|
+
},
|
|
1422
|
+
each: (list, handler, options = {}) => eachItem(list, handler, options, eachSink)
|
|
1285
1423
|
};
|
|
1286
1424
|
const progress = Object.defineProperties(
|
|
1287
1425
|
{
|
|
@@ -1320,7 +1458,6 @@ var RunReporter = class {
|
|
|
1320
1458
|
signal,
|
|
1321
1459
|
throwIfCanceled: checkCanceled,
|
|
1322
1460
|
sleep: sleep2,
|
|
1323
|
-
attach: (image, options) => this.attach(image, options),
|
|
1324
1461
|
retry: (fn, options) => retryWithBackoff(fn, { ...options, signal, wait: sleep2 })
|
|
1325
1462
|
};
|
|
1326
1463
|
}
|
|
@@ -1411,22 +1548,28 @@ var RunReporter = class {
|
|
|
1411
1548
|
this.clearFlushTimer();
|
|
1412
1549
|
return this.takeLogs().slice(-MAX_LOGS_PER_PATCH);
|
|
1413
1550
|
}
|
|
1414
|
-
|
|
1551
|
+
/**
|
|
1552
|
+
* Linha de log da run com eco no terminal. `image` (opcional) vira o anexo da linha:
|
|
1553
|
+
* o id entra na entrada ANTES de qualquer I/O — é isso que mantém a ordem dos logs
|
|
1554
|
+
* intacta e o handler livre da latência do upload.
|
|
1555
|
+
*/
|
|
1556
|
+
log(level, message, image3) {
|
|
1415
1557
|
if (this.dead) return;
|
|
1416
1558
|
const scrubbed = scrubSecrets(safeString(message));
|
|
1417
|
-
|
|
1418
|
-
this.
|
|
1559
|
+
const ts = nowISO();
|
|
1560
|
+
const attachmentId = image3 === void 0 ? void 0 : this.queueAttachment(image3, ts);
|
|
1561
|
+
printRunLog(this.context.task, level, attachmentId ? `${scrubbed} [imagem]` : scrubbed);
|
|
1562
|
+
this.push(level, scrubbed, true, attachmentId ? [attachmentId] : void 0, ts);
|
|
1419
1563
|
}
|
|
1420
1564
|
/** Bufferiza uma entrada de log sem eco no terminal (cap, truncate, flush). */
|
|
1421
|
-
push(level, message, alreadyScrubbed = false, attachments) {
|
|
1422
|
-
const ts = nowISO();
|
|
1565
|
+
push(level, message, alreadyScrubbed = false, attachments, ts = nowISO()) {
|
|
1423
1566
|
if (this.dead) return ts;
|
|
1424
1567
|
const scrubbed = alreadyScrubbed ? message : scrubSecrets(message);
|
|
1425
1568
|
this.buffer.push({
|
|
1426
1569
|
ts,
|
|
1427
1570
|
level,
|
|
1428
1571
|
message: truncate(scrubbed, MAX_LOG_MESSAGE_CHARS),
|
|
1429
|
-
...attachments && attachments.length > 0 ? { attachments } : {}
|
|
1572
|
+
...attachments && attachments.length > 0 ? { attachments: attachments.slice(0, WIRE_LIMITS.MAX_ATTACHMENTS_PER_LOG_ENTRY) } : {}
|
|
1430
1573
|
});
|
|
1431
1574
|
if (this.buffer.length >= FLUSH_AT_BUFFERED) {
|
|
1432
1575
|
this.flushLogs();
|
|
@@ -1569,7 +1712,7 @@ var RunReporter = class {
|
|
|
1569
1712
|
* de status, o servidor aceita itens mesmo com a run cancelada (trabalho já feito),
|
|
1570
1713
|
* então um reporter morto não descarta: só um kill() de exit path descarta.
|
|
1571
1714
|
*/
|
|
1572
|
-
addItem(status, message, payload, id) {
|
|
1715
|
+
addItem(status, message, payload, id, image3) {
|
|
1573
1716
|
if (this.itemsClosed || this.itemsUnsupported) return;
|
|
1574
1717
|
if (this.itemCount >= MAX_ITEMS_PER_RUN) {
|
|
1575
1718
|
if (!this.itemsQuotaExceeded) {
|
|
@@ -1594,13 +1737,16 @@ var RunReporter = class {
|
|
|
1594
1737
|
scrubbedPayload = void 0;
|
|
1595
1738
|
}
|
|
1596
1739
|
}
|
|
1740
|
+
const ts = nowISO();
|
|
1741
|
+
const attachmentId = image3 === void 0 ? void 0 : this.queueAttachment(image3, ts);
|
|
1597
1742
|
this.itemsBuffer.push({
|
|
1598
1743
|
id: id ? truncate(String(id), 255) : uuid4(),
|
|
1599
1744
|
seq: this.itemSeq++,
|
|
1600
1745
|
status,
|
|
1601
1746
|
...message ? { message: truncate(scrubSecrets(safeString(message)), MAX_ITEM_MESSAGE_CHARS) } : {},
|
|
1602
1747
|
...scrubbedPayload ? { payload: scrubbedPayload } : {},
|
|
1603
|
-
ts
|
|
1748
|
+
ts,
|
|
1749
|
+
...attachmentId ? { attachments: [attachmentId] } : {}
|
|
1604
1750
|
});
|
|
1605
1751
|
if (this.itemsBuffer.length >= ITEMS_FLUSH_AT_BUFFERED) {
|
|
1606
1752
|
this.flushItems();
|
|
@@ -1680,59 +1826,51 @@ var RunReporter = class {
|
|
|
1680
1826
|
}
|
|
1681
1827
|
// ── Anexos ───────────────────────────────────────────────────────────────────
|
|
1682
1828
|
/**
|
|
1683
|
-
*
|
|
1684
|
-
*
|
|
1685
|
-
*
|
|
1686
|
-
*
|
|
1829
|
+
* Pendura uma imagem num evento da run (log, item ou step): faz as checagens que não
|
|
1830
|
+
* dependem de I/O (reporter morto, instalação sem anexos, cota), reserva o id e dispara
|
|
1831
|
+
* o upload em segundo plano. Devolve o id — já referenciável pelo evento — ou undefined
|
|
1832
|
+
* quando a imagem foi descartada (sempre com aviso no log da run). Nunca lança: todo
|
|
1833
|
+
* caminho de erro do upload vira aviso. O hint `attachment` de `hobots.captureException`
|
|
1834
|
+
* também cai aqui via `log()`.
|
|
1687
1835
|
*/
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
const rawMessage = options.message !== void 0 ? safeString(options.message) : void 0;
|
|
1693
|
-
const caption = rawCaption ? truncate(scrubSecrets(rawCaption), MAX_CAPTION_CHARS) : void 0;
|
|
1694
|
-
const message = rawMessage ?? rawCaption ?? "captura de tela";
|
|
1695
|
-
if (this.dead) return { id, ok: false, reason: "canceled" };
|
|
1696
|
-
if (this.attachmentsUnsupported) {
|
|
1697
|
-
this.log(level, message);
|
|
1698
|
-
return { id, ok: false, reason: "unsupported" };
|
|
1699
|
-
}
|
|
1836
|
+
queueAttachment(imageIn, ts) {
|
|
1837
|
+
if (this.dead) return void 0;
|
|
1838
|
+
const image3 = toImageAttachment(imageIn);
|
|
1839
|
+
if (this.attachmentsUnsupported) return void 0;
|
|
1700
1840
|
if (this.attachmentCount >= MAX_ATTACHMENTS_PER_RUN) {
|
|
1701
|
-
this.
|
|
1702
|
-
|
|
1703
|
-
|
|
1841
|
+
if (this.attachmentCount === MAX_ATTACHMENTS_PER_RUN) {
|
|
1842
|
+
this.attachmentCount++;
|
|
1843
|
+
this.log("warning", `imagem descartada: limite de ${MAX_ATTACHMENTS_PER_RUN} por execu\xE7\xE3o atingido`);
|
|
1844
|
+
}
|
|
1845
|
+
return void 0;
|
|
1704
1846
|
}
|
|
1705
1847
|
this.attachmentCount++;
|
|
1706
|
-
const
|
|
1707
|
-
|
|
1708
|
-
const
|
|
1709
|
-
|
|
1710
|
-
const result = new Promise((resolve2) => {
|
|
1711
|
-
settle = resolve2;
|
|
1712
|
-
});
|
|
1713
|
-
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" }));
|
|
1848
|
+
const id = uuid4();
|
|
1849
|
+
const rawCaption = image3.caption !== void 0 ? safeString(image3.caption) : void 0;
|
|
1850
|
+
const caption = rawCaption ? truncate(scrubSecrets(rawCaption), MAX_CAPTION_CHARS) : void 0;
|
|
1851
|
+
const work = this.uploadAttachment(id, image3.input, { caption, logTs: ts, contentType: image3.contentType }).then(() => void 0).catch(() => void 0);
|
|
1714
1852
|
this.pendingAttachments.add(work);
|
|
1715
1853
|
void work.finally(() => this.pendingAttachments.delete(work));
|
|
1716
|
-
return
|
|
1854
|
+
return id;
|
|
1717
1855
|
}
|
|
1718
1856
|
/** Retorna o motivo da falha, ou undefined em sucesso. */
|
|
1719
|
-
async uploadAttachment(id,
|
|
1857
|
+
async uploadAttachment(id, image3, meta) {
|
|
1720
1858
|
let bytes;
|
|
1721
1859
|
try {
|
|
1722
|
-
bytes = await toBytes(
|
|
1860
|
+
bytes = await toBytes(image3);
|
|
1723
1861
|
} catch (error) {
|
|
1724
|
-
this.log("warning", `
|
|
1862
|
+
this.log("warning", `imagem n\xE3o p\xF4de ser lida: ${String(error)}`);
|
|
1725
1863
|
return "read-failed";
|
|
1726
1864
|
}
|
|
1727
1865
|
const contentType = sniffContentType(bytes) ?? meta.contentType;
|
|
1728
1866
|
if (!contentType) {
|
|
1729
|
-
this.log("warning", "
|
|
1867
|
+
this.log("warning", "imagem descartada: formato n\xE3o reconhecido (aceitos: PNG, JPEG, WEBP)");
|
|
1730
1868
|
return "unsupported-format";
|
|
1731
1869
|
}
|
|
1732
1870
|
if (bytes.byteLength > MAX_ATTACHMENT_BYTES) {
|
|
1733
1871
|
this.log(
|
|
1734
1872
|
"warning",
|
|
1735
|
-
`
|
|
1873
|
+
`imagem descartada: ${Math.round(bytes.byteLength / 1024)} KB excede o limite de ${MAX_ATTACHMENT_BYTES / 1024 / 1024} MB`
|
|
1736
1874
|
);
|
|
1737
1875
|
return "too-large";
|
|
1738
1876
|
}
|
|
@@ -1763,11 +1901,11 @@ var RunReporter = class {
|
|
|
1763
1901
|
return "unsupported";
|
|
1764
1902
|
}
|
|
1765
1903
|
if (error instanceof TasksApiError && error.status === 429) {
|
|
1766
|
-
this.log("warning", "
|
|
1904
|
+
this.log("warning", "imagem descartada: limite de anexos por execu\xE7\xE3o atingido no servidor");
|
|
1767
1905
|
return "quota";
|
|
1768
1906
|
}
|
|
1769
1907
|
if (this.abortController.signal.aborted) return "canceled";
|
|
1770
|
-
this.log("warning", `falha ao enviar
|
|
1908
|
+
this.log("warning", `falha ao enviar a imagem: ${String(error)}`);
|
|
1771
1909
|
void this.api.confirmAttachment(this.runId, id, { status: "failed" }).catch(() => {
|
|
1772
1910
|
});
|
|
1773
1911
|
return "upload-failed";
|
|
@@ -1931,23 +2069,39 @@ var Step = class {
|
|
|
1931
2069
|
/**
|
|
1932
2070
|
* Desfecho da step. `message` (opcional) é o motivo legível — vai em `data.message`
|
|
1933
2071
|
* e aparece na Central (performance e banner da execução) e no log de FINISH.
|
|
2072
|
+
* `options.image` pendura um print do estado da tela em `data.attachments`.
|
|
1934
2073
|
*/
|
|
1935
|
-
setStatus(status, message) {
|
|
2074
|
+
setStatus(status, message, options) {
|
|
1936
2075
|
this.status = status;
|
|
1937
2076
|
if (message) this.setData("message", stepMessage(message));
|
|
2077
|
+
if (options?.image !== void 0) this.attachImage(options.image);
|
|
1938
2078
|
return this;
|
|
1939
2079
|
}
|
|
1940
2080
|
/**
|
|
1941
2081
|
* Marca a step como `error` guardando o motivo em `data.error` ({ type, message }).
|
|
1942
2082
|
* Aceita qualquer valor lançado; `message` sobrescreve a mensagem do erro.
|
|
2083
|
+
* `options.image` pendura um print do estado da tela em `data.attachments`.
|
|
1943
2084
|
*/
|
|
1944
|
-
setError(error, message) {
|
|
2085
|
+
setError(error, message, options) {
|
|
1945
2086
|
this.status = "error";
|
|
1946
2087
|
const type = error instanceof Error ? error.name : typeof error === "object" && error !== null ? "Error" : void 0;
|
|
1947
2088
|
const raw = message ?? (error instanceof Error ? error.message || error.name : String(error));
|
|
1948
2089
|
this.setData("error", { ...type ? { type } : {}, message: stepMessage(raw) });
|
|
2090
|
+
if (options?.image !== void 0) this.attachImage(options.image);
|
|
1949
2091
|
return this;
|
|
1950
2092
|
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Dispara o upload pela run (sink do RunReporter) e referencia o anexo em
|
|
2095
|
+
* `data.attachments` (chave reservada; teto igual ao das linhas de log). Fora de uma
|
|
2096
|
+
* run não há onde pendurar a imagem — descarta com aviso único.
|
|
2097
|
+
*/
|
|
2098
|
+
attachImage(image3) {
|
|
2099
|
+
const current = Array.isArray(this.data?.attachments) ? this.data.attachments : [];
|
|
2100
|
+
if (current.length >= MAX_ATTACHMENTS_PER_LOG_ENTRY) return;
|
|
2101
|
+
const id = this.transaction.attachImage(image3);
|
|
2102
|
+
if (!id) return;
|
|
2103
|
+
this.setData("attachments", [...current, id]);
|
|
2104
|
+
}
|
|
1951
2105
|
/** Motivo registrado via setStatus(…, message) ou setError — usado no log de FINISH. */
|
|
1952
2106
|
reason() {
|
|
1953
2107
|
const error = this.data?.error;
|
|
@@ -2008,6 +2162,8 @@ var Transaction = class {
|
|
|
2008
2162
|
tags = {};
|
|
2009
2163
|
finished = false;
|
|
2010
2164
|
lifecycleSink;
|
|
2165
|
+
attachmentSink;
|
|
2166
|
+
warnedNoAttachmentSink = false;
|
|
2011
2167
|
// instalado pelo RunReporter: abrir uma step é um ponto de parada cooperativo (lança RunCanceled)
|
|
2012
2168
|
stepGuard;
|
|
2013
2169
|
// eventos emitidos antes do sink existir (o START da transaction sai no construtor,
|
|
@@ -2038,6 +2194,19 @@ var Transaction = class {
|
|
|
2038
2194
|
this.lifecycleBacklog = [];
|
|
2039
2195
|
for (const [level, message] of backlog) sink(level, message);
|
|
2040
2196
|
}
|
|
2197
|
+
/** Conecta o pipeline de anexos da run — é o que dá imagem às steps. */
|
|
2198
|
+
setAttachmentSink(sink) {
|
|
2199
|
+
this.attachmentSink = sink;
|
|
2200
|
+
}
|
|
2201
|
+
/** Imagem de uma step → id do anexo pela run; sem run, descarta com aviso único. */
|
|
2202
|
+
attachImage(image3) {
|
|
2203
|
+
if (this.attachmentSink) return this.attachmentSink(image3, nowISO());
|
|
2204
|
+
if (!this.warnedNoAttachmentSink) {
|
|
2205
|
+
this.warnedNoAttachmentSink = true;
|
|
2206
|
+
console.warn("[hobots] imagem de step descartada \u2014 s\xF3 \xE9 suportada dentro de uma execu\xE7\xE3o de task");
|
|
2207
|
+
}
|
|
2208
|
+
return void 0;
|
|
2209
|
+
}
|
|
2041
2210
|
/**
|
|
2042
2211
|
* Conecta a checagem de cancelamento chamada antes de cada step nova — é assim que
|
|
2043
2212
|
* `hobots.transaction.startChild()` (e `step.startChild()`) param uma run cancelada.
|
|
@@ -2127,6 +2296,7 @@ async function executeRun(input) {
|
|
|
2127
2296
|
await runWithRunContext({ reporter }, () => invokeWithRetry(task, run, reporter, logger));
|
|
2128
2297
|
await reporter.finalizeAttachments();
|
|
2129
2298
|
await reporter.finalizeItems();
|
|
2299
|
+
warnIncompleteProgress(reporter);
|
|
2130
2300
|
tx.setStatus("ok");
|
|
2131
2301
|
tx.finish();
|
|
2132
2302
|
reporter.reportSuccess();
|
|
@@ -2144,6 +2314,13 @@ async function executeRun(input) {
|
|
|
2144
2314
|
tracker.remove(reporter);
|
|
2145
2315
|
}
|
|
2146
2316
|
}
|
|
2317
|
+
function warnIncompleteProgress(reporter) {
|
|
2318
|
+
const snapshot = reporter.context.progress.snapshot;
|
|
2319
|
+
if (!snapshot || snapshot.current >= snapshot.total) return;
|
|
2320
|
+
reporter.context.log.warn(
|
|
2321
|
+
`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`
|
|
2322
|
+
);
|
|
2323
|
+
}
|
|
2147
2324
|
function invokeWithRetry(task, run, reporter, logger) {
|
|
2148
2325
|
const { retries, retryDelayMs } = task.options;
|
|
2149
2326
|
const total = retries + 1;
|
|
@@ -2198,8 +2375,8 @@ function waitForCancelGrace(signal, graceMs) {
|
|
|
2198
2375
|
signal.addEventListener("abort", () => setTimeout(resolve2, graceMs), { once: true });
|
|
2199
2376
|
});
|
|
2200
2377
|
}
|
|
2201
|
-
var MAX_ERROR_MESSAGE_CHARS =
|
|
2202
|
-
var MAX_ERROR_STACK_CHARS =
|
|
2378
|
+
var MAX_ERROR_MESSAGE_CHARS = WIRE_LIMITS.MAX_ERROR_MESSAGE_CHARS;
|
|
2379
|
+
var MAX_ERROR_STACK_CHARS = WIRE_LIMITS.MAX_ERROR_STACK_CHARS;
|
|
2203
2380
|
function toRunError(error) {
|
|
2204
2381
|
if (error instanceof Error) {
|
|
2205
2382
|
return {
|
|
@@ -2214,7 +2391,7 @@ function toRunError(error) {
|
|
|
2214
2391
|
// src/tasks/agent.ts
|
|
2215
2392
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
2216
2393
|
var MIN_POLL_INTERVAL_MS = 1e3;
|
|
2217
|
-
var MAX_CLAIM_PER_POLL =
|
|
2394
|
+
var MAX_CLAIM_PER_POLL = WIRE_LIMITS.MAX_CLAIM_PER_POLL;
|
|
2218
2395
|
var TaskAgent = class {
|
|
2219
2396
|
constructor(options) {
|
|
2220
2397
|
this.options = options;
|
|
@@ -2349,8 +2526,8 @@ var TaskAgent = class {
|
|
|
2349
2526
|
|
|
2350
2527
|
// src/tasks/item-columns.ts
|
|
2351
2528
|
var KEY_RE = /^[a-zA-Z0-9_.-]{1,100}$/;
|
|
2352
|
-
var MAX_COLUMNS =
|
|
2353
|
-
var MAX_LABEL_CHARS =
|
|
2529
|
+
var MAX_COLUMNS = WIRE_LIMITS.MAX_ITEM_COLUMNS;
|
|
2530
|
+
var MAX_LABEL_CHARS = WIRE_LIMITS.MAX_ITEM_COLUMN_LABEL_CHARS;
|
|
2354
2531
|
function normalizeItemColumns(slug, input, logger) {
|
|
2355
2532
|
if (input === void 0 || input === null) return void 0;
|
|
2356
2533
|
const columns = input.columns;
|
|
@@ -2797,13 +2974,8 @@ function forwardAttachment(rt, attachment, message, type) {
|
|
|
2797
2974
|
rt.logger.warn("attachment descartado \u2014 s\xF3 \xE9 suportado dentro de uma execu\xE7\xE3o de task");
|
|
2798
2975
|
return;
|
|
2799
2976
|
}
|
|
2800
|
-
const withMeta = typeof attachment === "object" && "image" in attachment ? attachment :
|
|
2801
|
-
|
|
2802
|
-
message,
|
|
2803
|
-
level: toRunLogLevel(type),
|
|
2804
|
-
caption: withMeta.caption,
|
|
2805
|
-
contentType: withMeta.contentType
|
|
2806
|
-
});
|
|
2977
|
+
const withMeta = typeof attachment === "object" && !isImageAttachment(attachment) && "image" in attachment ? image(attachment.image, { caption: attachment.caption, contentType: attachment.contentType }) : attachment;
|
|
2978
|
+
reporter.log(toRunLogLevel(type), message, withMeta);
|
|
2807
2979
|
}
|
|
2808
2980
|
function captureException(error, hint) {
|
|
2809
2981
|
const rt = runtime;
|
|
@@ -2850,15 +3022,34 @@ function warnOutsideRun(member) {
|
|
|
2850
3022
|
else console.warn(`[hobots] ${message}`);
|
|
2851
3023
|
}
|
|
2852
3024
|
var FALLBACK_TASK = "hobots";
|
|
3025
|
+
var fallbackLogAt = (level) => (message, ...rest) => {
|
|
3026
|
+
const { text, image: dropped } = splitLogArgs(message, rest);
|
|
3027
|
+
printRunLog(FALLBACK_TASK, level, dropped ? `${text} [imagem descartada]` : text);
|
|
3028
|
+
};
|
|
2853
3029
|
var fallbackLog = {
|
|
2854
|
-
debug: (
|
|
2855
|
-
info: (
|
|
2856
|
-
warn: (
|
|
2857
|
-
error: (
|
|
2858
|
-
success: (
|
|
3030
|
+
debug: fallbackLogAt("debug"),
|
|
3031
|
+
info: fallbackLogAt("info"),
|
|
3032
|
+
warn: fallbackLogAt("warning"),
|
|
3033
|
+
error: fallbackLogAt("error"),
|
|
3034
|
+
success: fallbackLogAt("success")
|
|
2859
3035
|
};
|
|
2860
3036
|
var noop = () => void 0;
|
|
2861
|
-
var
|
|
3037
|
+
var fallbackEachSink = {
|
|
3038
|
+
report: noop,
|
|
3039
|
+
startStep: () => void 0,
|
|
3040
|
+
declareTotal: noop,
|
|
3041
|
+
advance: noop,
|
|
3042
|
+
checkCanceled: noop,
|
|
3043
|
+
isAborted: () => false,
|
|
3044
|
+
logError: (message) => printRunLog(FALLBACK_TASK, "error", message)
|
|
3045
|
+
};
|
|
3046
|
+
var fallbackItems = {
|
|
3047
|
+
add: noop,
|
|
3048
|
+
succeeded: noop,
|
|
3049
|
+
failed: noop,
|
|
3050
|
+
occurrence: noop,
|
|
3051
|
+
each: (list, handler, options = {}) => eachItem(list, handler, options, fallbackEachSink)
|
|
3052
|
+
};
|
|
2862
3053
|
var fallbackProgress = { total: noop, advance: noop, set: noop, current: 0, snapshot: null };
|
|
2863
3054
|
var neverAborts = new AbortController().signal;
|
|
2864
3055
|
var detachedTransaction;
|
|
@@ -2886,9 +3077,6 @@ var hobots = Object.defineProperties({}, {
|
|
|
2886
3077
|
signal: getter("signal", () => neverAborts),
|
|
2887
3078
|
throwIfCanceled: method(() => resolve("throwIfCanceled")?.throwIfCanceled()),
|
|
2888
3079
|
sleep: method((ms) => resolve("sleep")?.sleep(ms) ?? sleep(ms)),
|
|
2889
|
-
attach: method(
|
|
2890
|
-
(image, options) => resolve("attach")?.attach(image, options) ?? Promise.resolve({ id: "", ok: false, reason: "canceled" })
|
|
2891
|
-
),
|
|
2892
3080
|
retry: method((fn, options) => {
|
|
2893
3081
|
const reporter = currentReporter();
|
|
2894
3082
|
return reporter ? reporter.context.retry(fn, options) : retryWithBackoff(fn, options);
|
|
@@ -2903,7 +3091,8 @@ var hobots = Object.defineProperties({}, {
|
|
|
2903
3091
|
installGlobalHobots();
|
|
2904
3092
|
}),
|
|
2905
3093
|
close: method((timeoutMs) => close(timeoutMs)),
|
|
2906
|
-
captureException: method((error, hint) => captureException(error, hint))
|
|
3094
|
+
captureException: method((error, hint) => captureException(error, hint)),
|
|
3095
|
+
image: method(image)
|
|
2907
3096
|
});
|
|
2908
3097
|
function installGlobalHobots() {
|
|
2909
3098
|
if (globalThis.hobots === hobots) return;
|
|
@@ -2914,6 +3103,7 @@ var start2 = hobots.start;
|
|
|
2914
3103
|
var close2 = hobots.close;
|
|
2915
3104
|
var captureException2 = hobots.captureException;
|
|
2916
3105
|
var retry = hobots.retry;
|
|
3106
|
+
var image2 = hobots.image;
|
|
2917
3107
|
|
|
2918
3108
|
// src/index.ts
|
|
2919
3109
|
var src_default = hobots;
|
|
@@ -2922,6 +3112,7 @@ export {
|
|
|
2922
3112
|
close2 as close,
|
|
2923
3113
|
src_default as default,
|
|
2924
3114
|
hobots,
|
|
3115
|
+
image2 as image,
|
|
2925
3116
|
register2 as register,
|
|
2926
3117
|
retry,
|
|
2927
3118
|
start2 as start
|