hobots 2.0.0 → 2.2.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 +22 -3
- package/dist/index.cjs +109 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -8
- package/dist/index.d.ts +28 -8
- package/dist/index.js +109 -29
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +24 -4
- package/dist/protocol.d.ts +24 -4
- package/docs/api-reference.md +17 -7
- package/docs/concepts.md +13 -11
- package/docs/protocol.md +3 -1
- package/docs/tasks.md +39 -1
- package/docs/telemetry.md +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,7 +113,7 @@ try {
|
|
|
113
113
|
await processarNota(nota);
|
|
114
114
|
} catch (error) {
|
|
115
115
|
Hobots.captureException(error, {
|
|
116
|
-
|
|
116
|
+
type: 'error',
|
|
117
117
|
tags: { cliente: 'acme' },
|
|
118
118
|
fingerprint: ['sefaz-timeout'], // agrupa manualmente; sem isso o servidor agrupa pelo stack
|
|
119
119
|
});
|
|
@@ -123,9 +123,9 @@ try {
|
|
|
123
123
|
Hobots.captureMessage('Lote processado com sucesso', 'success');
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
Ambas retornam o `event_id` (ou `undefined` se não inicializado). O hint aceita `
|
|
126
|
+
Ambas retornam o `event_id` (ou `undefined` se não inicializado). O hint aceita `type`, `tags`, `extra` e `fingerprint`. Erros **não tratados** são capturados e flushados automaticamente antes do processo sair — desligue com `captureUnhandled: false`. Os eventos aparecem agrupados em issues no módulo **Issues** do app.
|
|
127
127
|
|
|
128
|
-
`
|
|
128
|
+
`EventType = 'fatal' | 'error' | 'warning' | 'success'`. Não há `'info'`/`'debug'`: narração não abre issue — para isso existem o log da execução e as breadcrumbs. Use `'success'` para reportar itens concluídos com êxito — contam como eventos, mas **não** viram issue nem disparam alertas.
|
|
129
129
|
|
|
130
130
|
### Breadcrumbs
|
|
131
131
|
|
|
@@ -261,6 +261,7 @@ interface RunContext {
|
|
|
261
261
|
task: string;
|
|
262
262
|
log: RunLogger; // ctx.log.debug/info/warn/error/success(message)
|
|
263
263
|
items: RunItems; // ctx.items.succeeded/failed/occurrence — a entrega do bot
|
|
264
|
+
progress: RunProgressReporter; // ctx.progress.total/advance/set — barra + tempo restante no app
|
|
264
265
|
tx: Transaction; // transaction desta run — correlacionada e finalizada pelo SDK
|
|
265
266
|
signal: AbortSignal;
|
|
266
267
|
throwIfCanceled(): void; // lança RunCanceled se o signal já disparou
|
|
@@ -271,6 +272,7 @@ interface RunContext {
|
|
|
271
272
|
- **`params`** — os dados do formulário configurado no app (JSON validado). Tipável: `Hobots.register<{ lote: number }>(...)`.
|
|
272
273
|
- **`ctx.log.<level>(message)`** — níveis `debug`, `info`, `warn`, `error` e `success`; logs enviados **incrementalmente** ao app (PATCHes com throttle), visíveis na solicitação quase em tempo real; também impressos no terminal local, coloridos por nível.
|
|
273
274
|
- **`ctx.items`** — registra os **itens que a execução processou/gerou** (a entrega do bot: notas fiscais baixadas, boletos emitidos…), cada um com status `succeeded`, `failed` (falha técnica) ou `occurrence` (ocorrência de negócio, ex.: "nota nº 10 não encontrada") e um `payload` de atributos livres. Aparecem na aba **itens** da solicitação, com totalizadores; as colunas exibidas são configuradas por formulário no app. Guia: [Itens de execução](./docs/tasks.md#itens-de-execução-ctxitems).
|
|
275
|
+
- **`ctx.progress`** — **opcional**: declare quantos itens a run vai processar (`ctx.progress.total(n)`) e avance a cada item (`ctx.progress.advance()`); o app mostra barra, percentual e tempo restante estimado na solicitação. Independente de `ctx.items`. Guia: [Progresso](./docs/tasks.md#progresso-da-execução-ctxprogress).
|
|
274
276
|
- **`ctx.tx`** — a transaction de performance desta run, já correlacionada e finalizada pelo SDK. Use `ctx.tx.startChild(op, description)` para medir as etapas — elas viram o waterfall da execução no app. `startTransaction()` chamado dentro do handler retorna essa mesma transaction. Conceito: [ctx.tx](./docs/concepts.md#transaction-de-run-ctxtx).
|
|
275
277
|
- **`ctx.signal`** — `AbortSignal` que dispara quando a run é **cancelada no app**, em **timeout** ou no **shutdown**.
|
|
276
278
|
- **`ctx.throwIfCanceled()`** — o ponto de parada de uma linha; lança `RunCanceled` se o `signal` já disparou.
|
|
@@ -299,6 +301,23 @@ Hobots.register('baixar-notas', async (params, ctx) => {
|
|
|
299
301
|
|
|
300
302
|
Chamadas síncronas e bufferizadas (lotes de até 500; dreno antes do reporte final). O `id` opcional é a identidade de negócio do item na run — repetido, é ignorado pelo servidor (registro único, retry idempotente). Limites: 10.000 itens/run, payload 16 KB, mensagem 2.000 caracteres. Detalhes em [Itens de execução](./docs/tasks.md#itens-de-execução-ctxitems).
|
|
301
303
|
|
|
304
|
+
### Progresso (`ctx.progress`)
|
|
305
|
+
|
|
306
|
+
Quando a run percorre uma lista conhecida, declare o total e avance a cada item — a solicitação no app ganha barra de progresso, percentual (`10/100 · 10%`) e **tempo restante estimado**:
|
|
307
|
+
|
|
308
|
+
```js
|
|
309
|
+
Hobots.register('baixar-notas', async (params, ctx) => {
|
|
310
|
+
const notas = await listarNotas(params);
|
|
311
|
+
ctx.progress.total(notas.length);
|
|
312
|
+
for (const nota of notas) {
|
|
313
|
+
await baixar(nota);
|
|
314
|
+
ctx.progress.advance();
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Opcional e independente de `ctx.items` (use um, outro ou ambos). Sem `total()` nada é enviado. Chamadas síncronas e baratas: o snapshot pega carona nos PATCHes de log e, no pior caso, sai 1 vez por segundo; o PATCH terminal sempre leva o valor final. `ctx.progress.set(current, total?)` define um valor absoluto; `ctx.progress.current` e `ctx.progress.snapshot` leem o estado. Detalhes em [Progresso da execução](./docs/tasks.md#progresso-da-execução-ctxprogress).
|
|
320
|
+
|
|
302
321
|
### Anexos (screenshots)
|
|
303
322
|
|
|
304
323
|
Texto de log conta o que o robô fez; um print conta **como estava a tela**. Os métodos de captura (`Hobots.captureException` e `Hobots.captureMessage`) aceitam um `attachment` no hint: dentro de uma execução de task, a imagem vira anexo da linha de log da run que espelha a captura — no app ela aparece como miniatura logo abaixo dessa linha, clicável para ampliar.
|
package/dist/index.cjs
CHANGED
|
@@ -161,7 +161,7 @@ function scrubSecrets(text) {
|
|
|
161
161
|
|
|
162
162
|
// src/utils.ts
|
|
163
163
|
var SDK_NAME = "hobots";
|
|
164
|
-
var SDK_VERSION = true ? "2.
|
|
164
|
+
var SDK_VERSION = true ? "2.2.0" : "0.0.0-dev";
|
|
165
165
|
function isNode() {
|
|
166
166
|
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
167
167
|
}
|
|
@@ -291,34 +291,34 @@ function safeString(value) {
|
|
|
291
291
|
}
|
|
292
292
|
return String(value);
|
|
293
293
|
}
|
|
294
|
-
function eventFromException(error,
|
|
295
|
-
let
|
|
294
|
+
function eventFromException(error, type = "error") {
|
|
295
|
+
let exceptionType;
|
|
296
296
|
let value;
|
|
297
297
|
let frames = [];
|
|
298
298
|
if (error instanceof Error) {
|
|
299
|
-
|
|
299
|
+
exceptionType = error.name || "Error";
|
|
300
300
|
value = scrubSecrets(error.message);
|
|
301
301
|
frames = parseStacktrace(error.stack);
|
|
302
302
|
} else {
|
|
303
|
-
|
|
303
|
+
exceptionType = "NonError";
|
|
304
304
|
value = scrubSecrets(safeString(error));
|
|
305
305
|
}
|
|
306
306
|
return {
|
|
307
307
|
event_id: uuid4(),
|
|
308
308
|
timestamp: nowISO(),
|
|
309
|
-
|
|
309
|
+
type,
|
|
310
310
|
exception: {
|
|
311
|
-
type,
|
|
311
|
+
type: exceptionType,
|
|
312
312
|
value,
|
|
313
313
|
...frames.length > 0 ? { stacktrace: { frames } } : {}
|
|
314
314
|
}
|
|
315
315
|
};
|
|
316
316
|
}
|
|
317
|
-
function eventFromMessage(message,
|
|
317
|
+
function eventFromMessage(message, type = "warning") {
|
|
318
318
|
return {
|
|
319
319
|
event_id: uuid4(),
|
|
320
320
|
timestamp: nowISO(),
|
|
321
|
-
|
|
321
|
+
type,
|
|
322
322
|
message: scrubSecrets(message)
|
|
323
323
|
};
|
|
324
324
|
}
|
|
@@ -481,10 +481,10 @@ var Client = class {
|
|
|
481
481
|
return `Client { baseUrl: '${this.#config.baseUrl}' }`;
|
|
482
482
|
}
|
|
483
483
|
captureException(error, hint, scope2) {
|
|
484
|
-
return this.captureEvent(eventFromException(error, hint?.
|
|
484
|
+
return this.captureEvent(eventFromException(error, hint?.type ?? "error"), hint, scope2);
|
|
485
485
|
}
|
|
486
|
-
captureMessage(message,
|
|
487
|
-
return this.captureEvent(eventFromMessage(message,
|
|
486
|
+
captureMessage(message, type, hint, scope2) {
|
|
487
|
+
return this.captureEvent(eventFromMessage(message, type), hint, scope2);
|
|
488
488
|
}
|
|
489
489
|
captureEvent(event, hint, scope2) {
|
|
490
490
|
const sampleRate = this.options.sampleRate ?? 1;
|
|
@@ -506,7 +506,7 @@ var Client = class {
|
|
|
506
506
|
const extra = { ...scope2.extra, ...event.extra, ...hint?.extra };
|
|
507
507
|
return {
|
|
508
508
|
...event,
|
|
509
|
-
|
|
509
|
+
type: hint?.type ?? event.type ?? scope2.type ?? "error",
|
|
510
510
|
release: event.release ?? this.options.release,
|
|
511
511
|
environment: event.environment ?? this.options.environment ?? "production",
|
|
512
512
|
tags: Object.keys(tags).length > 0 ? tags : void 0,
|
|
@@ -624,7 +624,7 @@ function installGlobalHandlers(client2, getScope) {
|
|
|
624
624
|
process.on(
|
|
625
625
|
"uncaughtException",
|
|
626
626
|
markInternal((error) => {
|
|
627
|
-
client2.captureException(error, {
|
|
627
|
+
client2.captureException(error, { type: "fatal", tags: { mechanism: "uncaughtException" } }, getScope());
|
|
628
628
|
void client2.flush(2e3).then(async () => {
|
|
629
629
|
if (externalListenerCount("uncaughtException") === 0) {
|
|
630
630
|
await awaitEmergencyTasks(EMERGENCY_REPORT_CAP_MS);
|
|
@@ -637,7 +637,7 @@ function installGlobalHandlers(client2, getScope) {
|
|
|
637
637
|
process.on(
|
|
638
638
|
"unhandledRejection",
|
|
639
639
|
markInternal((reason) => {
|
|
640
|
-
client2.captureException(reason, {
|
|
640
|
+
client2.captureException(reason, { type: "error", tags: { mechanism: "unhandledRejection" } }, getScope());
|
|
641
641
|
void client2.flush(2e3);
|
|
642
642
|
})
|
|
643
643
|
);
|
|
@@ -668,7 +668,7 @@ var Scope = class _Scope {
|
|
|
668
668
|
user;
|
|
669
669
|
contexts = {};
|
|
670
670
|
extra = {};
|
|
671
|
-
|
|
671
|
+
type;
|
|
672
672
|
fingerprint;
|
|
673
673
|
breadcrumbs = [];
|
|
674
674
|
setTag(key, value) {
|
|
@@ -699,8 +699,8 @@ var Scope = class _Scope {
|
|
|
699
699
|
Object.assign(this.extra, extras);
|
|
700
700
|
return this;
|
|
701
701
|
}
|
|
702
|
-
|
|
703
|
-
this.
|
|
702
|
+
setType(type) {
|
|
703
|
+
this.type = type;
|
|
704
704
|
return this;
|
|
705
705
|
}
|
|
706
706
|
setFingerprint(fingerprint) {
|
|
@@ -724,7 +724,7 @@ var Scope = class _Scope {
|
|
|
724
724
|
next.user = this.user ? { ...this.user } : void 0;
|
|
725
725
|
next.contexts = Object.fromEntries(Object.entries(this.contexts).map(([k, v]) => [k, { ...v }]));
|
|
726
726
|
next.extra = { ...this.extra };
|
|
727
|
-
next.
|
|
727
|
+
next.type = this.type;
|
|
728
728
|
next.fingerprint = this.fingerprint ? [...this.fingerprint] : void 0;
|
|
729
729
|
next.breadcrumbs = [...this.breadcrumbs];
|
|
730
730
|
return next;
|
|
@@ -1201,6 +1201,7 @@ var MAX_ITEM_MESSAGE_CHARS = 2e3;
|
|
|
1201
1201
|
var MAX_ITEM_PAYLOAD_BYTES = 16384;
|
|
1202
1202
|
var ITEMS_FLUSH_AT_BUFFERED = 100;
|
|
1203
1203
|
var ITEMS_DRAIN_MS = 15e3;
|
|
1204
|
+
var PROGRESS_FLUSH_MS = 1e3;
|
|
1204
1205
|
function scrubPayloadValue(value, depth) {
|
|
1205
1206
|
if (typeof value === "string") return scrubSecrets(value);
|
|
1206
1207
|
if (depth >= 4 || value === null || typeof value !== "object") return value;
|
|
@@ -1235,12 +1236,28 @@ var RunReporter = class {
|
|
|
1235
1236
|
failed: (message, payload, options) => this.addItem("failed", message, payload, options?.id),
|
|
1236
1237
|
occurrence: (message, payload, options) => this.addItem("occurrence", message, payload, options?.id)
|
|
1237
1238
|
};
|
|
1239
|
+
const progress = Object.defineProperties(
|
|
1240
|
+
{
|
|
1241
|
+
total: (total) => this.setProgress(this.progressCurrent, total),
|
|
1242
|
+
advance: (count = 1) => this.setProgress(this.progressCurrent + count, this.progressTotal),
|
|
1243
|
+
set: (current, total) => this.setProgress(current, total ?? this.progressTotal)
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
current: { enumerable: true, get: () => this.progressCurrent },
|
|
1247
|
+
snapshot: {
|
|
1248
|
+
enumerable: true,
|
|
1249
|
+
get: () => this.progressTotal == null ? null : { current: this.progressCurrent, total: this.progressTotal }
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
// defineProperties não tipa os getters adicionados — a interface é a fonte de verdade
|
|
1253
|
+
);
|
|
1238
1254
|
const signal = this.abortController.signal;
|
|
1239
1255
|
this.context = {
|
|
1240
1256
|
runId,
|
|
1241
1257
|
task,
|
|
1242
1258
|
log,
|
|
1243
1259
|
items,
|
|
1260
|
+
progress,
|
|
1244
1261
|
tx,
|
|
1245
1262
|
signal,
|
|
1246
1263
|
throwIfCanceled: () => {
|
|
@@ -1284,6 +1301,14 @@ var RunReporter = class {
|
|
|
1284
1301
|
uploadQueue = [];
|
|
1285
1302
|
/** Uma vez que a instalação recusa anexos, para de tentar (e de avisar) nesta run. */
|
|
1286
1303
|
attachmentsUnsupported = false;
|
|
1304
|
+
// Progresso (ctx.progress): snapshot absoluto, enviado com throttle via piggyback
|
|
1305
|
+
// em `enqueue()` — nunca gera tráfego próprio enquanto logs/heartbeat já fluem.
|
|
1306
|
+
progressCurrent = 0;
|
|
1307
|
+
progressTotal = null;
|
|
1308
|
+
/** Snapshot ainda não entregue ao servidor. */
|
|
1309
|
+
progressDirty = false;
|
|
1310
|
+
progressTimer;
|
|
1311
|
+
progressWarned = false;
|
|
1287
1312
|
get isDead() {
|
|
1288
1313
|
return this.dead;
|
|
1289
1314
|
}
|
|
@@ -1301,6 +1326,7 @@ var RunReporter = class {
|
|
|
1301
1326
|
this.abort();
|
|
1302
1327
|
this.dead = true;
|
|
1303
1328
|
this.clearFlushTimer();
|
|
1329
|
+
this.clearProgressTimer();
|
|
1304
1330
|
this.buffer = [];
|
|
1305
1331
|
this.itemsClosed = true;
|
|
1306
1332
|
this.clearItemsTimer();
|
|
@@ -1380,13 +1406,63 @@ var RunReporter = class {
|
|
|
1380
1406
|
reportSuccess() {
|
|
1381
1407
|
this.stopCancelWatch();
|
|
1382
1408
|
this.clearFlushTimer();
|
|
1409
|
+
this.forceFinalProgress();
|
|
1383
1410
|
this.enqueue({ status: "succeeded", logs: this.takeLogs() });
|
|
1384
1411
|
}
|
|
1385
1412
|
reportFailure(error) {
|
|
1386
1413
|
this.stopCancelWatch();
|
|
1387
1414
|
this.clearFlushTimer();
|
|
1415
|
+
this.forceFinalProgress();
|
|
1388
1416
|
this.enqueue({ status: "failed", error, logs: this.takeLogs() });
|
|
1389
1417
|
}
|
|
1418
|
+
// ── Progresso ────────────────────────────────────────────────────────────────
|
|
1419
|
+
/** Valida, clampa e marca o snapshot como pendente; agenda flush só se nada mais vai sair. */
|
|
1420
|
+
setProgress(current, total) {
|
|
1421
|
+
if (this.dead) return;
|
|
1422
|
+
if (total != null && (!Number.isInteger(total) || total < 1)) {
|
|
1423
|
+
if (!this.progressWarned) {
|
|
1424
|
+
this.progressWarned = true;
|
|
1425
|
+
this.logger.warn(`ctx.progress: total inv\xE1lido (${String(total)}) \u2014 precisa ser inteiro >= 1; ignorado`);
|
|
1426
|
+
}
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
const safeCurrent = Number.isFinite(current) ? Math.max(0, Math.floor(current)) : this.progressCurrent;
|
|
1430
|
+
const next = total == null ? safeCurrent : Math.min(safeCurrent, total);
|
|
1431
|
+
if (next === this.progressCurrent && total === this.progressTotal) return;
|
|
1432
|
+
this.progressCurrent = next;
|
|
1433
|
+
this.progressTotal = total;
|
|
1434
|
+
if (total == null) return;
|
|
1435
|
+
this.progressDirty = true;
|
|
1436
|
+
if (this.progressTimer) return;
|
|
1437
|
+
this.progressTimer = setTimeout(() => {
|
|
1438
|
+
this.progressTimer = void 0;
|
|
1439
|
+
this.flushProgress();
|
|
1440
|
+
}, PROGRESS_FLUSH_MS);
|
|
1441
|
+
unrefTimer(this.progressTimer);
|
|
1442
|
+
}
|
|
1443
|
+
flushProgress() {
|
|
1444
|
+
this.clearProgressTimer();
|
|
1445
|
+
if (this.dead || !this.progressDirty) return;
|
|
1446
|
+
if (this.buffer.length > 0) this.flushLogs();
|
|
1447
|
+
else this.enqueue({ status: "running" });
|
|
1448
|
+
}
|
|
1449
|
+
clearProgressTimer() {
|
|
1450
|
+
if (this.progressTimer) {
|
|
1451
|
+
clearTimeout(this.progressTimer);
|
|
1452
|
+
this.progressTimer = void 0;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
/** O PATCH terminal sempre leva o snapshot final (o app mostra "87/100" numa run que falhou). */
|
|
1456
|
+
forceFinalProgress() {
|
|
1457
|
+
this.clearProgressTimer();
|
|
1458
|
+
this.progressDirty = this.progressTotal != null;
|
|
1459
|
+
}
|
|
1460
|
+
/** Consome o snapshot pendente para pegar carona no próximo PATCH. */
|
|
1461
|
+
takeProgress() {
|
|
1462
|
+
if (!this.progressDirty || this.progressTotal == null) return void 0;
|
|
1463
|
+
this.progressDirty = false;
|
|
1464
|
+
return { current: this.progressCurrent, total: this.progressTotal };
|
|
1465
|
+
}
|
|
1390
1466
|
/**
|
|
1391
1467
|
* Heartbeat de cancelamento: enquanto o handler roda, um PATCH 'running' vazio
|
|
1392
1468
|
* periódico faz o servidor responder 409 se a run foi cancelada no app — o que
|
|
@@ -1649,11 +1725,14 @@ var RunReporter = class {
|
|
|
1649
1725
|
new Promise((resolve) => unrefTimer(setTimeout(resolve, timeoutMs)))
|
|
1650
1726
|
]);
|
|
1651
1727
|
}
|
|
1652
|
-
enqueue(
|
|
1728
|
+
enqueue(updateIn) {
|
|
1653
1729
|
if (this.dead) {
|
|
1654
|
-
this.salvageLogs(
|
|
1730
|
+
this.salvageLogs(updateIn.logs);
|
|
1655
1731
|
return;
|
|
1656
1732
|
}
|
|
1733
|
+
this.clearProgressTimer();
|
|
1734
|
+
const progress = this.takeProgress();
|
|
1735
|
+
const update = progress ? { ...updateIn, progress } : updateIn;
|
|
1657
1736
|
this.pendingUpdates++;
|
|
1658
1737
|
this.chain = this.chain.then(async () => {
|
|
1659
1738
|
if (this.dead) {
|
|
@@ -1679,6 +1758,7 @@ var RunReporter = class {
|
|
|
1679
1758
|
this.buffer.unshift(...update.logs);
|
|
1680
1759
|
this.scheduleFlush();
|
|
1681
1760
|
}
|
|
1761
|
+
if (update.progress && this.progressTotal != null) this.progressDirty = true;
|
|
1682
1762
|
this.logger.error(`update da run ${this.runId} perdido:`, error);
|
|
1683
1763
|
}
|
|
1684
1764
|
}).finally(() => {
|
|
@@ -2084,10 +2164,10 @@ function init(options) {
|
|
|
2084
2164
|
function getClient() {
|
|
2085
2165
|
return client;
|
|
2086
2166
|
}
|
|
2087
|
-
function toRunLogLevel(
|
|
2088
|
-
return
|
|
2167
|
+
function toRunLogLevel(type) {
|
|
2168
|
+
return type === "fatal" ? "error" : type;
|
|
2089
2169
|
}
|
|
2090
|
-
function forwardAttachment(attachment, message,
|
|
2170
|
+
function forwardAttachment(attachment, message, type) {
|
|
2091
2171
|
const attach = currentRunAttach();
|
|
2092
2172
|
if (!attach) {
|
|
2093
2173
|
client?.logger.warn("attachment descartado \u2014 s\xF3 \xE9 suportado dentro de uma execu\xE7\xE3o de task (register/start)");
|
|
@@ -2096,7 +2176,7 @@ function forwardAttachment(attachment, message, level) {
|
|
|
2096
2176
|
const withMeta = typeof attachment === "object" && "image" in attachment ? attachment : { image: attachment };
|
|
2097
2177
|
void attach(withMeta.image, {
|
|
2098
2178
|
message,
|
|
2099
|
-
level: toRunLogLevel(
|
|
2179
|
+
level: toRunLogLevel(type),
|
|
2100
2180
|
caption: withMeta.caption,
|
|
2101
2181
|
contentType: withMeta.contentType
|
|
2102
2182
|
});
|
|
@@ -2104,15 +2184,15 @@ function forwardAttachment(attachment, message, level) {
|
|
|
2104
2184
|
function captureException(error, hint) {
|
|
2105
2185
|
if (hint?.attachment) {
|
|
2106
2186
|
const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
2107
|
-
forwardAttachment(hint.attachment, message, hint.
|
|
2187
|
+
forwardAttachment(hint.attachment, message, hint.type ?? "error");
|
|
2108
2188
|
}
|
|
2109
2189
|
return client?.captureException(error, hint, scope);
|
|
2110
2190
|
}
|
|
2111
|
-
function captureMessage(message,
|
|
2191
|
+
function captureMessage(message, type = "warning", hint) {
|
|
2112
2192
|
if (hint?.attachment) {
|
|
2113
|
-
forwardAttachment(hint.attachment, message, hint.
|
|
2193
|
+
forwardAttachment(hint.attachment, message, hint.type ?? type);
|
|
2114
2194
|
}
|
|
2115
|
-
return client?.captureMessage(message,
|
|
2195
|
+
return client?.captureMessage(message, type, hint, scope);
|
|
2116
2196
|
}
|
|
2117
2197
|
function addBreadcrumb(crumb) {
|
|
2118
2198
|
scope.addBreadcrumb(crumb, client?.options.maxBreadcrumbs ?? DEFAULT_MAX_BREADCRUMBS);
|