hobots 1.7.5 → 1.8.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 +14 -34
- package/dist/index.cjs +27 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -36
- package/dist/index.d.ts +19 -36
- package/dist/index.js +27 -80
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +9 -25
- package/dist/protocol.d.ts +9 -25
- package/docs/README.md +4 -4
- package/docs/api-reference.md +5 -27
- package/docs/concepts.md +27 -51
- package/docs/getting-started.md +1 -1
- package/docs/protocol.md +1 -2
- package/docs/tasks.md +6 -6
- package/docs/{monitor.md → telemetry.md} +13 -35
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# hobots
|
|
2
2
|
|
|
3
|
-
SDK JavaScript/TypeScript da **Hobots** para instrumentar
|
|
3
|
+
SDK JavaScript/TypeScript da **Hobots** para instrumentar agentes (RPAs) e integrações.
|
|
4
4
|
|
|
5
|
-
- **Telemetria** — o que o programa **emite** sozinho: erros com stack trace (módulo **Issues** do app), performance (transactions/
|
|
5
|
+
- **Telemetria** — o que o programa **emite** sozinho: erros com stack trace (módulo **Issues** do app), performance (transactions/etapas) e heartbeats de uptime (módulo **Agentes**).
|
|
6
6
|
- **Tasks** — execução **sob demanda**: o agente faz polling no app da Hobots, executa handlers registrados e reporta status e logs (módulo **Solicitações**).
|
|
7
7
|
|
|
8
8
|
**Um único import e um único `init()`** cobrem as duas capabilities. Cliente HTTP puro, **sem dependências de runtime**. Requer **Node 18+** (usa o `fetch` global); a telemetria também roda no browser para captura de erros.
|
|
@@ -30,7 +30,7 @@ O SDK expõe **duas capabilities** autenticadas pelo **mesmo Client Secret do ag
|
|
|
30
30
|
|
|
31
31
|
| Capability | Como habilita | Para quê | Ciclo de vida |
|
|
32
32
|
| --- | --- | --- | --- |
|
|
33
|
-
| **Telemetria** | sempre ativa no `init()` | O que o programa emite sozinho: erros, transactions/
|
|
33
|
+
| **Telemetria** | sempre ativa no `init()` | O que o programa emite sozinho: erros, transactions/etapas, heartbeat. | Timers `unref`'d — **não** segura o processo. Chame `close()` no fim. |
|
|
34
34
|
| **Tasks** | `tasks: true` (ou opções) no `init()` | Execução remota sob demanda via polling. | `start()` **segura o processo vivo** até `stop()`/`close()`. |
|
|
35
35
|
|
|
36
36
|
Você usa **uma, outra ou as duas**:
|
|
@@ -158,16 +158,16 @@ Hobots.withScope((scope) => {
|
|
|
158
158
|
});
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
### Performance: transactions e
|
|
161
|
+
### Performance: transactions e etapas
|
|
162
162
|
|
|
163
163
|
```js
|
|
164
164
|
const tx = Hobots.startTransaction('processar-lote', 'rpa.job');
|
|
165
165
|
|
|
166
|
-
const
|
|
166
|
+
const step = tx.startChild('http.client', 'GET /api/notas');
|
|
167
167
|
await api.buscarNotas();
|
|
168
|
-
|
|
168
|
+
step.setData('notas', 42).finish();
|
|
169
169
|
|
|
170
|
-
const filho =
|
|
170
|
+
const filho = step.startChild('db.query', 'INSERT INTO notas'); // etapas aninham
|
|
171
171
|
await gravar();
|
|
172
172
|
filho.finish();
|
|
173
173
|
|
|
@@ -175,31 +175,11 @@ tx.setStatus('ok'); // ou 'error'
|
|
|
175
175
|
tx.finish(); // só aqui a transaction é enviada (respeitando tracesSampleRate)
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
- `startChild(op?, description?)` existe em `Transaction` **e** `
|
|
179
|
-
- Métodos encadeáveis: `setStatus`, `setData` (
|
|
180
|
-
- `finish()` na transaction fecha
|
|
178
|
+
- `startChild(op?, description?)` existe em `Transaction` **e** `Step` (aninhamento arbitrário).
|
|
179
|
+
- Métodos encadeáveis: `setStatus`, `setData` (step), `setTag`/`setName` (transaction).
|
|
180
|
+
- `finish()` na transaction fecha as etapas abertas e envia o payload; nada é enviado se ela não foi amostrada. A amostragem é decidida no `startTransaction()`.
|
|
181
181
|
|
|
182
|
-
Dentro de um handler de task, `startTransaction()` **retorna a transaction da própria run** (`ctx.tx`) em vez de criar uma segunda — cada execução tem exatamente **uma** transaction. Conceitos: [Transaction](./docs/concepts.md#transaction) · [
|
|
183
|
-
|
|
184
|
-
### Crons (check-ins)
|
|
185
|
-
|
|
186
|
-
Monitora jobs agendados no módulo **Monitores** do app: check-in `in_progress` na entrada, `ok`/`error` na saída, com duração medida. O jeito recomendado é `withMonitor`, que faz o par e captura exceções:
|
|
187
|
-
|
|
188
|
-
```js
|
|
189
|
-
await Hobots.withMonitor(
|
|
190
|
-
'sync-notas',
|
|
191
|
-
() => executarSync(),
|
|
192
|
-
{ schedule: '0 */2 * * *', timezone: 'America/Fortaleza' }
|
|
193
|
-
);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
O `schedule` (expressão cron) faz o servidor **criar/atualizar o monitor automaticamente** (upsert) e habilita a detecção de **execução perdida**. Para controle manual:
|
|
197
|
-
|
|
198
|
-
```js
|
|
199
|
-
const id = Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'in_progress' });
|
|
200
|
-
// … trabalho …
|
|
201
|
-
Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'ok', checkInId: id, durationMs: 1234 });
|
|
202
|
-
```
|
|
182
|
+
Dentro de um handler de task, `startTransaction()` **retorna a transaction da própria run** (`ctx.tx`) em vez de criar uma segunda — cada execução tem exatamente **uma** transaction. Conceitos: [Transaction](./docs/concepts.md#transaction) · [Step](./docs/concepts.md#step).
|
|
203
183
|
|
|
204
184
|
### Heartbeat (uptime)
|
|
205
185
|
|
|
@@ -353,7 +333,7 @@ Para parar de aceitar execuções **sem** derrubar a telemetria, use `stop(timeo
|
|
|
353
333
|
|
|
354
334
|
| Import | Conteúdo |
|
|
355
335
|
| --- | --- |
|
|
356
|
-
| `hobots` | Tudo: `init`, telemetria (captura, transactions,
|
|
336
|
+
| `hobots` | Tudo: `init`, telemetria (captura, transactions, heartbeat), tasks (`register`/`start`/`stop`), `close`, classes e tipos. |
|
|
357
337
|
| `hobots/protocol` | Tipos do wire format (telemetria e tasks). |
|
|
358
338
|
|
|
359
339
|
Empacotado em **ESM e CommonJS** com **definições de tipos** (`.d.ts`) para todas as entradas.
|
|
@@ -364,11 +344,11 @@ Empacotado em **ESM e CommonJS** com **definições de tipos** (`.d.ts`) para to
|
|
|
364
344
|
|
|
365
345
|
Guias detalhados acompanham o pacote em [`docs/`](./docs/README.md).
|
|
366
346
|
|
|
367
|
-
Novo no vocabulário de observabilidade (transaction,
|
|
347
|
+
Novo no vocabulário de observabilidade (transaction, step, breadcrumb, tag, context, extra, flush, close)? Comece por [Conceitos](./docs/concepts.md) — as outras páginas assumem esses termos.
|
|
368
348
|
|
|
369
349
|
- [Conceitos](./docs/concepts.md) — o que cada coisa é, por que existe e quando escolher uma em vez da outra.
|
|
370
350
|
- [Getting started](./docs/getting-started.md) — instalação, Client Secret, primeiro `init`, telemetria e tasks.
|
|
371
|
-
- [Telemetria](./docs/
|
|
351
|
+
- [Telemetria](./docs/telemetry.md) — erros, breadcrumbs, escopo, transactions/etapas, heartbeat.
|
|
372
352
|
- [Tasks](./docs/tasks.md) — handlers, `RunContext`, cancelamento, concorrência, idempotência.
|
|
373
353
|
- [Referência de API](./docs/api-reference.md) — todas as funções e tabelas de opções com defaults.
|
|
374
354
|
- [Protocolo & transporte](./docs/protocol.md) — o Client Secret, endpoints, envelope, retries.
|
package/dist/index.cjs
CHANGED
|
@@ -33,12 +33,11 @@ __export(src_exports, {
|
|
|
33
33
|
Client: () => Client,
|
|
34
34
|
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
35
35
|
Scope: () => Scope,
|
|
36
|
-
|
|
36
|
+
Step: () => Step,
|
|
37
37
|
Transaction: () => Transaction,
|
|
38
38
|
addBreadcrumb: () => addBreadcrumb,
|
|
39
39
|
captureException: () => captureException,
|
|
40
40
|
captureMessage: () => captureMessage,
|
|
41
|
-
checkIn: () => checkIn,
|
|
42
41
|
close: () => close,
|
|
43
42
|
flush: () => flush,
|
|
44
43
|
getClient: () => getClient,
|
|
@@ -53,7 +52,6 @@ __export(src_exports, {
|
|
|
53
52
|
start: () => start,
|
|
54
53
|
startTransaction: () => startTransaction,
|
|
55
54
|
stop: () => stop,
|
|
56
|
-
withMonitor: () => withMonitor,
|
|
57
55
|
withScope: () => withScope
|
|
58
56
|
});
|
|
59
57
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -163,7 +161,7 @@ function scrubSecrets(text) {
|
|
|
163
161
|
|
|
164
162
|
// src/utils.ts
|
|
165
163
|
var SDK_NAME = "hobots";
|
|
166
|
-
var SDK_VERSION = true ? "1.
|
|
164
|
+
var SDK_VERSION = true ? "1.8.0" : "0.0.0-dev";
|
|
167
165
|
function isNode() {
|
|
168
166
|
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
169
167
|
}
|
|
@@ -517,16 +515,6 @@ var Client = class {
|
|
|
517
515
|
}
|
|
518
516
|
});
|
|
519
517
|
}
|
|
520
|
-
sendCheckIn(payload) {
|
|
521
|
-
this.transport.enqueue({
|
|
522
|
-
type: "check_in",
|
|
523
|
-
payload: {
|
|
524
|
-
...payload,
|
|
525
|
-
release: payload.release ?? this.options.release,
|
|
526
|
-
environment: payload.environment ?? this.options.environment ?? "production"
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
518
|
sendHeartbeat(payload) {
|
|
531
519
|
this.transport.enqueue({
|
|
532
520
|
type: "heartbeat",
|
|
@@ -719,10 +707,10 @@ var Scope = class _Scope {
|
|
|
719
707
|
};
|
|
720
708
|
|
|
721
709
|
// src/transaction.ts
|
|
722
|
-
function
|
|
710
|
+
function stepId() {
|
|
723
711
|
return uuid4().slice(0, 16);
|
|
724
712
|
}
|
|
725
|
-
function
|
|
713
|
+
function stepLabel(op, description) {
|
|
726
714
|
return [op, description].filter(Boolean).join(" \u2014 ") || "(sem nome)";
|
|
727
715
|
}
|
|
728
716
|
function levelForStatus(status) {
|
|
@@ -749,14 +737,14 @@ function colorForStatus(status) {
|
|
|
749
737
|
return "green";
|
|
750
738
|
}
|
|
751
739
|
}
|
|
752
|
-
var
|
|
753
|
-
constructor(transaction,
|
|
740
|
+
var Step = class {
|
|
741
|
+
constructor(transaction, parentStepId, op, description) {
|
|
754
742
|
this.transaction = transaction;
|
|
755
|
-
this.
|
|
743
|
+
this.parentStepId = parentStepId;
|
|
756
744
|
this.op = op;
|
|
757
745
|
this.description = description;
|
|
758
746
|
}
|
|
759
|
-
|
|
747
|
+
stepId = stepId();
|
|
760
748
|
startTimestamp = nowISO();
|
|
761
749
|
status = "ok";
|
|
762
750
|
endTimestamp;
|
|
@@ -769,17 +757,17 @@ var Span = class {
|
|
|
769
757
|
this.data = { ...this.data, [key]: value };
|
|
770
758
|
return this;
|
|
771
759
|
}
|
|
772
|
-
/**
|
|
760
|
+
/** Step aninhada (filha desta step). */
|
|
773
761
|
startChild(op, description) {
|
|
774
|
-
return this.transaction.
|
|
762
|
+
return this.transaction.createStep(this.stepId, op, description);
|
|
775
763
|
}
|
|
776
764
|
finish() {
|
|
777
765
|
if (this.endTimestamp) return;
|
|
778
766
|
this.endTimestamp = nowISO();
|
|
779
767
|
this.transaction.emit(
|
|
780
|
-
"
|
|
768
|
+
"step",
|
|
781
769
|
"finish",
|
|
782
|
-
|
|
770
|
+
stepLabel(this.op, this.description),
|
|
783
771
|
this.startTimestamp,
|
|
784
772
|
this.endTimestamp,
|
|
785
773
|
this.status
|
|
@@ -787,8 +775,8 @@ var Span = class {
|
|
|
787
775
|
}
|
|
788
776
|
toJSON() {
|
|
789
777
|
return {
|
|
790
|
-
|
|
791
|
-
|
|
778
|
+
step_id: this.stepId,
|
|
779
|
+
parent_step_id: this.parentStepId,
|
|
792
780
|
op: this.op,
|
|
793
781
|
description: this.description,
|
|
794
782
|
status: this.status,
|
|
@@ -808,10 +796,10 @@ var Transaction = class {
|
|
|
808
796
|
this.emit("transaction", "start", op ? `${name} (${op})` : name);
|
|
809
797
|
}
|
|
810
798
|
eventId = uuid4();
|
|
811
|
-
|
|
799
|
+
stepId = stepId();
|
|
812
800
|
startTimestamp = nowISO();
|
|
813
801
|
status = "ok";
|
|
814
|
-
|
|
802
|
+
steps = [];
|
|
815
803
|
tags = {};
|
|
816
804
|
finished = false;
|
|
817
805
|
lifecycleSink;
|
|
@@ -819,7 +807,7 @@ var Transaction = class {
|
|
|
819
807
|
// antes do RunReporter conectar) — replay no setLifecycleSink
|
|
820
808
|
lifecycleBacklog = [];
|
|
821
809
|
/**
|
|
822
|
-
* Ecoa no terminal o início/fim de
|
|
810
|
+
* Ecoa no terminal o início/fim de uma step ou transaction (sempre, independente de
|
|
823
811
|
* sampling ou do debug) e espelha a linha no sink de lifecycle, se conectado — é
|
|
824
812
|
* assim que os eventos de performance também aparecem nos logs da run no app.
|
|
825
813
|
*/
|
|
@@ -840,15 +828,15 @@ var Transaction = class {
|
|
|
840
828
|
this.lifecycleBacklog = [];
|
|
841
829
|
for (const [level, message] of backlog) sink(level, message);
|
|
842
830
|
}
|
|
843
|
-
|
|
844
|
-
const
|
|
845
|
-
this.
|
|
846
|
-
this.emit("
|
|
847
|
-
return
|
|
831
|
+
createStep(parentStepId, op, description) {
|
|
832
|
+
const step = new Step(this, parentStepId, op, description);
|
|
833
|
+
this.steps.push(step);
|
|
834
|
+
this.emit("step", "start", stepLabel(op, description));
|
|
835
|
+
return step;
|
|
848
836
|
}
|
|
849
|
-
/**
|
|
837
|
+
/** Step direta da transaction. */
|
|
850
838
|
startChild(op, description) {
|
|
851
|
-
return this.
|
|
839
|
+
return this.createStep(this.stepId, op, description);
|
|
852
840
|
}
|
|
853
841
|
setTag(key, value) {
|
|
854
842
|
this.tags[key] = value;
|
|
@@ -865,7 +853,7 @@ var Transaction = class {
|
|
|
865
853
|
finish() {
|
|
866
854
|
if (this.finished) return;
|
|
867
855
|
this.finished = true;
|
|
868
|
-
for (const
|
|
856
|
+
for (const step of this.steps) step.finish();
|
|
869
857
|
const endTimestamp = nowISO();
|
|
870
858
|
this.emit(
|
|
871
859
|
"transaction",
|
|
@@ -883,7 +871,7 @@ var Transaction = class {
|
|
|
883
871
|
status: this.status,
|
|
884
872
|
start_timestamp: this.startTimestamp,
|
|
885
873
|
timestamp: endTimestamp,
|
|
886
|
-
|
|
874
|
+
steps: this.steps.map((step) => step.toJSON()),
|
|
887
875
|
tags: Object.keys(this.tags).length > 0 ? this.tags : void 0,
|
|
888
876
|
run_id: this.runId
|
|
889
877
|
};
|
|
@@ -891,34 +879,6 @@ var Transaction = class {
|
|
|
891
879
|
}
|
|
892
880
|
};
|
|
893
881
|
|
|
894
|
-
// src/checkin.ts
|
|
895
|
-
function sendCheckIn(client2, options) {
|
|
896
|
-
const checkInId = options.checkInId ?? uuid4();
|
|
897
|
-
client2.sendCheckIn({
|
|
898
|
-
check_in_id: checkInId,
|
|
899
|
-
monitor_slug: options.monitorSlug,
|
|
900
|
-
status: options.status,
|
|
901
|
-
duration_ms: options.durationMs,
|
|
902
|
-
schedule: options.schedule,
|
|
903
|
-
timezone: options.timezone
|
|
904
|
-
});
|
|
905
|
-
return checkInId;
|
|
906
|
-
}
|
|
907
|
-
async function withMonitorImpl(client2, captureError, monitorSlug, fn, options) {
|
|
908
|
-
const base = { monitorSlug, schedule: options?.schedule, timezone: options?.timezone };
|
|
909
|
-
const checkInId = sendCheckIn(client2, { ...base, status: "in_progress" });
|
|
910
|
-
const startedAt = Date.now();
|
|
911
|
-
try {
|
|
912
|
-
const result = await fn();
|
|
913
|
-
sendCheckIn(client2, { ...base, status: "ok", checkInId, durationMs: Date.now() - startedAt });
|
|
914
|
-
return result;
|
|
915
|
-
} catch (error) {
|
|
916
|
-
sendCheckIn(client2, { ...base, status: "error", checkInId, durationMs: Date.now() - startedAt });
|
|
917
|
-
captureError(error);
|
|
918
|
-
throw error;
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
|
|
922
882
|
// src/tasks/api.ts
|
|
923
883
|
var POLL_TIMEOUT_MS = 3e4;
|
|
924
884
|
var UPDATE_TIMEOUT_MS = 1e4;
|
|
@@ -1464,7 +1424,7 @@ var TaskAgent = class {
|
|
|
1464
1424
|
{
|
|
1465
1425
|
agent: {
|
|
1466
1426
|
// identidade canônica do agente no painel — o mesmo instanceId do
|
|
1467
|
-
// heartbeat
|
|
1427
|
+
// heartbeat da Telemetria, então os dois canais convergem em um agente
|
|
1468
1428
|
instance_id: this.instanceId,
|
|
1469
1429
|
version: SDK_VERSION,
|
|
1470
1430
|
host: hostname(),
|
|
@@ -1666,19 +1626,6 @@ function startTransaction(name, op) {
|
|
|
1666
1626
|
const sampled = rate >= 1 || Math.random() < rate;
|
|
1667
1627
|
return new Transaction(client, name, op, sampled);
|
|
1668
1628
|
}
|
|
1669
|
-
function checkIn(options) {
|
|
1670
|
-
return client ? sendCheckIn(client, options) : void 0;
|
|
1671
|
-
}
|
|
1672
|
-
async function withMonitor(monitorSlug, fn, options) {
|
|
1673
|
-
if (!client) return fn();
|
|
1674
|
-
return withMonitorImpl(
|
|
1675
|
-
client,
|
|
1676
|
-
(error) => captureException(error, { tags: { monitor: monitorSlug } }),
|
|
1677
|
-
monitorSlug,
|
|
1678
|
-
fn,
|
|
1679
|
-
options
|
|
1680
|
-
);
|
|
1681
|
-
}
|
|
1682
1629
|
function flush(timeoutMs) {
|
|
1683
1630
|
return client ? client.flush(timeoutMs) : Promise.resolve(true);
|
|
1684
1631
|
}
|