hobots 1.1.0 → 1.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 +23 -18
- package/dist/index.cjs +25 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -20
- package/dist/index.d.ts +25 -20
- package/dist/index.js +25 -29
- package/dist/index.js.map +1 -1
- package/docs/README.md +12 -6
- package/docs/api-reference.md +10 -10
- package/docs/getting-started.md +15 -11
- package/docs/manager.md +3 -2
- package/docs/monitor.md +3 -2
- package/docs/protocol.md +8 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Também funciona em CommonJS: `const Hobots = require('hobots')`.
|
|
|
26
26
|
|
|
27
27
|
## Um SDK, duas capabilities, um `init()`
|
|
28
28
|
|
|
29
|
-
O SDK expõe **duas capabilities** autenticadas
|
|
29
|
+
O SDK expõe **duas capabilities** autenticadas pelo **mesmo Client Secret do projeto**, configuradas em um único `init()`:
|
|
30
30
|
|
|
31
31
|
| Capability | Como habilita | Para quê | Ciclo de vida |
|
|
32
32
|
| --- | --- | --- | --- |
|
|
@@ -35,13 +35,14 @@ O SDK expõe **duas capabilities** autenticadas pela **mesma DSN única do proje
|
|
|
35
35
|
|
|
36
36
|
Você usa **uma, outra ou as duas**:
|
|
37
37
|
|
|
38
|
-
- Só saber se o robô quebrou, quanto demora e se está vivo? → `init({
|
|
39
|
-
- Disparar o robô sob demanda a partir de um formulário no app? → `init({
|
|
38
|
+
- Só saber se o robô quebrou, quanto demora e se está vivo? → `init({ clientSecret, heartbeat: true })`.
|
|
39
|
+
- Disparar o robô sob demanda a partir de um formulário no app? → `init({ clientSecret, manager: true })` + `register()` + `start()`.
|
|
40
40
|
- Ambos? Passe `heartbeat` e `manager` no mesmo `init()` — o `instanceId` é a identidade única, e os dois canais convergem em **um agente** no painel.
|
|
41
41
|
|
|
42
42
|
```js
|
|
43
43
|
Hobots.init({
|
|
44
|
-
|
|
44
|
+
clientSecret: 'hb_<64 hex>',
|
|
45
|
+
// baseUrl: 'http://localhost:3002', // só em desenvolvimento
|
|
45
46
|
instanceId: 'vm-cliente-01',
|
|
46
47
|
heartbeat: true, // Monitor: "estou vivo" a cada 30s
|
|
47
48
|
manager: { pollIntervalMs: 5_000 }, // Manager: execução sob demanda
|
|
@@ -57,15 +58,15 @@ Hobots.start(); // inicia o polling do Manager (segura o processo vivo)
|
|
|
57
58
|
|
|
58
59
|
---
|
|
59
60
|
|
|
60
|
-
## O
|
|
61
|
+
## O Client Secret
|
|
61
62
|
|
|
62
|
-
Cada projeto tem **
|
|
63
|
+
Cada projeto tem **um único Client Secret** — a mesma credencial autentica o Monitor **e** o Manager:
|
|
63
64
|
|
|
64
65
|
```
|
|
65
|
-
|
|
66
|
+
hb_<64 hex>
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
(Chaves antigas, 64 hex puros, continuam válidas no servidor.) A credencial é **secreta** e viaja sempre no header `Authorization: Bearer` — nunca na URL. Copie o Client Secret no app, em **Configurações → Projetos** — os snippets de integração já vêm prontos. O SDK fala com `https://app.hobots.app` por padrão; só sobrescreva `baseUrl` em desenvolvimento (ex.: `http://localhost:3002`).
|
|
69
70
|
|
|
70
71
|
---
|
|
71
72
|
|
|
@@ -79,7 +80,8 @@ Inicialize **uma vez**, o mais cedo possível no processo. Cria o cliente, insta
|
|
|
79
80
|
|
|
80
81
|
```js
|
|
81
82
|
Hobots.init({
|
|
82
|
-
|
|
83
|
+
clientSecret: 'hb_<64 hex>',
|
|
84
|
+
// baseUrl: 'http://localhost:3002', // só em desenvolvimento
|
|
83
85
|
environment: 'production',
|
|
84
86
|
release: 'robo-nfe@1.4.2',
|
|
85
87
|
instanceId: 'vm-cliente-01',
|
|
@@ -90,7 +92,8 @@ Hobots.init({
|
|
|
90
92
|
|
|
91
93
|
| Opção | Tipo | Default | Descrição |
|
|
92
94
|
| --- | --- | --- | --- |
|
|
93
|
-
| `
|
|
95
|
+
| `clientSecret` | `string` | **obrigatório** | o Client Secret do projeto (`hb_<64 hex>`), copiado em **Configurações → Projetos** |
|
|
96
|
+
| `baseUrl` | `string` | `'https://app.hobots.app'` | host do app da Hobots — só sobrescreva em desenvolvimento (ex.: `http://localhost:3002`) |
|
|
94
97
|
| `environment` | `string` | `'production'` | ambiente lógico |
|
|
95
98
|
| `release` | `string` | — | versão do programa, ex. `robo-nfe@1.4.2` |
|
|
96
99
|
| `instanceId` | `string` | **obrigatório** | identidade única da instância — heartbeat do Monitor e agente do Manager convergem nela |
|
|
@@ -203,7 +206,7 @@ Bate "estou vivo" periodicamente; o servidor acusa o robô **offline** quando os
|
|
|
203
206
|
|
|
204
207
|
```js
|
|
205
208
|
Hobots.init({
|
|
206
|
-
|
|
209
|
+
clientSecret,
|
|
207
210
|
heartbeat: { intervalMs: 30_000, name: 'Robô NFe — VM 01' },
|
|
208
211
|
});
|
|
209
212
|
```
|
|
@@ -223,13 +226,14 @@ Chame `close` antes do processo sair. Os timers do Monitor são `unref`'d — el
|
|
|
223
226
|
|
|
224
227
|
## Manager
|
|
225
228
|
|
|
226
|
-
Capability de **execução remota sob demanda**, habilitada com `manager: true` (ou opções) no `init()`. O agente faz polling no app, executa os handlers registrados quando aparece trabalho e reporta status e logs incrementais.
|
|
229
|
+
Capability de **execução remota sob demanda**, habilitada com `manager: true` (ou opções) no `init()`. O agente faz polling no app, executa os handlers registrados quando aparece trabalho e reporta status e logs incrementais. Mesmo Client Secret, mesmo `debug` e o `instanceId` como identidade — nenhum handler global extra é instalado.
|
|
227
230
|
|
|
228
231
|
### Ciclo de vida
|
|
229
232
|
|
|
230
233
|
```js
|
|
231
234
|
Hobots.init({
|
|
232
|
-
|
|
235
|
+
clientSecret: 'hb_<64 hex>',
|
|
236
|
+
// baseUrl: 'http://localhost:3002', // só em desenvolvimento
|
|
233
237
|
instanceId: 'vm-cliente-01',
|
|
234
238
|
manager: true, // ou { pollIntervalMs, concurrency, ... }
|
|
235
239
|
});
|
|
@@ -260,7 +264,7 @@ process.on('SIGINT', () => {
|
|
|
260
264
|
| `taskTimeoutMs` | `number` | — | timeout client-side por run (não mata o handler; servidor é o backstop) |
|
|
261
265
|
| `logFlushIntervalMs` | `number` | `2000` | intervalo do envio incremental de logs |
|
|
262
266
|
|
|
263
|
-
|
|
267
|
+
O Client Secret, o `debug` e a identidade do agente (`instanceId`) vêm do `init()` — o heartbeat do Monitor e o agente do Manager convergem em **um agente** no painel automaticamente.
|
|
264
268
|
|
|
265
269
|
### O handler e o `RunContext`
|
|
266
270
|
|
|
@@ -354,7 +358,7 @@ A 2.0 unifica o Manager no import raiz — `hobots/manager` **foi removido**:
|
|
|
354
358
|
|
|
355
359
|
-Monitor.init({ dsn, serverName: 'vm-01', heartbeat: true });
|
|
356
360
|
-Manager.init({ dsn, agentName: 'vm-01' });
|
|
357
|
-
+Hobots.init({
|
|
361
|
+
+Hobots.init({ clientSecret, instanceId: 'vm-01', heartbeat: true, manager: true });
|
|
358
362
|
|
|
359
363
|
-Manager.register('minha-task', handler);
|
|
360
364
|
-Manager.start();
|
|
@@ -366,8 +370,9 @@ A 2.0 unifica o Manager no import raiz — `hobots/manager` **foi removido**:
|
|
|
366
370
|
+await Hobots.close(15_000);
|
|
367
371
|
```
|
|
368
372
|
|
|
373
|
+
- A `dsn` (mecanismo antigo, `https://<secretKey>@host/<slug>`) não existe mais — passe `clientSecret` (e `baseUrl` só em desenvolvimento). Copie o Client Secret em **Configurações → Projetos**.
|
|
369
374
|
- `agentName` e `serverName` não existem mais — a identidade do agente é o `instanceId` (obrigatório, sem fallback).
|
|
370
|
-
- As opções do Manager (`pollIntervalMs`, `concurrency`, `taskTimeoutMs`, `logFlushIntervalMs`) vão no campo `manager` do `init()`; `
|
|
375
|
+
- As opções do Manager (`pollIntervalMs`, `concurrency`, `taskTimeoutMs`, `logFlushIntervalMs`) vão no campo `manager` do `init()`; `clientSecret` e `debug` não se repetem.
|
|
371
376
|
- Tipos (`ManagerTaskHandler`, `RunContext`, `ManagerOptions`) e classes (`ManagerAgent`, `ManagerApi`) agora vêm de `hobots`; o wire format vem de `hobots/protocol`.
|
|
372
377
|
|
|
373
378
|
---
|
|
@@ -376,11 +381,11 @@ A 2.0 unifica o Manager no import raiz — `hobots/manager` **foi removido**:
|
|
|
376
381
|
|
|
377
382
|
Guias detalhados acompanham o pacote em [`docs/`](./docs/README.md):
|
|
378
383
|
|
|
379
|
-
- [Getting started](./docs/getting-started.md) — instalação,
|
|
384
|
+
- [Getting started](./docs/getting-started.md) — instalação, Client Secret, primeiro `init`, Monitor vs Hobots.
|
|
380
385
|
- [Monitor](./docs/monitor.md) — erros, breadcrumbs, escopo, transactions/spans, crons, heartbeat.
|
|
381
386
|
- [Manager](./docs/manager.md) — handlers, `RunContext`, cancelamento, concorrência, idempotência.
|
|
382
387
|
- [Referência de API](./docs/api-reference.md) — todas as funções e tabelas de opções com defaults.
|
|
383
|
-
- [Protocolo & transporte](./docs/protocol.md) —
|
|
388
|
+
- [Protocolo & transporte](./docs/protocol.md) — o Client Secret, endpoints, envelope, retries.
|
|
384
389
|
|
|
385
390
|
---
|
|
386
391
|
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
Client: () => Client,
|
|
24
|
+
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
24
25
|
ManagerAgent: () => ManagerAgent,
|
|
25
26
|
ManagerApi: () => ManagerApi,
|
|
26
27
|
ManagerApiError: () => ManagerApiError,
|
|
@@ -35,8 +36,8 @@ __export(src_exports, {
|
|
|
35
36
|
flush: () => flush,
|
|
36
37
|
getClient: () => getClient,
|
|
37
38
|
init: () => init,
|
|
38
|
-
parseDsn: () => parseDsn,
|
|
39
39
|
register: () => register,
|
|
40
|
+
resolveConfig: () => resolveConfig,
|
|
40
41
|
setContext: () => setContext,
|
|
41
42
|
setExtra: () => setExtra,
|
|
42
43
|
setTag: () => setTag,
|
|
@@ -50,29 +51,24 @@ __export(src_exports, {
|
|
|
50
51
|
});
|
|
51
52
|
module.exports = __toCommonJS(src_exports);
|
|
52
53
|
|
|
53
|
-
// src/
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// src/config.ts
|
|
55
|
+
var DEFAULT_BASE_URL = "https://app.hobots.app";
|
|
56
|
+
function resolveConfig(options, prefix = "[hobots]") {
|
|
57
|
+
const key = options.clientSecret?.trim();
|
|
58
|
+
if (!key) {
|
|
59
|
+
throw new Error(`${prefix} clientSecret ausente \u2014 copie o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos`);
|
|
60
|
+
}
|
|
61
|
+
const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
56
62
|
try {
|
|
57
|
-
|
|
63
|
+
new URL(baseUrl);
|
|
58
64
|
} catch {
|
|
59
|
-
throw new Error(`${prefix}
|
|
65
|
+
throw new Error(`${prefix} baseUrl inv\xE1lida: "${baseUrl}" \u2014 esperado ex.: https://app.hobots.app`);
|
|
60
66
|
}
|
|
61
|
-
const key = url.username;
|
|
62
|
-
const path = url.pathname.replace(/^\/+/, "");
|
|
63
|
-
if (!key || !path) {
|
|
64
|
-
throw new Error(`${prefix} DSN inv\xE1lido: "${dsn}" \u2014 esperado https://<key>@host/<projeto>`);
|
|
65
|
-
}
|
|
66
|
-
return { key, path, origin: `${url.protocol}//${url.host}` };
|
|
67
|
-
}
|
|
68
|
-
function parseDsn(dsn) {
|
|
69
|
-
const { key, path, origin } = parseDsnUrl(dsn, "[hobots]");
|
|
70
67
|
return {
|
|
71
68
|
key,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
managerBaseUrl: `${origin}/api/manager`
|
|
69
|
+
baseUrl,
|
|
70
|
+
ingestEndpoint: `${baseUrl}/api/ingest`,
|
|
71
|
+
managerBaseUrl: `${baseUrl}/api/manager`
|
|
76
72
|
};
|
|
77
73
|
}
|
|
78
74
|
|
|
@@ -308,16 +304,16 @@ function runtimeContexts() {
|
|
|
308
304
|
}
|
|
309
305
|
var Client = class {
|
|
310
306
|
options;
|
|
311
|
-
|
|
307
|
+
config;
|
|
312
308
|
logger;
|
|
313
309
|
transport;
|
|
314
310
|
constructor(options) {
|
|
315
311
|
this.options = options;
|
|
316
312
|
this.logger = makeLogger(!!options.debug);
|
|
317
|
-
this.
|
|
313
|
+
this.config = resolveConfig(options);
|
|
318
314
|
this.transport = new Transport({
|
|
319
|
-
endpoint: this.
|
|
320
|
-
key: this.
|
|
315
|
+
endpoint: this.config.ingestEndpoint,
|
|
316
|
+
key: this.config.key,
|
|
321
317
|
logger: this.logger,
|
|
322
318
|
flushIntervalMs: options.flushIntervalMs,
|
|
323
319
|
maxBatchSize: options.maxBatchSize
|
|
@@ -891,14 +887,14 @@ var ManagerAgent = class {
|
|
|
891
887
|
this.options = options;
|
|
892
888
|
this.registry = registry2;
|
|
893
889
|
this.logger = makeLogger(options.debug ?? false, "[hobots-manager]");
|
|
894
|
-
const
|
|
895
|
-
this.api = new ManagerApi({ baseUrl:
|
|
890
|
+
const config = resolveConfig(options, "[hobots-manager]");
|
|
891
|
+
this.api = new ManagerApi({ baseUrl: config.managerBaseUrl, key: config.key, logger: this.logger });
|
|
896
892
|
this.pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
897
893
|
this.concurrency = Math.min(MAX_CONCURRENCY, Math.max(1, options.concurrency ?? 1));
|
|
898
894
|
this.instanceId = options.instanceId;
|
|
899
895
|
this.taskTimeoutMs = options.taskTimeoutMs;
|
|
900
896
|
this.logFlushIntervalMs = options.logFlushIntervalMs;
|
|
901
|
-
this.logger.debug("agente configurado", { baseUrl:
|
|
897
|
+
this.logger.debug("agente configurado", { baseUrl: config.managerBaseUrl });
|
|
902
898
|
}
|
|
903
899
|
logger;
|
|
904
900
|
api;
|
|
@@ -995,7 +991,7 @@ var ManagerAgent = class {
|
|
|
995
991
|
if (error instanceof ManagerApiError && error.status === 401) {
|
|
996
992
|
this.consecutiveAuthFailures++;
|
|
997
993
|
if (this.consecutiveAuthFailures === 1 || this.consecutiveAuthFailures % 10 === 0) {
|
|
998
|
-
this.logger.error("chave rejeitada (401) \u2014 verifique
|
|
994
|
+
this.logger.error("chave rejeitada (401) \u2014 verifique o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos");
|
|
999
995
|
}
|
|
1000
996
|
return Math.max(this.pollIntervalMs, AUTH_FAILURE_INTERVAL_MS);
|
|
1001
997
|
}
|
|
@@ -1109,11 +1105,11 @@ function init(options) {
|
|
|
1109
1105
|
if (options.manager) {
|
|
1110
1106
|
const managerOptions = options.manager === true ? {} : options.manager;
|
|
1111
1107
|
agent = new ManagerAgent(
|
|
1112
|
-
{ ...managerOptions,
|
|
1108
|
+
{ ...managerOptions, clientSecret: options.clientSecret, baseUrl: options.baseUrl, instanceId: options.instanceId, debug: options.debug },
|
|
1113
1109
|
registry
|
|
1114
1110
|
);
|
|
1115
1111
|
}
|
|
1116
|
-
client.logger.debug("inicializado", { endpoint: client.
|
|
1112
|
+
client.logger.debug("inicializado", { endpoint: client.config.ingestEndpoint });
|
|
1117
1113
|
}
|
|
1118
1114
|
function getClient() {
|
|
1119
1115
|
return client;
|