hobots 4.0.0 → 4.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 +33 -1
- package/dist/{chunk-5WIIACWC.js → chunk-HKCDMUA3.js} +1 -2
- package/dist/chunk-HKCDMUA3.js.map +1 -0
- package/dist/index.cjs +438 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -3
- package/dist/index.d.ts +64 -3
- package/dist/index.js +439 -31
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs +0 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +39 -3
- package/dist/protocol.d.ts +39 -3
- package/dist/protocol.js +1 -1
- package/docs/api-reference.md +4 -1
- package/docs/protocol.md +12 -2
- package/docs/runs.md +60 -2
- package/package.json +1 -1
- package/dist/chunk-5WIIACWC.js.map +0 -1
package/dist/protocol.cjs
CHANGED
package/dist/protocol.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol.ts","../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida\n * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)\n * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único\n * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.\n */\n\nexport { WIRE_LIMITS, type WireLimits } from './wire-limits';\n\nimport type { EnvironmentInput } from './environment-protocol';\nimport type { MachineSnapshot } from './machine-protocol';\n\n// Wire format de execuções (agente ↔ servidor) — reexportado aqui para o app\n// consumir tudo de `hobots/protocol`.\nexport type {\n RunStatus,\n RunUpdateStatus,\n RunLogLevel,\n RunLogEntry,\n InstanceInfo,\n PollRequest,\n RunDescriptor,\n PollResponse,\n RunCreateRequest,\n RunCreateResponse,\n RunError,\n RunProgress,\n RunUpdateRequest,\n RunUpdateResponse,\n RunItemStatus,\n RunItemInput,\n RunItemsCreateRequest,\n RunItemsCreateResponse,\n ItemColumn,\n ItemsDeclaration,\n InstanceMode,\n RunAttachmentContentType,\n RunAttachmentCreateRequest,\n RunAttachmentCreateResponse,\n RunAttachmentConfirmRequest,\n RunAttachmentConfirmResponse,\n} from './tasks/protocol';\n\n// Snapshot de recursos da máquina — usado no heartbeat, no poll e em contexts.machine.\nexport type { MachineProcess, MachineSnapshot } from './machine-protocol';\nexport type { Environment, EnvironmentInput } from './environment-protocol';\n\n/**\n * Tipo de um evento — o que ele é, não o quanto ele fala. Só 'fatal', 'error' e\n * 'warning' viram issue; 'success' é ingerido e nunca abre issue.\n * Ruído de log não é evento: para isso existem os logs da execução (RunLogLevel)\n * e as breadcrumbs, que têm níveis próprios com 'debug'/'info'.\n */\nexport type EventType = 'fatal' | 'error' | 'warning' | 'success';\n\n/** Nível de uma breadcrumb — trilha do que aconteceu antes, aqui log é bem-vindo. */\nexport type BreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error' | 'fatal';\n\n/** Frames em ordem innermost-first (mesma ordem impressa pelo V8). */\nexport interface StackFrame {\n function?: string;\n filename?: string;\n lineno?: number;\n colno?: number;\n in_app: boolean;\n}\n\nexport interface Breadcrumb {\n /** ISO 8601 */\n timestamp: string;\n type?: string;\n category?: string;\n message?: string;\n level?: BreadcrumbLevel;\n data?: Record<string, unknown>;\n}\n\nexport interface ExceptionData {\n type: string;\n value: string;\n stacktrace?: { frames: StackFrame[] };\n}\n\nexport interface EventUser {\n id?: string;\n username?: string;\n email?: string;\n}\n\nexport interface EventPayload {\n /** uuid v4 sem hífens (32 hex), gerado pelo SDK */\n event_id: string;\n /** ISO 8601 */\n timestamp: string;\n type: EventType;\n message?: string;\n exception?: ExceptionData;\n /** Override de agrupamento; quando ausente o servidor calcula pelo stack trace */\n fingerprint?: string[];\n breadcrumbs?: Breadcrumb[];\n tags?: Record<string, string>;\n user?: EventUser;\n contexts?: Record<string, Record<string, unknown>>;\n extra?: Record<string, unknown>;\n release?: string;\n environment?: EnvironmentInput;\n}\n\n/** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */\nexport type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled';\n\nexport interface StepData {\n /** 16 hex */\n step_id: string;\n parent_step_id?: string;\n op?: string;\n description?: string;\n status?: StepStatus;\n /** ISO 8601 */\n start_timestamp: string;\n /** ISO 8601 (fim da step) */\n timestamp: string;\n data?: Record<string, unknown>;\n}\n\nexport interface TransactionPayload {\n event_id: string;\n name: string;\n op?: string;\n status: string;\n start_timestamp: string;\n timestamp: string;\n steps: StepData[];\n tags?: Record<string, string>;\n release?: string;\n environment?: EnvironmentInput;\n /** Correlaciona esta transaction a uma execução do agente (hobots.transaction dentro do handler) */\n run_id?: string;\n}\n\nexport interface HeartbeatPayload {\n instance_id: string;\n name?: string;\n interval_ms: number;\n /** ISO 8601 */\n timestamp: string;\n metadata?: Record<string, unknown>;\n release?: string;\n /** Ambiente da instância — é ele que o app exibe e que as regras de alerta filtram */\n environment?: EnvironmentInput;\n /** Recursos da máquina no momento do beat (CPU, memória, disco, processo) */\n machine?: MachineSnapshot;\n}\n\nexport type EnvelopeItem =\n | { type: 'event'; payload: EventPayload }\n | { type: 'transaction'; payload: TransactionPayload }\n | { type: 'heartbeat'; payload: HeartbeatPayload };\n\nexport interface Envelope {\n sdk: { name: string; version: string };\n /** ISO 8601 */\n sent_at: string;\n items: EnvelopeItem[];\n}\n","{\n \"MAX_ITEMS_PER_ENVELOPE\": 50,\n \"HEARTBEAT_DEFAULT_INTERVAL_MS\": 30000,\n \"HEARTBEAT_MIN_INTERVAL_MS\": 1000,\n \"HEARTBEAT_MAX_INTERVAL_MS\": 900000,\n \"MAX_CLAIM_PER_POLL\": 5,\n \"MAX_LOG_MESSAGE_CHARS\": 10000,\n \"MAX_LOGS_PER_PATCH\": 100,\n \"MAX_ERROR_MESSAGE_CHARS\": 10000,\n \"MAX_ERROR_STACK_CHARS\": 20000,\n \"
|
|
1
|
+
{"version":3,"sources":["../src/protocol.ts","../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida\n * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)\n * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único\n * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.\n */\n\nexport { WIRE_LIMITS, type WireLimits } from './wire-limits';\n\nimport type { EnvironmentInput } from './environment-protocol';\nimport type { MachineSnapshot } from './machine-protocol';\n\n// Wire format de execuções (agente ↔ servidor) — reexportado aqui para o app\n// consumir tudo de `hobots/protocol`.\nexport type {\n RunStatus,\n RunUpdateStatus,\n RunLogLevel,\n RunLogEntry,\n InstanceInfo,\n PollRequest,\n RunDescriptor,\n PollResponse,\n RunCreateRequest,\n RunCreateResponse,\n RunError,\n RunProgress,\n RunUpdateRequest,\n RunUpdateResponse,\n RunItemStatus,\n RunItemInput,\n RunItemsCreateRequest,\n RunItemsCreateResponse,\n ItemColumn,\n ItemsDeclaration,\n InstanceMode,\n RunAttachmentContentType,\n RunAttachmentCreateRequest,\n RunAttachmentCreateResponse,\n RunAttachmentConfirmRequest,\n RunAttachmentConfirmResponse,\n FileStorage,\n FileRef,\n FileDownloadResponse,\n} from './tasks/protocol';\n\n// Snapshot de recursos da máquina — usado no heartbeat, no poll e em contexts.machine.\nexport type { MachineProcess, MachineSnapshot } from './machine-protocol';\nexport type { Environment, EnvironmentInput } from './environment-protocol';\n\n/**\n * Tipo de um evento — o que ele é, não o quanto ele fala. Só 'fatal', 'error' e\n * 'warning' viram issue; 'success' é ingerido e nunca abre issue.\n * Ruído de log não é evento: para isso existem os logs da execução (RunLogLevel)\n * e as breadcrumbs, que têm níveis próprios com 'debug'/'info'.\n */\nexport type EventType = 'fatal' | 'error' | 'warning' | 'success';\n\n/** Nível de uma breadcrumb — trilha do que aconteceu antes, aqui log é bem-vindo. */\nexport type BreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error' | 'fatal';\n\n/** Frames em ordem innermost-first (mesma ordem impressa pelo V8). */\nexport interface StackFrame {\n function?: string;\n filename?: string;\n lineno?: number;\n colno?: number;\n in_app: boolean;\n}\n\nexport interface Breadcrumb {\n /** ISO 8601 */\n timestamp: string;\n type?: string;\n category?: string;\n message?: string;\n level?: BreadcrumbLevel;\n data?: Record<string, unknown>;\n}\n\nexport interface ExceptionData {\n type: string;\n value: string;\n stacktrace?: { frames: StackFrame[] };\n}\n\nexport interface EventUser {\n id?: string;\n username?: string;\n email?: string;\n}\n\nexport interface EventPayload {\n /** uuid v4 sem hífens (32 hex), gerado pelo SDK */\n event_id: string;\n /** ISO 8601 */\n timestamp: string;\n type: EventType;\n message?: string;\n exception?: ExceptionData;\n /** Override de agrupamento; quando ausente o servidor calcula pelo stack trace */\n fingerprint?: string[];\n breadcrumbs?: Breadcrumb[];\n tags?: Record<string, string>;\n user?: EventUser;\n contexts?: Record<string, Record<string, unknown>>;\n extra?: Record<string, unknown>;\n release?: string;\n environment?: EnvironmentInput;\n}\n\n/** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */\nexport type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled';\n\nexport interface StepData {\n /** 16 hex */\n step_id: string;\n parent_step_id?: string;\n op?: string;\n description?: string;\n status?: StepStatus;\n /** ISO 8601 */\n start_timestamp: string;\n /** ISO 8601 (fim da step) */\n timestamp: string;\n data?: Record<string, unknown>;\n}\n\nexport interface TransactionPayload {\n event_id: string;\n name: string;\n op?: string;\n status: string;\n start_timestamp: string;\n timestamp: string;\n steps: StepData[];\n tags?: Record<string, string>;\n release?: string;\n environment?: EnvironmentInput;\n /** Correlaciona esta transaction a uma execução do agente (hobots.transaction dentro do handler) */\n run_id?: string;\n}\n\nexport interface HeartbeatPayload {\n instance_id: string;\n name?: string;\n interval_ms: number;\n /** ISO 8601 */\n timestamp: string;\n metadata?: Record<string, unknown>;\n release?: string;\n /** Ambiente da instância — é ele que o app exibe e que as regras de alerta filtram */\n environment?: EnvironmentInput;\n /** Recursos da máquina no momento do beat (CPU, memória, disco, processo) */\n machine?: MachineSnapshot;\n}\n\nexport type EnvelopeItem =\n | { type: 'event'; payload: EventPayload }\n | { type: 'transaction'; payload: TransactionPayload }\n | { type: 'heartbeat'; payload: HeartbeatPayload };\n\nexport interface Envelope {\n sdk: { name: string; version: string };\n /** ISO 8601 */\n sent_at: string;\n items: EnvelopeItem[];\n}\n","{\n \"MAX_ITEMS_PER_ENVELOPE\": 50,\n \"HEARTBEAT_DEFAULT_INTERVAL_MS\": 30000,\n \"HEARTBEAT_MIN_INTERVAL_MS\": 1000,\n \"HEARTBEAT_MAX_INTERVAL_MS\": 900000,\n \"MAX_CLAIM_PER_POLL\": 5,\n \"MAX_LOG_MESSAGE_CHARS\": 10000,\n \"MAX_LOGS_PER_PATCH\": 100,\n \"MAX_ERROR_MESSAGE_CHARS\": 10000,\n \"MAX_ERROR_STACK_CHARS\": 20000,\n \"MAX_ITEMS_PER_REQUEST\": 500,\n \"MAX_ITEM_MESSAGE_CHARS\": 2000,\n \"MAX_ITEM_PAYLOAD_BYTES\": 16384,\n \"MAX_ITEM_COLUMNS\": 12,\n \"MAX_ITEM_COLUMN_LABEL_CHARS\": 60,\n \"MAX_ATTACHMENT_BYTES\": 5242880,\n \"MAX_ATTACHMENTS_PER_RUN\": 20,\n \"MAX_ATTACHMENTS_PER_LOG_ENTRY\": 4,\n \"MAX_CAPTION_CHARS\": 200,\n \"MAX_IMAGE_DIMENSION_PX\": 20000\n}\n","import limits from '../protocol-limits.json';\n\n/**\n * Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK\n * Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python\n * confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o\n * JSON (e, no Python, a constante espelhada — o teste acusa).\n */\nexport const WIRE_LIMITS = limits as Readonly<typeof limits>;\nexport type WireLimits = typeof WIRE_LIMITS;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA,EACE,wBAA0B;AAAA,EAC1B,+BAAiC;AAAA,EACjC,2BAA6B;AAAA,EAC7B,2BAA6B;AAAA,EAC7B,oBAAsB;AAAA,EACtB,uBAAyB;AAAA,EACzB,oBAAsB;AAAA,EACtB,yBAA2B;AAAA,EAC3B,uBAAyB;AAAA,EACzB,uBAAyB;AAAA,EACzB,wBAA0B;AAAA,EAC1B,wBAA0B;AAAA,EAC1B,kBAAoB;AAAA,EACpB,6BAA+B;AAAA,EAC/B,sBAAwB;AAAA,EACxB,yBAA2B;AAAA,EAC3B,+BAAiC;AAAA,EACjC,mBAAqB;AAAA,EACrB,wBAA0B;AAC5B;;;ACZO,IAAM,cAAc;","names":[]}
|
package/dist/protocol.d.cts
CHANGED
|
@@ -263,6 +263,44 @@ interface RunAttachmentConfirmRequest {
|
|
|
263
263
|
interface RunAttachmentConfirmResponse {
|
|
264
264
|
ok: true;
|
|
265
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Onde o arquivo de um campo de upload está guardado:
|
|
268
|
+
* - 's3': enviado pela Central — objeto temporário no S3; o bot baixa por URL
|
|
269
|
+
* pré-assinada e confirma (DELETE), e o servidor apaga o objeto na hora.
|
|
270
|
+
* - 'local': escolhido no Studio, no MESMO computador do bot — fica em
|
|
271
|
+
* `$HOBOTS_LOCAL_FILES_DIR/<id>/<nome>` e nunca vai para a nuvem.
|
|
272
|
+
*/
|
|
273
|
+
type FileStorage = 's3' | 'local';
|
|
274
|
+
/**
|
|
275
|
+
* Valor de um campo de upload nos params da run (campo único) — ou um array deles
|
|
276
|
+
* (campo "vários arquivos"). Mesma forma do `FileRef` de `@workspace/task-forms`.
|
|
277
|
+
*/
|
|
278
|
+
interface FileRef {
|
|
279
|
+
/** id do arquivo na run (no storage 'local', um uuid — nome da pasta em HOBOTS_LOCAL_FILES_DIR) */
|
|
280
|
+
id: string;
|
|
281
|
+
/** nome original, como o usuário enviou */
|
|
282
|
+
name: string;
|
|
283
|
+
/** tamanho em bytes */
|
|
284
|
+
size: number;
|
|
285
|
+
contentType: string;
|
|
286
|
+
storage: FileStorage;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* POST /v1/runs/{id}/files/{fileId}/download (corpo vazio) — 200 com a URL pré-assinada
|
|
290
|
+
* de GET; 404 = arquivo não existe nesta run; 410 = já baixado (confirmado) ou expirado.
|
|
291
|
+
* Depois do GET completo o agente confirma com DELETE /v1/runs/{id}/files/{fileId}
|
|
292
|
+
* (204, idempotente), e o servidor apaga o objeto do S3.
|
|
293
|
+
*/
|
|
294
|
+
interface FileDownloadResponse {
|
|
295
|
+
/** URL pré-assinada de GET direto no S3 (não envie Authorization nesta requisição) */
|
|
296
|
+
url: string;
|
|
297
|
+
/** Validade da URL, em segundos */
|
|
298
|
+
expires_in: number;
|
|
299
|
+
name: string;
|
|
300
|
+
/** tamanho exato em bytes — o SDK confere o download contra ele */
|
|
301
|
+
size: number;
|
|
302
|
+
content_type: string;
|
|
303
|
+
}
|
|
266
304
|
|
|
267
305
|
var MAX_ITEMS_PER_ENVELOPE = 50;
|
|
268
306
|
var HEARTBEAT_DEFAULT_INTERVAL_MS = 30000;
|
|
@@ -273,7 +311,6 @@ var MAX_LOG_MESSAGE_CHARS = 10000;
|
|
|
273
311
|
var MAX_LOGS_PER_PATCH = 100;
|
|
274
312
|
var MAX_ERROR_MESSAGE_CHARS = 10000;
|
|
275
313
|
var MAX_ERROR_STACK_CHARS = 20000;
|
|
276
|
-
var MAX_ITEMS_PER_RUN = 10000;
|
|
277
314
|
var MAX_ITEMS_PER_REQUEST = 500;
|
|
278
315
|
var MAX_ITEM_MESSAGE_CHARS = 2000;
|
|
279
316
|
var MAX_ITEM_PAYLOAD_BYTES = 16384;
|
|
@@ -294,7 +331,6 @@ var limits = {
|
|
|
294
331
|
MAX_LOGS_PER_PATCH: MAX_LOGS_PER_PATCH,
|
|
295
332
|
MAX_ERROR_MESSAGE_CHARS: MAX_ERROR_MESSAGE_CHARS,
|
|
296
333
|
MAX_ERROR_STACK_CHARS: MAX_ERROR_STACK_CHARS,
|
|
297
|
-
MAX_ITEMS_PER_RUN: MAX_ITEMS_PER_RUN,
|
|
298
334
|
MAX_ITEMS_PER_REQUEST: MAX_ITEMS_PER_REQUEST,
|
|
299
335
|
MAX_ITEM_MESSAGE_CHARS: MAX_ITEM_MESSAGE_CHARS,
|
|
300
336
|
MAX_ITEM_PAYLOAD_BYTES: MAX_ITEM_PAYLOAD_BYTES,
|
|
@@ -443,4 +479,4 @@ interface Envelope {
|
|
|
443
479
|
items: EnvelopeItem[];
|
|
444
480
|
}
|
|
445
481
|
|
|
446
|
-
export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type HeartbeatPayload, type InstanceInfo, type InstanceMode, type ItemColumn, type ItemsDeclaration, type MachineProcess, type MachineSnapshot, type PollRequest, type PollResponse, type RunAttachmentConfirmRequest, type RunAttachmentConfirmResponse, type RunAttachmentContentType, type RunAttachmentCreateRequest, type RunAttachmentCreateResponse, type RunCreateRequest, type RunCreateResponse, type RunDescriptor, type RunError, type RunItemInput, type RunItemStatus, type RunItemsCreateRequest, type RunItemsCreateResponse, type RunLogEntry, type RunLogLevel, type RunProgress, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
|
482
|
+
export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type FileDownloadResponse, type FileRef, type FileStorage, type HeartbeatPayload, type InstanceInfo, type InstanceMode, type ItemColumn, type ItemsDeclaration, type MachineProcess, type MachineSnapshot, type PollRequest, type PollResponse, type RunAttachmentConfirmRequest, type RunAttachmentConfirmResponse, type RunAttachmentContentType, type RunAttachmentCreateRequest, type RunAttachmentCreateResponse, type RunCreateRequest, type RunCreateResponse, type RunDescriptor, type RunError, type RunItemInput, type RunItemStatus, type RunItemsCreateRequest, type RunItemsCreateResponse, type RunLogEntry, type RunLogLevel, type RunProgress, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
package/dist/protocol.d.ts
CHANGED
|
@@ -263,6 +263,44 @@ interface RunAttachmentConfirmRequest {
|
|
|
263
263
|
interface RunAttachmentConfirmResponse {
|
|
264
264
|
ok: true;
|
|
265
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Onde o arquivo de um campo de upload está guardado:
|
|
268
|
+
* - 's3': enviado pela Central — objeto temporário no S3; o bot baixa por URL
|
|
269
|
+
* pré-assinada e confirma (DELETE), e o servidor apaga o objeto na hora.
|
|
270
|
+
* - 'local': escolhido no Studio, no MESMO computador do bot — fica em
|
|
271
|
+
* `$HOBOTS_LOCAL_FILES_DIR/<id>/<nome>` e nunca vai para a nuvem.
|
|
272
|
+
*/
|
|
273
|
+
type FileStorage = 's3' | 'local';
|
|
274
|
+
/**
|
|
275
|
+
* Valor de um campo de upload nos params da run (campo único) — ou um array deles
|
|
276
|
+
* (campo "vários arquivos"). Mesma forma do `FileRef` de `@workspace/task-forms`.
|
|
277
|
+
*/
|
|
278
|
+
interface FileRef {
|
|
279
|
+
/** id do arquivo na run (no storage 'local', um uuid — nome da pasta em HOBOTS_LOCAL_FILES_DIR) */
|
|
280
|
+
id: string;
|
|
281
|
+
/** nome original, como o usuário enviou */
|
|
282
|
+
name: string;
|
|
283
|
+
/** tamanho em bytes */
|
|
284
|
+
size: number;
|
|
285
|
+
contentType: string;
|
|
286
|
+
storage: FileStorage;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* POST /v1/runs/{id}/files/{fileId}/download (corpo vazio) — 200 com a URL pré-assinada
|
|
290
|
+
* de GET; 404 = arquivo não existe nesta run; 410 = já baixado (confirmado) ou expirado.
|
|
291
|
+
* Depois do GET completo o agente confirma com DELETE /v1/runs/{id}/files/{fileId}
|
|
292
|
+
* (204, idempotente), e o servidor apaga o objeto do S3.
|
|
293
|
+
*/
|
|
294
|
+
interface FileDownloadResponse {
|
|
295
|
+
/** URL pré-assinada de GET direto no S3 (não envie Authorization nesta requisição) */
|
|
296
|
+
url: string;
|
|
297
|
+
/** Validade da URL, em segundos */
|
|
298
|
+
expires_in: number;
|
|
299
|
+
name: string;
|
|
300
|
+
/** tamanho exato em bytes — o SDK confere o download contra ele */
|
|
301
|
+
size: number;
|
|
302
|
+
content_type: string;
|
|
303
|
+
}
|
|
266
304
|
|
|
267
305
|
var MAX_ITEMS_PER_ENVELOPE = 50;
|
|
268
306
|
var HEARTBEAT_DEFAULT_INTERVAL_MS = 30000;
|
|
@@ -273,7 +311,6 @@ var MAX_LOG_MESSAGE_CHARS = 10000;
|
|
|
273
311
|
var MAX_LOGS_PER_PATCH = 100;
|
|
274
312
|
var MAX_ERROR_MESSAGE_CHARS = 10000;
|
|
275
313
|
var MAX_ERROR_STACK_CHARS = 20000;
|
|
276
|
-
var MAX_ITEMS_PER_RUN = 10000;
|
|
277
314
|
var MAX_ITEMS_PER_REQUEST = 500;
|
|
278
315
|
var MAX_ITEM_MESSAGE_CHARS = 2000;
|
|
279
316
|
var MAX_ITEM_PAYLOAD_BYTES = 16384;
|
|
@@ -294,7 +331,6 @@ var limits = {
|
|
|
294
331
|
MAX_LOGS_PER_PATCH: MAX_LOGS_PER_PATCH,
|
|
295
332
|
MAX_ERROR_MESSAGE_CHARS: MAX_ERROR_MESSAGE_CHARS,
|
|
296
333
|
MAX_ERROR_STACK_CHARS: MAX_ERROR_STACK_CHARS,
|
|
297
|
-
MAX_ITEMS_PER_RUN: MAX_ITEMS_PER_RUN,
|
|
298
334
|
MAX_ITEMS_PER_REQUEST: MAX_ITEMS_PER_REQUEST,
|
|
299
335
|
MAX_ITEM_MESSAGE_CHARS: MAX_ITEM_MESSAGE_CHARS,
|
|
300
336
|
MAX_ITEM_PAYLOAD_BYTES: MAX_ITEM_PAYLOAD_BYTES,
|
|
@@ -443,4 +479,4 @@ interface Envelope {
|
|
|
443
479
|
items: EnvelopeItem[];
|
|
444
480
|
}
|
|
445
481
|
|
|
446
|
-
export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type HeartbeatPayload, type InstanceInfo, type InstanceMode, type ItemColumn, type ItemsDeclaration, type MachineProcess, type MachineSnapshot, type PollRequest, type PollResponse, type RunAttachmentConfirmRequest, type RunAttachmentConfirmResponse, type RunAttachmentContentType, type RunAttachmentCreateRequest, type RunAttachmentCreateResponse, type RunCreateRequest, type RunCreateResponse, type RunDescriptor, type RunError, type RunItemInput, type RunItemStatus, type RunItemsCreateRequest, type RunItemsCreateResponse, type RunLogEntry, type RunLogLevel, type RunProgress, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
|
482
|
+
export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type FileDownloadResponse, type FileRef, type FileStorage, type HeartbeatPayload, type InstanceInfo, type InstanceMode, type ItemColumn, type ItemsDeclaration, type MachineProcess, type MachineSnapshot, type PollRequest, type PollResponse, type RunAttachmentConfirmRequest, type RunAttachmentConfirmResponse, type RunAttachmentContentType, type RunAttachmentCreateRequest, type RunAttachmentCreateResponse, type RunCreateRequest, type RunCreateResponse, type RunDescriptor, type RunError, type RunItemInput, type RunItemStatus, type RunItemsCreateRequest, type RunItemsCreateResponse, type RunLogEntry, type RunLogLevel, type RunProgress, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
package/dist/protocol.js
CHANGED
package/docs/api-reference.md
CHANGED
|
@@ -19,6 +19,7 @@ ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois do
|
|
|
19
19
|
| `hobots.captureException` | `(error: unknown, hint?: CaptureHint) => string \| undefined` | Issue no módulo Issues; devolve o `event_id`. Antes de iniciar o agente: descarta com aviso. |
|
|
20
20
|
| `hobots.retry` | `<T>(fn: (attempt: number) => T \| Promise<T>, options?: RetryOptions) => Promise<T>` | async-retry; dentro de uma execução usa o signal dela. |
|
|
21
21
|
| `hobots.image` | `(input: AttachInput, options?: ImageOptions) => ImageAttachment` | Embrulha um print para ir junto de um log, item ou step. Puro, nunca lança. |
|
|
22
|
+
| `isFileRef` / `hobots.isFileRef` | `(value: unknown) => value is FileRef` | Reconhece um arquivo de campo de upload nos params. Puro. |
|
|
22
23
|
|
|
23
24
|
## Contexto da execução (`RunContext` — os membros de `hobots` e o `ctx` do handler)
|
|
24
25
|
|
|
@@ -29,7 +30,9 @@ ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois do
|
|
|
29
30
|
| `log` | `RunLogger` — `debug/info/warn/error/success(message, ...rest)` | Nunca lança. Vários argumentos viram texto unidos por espaço (como `console.log`); um `hobots.image(...)` no **último** argumento vira o print da linha. Eco no terminal: `[hobots] INFO …` |
|
|
30
31
|
| `items` | `RunItems` — `add(item)`, `succeeded(payload?, opts?)`, `failed(message, payload?, opts?)`, `occurrence(message, payload?, opts?)`; `opts.id` = identidade de negócio, `opts.image` = print do item. `each(list, (element, item, index) => …, { id?, payload?, op?, description?, progress? }) => Promise<{ total, succeeded, failed, occurrence }>` processa a lista inteira: exceção no handler vira item `failed` + step em erro e o loop segue; `item: RunItemHandle` = `succeeded(payload?, { image }?)/failed(msg, payload?, { image }?)/occurrence(…)`, `id`, `index`, `step`, `reported` | Ponto de parada cooperativo (o `each` para só em cancelamento/timeout) |
|
|
31
32
|
| `progress` | `RunProgressReporter` — `total(n)`, `advance(count = 1)`, `set(current, total?)`, `current`, `snapshot` | `total/advance/set` são pontos de parada |
|
|
32
|
-
| `
|
|
33
|
+
| `files` | `RunFiles` — `list(): FileRef[]`, `get(field): FileRef \| FileRef[] \| undefined`, `download(refOrField: FileRef \| string, { dest? }?): Promise<string>`, `downloadAll(field, { dest? }?): Promise<string[]>`, `read(refOrField): Promise<Buffer>` | Arquivos do formulário; o download consome a origem (S3 confirmado/apagado, pasta do Studio removida). Cópias sem `dest` são apagadas no fim da execução. Respeita o `signal`. Ver [Execuções](./runs.md#arquivos-do-formulário-hobotsfiles) |
|
|
34
|
+
| `flush` | `(timeoutMs = 15_000) => Promise<void>` — envia já as steps raiz finalizadas (transactions parciais, op `hobots.run.flush`) e os itens/logs/progresso pendentes | Nunca lança |
|
|
35
|
+
| `transaction` | `Transaction` (`run`, op `hobots.run`) — `startChild(op?, description?)`, `flush()`, `setTag`, `setStatus`, `setName`; `Step` — `startChild`, `setStatus('ok' \| 'warning' \| 'error', message?, { image }?)`, `setError(err, message?, { image }?)` (motivo em `data.error`, print em `data.attachments`, exibidos na Central), `setData(k, v)`, `finish()` | Finalizada pelo SDK; `startChild` é ponto de parada |
|
|
33
36
|
| `signal` | `AbortSignal` | Cancelamento (app, timeout, shutdown) |
|
|
34
37
|
| `throwIfCanceled()` | `() => void` | Lança `RunCanceled` se o signal disparou |
|
|
35
38
|
| `sleep(ms)` | `(ms: number) => Promise<void>` | Rejeita com `RunCanceled` no cancelamento |
|
package/docs/protocol.md
CHANGED
|
@@ -161,7 +161,7 @@ Resposta `200` `RunItemsCreateResponse`: `{ "accepted": 1, "duplicates": 0 }`
|
|
|
161
161
|
|
|
162
162
|
- **Run cancelada/terminal aceita itens** (200): item é fato de trabalho já feito — mesmo racional do log tardio. Esta rota não tem 409.
|
|
163
163
|
- O insert e os **contadores materializados** da run (`items_total/succeeded/failed/occurrence`, que alimentam os totalizadores no app) saem num único statement atômico no servidor.
|
|
164
|
-
- Retry `[1s, 4s, 16s]` para rede/5xx; `404` = servidor sem o recurso (o SDK degrada em silêncio); `
|
|
164
|
+
- Retry `[1s, 4s, 16s]` para rede/5xx; `404` = servidor sem o recurso (o SDK degrada em silêncio); `402` = armazenamento do plano esgotado. Não há teto de itens por run.
|
|
165
165
|
|
|
166
166
|
| Status | Quando |
|
|
167
167
|
| --- | --- |
|
|
@@ -169,7 +169,7 @@ Resposta `200` `RunItemsCreateResponse`: `{ "accepted": 1, "duplicates": 0 }`
|
|
|
169
169
|
| `404` | execução inexistente ou de outro projeto |
|
|
170
170
|
| `413` | corpo acima de 1 MB |
|
|
171
171
|
| `422` | payload inválido |
|
|
172
|
-
| `
|
|
172
|
+
| `402` | armazenamento do plano esgotado (`storage_limit`) |
|
|
173
173
|
|
|
174
174
|
### `POST /v1/runs/{id}/attachments`
|
|
175
175
|
|
|
@@ -220,6 +220,16 @@ Confirma o upload. Corpo `RunAttachmentConfirmRequest`: `{ "status": "uploaded"
|
|
|
220
220
|
|
|
221
221
|
Limites de anexo (aplicados no SDK **e** no servidor): PNG/JPEG/WEBP, 5 MB por imagem, 20 por execução, 4 por evento (linha de log, item ou step).
|
|
222
222
|
|
|
223
|
+
### `POST /v1/runs/{id}/files/{fileId}/download`
|
|
224
|
+
|
|
225
|
+
Arquivo de campo de upload do formulário com `storage: 's3'` (o valor do campo nos params é um `FileRef` `{ id, name, size, contentType, storage }`, ou uma lista). Corpo vazio. Resposta `FileDownloadResponse`: `{ "url", "expires_in", "name", "size", "content_type" }` — `url` é um GET pré-assinado direto no S3 (o SDK **não** manda `Authorization` nele). `404` = o arquivo não existe nesta execução; `410` = já baixado (confirmado) ou expirado.
|
|
226
|
+
|
|
227
|
+
### `DELETE /v1/runs/{id}/files/{fileId}`
|
|
228
|
+
|
|
229
|
+
Confirma o download: o servidor apaga o objeto do S3 na hora. `204`, idempotente. O SDK só chama depois do GET completo e do tamanho conferido; `404`/`410` aqui contam como confirmado.
|
|
230
|
+
|
|
231
|
+
Arquivos com `storage: 'local'` (escolhidos no Studio) não passam pela API: ficam em `$HOBOTS_LOCAL_FILES_DIR/<id>/<nome>` no computador do bot.
|
|
232
|
+
|
|
223
233
|
## Onde vive o claim atômico
|
|
224
234
|
|
|
225
235
|
O `POST /v1/runs/poll` no app chama `claimPendingRuns()` em
|
package/docs/runs.md
CHANGED
|
@@ -16,7 +16,7 @@ hobots.start(async () => { /* while (true) { … } */ });
|
|
|
16
16
|
- `start` — ao iniciar, o SDK cria a execução (`POST /v1/runs`) e roda o handler com `params = {}`. Enquanto a plataforma não responde, insiste com backoff — o handler só começa quando a execução existe. Quando o handler retorna, a execução fecha como `succeeded` (ou `failed` após os retries) e o processo segue vivo pelo heartbeat. **Uma execução por processo** — para "recomeçar", reinicie o robô.
|
|
17
17
|
- **Uma chamada por processo**: `register` ou `start`. A segunda lança (`o agente já foi iniciado`). Dois trabalhos diferentes são dois agentes.
|
|
18
18
|
|
|
19
|
-
> No modo start, lembre do teto de **1000 linhas de log por execução** no servidor: logue novidades e use `hobots.items` para o trabalho feito (
|
|
19
|
+
> No modo start, lembre do teto de **1000 linhas de log por execução** no servidor: logue novidades e use `hobots.items` para o trabalho feito (sem teto por execução — só o armazenamento do plano limita).
|
|
20
20
|
|
|
21
21
|
## O handler e o objeto `hobots`
|
|
22
22
|
|
|
@@ -68,7 +68,7 @@ hobots.items.add({ status: 'succeeded', id: '11', payload: { … } });
|
|
|
68
68
|
|
|
69
69
|
- Chamadas síncronas e bufferizadas (lotes de até 500); o SDK drena o buffer antes do reporte final.
|
|
70
70
|
- `id` é a identidade de negócio do item na execução — repetido, **vale o último reporte** (o servidor faz upsert: uma conta que falhou numa tentativa e deu certo no retry fica como sucesso; retry de rede é no-op). Sem `id`, cada chamada é um item novo.
|
|
71
|
-
- Limites:
|
|
71
|
+
- Limites: sem teto de itens por execução (só o armazenamento do plano), payload 16 KB, mensagem 2.000 caracteres. Uma execução cancelada ainda aceita os itens já bufferizados (trabalho feito).
|
|
72
72
|
- Cada chamada é um **ponto de parada cooperativo** (lança `RunCanceled` se a execução foi cancelada).
|
|
73
73
|
|
|
74
74
|
### Processar uma lista inteira (`hobots.items.each`)
|
|
@@ -112,6 +112,34 @@ hobots.register(handler, {
|
|
|
112
112
|
- A declaração vai na presença da instância (`instance.items` no poll / abertura de run). No app, **Configurações → agente → itens da execução** pode personalizar as colunas (e restaurar as do código).
|
|
113
113
|
- Sem declaração nem personalização, o app mostra as chaves encontradas nos próprios payloads.
|
|
114
114
|
|
|
115
|
+
## Entregar enquanto processa (`hobots.flush()`)
|
|
116
|
+
|
|
117
|
+
A transaction da execução só é enviada quando a run termina — num agente sempre ligado (`start()`) isso é nunca. `hobots.flush()` deixa o **bot** decidir quando entregar o que já fez:
|
|
118
|
+
|
|
119
|
+
- cada step **raiz** já finalizada (com todas as filhas; as filhas ainda abertas são fechadas) vai numa transaction parcial da mesma run (`op` `hobots.run.flush`, `event_id` novo, até 200 steps cada) e sai da memória do SDK; steps raiz ainda abertas ficam para o próximo flush;
|
|
120
|
+
- itens, logs e progresso pendentes saem já, sem esperar o throttle;
|
|
121
|
+
- aguarda a entrega com teto (`timeoutMs`, default 15 s) e **nunca lança** — pode ir num `finally`.
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
hobots.start(async () => {
|
|
125
|
+
while (true) {
|
|
126
|
+
const lote = await fila.pegar();
|
|
127
|
+
if (lote.length) {
|
|
128
|
+
const rodada = hobots.transaction.startChild('rodada', `${lote.length} pedido(s)`);
|
|
129
|
+
try {
|
|
130
|
+
for (const pedido of lote) await processar(pedido, rodada); // steps filhas + hobots.items.*
|
|
131
|
+
} finally {
|
|
132
|
+
rodada.finish();
|
|
133
|
+
await hobots.flush(); // waterfall e itens desta rodada já na Central
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
await hobots.sleep(6_000);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Fila vazia → não abra step: cada step também vira duas linhas (START/FINISH) no log da execução, que guarda no máximo 1000.
|
|
142
|
+
|
|
115
143
|
## Progresso (`hobots.progress`)
|
|
116
144
|
|
|
117
145
|
```js
|
|
@@ -124,6 +152,36 @@ for (const nota of notas) {
|
|
|
124
152
|
|
|
125
153
|
Opcional e independente de `items`. Sem `total()` nada é enviado. Snapshot absoluto que pega carona nos PATCHes de log (no pior caso 1/s); o PATCH terminal leva o valor final. `set(atual, total?)`, `current` e `snapshot` completam a API. `total/advance/set` são pontos de parada cooperativos; `current`/`snapshot` nunca lançam.
|
|
126
154
|
|
|
155
|
+
## Arquivos do formulário (`hobots.files`)
|
|
156
|
+
|
|
157
|
+
Um campo de upload do formulário chega nos `params` como um `FileRef` — `{ id, name, size, contentType, storage }` — ou como uma lista deles (campo "vários arquivos"). `hobots.files` traz o arquivo para o disco desta máquina:
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
const caminho = await hobots.files.download('planilha'); // campo único
|
|
161
|
+
const caminhos = await hobots.files.downloadAll('notas', { dest: './entrada' }); // lista
|
|
162
|
+
const bytes = await hobots.files.read('contrato'); // Buffer em memória
|
|
163
|
+
for (const ref of hobots.files.list()) hobots.log.info(ref.name, ref.size);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
| Método | Retorno | Notas |
|
|
167
|
+
| --- | --- | --- |
|
|
168
|
+
| `list()` | `FileRef[]` | Todos os arquivos dos params (campos de topo, valor único ou lista), na ordem dos campos. |
|
|
169
|
+
| `get(campo)` | `FileRef \| FileRef[] \| undefined` | `undefined` se o campo não tem arquivo. |
|
|
170
|
+
| `download(refOuCampo, { dest? })` | `Promise<string>` | Caminho local. Campo com vários arquivos lança — use `downloadAll` ou passe um item. |
|
|
171
|
+
| `downloadAll(campo, { dest? })` | `Promise<string[]>` | Em ordem; aqui `dest` é sempre uma pasta. |
|
|
172
|
+
| `read(refOuCampo)` | `Promise<Buffer>` | Baixa, lê e apaga a cópia. |
|
|
173
|
+
|
|
174
|
+
**Origem consumida.** O arquivo é baixado **uma vez**:
|
|
175
|
+
|
|
176
|
+
- `storage: 's3'` (enviado pela Central): o SDK pede a URL pré-assinada, baixa em streaming para um `.part`, confere o tamanho contra o anunciado e só então confirma — o servidor apaga o objeto do S3 na hora. Uma falha (rede, tamanho divergente, 60 s sem bytes novos, cancelamento) apaga o `.part`, **não confirma** e o download pode ser tentado de novo. Depois de confirmado, um novo download lança `TasksApiError` 410 `arquivo "x" já baixado ou expirado`; arquivo que não existe na execução, 404 `arquivo "x" não encontrado nesta execução`. Se a confirmação falhar (o arquivo já está no disco), o download dá certo e sai um aviso no log da execução — o servidor apaga o objeto quando ele expirar.
|
|
177
|
+
- `storage: 'local'` (escolhido no Studio): o arquivo **nunca sai do computador**. O Studio o deixa em `$HOBOTS_LOCAL_FILES_DIR/<id>/<nome>`; o SDK confere que o id é um uuid e que a pasta resolvida fica dentro do diretório, copia o único arquivo regular dela (links simbólicos não contam), confere o tamanho e apaga a pasta de origem. Sem a env ou sem a pasta (bot em outro computador, arquivo já consumido): `arquivo "x" enviado pelo Studio de outro computador ou já consumido`.
|
|
178
|
+
|
|
179
|
+
**Destino.** Sem `dest`, a cópia vai para uma subpasta própria dentro da pasta temporária da execução, **apagada quando a execução termina** (arquivo de cliente não fica esquecido no disco). `dest` que é uma pasta existente — ou termina em `/` — recebe o arquivo com o nome original (só o último segmento, sem caracteres proibidos no Windows); qualquer outro caminho é o arquivo final (as pastas intermediárias são criadas).
|
|
180
|
+
|
|
181
|
+
**Cancelamento.** `download`/`downloadAll`/`read` respeitam `hobots.signal`: cancelada a execução, lançam `RunCanceled` e o arquivo não é consumido. Fora de uma execução, `list()` é vazio e os downloads rejeitam.
|
|
182
|
+
|
|
183
|
+
`isFileRef(valor)` (export do pacote, também `hobots.isFileRef`) reconhece a forma de um `FileRef` — útil para percorrer params aninhados.
|
|
184
|
+
|
|
127
185
|
## Imagens (screenshots)
|
|
128
186
|
|
|
129
187
|
Um print vai **junto do evento** que ele ilustra — a linha de log, o item ou a step — para o
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hobots",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "SDK JavaScript da Hobots — o agente é a própria tarefa: register() atende solicitações da plataforma (sob demanda), start() roda sempre ligado e reporta logs, itens e progresso. Credenciais por env, heartbeat sempre ligado, objeto global `hobots`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["{\n \"MAX_ITEMS_PER_ENVELOPE\": 50,\n \"HEARTBEAT_DEFAULT_INTERVAL_MS\": 30000,\n \"HEARTBEAT_MIN_INTERVAL_MS\": 1000,\n \"HEARTBEAT_MAX_INTERVAL_MS\": 900000,\n \"MAX_CLAIM_PER_POLL\": 5,\n \"MAX_LOG_MESSAGE_CHARS\": 10000,\n \"MAX_LOGS_PER_PATCH\": 100,\n \"MAX_ERROR_MESSAGE_CHARS\": 10000,\n \"MAX_ERROR_STACK_CHARS\": 20000,\n \"MAX_ITEMS_PER_RUN\": 10000,\n \"MAX_ITEMS_PER_REQUEST\": 500,\n \"MAX_ITEM_MESSAGE_CHARS\": 2000,\n \"MAX_ITEM_PAYLOAD_BYTES\": 16384,\n \"MAX_ITEM_COLUMNS\": 12,\n \"MAX_ITEM_COLUMN_LABEL_CHARS\": 60,\n \"MAX_ATTACHMENT_BYTES\": 5242880,\n \"MAX_ATTACHMENTS_PER_RUN\": 20,\n \"MAX_ATTACHMENTS_PER_LOG_ENTRY\": 4,\n \"MAX_CAPTION_CHARS\": 200,\n \"MAX_IMAGE_DIMENSION_PX\": 20000\n}\n","import limits from '../protocol-limits.json';\n\n/**\n * Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK\n * Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python\n * confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o\n * JSON (e, no Python, a constante espelhada — o teste acusa).\n */\nexport const WIRE_LIMITS = limits as Readonly<typeof limits>;\nexport type WireLimits = typeof WIRE_LIMITS;\n"],"mappings":";AAAA;AAAA,EACE,wBAA0B;AAAA,EAC1B,+BAAiC;AAAA,EACjC,2BAA6B;AAAA,EAC7B,2BAA6B;AAAA,EAC7B,oBAAsB;AAAA,EACtB,uBAAyB;AAAA,EACzB,oBAAsB;AAAA,EACtB,yBAA2B;AAAA,EAC3B,uBAAyB;AAAA,EACzB,mBAAqB;AAAA,EACrB,uBAAyB;AAAA,EACzB,wBAA0B;AAAA,EAC1B,wBAA0B;AAAA,EAC1B,kBAAoB;AAAA,EACpB,6BAA+B;AAAA,EAC/B,sBAAwB;AAAA,EACxB,yBAA2B;AAAA,EAC3B,+BAAiC;AAAA,EACjC,mBAAqB;AAAA,EACrB,wBAA0B;AAC5B;;;ACbO,IAAM,cAAc;","names":[]}
|