hobots 1.10.0 → 2.0.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/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 ? "1.10.0" : "0.0.0-dev";
164
+ var SDK_VERSION = true ? "2.0.0" : "0.0.0-dev";
165
165
  function isNode() {
166
166
  return typeof process !== "undefined" && typeof process.versions?.node === "string";
167
167
  }
@@ -354,7 +354,8 @@ var Transport = class {
354
354
  return;
355
355
  }
356
356
  if (this.buffer.length >= this.maxQueueSize) {
357
- this.buffer.shift();
357
+ const dropIndex = this.buffer.findIndex((queued) => queued.type !== "heartbeat");
358
+ this.buffer.splice(dropIndex === -1 ? 0 : dropIndex, 1);
358
359
  this.logger.warn("fila cheia, item mais antigo descartado");
359
360
  }
360
361
  this.buffer.push(item);
@@ -445,6 +446,8 @@ function runtimeContexts() {
445
446
  }
446
447
  var Client = class {
447
448
  logger;
449
+ /** Eco de lifecycle (Transaction.emit) e afins só imprimem no terminal com debug ligado. */
450
+ debug;
448
451
  // campos privados + getters de protótipo: o clientSecret não aparece em
449
452
  // JSON.stringify/serialização enumerável do Client (ex.: um objeto capturado
450
453
  // que referencie o client), mas client.options/config seguem funcionando
@@ -453,7 +456,8 @@ var Client = class {
453
456
  transport;
454
457
  constructor(options, config = resolveConfig(options)) {
455
458
  this.#options = options;
456
- this.logger = makeLogger(!!options.debug);
459
+ this.debug = !!options.debug;
460
+ this.logger = makeLogger(this.debug);
457
461
  this.#config = config;
458
462
  this.transport = new Transport({
459
463
  endpoint: this.#config.ingestEndpoint,
@@ -540,6 +544,8 @@ var Client = class {
540
544
 
541
545
  // src/heartbeat.ts
542
546
  var DEFAULT_INTERVAL_MS = 3e4;
547
+ var MIN_REPORTED_INTERVAL_MS = 1e3;
548
+ var MAX_REPORTED_INTERVAL_MS = 9e5;
543
549
  var Heartbeat = class {
544
550
  constructor(client2, options = {}, instanceId) {
545
551
  this.client = client2;
@@ -556,12 +562,22 @@ var Heartbeat = class {
556
562
  start() {
557
563
  if (this.timer) return;
558
564
  this.beat();
559
- this.timer = setInterval(() => this.beat(), this.intervalMs);
565
+ this.schedule();
566
+ }
567
+ /** Jitter de ±10%: uma frota iniciada junto não sincroniza todos os beats no mesmo segundo. */
568
+ schedule() {
569
+ this.timer = setTimeout(
570
+ () => {
571
+ this.beat();
572
+ this.schedule();
573
+ },
574
+ this.intervalMs * (0.9 + Math.random() * 0.2)
575
+ );
560
576
  unrefTimer(this.timer);
561
577
  }
562
578
  stop() {
563
579
  if (this.timer) {
564
- clearInterval(this.timer);
580
+ clearTimeout(this.timer);
565
581
  this.timer = void 0;
566
582
  }
567
583
  }
@@ -569,7 +585,7 @@ var Heartbeat = class {
569
585
  this.client.sendHeartbeat({
570
586
  instance_id: this.instanceId,
571
587
  name: this.name,
572
- interval_ms: this.intervalMs,
588
+ interval_ms: Math.min(Math.max(this.intervalMs, MIN_REPORTED_INTERVAL_MS), MAX_REPORTED_INTERVAL_MS),
573
589
  timestamp: nowISO(),
574
590
  metadata: this.metadata
575
591
  });
@@ -816,15 +832,18 @@ var Transaction = class {
816
832
  // antes do RunReporter conectar) — replay no setLifecycleSink
817
833
  lifecycleBacklog = [];
818
834
  /**
819
- * Ecoa no terminal o início/fim de uma step ou transaction (sempre, independente de
820
- * sampling ou do debug) e espelha a linha no sink de lifecycle, se conectado — é
821
- * assim que os eventos de performance também aparecem nos logs da run no app.
835
+ * Registra o início/fim de uma step ou transaction: espelha a linha no sink de
836
+ * lifecycle, se conectado (é assim que os eventos de performance aparecem nos
837
+ * logs da run no app), e ecoa no terminal apenas com `debug: true` — o SDK não
838
+ * escreve no stdout do processo do usuário sem permissão.
822
839
  */
823
840
  emit(kind, phase, label, startTs, endTs, status) {
824
841
  const durationMs = startTs && endTs ? new Date(endTs).getTime() - new Date(startTs).getTime() : void 0;
825
- const tag = colorize(`[hobots:${kind}] ${phase.toUpperCase()}`, phase === "finish" ? colorForStatus(status ?? "ok") : "cyan");
826
842
  const suffix = durationMs != null ? ` (${durationMs}ms)` : "";
827
- console.log(`${tag} ${label}${suffix}`);
843
+ if (this.client?.debug) {
844
+ const tag = colorize(`[hobots:${kind}] ${phase.toUpperCase()}`, phase === "finish" ? colorForStatus(status ?? "ok") : "cyan");
845
+ console.log(`${tag} ${label}${suffix}`);
846
+ }
828
847
  const level = phase === "finish" ? levelForStatus(status ?? "ok") : "info";
829
848
  const message = `[${kind}] ${phase.toUpperCase()} ${label}${suffix}`;
830
849
  if (this.lifecycleSink) this.lifecycleSink(level, message);
@@ -1871,13 +1890,17 @@ var TaskAgent = class {
1871
1890
  try {
1872
1891
  const response = await this.api.poll(
1873
1892
  {
1874
- agent: {
1893
+ instance: {
1875
1894
  // identidade canônica do agente no painel — o mesmo instanceId do
1876
1895
  // heartbeat da Telemetria, então os dois canais convergem em um agente
1877
1896
  instance_id: this.instanceId,
1878
1897
  version: SDK_VERSION,
1879
1898
  host: hostname(),
1880
- tasks: [...this.registry.keys()]
1899
+ tasks: [...this.registry.keys()],
1900
+ // o servidor calcula a tolerância de offline (3×) a partir disto em
1901
+ // agentes poll-only — sem o campo, um poll lento flaparia offline/online.
1902
+ // Clampado à faixa aceita pelo schema do poll (1s..15min).
1903
+ poll_interval_ms: Math.min(Math.max(this.pollIntervalMs, 1e3), 9e5)
1881
1904
  },
1882
1905
  max: Math.min(MAX_CONCURRENCY, this.concurrency - this.activeRuns.size),
1883
1906
  tasks: [...this.registry.keys()]