hobots 1.5.1 → 1.6.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 +2 -32
- package/dist/index.cjs +179 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +179 -40
- package/dist/index.js.map +1 -1
- package/dist/manager/protocol.cjs.map +1 -1
- package/dist/manager/protocol.d.cts +1 -1
- package/dist/manager/protocol.d.ts +1 -1
- package/docs/api-reference.md +0 -2
- package/docs/concepts.md +40 -40
- package/docs/getting-started.md +1 -1
- package/docs/protocol.md +2 -4
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,20 +1,46 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
2
|
var DEFAULT_BASE_URL = "https://api2.hobots.app";
|
|
3
|
+
var SECRET_PATTERN = /^(hb_)?[a-f0-9]{64}$/i;
|
|
3
4
|
function envBaseUrl() {
|
|
4
5
|
if (typeof process === "undefined" || !process.env) return void 0;
|
|
5
6
|
return process.env.HOBOTS_API_URL?.trim() || void 0;
|
|
6
7
|
}
|
|
8
|
+
function isLoopbackHost(hostname2) {
|
|
9
|
+
return hostname2 === "localhost" || hostname2.endsWith(".localhost") || hostname2.startsWith("127.") || hostname2 === "[::1]" || hostname2 === "::1" || hostname2 === "0.0.0.0";
|
|
10
|
+
}
|
|
11
|
+
var warnedInsecureBaseUrl = false;
|
|
12
|
+
function validateBaseUrl(raw, prefix) {
|
|
13
|
+
let url;
|
|
14
|
+
try {
|
|
15
|
+
url = new URL(raw);
|
|
16
|
+
} catch {
|
|
17
|
+
throw new Error(`${prefix} HOBOTS_API_URL inv\xE1lida \u2014 esperado URL http(s), ex.: http://localhost:3001`);
|
|
18
|
+
}
|
|
19
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
20
|
+
throw new Error(`${prefix} HOBOTS_API_URL com esquema "${url.protocol}" n\xE3o suportado \u2014 use http(s)`);
|
|
21
|
+
}
|
|
22
|
+
if (url.username || url.password) {
|
|
23
|
+
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`);
|
|
24
|
+
}
|
|
25
|
+
if (url.protocol === "http:" && !isLoopbackHost(url.hostname) && !warnedInsecureBaseUrl) {
|
|
26
|
+
warnedInsecureBaseUrl = true;
|
|
27
|
+
console.warn(
|
|
28
|
+
`${prefix} HOBOTS_API_URL usa http para o host remoto "${url.hostname}" \u2014 o Client Secret trafega sem TLS`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return raw.replace(/\/+$/, "");
|
|
32
|
+
}
|
|
7
33
|
function resolveConfig(options, prefix = "[hobots]") {
|
|
8
34
|
const key = options.clientSecret?.trim();
|
|
9
35
|
if (!key) {
|
|
10
36
|
throw new Error(`${prefix} clientSecret ausente \u2014 copie o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos`);
|
|
11
37
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
throw new Error(`${prefix} HOBOTS_API_URL inv\xE1lida: "${baseUrl}" \u2014 esperado ex.: http://localhost:3001`);
|
|
38
|
+
if (!SECRET_PATTERN.test(key)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`${prefix} clientSecret com formato inv\xE1lido (${key.length} caracteres) \u2014 esperado "hb_" + 64 hex; copie o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos`
|
|
41
|
+
);
|
|
17
42
|
}
|
|
43
|
+
const baseUrl = validateBaseUrl(envBaseUrl() ?? DEFAULT_BASE_URL, prefix);
|
|
18
44
|
return {
|
|
19
45
|
key,
|
|
20
46
|
baseUrl,
|
|
@@ -56,9 +82,28 @@ function parseStacktrace(stack) {
|
|
|
56
82
|
return frames;
|
|
57
83
|
}
|
|
58
84
|
|
|
85
|
+
// src/scrub.ts
|
|
86
|
+
var SECRET_PATTERNS = [
|
|
87
|
+
// client secret da Hobots
|
|
88
|
+
[/hb_[a-f0-9]{16,}/gi, "[REDACTED]"],
|
|
89
|
+
// tokens bearer em headers/mensagens
|
|
90
|
+
[/\b(authorization:?\s*)?bearer\s+[a-z0-9._~+/=-]{8,}/gi, "Bearer [REDACTED]"],
|
|
91
|
+
// chaves no formato sk-… (OpenAI e afins)
|
|
92
|
+
[/\bsk-[a-z0-9_-]{16,}\b/gi, "[REDACTED]"],
|
|
93
|
+
// credenciais embutidas em URL (https://user:pass@host)
|
|
94
|
+
[/\/\/[^/\s:@]+:[^/\s@]+@/g, "//[REDACTED]@"]
|
|
95
|
+
];
|
|
96
|
+
function scrubSecrets(text) {
|
|
97
|
+
let out = text;
|
|
98
|
+
for (const [pattern, replacement] of SECRET_PATTERNS) {
|
|
99
|
+
out = out.replace(pattern, replacement);
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
59
104
|
// src/utils.ts
|
|
60
105
|
var SDK_NAME = "hobots";
|
|
61
|
-
var SDK_VERSION = true ? "1.
|
|
106
|
+
var SDK_VERSION = true ? "1.6.0" : "0.0.0-dev";
|
|
62
107
|
function isNode() {
|
|
63
108
|
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
64
109
|
}
|
|
@@ -67,6 +112,12 @@ function uuid4() {
|
|
|
67
112
|
if (cryptoRef && typeof cryptoRef.randomUUID === "function") {
|
|
68
113
|
return cryptoRef.randomUUID().replace(/-/g, "");
|
|
69
114
|
}
|
|
115
|
+
if (cryptoRef && typeof cryptoRef.getRandomValues === "function") {
|
|
116
|
+
const bytes = cryptoRef.getRandomValues(new Uint8Array(16));
|
|
117
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
118
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
119
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
120
|
+
}
|
|
70
121
|
let out = "";
|
|
71
122
|
for (let i = 0; i < 32; i++) {
|
|
72
123
|
out += Math.floor(Math.random() * 16).toString(16);
|
|
@@ -85,7 +136,42 @@ function sleep(ms) {
|
|
|
85
136
|
unrefTimer(timer);
|
|
86
137
|
});
|
|
87
138
|
}
|
|
88
|
-
|
|
139
|
+
function jitter(baseMs) {
|
|
140
|
+
return Math.floor(baseMs / 2 + Math.random() * (baseMs / 2));
|
|
141
|
+
}
|
|
142
|
+
var MAX_RETRY_AFTER_MS = 6e4;
|
|
143
|
+
function retryAfterMs(response) {
|
|
144
|
+
const header = response.headers.get("retry-after");
|
|
145
|
+
if (!header) return void 0;
|
|
146
|
+
const seconds = Number(header);
|
|
147
|
+
if (Number.isFinite(seconds)) {
|
|
148
|
+
return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, seconds * 1e3));
|
|
149
|
+
}
|
|
150
|
+
const date = Date.parse(header);
|
|
151
|
+
if (Number.isNaN(date)) return void 0;
|
|
152
|
+
return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, date - Date.now()));
|
|
153
|
+
}
|
|
154
|
+
function withTimeoutSignal(timeoutMs, external) {
|
|
155
|
+
const controller = new AbortController();
|
|
156
|
+
const onAbort = () => controller.abort(external?.reason);
|
|
157
|
+
if (external?.aborted) {
|
|
158
|
+
onAbort();
|
|
159
|
+
} else {
|
|
160
|
+
external?.addEventListener("abort", onAbort, { once: true });
|
|
161
|
+
}
|
|
162
|
+
const timer = setTimeout(() => {
|
|
163
|
+
controller.abort(Object.assign(new Error(`timeout ap\xF3s ${timeoutMs}ms`), { name: "TimeoutError" }));
|
|
164
|
+
}, timeoutMs);
|
|
165
|
+
unrefTimer(timer);
|
|
166
|
+
return {
|
|
167
|
+
signal: controller.signal,
|
|
168
|
+
cleanup: () => {
|
|
169
|
+
clearTimeout(timer);
|
|
170
|
+
external?.removeEventListener("abort", onAbort);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
var PREFIX = "[hobots]";
|
|
89
175
|
function makeLogger(enabled, prefix = PREFIX) {
|
|
90
176
|
return {
|
|
91
177
|
debug: (...args) => enabled && console.debug(colorize(prefix, "gray"), ...args),
|
|
@@ -126,11 +212,11 @@ function eventFromException(error, level = "error") {
|
|
|
126
212
|
let frames = [];
|
|
127
213
|
if (error instanceof Error) {
|
|
128
214
|
type = error.name || "Error";
|
|
129
|
-
value = error.message;
|
|
215
|
+
value = scrubSecrets(error.message);
|
|
130
216
|
frames = parseStacktrace(error.stack);
|
|
131
217
|
} else {
|
|
132
218
|
type = "NonError";
|
|
133
|
-
value = safeString(error);
|
|
219
|
+
value = scrubSecrets(safeString(error));
|
|
134
220
|
}
|
|
135
221
|
return {
|
|
136
222
|
event_id: uuid4(),
|
|
@@ -148,12 +234,13 @@ function eventFromMessage(message, level = "info") {
|
|
|
148
234
|
event_id: uuid4(),
|
|
149
235
|
timestamp: nowISO(),
|
|
150
236
|
level,
|
|
151
|
-
message
|
|
237
|
+
message: scrubSecrets(message)
|
|
152
238
|
};
|
|
153
239
|
}
|
|
154
240
|
|
|
155
241
|
// src/transport.ts
|
|
156
242
|
var RETRY_DELAYS_MS = [1e3, 4e3, 16e3];
|
|
243
|
+
var REQUEST_TIMEOUT_MS = 1e4;
|
|
157
244
|
var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
|
|
158
245
|
var DEFAULT_MAX_BATCH_SIZE = 10;
|
|
159
246
|
var DEFAULT_MAX_QUEUE_SIZE = 200;
|
|
@@ -220,11 +307,13 @@ var Transport = class {
|
|
|
220
307
|
}
|
|
221
308
|
async sendWithRetry(envelope) {
|
|
222
309
|
for (let attempt = 0; ; attempt++) {
|
|
310
|
+
let serverDelay;
|
|
223
311
|
try {
|
|
224
312
|
const response = await fetch(this.endpoint, {
|
|
225
313
|
method: "POST",
|
|
226
314
|
headers: { "content-type": "application/json", authorization: `Bearer ${this.key}` },
|
|
227
|
-
body: JSON.stringify(envelope)
|
|
315
|
+
body: JSON.stringify(envelope),
|
|
316
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
228
317
|
});
|
|
229
318
|
if (response.ok) {
|
|
230
319
|
this.logger.debug(`envelope enviado (${envelope.items.length} itens)`);
|
|
@@ -234,13 +323,15 @@ var Transport = class {
|
|
|
234
323
|
this.logger.error(`envelope rejeitado (HTTP ${response.status}), descartado`);
|
|
235
324
|
return;
|
|
236
325
|
}
|
|
326
|
+
if (response.status === 429) serverDelay = retryAfterMs(response);
|
|
237
327
|
throw new Error(`HTTP ${response.status}`);
|
|
238
328
|
} catch (error) {
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
329
|
+
const base = RETRY_DELAYS_MS[attempt];
|
|
330
|
+
if (base === void 0) {
|
|
241
331
|
this.logger.error("envelope descartado ap\xF3s retries:", error);
|
|
242
332
|
return;
|
|
243
333
|
}
|
|
334
|
+
const delay = serverDelay ?? jitter(base);
|
|
244
335
|
this.logger.warn(`falha no envio (${String(error)}), retry em ${delay}ms`);
|
|
245
336
|
await sleep(delay);
|
|
246
337
|
}
|
|
@@ -270,22 +361,38 @@ function runtimeContexts() {
|
|
|
270
361
|
return { runtime: { name: "browser" } };
|
|
271
362
|
}
|
|
272
363
|
var Client = class {
|
|
273
|
-
options;
|
|
274
|
-
config;
|
|
275
364
|
logger;
|
|
365
|
+
// campos privados + getters de protótipo: o clientSecret não aparece em
|
|
366
|
+
// JSON.stringify/serialização enumerável do Client (ex.: um objeto capturado
|
|
367
|
+
// que referencie o client), mas client.options/config seguem funcionando
|
|
368
|
+
#options;
|
|
369
|
+
#config;
|
|
276
370
|
transport;
|
|
277
371
|
constructor(options) {
|
|
278
|
-
this
|
|
372
|
+
this.#options = options;
|
|
279
373
|
this.logger = makeLogger(!!options.debug);
|
|
280
|
-
this
|
|
374
|
+
this.#config = resolveConfig(options);
|
|
281
375
|
this.transport = new Transport({
|
|
282
|
-
endpoint: this
|
|
283
|
-
key: this
|
|
376
|
+
endpoint: this.#config.ingestEndpoint,
|
|
377
|
+
key: this.#config.key,
|
|
284
378
|
logger: this.logger,
|
|
285
379
|
flushIntervalMs: options.flushIntervalMs,
|
|
286
380
|
maxBatchSize: options.maxBatchSize
|
|
287
381
|
});
|
|
288
382
|
}
|
|
383
|
+
get options() {
|
|
384
|
+
return this.#options;
|
|
385
|
+
}
|
|
386
|
+
get config() {
|
|
387
|
+
return this.#config;
|
|
388
|
+
}
|
|
389
|
+
/** Serialização explícita nunca inclui o secret. */
|
|
390
|
+
toJSON() {
|
|
391
|
+
return { sdk: SDK_NAME, version: SDK_VERSION, baseUrl: this.#config.baseUrl };
|
|
392
|
+
}
|
|
393
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
394
|
+
return `Client { baseUrl: '${this.#config.baseUrl}' }`;
|
|
395
|
+
}
|
|
289
396
|
captureException(error, hint, scope2) {
|
|
290
397
|
return this.captureEvent(eventFromException(error, hint?.level ?? "error"), hint, scope2);
|
|
291
398
|
}
|
|
@@ -704,6 +811,8 @@ async function withMonitorImpl(client2, captureError, monitorSlug, fn, options)
|
|
|
704
811
|
|
|
705
812
|
// src/manager/api.ts
|
|
706
813
|
var RETRY_DELAYS_MS2 = [1e3, 4e3, 16e3];
|
|
814
|
+
var POLL_TIMEOUT_MS = 3e4;
|
|
815
|
+
var UPDATE_TIMEOUT_MS = 1e4;
|
|
707
816
|
var ManagerApiError = class extends Error {
|
|
708
817
|
constructor(message, status) {
|
|
709
818
|
super(message);
|
|
@@ -728,16 +837,39 @@ var ManagerApi = class {
|
|
|
728
837
|
}
|
|
729
838
|
/** Um request só — o loop de polling é quem decide o backoff entre tentativas. */
|
|
730
839
|
async poll(request, signal) {
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
840
|
+
const { signal: timeoutSignal, cleanup } = withTimeoutSignal(POLL_TIMEOUT_MS, signal);
|
|
841
|
+
let response;
|
|
842
|
+
try {
|
|
843
|
+
response = await fetch(`${this.baseUrl}/poll`, {
|
|
844
|
+
method: "POST",
|
|
845
|
+
headers: this.headers(),
|
|
846
|
+
body: JSON.stringify(request),
|
|
847
|
+
signal: timeoutSignal
|
|
848
|
+
});
|
|
849
|
+
} finally {
|
|
850
|
+
cleanup();
|
|
851
|
+
}
|
|
737
852
|
if (!response.ok) {
|
|
738
853
|
throw new ManagerApiError(`poll falhou (HTTP ${response.status})`, response.status);
|
|
739
854
|
}
|
|
740
|
-
return await response.json();
|
|
855
|
+
return this.parsePollResponse(await response.json(), request.max ?? 1);
|
|
856
|
+
}
|
|
857
|
+
/** Nunca confia no shape da resposta: runs malformadas são descartadas e o `max` é respeitado. */
|
|
858
|
+
parsePollResponse(body, max) {
|
|
859
|
+
const runs = body?.runs;
|
|
860
|
+
if (!Array.isArray(runs)) {
|
|
861
|
+
throw new ManagerApiError("resposta inv\xE1lida do poll (campo runs ausente)", 0);
|
|
862
|
+
}
|
|
863
|
+
const valid = [];
|
|
864
|
+
for (const run of runs.slice(0, Math.max(0, max))) {
|
|
865
|
+
if (typeof run?.id !== "string" || typeof run.task !== "string") continue;
|
|
866
|
+
const params = run.params && typeof run.params === "object" && !Array.isArray(run.params) ? run.params : {};
|
|
867
|
+
valid.push({ ...run, id: run.id, task: run.task, params });
|
|
868
|
+
}
|
|
869
|
+
if (valid.length < runs.length) {
|
|
870
|
+
this.logger.warn(`poll retornou ${runs.length - valid.length} run(s) inv\xE1lida(s)/excedente(s) \u2014 descartadas`);
|
|
871
|
+
}
|
|
872
|
+
return { runs: valid };
|
|
741
873
|
}
|
|
742
874
|
/**
|
|
743
875
|
* PATCH de status/logs com retry em falha de rede/5xx/429.
|
|
@@ -746,25 +878,29 @@ var ManagerApi = class {
|
|
|
746
878
|
async updateRun(runId, update) {
|
|
747
879
|
for (let attempt = 0; ; attempt++) {
|
|
748
880
|
let retriable;
|
|
881
|
+
let serverDelay;
|
|
749
882
|
try {
|
|
750
883
|
const response = await fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}`, {
|
|
751
884
|
method: "PATCH",
|
|
752
885
|
headers: this.headers(),
|
|
753
|
-
body: JSON.stringify(update)
|
|
886
|
+
body: JSON.stringify(update),
|
|
887
|
+
signal: AbortSignal.timeout(UPDATE_TIMEOUT_MS)
|
|
754
888
|
});
|
|
755
889
|
if (response.ok) return;
|
|
756
890
|
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
757
891
|
throw new ManagerApiError(`update rejeitado (HTTP ${response.status})`, response.status);
|
|
758
892
|
}
|
|
893
|
+
if (response.status === 429) serverDelay = retryAfterMs(response);
|
|
759
894
|
retriable = new Error(`HTTP ${response.status}`);
|
|
760
895
|
} catch (error) {
|
|
761
896
|
if (error instanceof ManagerApiError) throw error;
|
|
762
897
|
retriable = error;
|
|
763
898
|
}
|
|
764
|
-
const
|
|
765
|
-
if (
|
|
899
|
+
const base = RETRY_DELAYS_MS2[attempt];
|
|
900
|
+
if (base === void 0) {
|
|
766
901
|
throw new Error(`update da run ${runId} descartado ap\xF3s retries: ${String(retriable)}`);
|
|
767
902
|
}
|
|
903
|
+
const delay = serverDelay ?? jitter(base);
|
|
768
904
|
this.logger.warn(`falha no update da run ${runId} (${String(retriable)}), retry em ${delay}ms`);
|
|
769
905
|
await sleep(delay);
|
|
770
906
|
}
|
|
@@ -888,13 +1024,14 @@ var RunReporter = class {
|
|
|
888
1024
|
}
|
|
889
1025
|
log(level, message) {
|
|
890
1026
|
if (this.dead) return;
|
|
891
|
-
|
|
1027
|
+
const scrubbed = scrubSecrets(message);
|
|
1028
|
+
printRunLog(this.context.task, level, scrubbed);
|
|
892
1029
|
if (this.loggedCount >= MAX_LOGS_PER_RUN) {
|
|
893
1030
|
this.droppedCount++;
|
|
894
1031
|
return;
|
|
895
1032
|
}
|
|
896
1033
|
this.loggedCount++;
|
|
897
|
-
const truncated =
|
|
1034
|
+
const truncated = scrubbed.length > MAX_LOG_MESSAGE_CHARS ? `${scrubbed.slice(0, MAX_LOG_MESSAGE_CHARS)}\u2026 [truncado]` : scrubbed;
|
|
898
1035
|
this.buffer.push({ ts: nowISO(), level, message: truncated });
|
|
899
1036
|
if (this.buffer.length >= FLUSH_AT_BUFFERED) {
|
|
900
1037
|
this.flushLogs();
|
|
@@ -1078,8 +1215,8 @@ var ManagerAgent = class {
|
|
|
1078
1215
|
constructor(options, registry2) {
|
|
1079
1216
|
this.options = options;
|
|
1080
1217
|
this.registry = registry2;
|
|
1081
|
-
this.logger = makeLogger(options.debug ?? false, "[hobots
|
|
1082
|
-
const config = resolveConfig(options, "[hobots
|
|
1218
|
+
this.logger = makeLogger(options.debug ?? false, "[hobots]");
|
|
1219
|
+
const config = resolveConfig(options, "[hobots]");
|
|
1083
1220
|
this.api = new ManagerApi({ baseUrl: config.managerBaseUrl, key: config.key, logger: this.logger });
|
|
1084
1221
|
this.client = options.client;
|
|
1085
1222
|
this.pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
@@ -1113,10 +1250,10 @@ var ManagerAgent = class {
|
|
|
1113
1250
|
start() {
|
|
1114
1251
|
if (this.state === "started") return;
|
|
1115
1252
|
if (this.state === "stopping") {
|
|
1116
|
-
throw new Error("[hobots
|
|
1253
|
+
throw new Error("[hobots] start() chamado durante stop() \u2014 aguarde o stop terminar");
|
|
1117
1254
|
}
|
|
1118
1255
|
if (this.registry.size === 0) {
|
|
1119
|
-
throw new Error("[hobots
|
|
1256
|
+
throw new Error("[hobots] nenhuma task registrada \u2014 chame register() antes de start()");
|
|
1120
1257
|
}
|
|
1121
1258
|
this.state = "started";
|
|
1122
1259
|
if (this.options.installExitHandlers !== false && !this.uninstallShutdown) {
|
|
@@ -1198,6 +1335,7 @@ var ManagerAgent = class {
|
|
|
1198
1335
|
this.consecutiveFailures = 0;
|
|
1199
1336
|
this.consecutiveAuthFailures = 0;
|
|
1200
1337
|
for (const run of response.runs) {
|
|
1338
|
+
if (this.activeRuns.size >= this.concurrency) break;
|
|
1201
1339
|
this.dispatch(run);
|
|
1202
1340
|
}
|
|
1203
1341
|
this.schedule(response.runs.length > 0 ? 0 : this.pollIntervalMs);
|
|
@@ -1218,7 +1356,7 @@ var ManagerAgent = class {
|
|
|
1218
1356
|
}
|
|
1219
1357
|
this.consecutiveFailures++;
|
|
1220
1358
|
const ladder = POLL_RETRY_DELAYS_MS[Math.min(this.consecutiveFailures - 1, POLL_RETRY_DELAYS_MS.length - 1)];
|
|
1221
|
-
const delay = Math.min(Math.max(ladder, 0), Math.max(this.pollIntervalMs, 16e3));
|
|
1359
|
+
const delay = Math.min(Math.max(jitter(ladder), 0), Math.max(this.pollIntervalMs, 16e3));
|
|
1222
1360
|
this.logger.warn(`poll falhou (${String(error)}), pr\xF3xima tentativa em ${delay}ms`);
|
|
1223
1361
|
return delay;
|
|
1224
1362
|
}
|
|
@@ -1230,7 +1368,7 @@ var ManagerAgent = class {
|
|
|
1230
1368
|
this.activeRuns.add(promise);
|
|
1231
1369
|
}
|
|
1232
1370
|
async executeRun(run) {
|
|
1233
|
-
const tx = new Transaction(this.client, `run:${run.task}`, "
|
|
1371
|
+
const tx = new Transaction(this.client, `run:${run.task}`, "hobots.task", true, run.id);
|
|
1234
1372
|
const reporter = new RunReporter(this.api, run.id, run.task, this.logger, tx, this.logFlushIntervalMs, this.cancelCheckIntervalMs);
|
|
1235
1373
|
this.reporters.add(reporter);
|
|
1236
1374
|
try {
|
|
@@ -1296,11 +1434,11 @@ function toRunError(error) {
|
|
|
1296
1434
|
if (error instanceof Error) {
|
|
1297
1435
|
return {
|
|
1298
1436
|
type: error.name,
|
|
1299
|
-
message: truncate(error.message, MAX_ERROR_MESSAGE_CHARS),
|
|
1300
|
-
stack: error.stack ? truncate(error.stack, MAX_ERROR_STACK_CHARS) : void 0
|
|
1437
|
+
message: scrubSecrets(truncate(error.message, MAX_ERROR_MESSAGE_CHARS)),
|
|
1438
|
+
stack: error.stack ? scrubSecrets(truncate(error.stack, MAX_ERROR_STACK_CHARS)) : void 0
|
|
1301
1439
|
};
|
|
1302
1440
|
}
|
|
1303
|
-
return { message: truncate(String(error), MAX_ERROR_MESSAGE_CHARS) };
|
|
1441
|
+
return { message: scrubSecrets(truncate(String(error), MAX_ERROR_MESSAGE_CHARS)) };
|
|
1304
1442
|
}
|
|
1305
1443
|
|
|
1306
1444
|
// src/core.ts
|
|
@@ -1444,6 +1582,7 @@ export {
|
|
|
1444
1582
|
init,
|
|
1445
1583
|
register,
|
|
1446
1584
|
resolveConfig,
|
|
1585
|
+
scrubSecrets,
|
|
1447
1586
|
setContext,
|
|
1448
1587
|
setExtra,
|
|
1449
1588
|
setTag,
|