hobots 1.9.0 → 1.9.1

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.d.cts CHANGED
@@ -1,6 +1,9 @@
1
1
  import { Breadcrumb, EventUser, Severity, EventPayload, TransactionPayload, HeartbeatPayload, StepStatus, RunLogLevel, StepData, RunAttachmentContentType } from './protocol.cjs';
2
2
  export { AgentInfo, Envelope, EnvelopeItem, ExceptionData, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunDescriptor, RunError, RunLogEntry, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame } from './protocol.cjs';
3
3
 
4
+ /** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
5
+ type AttachInput = Uint8Array | ArrayBuffer | string;
6
+
4
7
  /** API oficial da Hobots — o SDK sempre fala com ela em produção. */
5
8
  declare const DEFAULT_BASE_URL = "https://api2.hobots.app";
6
9
  interface ResolvedConfig {
@@ -123,31 +126,6 @@ declare class Transaction {
123
126
  finish(): void;
124
127
  }
125
128
 
126
- interface AttachOptions {
127
- /** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
128
- caption?: string;
129
- /** Nível da linha de log que carrega o anexo. Default: 'info' */
130
- level?: RunLogLevel;
131
- /** Texto da linha de log. Default: a legenda, ou 'captura de tela' */
132
- message?: string;
133
- /** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
134
- contentType?: RunAttachmentContentType;
135
- }
136
- type AttachFailureReason =
137
- /** A instalação do Hobots não tem anexos habilitados (ou a API é anterior ao recurso) */
138
- 'unsupported' | 'too-large' | 'quota' | 'read-failed'
139
- /** Formato não reconhecido ou fora de PNG/JPEG/WEBP */
140
- | 'unsupported-format' | 'upload-failed' | 'canceled';
141
- interface AttachResult {
142
- /** Id do anexo, o mesmo referenciado na linha de log */
143
- id: string;
144
- ok: boolean;
145
- /** Motivo do insucesso — para diagnóstico; `attach` nunca lança */
146
- reason?: AttachFailureReason;
147
- }
148
- /** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
149
- type AttachInput = Uint8Array | ArrayBuffer | string;
150
-
151
129
  /** Opções de tasks dentro de `init({ tasks: ... })`. Credencial (clientSecret), identidade (instanceId) e debug vêm do init. */
152
130
  interface TasksOptions {
153
131
  /** Intervalo entre polls sem trabalho. Default: 5_000 (mínimo 1_000) */
@@ -202,22 +180,6 @@ interface RunContext {
202
180
  throwIfCanceled(): void;
203
181
  /** Sleep cancelável: rejeita com `RunCanceled` se ctx.signal disparar antes de ms. */
204
182
  sleep(ms: number): Promise<void>;
205
- /**
206
- * Anexa uma imagem (print da tela) a uma linha de log da execução — a evidência
207
- * visual aparece como miniatura junto do log, na aba "logs do agente".
208
- *
209
- * Aceita bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo
210
- * (só em Node). A linha de log é registrada imediatamente; o upload roda em
211
- * segundo plano e **nunca bloqueia nem lança** — falhas viram um aviso no log da
212
- * run e um `{ ok: false, reason }` no retorno, que pode ser ignorado com `void`.
213
- *
214
- * PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
215
- *
216
- * ```ts
217
- * await ctx.attach(await page.screenshot(), { caption: 'portal após o login' });
218
- * ```
219
- */
220
- attach(image: AttachInput, options?: AttachOptions): Promise<AttachResult>;
221
183
  }
222
184
  /** O retorno do handler é ignorado — nada além de status/logs/erro é enviado ao servidor. */
223
185
  type TaskHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => void | Promise<void>;
@@ -265,17 +227,43 @@ interface InitOptions {
265
227
  /** Itens por envelope antes de flush imediato. Default: 10 */
266
228
  maxBatchSize?: number;
267
229
  }
230
+ /** Imagem enviada junto de um capture* — com legenda e content-type opcionais. */
231
+ interface CaptureAttachment {
232
+ /** Bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo (só em Node) */
233
+ image: AttachInput;
234
+ /** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
235
+ caption?: string;
236
+ /** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
237
+ contentType?: RunAttachmentContentType;
238
+ }
268
239
  interface CaptureHint {
269
240
  level?: Severity;
270
241
  tags?: Record<string, string>;
271
242
  extra?: Record<string, unknown>;
272
243
  fingerprint?: string[];
244
+ /**
245
+ * Print da tela enviado junto da captura. Dentro de uma execução de task, a imagem
246
+ * vira anexo da linha de log da execução que espelha o evento — miniatura na aba
247
+ * "logs do agente". Fora de uma execução não há onde pendurar a imagem: o SDK
248
+ * descarta com um aviso. O upload roda em segundo plano e **nunca bloqueia nem lança**.
249
+ *
250
+ * PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
251
+ *
252
+ * ```ts
253
+ * Hobots.captureException(error, { attachment: { image: await page.screenshot(), caption: 'tela no momento do erro' } });
254
+ * ```
255
+ */
256
+ attachment?: AttachInput | CaptureAttachment;
273
257
  }
274
258
 
275
259
  /** Inicializa o SDK. Chame uma vez, o mais cedo possível no programa. */
276
260
  declare function init(options: InitOptions): void;
277
261
  declare function getClient(): Client | undefined;
278
- /** Captura uma exceção e retorna o event_id (undefined se o SDK não foi inicializado). */
262
+ /**
263
+ * Captura uma exceção e retorna o event_id (undefined se o SDK não foi inicializado).
264
+ * `hint.attachment` envia um print junto — dentro de uma execução de task, ele aparece
265
+ * como miniatura na linha de log da run correspondente ao erro.
266
+ */
279
267
  declare function captureException(error: unknown, hint?: CaptureHint): string | undefined;
280
268
  declare function captureMessage(message: string, level?: Severity, hint?: CaptureHint): string | undefined;
281
269
  /** Registra um breadcrumb — anexado aos próximos eventos como trilha do que aconteceu antes. */
@@ -308,4 +296,4 @@ declare function close(timeoutMs?: number): Promise<boolean>;
308
296
 
309
297
  declare function scrubSecrets(text: string): string;
310
298
 
311
- export { type AttachFailureReason, type AttachOptions, type AttachResult, Breadcrumb, type BreadcrumbInput, type CaptureHint, Client, DEFAULT_BASE_URL, EventPayload, EventUser, type HeartbeatOptions, HeartbeatPayload, type InitOptions, RunAttachmentContentType, type RunContext, RunLogLevel, Scope, Severity, Step, StepData, type TaskHandler, type TasksOptions, Transaction, TransactionPayload, addBreadcrumb, captureException, captureMessage, close, flush, getClient, init, register, scrubSecrets, setContext, setExtra, setTag, setTags, setUser, start, startTransaction, stop, withScope };
299
+ export { type AttachInput, Breadcrumb, type BreadcrumbInput, type CaptureAttachment, type CaptureHint, Client, DEFAULT_BASE_URL, EventPayload, EventUser, type HeartbeatOptions, HeartbeatPayload, type InitOptions, RunAttachmentContentType, type RunContext, RunLogLevel, Scope, Severity, Step, StepData, type TaskHandler, type TasksOptions, Transaction, TransactionPayload, addBreadcrumb, captureException, captureMessage, close, flush, getClient, init, register, scrubSecrets, setContext, setExtra, setTag, setTags, setUser, start, startTransaction, stop, withScope };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import { Breadcrumb, EventUser, Severity, EventPayload, TransactionPayload, HeartbeatPayload, StepStatus, RunLogLevel, StepData, RunAttachmentContentType } from './protocol.js';
2
2
  export { AgentInfo, Envelope, EnvelopeItem, ExceptionData, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunDescriptor, RunError, RunLogEntry, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame } from './protocol.js';
3
3
 
4
+ /** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
5
+ type AttachInput = Uint8Array | ArrayBuffer | string;
6
+
4
7
  /** API oficial da Hobots — o SDK sempre fala com ela em produção. */
5
8
  declare const DEFAULT_BASE_URL = "https://api2.hobots.app";
6
9
  interface ResolvedConfig {
@@ -123,31 +126,6 @@ declare class Transaction {
123
126
  finish(): void;
124
127
  }
125
128
 
126
- interface AttachOptions {
127
- /** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
128
- caption?: string;
129
- /** Nível da linha de log que carrega o anexo. Default: 'info' */
130
- level?: RunLogLevel;
131
- /** Texto da linha de log. Default: a legenda, ou 'captura de tela' */
132
- message?: string;
133
- /** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
134
- contentType?: RunAttachmentContentType;
135
- }
136
- type AttachFailureReason =
137
- /** A instalação do Hobots não tem anexos habilitados (ou a API é anterior ao recurso) */
138
- 'unsupported' | 'too-large' | 'quota' | 'read-failed'
139
- /** Formato não reconhecido ou fora de PNG/JPEG/WEBP */
140
- | 'unsupported-format' | 'upload-failed' | 'canceled';
141
- interface AttachResult {
142
- /** Id do anexo, o mesmo referenciado na linha de log */
143
- id: string;
144
- ok: boolean;
145
- /** Motivo do insucesso — para diagnóstico; `attach` nunca lança */
146
- reason?: AttachFailureReason;
147
- }
148
- /** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
149
- type AttachInput = Uint8Array | ArrayBuffer | string;
150
-
151
129
  /** Opções de tasks dentro de `init({ tasks: ... })`. Credencial (clientSecret), identidade (instanceId) e debug vêm do init. */
152
130
  interface TasksOptions {
153
131
  /** Intervalo entre polls sem trabalho. Default: 5_000 (mínimo 1_000) */
@@ -202,22 +180,6 @@ interface RunContext {
202
180
  throwIfCanceled(): void;
203
181
  /** Sleep cancelável: rejeita com `RunCanceled` se ctx.signal disparar antes de ms. */
204
182
  sleep(ms: number): Promise<void>;
205
- /**
206
- * Anexa uma imagem (print da tela) a uma linha de log da execução — a evidência
207
- * visual aparece como miniatura junto do log, na aba "logs do agente".
208
- *
209
- * Aceita bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo
210
- * (só em Node). A linha de log é registrada imediatamente; o upload roda em
211
- * segundo plano e **nunca bloqueia nem lança** — falhas viram um aviso no log da
212
- * run e um `{ ok: false, reason }` no retorno, que pode ser ignorado com `void`.
213
- *
214
- * PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
215
- *
216
- * ```ts
217
- * await ctx.attach(await page.screenshot(), { caption: 'portal após o login' });
218
- * ```
219
- */
220
- attach(image: AttachInput, options?: AttachOptions): Promise<AttachResult>;
221
183
  }
222
184
  /** O retorno do handler é ignorado — nada além de status/logs/erro é enviado ao servidor. */
223
185
  type TaskHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => void | Promise<void>;
@@ -265,17 +227,43 @@ interface InitOptions {
265
227
  /** Itens por envelope antes de flush imediato. Default: 10 */
266
228
  maxBatchSize?: number;
267
229
  }
230
+ /** Imagem enviada junto de um capture* — com legenda e content-type opcionais. */
231
+ interface CaptureAttachment {
232
+ /** Bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo (só em Node) */
233
+ image: AttachInput;
234
+ /** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
235
+ caption?: string;
236
+ /** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
237
+ contentType?: RunAttachmentContentType;
238
+ }
268
239
  interface CaptureHint {
269
240
  level?: Severity;
270
241
  tags?: Record<string, string>;
271
242
  extra?: Record<string, unknown>;
272
243
  fingerprint?: string[];
244
+ /**
245
+ * Print da tela enviado junto da captura. Dentro de uma execução de task, a imagem
246
+ * vira anexo da linha de log da execução que espelha o evento — miniatura na aba
247
+ * "logs do agente". Fora de uma execução não há onde pendurar a imagem: o SDK
248
+ * descarta com um aviso. O upload roda em segundo plano e **nunca bloqueia nem lança**.
249
+ *
250
+ * PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
251
+ *
252
+ * ```ts
253
+ * Hobots.captureException(error, { attachment: { image: await page.screenshot(), caption: 'tela no momento do erro' } });
254
+ * ```
255
+ */
256
+ attachment?: AttachInput | CaptureAttachment;
273
257
  }
274
258
 
275
259
  /** Inicializa o SDK. Chame uma vez, o mais cedo possível no programa. */
276
260
  declare function init(options: InitOptions): void;
277
261
  declare function getClient(): Client | undefined;
278
- /** Captura uma exceção e retorna o event_id (undefined se o SDK não foi inicializado). */
262
+ /**
263
+ * Captura uma exceção e retorna o event_id (undefined se o SDK não foi inicializado).
264
+ * `hint.attachment` envia um print junto — dentro de uma execução de task, ele aparece
265
+ * como miniatura na linha de log da run correspondente ao erro.
266
+ */
279
267
  declare function captureException(error: unknown, hint?: CaptureHint): string | undefined;
280
268
  declare function captureMessage(message: string, level?: Severity, hint?: CaptureHint): string | undefined;
281
269
  /** Registra um breadcrumb — anexado aos próximos eventos como trilha do que aconteceu antes. */
@@ -308,4 +296,4 @@ declare function close(timeoutMs?: number): Promise<boolean>;
308
296
 
309
297
  declare function scrubSecrets(text: string): string;
310
298
 
311
- export { type AttachFailureReason, type AttachOptions, type AttachResult, Breadcrumb, type BreadcrumbInput, type CaptureHint, Client, DEFAULT_BASE_URL, EventPayload, EventUser, type HeartbeatOptions, HeartbeatPayload, type InitOptions, RunAttachmentContentType, type RunContext, RunLogLevel, Scope, Severity, Step, StepData, type TaskHandler, type TasksOptions, Transaction, TransactionPayload, addBreadcrumb, captureException, captureMessage, close, flush, getClient, init, register, scrubSecrets, setContext, setExtra, setTag, setTags, setUser, start, startTransaction, stop, withScope };
299
+ export { type AttachInput, Breadcrumb, type BreadcrumbInput, type CaptureAttachment, type CaptureHint, Client, DEFAULT_BASE_URL, EventPayload, EventUser, type HeartbeatOptions, HeartbeatPayload, type InitOptions, RunAttachmentContentType, type RunContext, RunLogLevel, Scope, Severity, Step, StepData, type TaskHandler, type TasksOptions, Transaction, TransactionPayload, addBreadcrumb, captureException, captureMessage, close, flush, getClient, init, register, scrubSecrets, setContext, setExtra, setTag, setTags, setUser, start, startTransaction, stop, withScope };
package/dist/index.js CHANGED
@@ -1114,8 +1114,7 @@ var RunReporter = class {
1114
1114
  throwIfCanceled: () => {
1115
1115
  if (signal.aborted) throw runCanceledError();
1116
1116
  },
1117
- sleep: (ms) => cancelableSleep(ms, signal),
1118
- attach: (image, options) => this.attach(image, options)
1117
+ sleep: (ms) => cancelableSleep(ms, signal)
1119
1118
  };
1120
1119
  }
1121
1120
  context;
@@ -1260,7 +1259,8 @@ var RunReporter = class {
1260
1259
  /**
1261
1260
  * Registra a linha de log com o id do anexo (síncrono, na ordem certa) e dispara
1262
1261
  * o upload em segundo plano. Nunca lança: todo caminho de erro vira `{ ok: false }`
1263
- * com um aviso no log da run.
1262
+ * com um aviso no log da run. Chega ao handler pelos capture* do SDK — o hint
1263
+ * `attachment` de Hobots.captureException/captureMessage cai aqui via run-context-store.
1264
1264
  */
1265
1265
  async attach(image, options = {}) {
1266
1266
  const id = uuid4();
@@ -1447,6 +1447,9 @@ async function runWithRunContext(store, fn) {
1447
1447
  function currentRunTransaction() {
1448
1448
  return storage?.getStore()?.tx;
1449
1449
  }
1450
+ function currentRunAttach() {
1451
+ return storage?.getStore()?.attach;
1452
+ }
1450
1453
 
1451
1454
  // src/tasks/shutdown.ts
1452
1455
  var WATCHED_SIGNALS = ["SIGINT", "SIGTERM"];
@@ -1688,7 +1691,10 @@ var TaskAgent = class {
1688
1691
  }
1689
1692
  this.logger.debug(`executando run ${run.id} (${run.task})`);
1690
1693
  try {
1691
- await runWithRunContext({ runId: run.id, tx }, () => this.invokeWithTimeout(handler, run, reporter));
1694
+ await runWithRunContext(
1695
+ { runId: run.id, tx, attach: (image, options) => reporter.attach(image, options) },
1696
+ () => this.invokeWithTimeout(handler, run, reporter)
1697
+ );
1692
1698
  await reporter.finalizeAttachments();
1693
1699
  tx.setStatus("ok");
1694
1700
  tx.finish();
@@ -1778,10 +1784,34 @@ function init(options) {
1778
1784
  function getClient() {
1779
1785
  return client;
1780
1786
  }
1787
+ function toRunLogLevel(level) {
1788
+ return level === "fatal" ? "error" : level;
1789
+ }
1790
+ function forwardAttachment(attachment, message, level) {
1791
+ const attach = currentRunAttach();
1792
+ if (!attach) {
1793
+ client?.logger.warn("attachment descartado \u2014 s\xF3 \xE9 suportado dentro de uma execu\xE7\xE3o de task (register/start)");
1794
+ return;
1795
+ }
1796
+ const withMeta = typeof attachment === "object" && "image" in attachment ? attachment : { image: attachment };
1797
+ void attach(withMeta.image, {
1798
+ message,
1799
+ level: toRunLogLevel(level),
1800
+ caption: withMeta.caption,
1801
+ contentType: withMeta.contentType
1802
+ });
1803
+ }
1781
1804
  function captureException(error, hint) {
1805
+ if (hint?.attachment) {
1806
+ const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
1807
+ forwardAttachment(hint.attachment, message, hint.level ?? "error");
1808
+ }
1782
1809
  return client?.captureException(error, hint, scope);
1783
1810
  }
1784
1811
  function captureMessage(message, level = "info", hint) {
1812
+ if (hint?.attachment) {
1813
+ forwardAttachment(hint.attachment, message, hint.level ?? level);
1814
+ }
1785
1815
  return client?.captureMessage(message, level, hint, scope);
1786
1816
  }
1787
1817
  function addBreadcrumb(crumb) {